/[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

Contents of /trunk/src/devices/dev_vga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show 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 /*
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