diff options
Diffstat (limited to 'hw/display/sm501.c')
| -rw-r--r-- | hw/display/sm501.c | 127 |
1 files changed, 92 insertions, 35 deletions
diff --git a/hw/display/sm501.c b/hw/display/sm501.c index e1d0591d36..17835159fc 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -28,6 +28,7 @@ #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" +#include "hw/usb/hcd-ohci.h" #include "hw/char/serial.h" #include "ui/console.h" #include "hw/sysbus.h" @@ -691,7 +692,7 @@ static void sm501_2d_operation(SM501State *s) unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); - bool overlap = false; + bool overlap = false, fallback = false; if ((s->twoD_stretch >> 16) & 0xF) { qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); @@ -753,7 +754,7 @@ static void sm501_2d_operation(SM501State *s) } if ((rop_mode && rop == 0x5) || (!rop_mode && rop == 0x55)) { - /* Invert dest, is there a way to do this with pixman? */ + /* DSTINVERT, is there a way to do this with pixman? */ unsigned int x, y, i; uint8_t *d = s->local_mem + dst_base; @@ -763,6 +764,34 @@ static void sm501_2d_operation(SM501State *s) stn_he_p(&d[i], bypp, ~ldn_he_p(&d[i], bypp)); } } + } else if (!rop_mode && rop == 0x99) { + /* DSxn, is there a way to do this with pixman? */ + unsigned int x, y, i, j; + uint8_t *sp = s->local_mem + src_base; + uint8_t *d = s->local_mem + dst_base; + + for (y = 0; y < height; y++) { + i = (dst_x + (dst_y + y) * dst_pitch) * bypp; + j = (src_x + (src_y + y) * src_pitch) * bypp; + for (x = 0; x < width; x++, i += bypp, j += bypp) { + stn_he_p(&d[i], bypp, + ~(ldn_he_p(&sp[j], bypp) ^ ldn_he_p(&d[i], bypp))); + } + } + } else if (!rop_mode && rop == 0xee) { + /* SRCPAINT, is there a way to do this with pixman? */ + unsigned int x, y, i, j; + uint8_t *sp = s->local_mem + src_base; + uint8_t *d = s->local_mem + dst_base; + + for (y = 0; y < height; y++) { + i = (dst_x + (dst_y + y) * dst_pitch) * bypp; + j = (src_x + (src_y + y) * src_pitch) * bypp; + for (x = 0; x < width; x++, i += bypp, j += bypp) { + stn_he_p(&d[i], bypp, + ldn_he_p(&sp[j], bypp) | ldn_he_p(&d[i], bypp)); + } + } } else { /* Do copy src for unimplemented ops, better than unpainted area */ if ((rop_mode && (rop != 0xc || rop2_source_is_pattern)) || @@ -806,25 +835,48 @@ static void sm501_2d_operation(SM501State *s) if (tmp_stride * sizeof(uint32_t) * height > sizeof(tmp_buf)) { tmp = g_malloc(tmp_stride * sizeof(uint32_t) * height); } - pixman_blt((uint32_t *)&s->local_mem[src_base], tmp, - src_pitch * bypp / sizeof(uint32_t), - tmp_stride, 8 * bypp, 8 * bypp, - src_x, src_y, 0, 0, width, height); - pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base], - tmp_stride, - dst_pitch * bypp / sizeof(uint32_t), - 8 * bypp, 8 * bypp, - 0, 0, dst_x, dst_y, width, height); + fallback = !pixman_blt((uint32_t *)&s->local_mem[src_base], + tmp, + src_pitch * bypp / sizeof(uint32_t), + tmp_stride, + 8 * bypp, 8 * bypp, + src_x, src_y, 0, 0, width, height); + if (!fallback) { + fallback = !pixman_blt(tmp, + (uint32_t *)&s->local_mem[dst_base], + tmp_stride, + dst_pitch * bypp / sizeof(uint32_t), + 8 * bypp, 8 * bypp, + 0, 0, dst_x, dst_y, width, height); + } if (tmp != tmp_buf) { g_free(tmp); } } else { - pixman_blt((uint32_t *)&s->local_mem[src_base], - (uint32_t *)&s->local_mem[dst_base], - src_pitch * bypp / sizeof(uint32_t), - dst_pitch * bypp / sizeof(uint32_t), - 8 * bypp, 8 * bypp, - src_x, src_y, dst_x, dst_y, width, height); + fallback = !pixman_blt((uint32_t *)&s->local_mem[src_base], + (uint32_t *)&s->local_mem[dst_base], + src_pitch * bypp / sizeof(uint32_t), + dst_pitch * bypp / sizeof(uint32_t), + 8 * bypp, 8 * bypp, src_x, src_y, + dst_x, dst_y, width, height); + } + if (fallback) { + uint8_t *sp = s->local_mem + src_base; + uint8_t *d = s->local_mem + dst_base; + unsigned int y, i, j; + for (y = 0; y < height; y++) { + if (overlap) { /* overlap also means rtl */ + i = (dst_y + height - 1 - y) * dst_pitch; + i = (dst_x + i) * bypp; + j = (src_y + height - 1 - y) * src_pitch; + j = (src_x + j) * bypp; + memmove(&d[i], &sp[j], width * bypp); + } else { + i = (dst_x + (dst_y + y) * dst_pitch) * bypp; + j = (src_x + (src_y + y) * src_pitch) * bypp; + memcpy(&d[i], &sp[j], width * bypp); + } + } } } break; @@ -839,13 +891,19 @@ static void sm501_2d_operation(SM501State *s) color = cpu_to_le16(color); } - if (width == 1 && height == 1) { - unsigned int i = (dst_x + dst_y * dst_pitch) * bypp; - stn_he_p(&s->local_mem[dst_base + i], bypp, color); - } else { - pixman_fill((uint32_t *)&s->local_mem[dst_base], - dst_pitch * bypp / sizeof(uint32_t), - 8 * bypp, dst_x, dst_y, width, height, color); + if ((width == 1 && height == 1) || + !pixman_fill((uint32_t *)&s->local_mem[dst_base], + dst_pitch * bypp / sizeof(uint32_t), 8 * bypp, + dst_x, dst_y, width, height, color)) { + /* fallback when pixman failed or we don't want to call it */ + uint8_t *d = s->local_mem + dst_base; + unsigned int x, y, i; + for (y = 0; y < height; y++, i += dst_pitch * bypp) { + i = (dst_x + (dst_y + y) * dst_pitch) * bypp; + for (x = 0; x < width; x++, i += bypp) { + stn_he_p(&d[i], bypp, color); + } + } } break; } @@ -1943,15 +2001,14 @@ struct SM501SysBusState { /*< public >*/ SM501State state; uint32_t vram_size; - uint32_t base; SerialMM serial; + OHCISysBusState ohci; }; static void sm501_realize_sysbus(DeviceState *dev, Error **errp) { SM501SysBusState *s = SYSBUS_SM501(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - DeviceState *usb_dev; MemoryRegion *mr; sm501_init(&s->state, dev, s->vram_size); @@ -1964,13 +2021,10 @@ static void sm501_realize_sysbus(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->state.mmio_region); /* bridge to usb host emulation module */ - usb_dev = qdev_new("sysbus-ohci"); - qdev_prop_set_uint32(usb_dev, "num-ports", 2); - qdev_prop_set_uint64(usb_dev, "dma-offset", s->base); - sysbus_realize_and_unref(SYS_BUS_DEVICE(usb_dev), &error_fatal); + sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->ohci), &error_fatal); memory_region_add_subregion(&s->state.mmio_region, SM501_USB_HOST, - sysbus_mmio_get_region(SYS_BUS_DEVICE(usb_dev), 0)); - sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev)); + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ohci), 0)); + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->ohci)); /* bridge to serial emulation module */ sysbus_realize(SYS_BUS_DEVICE(&s->serial), &error_fatal); @@ -1981,7 +2035,6 @@ static void sm501_realize_sysbus(DeviceState *dev, Error **errp) static Property sm501_sysbus_properties[] = { DEFINE_PROP_UINT32("vram-size", SM501SysBusState, vram_size, 0), - DEFINE_PROP_UINT32("base", SM501SysBusState, base, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -2017,15 +2070,19 @@ static void sm501_sysbus_class_init(ObjectClass *klass, void *data) static void sm501_sysbus_init(Object *o) { SM501SysBusState *sm501 = SYSBUS_SM501(o); + OHCISysBusState *ohci = &sm501->ohci; SerialMM *smm = &sm501->serial; + object_initialize_child(o, "ohci", ohci, TYPE_SYSBUS_OHCI); + object_property_add_alias(o, "dma-offset", OBJECT(ohci), "dma-offset"); + qdev_prop_set_uint32(DEVICE(ohci), "num-ports", 2); + object_initialize_child(o, "serial", smm, TYPE_SERIAL_MM); qdev_set_legacy_instance_id(DEVICE(smm), SM501_UART0, 2); qdev_prop_set_uint8(DEVICE(smm), "regshift", 2); qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN); - object_property_add_alias(o, "chardev", - OBJECT(smm), "chardev"); + object_property_add_alias(o, "chardev", OBJECT(smm), "chardev"); } static const TypeInfo sm501_sysbus_info = { |