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