faster Cirrus VGA VRAM access


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1114 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/cpu-all.h b/cpu-all.h
index 2879c11..e1bdc91 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -692,6 +692,8 @@
                            CPUReadMemoryFunc **mem_read,
                            CPUWriteMemoryFunc **mem_write,
                            void *opaque);
+CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
+CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
 
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write);
diff --git a/exec.c b/exec.c
index 95883be..5f2a87c 100644
--- a/exec.c
+++ b/exec.c
@@ -1977,6 +1977,16 @@
     return io_index << IO_MEM_SHIFT;
 }
 
+CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
+{
+    return io_mem_write[io_index >> IO_MEM_SHIFT];
+}
+
+CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
+{
+    return io_mem_read[io_index >> IO_MEM_SHIFT];
+}
+
 /* physical memory access (slow version, mainly for debug) */
 #if defined(CONFIG_USER_ONLY)
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index bd2355b..9d80515 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -259,9 +259,6 @@
     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 @@
     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 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 @@
     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)
@@ -746,6 +743,7 @@
     }
     s->cirrus_srcptr = s->cirrus_bltbuf;
     s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
+    cirrus_update_memory_access(s);
     return 1;
 }
 
@@ -1199,7 +1197,6 @@
     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 +1211,10 @@
 	       reg_index, reg_value);
 #endif
 	break;
+    case 0x17:			// Configuration Readback and Extended Control
+	s->sr[reg_index] = reg_value;
+        cirrus_update_memory_access(s);
+        break;
     default:
 #ifdef DEBUG_CIRRUS
 	printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index,
@@ -1348,13 +1349,19 @@
 	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
@@ -2304,6 +2311,36 @@
     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 +2442,37 @@
     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)
@@ -2933,6 +3001,8 @@
     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,