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