/[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 12 - (show annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 32314 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26