--- trunk/src/devices/dev_vga.c 2007/10/08 16:18:11 6 +++ trunk/src/devices/dev_vga.c 2007/10/08 16:19:23 20 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: dev_vga.c,v 1.74 2005/05/29 16:04:28 debug Exp $ + * $Id: dev_vga.c,v 1.90 2005/11/13 00:14:10 debug Exp $ * * VGA charcell and graphics device. * @@ -52,14 +52,12 @@ #include "fonts/font8x16.c" -/* For bintranslated videomem -> framebuffer updates: */ -#define VGA_TICK_SHIFT 16 +/* For videomem -> framebuffer updates: */ +#define VGA_TICK_SHIFT 18 #define MAX_RETRACE_SCANLINES 420 #define N_IS1_READ_THRESHOLD 50 -#define VGA_MEM_MAXY 60 -#define VGA_MEM_ALLOCY 60 #define GFX_ADDR_WINDOW 0x18000 #define VGA_FB_ADDR 0x1c00000000ULL @@ -94,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; @@ -146,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; @@ -260,11 +277,11 @@ d->charcells_outputed[i+1] = d->charcells[base+i+1]; if (!printed_last || x == 0) { - sprintf(s, "\033[%i;%iH", y + 1, x + 1); + snprintf(s, sizeof(s), "\033[%i;%iH", y + 1, x + 1); c_putstr(d, s); } if (oldcolor < 0 || (bg<<4)+fg != oldcolor || !printed_last) { - sprintf(s, "\033[0;"); c_putstr(d, s); + snprintf(s, sizeof(s), "\033[0;"); c_putstr(d, s); switch (fg & 7) { case 0: c_putstr(d, "30"); break; @@ -301,7 +318,7 @@ } /* Restore the terminal's cursor position: */ - sprintf(s, "\033[%i;%iH", d->cursor_y + 1, d->cursor_x + 1); + snprintf(s, sizeof(s), "\033[%i;%iH", d->cursor_y + 1, d->cursor_x + 1); c_putstr(d, s); } @@ -387,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; @@ -471,20 +496,32 @@ void dev_vga_tick(struct cpu *cpu, void *extra) { struct vga_data *d = extra; - uint64_t low = (uint64_t)-1, high; + int64_t low = -1, high; vga_update_cursor(cpu->machine, d); /* TODO: text vs graphics tick? */ - memory_device_bintrans_access(cpu, cpu->mem, extra, &low, &high); + memory_device_dyntrans_access(cpu, cpu->mem, extra, + (uint64_t *) &low, (uint64_t *) &high); - if ((int64_t)low != -1) { - debug("[ dev_vga_tick: bintrans access, %llx .. %llx ]\n", + if (low != -1) { + 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: dyntrans access, %llx .. %llx ]\n", (long long)low, (long long)high); + low -= base; + high -= base; d->update_x1 = 0; d->update_x2 = d->max_x - 1; - d->update_y1 = (low/2) / d->max_x; - d->update_y2 = ((high/2) / d->max_x) + 1; + new_u_y1 = (low/2) / d->max_x; + new_u_y2 = ((high/2) / d->max_x) + 1; + if (new_u_y1 < d->update_y1) + d->update_y1 = new_u_y1; + if (new_u_y2 > d->update_y2) + d->update_y2 = new_u_y2; + 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; @@ -645,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; @@ -655,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]; @@ -712,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 */ @@ -725,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; @@ -741,7 +777,8 @@ case 0x01: d->cur_mode = MODE_CHARCELL; d->max_x = 40; d->max_y = 25; - d->pixel_repx = 2; d->pixel_repy = 1; + d->pixel_repx = machine->x11_scaleup * 2; + d->pixel_repy = machine->x11_scaleup; d->font_width = 8; d->font_height = 16; d->font = font8x16; @@ -751,7 +788,7 @@ case 0x03: d->cur_mode = MODE_CHARCELL; d->max_x = 80; d->max_y = 25; - d->pixel_repx = d->pixel_repy = 1; + d->pixel_repx = d->pixel_repy = machine->x11_scaleup; d->font_width = 8; d->font_height = 16; d->font = font8x16; @@ -761,8 +798,8 @@ d->max_x = 160; d->max_y = 200; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; - d->pixel_repx = 4; - d->pixel_repy = 2; + d->pixel_repx = 4 * machine->x11_scaleup; + d->pixel_repy = 2 * machine->x11_scaleup; break; case 0x09: case 0x0d: @@ -770,36 +807,38 @@ d->max_x = 320; d->max_y = 200; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; - d->pixel_repx = d->pixel_repy = 2; + d->pixel_repx = d->pixel_repy = + 2 * machine->x11_scaleup; break; case 0x0e: d->cur_mode = MODE_GRAPHICS; d->max_x = 640; d->max_y = 200; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; - d->pixel_repx = 1; - d->pixel_repy = 2; + d->pixel_repx = machine->x11_scaleup; + d->pixel_repy = machine->x11_scaleup * 2; break; case 0x10: d->cur_mode = MODE_GRAPHICS; d->max_x = 640; d->max_y = 350; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; - d->pixel_repx = d->pixel_repy = 1; + d->pixel_repx = d->pixel_repy = machine->x11_scaleup; break; case 0x12: d->cur_mode = MODE_GRAPHICS; d->max_x = 640; d->max_y = 480; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; - d->pixel_repx = d->pixel_repy = 1; + d->pixel_repx = d->pixel_repy = machine->x11_scaleup; break; case 0x13: d->cur_mode = MODE_GRAPHICS; d->max_x = 320; d->max_y = 200; d->graphics_mode = GRAPHICS_MODE_8BIT; d->bits_per_pixel = 8; - d->pixel_repx = d->pixel_repy = 2; + d->pixel_repx = d->pixel_repy = + 2 * machine->x11_scaleup; break; default: fatal("TODO! video mode change hack (mode 0x%02x)\n", @@ -830,6 +869,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; @@ -854,7 +894,10 @@ int regnr, int idata) { switch (regnr) { - case VGA_SEQ_MAP_MASK: /* 0x02 */ + case VGA_SEQ_RESET: + case VGA_SEQ_MAP_MASK: + case VGA_SEQ_SEQUENCER_MEMORY_MODE: + debug("[ vga_sequencer_reg_write: select %i: TODO ]\n", regnr); break; default:fatal("[ vga_sequencer_reg_write: select %i ]\n", regnr); /* cpu->running = 0; */ @@ -871,7 +914,11 @@ struct vga_data *d, int regnr, int idata) { switch (regnr) { - case VGA_GRAPHCONTR_MASK: /* 0x08 */ + case VGA_GRAPHCONTR_READMAPSELECT: + case VGA_GRAPHCONTR_GRAPHICSMODE: + case VGA_GRAPHCONTR_MISC: + case VGA_GRAPHCONTR_MASK: + debug("[ vga_graphcontr_reg_write: select %i: TODO ]\n", regnr); break; default:fatal("[ vga_graphcontr_reg_write: select %i ]\n", regnr); /* cpu->running = 0; */ @@ -887,6 +934,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; */ @@ -978,7 +1029,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 */ } @@ -1103,10 +1154,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); } } @@ -1132,7 +1183,7 @@ uint64_t videomem_base, uint64_t control_base, char *name) { struct vga_data *d; - int i, x,y, tmpi; + int i; size_t allocsize; d = malloc(sizeof(struct vga_data)); @@ -1148,31 +1199,31 @@ d->control_base = control_base; d->max_x = 80; d->max_y = 25; - d->pixel_repx = 1; - d->pixel_repy = 1; d->cur_mode = MODE_CHARCELL; d->crtc_reg[0xff] = 0x03; - d->charcells_size = d->max_x * VGA_MEM_MAXY * 2; + d->charcells_size = 0x8000; d->gfx_mem_size = 1; /* Nothing, as we start in text mode */ + d->pixel_repx = d->pixel_repy = machine->x11_scaleup; - /* Allocate in 4KB pages, to make it possible to use bintrans: */ - allocsize = ((d->charcells_size - 1) | 0xfff) + 1; + /* Allocate in full pages, to make it possible to use bintrans: */ + 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); } - for (y=0; ymax_x; x++) { - char ch = ' '; - i = (x + d->max_x * y) * 2; - d->charcells[i] = ch; - d->charcells[i+1] = 0x07; /* Default color */ - } + 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); @@ -1189,23 +1240,22 @@ d->fb_max_y *= d->font_height; } + memory_device_register(mem, "vga_charcells", videomem_base + 0x18000, + allocsize, dev_vga_access, d, DM_DYNTRANS_OK | + DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS, + d->charcells); + memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW, + dev_vga_graphics_access, d, DM_DEFAULT | + DM_READS_HAVE_NO_SIDE_EFFECTS, d->gfx_mem); + memory_device_register(mem, "vga_ctrl", control_base, + 32, dev_vga_ctrl_access, d, DM_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", 0); + 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_BINTRANS_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_BINTRANS_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); - /* This will force an initial redraw/resynch: */ d->update_x1 = 0; d->update_x2 = d->max_x - 1; @@ -1215,10 +1265,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); }