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