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