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