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