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