]> git.proxmox.com Git - qemu.git/blame - hw/vga.c
PCI interrupt support - PCI BIOS interrupt remapping - more accurate memory mapping...
[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
5467a722
FB
33/* S3 VGA is deprecated - another graphic card will be emulated */
34//#define CONFIG_S3VGA
e89f66ec
FB
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
4fa0f5d2
FB
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
e89f66ec
FB
71typedef 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];
4f2ac237 95 int32_t bank_offset;
4fa0f5d2
FB
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;
cae61cef 101 uint32_t vbe_bank_mask;
4fa0f5d2 102#endif
e89f66ec 103 /* display refresh support */
e89f66ec
FB
104 DisplayState *ds;
105 uint32_t font_offsets[2];
106 int graphic_mode;
17b0018b
FB
107 uint8_t shift_control;
108 uint8_t double_scan;
e89f66ec
FB
109 uint32_t line_offset;
110 uint32_t line_compare;
111 uint32_t start_addr;
112 uint8_t last_cw, last_ch;
2aebb3eb
FB
113 uint32_t last_width, last_height; /* in chars or pixels */
114 uint32_t last_scr_width, last_scr_height; /* in pixels */
e89f66ec
FB
115 uint8_t cursor_start, cursor_end;
116 uint32_t cursor_offset;
17b0018b 117 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
39cf7803 118 /* tell for each page if it has been updated since the last time */
e89f66ec 119 uint32_t last_palette[256];
17b0018b 120#define CH_ATTR_SIZE (160 * 100)
e89f66ec
FB
121 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
122} VGAState;
123
124/* force some bits to zero */
125static 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
136static 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
b8ed223b 162#ifdef WORDS_BIGENDIAN
e89f66ec
FB
163#define PAT(x) cbswap_32(x)
164#else
165#define PAT(x) (x)
166#endif
167
b8ed223b
FB
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
e89f66ec
FB
180static 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
b8ed223b 201#ifdef WORDS_BIGENDIAN
e89f66ec
FB
202#define PAT(x) (x)
203#else
204#define PAT(x) cbswap_32(x)
205#endif
206
207static 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
226static const uint32_t dmask4[4] = {
227 PAT(0x00000000),
228 PAT(0x0000ffff),
229 PAT(0xffff0000),
230 PAT(0xffffffff),
231};
232
233static uint32_t expand4[256];
234static uint16_t expand2[256];
17b0018b 235static uint8_t expand4to8[16];
e89f66ec
FB
236
237VGAState vga_state;
238int vga_io_memory;
239
0f35920c 240static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
e89f66ec 241{
0f35920c 242 VGAState *s = opaque;
e89f66ec
FB
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];
a41bc9af
FB
273#ifdef DEBUG_VGA_REG
274 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
275#endif
e89f66ec
FB
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];
a41bc9af
FB
298#ifdef DEBUG_VGA_REG
299 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
300#endif
e89f66ec
FB
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];
a41bc9af
FB
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
e89f66ec
FB
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 }
4fa0f5d2 330#if defined(DEBUG_VGA)
e89f66ec
FB
331 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
332#endif
333 return val;
334}
335
0f35920c 336static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
e89f66ec 337{
0f35920c 338 VGAState *s = opaque;
5467a722 339 int index;
e89f66ec
FB
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:
a41bc9af
FB
389#ifdef DEBUG_VGA_REG
390 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
391#endif
e89f66ec
FB
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:
a41bc9af
FB
416#ifdef DEBUG_VGA_REG
417 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
418#endif
e89f66ec
FB
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:
a41bc9af
FB
427#ifdef DEBUG_VGA_REG
428 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
429#endif
e89f66ec
FB
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
a41bc9af 447#ifdef CONFIG_S3VGA
e89f66ec
FB
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 */
5467a722
FB
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 }
e89f66ec
FB
463 break;
464 case 0x51:
465 /* update start address */
5467a722
FB
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 }
e89f66ec 472 break;
a41bc9af 473#endif
e89f66ec
FB
474 default:
475 s->cr[s->cr_index] = val;
476 break;
477 }
a41bc9af
FB
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
e89f66ec
FB
483 break;
484 case 0x3ba:
485 case 0x3da:
486 s->fcr = val & 0x10;
487 break;
488 }
489}
490
4fa0f5d2 491#ifdef CONFIG_BOCHS_VBE
0f35920c 492static uint32_t vbe_ioport_read(void *opaque, uint32_t addr)
4fa0f5d2 493{
0f35920c 494 VGAState *s = opaque;
4fa0f5d2
FB
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
0f35920c 512static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
4fa0f5d2 513{
0f35920c 514 VGAState *s = opaque;
4fa0f5d2
FB
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:
cae61cef
FB
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 }
4fa0f5d2
FB
530 break;
531 case VBE_DISPI_INDEX_XRES:
cae61cef
FB
532 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
533 s->vbe_regs[s->vbe_index] = val;
534 }
4fa0f5d2
FB
535 break;
536 case VBE_DISPI_INDEX_YRES:
cae61cef
FB
537 if (val <= VBE_DISPI_MAX_YRES) {
538 s->vbe_regs[s->vbe_index] = val;
539 }
4fa0f5d2
FB
540 break;
541 case VBE_DISPI_INDEX_BPP:
542 if (val == 0)
543 val = 8;
cae61cef
FB
544 if (val == 4 || val == 8 || val == 15 ||
545 val == 16 || val == 24 || val == 32) {
546 s->vbe_regs[s->vbe_index] = val;
547 }
4fa0f5d2
FB
548 break;
549 case VBE_DISPI_INDEX_BANK:
cae61cef
FB
550 val &= s->vbe_bank_mask;
551 s->vbe_regs[s->vbe_index] = val;
26aa7d72 552 s->bank_offset = (val << 16);
4fa0f5d2
FB
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
cae61cef
FB
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 */
4fa0f5d2
FB
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;
646be93b 600 s->sr[4] |= 0x08; /* set chain 4 mode */
141253b2 601 s->sr[2] |= 0x0f; /* activate all planes */
4fa0f5d2
FB
602 }
603 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
604 s->cr[0x09] &= ~0x9f; /* no double scan */
cae61cef
FB
605 } else {
606 /* XXX: the bios should do that */
26aa7d72 607 s->bank_offset = 0;
cae61cef 608 }
141253b2 609 s->vbe_regs[s->vbe_index] = val;
cae61cef
FB
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;
4fa0f5d2
FB
643 }
644 break;
645 default:
646 break;
647 }
4fa0f5d2
FB
648 }
649}
650#endif
651
e89f66ec 652/* called for accesses between 0xa0000 and 0xc0000 */
2e12669a 653static uint32_t vga_mem_readb(target_phys_addr_t addr)
e89f66ec
FB
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;
26aa7d72 661 addr &= 0x1ffff;
e89f66ec
FB
662 switch(memory_map_mode) {
663 case 0:
e89f66ec
FB
664 break;
665 case 1:
26aa7d72 666 if (addr >= 0x10000)
e89f66ec 667 return 0xff;
cae61cef 668 addr += s->bank_offset;
e89f66ec
FB
669 break;
670 case 2:
26aa7d72 671 addr -= 0x10000;
e89f66ec
FB
672 if (addr >= 0x8000)
673 return 0xff;
674 break;
675 default:
676 case 3:
26aa7d72 677 addr -= 0x18000;
c92b2e84
FB
678 if (addr >= 0x8000)
679 return 0xff;
e89f66ec
FB
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];
b8ed223b 697 ret = GET_PLANE(s->latch, plane);
e89f66ec
FB
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
2e12669a 709static uint32_t vga_mem_readw(target_phys_addr_t addr)
e89f66ec
FB
710{
711 uint32_t v;
712 v = vga_mem_readb(addr);
713 v |= vga_mem_readb(addr + 1) << 8;
714 return v;
715}
716
2e12669a 717static uint32_t vga_mem_readl(target_phys_addr_t addr)
e89f66ec
FB
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
e89f66ec 727/* called for accesses between 0xa0000 and 0xc0000 */
2e12669a 728static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val)
e89f66ec
FB
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
17b0018b 734#ifdef DEBUG_VGA_MEM
e89f66ec
FB
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;
26aa7d72 739 addr &= 0x1ffff;
e89f66ec
FB
740 switch(memory_map_mode) {
741 case 0:
e89f66ec
FB
742 break;
743 case 1:
26aa7d72 744 if (addr >= 0x10000)
e89f66ec 745 return;
cae61cef 746 addr += s->bank_offset;
e89f66ec
FB
747 break;
748 case 2:
26aa7d72 749 addr -= 0x10000;
e89f66ec
FB
750 if (addr >= 0x8000)
751 return;
752 break;
753 default:
754 case 3:
26aa7d72 755 addr -= 0x18000;
c92b2e84
FB
756 if (addr >= 0x8000)
757 return;
e89f66ec
FB
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;
17b0018b 766#ifdef DEBUG_VGA_MEM
e89f66ec
FB
767 printf("vga: chain4: [0x%x]\n", addr);
768#endif
4fa0f5d2 769 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
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;
17b0018b 777#ifdef DEBUG_VGA_MEM
e89f66ec
FB
778 printf("vga: odd/even: [0x%x]\n", addr);
779#endif
4fa0f5d2 780 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
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;
a41bc9af 809 val = (val >> b) | (val << (8 - b));
e89f66ec
FB
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);
17b0018b 848#ifdef DEBUG_VGA_MEM
e89f66ec
FB
849 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
850 addr * 4, write_mask, val);
851#endif
4fa0f5d2 852 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
e89f66ec
FB
853 }
854}
855
2e12669a 856static void vga_mem_writew(target_phys_addr_t addr, uint32_t val)
e89f66ec 857{
5467a722
FB
858 vga_mem_writeb(addr, val & 0xff);
859 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
e89f66ec
FB
860}
861
2e12669a 862static void vga_mem_writel(target_phys_addr_t addr, uint32_t val)
e89f66ec 863{
5467a722
FB
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);
e89f66ec
FB
868}
869
e89f66ec
FB
870typedef 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);
873typedef 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);
876typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
877 const uint8_t *s, int width);
878
879static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
880{
881 /* XXX: TODO */
882 return 0;
883}
884
885static 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
890static 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
895static 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
912static 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
17b0018b
FB
920static 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
929static 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
937static 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
945static 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
e89f66ec
FB
952/* return true if the palette was modified */
953static int update_palette16(VGAState *s)
954{
17b0018b 955 int full_update, i;
e89f66ec 956 uint32_t v, col, *palette;
e89f66ec
FB
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;
17b0018b
FB
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;
e89f66ec 973 }
17b0018b
FB
974 }
975 return full_update;
976}
977
978/* return true if the palette was modified */
979static 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]));
e89f66ec
FB
991 if (col != palette[i]) {
992 full_update = 1;
993 palette[i] = col;
994 }
17b0018b 995 v += 3;
e89f66ec
FB
996 }
997 return full_update;
998}
999
1000/* update start_addr and line_offset. Return TRUE if modified */
1001static int update_basic_params(VGAState *s)
1002{
1003 int full_update;
5467a722 1004 uint32_t start_addr, line_offset, line_compare;
e89f66ec
FB
1005
1006 full_update = 0;
4fa0f5d2
FB
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];
a41bc9af 1017#ifdef CONFIG_S3VGA
5467a722
FB
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 }
a41bc9af 1025#endif
4fa0f5d2
FB
1026 line_offset <<= 3;
1027
1028 /* starting address */
1029 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
a41bc9af 1030#ifdef CONFIG_S3VGA
4fa0f5d2 1031 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
a41bc9af 1032#endif
4fa0f5d2
FB
1033 }
1034
e89f66ec
FB
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
1051static 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
1066static 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
17b0018b
FB
1073static 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
e89f66ec
FB
1080static 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
1087static 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 */
1114static 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;
eccabc6e 1154 if (!(s->sr[1] & 0x01))
e89f66ec 1155 cw = 9;
17b0018b
FB
1156 if (s->sr[1] & 0x08)
1157 cw = 16; /* NOTE: no 18 pixel wide */
e89f66ec
FB
1158 x_incr = cw * ((s->ds->depth + 7) >> 3);
1159 width = (s->cr[0x01] + 1);
17b0018b
FB
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 }
3294b949
FB
1169 if ((height * width) > CH_ATTR_SIZE) {
1170 /* better than nothing: exit if transient size is too big */
1171 return;
1172 }
1173
e89f66ec 1174 if (width != s->last_width || height != s->last_height ||
eccabc6e 1175 cw != s->last_cw || cheight != s->last_ch) {
2aebb3eb
FB
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);
e89f66ec
FB
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 }
39cf7803 1199 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
e89f66ec
FB
1200
1201 depth_index = get_depth_index(s->ds->depth);
17b0018b
FB
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];
e89f66ec
FB
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];
17b0018b 1235 if (cw != 9) {
e89f66ec
FB
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;
17b0018b 1257 if (cw != 9) {
e89f66ec
FB
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
17b0018b
FB
1280enum {
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,
4fa0f5d2 1289 VGA_DRAW_LINE24,
17b0018b
FB
1290 VGA_DRAW_LINE32,
1291 VGA_DRAW_LINE_NB,
1292};
1293
1294static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1295 vga_draw_line2_8,
1296 vga_draw_line2_16,
1297 vga_draw_line2_16,
1298 vga_draw_line2_32,
1299
17b0018b
FB
1300 vga_draw_line2d2_8,
1301 vga_draw_line2d2_16,
1302 vga_draw_line2d2_16,
1303 vga_draw_line2d2_32,
1304
e89f66ec
FB
1305 vga_draw_line4_8,
1306 vga_draw_line4_16,
1307 vga_draw_line4_16,
1308 vga_draw_line4_32,
1309
17b0018b
FB
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
e89f66ec
FB
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
4fa0f5d2
FB
1335 vga_draw_line24_8,
1336 vga_draw_line24_15,
1337 vga_draw_line24_16,
1338 vga_draw_line24_32,
1339
e89f66ec
FB
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 */
1352static void vga_draw_graphic(VGAState *s, int full_update)
1353{
17b0018b 1354 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
39cf7803 1355 int width, height, shift_control, line_offset, page0, page1, bwidth;
a07cf92a 1356 int disp_width, multi_scan, multi_run;
e89f66ec 1357 uint8_t *d;
39cf7803 1358 uint32_t v, addr1, addr;
e89f66ec 1359 vga_draw_line_func *vga_draw_line;
17b0018b 1360
e89f66ec
FB
1361 full_update |= update_basic_params(s);
1362
39cf7803 1363 width = (s->cr[0x01] + 1) * 8;
e89f66ec
FB
1364 height = s->cr[0x12] |
1365 ((s->cr[0x07] & 0x02) << 7) |
1366 ((s->cr[0x07] & 0x40) << 3);
1367 height = (height + 1);
17b0018b
FB
1368 disp_width = width;
1369
e89f66ec 1370 shift_control = (s->gr[0x05] >> 5) & 3;
a07cf92a
FB
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;
17b0018b
FB
1378 if (shift_control != s->shift_control ||
1379 double_scan != s->double_scan) {
e89f66ec
FB
1380 full_update = 1;
1381 s->shift_control = shift_control;
17b0018b 1382 s->double_scan = double_scan;
e89f66ec
FB
1383 }
1384
17b0018b
FB
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 {
4fa0f5d2
FB
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 }
17b0018b 1429 }
e89f66ec 1430 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
17b0018b
FB
1431
1432 if (disp_width != s->last_width ||
1433 height != s->last_height) {
1434 dpy_resize(s->ds, disp_width, height);
2aebb3eb
FB
1435 s->last_scr_width = disp_width;
1436 s->last_scr_height = height;
17b0018b
FB
1437 s->last_width = disp_width;
1438 s->last_height = height;
1439 full_update = 1;
1440 }
1441
e89f66ec 1442 line_offset = s->line_offset;
17b0018b
FB
1443#if 0
1444 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1445 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1446#endif
e89f66ec 1447 addr1 = (s->start_addr * 4);
39cf7803
FB
1448 bwidth = width * 4;
1449 y_start = -1;
e89f66ec
FB
1450 page_min = 0x7fffffff;
1451 page_max = -1;
1452 d = s->ds->data;
1453 linesize = s->ds->linesize;
17b0018b 1454 y1 = 0;
e89f66ec
FB
1455 for(y = 0; y < height; y++) {
1456 addr = addr1;
39cf7803 1457 if (!(s->cr[0x17] & 1)) {
17b0018b 1458 int shift;
e89f66ec 1459 /* CGA compatibility handling */
17b0018b
FB
1460 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1461 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1462 }
39cf7803 1463 if (!(s->cr[0x17] & 2)) {
17b0018b 1464 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1465 }
4fa0f5d2
FB
1466 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1467 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1468 update = full_update | cpu_physical_memory_is_dirty(page0) |
1469 cpu_physical_memory_is_dirty(page1);
1470 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1471 /* if wide line, can use another page */
4fa0f5d2 1472 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
39cf7803 1473 }
e89f66ec 1474 if (update) {
39cf7803
FB
1475 if (y_start < 0)
1476 y_start = y;
e89f66ec
FB
1477 if (page0 < page_min)
1478 page_min = page0;
1479 if (page1 > page_max)
1480 page_max = page1;
1481 vga_draw_line(s, d, s->vram_ptr + addr, width);
39cf7803
FB
1482 } else {
1483 if (y_start >= 0) {
1484 /* flush to display */
1485 dpy_update(s->ds, 0, y_start,
17b0018b 1486 disp_width, y - y_start);
39cf7803
FB
1487 y_start = -1;
1488 }
e89f66ec 1489 }
a07cf92a
FB
1490 if (!multi_run) {
1491 if (!double_scan || (y & 1) != 0) {
1492 if (y1 == s->line_compare) {
1493 addr1 = 0;
1494 } else {
1495 mask = (s->cr[0x17] & 3) ^ 3;
1496 if ((y1 & mask) == mask)
1497 addr1 += line_offset;
1498 }
1499 y1++;
17b0018b 1500 }
a07cf92a
FB
1501 multi_run = multi_scan;
1502 } else {
1503 multi_run--;
17b0018b 1504 y1++;
e89f66ec
FB
1505 }
1506 d += linesize;
1507 }
39cf7803
FB
1508 if (y_start >= 0) {
1509 /* flush to display */
1510 dpy_update(s->ds, 0, y_start,
17b0018b 1511 disp_width, y - y_start);
39cf7803 1512 }
e89f66ec
FB
1513 /* reset modified pages */
1514 if (page_max != -1) {
4fa0f5d2 1515 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
e89f66ec
FB
1516 }
1517}
1518
2aebb3eb
FB
1519static 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
e89f66ec
FB
1546void vga_update_display(void)
1547{
1548 VGAState *s = &vga_state;
1549 int full_update, graphic_mode;
1550
1551 if (s->ds->depth == 0) {
0f35920c 1552 /* nothing to do */
59a983b9
FB
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
e89f66ec 1570 full_update = 0;
2aebb3eb
FB
1571 if (!(s->ar_index & 0x20)) {
1572 graphic_mode = GMODE_BLANK;
1573 } else {
1574 graphic_mode = s->gr[6] & 1;
1575 }
e89f66ec
FB
1576 if (graphic_mode != s->graphic_mode) {
1577 s->graphic_mode = graphic_mode;
1578 full_update = 1;
1579 }
2aebb3eb
FB
1580 switch(graphic_mode) {
1581 case GMODE_TEXT:
e89f66ec 1582 vga_draw_text(s, full_update);
2aebb3eb
FB
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 }
e89f66ec
FB
1592 }
1593}
1594
59a983b9 1595static void vga_reset(VGAState *s)
e89f66ec
FB
1596{
1597 memset(s, 0, sizeof(VGAState));
a41bc9af 1598#ifdef CONFIG_S3VGA
e89f66ec
FB
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;
a41bc9af 1604#endif
e89f66ec
FB
1605 s->graphic_mode = -1; /* force full update */
1606}
1607
59a983b9 1608static CPUReadMemoryFunc *vga_mem_read[3] = {
e89f66ec
FB
1609 vga_mem_readb,
1610 vga_mem_readw,
1611 vga_mem_readl,
1612};
1613
59a983b9 1614static CPUWriteMemoryFunc *vga_mem_write[3] = {
e89f66ec
FB
1615 vga_mem_writeb,
1616 vga_mem_writew,
1617 vga_mem_writel,
1618};
1619
b0a21b53
FB
1620static 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
1661static 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
7138fcfb
FB
1712int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1713 unsigned long vga_ram_offset, int vga_ram_size)
e89f66ec
FB
1714{
1715 VGAState *s = &vga_state;
17b0018b 1716 int i, j, v, b;
e89f66ec
FB
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 }
17b0018b
FB
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 }
e89f66ec
FB
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
b0a21b53
FB
1748 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1749
0f35920c 1750 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
e89f66ec 1751
0f35920c
FB
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);
e89f66ec 1756
0f35920c 1757 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
e89f66ec 1758
0f35920c
FB
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);
26aa7d72 1763 s->bank_offset = 0;
e89f66ec 1764
4fa0f5d2
FB
1765#ifdef CONFIG_BOCHS_VBE
1766 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
cae61cef 1767 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
0f35920c
FB
1768 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s);
1769 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s);
4fa0f5d2 1770
0f35920c
FB
1771 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s);
1772 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s);
646be93b
FB
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);
4fa0f5d2
FB
1780#endif
1781
e89f66ec 1782 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
26aa7d72
FB
1783 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1784 vga_io_memory);
4fa0f5d2 1785#ifdef CONFIG_BOCHS_VBE
26aa7d72 1786#if defined (TARGET_I386)
4fa0f5d2
FB
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
7138fcfb 1791#endif
e89f66ec
FB
1792 return 0;
1793}
59a983b9
FB
1794
1795/********************************************************/
1796/* vga screen dump */
1797
1798static int vga_save_w, vga_save_h;
1799
1800static void vga_save_dpy_update(DisplayState *s,
1801 int x, int y, int w, int h)
1802{
1803}
1804
1805static 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
1813static void vga_save_dpy_refresh(DisplayState *s)
1814{
1815}
1816
1817static 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 */
1848void 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}