/[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 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33386 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26