/[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 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 32510 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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

  ViewVC Help
Powered by ViewVC 1.1.26