/[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 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33963 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26