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