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