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