]> Git Repo - qemu.git/blobdiff - hw/vga.c
Register reset handlers
[qemu.git] / hw / vga.c
index eb0bae8b93ed6cb1a2ff1260bd1d53bfcf8aa159..058a77cc72a884b9beef76f622fc2e75ab148eb0 100644 (file)
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -27,6 +27,8 @@
 #include "pci.h"
 #include "vga_int.h"
 #include "pixel_ops.h"
+#include "qemu-timer.h"
+#include "kvm.h"
 
 //#define DEBUG_VGA
 //#define DEBUG_VGA_MEM
@@ -149,6 +151,136 @@ static uint8_t expand4to8[16];
 
 static void vga_screen_dump(void *opaque, const char *filename);
 
+static void vga_dumb_update_retrace_info(VGAState *s)
+{
+    (void) s;
+}
+
+static void vga_precise_update_retrace_info(VGAState *s)
+{
+    int htotal_chars;
+    int hretr_start_char;
+    int hretr_skew_chars;
+    int hretr_end_char;
+
+    int vtotal_lines;
+    int vretr_start_line;
+    int vretr_end_line;
+
+    int div2, sldiv2, dots;
+    int clocking_mode;
+    int clock_sel;
+    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
+    int64_t chars_per_sec;
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+
+    htotal_chars = s->cr[0x00] + 5;
+    hretr_start_char = s->cr[0x04];
+    hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
+    hretr_end_char = s->cr[0x05] & 0x1f;
+
+    vtotal_lines = (s->cr[0x06]
+                    | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
+        ;
+    vretr_start_line = s->cr[0x10]
+        | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
+        ;
+    vretr_end_line = s->cr[0x11] & 0xf;
+
+
+    div2 = (s->cr[0x17] >> 2) & 1;
+    sldiv2 = (s->cr[0x17] >> 3) & 1;
+
+    clocking_mode = (s->sr[0x01] >> 3) & 1;
+    clock_sel = (s->msr >> 2) & 3;
+    dots = (s->msr & 1) ? 8 : 9;
+
+    chars_per_sec = clk_hz[clock_sel] / dots;
+
+    htotal_chars <<= clocking_mode;
+
+    r->total_chars = vtotal_lines * htotal_chars;
+    if (r->freq) {
+        r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
+    } else {
+        r->ticks_per_char = ticks_per_sec / chars_per_sec;
+    }
+
+    r->vstart = vretr_start_line;
+    r->vend = r->vstart + vretr_end_line + 1;
+
+    r->hstart = hretr_start_char + hretr_skew_chars;
+    r->hend = r->hstart + hretr_end_char + 1;
+    r->htotal = htotal_chars;
+
+#if 0
+    printf (
+        "hz=%f\n"
+        "htotal = %d\n"
+        "hretr_start = %d\n"
+        "hretr_skew = %d\n"
+        "hretr_end = %d\n"
+        "vtotal = %d\n"
+        "vretr_start = %d\n"
+        "vretr_end = %d\n"
+        "div2 = %d sldiv2 = %d\n"
+        "clocking_mode = %d\n"
+        "clock_sel = %d %d\n"
+        "dots = %d\n"
+        "ticks/char = %lld\n"
+        "\n",
+        (double) ticks_per_sec / (r->ticks_per_char * r->total_chars),
+        htotal_chars,
+        hretr_start_char,
+        hretr_skew_chars,
+        hretr_end_char,
+        vtotal_lines,
+        vretr_start_line,
+        vretr_end_line,
+        div2, sldiv2,
+        clocking_mode,
+        clock_sel,
+        clk_hz[clock_sel],
+        dots,
+        r->ticks_per_char
+        );
+#endif
+}
+
+static uint8_t vga_precise_retrace(VGAState *s)
+{
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
+
+    if (r->total_chars) {
+        int cur_line, cur_line_char, cur_char;
+        int64_t cur_tick;
+
+        cur_tick = qemu_get_clock(vm_clock);
+
+        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
+        cur_line = cur_char / r->htotal;
+
+        if (cur_line >= r->vstart && cur_line <= r->vend) {
+            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
+        } else {
+            cur_line_char = cur_char % r->htotal;
+            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
+                val |= ST01_DISP_ENABLE;
+            }
+        }
+
+        return val;
+    } else {
+        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+    }
+}
+
+static uint8_t vga_dumb_retrace(VGAState *s)
+{
+    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+}
+
 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
 {
     VGAState *s = opaque;
@@ -228,8 +360,7 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
         case 0x3ba:
         case 0x3da:
             /* just toggle to fool polling */
-            s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
-            val = s->st01;
+            val = s->st01 = s->retrace(s);
             s->ar_flip_flop = 0;
             break;
         default:
@@ -291,6 +422,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         break;
     case 0x3c2:
         s->msr = val & ~0x10;
+        s->update_retrace_info(s);
         break;
     case 0x3c4:
         s->sr_index = val & 7;
@@ -300,6 +432,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
 #endif
         s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+        if (s->sr_index == 1) s->update_retrace_info(s);
         break;
     case 0x3c7:
         s->dac_read_index = val;
@@ -357,6 +490,18 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             s->cr[s->cr_index] = val;
             break;
         }
