/[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

Annotation of /trunk/src/devices/dev_vga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 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 dpavlin 4 /*
2 dpavlin 34 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 dpavlin 4 *
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 dpavlin 42 * $Id: dev_vga.c,v 1.104 2007/06/15 19:57:34 debug Exp $
29 dpavlin 4 *
30 dpavlin 42 * COMMENT: VGA framebuffer device (charcell and graphics modes)
31 dpavlin 4 *
32 dpavlin 6 * 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 dpavlin 4 */
35    
36     #include <stdio.h>
37     #include <stdlib.h>
38     #include <string.h>
39    
40 dpavlin 6 #include "console.h"
41 dpavlin 4 #include "cpu.h"
42     #include "devices.h"
43     #include "machine.h"
44     #include "memory.h"
45     #include "misc.h"
46    
47 dpavlin 6 #include "vga.h"
48    
49 dpavlin 4 /* 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 dpavlin 18 /* For videomem -> framebuffer updates: */
56 dpavlin 20 #define VGA_TICK_SHIFT 18
57 dpavlin 4
58 dpavlin 6 #define MAX_RETRACE_SCANLINES 420
59     #define N_IS1_READ_THRESHOLD 50
60    
61     #define GFX_ADDR_WINDOW 0x18000
62 dpavlin 4
63 dpavlin 6 #define VGA_FB_ADDR 0x1c00000000ULL
64 dpavlin 4
65 dpavlin 6 #define MODE_CHARCELL 1
66     #define MODE_GRAPHICS 2
67 dpavlin 4
68 dpavlin 6 #define GRAPHICS_MODE_8BIT 1
69     #define GRAPHICS_MODE_4BIT 2
70    
71 dpavlin 4 struct vga_data {
72     uint64_t videomem_base;
73     uint64_t control_base;
74    
75     struct vfb_data *fb;
76 dpavlin 22 uint32_t fb_size;
77 dpavlin 4
78 dpavlin 6 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 dpavlin 4 unsigned char *font;
93 dpavlin 6 size_t charcells_size;
94     unsigned char *charcells; /* 2 bytes per char */
95 dpavlin 18 unsigned char *charcells_outputed; /* text */
96     unsigned char *charcells_drawn; /* framebuffer */
97 dpavlin 4
98 dpavlin 6 /* Graphics: */
99     int graphics_mode;
100     int bits_per_pixel;
101     unsigned char *gfx_mem;
102 dpavlin 22 uint32_t gfx_mem_size;
103 dpavlin 4
104 dpavlin 6 /* Registers: */
105     int attribute_state; /* 0 or 1 */
106     unsigned char attribute_reg_select;
107     unsigned char attribute_reg[256];
108 dpavlin 4
109 dpavlin 6 unsigned char misc_output_reg;
110 dpavlin 4
111 dpavlin 6 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 dpavlin 4 int cursor_x;
137     int cursor_y;
138    
139     int modified;
140 dpavlin 22 int palette_modified;
141 dpavlin 4 int update_x1;
142     int update_y1;
143     int update_x2;
144     int update_y2;
145     };
146    
147    
148     /*
149 dpavlin 18 * 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 dpavlin 6 * register_reset():
168 dpavlin 4 *
169 dpavlin 6 * Resets many registers to sane values.
170     */
171     static void register_reset(struct vga_data *d)
172     {
173 dpavlin 18 /* Home cursor and start at the top: */
174 dpavlin 6 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 dpavlin 18 recalc_cursor_position(d);
180    
181 dpavlin 6 /* Reset cursor scanline stuff: */
182 dpavlin 18 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 dpavlin 6
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 dpavlin 22 d->palette_modified = 1;
212 dpavlin 6 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 dpavlin 42 * Called from vga_update() when x11 in_use is false. This causes modified
254 dpavlin 6 * 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 dpavlin 10 snprintf(s, sizeof(s), "\033[%i;%iH", y + 1, x + 1);
282 dpavlin 6 c_putstr(d, s);
283     }
284     if (oldcolor < 0 || (bg<<4)+fg != oldcolor || !printed_last) {
285 dpavlin 10 snprintf(s, sizeof(s), "\033[0;"); c_putstr(d, s);
286 dpavlin 6
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 dpavlin 10 snprintf(s, sizeof(s), "\033[%i;%iH", d->cursor_y + 1, d->cursor_x + 1);
323 dpavlin 6 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 dpavlin 22 uint32_t addr2 = (d->fb_max_x * iy
365     + ix) * 3;
366 dpavlin 6 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 dpavlin 4 * been written to. It will redraw all characters within the range x1,y1
381     * .. x2,y2 using the right palette.
382     */
383 dpavlin 6 static void vga_update_text(struct machine *machine, struct vga_data *d,
384 dpavlin 4 int x1, int y1, int x2, int y2)
385     {
386 dpavlin 22 int fg, bg, x,y, subx, line;
387     size_t i, start, end, base;
388 dpavlin 6 int font_size = d->font_height;
389     int font_width = d->font_width;
390     unsigned char *pal = d->fb->rgb_palette;
391 dpavlin 4
392 dpavlin 22 if (d->pixel_repx * font_width > 8*8) {
393     fatal("[ too large font ]\n");
394     return;
395     }
396    
397 dpavlin 4 /* 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 dpavlin 6 if (end >= d->charcells_size)
405     end = d->charcells_size - 1;
406 dpavlin 4
407 dpavlin 6 base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
408     + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
409    
410 dpavlin 42 if (!machine->x11_md.in_use)
411 dpavlin 6 vga_update_textmode(machine, d, base, start, end);
412    
413 dpavlin 4 for (i=start; i<=end; i+=2) {
414 dpavlin 6 unsigned char ch = d->charcells[i + base];
415 dpavlin 18
416 dpavlin 22 if (!d->palette_modified && d->charcells_drawn[i] == ch &&
417 dpavlin 18 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 dpavlin 6 fg = d->charcells[i+base + 1] & 15;
424     bg = (d->charcells[i+base + 1] >> 4) & 7;
425 dpavlin 4
426     /* Blink is hard to do :-), but inversion might be ok too: */
427 dpavlin 6 if (d->charcells[i+base + 1] & 128) {
428 dpavlin 4 int tmp = fg; fg = bg; bg = tmp;
429     }
430    
431 dpavlin 6 x = (i/2) % d->max_x; x *= font_width;
432     y = (i/2) / d->max_x; y *= font_size;
433 dpavlin 4
434 dpavlin 6 /* Draw the character: */
435     for (line = 0; line < font_size; line++) {
436 dpavlin 22 /* hardcoded for max 8 scaleup... :-) */
437     unsigned char rgb_line[3 * 8 * 8];
438     int iy;
439    
440 dpavlin 6 for (subx = 0; subx < font_width; subx++) {
441 dpavlin 22 int ix, color_index;
442 dpavlin 4
443 dpavlin 6 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 dpavlin 4 }
451    
452 dpavlin 6 if (d->font[ch * font_size + line] &
453     (128 >> subx))
454     color_index = fg;
455     else
456     color_index = bg;
457 dpavlin 4
458 dpavlin 22 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 dpavlin 4
463 dpavlin 22 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 dpavlin 42 3 * machine->x11_md.scaleup * font_width,
471 dpavlin 24 MEM_WRITE, d->fb);
472 dpavlin 4 }
473     }
474     }
475     }
476    
477    
478     /*
479     * vga_update_cursor():
480     */
481 dpavlin 6 static void vga_update_cursor(struct machine *machine, struct vga_data *d)
482 dpavlin 4 {
483 dpavlin 6 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 dpavlin 4 dev_fb_setcursor(d->fb,
499 dpavlin 6 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 dpavlin 4 }
504    
505    
506 dpavlin 42 DEVICE_TICK(vga)
507 dpavlin 4 {
508     struct vga_data *d = extra;
509 dpavlin 14 int64_t low = -1, high;
510 dpavlin 4
511 dpavlin 6 vga_update_cursor(cpu->machine, d);
512    
513     /* TODO: text vs graphics tick? */
514 dpavlin 14 memory_device_dyntrans_access(cpu, cpu->mem, extra,
515     (uint64_t *) &low, (uint64_t *) &high);
516 dpavlin 4
517 dpavlin 14 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 dpavlin 24 debug("[ dev_vga_tick: dyntrans access, %"PRIx64" .. %"
522     PRIx64" ]\n", (uint64_t) low, (uint64_t) high);
523 dpavlin 14 low -= base;
524     high -= base;
525 dpavlin 4 d->update_x1 = 0;
526     d->update_x2 = d->max_x - 1;
527 dpavlin 14 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 dpavlin 18 if (d->update_y1 < 0)
534     d->update_y1 = 0;
535 dpavlin 4 if (d->update_y2 >= d->max_y)
536     d->update_y2 = d->max_y - 1;
537     d->modified = 1;
538     }
539    
540 dpavlin 6 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 dpavlin 42 if (!cpu->machine->x11_md.in_use) {
560 dpavlin 6 /* 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 dpavlin 4 if (d->modified) {
566 dpavlin 6 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 dpavlin 4
573 dpavlin 22 d->palette_modified = 0;
574 dpavlin 4 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 dpavlin 6
581     if (d->n_is1_reads > N_IS1_READ_THRESHOLD)
582     d->n_is1_reads = 0;
583 dpavlin 4 }
584    
585    
586     /*
587 dpavlin 6 * Reads and writes to the VGA video memory (pixels).
588     */
589 dpavlin 22 DEVICE_ACCESS(vga_graphics)
590 dpavlin 6 {
591     struct vga_data *d = extra;
592 dpavlin 22 int j, x=0, y=0, x2=0, y2=0, modified = 0;
593     size_t i;
594 dpavlin 6
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 dpavlin 22 uint32_t addr = (y * d->max_x + x +
631     i*8 + j) * d->bits_per_pixel / 8;
632 dpavlin 6 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 dpavlin 42 * Reads and writes the VGA video memory (charcells).
683 dpavlin 4 */
684 dpavlin 22 DEVICE_ACCESS(vga)
685 dpavlin 4 {
686     struct vga_data *d = extra;
687     uint64_t idata = 0, odata = 0;
688 dpavlin 22 int x, y, x2, y2, r, base;
689     size_t i;
690 dpavlin 4
691 dpavlin 18 if (writeflag == MEM_WRITE)
692     idata = memory_readmax64(cpu, data, len);
693 dpavlin 4
694 dpavlin 6 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 dpavlin 4
702 dpavlin 18 if (relative_addr + len - 1 < d->charcells_size) {
703 dpavlin 4 if (writeflag == MEM_WRITE) {
704     for (i=0; i<len; i++) {
705 dpavlin 6 int old = d->charcells[relative_addr + i];
706 dpavlin 4 if (old != data[i]) {
707 dpavlin 6 d->charcells[relative_addr + i] =
708 dpavlin 4 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 dpavlin 6
723     if (y != y2) {
724     d->update_x1 = 0;
725     d->update_x2 = d->max_x - 1;
726     }
727 dpavlin 4 }
728     } else
729 dpavlin 6 memcpy(data, d->charcells + relative_addr, len);
730 dpavlin 4 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 dpavlin 6 * vga_crtc_reg_write():
753 dpavlin 4 *
754 dpavlin 6 * Writes to VGA CRTC registers.
755 dpavlin 4 */
756 dpavlin 6 static void vga_crtc_reg_write(struct machine *machine, struct vga_data *d,
757     int regnr, int idata)
758 dpavlin 4 {
759 dpavlin 28 int i, grayscale;
760 dpavlin 4
761     switch (regnr) {
762 dpavlin 6 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 dpavlin 18 recalc_cursor_position(d);
773 dpavlin 6 break;
774     case VGA_CRTC_CURSOR_LOCATION_HIGH: /* 0x0e */
775     case VGA_CRTC_CURSOR_LOCATION_LOW: /* 0x0f */
776 dpavlin 18 recalc_cursor_position(d);
777 dpavlin 4 break;
778 dpavlin 6 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 dpavlin 42 d->pixel_repx = machine->x11_md.scaleup * 2;
787     d->pixel_repy = machine->x11_md.scaleup;
788 dpavlin 6 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 dpavlin 42 d->pixel_repx = d->pixel_repy = machine->x11_md.scaleup;
798 dpavlin 6 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 dpavlin 42 d->pixel_repx = 4 * machine->x11_md.scaleup;
808     d->pixel_repy = 2 * machine->x11_md.scaleup;
809 dpavlin 6 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 dpavlin 20 d->pixel_repx = d->pixel_repy =
817 dpavlin 42 2 * machine->x11_md.scaleup;
818 dpavlin 6 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 dpavlin 42 d->pixel_repx = machine->x11_md.scaleup;
825     d->pixel_repy = machine->x11_md.scaleup * 2;
826 dpavlin 6 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 dpavlin 42 d->pixel_repx = d->pixel_repy = machine->x11_md.scaleup;
833 dpavlin 6 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 dpavlin 42 d->pixel_repx = d->pixel_repy = machine->x11_md.scaleup;
840 dpavlin 6 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 dpavlin 20 d->pixel_repx = d->pixel_repy =
847 dpavlin 42 2 * machine->x11_md.scaleup;
848 dpavlin 6 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 dpavlin 28 for (i=0; i<machine->ncpus; i++)
869     machine->cpus[i]->invalidate_translation_caches(
870     machine->cpus[i], 0, INVALIDATE_ALL);
871    
872 dpavlin 6 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 dpavlin 42 CHECK_ALLOCATION(d->gfx_mem = malloc(d->gfx_mem_size));
880    
881 dpavlin 6 /* Clear screen and reset the palette: */
882     memset(d->charcells_outputed, 0, d->charcells_size);
883 dpavlin 18 memset(d->charcells_drawn, 0, d->charcells_size);
884 dpavlin 6 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 dpavlin 4 regnr, idata);
895     }
896     }
897    
898    
899     /*
900 dpavlin 6 * 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 dpavlin 20 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 dpavlin 6 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 dpavlin 20 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 dpavlin 6 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 dpavlin 18 /* 0-15 are palette registers: TODO */
949     if (regnr >= 0 && regnr <= 0xf)
950     return;
951    
952 dpavlin 6 switch (regnr) {
953     default:fatal("[ vga_attribute_reg_write: select %i ]\n", regnr);
954     /* cpu->running = 0; */
955     }
956     }
957    
958    
959     /*
960 dpavlin 4 * dev_vga_ctrl_access():
961     *
962     * Reads and writes of the VGA control registers.
963     */
964 dpavlin 22 DEVICE_ACCESS(vga_ctrl)
965 dpavlin 4 {
966     struct vga_data *d = extra;
967 dpavlin 22 size_t i;
968 dpavlin 4 uint64_t idata = 0, odata = 0;
969    
970 dpavlin 6 for (i=0; i<len; i++) {
971     idata = data[i];
972 dpavlin 4
973 dpavlin 6 /* 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 dpavlin 4 break;
986 dpavlin 6 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 dpavlin 4 break;
992     }
993 dpavlin 6 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 dpavlin 18 debug("[ dev_vga: WARNING: Read from "
1042 dpavlin 6 "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 dpavlin 22 d->palette_modified = 1;
1073 dpavlin 6 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 dpavlin 42 CHECK_ALLOCATION(d->retrace_palette =
1143     malloc(
1144     MAX_RETRACE_SCANLINES * 256*3));
1145 dpavlin 6 }
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 dpavlin 18 debug("[ vga_ctrl: read from 0x%08lx ]\n",
1165 dpavlin 6 (long)relative_addr);
1166     } else {
1167 dpavlin 18 debug("[ vga_ctrl: write to 0x%08lx: 0x%08x"
1168 dpavlin 6 " ]\n", (long)relative_addr, (int)idata);
1169     }
1170 dpavlin 4 }
1171 dpavlin 6
1172     if (writeflag == MEM_READ)
1173     data[i] = odata;
1174    
1175     /* For multi-byte accesses: */
1176     relative_addr ++;
1177 dpavlin 4 }
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 dpavlin 6 uint64_t videomem_base, uint64_t control_base, char *name)
1191 dpavlin 4 {
1192     struct vga_data *d;
1193 dpavlin 42 size_t allocsize, i;
1194 dpavlin 4
1195 dpavlin 42 CHECK_ALLOCATION(d = malloc(sizeof(struct vga_data)));
1196 dpavlin 4 memset(d, 0, sizeof(struct vga_data));
1197    
1198 dpavlin 22 d->console_handle = console_start_slave(machine, "vga",
1199     CONSOLE_OUTPUT_ONLY);
1200 dpavlin 4
1201 dpavlin 6 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 dpavlin 14 d->charcells_size = 0x8000;
1208 dpavlin 6 d->gfx_mem_size = 1; /* Nothing, as we start in text mode */
1209 dpavlin 42 d->pixel_repx = d->pixel_repy = machine->x11_md.scaleup;
1210 dpavlin 6
1211 dpavlin 24 /* Allocate in full pages, to make it possible to use dyntrans: */
1212 dpavlin 14 allocsize = ((d->charcells_size-1) | (machine->arch_pagesize-1)) + 1;
1213 dpavlin 42 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 dpavlin 4
1218 dpavlin 18 memset(d->charcells_drawn, 0, d->charcells_size);
1219    
1220 dpavlin 14 for (i=0; i<d->charcells_size; i+=2) {
1221     d->charcells[i] = ' ';
1222     d->charcells[i+1] = 0x07; /* Default color */
1223 dpavlin 18 d->charcells_drawn[i] = ' ';
1224     d->charcells_drawn[i+1] = 0x07;
1225 dpavlin 4 }
1226    
1227 dpavlin 6 memset(d->charcells_outputed, 0, d->charcells_size);
1228     memset(d->gfx_mem, 0, d->gfx_mem_size);
1229    
1230 dpavlin 4 d->font = font8x16;
1231 dpavlin 6 d->font_width = 8;
1232     d->font_height = 16;
1233 dpavlin 4
1234 dpavlin 6 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 dpavlin 20 allocsize, dev_vga_access, d, DM_DYNTRANS_OK |
1243     DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS,
1244 dpavlin 18 d->charcells);
1245 dpavlin 6 memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW,
1246 dpavlin 20 dev_vga_graphics_access, d, DM_DEFAULT |
1247     DM_READS_HAVE_NO_SIDE_EFFECTS, d->gfx_mem);
1248 dpavlin 4 memory_device_register(mem, "vga_ctrl", control_base,
1249 dpavlin 20 32, dev_vga_ctrl_access, d, DM_DEFAULT, NULL);
1250 dpavlin 4
1251 dpavlin 18 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 dpavlin 6 /* 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 dpavlin 4
1264 dpavlin 42 machine_add_tickfunction(machine, dev_vga_tick, d, VGA_TICK_SHIFT);
1265 dpavlin 4
1266 dpavlin 18 register_reset(d);
1267    
1268 dpavlin 6 vga_update_cursor(machine, d);
1269 dpavlin 4 }
1270    

  ViewVC Help
Powered by ViewVC 1.1.26