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