/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 33884 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26