/[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 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 34152 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26