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