]> git.proxmox.com Git - mirror_qemu.git/blame - hw/vga.c
Change the way video graphics adapter is selected
[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;
c60e08d9 1158 qemu_console_resize(s->console, 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;
15342721 1421 int width, height, shift_control, line_offset, page0, page1, bwidth, bits;
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 }
15342721 1457 bits = 4;
17b0018b
FB
1458 } else if (shift_control == 1) {
1459 full_update |= update_palette16(s);
1460 if (s->sr[0x01] & 8) {
1461 v = VGA_DRAW_LINE2D2;
1462 disp_width <<= 1;
1463 } else {
1464 v = VGA_DRAW_LINE2;
1465 }
15342721 1466 bits = 4;
17b0018b 1467 } else {
798b0c25
FB
1468 switch(s->get_bpp(s)) {
1469 default:
1470 case 0:
4fa0f5d2
FB
1471 full_update |= update_palette256(s);
1472 v = VGA_DRAW_LINE8D2;
15342721 1473 bits = 4;
798b0c25
FB
1474 break;
1475 case 8:
1476 full_update |= update_palette256(s);
1477 v = VGA_DRAW_LINE8;
15342721 1478 bits = 8;
798b0c25
FB
1479 break;
1480 case 15:
1481 v = VGA_DRAW_LINE15;
15342721 1482 bits = 16;
798b0c25
FB
1483 break;
1484 case 16:
1485 v = VGA_DRAW_LINE16;
15342721 1486 bits = 16;
798b0c25
FB
1487 break;
1488 case 24:
1489 v = VGA_DRAW_LINE24;
15342721 1490 bits = 24;
798b0c25
FB
1491 break;
1492 case 32:
1493 v = VGA_DRAW_LINE32;
15342721 1494 bits = 32;
798b0c25 1495 break;
4fa0f5d2 1496 }
17b0018b 1497 }
d3079cd2 1498 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
17b0018b
FB
1499
1500 if (disp_width != s->last_width ||
1501 height != s->last_height) {
c60e08d9 1502 qemu_console_resize(s->console, disp_width, height);
2aebb3eb
FB
1503 s->last_scr_width = disp_width;
1504 s->last_scr_height = height;
17b0018b
FB
1505 s->last_width = disp_width;
1506 s->last_height = height;
1507 full_update = 1;
1508 }
a8aa669b
FB
1509 if (s->cursor_invalidate)
1510 s->cursor_invalidate(s);
3b46e624 1511
e89f66ec 1512 line_offset = s->line_offset;
17b0018b 1513#if 0
f6c958c8 1514 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
1515 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1516#endif
e89f66ec 1517 addr1 = (s->start_addr * 4);
15342721 1518 bwidth = (width * bits + 7) / 8;
39cf7803 1519 y_start = -1;
e89f66ec
FB
1520 page_min = 0x7fffffff;
1521 page_max = -1;
1522 d = s->ds->data;
1523 linesize = s->ds->linesize;
17b0018b 1524 y1 = 0;
e89f66ec
FB
1525 for(y = 0; y < height; y++) {
1526 addr = addr1;
39cf7803 1527 if (!(s->cr[0x17] & 1)) {
17b0018b 1528 int shift;
e89f66ec 1529 /* CGA compatibility handling */
17b0018b
FB
1530 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1531 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1532 }
39cf7803 1533 if (!(s->cr[0x17] & 2)) {
17b0018b 1534 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1535 }
4fa0f5d2
FB
1536 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1537 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
5fafdf24 1538 update = full_update |
0a962c02
FB
1539 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1540 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
4fa0f5d2 1541 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1542 /* if wide line, can use another page */
5fafdf24 1543 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
0a962c02 1544 VGA_DIRTY_FLAG);
39cf7803 1545 }
a8aa669b
FB
1546 /* explicit invalidation for the hardware cursor */
1547 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
e89f66ec 1548 if (update) {
39cf7803
FB
1549 if (y_start < 0)
1550 y_start = y;
e89f66ec
FB
1551 if (page0 < page_min)
1552 page_min = page0;
1553 if (page1 > page_max)
1554 page_max = page1;
1555 vga_draw_line(s, d, s->vram_ptr + addr, width);
a8aa669b
FB
1556 if (s->cursor_draw_line)
1557 s->cursor_draw_line(s, d, y);
39cf7803
FB
1558 } else {
1559 if (y_start >= 0) {
1560 /* flush to display */
5fafdf24 1561 dpy_update(s->ds, 0, y_start,
17b0018b 1562 disp_width, y - y_start);
39cf7803
FB
1563 y_start = -1;
1564 }
e89f66ec 1565 }
a07cf92a 1566 if (!multi_run) {
f6c958c8
FB
1567 mask = (s->cr[0x17] & 3) ^ 3;
1568 if ((y1 & mask) == mask)
1569 addr1 += line_offset;
1570 y1++;
a07cf92a
FB
1571 multi_run = multi_scan;
1572 } else {
1573 multi_run--;
e89f66ec 1574 }
f6c958c8
FB
1575 /* line compare acts on the displayed lines */
1576 if (y == s->line_compare)
1577 addr1 = 0;
e89f66ec
FB
1578 d += linesize;
1579 }
39cf7803
FB
1580 if (y_start >= 0) {
1581 /* flush to display */
5fafdf24 1582 dpy_update(s->ds, 0, y_start,
17b0018b 1583 disp_width, y - y_start);
39cf7803 1584 }
e89f66ec
FB
1585 /* reset modified pages */
1586 if (page_max != -1) {
0a962c02
FB
1587 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1588 VGA_DIRTY_FLAG);
e89f66ec 1589 }
a8aa669b 1590 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
e89f66ec
FB
1591}
1592
2aebb3eb
FB
1593static void vga_draw_blank(VGAState *s, int full_update)
1594{
1595 int i, w, val;
1596 uint8_t *d;
1597
1598 if (!full_update)
1599 return;
1600 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1601 return;
5fafdf24 1602 if (s->ds->depth == 8)
2aebb3eb
FB
1603 val = s->rgb_to_pixel(0, 0, 0);
1604 else
1605 val = 0;
1606 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1607 d = s->ds->data;
1608 for(i = 0; i < s->last_scr_height; i++) {
1609 memset(d, val, w);
1610 d += s->ds->linesize;
1611 }
5fafdf24 1612 dpy_update(s->ds, 0, 0,
2aebb3eb
FB
1613 s->last_scr_width, s->last_scr_height);
1614}
1615
1616#define GMODE_TEXT 0
1617#define GMODE_GRAPH 1
5fafdf24 1618#define GMODE_BLANK 2
2aebb3eb 1619
95219897 1620static void vga_update_display(void *opaque)
e89f66ec 1621{
95219897 1622 VGAState *s = (VGAState *)opaque;
e89f66ec
FB
1623 int full_update, graphic_mode;
1624
1625 if (s->ds->depth == 0) {
0f35920c 1626 /* nothing to do */
59a983b9 1627 } else {
5fafdf24 1628 s->rgb_to_pixel =
d3079cd2 1629 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
3b46e624 1630
e89f66ec 1631 full_update = 0;
2aebb3eb
FB
1632 if (!(s->ar_index & 0x20)) {
1633 graphic_mode = GMODE_BLANK;
1634 } else {
1635 graphic_mode = s->gr[6] & 1;
1636 }
e89f66ec
FB
1637 if (graphic_mode != s->graphic_mode) {
1638 s->graphic_mode = graphic_mode;
1639 full_update = 1;
1640 }
2aebb3eb
FB
1641 switch(graphic_mode) {
1642 case GMODE_TEXT:
e89f66ec 1643 vga_draw_text(s, full_update);
2aebb3eb
FB
1644 break;
1645 case GMODE_GRAPH:
1646 vga_draw_graphic(s, full_update);
1647 break;
1648 case GMODE_BLANK:
1649 default:
1650 vga_draw_blank(s, full_update);
1651 break;
1652 }
e89f66ec
FB
1653 }
1654}
1655
a130a41e 1656/* force a full display refresh */
95219897 1657static void vga_invalidate_display(void *opaque)
a130a41e 1658{
95219897 1659 VGAState *s = (VGAState *)opaque;
3b46e624 1660
a130a41e
FB
1661 s->last_width = -1;
1662 s->last_height = -1;
1663}
1664
59a983b9 1665static void vga_reset(VGAState *s)
e89f66ec
FB
1666{
1667 memset(s, 0, sizeof(VGAState));
e89f66ec
FB
1668 s->graphic_mode = -1; /* force full update */
1669}
1670
4d3b6f6e
AZ
1671#define TEXTMODE_X(x) ((x) % width)
1672#define TEXTMODE_Y(x) ((x) / width)
1673#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1674 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1675/* relay text rendering to the display driver
1676 * instead of doing a full vga_update_display() */
1677static void vga_update_text(void *opaque, console_ch_t *chardata)
1678{
1679 VGAState *s = (VGAState *) opaque;
1680 int graphic_mode, i, cursor_offset, cursor_visible;
1681 int cw, cheight, width, height, size, c_min, c_max;
1682 uint32_t *src;
1683 console_ch_t *dst, val;
1684 char msg_buffer[80];
5228c2d3 1685 int full_update = 0;
4d3b6f6e
AZ
1686
1687 if (!(s->ar_index & 0x20)) {
1688 graphic_mode = GMODE_BLANK;
1689 } else {
1690 graphic_mode = s->gr[6] & 1;
1691 }
1692 if (graphic_mode != s->graphic_mode) {
1693 s->graphic_mode = graphic_mode;
1694 full_update = 1;
1695 }
1696 if (s->last_width == -1) {
1697 s->last_width = 0;
1698 full_update = 1;
1699 }
1700
1701 switch (graphic_mode) {
1702 case GMODE_TEXT:
1703 /* TODO: update palette */
1704 full_update |= update_basic_params(s);
1705
1706 /* total width & height */
1707 cheight = (s->cr[9] & 0x1f) + 1;
1708 cw = 8;
1709 if (!(s->sr[1] & 0x01))
1710 cw = 9;
1711 if (s->sr[1] & 0x08)
1712 cw = 16; /* NOTE: no 18 pixel wide */
1713 width = (s->cr[0x01] + 1);
1714 if (s->cr[0x06] == 100) {
1715 /* ugly hack for CGA 160x100x16 - explain me the logic */
1716 height = 100;
1717 } else {
1718 height = s->cr[0x12] |
1719 ((s->cr[0x07] & 0x02) << 7) |
1720 ((s->cr[0x07] & 0x40) << 3);
1721 height = (height + 1) / cheight;
1722 }
1723
1724 size = (height * width);
1725 if (size > CH_ATTR_SIZE) {
1726 if (!full_update)
1727 return;
1728
363a37d5
BS
1729 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
1730 width, height);
4d3b6f6e
AZ
1731 break;
1732 }
1733
1734 if (width != s->last_width || height != s->last_height ||
1735 cw != s->last_cw || cheight != s->last_ch) {
1736 s->last_scr_width = width * cw;
1737 s->last_scr_height = height * cheight;
c60e08d9 1738 qemu_console_resize(s->console, width, height);
4d3b6f6e
AZ
1739 s->last_width = width;
1740 s->last_height = height;
1741 s->last_ch = cheight;
1742 s->last_cw = cw;
1743 full_update = 1;
1744 }
1745
1746 /* Update "hardware" cursor */
1747 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1748 if (cursor_offset != s->cursor_offset ||
1749 s->cr[0xa] != s->cursor_start ||
1750 s->cr[0xb] != s->cursor_end || full_update) {
1751 cursor_visible = !(s->cr[0xa] & 0x20);
1752 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
1753 dpy_cursor(s->ds,
1754 TEXTMODE_X(cursor_offset),
1755 TEXTMODE_Y(cursor_offset));
1756 else
1757 dpy_cursor(s->ds, -1, -1);
1758 s->cursor_offset = cursor_offset;
1759 s->cursor_start = s->cr[0xa];
1760 s->cursor_end = s->cr[0xb];
1761 }
1762
1763 src = (uint32_t *) s->vram_ptr + s->start_addr;
1764 dst = chardata;
1765
1766 if (full_update) {
1767 for (i = 0; i < size; src ++, dst ++, i ++)
1768 console_write_ch(dst, VMEM2CHTYPE(*src));
1769
1770 dpy_update(s->ds, 0, 0, width, height);
1771 } else {
1772 c_max = 0;
1773
1774 for (i = 0; i < size; src ++, dst ++, i ++) {
1775 console_write_ch(&val, VMEM2CHTYPE(*src));
1776 if (*dst != val) {
1777 *dst = val;
1778 c_max = i;
1779 break;
1780 }
1781 }
1782 c_min = i;
1783 for (; i < size; src ++, dst ++, i ++) {
1784 console_write_ch(&val, VMEM2CHTYPE(*src));
1785 if (*dst != val) {
1786 *dst = val;
1787 c_max = i;
1788 }
1789 }
1790
1791 if (c_min <= c_max) {
1792 i = TEXTMODE_Y(c_min);
1793 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
1794 }
1795 }
1796
1797 return;
1798 case GMODE_GRAPH:
1799 if (!full_update)
1800 return;
1801
1802 s->get_resolution(s, &width, &height);
363a37d5
BS
1803 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
1804 width, height);
4d3b6f6e
AZ
1805 break;
1806 case GMODE_BLANK:
1807 default:
1808 if (!full_update)
1809 return;
1810
363a37d5 1811 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
4d3b6f6e
AZ
1812 break;
1813 }
1814
1815 /* Display a message */
5228c2d3
AZ
1816 s->last_width = 60;
1817 s->last_height = height = 3;
4d3b6f6e 1818 dpy_cursor(s->ds, -1, -1);
c60e08d9 1819 qemu_console_resize(s->console, s->last_width, height);
4d3b6f6e 1820
5228c2d3 1821 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
4d3b6f6e
AZ
1822 console_write_ch(dst ++, ' ');
1823
1824 size = strlen(msg_buffer);
5228c2d3
AZ
1825 width = (s->last_width - size) / 2;
1826 dst = chardata + s->last_width + width;
4d3b6f6e
AZ
1827 for (i = 0; i < size; i ++)
1828 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
1829
5228c2d3 1830 dpy_update(s->ds, 0, 0, s->last_width, height);
4d3b6f6e
AZ
1831}
1832
59a983b9 1833static CPUReadMemoryFunc *vga_mem_read[3] = {
e89f66ec
FB
1834 vga_mem_readb,
1835 vga_mem_readw,
1836 vga_mem_readl,
1837};
1838
59a983b9 1839static CPUWriteMemoryFunc *vga_mem_write[3] = {
e89f66ec
FB
1840 vga_mem_writeb,
1841 vga_mem_writew,
1842 vga_mem_writel,
1843};
1844
b0a21b53
FB
1845static void vga_save(QEMUFile *f, void *opaque)
1846{
1847 VGAState *s = opaque;
1848 int i;
1849
d2269f6f
FB
1850 if (s->pci_dev)
1851 pci_device_save(s->pci_dev, f);
1852
b0a21b53
FB
1853 qemu_put_be32s(f, &s->latch);
1854 qemu_put_8s(f, &s->sr_index);
1855 qemu_put_buffer(f, s->sr, 8);
1856 qemu_put_8s(f, &s->gr_index);
1857 qemu_put_buffer(f, s->gr, 16);
1858 qemu_put_8s(f, &s->ar_index);
1859 qemu_put_buffer(f, s->ar, 21);
bee8d684 1860 qemu_put_be32(f, s->ar_flip_flop);
b0a21b53
FB
1861 qemu_put_8s(f, &s->cr_index);
1862 qemu_put_buffer(f, s->cr, 256);
1863 qemu_put_8s(f, &s->msr);
1864 qemu_put_8s(f, &s->fcr);
bee8d684 1865 qemu_put_byte(f, s->st00);
b0a21b53
FB
1866 qemu_put_8s(f, &s->st01);
1867
1868 qemu_put_8s(f, &s->dac_state);
1869 qemu_put_8s(f, &s->dac_sub_index);
1870 qemu_put_8s(f, &s->dac_read_index);
1871 qemu_put_8s(f, &s->dac_write_index);
1872 qemu_put_buffer(f, s->dac_cache, 3);
1873 qemu_put_buffer(f, s->palette, 768);
1874
bee8d684 1875 qemu_put_be32(f, s->bank_offset);
b0a21b53
FB
1876#ifdef CONFIG_BOCHS_VBE
1877 qemu_put_byte(f, 1);
1878 qemu_put_be16s(f, &s->vbe_index);
1879 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1880 qemu_put_be16s(f, &s->vbe_regs[i]);
1881 qemu_put_be32s(f, &s->vbe_start_addr);
1882 qemu_put_be32s(f, &s->vbe_line_offset);
1883 qemu_put_be32s(f, &s->vbe_bank_mask);
1884#else
1885 qemu_put_byte(f, 0);
1886#endif
1887}
1888
1889static int vga_load(QEMUFile *f, void *opaque, int version_id)
1890{
1891 VGAState *s = opaque;
d2269f6f 1892 int is_vbe, i, ret;
b0a21b53 1893
d2269f6f 1894 if (version_id > 2)
b0a21b53
FB
1895 return -EINVAL;
1896
d2269f6f
FB
1897 if (s->pci_dev && version_id >= 2) {
1898 ret = pci_device_load(s->pci_dev, f);
1899 if (ret < 0)
1900 return ret;
1901 }
1902
b0a21b53
FB
1903 qemu_get_be32s(f, &s->latch);
1904 qemu_get_8s(f, &s->sr_index);
1905 qemu_get_buffer(f, s->sr, 8);
1906 qemu_get_8s(f, &s->gr_index);
1907 qemu_get_buffer(f, s->gr, 16);
1908 qemu_get_8s(f, &s->ar_index);
1909 qemu_get_buffer(f, s->ar, 21);
bee8d684 1910 s->ar_flip_flop=qemu_get_be32(f);
b0a21b53
FB
1911 qemu_get_8s(f, &s->cr_index);
1912 qemu_get_buffer(f, s->cr, 256);
1913 qemu_get_8s(f, &s->msr);
1914 qemu_get_8s(f, &s->fcr);
1915 qemu_get_8s(f, &s->st00);
1916 qemu_get_8s(f, &s->st01);
1917
1918 qemu_get_8s(f, &s->dac_state);
1919 qemu_get_8s(f, &s->dac_sub_index);
1920 qemu_get_8s(f, &s->dac_read_index);
1921 qemu_get_8s(f, &s->dac_write_index);
1922 qemu_get_buffer(f, s->dac_cache, 3);
1923 qemu_get_buffer(f, s->palette, 768);
1924
bee8d684 1925 s->bank_offset=qemu_get_be32(f);
b0a21b53
FB
1926 is_vbe = qemu_get_byte(f);
1927#ifdef CONFIG_BOCHS_VBE
1928 if (!is_vbe)
1929 return -EINVAL;
1930 qemu_get_be16s(f, &s->vbe_index);
1931 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1932 qemu_get_be16s(f, &s->vbe_regs[i]);
1933 qemu_get_be32s(f, &s->vbe_start_addr);
1934 qemu_get_be32s(f, &s->vbe_line_offset);
1935 qemu_get_be32s(f, &s->vbe_bank_mask);
1936#else
1937 if (is_vbe)
1938 return -EINVAL;
1939#endif
1940
1941 /* force refresh */
1942 s->graphic_mode = -1;
1943 return 0;
1944}
1945
d2269f6f
FB
1946typedef struct PCIVGAState {
1947 PCIDevice dev;
1948 VGAState vga_state;
1949} PCIVGAState;
1950
5fafdf24 1951static void vga_map(PCIDevice *pci_dev, int region_num,
1078f663
FB
1952 uint32_t addr, uint32_t size, int type)
1953{
d2269f6f
FB
1954 PCIVGAState *d = (PCIVGAState *)pci_dev;
1955 VGAState *s = &d->vga_state;
d5295253
FB
1956 if (region_num == PCI_ROM_SLOT) {
1957 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
1958 } else {
1959 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1960 }
1078f663
FB
1961}
1962
5fafdf24 1963void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
798b0c25 1964 unsigned long vga_ram_offset, int vga_ram_size)
e89f66ec 1965{
17b0018b 1966 int i, j, v, b;
e89f66ec
FB
1967
1968 for(i = 0;i < 256; i++) {
1969 v = 0;
1970 for(j = 0; j < 8; j++) {
1971 v |= ((i >> j) & 1) << (j * 4);
1972 }
1973 expand4[i] = v;
1974
1975 v = 0;
1976 for(j = 0; j < 4; j++) {
1977 v |= ((i >> (2 * j)) & 3) << (j * 4);
1978 }
1979 expand2[i] = v;
1980 }
17b0018b
FB
1981 for(i = 0; i < 16; i++) {
1982 v = 0;
1983 for(j = 0; j < 4; j++) {
1984 b = ((i >> j) & 1);
1985 v |= b << (2 * j);
1986 v |= b << (2 * j + 1);
1987 }
1988 expand4to8[i] = v;
1989 }
e89f66ec
FB
1990
1991 vga_reset(s);
1992
1993 s->vram_ptr = vga_ram_base;
1994 s->vram_offset = vga_ram_offset;
1995 s->vram_size = vga_ram_size;
1996 s->ds = ds;
798b0c25
FB
1997 s->get_bpp = vga_get_bpp;
1998 s->get_offsets = vga_get_offsets;
a130a41e 1999 s->get_resolution = vga_get_resolution;
d34cab9f
TS
2000 s->update = vga_update_display;
2001 s->invalidate = vga_invalidate_display;
2002 s->screen_dump = vga_screen_dump;
4d3b6f6e 2003 s->text_update = vga_update_text;
798b0c25
FB
2004}
2005
d2269f6f 2006/* used by both ISA and PCI */
d34cab9f 2007void vga_init(VGAState *s)
798b0c25 2008{
d2269f6f 2009 int vga_io_memory;
7b17d41e 2010
d2269f6f 2011 register_savevm("vga", 0, 2, vga_save, vga_load, s);
b0a21b53 2012
0f35920c 2013 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
e89f66ec 2014
0f35920c
FB
2015 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2016 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2017 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2018 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
e89f66ec 2019
0f35920c 2020 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
e89f66ec 2021
0f35920c
FB
2022 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2023 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2024 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2025 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
26aa7d72 2026 s->bank_offset = 0;
e89f66ec 2027
4fa0f5d2
FB
2028#ifdef CONFIG_BOCHS_VBE
2029 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
cae61cef 2030 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
09a79b49
FB
2031#if defined (TARGET_I386)
2032 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2033 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
4fa0f5d2 2034
09a79b49
FB
2035 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2036 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
646be93b
FB
2037
2038 /* old Bochs IO ports */
09a79b49
FB
2039 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2040 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
646be93b 2041
09a79b49 2042 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
5fafdf24 2043 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
09a79b49
FB
2044#else
2045 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2046 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2047
2048 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2049 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
4fa0f5d2 2050#endif
09a79b49 2051#endif /* CONFIG_BOCHS_VBE */
4fa0f5d2 2052
a4193c8a 2053 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
5fafdf24 2054 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
26aa7d72 2055 vga_io_memory);
d2269f6f
FB
2056}
2057
2abec30b
TS
2058/* Memory mapped interface */
2059static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2060{
2061 VGAState *s = opaque;
2062
2063 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xff;
2064}
2065
2066static void vga_mm_writeb (void *opaque,
2067 target_phys_addr_t addr, uint32_t value)
2068{
2069 VGAState *s = opaque;
2070
2071 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xff);
2072}
2073
2074static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2075{
2076 VGAState *s = opaque;
2077
2078 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xffff;
2079}
2080
2081static void vga_mm_writew (void *opaque,
2082 target_phys_addr_t addr, uint32_t value)
2083{
2084 VGAState *s = opaque;
2085
2086 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xffff);
2087}
2088
2089static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2090{
2091 VGAState *s = opaque;
2092
2093 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift);
2094}
2095
2096static void vga_mm_writel (void *opaque,
2097 target_phys_addr_t addr, uint32_t value)
2098{
2099 VGAState *s = opaque;
2100
2101 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value);
2102}
2103
2104static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
2105 &vga_mm_readb,
2106 &vga_mm_readw,
2107 &vga_mm_readl,
2108};
2109
2110static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
2111 &vga_mm_writeb,
2112 &vga_mm_writew,
2113 &vga_mm_writel,
2114};
2115
2116static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2117 target_phys_addr_t ctrl_base, int it_shift)
2118{
2119 int s_ioport_ctrl, vga_io_memory;
2120
2121 s->base_ctrl = ctrl_base;
2122 s->it_shift = it_shift;
2123 s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2124 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2125
2126 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2127
2128 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2129 s->bank_offset = 0;
2130 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
2131}
2132
5fafdf24 2133int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
d2269f6f
FB
2134 unsigned long vga_ram_offset, int vga_ram_size)
2135{
2136 VGAState *s;
2137
2138 s = qemu_mallocz(sizeof(VGAState));
2139 if (!s)
2140 return -1;
2141
2142 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2143 vga_init(s);
1078f663 2144
c60e08d9
PB
2145 s->console = graphic_console_init(s->ds, s->update, s->invalidate,
2146 s->screen_dump, s->text_update, s);
d34cab9f 2147
4fa0f5d2 2148#ifdef CONFIG_BOCHS_VBE
d2269f6f 2149 /* XXX: use optimized standard vga accesses */
5fafdf24 2150 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
d2269f6f 2151 vga_ram_size, vga_ram_offset);
7138fcfb 2152#endif
d2269f6f
FB
2153 return 0;
2154}
2155
2abec30b
TS
2156int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
2157 unsigned long vga_ram_offset, int vga_ram_size,
2158 target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
2159 int it_shift)
2160{
2161 VGAState *s;
2162
2163 s = qemu_mallocz(sizeof(VGAState));
2164 if (!s)
2165 return -1;
2166
2167 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2168 vga_mm_init(s, vram_base, ctrl_base, it_shift);
2169
c60e08d9
PB
2170 s->console = graphic_console_init(s->ds, s->update, s->invalidate,
2171 s->screen_dump, s->text_update, s);
2abec30b
TS
2172
2173#ifdef CONFIG_BOCHS_VBE
2174 /* XXX: use optimized standard vga accesses */
2175 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2176 vga_ram_size, vga_ram_offset);
2177#endif
2178 return 0;
2179}
2180
5fafdf24 2181int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
d2269f6f
FB
2182 unsigned long vga_ram_offset, int vga_ram_size,
2183 unsigned long vga_bios_offset, int vga_bios_size)
2184{
2185 PCIVGAState *d;
2186 VGAState *s;
2187 uint8_t *pci_conf;
3b46e624 2188
5fafdf24 2189 d = (PCIVGAState *)pci_register_device(bus, "VGA",
d2269f6f
FB
2190 sizeof(PCIVGAState),
2191 -1, NULL, NULL);
2192 if (!d)
2193 return -1;
2194 s = &d->vga_state;
3b46e624 2195
d2269f6f
FB
2196 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2197 vga_init(s);
d34cab9f 2198
c60e08d9
PB
2199 s->console = graphic_console_init(s->ds, s->update, s->invalidate,
2200 s->screen_dump, s->text_update, s);
d34cab9f 2201
d2269f6f 2202 s->pci_dev = &d->dev;
3b46e624 2203
d2269f6f
FB
2204 pci_conf = d->dev.config;
2205 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2206 pci_conf[0x01] = 0x12;
2207 pci_conf[0x02] = 0x11;
2208 pci_conf[0x03] = 0x11;
5fafdf24 2209 pci_conf[0x0a] = 0x00; // VGA controller
d2269f6f
FB
2210 pci_conf[0x0b] = 0x03;
2211 pci_conf[0x0e] = 0x00; // header_type
3b46e624 2212
d2269f6f 2213 /* XXX: vga_ram_size must be a power of two */
5fafdf24 2214 pci_register_io_region(&d->dev, 0, vga_ram_size,
d2269f6f
FB
2215 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2216 if (vga_bios_size != 0) {
2217 unsigned int bios_total_size;
2218 s->bios_offset = vga_bios_offset;
2219 s->bios_size = vga_bios_size;
2220 /* must be a power of two */
2221 bios_total_size = 1;
2222 while (bios_total_size < vga_bios_size)
2223 bios_total_size <<= 1;
5fafdf24 2224 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
d2269f6f 2225 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1078f663 2226 }
e89f66ec
FB
2227 return 0;
2228}
59a983b9
FB
2229
2230/********************************************************/
2231/* vga screen dump */
2232
2233static int vga_save_w, vga_save_h;
2234
5fafdf24 2235static void vga_save_dpy_update(DisplayState *s,
59a983b9
FB
2236 int x, int y, int w, int h)
2237{
2238}
2239
2240static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2241{
2242 s->linesize = w * 4;
2243 s->data = qemu_malloc(h * s->linesize);
2244 vga_save_w = w;
2245 vga_save_h = h;
2246}
2247
2248static void vga_save_dpy_refresh(DisplayState *s)
2249{
2250}
2251
5fafdf24 2252int ppm_save(const char *filename, uint8_t *data,
f707cfba 2253 int w, int h, int linesize)
59a983b9
FB
2254{
2255 FILE *f;
2256 uint8_t *d, *d1;
2257 unsigned int v;
2258 int y, x;
2259
2260 f = fopen(filename, "wb");
2261 if (!f)
2262 return -1;
2263 fprintf(f, "P6\n%d %d\n%d\n",
2264 w, h, 255);
2265 d1 = data;
2266 for(y = 0; y < h; y++) {
2267 d = d1;
2268 for(x = 0; x < w; x++) {
2269 v = *(uint32_t *)d;
2270 fputc((v >> 16) & 0xff, f);
2271 fputc((v >> 8) & 0xff, f);
2272 fputc((v) & 0xff, f);
2273 d += 4;
2274 }
2275 d1 += linesize;
2276 }
2277 fclose(f);
2278 return 0;
2279}
2280
2281/* save the vga display in a PPM image even if no display is
2282 available */
95219897 2283static void vga_screen_dump(void *opaque, const char *filename)
59a983b9 2284{
95219897 2285 VGAState *s = (VGAState *)opaque;
59a983b9 2286 DisplayState *saved_ds, ds1, *ds = &ds1;
3b46e624 2287
59a983b9 2288 /* XXX: this is a little hackish */
95219897 2289 vga_invalidate_display(s);
59a983b9
FB
2290 saved_ds = s->ds;
2291
2292 memset(ds, 0, sizeof(DisplayState));
2293 ds->dpy_update = vga_save_dpy_update;
2294 ds->dpy_resize = vga_save_dpy_resize;
2295 ds->dpy_refresh = vga_save_dpy_refresh;
2296 ds->depth = 32;
2297
2298 s->ds = ds;
2299 s->graphic_mode = -1;
95219897 2300 vga_update_display(s);
3b46e624 2301
59a983b9 2302 if (ds->data) {
5fafdf24 2303 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
59a983b9
FB
2304 s->ds->linesize);
2305 qemu_free(ds->data);
2306 }
2307 s->ds = saved_ds;
2308}