]> git.proxmox.com Git - qemu.git/blame - hw/vga.c
added generic physical memory dirty bit support
[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;
c92b2e84
FB
497 if (addr >= 0x8000)
498 return 0xff;
e89f66ec
FB
499 break;
500 }
501
502 if (s->sr[4] & 0x08) {
503 /* chain 4 mode : simplest access */
504 ret = s->vram_ptr[addr];
505 } else if (s->gr[5] & 0x10) {
506 /* odd/even mode (aka text mode mapping) */
507 plane = (s->gr[4] & 2) | (addr & 1);
508 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
509 } else {
510 /* standard VGA latched access */
511 s->latch = ((uint32_t *)s->vram_ptr)[addr];
512
513 if (!(s->gr[5] & 0x08)) {
514 /* read mode 0 */
515 plane = s->gr[4];
b8ed223b 516 ret = GET_PLANE(s->latch, plane);
e89f66ec
FB
517 } else {
518 /* read mode 1 */
519 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
520 ret |= ret >> 16;
521 ret |= ret >> 8;
522 ret = (~ret) & 0xff;
523 }
524 }
525 return ret;
526}
527
528static uint32_t vga_mem_readw(uint32_t addr)
529{
530 uint32_t v;
531 v = vga_mem_readb(addr);
532 v |= vga_mem_readb(addr + 1) << 8;
533 return v;
534}
535
536static uint32_t vga_mem_readl(uint32_t addr)
537{
538 uint32_t v;
539 v = vga_mem_readb(addr);
540 v |= vga_mem_readb(addr + 1) << 8;
541 v |= vga_mem_readb(addr + 2) << 16;
542 v |= vga_mem_readb(addr + 3) << 24;
543 return v;
544}
545
e89f66ec
FB
546/* called for accesses between 0xa0000 and 0xc0000 */
547void vga_mem_writeb(uint32_t addr, uint32_t val)
548{
549 VGAState *s = &vga_state;
550 int memory_map_mode, plane, write_mode, b, func_select;
551 uint32_t write_mask, bit_mask, set_mask;
552
17b0018b 553#ifdef DEBUG_VGA_MEM
e89f66ec
FB
554 printf("vga: [0x%x] = 0x%02x\n", addr, val);
555#endif
556 /* convert to VGA memory offset */
557 memory_map_mode = (s->gr[6] >> 2) & 3;
558 switch(memory_map_mode) {
559 case 0:
560 addr -= 0xa0000;
561 break;
562 case 1:
563 addr -= 0xa0000;
564 if (addr >= 0x10000)
565 return;
566 break;
567 case 2:
568 addr -= 0xb0000;
569 if (addr >= 0x8000)
570 return;
571 break;
572 default:
573 case 3:
574 addr -= 0xb8000;
c92b2e84
FB
575 if (addr >= 0x8000)
576 return;
e89f66ec
FB
577 break;
578 }
579
580 if (s->sr[4] & 0x08) {
581 /* chain 4 mode : simplest access */
582 plane = addr & 3;
583 if (s->sr[2] & (1 << plane)) {
584 s->vram_ptr[addr] = val;
17b0018b 585#ifdef DEBUG_VGA_MEM
e89f66ec
FB
586 printf("vga: chain4: [0x%x]\n", addr);
587#endif
588 s->vram_updated[addr >> 12] = 1;
589 }
590 } else if (s->gr[5] & 0x10) {
591 /* odd/even mode (aka text mode mapping) */
592 plane = (s->gr[4] & 2) | (addr & 1);
593 if (s->sr[2] & (1 << plane)) {
594 addr = ((addr & ~1) << 1) | plane;
595 s->vram_ptr[addr] = val;
17b0018b 596#ifdef DEBUG_VGA_MEM
e89f66ec
FB
597 printf("vga: odd/even: [0x%x]\n", addr);
598#endif
599 s->vram_updated[addr >> 12] = 1;
600 }
601 } else {
602 /* standard VGA latched access */
603 write_mode = s->gr[5] & 3;
604 switch(write_mode) {
605 default:
606 case 0:
607 /* rotate */
608 b = s->gr[3] & 7;
609 val = ((val >> b) | (val << (8 - b))) & 0xff;
610 val |= val << 8;
611 val |= val << 16;
612
613 /* apply set/reset mask */
614 set_mask = mask16[s->gr[1]];
615 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
616 bit_mask = s->gr[8];
617 break;
618 case 1:
619 val = s->latch;
620 goto do_write;
621 case 2:
622 val = mask16[val & 0x0f];
623 bit_mask = s->gr[8];
624 break;
625 case 3:
626 /* rotate */
627 b = s->gr[3] & 7;
a41bc9af 628 val = (val >> b) | (val << (8 - b));
e89f66ec
FB
629
630 bit_mask = s->gr[8] & val;
631 val = mask16[s->gr[0]];
632 break;
633 }
634
635 /* apply logical operation */
636 func_select = s->gr[3] >> 3;
637 switch(func_select) {
638 case 0:
639 default:
640 /* nothing to do */
641 break;
642 case 1:
643 /* and */
644 val &= s->latch;
645 break;
646 case 2:
647 /* or */
648 val |= s->latch;
649 break;
650 case 3:
651 /* xor */
652 val ^= s->latch;
653 break;
654 }
655
656 /* apply bit mask */
657 bit_mask |= bit_mask << 8;
658 bit_mask |= bit_mask << 16;
659 val = (val & bit_mask) | (s->latch & ~bit_mask);
660
661 do_write:
662 /* mask data according to sr[2] */
663 write_mask = mask16[s->sr[2]];
664 ((uint32_t *)s->vram_ptr)[addr] =
665 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
666 (val & write_mask);
17b0018b 667#ifdef DEBUG_VGA_MEM
e89f66ec
FB
668 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
669 addr * 4, write_mask, val);
670#endif
671 s->vram_updated[addr >> 10] = 1;
672 }
673}
674
675void vga_mem_writew(uint32_t addr, uint32_t val)
676{
677 vga_mem_writeb(addr, val & 0xff);
678 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
679}
680
681void vga_mem_writel(uint32_t addr, uint32_t val)
682{
683 vga_mem_writeb(addr, val & 0xff);
684 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
685 vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
686 vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
687}
688
e89f66ec
FB
689typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
690 const uint8_t *font_ptr, int h,
691 uint32_t fgcol, uint32_t bgcol);
692typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
693 const uint8_t *font_ptr, int h,
694 uint32_t fgcol, uint32_t bgcol, int dup9);
695typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
696 const uint8_t *s, int width);
697
698static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
699{
700 /* XXX: TODO */
701 return 0;
702}
703
704static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
705{
706 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
707}
708
709static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
710{
711 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
712}
713
714static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
715{
716 return (r << 16) | (g << 8) | b;
717}
718
719#define DEPTH 8
720#include "vga_template.h"
721
722#define DEPTH 15
723#include "vga_template.h"
724
725#define DEPTH 16
726#include "vga_template.h"
727
728#define DEPTH 32
729#include "vga_template.h"
730
731static inline int c6_to_8(int v)
732{
733 int b;
734 v &= 0x3f;
735 b = v & 1;
736 return (v << 2) | (b << 1) | b;
737}
738
17b0018b
FB
739static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
740{
741 unsigned int col;
742 col = rgb_to_pixel8(r, g, b);
743 col |= col << 8;
744 col |= col << 16;
745 return col;
746}
747
748static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
749{
750 unsigned int col;
751 col = rgb_to_pixel15(r, g, b);
752 col |= col << 16;
753 return col;
754}
755
756static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
757{
758 unsigned int col;
759 col = rgb_to_pixel16(r, g, b);
760 col |= col << 16;
761 return col;
762}
763
764static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
765{
766 unsigned int col;
767 col = rgb_to_pixel32(r, g, b);
768 return col;
769}
770
e89f66ec
FB
771/* return true if the palette was modified */
772static int update_palette16(VGAState *s)
773{
17b0018b 774 int full_update, i;
e89f66ec 775 uint32_t v, col, *palette;
e89f66ec
FB
776
777 full_update = 0;
778 palette = s->last_palette;
779 for(i = 0; i < 16; i++) {
780 v = s->ar[i];
781 if (s->ar[0x10] & 0x80)
782 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
783 else
784 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
785 v = v * 3;
17b0018b
FB
786 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
787 c6_to_8(s->palette[v + 1]),
788 c6_to_8(s->palette[v + 2]));
789 if (col != palette[i]) {
790 full_update = 1;
791 palette[i] = col;
e89f66ec 792 }
17b0018b
FB
793 }
794 return full_update;
795}
796
797/* return true if the palette was modified */
798static int update_palette256(VGAState *s)
799{
800 int full_update, i;
801 uint32_t v, col, *palette;
802
803 full_update = 0;
804 palette = s->last_palette;
805 v = 0;
806 for(i = 0; i < 256; i++) {
807 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
808 c6_to_8(s->palette[v + 1]),
809 c6_to_8(s->palette[v + 2]));
e89f66ec
FB
810 if (col != palette[i]) {
811 full_update = 1;
812 palette[i] = col;
813 }
17b0018b 814 v += 3;
e89f66ec
FB
815 }
816 return full_update;
817}
818
819/* update start_addr and line_offset. Return TRUE if modified */
820static int update_basic_params(VGAState *s)
821{
822 int full_update;
823 uint32_t start_addr, line_offset, line_compare, v;
824
825 full_update = 0;
826 /* compute line_offset in bytes */
a41bc9af
FB
827 line_offset = s->cr[0x13];
828#ifdef CONFIG_S3VGA
e89f66ec
FB
829 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
830 if (v == 0)
831 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
a41bc9af
FB
832 line_offset |= (v << 8);
833#endif
e89f66ec 834 line_offset <<= 3;
39cf7803 835
e89f66ec
FB
836 /* starting address */
837 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
a41bc9af 838#ifdef CONFIG_S3VGA
e89f66ec 839 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
a41bc9af 840#endif
e89f66ec
FB
841
842 /* line compare */
843 line_compare = s->cr[0x18] |
844 ((s->cr[0x07] & 0x10) << 4) |
845 ((s->cr[0x09] & 0x40) << 3);
846
847 if (line_offset != s->line_offset ||
848 start_addr != s->start_addr ||
849 line_compare != s->line_compare) {
850 s->line_offset = line_offset;
851 s->start_addr = start_addr;
852 s->line_compare = line_compare;
853 full_update = 1;
854 }
855 return full_update;
856}
857
858static inline int get_depth_index(int depth)
859{
860 switch(depth) {
861 default:
862 case 8:
863 return 0;
864 case 15:
865 return 1;
866 case 16:
867 return 2;
868 case 32:
869 return 3;
870 }
871}
872
873static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
874 vga_draw_glyph8_8,
875 vga_draw_glyph8_16,
876 vga_draw_glyph8_16,
877 vga_draw_glyph8_32,
878};
879
17b0018b
FB
880static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
881 vga_draw_glyph16_8,
882 vga_draw_glyph16_16,
883 vga_draw_glyph16_16,
884 vga_draw_glyph16_32,
885};
886
e89f66ec
FB
887static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
888 vga_draw_glyph9_8,
889 vga_draw_glyph9_16,
890 vga_draw_glyph9_16,
891 vga_draw_glyph9_32,
892};
893
894static const uint8_t cursor_glyph[32 * 4] = {
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 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
908 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
909 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
910 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
911};
912
913/*
914 * Text mode update
915 * Missing:
916 * - double scan
917 * - double width
918 * - underline
919 * - flashing
920 */
921static void vga_draw_text(VGAState *s, int full_update)
922{
923 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
924 int cx_min, cx_max, linesize, x_incr;
925 uint32_t offset, fgcol, bgcol, v, cursor_offset;
926 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
927 const uint8_t *font_ptr, *font_base[2];
928 int dup9, line_offset, depth_index;
929 uint32_t *palette;
930 uint32_t *ch_attr_ptr;
931 vga_draw_glyph8_func *vga_draw_glyph8;
932 vga_draw_glyph9_func *vga_draw_glyph9;
933
934 full_update |= update_palette16(s);
935 palette = s->last_palette;
936
937 /* compute font data address (in plane 2) */
938 v = s->sr[3];
939 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
940 if (offset != s->font_offsets[0]) {
941 s->font_offsets[0] = offset;
942 full_update = 1;
943 }
944 font_base[0] = s->vram_ptr + offset;
945
946 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
947 font_base[1] = s->vram_ptr + offset;
948 if (offset != s->font_offsets[1]) {
949 s->font_offsets[1] = offset;
950 full_update = 1;
951 }
952
953 full_update |= update_basic_params(s);
954
955 line_offset = s->line_offset;
956 s1 = s->vram_ptr + (s->start_addr * 4);
957
958 /* total width & height */
959 cheight = (s->cr[9] & 0x1f) + 1;
960 cw = 8;
961 if (s->sr[1] & 0x01)
962 cw = 9;
17b0018b
FB
963 if (s->sr[1] & 0x08)
964 cw = 16; /* NOTE: no 18 pixel wide */
e89f66ec
FB
965 x_incr = cw * ((s->ds->depth + 7) >> 3);
966 width = (s->cr[0x01] + 1);
17b0018b
FB
967 if (s->cr[0x06] == 100) {
968 /* ugly hack for CGA 160x100x16 - explain me the logic */
969 height = 100;
970 } else {
971 height = s->cr[0x12] |
972 ((s->cr[0x07] & 0x02) << 7) |
973 ((s->cr[0x07] & 0x40) << 3);
974 height = (height + 1) / cheight;
975 }
e89f66ec
FB
976 if (width != s->last_width || height != s->last_height ||
977 cw != s->last_cw || cw != s->last_cw) {
978 dpy_resize(s->ds, width * cw, height * cheight);
979 s->last_width = width;
980 s->last_height = height;
981 s->last_ch = cheight;
982 s->last_cw = cw;
983 full_update = 1;
984 }
985 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
986 if (cursor_offset != s->cursor_offset ||
987 s->cr[0xa] != s->cursor_start ||
988 s->cr[0xb] != s->cursor_end) {
989 /* if the cursor position changed, we update the old and new
990 chars */
991 if (s->cursor_offset < CH_ATTR_SIZE)
992 s->last_ch_attr[s->cursor_offset] = -1;
993 if (cursor_offset < CH_ATTR_SIZE)
994 s->last_ch_attr[cursor_offset] = -1;
995 s->cursor_offset = cursor_offset;
996 s->cursor_start = s->cr[0xa];
997 s->cursor_end = s->cr[0xb];
998 }
39cf7803 999 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
e89f66ec
FB
1000
1001 depth_index = get_depth_index(s->ds->depth);
17b0018b
FB
1002 if (cw == 16)
1003 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1004 else
1005 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec
FB
1006 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1007
1008 dest = s->ds->data;
1009 linesize = s->ds->linesize;
1010 ch_attr_ptr = s->last_ch_attr;
1011 for(cy = 0; cy < height; cy++) {
1012 d1 = dest;
1013 src = s1;
1014 cx_min = width;
1015 cx_max = -1;
1016 for(cx = 0; cx < width; cx++) {
1017 ch_attr = *(uint16_t *)src;
1018 if (full_update || ch_attr != *ch_attr_ptr) {
1019 if (cx < cx_min)
1020 cx_min = cx;
1021 if (cx > cx_max)
1022 cx_max = cx;
1023 *ch_attr_ptr = ch_attr;
1024#ifdef WORDS_BIGENDIAN
1025 ch = ch_attr >> 8;
1026 cattr = ch_attr & 0xff;
1027#else
1028 ch = ch_attr & 0xff;
1029 cattr = ch_attr >> 8;
1030#endif
1031 font_ptr = font_base[(cattr >> 3) & 1];
1032 font_ptr += 32 * 4 * ch;
1033 bgcol = palette[cattr >> 4];
1034 fgcol = palette[cattr & 0x0f];
17b0018b 1035 if (cw != 9) {
e89f66ec
FB
1036 vga_draw_glyph8(d1, linesize,
1037 font_ptr, cheight, fgcol, bgcol);
1038 } else {
1039 dup9 = 0;
1040 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1041 dup9 = 1;
1042 vga_draw_glyph9(d1, linesize,
1043 font_ptr, cheight, fgcol, bgcol, dup9);
1044 }
1045 if (src == cursor_ptr &&
1046 !(s->cr[0x0a] & 0x20)) {
1047 int line_start, line_last, h;
1048 /* draw the cursor */
1049 line_start = s->cr[0x0a] & 0x1f;
1050 line_last = s->cr[0x0b] & 0x1f;
1051 /* XXX: check that */
1052 if (line_last > cheight - 1)
1053 line_last = cheight - 1;
1054 if (line_last >= line_start && line_start < cheight) {
1055 h = line_last - line_start + 1;
1056 d = d1 + linesize * line_start;
17b0018b 1057 if (cw != 9) {
e89f66ec
FB
1058 vga_draw_glyph8(d, linesize,
1059 cursor_glyph, h, fgcol, bgcol);
1060 } else {
1061 vga_draw_glyph9(d, linesize,
1062 cursor_glyph, h, fgcol, bgcol, 1);
1063 }
1064 }
1065 }
1066 }
1067 d1 += x_incr;
1068 src += 4;
1069 ch_attr_ptr++;
1070 }
1071 if (cx_max != -1) {
1072 dpy_update(s->ds, cx_min * cw, cy * cheight,
1073 (cx_max - cx_min + 1) * cw, cheight);
1074 }
1075 dest += linesize * cheight;
1076 s1 += line_offset;
1077 }
1078}
1079
17b0018b
FB
1080enum {
1081 VGA_DRAW_LINE2,
1082 VGA_DRAW_LINE2D2,
1083 VGA_DRAW_LINE4,
1084 VGA_DRAW_LINE4D2,
1085 VGA_DRAW_LINE8D2,
1086 VGA_DRAW_LINE8,
1087 VGA_DRAW_LINE15,
1088 VGA_DRAW_LINE16,
1089 VGA_DRAW_LINE32,
1090 VGA_DRAW_LINE_NB,
1091};
1092
1093static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1094 vga_draw_line2_8,
1095 vga_draw_line2_16,
1096 vga_draw_line2_16,
1097 vga_draw_line2_32,
1098
17b0018b
FB
1099 vga_draw_line2d2_8,
1100 vga_draw_line2d2_16,
1101 vga_draw_line2d2_16,
1102 vga_draw_line2d2_32,
1103
e89f66ec
FB
1104 vga_draw_line4_8,
1105 vga_draw_line4_16,
1106 vga_draw_line4_16,
1107 vga_draw_line4_32,
1108
17b0018b
FB
1109 vga_draw_line4d2_8,
1110 vga_draw_line4d2_16,
1111 vga_draw_line4d2_16,
1112 vga_draw_line4d2_32,
1113
1114 vga_draw_line8d2_8,
1115 vga_draw_line8d2_16,
1116 vga_draw_line8d2_16,
1117 vga_draw_line8d2_32,
1118
e89f66ec
FB
1119 vga_draw_line8_8,
1120 vga_draw_line8_16,
1121 vga_draw_line8_16,
1122 vga_draw_line8_32,
1123
1124 vga_draw_line15_8,
1125 vga_draw_line15_15,
1126 vga_draw_line15_16,
1127 vga_draw_line15_32,
1128
1129 vga_draw_line16_8,
1130 vga_draw_line16_15,
1131 vga_draw_line16_16,
1132 vga_draw_line16_32,
1133
1134 vga_draw_line32_8,
1135 vga_draw_line32_15,
1136 vga_draw_line32_16,
1137 vga_draw_line32_32,
1138};
1139
1140/*
1141 * graphic modes
1142 * Missing:
1143 * - double scan
1144 * - double width
1145 */
1146static void vga_draw_graphic(VGAState *s, int full_update)
1147{
17b0018b 1148 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
39cf7803 1149 int width, height, shift_control, line_offset, page0, page1, bwidth;
a07cf92a 1150 int disp_width, multi_scan, multi_run;
e89f66ec 1151 uint8_t *d;
39cf7803 1152 uint32_t v, addr1, addr;
e89f66ec 1153 vga_draw_line_func *vga_draw_line;
17b0018b 1154
e89f66ec
FB
1155 full_update |= update_basic_params(s);
1156
39cf7803 1157 width = (s->cr[0x01] + 1) * 8;
e89f66ec
FB
1158 height = s->cr[0x12] |
1159 ((s->cr[0x07] & 0x02) << 7) |
1160 ((s->cr[0x07] & 0x40) << 3);
1161 height = (height + 1);
17b0018b
FB
1162 disp_width = width;
1163
e89f66ec 1164 shift_control = (s->gr[0x05] >> 5) & 3;
a07cf92a
FB
1165 double_scan = (s->cr[0x09] & 0x80);
1166 if (shift_control > 1) {
1167 multi_scan = (s->cr[0x09] & 0x1f);
1168 } else {
1169 multi_scan = 0;
1170 }
1171 multi_run = multi_scan;
17b0018b
FB
1172 if (shift_control != s->shift_control ||
1173 double_scan != s->double_scan) {
e89f66ec
FB
1174 full_update = 1;
1175 s->shift_control = shift_control;
17b0018b 1176 s->double_scan = double_scan;
e89f66ec
FB
1177 }
1178
17b0018b
FB
1179 if (shift_control == 0) {
1180 full_update |= update_palette16(s);
1181 if (s->sr[0x01] & 8) {
1182 v = VGA_DRAW_LINE4D2;
1183 disp_width <<= 1;
1184 } else {
1185 v = VGA_DRAW_LINE4;
1186 }
1187 } else if (shift_control == 1) {
1188 full_update |= update_palette16(s);
1189 if (s->sr[0x01] & 8) {
1190 v = VGA_DRAW_LINE2D2;
1191 disp_width <<= 1;
1192 } else {
1193 v = VGA_DRAW_LINE2;
1194 }
1195 } else {
1196 full_update |= update_palette256(s);
1197 v = VGA_DRAW_LINE8D2;
17b0018b 1198 }
e89f66ec 1199 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
17b0018b
FB
1200
1201 if (disp_width != s->last_width ||
1202 height != s->last_height) {
1203 dpy_resize(s->ds, disp_width, height);
1204 s->last_width = disp_width;
1205 s->last_height = height;
1206 full_update = 1;
1207 }
1208
e89f66ec 1209 line_offset = s->line_offset;
17b0018b
FB
1210#if 0
1211 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1212 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1213#endif
e89f66ec 1214 addr1 = (s->start_addr * 4);
39cf7803
FB
1215 bwidth = width * 4;
1216 y_start = -1;
e89f66ec
FB
1217 page_min = 0x7fffffff;
1218 page_max = -1;
1219 d = s->ds->data;
1220 linesize = s->ds->linesize;
17b0018b 1221 y1 = 0;
e89f66ec
FB
1222 for(y = 0; y < height; y++) {
1223 addr = addr1;
39cf7803 1224 if (!(s->cr[0x17] & 1)) {
17b0018b 1225 int shift;
e89f66ec 1226 /* CGA compatibility handling */
17b0018b
FB
1227 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1228 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1229 }
39cf7803 1230 if (!(s->cr[0x17] & 2)) {
17b0018b 1231 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec
FB
1232 }
1233 page0 = addr >> 12;
39cf7803 1234 page1 = (addr + bwidth - 1) >> 12;
e89f66ec 1235 update = full_update | s->vram_updated[page0] | s->vram_updated[page1];
39cf7803
FB
1236 if ((page1 - page0) > 1) {
1237 /* if wide line, can use another page */
1238 update |= s->vram_updated[page0 + 1];
1239 }
e89f66ec 1240 if (update) {
39cf7803
FB
1241 if (y_start < 0)
1242 y_start = y;
e89f66ec
FB
1243 if (page0 < page_min)
1244 page_min = page0;
1245 if (page1 > page_max)
1246 page_max = page1;
1247 vga_draw_line(s, d, s->vram_ptr + addr, width);
39cf7803
FB
1248 } else {
1249 if (y_start >= 0) {
1250 /* flush to display */
1251 dpy_update(s->ds, 0, y_start,
17b0018b 1252 disp_width, y - y_start);
39cf7803
FB
1253 y_start = -1;
1254 }
e89f66ec 1255 }
a07cf92a
FB
1256 if (!multi_run) {
1257 if (!double_scan || (y & 1) != 0) {
1258 if (y1 == s->line_compare) {
1259 addr1 = 0;
1260 } else {
1261 mask = (s->cr[0x17] & 3) ^ 3;
1262 if ((y1 & mask) == mask)
1263 addr1 += line_offset;
1264 }
1265 y1++;
17b0018b 1266 }
a07cf92a
FB
1267 multi_run = multi_scan;
1268 } else {
1269 multi_run--;
17b0018b 1270 y1++;
e89f66ec
FB
1271 }
1272 d += linesize;
1273 }
39cf7803
FB
1274 if (y_start >= 0) {
1275 /* flush to display */
1276 dpy_update(s->ds, 0, y_start,
17b0018b 1277 disp_width, y - y_start);
39cf7803 1278 }
e89f66ec
FB
1279 /* reset modified pages */
1280 if (page_max != -1) {
1281 memset(s->vram_updated + page_min, 0, page_max - page_min + 1);
1282 }
1283}
1284
1285/* draw text terminal (very limited, just for simple boot debug
1286 messages) */
1287static int last_cursor_pos;
1288
1289void vga_draw_dumb(VGAState *s)
1290{
1291 int c, i, cursor_pos, eol;
1292
1293 cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8);
1294 eol = 0;
1295 for(i = last_cursor_pos; i < cursor_pos; i++) {
1296 /* XXX: should use vga RAM */
1297 c = phys_ram_base[0xb8000 + (i) * 2];
1298 if (c >= ' ') {
1299 putchar(c);
1300 eol = 0;
1301 } else {
1302 if (!eol)
1303 putchar('\n');
1304 eol = 1;
1305 }
1306 }
1307 fflush(stdout);
1308 last_cursor_pos = cursor_pos;
1309}
1310
1311void vga_update_display(void)
1312{
1313 VGAState *s = &vga_state;
1314 int full_update, graphic_mode;
1315
1316 if (s->ds->depth == 0) {
1317 vga_draw_dumb(s);
1318 } else {
1319 full_update = 0;
1320 graphic_mode = s->gr[6] & 1;
1321 if (graphic_mode != s->graphic_mode) {
1322 s->graphic_mode = graphic_mode;
1323 full_update = 1;
1324 }
1325 if (graphic_mode)
1326 vga_draw_graphic(s, full_update);
1327 else
1328 vga_draw_text(s, full_update);
1329 }
1330}
1331
1332void vga_reset(VGAState *s)
1333{
1334 memset(s, 0, sizeof(VGAState));
a41bc9af 1335#ifdef CONFIG_S3VGA
e89f66ec
FB
1336 /* chip ID for 8c968 */
1337 s->cr[0x2d] = 0x88;
1338 s->cr[0x2e] = 0xb0;
1339 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1340 s->cr[0x30] = 0xe1;
a41bc9af 1341#endif
e89f66ec
FB
1342 s->graphic_mode = -1; /* force full update */
1343}
1344
1345CPUReadMemoryFunc *vga_mem_read[3] = {
1346 vga_mem_readb,
1347 vga_mem_readw,
1348 vga_mem_readl,
1349};
1350
1351CPUWriteMemoryFunc *vga_mem_write[3] = {
1352 vga_mem_writeb,
1353 vga_mem_writew,
1354 vga_mem_writel,
1355};
1356
7138fcfb
FB
1357int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1358 unsigned long vga_ram_offset, int vga_ram_size)
e89f66ec
FB
1359{
1360 VGAState *s = &vga_state;
17b0018b 1361 int i, j, v, b;
e89f66ec
FB
1362
1363 for(i = 0;i < 256; i++) {
1364 v = 0;
1365 for(j = 0; j < 8; j++) {
1366 v |= ((i >> j) & 1) << (j * 4);
1367 }
1368 expand4[i] = v;
1369
1370 v = 0;
1371 for(j = 0; j < 4; j++) {
1372 v |= ((i >> (2 * j)) & 3) << (j * 4);
1373 }
1374 expand2[i] = v;
1375 }
17b0018b
FB
1376 for(i = 0; i < 16; i++) {
1377 v = 0;
1378 for(j = 0; j < 4; j++) {
1379 b = ((i >> j) & 1);
1380 v |= b << (2 * j);
1381 v |= b << (2 * j + 1);
1382 }
1383 expand4to8[i] = v;
1384 }
e89f66ec
FB
1385
1386 vga_reset(s);
1387
17b0018b
FB
1388 switch(ds->depth) {
1389 case 8:
1390 s->rgb_to_pixel = rgb_to_pixel8_dup;
1391 break;
1392 case 15:
1393 s->rgb_to_pixel = rgb_to_pixel15_dup;
1394 break;
1395 default:
1396 case 16:
1397 s->rgb_to_pixel = rgb_to_pixel16_dup;
1398 break;
1399 case 32:
1400 s->rgb_to_pixel = rgb_to_pixel32_dup;
1401 break;
1402 }
1403
e89f66ec
FB
1404 s->vram_ptr = vga_ram_base;
1405 s->vram_offset = vga_ram_offset;
1406 s->vram_size = vga_ram_size;
1407 s->ds = ds;
1408
1409 register_ioport_write(0x3c0, 16, vga_ioport_write, 1);
1410
1411 register_ioport_write(0x3b4, 2, vga_ioport_write, 1);
1412 register_ioport_write(0x3d4, 2, vga_ioport_write, 1);
1413 register_ioport_write(0x3ba, 1, vga_ioport_write, 1);
1414 register_ioport_write(0x3da, 1, vga_ioport_write, 1);
1415
1416 register_ioport_read(0x3c0, 16, vga_ioport_read, 1);
1417
1418 register_ioport_read(0x3b4, 2, vga_ioport_read, 1);
1419 register_ioport_read(0x3d4, 2, vga_ioport_read, 1);
1420 register_ioport_read(0x3ba, 1, vga_ioport_read, 1);
1421 register_ioport_read(0x3da, 1, vga_ioport_read, 1);
1422
1423 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
7138fcfb
FB
1424#if defined (TARGET_I386)
1425 cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory);
1426#elif defined (TARGET_PPC)
1427 cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory);
1428#endif
e89f66ec
FB
1429 return 0;
1430}