+
+        switch(s->cr_index) {
+        case 0x00:
+        case 0x04:
+        case 0x05:
+        case 0x06:
+        case 0x07:
+        case 0x11:
+        case 0x17:
+            s->update_retrace_info(s);
+            break;
+        }
         break;
     case 0x3ba:
     case 0x3da:
@@ -1007,7 +1152,7 @@ static int update_basic_params(VGAState *s)
 
 static inline int get_depth_index(DisplayState *s)
 {
-    switch(s->depth) {
+    switch(ds_get_bits_per_pixel(s)) {
     default:
     case 8:
         return 0;
@@ -1099,6 +1244,8 @@ static void vga_draw_text(VGAState *s, int full_update)
     vga_draw_glyph8_func *vga_draw_glyph8;
     vga_draw_glyph9_func *vga_draw_glyph9;
 
+    vga_dirty_log_stop(s);
+
     full_update |= update_palette16(s);
     palette = s->last_palette;
 
@@ -1135,7 +1282,7 @@ static void vga_draw_text(VGAState *s, int full_update)
         cw = 9;
     if (s->sr[1] & 0x08)
         cw = 16; /* NOTE: no 18 pixel wide */
-    x_incr = cw * ((s->ds->depth + 7) >> 3);
+    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
     width = (s->cr[0x01] + 1);
     if (s->cr[0x06] == 100) {
         /* ugly hack for CGA 160x100x16 - explain me the logic */
@@ -1185,8 +1332,8 @@ static void vga_draw_text(VGAState *s, int full_update)
         vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
     vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
 
-    dest = s->ds->data;
-    linesize = s->ds->linesize;
+    dest = ds_get_data(s->ds);
+    linesize = ds_get_linesize(s->ds);
     ch_attr_ptr = s->last_ch_attr;
     for(cy = 0; cy < height; cy++) {
         d1 = dest;
@@ -1412,6 +1559,18 @@ void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
     }
 }
 
+static void vga_sync_dirty_bitmap(VGAState *s)
+{
+    if (s->map_addr)
+        cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
+
+    if (s->lfb_vram_mapped) {
+        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
+        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
+    }
+    vga_dirty_log_start(s);
+}
+
 /*
  * graphic modes
  */
@@ -1426,6 +1585,9 @@ static void vga_draw_graphic(VGAState *s, int full_update)
 
     full_update |= update_basic_params(s);
 
+    if (!full_update)
+        vga_sync_dirty_bitmap(s);
+
     s->get_resolution(s, &width, &height);
     disp_width = width;
 
@@ -1519,8 +1681,8 @@ static void vga_draw_graphic(VGAState *s, int full_update)
     y_start = -1;
     page_min = 0x7fffffff;
     page_max = -1;
-    d = s->ds->data;
-    linesize = s->ds->linesize;
+    d = ds_get_data(s->ds);
+    linesize = ds_get_linesize(s->ds);
     y1 = 0;
     for(y = 0; y < height; y++) {
         addr = addr1;
@@ -1599,15 +1761,17 @@ static void vga_draw_blank(VGAState *s, int full_update)
         return;
     if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
         return;
-    if (s->ds->depth == 8)
+    vga_dirty_log_stop(s);
+
+    if (ds_get_bits_per_pixel(s->ds) == 8)
         val = s->rgb_to_pixel(0, 0, 0);
     else
         val = 0;
-    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
-    d = s->ds->data;
+    w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
+    d = ds_get_data(s->ds);
     for(i = 0; i < s->last_scr_height; i++) {
         memset(d, val, w);
-        d += s->ds->linesize;
+        d += ds_get_linesize(s->ds);
     }
     dpy_update(s->ds, 0, 0,
                s->last_scr_width, s->last_scr_height);
@@ -1622,7 +1786,7 @@ static void vga_update_display(void *opaque)
     VGAState *s = (VGAState *)opaque;
     int full_update, graphic_mode;
 
-    if (s->ds->depth == 0) {
+    if (ds_get_bits_per_pixel(s->ds) == 0) {
         /* nothing to do */
     } else {
         s->rgb_to_pixel =
@@ -1662,10 +1826,73 @@ static void vga_invalidate_display(void *opaque)
     s->last_height = -1;
 }
 
-static void vga_reset(VGAState *s)
+static void vga_reset(void *opaque)
 {
-    memset(s, 0, sizeof(VGAState));
+    VGAState *s = (VGAState *) opaque;
+
+    s->lfb_addr = 0;
+    s->lfb_end = 0;
+    s->map_addr = 0;
+    s->map_end = 0;
+    s->lfb_vram_mapped = 0;
+    s->bios_offset = 0;
+    s->bios_size = 0;
+    s->sr_index = 0;
+    memset(s->sr, '\0', sizeof(s->sr));
+    s->gr_index = 0;
+    memset(s->gr, '\0', sizeof(s->gr));
+    s->ar_index = 0;
+    memset(s->ar, '\0', sizeof(s->ar));
+    s->ar_flip_flop = 0;
+    s->cr_index = 0;
+    memset(s->cr, '\0', sizeof(s->cr));
+    s->msr = 0;
+    s->fcr = 0;
+    s->st00 = 0;
+    s->st01 = 0;
+    s->dac_state = 0;
+    s->dac_sub_index = 0;
+    s->dac_read_index = 0;
+    s->dac_write_index = 0;
+    memset(s->dac_cache, '\0', sizeof(s->dac_cache));
+    s->dac_8bit = 0;
+    memset(s->palette, '\0', sizeof(s->palette));
+    s->bank_offset = 0;
+#ifdef CONFIG_BOCHS_VBE
+    s->vbe_index = 0;
+    memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
+    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
+    s->vbe_start_addr = 0;
+    s->vbe_line_offset = 0;
+    s->vbe_bank_mask = (s->vram_size >> 16) - 1;
+#endif
+    memset(s->font_offsets, '\0', sizeof(s->font_offsets));
     s->graphic_mode = -1; /* force full update */
+    s->shift_control = 0;
+    s->double_scan = 0;
+    s->line_offset = 0;
+    s->line_compare = 0;
+    s->start_addr = 0;
+    s->plane_updated = 0;
+    s->last_cw = 0;
+    s->last_ch = 0;
+    s->last_width = 0;
+    s->last_height = 0;
+    s->last_scr_width = 0;
+    s->last_scr_height = 0;
+    s->cursor_start = 0;
+    s->cursor_end = 0;
+    s->cursor_offset = 0;
+    memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
+    memset(s->last_palette, '\0', sizeof(s->last_palette));
+    memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        break;
+    case VGA_RETRACE_PRECISE:
+        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
+        break;
+    }
 }
 
 #define TEXTMODE_X(x)  ((x) % width)
@@ -1948,6 +2175,28 @@ typedef struct PCIVGAState {
     VGAState vga_state;
 } PCIVGAState;
 
+void vga_dirty_log_start(VGAState *s)
+{
+    if (kvm_enabled() && s->map_addr)
+        kvm_log_start(s->map_addr, s->map_end - s->map_addr);
+
+    if (kvm_enabled() && s->lfb_vram_mapped) {
+        kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
+        kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
+    }
+}
+
+void vga_dirty_log_stop(VGAState *s)
+{
+    if (kvm_enabled() && s->map_addr)
+        kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
+
+    if (kvm_enabled() && s->lfb_vram_mapped) {
+        kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
+        kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
+    }
+}
+
 static void vga_map(PCIDevice *pci_dev, int region_num,
                     uint32_t addr, uint32_t size, int type)
 {
@@ -1958,10 +2207,15 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
     } else {
         cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
     }
+
+    s->map_addr = addr;
+    s->map_end = addr + VGA_RAM_SIZE;
+
+    vga_dirty_log_start(s);
 }
 
 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
-                     unsigned long vga_ram_offset, int vga_ram_size)
+                     ram_addr_t vga_ram_offset, int vga_ram_size)
 {
     int i, j, v, b;
 
@@ -1988,8 +2242,6 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
         expand4to8[i] = v;
     }
 
-    vga_reset(s);
-
     s->vram_ptr = vga_ram_base;
     s->vram_offset = vga_ram_offset;
     s->vram_size = vga_ram_size;
@@ -2001,6 +2253,19 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
     s->invalidate = vga_invalidate_display;
     s->screen_dump = vga_screen_dump;
     s->text_update = vga_update_text;
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        s->retrace = vga_dumb_retrace;
+        s->update_retrace_info = vga_dumb_update_retrace_info;
+        break;
+
+    case VGA_RETRACE_PRECISE:
+        s->retrace = vga_precise_retrace;
+        s->update_retrace_info = vga_precise_update_retrace_info;
+        break;
+    }
+    qemu_register_reset(vga_reset, s);
+    vga_reset(s);
 }
 
 /* used by both ISA and PCI */
