PS2 mouse and keyboard separation (Paul Brook)
[qemu] / hw / cirrus_vga.c
index bd2355b..934cde9 100644 (file)
@@ -31,7 +31,7 @@
 
 /*
  * TODO:
- *    - add support for WRITEMASK (GR2F)
+ *    - destination write mask support not complete (bits 5..7)
  *    - optimize linear mappings
  *    - optimize bitblt functions
  */
@@ -259,9 +259,6 @@ typedef struct CirrusVGAState {
     uint8_t *cirrus_srcptr;
     uint8_t *cirrus_srcptr_end;
     uint32_t cirrus_srccounter;
-    uint8_t *cirrus_dstptr;
-    uint8_t *cirrus_dstptr_end;
-    uint32_t cirrus_dstcounter;
     /* hwcursor display state */
     int last_hw_cursor_size;
     int last_hw_cursor_x;
@@ -269,6 +266,7 @@ typedef struct CirrusVGAState {
     int last_hw_cursor_y_start;
     int last_hw_cursor_y_end;
     int real_vram_size; /* XXX: suppress that */
+    CPUWriteMemoryFunc **cirrus_linear_write;
 } CirrusVGAState;
 
 typedef struct PCICirrusVGAState {
@@ -285,7 +283,8 @@ static uint8_t rop_to_index[256];
  ***************************************/
 
 
-static void cirrus_bitblt_reset(CirrusVGAState * s);
+static void cirrus_bitblt_reset(CirrusVGAState *s);
+static void cirrus_update_memory_access(CirrusVGAState *s);
 
 /***************************************
  *
@@ -711,9 +710,7 @@ static void cirrus_bitblt_reset(CirrusVGAState * s)
     s->cirrus_srcptr = &s->cirrus_bltbuf[0];
     s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
     s->cirrus_srccounter = 0;
-    s->cirrus_dstptr = &s->cirrus_bltbuf[0];
-    s->cirrus_dstptr_end = &s->cirrus_bltbuf[0];
-    s->cirrus_dstcounter = 0;
+    cirrus_update_memory_access(s);
 }
 
 static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
@@ -740,12 +737,14 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
             else
                 s->cirrus_blt_srcpitch = ((w + 7) >> 3);
        } else {
-           s->cirrus_blt_srcpitch = s->cirrus_blt_width;
+            /* always align input size to 32 bits */
+           s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
        }
         s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
     }
     s->cirrus_srcptr = s->cirrus_bltbuf;
     s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
+    cirrus_update_memory_access(s);
     return 1;
 }
 
@@ -791,7 +790,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
     blt_rop = s->gr[0x32];
 
 #ifdef DEBUG_BITBLT
-    printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spicth=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
+    printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
            blt_rop, 
            s->cirrus_blt_mode,
            s->cirrus_blt_modeext,
@@ -801,7 +800,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
            s->cirrus_blt_srcpitch,
            s->cirrus_blt_dstaddr,
            s->cirrus_blt_srcaddr,
-           s->sr[0x2f]);
+           s->gr[0x2f]);
 #endif
 
     switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
@@ -1043,10 +1042,10 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
     else
        offset <<= 12;
 
-    if (s->vram_size <= offset)
+    if (s->real_vram_size <= offset)
        limit = 0;
     else
-       limit = s->vram_size - offset;
+       limit = s->real_vram_size - offset;
 
     if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
        if (limit > 0x8000) {
@@ -1199,7 +1198,6 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
     case 0x14:                 // Scratch Register 2
     case 0x15:                 // Scratch Register 3
     case 0x16:                 // Performance Tuning Register
-    case 0x17:                 // Configuration Readback and Extended Control
     case 0x18:                 // Signature Generator Control
     case 0x19:                 // Signature Generator Result
     case 0x1a:                 // Signature Generator Result
@@ -1214,6 +1212,10 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
               reg_index, reg_value);
 #endif
        break;
+    case 0x17:                 // Configuration Readback and Extended Control
+       s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7);
+        cirrus_update_memory_access(s);
+        break;
     default:
 #ifdef DEBUG_CIRRUS
        printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index,
@@ -1348,13 +1350,19 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
        return CIRRUS_HOOK_NOT_HANDLED;
     case 0x05:                 // Standard VGA, Cirrus extended mode
        s->gr[reg_index] = reg_value & 0x7f;
+        cirrus_update_memory_access(s);
        break;
     case 0x09:                 // bank offset #0
     case 0x0A:                 // bank offset #1
