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