@@ -2026,8 +2291,6 @@ void vga_init(VGAState *s)
     s->bank_offset = 0;
 
 #ifdef CONFIG_BOCHS_VBE
-    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
-    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
 #if defined (TARGET_I386)
     register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
     register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
@@ -2053,6 +2316,7 @@ void vga_init(VGAState *s)
     vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
     cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
                                  vga_io_memory);
+    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
 }
 
 /* Memory mapped interface */
@@ -2060,7 +2324,7 @@ static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
 {
     VGAState *s = opaque;
 
-    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xff;
+    return vga_ioport_read(s, addr >> s->it_shift) & 0xff;
 }
 
 static void vga_mm_writeb (void *opaque,
@@ -2068,14 +2332,14 @@ static void vga_mm_writeb (void *opaque,
 {
     VGAState *s = opaque;
 
-    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xff);
+    vga_ioport_write(s, addr >> s->it_shift, value & 0xff);
 }
 
 static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
 {
     VGAState *s = opaque;
 
-    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xffff;
+    return vga_ioport_read(s, addr >> s->it_shift) & 0xffff;
 }
 
 static void vga_mm_writew (void *opaque,
@@ -2083,14 +2347,14 @@ static void vga_mm_writew (void *opaque,
 {
     VGAState *s = opaque;
 
-    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xffff);
+    vga_ioport_write(s, addr >> s->it_shift, value & 0xffff);
 }
 
 static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
 {
     VGAState *s = opaque;
 
-    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift);
+    return vga_ioport_read(s, addr >> s->it_shift);
 }
 
 static void vga_mm_writel (void *opaque,
@@ -2098,7 +2362,7 @@ static void vga_mm_writel (void *opaque,
 {
     VGAState *s = opaque;
 
-    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value);
+    vga_ioport_write(s, addr >> s->it_shift, value);
 }
 
 static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
@@ -2118,7 +2382,6 @@ static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
 {
     int s_ioport_ctrl, vga_io_memory;
 
-    s->base_ctrl = ctrl_base;
     s->it_shift = it_shift;
     s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
     vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
@@ -2128,6 +2391,7 @@ static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
     cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
     s->bank_offset = 0;
     cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
+    qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
 }
 
 int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
@@ -2240,7 +2504,7 @@ static void vga_save_dpy_update(DisplayState *s,
 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
 {
     s->linesize = w * 4;
-    s->data = qemu_malloc(h * s->linesize);
+    s->data = qemu_mallocz(h * s->linesize);
     vga_save_w = w;
     vga_save_h = h;
 }
@@ -2299,10 +2563,10 @@ static void vga_screen_dump(void *opaque, const char *filename)
     s->graphic_mode = -1;
     vga_update_display(s);
 
-    if (ds->data) {
-        ppm_save(filename, ds->data, vga_save_w, vga_save_h,
-                 s->ds->linesize);
-        qemu_free(ds->data);
+    if (ds_get_data(ds)) {
+        ppm_save(filename, ds_get_data(ds), vga_save_w, vga_save_h,
+                 ds_get_linesize(s->ds));
+        qemu_free(ds_get_data(ds));
     }
     s->ds = saved_ds;
 }
This page took 0.049761 seconds and 4 git commands to generate.