diff --git a/hw/pc.h b/hw/pc.h index e4db0715b8..37e2f87583 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -176,6 +176,10 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; +#define VGA_CGA_HACK_PALETTE_BLANKING (1<<0) +#define VGA_CGA_HACK_FONT_HEIGHT (1<<1) +extern int vga_cga_hacks; + static inline DeviceState *isa_vga_init(ISABus *bus) { ISADevice *dev; diff --git a/hw/vga.c b/hw/vga.c index f82ced8e66..a65fc26ab7 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -547,14 +547,31 @@ 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[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) && - s->cr_index <= VGA_CRTC_OVERFLOW) { - /* can always write bit 4 of CR7 */ - if (s->cr_index == VGA_CRTC_OVERFLOW) { - s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) | - (val & 0x10); + if (s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) { + if (s->cr_index <= VGA_CRTC_OVERFLOW) { + /* can always write bit 4 of CR7 */ + if (s->cr_index == VGA_CRTC_OVERFLOW) { + s->cr[VGA_CRTC_OVERFLOW] = + (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) | (val & 0x10); + } + return; + } else if ((vga_cga_hacks & VGA_CGA_HACK_FONT_HEIGHT) && + !(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) { + /* extra CGA compatibility hacks (not in standard VGA) */ + if (s->cr_index == VGA_CRTC_MAX_SCAN && + val == 7 && + (s->cr[VGA_CRTC_MAX_SCAN] & 0xf) == 0xf) { + return; + } else if (s->cr_index == VGA_CRTC_CURSOR_START && + val == 6 && + (s->cr[VGA_CRTC_MAX_SCAN] & 0xf) == 0xf) { + val = 0xd; + } else if (s->cr_index == VGA_CRTC_CURSOR_END && + val == 7 && + (s->cr[VGA_CRTC_MAX_SCAN] & 0xf) == 0xf) { + val = 0xe; + } } - return; } s->cr[s->cr_index] = val; @@ -1886,7 +1903,10 @@ static void vga_update_display(void *opaque) /* nothing to do */ } else { full_update = 0; - if (!(s->ar_index & 0x20)) { + if (!(s->ar_index & 0x20) && + /* extra CGA compatibility hacks (not in standard VGA */ + (!(vga_cga_hacks & VGA_CGA_HACK_PALETTE_BLANKING) || + (s->ar_index != 0 && s->ar_flip_flop))) { graphic_mode = GMODE_BLANK; } else { graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE; diff --git a/qemu-options.hx b/qemu-options.hx index 3e8085d463..0682338e9f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -975,6 +975,25 @@ Valid optional properties are @item retrace=dumb|precise Select dumb (default) or precise VGA retrace logic, useful for some DOS games/demos. +@item cga_hacks=@var{hack1}[+@var{hack2},[...]] +Enable various extra CGA compatibility hacks for programs that are +trying to directly set CGA modes without BIOS assistance nor +real knowledge of EGA/VGA. These might only work with -vga std. +Valid hacks are +@table @option +@item palette_blanking +Wait to blank the screen until palette registers seem to actually be +modified, instead of blanking it as soon as the palette address bit (0x10) +of the attribute address register (0x3c0) is cleared. +@item font_height +Ignore attempts to change the VGA font height (index 9), +cursor start (index 10), and cursor end (index 11) of the CRTC control +registers (0x3d5) if trying to set them to the default for CGA fonts +instead of VGA fonts. +@item all +Enable all CGA hacks. More CGA hacks may be added in future versions +of qemu. +@end table @end table ETEXI diff --git a/vl.c b/vl.c index febfd62c37..16d04a2ee2 100644 --- a/vl.c +++ b/vl.c @@ -179,6 +179,7 @@ int main(int argc, char **argv) static const char *data_dir; const char *bios_name = NULL; enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; +int vga_cga_hacks = 0; DisplayType display_type = DT_DEFAULT; int display_remote = 0; const char* keyboard_layout = NULL; @@ -1748,6 +1749,28 @@ static void select_vgahw (const char *p) else if (strstart(opts, "precise", &nextopt)) vga_retrace_method = VGA_RETRACE_PRECISE; else goto invalid_vga; + } else if (strstart(opts, ",cga_hacks=", &nextopt)) { + opts = nextopt; + while (*opts) { + if (strstart(opts, "all", &nextopt)) { + opts = nextopt; + vga_cga_hacks |= ~0; + } else if (strstart(opts, "palette_blanking", &nextopt)) { + opts = nextopt; + vga_cga_hacks |= VGA_CGA_HACK_PALETTE_BLANKING; + } else if (strstart(opts, "font_height", &nextopt)) { + opts = nextopt; + vga_cga_hacks |= VGA_CGA_HACK_FONT_HEIGHT; + } else { + break; + } + + if (*opts == '+') { + opts++; + } else { + break; + } + } } else goto invalid_vga; opts = nextopt; }