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