|
|
1.1 root 1: /*
2: * QEMU VGA Emulator.
1.1.1.5 root 3: *
1.1 root 4: * Copyright (c) 2003 Fabrice Bellard
1.1.1.5 root 5: *
1.1 root 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: */
1.1.1.5 root 24: #include "hw.h"
25: #include "console.h"
26: #include "pc.h"
27: #include "pci.h"
1.1 root 28: #include "vga_int.h"
1.1.1.5 root 29: #include "pixel_ops.h"
1.1.1.6 root 30: #include "qemu-timer.h"
1.1 root 31:
32: //#define DEBUG_VGA
33: //#define DEBUG_VGA_MEM
34: //#define DEBUG_VGA_REG
35:
36: //#define DEBUG_BOCHS_VBE
37:
38: /* force some bits to zero */
39: const uint8_t sr_mask[8] = {
1.1.1.10 root 40: 0x03,
41: 0x3d,
42: 0x0f,
43: 0x3f,
44: 0x0e,
45: 0x00,
46: 0x00,
47: 0xff,
1.1 root 48: };
49:
50: const uint8_t gr_mask[16] = {
1.1.1.10 root 51: 0x0f, /* 0x00 */
52: 0x0f, /* 0x01 */
53: 0x0f, /* 0x02 */
54: 0x1f, /* 0x03 */
55: 0x03, /* 0x04 */
56: 0x7b, /* 0x05 */
57: 0x0f, /* 0x06 */
58: 0x0f, /* 0x07 */
59: 0xff, /* 0x08 */
60: 0x00, /* 0x09 */
61: 0x00, /* 0x0a */
62: 0x00, /* 0x0b */
63: 0x00, /* 0x0c */
64: 0x00, /* 0x0d */
65: 0x00, /* 0x0e */
66: 0x00, /* 0x0f */
1.1 root 67: };
68:
69: #define cbswap_32(__x) \
70: ((uint32_t)( \
71: (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
72: (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
73: (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
74: (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
75:
1.1.1.12 root 76: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 77: #define PAT(x) cbswap_32(x)
78: #else
79: #define PAT(x) (x)
80: #endif
81:
1.1.1.12 root 82: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 83: #define BIG 1
84: #else
85: #define BIG 0
86: #endif
87:
1.1.1.12 root 88: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 89: #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
90: #else
91: #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
92: #endif
93:
94: static const uint32_t mask16[16] = {
95: PAT(0x00000000),
96: PAT(0x000000ff),
97: PAT(0x0000ff00),
98: PAT(0x0000ffff),
99: PAT(0x00ff0000),
100: PAT(0x00ff00ff),
101: PAT(0x00ffff00),
102: PAT(0x00ffffff),
103: PAT(0xff000000),
104: PAT(0xff0000ff),
105: PAT(0xff00ff00),
106: PAT(0xff00ffff),
107: PAT(0xffff0000),
108: PAT(0xffff00ff),
109: PAT(0xffffff00),
110: PAT(0xffffffff),
111: };
112:
113: #undef PAT
114:
1.1.1.12 root 115: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 116: #define PAT(x) (x)
117: #else
118: #define PAT(x) cbswap_32(x)
119: #endif
120:
121: static const uint32_t dmask16[16] = {
122: PAT(0x00000000),
123: PAT(0x000000ff),
124: PAT(0x0000ff00),
125: PAT(0x0000ffff),
126: PAT(0x00ff0000),
127: PAT(0x00ff00ff),
128: PAT(0x00ffff00),
129: PAT(0x00ffffff),
130: PAT(0xff000000),
131: PAT(0xff0000ff),
132: PAT(0xff00ff00),
133: PAT(0xff00ffff),
134: PAT(0xffff0000),
135: PAT(0xffff00ff),
136: PAT(0xffffff00),
137: PAT(0xffffffff),
138: };
139:
140: static const uint32_t dmask4[4] = {
141: PAT(0x00000000),
142: PAT(0x0000ffff),
143: PAT(0xffff0000),
144: PAT(0xffffffff),
145: };
146:
147: static uint32_t expand4[256];
148: static uint16_t expand2[256];
149: static uint8_t expand4to8[16];
150:
1.1.1.2 root 151: static void vga_screen_dump(void *opaque, const char *filename);
1.1.1.16! root 152: static const char *screen_dump_filename;
1.1.1.10 root 153: static DisplayChangeListener *screen_dump_dcl;
1.1.1.2 root 154:
1.1.1.16! root 155: static void vga_update_memory_access(VGACommonState *s)
! 156: {
! 157: MemoryRegion *region, *old_region = s->chain4_alias;
! 158: target_phys_addr_t base, offset, size;
! 159:
! 160: s->chain4_alias = NULL;
! 161:
! 162: if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
! 163: offset = 0;
! 164: switch ((s->gr[6] >> 2) & 3) {
! 165: case 0:
! 166: base = 0xa0000;
! 167: size = 0x20000;
! 168: break;
! 169: case 1:
! 170: base = 0xa0000;
! 171: size = 0x10000;
! 172: offset = s->bank_offset;
! 173: break;
! 174: case 2:
! 175: base = 0xb0000;
! 176: size = 0x8000;
! 177: break;
! 178: case 3:
! 179: default:
! 180: base = 0xb8000;
! 181: size = 0x8000;
! 182: break;
! 183: }
! 184: base += isa_mem_base;
! 185: region = g_malloc(sizeof(*region));
! 186: memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
! 187: memory_region_add_subregion_overlap(s->legacy_address_space, base,
! 188: region, 2);
! 189: s->chain4_alias = region;
! 190: }
! 191: if (old_region) {
! 192: memory_region_del_subregion(s->legacy_address_space, old_region);
! 193: memory_region_destroy(old_region);
! 194: g_free(old_region);
! 195: s->plane_updated = 0xf;
! 196: }
! 197: }
! 198:
1.1.1.12 root 199: static void vga_dumb_update_retrace_info(VGACommonState *s)
1.1.1.6 root 200: {
201: (void) s;
202: }
203:
1.1.1.12 root 204: static void vga_precise_update_retrace_info(VGACommonState *s)
1.1.1.6 root 205: {
206: int htotal_chars;
207: int hretr_start_char;
208: int hretr_skew_chars;
209: int hretr_end_char;
210:
211: int vtotal_lines;
212: int vretr_start_line;
213: int vretr_end_line;
214:
1.1.1.13 root 215: int dots;
216: #if 0
217: int div2, sldiv2;
218: #endif
1.1.1.6 root 219: int clocking_mode;
220: int clock_sel;
221: const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
222: int64_t chars_per_sec;
223: struct vga_precise_retrace *r = &s->retrace_info.precise;
224:
225: htotal_chars = s->cr[0x00] + 5;
226: hretr_start_char = s->cr[0x04];
227: hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
228: hretr_end_char = s->cr[0x05] & 0x1f;
229:
230: vtotal_lines = (s->cr[0x06]
231: | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
232: ;
233: vretr_start_line = s->cr[0x10]
234: | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
235: ;
236: vretr_end_line = s->cr[0x11] & 0xf;
237:
238:
239:
240: clocking_mode = (s->sr[0x01] >> 3) & 1;
241: clock_sel = (s->msr >> 2) & 3;
242: dots = (s->msr & 1) ? 8 : 9;
243:
244: chars_per_sec = clk_hz[clock_sel] / dots;
245:
246: htotal_chars <<= clocking_mode;
247:
248: r->total_chars = vtotal_lines * htotal_chars;
249: if (r->freq) {
1.1.1.12 root 250: r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
1.1.1.6 root 251: } else {
1.1.1.12 root 252: r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
1.1.1.6 root 253: }
254:
255: r->vstart = vretr_start_line;
256: r->vend = r->vstart + vretr_end_line + 1;
257:
258: r->hstart = hretr_start_char + hretr_skew_chars;
259: r->hend = r->hstart + hretr_end_char + 1;
260: r->htotal = htotal_chars;
261:
262: #if 0
1.1.1.13 root 263: div2 = (s->cr[0x17] >> 2) & 1;
264: sldiv2 = (s->cr[0x17] >> 3) & 1;
1.1.1.6 root 265: printf (
266: "hz=%f\n"
267: "htotal = %d\n"
268: "hretr_start = %d\n"
269: "hretr_skew = %d\n"
270: "hretr_end = %d\n"
271: "vtotal = %d\n"
272: "vretr_start = %d\n"
273: "vretr_end = %d\n"
274: "div2 = %d sldiv2 = %d\n"
275: "clocking_mode = %d\n"
276: "clock_sel = %d %d\n"
277: "dots = %d\n"
1.1.1.13 root 278: "ticks/char = %" PRId64 "\n"
1.1.1.6 root 279: "\n",
1.1.1.12 root 280: (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
1.1.1.6 root 281: htotal_chars,
282: hretr_start_char,
283: hretr_skew_chars,
284: hretr_end_char,
285: vtotal_lines,
286: vretr_start_line,
287: vretr_end_line,
288: div2, sldiv2,
289: clocking_mode,
290: clock_sel,
291: clk_hz[clock_sel],
292: dots,
293: r->ticks_per_char
294: );
295: #endif
296: }
297:
1.1.1.12 root 298: static uint8_t vga_precise_retrace(VGACommonState *s)
1.1.1.6 root 299: {
300: struct vga_precise_retrace *r = &s->retrace_info.precise;
301: uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
302:
303: if (r->total_chars) {
304: int cur_line, cur_line_char, cur_char;
305: int64_t cur_tick;
306:
1.1.1.15 root 307: cur_tick = qemu_get_clock_ns(vm_clock);
1.1.1.6 root 308:
309: cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
310: cur_line = cur_char / r->htotal;
311:
312: if (cur_line >= r->vstart && cur_line <= r->vend) {
313: val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
314: } else {
315: cur_line_char = cur_char % r->htotal;
316: if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
317: val |= ST01_DISP_ENABLE;
318: }
319: }
320:
321: return val;
322: } else {
323: return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
324: }
325: }
326:
1.1.1.12 root 327: static uint8_t vga_dumb_retrace(VGACommonState *s)
1.1.1.6 root 328: {
329: return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
330: }
331:
1.1.1.12 root 332: int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
1.1 root 333: {
1.1.1.12 root 334: if (s->msr & MSR_COLOR_EMULATION) {
335: /* Color */
336: return (addr >= 0x3b0 && addr <= 0x3bf);
337: } else {
338: /* Monochrome */
339: return (addr >= 0x3d0 && addr <= 0x3df);
340: }
341: }
342:
343: uint32_t vga_ioport_read(void *opaque, uint32_t addr)
344: {
345: VGACommonState *s = opaque;
1.1 root 346: int val, index;
347:
1.1.1.12 root 348: if (vga_ioport_invalid(s, addr)) {
1.1 root 349: val = 0xff;
350: } else {
351: switch(addr) {
352: case 0x3c0:
353: if (s->ar_flip_flop == 0) {
354: val = s->ar_index;
355: } else {
356: val = 0;
357: }
358: break;
359: case 0x3c1:
360: index = s->ar_index & 0x1f;
1.1.1.5 root 361: if (index < 21)
1.1 root 362: val = s->ar[index];
363: else
364: val = 0;
365: break;
366: case 0x3c2:
367: val = s->st00;
368: break;
369: case 0x3c4:
370: val = s->sr_index;
371: break;
372: case 0x3c5:
373: val = s->sr[s->sr_index];
374: #ifdef DEBUG_VGA_REG
375: printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
376: #endif
377: break;
378: case 0x3c7:
379: val = s->dac_state;
380: break;
1.1.1.12 root 381: case 0x3c8:
382: val = s->dac_write_index;
383: break;
1.1 root 384: case 0x3c9:
385: val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
386: if (++s->dac_sub_index == 3) {
387: s->dac_sub_index = 0;
388: s->dac_read_index++;
389: }
390: break;
391: case 0x3ca:
392: val = s->fcr;
393: break;
394: case 0x3cc:
395: val = s->msr;
396: break;
397: case 0x3ce:
398: val = s->gr_index;
399: break;
400: case 0x3cf:
401: val = s->gr[s->gr_index];
402: #ifdef DEBUG_VGA_REG
403: printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
404: #endif
405: break;
406: case 0x3b4:
407: case 0x3d4:
408: val = s->cr_index;
409: break;
410: case 0x3b5:
411: case 0x3d5:
412: val = s->cr[s->cr_index];
413: #ifdef DEBUG_VGA_REG
414: printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
415: #endif
416: break;
417: case 0x3ba:
418: case 0x3da:
419: /* just toggle to fool polling */
1.1.1.6 root 420: val = s->st01 = s->retrace(s);
1.1 root 421: s->ar_flip_flop = 0;
422: break;
423: default:
424: val = 0x00;
425: break;
426: }
427: }
428: #if defined(DEBUG_VGA)
429: printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
430: #endif
431: return val;
432: }
433:
1.1.1.12 root 434: void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
1.1 root 435: {
1.1.1.12 root 436: VGACommonState *s = opaque;
1.1 root 437: int index;
438:
439: /* check port range access depending on color/monochrome mode */
1.1.1.12 root 440: if (vga_ioport_invalid(s, addr)) {
1.1 root 441: return;
1.1.1.12 root 442: }
1.1 root 443: #ifdef DEBUG_VGA
444: printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
445: #endif
446:
447: switch(addr) {
448: case 0x3c0:
449: if (s->ar_flip_flop == 0) {
450: val &= 0x3f;
451: s->ar_index = val;
452: } else {
453: index = s->ar_index & 0x1f;
454: switch(index) {
455: case 0x00 ... 0x0f:
456: s->ar[index] = val & 0x3f;
457: break;
458: case 0x10:
459: s->ar[index] = val & ~0x10;
460: break;
461: case 0x11:
462: s->ar[index] = val;
463: break;
464: case 0x12:
465: s->ar[index] = val & ~0xc0;
466: break;
467: case 0x13:
468: s->ar[index] = val & ~0xf0;
469: break;
470: case 0x14:
471: s->ar[index] = val & ~0xf0;
472: break;
473: default:
474: break;
475: }
476: }
477: s->ar_flip_flop ^= 1;
478: break;
479: case 0x3c2:
480: s->msr = val & ~0x10;
1.1.1.6 root 481: s->update_retrace_info(s);
1.1 root 482: break;
483: case 0x3c4:
484: s->sr_index = val & 7;
485: break;
486: case 0x3c5:
487: #ifdef DEBUG_VGA_REG
488: printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
489: #endif
490: s->sr[s->sr_index] = val & sr_mask[s->sr_index];
1.1.1.6 root 491: if (s->sr_index == 1) s->update_retrace_info(s);
1.1.1.16! root 492: vga_update_memory_access(s);
1.1 root 493: break;
494: case 0x3c7:
495: s->dac_read_index = val;
496: s->dac_sub_index = 0;
497: s->dac_state = 3;
498: break;
499: case 0x3c8:
500: s->dac_write_index = val;
501: s->dac_sub_index = 0;
502: s->dac_state = 0;
503: break;
504: case 0x3c9:
505: s->dac_cache[s->dac_sub_index] = val;
506: if (++s->dac_sub_index == 3) {
507: memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
508: s->dac_sub_index = 0;
509: s->dac_write_index++;
510: }
511: break;
512: case 0x3ce:
513: s->gr_index = val & 0x0f;
514: break;
515: case 0x3cf:
516: #ifdef DEBUG_VGA_REG
517: printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
518: #endif
519: s->gr[s->gr_index] = val & gr_mask[s->gr_index];
1.1.1.16! root 520: vga_update_memory_access(s);
1.1 root 521: break;
522: case 0x3b4:
523: case 0x3d4:
524: s->cr_index = val;
525: break;
526: case 0x3b5:
527: case 0x3d5:
528: #ifdef DEBUG_VGA_REG
529: printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
530: #endif
531: /* handle CR0-7 protection */
532: if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
533: /* can always write bit 4 of CR7 */
534: if (s->cr_index == 7)
535: s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
536: return;
537: }
1.1.1.12 root 538: s->cr[s->cr_index] = val;
1.1.1.6 root 539:
540: switch(s->cr_index) {
541: case 0x00:
542: case 0x04:
543: case 0x05:
544: case 0x06:
545: case 0x07:
546: case 0x11:
547: case 0x17:
548: s->update_retrace_info(s);
549: break;
550: }
1.1 root 551: break;
552: case 0x3ba:
553: case 0x3da:
554: s->fcr = val & 0x10;
555: break;
556: }
557: }
558:
559: #ifdef CONFIG_BOCHS_VBE
560: static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
561: {
1.1.1.12 root 562: VGACommonState *s = opaque;
1.1 root 563: uint32_t val;
564: val = s->vbe_index;
565: return val;
566: }
567:
568: static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
569: {
1.1.1.12 root 570: VGACommonState *s = opaque;
1.1 root 571: uint32_t val;
572:
1.1.1.13 root 573: if (s->vbe_index < VBE_DISPI_INDEX_NB) {
1.1.1.3 root 574: if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
575: switch(s->vbe_index) {
576: /* XXX: do not hardcode ? */
577: case VBE_DISPI_INDEX_XRES:
578: val = VBE_DISPI_MAX_XRES;
579: break;
580: case VBE_DISPI_INDEX_YRES:
581: val = VBE_DISPI_MAX_YRES;
582: break;
583: case VBE_DISPI_INDEX_BPP:
584: val = VBE_DISPI_MAX_BPP;
585: break;
586: default:
1.1.1.5 root 587: val = s->vbe_regs[s->vbe_index];
1.1.1.3 root 588: break;
589: }
590: } else {
1.1.1.5 root 591: val = s->vbe_regs[s->vbe_index];
1.1.1.3 root 592: }
1.1.1.13 root 593: } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
594: val = s->vram_size / (64 * 1024);
1.1.1.3 root 595: } else {
1.1 root 596: val = 0;
1.1.1.3 root 597: }
1.1 root 598: #ifdef DEBUG_BOCHS_VBE
599: printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
600: #endif
601: return val;
602: }
603:
604: static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
605: {
1.1.1.12 root 606: VGACommonState *s = opaque;
1.1 root 607: s->vbe_index = val;
608: }
609:
610: static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
611: {
1.1.1.12 root 612: VGACommonState *s = opaque;
1.1 root 613:
614: if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
615: #ifdef DEBUG_BOCHS_VBE
616: printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
617: #endif
618: switch(s->vbe_index) {
619: case VBE_DISPI_INDEX_ID:
620: if (val == VBE_DISPI_ID0 ||
621: val == VBE_DISPI_ID1 ||
1.1.1.4 root 622: val == VBE_DISPI_ID2 ||
623: val == VBE_DISPI_ID3 ||
624: val == VBE_DISPI_ID4) {
1.1 root 625: s->vbe_regs[s->vbe_index] = val;
626: }
627: break;
628: case VBE_DISPI_INDEX_XRES:
629: if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
630: s->vbe_regs[s->vbe_index] = val;
631: }
632: break;
633: case VBE_DISPI_INDEX_YRES:
634: if (val <= VBE_DISPI_MAX_YRES) {
635: s->vbe_regs[s->vbe_index] = val;
636: }
637: break;
638: case VBE_DISPI_INDEX_BPP:
639: if (val == 0)
640: val = 8;
1.1.1.5 root 641: if (val == 4 || val == 8 || val == 15 ||
1.1 root 642: val == 16 || val == 24 || val == 32) {
643: s->vbe_regs[s->vbe_index] = val;
644: }
645: break;
646: case VBE_DISPI_INDEX_BANK:
1.1.1.4 root 647: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
648: val &= (s->vbe_bank_mask >> 2);
649: } else {
650: val &= s->vbe_bank_mask;
651: }
1.1 root 652: s->vbe_regs[s->vbe_index] = val;
653: s->bank_offset = (val << 16);
1.1.1.16! root 654: vga_update_memory_access(s);
1.1 root 655: break;
656: case VBE_DISPI_INDEX_ENABLE:
1.1.1.3 root 657: if ((val & VBE_DISPI_ENABLED) &&
658: !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
1.1 root 659: int h, shift_control;
660:
1.1.1.5 root 661: s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
1.1 root 662: s->vbe_regs[VBE_DISPI_INDEX_XRES];
1.1.1.5 root 663: s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
1.1 root 664: s->vbe_regs[VBE_DISPI_INDEX_YRES];
665: s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
666: s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
1.1.1.5 root 667:
1.1 root 668: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
669: s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
670: else
1.1.1.5 root 671: s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
1.1 root 672: ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
673: s->vbe_start_addr = 0;
1.1.1.3 root 674:
1.1 root 675: /* clear the screen (should be done in BIOS) */
676: if (!(val & VBE_DISPI_NOCLEARMEM)) {
1.1.1.5 root 677: memset(s->vram_ptr, 0,
1.1 root 678: s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
679: }
1.1.1.5 root 680:
1.1 root 681: /* we initialize the VGA graphic mode (should be done
682: in BIOS) */
683: s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
684: s->cr[0x17] |= 3; /* no CGA modes */
685: s->cr[0x13] = s->vbe_line_offset >> 3;
686: /* width */
687: s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
1.1.1.3 root 688: /* height (only meaningful if < 1024) */
1.1 root 689: h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
690: s->cr[0x12] = h;
1.1.1.5 root 691: s->cr[0x07] = (s->cr[0x07] & ~0x42) |
1.1 root 692: ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
693: /* line compare to 1023 */
694: s->cr[0x18] = 0xff;
695: s->cr[0x07] |= 0x10;
696: s->cr[0x09] |= 0x40;
1.1.1.5 root 697:
1.1 root 698: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
699: shift_control = 0;
700: s->sr[0x01] &= ~8; /* no double line */
701: } else {
702: shift_control = 2;
703: s->sr[4] |= 0x08; /* set chain 4 mode */
704: s->sr[2] |= 0x0f; /* activate all planes */
705: }
706: s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
707: s->cr[0x09] &= ~0x9f; /* no double scan */
708: } else {
709: /* XXX: the bios should do that */
710: s->bank_offset = 0;
711: }
1.1.1.4 root 712: s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
1.1 root 713: s->vbe_regs[s->vbe_index] = val;
1.1.1.16! root 714: vga_update_memory_access(s);
1.1 root 715: break;
716: case VBE_DISPI_INDEX_VIRT_WIDTH:
717: {
718: int w, h, line_offset;
719:
720: if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
721: return;
722: w = val;
723: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
724: line_offset = w >> 1;
725: else
726: line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
727: h = s->vram_size / line_offset;
728: /* XXX: support weird bochs semantics ? */
729: if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
730: return;
731: s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
732: s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
733: s->vbe_line_offset = line_offset;
734: }
735: break;
736: case VBE_DISPI_INDEX_X_OFFSET:
737: case VBE_DISPI_INDEX_Y_OFFSET:
738: {
739: int x;
740: s->vbe_regs[s->vbe_index] = val;
741: s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
742: x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
743: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
744: s->vbe_start_addr += x >> 1;
745: else
746: s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
747: s->vbe_start_addr >>= 2;
748: }
749: break;
750: default:
751: break;
752: }
753: }
754: }
755: #endif
756:
757: /* called for accesses between 0xa0000 and 0xc0000 */
1.1.1.16! root 758: uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
1.1 root 759: {
760: int memory_map_mode, plane;
761: uint32_t ret;
1.1.1.5 root 762:
1.1 root 763: /* convert to VGA memory offset */
764: memory_map_mode = (s->gr[6] >> 2) & 3;
765: addr &= 0x1ffff;
766: switch(memory_map_mode) {
767: case 0:
768: break;
769: case 1:
770: if (addr >= 0x10000)
771: return 0xff;
772: addr += s->bank_offset;
773: break;
774: case 2:
775: addr -= 0x10000;
776: if (addr >= 0x8000)
777: return 0xff;
778: break;
779: default:
780: case 3:
781: addr -= 0x18000;
782: if (addr >= 0x8000)
783: return 0xff;
784: break;
785: }
1.1.1.5 root 786:
1.1 root 787: if (s->sr[4] & 0x08) {
788: /* chain 4 mode : simplest access */
789: ret = s->vram_ptr[addr];
790: } else if (s->gr[5] & 0x10) {
791: /* odd/even mode (aka text mode mapping) */
792: plane = (s->gr[4] & 2) | (addr & 1);
793: ret = s->vram_ptr[((addr & ~1) << 1) | plane];
794: } else {
795: /* standard VGA latched access */
796: s->latch = ((uint32_t *)s->vram_ptr)[addr];
797:
798: if (!(s->gr[5] & 0x08)) {
799: /* read mode 0 */
800: plane = s->gr[4];
801: ret = GET_PLANE(s->latch, plane);
802: } else {
803: /* read mode 1 */
804: ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
805: ret |= ret >> 16;
806: ret |= ret >> 8;
807: ret = (~ret) & 0xff;
808: }
809: }
810: return ret;
811: }
812:
813: /* called for accesses between 0xa0000 and 0xc0000 */
1.1.1.16! root 814: void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
1.1 root 815: {
816: int memory_map_mode, plane, write_mode, b, func_select, mask;
817: uint32_t write_mask, bit_mask, set_mask;
818:
819: #ifdef DEBUG_VGA_MEM
1.1.1.10 root 820: printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
1.1 root 821: #endif
822: /* convert to VGA memory offset */
823: memory_map_mode = (s->gr[6] >> 2) & 3;
824: addr &= 0x1ffff;
825: switch(memory_map_mode) {
826: case 0:
827: break;
828: case 1:
829: if (addr >= 0x10000)
830: return;
831: addr += s->bank_offset;
832: break;
833: case 2:
834: addr -= 0x10000;
835: if (addr >= 0x8000)
836: return;
837: break;
838: default:
839: case 3:
840: addr -= 0x18000;
841: if (addr >= 0x8000)
842: return;
843: break;
844: }
1.1.1.5 root 845:
1.1 root 846: if (s->sr[4] & 0x08) {
847: /* chain 4 mode : simplest access */
848: plane = addr & 3;
849: mask = (1 << plane);
850: if (s->sr[2] & mask) {
851: s->vram_ptr[addr] = val;
852: #ifdef DEBUG_VGA_MEM
1.1.1.10 root 853: printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
1.1 root 854: #endif
855: s->plane_updated |= mask; /* only used to detect font change */
1.1.1.16! root 856: memory_region_set_dirty(&s->vram, addr);
1.1 root 857: }
858: } else if (s->gr[5] & 0x10) {
859: /* odd/even mode (aka text mode mapping) */
860: plane = (s->gr[4] & 2) | (addr & 1);
861: mask = (1 << plane);
862: if (s->sr[2] & mask) {
863: addr = ((addr & ~1) << 1) | plane;
864: s->vram_ptr[addr] = val;
865: #ifdef DEBUG_VGA_MEM
1.1.1.10 root 866: printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
1.1 root 867: #endif
868: s->plane_updated |= mask; /* only used to detect font change */
1.1.1.16! root 869: memory_region_set_dirty(&s->vram, addr);
1.1 root 870: }
871: } else {
872: /* standard VGA latched access */
873: write_mode = s->gr[5] & 3;
874: switch(write_mode) {
875: default:
876: case 0:
877: /* rotate */
878: b = s->gr[3] & 7;
879: val = ((val >> b) | (val << (8 - b))) & 0xff;
880: val |= val << 8;
881: val |= val << 16;
882:
883: /* apply set/reset mask */
884: set_mask = mask16[s->gr[1]];
885: val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
886: bit_mask = s->gr[8];
887: break;
888: case 1:
889: val = s->latch;
890: goto do_write;
891: case 2:
892: val = mask16[val & 0x0f];
893: bit_mask = s->gr[8];
894: break;
895: case 3:
896: /* rotate */
897: b = s->gr[3] & 7;
898: val = (val >> b) | (val << (8 - b));
899:
900: bit_mask = s->gr[8] & val;
901: val = mask16[s->gr[0]];
902: break;
903: }
904:
905: /* apply logical operation */
906: func_select = s->gr[3] >> 3;
907: switch(func_select) {
908: case 0:
909: default:
910: /* nothing to do */
911: break;
912: case 1:
913: /* and */
914: val &= s->latch;
915: break;
916: case 2:
917: /* or */
918: val |= s->latch;
919: break;
920: case 3:
921: /* xor */
922: val ^= s->latch;
923: break;
924: }
925:
926: /* apply bit mask */
927: bit_mask |= bit_mask << 8;
928: bit_mask |= bit_mask << 16;
929: val = (val & bit_mask) | (s->latch & ~bit_mask);
930:
931: do_write:
932: /* mask data according to sr[2] */
933: mask = s->sr[2];
934: s->plane_updated |= mask; /* only used to detect font change */
935: write_mask = mask16[mask];
1.1.1.5 root 936: ((uint32_t *)s->vram_ptr)[addr] =
937: (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
1.1 root 938: (val & write_mask);
939: #ifdef DEBUG_VGA_MEM
1.1.1.10 root 940: printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
941: addr * 4, write_mask, val);
1.1 root 942: #endif
1.1.1.16! root 943: memory_region_set_dirty(&s->vram, addr << 2);
1.1 root 944: }
945: }
946:
947: typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
948: const uint8_t *font_ptr, int h,
949: uint32_t fgcol, uint32_t bgcol);
950: typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
1.1.1.5 root 951: const uint8_t *font_ptr, int h,
1.1 root 952: uint32_t fgcol, uint32_t bgcol, int dup9);
1.1.1.12 root 953: typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
1.1 root 954: const uint8_t *s, int width);
955:
956: #define DEPTH 8
957: #include "vga_template.h"
958:
959: #define DEPTH 15
960: #include "vga_template.h"
961:
1.1.1.5 root 962: #define BGR_FORMAT
963: #define DEPTH 15
964: #include "vga_template.h"
965:
966: #define DEPTH 16
967: #include "vga_template.h"
968:
969: #define BGR_FORMAT
1.1 root 970: #define DEPTH 16
971: #include "vga_template.h"
972:
973: #define DEPTH 32
974: #include "vga_template.h"
975:
1.1.1.3 root 976: #define BGR_FORMAT
977: #define DEPTH 32
978: #include "vga_template.h"
979:
1.1 root 980: static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
981: {
982: unsigned int col;
983: col = rgb_to_pixel8(r, g, b);
984: col |= col << 8;
985: col |= col << 16;
986: return col;
987: }
988:
989: static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
990: {
991: unsigned int col;
992: col = rgb_to_pixel15(r, g, b);
993: col |= col << 16;
994: return col;
995: }
996:
1.1.1.5 root 997: static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
998: unsigned int b)
999: {
1000: unsigned int col;
1001: col = rgb_to_pixel15bgr(r, g, b);
1002: col |= col << 16;
1003: return col;
1004: }
1005:
1.1 root 1006: static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1007: {
1008: unsigned int col;
1009: col = rgb_to_pixel16(r, g, b);
1010: col |= col << 16;
1011: return col;
1012: }
1013:
1.1.1.5 root 1014: static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1015: unsigned int b)
1016: {
1017: unsigned int col;
1018: col = rgb_to_pixel16bgr(r, g, b);
1019: col |= col << 16;
1020: return col;
1021: }
1022:
1.1 root 1023: static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1024: {
1025: unsigned int col;
1026: col = rgb_to_pixel32(r, g, b);
1027: return col;
1028: }
1029:
1.1.1.3 root 1030: static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1031: {
1032: unsigned int col;
1033: col = rgb_to_pixel32bgr(r, g, b);
1034: return col;
1035: }
1036:
1.1 root 1037: /* return true if the palette was modified */
1.1.1.12 root 1038: static int update_palette16(VGACommonState *s)
1.1 root 1039: {
1040: int full_update, i;
1041: uint32_t v, col, *palette;
1042:
1043: full_update = 0;
1044: palette = s->last_palette;
1045: for(i = 0; i < 16; i++) {
1046: v = s->ar[i];
1047: if (s->ar[0x10] & 0x80)
1048: v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1049: else
1050: v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1051: v = v * 3;
1.1.1.5 root 1052: col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1053: c6_to_8(s->palette[v + 1]),
1.1 root 1054: c6_to_8(s->palette[v + 2]));
1055: if (col != palette[i]) {
1056: full_update = 1;
1057: palette[i] = col;
1058: }
1059: }
1060: return full_update;
1061: }
1062:
1063: /* return true if the palette was modified */
1.1.1.12 root 1064: static int update_palette256(VGACommonState *s)
1.1 root 1065: {
1066: int full_update, i;
1067: uint32_t v, col, *palette;
1068:
1069: full_update = 0;
1070: palette = s->last_palette;
1071: v = 0;
1072: for(i = 0; i < 256; i++) {
1.1.1.4 root 1073: if (s->dac_8bit) {
1.1.1.5 root 1074: col = s->rgb_to_pixel(s->palette[v],
1075: s->palette[v + 1],
1.1.1.4 root 1076: s->palette[v + 2]);
1077: } else {
1.1.1.5 root 1078: col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1079: c6_to_8(s->palette[v + 1]),
1.1.1.4 root 1080: c6_to_8(s->palette[v + 2]));
1081: }
1.1 root 1082: if (col != palette[i]) {
1083: full_update = 1;
1084: palette[i] = col;
1085: }
1086: v += 3;
1087: }
1088: return full_update;
1089: }
1090:
1.1.1.12 root 1091: static void vga_get_offsets(VGACommonState *s,
1.1.1.5 root 1092: uint32_t *pline_offset,
1.1.1.4 root 1093: uint32_t *pstart_addr,
1094: uint32_t *pline_compare)
1.1 root 1095: {
1.1.1.4 root 1096: uint32_t start_addr, line_offset, line_compare;
1.1 root 1097: #ifdef CONFIG_BOCHS_VBE
1098: if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1099: line_offset = s->vbe_line_offset;
1100: start_addr = s->vbe_start_addr;
1.1.1.4 root 1101: line_compare = 65535;
1.1 root 1102: } else
1103: #endif
1.1.1.5 root 1104: {
1.1 root 1105: /* compute line_offset in bytes */
1106: line_offset = s->cr[0x13];
1107: line_offset <<= 3;
1108:
1109: /* starting address */
1110: start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1.1.1.4 root 1111:
1112: /* line compare */
1.1.1.5 root 1113: line_compare = s->cr[0x18] |
1.1.1.4 root 1114: ((s->cr[0x07] & 0x10) << 4) |
1115: ((s->cr[0x09] & 0x40) << 3);
1.1 root 1116: }
1117: *pline_offset = line_offset;
1118: *pstart_addr = start_addr;
1.1.1.4 root 1119: *pline_compare = line_compare;
1.1 root 1120: }
1121:
1122: /* update start_addr and line_offset. Return TRUE if modified */
1.1.1.12 root 1123: static int update_basic_params(VGACommonState *s)
1.1 root 1124: {
1125: int full_update;
1126: uint32_t start_addr, line_offset, line_compare;
1.1.1.5 root 1127:
1.1 root 1128: full_update = 0;
1129:
1.1.1.4 root 1130: s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1.1 root 1131:
1132: if (line_offset != s->line_offset ||
1133: start_addr != s->start_addr ||
1134: line_compare != s->line_compare) {
1135: s->line_offset = line_offset;
1136: s->start_addr = start_addr;
1137: s->line_compare = line_compare;
1138: full_update = 1;
1139: }
1140: return full_update;
1141: }
1142:
1.1.1.5 root 1143: #define NB_DEPTHS 7
1.1.1.3 root 1144:
1145: static inline int get_depth_index(DisplayState *s)
1.1 root 1146: {
1.1.1.6 root 1147: switch(ds_get_bits_per_pixel(s)) {
1.1 root 1148: default:
1149: case 8:
1150: return 0;
1151: case 15:
1.1.1.6 root 1152: return 1;
1.1 root 1153: case 16:
1.1.1.6 root 1154: return 2;
1.1 root 1155: case 32:
1.1.1.10 root 1156: if (is_surface_bgr(s->surface))
1157: return 4;
1158: else
1159: return 3;
1.1 root 1160: }
1161: }
1162:
1.1.1.13 root 1163: static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
1.1 root 1164: vga_draw_glyph8_8,
1165: vga_draw_glyph8_16,
1166: vga_draw_glyph8_16,
1167: vga_draw_glyph8_32,
1.1.1.3 root 1168: vga_draw_glyph8_32,
1.1.1.5 root 1169: vga_draw_glyph8_16,
1170: vga_draw_glyph8_16,
1.1 root 1171: };
1172:
1.1.1.13 root 1173: static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
1.1 root 1174: vga_draw_glyph16_8,
1175: vga_draw_glyph16_16,
1176: vga_draw_glyph16_16,
1177: vga_draw_glyph16_32,
1.1.1.3 root 1178: vga_draw_glyph16_32,
1.1.1.5 root 1179: vga_draw_glyph16_16,
1180: vga_draw_glyph16_16,
1.1 root 1181: };
1182:
1.1.1.13 root 1183: static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
1.1 root 1184: vga_draw_glyph9_8,
1185: vga_draw_glyph9_16,
1186: vga_draw_glyph9_16,
1187: vga_draw_glyph9_32,
1.1.1.3 root 1188: vga_draw_glyph9_32,
1.1.1.5 root 1189: vga_draw_glyph9_16,
1190: vga_draw_glyph9_16,
1.1 root 1191: };
1.1.1.5 root 1192:
1.1 root 1193: static const uint8_t cursor_glyph[32 * 4] = {
1194: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1195: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1196: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1197: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1198: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1199: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1200: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1201: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1202: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1203: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1204: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1205: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1206: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1207: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1208: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1209: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1.1.1.5 root 1210: };
1.1 root 1211:
1.1.1.12 root 1212: static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1.1.1.6 root 1213: int *pcwidth, int *pcheight)
1214: {
1215: int width, cwidth, height, cheight;
1216:
1217: /* total width & height */
1218: cheight = (s->cr[9] & 0x1f) + 1;
1219: cwidth = 8;
1220: if (!(s->sr[1] & 0x01))
1221: cwidth = 9;
1222: if (s->sr[1] & 0x08)
1223: cwidth = 16; /* NOTE: no 18 pixel wide */
1224: width = (s->cr[0x01] + 1);
1225: if (s->cr[0x06] == 100) {
1226: /* ugly hack for CGA 160x100x16 - explain me the logic */
1227: height = 100;
1228: } else {
1229: height = s->cr[0x12] |
1230: ((s->cr[0x07] & 0x02) << 7) |
1231: ((s->cr[0x07] & 0x40) << 3);
1232: height = (height + 1) / cheight;
1233: }
1234:
1235: *pwidth = width;
1236: *pheight = height;
1237: *pcwidth = cwidth;
1238: *pcheight = cheight;
1239: }
1240:
1241: typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1242:
1.1.1.13 root 1243: static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
1.1.1.6 root 1244: rgb_to_pixel8_dup,
1245: rgb_to_pixel15_dup,
1246: rgb_to_pixel16_dup,
1247: rgb_to_pixel32_dup,
1248: rgb_to_pixel32bgr_dup,
1249: rgb_to_pixel15bgr_dup,
1250: rgb_to_pixel16bgr_dup,
1251: };
1252:
1.1.1.5 root 1253: /*
1254: * Text mode update
1.1 root 1255: * Missing:
1256: * - double scan
1.1.1.5 root 1257: * - double width
1.1 root 1258: * - underline
1259: * - flashing
1260: */
1.1.1.12 root 1261: static void vga_draw_text(VGACommonState *s, int full_update)
1.1 root 1262: {
1263: int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1.1.1.12 root 1264: int cx_min, cx_max, linesize, x_incr, line, line1;
1.1 root 1265: uint32_t offset, fgcol, bgcol, v, cursor_offset;
1.1.1.12 root 1266: uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1.1 root 1267: const uint8_t *font_ptr, *font_base[2];
1268: int dup9, line_offset, depth_index;
1269: uint32_t *palette;
1270: uint32_t *ch_attr_ptr;
1271: vga_draw_glyph8_func *vga_draw_glyph8;
1272: vga_draw_glyph9_func *vga_draw_glyph9;
1273:
1274: /* compute font data address (in plane 2) */
1275: v = s->sr[3];
1276: offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1277: if (offset != s->font_offsets[0]) {
1278: s->font_offsets[0] = offset;
1279: full_update = 1;
1280: }
1281: font_base[0] = s->vram_ptr + offset;
1282:
1283: offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1284: font_base[1] = s->vram_ptr + offset;
1285: if (offset != s->font_offsets[1]) {
1286: s->font_offsets[1] = offset;
1287: full_update = 1;
1288: }
1.1.1.16! root 1289: if (s->plane_updated & (1 << 2) || s->chain4_alias) {
1.1 root 1290: /* if the plane 2 was modified since the last display, it
1291: indicates the font may have been modified */
1292: s->plane_updated = 0;
1293: full_update = 1;
1294: }
1295: full_update |= update_basic_params(s);
1296:
1297: line_offset = s->line_offset;
1298:
1.1.1.6 root 1299: vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1.1 root 1300: if ((height * width) > CH_ATTR_SIZE) {
1301: /* better than nothing: exit if transient size is too big */
1302: return;
1303: }
1304:
1305: if (width != s->last_width || height != s->last_height ||
1.1.1.6 root 1306: cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1.1 root 1307: s->last_scr_width = width * cw;
1308: s->last_scr_height = height * cheight;
1.1.1.6 root 1309: qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1310: s->last_depth = 0;
1.1 root 1311: s->last_width = width;
1312: s->last_height = height;
1313: s->last_ch = cheight;
1314: s->last_cw = cw;
1315: full_update = 1;
1316: }
1.1.1.6 root 1317: s->rgb_to_pixel =
1318: rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1319: full_update |= update_palette16(s);
1320: palette = s->last_palette;
1321: x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1322:
1.1 root 1323: cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1324: if (cursor_offset != s->cursor_offset ||
1325: s->cr[0xa] != s->cursor_start ||
1326: s->cr[0xb] != s->cursor_end) {
1327: /* if the cursor position changed, we update the old and new
1328: chars */
1329: if (s->cursor_offset < CH_ATTR_SIZE)
1330: s->last_ch_attr[s->cursor_offset] = -1;
1331: if (cursor_offset < CH_ATTR_SIZE)
1332: s->last_ch_attr[cursor_offset] = -1;
1333: s->cursor_offset = cursor_offset;
1334: s->cursor_start = s->cr[0xa];
1335: s->cursor_end = s->cr[0xb];
1336: }
1337: cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1.1.1.5 root 1338:
1.1.1.3 root 1339: depth_index = get_depth_index(s->ds);
1.1 root 1340: if (cw == 16)
1341: vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1342: else
1343: vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1344: vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1.1.1.5 root 1345:
1.1.1.6 root 1346: dest = ds_get_data(s->ds);
1347: linesize = ds_get_linesize(s->ds);
1.1 root 1348: ch_attr_ptr = s->last_ch_attr;
1.1.1.12 root 1349: line = 0;
1350: offset = s->start_addr * 4;
1.1 root 1351: for(cy = 0; cy < height; cy++) {
1352: d1 = dest;
1.1.1.12 root 1353: src = s->vram_ptr + offset;
1.1 root 1354: cx_min = width;
1355: cx_max = -1;
1356: for(cx = 0; cx < width; cx++) {
1357: ch_attr = *(uint16_t *)src;
1358: if (full_update || ch_attr != *ch_attr_ptr) {
1359: if (cx < cx_min)
1360: cx_min = cx;
1361: if (cx > cx_max)
1362: cx_max = cx;
1363: *ch_attr_ptr = ch_attr;
1.1.1.12 root 1364: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 1365: ch = ch_attr >> 8;
1366: cattr = ch_attr & 0xff;
1367: #else
1368: ch = ch_attr & 0xff;
1369: cattr = ch_attr >> 8;
1370: #endif
1371: font_ptr = font_base[(cattr >> 3) & 1];
1372: font_ptr += 32 * 4 * ch;
1373: bgcol = palette[cattr >> 4];
1374: fgcol = palette[cattr & 0x0f];
1375: if (cw != 9) {
1.1.1.5 root 1376: vga_draw_glyph8(d1, linesize,
1.1 root 1377: font_ptr, cheight, fgcol, bgcol);
1378: } else {
1379: dup9 = 0;
1380: if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1381: dup9 = 1;
1.1.1.5 root 1382: vga_draw_glyph9(d1, linesize,
1.1 root 1383: font_ptr, cheight, fgcol, bgcol, dup9);
1384: }
1385: if (src == cursor_ptr &&
1386: !(s->cr[0x0a] & 0x20)) {
1387: int line_start, line_last, h;
1388: /* draw the cursor */
1389: line_start = s->cr[0x0a] & 0x1f;
1390: line_last = s->cr[0x0b] & 0x1f;
1391: /* XXX: check that */
1392: if (line_last > cheight - 1)
1393: line_last = cheight - 1;
1394: if (line_last >= line_start && line_start < cheight) {
1395: h = line_last - line_start + 1;
1396: d = d1 + linesize * line_start;
1397: if (cw != 9) {
1.1.1.5 root 1398: vga_draw_glyph8(d, linesize,
1.1 root 1399: cursor_glyph, h, fgcol, bgcol);
1400: } else {
1.1.1.5 root 1401: vga_draw_glyph9(d, linesize,
1.1 root 1402: cursor_glyph, h, fgcol, bgcol, 1);
1403: }
1404: }
1405: }
1406: }
1407: d1 += x_incr;
1408: src += 4;
1409: ch_attr_ptr++;
1410: }
1411: if (cx_max != -1) {
1.1.1.5 root 1412: dpy_update(s->ds, cx_min * cw, cy * cheight,
1.1 root 1413: (cx_max - cx_min + 1) * cw, cheight);
1414: }
1415: dest += linesize * cheight;
1.1.1.12 root 1416: line1 = line + cheight;
1417: offset += line_offset;
1418: if (line < s->line_compare && line1 >= s->line_compare) {
1419: offset = 0;
1420: }
1421: line = line1;
1.1 root 1422: }
1423: }
1424:
1425: enum {
1426: VGA_DRAW_LINE2,
1427: VGA_DRAW_LINE2D2,
1428: VGA_DRAW_LINE4,
1429: VGA_DRAW_LINE4D2,
1430: VGA_DRAW_LINE8D2,
1431: VGA_DRAW_LINE8,
1432: VGA_DRAW_LINE15,
1433: VGA_DRAW_LINE16,
1434: VGA_DRAW_LINE24,
1435: VGA_DRAW_LINE32,
1436: VGA_DRAW_LINE_NB,
1437: };
1438:
1.1.1.13 root 1439: static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1.1 root 1440: vga_draw_line2_8,
1441: vga_draw_line2_16,
1442: vga_draw_line2_16,
1443: vga_draw_line2_32,
1.1.1.3 root 1444: vga_draw_line2_32,
1.1.1.5 root 1445: vga_draw_line2_16,
1446: vga_draw_line2_16,
1.1 root 1447:
1448: vga_draw_line2d2_8,
1449: vga_draw_line2d2_16,
1450: vga_draw_line2d2_16,
1451: vga_draw_line2d2_32,
1.1.1.3 root 1452: vga_draw_line2d2_32,
1.1.1.5 root 1453: vga_draw_line2d2_16,
1454: vga_draw_line2d2_16,
1.1 root 1455:
1456: vga_draw_line4_8,
1457: vga_draw_line4_16,
1458: vga_draw_line4_16,
1459: vga_draw_line4_32,
1.1.1.3 root 1460: vga_draw_line4_32,
1.1.1.5 root 1461: vga_draw_line4_16,
1462: vga_draw_line4_16,
1.1 root 1463:
1464: vga_draw_line4d2_8,
1465: vga_draw_line4d2_16,
1466: vga_draw_line4d2_16,
1467: vga_draw_line4d2_32,
1.1.1.3 root 1468: vga_draw_line4d2_32,
1.1.1.5 root 1469: vga_draw_line4d2_16,
1470: vga_draw_line4d2_16,
1.1 root 1471:
1472: vga_draw_line8d2_8,
1473: vga_draw_line8d2_16,
1474: vga_draw_line8d2_16,
1475: vga_draw_line8d2_32,
1.1.1.3 root 1476: vga_draw_line8d2_32,
1.1.1.5 root 1477: vga_draw_line8d2_16,
1478: vga_draw_line8d2_16,
1.1 root 1479:
1480: vga_draw_line8_8,
1481: vga_draw_line8_16,
1482: vga_draw_line8_16,
1483: vga_draw_line8_32,
1.1.1.3 root 1484: vga_draw_line8_32,
1.1.1.5 root 1485: vga_draw_line8_16,
1486: vga_draw_line8_16,
1.1 root 1487:
1488: vga_draw_line15_8,
1489: vga_draw_line15_15,
1490: vga_draw_line15_16,
1491: vga_draw_line15_32,
1.1.1.3 root 1492: vga_draw_line15_32bgr,
1.1.1.5 root 1493: vga_draw_line15_15bgr,
1494: vga_draw_line15_16bgr,
1.1 root 1495:
1496: vga_draw_line16_8,
1497: vga_draw_line16_15,
1498: vga_draw_line16_16,
1499: vga_draw_line16_32,
1.1.1.3 root 1500: vga_draw_line16_32bgr,
1.1.1.5 root 1501: vga_draw_line16_15bgr,
1502: vga_draw_line16_16bgr,
1.1 root 1503:
1504: vga_draw_line24_8,
1505: vga_draw_line24_15,
1506: vga_draw_line24_16,
1507: vga_draw_line24_32,
1.1.1.3 root 1508: vga_draw_line24_32bgr,
1.1.1.5 root 1509: vga_draw_line24_15bgr,
1510: vga_draw_line24_16bgr,
1.1 root 1511:
1512: vga_draw_line32_8,
1513: vga_draw_line32_15,
1514: vga_draw_line32_16,
1515: vga_draw_line32_32,
1.1.1.3 root 1516: vga_draw_line32_32bgr,
1.1.1.5 root 1517: vga_draw_line32_15bgr,
1518: vga_draw_line32_16bgr,
1.1.1.3 root 1519: };
1520:
1.1.1.12 root 1521: static int vga_get_bpp(VGACommonState *s)
1.1 root 1522: {
1523: int ret;
1524: #ifdef CONFIG_BOCHS_VBE
1525: if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1526: ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1.1.1.5 root 1527: } else
1.1 root 1528: #endif
1529: {
1530: ret = 0;
1531: }
1532: return ret;
1533: }
1534:
1.1.1.12 root 1535: static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1.1 root 1536: {
1537: int width, height;
1.1.1.5 root 1538:
1.1.1.3 root 1539: #ifdef CONFIG_BOCHS_VBE
1540: if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1541: width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1542: height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1.1.1.5 root 1543: } else
1.1.1.3 root 1544: #endif
1545: {
1546: width = (s->cr[0x01] + 1) * 8;
1.1.1.5 root 1547: height = s->cr[0x12] |
1548: ((s->cr[0x07] & 0x02) << 7) |
1.1.1.3 root 1549: ((s->cr[0x07] & 0x40) << 3);
1550: height = (height + 1);
1551: }
1.1 root 1552: *pwidth = width;
1553: *pheight = height;
1554: }
1555:
1.1.1.12 root 1556: void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1.1 root 1557: {
1558: int y;
1559: if (y1 >= VGA_MAX_HEIGHT)
1560: return;
1561: if (y2 >= VGA_MAX_HEIGHT)
1562: y2 = VGA_MAX_HEIGHT;
1563: for(y = y1; y < y2; y++) {
1564: s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1565: }
1566: }
1567:
1.1.1.12 root 1568: static void vga_sync_dirty_bitmap(VGACommonState *s)
1.1.1.6 root 1569: {
1.1.1.16! root 1570: memory_region_sync_dirty_bitmap(&s->vram);
1.1.1.12 root 1571: }
1572:
1573: void vga_dirty_log_start(VGACommonState *s)
1574: {
1.1.1.16! root 1575: memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
1.1.1.12 root 1576: }
1577:
1578: void vga_dirty_log_stop(VGACommonState *s)
1579: {
1.1.1.16! root 1580: memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
1.1.1.6 root 1581: }
1582:
1.1.1.5 root 1583: /*
1.1 root 1584: * graphic modes
1585: */
1.1.1.12 root 1586: static void vga_draw_graphic(VGACommonState *s, int full_update)
1.1 root 1587: {
1.1.1.10 root 1588: int y1, y, update, linesize, y_start, double_scan, mask, depth;
1589: int width, height, shift_control, line_offset, bwidth, bits;
1590: ram_addr_t page0, page1, page_min, page_max;
1.1 root 1591: int disp_width, multi_scan, multi_run;
1592: uint8_t *d;
1593: uint32_t v, addr1, addr;
1594: vga_draw_line_func *vga_draw_line;
1.1.1.5 root 1595:
1.1 root 1596: full_update |= update_basic_params(s);
1597:
1.1.1.6 root 1598: if (!full_update)
1599: vga_sync_dirty_bitmap(s);
1600:
1.1 root 1601: s->get_resolution(s, &width, &height);
1602: disp_width = width;
1603:
1604: shift_control = (s->gr[0x05] >> 5) & 3;
1605: double_scan = (s->cr[0x09] >> 7);
1606: if (shift_control != 1) {
1607: multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1608: } else {
1609: /* in CGA modes, multi_scan is ignored */
1610: /* XXX: is it correct ? */
1611: multi_scan = double_scan;
1612: }
1613: multi_run = multi_scan;
1614: if (shift_control != s->shift_control ||
1615: double_scan != s->double_scan) {
1616: full_update = 1;
1617: s->shift_control = shift_control;
1618: s->double_scan = double_scan;
1619: }
1.1.1.5 root 1620:
1.1.1.8 root 1621: if (shift_control == 0) {
1622: if (s->sr[0x01] & 8) {
1623: disp_width <<= 1;
1624: }
1625: } else if (shift_control == 1) {
1626: if (s->sr[0x01] & 8) {
1627: disp_width <<= 1;
1628: }
1629: }
1630:
1.1.1.6 root 1631: depth = s->get_bpp(s);
1632: if (s->line_offset != s->last_line_offset ||
1633: disp_width != s->last_width ||
1634: height != s->last_height ||
1635: s->last_depth != depth) {
1.1.1.12 root 1636: #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1.1.1.6 root 1637: if (depth == 16 || depth == 32) {
1638: #else
1639: if (depth == 32) {
1640: #endif
1.1.1.10 root 1641: qemu_free_displaysurface(s->ds);
1642: s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1643: s->line_offset,
1644: s->vram_ptr + (s->start_addr * 4));
1.1.1.12 root 1645: #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1.1.1.10 root 1646: s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1.1.1.6 root 1647: #endif
1.1.1.10 root 1648: dpy_resize(s->ds);
1.1.1.6 root 1649: } else {
1650: qemu_console_resize(s->ds, disp_width, height);
1651: }
1652: s->last_scr_width = disp_width;
1653: s->last_scr_height = height;
1654: s->last_width = disp_width;
1655: s->last_height = height;
1656: s->last_line_offset = s->line_offset;
1657: s->last_depth = depth;
1658: full_update = 1;
1.1.1.10 root 1659: } else if (is_buffer_shared(s->ds->surface) &&
1.1.1.6 root 1660: (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1661: s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1662: dpy_setdata(s->ds);
1663: }
1664:
1665: s->rgb_to_pixel =
1666: rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1667:
1.1 root 1668: if (shift_control == 0) {
1669: full_update |= update_palette16(s);
1670: if (s->sr[0x01] & 8) {
1671: v = VGA_DRAW_LINE4D2;
1672: } else {
1673: v = VGA_DRAW_LINE4;
1674: }
1.1.1.6 root 1675: bits = 4;
1.1 root 1676: } else if (shift_control == 1) {
1677: full_update |= update_palette16(s);
1678: if (s->sr[0x01] & 8) {
1679: v = VGA_DRAW_LINE2D2;
1680: } else {
1681: v = VGA_DRAW_LINE2;
1682: }
1.1.1.6 root 1683: bits = 4;
1.1 root 1684: } else {
1685: switch(s->get_bpp(s)) {
1686: default:
1687: case 0:
1688: full_update |= update_palette256(s);
1689: v = VGA_DRAW_LINE8D2;
1.1.1.6 root 1690: bits = 4;
1.1 root 1691: break;
1692: case 8:
1693: full_update |= update_palette256(s);
1694: v = VGA_DRAW_LINE8;
1.1.1.6 root 1695: bits = 8;
1.1 root 1696: break;
1697: case 15:
1698: v = VGA_DRAW_LINE15;
1.1.1.6 root 1699: bits = 16;
1.1 root 1700: break;
1701: case 16:
1702: v = VGA_DRAW_LINE16;
1.1.1.6 root 1703: bits = 16;
1.1 root 1704: break;
1705: case 24:
1706: v = VGA_DRAW_LINE24;
1.1.1.6 root 1707: bits = 24;
1.1 root 1708: break;
1709: case 32:
1710: v = VGA_DRAW_LINE32;
1.1.1.6 root 1711: bits = 32;
1.1 root 1712: break;
1713: }
1714: }
1.1.1.3 root 1715: vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1.1 root 1716:
1.1.1.6 root 1717: if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1.1 root 1718: s->cursor_invalidate(s);
1.1.1.5 root 1719:
1.1 root 1720: line_offset = s->line_offset;
1721: #if 0
1722: 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",
1723: width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1724: #endif
1725: addr1 = (s->start_addr * 4);
1.1.1.6 root 1726: bwidth = (width * bits + 7) / 8;
1.1 root 1727: y_start = -1;
1.1.1.10 root 1728: page_min = -1;
1729: page_max = 0;
1.1.1.6 root 1730: d = ds_get_data(s->ds);
1731: linesize = ds_get_linesize(s->ds);
1.1 root 1732: y1 = 0;
1733: for(y = 0; y < height; y++) {
1734: addr = addr1;
1735: if (!(s->cr[0x17] & 1)) {
1736: int shift;
1737: /* CGA compatibility handling */
1738: shift = 14 + ((s->cr[0x17] >> 6) & 1);
1739: addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1740: }
1741: if (!(s->cr[0x17] & 2)) {
1742: addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1743: }
1.1.1.16! root 1744: page0 = addr & TARGET_PAGE_MASK;
! 1745: page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
1.1.1.5 root 1746: update = full_update |
1.1.1.16! root 1747: memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
! 1748: memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
1.1 root 1749: if ((page1 - page0) > TARGET_PAGE_SIZE) {
1750: /* if wide line, can use another page */
1.1.1.16! root 1751: update |= memory_region_get_dirty(&s->vram,
! 1752: page0 + TARGET_PAGE_SIZE,
! 1753: DIRTY_MEMORY_VGA);
1.1 root 1754: }
1755: /* explicit invalidation for the hardware cursor */
1756: update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1757: if (update) {
1758: if (y_start < 0)
1759: y_start = y;
1760: if (page0 < page_min)
1761: page_min = page0;
1762: if (page1 > page_max)
1763: page_max = page1;
1.1.1.6 root 1764: if (!(is_buffer_shared(s->ds->surface))) {
1765: vga_draw_line(s, d, s->vram_ptr + addr, width);
1766: if (s->cursor_draw_line)
1767: s->cursor_draw_line(s, d, y);
1768: }
1.1 root 1769: } else {
1770: if (y_start >= 0) {
1771: /* flush to display */
1.1.1.5 root 1772: dpy_update(s->ds, 0, y_start,
1.1 root 1773: disp_width, y - y_start);
1774: y_start = -1;
1775: }
1776: }
1777: if (!multi_run) {
1778: mask = (s->cr[0x17] & 3) ^ 3;
1779: if ((y1 & mask) == mask)
1780: addr1 += line_offset;
1781: y1++;
1782: multi_run = multi_scan;
1783: } else {
1784: multi_run--;
1785: }
1786: /* line compare acts on the displayed lines */
1787: if (y == s->line_compare)
1788: addr1 = 0;
1789: d += linesize;
1790: }
1791: if (y_start >= 0) {
1792: /* flush to display */
1.1.1.5 root 1793: dpy_update(s->ds, 0, y_start,
1.1 root 1794: disp_width, y - y_start);
1795: }
1796: /* reset modified pages */
1.1.1.10 root 1797: if (page_max >= page_min) {
1.1.1.16! root 1798: memory_region_reset_dirty(&s->vram,
! 1799: page_min,
! 1800: page_max + TARGET_PAGE_SIZE - page_min,
! 1801: DIRTY_MEMORY_VGA);
1.1 root 1802: }
1803: memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1804: }
1805:
1.1.1.12 root 1806: static void vga_draw_blank(VGACommonState *s, int full_update)
1.1 root 1807: {
1808: int i, w, val;
1809: uint8_t *d;
1810:
1811: if (!full_update)
1812: return;
1813: if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1814: return;
1.1.1.6 root 1815:
1816: s->rgb_to_pixel =
1817: rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1818: if (ds_get_bits_per_pixel(s->ds) == 8)
1.1 root 1819: val = s->rgb_to_pixel(0, 0, 0);
1820: else
1821: val = 0;
1.1.1.6 root 1822: w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1823: d = ds_get_data(s->ds);
1.1 root 1824: for(i = 0; i < s->last_scr_height; i++) {
1825: memset(d, val, w);
1.1.1.6 root 1826: d += ds_get_linesize(s->ds);
1.1 root 1827: }
1.1.1.5 root 1828: dpy_update(s->ds, 0, 0,
1.1 root 1829: s->last_scr_width, s->last_scr_height);
1830: }
1831:
1832: #define GMODE_TEXT 0
1833: #define GMODE_GRAPH 1
1.1.1.5 root 1834: #define GMODE_BLANK 2
1.1 root 1835:
1.1.1.2 root 1836: static void vga_update_display(void *opaque)
1.1 root 1837: {
1.1.1.12 root 1838: VGACommonState *s = opaque;
1.1 root 1839: int full_update, graphic_mode;
1840:
1.1.1.16! root 1841: qemu_flush_coalesced_mmio_buffer();
! 1842:
1.1.1.6 root 1843: if (ds_get_bits_per_pixel(s->ds) == 0) {
1.1 root 1844: /* nothing to do */
1845: } else {
1.1.1.11 root 1846: full_update = 0;
1.1 root 1847: if (!(s->ar_index & 0x20)) {
1848: graphic_mode = GMODE_BLANK;
1849: } else {
1850: graphic_mode = s->gr[6] & 1;
1851: }
1852: if (graphic_mode != s->graphic_mode) {
1853: s->graphic_mode = graphic_mode;
1854: full_update = 1;
1855: }
1856: switch(graphic_mode) {
1857: case GMODE_TEXT:
1858: vga_draw_text(s, full_update);
1859: break;
1860: case GMODE_GRAPH:
1861: vga_draw_graphic(s, full_update);
1862: break;
1863: case GMODE_BLANK:
1864: default:
1865: vga_draw_blank(s, full_update);
1866: break;
1867: }
1868: }
1869: }
1870:
1871: /* force a full display refresh */
1.1.1.2 root 1872: static void vga_invalidate_display(void *opaque)
1.1 root 1873: {
1.1.1.12 root 1874: VGACommonState *s = opaque;
1.1.1.5 root 1875:
1.1.1.11 root 1876: s->last_width = -1;
1877: s->last_height = -1;
1.1 root 1878: }
1879:
1.1.1.12 root 1880: void vga_common_reset(VGACommonState *s)
1.1 root 1881: {
1.1.1.6 root 1882: s->sr_index = 0;
1883: memset(s->sr, '\0', sizeof(s->sr));
1884: s->gr_index = 0;
1885: memset(s->gr, '\0', sizeof(s->gr));
1886: s->ar_index = 0;
1887: memset(s->ar, '\0', sizeof(s->ar));
1888: s->ar_flip_flop = 0;
1889: s->cr_index = 0;
1890: memset(s->cr, '\0', sizeof(s->cr));
1891: s->msr = 0;
1892: s->fcr = 0;
1893: s->st00 = 0;
1894: s->st01 = 0;
1895: s->dac_state = 0;
1896: s->dac_sub_index = 0;
1897: s->dac_read_index = 0;
1898: s->dac_write_index = 0;
1899: memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1900: s->dac_8bit = 0;
1901: memset(s->palette, '\0', sizeof(s->palette));
1902: s->bank_offset = 0;
1903: #ifdef CONFIG_BOCHS_VBE
1904: s->vbe_index = 0;
1905: memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1.1.1.13 root 1906: s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1.1.1.6 root 1907: s->vbe_start_addr = 0;
1908: s->vbe_line_offset = 0;
1909: s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1910: #endif
1911: memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1.1 root 1912: s->graphic_mode = -1; /* force full update */
1.1.1.6 root 1913: s->shift_control = 0;
1914: s->double_scan = 0;
1915: s->line_offset = 0;
1916: s->line_compare = 0;
1917: s->start_addr = 0;
1918: s->plane_updated = 0;
1919: s->last_cw = 0;
1920: s->last_ch = 0;
1921: s->last_width = 0;
1922: s->last_height = 0;
1923: s->last_scr_width = 0;
1924: s->last_scr_height = 0;
1925: s->cursor_start = 0;
1926: s->cursor_end = 0;
1927: s->cursor_offset = 0;
1928: memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1929: memset(s->last_palette, '\0', sizeof(s->last_palette));
1930: memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1931: switch (vga_retrace_method) {
1932: case VGA_RETRACE_DUMB:
1933: break;
1934: case VGA_RETRACE_PRECISE:
1935: memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1936: break;
1937: }
1.1.1.16! root 1938: vga_update_memory_access(s);
1.1.1.6 root 1939: }
1940:
1.1.1.12 root 1941: static void vga_reset(void *opaque)
1942: {
1943: VGACommonState *s = opaque;
1944: vga_common_reset(s);
1945: }
1946:
1.1.1.6 root 1947: #define TEXTMODE_X(x) ((x) % width)
1948: #define TEXTMODE_Y(x) ((x) / width)
1949: #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1950: ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1951: /* relay text rendering to the display driver
1952: * instead of doing a full vga_update_display() */
1953: static void vga_update_text(void *opaque, console_ch_t *chardata)
1954: {
1.1.1.12 root 1955: VGACommonState *s = opaque;
1.1.1.6 root 1956: int graphic_mode, i, cursor_offset, cursor_visible;
1957: int cw, cheight, width, height, size, c_min, c_max;
1958: uint32_t *src;
1959: console_ch_t *dst, val;
1960: char msg_buffer[80];
1961: int full_update = 0;
1962:
1.1.1.16! root 1963: qemu_flush_coalesced_mmio_buffer();
! 1964:
1.1.1.6 root 1965: if (!(s->ar_index & 0x20)) {
1966: graphic_mode = GMODE_BLANK;
1967: } else {
1968: graphic_mode = s->gr[6] & 1;
1969: }
1970: if (graphic_mode != s->graphic_mode) {
1971: s->graphic_mode = graphic_mode;
1972: full_update = 1;
1973: }
1974: if (s->last_width == -1) {
1975: s->last_width = 0;
1976: full_update = 1;
1977: }
1978:
1979: switch (graphic_mode) {
1980: case GMODE_TEXT:
1981: /* TODO: update palette */
1982: full_update |= update_basic_params(s);
1983:
1984: /* total width & height */
1985: cheight = (s->cr[9] & 0x1f) + 1;
1986: cw = 8;
1987: if (!(s->sr[1] & 0x01))
1988: cw = 9;
1989: if (s->sr[1] & 0x08)
1990: cw = 16; /* NOTE: no 18 pixel wide */
1991: width = (s->cr[0x01] + 1);
1992: if (s->cr[0x06] == 100) {
1993: /* ugly hack for CGA 160x100x16 - explain me the logic */
1994: height = 100;
1995: } else {
1996: height = s->cr[0x12] |
1997: ((s->cr[0x07] & 0x02) << 7) |
1998: ((s->cr[0x07] & 0x40) << 3);
1999: height = (height + 1) / cheight;
2000: }
2001:
2002: size = (height * width);
2003: if (size > CH_ATTR_SIZE) {
2004: if (!full_update)
2005: return;
2006:
2007: snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2008: width, height);
2009: break;
2010: }
2011:
2012: if (width != s->last_width || height != s->last_height ||
2013: cw != s->last_cw || cheight != s->last_ch) {
2014: s->last_scr_width = width * cw;
2015: s->last_scr_height = height * cheight;
2016: s->ds->surface->width = width;
2017: s->ds->surface->height = height;
2018: dpy_resize(s->ds);
2019: s->last_width = width;
2020: s->last_height = height;
2021: s->last_ch = cheight;
2022: s->last_cw = cw;
2023: full_update = 1;
2024: }
2025:
2026: /* Update "hardware" cursor */
2027: cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2028: if (cursor_offset != s->cursor_offset ||
2029: s->cr[0xa] != s->cursor_start ||
2030: s->cr[0xb] != s->cursor_end || full_update) {
2031: cursor_visible = !(s->cr[0xa] & 0x20);
2032: if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2033: dpy_cursor(s->ds,
2034: TEXTMODE_X(cursor_offset),
2035: TEXTMODE_Y(cursor_offset));
2036: else
2037: dpy_cursor(s->ds, -1, -1);
2038: s->cursor_offset = cursor_offset;
2039: s->cursor_start = s->cr[0xa];
2040: s->cursor_end = s->cr[0xb];
2041: }
2042:
2043: src = (uint32_t *) s->vram_ptr + s->start_addr;
2044: dst = chardata;
2045:
2046: if (full_update) {
2047: for (i = 0; i < size; src ++, dst ++, i ++)
1.1.1.14 root 2048: console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
1.1.1.6 root 2049:
2050: dpy_update(s->ds, 0, 0, width, height);
2051: } else {
2052: c_max = 0;
2053:
2054: for (i = 0; i < size; src ++, dst ++, i ++) {
1.1.1.14 root 2055: console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1.1.1.6 root 2056: if (*dst != val) {
2057: *dst = val;
2058: c_max = i;
2059: break;
2060: }
2061: }
2062: c_min = i;
2063: for (; i < size; src ++, dst ++, i ++) {
1.1.1.14 root 2064: console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1.1.1.6 root 2065: if (*dst != val) {
2066: *dst = val;
2067: c_max = i;
2068: }
2069: }
2070:
2071: if (c_min <= c_max) {
2072: i = TEXTMODE_Y(c_min);
2073: dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2074: }
2075: }
2076:
2077: return;
2078: case GMODE_GRAPH:
2079: if (!full_update)
2080: return;
2081:
2082: s->get_resolution(s, &width, &height);
2083: snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2084: width, height);
2085: break;
2086: case GMODE_BLANK:
2087: default:
2088: if (!full_update)
2089: return;
2090:
2091: snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2092: break;
2093: }
2094:
2095: /* Display a message */
2096: s->last_width = 60;
2097: s->last_height = height = 3;
2098: dpy_cursor(s->ds, -1, -1);
2099: s->ds->surface->width = s->last_width;
2100: s->ds->surface->height = height;
2101: dpy_resize(s->ds);
2102:
2103: for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2104: console_write_ch(dst ++, ' ');
2105:
2106: size = strlen(msg_buffer);
2107: width = (s->last_width - size) / 2;
2108: dst = chardata + s->last_width + width;
2109: for (i = 0; i < size; i ++)
2110: console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2111:
2112: dpy_update(s->ds, 0, 0, s->last_width, height);
1.1 root 2113: }
2114:
1.1.1.16! root 2115: static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
! 2116: unsigned size)
! 2117: {
! 2118: VGACommonState *s = opaque;
! 2119:
! 2120: return vga_mem_readb(s, addr);
! 2121: }
! 2122:
! 2123: static void vga_mem_write(void *opaque, target_phys_addr_t addr,
! 2124: uint64_t data, unsigned size)
! 2125: {
! 2126: VGACommonState *s = opaque;
! 2127:
! 2128: return vga_mem_writeb(s, addr, data);
! 2129: }
1.1 root 2130:
1.1.1.16! root 2131: const MemoryRegionOps vga_mem_ops = {
! 2132: .read = vga_mem_read,
! 2133: .write = vga_mem_write,
! 2134: .endianness = DEVICE_LITTLE_ENDIAN,
! 2135: .impl = {
! 2136: .min_access_size = 1,
! 2137: .max_access_size = 1,
! 2138: },
1.1 root 2139: };
2140:
1.1.1.12 root 2141: static int vga_common_post_load(void *opaque, int version_id)
1.1 root 2142: {
1.1.1.12 root 2143: VGACommonState *s = opaque;
1.1 root 2144:
2145: /* force refresh */
2146: s->graphic_mode = -1;
2147: return 0;
2148: }
2149:
1.1.1.12 root 2150: const VMStateDescription vmstate_vga_common = {
2151: .name = "vga",
2152: .version_id = 2,
2153: .minimum_version_id = 2,
2154: .minimum_version_id_old = 2,
2155: .post_load = vga_common_post_load,
2156: .fields = (VMStateField []) {
2157: VMSTATE_UINT32(latch, VGACommonState),
2158: VMSTATE_UINT8(sr_index, VGACommonState),
2159: VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2160: VMSTATE_UINT8(gr_index, VGACommonState),
2161: VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2162: VMSTATE_UINT8(ar_index, VGACommonState),
2163: VMSTATE_BUFFER(ar, VGACommonState),
2164: VMSTATE_INT32(ar_flip_flop, VGACommonState),
2165: VMSTATE_UINT8(cr_index, VGACommonState),
2166: VMSTATE_BUFFER(cr, VGACommonState),
2167: VMSTATE_UINT8(msr, VGACommonState),
2168: VMSTATE_UINT8(fcr, VGACommonState),
2169: VMSTATE_UINT8(st00, VGACommonState),
2170: VMSTATE_UINT8(st01, VGACommonState),
2171:
2172: VMSTATE_UINT8(dac_state, VGACommonState),
2173: VMSTATE_UINT8(dac_sub_index, VGACommonState),
2174: VMSTATE_UINT8(dac_read_index, VGACommonState),
2175: VMSTATE_UINT8(dac_write_index, VGACommonState),
2176: VMSTATE_BUFFER(dac_cache, VGACommonState),
2177: VMSTATE_BUFFER(palette, VGACommonState),
1.1.1.4 root 2178:
1.1.1.12 root 2179: VMSTATE_INT32(bank_offset, VGACommonState),
2180: VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2181: #ifdef CONFIG_BOCHS_VBE
2182: VMSTATE_UINT16(vbe_index, VGACommonState),
2183: VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2184: VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2185: VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2186: VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2187: #endif
2188: VMSTATE_END_OF_LIST()
1.1 root 2189: }
1.1.1.12 root 2190: };
1.1 root 2191:
1.1.1.12 root 2192: void vga_common_init(VGACommonState *s, int vga_ram_size)
1.1 root 2193: {
2194: int i, j, v, b;
2195:
2196: for(i = 0;i < 256; i++) {
2197: v = 0;
2198: for(j = 0; j < 8; j++) {
2199: v |= ((i >> j) & 1) << (j * 4);
2200: }
2201: expand4[i] = v;
2202:
2203: v = 0;
2204: for(j = 0; j < 4; j++) {
2205: v |= ((i >> (2 * j)) & 3) << (j * 4);
2206: }
2207: expand2[i] = v;
2208: }
2209: for(i = 0; i < 16; i++) {
2210: v = 0;
2211: for(j = 0; j < 4; j++) {
2212: b = ((i >> j) & 1);
2213: v |= b << (2 * j);
2214: v |= b << (2 * j + 1);
2215: }
2216: expand4to8[i] = v;
2217: }
2218:
1.1.1.12 root 2219: #ifdef CONFIG_BOCHS_VBE
2220: s->is_vbe_vmstate = 1;
2221: #else
2222: s->is_vbe_vmstate = 0;
2223: #endif
1.1.1.16! root 2224: memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size);
! 2225: s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
1.1 root 2226: s->vram_size = vga_ram_size;
2227: s->get_bpp = vga_get_bpp;
2228: s->get_offsets = vga_get_offsets;
2229: s->get_resolution = vga_get_resolution;
1.1.1.5 root 2230: s->update = vga_update_display;
2231: s->invalidate = vga_invalidate_display;
2232: s->screen_dump = vga_screen_dump;
1.1.1.6 root 2233: s->text_update = vga_update_text;
2234: switch (vga_retrace_method) {
2235: case VGA_RETRACE_DUMB:
2236: s->retrace = vga_dumb_retrace;
2237: s->update_retrace_info = vga_dumb_update_retrace_info;
2238: break;
2239:
2240: case VGA_RETRACE_PRECISE:
2241: s->retrace = vga_precise_retrace;
2242: s->update_retrace_info = vga_precise_update_retrace_info;
2243: break;
2244: }
1.1.1.16! root 2245: vga_dirty_log_start(s);
1.1 root 2246: }
2247:
1.1.1.16! root 2248: static const MemoryRegionPortio vga_portio_list[] = {
! 2249: { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
! 2250: { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
! 2251: { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
! 2252: { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
! 2253: { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
! 2254: PORTIO_END_OF_LIST(),
! 2255: };
1.1 root 2256:
2257: #ifdef CONFIG_BOCHS_VBE
1.1.1.16! root 2258: static const MemoryRegionPortio vbe_portio_list[] = {
! 2259: { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
! 2260: # ifdef TARGET_I386
! 2261: { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
! 2262: # else
! 2263: { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
! 2264: # endif
! 2265: PORTIO_END_OF_LIST(),
! 2266: };
! 2267: #endif /* CONFIG_BOCHS_VBE */
1.1 root 2268:
1.1.1.16! root 2269: /* Used by both ISA and PCI */
! 2270: MemoryRegion *vga_init_io(VGACommonState *s,
! 2271: const MemoryRegionPortio **vga_ports,
! 2272: const MemoryRegionPortio **vbe_ports)
! 2273: {
! 2274: MemoryRegion *vga_mem;
1.1 root 2275:
1.1.1.16! root 2276: *vga_ports = vga_portio_list;
! 2277: *vbe_ports = NULL;
! 2278: #ifdef CONFIG_BOCHS_VBE
! 2279: *vbe_ports = vbe_portio_list;
1.1 root 2280: #endif
2281:
1.1.1.16! root 2282: vga_mem = g_malloc(sizeof(*vga_mem));
! 2283: memory_region_init_io(vga_mem, &vga_mem_ops, s,
! 2284: "vga-lowmem", 0x20000);
! 2285:
! 2286: return vga_mem;
1.1.1.15 root 2287: }
2288:
1.1.1.16! root 2289: void vga_init(VGACommonState *s, MemoryRegion *address_space,
! 2290: MemoryRegion *address_space_io, bool init_vga_ports)
1.1.1.15 root 2291: {
1.1.1.16! root 2292: MemoryRegion *vga_io_memory;
! 2293: const MemoryRegionPortio *vga_ports, *vbe_ports;
! 2294: PortioList *vga_port_list = g_new(PortioList, 1);
! 2295: PortioList *vbe_port_list = g_new(PortioList, 1);
1.1.1.15 root 2296:
2297: qemu_register_reset(vga_reset, s);
2298:
2299: s->bank_offset = 0;
2300:
1.1.1.16! root 2301: s->legacy_address_space = address_space;
! 2302:
! 2303: vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
! 2304: memory_region_add_subregion_overlap(address_space,
! 2305: isa_mem_base + 0x000a0000,
! 2306: vga_io_memory,
! 2307: 1);
! 2308: memory_region_set_coalescing(vga_io_memory);
! 2309: if (init_vga_ports) {
! 2310: portio_list_init(vga_port_list, vga_ports, s, "vga");
! 2311: portio_list_add(vga_port_list, address_space_io, 0x3b0);
! 2312: }
! 2313: if (vbe_ports) {
! 2314: portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
! 2315: portio_list_add(vbe_port_list, address_space_io, 0x1ce);
! 2316: }
1.1.1.4 root 2317: }
1.1 root 2318:
1.1.1.16! root 2319: void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
1.1.1.4 root 2320: {
1.1 root 2321: #ifdef CONFIG_BOCHS_VBE
1.1.1.4 root 2322: /* XXX: use optimized standard vga accesses */
1.1.1.16! root 2323: memory_region_add_subregion(system_memory,
! 2324: VBE_DISPI_LFB_PHYSICAL_ADDRESS,
! 2325: &s->vram);
1.1.1.12 root 2326: s->vbe_mapped = 1;
2327: #endif
1.1.1.4 root 2328: }
1.1 root 2329: /********************************************************/
2330: /* vga screen dump */
2331:
1.1.1.10 root 2332: static void vga_save_dpy_update(DisplayState *ds,
1.1 root 2333: int x, int y, int w, int h)
2334: {
1.1.1.10 root 2335: if (screen_dump_filename) {
2336: ppm_save(screen_dump_filename, ds->surface);
2337: }
1.1 root 2338: }
2339:
1.1.1.6 root 2340: static void vga_save_dpy_resize(DisplayState *s)
1.1 root 2341: {
2342: }
2343:
2344: static void vga_save_dpy_refresh(DisplayState *s)
2345: {
2346: }
2347:
1.1.1.6 root 2348: int ppm_save(const char *filename, struct DisplaySurface *ds)
1.1 root 2349: {
2350: FILE *f;
2351: uint8_t *d, *d1;
1.1.1.6 root 2352: uint32_t v;
1.1 root 2353: int y, x;
1.1.1.6 root 2354: uint8_t r, g, b;
1.1.1.15 root 2355: int ret;
2356: char *linebuf, *pbuf;
1.1 root 2357:
2358: f = fopen(filename, "wb");
2359: if (!f)
2360: return -1;
2361: fprintf(f, "P6\n%d %d\n%d\n",
1.1.1.6 root 2362: ds->width, ds->height, 255);
1.1.1.16! root 2363: linebuf = g_malloc(ds->width * 3);
1.1.1.6 root 2364: d1 = ds->data;
2365: for(y = 0; y < ds->height; y++) {
1.1 root 2366: d = d1;
1.1.1.15 root 2367: pbuf = linebuf;
1.1.1.6 root 2368: for(x = 0; x < ds->width; x++) {
2369: if (ds->pf.bits_per_pixel == 32)
2370: v = *(uint32_t *)d;
2371: else
2372: v = (uint32_t) (*(uint16_t *)d);
2373: r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2374: (ds->pf.rmax + 1);
2375: g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2376: (ds->pf.gmax + 1);
2377: b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2378: (ds->pf.bmax + 1);
1.1.1.15 root 2379: *pbuf++ = r;
2380: *pbuf++ = g;
2381: *pbuf++ = b;
1.1.1.6 root 2382: d += ds->pf.bytes_per_pixel;
1.1 root 2383: }
1.1.1.6 root 2384: d1 += ds->linesize;
1.1.1.15 root 2385: ret = fwrite(linebuf, 1, pbuf - linebuf, f);
2386: (void)ret;
1.1 root 2387: }
1.1.1.16! root 2388: g_free(linebuf);
1.1 root 2389: fclose(f);
2390: return 0;
2391: }
2392:
1.1.1.10 root 2393: static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
1.1.1.6 root 2394: {
1.1.1.10 root 2395: DisplayChangeListener *dcl;
1.1.1.6 root 2396:
1.1.1.16! root 2397: dcl = g_malloc0(sizeof(DisplayChangeListener));
1.1.1.10 root 2398: dcl->dpy_update = vga_save_dpy_update;
2399: dcl->dpy_resize = vga_save_dpy_resize;
2400: dcl->dpy_refresh = vga_save_dpy_refresh;
2401: register_displaychangelistener(ds, dcl);
2402: return dcl;
1.1.1.6 root 2403: }
2404:
2405: /* save the vga display in a PPM image even if no display is
2406: available */
2407: static void vga_screen_dump(void *opaque, const char *filename)
2408: {
1.1.1.12 root 2409: VGACommonState *s = opaque;
1.1.1.6 root 2410:
1.1.1.10 root 2411: if (!screen_dump_dcl)
2412: screen_dump_dcl = vga_screen_dump_init(s->ds);
2413:
1.1.1.16! root 2414: screen_dump_filename = filename;
1.1.1.9 root 2415: vga_invalidate_display(s);
1.1.1.10 root 2416: vga_hw_update();
1.1.1.16! root 2417: screen_dump_filename = NULL;
1.1.1.6 root 2418: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.