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