/[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 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33896 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26