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