25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $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 $ |
29 |
* |
* |
30 |
* VGA charcell and graphics device. |
* VGA charcell and graphics device. |
31 |
* |
* |
52 |
#include "fonts/font8x16.c" |
#include "fonts/font8x16.c" |
53 |
|
|
54 |
|
|
55 |
/* For bintranslated videomem -> framebuffer updates: */ |
/* For videomem -> framebuffer updates: */ |
56 |
#define VGA_TICK_SHIFT 16 |
#define VGA_TICK_SHIFT 19 |
57 |
|
|
58 |
#define MAX_RETRACE_SCANLINES 420 |
#define MAX_RETRACE_SCANLINES 420 |
59 |
#define N_IS1_READ_THRESHOLD 50 |
#define N_IS1_READ_THRESHOLD 50 |
92 |
unsigned char *font; |
unsigned char *font; |
93 |
size_t charcells_size; |
size_t charcells_size; |
94 |
unsigned char *charcells; /* 2 bytes per char */ |
unsigned char *charcells; /* 2 bytes per char */ |
95 |
unsigned char *charcells_outputed; |
unsigned char *charcells_outputed; /* text */ |
96 |
|
unsigned char *charcells_drawn; /* framebuffer */ |
97 |
|
|
98 |
/* Graphics: */ |
/* Graphics: */ |
99 |
int graphics_mode; |
int graphics_mode; |
145 |
|
|
146 |
|
|
147 |
/* |
/* |
148 |
|
* recalc_cursor_position(): |
149 |
|
* |
150 |
|
* Should be called whenever the cursor location _or_ the display |
151 |
|
* base has been changed. |
152 |
|
*/ |
153 |
|
static void recalc_cursor_position(struct vga_data *d) |
154 |
|
{ |
155 |
|
int base = (d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) |
156 |
|
+ d->crtc_reg[VGA_CRTC_START_ADDR_LOW]; |
157 |
|
int ofs = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] * 256 + |
158 |
|
d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW]; |
159 |
|
ofs -= base; |
160 |
|
d->cursor_x = ofs % d->max_x; |
161 |
|
d->cursor_y = ofs / d->max_x; |
162 |
|
} |
163 |
|
|
164 |
|
|
165 |
|
/* |
166 |
* register_reset(): |
* register_reset(): |
167 |
* |
* |
168 |
* Resets many registers to sane values. |
* Resets many registers to sane values. |
169 |
*/ |
*/ |
170 |
static void register_reset(struct vga_data *d) |
static void register_reset(struct vga_data *d) |
171 |
{ |
{ |
172 |
/* Home cursor: */ |
/* Home cursor and start at the top: */ |
|
d->cursor_x = d->cursor_y = 0; |
|
173 |
d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] = |
d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] = |
174 |
d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW] = 0; |
d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW] = 0; |
|
|
|
175 |
d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] = |
d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] = |
176 |
d->crtc_reg[VGA_CRTC_START_ADDR_LOW] = 0; |
d->crtc_reg[VGA_CRTC_START_ADDR_LOW] = 0; |
177 |
|
|
178 |
|
recalc_cursor_position(d); |
179 |
|
|
180 |
/* Reset cursor scanline stuff: */ |
/* Reset cursor scanline stuff: */ |
181 |
d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] = d->font_height - 4; |
d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] = d->font_height - 2; |
182 |
d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END] = d->font_height - 2; |
d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END] = d->font_height - 1; |
183 |
|
|
184 |
d->sequencer_reg[VGA_SEQ_MAP_MASK] = 0x0f; |
d->sequencer_reg[VGA_SEQ_MAP_MASK] = 0x0f; |
185 |
d->graphcontr_reg[VGA_GRAPHCONTR_MASK] = 0xff; |
d->graphcontr_reg[VGA_GRAPHCONTR_MASK] = 0xff; |
404 |
|
|
405 |
for (i=start; i<=end; i+=2) { |
for (i=start; i<=end; i+=2) { |
406 |
unsigned char ch = d->charcells[i + base]; |
unsigned char ch = d->charcells[i + base]; |
407 |
|
|
408 |
|
if (d->charcells_drawn[i] == ch && |
409 |
|
d->charcells_drawn[i+1] == d->charcells[i+base+1]) |
410 |
|
continue; |
411 |
|
|
412 |
|
d->charcells_drawn[i] = ch; |
413 |
|
d->charcells_drawn[i+1] = d->charcells[i + base + 1]; |
414 |
|
|
415 |
fg = d->charcells[i+base + 1] & 15; |
fg = d->charcells[i+base + 1] & 15; |
416 |
bg = (d->charcells[i+base + 1] >> 4) & 7; |
bg = (d->charcells[i+base + 1] >> 4) & 7; |
417 |
|
|
508 |
int base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) |
int base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) |
509 |
+ d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; |
+ d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; |
510 |
int new_u_y1, new_u_y2; |
int new_u_y1, new_u_y2; |
511 |
debug("[ dev_vga_tick: bintrans access, %llx .. %llx ]\n", |
debug("[ dev_vga_tick: dyntrans access, %llx .. %llx ]\n", |
512 |
(long long)low, (long long)high); |
(long long)low, (long long)high); |
513 |
low -= base; |
low -= base; |
514 |
high -= base; |
high -= base; |
520 |
d->update_y1 = new_u_y1; |
d->update_y1 = new_u_y1; |
521 |
if (new_u_y2 > d->update_y2) |
if (new_u_y2 > d->update_y2) |
522 |
d->update_y2 = new_u_y2; |
d->update_y2 = new_u_y2; |
523 |
if (d->update_y2 < 0) |
if (d->update_y1 < 0) |
524 |
d->update_y2 = 0; |
d->update_y1 = 0; |
525 |
if (d->update_y2 >= d->max_y) |
if (d->update_y2 >= d->max_y) |
526 |
d->update_y2 = d->max_y - 1; |
d->update_y2 = d->max_y - 1; |
527 |
d->modified = 1; |
d->modified = 1; |
682 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
683 |
int i, x, y, x2, y2, r, base; |
int i, x, y, x2, y2, r, base; |
684 |
|
|
685 |
idata = memory_readmax64(cpu, data, len); |
if (writeflag == MEM_WRITE) |
686 |
|
idata = memory_readmax64(cpu, data, len); |
687 |
|
|
688 |
base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) |
base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) |
689 |
+ d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; |
+ d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; |
693 |
y2 = (r+len-1) / (d->max_x * 2); |
y2 = (r+len-1) / (d->max_x * 2); |
694 |
x2 = ((r+len-1)/2) % d->max_x; |
x2 = ((r+len-1)/2) % d->max_x; |
695 |
|
|
696 |
if (relative_addr < d->charcells_size) { |
if (relative_addr + len - 1 < d->charcells_size) { |
697 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
698 |
for (i=0; i<len; i++) { |
for (i=0; i<len; i++) { |
699 |
int old = d->charcells[relative_addr + i]; |
int old = d->charcells[relative_addr + i]; |
750 |
static void vga_crtc_reg_write(struct machine *machine, struct vga_data *d, |
static void vga_crtc_reg_write(struct machine *machine, struct vga_data *d, |
751 |
int regnr, int idata) |
int regnr, int idata) |
752 |
{ |
{ |
753 |
int ofs, grayscale; |
int grayscale; |
754 |
|
|
755 |
switch (regnr) { |
switch (regnr) { |
756 |
case VGA_CRTC_CURSOR_SCANLINE_START: /* 0x0a */ |
case VGA_CRTC_CURSOR_SCANLINE_START: /* 0x0a */ |
763 |
d->update_y1 = 0; |
d->update_y1 = 0; |
764 |
d->update_y2 = d->max_y - 1; |
d->update_y2 = d->max_y - 1; |
765 |
d->modified = 1; |
d->modified = 1; |
766 |
|
recalc_cursor_position(d); |
767 |
break; |
break; |
768 |
case VGA_CRTC_CURSOR_LOCATION_HIGH: /* 0x0e */ |
case VGA_CRTC_CURSOR_LOCATION_HIGH: /* 0x0e */ |
769 |
case VGA_CRTC_CURSOR_LOCATION_LOW: /* 0x0f */ |
case VGA_CRTC_CURSOR_LOCATION_LOW: /* 0x0f */ |
770 |
ofs = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] * 256 + |
recalc_cursor_position(d); |
|
d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW]; |
|
|
d->cursor_x = ofs % d->max_x; |
|
|
d->cursor_y = ofs / d->max_x; |
|
771 |
break; |
break; |
772 |
case 0xff: |
case 0xff: |
773 |
grayscale = 0; |
grayscale = 0; |
866 |
|
|
867 |
/* Clear screen and reset the palette: */ |
/* Clear screen and reset the palette: */ |
868 |
memset(d->charcells_outputed, 0, d->charcells_size); |
memset(d->charcells_outputed, 0, d->charcells_size); |
869 |
|
memset(d->charcells_drawn, 0, d->charcells_size); |
870 |
memset(d->gfx_mem, 0, d->gfx_mem_size); |
memset(d->gfx_mem, 0, d->gfx_mem_size); |
871 |
d->update_x1 = 0; |
d->update_x1 = 0; |
872 |
d->update_x2 = d->max_x - 1; |
d->update_x2 = d->max_x - 1; |
924 |
static void vga_attribute_reg_write(struct machine *machine, struct vga_data *d, |
static void vga_attribute_reg_write(struct machine *machine, struct vga_data *d, |
925 |
int regnr, int idata) |
int regnr, int idata) |
926 |
{ |
{ |
927 |
|
/* 0-15 are palette registers: TODO */ |
928 |
|
if (regnr >= 0 && regnr <= 0xf) |
929 |
|
return; |
930 |
|
|
931 |
switch (regnr) { |
switch (regnr) { |
932 |
default:fatal("[ vga_attribute_reg_write: select %i ]\n", regnr); |
default:fatal("[ vga_attribute_reg_write: select %i ]\n", regnr); |
933 |
/* cpu->running = 0; */ |
/* cpu->running = 0; */ |
1019 |
d->palette_read_index = idata; |
d->palette_read_index = idata; |
1020 |
d->palette_read_subindex = 0; |
d->palette_read_subindex = 0; |
1021 |
} else { |
} else { |
1022 |
fatal("[ dev_vga: WARNING: Read from " |
debug("[ dev_vga: WARNING: Read from " |
1023 |
"VGA_DAC_ADDR_READ? TODO ]\n"); |
"VGA_DAC_ADDR_READ? TODO ]\n"); |
1024 |
/* TODO */ |
/* TODO */ |
1025 |
} |
} |
1144 |
|
|
1145 |
default: |
default: |
1146 |
if (writeflag==MEM_READ) { |
if (writeflag==MEM_READ) { |
1147 |
fatal("[ vga_ctrl: read from 0x%08lx ]\n", |
debug("[ vga_ctrl: read from 0x%08lx ]\n", |
1148 |
(long)relative_addr); |
(long)relative_addr); |
1149 |
} else { |
} else { |
1150 |
fatal("[ vga_ctrl: write to 0x%08lx: 0x%08x" |
debug("[ vga_ctrl: write to 0x%08lx: 0x%08x" |
1151 |
" ]\n", (long)relative_addr, (int)idata); |
" ]\n", (long)relative_addr, (int)idata); |
1152 |
} |
} |
1153 |
} |
} |
1173 |
uint64_t videomem_base, uint64_t control_base, char *name) |
uint64_t videomem_base, uint64_t control_base, char *name) |
1174 |
{ |
{ |
1175 |
struct vga_data *d; |
struct vga_data *d; |
1176 |
int i, tmpi; |
int i; |
1177 |
size_t allocsize; |
size_t allocsize; |
1178 |
|
|
1179 |
d = malloc(sizeof(struct vga_data)); |
d = malloc(sizeof(struct vga_data)); |
1200 |
allocsize = ((d->charcells_size-1) | (machine->arch_pagesize-1)) + 1; |
allocsize = ((d->charcells_size-1) | (machine->arch_pagesize-1)) + 1; |
1201 |
d->charcells = malloc(d->charcells_size); |
d->charcells = malloc(d->charcells_size); |
1202 |
d->charcells_outputed = malloc(d->charcells_size); |
d->charcells_outputed = malloc(d->charcells_size); |
1203 |
|
d->charcells_drawn = malloc(d->charcells_size); |
1204 |
d->gfx_mem = malloc(d->gfx_mem_size); |
d->gfx_mem = malloc(d->gfx_mem_size); |
1205 |
if (d->charcells == NULL || d->charcells_outputed == NULL || |
if (d->charcells == NULL || d->charcells_outputed == NULL || |
1206 |
d->gfx_mem == NULL) { |
d->charcells_drawn == NULL || d->gfx_mem == NULL) { |
1207 |
fprintf(stderr, "out of memory in dev_vga_init()\n"); |
fprintf(stderr, "out of memory in dev_vga_init()\n"); |
1208 |
exit(1); |
exit(1); |
1209 |
} |
} |
1210 |
|
|
1211 |
|
memset(d->charcells_drawn, 0, d->charcells_size); |
1212 |
|
|
1213 |
for (i=0; i<d->charcells_size; i+=2) { |
for (i=0; i<d->charcells_size; i+=2) { |
1214 |
d->charcells[i] = ' '; |
d->charcells[i] = ' '; |
1215 |
d->charcells[i+1] = 0x07; /* Default color */ |
d->charcells[i+1] = 0x07; /* Default color */ |
1216 |
|
d->charcells_drawn[i] = ' '; |
1217 |
|
d->charcells_drawn[i+1] = 0x07; |
1218 |
} |
} |
1219 |
|
|
1220 |
memset(d->charcells_outputed, 0, d->charcells_size); |
memset(d->charcells_outputed, 0, d->charcells_size); |
1231 |
d->fb_max_y *= d->font_height; |
d->fb_max_y *= d->font_height; |
1232 |
} |
} |
1233 |
|
|
|
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? */ |
|
1234 |
memory_device_register(mem, "vga_charcells", videomem_base + 0x18000, |
memory_device_register(mem, "vga_charcells", videomem_base + 0x18000, |
1235 |
allocsize, dev_vga_access, d, MEM_DYNTRANS_OK | |
allocsize, dev_vga_access, d, MEM_DYNTRANS_OK | |
1236 |
MEM_READING_HAS_NO_SIDE_EFFECTS, d->charcells); |
MEM_DYNTRANS_WRITE_OK | MEM_READING_HAS_NO_SIDE_EFFECTS, |
1237 |
|
d->charcells); |
1238 |
memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW, |
memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW, |
1239 |
dev_vga_graphics_access, d, MEM_DEFAULT | |
dev_vga_graphics_access, d, MEM_DEFAULT | |
1240 |
MEM_READING_HAS_NO_SIDE_EFFECTS, d->gfx_mem); |
MEM_READING_HAS_NO_SIDE_EFFECTS, d->gfx_mem); |
1241 |
memory_device_register(mem, "vga_ctrl", control_base, |
memory_device_register(mem, "vga_ctrl", control_base, |
1242 |
32, dev_vga_ctrl_access, d, MEM_DEFAULT, NULL); |
32, dev_vga_ctrl_access, d, MEM_DEFAULT, NULL); |
1243 |
|
|
1244 |
|
d->fb = dev_fb_init(machine, mem, VGA_FB_ADDR, VFB_GENERIC, |
1245 |
|
d->fb_max_x, d->fb_max_y, d->fb_max_x, d->fb_max_y, 24, "VGA"); |
1246 |
|
d->fb_size = d->fb_max_x * d->fb_max_y * 3; |
1247 |
|
|
1248 |
|
reset_palette(d, 0); |
1249 |
|
|
1250 |
/* This will force an initial redraw/resynch: */ |
/* This will force an initial redraw/resynch: */ |
1251 |
d->update_x1 = 0; |
d->update_x1 = 0; |
1252 |
d->update_x2 = d->max_x - 1; |
d->update_x2 = d->max_x - 1; |
1256 |
|
|
1257 |
machine_add_tickfunction(machine, dev_vga_tick, d, VGA_TICK_SHIFT); |
machine_add_tickfunction(machine, dev_vga_tick, d, VGA_TICK_SHIFT); |
1258 |
|
|
|
vga_update_cursor(machine, d); |
|
|
|
|
|
tmpi = d->cursor_y * d->max_x + d->cursor_x; |
|
|
|
|
1259 |
register_reset(d); |
register_reset(d); |
1260 |
|
|
1261 |
|
vga_update_cursor(machine, d); |
1262 |
} |
} |
1263 |
|
|