Signed-off-by: Michael Slade <msl...@epic-code.com.au> --- hw/display/vga.c | 50 +++++++++++++++++++++++++++++++++----------- hw/display/vga_int.h | 2 ++ 2 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c index 72181330b8..03d9181d58 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -36,8 +36,10 @@ //#define DEBUG_VGA_MEM //#define DEBUG_VGA_REG -/* 16 state changes per vertical frame @60 Hz */ +/* state change per 16 frames @60 Hz */ #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60) +/* state change per 32 frames @60 Hz */ +#define VGA_TEXT_BLINK_PERIOD_MS (1000 * 2 * 32 / 60) /* * Video Graphics Array (VGA) @@ -1165,6 +1167,7 @@ static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight *pcheight = cheight; } + /* * Text mode update * Missing: @@ -1185,6 +1188,8 @@ static void vga_draw_text(VGACommonState *s, int full_update) uint32_t *palette; uint32_t *ch_attr_ptr; int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); + bool cursor_blink = 0; + bool attr_blink = 0; /* compute font data address (in plane 2) */ v = sr(s, VGA_SEQ_CHARACTER_MAP); @@ -1266,6 +1271,13 @@ static void vga_draw_text(VGACommonState *s, int full_update) if (now >= s->cursor_blink_time) { s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2; s->cursor_visible_phase = !s->cursor_visible_phase; + cursor_blink = 1; + } + bool blink_active = s->ar[VGA_ATC_MODE] & 0x08; + if (now >= s->attr_blink_time) { + s->attr_blink_time = now + VGA_TEXT_BLINK_PERIOD_MS / 2; + s->attr_blink_visible_phase = !s->attr_blink_visible_phase; + attr_blink = blink_active; } dest = surface_data(surface); @@ -1283,23 +1295,36 @@ static void vga_draw_text(VGACommonState *s, int full_update) break; } ch_attr = *(uint16_t *)src; - if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) { +#ifdef HOST_WORDS_BIGENDIAN + ch = ch_attr >> 8; + cattr = ch_attr & 0xff; +#else + ch = ch_attr & 0xff; + cattr = ch_attr >> 8; +#endif + + if ( + full_update || + ch_attr != *ch_attr_ptr || + (src == cursor_ptr && cursor_blink) || + (attr_blink && (cattr & 0x80)) + ) { if (cx < cx_min) cx_min = cx; if (cx > cx_max) cx_max = cx; *ch_attr_ptr = ch_attr; -#ifdef HOST_WORDS_BIGENDIAN - ch = ch_attr >> 8; - cattr = ch_attr & 0xff; -#else - ch = ch_attr & 0xff; - cattr = ch_attr >> 8; -#endif font_ptr = font_base[(cattr >> 3) & 1]; font_ptr += 32 * 4 * ch; - bgcol = palette[cattr >> 4]; - fgcol = palette[cattr & 0x0f]; + if (blink_active) { + bgcol = palette[(cattr >> 4) & 7]; + fgcol = (!(cattr & 0x80) || s->attr_blink_visible_phase) ? + palette[cattr & 0x0f] : + bgcol; + } else { + bgcol = palette[cattr >> 4]; + fgcol = palette[cattr & 0x0f]; + } if (cw == 16) { vga_draw_glyph16(d1, linesize, font_ptr, cheight, fgcol, bgcol); @@ -1756,7 +1781,8 @@ static void vga_update_display(void *opaque) } if (graphic_mode != s->graphic_mode) { s->graphic_mode = graphic_mode; - s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); + s->cursor_blink_time = s->attr_blink_time = + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); full_update = 1; } switch(graphic_mode) { diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index fe23b81442..775b3e7aa9 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -157,7 +157,9 @@ typedef struct VGACommonState { bool force_shadow; uint8_t cursor_start, cursor_end; bool cursor_visible_phase; + bool attr_blink_visible_phase; int64_t cursor_blink_time; + int64_t attr_blink_time; uint32_t cursor_offset; const GraphicHwOps *hw_ops; bool full_update_text; -- 2.17.1