/[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 24 - (hide annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 34015 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26