/[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 4 - (hide annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 13736 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.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     * $Id: dev_vga.c,v 1.37 2005/04/15 21:39:56 debug Exp $
29     *
30     * VGA text console device.
31     *
32     * A few ugly hacks are used. The default resolution is 640x480, which
33     * means that the following font sizes and text resolutions can be used:
34     *
35     * 8x16 80 x 30
36     * 8x10 (with the last line repeated twice) 80 x 43
37     * 8x8 80 x 60
38     *
39     * There is only a mode switch when actual non-space text is written outside
40     * the current window.
41     */
42    
43     #include <stdio.h>
44     #include <stdlib.h>
45     #include <string.h>
46    
47     #include "cpu.h"
48     #include "devices.h"
49     #include "machine.h"
50     #include "memory.h"
51     #include "misc.h"
52    
53     /* These are generated from binary font files: */
54     #include "fonts/font8x8.c"
55     #include "fonts/font8x10.c"
56     #include "fonts/font8x16.c"
57    
58    
59     /* For bintranslated videomem -> framebuffer updates: */
60     #define VGA_TICK_SHIFT 14
61    
62     #define VGA_MEM_MAXY 60
63     #define VGA_MEM_ALLOCY 67
64    
65    
66     #define VGA_FB_ADDR 0x1230000000ULL
67    
68     struct vga_data {
69     uint64_t videomem_base;
70     uint64_t control_base;
71    
72     struct vfb_data *fb;
73    
74     int font_size;
75     unsigned char *font;
76    
77     int max_x;
78     int max_y;
79     size_t videomem_size;
80     unsigned char *videomem; /* 2 bytes per char */
81    
82     unsigned char selected_register;
83     unsigned char reg[256];
84    
85     int palette_index;
86     int palette_subindex;
87    
88     int cursor_x;
89     int cursor_y;
90    
91     int modified;
92     int update_x1;
93     int update_y1;
94     int update_x2;
95     int update_y2;
96     };
97    
98    
99     /*
100     * vga_update():
101     *
102     * This function should be called whenever any part of d->videomem[] has
103     * been written to. It will redraw all characters within the range x1,y1
104     * .. x2,y2 using the right palette.
105     */
106     static void vga_update(struct machine *machine, struct vga_data *d,
107     int x1, int y1, int x2, int y2)
108     {
109     int fg, bg, i, x,y, subx, line, start, end;
110    
111     /* Hm... I'm still using the old start..end code: */
112     start = (d->max_x * y1 + x1) * 2;
113     end = (d->max_x * y2 + x2) * 2;
114    
115     start &= ~1;
116     end |= 1;
117    
118     if (end >= d->videomem_size)
119     end = d->videomem_size - 1;
120    
121     for (i=start; i<=end; i+=2) {
122     unsigned char ch = d->videomem[i];
123     fg = d->videomem[i+1] & 15;
124     bg = (d->videomem[i+1] >> 4) & 7;
125    
126     /* Blink is hard to do :-), but inversion might be ok too: */
127     if (d->videomem[i+1] & 128) {
128     int tmp = fg; fg = bg; bg = tmp;
129     }
130    
131     x = (i/2) % d->max_x; x *= 8;
132     y = (i/2) / d->max_x; y *= d->font_size;
133    
134     for (line = 0; line < d->font_size; line++) {
135     for (subx = 0; subx < 8; subx++) {
136     unsigned char pixel[3];
137     int addr, line2readfrom = line;
138     int actualfontheight = d->font_size;
139    
140     if (d->font_size == 11) {
141     actualfontheight = 10;
142     if (line == 10)
143     line2readfrom = 9;
144     }
145    
146     addr = (d->max_x*8 * (line+y) + x + subx)
147     * 3;
148    
149     pixel[0] = d->fb->rgb_palette[bg * 3 + 0];
150     pixel[1] = d->fb->rgb_palette[bg * 3 + 1];
151     pixel[2] = d->fb->rgb_palette[bg * 3 + 2];
152    
153     if (d->font[ch * actualfontheight +
154     line2readfrom] & (128 >> subx)) {
155     pixel[0] = d->fb->rgb_palette
156     [fg * 3 + 0];
157     pixel[1] = d->fb->rgb_palette
158     [fg * 3 + 1];
159     pixel[2] = d->fb->rgb_palette
160     [fg * 3 + 2];
161     }
162    
163     /* TODO: don't hardcode */
164     if (addr < 640 * 480 *3)
165     dev_fb_access(machine->cpus[0],
166     machine->memory, addr, &pixel[0],
167     sizeof(pixel), MEM_WRITE, d->fb);
168     }
169     }
170     }
171     }
172    
173    
174     /*
175     * vga_update_cursor():
176     */
177     static void vga_update_cursor(struct vga_data *d)
178     {
179     /* TODO: Don't hardcode the cursor size. */
180     dev_fb_setcursor(d->fb,
181     d->cursor_x * 8, d->cursor_y * d->font_size +
182     d->font_size - 4, 1, 8, 3);
183     }
184    
185    
186     /*
187     * dev_vga_tick():
188     */
189     void dev_vga_tick(struct cpu *cpu, void *extra)
190     {
191     struct vga_data *d = extra;
192     uint64_t low = (uint64_t)-1, high;
193    
194     memory_device_bintrans_access(cpu, cpu->mem, extra, &low, &high);
195    
196     if ((int64_t)low != -1) {
197     debug("[ dev_vga_tick: bintrans access, %llx .. %llx ]\n",
198     (long long)low, (long long)high);
199     d->update_x1 = 0;
200     d->update_x2 = d->max_x - 1;
201     d->update_y1 = (low/2) / d->max_x;
202     d->update_y2 = ((high/2) / d->max_x) + 1;
203     if (d->update_y2 >= d->max_y)
204     d->update_y2 = d->max_y - 1;
205     d->modified = 1;
206     }
207    
208     if (d->modified) {
209     vga_update(cpu->machine, d,
210     d->update_x1, d->update_y1, d->update_x2, d->update_y2);
211    
212     d->modified = 0;
213     d->update_x1 = 999999;
214     d->update_x2 = -1;
215     d->update_y1 = 999999;
216     d->update_y2 = -1;
217     }
218     }
219    
220    
221     /*
222     * dev_vga_access():
223     *
224     * Reads and writes to the VGA video memory.
225     */
226     int dev_vga_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr,
227     unsigned char *data, size_t len, int writeflag, void *extra)
228     {
229     struct vga_data *d = extra;
230     uint64_t idata = 0, odata = 0;
231     int i, x, y, x2, y2;
232    
233     idata = memory_readmax64(cpu, data, len);
234    
235     y = relative_addr / (d->max_x * 2);
236     x = (relative_addr/2) % d->max_x;
237    
238     y2 = (relative_addr+len-1) / (d->max_x * 2);
239     x2 = ((relative_addr+len-1)/2) % d->max_x;
240    
241     /*
242     * Switch fonts? This is an ugly hack which only switches when
243     * parts of the video ram is accessed that are outside the current
244     * screen. (Specially "crafted" :-) to work with Windows NT.)
245     */
246     if (writeflag && (idata & 255) != 0x20 && (relative_addr & 1) == 0) {
247     if (y >= 43 && d->font_size > 8) {
248     /* Switch to 8x8 font: */
249     debug("SWITCHING to 8x8 font\n");
250     d->font_size = 8;
251     d->font = font8x8;
252     d->max_y = VGA_MEM_MAXY;
253     vga_update(cpu->machine, d, 0, 0,
254     d->max_x - 1, d->max_y - 1);
255     vga_update_cursor(d);
256     } else if (y >= 30 && d->font_size > 11) {
257     /* Switch to 8x10 font: */
258     debug("SWITCHING to 8x10 font\n");
259     d->font_size = 11; /* NOTE! 11 */
260     d->font = font8x10;
261     vga_update(cpu->machine, d, 0, 0,
262     d->max_x - 1, d->max_y - 1);
263     d->max_y = 43;
264     vga_update_cursor(d);
265     }
266     }
267    
268     if (relative_addr < d->videomem_size) {
269     if (writeflag == MEM_WRITE) {
270     for (i=0; i<len; i++) {
271     int old = d->videomem[relative_addr + i];
272     if (old != data[i]) {
273     d->videomem[relative_addr + i] =
274     data[i];
275     d->modified = 1;
276     }
277     }
278    
279     if (d->modified) {
280     if (x < d->update_x1) d->update_x1 = x;
281     if (x > d->update_x2) d->update_x2 = x;
282     if (y < d->update_y1) d->update_y1 = y;
283     if (y > d->update_y2) d->update_y2 = y;
284    
285     if (x2 < d->update_x1) d->update_x1 = x2;
286     if (x2 > d->update_x2) d->update_x2 = x2;
287     if (y2 < d->update_y1) d->update_y1 = y2;
288     if (y2 > d->update_y2) d->update_y2 = y2;
289     }
290     } else
291     memcpy(data, d->videomem + relative_addr, len);
292     return 1;
293     }
294    
295     switch (relative_addr) {
296     default:
297     if (writeflag==MEM_READ) {
298     debug("[ vga: read from 0x%08lx ]\n",
299     (long)relative_addr);
300     } else {
301     debug("[ vga: write to 0x%08lx: 0x%08x ]\n",
302     (long)relative_addr, idata);
303     }
304     }
305    
306     if (writeflag == MEM_READ)
307     memory_writemax64(cpu, data, len, odata);
308    
309     return 1;
310     }
311    
312    
313     /*
314     * vga_reg_write():
315     *
316     * Writes to VGA control registers.
317     */
318     static void vga_reg_write(struct vga_data *d, int regnr, int idata)
319     {
320     int ofs;
321    
322     switch (regnr) {
323     case 0x0e:
324     case 0x0f:
325     ofs = d->reg[0x0e] * 256 + d->reg[0x0f];
326     d->cursor_x = ofs % d->max_x;
327     d->cursor_y = ofs / d->max_x;
328     vga_update_cursor(d);
329     break;
330     default:
331     debug("[ vga_reg_write: regnr=0x%02x idata=0x%02x ]\n",
332     regnr, idata);
333     }
334     }
335    
336    
337     /*
338     * dev_vga_ctrl_access():
339     *
340     * Reads and writes of the VGA control registers.
341     */
342     int dev_vga_ctrl_access(struct cpu *cpu, struct memory *mem,
343     uint64_t relative_addr, unsigned char *data, size_t len,
344     int writeflag, void *extra)
345     {
346     struct vga_data *d = extra;
347     uint64_t idata = 0, odata = 0;
348    
349     idata = memory_readmax64(cpu, data, len);
350    
351     switch (relative_addr) {
352     case 0x01: /* "Other video attributes" */
353     odata = 0xff; /* ? */
354     break;
355     case 0x08:
356     if (writeflag == MEM_WRITE) {
357     d->palette_index = idata;
358     d->palette_subindex = 0;
359     } else {
360     odata = d->palette_index;
361     }
362     break;
363     case 0x09:
364     if (writeflag == MEM_WRITE) {
365     int new = (idata & 63) << 2;
366     int old = d->fb->rgb_palette[d->palette_index * 3 +
367     d->palette_subindex];
368     d->fb->rgb_palette[d->palette_index * 3 +
369     d->palette_subindex] = new;
370     /* Redraw whole screen, if the palette changed: */
371     if (new != old) {
372     d->modified = 1;
373     d->update_x1 = d->update_y1 = 0;
374     d->update_x2 = d->max_x - 1;
375     d->update_y2 = d->max_y - 1;
376     }
377     } else {
378     odata = (d->fb->rgb_palette[d->palette_index * 3 +
379     d->palette_subindex] >> 2) & 63;
380     }
381     d->palette_subindex ++;
382     if (d->palette_subindex == 3) {
383     d->palette_index ++;
384     d->palette_subindex = 0;
385     }
386     d->palette_index &= 255;
387     break;
388     case 0x0c: /* VGA graphics 1 position */
389     odata = 1; /* ? */
390     break;
391     case 0x14: /* register select */
392     if (writeflag == MEM_READ)
393     odata = d->selected_register;
394     else
395     d->selected_register = idata;
396     break;
397     case 0x15: if (writeflag == MEM_READ)
398     odata = d->reg[d->selected_register];
399     else {
400     d->reg[d->selected_register] = idata;
401     vga_reg_write(d, d->selected_register, idata);
402     }
403     break;
404     case 0x1a: /* Status register */
405     odata = 1; /* Display enabled */
406     /* odata |= 16; */ /* Vertical retrace */
407     break;
408     default:
409     if (writeflag==MEM_READ) {
410     fatal("[ vga_ctrl: read from 0x%08lx ]\n",
411     (long)relative_addr);
412     } else {
413     static int warning = 0;
414     warning ++;
415     if (warning > 2)
416     break;
417     if (warning > 1) {
418     fatal("[ vga_ctrl: multiple unimplemented wr"
419     "ites, ignoring warnings from now on ]\n");
420     break;
421     }
422     fatal("[ vga_ctrl: write to 0x%08lx: 0x%08x ]\n",
423     (long)relative_addr, idata);
424     }
425     }
426    
427     if (writeflag == MEM_READ)
428     memory_writemax64(cpu, data, len, odata);
429    
430     return 1;
431     }
432    
433    
434     /*
435     * dev_vga_init():
436     *
437     * Register a VGA text console device. max_x and max_y could be something
438     * like 80 and 25, respectively.
439     */
440     void dev_vga_init(struct machine *machine, struct memory *mem,
441     uint64_t videomem_base, uint64_t control_base, int max_x, int max_y,
442     char *name)
443     {
444     struct vga_data *d;
445     int r,g,b,i, x,y;
446     size_t allocsize;
447    
448     d = malloc(sizeof(struct vga_data));
449     if (d == NULL) {
450     fprintf(stderr, "out of memory\n");
451     exit(1);
452     }
453     memset(d, 0, sizeof(struct vga_data));
454    
455     d->videomem_base = videomem_base;
456     d->control_base = control_base;
457     d->max_x = max_x;
458     d->max_y = max_y;
459     d->videomem_size = max_x * VGA_MEM_MAXY * 2;
460     d->cursor_y = 2;
461    
462     /* Allocate in 4KB pages, to make it possible to use bintrans: */
463     allocsize = ((d->videomem_size - 1) | 0xfff) + 1;
464     d->videomem = malloc(d->videomem_size);
465     if (d->videomem == NULL) {
466     fprintf(stderr, "out of memory in dev_vga_init()\n");
467     exit(1);
468     }
469    
470     for (y=0; y<VGA_MEM_MAXY; y++) {
471     char s[81];
472     #ifdef VERSION
473     strcpy(s, " GXemul " VERSION);
474     #else
475     strcpy(s, " GXemul");
476     #endif
477     memset(s+strlen(s), ' ', 80 - strlen(s));
478     memcpy(s+79-strlen(name), name, strlen(name));
479     s[80] = 0;
480    
481     for (x=0; x<max_x; x++) {
482     char ch = ' ';
483     if (y == 0)
484     ch = s[x];
485     i = (x + max_x * y) * 2;
486     d->videomem[i] = ch;
487    
488     /* Default color: */
489     d->videomem[i+1] = y==0? 0x70 : 0x07;
490     }
491     }
492    
493     d->font_size = 16;
494     d->font = font8x16;
495    
496     d->fb = dev_fb_init(machine, mem, VGA_FB_ADDR, VFB_GENERIC,
497     8*max_x, 16*max_y, 8*max_x, 16*max_y, 24, "VGA", 0);
498    
499     i = 0;
500     for (r=0; r<2; r++)
501     for (g=0; g<2; g++)
502     for (b=0; b<2; b++) {
503     d->fb->rgb_palette[i + 0] = r * 0xaa;
504     d->fb->rgb_palette[i + 1] = g * 0xaa;
505     d->fb->rgb_palette[i + 2] = b * 0xaa;
506     i+=3;
507     }
508     for (r=0; r<2; r++)
509     for (g=0; g<2; g++)
510     for (b=0; b<2; b++) {
511     d->fb->rgb_palette[i + 0] = r * 0xaa + 0x55;
512     d->fb->rgb_palette[i + 1] = g * 0xaa + 0x55;
513     d->fb->rgb_palette[i + 2] = b * 0xaa + 0x55;
514     i+=3;
515     }
516    
517     memory_device_register(mem, "vga_mem", videomem_base, allocsize,
518     dev_vga_access, d, MEM_BINTRANS_OK
519     /* | MEM_BINTRANS_WRITE_OK <-- This works with OpenBSD/arc, but not
520     with Windows NT yet. Why? */
521     ,
522     d->videomem);
523     memory_device_register(mem, "vga_ctrl", control_base,
524     32, dev_vga_ctrl_access, d, MEM_DEFAULT, NULL);
525    
526     /* Make sure that the first line is in synch. */
527     vga_update(machine, d, 0, 0, d->max_x - 1, 0);
528    
529     d->update_x1 = 999999;
530     d->update_x2 = -1;
531     d->update_y1 = 999999;
532     d->update_y2 = -1;
533     d->modified = 0;
534    
535     machine_add_tickfunction(machine, dev_vga_tick, d, VGA_TICK_SHIFT);
536    
537     vga_update_cursor(d);
538     }
539    

  ViewVC Help
Powered by ViewVC 1.1.26