]> git.proxmox.com Git - mirror_qemu.git/blame - hw/vga.c
full screen support (initial patch by malc)
[mirror_qemu.git] / hw / vga.c
CommitLineData
e89f66ec 1/*
4fa0f5d2 2 * QEMU VGA Emulator.
e89f66ec
FB
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
e89f66ec
FB
24#include "vl.h"
25
e89f66ec 26//#define DEBUG_VGA
17b0018b 27//#define DEBUG_VGA_MEM
a41bc9af
FB
28//#define DEBUG_VGA_REG
29
30//#define DEBUG_S3
4fa0f5d2
FB
31//#define DEBUG_BOCHS_VBE
32
5467a722
FB
33/* S3 VGA is deprecated - another graphic card will be emulated */
34//#define CONFIG_S3VGA
e89f66ec
FB
35
36#define MSR_COLOR_EMULATION 0x01
37#define MSR_PAGE_SELECT 0x20
38
39#define ST01_V_RETRACE 0x08
40#define ST01_DISP_ENABLE 0x01
41
4fa0f5d2
FB
42/* bochs VBE support */
43#define CONFIG_BOCHS_VBE
44
45#define VBE_DISPI_MAX_XRES 1024
46#define VBE_DISPI_MAX_YRES 768
47
48#define VBE_DISPI_INDEX_ID 0x0
49#define VBE_DISPI_INDEX_XRES 0x1
50#define VBE_DISPI_INDEX_YRES 0x2
51#define VBE_DISPI_INDEX_BPP 0x3
52#define VBE_DISPI_INDEX_ENABLE 0x4
53#define VBE_DISPI_INDEX_BANK 0x5
54#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
55#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
56#define VBE_DISPI_INDEX_X_OFFSET 0x8
57#define VBE_DISPI_INDEX_Y_OFFSET 0x9
58#define VBE_DISPI_INDEX_NB 0xa
59
60#define VBE_DISPI_ID0 0xB0C0
61#define VBE_DISPI_ID1 0xB0C1
62#define VBE_DISPI_ID2 0xB0C2
63
64#define VBE_DISPI_DISABLED 0x00
65#define VBE_DISPI_ENABLED 0x01
66#define VBE_DISPI_LFB_ENABLED 0x40
67#define VBE_DISPI_NOCLEARMEM 0x80
68
69#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
70
e89f66ec
FB
71typedef struct VGAState {
72 uint8_t *vram_ptr;
73 unsigned long vram_offset;
74 unsigned int vram_size;
75 uint32_t latch;
76 uint8_t sr_index;
77 uint8_t sr[8];
78 uint8_t gr_index;
79 uint8_t gr[16];
80 uint8_t ar_index;
81 uint8_t ar[21];
82 int ar_flip_flop;
83 uint8_t cr_index;
84 uint8_t cr[256]; /* CRT registers */
85 uint8_t msr; /* Misc Output Register */
86 uint8_t fcr; /* Feature Control Register */
87 uint8_t st00; /* status 0 */
88 uint8_t st01; /* status 1 */
89 uint8_t dac_state;
90 uint8_t dac_sub_index;
91 uint8_t dac_read_index;
92 uint8_t dac_write_index;
93 uint8_t dac_cache[3]; /* used when writing */
94 uint8_t palette[768];
4f2ac237 95 int32_t bank_offset;
4fa0f5d2
FB
96#ifdef CONFIG_BOCHS_VBE
97 uint16_t vbe_index;
98 uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
99 uint32_t vbe_start_addr;
100 uint32_t vbe_line_offset;
cae61cef 101 uint32_t vbe_bank_mask;
4fa0f5d2 102#endif
e89f66ec 103 /* display refresh support */
e89f66ec
FB
104 DisplayState *ds;
105 uint32_t font_offsets[2];
106 int graphic_mode;
17b0018b
FB
107 uint8_t shift_control;
108 uint8_t double_scan;
e89f66ec
FB
109 uint32_t line_offset;
110 uint32_t line_compare;
111 uint32_t start_addr;
112 uint8_t last_cw, last_ch;
2aebb3eb
FB
113 uint32_t last_width, last_height; /* in chars or pixels */
114 uint32_t last_scr_width, last_scr_height; /* in pixels */
e89f66ec
FB
115 uint8_t cursor_start, cursor_end;
116 uint32_t cursor_offset;
17b0018b 117 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
39cf7803 118 /* tell for each page if it has been updated since the last time */
e89f66ec 119 uint32_t last_palette[256];
17b0018b 120#define CH_ATTR_SIZE (160 * 100)
e89f66ec
FB
121 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
122} VGAState;
123
124/* force some bits to zero */
125static const uint8_t sr_mask[8] = {
126 (uint8_t)~0xfc,
127 (uint8_t)~0xc2,
128 (uint8_t)~0xf0,
129 (uint8_t)~0xc0,
130 (uint8_t)~0xf1,
131 (uint8_t)~0xff,
132 (uint8_t)~0xff,
133 (uint8_t)~0x00,
134};
135
136static const uint8_t gr_mask[16] = {
137 (uint8_t)~0xf0, /* 0x00 */
138 (uint8_t)~0xf0, /* 0x01 */
139 (uint8_t)~0xf0, /* 0x02 */
140 (uint8_t)~0xe0, /* 0x03 */
141 (uint8_t)~0xfc, /* 0x04 */
142 (uint8_t)~0x84, /* 0x05 */
143 (uint8_t)~0xf0, /* 0x06 */
144 (uint8_t)~0xf0, /* 0x07 */
145 (uint8_t)~0x00, /* 0x08 */
146 (uint8_t)~0xff, /* 0x09 */
147 (uint8_t)~0xff, /* 0x0a */
148 (uint8_t)~0xff, /* 0x0b */
149 (uint8_t)~0xff, /* 0x0c */
150 (uint8_t)~0xff, /* 0x0d */
151 (uint8_t)~0xff, /* 0x0e */
152 (uint8_t)~0xff, /* 0x0f */
153};
154
155#define cbswap_32(__x) \
156((uint32_t)( \
157 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
158 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
159 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
160 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
161
b8ed223b 162#ifdef WORDS_BIGENDIAN
e89f66ec
FB
163#define PAT(x) cbswap_32(x)
164#else
165#define PAT(x) (x)
166#endif
167
b8ed223b
FB
168#ifdef WORDS_BIGENDIAN
169#define BIG 1
170#else
171#define BIG 0
172#endif
173
174#ifdef WORDS_BIGENDIAN
175#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
176#else
177#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
178#endif
179
e89f66ec
FB
180static const uint32_t mask16[16] = {
181 PAT(0x00000000),
182 PAT(0x000000ff),
183 PAT(0x0000ff00),
184 PAT(0x0000ffff),
185 PAT(0x00ff0000),
186 PAT(0x00ff00ff),
187 PAT(0x00ffff00),
188 PAT(0x00ffffff),
189 PAT(0xff000000),
190 PAT(0xff0000ff),
191 PAT(0xff00ff00),
192 PAT(0xff00ffff),
193 PAT(0xffff0000),
194 PAT(0xffff00ff),
195 PAT(0xffffff00),
196 PAT(0xffffffff),
197};
198
199#undef PAT
200
b8ed223b 201#ifdef WORDS_BIGENDIAN
e89f66ec
FB
202#define PAT(x) (x)
203#else
204#define PAT(x) cbswap_32(x)
205#endif
206
207static const uint32_t dmask16[16] = {
208 PAT(0x00000000),
209 PAT(0x000000ff),
210 PAT(0x0000ff00),
211 PAT(0x0000ffff),
212 PAT(0x00ff0000),
213 PAT(0x00ff00ff),
214 PAT(0x00ffff00),
215 PAT(0x00ffffff),
216 PAT(0xff000000),
217 PAT(0xff0000ff),
218 PAT(0xff00ff00),
219 PAT(0xff00ffff),
220 PAT(0xffff0000),
221 PAT(0xffff00ff),
222 PAT(0xffffff00),
223 PAT(0xffffffff),
224};
225
226static const uint32_t dmask4[4] = {
227 PAT(0x00000000),
228 PAT(0x0000ffff),
229 PAT(0xffff0000),
230 PAT(0xffffffff),
231};
232
233static uint32_t expand4[256];
234static uint16_t expand2[256];
17b0018b 235static uint8_t expand4to8[16];
e89f66ec
FB
236
237VGAState vga_state;
238int vga_io_memory;
239
0f35920c 240static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
e89f66ec 241{
0f35920c 242 VGAState *s = opaque;
e89f66ec
FB
243 int val, index;
244
245 /* check port range access depending on color/monochrome mode */
246 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
247 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
248 val = 0xff;
249 } else {
250 switch(addr) {
251 case 0x3c0:
252 if (s->ar_flip_flop == 0) {
253 val = s->ar_index;
254 } else {
255 val = 0;
256 }
257 break;
258 case 0x3c1:
259 index = s->ar_index & 0x1f;
260 if (index < 21)
261 val = s->ar[index];
262 else
263 val = 0;
264 break;
265 case 0x3c2:
266 val = s->st00;
267 break;
268 case 0x3c4:
269 val = s->sr_index;
270 break;
271 case 0x3c5:
272 val = s->sr[s->sr_index];
a41bc9af
FB
273#ifdef DEBUG_VGA_REG
274 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
275#endif
e89f66ec
FB
276 break;
277 case 0x3c7:
278 val = s->dac_state;
279 break;
280 case 0x3c9:
281 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
282 if (++s->dac_sub_index == 3) {
283 s->dac_sub_index = 0;
284 s->dac_read_index++;
285 }
286 break;
287 case 0x3ca:
288 val = s->fcr;
289 break;
290 case 0x3cc:
291 val = s->msr;
292 break;
293 case 0x3ce:
294 val = s->gr_index;
295 break;
296 case 0x3cf:
297 val = s->gr[s->gr_index];
a41bc9af
FB
298#ifdef DEBUG_VGA_REG
299 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
300#endif
e89f66ec
FB
301 break;
302 case 0x3b4:
303 case 0x3d4:
304 val = s->cr_index;
305 break;
306 case 0x3b5:
307 case 0x3d5:
308 val = s->cr[s->cr_index];
a41bc9af
FB
309#ifdef DEBUG_VGA_REG
310 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
311#endif
312#ifdef DEBUG_S3
313 if (s->cr_index >= 0x20)
314 printf("S3: CR read index=0x%x val=0x%x\n",
315 s->cr_index, val);
316#endif
e89f66ec
FB
317 break;
318 case 0x3ba:
319 case 0x3da:
320 /* just toggle to fool polling */
321 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
322 val = s->st01;
323 s->ar_flip_flop = 0;
324 break;
325 default:
326 val = 0x00;
327 break;
328 }
329 }
4fa0f5d2 330#if defined(DEBUG_VGA)
e89f66ec
FB
331 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
332#endif
333 return val;
334}
335
0f35920c 336static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
e89f66ec 337{
0f35920c 338 VGAState *s = opaque;
5467a722 339 int index;
e89f66ec
FB
340
341 /* check port range access depending on color/monochrome mode */
342 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
343 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
344 return;
345
346#ifdef DEBUG_VGA
347 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
348#endif
349
350 switch(addr) {
351 case 0x3c0:
352 if (s->ar_flip_flop == 0) {
353 val &= 0x3f;
354 s->ar_index = val;
355 } else {
356 index = s->ar_index & 0x1f;
357 switch(index) {
358 case 0x00 ... 0x0f:
359 s->ar[index] = val & 0x3f;
360 break;
361 case 0x10:
362 s->ar[index] = val & ~0x10;
363 break;
364 case 0x11:
365 s->ar[index] = val;
366 break;
367 case 0x12:
368 s->ar[index] = val & ~0xc0;
369 break;
370 case 0x13:
371 s->ar[index] = val & ~0xf0;
372 break;
373 case 0x14:
374 s->ar[index] = val & ~0xf0;
375 break;
376 default:
377 break;
378 }
379 }
380 s->ar_flip_flop ^= 1;
381 break;
382 case 0x3c2:
383 s->msr = val & ~0x10;
384 break;
385 case 0x3c4:
386 s->sr_index = val & 7;
387 break;
388 case 0x3c5:
a41bc9af
FB
389#ifdef DEBUG_VGA_REG
390 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
391#endif
e89f66ec
FB
392 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
393 break;
394 case 0x3c7:
395 s->dac_read_index = val;
396 s->dac_sub_index = 0;
397 s->dac_state = 3;
398 break;
399 case 0x3c8:
400 s->dac_write_index = val;
401 s->dac_sub_index = 0;
402 s->dac_state = 0;
403 break;
404 case 0x3c9:
405 s->dac_cache[s->dac_sub_index] = val;
406 if (++s->dac_sub_index == 3) {
407 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
408 s->dac_sub_index = 0;
409 s->dac_write_index++;
410 }
411 break;
412 case 0x3ce:
413 s->gr_index = val & 0x0f;
414 break;
415 case 0x3cf:
a41bc9af
FB
416#ifdef DEBUG_VGA_REG
417 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
418#endif
e89f66ec
FB
419 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
420 break;
421 case 0x3b4:
422 case 0x3d4:
423 s->cr_index = val;
424 break;
425 case 0x3b5:
426 case 0x3d5:
a41bc9af
FB
427#ifdef DEBUG_VGA_REG
428 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
429#endif
e89f66ec
FB
430 /* handle CR0-7 protection */
431 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
432 /* can always write bit 4 of CR7 */
433 if (s->cr_index == 7)
434 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
435 return;
436 }
437 switch(s->cr_index) {
438 case 0x01: /* horizontal display end */
439 case 0x07:
440 case 0x09:
441 case 0x0c:
442 case 0x0d:
443 case 0x12: /* veritcal display end */
444 s->cr[s->cr_index] = val;
445 break;
446
a41bc9af 447#ifdef CONFIG_S3VGA
e89f66ec
FB
448 /* S3 registers */
449 case 0x2d:
450 case 0x2e:
451 case 0x2f:
452 case 0x30:
453 /* chip ID, cannot write */
454 break;
455 case 0x31:
456 /* update start address */
5467a722
FB
457 {
458 int v;
459 s->cr[s->cr_index] = val;
460 v = (val >> 4) & 3;
461 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
462 }
e89f66ec
FB
463 break;
464 case 0x51:
465 /* update start address */
5467a722
FB
466 {
467 int v;
468 s->cr[s->cr_index] = val;
469 v = val & 3;
470 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
471 }
e89f66ec 472 break;
a41bc9af 473#endif
e89f66ec
FB
474 default:
475 s->cr[s->cr_index] = val;
476 break;
477 }
a41bc9af
FB
478#ifdef DEBUG_S3
479 if (s->cr_index >= 0x20)
480 printf("S3: CR write index=0x%x val=0x%x\n",
481 s->cr_index, val);
482#endif
e89f66ec
FB
483 break;
484 case 0x3ba:
485 case 0x3da:
486 s->fcr = val & 0x10;
487 break;
488 }
489}
490
4fa0f5d2 491#ifdef CONFIG_BOCHS_VBE
0f35920c 492static uint32_t vbe_ioport_read(void *opaque, uint32_t addr)
4fa0f5d2 493{
0f35920c 494 VGAState *s = opaque;
4fa0f5d2
FB
495 uint32_t val;
496
497 addr &= 1;
498 if (addr == 0) {
499 val = s->vbe_index;
500 } else {
501 if (s->vbe_index <= VBE_DISPI_INDEX_NB)
502 val = s->vbe_regs[s->vbe_index];
503 else
504 val = 0;
505#ifdef DEBUG_BOCHS_VBE
506 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
507#endif
508 }
509 return val;
510}
511
0f35920c 512static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
4fa0f5d2 513{
0f35920c 514 VGAState *s = opaque;
4fa0f5d2
FB
515
516 addr &= 1;
517 if (addr == 0) {
518 s->vbe_index = val;
519 } else if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
520#ifdef DEBUG_BOCHS_VBE
521 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
522#endif
523 switch(s->vbe_index) {
524 case VBE_DISPI_INDEX_ID:
cae61cef
FB
525 if (val == VBE_DISPI_ID0 ||
526 val == VBE_DISPI_ID1 ||
527 val == VBE_DISPI_ID2) {
528 s->vbe_regs[s->vbe_index] = val;
529 }
4fa0f5d2
FB
530 break;
531 case VBE_DISPI_INDEX_XRES:
cae61cef
FB
532 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
533 s->vbe_regs[s->vbe_index] = val;
534 }
4fa0f5d2
FB
535 break;
536 case VBE_DISPI_INDEX_YRES:
cae61cef
FB
537 if (val <= VBE_DISPI_MAX_YRES) {
538 s->vbe_regs[s->vbe_index] = val;
539 }
4fa0f5d2
FB
540 break;
541 case VBE_DISPI_INDEX_BPP:
542 if (val == 0)
543 val = 8;
cae61cef
FB
544 if (val == 4 || val == 8 || val == 15 ||
545 val == 16 || val == 24 || val == 32) {
546 s->vbe_regs[s->vbe_index] = val;
547 }
4fa0f5d2
FB
548 break;
549 case VBE_DISPI_INDEX_BANK:
cae61cef
FB
550 val &= s->vbe_bank_mask;
551 s->vbe_regs[s->vbe_index] = val;
552 s->bank_offset = (val << 16) - 0xa0000;
4fa0f5d2
FB
553 break;
554 case VBE_DISPI_INDEX_ENABLE:
555 if (val & VBE_DISPI_ENABLED) {
556 int h, shift_control;
557
558 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
559 s->vbe_regs[VBE_DISPI_INDEX_XRES];
560 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
561 s->vbe_regs[VBE_DISPI_INDEX_YRES];
562 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
563 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
564
565 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
566 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
567 else
568 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
569 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
570 s->vbe_start_addr = 0;
571
572 /* clear the screen (should be done in BIOS) */
573 if (!(val & VBE_DISPI_NOCLEARMEM)) {
574 memset(s->vram_ptr, 0,
575 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
576 }
577
cae61cef
FB
578 /* we initialize the VGA graphic mode (should be done
579 in BIOS) */
580 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
4fa0f5d2
FB
581 s->cr[0x17] |= 3; /* no CGA modes */
582 s->cr[0x13] = s->vbe_line_offset >> 3;
583 /* width */
584 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
585 /* height */
586 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
587 s->cr[0x12] = h;
588 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
589 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
590 /* line compare to 1023 */
591 s->cr[0x18] = 0xff;
592 s->cr[0x07] |= 0x10;
593 s->cr[0x09] |= 0x40;
594
595 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
596 shift_control = 0;
597 s->sr[0x01] &= ~8; /* no double line */
598 } else {
599 shift_control = 2;
600 }
601 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
602 s->cr[0x09] &= ~0x9f; /* no double scan */
cae61cef
FB
603 s->vbe_regs[s->vbe_index] = val;
604 } else {
605 /* XXX: the bios should do that */
606 s->bank_offset = -0xa0000;
607 }
608 break;
609 case VBE_DISPI_INDEX_VIRT_WIDTH:
610 {
611 int w, h, line_offset;
612
613 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
614 return;
615 w = val;
616 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
617 line_offset = w >> 1;
618 else
619 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
620 h = s->vram_size / line_offset;
621 /* XXX: support weird bochs semantics ? */
622 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
623 return;
624 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
625 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
626 s->vbe_line_offset = line_offset;
627 }
628 break;
629 case VBE_DISPI_INDEX_X_OFFSET:
630 case VBE_DISPI_INDEX_Y_OFFSET:
631 {
632 int x;
633 s->vbe_regs[s->vbe_index] = val;
634 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
635 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
636 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
637 s->vbe_start_addr += x >> 1;
638 else
639 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
640 s->vbe_start_addr >>= 2;
4fa0f5d2
FB
641 }
642 break;
643 default:
644 break;
645 }
4fa0f5d2
FB
646 }
647}
648#endif
649
e89f66ec 650/* called for accesses between 0xa0000 and 0xc0000 */
2e12669a 651static uint32_t vga_mem_readb(target_phys_addr_t addr)
e89f66ec
FB
652{
653 VGAState *s = &vga_state;
654 int memory_map_mode, plane;
655 uint32_t ret;
656
657 /* convert to VGA memory offset */
658 memory_map_mode = (s->gr[6] >> 2) & 3;
659 switch(memory_map_mode) {
660 case 0:
661 addr -= 0xa0000;
662 break;
663 case 1:
cae61cef 664 if (addr >= 0xb0000)
e89f66ec 665 return 0xff;
cae61cef 666 addr += s->bank_offset;
e89f66ec
FB
667 break;
668 case 2:
669 addr -= 0xb0000;
670 if (addr >= 0x8000)
671 return 0xff;
672 break;
673 default:
674 case 3:
675 addr -= 0xb8000;
c92b2e84
FB
676 if (addr >= 0x8000)
677 return 0xff;
e89f66ec
FB
678 break;
679 }
680
681 if (s->sr[4] & 0x08) {
682 /* chain 4 mode : simplest access */
683 ret = s->vram_ptr[addr];
684 } else if (s->gr[5] & 0x10) {
685 /* odd/even mode (aka text mode mapping) */
686 plane = (s->gr[4] & 2) | (addr & 1);
687 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
688 } else {
689 /* standard VGA latched access */
690 s->latch = ((uint32_t *)s->vram_ptr)[addr];
691
692 if (!(s->gr[5] & 0x08)) {
693 /* read mode 0 */
694 plane = s->gr[4];
b8ed223b 695 ret = GET_PLANE(s->latch, plane);
e89f66ec
FB
696 } else {
697 /* read mode 1 */
698 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
699 ret |= ret >> 16;
700 ret |= ret >> 8;
701 ret = (~ret) & 0xff;
702 }
703 }
704 return ret;
705}
706
2e12669a 707static uint32_t vga_mem_readw(target_phys_addr_t addr)
e89f66ec
FB
708{
709 uint32_t v;
710 v = vga_mem_readb(addr);
711 v |= vga_mem_readb(addr + 1) << 8;
712 return v;
713}
714
2e12669a 715static uint32_t vga_mem_readl(target_phys_addr_t addr)
e89f66ec
FB
716{
717 uint32_t v;
718 v = vga_mem_readb(addr);
719 v |= vga_mem_readb(addr + 1) << 8;
720 v |= vga_mem_readb(addr + 2) << 16;
721 v |= vga_mem_readb(addr + 3) << 24;
722 return v;
723}
724
e89f66ec 725/* called for accesses between 0xa0000 and 0xc0000 */
2e12669a 726static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val)
e89f66ec
FB
727{
728 VGAState *s = &vga_state;
729 int memory_map_mode, plane, write_mode, b, func_select;
730 uint32_t write_mask, bit_mask, set_mask;
731
17b0018b 732#ifdef DEBUG_VGA_MEM
e89f66ec
FB
733 printf("vga: [0x%x] = 0x%02x\n", addr, val);
734#endif
735 /* convert to VGA memory offset */
736 memory_map_mode = (s->gr[6] >> 2) & 3;
737 switch(memory_map_mode) {
738 case 0:
739 addr -= 0xa0000;
740 break;
741 case 1:
cae61cef 742 if (addr >= 0xb0000)
e89f66ec 743 return;
cae61cef 744 addr += s->bank_offset;
e89f66ec
FB
745 break;
746 case 2:
747 addr -= 0xb0000;
748 if (addr >= 0x8000)
749 return;
750 break;
751 default:
752 case 3:
753 addr -= 0xb8000;
c92b2e84
FB
754 if (addr >= 0x8000)
755 return;
e89f66ec
FB
756 break;
757 }
758
759 if (s->sr[4] & 0x08) {
760 /* chain 4 mode : simplest access */
761 plane = addr & 3;
762 if (s->sr[2] & (1 << plane)) {
763 s->vram_ptr[addr] = val;
17b0018b 764#ifdef DEBUG_VGA_MEM
e89f66ec
FB
765 printf("vga: chain4: [0x%x]\n", addr);
766#endif
4fa0f5d2 767 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
768 }
769 } else if (s->gr[5] & 0x10) {
770 /* odd/even mode (aka text mode mapping) */
771 plane = (s->gr[4] & 2) | (addr & 1);
772 if (s->sr[2] & (1 << plane)) {
773 addr = ((addr & ~1) << 1) | plane;
774 s->vram_ptr[addr] = val;
17b0018b 775#ifdef DEBUG_VGA_MEM
e89f66ec
FB
776 printf("vga: odd/even: [0x%x]\n", addr);
777#endif
4fa0f5d2 778 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
779 }
780 } else {
781 /* standard VGA latched access */
782 write_mode = s->gr[5] & 3;
783 switch(write_mode) {
784 default:
785 case 0:
786 /* rotate */
787 b = s->gr[3] & 7;
788 val = ((val >> b) | (val << (8 - b))) & 0xff;
789 val |= val << 8;
790 val |= val << 16;
791
792 /* apply set/reset mask */
793 set_mask = mask16[s->gr[1]];
794 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
795 bit_mask = s->gr[8];
796 break;
797 case 1:
798 val = s->latch;
799 goto do_write;
800 case 2:
801 val = mask16[val & 0x0f];
802 bit_mask = s->gr[8];
803 break;
804 case 3:
805 /* rotate */
806 b = s->gr[3] & 7;
a41bc9af 807 val = (val >> b) | (val << (8 - b));
e89f66ec
FB
808
809 bit_mask = s->gr[8] & val;
810 val = mask16[s->gr[0]];
811 break;
812 }
813
814 /* apply logical operation */
815 func_select = s->gr[3] >> 3;
816 switch(func_select) {
817 case 0:
818 default:
819 /* nothing to do */
820 break;
821 case 1:
822 /* and */
823 val &= s->latch;
824 break;
825 case 2:
826 /* or */
827 val |= s->latch;
828 break;
829 case 3:
830 /* xor */
831 val ^= s->latch;
832 break;
833 }
834
835 /* apply bit mask */
836 bit_mask |= bit_mask << 8;
837 bit_mask |= bit_mask << 16;
838 val = (val & bit_mask) | (s->latch & ~bit_mask);
839
840 do_write:
841 /* mask data according to sr[2] */
842 write_mask = mask16[s->sr[2]];
843 ((uint32_t *)s->vram_ptr)[addr] =
844 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
845 (val & write_mask);
17b0018b 846#ifdef DEBUG_VGA_MEM
e89f66ec
FB
847 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
848 addr * 4, write_mask, val);
849#endif
4fa0f5d2 850 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
e89f66ec
FB
851 }
852}
853
2e12669a 854static void vga_mem_writew(target_phys_addr_t addr, uint32_t val)
e89f66ec 855{
5467a722
FB
856 vga_mem_writeb(addr, val & 0xff);
857 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
e89f66ec
FB
858}
859
2e12669a 860static void vga_mem_writel(target_phys_addr_t addr, uint32_t val)
e89f66ec 861{
5467a722
FB
862 vga_mem_writeb(addr, val & 0xff);
863 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
864 vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
865 vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
e89f66ec
FB
866}
867
e89f66ec
FB
868typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
869 const uint8_t *font_ptr, int h,
870 uint32_t fgcol, uint32_t bgcol);
871typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
872 const uint8_t *font_ptr, int h,
873 uint32_t fgcol, uint32_t bgcol, int dup9);
874typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
875 const uint8_t *s, int width);
876
877static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
878{
879 /* XXX: TODO */
880 return 0;
881}
882
883static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
884{
885 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
886}
887
888static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
889{
890 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
891}
892
893static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
894{
895 return (r << 16) | (g << 8) | b;
896}
897
898#define DEPTH 8
899#include "vga_template.h"
900
901#define DEPTH 15
902#include "vga_template.h"
903
904#define DEPTH 16
905#include "vga_template.h"
906
907#define DEPTH 32
908#include "vga_template.h"
909
910static inline int c6_to_8(int v)
911{
912 int b;
913 v &= 0x3f;
914 b = v & 1;
915 return (v << 2) | (b << 1) | b;
916}
917
17b0018b
FB
918static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
919{
920 unsigned int col;
921 col = rgb_to_pixel8(r, g, b);
922 col |= col << 8;
923 col |= col << 16;
924 return col;
925}
926
927static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
928{
929 unsigned int col;
930 col = rgb_to_pixel15(r, g, b);
931 col |= col << 16;
932 return col;
933}
934
935static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
936{
937 unsigned int col;
938 col = rgb_to_pixel16(r, g, b);
939 col |= col << 16;
940 return col;
941}
942
943static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
944{
945 unsigned int col;
946 col = rgb_to_pixel32(r, g, b);
947 return col;
948}
949
e89f66ec
FB
950/* return true if the palette was modified */
951static int update_palette16(VGAState *s)
952{
17b0018b 953 int full_update, i;
e89f66ec 954 uint32_t v, col, *palette;
e89f66ec
FB
955
956 full_update = 0;
957 palette = s->last_palette;
958 for(i = 0; i < 16; i++) {
959 v = s->ar[i];
960 if (s->ar[0x10] & 0x80)
961 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
962 else
963 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
964 v = v * 3;
17b0018b
FB
965 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
966 c6_to_8(s->palette[v + 1]),
967 c6_to_8(s->palette[v + 2]));
968 if (col != palette[i]) {
969 full_update = 1;
970 palette[i] = col;
e89f66ec 971 }
17b0018b
FB
972 }
973 return full_update;
974}
975
976/* return true if the palette was modified */
977static int update_palette256(VGAState *s)
978{
979 int full_update, i;
980 uint32_t v, col, *palette;
981
982 full_update = 0;
983 palette = s->last_palette;
984 v = 0;
985 for(i = 0; i < 256; i++) {
986 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
987 c6_to_8(s->palette[v + 1]),
988 c6_to_8(s->palette[v + 2]));
e89f66ec
FB
989 if (col != palette[i]) {
990 full_update = 1;
991 palette[i] = col;
992 }
17b0018b 993 v += 3;
e89f66ec
FB
994 }
995 return full_update;
996}
997
998/* update start_addr and line_offset. Return TRUE if modified */
999static int update_basic_params(VGAState *s)
1000{
1001 int full_update;
5467a722 1002 uint32_t start_addr, line_offset, line_compare;
e89f66ec
FB
1003
1004 full_update = 0;
4fa0f5d2
FB
1005
1006#ifdef CONFIG_BOCHS_VBE
1007 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1008 line_offset = s->vbe_line_offset;
1009 start_addr = s->vbe_start_addr;
1010 } else
1011#endif
1012 {
1013 /* compute line_offset in bytes */
1014 line_offset = s->cr[0x13];
a41bc9af 1015#ifdef CONFIG_S3VGA
5467a722
FB
1016 {
1017 uinr32_t v;
1018 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
1019 if (v == 0)
1020 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
1021 line_offset |= (v << 8);
1022 }
a41bc9af 1023#endif
4fa0f5d2
FB
1024 line_offset <<= 3;
1025
1026 /* starting address */
1027 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
a41bc9af 1028#ifdef CONFIG_S3VGA
4fa0f5d2 1029 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
a41bc9af 1030#endif
4fa0f5d2
FB
1031 }
1032
e89f66ec
FB
1033 /* line compare */
1034 line_compare = s->cr[0x18] |
1035 ((s->cr[0x07] & 0x10) << 4) |
1036 ((s->cr[0x09] & 0x40) << 3);
1037
1038 if (line_offset != s->line_offset ||
1039 start_addr != s->start_addr ||
1040 line_compare != s->line_compare) {
1041 s->line_offset = line_offset;
1042 s->start_addr = start_addr;
1043 s->line_compare = line_compare;
1044 full_update = 1;
1045 }
1046 return full_update;
1047}
1048
1049static inline int get_depth_index(int depth)
1050{
1051 switch(depth) {
1052 default:
1053 case 8:
1054 return 0;
1055 case 15:
1056 return 1;
1057 case 16:
1058 return 2;
1059 case 32:
1060 return 3;
1061 }
1062}
1063
1064static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1065 vga_draw_glyph8_8,
1066 vga_draw_glyph8_16,
1067 vga_draw_glyph8_16,
1068 vga_draw_glyph8_32,
1069};
1070
17b0018b
FB
1071static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1072 vga_draw_glyph16_8,
1073 vga_draw_glyph16_16,
1074 vga_draw_glyph16_16,
1075 vga_draw_glyph16_32,
1076};
1077
e89f66ec
FB
1078static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1079 vga_draw_glyph9_8,
1080 vga_draw_glyph9_16,
1081 vga_draw_glyph9_16,
1082 vga_draw_glyph9_32,
1083};
1084
1085static const uint8_t cursor_glyph[32 * 4] = {
1086 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1087 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1088 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1089 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1090 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1091 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1092 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1093 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1094 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1095 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1096 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1097 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1098 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1099 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1102};
1103
1104/*
1105 * Text mode update
1106 * Missing:
1107 * - double scan
1108 * - double width
1109 * - underline
1110 * - flashing
1111 */
1112static void vga_draw_text(VGAState *s, int full_update)
1113{
1114 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1115 int cx_min, cx_max, linesize, x_incr;
1116 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1117 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1118 const uint8_t *font_ptr, *font_base[2];
1119 int dup9, line_offset, depth_index;
1120 uint32_t *palette;
1121 uint32_t *ch_attr_ptr;
1122 vga_draw_glyph8_func *vga_draw_glyph8;
1123 vga_draw_glyph9_func *vga_draw_glyph9;
1124
1125 full_update |= update_palette16(s);
1126 palette = s->last_palette;
1127
1128 /* compute font data address (in plane 2) */
1129 v = s->sr[3];
1130 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1131 if (offset != s->font_offsets[0]) {
1132 s->font_offsets[0] = offset;
1133 full_update = 1;
1134 }
1135 font_base[0] = s->vram_ptr + offset;
1136
1137 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1138 font_base[1] = s->vram_ptr + offset;
1139 if (offset != s->font_offsets[1]) {
1140 s->font_offsets[1] = offset;
1141 full_update = 1;
1142 }
1143
1144 full_update |= update_basic_params(s);
1145
1146 line_offset = s->line_offset;
1147 s1 = s->vram_ptr + (s->start_addr * 4);
1148
1149 /* total width & height */
1150 cheight = (s->cr[9] & 0x1f) + 1;
1151 cw = 8;
eccabc6e 1152 if (!(s->sr[1] & 0x01))
e89f66ec 1153 cw = 9;
17b0018b
FB
1154 if (s->sr[1] & 0x08)
1155 cw = 16; /* NOTE: no 18 pixel wide */
e89f66ec
FB
1156 x_incr = cw * ((s->ds->depth + 7) >> 3);
1157 width = (s->cr[0x01] + 1);
17b0018b
FB
1158 if (s->cr[0x06] == 100) {
1159 /* ugly hack for CGA 160x100x16 - explain me the logic */
1160 height = 100;
1161 } else {
1162 height = s->cr[0x12] |
1163 ((s->cr[0x07] & 0x02) << 7) |
1164 ((s->cr[0x07] & 0x40) << 3);
1165 height = (height + 1) / cheight;
1166 }
3294b949
FB
1167 if ((height * width) > CH_ATTR_SIZE) {
1168 /* better than nothing: exit if transient size is too big */
1169 return;
1170 }
1171
e89f66ec 1172 if (width != s->last_width || height != s->last_height ||
eccabc6e 1173 cw != s->last_cw || cheight != s->last_ch) {
2aebb3eb
FB
1174 s->last_scr_width = width * cw;
1175 s->last_scr_height = height * cheight;
1176 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
e89f66ec
FB
1177 s->last_width = width;
1178 s->last_height = height;
1179 s->last_ch = cheight;
1180 s->last_cw = cw;
1181 full_update = 1;
1182 }
1183 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1184 if (cursor_offset != s->cursor_offset ||
1185 s->cr[0xa] != s->cursor_start ||
1186 s->cr[0xb] != s->cursor_end) {
1187 /* if the cursor position changed, we update the old and new
1188 chars */
1189 if (s->cursor_offset < CH_ATTR_SIZE)
1190 s->last_ch_attr[s->cursor_offset] = -1;
1191 if (cursor_offset < CH_ATTR_SIZE)
1192 s->last_ch_attr[cursor_offset] = -1;
1193 s->cursor_offset = cursor_offset;
1194 s->cursor_start = s->cr[0xa];
1195 s->cursor_end = s->cr[0xb];
1196 }
39cf7803 1197 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
e89f66ec
FB
1198
1199 depth_index = get_depth_index(s->ds->depth);
17b0018b
FB
1200 if (cw == 16)
1201 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1202 else
1203 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec
FB
1204 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1205
1206 dest = s->ds->data;
1207 linesize = s->ds->linesize;
1208 ch_attr_ptr = s->last_ch_attr;
1209 for(cy = 0; cy < height; cy++) {
1210 d1 = dest;
1211 src = s1;
1212 cx_min = width;
1213 cx_max = -1;
1214 for(cx = 0; cx < width; cx++) {
1215 ch_attr = *(uint16_t *)src;
1216 if (full_update || ch_attr != *ch_attr_ptr) {
1217 if (cx < cx_min)
1218 cx_min = cx;
1219 if (cx > cx_max)
1220 cx_max = cx;
1221 *ch_attr_ptr = ch_attr;
1222#ifdef WORDS_BIGENDIAN
1223 ch = ch_attr >> 8;
1224 cattr = ch_attr & 0xff;
1225#else
1226 ch = ch_attr & 0xff;
1227 cattr = ch_attr >> 8;
1228#endif
1229 font_ptr = font_base[(cattr >> 3) & 1];
1230 font_ptr += 32 * 4 * ch;
1231 bgcol = palette[cattr >> 4];
1232 fgcol = palette[cattr & 0x0f];
17b0018b 1233 if (cw != 9) {
e89f66ec
FB
1234 vga_draw_glyph8(d1, linesize,
1235 font_ptr, cheight, fgcol, bgcol);
1236 } else {
1237 dup9 = 0;
1238 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1239 dup9 = 1;
1240 vga_draw_glyph9(d1, linesize,
1241 font_ptr, cheight, fgcol, bgcol, dup9);
1242 }
1243 if (src == cursor_ptr &&
1244 !(s->cr[0x0a] & 0x20)) {
1245 int line_start, line_last, h;
1246 /* draw the cursor */
1247 line_start = s->cr[0x0a] & 0x1f;
1248 line_last = s->cr[0x0b] & 0x1f;
1249 /* XXX: check that */
1250 if (line_last > cheight - 1)
1251 line_last = cheight - 1;
1252 if (line_last >= line_start && line_start < cheight) {
1253 h = line_last - line_start + 1;
1254 d = d1 + linesize * line_start;
17b0018b 1255 if (cw != 9) {
e89f66ec
FB
1256 vga_draw_glyph8(d, linesize,
1257 cursor_glyph, h, fgcol, bgcol);
1258 } else {
1259 vga_draw_glyph9(d, linesize,
1260 cursor_glyph, h, fgcol, bgcol, 1);
1261 }
1262 }
1263 }
1264 }
1265 d1 += x_incr;
1266 src += 4;
1267 ch_attr_ptr++;
1268 }
1269 if (cx_max != -1) {
1270 dpy_update(s->ds, cx_min * cw, cy * cheight,
1271 (cx_max - cx_min + 1) * cw, cheight);
1272 }
1273 dest += linesize * cheight;
1274 s1 += line_offset;
1275 }
1276}
1277
17b0018b
FB
1278enum {
1279 VGA_DRAW_LINE2,
1280 VGA_DRAW_LINE2D2,
1281 VGA_DRAW_LINE4,
1282 VGA_DRAW_LINE4D2,
1283 VGA_DRAW_LINE8D2,
1284 VGA_DRAW_LINE8,
1285 VGA_DRAW_LINE15,
1286 VGA_DRAW_LINE16,
4fa0f5d2 1287 VGA_DRAW_LINE24,
17b0018b
FB
1288 VGA_DRAW_LINE32,
1289 VGA_DRAW_LINE_NB,
1290};
1291
1292static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1293 vga_draw_line2_8,
1294 vga_draw_line2_16,
1295 vga_draw_line2_16,
1296 vga_draw_line2_32,
1297
17b0018b
FB
1298 vga_draw_line2d2_8,
1299 vga_draw_line2d2_16,
1300 vga_draw_line2d2_16,
1301 vga_draw_line2d2_32,
1302
e89f66ec
FB
1303 vga_draw_line4_8,
1304 vga_draw_line4_16,
1305 vga_draw_line4_16,
1306 vga_draw_line4_32,
1307
17b0018b
FB
1308 vga_draw_line4d2_8,
1309 vga_draw_line4d2_16,
1310 vga_draw_line4d2_16,
1311 vga_draw_line4d2_32,
1312
1313 vga_draw_line8d2_8,
1314 vga_draw_line8d2_16,
1315 vga_draw_line8d2_16,
1316 vga_draw_line8d2_32,
1317
e89f66ec
FB
1318 vga_draw_line8_8,
1319 vga_draw_line8_16,
1320 vga_draw_line8_16,
1321 vga_draw_line8_32,
1322
1323 vga_draw_line15_8,
1324 vga_draw_line15_15,
1325 vga_draw_line15_16,
1326 vga_draw_line15_32,
1327
1328 vga_draw_line16_8,
1329 vga_draw_line16_15,
1330 vga_draw_line16_16,
1331 vga_draw_line16_32,
1332
4fa0f5d2
FB
1333 vga_draw_line24_8,
1334 vga_draw_line24_15,
1335 vga_draw_line24_16,
1336 vga_draw_line24_32,
1337
e89f66ec
FB
1338 vga_draw_line32_8,
1339 vga_draw_line32_15,
1340 vga_draw_line32_16,
1341 vga_draw_line32_32,
1342};
1343
1344/*
1345 * graphic modes
1346 * Missing:
1347 * - double scan
1348 * - double width
1349 */
1350static void vga_draw_graphic(VGAState *s, int full_update)
1351{
17b0018b 1352 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
39cf7803 1353 int width, height, shift_control, line_offset, page0, page1, bwidth;
a07cf92a 1354 int disp_width, multi_scan, multi_run;
e89f66ec 1355 uint8_t *d;
39cf7803 1356 uint32_t v, addr1, addr;
e89f66ec 1357 vga_draw_line_func *vga_draw_line;
17b0018b 1358
e89f66ec
FB
1359 full_update |= update_basic_params(s);
1360
39cf7803 1361 width = (s->cr[0x01] + 1) * 8;
e89f66ec
FB
1362 height = s->cr[0x12] |
1363 ((s->cr[0x07] & 0x02) << 7) |
1364 ((s->cr[0x07] & 0x40) << 3);
1365 height = (height + 1);
17b0018b
FB
1366 disp_width = width;
1367
e89f66ec 1368 shift_control = (s->gr[0x05] >> 5) & 3;
a07cf92a
FB
1369 double_scan = (s->cr[0x09] & 0x80);
1370 if (shift_control > 1) {
1371 multi_scan = (s->cr[0x09] & 0x1f);
1372 } else {
1373 multi_scan = 0;
1374 }
1375 multi_run = multi_scan;
17b0018b
FB
1376 if (shift_control != s->shift_control ||
1377 double_scan != s->double_scan) {
e89f66ec
FB
1378 full_update = 1;
1379 s->shift_control = shift_control;
17b0018b 1380 s->double_scan = double_scan;
e89f66ec
FB
1381 }
1382
17b0018b
FB
1383 if (shift_control == 0) {
1384 full_update |= update_palette16(s);
1385 if (s->sr[0x01] & 8) {
1386 v = VGA_DRAW_LINE4D2;
1387 disp_width <<= 1;
1388 } else {
1389 v = VGA_DRAW_LINE4;
1390 }
1391 } else if (shift_control == 1) {
1392 full_update |= update_palette16(s);
1393 if (s->sr[0x01] & 8) {
1394 v = VGA_DRAW_LINE2D2;
1395 disp_width <<= 1;
1396 } else {
1397 v = VGA_DRAW_LINE2;
1398 }
1399 } else {
4fa0f5d2
FB
1400#ifdef CONFIG_BOCHS_VBE
1401 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1402 switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) {
1403 default:
1404 case 8:
1405 full_update |= update_palette256(s);
1406 v = VGA_DRAW_LINE8;
1407 break;
1408 case 15:
1409 v = VGA_DRAW_LINE15;
1410 break;
1411 case 16:
1412 v = VGA_DRAW_LINE16;
1413 break;
1414 case 24:
1415 v = VGA_DRAW_LINE24;
1416 break;
1417 case 32:
1418 v = VGA_DRAW_LINE32;
1419 break;
1420 }
1421 } else
1422#endif
1423 {
1424 full_update |= update_palette256(s);
1425 v = VGA_DRAW_LINE8D2;
1426 }
17b0018b 1427 }
e89f66ec 1428 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
17b0018b
FB
1429
1430 if (disp_width != s->last_width ||
1431 height != s->last_height) {
1432 dpy_resize(s->ds, disp_width, height);
2aebb3eb
FB
1433 s->last_scr_width = disp_width;
1434 s->last_scr_height = height;
17b0018b
FB
1435 s->last_width = disp_width;
1436 s->last_height = height;
1437 full_update = 1;
1438 }
1439
e89f66ec 1440 line_offset = s->line_offset;
17b0018b
FB
1441#if 0
1442 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1443 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1444#endif
e89f66ec 1445 addr1 = (s->start_addr * 4);
39cf7803
FB
1446 bwidth = width * 4;
1447 y_start = -1;
e89f66ec
FB
1448 page_min = 0x7fffffff;
1449 page_max = -1;
1450 d = s->ds->data;
1451 linesize = s->ds->linesize;
17b0018b 1452 y1 = 0;
e89f66ec
FB
1453 for(y = 0; y < height; y++) {
1454 addr = addr1;
39cf7803 1455 if (!(s->cr[0x17] & 1)) {
17b0018b 1456 int shift;
e89f66ec 1457 /* CGA compatibility handling */
17b0018b
FB
1458 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1459 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1460 }
39cf7803 1461 if (!(s->cr[0x17] & 2)) {
17b0018b 1462 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1463 }
4fa0f5d2
FB
1464 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1465 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1466 update = full_update | cpu_physical_memory_is_dirty(page0) |
1467 cpu_physical_memory_is_dirty(page1);
1468 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1469 /* if wide line, can use another page */
4fa0f5d2 1470 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
39cf7803 1471 }
e89f66ec 1472 if (update) {
39cf7803
FB
1473 if (y_start < 0)
1474 y_start = y;
e89f66ec
FB
1475 if (page0 < page_min)
1476 page_min = page0;
1477 if (page1 > page_max)
1478 page_max = page1;
1479 vga_draw_line(s, d, s->vram_ptr + addr, width);
39cf7803
FB
1480 } else {
1481 if (y_start >= 0) {
1482 /* flush to display */
1483 dpy_update(s->ds, 0, y_start,
17b0018b 1484 disp_width, y - y_start);
39cf7803
FB
1485 y_start = -1;
1486 }
e89f66ec 1487 }
a07cf92a
FB
1488 if (!multi_run) {
1489 if (!double_scan || (y & 1) != 0) {
1490 if (y1 == s->line_compare) {
1491 addr1 = 0;
1492 } else {
1493 mask = (s->cr[0x17] & 3) ^ 3;
1494 if ((y1 & mask) == mask)
1495 addr1 += line_offset;
1496 }
1497 y1++;
17b0018b 1498 }
a07cf92a
FB
1499 multi_run = multi_scan;
1500 } else {
1501 multi_run--;
17b0018b 1502 y1++;
e89f66ec
FB
1503 }
1504 d += linesize;
1505 }
39cf7803
FB
1506 if (y_start >= 0) {
1507 /* flush to display */
1508 dpy_update(s->ds, 0, y_start,
17b0018b 1509 disp_width, y - y_start);
39cf7803 1510 }
e89f66ec
FB
1511 /* reset modified pages */
1512 if (page_max != -1) {
4fa0f5d2 1513 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
e89f66ec
FB
1514 }
1515}
1516
2aebb3eb
FB
1517static void vga_draw_blank(VGAState *s, int full_update)
1518{
1519 int i, w, val;
1520 uint8_t *d;
1521
1522 if (!full_update)
1523 return;
1524 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1525 return;
1526 if (s->ds->depth == 8)
1527 val = s->rgb_to_pixel(0, 0, 0);
1528 else
1529 val = 0;
1530 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1531 d = s->ds->data;
1532 for(i = 0; i < s->last_scr_height; i++) {
1533 memset(d, val, w);
1534 d += s->ds->linesize;
1535 }
1536 dpy_update(s->ds, 0, 0,
1537 s->last_scr_width, s->last_scr_height);
1538}
1539
1540#define GMODE_TEXT 0
1541#define GMODE_GRAPH 1
1542#define GMODE_BLANK 2
1543
e89f66ec
FB
1544void vga_update_display(void)
1545{
1546 VGAState *s = &vga_state;
1547 int full_update, graphic_mode;
1548
1549 if (s->ds->depth == 0) {
0f35920c 1550 /* nothing to do */
59a983b9
FB
1551 } else {
1552 switch(s->ds->depth) {
1553 case 8:
1554 s->rgb_to_pixel = rgb_to_pixel8_dup;
1555 break;
1556 case 15:
1557 s->rgb_to_pixel = rgb_to_pixel15_dup;
1558 break;
1559 default:
1560 case 16:
1561 s->rgb_to_pixel = rgb_to_pixel16_dup;
1562 break;
1563 case 32:
1564 s->rgb_to_pixel = rgb_to_pixel32_dup;
1565 break;
1566 }
1567
e89f66ec 1568 full_update = 0;
2aebb3eb
FB
1569 if (!(s->ar_index & 0x20)) {
1570 graphic_mode = GMODE_BLANK;
1571 } else {
1572 graphic_mode = s->gr[6] & 1;
1573 }
e89f66ec
FB
1574 if (graphic_mode != s->graphic_mode) {
1575 s->graphic_mode = graphic_mode;
1576 full_update = 1;
1577 }
2aebb3eb
FB
1578 switch(graphic_mode) {
1579 case GMODE_TEXT:
e89f66ec 1580 vga_draw_text(s, full_update);
2aebb3eb
FB
1581 break;
1582 case GMODE_GRAPH:
1583 vga_draw_graphic(s, full_update);
1584 break;
1585 case GMODE_BLANK:
1586 default:
1587 vga_draw_blank(s, full_update);
1588 break;
1589 }
e89f66ec
FB
1590 }
1591}
1592
59a983b9 1593static void vga_reset(VGAState *s)
e89f66ec
FB
1594{
1595 memset(s, 0, sizeof(VGAState));
a41bc9af 1596#ifdef CONFIG_S3VGA
e89f66ec
FB
1597 /* chip ID for 8c968 */
1598 s->cr[0x2d] = 0x88;
1599 s->cr[0x2e] = 0xb0;
1600 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1601 s->cr[0x30] = 0xe1;
a41bc9af 1602#endif
e89f66ec
FB
1603 s->graphic_mode = -1; /* force full update */
1604}
1605
59a983b9 1606static CPUReadMemoryFunc *vga_mem_read[3] = {
e89f66ec
FB
1607 vga_mem_readb,
1608 vga_mem_readw,
1609 vga_mem_readl,
1610};
1611
59a983b9 1612static CPUWriteMemoryFunc *vga_mem_write[3] = {
e89f66ec
FB
1613 vga_mem_writeb,
1614 vga_mem_writew,
1615 vga_mem_writel,
1616};
1617
b0a21b53
FB
1618static void vga_save(QEMUFile *f, void *opaque)
1619{
1620 VGAState *s = opaque;
1621 int i;
1622
1623 qemu_put_be32s(f, &s->latch);
1624 qemu_put_8s(f, &s->sr_index);
1625 qemu_put_buffer(f, s->sr, 8);
1626 qemu_put_8s(f, &s->gr_index);
1627 qemu_put_buffer(f, s->gr, 16);
1628 qemu_put_8s(f, &s->ar_index);
1629 qemu_put_buffer(f, s->ar, 21);
1630 qemu_put_be32s(f, &s->ar_flip_flop);
1631 qemu_put_8s(f, &s->cr_index);
1632 qemu_put_buffer(f, s->cr, 256);
1633 qemu_put_8s(f, &s->msr);
1634 qemu_put_8s(f, &s->fcr);
1635 qemu_put_8s(f, &s->st00);
1636 qemu_put_8s(f, &s->st01);
1637
1638 qemu_put_8s(f, &s->dac_state);
1639 qemu_put_8s(f, &s->dac_sub_index);
1640 qemu_put_8s(f, &s->dac_read_index);
1641 qemu_put_8s(f, &s->dac_write_index);
1642 qemu_put_buffer(f, s->dac_cache, 3);
1643 qemu_put_buffer(f, s->palette, 768);
1644
1645 qemu_put_be32s(f, &s->bank_offset);
1646#ifdef CONFIG_BOCHS_VBE
1647 qemu_put_byte(f, 1);
1648 qemu_put_be16s(f, &s->vbe_index);
1649 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1650 qemu_put_be16s(f, &s->vbe_regs[i]);
1651 qemu_put_be32s(f, &s->vbe_start_addr);
1652 qemu_put_be32s(f, &s->vbe_line_offset);
1653 qemu_put_be32s(f, &s->vbe_bank_mask);
1654#else
1655 qemu_put_byte(f, 0);
1656#endif
1657}
1658
1659static int vga_load(QEMUFile *f, void *opaque, int version_id)
1660{
1661 VGAState *s = opaque;
1662 int is_vbe, i;
1663
1664 if (version_id != 1)
1665 return -EINVAL;
1666
1667 qemu_get_be32s(f, &s->latch);
1668 qemu_get_8s(f, &s->sr_index);
1669 qemu_get_buffer(f, s->sr, 8);
1670 qemu_get_8s(f, &s->gr_index);
1671 qemu_get_buffer(f, s->gr, 16);
1672 qemu_get_8s(f, &s->ar_index);
1673 qemu_get_buffer(f, s->ar, 21);
1674 qemu_get_be32s(f, &s->ar_flip_flop);
1675 qemu_get_8s(f, &s->cr_index);
1676 qemu_get_buffer(f, s->cr, 256);
1677 qemu_get_8s(f, &s->msr);
1678 qemu_get_8s(f, &s->fcr);
1679 qemu_get_8s(f, &s->st00);
1680 qemu_get_8s(f, &s->st01);
1681
1682 qemu_get_8s(f, &s->dac_state);
1683 qemu_get_8s(f, &s->dac_sub_index);
1684 qemu_get_8s(f, &s->dac_read_index);
1685 qemu_get_8s(f, &s->dac_write_index);
1686 qemu_get_buffer(f, s->dac_cache, 3);
1687 qemu_get_buffer(f, s->palette, 768);
1688
1689 qemu_get_be32s(f, &s->bank_offset);
1690 is_vbe = qemu_get_byte(f);
1691#ifdef CONFIG_BOCHS_VBE
1692 if (!is_vbe)
1693 return -EINVAL;
1694 qemu_get_be16s(f, &s->vbe_index);
1695 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1696 qemu_get_be16s(f, &s->vbe_regs[i]);
1697 qemu_get_be32s(f, &s->vbe_start_addr);
1698 qemu_get_be32s(f, &s->vbe_line_offset);
1699 qemu_get_be32s(f, &s->vbe_bank_mask);
1700#else
1701 if (is_vbe)
1702 return -EINVAL;
1703#endif
1704
1705 /* force refresh */
1706 s->graphic_mode = -1;
1707 return 0;
1708}
1709
7138fcfb
FB
1710int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1711 unsigned long vga_ram_offset, int vga_ram_size)
e89f66ec
FB
1712{
1713 VGAState *s = &vga_state;
17b0018b 1714 int i, j, v, b;
e89f66ec
FB
1715
1716 for(i = 0;i < 256; i++) {
1717 v = 0;
1718 for(j = 0; j < 8; j++) {
1719 v |= ((i >> j) & 1) << (j * 4);
1720 }
1721 expand4[i] = v;
1722
1723 v = 0;
1724 for(j = 0; j < 4; j++) {
1725 v |= ((i >> (2 * j)) & 3) << (j * 4);
1726 }
1727 expand2[i] = v;
1728 }
17b0018b
FB
1729 for(i = 0; i < 16; i++) {
1730 v = 0;
1731 for(j = 0; j < 4; j++) {
1732 b = ((i >> j) & 1);
1733 v |= b << (2 * j);
1734 v |= b << (2 * j + 1);
1735 }
1736 expand4to8[i] = v;
1737 }
e89f66ec
FB
1738
1739 vga_reset(s);
1740
1741 s->vram_ptr = vga_ram_base;
1742 s->vram_offset = vga_ram_offset;
1743 s->vram_size = vga_ram_size;
1744 s->ds = ds;
1745
b0a21b53
FB
1746 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1747
0f35920c 1748 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
e89f66ec 1749
0f35920c
FB
1750 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1751 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1752 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1753 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
e89f66ec 1754
0f35920c 1755 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
e89f66ec 1756
0f35920c
FB
1757 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1758 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1759 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1760 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
cae61cef 1761 s->bank_offset = -0xa0000;
e89f66ec 1762
4fa0f5d2
FB
1763#ifdef CONFIG_BOCHS_VBE
1764 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
cae61cef 1765 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
0f35920c
FB
1766 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s);
1767 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s);
4fa0f5d2 1768
0f35920c
FB
1769 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s);
1770 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s);
4fa0f5d2
FB
1771#endif
1772
e89f66ec 1773 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
7138fcfb
FB
1774#if defined (TARGET_I386)
1775 cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory);
4fa0f5d2
FB
1776#ifdef CONFIG_BOCHS_VBE
1777 /* XXX: use optimized standard vga accesses */
1778 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1779 vga_ram_size, vga_ram_offset);
1780#endif
7138fcfb
FB
1781#elif defined (TARGET_PPC)
1782 cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory);
1783#endif
e89f66ec
FB
1784 return 0;
1785}
59a983b9
FB
1786
1787/********************************************************/
1788/* vga screen dump */
1789
1790static int vga_save_w, vga_save_h;
1791
1792static void vga_save_dpy_update(DisplayState *s,
1793 int x, int y, int w, int h)
1794{
1795}
1796
1797static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1798{
1799 s->linesize = w * 4;
1800 s->data = qemu_malloc(h * s->linesize);
1801 vga_save_w = w;
1802 vga_save_h = h;
1803}
1804
1805static void vga_save_dpy_refresh(DisplayState *s)
1806{
1807}
1808
1809static int ppm_save(const char *filename, uint8_t *data,
1810 int w, int h, int linesize)
1811{
1812 FILE *f;
1813 uint8_t *d, *d1;
1814 unsigned int v;
1815 int y, x;
1816
1817 f = fopen(filename, "wb");
1818 if (!f)
1819 return -1;
1820 fprintf(f, "P6\n%d %d\n%d\n",
1821 w, h, 255);
1822 d1 = data;
1823 for(y = 0; y < h; y++) {
1824 d = d1;
1825 for(x = 0; x < w; x++) {
1826 v = *(uint32_t *)d;
1827 fputc((v >> 16) & 0xff, f);
1828 fputc((v >> 8) & 0xff, f);
1829 fputc((v) & 0xff, f);
1830 d += 4;
1831 }
1832 d1 += linesize;
1833 }
1834 fclose(f);
1835 return 0;
1836}
1837
1838/* save the vga display in a PPM image even if no display is
1839 available */
1840void vga_screen_dump(const char *filename)
1841{
1842 VGAState *s = &vga_state;
1843 DisplayState *saved_ds, ds1, *ds = &ds1;
1844
1845 /* XXX: this is a little hackish */
1846 s->last_width = -1;
1847 s->last_height = -1;
1848 saved_ds = s->ds;
1849
1850 memset(ds, 0, sizeof(DisplayState));
1851 ds->dpy_update = vga_save_dpy_update;
1852 ds->dpy_resize = vga_save_dpy_resize;
1853 ds->dpy_refresh = vga_save_dpy_refresh;
1854 ds->depth = 32;
1855
1856 s->ds = ds;
1857 s->graphic_mode = -1;
1858 vga_update_display();
1859
1860 if (ds->data) {
1861 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
1862 s->ds->linesize);
1863 qemu_free(ds->data);
1864 }
1865 s->ds = saved_ds;
1866}