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