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