]> git.proxmox.com Git - qemu.git/blame - hw/vga.c
removed SIGIOT
[qemu.git] / hw / vga.c
CommitLineData
e89f66ec
FB
1/*
2 * QEMU VGA Emulator. An S3 86c968 is emulated
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include <stdlib.h>
25#include <stdio.h>
26#include <stdarg.h>
27#include <string.h>
28#include <getopt.h>
29#include <inttypes.h>
30#include <unistd.h>
31#include <sys/mman.h>
32#include <fcntl.h>
33#include <signal.h>
34#include <time.h>
35#include <sys/time.h>
36#include <malloc.h>
37#include <termios.h>
38#include <sys/poll.h>
39#include <errno.h>
40#include <sys/wait.h>
41#include <netinet/in.h>
42
6180a181
FB
43#include "cpu.h"
44#include "exec-all.h"
e89f66ec
FB
45
46#include "vl.h"
47
48#define NO_THUNK_TYPE_SIZE
49#include "thunk.h"
50
51//#define DEBUG_VGA
17b0018b 52//#define DEBUG_VGA_MEM
e89f66ec
FB
53
54#define MSR_COLOR_EMULATION 0x01
55#define MSR_PAGE_SELECT 0x20
56
57#define ST01_V_RETRACE 0x08
58#define ST01_DISP_ENABLE 0x01
59
60typedef struct VGAState {
61 uint8_t *vram_ptr;
62 unsigned long vram_offset;
63 unsigned int vram_size;
64 uint32_t latch;
65 uint8_t sr_index;
66 uint8_t sr[8];
67 uint8_t gr_index;
68 uint8_t gr[16];
69 uint8_t ar_index;
70 uint8_t ar[21];
71 int ar_flip_flop;
72 uint8_t cr_index;
73 uint8_t cr[256]; /* CRT registers */
74 uint8_t msr; /* Misc Output Register */
75 uint8_t fcr; /* Feature Control Register */
76 uint8_t st00; /* status 0 */
77 uint8_t st01; /* status 1 */
78 uint8_t dac_state;
79 uint8_t dac_sub_index;
80 uint8_t dac_read_index;
81 uint8_t dac_write_index;
82 uint8_t dac_cache[3]; /* used when writing */
83 uint8_t palette[768];
84
85 /* display refresh support */
e89f66ec
FB
86 DisplayState *ds;
87 uint32_t font_offsets[2];
88 int graphic_mode;
17b0018b
FB
89 uint8_t shift_control;
90 uint8_t double_scan;
e89f66ec
FB
91 uint32_t line_offset;
92 uint32_t line_compare;
93 uint32_t start_addr;
94 uint8_t last_cw, last_ch;
95 uint32_t last_width, last_height;
96 uint8_t cursor_start, cursor_end;
97 uint32_t cursor_offset;
17b0018b 98 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
39cf7803 99 /* tell for each page if it has been updated since the last time */
e89f66ec
FB
100 uint8_t vram_updated[VGA_RAM_SIZE / 4096];
101 uint32_t last_palette[256];
17b0018b 102#define CH_ATTR_SIZE (160 * 100)
e89f66ec
FB
103 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
104} VGAState;
105
106/* force some bits to zero */
107static const uint8_t sr_mask[8] = {
108 (uint8_t)~0xfc,
109 (uint8_t)~0xc2,
110 (uint8_t)~0xf0,
111 (uint8_t)~0xc0,
112 (uint8_t)~0xf1,
113 (uint8_t)~0xff,
114 (uint8_t)~0xff,
115 (uint8_t)~0x00,
116};
117
118static const uint8_t gr_mask[16] = {
119 (uint8_t)~0xf0, /* 0x00 */
120 (uint8_t)~0xf0, /* 0x01 */
121 (uint8_t)~0xf0, /* 0x02 */
122 (uint8_t)~0xe0, /* 0x03 */
123 (uint8_t)~0xfc, /* 0x04 */
124 (uint8_t)~0x84, /* 0x05 */
125 (uint8_t)~0xf0, /* 0x06 */
126 (uint8_t)~0xf0, /* 0x07 */
127 (uint8_t)~0x00, /* 0x08 */
128 (uint8_t)~0xff, /* 0x09 */
129 (uint8_t)~0xff, /* 0x0a */
130 (uint8_t)~0xff, /* 0x0b */
131 (uint8_t)~0xff, /* 0x0c */
132 (uint8_t)~0xff, /* 0x0d */
133 (uint8_t)~0xff, /* 0x0e */
134 (uint8_t)~0xff, /* 0x0f */
135};
136
137#define cbswap_32(__x) \
138((uint32_t)( \
139 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
140 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
141 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
142 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
143
144#ifdef WORD_BIGENDIAN
145#define PAT(x) cbswap_32(x)
146#else
147#define PAT(x) (x)
148#endif
149
150static const uint32_t mask16[16] = {
151 PAT(0x00000000),
152 PAT(0x000000ff),
153 PAT(0x0000ff00),
154 PAT(0x0000ffff),
155 PAT(0x00ff0000),
156 PAT(0x00ff00ff),
157 PAT(0x00ffff00),
158 PAT(0x00ffffff),
159 PAT(0xff000000),
160 PAT(0xff0000ff),
161 PAT(0xff00ff00),
162 PAT(0xff00ffff),
163 PAT(0xffff0000),
164 PAT(0xffff00ff),
165 PAT(0xffffff00),
166 PAT(0xffffffff),
167};
168
169#undef PAT
170
171#ifdef WORD_BIGENDIAN
172#define PAT(x) (x)
173#else
174#define PAT(x) cbswap_32(x)
175#endif
176
177static const uint32_t dmask16[16] = {
178 PAT(0x00000000),
179 PAT(0x000000ff),
180 PAT(0x0000ff00),
181 PAT(0x0000ffff),
182 PAT(0x00ff0000),
183 PAT(0x00ff00ff),
184 PAT(0x00ffff00),
185 PAT(0x00ffffff),
186 PAT(0xff000000),
187 PAT(0xff0000ff),
188 PAT(0xff00ff00),
189 PAT(0xff00ffff),
190 PAT(0xffff0000),
191 PAT(0xffff00ff),
192 PAT(0xffffff00),
193 PAT(0xffffffff),
194};
195
196static const uint32_t dmask4[4] = {
197 PAT(0x00000000),
198 PAT(0x0000ffff),
199 PAT(0xffff0000),
200 PAT(0xffffffff),
201};
202
203static uint32_t expand4[256];
204static uint16_t expand2[256];
17b0018b 205static uint8_t expand4to8[16];
e89f66ec
FB
206
207VGAState vga_state;
208int vga_io_memory;
209
210static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr)
211{
212 VGAState *s = &vga_state;
213 int val, index;
214
215 /* check port range access depending on color/monochrome mode */
216 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
217 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
218 val = 0xff;
219 } else {
220 switch(addr) {
221 case 0x3c0:
222 if (s->ar_flip_flop == 0) {
223 val = s->ar_index;
224 } else {
225 val = 0;
226 }
227 break;
228 case 0x3c1:
229 index = s->ar_index & 0x1f;
230 if (index < 21)
231 val = s->ar[index];
232 else
233 val = 0;
234 break;
235 case 0x3c2:
236 val = s->st00;
237 break;
238 case 0x3c4:
239 val = s->sr_index;
240 break;
241 case 0x3c5:
242 val = s->sr[s->sr_index];
243 break;
244 case 0x3c7:
245 val = s->dac_state;
246 break;
247 case 0x3c9:
248 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
249 if (++s->dac_sub_index == 3) {
250 s->dac_sub_index = 0;
251 s->dac_read_index++;
252 }
253 break;
254 case 0x3ca:
255 val = s->fcr;
256 break;
257 case 0x3cc:
258 val = s->msr;
259 break;
260 case 0x3ce:
261 val = s->gr_index;
262 break;
263 case 0x3cf:
264 val = s->gr[s->gr_index];
265 break;
266 case 0x3b4:
267 case 0x3d4:
268 val = s->cr_index;
269 break;
270 case 0x3b5:
271 case 0x3d5:
272 val = s->cr[s->cr_index];
273 break;
274 case 0x3ba:
275 case 0x3da:
276 /* just toggle to fool polling */
277 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
278 val = s->st01;
279 s->ar_flip_flop = 0;
280 break;
281 default:
282 val = 0x00;
283 break;
284 }
285 }
286#ifdef DEBUG_VGA
287 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
288#endif
289 return val;
290}
291
292static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
293{
294 VGAState *s = &vga_state;
295 int index, v;
296
297 /* check port range access depending on color/monochrome mode */
298 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
299 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
300 return;
301
302#ifdef DEBUG_VGA
303 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
304#endif
305
306 switch(addr) {
307 case 0x3c0:
308 if (s->ar_flip_flop == 0) {
309 val &= 0x3f;
310 s->ar_index = val;
311 } else {
312 index = s->ar_index & 0x1f;
313 switch(index) {
314 case 0x00 ... 0x0f:
315 s->ar[index] = val & 0x3f;
316 break;
317 case 0x10:
318 s->ar[index] = val & ~0x10;
319 break;
320 case 0x11:
321 s->ar[index] = val;
322 break;
323 case 0x12:
324 s->ar[index] = val & ~0xc0;
325 break;
326 case 0x13:
327 s->ar[index] = val & ~0xf0;
328 break;
329 case 0x14:
330 s->ar[index] = val & ~0xf0;
331 break;
332 default:
333 break;
334 }
335 }
336 s->ar_flip_flop ^= 1;
337 break;
338 case 0x3c2:
339 s->msr = val & ~0x10;
340 break;
341 case 0x3c4:
342 s->sr_index = val & 7;
343 break;
344 case 0x3c5:
345 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
346 break;
347 case 0x3c7:
348 s->dac_read_index = val;
349 s->dac_sub_index = 0;
350 s->dac_state = 3;
351 break;
352 case 0x3c8:
353 s->dac_write_index = val;
354 s->dac_sub_index = 0;
355 s->dac_state = 0;
356 break;
357 case 0x3c9:
358 s->dac_cache[s->dac_sub_index] = val;
359 if (++s->dac_sub_index == 3) {
360 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
361 s->dac_sub_index = 0;
362 s->dac_write_index++;
363 }
364 break;
365 case 0x3ce:
366 s->gr_index = val & 0x0f;
367 break;
368 case 0x3cf:
369 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
370 break;
371 case 0x3b4:
372 case 0x3d4:
373 s->cr_index = val;
374 break;
375 case 0x3b5:
376 case 0x3d5:
377 /* handle CR0-7 protection */
378 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
379 /* can always write bit 4 of CR7 */
380 if (s->cr_index == 7)
381 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
382 return;
383 }
384 switch(s->cr_index) {
385 case 0x01: /* horizontal display end */
386 case 0x07:
387 case 0x09:
388 case 0x0c:
389 case 0x0d:
390 case 0x12: /* veritcal display end */
391 s->cr[s->cr_index] = val;
392 break;
393
394 /* S3 registers */
395 case 0x2d:
396 case 0x2e:
397 case 0x2f:
398 case 0x30:
399 /* chip ID, cannot write */
400 break;
401 case 0x31:
402 /* update start address */
403 s->cr[s->cr_index] = val;
404 v = (val >> 4) & 3;
405 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
406 break;
407 case 0x51:
408 /* update start address */
409 s->cr[s->cr_index] = val;
410 v = val & 3;
411 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
412 break;
413 default:
414 s->cr[s->cr_index] = val;
415 break;
416 }
417 break;
418 case 0x3ba:
419 case 0x3da:
420 s->fcr = val & 0x10;
421 break;
422 }
423}
424
425/* called for accesses between 0xa0000 and 0xc0000 */
426static uint32_t vga_mem_readb(uint32_t addr)
427{
428 VGAState *s = &vga_state;
429 int memory_map_mode, plane;
430 uint32_t ret;
431
432 /* convert to VGA memory offset */
433 memory_map_mode = (s->gr[6] >> 2) & 3;
434 switch(memory_map_mode) {
435 case 0:
436 addr -= 0xa0000;
437 break;
438 case 1:
439 addr -= 0xa0000;
440 if (addr >= 0x10000)
441 return 0xff;
442 break;
443 case 2:
444 addr -= 0xb0000;
445 if (addr >= 0x8000)
446 return 0xff;
447 break;
448 default:
449 case 3:
450 addr -= 0xb8000;
451 break;
452 }
453
454 if (s->sr[4] & 0x08) {
455 /* chain 4 mode : simplest access */
456 ret = s->vram_ptr[addr];
457 } else if (s->gr[5] & 0x10) {
458 /* odd/even mode (aka text mode mapping) */
459 plane = (s->gr[4] & 2) | (addr & 1);
460 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
461 } else {
462 /* standard VGA latched access */
463 s->latch = ((uint32_t *)s->vram_ptr)[addr];
464
465 if (!(s->gr[5] & 0x08)) {
466 /* read mode 0 */
467 plane = s->gr[4];
468#ifdef WORD_BIGENDIAN
469 ret = (s->latch >> (24 - (plane * 8))) & 0xff;
470#else
471 ret = (s->latch >> (plane * 8)) & 0xff;
472#endif
473 } else {
474 /* read mode 1 */
475 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
476 ret |= ret >> 16;
477 ret |= ret >> 8;
478 ret = (~ret) & 0xff;
479 }
480 }
481 return ret;
482}
483
484static uint32_t vga_mem_readw(uint32_t addr)
485{
486 uint32_t v;
487 v = vga_mem_readb(addr);
488 v |= vga_mem_readb(addr + 1) << 8;
489 return v;
490}
491
492static uint32_t vga_mem_readl(uint32_t addr)
493{
494 uint32_t v;
495 v = vga_mem_readb(addr);
496 v |= vga_mem_readb(addr + 1) << 8;
497 v |= vga_mem_readb(addr + 2) << 16;
498 v |= vga_mem_readb(addr + 3) << 24;
499 return v;
500}
501
502
503/* called for accesses between 0xa0000 and 0xc0000 */
504void vga_mem_writeb(uint32_t addr, uint32_t val)
505{
506 VGAState *s = &vga_state;
507 int memory_map_mode, plane, write_mode, b, func_select;
508 uint32_t write_mask, bit_mask, set_mask;
509
17b0018b 510#ifdef DEBUG_VGA_MEM
e89f66ec
FB
511 printf("vga: [0x%x] = 0x%02x\n", addr, val);
512#endif
513 /* convert to VGA memory offset */
514 memory_map_mode = (s->gr[6] >> 2) & 3;
515 switch(memory_map_mode) {
516 case 0:
517 addr -= 0xa0000;
518 break;
519 case 1:
520 addr -= 0xa0000;
521 if (addr >= 0x10000)
522 return;
523 break;
524 case 2:
525 addr -= 0xb0000;
526 if (addr >= 0x8000)
527 return;
528 break;
529 default:
530 case 3:
531 addr -= 0xb8000;
532 break;
533 }
534
535 if (s->sr[4] & 0x08) {
536 /* chain 4 mode : simplest access */
537 plane = addr & 3;
538 if (s->sr[2] & (1 << plane)) {
539 s->vram_ptr[addr] = val;
17b0018b 540#ifdef DEBUG_VGA_MEM
e89f66ec
FB
541 printf("vga: chain4: [0x%x]\n", addr);
542#endif
543 s->vram_updated[addr >> 12] = 1;
544 }
545 } else if (s->gr[5] & 0x10) {
546 /* odd/even mode (aka text mode mapping) */
547 plane = (s->gr[4] & 2) | (addr & 1);
548 if (s->sr[2] & (1 << plane)) {
549 addr = ((addr & ~1) << 1) | plane;
550 s->vram_ptr[addr] = val;
17b0018b 551#ifdef DEBUG_VGA_MEM
e89f66ec
FB
552 printf("vga: odd/even: [0x%x]\n", addr);
553#endif
554 s->vram_updated[addr >> 12] = 1;
555 }
556 } else {
557 /* standard VGA latched access */
558 write_mode = s->gr[5] & 3;
559 switch(write_mode) {
560 default:
561 case 0:
562 /* rotate */
563 b = s->gr[3] & 7;
564 val = ((val >> b) | (val << (8 - b))) & 0xff;
565 val |= val << 8;
566 val |= val << 16;
567
568 /* apply set/reset mask */
569 set_mask = mask16[s->gr[1]];
570 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
571 bit_mask = s->gr[8];
572 break;
573 case 1:
574 val = s->latch;
575 goto do_write;
576 case 2:
577 val = mask16[val & 0x0f];
578 bit_mask = s->gr[8];
579 break;
580 case 3:
581 /* rotate */
582 b = s->gr[3] & 7;
583 val = ((val >> b) | (val << (8 - b)));
584
585 bit_mask = s->gr[8] & val;
586 val = mask16[s->gr[0]];
587 break;
588 }
589
590 /* apply logical operation */
591 func_select = s->gr[3] >> 3;
592 switch(func_select) {
593 case 0:
594 default:
595 /* nothing to do */
596 break;
597 case 1:
598 /* and */
599 val &= s->latch;
600 break;
601 case 2:
602 /* or */
603 val |= s->latch;
604 break;
605 case 3:
606 /* xor */
607 val ^= s->latch;
608 break;
609 }
610
611 /* apply bit mask */
612 bit_mask |= bit_mask << 8;
613 bit_mask |= bit_mask << 16;
614 val = (val & bit_mask) | (s->latch & ~bit_mask);
615
616 do_write:
617 /* mask data according to sr[2] */
618 write_mask = mask16[s->sr[2]];
619 ((uint32_t *)s->vram_ptr)[addr] =
620 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
621 (val & write_mask);
17b0018b 622#ifdef DEBUG_VGA_MEM
e89f66ec
FB
623 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
624 addr * 4, write_mask, val);
625#endif
626 s->vram_updated[addr >> 10] = 1;
627 }
628}
629
630void vga_mem_writew(uint32_t addr, uint32_t val)
631{
632 vga_mem_writeb(addr, val & 0xff);
633 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
634}
635
636void vga_mem_writel(uint32_t addr, uint32_t val)
637{
638 vga_mem_writeb(addr, val & 0xff);
639 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
640 vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
641 vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
642}
643
644#ifdef WORD_BIGENDIAN
645#define BIG 1
646#else
647#define BIG 0
648#endif
649
650#ifdef WORDS_BIGENDIAN
651#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
652#else
653#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
654#endif
655
656typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
657 const uint8_t *font_ptr, int h,
658 uint32_t fgcol, uint32_t bgcol);
659typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
660 const uint8_t *font_ptr, int h,
661 uint32_t fgcol, uint32_t bgcol, int dup9);
662typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
663 const uint8_t *s, int width);
664
665static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
666{
667 /* XXX: TODO */
668 return 0;
669}
670
671static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
672{
673 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
674}
675
676static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
677{
678 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
679}
680
681static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
682{
683 return (r << 16) | (g << 8) | b;
684}
685
686#define DEPTH 8
687#include "vga_template.h"
688
689#define DEPTH 15
690#include "vga_template.h"
691
692#define DEPTH 16
693#include "vga_template.h"
694
695#define DEPTH 32
696#include "vga_template.h"
697
698static inline int c6_to_8(int v)
699{
700 int b;
701 v &= 0x3f;
702 b = v & 1;
703 return (v << 2) | (b << 1) | b;
704}
705
17b0018b
FB
706static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
707{
708 unsigned int col;
709 col = rgb_to_pixel8(r, g, b);
710 col |= col << 8;
711 col |= col << 16;
712 return col;
713}
714
715static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
716{
717 unsigned int col;
718 col = rgb_to_pixel15(r, g, b);
719 col |= col << 16;
720 return col;
721}
722
723static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
724{
725 unsigned int col;
726 col = rgb_to_pixel16(r, g, b);
727 col |= col << 16;
728 return col;
729}
730
731static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
732{
733 unsigned int col;
734 col = rgb_to_pixel32(r, g, b);
735 return col;
736}
737
e89f66ec
FB
738/* return true if the palette was modified */
739static int update_palette16(VGAState *s)
740{
17b0018b 741 int full_update, i;
e89f66ec 742 uint32_t v, col, *palette;
e89f66ec
FB
743
744 full_update = 0;
745 palette = s->last_palette;
746 for(i = 0; i < 16; i++) {
747 v = s->ar[i];
748 if (s->ar[0x10] & 0x80)
749 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
750 else
751 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
752 v = v * 3;
17b0018b
FB
753 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
754 c6_to_8(s->palette[v + 1]),
755 c6_to_8(s->palette[v + 2]));
756 if (col != palette[i]) {
757 full_update = 1;
758 palette[i] = col;
e89f66ec 759 }
17b0018b
FB
760 }
761 return full_update;
762}
763
764/* return true if the palette was modified */
765static int update_palette256(VGAState *s)
766{
767 int full_update, i;
768 uint32_t v, col, *palette;
769
770 full_update = 0;
771 palette = s->last_palette;
772 v = 0;
773 for(i = 0; i < 256; i++) {
774 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
775 c6_to_8(s->palette[v + 1]),
776 c6_to_8(s->palette[v + 2]));
e89f66ec
FB
777 if (col != palette[i]) {
778 full_update = 1;
779 palette[i] = col;
780 }
17b0018b 781 v += 3;
e89f66ec
FB
782 }
783 return full_update;
784}
785
786/* update start_addr and line_offset. Return TRUE if modified */
787static int update_basic_params(VGAState *s)
788{
789 int full_update;
790 uint32_t start_addr, line_offset, line_compare, v;
791
792 full_update = 0;
793 /* compute line_offset in bytes */
794 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
795 if (v == 0)
796 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
797 line_offset = s->cr[0x13] | (v << 8);
798 line_offset <<= 3;
39cf7803 799
e89f66ec
FB
800 /* starting address */
801 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
802 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
803
804 /* line compare */
805 line_compare = s->cr[0x18] |
806 ((s->cr[0x07] & 0x10) << 4) |
807 ((s->cr[0x09] & 0x40) << 3);
808
809 if (line_offset != s->line_offset ||
810 start_addr != s->start_addr ||
811 line_compare != s->line_compare) {
812 s->line_offset = line_offset;
813 s->start_addr = start_addr;
814 s->line_compare = line_compare;
815 full_update = 1;
816 }
817 return full_update;
818}
819
820static inline int get_depth_index(int depth)
821{
822 switch(depth) {
823 default:
824 case 8:
825 return 0;
826 case 15:
827 return 1;
828 case 16:
829 return 2;
830 case 32:
831 return 3;
832 }
833}
834
835static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
836 vga_draw_glyph8_8,
837 vga_draw_glyph8_16,
838 vga_draw_glyph8_16,
839 vga_draw_glyph8_32,
840};
841
17b0018b
FB
842static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
843 vga_draw_glyph16_8,
844 vga_draw_glyph16_16,
845 vga_draw_glyph16_16,
846 vga_draw_glyph16_32,
847};
848
e89f66ec
FB
849static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
850 vga_draw_glyph9_8,
851 vga_draw_glyph9_16,
852 vga_draw_glyph9_16,
853 vga_draw_glyph9_32,
854};
855
856static const uint8_t cursor_glyph[32 * 4] = {
857 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
858 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
859 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
860 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
861 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
862 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
863 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
864 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
865 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
866 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
867 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
868 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
869 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
870 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
871 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
872 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
873};
874
875/*
876 * Text mode update
877 * Missing:
878 * - double scan
879 * - double width
880 * - underline
881 * - flashing
882 */
883static void vga_draw_text(VGAState *s, int full_update)
884{
885 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
886 int cx_min, cx_max, linesize, x_incr;
887 uint32_t offset, fgcol, bgcol, v, cursor_offset;
888 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
889 const uint8_t *font_ptr, *font_base[2];
890 int dup9, line_offset, depth_index;
891 uint32_t *palette;
892 uint32_t *ch_attr_ptr;
893 vga_draw_glyph8_func *vga_draw_glyph8;
894 vga_draw_glyph9_func *vga_draw_glyph9;
895
896 full_update |= update_palette16(s);
897 palette = s->last_palette;
898
899 /* compute font data address (in plane 2) */
900 v = s->sr[3];
901 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
902 if (offset != s->font_offsets[0]) {
903 s->font_offsets[0] = offset;
904 full_update = 1;
905 }
906 font_base[0] = s->vram_ptr + offset;
907
908 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
909 font_base[1] = s->vram_ptr + offset;
910 if (offset != s->font_offsets[1]) {
911 s->font_offsets[1] = offset;
912 full_update = 1;
913 }
914
915 full_update |= update_basic_params(s);
916
917 line_offset = s->line_offset;
918 s1 = s->vram_ptr + (s->start_addr * 4);
919
920 /* total width & height */
921 cheight = (s->cr[9] & 0x1f) + 1;
922 cw = 8;
923 if (s->sr[1] & 0x01)
924 cw = 9;
17b0018b
FB
925 if (s->sr[1] & 0x08)
926 cw = 16; /* NOTE: no 18 pixel wide */
e89f66ec
FB
927 x_incr = cw * ((s->ds->depth + 7) >> 3);
928 width = (s->cr[0x01] + 1);
17b0018b
FB
929 if (s->cr[0x06] == 100) {
930 /* ugly hack for CGA 160x100x16 - explain me the logic */
931 height = 100;
932 } else {
933 height = s->cr[0x12] |
934 ((s->cr[0x07] & 0x02) << 7) |
935 ((s->cr[0x07] & 0x40) << 3);
936 height = (height + 1) / cheight;
937 }
e89f66ec
FB
938 if (width != s->last_width || height != s->last_height ||
939 cw != s->last_cw || cw != s->last_cw) {
940 dpy_resize(s->ds, width * cw, height * cheight);
941 s->last_width = width;
942 s->last_height = height;
943 s->last_ch = cheight;
944 s->last_cw = cw;
945 full_update = 1;
946 }
947 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
948 if (cursor_offset != s->cursor_offset ||
949 s->cr[0xa] != s->cursor_start ||
950 s->cr[0xb] != s->cursor_end) {
951 /* if the cursor position changed, we update the old and new
952 chars */
953 if (s->cursor_offset < CH_ATTR_SIZE)
954 s->last_ch_attr[s->cursor_offset] = -1;
955 if (cursor_offset < CH_ATTR_SIZE)
956 s->last_ch_attr[cursor_offset] = -1;
957 s->cursor_offset = cursor_offset;
958 s->cursor_start = s->cr[0xa];
959 s->cursor_end = s->cr[0xb];
960 }
39cf7803 961 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
e89f66ec
FB
962
963 depth_index = get_depth_index(s->ds->depth);
17b0018b
FB
964 if (cw == 16)
965 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
966 else
967 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec
FB
968 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
969
970 dest = s->ds->data;
971 linesize = s->ds->linesize;
972 ch_attr_ptr = s->last_ch_attr;
973 for(cy = 0; cy < height; cy++) {
974 d1 = dest;
975 src = s1;
976 cx_min = width;
977 cx_max = -1;
978 for(cx = 0; cx < width; cx++) {
979 ch_attr = *(uint16_t *)src;
980 if (full_update || ch_attr != *ch_attr_ptr) {
981 if (cx < cx_min)
982 cx_min = cx;
983 if (cx > cx_max)
984 cx_max = cx;
985 *ch_attr_ptr = ch_attr;
986#ifdef WORDS_BIGENDIAN
987 ch = ch_attr >> 8;
988 cattr = ch_attr & 0xff;
989#else
990 ch = ch_attr & 0xff;
991 cattr = ch_attr >> 8;
992#endif
993 font_ptr = font_base[(cattr >> 3) & 1];
994 font_ptr += 32 * 4 * ch;
995 bgcol = palette[cattr >> 4];
996 fgcol = palette[cattr & 0x0f];
17b0018b 997 if (cw != 9) {
e89f66ec
FB
998 vga_draw_glyph8(d1, linesize,
999 font_ptr, cheight, fgcol, bgcol);
1000 } else {
1001 dup9 = 0;
1002 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1003 dup9 = 1;
1004 vga_draw_glyph9(d1, linesize,
1005 font_ptr, cheight, fgcol, bgcol, dup9);
1006 }
1007 if (src == cursor_ptr &&
1008 !(s->cr[0x0a] & 0x20)) {
1009 int line_start, line_last, h;
1010 /* draw the cursor */
1011 line_start = s->cr[0x0a] & 0x1f;
1012 line_last = s->cr[0x0b] & 0x1f;
1013 /* XXX: check that */
1014 if (line_last > cheight - 1)
1015 line_last = cheight - 1;
1016 if (line_last >= line_start && line_start < cheight) {
1017 h = line_last - line_start + 1;
1018 d = d1 + linesize * line_start;
17b0018b 1019 if (cw != 9) {
e89f66ec
FB
1020 vga_draw_glyph8(d, linesize,
1021 cursor_glyph, h, fgcol, bgcol);
1022 } else {
1023 vga_draw_glyph9(d, linesize,
1024 cursor_glyph, h, fgcol, bgcol, 1);
1025 }
1026 }
1027 }
1028 }
1029 d1 += x_incr;
1030 src += 4;
1031 ch_attr_ptr++;
1032 }
1033 if (cx_max != -1) {
1034 dpy_update(s->ds, cx_min * cw, cy * cheight,
1035 (cx_max - cx_min + 1) * cw, cheight);
1036 }
1037 dest += linesize * cheight;
1038 s1 += line_offset;
1039 }
1040}
1041
17b0018b
FB
1042enum {
1043 VGA_DRAW_LINE2,
1044 VGA_DRAW_LINE2D2,
1045 VGA_DRAW_LINE4,
1046 VGA_DRAW_LINE4D2,
1047 VGA_DRAW_LINE8D2,
1048 VGA_DRAW_LINE8,
1049 VGA_DRAW_LINE15,
1050 VGA_DRAW_LINE16,
1051 VGA_DRAW_LINE32,
1052 VGA_DRAW_LINE_NB,
1053};
1054
1055static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1056 vga_draw_line2_8,
1057 vga_draw_line2_16,
1058 vga_draw_line2_16,
1059 vga_draw_line2_32,
1060
17b0018b
FB
1061 vga_draw_line2d2_8,
1062 vga_draw_line2d2_16,
1063 vga_draw_line2d2_16,
1064 vga_draw_line2d2_32,
1065
e89f66ec
FB
1066 vga_draw_line4_8,
1067 vga_draw_line4_16,
1068 vga_draw_line4_16,
1069 vga_draw_line4_32,
1070
17b0018b
FB
1071 vga_draw_line4d2_8,
1072 vga_draw_line4d2_16,
1073 vga_draw_line4d2_16,
1074 vga_draw_line4d2_32,
1075
1076 vga_draw_line8d2_8,
1077 vga_draw_line8d2_16,
1078 vga_draw_line8d2_16,
1079 vga_draw_line8d2_32,
1080
e89f66ec
FB
1081 vga_draw_line8_8,
1082 vga_draw_line8_16,
1083 vga_draw_line8_16,
1084 vga_draw_line8_32,
1085
1086 vga_draw_line15_8,
1087 vga_draw_line15_15,
1088 vga_draw_line15_16,
1089 vga_draw_line15_32,
1090
1091 vga_draw_line16_8,
1092 vga_draw_line16_15,
1093 vga_draw_line16_16,
1094 vga_draw_line16_32,
1095
1096 vga_draw_line32_8,
1097 vga_draw_line32_15,
1098 vga_draw_line32_16,
1099 vga_draw_line32_32,
1100};
1101
1102/*
1103 * graphic modes
1104 * Missing:
1105 * - double scan
1106 * - double width
1107 */
1108static void vga_draw_graphic(VGAState *s, int full_update)
1109{
17b0018b 1110 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
39cf7803 1111 int width, height, shift_control, line_offset, page0, page1, bwidth;
17b0018b 1112 int disp_width;
e89f66ec 1113 uint8_t *d;
39cf7803 1114 uint32_t v, addr1, addr;
e89f66ec 1115 vga_draw_line_func *vga_draw_line;
17b0018b 1116
e89f66ec
FB
1117 full_update |= update_basic_params(s);
1118
39cf7803 1119 width = (s->cr[0x01] + 1) * 8;
e89f66ec
FB
1120 height = s->cr[0x12] |
1121 ((s->cr[0x07] & 0x02) << 7) |
1122 ((s->cr[0x07] & 0x40) << 3);
1123 height = (height + 1);
17b0018b
FB
1124 disp_width = width;
1125
e89f66ec 1126 shift_control = (s->gr[0x05] >> 5) & 3;
9da8ba18
FB
1127 if (shift_control > 1)
1128 double_scan = ((s->cr[0x09] & 0x1f) != 0);
1129 else
1130 double_scan = (s->cr[0x09] & 0x80);
17b0018b
FB
1131 if (shift_control != s->shift_control ||
1132 double_scan != s->double_scan) {
e89f66ec
FB
1133 full_update = 1;
1134 s->shift_control = shift_control;
17b0018b 1135 s->double_scan = double_scan;
e89f66ec
FB
1136 }
1137
17b0018b
FB
1138 if (shift_control == 0) {
1139 full_update |= update_palette16(s);
1140 if (s->sr[0x01] & 8) {
1141 v = VGA_DRAW_LINE4D2;
1142 disp_width <<= 1;
1143 } else {
1144 v = VGA_DRAW_LINE4;
1145 }
1146 } else if (shift_control == 1) {
1147 full_update |= update_palette16(s);
1148 if (s->sr[0x01] & 8) {
1149 v = VGA_DRAW_LINE2D2;
1150 disp_width <<= 1;
1151 } else {
1152 v = VGA_DRAW_LINE2;
1153 }
1154 } else {
1155 full_update |= update_palette256(s);
1156 v = VGA_DRAW_LINE8D2;
17b0018b 1157 }
e89f66ec 1158 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
17b0018b
FB
1159
1160 if (disp_width != s->last_width ||
1161 height != s->last_height) {
1162 dpy_resize(s->ds, disp_width, height);
1163 s->last_width = disp_width;
1164 s->last_height = height;
1165 full_update = 1;
1166 }
1167
e89f66ec 1168 line_offset = s->line_offset;
17b0018b
FB
1169#if 0
1170 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1171 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1172#endif
e89f66ec 1173 addr1 = (s->start_addr * 4);
39cf7803
FB
1174 bwidth = width * 4;
1175 y_start = -1;
e89f66ec
FB
1176 page_min = 0x7fffffff;
1177 page_max = -1;
1178 d = s->ds->data;
1179 linesize = s->ds->linesize;
17b0018b 1180 y1 = 0;
e89f66ec
FB
1181 for(y = 0; y < height; y++) {
1182 addr = addr1;
39cf7803 1183 if (!(s->cr[0x17] & 1)) {
17b0018b 1184 int shift;
e89f66ec 1185 /* CGA compatibility handling */
17b0018b
FB
1186 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1187 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1188 }
39cf7803 1189 if (!(s->cr[0x17] & 2)) {
17b0018b 1190 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec
FB
1191 }
1192 page0 = addr >> 12;
39cf7803 1193 page1 = (addr + bwidth - 1) >> 12;
e89f66ec 1194 update = full_update | s->vram_updated[page0] | s->vram_updated[page1];
39cf7803
FB
1195 if ((page1 - page0) > 1) {
1196 /* if wide line, can use another page */
1197 update |= s->vram_updated[page0 + 1];
1198 }
e89f66ec 1199 if (update) {
39cf7803
FB
1200 if (y_start < 0)
1201 y_start = y;
e89f66ec
FB
1202 if (page0 < page_min)
1203 page_min = page0;
1204 if (page1 > page_max)
1205 page_max = page1;
1206 vga_draw_line(s, d, s->vram_ptr + addr, width);
39cf7803
FB
1207 } else {
1208 if (y_start >= 0) {
1209 /* flush to display */
1210 dpy_update(s->ds, 0, y_start,
17b0018b 1211 disp_width, y - y_start);
39cf7803
FB
1212 y_start = -1;
1213 }
e89f66ec 1214 }
17b0018b
FB
1215 if (!double_scan || (y & 1) != 0) {
1216 if (y1 == s->line_compare) {
1217 addr1 = 0;
1218 } else {
1219 mask = (s->cr[0x17] & 3) ^ 3;
1220 if ((y1 & mask) == mask)
1221 addr1 += line_offset;
1222 }
1223 y1++;
e89f66ec
FB
1224 }
1225 d += linesize;
1226 }
39cf7803
FB
1227 if (y_start >= 0) {
1228 /* flush to display */
1229 dpy_update(s->ds, 0, y_start,
17b0018b 1230 disp_width, y - y_start);
39cf7803 1231 }
e89f66ec
FB
1232 /* reset modified pages */
1233 if (page_max != -1) {
1234 memset(s->vram_updated + page_min, 0, page_max - page_min + 1);
1235 }
1236}
1237
1238/* draw text terminal (very limited, just for simple boot debug
1239 messages) */
1240static int last_cursor_pos;
1241
1242void vga_draw_dumb(VGAState *s)
1243{
1244 int c, i, cursor_pos, eol;
1245
1246 cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8);
1247 eol = 0;
1248 for(i = last_cursor_pos; i < cursor_pos; i++) {
1249 /* XXX: should use vga RAM */
1250 c = phys_ram_base[0xb8000 + (i) * 2];
1251 if (c >= ' ') {
1252 putchar(c);
1253 eol = 0;
1254 } else {
1255 if (!eol)
1256 putchar('\n');
1257 eol = 1;
1258 }
1259 }
1260 fflush(stdout);
1261 last_cursor_pos = cursor_pos;
1262}
1263
1264void vga_update_display(void)
1265{
1266 VGAState *s = &vga_state;
1267 int full_update, graphic_mode;
1268
1269 if (s->ds->depth == 0) {
1270 vga_draw_dumb(s);
1271 } else {
1272 full_update = 0;
1273 graphic_mode = s->gr[6] & 1;
1274 if (graphic_mode != s->graphic_mode) {
1275 s->graphic_mode = graphic_mode;
1276 full_update = 1;
1277 }
1278 if (graphic_mode)
1279 vga_draw_graphic(s, full_update);
1280 else
1281 vga_draw_text(s, full_update);
1282 }
1283}
1284
1285void vga_reset(VGAState *s)
1286{
1287 memset(s, 0, sizeof(VGAState));
1288 /* chip ID for 8c968 */
1289 s->cr[0x2d] = 0x88;
1290 s->cr[0x2e] = 0xb0;
1291 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1292 s->cr[0x30] = 0xe1;
1293 s->graphic_mode = -1; /* force full update */
1294}
1295
1296CPUReadMemoryFunc *vga_mem_read[3] = {
1297 vga_mem_readb,
1298 vga_mem_readw,
1299 vga_mem_readl,
1300};
1301
1302CPUWriteMemoryFunc *vga_mem_write[3] = {
1303 vga_mem_writeb,
1304 vga_mem_writew,
1305 vga_mem_writel,
1306};
1307
1308int vga_init(DisplayState *ds, uint8_t *vga_ram_base,
1309 unsigned long vga_ram_offset, int vga_ram_size)
1310{
1311 VGAState *s = &vga_state;
17b0018b 1312 int i, j, v, b;
e89f66ec
FB
1313
1314 for(i = 0;i < 256; i++) {
1315 v = 0;
1316 for(j = 0; j < 8; j++) {
1317 v |= ((i >> j) & 1) << (j * 4);
1318 }
1319 expand4[i] = v;
1320
1321 v = 0;
1322 for(j = 0; j < 4; j++) {
1323 v |= ((i >> (2 * j)) & 3) << (j * 4);
1324 }
1325 expand2[i] = v;
1326 }
17b0018b
FB
1327 for(i = 0; i < 16; i++) {
1328 v = 0;
1329 for(j = 0; j < 4; j++) {
1330 b = ((i >> j) & 1);
1331 v |= b << (2 * j);
1332 v |= b << (2 * j + 1);
1333 }
1334 expand4to8[i] = v;
1335 }
e89f66ec
FB
1336
1337 vga_reset(s);
1338
17b0018b
FB
1339 switch(ds->depth) {
1340 case 8:
1341 s->rgb_to_pixel = rgb_to_pixel8_dup;
1342 break;
1343 case 15:
1344 s->rgb_to_pixel = rgb_to_pixel15_dup;
1345 break;
1346 default:
1347 case 16:
1348 s->rgb_to_pixel = rgb_to_pixel16_dup;
1349 break;
1350 case 32:
1351 s->rgb_to_pixel = rgb_to_pixel32_dup;
1352 break;
1353 }
1354
e89f66ec
FB
1355 s->vram_ptr = vga_ram_base;
1356 s->vram_offset = vga_ram_offset;
1357 s->vram_size = vga_ram_size;
1358 s->ds = ds;
1359
1360 register_ioport_write(0x3c0, 16, vga_ioport_write, 1);
1361
1362 register_ioport_write(0x3b4, 2, vga_ioport_write, 1);
1363 register_ioport_write(0x3d4, 2, vga_ioport_write, 1);
1364 register_ioport_write(0x3ba, 1, vga_ioport_write, 1);
1365 register_ioport_write(0x3da, 1, vga_ioport_write, 1);
1366
1367 register_ioport_read(0x3c0, 16, vga_ioport_read, 1);
1368
1369 register_ioport_read(0x3b4, 2, vga_ioport_read, 1);
1370 register_ioport_read(0x3d4, 2, vga_ioport_read, 1);
1371 register_ioport_read(0x3ba, 1, vga_ioport_read, 1);
1372 register_ioport_read(0x3da, 1, vga_ioport_read, 1);
1373
1374 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1375 cpu_register_physical_memory(0xa0000, 0x20000, vga_io_memory);
1376 return 0;
1377}