]> git.proxmox.com Git - qemu.git/blobdiff - hw/sm501.c
Merge remote-tracking branch 'spice/spice.v39' into staging
[qemu.git] / hw / sm501.c
index b5ec2dae9c229f64da95c30e9b1a5928ebbb6ad3..0f0bf96609b0dcedccda4f518816ccc8aef890ce 100644 (file)
@@ -29,6 +29,7 @@
 #include "devices.h"
 #include "sysbus.h"
 #include "qdev-addr.h"
+#include "range.h"
 
 /*
  * Status: 2010/05/07
@@ -510,6 +511,7 @@ typedef struct SM501State {
     uint32_t dc_crt_hwc_color_1_2;
     uint32_t dc_crt_hwc_color_3;
 
+    uint32_t twoD_source;
     uint32_t twoD_destination;
     uint32_t twoD_dimension;
     uint32_t twoD_control;
@@ -635,6 +637,9 @@ static void sm501_2d_operation(SM501State * s)
 {
     /* obtain operation parameters */
     int operation = (s->twoD_control >> 16) & 0x1f;
+    int rtl = s->twoD_control & 0x8000000;
+    int src_x = (s->twoD_source >> 16) & 0x01FFF;
+    int src_y = s->twoD_source & 0xFFFF;
     int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
     int dst_y = s->twoD_destination & 0xFFFF;
     int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
@@ -644,10 +649,9 @@ static void sm501_2d_operation(SM501State * s)
     int addressing = (s->twoD_stretch >> 16) & 0xF;
 
     /* get frame buffer info */
-#if 0 /* for future use */
     uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
-#endif
     uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
+    int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
     int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
 
     if (addressing != 0x0) {
@@ -662,8 +666,36 @@ static void sm501_2d_operation(SM501State * s)
     }
 
     switch (operation) {
-    case 0x01: /* fill rectangle */
+    case 0x00: /* copy area */
+#define COPY_AREA(_bpp, _pixel_type, rtl) {                                 \
+        int y, x, index_d, index_s;                                         \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                if (rtl) {                                                  \
+                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
+                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
+                } else {                                                    \
+                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
+                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+                }                                                           \
+                *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
+            }                                                               \
+        }                                                                   \
+    }
+        switch (format_flags) {
+        case 0:
+            COPY_AREA(1, uint8_t, rtl);
+            break;
+        case 1:
+            COPY_AREA(2, uint16_t, rtl);
+            break;
+        case 2:
+            COPY_AREA(4, uint32_t, rtl);
+            break;
+        }
+        break;
 
+    case 0x01: /* fill rectangle */
 #define FILL_RECT(_bpp, _pixel_type) {                                      \
         int y, x;                                                           \
         for (y = 0; y < operation_height; y++) {                            \
@@ -814,7 +846,7 @@ static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr)
     /* TODO : consider BYTE/WORD access */
     /* TODO : consider endian */
 
-    assert(0 <= addr && addr < 0x400 * 3);
+    assert(range_covers_byte(0, 0x400 * 3, addr));
     return *(uint32_t*)&s->dc_palette[addr];
 }
 
@@ -828,7 +860,7 @@ static void sm501_palette_write(void *opaque,
     /* TODO : consider BYTE/WORD access */
     /* TODO : consider endian */
 
-    assert(0 <= addr && addr < 0x400 * 3);
+    assert(range_covers_byte(0, 0x400 * 3, addr));
     *(uint32_t*)&s->dc_palette[addr] = value;
 }
 
@@ -1071,6 +1103,9 @@ static void sm501_2d_engine_write(void *opaque,
                   addr, value);
 
     switch(addr) {
+    case SM501_2D_SOURCE:
+        s->twoD_source = value;
+        break;
     case SM501_2D_DESTINATION:
         s->twoD_destination = value;
         break;
@@ -1239,8 +1274,8 @@ static void sm501_draw_crt(SM501State * s)
     draw_hwc_line_func * draw_hwc_line = NULL;
     int full_update = 0;
     int y_start = -1;
-    int page_min = 0x7fffffff;
-    int page_max = -1;
+    ram_addr_t page_min = ~0l;
+    ram_addr_t page_max = 0l;
     ram_addr_t offset = s->local_mem_offset;
 
     /* choose draw_line function */
@@ -1336,9 +1371,10 @@ static void sm501_draw_crt(SM501State * s)
        dpy_update(s->ds, 0, y_start, width, y - y_start);
 
     /* clear dirty flags */
-    if (page_max != -1)
+    if (page_min != ~0l) {
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
                                        VGA_DIRTY_FLAG);
+    }
 }
 
 static void sm501_update_display(void *opaque)
@@ -1371,22 +1407,25 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
     s->dc_crt_control = 0x00010000;
 
     /* allocate local memory */
-    s->local_mem_offset = qemu_ram_alloc(local_mem_bytes);
+    s->local_mem_offset = qemu_ram_alloc(NULL, "sm501.local", local_mem_bytes);
     s->local_mem = qemu_get_ram_ptr(s->local_mem_offset);
     cpu_register_physical_memory(base, local_mem_bytes, s->local_mem_offset);
 
     /* map mmio */
     sm501_system_config_index
        = cpu_register_io_memory(sm501_system_config_readfn,
-                                sm501_system_config_writefn, s);
+                                sm501_system_config_writefn, s,
+                                 DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base + MMIO_BASE_OFFSET,
                                 0x6c, sm501_system_config_index);
     sm501_disp_ctrl_index = cpu_register_io_memory(sm501_disp_ctrl_readfn,
-                                                  sm501_disp_ctrl_writefn, s);
+                                                  sm501_disp_ctrl_writefn, s,
+                                                   DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC,
                                  0x1000, sm501_disp_ctrl_index);
     sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn,
-                                                   sm501_2d_engine_writefn, s);
+                                                   sm501_2d_engine_writefn, s,
+                                                   DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
                                  0x54, sm501_2d_engine_index);