/[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 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33896 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26