/[gxemul]/trunk/src/devices/dev_vga.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_vga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 34152 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


1 /*
2 * Copyright (C) 2004-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_vga.c,v 1.100 2006/07/08 12:30:02 debug Exp $
29 *
30 * VGA charcell and graphics device.
31 *
32 * It should work with 80x25 and 40x25 text modes, and with a few graphics
33 * modes as long as no fancy VGA features are used.
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "console.h"
41 #include "cpu.h"
42 #include "devices.h"
43 #include "machine.h"
44 #include "memory.h"
45 #include "misc.h"
46
47 #include "vga.h"
48
49 /* These are generated from binary font files: */
50 #include "fonts/font8x8.c"
51 #include "fonts/font8x10.c"
52 #include "fonts/font8x16.c"
53
54
55 /* For videomem -> framebuffer updates: */
56 #define VGA_TICK_SHIFT 18
57
58 #define MAX_RETRACE_SCANLINES 420
59 #define N_IS1_READ_THRESHOLD 50
60
61 #define GFX_ADDR_WINDOW 0x18000
62
63 #define VGA_FB_ADDR 0x1c00000000ULL
64
65 #define MODE_CHARCELL 1
66 #define MODE_GRAPHICS 2
67
68 #define GRAPHICS_MODE_8BIT 1
69 #define GRAPHICS_MODE_4BIT 2
70
71 struct vga_data {
72 uint64_t videomem_base;
73 uint64_t control_base;
74
75 struct vfb_data *fb;
76 uint32_t fb_size;
77
78 int fb_max_x; /* pixels */
79 int fb_max_y; /* pixels */
80 int max_x; /* charcells or pixels */
81 int max_y; /* charcells or pixels */
82
83 /* Selects charcell mode or graphics mode: */
84 int cur_mode;
85
86 /* Common for text and graphics modes: */
87 int pixel_repx, pixel_repy;
88
89 /* Textmode: */
90 int font_width;
91 int font_height;
92 unsigned char *font;
93 size_t charcells_size;
94 unsigned char *charcells; /* 2 bytes per char */
95 unsigned char *charcells_outputed; /* text */
96 unsigned char *charcells_drawn; /* framebuffer */
97
98 /* Graphics: */
99 int graphics_mode;
100 int bits_per_pixel;
101 unsigned char *gfx_mem;
102 uint32_t gfx_mem_size;
103
104 /* Registers: */
105 int attribute_state; /* 0 or 1 */
106 unsigned char attribute_reg_select;
107 unsigned char attribute_reg[256];
108
109 unsigned char misc_output_reg;
110
111 unsigned char sequencer_reg_select;
112 unsigned char sequencer_reg[256];
113
114 unsigned char graphcontr_reg_select;
115 unsigned char graphcontr_reg[256];
116
117 unsigned char crtc_reg_select;
118 unsigned char crtc_reg[256];
119
120 unsigned char palette_read_index;
121 char palette_read_subindex;
122 unsigned char palette_write_index;
123 char palette_write_subindex;
124
125 int current_retrace_line;
126 int input_status_1;
127
128 /* Palette per scanline during retrace: */
129 unsigned char *retrace_palette;
130 int use_palette_per_line;
131 int64_t n_is1_reads;
132
133 /* Misc.: */
134 int console_handle;
135
136 int cursor_x;
137 int cursor_y;
138
139 int modified;
140 int palette_modified;
141 int update_x1;
142 int update_y1;
143 int update_x2;
144 int update_y2;
145 };
146
147
148 /*
149 * recalc_cursor_position():
150 *
151 * Should be called whenever the cursor location _or_ the display
152 * base has been changed.
153 */
154 static void recalc_cursor_position(struct vga_data *d)
155 {
156 int base = (d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
157 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW];
158 int ofs = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] * 256 +
159 d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW];
160 ofs -= base;
161 d->cursor_x = ofs % d->max_x;
162 d->cursor_y = ofs / d->max_x;
163 }
164
165
166 /*
167 * register_reset():
168 *
169 * Resets many registers to sane values.
170 */
171 static void register_reset(struct vga_data *d)
172 {
173 /* Home cursor and start at the top: */
174 d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] =
175 d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW] = 0;
176 d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] =
177 d->crtc_reg[VGA_CRTC_START_ADDR_LOW] = 0;
178
179 recalc_cursor_position(d);
180
181 /* Reset cursor scanline stuff: */
182 d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] = d->font_height - 2;
183 d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END] = d->font_height - 1;
184
185 d->sequencer_reg[VGA_SEQ_MAP_MASK] = 0x0f;
186 d->graphcontr_reg[VGA_GRAPHCONTR_MASK] = 0xff;
187
188 d->misc_output_reg = VGA_MISC_OUTPUT_IOAS;
189 d->n_is1_reads = 0;
190 }
191
192
193 static void c_putstr(struct vga_data *d, char *s)
194 {
195 while (*s)
196 console_putchar(d->console_handle, *s++);
197 }
198
199
200 /*
201 * reset_palette():
202 */
203 static void reset_palette(struct vga_data *d, int grayscale)
204 {
205 int i, r, g, b;
206
207 /* TODO: default values for entry 16..255? */
208 for (i=16; i<256; i++)
209 d->fb->rgb_palette[i*3 + 0] = d->fb->rgb_palette[i*3 + 1] =
210 d->fb->rgb_palette[i*3 + 2] = (i & 15) * 4;
211 d->palette_modified = 1;
212 i = 0;
213
214 if (grayscale) {
215 for (r=0; r<2; r++)
216 for (g=0; g<2; g++)
217 for (b=0; b<2; b++) {
218 d->fb->rgb_palette[i + 0] =
219 d->fb->rgb_palette[i + 1] =
220 d->fb->rgb_palette[i + 2] =
221 (r+g+b) * 0xaa / 3;
222 d->fb->rgb_palette[i + 8*3 + 0] =
223 d->fb->rgb_palette[i + 8*3 + 1] =
224 d->fb->rgb_palette[i + 8*3 + 2] =
225 (r+g+b) * 0xaa / 3 + 0x55;
226 i+=3;
227 }
228 return;
229 }
230
231 for (r=0; r<2; r++)
232 for (g=0; g<2; g++)
233 for (b=0; b<2; b++) {
234 d->fb->rgb_palette[i + 0] = r * 0xaa;
235 d->fb->rgb_palette[i + 1] = g * 0xaa;
236 d->fb->rgb_palette[i + 2] = b * 0xaa;
237 i+=3;
238 }
239 for (r=0; r<2; r++)
240 for (g=0; g<2; g++)
241 for (b=0; b<2; b++) {
242 d->fb->rgb_palette[i + 0] = r * 0xaa + 0x55;
243 d->fb->rgb_palette[i + 1] = g * 0xaa + 0x55;
244 d->fb->rgb_palette[i + 2] = b * 0xaa + 0x55;
245 i+=3;
246 }
247 }
248
249
250 /*
251 * vga_update_textmode():
252 *
253 * Called from vga_update() when use_x11 is false. This causes modified
254 * character cells to be "simulated" by outputing ANSI escape sequences
255 * that draw the characters in a terminal window instead.
256 */
257 static void vga_update_textmode(struct machine *machine,
258 struct vga_data *d, int base, int start, int end)
259 {
260 char s[50];
261 int i, oldcolor = -1, printed_last = 0;
262
263 for (i=start; i<=end; i+=2) {
264 unsigned char ch = d->charcells[base+i];
265 int fg = d->charcells[base+i+1] & 15;
266 int bg = (d->charcells[base+i+1] >> 4) & 15;
267 /* top bit of bg = blink */
268 int x = (i/2) % d->max_x;
269 int y = (i/2) / d->max_x;
270
271 if (d->charcells[base+i] == d->charcells_outputed[i] &&
272 d->charcells[base+i+1] == d->charcells_outputed[i+1]) {
273 printed_last = 0;
274 continue;
275 }
276
277 d->charcells_outputed[i] = d->charcells[base+i];
278 d->charcells_outputed[i+1] = d->charcells[base+i+1];
279
280 if (!printed_last || x == 0) {
281 snprintf(s, sizeof(s), "\033[%i;%iH", y + 1, x + 1);
282 c_putstr(d, s);
283 }
284 if (oldcolor < 0 || (bg<<4)+fg != oldcolor || !printed_last) {
285 snprintf(s, sizeof(s), "\033[0;"); c_putstr(d, s);
286
287 switch (fg & 7) {
288 case 0: c_putstr(d, "30"); break;
289 case 1: c_putstr(d, "34"); break;
290 case 2: c_putstr(d, "32"); break;
291 case 3: c_putstr(d, "36"); break;
292 case 4: c_putstr(d, "31"); break;
293 case 5: c_putstr(d, "35"); break;
294 case 6: c_putstr(d, "33"); break;
295 case 7: c_putstr(d, "37"); break;
296 }
297 if (fg & 8)
298 c_putstr(d, ";1");
299 c_putstr(d, ";");
300 switch (bg & 7) {
301 case 0: c_putstr(d, "40"); break;
302 case 1: c_putstr(d, "44"); break;
303 case 2: c_putstr(d, "42"); break;
304 case 3: c_putstr(d, "46"); break;
305 case 4: c_putstr(d, "41"); break;
306 case 5: c_putstr(d, "45"); break;
307 case 6: c_putstr(d, "43"); break;
308 case 7: c_putstr(d, "47"); break;
309 }
310 /* TODO: blink */
311 c_putstr(d, "m");
312 }
313
314 if (ch >= 0x20 && ch != 127)
315 console_putchar(d->console_handle, ch);
316
317 oldcolor = (bg << 4) + fg;
318 printed_last = 1;
319 }
320
321 /* Restore the terminal's cursor position: */
322 snprintf(s, sizeof(s), "\033[%i;%iH", d->cursor_y + 1, d->cursor_x + 1);
323 c_putstr(d, s);
324 }
325
326
327 /*
328 * vga_update_graphics():
329 *
330 * This function should be called whenever any part of d->gfx_mem[] has
331 * been written to. It will redraw all pixels within the range x1,y1
332 * .. x2,y2 using the right palette.
333 */
334 static void vga_update_graphics(struct machine *machine, struct vga_data *d,
335 int x1, int y1, int x2, int y2)
336 {
337 int x, y, ix, iy, c, rx = d->pixel_repx, ry = d->pixel_repy;
338 unsigned char pixel[3];
339
340 for (y=y1; y<=y2; y++)
341 for (x=x1; x<=x2; x++) {
342 /* addr is where to read from VGA memory, addr2 is
343 where to write on the 24-bit framebuffer device */
344 int addr = (y * d->max_x + x) * d->bits_per_pixel;
345 switch (d->bits_per_pixel) {
346 case 8: addr >>= 3;
347 c = d->gfx_mem[addr];
348 pixel[0] = d->fb->rgb_palette[c*3+0];
349 pixel[1] = d->fb->rgb_palette[c*3+1];
350 pixel[2] = d->fb->rgb_palette[c*3+2];
351 break;
352 case 4: addr >>= 2;
353 if (addr & 1)
354 c = d->gfx_mem[addr >> 1] >> 4;
355 else
356 c = d->gfx_mem[addr >> 1] & 0xf;
357 pixel[0] = d->fb->rgb_palette[c*3+0];
358 pixel[1] = d->fb->rgb_palette[c*3+1];
359 pixel[2] = d->fb->rgb_palette[c*3+2];
360 break;
361 }
362 for (iy=y*ry; iy<(y+1)*ry; iy++)
363 for (ix=x*rx; ix<(x+1)*rx; ix++) {
364 uint32_t addr2 = (d->fb_max_x * iy
365 + ix) * 3;
366 if (addr2 < d->fb_size)
367 dev_fb_access(machine->cpus[0],
368 machine->memory, addr2,
369 pixel, sizeof(pixel),
370 MEM_WRITE, d->fb);
371 }
372 }
373 }
374
375
376 /*
377 * vga_update_text():
378 *
379 * This function should be called whenever any part of d->charcells[] has
380 * been written to. It will redraw all characters within the range x1,y1
381 * .. x2,y2 using the right palette.
382 */
383 static void vga_update_text(struct machine *machine, struct vga_data *d,
384 int x1, int y1, int x2, int y2)
385 {
386 int fg, bg, x,y, subx, line;
387 size_t i, start, end, base;
388 int font_size = d->font_height;
389 int font_width = d->font_width;
390 unsigned char *pal = d->fb->rgb_palette;
391
392 if (d->pixel_repx * font_width > 8*8) {
393 fatal("[ too large font ]\n");
394 return;
395 }
396
397 /* Hm... I'm still using the old start..end code: */
398 start = (d->max_x * y1 + x1) * 2;
399 end = (d->max_x * y2 + x2) * 2;
400
401 start &= ~1;
402 end |= 1;
403
404 if (end >= d->charcells_size)
405 end = d->charcells_size - 1;
406
407 base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
408 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
409
410 if (!machine->use_x11)
411 vga_update_textmode(machine, d, base, start, end);
412
413 for (i=start; i<=end; i+=2) {
414 unsigned char ch = d->charcells[i + base];
415
416 if (!d->palette_modified && d->charcells_drawn[i] == ch &&
417 d->charcells_drawn[i+1] == d->charcells[i+base+1])
418 continue;
419
420 d->charcells_drawn[i] = ch;
421 d->charcells_drawn[i+1] = d->charcells[i + base + 1];
422
423 fg = d->charcells[i+base + 1] & 15;
424 bg = (d->charcells[i+base + 1] >> 4) & 7;
425
426 /* Blink is hard to do :-), but inversion might be ok too: */
427 if (d->charcells[i+base + 1] & 128) {
428 int tmp = fg; fg = bg; bg = tmp;
429 }
430
431 x = (i/2) % d->max_x; x *= font_width;
432 y = (i/2) / d->max_x; y *= font_size;
433
434 /* Draw the character: */
435 for (line = 0; line < font_size; line++) {
436 /* hardcoded for max 8 scaleup... :-) */
437 unsigned char rgb_line[3 * 8 * 8];
438 int iy;
439
440 for (subx = 0; subx < font_width; subx++) {
441 int ix, color_index;
442
443 if (d->use_palette_per_line) {
444 int sline = d->pixel_repy * (line+y);
445 if (sline < MAX_RETRACE_SCANLINES)
446 pal = d->retrace_palette
447 + sline * 256*3;
448 else
449 pal = d->fb->rgb_palette;
450 }
451
452 if (d->font[ch * font_size + line] &
453 (128 >> subx))
454 color_index = fg;
455 else
456 color_index = bg;
457
458 for (ix=0; ix<d->pixel_repx; ix++)
459 memcpy(rgb_line + (subx*d->pixel_repx +
460 ix) * 3, &pal[color_index * 3], 3);
461 }
462
463 for (iy=0; iy<d->pixel_repy; iy++) {
464 uint32_t addr = (d->fb_max_x * (d->pixel_repy *
465 (line+y) + iy) + x * d->pixel_repx) * 3;
466 if (addr >= d->fb_size)
467 continue;
468 dev_fb_access(machine->cpus[0],
469 machine->memory, addr, rgb_line,
470 3 * machine->x11_scaleup * font_width,
471 MEM_WRITE, d->fb);
472 }
473 }
474 }
475 }
476
477
478 /*
479 * vga_update_cursor():
480 */
481 static void vga_update_cursor(struct machine *machine, struct vga_data *d)
482 {
483 int onoff = 1, height = d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END]
484 - d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] + 1;
485
486 if (d->cur_mode != MODE_CHARCELL)
487 onoff = 0;
488
489 if (d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] >
490 d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END]) {
491 onoff = 0;
492 height = 1;
493 }
494
495 if (d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] >= d->font_height)
496 onoff = 0;
497
498 dev_fb_setcursor(d->fb,
499 d->cursor_x * d->font_width * d->pixel_repx, (d->cursor_y *
500 d->font_height + d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START]) *
501 d->pixel_repy, onoff, d->font_width * d->pixel_repx, height *
502 d->pixel_repy);
503 }
504
505
506 /*
507 * dev_vga_tick():
508 */
509 void dev_vga_tick(struct cpu *cpu, void *extra)
510 {
511 struct vga_data *d = extra;
512 int64_t low = -1, high;
513
514 vga_update_cursor(cpu->machine, d);
515
516 /* TODO: text vs graphics tick? */
517 memory_device_dyntrans_access(cpu, cpu->mem, extra,
518 (uint64_t *) &low, (uint64_t *) &high);
519
520 if (low != -1) {
521 int base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
522 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
523 int new_u_y1, new_u_y2;
524 debug("[ dev_vga_tick: dyntrans access, %"PRIx64" .. %"
525 PRIx64" ]\n", (uint64_t) low, (uint64_t) high);
526 low -= base;
527 high -= base;
528 d->update_x1 = 0;
529 d->update_x2 = d->max_x - 1;
530 new_u_y1 = (low/2) / d->max_x;
531 new_u_y2 = ((high/2) / d->max_x) + 1;
532 if (new_u_y1 < d->update_y1)
533 d->update_y1 = new_u_y1;
534 if (new_u_y2 > d->update_y2)
535 d->update_y2 = new_u_y2;
536 if (d->update_y1 < 0)
537 d->update_y1 = 0;
538 if (d->update_y2 >= d->max_y)
539 d->update_y2 = d->max_y - 1;
540 d->modified = 1;
541 }
542
543 if (d->n_is1_reads > N_IS1_READ_THRESHOLD &&
544 d->retrace_palette != NULL) {
545 d->use_palette_per_line = 1;
546 d->update_x1 = 0;
547 d->update_x2 = d->max_x - 1;
548 d->update_y1 = 0;
549 d->update_y2 = d->max_y - 1;
550 d->modified = 1;
551 } else {
552 if (d->use_palette_per_line) {
553 d->use_palette_per_line = 0;
554 d->update_x1 = 0;
555 d->update_x2 = d->max_x - 1;
556 d->update_y1 = 0;
557 d->update_y2 = d->max_y - 1;
558 d->modified = 1;
559 }
560 }
561
562 if (!cpu->machine->use_x11) {
563 /* NOTE: 2 > 0, so this only updates the cursor, no
564 character cells. */
565 vga_update_textmode(cpu->machine, d, 0, 2, 0);
566 }
567
568 if (d->modified) {
569 if (d->cur_mode == MODE_CHARCELL)
570 vga_update_text(cpu->machine, d, d->update_x1,
571 d->update_y1, d->update_x2, d->update_y2);
572 else
573 vga_update_graphics(cpu->machine, d, d->update_x1,
574 d->update_y1, d->update_x2, d->update_y2);
575
576 d->palette_modified = 0;
577 d->modified = 0;
578 d->update_x1 = 999999;
579 d->update_x2 = -1;
580 d->update_y1 = 999999;
581 d->update_y2 = -1;
582 }
583
584 if (d->n_is1_reads > N_IS1_READ_THRESHOLD)
585 d->n_is1_reads = 0;
586 }
587
588
589 /*
590 * vga_graphics_access():
591 *
592 * Reads and writes to the VGA video memory (pixels).
593 */
594 DEVICE_ACCESS(vga_graphics)
595 {
596 struct vga_data *d = extra;
597 int j, x=0, y=0, x2=0, y2=0, modified = 0;
598 size_t i;
599
600 if (relative_addr + len >= GFX_ADDR_WINDOW)
601 return 0;
602
603 if (d->cur_mode != MODE_GRAPHICS)
604 return 1;
605
606 switch (d->graphics_mode) {
607 case GRAPHICS_MODE_8BIT:
608 y = relative_addr / d->max_x;
609 x = relative_addr % d->max_x;
610 y2 = (relative_addr+len-1) / d->max_x;
611 x2 = (relative_addr+len-1) % d->max_x;
612
613 if (writeflag == MEM_WRITE) {
614 memcpy(d->gfx_mem + relative_addr, data, len);
615 modified = 1;
616 } else
617 memcpy(data, d->gfx_mem + relative_addr, len);
618 break;
619 case GRAPHICS_MODE_4BIT:
620 y = relative_addr * 8 / d->max_x;
621 x = relative_addr * 8 % d->max_x;
622 y2 = ((relative_addr+len)*8-1) / d->max_x;
623 x2 = ((relative_addr+len)*8-1) % d->max_x;
624 /* TODO: color stuff */
625
626 /* Read/write d->gfx_mem in 4-bit color: */
627 if (writeflag == MEM_WRITE) {
628 /* i is byte index to write, j is bit index */
629 for (i=0; i<len; i++)
630 for (j=0; j<8; j++) {
631 int pixelmask = 1 << (7-j);
632 int b = data[i] & pixelmask;
633 int m = d->sequencer_reg[
634 VGA_SEQ_MAP_MASK] & 0x0f;
635 uint32_t addr = (y * d->max_x + x +
636 i*8 + j) * d->bits_per_pixel / 8;
637 unsigned char byte;
638 if (!(d->graphcontr_reg[
639 VGA_GRAPHCONTR_MASK] & pixelmask))
640 continue;
641 if (addr >= d->gfx_mem_size)
642 continue;
643 byte = d->gfx_mem[addr];
644 if (b && j&1)
645 byte |= m << 4;
646 if (b && !(j&1))
647 byte |= m;
648 if (!b && j&1)
649 byte &= ~(m << 4);
650 if (!b && !(j&1))
651 byte &= ~m;
652 d->gfx_mem[addr] = byte;
653 }
654 modified = 1;
655 } else {
656 fatal("TODO: 4 bit graphics read, mask=0x%02x\n",
657 d->sequencer_reg[VGA_SEQ_MAP_MASK]);
658 for (i=0; i<len; i++)
659 data[i] = random();
660 }
661 break;
662 default:fatal("dev_vga: Unimplemented graphics mode %i\n",
663 d->graphics_mode);
664 cpu->running = 0;
665 }
666
667 if (modified) {
668 d->modified = 1;
669 if (x < d->update_x1) d->update_x1 = x;
670 if (x > d->update_x2) d->update_x2 = x;
671 if (y < d->update_y1) d->update_y1 = y;
672 if (y > d->update_y2) d->update_y2 = y;
673 if (x2 < d->update_x1) d->update_x1 = x2;
674 if (x2 > d->update_x2) d->update_x2 = x2;
675 if (y2 < d->update_y1) d->update_y1 = y2;
676 if (y2 > d->update_y2) d->update_y2 = y2;
677 if (y != y2) {
678 d->update_x1 = 0;
679 d->update_x2 = d->max_x - 1;
680 }
681 }
682 return 1;
683 }
684
685
686 /*
687 * dev_vga_access():
688 *
689 * Reads and writes to the VGA video memory (charcells).
690 */
691 DEVICE_ACCESS(vga)
692 {
693 struct vga_data *d = extra;
694 uint64_t idata = 0, odata = 0;
695 int x, y, x2, y2, r, base;
696 size_t i;
697
698 if (writeflag == MEM_WRITE)
699 idata = memory_readmax64(cpu, data, len);
700
701 base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
702 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
703 r = relative_addr - base;
704 y = r / (d->max_x * 2);
705 x = (r/2) % d->max_x;
706 y2 = (r+len-1) / (d->max_x * 2);
707 x2 = ((r+len-1)/2) % d->max_x;
708
709 if (relative_addr + len - 1 < d->charcells_size) {
710 if (writeflag == MEM_WRITE) {
711 for (i=0; i<len; i++) {
712 int old = d->charcells[relative_addr + i];
713 if (old != data[i]) {
714 d->charcells[relative_addr + i] =
715 data[i];
716 d->modified = 1;
717 }
718 }
719
720 if (d->modified) {
721 if (x < d->update_x1) d->update_x1 = x;
722 if (x > d->update_x2) d->update_x2 = x;
723 if (y < d->update_y1) d->update_y1 = y;
724 if (y > d->update_y2) d->update_y2 = y;
725 if (x2 < d->update_x1) d->update_x1 = x2;
726 if (x2 > d->update_x2) d->update_x2 = x2;
727 if (y2 < d->update_y1) d->update_y1 = y2;
728 if (y2 > d->update_y2) d->update_y2 = y2;
729
730 if (y != y2) {
731 d->update_x1 = 0;
732 d->update_x2 = d->max_x - 1;
733 }
734 }
735 } else
736 memcpy(data, d->charcells + relative_addr, len);
737 return 1;
738 }
739
740 switch (relative_addr) {
741 default:
742 if (writeflag==MEM_READ) {
743 debug("[ vga: read from 0x%08lx ]\n",
744 (long)relative_addr);
745 } else {
746 debug("[ vga: write to 0x%08lx: 0x%08x ]\n",
747 (long)relative_addr, idata);
748 }
749 }
750
751 if (writeflag == MEM_READ)
752 memory_writemax64(cpu, data, len, odata);
753
754 return 1;
755 }
756
757
758 /*
759 * vga_crtc_reg_write():
760 *
761 * Writes to VGA CRTC registers.
762 */
763 static void vga_crtc_reg_write(struct machine *machine, struct vga_data *d,
764 int regnr, int idata)
765 {
766 int i, grayscale;
767
768 switch (regnr) {
769 case VGA_CRTC_CURSOR_SCANLINE_START: /* 0x0a */
770 case VGA_CRTC_CURSOR_SCANLINE_END: /* 0x0b */
771 break;
772 case VGA_CRTC_START_ADDR_HIGH: /* 0x0c */
773 case VGA_CRTC_START_ADDR_LOW: /* 0x0d */
774 d->update_x1 = 0;
775 d->update_x2 = d->max_x - 1;
776 d->update_y1 = 0;
777 d->update_y2 = d->max_y - 1;
778 d->modified = 1;
779 recalc_cursor_position(d);
780 break;
781 case VGA_CRTC_CURSOR_LOCATION_HIGH: /* 0x0e */
782 case VGA_CRTC_CURSOR_LOCATION_LOW: /* 0x0f */
783 recalc_cursor_position(d);
784 break;
785 case 0xff:
786 grayscale = 0;
787 switch (d->crtc_reg[0xff]) {
788 case 0x00:
789 grayscale = 1;
790 case 0x01:
791 d->cur_mode = MODE_CHARCELL;
792 d->max_x = 40; d->max_y = 25;
793 d->pixel_repx = machine->x11_scaleup * 2;
794 d->pixel_repy = machine->x11_scaleup;
795 d->font_width = 8;
796 d->font_height = 16;
797 d->font = font8x16;
798 break;
799 case 0x02:
800 grayscale = 1;
801 case 0x03:
802 d->cur_mode = MODE_CHARCELL;
803 d->max_x = 80; d->max_y = 25;
804 d->pixel_repx = d->pixel_repy = machine->x11_scaleup;
805 d->font_width = 8;
806 d->font_height = 16;
807 d->font = font8x16;
808 break;
809 case 0x08:
810 d->cur_mode = MODE_GRAPHICS;
811 d->max_x = 160; d->max_y = 200;
812 d->graphics_mode = GRAPHICS_MODE_4BIT;
813 d->bits_per_pixel = 4;
814 d->pixel_repx = 4 * machine->x11_scaleup;
815 d->pixel_repy = 2 * machine->x11_scaleup;
816 break;
817 case 0x09:
818 case 0x0d:
819 d->cur_mode = MODE_GRAPHICS;
820 d->max_x = 320; d->max_y = 200;
821 d->graphics_mode = GRAPHICS_MODE_4BIT;
822 d->bits_per_pixel = 4;
823 d->pixel_repx = d->pixel_repy =
824 2 * machine->x11_scaleup;
825 break;
826 case 0x0e:
827 d->cur_mode = MODE_GRAPHICS;
828 d->max_x = 640; d->max_y = 200;
829 d->graphics_mode = GRAPHICS_MODE_4BIT;
830 d->bits_per_pixel = 4;
831 d->pixel_repx = machine->x11_scaleup;
832 d->pixel_repy = machine->x11_scaleup * 2;
833 break;
834 case 0x10:
835 d->cur_mode = MODE_GRAPHICS;
836 d->max_x = 640; d->max_y = 350;
837 d->graphics_mode = GRAPHICS_MODE_4BIT;
838 d->bits_per_pixel = 4;
839 d->pixel_repx = d->pixel_repy = machine->x11_scaleup;
840 break;
841 case 0x12:
842 d->cur_mode = MODE_GRAPHICS;
843 d->max_x = 640; d->max_y = 480;
844 d->graphics_mode = GRAPHICS_MODE_4BIT;
845 d->bits_per_pixel = 4;
846 d->pixel_repx = d->pixel_repy = machine->x11_scaleup;
847 break;
848 case 0x13:
849 d->cur_mode = MODE_GRAPHICS;
850 d->max_x = 320; d->max_y = 200;
851 d->graphics_mode = GRAPHICS_MODE_8BIT;
852 d->bits_per_pixel = 8;
853 d->pixel_repx = d->pixel_repy =
854 2 * machine->x11_scaleup;
855 break;
856 default:
857 fatal("TODO! video mode change hack (mode 0x%02x)\n",
858 d->crtc_reg[0xff]);
859 exit(1);
860 }
861
862 if (d->cur_mode == MODE_CHARCELL) {
863 dev_fb_resize(d->fb, d->max_x * d->font_width *
864 d->pixel_repx, d->max_y * d->font_height *
865 d->pixel_repy);
866 d->fb_size = d->max_x * d->pixel_repx * d->font_width *
867 d->max_y * d->pixel_repy * d->font_height * 3;
868 } else {
869 dev_fb_resize(d->fb, d->max_x * d->pixel_repx,
870 d->max_y * d->pixel_repy);
871 d->fb_size = d->max_x * d->pixel_repx *
872 d->max_y * d->pixel_repy * 3;
873 }
874
875 for (i=0; i<machine->ncpus; i++)
876 machine->cpus[i]->invalidate_translation_caches(
877 machine->cpus[i], 0, INVALIDATE_ALL);
878
879 if (d->gfx_mem != NULL)
880 free(d->gfx_mem);
881 d->gfx_mem_size = 1;
882 if (d->cur_mode == MODE_GRAPHICS)
883 d->gfx_mem_size = d->max_x * d->max_y /
884 (d->graphics_mode == GRAPHICS_MODE_8BIT? 1 : 2);
885 d->gfx_mem = malloc(d->gfx_mem_size);
886
887 /* Clear screen and reset the palette: */
888 memset(d->charcells_outputed, 0, d->charcells_size);
889 memset(d->charcells_drawn, 0, d->charcells_size);
890 memset(d->gfx_mem, 0, d->gfx_mem_size);
891 d->update_x1 = 0;
892 d->update_x2 = d->max_x - 1;
893 d->update_y1 = 0;
894 d->update_y2 = d->max_y - 1;
895 d->modified = 1;
896 reset_palette(d, grayscale);
897 register_reset(d);
898 break;
899 default:fatal("[ vga_crtc_reg_write: regnr=0x%02x idata=0x%02x ]\n",
900 regnr, idata);
901 }
902 }
903
904
905 /*
906 * vga_sequencer_reg_write():
907 *
908 * Writes to VGA Sequencer registers.
909 */
910 static void vga_sequencer_reg_write(struct machine *machine, struct vga_data *d,
911 int regnr, int idata)
912 {
913 switch (regnr) {
914 case VGA_SEQ_RESET:
915 case VGA_SEQ_MAP_MASK:
916 case VGA_SEQ_SEQUENCER_MEMORY_MODE:
917 debug("[ vga_sequencer_reg_write: select %i: TODO ]\n", regnr);
918 break;
919 default:fatal("[ vga_sequencer_reg_write: select %i ]\n", regnr);
920 /* cpu->running = 0; */
921 }
922 }
923
924
925 /*
926 * vga_graphcontr_reg_write():
927 *
928 * Writes to VGA Graphics Controller registers.
929 */
930 static void vga_graphcontr_reg_write(struct machine *machine,
931 struct vga_data *d, int regnr, int idata)
932 {
933 switch (regnr) {
934 case VGA_GRAPHCONTR_READMAPSELECT:
935 case VGA_GRAPHCONTR_GRAPHICSMODE:
936 case VGA_GRAPHCONTR_MISC:
937 case VGA_GRAPHCONTR_MASK:
938 debug("[ vga_graphcontr_reg_write: select %i: TODO ]\n", regnr);
939 break;
940 default:fatal("[ vga_graphcontr_reg_write: select %i ]\n", regnr);
941 /* cpu->running = 0; */
942 }
943 }
944
945
946 /*
947 * vga_attribute_reg_write():
948 *
949 * Writes to VGA Attribute registers.
950 */
951 static void vga_attribute_reg_write(struct machine *machine, struct vga_data *d,
952 int regnr, int idata)
953 {
954 /* 0-15 are palette registers: TODO */
955 if (regnr >= 0 && regnr <= 0xf)
956 return;
957
958 switch (regnr) {
959 default:fatal("[ vga_attribute_reg_write: select %i ]\n", regnr);
960 /* cpu->running = 0; */
961 }
962 }
963
964
965 /*
966 * dev_vga_ctrl_access():
967 *
968 * Reads and writes of the VGA control registers.
969 */
970 DEVICE_ACCESS(vga_ctrl)
971 {
972 struct vga_data *d = extra;
973 size_t i;
974 uint64_t idata = 0, odata = 0;
975
976 for (i=0; i<len; i++) {
977 idata = data[i];
978
979 /* 0x3C0 + relative_addr... */
980
981 switch (relative_addr) {
982
983 case VGA_ATTRIBUTE_ADDR: /* 0x00 */
984 switch (d->attribute_state) {
985 case 0: if (writeflag == MEM_READ)
986 odata = d->attribute_reg_select;
987 else {
988 d->attribute_reg_select = 1;
989 d->attribute_state = 1;
990 }
991 break;
992 case 1: d->attribute_state = 0;
993 d->attribute_reg[d->attribute_reg_select] =
994 idata;
995 vga_attribute_reg_write(cpu->machine, d,
996 d->attribute_reg_select, idata);
997 break;
998 }
999 break;
1000 case VGA_ATTRIBUTE_DATA_READ: /* 0x01 */
1001 if (writeflag == MEM_WRITE)
1002 fatal("[ dev_vga: WARNING: Write to "
1003 "VGA_ATTRIBUTE_DATA_READ? ]\n");
1004 else {
1005 if (d->attribute_state == 0)
1006 fatal("[ dev_vga: WARNING: Read from "
1007 "VGA_ATTRIBUTE_DATA_READ, but no"
1008 " register selected? ]\n");
1009 else
1010 odata = d->attribute_reg[
1011 d->attribute_reg_select];
1012 }
1013 break;
1014
1015 case VGA_MISC_OUTPUT_W: /* 0x02 */
1016 if (writeflag == MEM_WRITE)
1017 d->misc_output_reg = idata;
1018 else {
1019 /* Reads: Input Status 0 */
1020 odata = 0x00;
1021 }
1022 break;
1023
1024 case VGA_SEQUENCER_ADDR: /* 0x04 */
1025 if (writeflag == MEM_READ)
1026 odata = d->sequencer_reg_select;
1027 else
1028 d->sequencer_reg_select = idata;
1029 break;
1030 case VGA_SEQUENCER_DATA: /* 0x05 */
1031 if (writeflag == MEM_READ)
1032 odata = d->sequencer_reg[
1033 d->sequencer_reg_select];
1034 else {
1035 d->sequencer_reg[d->
1036 sequencer_reg_select] = idata;
1037 vga_sequencer_reg_write(cpu->machine, d,
1038 d->sequencer_reg_select, idata);
1039 }
1040 break;
1041
1042 case VGA_DAC_ADDR_READ: /* 0x07 */
1043 if (writeflag == MEM_WRITE) {
1044 d->palette_read_index = idata;
1045 d->palette_read_subindex = 0;
1046 } else {
1047 debug("[ dev_vga: WARNING: Read from "
1048 "VGA_DAC_ADDR_READ? TODO ]\n");
1049 /* TODO */
1050 }
1051 break;
1052 case VGA_DAC_ADDR_WRITE: /* 0x08 */
1053 if (writeflag == MEM_WRITE) {
1054 d->palette_write_index = idata;
1055 d->palette_write_subindex = 0;
1056
1057 /* TODO: Is this correct? */
1058 d->palette_read_index = idata;
1059 d->palette_read_subindex = 0;
1060 } else {
1061 fatal("[ dev_vga: WARNING: Read from "
1062 "VGA_DAC_ADDR_WRITE? ]\n");
1063 odata = d->palette_write_index;
1064 }
1065 break;
1066 case VGA_DAC_DATA: /* 0x09 */
1067 if (writeflag == MEM_WRITE) {
1068 int new = (idata & 63) << 2;
1069 int old = d->fb->rgb_palette[d->
1070 palette_write_index*3+d->
1071 palette_write_subindex];
1072 d->fb->rgb_palette[d->palette_write_index * 3 +
1073 d->palette_write_subindex] = new;
1074 /* Redraw whole screen, if the
1075 palette changed: */
1076 if (new != old) {
1077 d->modified = 1;
1078 d->palette_modified = 1;
1079 d->update_x1 = d->update_y1 = 0;
1080 d->update_x2 = d->max_x - 1;
1081 d->update_y2 = d->max_y - 1;
1082 }
1083 d->palette_write_subindex ++;
1084 if (d->palette_write_subindex == 3) {
1085 d->palette_write_index ++;
1086 d->palette_write_subindex = 0;
1087 }
1088 } else {
1089 odata = (d->fb->rgb_palette[d->
1090 palette_read_index * 3 +
1091 d->palette_read_subindex] >> 2) & 63;
1092 d->palette_read_subindex ++;
1093 if (d->palette_read_subindex == 3) {
1094 d->palette_read_index ++;
1095 d->palette_read_subindex = 0;
1096 }
1097 }
1098 break;
1099
1100 case VGA_MISC_OUTPUT_R:
1101 odata = d->misc_output_reg;
1102 break;
1103
1104 case VGA_GRAPHCONTR_ADDR: /* 0x0e */
1105 if (writeflag == MEM_READ)
1106 odata = d->graphcontr_reg_select;
1107 else
1108 d->graphcontr_reg_select = idata;
1109 break;
1110 case VGA_GRAPHCONTR_DATA: /* 0x0f */
1111 if (writeflag == MEM_READ)
1112 odata = d->graphcontr_reg[
1113 d->graphcontr_reg_select];
1114 else {
1115 d->graphcontr_reg[d->
1116 graphcontr_reg_select] = idata;
1117 vga_graphcontr_reg_write(cpu->machine, d,
1118 d->graphcontr_reg_select, idata);
1119 }
1120 break;
1121
1122 case VGA_CRTC_ADDR: /* 0x14 */
1123 if (writeflag == MEM_READ)
1124 odata = d->crtc_reg_select;
1125 else
1126 d->crtc_reg_select = idata;
1127 break;
1128 case VGA_CRTC_DATA: /* 0x15 */
1129 if (writeflag == MEM_READ)
1130 odata = d->crtc_reg[d->crtc_reg_select];
1131 else {
1132 d->crtc_reg[d->crtc_reg_select] = idata;
1133 vga_crtc_reg_write(cpu->machine, d,
1134 d->crtc_reg_select, idata);
1135 }
1136 break;
1137
1138 case VGA_INPUT_STATUS_1: /* 0x1A */
1139 odata = 0;
1140 d->n_is1_reads ++;
1141 d->current_retrace_line ++;
1142 d->current_retrace_line %= (MAX_RETRACE_SCANLINES * 8);
1143 /* Whenever we are "inside" a scan line, copy the
1144 current palette into retrace_palette[][]: */
1145 if ((d->current_retrace_line & 7) == 7) {
1146 if (d->retrace_palette == NULL &&
1147 d->n_is1_reads > N_IS1_READ_THRESHOLD) {
1148 d->retrace_palette = malloc(
1149 MAX_RETRACE_SCANLINES * 256*3);
1150 if (d->retrace_palette == NULL) {
1151 fatal("out of memory\n");
1152 exit(1);
1153 }
1154 }
1155 if (d->retrace_palette != NULL)
1156 memcpy(d->retrace_palette + (d->
1157 current_retrace_line >> 3) * 256*3,
1158 d->fb->rgb_palette, d->cur_mode ==
1159 MODE_CHARCELL? (16*3) : (256*3));
1160 }
1161 /* These need to go on and off, to fake the
1162 real vertical and horizontal retrace info. */
1163 if (d->current_retrace_line < 20*8)
1164 odata |= VGA_IS1_DISPLAY_VRETRACE;
1165 else {
1166 if ((d->current_retrace_line & 7) == 0)
1167 odata = VGA_IS1_DISPLAY_DISPLAY_DISABLE;
1168 }
1169 break;
1170
1171 default:
1172 if (writeflag==MEM_READ) {
1173 debug("[ vga_ctrl: read from 0x%08lx ]\n",
1174 (long)relative_addr);
1175 } else {
1176 debug("[ vga_ctrl: write to 0x%08lx: 0x%08x"
1177 " ]\n", (long)relative_addr, (int)idata);
1178 }
1179 }
1180
1181 if (writeflag == MEM_READ)
1182 data[i] = odata;
1183
1184 /* For multi-byte accesses: */
1185 relative_addr ++;
1186 }
1187
1188 return 1;
1189 }
1190
1191
1192 /*
1193 * dev_vga_init():
1194 *
1195 * Register a VGA text console device. max_x and max_y could be something
1196 * like 80 and 25, respectively.
1197 */
1198 void dev_vga_init(struct machine *machine, struct memory *mem,
1199 uint64_t videomem_base, uint64_t control_base, char *name)
1200 {
1201 struct vga_data *d;
1202 size_t i;
1203 size_t allocsize;
1204
1205 d = malloc(sizeof(struct vga_data));
1206 if (d == NULL) {
1207 fprintf(stderr, "out of memory\n");
1208 exit(1);
1209 }
1210 memset(d, 0, sizeof(struct vga_data));
1211
1212 d->console_handle = console_start_slave(machine, "vga",
1213 CONSOLE_OUTPUT_ONLY);
1214
1215 d->videomem_base = videomem_base;
1216 d->control_base = control_base;
1217 d->max_x = 80;
1218 d->max_y = 25;
1219 d->cur_mode = MODE_CHARCELL;
1220 d->crtc_reg[0xff] = 0x03;
1221 d->charcells_size = 0x8000;
1222 d->gfx_mem_size = 1; /* Nothing, as we start in text mode */
1223 d->pixel_repx = d->pixel_repy = machine->x11_scaleup;
1224
1225 /* Allocate in full pages, to make it possible to use dyntrans: */
1226 allocsize = ((d->charcells_size-1) | (machine->arch_pagesize-1)) + 1;
1227 d->charcells = malloc(d->charcells_size);
1228 d->charcells_outputed = malloc(d->charcells_size);
1229 d->charcells_drawn = malloc(d->charcells_size);
1230 d->gfx_mem = malloc(d->gfx_mem_size);
1231 if (d->charcells == NULL || d->charcells_outputed == NULL ||
1232 d->charcells_drawn == NULL || d->gfx_mem == NULL) {
1233 fprintf(stderr, "out of memory in dev_vga_init()\n");
1234 exit(1);
1235 }
1236
1237 memset(d->charcells_drawn, 0, d->charcells_size);
1238
1239 for (i=0; i<d->charcells_size; i+=2) {
1240 d->charcells[i] = ' ';
1241 d->charcells[i+1] = 0x07; /* Default color */
1242 d->charcells_drawn[i] = ' ';
1243 d->charcells_drawn[i+1] = 0x07;
1244 }
1245
1246 memset(d->charcells_outputed, 0, d->charcells_size);
1247 memset(d->gfx_mem, 0, d->gfx_mem_size);
1248
1249 d->font = font8x16;
1250 d->font_width = 8;
1251 d->font_height = 16;
1252
1253 d->fb_max_x = d->pixel_repx * d->max_x;
1254 d->fb_max_y = d->pixel_repy * d->max_y;
1255 if (d->cur_mode == MODE_CHARCELL) {
1256 d->fb_max_x *= d->font_width;
1257 d->fb_max_y *= d->font_height;
1258 }
1259
1260 memory_device_register(mem, "vga_charcells", videomem_base + 0x18000,
1261 allocsize, dev_vga_access, d, DM_DYNTRANS_OK |
1262 DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS,
1263 d->charcells);
1264 memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW,
1265 dev_vga_graphics_access, d, DM_DEFAULT |
1266 DM_READS_HAVE_NO_SIDE_EFFECTS, d->gfx_mem);
1267 memory_device_register(mem, "vga_ctrl", control_base,
1268 32, dev_vga_ctrl_access, d, DM_DEFAULT, NULL);
1269
1270 d->fb = dev_fb_init(machine, mem, VGA_FB_ADDR, VFB_GENERIC,
1271 d->fb_max_x, d->fb_max_y, d->fb_max_x, d->fb_max_y, 24, "VGA");
1272 d->fb_size = d->fb_max_x * d->fb_max_y * 3;
1273
1274 reset_palette(d, 0);
1275
1276 /* This will force an initial redraw/resynch: */
1277 d->update_x1 = 0;
1278 d->update_x2 = d->max_x - 1;
1279 d->update_y1 = 0;
1280 d->update_y2 = d->max_y - 1;
1281 d->modified = 1;
1282
1283 machine_add_tickfunction(machine, dev_vga_tick, d,
1284 VGA_TICK_SHIFT, 0.0);
1285
1286 register_reset(d);
1287
1288 vga_update_cursor(machine, d);
1289 }
1290

  ViewVC Help
Powered by ViewVC 1.1.26