]> git.proxmox.com Git - mirror_qemu.git/blame - hw/vga.c
temporary hack for PowerPC system emulation
[mirror_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;
a07cf92a 1112 int disp_width, multi_scan, multi_run;
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;
a07cf92a
FB
1127 double_scan = (s->cr[0x09] & 0x80);
1128 if (shift_control > 1) {
1129 multi_scan = (s->cr[0x09] & 0x1f);
1130 } else {
1131 multi_scan = 0;
1132 }
1133 multi_run = multi_scan;
17b0018b
FB
1134 if (shift_control != s->shift_control ||
1135 double_scan != s->double_scan) {
e89f66ec
FB
1136 full_update = 1;
1137 s->shift_control = shift_control;
17b0018b 1138 s->double_scan = double_scan;
e89f66ec
FB
1139 }
1140
17b0018b
FB
1141 if (shift_control == 0) {
1142 full_update |= update_palette16(s);
1143 if (s->sr[0x01] & 8) {
1144 v = VGA_DRAW_LINE4D2;
1145 disp_width <<= 1;
1146 } else {
1147 v = VGA_DRAW_LINE4;
1148 }
1149 } else if (shift_control == 1) {
1150 full_update |= update_palette16(s);
1151 if (s->sr[0x01] & 8) {
1152 v = VGA_DRAW_LINE2D2;
1153 disp_width <<= 1;
1154 } else {
1155 v = VGA_DRAW_LINE2;
1156 }
1157 } else {
1158 full_update |= update_palette256(s);
1159 v = VGA_DRAW_LINE8D2;
17b0018b 1160 }
e89f66ec 1161 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
17b0018b
FB
1162
1163 if (disp_width != s->last_width ||
1164 height != s->last_height) {
1165 dpy_resize(s->ds, disp_width, height);
1166 s->last_width = disp_width;
1167 s->last_height = height;
1168 full_update = 1;
1169 }
1170
e89f66ec 1171 line_offset = s->line_offset;
17b0018b
FB
1172#if 0
1173 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1174 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1175#endif
e89f66ec 1176 addr1 = (s->start_addr * 4);
39cf7803
FB
1177 bwidth = width * 4;
1178 y_start = -1;
e89f66ec
FB
1179 page_min = 0x7fffffff;
1180 page_max = -1;
1181 d = s->ds->data;
1182 linesize = s->ds->linesize;
17b0018b 1183 y1 = 0;
e89f66ec
FB
1184 for(y = 0; y < height; y++) {
1185 addr = addr1;
39cf7803 1186 if (!(s->cr[0x17] & 1)) {
17b0018b 1187 int shift;
e89f66ec 1188 /* CGA compatibility handling */
17b0018b
FB
1189 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1190 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1191 }
39cf7803 1192 if (!(s->cr[0x17] & 2)) {
17b0018b 1193 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec
FB
1194 }
1195 page0 = addr >> 12;
39cf7803 1196 page1 = (addr + bwidth - 1) >> 12;
e89f66ec 1197 update = full_update | s->vram_updated[page0] | s->vram_updated[page1];
39cf7803
FB
1198 if ((page1 - page0) > 1) {
1199 /* if wide line, can use another page */
1200 update |= s->vram_updated[page0 + 1];
1201 }
e89f66ec 1202 if (update) {
39cf7803
FB
1203 if (y_start < 0)
1204 y_start = y;
e89f66ec
FB
1205 if (page0 < page_min)
1206 page_min = page0;
1207 if (page1 > page_max)
1208 page_max = page1;
1209 vga_draw_line(s, d, s->vram_ptr + addr, width);
39cf7803
FB
1210 } else {
1211 if (y_start >= 0) {
1212 /* flush to display */
1213 dpy_update(s->ds, 0, y_start,
17b0018b 1214 disp_width, y - y_start);
39cf7803
FB
1215 y_start = -1;
1216 }
e89f66ec 1217 }
a07cf92a
FB
1218 if (!multi_run) {
1219 if (!double_scan || (y & 1) != 0) {
1220 if (y1 == s->line_compare) {
1221 addr1 = 0;
1222 } else {
1223 mask = (s->cr[0x17] & 3) ^ 3;
1224 if ((y1 & mask) == mask)
1225 addr1 += line_offset;
1226 }
1227 y1++;
17b0018b 1228 }
a07cf92a
FB
1229 multi_run = multi_scan;
1230 } else {
1231 multi_run--;
17b0018b 1232 y1++;
e89f66ec
FB
1233 }
1234 d += linesize;
1235 }
39cf7803
FB
1236 if (y_start >= 0) {
1237 /* flush to display */
1238 dpy_update(s->ds, 0, y_start,
17b0018b 1239 disp_width, y - y_start);
39cf7803 1240 }
e89f66ec
FB
1241 /* reset modified pages */
1242 if (page_max != -1) {
1243 memset(s->vram_updated + page_min, 0, page_max - page_min + 1);
1244 }
1245}
1246
1247/* draw text terminal (very limited, just for simple boot debug
1248 messages) */
1249static int last_cursor_pos;
1250
1251void vga_draw_dumb(VGAState *s)
1252{
1253 int c, i, cursor_pos, eol;
1254
1255 cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8);
1256 eol = 0;
1257 for(i = last_cursor_pos; i < cursor_pos; i++) {
1258 /* XXX: should use vga RAM */
1259 c = phys_ram_base[0xb8000 + (i) * 2];
1260 if (c >= ' ') {
1261 putchar(c);
1262 eol = 0;
1263 } else {
1264 if (!eol)
1265 putchar('\n');
1266 eol = 1;
1267 }
1268 }
1269 fflush(stdout);
1270 last_cursor_pos = cursor_pos;
1271}
1272
1273void vga_update_display(void)
1274{
1275 VGAState *s = &vga_state;
1276 int full_update, graphic_mode;
1277
1278 if (s->ds->depth == 0) {
1279 vga_draw_dumb(s);
1280 } else {
1281 full_update = 0;
1282 graphic_mode = s->gr[6] & 1;
1283 if (graphic_mode != s->graphic_mode) {
1284 s->graphic_mode = graphic_mode;
1285 full_update = 1;
1286 }
1287 if (graphic_mode)
1288 vga_draw_graphic(s, full_update);
1289 else
1290 vga_draw_text(s, full_update);
1291 }
1292}
1293
1294void vga_reset(VGAState *s)
1295{
1296 memset(s, 0, sizeof(VGAState));
1297 /* chip ID for 8c968 */
1298 s->cr[0x2d] = 0x88;
1299 s->cr[0x2e] = 0xb0;
1300 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1301 s->cr[0x30] = 0xe1;
1302 s->graphic_mode = -1; /* force full update */
1303}
1304
1305CPUReadMemoryFunc *vga_mem_read[3] = {
1306 vga_mem_readb,
1307 vga_mem_readw,
1308 vga_mem_readl,
1309};
1310
1311CPUWriteMemoryFunc *vga_mem_write[3] = {
1312 vga_mem_writeb,
1313 vga_mem_writew,
1314 vga_mem_writel,
1315};
1316
1317int vga_init(DisplayState *ds, uint8_t *vga_ram_base,
1318 unsigned long vga_ram_offset, int vga_ram_size)
1319{
1320 VGAState *s = &vga_state;
17b0018b 1321 int i, j, v, b;
e89f66ec
FB
1322
1323 for(i = 0;i < 256; i++) {
1324 v = 0;
1325 for(j = 0; j < 8; j++) {
1326 v |= ((i >> j) & 1) << (j * 4);
1327 }
1328 expand4[i] = v;
1329
1330 v = 0;
1331 for(j = 0; j < 4; j++) {
1332 v |= ((i >> (2 * j)) & 3) << (j * 4);
1333 }
1334 expand2[i] = v;
1335 }
17b0018b
FB
1336 for(i = 0; i < 16; i++) {
1337 v = 0;
1338 for(j = 0; j < 4; j++) {
1339 b = ((i >> j) & 1);
1340 v |= b << (2 * j);
1341 v |= b << (2 * j + 1);
1342 }
1343 expand4to8[i] = v;
1344 }
e89f66ec
FB
1345
1346 vga_reset(s);
1347
17b0018b
FB
1348 switch(ds->depth) {
1349 case 8:
1350 s->rgb_to_pixel = rgb_to_pixel8_dup;
1351 break;
1352 case 15:
1353 s->rgb_to_pixel = rgb_to_pixel15_dup;
1354 break;
1355 default:
1356 case 16:
1357 s->rgb_to_pixel = rgb_to_pixel16_dup;
1358 break;
1359 case 32:
1360 s->rgb_to_pixel = rgb_to_pixel32_dup;
1361 break;
1362 }
1363
e89f66ec
FB
1364 s->vram_ptr = vga_ram_base;
1365 s->vram_offset = vga_ram_offset;
1366 s->vram_size = vga_ram_size;
1367 s->ds = ds;
1368
1369 register_ioport_write(0x3c0, 16, vga_ioport_write, 1);
1370
1371 register_ioport_write(0x3b4, 2, vga_ioport_write, 1);
1372 register_ioport_write(0x3d4, 2, vga_ioport_write, 1);
1373 register_ioport_write(0x3ba, 1, vga_ioport_write, 1);
1374 register_ioport_write(0x3da, 1, vga_ioport_write, 1);
1375
1376 register_ioport_read(0x3c0, 16, vga_ioport_read, 1);
1377
1378 register_ioport_read(0x3b4, 2, vga_ioport_read, 1);
1379 register_ioport_read(0x3d4, 2, vga_ioport_read, 1);
1380 register_ioport_read(0x3ba, 1, vga_ioport_read, 1);
1381 register_ioport_read(0x3da, 1, vga_ioport_read, 1);
1382
1383 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1384 cpu_register_physical_memory(0xa0000, 0x20000, vga_io_memory);
1385 return 0;
1386}