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