+       s->gr[reg_index] = reg_value;
+       cirrus_update_bank_ptr(s, 0);
+       cirrus_update_bank_ptr(s, 1);
+        break;
     case 0x0B:
        s->gr[reg_index] = reg_value;
        cirrus_update_bank_ptr(s, 0);
        cirrus_update_bank_ptr(s, 1);
+        cirrus_update_memory_access(s);
        break;
     case 0x10:                 // BGCOLOR 0x0000ff00
     case 0x11:                 // FGCOLOR 0x0000ff00
@@ -1772,11 +1780,12 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
     dst = s->vram_ptr + offset;
     for (x = 0; x < 8; x++) {
        if (val & 0x80) {
-           *dst++ = s->cirrus_shadow_gr1;
+           *dst = s->cirrus_shadow_gr1;
        } else if (mode == 5) {
-           *dst++ = s->cirrus_shadow_gr0;
+           *dst = s->cirrus_shadow_gr0;
        }
        val <<= 1;
+       dst++;
     }
     cpu_physical_memory_set_dirty(s->vram_offset + offset);
     cpu_physical_memory_set_dirty(s->vram_offset + offset + 7);
@@ -1794,13 +1803,14 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
     dst = s->vram_ptr + offset;
     for (x = 0; x < 8; x++) {
        if (val & 0x80) {
-           *dst++ = s->cirrus_shadow_gr1;
-           *dst++ = s->gr[0x11];
+           *dst = s->cirrus_shadow_gr1;
+           *(dst + 1) = s->gr[0x11];
        } else if (mode == 5) {
-           *dst++ = s->cirrus_shadow_gr0;
-           *dst++ = s->gr[0x10];
+           *dst = s->cirrus_shadow_gr0;
+           *(dst + 1) = s->gr[0x10];
        }
        val <<= 1;
+       dst += 2;
     }
     cpu_physical_memory_set_dirty(s->vram_offset + offset);
     cpu_physical_memory_set_dirty(s->vram_offset + offset + 15);
@@ -2304,6 +2314,36 @@ static CPUWriteMemoryFunc *cirrus_linear_write[3] = {
     cirrus_linear_writel,
 };
 
+static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                     uint32_t val)
+{
+    CirrusVGAState *s = (CirrusVGAState *) opaque;
+
+    addr &= s->cirrus_addr_mask;
+    *(s->vram_ptr + addr) = val;
+    cpu_physical_memory_set_dirty(s->vram_offset + addr);
+}
+
+static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr,
+                                     uint32_t val)
+{
+    CirrusVGAState *s = (CirrusVGAState *) opaque;
+
+    addr &= s->cirrus_addr_mask;
+    cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val);
+    cpu_physical_memory_set_dirty(s->vram_offset + addr);
+}
+
+static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr,
+                                     uint32_t val)
+{
+    CirrusVGAState *s = (CirrusVGAState *) opaque;
+
+    addr &= s->cirrus_addr_mask;
+    cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val);
+    cpu_physical_memory_set_dirty(s->vram_offset + addr);
+}
+
 /***************************************
  *
  *  system to screen memory access
@@ -2405,6 +2445,37 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
     cirrus_linear_bitblt_writel,
 };
 
+/* Compute the memory access functions */
+static void cirrus_update_memory_access(CirrusVGAState *s)
+{
+    unsigned mode;
+
+    if ((s->sr[0x17] & 0x44) == 0x44) {
+        goto generic_io;
+    } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+        goto generic_io;
+    } else {
+       if ((s->gr[0x0B] & 0x14) == 0x14) {
+            goto generic_io;
+       } else if (s->gr[0x0B] & 0x02) {
+            goto generic_io;
+        }
+        
+       mode = s->gr[0x05] & 0x7;
+       if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
+            s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
+            s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
+            s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
+        } else {
+        generic_io:
+            s->cirrus_linear_write[0] = cirrus_linear_writeb;
+            s->cirrus_linear_write[1] = cirrus_linear_writew;
+            s->cirrus_linear_write[2] = cirrus_linear_writel;
+        }
+    }
+}
+
+
 /* I/O ports */
 
 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
@@ -2621,7 +2692,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
 #endif
        /* handle CR0-7 protection */
-       if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
+       if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
            /* can always write bit 4 of CR7 */
            if (s->cr_index == 7)
                s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
@@ -2933,6 +3004,8 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
     s->cirrus_linear_io_addr =
        cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write,
                               s);
+    s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr);
+
     /* I/O handler for LFB */
     s->cirrus_linear_bitblt_io_addr =
        cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write,