/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33963 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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.95 2006/01/01 13:17:18 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 * font_width, MEM_WRITE, d->fb);
471 }
472 }
473 }
474 }
475
476
477 /*
478 * vga_update_cursor():
479 */
480 static void vga_update_cursor(struct machine *machine, struct vga_data *d)
481 {
482 int onoff = 1, height = d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END]
483 - d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] + 1;
484
485 if (d->cur_mode != MODE_CHARCELL)
486 onoff = 0;
487
488 if (d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] >
489 d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END]) {
490 onoff = 0;
491 height = 1;
492 }
493
494 if (d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] >= d->font_height)
495 onoff = 0;
496
497 dev_fb_setcursor(d->fb,
498 d->cursor_x * d->font_width * d->pixel_repx, (d->cursor_y *
499 d->font_height + d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START]) *
500 d->pixel_repy, onoff, d->font_width * d->pixel_repx, height *
501 d->pixel_repy);
502 }
503
504
505 /*
506 * dev_vga_tick():
507 */
508 void dev_vga_tick(struct cpu *cpu, void *extra)
509 {
510 struct vga_data *d = extra;
511 int64_t low = -1, high;
512
513 vga_update_cursor(cpu->machine, d);
514
515 /* TODO: text vs graphics tick? */
516 memory_device_dyntrans_access(cpu, cpu->mem, extra,
517 (uint64_t *) &low, (uint64_t *) &high);
518
519 if (low != -1) {
520 int base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
521 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
522 int new_u_y1, new_u_y2;
523 debug("[ dev_vga_tick: dyntrans access, %llx .. %llx ]\n",
524 (long long)low, (long long)high);
525 low -= base;
526 high -= base;
527 d->update_x1 = 0;
528 d->update_x2 = d->max_x - 1;
529 new_u_y1 = (low/2) / d->max_x;
530 new_u_y2 = ((high/2) / d->max_x) + 1;
531 if (new_u_y1 < d->update_y1)
532 d->update_y1 = new_u_y1;
533 if (new_u_y2 > d->update_y2)
534 d->update_y2 = new_u_y2;
535 if (d->update_y1 < 0)
536 d->update_y1 = 0;
537 if (d->update_y2 >= d->max_y)
538 d->update_y2 = d->max_y - 1;
539 d->modified = 1;
540 }
541
542 if (d->n_is1_reads > N_IS1_READ_THRESHOLD &&
543 d->retrace_palette != NULL) {
544 d->use_palette_per_line = 1;
545 d->update_x1 = 0;
546 d->update_x2 = d->max_x - 1;
547 d->update_y1 = 0;
548 d->update_y2 = d->max_y - 1;
549 d->modified = 1;
550 } else {
551 if (d->use_palette_per_line) {
552 d->use_palette_per_line = 0;
553 d->update_x1 = 0;
554 d->update_x2 = d->max_x - 1;
555 d->update_y1 = 0;
556 d->update_y2 = d->max_y - 1;
557 d->modified = 1;
558 }
559 }
560
561 if (!cpu->machine->use_x11) {
562 /* NOTE: 2 > 0, so this only updates the cursor, no
563 character cells. */
564 vga_update_textmode(cpu->machine, d, 0, 2, 0);
565 }
566
567 if (d->modified) {
568 if (d->cur_mode == MODE_CHARCELL)
569 vga_update_text(cpu->machine, d, d->update_x1,
570 d->update_y1, d->update_x2, d->update_y2);
571 else
572 vga_update_graphics(cpu->machine, d, d->update_x1,
573 d->update_y1, d->update_x2, d->update_y2);
574
575 d->palette_modified = 0;
576 d->modified = 0;
577 d->update_x1 = 999999;
578 d->update_x2 = -1;
579 d->update_y1 = 999999;
580 d->update_y2 = -1;
581 }
582
583 if (d->n_is1_reads > N_IS1_READ_THRESHOLD)
584 d->n_is1_reads = 0;
585 }
586
587
588 /*
589 * vga_graphics_access():
590 *
591 * Reads and writes to the VGA video memory (pixels).
592 */
593 DEVICE_ACCESS(vga_graphics)
594 {
595 struct vga_data *d = extra;
596 int j, x=0, y=0, x2=0, y2=0, modified = 0;
597 size_t i;
598
599 if (relative_addr + len >= GFX_ADDR_WINDOW)
600 return 0;
601
602 if (d->cur_mode != MODE_GRAPHICS)
603 return 1;
604
605 switch (d->graphics_mode) {
606 case GRAPHICS_MODE_8BIT:
607 y = relative_addr / d->max_x;
608 x = relative_addr % d->max_x;
609 y2 = (relative_addr+len-1) / d->max_x;
610 x2 = (relative_addr+len-1) % d->max_x;
611
612 if (writeflag == MEM_WRITE) {
613 memcpy(d->gfx_mem + relative_addr, data, len);
614 modified = 1;
615 } else
616 memcpy(data, d->gfx_mem + relative_addr, len);
617 break;
618 case GRAPHICS_MODE_4BIT:
619 y = relative_addr * 8 / d->max_x;
620 x = relative_addr * 8 % d->max_x;
621 y2 = ((relative_addr+len)*8-1) / d->max_x;
622 x2 = ((relative_addr+len)*8-1) % d->max_x;
623 /* TODO: color stuff */
624
625 /* Read/write d->gfx_mem in 4-bit color: */
626 if (writeflag == MEM_WRITE) {
627 /* i is byte index to write, j is bit index */
628 for (i=0; i<len; i++)
629 for (j=0; j<8; j++) {
630 int pixelmask = 1 << (7-j);
631 int b = data[i] & pixelmask;
632 int m = d->sequencer_reg[
633 VGA_SEQ_MAP_MASK] & 0x0f;
634 uint32_t addr = (y * d->max_x + x +
635 i*8 + j) * d->bits_per_pixel / 8;
636 unsigned char byte;
637 if (!(d->graphcontr_reg[
638 VGA_GRAPHCONTR_MASK] & pixelmask))
639 continue;
640 if (addr >= d->gfx_mem_size)
641 continue;
642 byte = d->gfx_mem[addr];
643 if (b && j&1)
644 byte |= m << 4;
645 if (b && !(j&1))
646 byte |= m;
647 if (!b && j&1)
648 byte &= ~(m << 4);
649 if (!b && !(j&1))
650 byte &= ~m;
651 d->gfx_mem[addr] = byte;
652 }
653 modified = 1;
654 } else {
655 fatal("TODO: 4 bit graphics read, mask=0x%02x\n",
656 d->sequencer_reg[VGA_SEQ_MAP_MASK]);
657 for (i=0; i<len; i++)
658 data[i] = random();
659 }
660 break;
661 default:fatal("dev_vga: Unimplemented graphics mode %i\n",
662 d->graphics_mode);
663 cpu->running = 0;
664 }
665
666 if (modified) {
667 d->modified = 1;
668 if (x < d->update_x1) d->update_x1 = x;
669 if (x > d->update_x2) d->update_x2 = x;
670 if (y < d->update_y1) d->update_y1 = y;
671 if (y > d->update_y2) d->update_y2 = y;
672 if (x2 < d->update_x1) d->update_x1 = x2;
673 if (x2 > d->update_x2) d->update_x2 = x2;
674 if (y2 < d->update_y1) d->update_y1 = y2;
675 if (y2 > d->update_y2) d->update_y2 = y2;
676 if (y != y2) {
677 d->update_x1 = 0;
678 d->update_x2 = d->max_x - 1;
679 }
680 }
681 return 1;
682 }
683
684
685 /*
686 * dev_vga_access():
687 *
688 * Reads and writes to the VGA video memory (charcells).
689 */
690 DEVICE_ACCESS(vga)
691 {
692 struct vga_data *d = extra;
693 uint64_t idata = 0, odata = 0;
694 int x, y, x2, y2, r, base;
695 size_t i;
696
697 if (writeflag == MEM_WRITE)
698 idata = memory_readmax64(cpu, data, len);
699
700 base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
701 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
702 r = relative_addr - base;
703 y = r / (d->max_x * 2);
704 x = (r/2) % d->max_x;
705 y2 = (r+len-1) / (d->max_x * 2);
706 x2 = ((r+len-1)/2) % d->max_x;
707
708 if (relative_addr + len - 1 < d->charcells_size) {
709 if (writeflag == MEM_WRITE) {
710 for (i=0; i<len; i++) {
711 int old = d->charcells[relative_addr + i];
712 if (old != data[i]) {
713 d->charcells[relative_addr + i] =
714 data[i];
715 d->modified = 1;
716 }
717 }
718
719 if (d->modified) {
720 if (x < d->update_x1) d->update_x1 = x;
721 if (x > d->update_x2) d->update_x2 = x;
722 if (y < d->update_y1) d->update_y1 = y;
723 if (y > d->update_y2) d->update_y2 = y;
724 if (x2 < d->update_x1) d->update_x1 = x2;
725 if (x2 > d->update_x2) d->update_x2 = x2;
726 if (y2 < d->update_y1) d->update_y1 = y2;
727 if (y2 > d->update_y2) d->update_y2 = y2;
728
729 if (y != y2) {
730 d->update_x1 = 0;
731 d->update_x2 = d->max_x - 1;
732 }
733 }
734 } else
735 memcpy(data, d->charcells + relative_addr, len);
736 return 1;
737 }
738
739 switch (relative_addr) {
740 default:
741 if (writeflag==MEM_READ) {
742 debug("[ vga: read from 0x%08lx ]\n",
743 (long)relative_addr);
744 } else {
745 debug("[ vga: write to 0x%08lx: 0x%08x ]\n",
746 (long)relative_addr, idata);
747 }
748 }
749
750 if (writeflag == MEM_READ)
751 memory_writemax64(cpu, data, len, odata);
752
753 return 1;
754 }
755
756
757 /*
758 * vga_crtc_reg_write():
759 *
760 * Writes to VGA CRTC registers.
761 */
762 static void vga_crtc_reg_write(struct machine *machine, struct vga_data *d,
763 int regnr, int idata)
764 {
765 int grayscale;
766
767 switch (regnr) {
768 case VGA_CRTC_CURSOR_SCANLINE_START: /* 0x0a */
769 case VGA_CRTC_CURSOR_SCANLINE_END: /* 0x0b */
770 break;
771 case VGA_CRTC_START_ADDR_HIGH: /* 0x0c */
772 case VGA_CRTC_START_ADDR_LOW: /* 0x0d */
773 d->update_x1 = 0;
774 d->update_x2 = d->max_x - 1;
775 d->update_y1 = 0;
776 d->update_y2 = d->max_y - 1;
777 d->modified = 1;
778 recalc_cursor_position(d);
779 break;
780 case VGA_CRTC_CURSOR_LOCATION_HIGH: /* 0x0e */
781 case VGA_CRTC_CURSOR_LOCATION_LOW: /* 0x0f */
782 recalc_cursor_position(d);
783 break;
784 case 0xff:
785 grayscale = 0;
786 switch (d->crtc_reg[0xff]) {
787 case 0x00:
788 grayscale = 1;
789 case 0x01:
790 d->cur_mode = MODE_CHARCELL;
791 d->max_x = 40; d->max_y = 25;
792 d->pixel_repx = machine->x11_scaleup * 2;
793 d->pixel_repy = machine->x11_scaleup;
794 d->font_width = 8;
795 d->font_height = 16;
796 d->font = font8x16;
797 break;
798 case 0x02:
799 grayscale = 1;
800 case 0x03:
801 d->cur_mode = MODE_CHARCELL;
802 d->max_x = 80; d->max_y = 25;
803 d->pixel_repx = d->pixel_repy = machine->x11_scaleup;
804 d->font_width = 8;
805 d->font_height = 16;
806 d->font = font8x16;
807 break;
808 case 0x08:
809 d->cur_mode = MODE_GRAPHICS;
810 d->max_x = 160; d->max_y = 200;
811 d->graphics_mode = GRAPHICS_MODE_4BIT;
812 d->bits_per_pixel = 4;
813 d->pixel_repx = 4 * machine->x11_scaleup;
814 d->pixel_repy = 2 * machine->x11_scaleup;
815 break;
816 case 0x09:
817 case 0x0d:
818 d->cur_mode = MODE_GRAPHICS;
819 d->max_x = 320; d->max_y = 200;
820 d->graphics_mode = GRAPHICS_MODE_4BIT;
821 d->bits_per_pixel = 4;
822 d->pixel_repx = d->pixel_repy =
823 2 * machine->x11_scaleup;
824 break;
825 case 0x0e:
826 d->cur_mode = MODE_GRAPHICS;
827 d->max_x = 640; d->max_y = 200;
828 d->graphics_mode = GRAPHICS_MODE_4BIT;
829 d->bits_per_pixel = 4;
830 d->pixel_repx = machine->x11_scaleup;
831 d->pixel_repy = machine->x11_scaleup * 2;
832 break;
833 case 0x10:
834 d->cur_mode = MODE_GRAPHICS;
835 d->max_x = 640; d->max_y = 350;
836 d->graphics_mode = GRAPHICS_MODE_4BIT;
837 d->bits_per_pixel = 4;
838 d->pixel_repx = d->pixel_repy = machine->x11_scaleup;
839 break;
840 case 0x12:
841 d->cur_mode = MODE_GRAPHICS;
842 d->max_x = 640; d->max_y = 480;
843 d->graphics_mode = GRAPHICS_MODE_4BIT;
844 d->bits_per_pixel = 4;
845 d->pixel_repx = d->pixel_repy = machine->x11_scaleup;
846 break;
847 case 0x13:
848 d->cur_mode = MODE_GRAPHICS;
849 d->max_x = 320; d->max_y = 200;
850 d->graphics_mode = GRAPHICS_MODE_8BIT;
851 d->bits_per_pixel = 8;
852 d->pixel_repx = d->pixel_repy =
853 2 * machine->x11_scaleup;
854 break;
855 default:
856 fatal("TODO! video mode change hack (mode 0x%02x)\n",
857 d->crtc_reg[0xff]);
858 exit(1);
859 }
860
861 if (d->cur_mode == MODE_CHARCELL) {
862 dev_fb_resize(d->fb, d->max_x * d->font_width *
863 d->pixel_repx, d->max_y * d->font_height *
864 d->pixel_repy);
865 d->fb_size = d->max_x * d->pixel_repx * d->font_width *
866 d->max_y * d->pixel_repy * d->font_height * 3;
867 } else {
868 dev_fb_resize(d->fb, d->max_x * d->pixel_repx,
869 d->max_y * d->pixel_repy);
870 d->fb_size = d->max_x * d->pixel_repx *
871 d->max_y * d->pixel_repy * 3;
872 }
873
874 if (d->gfx_mem != NULL)
875 free(d->gfx_mem);
876 d->gfx_mem_size = 1;
877 if (d->cur_mode == MODE_GRAPHICS)
878 d->gfx_mem_size = d->max_x * d->max_y /
879 (d->graphics_mode == GRAPHICS_MODE_8BIT? 1 : 2);
880 d->gfx_mem = malloc(d->gfx_mem_size);
881
882 /* Clear screen and reset the palette: */
883 memset(d->charcells_outputed, 0, d->charcells_size);
884 memset(d->charcells_drawn, 0, d->charcells_size);
885 memset(d->gfx_mem, 0, d->gfx_mem_size);
886 d->update_x1 = 0;
887 d->update_x2 = d->max_x - 1;
888 d->update_y1 = 0;
889 d->update_y2 = d->max_y - 1;
890 d->modified = 1;
891 reset_palette(d, grayscale);
892 register_reset(d);
893 break;
894 default:fatal("[ vga_crtc_reg_write: regnr=0x%02x idata=0x%02x ]\n",
895 regnr, idata);
896 }
897 }
898
899
900 /*
901 * vga_sequencer_reg_write():
902 *
903 * Writes to VGA Sequencer registers.
904 */
905 static void vga_sequencer_reg_write(struct machine *machine, struct vga_data *d,
906 int regnr, int idata)
907 {
908 switch (regnr) {
909 case VGA_SEQ_RESET:
910 case VGA_SEQ_MAP_MASK:
911 case VGA_SEQ_SEQUENCER_MEMORY_MODE:
912 debug("[ vga_sequencer_reg_write: select %i: TODO ]\n", regnr);
913 break;
914 default:fatal("[ vga_sequencer_reg_write: select %i ]\n", regnr);
915 /* cpu->running = 0; */
916 }
917 }
918
919
920 /*
921 * vga_graphcontr_reg_write():
922 *
923 * Writes to VGA Graphics Controller registers.
924 */
925 static void vga_graphcontr_reg_write(struct machine *machine,
926 struct vga_data *d, int regnr, int idata)
927 {
928 switch (regnr) {
929 case VGA_GRAPHCONTR_READMAPSELECT:
930 case VGA_GRAPHCONTR_GRAPHICSMODE:
931 case VGA_GRAPHCONTR_MISC:
932 case VGA_GRAPHCONTR_MASK:
933 debug("[ vga_graphcontr_reg_write: select %i: TODO ]\n", regnr);
934 break;
935 default:fatal("[ vga_graphcontr_reg_write: select %i ]\n", regnr);
936 /* cpu->running = 0; */
937 }
938 }
939
940
941 /*
942 * vga_attribute_reg_write():
943 *
944 * Writes to VGA Attribute registers.
945 */
946 static void vga_attribute_reg_write(struct machine *machine, struct vga_data *d,
947 int regnr, int idata)
948 {
949 /* 0-15 are palette registers: TODO */
950 if (regnr >= 0 && regnr <= 0xf)
951 return;
952
953 switch (regnr) {
954 default:fatal("[ vga_attribute_reg_write: select %i ]\n", regnr);
955 /* cpu->running = 0; */
956 }
957 }
958
959
960 /*
961 * dev_vga_ctrl_access():
962 *
963 * Reads and writes of the VGA control registers.
964 */
965 DEVICE_ACCESS(vga_ctrl)
966 {
967 struct vga_data *d = extra;
968 size_t i;
969 uint64_t idata = 0, odata = 0;
970
971 for (i=0; i<len; i++) {
972 idata = data[i];
973
974 /* 0x3C0 + relative_addr... */
975
976 switch (relative_addr) {
977
978 case VGA_ATTRIBUTE_ADDR: /* 0x00 */
979 switch (d->attribute_state) {
980 case 0: if (writeflag == MEM_READ)
981 odata = d->attribute_reg_select;
982 else {
983 d->attribute_reg_select = 1;
984 d->attribute_state = 1;
985 }
986 break;
987 case 1: d->attribute_state = 0;
988 d->attribute_reg[d->attribute_reg_select] =
989 idata;
990 vga_attribute_reg_write(cpu->machine, d,
991 d->attribute_reg_select, idata);
992 break;
993 }
994 break;
995 case VGA_ATTRIBUTE_DATA_READ: /* 0x01 */
996 if (writeflag == MEM_WRITE)
997 fatal("[ dev_vga: WARNING: Write to "
998 "VGA_ATTRIBUTE_DATA_READ? ]\n");
999 else {
1000 if (d->attribute_state == 0)
1001 fatal("[ dev_vga: WARNING: Read from "
1002 "VGA_ATTRIBUTE_DATA_READ, but no"
1003 " register selected? ]\n");
1004 else
1005 odata = d->attribute_reg[
1006 d->attribute_reg_select];
1007 }
1008 break;
1009
1010 case VGA_MISC_OUTPUT_W: /* 0x02 */
1011 if (writeflag == MEM_WRITE)
1012 d->misc_output_reg = idata;
1013 else {
1014 /* Reads: Input Status 0 */
1015 odata = 0x00;
1016 }
1017 break;
1018
1019 case VGA_SEQUENCER_ADDR: /* 0x04 */
1020 if (writeflag == MEM_READ)
1021 odata = d->sequencer_reg_select;
1022 else
1023 d->sequencer_reg_select = idata;
1024 break;
1025 case VGA_SEQUENCER_DATA: /* 0x05 */
1026 if (writeflag == MEM_READ)
1027 odata = d->sequencer_reg[
1028 d->sequencer_reg_select];
1029 else {
1030 d->sequencer_reg[d->
1031 sequencer_reg_select] = idata;
1032 vga_sequencer_reg_write(cpu->machine, d,
1033 d->sequencer_reg_select, idata);
1034 }
1035 break;
1036
1037 case VGA_DAC_ADDR_READ: /* 0x07 */
1038 if (writeflag == MEM_WRITE) {
1039 d->palette_read_index = idata;
1040 d->palette_read_subindex = 0;
1041 } else {
1042 debug("[ dev_vga: WARNING: Read from "
1043 "VGA_DAC_ADDR_READ? TODO ]\n");
1044 /* TODO */
1045 }
1046 break;
1047 case VGA_DAC_ADDR_WRITE: /* 0x08 */
1048 if (writeflag == MEM_WRITE) {
1049 d->palette_write_index = idata;
1050 d->palette_write_subindex = 0;
1051
1052 /* TODO: Is this correct? */
1053 d->palette_read_index = idata;
1054 d->palette_read_subindex = 0;
1055 } else {
1056 fatal("[ dev_vga: WARNING: Read from "
1057 "VGA_DAC_ADDR_WRITE? ]\n");
1058 odata = d->palette_write_index;
1059 }
1060 break;
1061 case VGA_DAC_DATA: /* 0x09 */
1062 if (writeflag == MEM_WRITE) {
1063 int new = (idata & 63) << 2;
1064 int old = d->fb->rgb_palette[d->
1065 palette_write_index*3+d->
1066 palette_write_subindex];
1067 d->fb->rgb_palette[d->palette_write_index * 3 +
1068 d->palette_write_subindex] = new;
1069 /* Redraw whole screen, if the
1070 palette changed: */
1071 if (new != old) {
1072 d->modified = 1;
1073 d->palette_modified = 1;
1074 d->update_x1 = d->update_y1 = 0;
1075 d->update_x2 = d->max_x - 1;
1076 d->update_y2 = d->max_y - 1;
1077 }
1078 d->palette_write_subindex ++;
1079 if (d->palette_write_subindex == 3) {
1080 d->palette_write_index ++;
1081 d->palette_write_subindex = 0;
1082 }
1083 } else {
1084 odata = (d->fb->rgb_palette[d->
1085 palette_read_index * 3 +
1086 d->palette_read_subindex] >> 2) & 63;
1087 d->palette_read_subindex ++;
1088 if (d->palette_read_subindex == 3) {
1089 d->palette_read_index ++;
1090 d->palette_read_subindex = 0;
1091 }
1092 }
1093 break;
1094
1095 case VGA_MISC_OUTPUT_R:
1096 odata = d->misc_output_reg;
1097 break;
1098
1099 case VGA_GRAPHCONTR_ADDR: /* 0x0e */
1100 if (writeflag == MEM_READ)
1101 odata = d->graphcontr_reg_select;
1102 else
1103 d->graphcontr_reg_select = idata;
1104 break;
1105 case VGA_GRAPHCONTR_DATA: /* 0x0f */
1106 if (writeflag == MEM_READ)
1107 odata = d->graphcontr_reg[
1108 d->graphcontr_reg_select];
1109 else {
1110 d->graphcontr_reg[d->
1111 graphcontr_reg_select] = idata;
1112 vga_graphcontr_reg_write(cpu->machine, d,
1113 d->graphcontr_reg_select, idata);
1114 }
1115 break;
1116
1117 case VGA_CRTC_ADDR: /* 0x14 */
1118 if (writeflag == MEM_READ)
1119 odata = d->crtc_reg_select;
1120 else
1121 d->crtc_reg_select = idata;
1122 break;
1123 case VGA_CRTC_DATA: /* 0x15 */
1124 if (writeflag == MEM_READ)
1125 odata = d->crtc_reg[d->crtc_reg_select];
1126 else {
1127 d->crtc_reg[d->crtc_reg_select] = idata;
1128 vga_crtc_reg_write(cpu->machine, d,
1129 d->crtc_reg_select, idata);
1130 }
1131 break;
1132
1133 case VGA_INPUT_STATUS_1: /* 0x1A */
1134 odata = 0;
1135 d->n_is1_reads ++;
1136 d->current_retrace_line ++;
1137 d->current_retrace_line %= (MAX_RETRACE_SCANLINES * 8);
1138 /* Whenever we are "inside" a scan line, copy the
1139 current palette into retrace_palette[][]: */
1140 if ((d->current_retrace_line & 7) == 7) {
1141 if (d->retrace_palette == NULL &&
1142 d->n_is1_reads > N_IS1_READ_THRESHOLD) {
1143 d->retrace_palette = malloc(
1144 MAX_RETRACE_SCANLINES * 256*3);
1145 if (d->retrace_palette == NULL) {
1146 fatal("out of memory\n");
1147 exit(1);
1148 }
1149 }
1150 if (d->retrace_palette != NULL)
1151 memcpy(d->retrace_palette + (d->
1152 current_retrace_line >> 3) * 256*3,
1153 d->fb->rgb_palette, d->cur_mode ==
1154 MODE_CHARCELL? (16*3) : (256*3));
1155 }
1156 /* These need to go on and off, to fake the
1157 real vertical and horizontal retrace info. */
1158 if (d->current_retrace_line < 20*8)
1159 odata |= VGA_IS1_DISPLAY_VRETRACE;
1160 else {
1161 if ((d->current_retrace_line & 7) == 0)
1162 odata = VGA_IS1_DISPLAY_DISPLAY_DISABLE;
1163 }
1164 break;
1165
1166 default:
1167 if (writeflag==MEM_READ) {
1168 debug("[ vga_ctrl: read from 0x%08lx ]\n",
1169 (long)relative_addr);
1170 } else {
1171 debug("[ vga_ctrl: write to 0x%08lx: 0x%08x"
1172 " ]\n", (long)relative_addr, (int)idata);
1173 }
1174 }
1175
1176 if (writeflag == MEM_READ)
1177 data[i] = odata;
1178
1179 /* For multi-byte accesses: */
1180 relative_addr ++;
1181 }
1182
1183 return 1;
1184 }
1185
1186
1187 /*
1188 * dev_vga_init():
1189 *
1190 * Register a VGA text console device. max_x and max_y could be something
1191 * like 80 and 25, respectively.
1192 */
1193 void dev_vga_init(struct machine *machine, struct memory *mem,
1194 uint64_t videomem_base, uint64_t control_base, char *name)
1195 {
1196 struct vga_data *d;
1197 size_t i;
1198 size_t allocsize;
1199
1200 d = malloc(sizeof(struct vga_data));
1201 if (d == NULL) {
1202 fprintf(stderr, "out of memory\n");
1203 exit(1);
1204 }
1205 memset(d, 0, sizeof(struct vga_data));
1206
1207 d->console_handle = console_start_slave(machine, "vga",
1208 CONSOLE_OUTPUT_ONLY);
1209
1210 d->videomem_base = videomem_base;
1211 d->control_base = control_base;
1212 d->max_x = 80;
1213 d->max_y = 25;
1214 d->cur_mode = MODE_CHARCELL;
1215 d->crtc_reg[0xff] = 0x03;
1216 d->charcells_size = 0x8000;
1217 d->gfx_mem_size = 1; /* Nothing, as we start in text mode */
1218 d->pixel_repx = d->pixel_repy = machine->x11_scaleup;
1219
1220 /* Allocate in full pages, to make it possible to use bintrans: */
1221 allocsize = ((d->charcells_size-1) | (machine->arch_pagesize-1)) + 1;
1222 d->charcells = malloc(d->charcells_size);
1223 d->charcells_outputed = malloc(d->charcells_size);
1224 d->charcells_drawn = malloc(d->charcells_size);
1225 d->gfx_mem = malloc(d->gfx_mem_size);
1226 if (d->charcells == NULL || d->charcells_outputed == NULL ||
1227 d->charcells_drawn == NULL || d->gfx_mem == NULL) {
1228 fprintf(stderr, "out of memory in dev_vga_init()\n");
1229 exit(1);
1230 }
1231
1232 memset(d->charcells_drawn, 0, d->charcells_size);
1233
1234 for (i=0; i<d->charcells_size; i+=2) {
1235 d->charcells[i] = ' ';
1236 d->charcells[i+1] = 0x07; /* Default color */
1237 d->charcells_drawn[i] = ' ';
1238 d->charcells_drawn[i+1] = 0x07;
1239 }
1240
1241 memset(d->charcells_outputed, 0, d->charcells_size);
1242 memset(d->gfx_mem, 0, d->gfx_mem_size);
1243
1244 d->font = font8x16;
1245 d->font_width = 8;
1246 d->font_height = 16;
1247
1248 d->fb_max_x = d->pixel_repx * d->max_x;
1249 d->fb_max_y = d->pixel_repy * d->max_y;
1250 if (d->cur_mode == MODE_CHARCELL) {
1251 d->fb_max_x *= d->font_width;
1252 d->fb_max_y *= d->font_height;
1253 }
1254
1255 memory_device_register(mem, "vga_charcells", videomem_base + 0x18000,
1256 allocsize, dev_vga_access, d, DM_DYNTRANS_OK |
1257 DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS,
1258 d->charcells);
1259 memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW,
1260 dev_vga_graphics_access, d, DM_DEFAULT |
1261 DM_READS_HAVE_NO_SIDE_EFFECTS, d->gfx_mem);
1262 memory_device_register(mem, "vga_ctrl", control_base,
1263 32, dev_vga_ctrl_access, d, DM_DEFAULT, NULL);
1264
1265 d->fb = dev_fb_init(machine, mem, VGA_FB_ADDR, VFB_GENERIC,
1266 d->fb_max_x, d->fb_max_y, d->fb_max_x, d->fb_max_y, 24, "VGA");
1267 d->fb_size = d->fb_max_x * d->fb_max_y * 3;
1268
1269 reset_palette(d, 0);
1270
1271 /* This will force an initial redraw/resynch: */
1272 d->update_x1 = 0;
1273 d->update_x2 = d->max_x - 1;
1274 d->update_y1 = 0;
1275 d->update_y2 = d->max_y - 1;
1276 d->modified = 1;
1277
1278 machine_add_tickfunction(machine, dev_vga_tick, d, VGA_TICK_SHIFT);
1279
1280 register_reset(d);
1281
1282 vga_update_cursor(machine, d);
1283 }
1284

  ViewVC Help
Powered by ViewVC 1.1.26