]> git.proxmox.com Git - qemu.git/blob - hw/vga.c
Merge remote-tracking branch 'spice/spice.v39' into staging
[qemu.git] / hw / vga.c
1 /*
2 * QEMU VGA Emulator.
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "hw.h"
25 #include "console.h"
26 #include "pc.h"
27 #include "pci.h"
28 #include "vga_int.h"
29 #include "pixel_ops.h"
30 #include "qemu-timer.h"
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] = {
40 0x03,
41 0x3d,
42 0x0f,
43 0x3f,
44 0x0e,
45 0x00,
46 0x00,
47 0xff,
48 };
49
50 const uint8_t gr_mask[16] = {
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 */
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
76 #ifdef HOST_WORDS_BIGENDIAN
77 #define PAT(x) cbswap_32(x)
78 #else
79 #define PAT(x) (x)
80 #endif
81
82 #ifdef HOST_WORDS_BIGENDIAN
83 #define BIG 1
84 #else
85 #define BIG 0
86 #endif
87
88 #ifdef HOST_WORDS_BIGENDIAN
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
115 #ifdef HOST_WORDS_BIGENDIAN
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
151 static void vga_screen_dump(void *opaque, const char *filename);
152 static char *screen_dump_filename;
153 static DisplayChangeListener *screen_dump_dcl;
154
155 static void vga_dumb_update_retrace_info(VGACommonState *s)
156 {
157 (void) s;
158 }
159
160 static void vga_precise_update_retrace_info(VGACommonState *s)
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
171 int dots;
172 #if 0
173 int div2, sldiv2;
174 #endif
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) {
206 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
207 } else {
208 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
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
219 div2 = (s->cr[0x17] >> 2) & 1;
220 sldiv2 = (s->cr[0x17] >> 3) & 1;
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"
234 "ticks/char = %" PRId64 "\n"
235 "\n",
236 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
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
254 static uint8_t vga_precise_retrace(VGACommonState *s)
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
263 cur_tick = qemu_get_clock_ns(vm_clock);
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
283 static uint8_t vga_dumb_retrace(VGACommonState *s)
284 {
285 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
286 }
287
288 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
289 {
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;
302 int val, index;
303
304 if (vga_ioport_invalid(s, addr)) {
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;
317 if (index < 21)
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;
337 case 0x3c8:
338 val = s->dac_write_index;
339 break;
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 */
376 val = s->st01 = s->retrace(s);
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
390 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
391 {
392 VGACommonState *s = opaque;
393 int index;
394
395 /* check port range access depending on color/monochrome mode */
396 if (vga_ioport_invalid(s, addr)) {
397 return;
398 }
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;
437 s->update_retrace_info(s);
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];
447 if (s->sr_index == 1) s->update_retrace_info(s);
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 }
492 s->cr[s->cr_index] = val;
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 }
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 {
516 VGACommonState *s = opaque;
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 {
524 VGACommonState *s = opaque;
525 uint32_t val;
526
527 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
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:
541 val = s->vbe_regs[s->vbe_index];
542 break;
543 }
544 } else {
545 val = s->vbe_regs[s->vbe_index];
546 }
547 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
548 val = s->vram_size / (64 * 1024);
549 } else {
550 val = 0;
551 }
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 {
560 VGACommonState *s = opaque;
561 s->vbe_index = val;
562 }
563
564 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
565 {
566 VGACommonState *s = opaque;
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 ||
576 val == VBE_DISPI_ID2 ||
577 val == VBE_DISPI_ID3 ||
578 val == VBE_DISPI_ID4) {
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;
595 if (val == 4 || val == 8 || val == 15 ||
596 val == 16 || val == 24 || val == 32) {
597 s->vbe_regs[s->vbe_index] = val;
598 }
599 break;
600 case VBE_DISPI_INDEX_BANK:
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 }
606 s->vbe_regs[s->vbe_index] = val;
607 s->bank_offset = (val << 16);
608 break;
609 case VBE_DISPI_INDEX_ENABLE:
610 if ((val & VBE_DISPI_ENABLED) &&
611 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
612 int h, shift_control;
613
614 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
615 s->vbe_regs[VBE_DISPI_INDEX_XRES];
616 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
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;
620
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
624 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
625 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
626 s->vbe_start_addr = 0;
627
628 /* clear the screen (should be done in BIOS) */
629 if (!(val & VBE_DISPI_NOCLEARMEM)) {
630 memset(s->vram_ptr, 0,
631 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
632 }
633
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;
641 /* height (only meaningful if < 1024) */
642 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
643 s->cr[0x12] = h;
644 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
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;
650
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 }
665 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
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 {
712 VGACommonState *s = opaque;
713 int memory_map_mode, plane;
714 uint32_t ret;
715
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 }
739
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 {
787 VGACommonState *s = opaque;
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
792 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
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 }
817
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
825 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
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
838 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
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];
908 ((uint32_t *)s->vram_ptr)[addr] =
909 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
910 (val & write_mask);
911 #ifdef DEBUG_VGA_MEM
912 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
913 addr * 4, write_mask, val);
914 #endif
915 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
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,
937 const uint8_t *font_ptr, int h,
938 uint32_t fgcol, uint32_t bgcol, int dup9);
939 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
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
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
956 #define DEPTH 16
957 #include "vga_template.h"
958
959 #define DEPTH 32
960 #include "vga_template.h"
961
962 #define BGR_FORMAT
963 #define DEPTH 32
964 #include "vga_template.h"
965
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
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
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
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
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
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
1023 /* return true if the palette was modified */
1024 static int update_palette16(VGACommonState *s)
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;
1038 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1039 c6_to_8(s->palette[v + 1]),
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 */
1050 static int update_palette256(VGACommonState *s)
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++) {
1059 if (s->dac_8bit) {
1060 col = s->rgb_to_pixel(s->palette[v],
1061 s->palette[v + 1],
1062 s->palette[v + 2]);
1063 } else {
1064 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1065 c6_to_8(s->palette[v + 1]),
1066 c6_to_8(s->palette[v + 2]));
1067 }
1068 if (col != palette[i]) {
1069 full_update = 1;
1070 palette[i] = col;
1071 }
1072 v += 3;
1073 }
1074 return full_update;
1075 }
1076
1077 static void vga_get_offsets(VGACommonState *s,
1078 uint32_t *pline_offset,
1079 uint32_t *pstart_addr,
1080 uint32_t *pline_compare)
1081 {
1082 uint32_t start_addr, line_offset, line_compare;
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;
1087 line_compare = 65535;
1088 } else
1089 #endif
1090 {
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);
1097
1098 /* line compare */
1099 line_compare = s->cr[0x18] |
1100 ((s->cr[0x07] & 0x10) << 4) |
1101 ((s->cr[0x09] & 0x40) << 3);
1102 }
1103 *pline_offset = line_offset;
1104 *pstart_addr = start_addr;
1105 *pline_compare = line_compare;
1106 }
1107
1108 /* update start_addr and line_offset. Return TRUE if modified */
1109 static int update_basic_params(VGACommonState *s)
1110 {
1111 int full_update;
1112 uint32_t start_addr, line_offset, line_compare;
1113
1114 full_update = 0;
1115
1116 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
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
1129 #define NB_DEPTHS 7
1130
1131 static inline int get_depth_index(DisplayState *s)
1132 {
1133 switch(ds_get_bits_per_pixel(s)) {
1134 default:
1135 case 8:
1136 return 0;
1137 case 15:
1138 return 1;
1139 case 16:
1140 return 2;
1141 case 32:
1142 if (is_surface_bgr(s->surface))
1143 return 4;
1144 else
1145 return 3;
1146 }
1147 }
1148
1149 static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
1150 vga_draw_glyph8_8,
1151 vga_draw_glyph8_16,
1152 vga_draw_glyph8_16,
1153 vga_draw_glyph8_32,
1154 vga_draw_glyph8_32,
1155 vga_draw_glyph8_16,
1156 vga_draw_glyph8_16,
1157 };
1158
1159 static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
1160 vga_draw_glyph16_8,
1161 vga_draw_glyph16_16,
1162 vga_draw_glyph16_16,
1163 vga_draw_glyph16_32,
1164 vga_draw_glyph16_32,
1165 vga_draw_glyph16_16,
1166 vga_draw_glyph16_16,
1167 };
1168
1169 static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
1170 vga_draw_glyph9_8,
1171 vga_draw_glyph9_16,
1172 vga_draw_glyph9_16,
1173 vga_draw_glyph9_32,
1174 vga_draw_glyph9_32,
1175 vga_draw_glyph9_16,
1176 vga_draw_glyph9_16,
1177 };
1178
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,
1196 };
1197
1198 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
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
1229 static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
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
1239 /*
1240 * Text mode update
1241 * Missing:
1242 * - double scan
1243 * - double width
1244 * - underline
1245 * - flashing
1246 */
1247 static void vga_draw_text(VGACommonState *s, int full_update)
1248 {
1249 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1250 int cx_min, cx_max, linesize, x_incr, line, line1;
1251 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1252 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
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
1285 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
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 ||
1292 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1293 s->last_scr_width = width * cw;
1294 s->last_scr_height = height * cheight;
1295 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1296 s->last_depth = 0;
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 }
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
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;
1324
1325 depth_index = get_depth_index(s->ds);
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];
1331
1332 dest = ds_get_data(s->ds);
1333 linesize = ds_get_linesize(s->ds);
1334 ch_attr_ptr = s->last_ch_attr;
1335 line = 0;
1336 offset = s->start_addr * 4;
1337 for(cy = 0; cy < height; cy++) {
1338 d1 = dest;
1339 src = s->vram_ptr + offset;
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;
1350 #ifdef HOST_WORDS_BIGENDIAN
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) {
1362 vga_draw_glyph8(d1, linesize,
1363 font_ptr, cheight, fgcol, bgcol);
1364 } else {
1365 dup9 = 0;
1366 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1367 dup9 = 1;
1368 vga_draw_glyph9(d1, linesize,
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) {
1384 vga_draw_glyph8(d, linesize,
1385 cursor_glyph, h, fgcol, bgcol);
1386 } else {
1387 vga_draw_glyph9(d, linesize,
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) {
1398 dpy_update(s->ds, cx_min * cw, cy * cheight,
1399 (cx_max - cx_min + 1) * cw, cheight);
1400 }
1401 dest += linesize * cheight;
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;
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
1425 static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1426 vga_draw_line2_8,
1427 vga_draw_line2_16,
1428 vga_draw_line2_16,
1429 vga_draw_line2_32,
1430 vga_draw_line2_32,
1431 vga_draw_line2_16,
1432 vga_draw_line2_16,
1433
1434 vga_draw_line2d2_8,
1435 vga_draw_line2d2_16,
1436 vga_draw_line2d2_16,
1437 vga_draw_line2d2_32,
1438 vga_draw_line2d2_32,
1439 vga_draw_line2d2_16,
1440 vga_draw_line2d2_16,
1441
1442 vga_draw_line4_8,
1443 vga_draw_line4_16,
1444 vga_draw_line4_16,
1445 vga_draw_line4_32,
1446 vga_draw_line4_32,
1447 vga_draw_line4_16,
1448 vga_draw_line4_16,
1449
1450 vga_draw_line4d2_8,
1451 vga_draw_line4d2_16,
1452 vga_draw_line4d2_16,
1453 vga_draw_line4d2_32,
1454 vga_draw_line4d2_32,
1455 vga_draw_line4d2_16,
1456 vga_draw_line4d2_16,
1457
1458 vga_draw_line8d2_8,
1459 vga_draw_line8d2_16,
1460 vga_draw_line8d2_16,
1461 vga_draw_line8d2_32,
1462 vga_draw_line8d2_32,
1463 vga_draw_line8d2_16,
1464 vga_draw_line8d2_16,
1465
1466 vga_draw_line8_8,
1467 vga_draw_line8_16,
1468 vga_draw_line8_16,
1469 vga_draw_line8_32,
1470 vga_draw_line8_32,
1471 vga_draw_line8_16,
1472 vga_draw_line8_16,
1473
1474 vga_draw_line15_8,
1475 vga_draw_line15_15,
1476 vga_draw_line15_16,
1477 vga_draw_line15_32,
1478 vga_draw_line15_32bgr,
1479 vga_draw_line15_15bgr,
1480 vga_draw_line15_16bgr,
1481
1482 vga_draw_line16_8,
1483 vga_draw_line16_15,
1484 vga_draw_line16_16,
1485 vga_draw_line16_32,
1486 vga_draw_line16_32bgr,
1487 vga_draw_line16_15bgr,
1488 vga_draw_line16_16bgr,
1489
1490 vga_draw_line24_8,
1491 vga_draw_line24_15,
1492 vga_draw_line24_16,
1493 vga_draw_line24_32,
1494 vga_draw_line24_32bgr,
1495 vga_draw_line24_15bgr,
1496 vga_draw_line24_16bgr,
1497
1498 vga_draw_line32_8,
1499 vga_draw_line32_15,
1500 vga_draw_line32_16,
1501 vga_draw_line32_32,
1502 vga_draw_line32_32bgr,
1503 vga_draw_line32_15bgr,
1504 vga_draw_line32_16bgr,
1505 };
1506
1507 static int vga_get_bpp(VGACommonState *s)
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];
1513 } else
1514 #endif
1515 {
1516 ret = 0;
1517 }
1518 return ret;
1519 }
1520
1521 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1522 {
1523 int width, height;
1524
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];
1529 } else
1530 #endif
1531 {
1532 width = (s->cr[0x01] + 1) * 8;
1533 height = s->cr[0x12] |
1534 ((s->cr[0x07] & 0x02) << 7) |
1535 ((s->cr[0x07] & 0x40) << 3);
1536 height = (height + 1);
1537 }
1538 *pwidth = width;
1539 *pheight = height;
1540 }
1541
1542 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
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
1554 static void vga_sync_dirty_bitmap(VGACommonState *s)
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 }
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 {
1575 if (s->map_addr) {
1576 cpu_physical_log_start(s->map_addr, s->map_end - s->map_addr);
1577 }
1578
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);
1582 }
1583
1584 #ifdef CONFIG_BOCHS_VBE
1585 if (s->vbe_mapped) {
1586 cpu_physical_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
1587 }
1588 #endif
1589 }
1590
1591 void vga_dirty_log_stop(VGACommonState *s)
1592 {
1593 if (s->map_addr) {
1594 cpu_physical_log_stop(s->map_addr, s->map_end - s->map_addr);
1595 }
1596
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);
1600 }
1601
1602 #ifdef CONFIG_BOCHS_VBE
1603 if (s->vbe_mapped) {
1604 cpu_physical_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
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);
1613 }
1614
1615 /*
1616 * graphic modes
1617 */
1618 static void vga_draw_graphic(VGACommonState *s, int full_update)
1619 {
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;
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;
1627
1628 full_update |= update_basic_params(s);
1629
1630 if (!full_update)
1631 vga_sync_dirty_bitmap(s);
1632
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 }
1652
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
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) {
1668 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1669 if (depth == 16 || depth == 32) {
1670 #else
1671 if (depth == 32) {
1672 #endif
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));
1677 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1678 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1679 #endif
1680 dpy_resize(s->ds);
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;
1691 } else if (is_buffer_shared(s->ds->surface) &&
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
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 }
1707 bits = 4;
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 }
1715 bits = 4;
1716 } else {
1717 switch(s->get_bpp(s)) {
1718 default:
1719 case 0:
1720 full_update |= update_palette256(s);
1721 v = VGA_DRAW_LINE8D2;
1722 bits = 4;
1723 break;
1724 case 8:
1725 full_update |= update_palette256(s);
1726 v = VGA_DRAW_LINE8;
1727 bits = 8;
1728 break;
1729 case 15:
1730 v = VGA_DRAW_LINE15;
1731 bits = 16;
1732 break;
1733 case 16:
1734 v = VGA_DRAW_LINE16;
1735 bits = 16;
1736 break;
1737 case 24:
1738 v = VGA_DRAW_LINE24;
1739 bits = 24;
1740 break;
1741 case 32:
1742 v = VGA_DRAW_LINE32;
1743 bits = 32;
1744 break;
1745 }
1746 }
1747 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1748
1749 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1750 s->cursor_invalidate(s);
1751
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);
1758 bwidth = (width * bits + 7) / 8;
1759 y_start = -1;
1760 page_min = -1;
1761 page_max = 0;
1762 d = ds_get_data(s->ds);
1763 linesize = ds_get_linesize(s->ds);
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);
1778 update = full_update |
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 */
1783 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
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;
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 }
1800 } else {
1801 if (y_start >= 0) {
1802 /* flush to display */
1803 dpy_update(s->ds, 0, y_start,
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 */
1824 dpy_update(s->ds, 0, y_start,
1825 disp_width, y - y_start);
1826 }
1827 /* reset modified pages */
1828 if (page_max >= page_min) {
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
1835 static void vga_draw_blank(VGACommonState *s, int full_update)
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;
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)
1848 val = s->rgb_to_pixel(0, 0, 0);
1849 else
1850 val = 0;
1851 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1852 d = ds_get_data(s->ds);
1853 for(i = 0; i < s->last_scr_height; i++) {
1854 memset(d, val, w);
1855 d += ds_get_linesize(s->ds);
1856 }
1857 dpy_update(s->ds, 0, 0,
1858 s->last_scr_width, s->last_scr_height);
1859 }
1860
1861 #define GMODE_TEXT 0
1862 #define GMODE_GRAPH 1
1863 #define GMODE_BLANK 2
1864
1865 static void vga_update_display(void *opaque)
1866 {
1867 VGACommonState *s = opaque;
1868 int full_update, graphic_mode;
1869
1870 if (ds_get_bits_per_pixel(s->ds) == 0) {
1871 /* nothing to do */
1872 } else {
1873 full_update = 0;
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 */
1899 static void vga_invalidate_display(void *opaque)
1900 {
1901 VGACommonState *s = opaque;
1902
1903 s->last_width = -1;
1904 s->last_height = -1;
1905 }
1906
1907 void vga_common_reset(VGACommonState *s)
1908 {
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));
1938 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
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));
1944 s->graphic_mode = -1; /* force full update */
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
1972 static void vga_reset(void *opaque)
1973 {
1974 VGACommonState *s = opaque;
1975 vga_common_reset(s);
1976 }
1977
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 {
1986 VGACommonState *s = opaque;
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 ++)
2077 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
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 ++) {
2084 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
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 ++) {
2093 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
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);
2142 }
2143
2144 CPUReadMemoryFunc * const vga_mem_read[3] = {
2145 vga_mem_readb,
2146 vga_mem_readw,
2147 vga_mem_readl,
2148 };
2149
2150 CPUWriteMemoryFunc * const vga_mem_write[3] = {
2151 vga_mem_writeb,
2152 vga_mem_writew,
2153 vga_mem_writel,
2154 };
2155
2156 static int vga_common_post_load(void *opaque, int version_id)
2157 {
2158 VGACommonState *s = opaque;
2159
2160 /* force refresh */
2161 s->graphic_mode = -1;
2162 return 0;
2163 }
2164
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),
2193
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()
2204 }
2205 };
2206
2207 void vga_common_init(VGACommonState *s, int vga_ram_size)
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
2234 #ifdef CONFIG_BOCHS_VBE
2235 s->is_vbe_vmstate = 1;
2236 #else
2237 s->is_vbe_vmstate = 0;
2238 #endif
2239 s->vram_offset = qemu_ram_alloc(NULL, "vga.vram", vga_ram_size);
2240 s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
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;
2245 s->update = vga_update_display;
2246 s->invalidate = vga_invalidate_display;
2247 s->screen_dump = vga_screen_dump;
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 }
2260 }
2261
2262 /* used by both ISA and PCI */
2263 int vga_init_io(VGACommonState *s)
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
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);
2308 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2309 vga_io_memory);
2310 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
2311 }
2312
2313 void vga_init_vbe(VGACommonState *s)
2314 {
2315 #ifdef CONFIG_BOCHS_VBE
2316 /* XXX: use optimized standard vga accesses */
2317 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2318 VGA_RAM_SIZE, s->vram_offset);
2319 s->vbe_mapped = 1;
2320 #endif
2321 }
2322 /********************************************************/
2323 /* vga screen dump */
2324
2325 static void vga_save_dpy_update(DisplayState *ds,
2326 int x, int y, int w, int h)
2327 {
2328 if (screen_dump_filename) {
2329 ppm_save(screen_dump_filename, ds->surface);
2330 screen_dump_filename = NULL;
2331 }
2332 }
2333
2334 static void vga_save_dpy_resize(DisplayState *s)
2335 {
2336 }
2337
2338 static void vga_save_dpy_refresh(DisplayState *s)
2339 {
2340 }
2341
2342 int ppm_save(const char *filename, struct DisplaySurface *ds)
2343 {
2344 FILE *f;
2345 uint8_t *d, *d1;
2346 uint32_t v;
2347 int y, x;
2348 uint8_t r, g, b;
2349 int ret;
2350 char *linebuf, *pbuf;
2351
2352 f = fopen(filename, "wb");
2353 if (!f)
2354 return -1;
2355 fprintf(f, "P6\n%d %d\n%d\n",
2356 ds->width, ds->height, 255);
2357 linebuf = qemu_malloc(ds->width * 3);
2358 d1 = ds->data;
2359 for(y = 0; y < ds->height; y++) {
2360 d = d1;
2361 pbuf = linebuf;
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);
2373 *pbuf++ = r;
2374 *pbuf++ = g;
2375 *pbuf++ = b;
2376 d += ds->pf.bytes_per_pixel;
2377 }
2378 d1 += ds->linesize;
2379 ret = fwrite(linebuf, 1, pbuf - linebuf, f);
2380 (void)ret;
2381 }
2382 qemu_free(linebuf);
2383 fclose(f);
2384 return 0;
2385 }
2386
2387 static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
2388 {
2389 DisplayChangeListener *dcl;
2390
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;
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 {
2403 VGACommonState *s = opaque;
2404
2405 if (!screen_dump_dcl)
2406 screen_dump_dcl = vga_screen_dump_init(s->ds);
2407
2408 screen_dump_filename = (char *)filename;
2409 vga_invalidate_display(s);
2410 vga_hw_update();
2411 }
2412