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