/[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 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 34152 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26