--- trunk/src/devices/dev_vga.c 2007/10/08 16:19:05 17 +++ trunk/src/devices/dev_vga.c 2007/10/08 16:19:11 18 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: dev_vga.c,v 1.81 2005/10/07 22:10:52 debug Exp $ + * $Id: dev_vga.c,v 1.86 2005/10/27 14:01:14 debug Exp $ * * VGA charcell and graphics device. * @@ -52,8 +52,8 @@ #include "fonts/font8x16.c" -/* For bintranslated videomem -> framebuffer updates: */ -#define VGA_TICK_SHIFT 16 +/* For videomem -> framebuffer updates: */ +#define VGA_TICK_SHIFT 19 #define MAX_RETRACE_SCANLINES 420 #define N_IS1_READ_THRESHOLD 50 @@ -92,7 +92,8 @@ unsigned char *font; size_t charcells_size; unsigned char *charcells; /* 2 bytes per char */ - unsigned char *charcells_outputed; + unsigned char *charcells_outputed; /* text */ + unsigned char *charcells_drawn; /* framebuffer */ /* Graphics: */ int graphics_mode; @@ -144,23 +145,41 @@ /* + * recalc_cursor_position(): + * + * Should be called whenever the cursor location _or_ the display + * base has been changed. + */ +static void recalc_cursor_position(struct vga_data *d) +{ + int base = (d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) + + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]; + int ofs = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] * 256 + + d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW]; + ofs -= base; + d->cursor_x = ofs % d->max_x; + d->cursor_y = ofs / d->max_x; +} + + +/* * register_reset(): * * Resets many registers to sane values. */ static void register_reset(struct vga_data *d) { - /* Home cursor: */ - d->cursor_x = d->cursor_y = 0; + /* Home cursor and start at the top: */ d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW] = 0; - d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] = d->crtc_reg[VGA_CRTC_START_ADDR_LOW] = 0; + recalc_cursor_position(d); + /* Reset cursor scanline stuff: */ - d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] = d->font_height - 4; - d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END] = d->font_height - 2; + d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] = d->font_height - 2; + d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END] = d->font_height - 1; d->sequencer_reg[VGA_SEQ_MAP_MASK] = 0x0f; d->graphcontr_reg[VGA_GRAPHCONTR_MASK] = 0xff; @@ -385,6 +404,14 @@ for (i=start; i<=end; i+=2) { unsigned char ch = d->charcells[i + base]; + + if (d->charcells_drawn[i] == ch && + d->charcells_drawn[i+1] == d->charcells[i+base+1]) + continue; + + d->charcells_drawn[i] = ch; + d->charcells_drawn[i+1] = d->charcells[i + base + 1]; + fg = d->charcells[i+base + 1] & 15; bg = (d->charcells[i+base + 1] >> 4) & 7; @@ -481,7 +508,7 @@ int base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; int new_u_y1, new_u_y2; - debug("[ dev_vga_tick: bintrans access, %llx .. %llx ]\n", + debug("[ dev_vga_tick: dyntrans access, %llx .. %llx ]\n", (long long)low, (long long)high); low -= base; high -= base; @@ -493,8 +520,8 @@ d->update_y1 = new_u_y1; if (new_u_y2 > d->update_y2) d->update_y2 = new_u_y2; - if (d->update_y2 < 0) - d->update_y2 = 0; + if (d->update_y1 < 0) + d->update_y1 = 0; if (d->update_y2 >= d->max_y) d->update_y2 = d->max_y - 1; d->modified = 1; @@ -655,7 +682,8 @@ uint64_t idata = 0, odata = 0; int i, x, y, x2, y2, r, base; - idata = memory_readmax64(cpu, data, len); + if (writeflag == MEM_WRITE) + idata = memory_readmax64(cpu, data, len); base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; @@ -665,7 +693,7 @@ y2 = (r+len-1) / (d->max_x * 2); x2 = ((r+len-1)/2) % d->max_x; - if (relative_addr < d->charcells_size) { + if (relative_addr + len - 1 < d->charcells_size) { if (writeflag == MEM_WRITE) { for (i=0; icharcells[relative_addr + i]; @@ -722,7 +750,7 @@ static void vga_crtc_reg_write(struct machine *machine, struct vga_data *d, int regnr, int idata) { - int ofs, grayscale; + int grayscale; switch (regnr) { case VGA_CRTC_CURSOR_SCANLINE_START: /* 0x0a */ @@ -735,13 +763,11 @@ d->update_y1 = 0; d->update_y2 = d->max_y - 1; d->modified = 1; + recalc_cursor_position(d); break; case VGA_CRTC_CURSOR_LOCATION_HIGH: /* 0x0e */ case VGA_CRTC_CURSOR_LOCATION_LOW: /* 0x0f */ - ofs = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] * 256 + - d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW]; - d->cursor_x = ofs % d->max_x; - d->cursor_y = ofs / d->max_x; + recalc_cursor_position(d); break; case 0xff: grayscale = 0; @@ -840,6 +866,7 @@ /* Clear screen and reset the palette: */ memset(d->charcells_outputed, 0, d->charcells_size); + memset(d->charcells_drawn, 0, d->charcells_size); memset(d->gfx_mem, 0, d->gfx_mem_size); d->update_x1 = 0; d->update_x2 = d->max_x - 1; @@ -897,6 +924,10 @@ static void vga_attribute_reg_write(struct machine *machine, struct vga_data *d, int regnr, int idata) { + /* 0-15 are palette registers: TODO */ + if (regnr >= 0 && regnr <= 0xf) + return; + switch (regnr) { default:fatal("[ vga_attribute_reg_write: select %i ]\n", regnr); /* cpu->running = 0; */ @@ -988,7 +1019,7 @@ d->palette_read_index = idata; d->palette_read_subindex = 0; } else { - fatal("[ dev_vga: WARNING: Read from " + debug("[ dev_vga: WARNING: Read from " "VGA_DAC_ADDR_READ? TODO ]\n"); /* TODO */ } @@ -1113,10 +1144,10 @@ default: if (writeflag==MEM_READ) { - fatal("[ vga_ctrl: read from 0x%08lx ]\n", + debug("[ vga_ctrl: read from 0x%08lx ]\n", (long)relative_addr); } else { - fatal("[ vga_ctrl: write to 0x%08lx: 0x%08x" + debug("[ vga_ctrl: write to 0x%08lx: 0x%08x" " ]\n", (long)relative_addr, (int)idata); } } @@ -1142,7 +1173,7 @@ uint64_t videomem_base, uint64_t control_base, char *name) { struct vga_data *d; - int i, tmpi; + int i; size_t allocsize; d = malloc(sizeof(struct vga_data)); @@ -1169,16 +1200,21 @@ allocsize = ((d->charcells_size-1) | (machine->arch_pagesize-1)) + 1; d->charcells = malloc(d->charcells_size); d->charcells_outputed = malloc(d->charcells_size); + d->charcells_drawn = malloc(d->charcells_size); d->gfx_mem = malloc(d->gfx_mem_size); if (d->charcells == NULL || d->charcells_outputed == NULL || - d->gfx_mem == NULL) { + d->charcells_drawn == NULL || d->gfx_mem == NULL) { fprintf(stderr, "out of memory in dev_vga_init()\n"); exit(1); } + memset(d->charcells_drawn, 0, d->charcells_size); + for (i=0; icharcells_size; i+=2) { d->charcells[i] = ' '; d->charcells[i+1] = 0x07; /* Default color */ + d->charcells_drawn[i] = ' '; + d->charcells_drawn[i+1] = 0x07; } memset(d->charcells_outputed, 0, d->charcells_size); @@ -1195,23 +1231,22 @@ d->fb_max_y *= d->font_height; } - d->fb = dev_fb_init(machine, mem, VGA_FB_ADDR, VFB_GENERIC, - d->fb_max_x, d->fb_max_y, d->fb_max_x, d->fb_max_y, 24, "VGA"); - d->fb_size = d->fb_max_x * d->fb_max_y * 3; - - reset_palette(d, 0); - - /* MEM_DYNTRANS_WRITE_OK <-- This works with OpenBSD/arc, but not - with Windows NT yet. Why? */ memory_device_register(mem, "vga_charcells", videomem_base + 0x18000, allocsize, dev_vga_access, d, MEM_DYNTRANS_OK | - MEM_READING_HAS_NO_SIDE_EFFECTS, d->charcells); + MEM_DYNTRANS_WRITE_OK | MEM_READING_HAS_NO_SIDE_EFFECTS, + d->charcells); memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW, dev_vga_graphics_access, d, MEM_DEFAULT | MEM_READING_HAS_NO_SIDE_EFFECTS, d->gfx_mem); memory_device_register(mem, "vga_ctrl", control_base, 32, dev_vga_ctrl_access, d, MEM_DEFAULT, NULL); + d->fb = dev_fb_init(machine, mem, VGA_FB_ADDR, VFB_GENERIC, + d->fb_max_x, d->fb_max_y, d->fb_max_x, d->fb_max_y, 24, "VGA"); + d->fb_size = d->fb_max_x * d->fb_max_y * 3; + + reset_palette(d, 0); + /* This will force an initial redraw/resynch: */ d->update_x1 = 0; d->update_x2 = d->max_x - 1; @@ -1221,10 +1256,8 @@ machine_add_tickfunction(machine, dev_vga_tick, d, VGA_TICK_SHIFT); - vga_update_cursor(machine, d); - - tmpi = d->cursor_y * d->max_x + d->cursor_x; - register_reset(d); + + vga_update_cursor(machine, d); }