--- trunk/src/devices/dev_vga.c 2007/10/08 16:18:51 14 +++ trunk/src/devices/dev_vga.c 2007/10/08 16:19:37 22 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2005 Anders Gavare. All rights reserved. + * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -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.95 2006/01/01 13:17:18 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 18 #define MAX_RETRACE_SCANLINES 420 #define N_IS1_READ_THRESHOLD 50 @@ -73,7 +73,7 @@ uint64_t control_base; struct vfb_data *fb; - size_t fb_size; + uint32_t fb_size; int fb_max_x; /* pixels */ int fb_max_y; /* pixels */ @@ -92,13 +92,14 @@ 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; int bits_per_pixel; unsigned char *gfx_mem; - size_t gfx_mem_size; + uint32_t gfx_mem_size; /* Registers: */ int attribute_state; /* 0 or 1 */ @@ -136,6 +137,7 @@ int cursor_y; int modified; + int palette_modified; int update_x1; int update_y1; int update_x2; @@ -144,23 +146,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; @@ -188,7 +208,7 @@ for (i=16; i<256; i++) d->fb->rgb_palette[i*3 + 0] = d->fb->rgb_palette[i*3 + 1] = d->fb->rgb_palette[i*3 + 2] = (i & 15) * 4; - + d->palette_modified = 1; i = 0; if (grayscale) { @@ -341,7 +361,8 @@ } for (iy=y*ry; iy<(y+1)*ry; iy++) for (ix=x*rx; ix<(x+1)*rx; ix++) { - int addr2 = (d->fb_max_x * iy + ix) * 3; + uint32_t addr2 = (d->fb_max_x * iy + + ix) * 3; if (addr2 < d->fb_size) dev_fb_access(machine->cpus[0], machine->memory, addr2, @@ -362,11 +383,17 @@ static void vga_update_text(struct machine *machine, struct vga_data *d, int x1, int y1, int x2, int y2) { - int fg, bg, i, x,y, subx, line, start, end, base; + int fg, bg, x,y, subx, line; + size_t i, start, end, base; int font_size = d->font_height; int font_width = d->font_width; unsigned char *pal = d->fb->rgb_palette; + if (d->pixel_repx * font_width > 8*8) { + fatal("[ too large font ]\n"); + return; + } + /* Hm... I'm still using the old start..end code: */ start = (d->max_x * y1 + x1) * 2; end = (d->max_x * y2 + x2) * 2; @@ -385,6 +412,14 @@ for (i=start; i<=end; i+=2) { unsigned char ch = d->charcells[i + base]; + + if (!d->palette_modified && 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; @@ -398,8 +433,12 @@ /* Draw the character: */ for (line = 0; line < font_size; line++) { + /* hardcoded for max 8 scaleup... :-) */ + unsigned char rgb_line[3 * 8 * 8]; + int iy; + for (subx = 0; subx < font_width; subx++) { - int ix, iy, color_index; + int ix, color_index; if (d->use_palette_per_line) { int sline = d->pixel_repy * (line+y); @@ -416,19 +455,19 @@ else color_index = bg; - for (iy=0; iypixel_repy; iy++) - for (ix=0; ixpixel_repx; ix++) { - int addr = (d->fb_max_x* (d->pixel_repy - * (line+y) + iy) + (x+subx) * - d->pixel_repx + ix) * 3; + for (ix=0; ixpixel_repx; ix++) + memcpy(rgb_line + (subx*d->pixel_repx + + ix) * 3, &pal[color_index * 3], 3); + } - if (addr >= d->fb_size) - continue; - dev_fb_access(machine->cpus[0], - machine->memory, addr, - &pal[color_index * 3], 3, - MEM_WRITE, d->fb); - } + for (iy=0; iypixel_repy; iy++) { + uint32_t addr = (d->fb_max_x * (d->pixel_repy * + (line+y) + iy) + x * d->pixel_repx) * 3; + if (addr >= d->fb_size) + continue; + dev_fb_access(machine->cpus[0], + machine->memory, addr, rgb_line, + 3 * font_width, MEM_WRITE, d->fb); } } } @@ -481,7 +520,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 +532,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; @@ -533,6 +572,7 @@ vga_update_graphics(cpu->machine, d, d->update_x1, d->update_y1, d->update_x2, d->update_y2); + d->palette_modified = 0; d->modified = 0; d->update_x1 = 999999; d->update_x2 = -1; @@ -550,12 +590,11 @@ * * Reads and writes to the VGA video memory (pixels). */ -int dev_vga_graphics_access(struct cpu *cpu, struct memory *mem, - uint64_t relative_addr, unsigned char *data, size_t len, - int writeflag, void *extra) +DEVICE_ACCESS(vga_graphics) { struct vga_data *d = extra; - int i,j, x=0, y=0, x2=0, y2=0, modified = 0; + int j, x=0, y=0, x2=0, y2=0, modified = 0; + size_t i; if (relative_addr + len >= GFX_ADDR_WINDOW) return 0; @@ -592,8 +631,8 @@ int b = data[i] & pixelmask; int m = d->sequencer_reg[ VGA_SEQ_MAP_MASK] & 0x0f; - int addr = (y * d->max_x + x + i*8 + j) - * d->bits_per_pixel / 8; + uint32_t addr = (y * d->max_x + x + + i*8 + j) * d->bits_per_pixel / 8; unsigned char byte; if (!(d->graphcontr_reg[ VGA_GRAPHCONTR_MASK] & pixelmask)) @@ -648,14 +687,15 @@ * * Reads and writes to the VGA video memory (charcells). */ -int dev_vga_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, - unsigned char *data, size_t len, int writeflag, void *extra) +DEVICE_ACCESS(vga) { struct vga_data *d = extra; uint64_t idata = 0, odata = 0; - int i, x, y, x2, y2, r, base; + int x, y, x2, y2, r, base; + size_t i; - 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 +705,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 +762,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 +775,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; @@ -751,7 +789,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; @@ -761,7 +800,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; @@ -771,8 +810,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: @@ -780,36 +819,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", @@ -840,6 +881,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; @@ -864,7 +906,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; */ @@ -881,7 +926,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; */ @@ -897,6 +946,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; */ @@ -909,12 +962,10 @@ * * Reads and writes of the VGA control registers. */ -int dev_vga_ctrl_access(struct cpu *cpu, struct memory *mem, - uint64_t relative_addr, unsigned char *data, size_t len, - int writeflag, void *extra) +DEVICE_ACCESS(vga_ctrl) { struct vga_data *d = extra; - int i; + size_t i; uint64_t idata = 0, odata = 0; for (i=0; ipalette_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 */ } @@ -1019,6 +1070,7 @@ palette changed: */ if (new != old) { d->modified = 1; + d->palette_modified = 1; d->update_x1 = d->update_y1 = 0; d->update_x2 = d->max_x - 1; d->update_y2 = d->max_y - 1; @@ -1113,10 +1165,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 +1194,7 @@ uint64_t videomem_base, uint64_t control_base, char *name) { struct vga_data *d; - int i, tmpi; + size_t i; size_t allocsize; d = malloc(sizeof(struct vga_data)); @@ -1152,33 +1204,38 @@ } memset(d, 0, sizeof(struct vga_data)); - d->console_handle = console_start_slave(machine, name); + d->console_handle = console_start_slave(machine, "vga", + CONSOLE_OUTPUT_ONLY); d->videomem_base = videomem_base; 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 = 0x8000; d->gfx_mem_size = 1; /* Nothing, as we start in text mode */ + d->pixel_repx = d->pixel_repy = machine->x11_scaleup; /* 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); } + 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 +1252,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"); 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); - 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; @@ -1221,10 +1277,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); }