new directory structure
[qemu] / hw / vga.c
1 /*
2  * QEMU VGA Emulator. An S3 86c968 is emulated
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 <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <getopt.h>
29 #include <inttypes.h>
30 #include <unistd.h>
31 #include <sys/mman.h>
32 #include <fcntl.h>
33 #include <signal.h>
34 #include <time.h>
35 #include <sys/time.h>
36 #include <malloc.h>
37 #include <termios.h>
38 #include <sys/poll.h>
39 #include <errno.h>
40 #include <sys/wait.h>
41 #include <netinet/in.h>
42
43 #include "cpu.h"
44 #include "exec-all.h"
45
46 #include "vl.h"
47
48 #define NO_THUNK_TYPE_SIZE
49 #include "thunk.h"
50
51 //#define DEBUG_VGA
52 //#define DEBUG_VGA_MEM
53
54 #define MSR_COLOR_EMULATION 0x01
55 #define MSR_PAGE_SELECT     0x20
56
57 #define ST01_V_RETRACE      0x08
58 #define ST01_DISP_ENABLE    0x01
59
60 typedef struct VGAState {
61     uint8_t *vram_ptr;
62     unsigned long vram_offset;
63     unsigned int vram_size;
64     uint32_t latch;
65     uint8_t sr_index;
66     uint8_t sr[8];
67     uint8_t gr_index;
68     uint8_t gr[16];
69     uint8_t ar_index;
70     uint8_t ar[21];
71     int ar_flip_flop;
72     uint8_t cr_index;
73     uint8_t cr[256]; /* CRT registers */
74     uint8_t msr; /* Misc Output Register */
75     uint8_t fcr; /* Feature Control Register */
76     uint8_t st00; /* status 0 */
77     uint8_t st01; /* status 1 */
78     uint8_t dac_state;
79     uint8_t dac_sub_index;
80     uint8_t dac_read_index;
81     uint8_t dac_write_index;
82     uint8_t dac_cache[3]; /* used when writing */
83     uint8_t palette[768];
84
85     /* display refresh support */
86     DisplayState *ds;
87     uint32_t font_offsets[2];
88     int graphic_mode;
89     uint8_t shift_control;
90     uint8_t double_scan;
91     uint32_t line_offset;
92     uint32_t line_compare;
93     uint32_t start_addr;
94     uint8_t last_cw, last_ch;
95     uint32_t last_width, last_height;
96     uint8_t cursor_start, cursor_end;
97     uint32_t cursor_offset;
98     unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
99     /* tell for each page if it has been updated since the last time */
100     uint8_t vram_updated[VGA_RAM_SIZE / 4096];
101     uint32_t last_palette[256];
102 #define CH_ATTR_SIZE (160 * 100)
103     uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
104 } VGAState;
105
106 /* force some bits to zero */
107 static const uint8_t sr_mask[8] = {
108     (uint8_t)~0xfc,
109     (uint8_t)~0xc2,
110     (uint8_t)~0xf0,
111     (uint8_t)~0xc0,
112     (uint8_t)~0xf1,
113     (uint8_t)~0xff,
114     (uint8_t)~0xff,
115     (uint8_t)~0x00,
116 };
117
118 static const uint8_t gr_mask[16] = {
119     (uint8_t)~0xf0, /* 0x00 */
120     (uint8_t)~0xf0, /* 0x01 */
121     (uint8_t)~0xf0, /* 0x02 */
122     (uint8_t)~0xe0, /* 0x03 */
123     (uint8_t)~0xfc, /* 0x04 */
124     (uint8_t)~0x84, /* 0x05 */
125     (uint8_t)~0xf0, /* 0x06 */
126     (uint8_t)~0xf0, /* 0x07 */
127     (uint8_t)~0x00, /* 0x08 */
128     (uint8_t)~0xff, /* 0x09 */
129     (uint8_t)~0xff, /* 0x0a */
130     (uint8_t)~0xff, /* 0x0b */
131     (uint8_t)~0xff, /* 0x0c */
132     (uint8_t)~0xff, /* 0x0d */
133     (uint8_t)~0xff, /* 0x0e */
134     (uint8_t)~0xff, /* 0x0f */
135 };
136
137 #define cbswap_32(__x) \
138 ((uint32_t)( \
139                 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
140                 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
141                 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
142                 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
143
144 #ifdef WORD_BIGENDIAN
145 #define PAT(x) cbswap_32(x)
146 #else
147 #define PAT(x) (x)
148 #endif
149
150 static const uint32_t mask16[16] = {
151     PAT(0x00000000),
152     PAT(0x000000ff),
153     PAT(0x0000ff00),
154     PAT(0x0000ffff),
155     PAT(0x00ff0000),
156     PAT(0x00ff00ff),
157     PAT(0x00ffff00),
158     PAT(0x00ffffff),
159     PAT(0xff000000),
160     PAT(0xff0000ff),
161     PAT(0xff00ff00),
162     PAT(0xff00ffff),
163     PAT(0xffff0000),
164     PAT(0xffff00ff),
165     PAT(0xffffff00),
166     PAT(0xffffffff),
167 };
168
169 #undef PAT
170
171 #ifdef WORD_BIGENDIAN
172 #define PAT(x) (x)
173 #else
174 #define PAT(x) cbswap_32(x)
175 #endif
176
177 static const uint32_t dmask16[16] = {
178     PAT(0x00000000),
179     PAT(0x000000ff),
180     PAT(0x0000ff00),
181     PAT(0x0000ffff),
182     PAT(0x00ff0000),
183     PAT(0x00ff00ff),
184     PAT(0x00ffff00),
185     PAT(0x00ffffff),
186     PAT(0xff000000),
187     PAT(0xff0000ff),
188     PAT(0xff00ff00),
189     PAT(0xff00ffff),
190     PAT(0xffff0000),
191     PAT(0xffff00ff),
192     PAT(0xffffff00),
193     PAT(0xffffffff),
194 };
195
196 static const uint32_t dmask4[4] = {
197     PAT(0x00000000),
198     PAT(0x0000ffff),
199     PAT(0xffff0000),
200     PAT(0xffffffff),
201 };
202
203 static uint32_t expand4[256];
204 static uint16_t expand2[256];
205 static uint8_t expand4to8[16];
206
207 VGAState vga_state;
208 int vga_io_memory;
209
210 static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr)
211 {
212     VGAState *s = &vga_state;
213     int val, index;
214
215     /* check port range access depending on color/monochrome mode */
216     if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
217         (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
218         val = 0xff;
219     } else {
220         switch(addr) {
221         case 0x3c0:
222             if (s->ar_flip_flop == 0) {
223                 val = s->ar_index;
224             } else {
225                 val = 0;
226             }
227             break;
228         case 0x3c1:
229             index = s->ar_index & 0x1f;
230             if (index < 21) 
231                 val = s->ar[index];
232             else
233                 val = 0;
234             break;
235         case 0x3c2:
236             val = s->st00;
237             break;
238         case 0x3c4:
239             val = s->sr_index;
240             break;
241         case 0x3c5:
242             val = s->sr[s->sr_index];
243             break;
244         case 0x3c7:
245             val = s->dac_state;
246             break;
247         case 0x3c9:
248             val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
249             if (++s->dac_sub_index == 3) {
250                 s->dac_sub_index = 0;
251                 s->dac_read_index++;
252             }
253             break;
254         case 0x3ca:
255             val = s->fcr;
256             break;
257         case 0x3cc:
258             val = s->msr;
259             break;
260         case 0x3ce:
261             val = s->gr_index;
262             break;
263         case 0x3cf:
264             val = s->gr[s->gr_index];
265             break;
266         case 0x3b4:
267         case 0x3d4:
268             val = s->cr_index;
269             break;
270         case 0x3b5:
271         case 0x3d5:
272             val = s->cr[s->cr_index];
273             break;
274         case 0x3ba:
275         case 0x3da:
276             /* just toggle to fool polling */
277             s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
278             val = s->st01;
279             s->ar_flip_flop = 0;
280             break;
281         default:
282             val = 0x00;
283             break;
284         }
285     }
286 #ifdef DEBUG_VGA
287     printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
288 #endif
289     return val;
290 }
291
292 static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
293 {
294     VGAState *s = &vga_state;
295     int index, v;
296
297     /* check port range access depending on color/monochrome mode */
298     if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
299         (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
300         return;
301
302 #ifdef DEBUG_VGA
303     printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
304 #endif
305
306     switch(addr) {
307     case 0x3c0:
308         if (s->ar_flip_flop == 0) {
309             val &= 0x3f;
310             s->ar_index = val;
311         } else {
312             index = s->ar_index & 0x1f;
313             switch(index) {
314             case 0x00 ... 0x0f:
315                 s->ar[index] = val & 0x3f;
316                 break;
317             case 0x10:
318                 s->ar[index] = val & ~0x10;
319                 break;
320             case 0x11:
321                 s->ar[index] = val;
322                 break;
323             case 0x12:
324                 s->ar[index] = val & ~0xc0;
325                 break;
326             case 0x13:
327                 s->ar[index] = val & ~0xf0;
328                 break;
329             case 0x14:
330                 s->ar[index] = val & ~0xf0;
331                 break;
332             default:
333                 break;
334             }
335         }
336         s->ar_flip_flop ^= 1;
337         break;
338     case 0x3c2:
339         s->msr = val & ~0x10;
340         break;
341     case 0x3c4:
342         s->sr_index = val & 7;
343         break;
344     case 0x3c5:
345         s->sr[s->sr_index] = val & sr_mask[s->sr_index];
346         break;
347     case 0x3c7:
348         s->dac_read_index = val;
349         s->dac_sub_index = 0;
350         s->dac_state = 3;
351         break;
352     case 0x3c8:
353         s->dac_write_index = val;
354         s->dac_sub_index = 0;
355         s->dac_state = 0;
356         break;
357     case 0x3c9:
358         s->dac_cache[s->dac_sub_index] = val;
359         if (++s->dac_sub_index == 3) {
360             memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
361             s->dac_sub_index = 0;
362             s->dac_write_index++;
363         }
364         break;
365     case 0x3ce:
366         s->gr_index = val & 0x0f;
367         break;
368     case 0x3cf:
369         s->gr[s->gr_index] = val & gr_mask[s->gr_index];
370         break;
371     case 0x3b4:
372     case 0x3d4:
373         s->cr_index = val;
374         break;
375     case 0x3b5:
376     case 0x3d5:
377         /* handle CR0-7 protection */
378         if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
379             /* can always write bit 4 of CR7 */
380             if (s->cr_index == 7)
381                 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
382             return;
383         }
384         switch(s->cr_index) {
385         case 0x01: /* horizontal display end */
386         case 0x07:
387         case 0x09:
388         case 0x0c:
389         case 0x0d:
390         case 0x12: /* veritcal display end */
391             s->cr[s->cr_index] = val;
392             break;
393
394             /* S3 registers */
395         case 0x2d:
396         case 0x2e:
397         case 0x2f:
398         case 0x30:
399             /* chip ID, cannot write */
400             break;
401         case 0x31:
402             /* update start address */
403             s->cr[s->cr_index] = val;
404             v = (val >> 4) & 3;
405             s->cr[0x69] = (s->cr[69] & ~0x03) | v;
406             break;
407         case 0x51:
408             /* update start address */
409             s->cr[s->cr_index] = val;
410             v = val & 3;
411             s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
412             break;
413         default:
414             s->cr[s->cr_index] = val;
415             break;
416         }
417         break;
418     case 0x3ba:
419     case 0x3da:
420         s->fcr = val & 0x10;
421         break;
422     }
423 }
424
425 /* called for accesses between 0xa0000 and 0xc0000 */
426 static uint32_t vga_mem_readb(uint32_t addr)
427 {
428     VGAState *s = &vga_state;
429     int memory_map_mode, plane;
430     uint32_t ret;
431     
432     /* convert to VGA memory offset */
433     memory_map_mode = (s->gr[6] >> 2) & 3;
434     switch(memory_map_mode) {
435     case 0:
436         addr -= 0xa0000;
437         break;
438     case 1:
439         addr -= 0xa0000;
440         if (addr >= 0x10000)
441             return 0xff;
442         break;
443     case 2:
444         addr -= 0xb0000;
445         if (addr >= 0x8000)
446             return 0xff;
447         break;
448     default:
449     case 3:
450         addr -= 0xb8000;
451         break;
452     }
453     
454     if (s->sr[4] & 0x08) {
455         /* chain 4 mode : simplest access */
456         ret = s->vram_ptr[addr];
457     } else if (s->gr[5] & 0x10) {
458         /* odd/even mode (aka text mode mapping) */
459         plane = (s->gr[4] & 2) | (addr & 1);
460         ret = s->vram_ptr[((addr & ~1) << 1) | plane];
461     } else {
462         /* standard VGA latched access */
463         s->latch = ((uint32_t *)s->vram_ptr)[addr];
464
465         if (!(s->gr[5] & 0x08)) {
466             /* read mode 0 */
467             plane = s->gr[4];
468 #ifdef WORD_BIGENDIAN
469             ret = (s->latch >> (24 - (plane * 8))) & 0xff;
470 #else
471             ret = (s->latch >> (plane * 8)) & 0xff;
472 #endif
473         } else {
474             /* read mode 1 */
475             ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
476             ret |= ret >> 16;
477             ret |= ret >> 8;
478             ret = (~ret) & 0xff;
479         }
480     }
481     return ret;
482 }
483
484 static uint32_t vga_mem_readw(uint32_t addr)
485 {
486     uint32_t v;
487     v = vga_mem_readb(addr);
488     v |= vga_mem_readb(addr + 1) << 8;
489     return v;
490 }
491
492 static uint32_t vga_mem_readl(uint32_t addr)
493 {
494     uint32_t v;
495     v = vga_mem_readb(addr);
496     v |= vga_mem_readb(addr + 1) << 8;
497     v |= vga_mem_readb(addr + 2) << 16;
498     v |= vga_mem_readb(addr + 3) << 24;
499     return v;
500 }
501
502
503 /* called for accesses between 0xa0000 and 0xc0000 */
504 void vga_mem_writeb(uint32_t addr, uint32_t val)
505 {
506     VGAState *s = &vga_state;
507     int memory_map_mode, plane, write_mode, b, func_select;
508     uint32_t write_mask, bit_mask, set_mask;
509
510 #ifdef DEBUG_VGA_MEM
511     printf("vga: [0x%x] = 0x%02x\n", addr, val);
512 #endif
513     /* convert to VGA memory offset */
514     memory_map_mode = (s->gr[6] >> 2) & 3;
515     switch(memory_map_mode) {
516     case 0:
517         addr -= 0xa0000;
518         break;
519     case 1:
520         addr -= 0xa0000;
521         if (addr >= 0x10000)
522             return;
523         break;
524     case 2:
525         addr -= 0xb0000;
526         if (addr >= 0x8000)
527             return;
528         break;
529     default:
530     case 3:
531         addr -= 0xb8000;
532         break;
533     }
534     
535     if (s->sr[4] & 0x08) {
536         /* chain 4 mode : simplest access */
537         plane = addr & 3;
538         if (s->sr[2] & (1 << plane)) {
539             s->vram_ptr[addr] = val;
540 #ifdef DEBUG_VGA_MEM
541             printf("vga: chain4: [0x%x]\n", addr);
542 #endif
543             s->vram_updated[addr >> 12] = 1;
544         }
545     } else if (s->gr[5] & 0x10) {
546         /* odd/even mode (aka text mode mapping) */
547         plane = (s->gr[4] & 2) | (addr & 1);
548         if (s->sr[2] & (1 << plane)) {
549             addr = ((addr & ~1) << 1) | plane;
550             s->vram_ptr[addr] = val;
551 #ifdef DEBUG_VGA_MEM
552             printf("vga: odd/even: [0x%x]\n", addr);
553 #endif
554             s->vram_updated[addr >> 12] = 1;
555         }
556     } else {
557         /* standard VGA latched access */
558         write_mode = s->gr[5] & 3;
559         switch(write_mode) {
560         default:
561         case 0:
562             /* rotate */
563             b = s->gr[3] & 7;
564             val = ((val >> b) | (val << (8 - b))) & 0xff;
565             val |= val << 8;
566             val |= val << 16;
567
568             /* apply set/reset mask */
569             set_mask = mask16[s->gr[1]];
570             val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
571             bit_mask = s->gr[8];
572             break;
573         case 1:
574             val = s->latch;
575             goto do_write;
576         case 2:
577             val = mask16[val & 0x0f];
578             bit_mask = s->gr[8];
579             break;
580         case 3:
581             /* rotate */
582             b = s->gr[3] & 7;
583             val = ((val >> b) | (val << (8 - b)));
584
585             bit_mask = s->gr[8] & val;
586             val = mask16[s->gr[0]];
587             break;
588         }
589
590         /* apply logical operation */
591         func_select = s->gr[3] >> 3;
592         switch(func_select) {
593         case 0:
594         default:
595             /* nothing to do */
596             break;
597         case 1:
598             /* and */
599             val &= s->latch;
600             break;
601         case 2:
602             /* or */
603             val |= s->latch;
604             break;
605         case 3:
606             /* xor */
607             val ^= s->latch;
608             break;
609         }
610
611         /* apply bit mask */
612         bit_mask |= bit_mask << 8;
613         bit_mask |= bit_mask << 16;
614         val = (val & bit_mask) | (s->latch & ~bit_mask);
615
616     do_write:
617         /* mask data according to sr[2] */
618         write_mask = mask16[s->sr[2]];
619         ((uint32_t *)s->vram_ptr)[addr] = 
620             (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | 
621             (val & write_mask);
622 #ifdef DEBUG_VGA_MEM
623             printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", 
624                    addr * 4, write_mask, val);
625 #endif
626         s->vram_updated[addr >> 10] = 1;
627     }
628 }
629
630 void vga_mem_writew(uint32_t addr, uint32_t val)
631 {
632     vga_mem_writeb(addr, val & 0xff);
633     vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
634 }
635
636 void vga_mem_writel(uint32_t addr, uint32_t val)
637 {
638     vga_mem_writeb(addr, val & 0xff);
639     vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
640     vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
641     vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
642 }
643
644 #ifdef WORD_BIGENDIAN
645 #define BIG 1
646 #else
647 #define BIG 0
648 #endif
649
650 #ifdef WORDS_BIGENDIAN
651 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
652 #else
653 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
654 #endif
655
656 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
657                              const uint8_t *font_ptr, int h,
658                              uint32_t fgcol, uint32_t bgcol);
659 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
660                                   const uint8_t *font_ptr, int h, 
661                                   uint32_t fgcol, uint32_t bgcol, int dup9);
662 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, 
663                                 const uint8_t *s, int width);
664
665 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
666 {
667     /* XXX: TODO */
668     return 0;
669 }
670
671 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
672 {
673     return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
674 }
675
676 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
677 {
678     return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
679 }
680
681 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
682 {
683     return (r << 16) | (g << 8) | b;
684 }
685
686 #define DEPTH 8
687 #include "vga_template.h"
688
689 #define DEPTH 15
690 #include "vga_template.h"
691
692 #define DEPTH 16
693 #include "vga_template.h"
694
695 #define DEPTH 32
696 #include "vga_template.h"
697
698 static inline int c6_to_8(int v)
699 {
700     int b;
701     v &= 0x3f;
702     b = v & 1;
703     return (v << 2) | (b << 1) | b;
704 }
705
706 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
707 {
708     unsigned int col;
709     col = rgb_to_pixel8(r, g, b);
710     col |= col << 8;
711     col |= col << 16;
712     return col;
713 }
714
715 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
716 {
717     unsigned int col;
718     col = rgb_to_pixel15(r, g, b);
719     col |= col << 16;
720     return col;
721 }
722
723 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
724 {
725     unsigned int col;
726     col = rgb_to_pixel16(r, g, b);
727     col |= col << 16;
728     return col;
729 }
730
731 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
732 {
733     unsigned int col;
734     col = rgb_to_pixel32(r, g, b);
735     return col;
736 }
737
738 /* return true if the palette was modified */
739 static int update_palette16(VGAState *s)
740 {
741     int full_update, i;
742     uint32_t v, col, *palette;
743
744     full_update = 0;
745     palette = s->last_palette;
746     for(i = 0; i < 16; i++) {
747         v = s->ar[i];
748         if (s->ar[0x10] & 0x80)
749             v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
750         else
751             v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
752         v = v * 3;
753         col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
754                               c6_to_8(s->palette[v + 1]), 
755                               c6_to_8(s->palette[v + 2]));
756         if (col != palette[i]) {
757             full_update = 1;
758             palette[i] = col;
759         }
760     }
761     return full_update;
762 }
763
764 /* return true if the palette was modified */
765 static int update_palette256(VGAState *s)
766 {
767     int full_update, i;
768     uint32_t v, col, *palette;
769
770     full_update = 0;
771     palette = s->last_palette;
772     v = 0;
773     for(i = 0; i < 256; i++) {
774         col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
775                               c6_to_8(s->palette[v + 1]), 
776                               c6_to_8(s->palette[v + 2]));
777         if (col != palette[i]) {
778             full_update = 1;
779             palette[i] = col;
780         }
781         v += 3;
782     }
783     return full_update;
784 }
785
786 /* update start_addr and line_offset. Return TRUE if modified */
787 static int update_basic_params(VGAState *s)
788 {
789     int full_update;
790     uint32_t start_addr, line_offset, line_compare, v;
791     
792     full_update = 0;
793     /* compute line_offset in bytes */
794     v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
795     if (v == 0)
796         v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
797     line_offset = s->cr[0x13] | (v << 8);
798     line_offset <<= 3;
799
800     /* starting address */
801     start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
802     start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
803
804     /* line compare */
805     line_compare = s->cr[0x18] | 
806         ((s->cr[0x07] & 0x10) << 4) |
807         ((s->cr[0x09] & 0x40) << 3);
808
809     if (line_offset != s->line_offset ||
810         start_addr != s->start_addr ||
811         line_compare != s->line_compare) {
812         s->line_offset = line_offset;
813         s->start_addr = start_addr;
814         s->line_compare = line_compare;
815         full_update = 1;
816     }
817     return full_update;
818 }
819
820 static inline int get_depth_index(int depth)
821 {
822     switch(depth) {
823     default:
824     case 8:
825         return 0;
826     case 15:
827         return 1;
828     case 16:
829         return 2;
830     case 32:
831         return 3;
832     }
833 }
834
835 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
836     vga_draw_glyph8_8,
837     vga_draw_glyph8_16,
838     vga_draw_glyph8_16,
839     vga_draw_glyph8_32,
840 };
841
842 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
843     vga_draw_glyph16_8,
844     vga_draw_glyph16_16,
845     vga_draw_glyph16_16,
846     vga_draw_glyph16_32,
847 };
848
849 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
850     vga_draw_glyph9_8,
851     vga_draw_glyph9_16,
852     vga_draw_glyph9_16,
853     vga_draw_glyph9_32,
854 };
855     
856 static const uint8_t cursor_glyph[32 * 4] = {
857     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
858     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
859     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
860     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
861     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
862     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
863     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
864     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
865     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
866     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
867     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
868     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
869     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
870     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
871     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
872     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
873 };    
874
875 /* 
876  * Text mode update 
877  * Missing:
878  * - double scan
879  * - double width 
880  * - underline
881  * - flashing
882  */
883 static void vga_draw_text(VGAState *s, int full_update)
884 {
885     int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
886     int cx_min, cx_max, linesize, x_incr;
887     uint32_t offset, fgcol, bgcol, v, cursor_offset;
888     uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
889     const uint8_t *font_ptr, *font_base[2];
890     int dup9, line_offset, depth_index;
891     uint32_t *palette;
892     uint32_t *ch_attr_ptr;
893     vga_draw_glyph8_func *vga_draw_glyph8;
894     vga_draw_glyph9_func *vga_draw_glyph9;
895
896     full_update |= update_palette16(s);
897     palette = s->last_palette;
898     
899     /* compute font data address (in plane 2) */
900     v = s->sr[3];
901     offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
902     if (offset != s->font_offsets[0]) {
903         s->font_offsets[0] = offset;
904         full_update = 1;
905     }
906     font_base[0] = s->vram_ptr + offset;
907
908     offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
909     font_base[1] = s->vram_ptr + offset;
910     if (offset != s->font_offsets[1]) {
911         s->font_offsets[1] = offset;
912         full_update = 1;
913     }
914
915     full_update |= update_basic_params(s);
916
917     line_offset = s->line_offset;
918     s1 = s->vram_ptr + (s->start_addr * 4);
919
920     /* total width & height */
921     cheight = (s->cr[9] & 0x1f) + 1;
922     cw = 8;
923     if (s->sr[1] & 0x01)
924         cw = 9;
925     if (s->sr[1] & 0x08)
926         cw = 16; /* NOTE: no 18 pixel wide */
927     x_incr = cw * ((s->ds->depth + 7) >> 3);
928     width = (s->cr[0x01] + 1);
929     if (s->cr[0x06] == 100) {
930         /* ugly hack for CGA 160x100x16 - explain me the logic */
931         height = 100;
932     } else {
933         height = s->cr[0x12] | 
934             ((s->cr[0x07] & 0x02) << 7) | 
935             ((s->cr[0x07] & 0x40) << 3);
936         height = (height + 1) / cheight;
937     }
938     if (width != s->last_width || height != s->last_height ||
939         cw != s->last_cw || cw != s->last_cw) {
940         dpy_resize(s->ds, width * cw, height * cheight);
941         s->last_width = width;
942         s->last_height = height;
943         s->last_ch = cheight;
944         s->last_cw = cw;
945         full_update = 1;
946     }
947     cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
948     if (cursor_offset != s->cursor_offset ||
949         s->cr[0xa] != s->cursor_start ||
950         s->cr[0xb] != s->cursor_end) {
951       /* if the cursor position changed, we update the old and new
952          chars */
953         if (s->cursor_offset < CH_ATTR_SIZE)
954             s->last_ch_attr[s->cursor_offset] = -1;
955         if (cursor_offset < CH_ATTR_SIZE)
956             s->last_ch_attr[cursor_offset] = -1;
957         s->cursor_offset = cursor_offset;
958         s->cursor_start = s->cr[0xa];
959         s->cursor_end = s->cr[0xb];
960     }
961     cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
962     
963     depth_index = get_depth_index(s->ds->depth);
964     if (cw == 16)
965         vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
966     else
967         vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
968     vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
969     
970     dest = s->ds->data;
971     linesize = s->ds->linesize;
972     ch_attr_ptr = s->last_ch_attr;
973     for(cy = 0; cy < height; cy++) {
974         d1 = dest;
975         src = s1;
976         cx_min = width;
977         cx_max = -1;
978         for(cx = 0; cx < width; cx++) {
979             ch_attr = *(uint16_t *)src;
980             if (full_update || ch_attr != *ch_attr_ptr) {
981                 if (cx < cx_min)
982                     cx_min = cx;
983                 if (cx > cx_max)
984                     cx_max = cx;
985                 *ch_attr_ptr = ch_attr;
986 #ifdef WORDS_BIGENDIAN
987                 ch = ch_attr >> 8;
988                 cattr = ch_attr & 0xff;
989 #else
990                 ch = ch_attr & 0xff;
991                 cattr = ch_attr >> 8;
992 #endif
993                 font_ptr = font_base[(cattr >> 3) & 1];
994                 font_ptr += 32 * 4 * ch;
995                 bgcol = palette[cattr >> 4];
996                 fgcol = palette[cattr & 0x0f];
997                 if (cw != 9) {
998                     vga_draw_glyph8(d1, linesize, 
999                                     font_ptr, cheight, fgcol, bgcol);
1000                 } else {
1001                     dup9 = 0;
1002                     if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1003                         dup9 = 1;
1004                     vga_draw_glyph9(d1, linesize, 
1005                                     font_ptr, cheight, fgcol, bgcol, dup9);
1006                 }
1007                 if (src == cursor_ptr &&
1008                     !(s->cr[0x0a] & 0x20)) {
1009                     int line_start, line_last, h;
1010                     /* draw the cursor */
1011                     line_start = s->cr[0x0a] & 0x1f;
1012                     line_last = s->cr[0x0b] & 0x1f;
1013                     /* XXX: check that */
1014                     if (line_last > cheight - 1)
1015                         line_last = cheight - 1;
1016                     if (line_last >= line_start && line_start < cheight) {
1017                         h = line_last - line_start + 1;
1018                         d = d1 + linesize * line_start;
1019                         if (cw != 9) {
1020                             vga_draw_glyph8(d, linesize, 
1021                                             cursor_glyph, h, fgcol, bgcol);
1022                         } else {
1023                             vga_draw_glyph9(d, linesize, 
1024                                             cursor_glyph, h, fgcol, bgcol, 1);
1025                         }
1026                     }
1027                 }
1028             }
1029             d1 += x_incr;
1030             src += 4;
1031             ch_attr_ptr++;
1032         }
1033         if (cx_max != -1) {
1034             dpy_update(s->ds, cx_min * cw, cy * cheight, 
1035                        (cx_max - cx_min + 1) * cw, cheight);
1036         }
1037         dest += linesize * cheight;
1038         s1 += line_offset;
1039     }
1040 }
1041
1042 enum {
1043     VGA_DRAW_LINE2,
1044     VGA_DRAW_LINE2D2,
1045     VGA_DRAW_LINE4,
1046     VGA_DRAW_LINE4D2,
1047     VGA_DRAW_LINE8D2,
1048     VGA_DRAW_LINE8,
1049     VGA_DRAW_LINE15,
1050     VGA_DRAW_LINE16,
1051     VGA_DRAW_LINE32,
1052     VGA_DRAW_LINE_NB,
1053 };
1054
1055 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1056     vga_draw_line2_8,
1057     vga_draw_line2_16,
1058     vga_draw_line2_16,
1059     vga_draw_line2_32,
1060
1061     vga_draw_line2d2_8,
1062     vga_draw_line2d2_16,
1063     vga_draw_line2d2_16,
1064     vga_draw_line2d2_32,
1065
1066     vga_draw_line4_8,
1067     vga_draw_line4_16,
1068     vga_draw_line4_16,
1069     vga_draw_line4_32,
1070
1071     vga_draw_line4d2_8,
1072     vga_draw_line4d2_16,
1073     vga_draw_line4d2_16,
1074     vga_draw_line4d2_32,
1075
1076     vga_draw_line8d2_8,
1077     vga_draw_line8d2_16,
1078     vga_draw_line8d2_16,
1079     vga_draw_line8d2_32,
1080
1081     vga_draw_line8_8,
1082     vga_draw_line8_16,
1083     vga_draw_line8_16,
1084     vga_draw_line8_32,
1085
1086     vga_draw_line15_8,
1087     vga_draw_line15_15,
1088     vga_draw_line15_16,
1089     vga_draw_line15_32,
1090
1091     vga_draw_line16_8,
1092     vga_draw_line16_15,
1093     vga_draw_line16_16,
1094     vga_draw_line16_32,
1095
1096     vga_draw_line32_8,
1097     vga_draw_line32_15,
1098     vga_draw_line32_16,
1099     vga_draw_line32_32,
1100 };
1101
1102 /* 
1103  * graphic modes
1104  * Missing:
1105  * - double scan
1106  * - double width 
1107  */
1108 static void vga_draw_graphic(VGAState *s, int full_update)
1109 {
1110     int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1111     int width, height, shift_control, line_offset, page0, page1, bwidth;
1112     int disp_width;
1113     uint8_t *d;
1114     uint32_t v, addr1, addr;
1115     vga_draw_line_func *vga_draw_line;
1116     
1117     full_update |= update_basic_params(s);
1118
1119     width = (s->cr[0x01] + 1) * 8;
1120     height = s->cr[0x12] | 
1121         ((s->cr[0x07] & 0x02) << 7) | 
1122         ((s->cr[0x07] & 0x40) << 3);
1123     height = (height + 1);
1124     disp_width = width;
1125     
1126     shift_control = (s->gr[0x05] >> 5) & 3;
1127     if (shift_control > 1)
1128         double_scan = ((s->cr[0x09] & 0x1f) != 0);
1129     else
1130         double_scan = (s->cr[0x09] & 0x80);
1131     if (shift_control != s->shift_control ||
1132         double_scan != s->double_scan) {
1133         full_update = 1;
1134         s->shift_control = shift_control;
1135         s->double_scan = double_scan;
1136     }
1137     
1138     if (shift_control == 0) {
1139         full_update |= update_palette16(s);
1140         if (s->sr[0x01] & 8) {
1141             v = VGA_DRAW_LINE4D2;
1142             disp_width <<= 1;
1143         } else {
1144             v = VGA_DRAW_LINE4;
1145         }
1146     } else if (shift_control == 1) {
1147         full_update |= update_palette16(s);
1148         if (s->sr[0x01] & 8) {
1149             v = VGA_DRAW_LINE2D2;
1150             disp_width <<= 1;
1151         } else {
1152             v = VGA_DRAW_LINE2;
1153         }
1154     } else {
1155         full_update |= update_palette256(s);
1156         v = VGA_DRAW_LINE8D2;
1157     }
1158     vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1159
1160     if (disp_width != s->last_width ||
1161         height != s->last_height) {
1162         dpy_resize(s->ds, disp_width, height);
1163         s->last_width = disp_width;
1164         s->last_height = height;
1165         full_update = 1;
1166     }
1167
1168     line_offset = s->line_offset;
1169 #if 0
1170     printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1171            width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1172 #endif
1173     addr1 = (s->start_addr * 4);
1174     bwidth = width * 4;
1175     y_start = -1;
1176     page_min = 0x7fffffff;
1177     page_max = -1;
1178     d = s->ds->data;
1179     linesize = s->ds->linesize;
1180     y1 = 0;
1181     for(y = 0; y < height; y++) {
1182         addr = addr1;
1183         if (!(s->cr[0x17] & 1)) {
1184             int shift;
1185             /* CGA compatibility handling */
1186             shift = 14 + ((s->cr[0x17] >> 6) & 1);
1187             addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1188         }
1189         if (!(s->cr[0x17] & 2)) {
1190             addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1191         }
1192         page0 = addr >> 12;
1193         page1 = (addr + bwidth - 1) >> 12;
1194         update = full_update | s->vram_updated[page0] | s->vram_updated[page1];
1195         if ((page1 - page0) > 1) {
1196             /* if wide line, can use another page */
1197             update |= s->vram_updated[page0 + 1];
1198         }
1199         if (update) {
1200             if (y_start < 0)
1201                 y_start = y;
1202             if (page0 < page_min)
1203                 page_min = page0;
1204             if (page1 > page_max)
1205                 page_max = page1;
1206             vga_draw_line(s, d, s->vram_ptr + addr, width);
1207         } else {
1208             if (y_start >= 0) {
1209                 /* flush to display */
1210                 dpy_update(s->ds, 0, y_start, 
1211                            disp_width, y - y_start);
1212                 y_start = -1;
1213             }
1214         }
1215         if (!double_scan || (y & 1) != 0) {
1216             if (y1 == s->line_compare) {
1217                 addr1 = 0;
1218             } else {
1219                 mask = (s->cr[0x17] & 3) ^ 3;
1220                 if ((y1 & mask) == mask)
1221                     addr1 += line_offset; 
1222             }
1223             y1++;
1224         }
1225         d += linesize;
1226     }
1227     if (y_start >= 0) {
1228         /* flush to display */
1229         dpy_update(s->ds, 0, y_start, 
1230                    disp_width, y - y_start);
1231     }
1232     /* reset modified pages */
1233     if (page_max != -1) {
1234         memset(s->vram_updated + page_min, 0, page_max - page_min + 1);
1235     }
1236 }
1237
1238 /* draw text terminal (very limited, just for simple boot debug
1239    messages) */
1240 static int last_cursor_pos;
1241
1242 void vga_draw_dumb(VGAState *s)
1243 {
1244     int c, i, cursor_pos, eol;
1245
1246     cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8);
1247     eol = 0;
1248     for(i = last_cursor_pos; i < cursor_pos; i++) {
1249         /* XXX: should use vga RAM */
1250         c = phys_ram_base[0xb8000 + (i) * 2];
1251         if (c >= ' ') {
1252             putchar(c);
1253             eol = 0;
1254         } else {
1255             if (!eol)
1256                 putchar('\n');
1257             eol = 1;
1258         }
1259     }
1260     fflush(stdout);
1261     last_cursor_pos = cursor_pos;
1262 }
1263
1264 void vga_update_display(void)
1265 {
1266     VGAState *s = &vga_state;
1267     int full_update, graphic_mode;
1268
1269     if (s->ds->depth == 0) {
1270         vga_draw_dumb(s);
1271     } else {
1272         full_update = 0;
1273         graphic_mode = s->gr[6] & 1;
1274         if (graphic_mode != s->graphic_mode) {
1275             s->graphic_mode = graphic_mode;
1276             full_update = 1;
1277         }
1278         if (graphic_mode)
1279             vga_draw_graphic(s, full_update);
1280         else
1281             vga_draw_text(s, full_update);
1282     }
1283 }
1284
1285 void vga_reset(VGAState *s)
1286 {
1287     memset(s, 0, sizeof(VGAState));
1288     /* chip ID for 8c968 */
1289     s->cr[0x2d] = 0x88;
1290     s->cr[0x2e] = 0xb0;
1291     s->cr[0x2f] = 0x01; /* XXX: check revision code */
1292     s->cr[0x30] = 0xe1;
1293     s->graphic_mode = -1; /* force full update */
1294 }
1295
1296 CPUReadMemoryFunc *vga_mem_read[3] = {
1297     vga_mem_readb,
1298     vga_mem_readw,
1299     vga_mem_readl,
1300 };
1301
1302 CPUWriteMemoryFunc *vga_mem_write[3] = {
1303     vga_mem_writeb,
1304     vga_mem_writew,
1305     vga_mem_writel,
1306 };
1307
1308 int vga_init(DisplayState *ds, uint8_t *vga_ram_base, 
1309              unsigned long vga_ram_offset, int vga_ram_size)
1310 {
1311     VGAState *s = &vga_state;
1312     int i, j, v, b;
1313
1314     for(i = 0;i < 256; i++) {
1315         v = 0;
1316         for(j = 0; j < 8; j++) {
1317             v |= ((i >> j) & 1) << (j * 4);
1318         }
1319         expand4[i] = v;
1320
1321         v = 0;
1322         for(j = 0; j < 4; j++) {
1323             v |= ((i >> (2 * j)) & 3) << (j * 4);
1324         }
1325         expand2[i] = v;
1326     }
1327     for(i = 0; i < 16; i++) {
1328         v = 0;
1329         for(j = 0; j < 4; j++) {
1330             b = ((i >> j) & 1);
1331             v |= b << (2 * j);
1332             v |= b << (2 * j + 1);
1333         }
1334         expand4to8[i] = v;
1335     }
1336
1337     vga_reset(s);
1338
1339     switch(ds->depth) {
1340     case 8:
1341         s->rgb_to_pixel = rgb_to_pixel8_dup;
1342         break;
1343     case 15:
1344         s->rgb_to_pixel = rgb_to_pixel15_dup;
1345         break;
1346     default:
1347     case 16:
1348         s->rgb_to_pixel = rgb_to_pixel16_dup;
1349         break;
1350     case 32:
1351         s->rgb_to_pixel = rgb_to_pixel32_dup;
1352         break;
1353     }
1354
1355     s->vram_ptr = vga_ram_base;
1356     s->vram_offset = vga_ram_offset;
1357     s->vram_size = vga_ram_size;
1358     s->ds = ds;
1359
1360     register_ioport_write(0x3c0, 16, vga_ioport_write, 1);
1361
1362     register_ioport_write(0x3b4, 2, vga_ioport_write, 1);
1363     register_ioport_write(0x3d4, 2, vga_ioport_write, 1);
1364     register_ioport_write(0x3ba, 1, vga_ioport_write, 1);
1365     register_ioport_write(0x3da, 1, vga_ioport_write, 1);
1366
1367     register_ioport_read(0x3c0, 16, vga_ioport_read, 1);
1368
1369     register_ioport_read(0x3b4, 2, vga_ioport_read, 1);
1370     register_ioport_read(0x3d4, 2, vga_ioport_read, 1);
1371     register_ioport_read(0x3ba, 1, vga_ioport_read, 1);
1372     register_ioport_read(0x3da, 1, vga_ioport_read, 1);
1373
1374     vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1375     cpu_register_physical_memory(0xa0000, 0x20000, vga_io_memory);
1376     return 0;
1377 }