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