]> git.proxmox.com Git - mirror_qemu.git/blame - hw/vga.c
interlace support
[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 149
7b17d41e 150VGAState *vga_state;
e89f66ec
FB
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
17b0018b
FB
855static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
856{
857 unsigned int col;
858 col = rgb_to_pixel8(r, g, b);
859 col |= col << 8;
860 col |= col << 16;
861 return col;
862}
863
864static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
865{
866 unsigned int col;
867 col = rgb_to_pixel15(r, g, b);
868 col |= col << 16;
869 return col;
870}
871
872static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
873{
874 unsigned int col;
875 col = rgb_to_pixel16(r, g, b);
876 col |= col << 16;
877 return col;
878}
879
880static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
881{
882 unsigned int col;
883 col = rgb_to_pixel32(r, g, b);
884 return col;
885}
886
e89f66ec
FB
887/* return true if the palette was modified */
888static int update_palette16(VGAState *s)
889{
17b0018b 890 int full_update, i;
e89f66ec 891 uint32_t v, col, *palette;
e89f66ec
FB
892
893 full_update = 0;
894 palette = s->last_palette;
895 for(i = 0; i < 16; i++) {
896 v = s->ar[i];
897 if (s->ar[0x10] & 0x80)
898 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
899 else
900 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
901 v = v * 3;
17b0018b
FB
902 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
903 c6_to_8(s->palette[v + 1]),
904 c6_to_8(s->palette[v + 2]));
905 if (col != palette[i]) {
906 full_update = 1;
907 palette[i] = col;
e89f66ec 908 }
17b0018b
FB
909 }
910 return full_update;
911}
912
913/* return true if the palette was modified */
914static int update_palette256(VGAState *s)
915{
916 int full_update, i;
917 uint32_t v, col, *palette;
918
919 full_update = 0;
920 palette = s->last_palette;
921 v = 0;
922 for(i = 0; i < 256; i++) {
923 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
924 c6_to_8(s->palette[v + 1]),
925 c6_to_8(s->palette[v + 2]));
e89f66ec
FB
926 if (col != palette[i]) {
927 full_update = 1;
928 palette[i] = col;
929 }
17b0018b 930 v += 3;
e89f66ec
FB
931 }
932 return full_update;
933}
934
798b0c25
FB
935static void vga_get_offsets(VGAState *s,
936 uint32_t *pline_offset,
937 uint32_t *pstart_addr)
e89f66ec 938{
798b0c25 939 uint32_t start_addr, line_offset;
4fa0f5d2
FB
940#ifdef CONFIG_BOCHS_VBE
941 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
942 line_offset = s->vbe_line_offset;
943 start_addr = s->vbe_start_addr;
944 } else
945#endif
946 {
947 /* compute line_offset in bytes */
948 line_offset = s->cr[0x13];
a41bc9af 949#ifdef CONFIG_S3VGA
5467a722
FB
950 {
951 uinr32_t v;
952 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
953 if (v == 0)
954 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
955 line_offset |= (v << 8);
956 }
a41bc9af 957#endif
4fa0f5d2
FB
958 line_offset <<= 3;
959
960 /* starting address */
961 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
a41bc9af 962#ifdef CONFIG_S3VGA
4fa0f5d2 963 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
a41bc9af 964#endif
4fa0f5d2 965 }
798b0c25
FB
966 *pline_offset = line_offset;
967 *pstart_addr = start_addr;
968}
969
970/* update start_addr and line_offset. Return TRUE if modified */
971static int update_basic_params(VGAState *s)
972{
973 int full_update;
974 uint32_t start_addr, line_offset, line_compare;
4fa0f5d2 975
798b0c25
FB
976 full_update = 0;
977
978 s->get_offsets(s, &line_offset, &start_addr);
e89f66ec
FB
979 /* line compare */
980 line_compare = s->cr[0x18] |
981 ((s->cr[0x07] & 0x10) << 4) |
982 ((s->cr[0x09] & 0x40) << 3);
983
984 if (line_offset != s->line_offset ||
985 start_addr != s->start_addr ||
986 line_compare != s->line_compare) {
987 s->line_offset = line_offset;
988 s->start_addr = start_addr;
989 s->line_compare = line_compare;
990 full_update = 1;
991 }
992 return full_update;
993}
994
995static inline int get_depth_index(int depth)
996{
997 switch(depth) {
998 default:
999 case 8:
1000 return 0;
1001 case 15:
1002 return 1;
1003 case 16:
1004 return 2;
1005 case 32:
1006 return 3;
1007 }
1008}
1009
1010static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1011 vga_draw_glyph8_8,
1012 vga_draw_glyph8_16,
1013 vga_draw_glyph8_16,
1014 vga_draw_glyph8_32,
1015};
1016
17b0018b
FB
1017static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1018 vga_draw_glyph16_8,
1019 vga_draw_glyph16_16,
1020 vga_draw_glyph16_16,
1021 vga_draw_glyph16_32,
1022};
1023
e89f66ec
FB
1024static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1025 vga_draw_glyph9_8,
1026 vga_draw_glyph9_16,
1027 vga_draw_glyph9_16,
1028 vga_draw_glyph9_32,
1029};
1030
1031static const uint8_t cursor_glyph[32 * 4] = {
1032 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1033 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1034 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1035 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1036 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1037 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1038 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1039 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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};
1049
1050/*
1051 * Text mode update
1052 * Missing:
1053 * - double scan
1054 * - double width
1055 * - underline
1056 * - flashing
1057 */
1058static void vga_draw_text(VGAState *s, int full_update)
1059{
1060 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1061 int cx_min, cx_max, linesize, x_incr;
1062 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1063 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1064 const uint8_t *font_ptr, *font_base[2];
1065 int dup9, line_offset, depth_index;
1066 uint32_t *palette;
1067 uint32_t *ch_attr_ptr;
1068 vga_draw_glyph8_func *vga_draw_glyph8;
1069 vga_draw_glyph9_func *vga_draw_glyph9;
1070
1071 full_update |= update_palette16(s);
1072 palette = s->last_palette;
1073
1074 /* compute font data address (in plane 2) */
1075 v = s->sr[3];
1078f663 1076 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1077 if (offset != s->font_offsets[0]) {
1078 s->font_offsets[0] = offset;
1079 full_update = 1;
1080 }
1081 font_base[0] = s->vram_ptr + offset;
1082
1078f663 1083 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1084 font_base[1] = s->vram_ptr + offset;
1085 if (offset != s->font_offsets[1]) {
1086 s->font_offsets[1] = offset;
1087 full_update = 1;
1088 }
1089
1090 full_update |= update_basic_params(s);
1091
1092 line_offset = s->line_offset;
1093 s1 = s->vram_ptr + (s->start_addr * 4);
1094
1095 /* total width & height */
1096 cheight = (s->cr[9] & 0x1f) + 1;
1097 cw = 8;
eccabc6e 1098 if (!(s->sr[1] & 0x01))
e89f66ec 1099 cw = 9;
17b0018b
FB
1100 if (s->sr[1] & 0x08)
1101 cw = 16; /* NOTE: no 18 pixel wide */
e89f66ec
FB
1102 x_incr = cw * ((s->ds->depth + 7) >> 3);
1103 width = (s->cr[0x01] + 1);
17b0018b
FB
1104 if (s->cr[0x06] == 100) {
1105 /* ugly hack for CGA 160x100x16 - explain me the logic */
1106 height = 100;
1107 } else {
1108 height = s->cr[0x12] |
1109 ((s->cr[0x07] & 0x02) << 7) |
1110 ((s->cr[0x07] & 0x40) << 3);
1111 height = (height + 1) / cheight;
1112 }
3294b949
FB
1113 if ((height * width) > CH_ATTR_SIZE) {
1114 /* better than nothing: exit if transient size is too big */
1115 return;
1116 }
1117
e89f66ec 1118 if (width != s->last_width || height != s->last_height ||
eccabc6e 1119 cw != s->last_cw || cheight != s->last_ch) {
2aebb3eb
FB
1120 s->last_scr_width = width * cw;
1121 s->last_scr_height = height * cheight;
1122 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
e89f66ec
FB
1123 s->last_width = width;
1124 s->last_height = height;
1125 s->last_ch = cheight;
1126 s->last_cw = cw;
1127 full_update = 1;
1128 }
1129 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1130 if (cursor_offset != s->cursor_offset ||
1131 s->cr[0xa] != s->cursor_start ||
1132 s->cr[0xb] != s->cursor_end) {
1133 /* if the cursor position changed, we update the old and new
1134 chars */
1135 if (s->cursor_offset < CH_ATTR_SIZE)
1136 s->last_ch_attr[s->cursor_offset] = -1;
1137 if (cursor_offset < CH_ATTR_SIZE)
1138 s->last_ch_attr[cursor_offset] = -1;
1139 s->cursor_offset = cursor_offset;
1140 s->cursor_start = s->cr[0xa];
1141 s->cursor_end = s->cr[0xb];
1142 }
39cf7803 1143 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
e89f66ec
FB
1144
1145 depth_index = get_depth_index(s->ds->depth);
17b0018b
FB
1146 if (cw == 16)
1147 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1148 else
1149 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec
FB
1150 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1151
1152 dest = s->ds->data;
1153 linesize = s->ds->linesize;
1154 ch_attr_ptr = s->last_ch_attr;
1155 for(cy = 0; cy < height; cy++) {
1156 d1 = dest;
1157 src = s1;
1158 cx_min = width;
1159 cx_max = -1;
1160 for(cx = 0; cx < width; cx++) {
1161 ch_attr = *(uint16_t *)src;
1162 if (full_update || ch_attr != *ch_attr_ptr) {
1163 if (cx < cx_min)
1164 cx_min = cx;
1165 if (cx > cx_max)
1166 cx_max = cx;
1167 *ch_attr_ptr = ch_attr;
1168#ifdef WORDS_BIGENDIAN
1169 ch = ch_attr >> 8;
1170 cattr = ch_attr & 0xff;
1171#else
1172 ch = ch_attr & 0xff;
1173 cattr = ch_attr >> 8;
1174#endif
1175 font_ptr = font_base[(cattr >> 3) & 1];
1176 font_ptr += 32 * 4 * ch;
1177 bgcol = palette[cattr >> 4];
1178 fgcol = palette[cattr & 0x0f];
17b0018b 1179 if (cw != 9) {
e89f66ec
FB
1180 vga_draw_glyph8(d1, linesize,
1181 font_ptr, cheight, fgcol, bgcol);
1182 } else {
1183 dup9 = 0;
1184 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1185 dup9 = 1;
1186 vga_draw_glyph9(d1, linesize,
1187 font_ptr, cheight, fgcol, bgcol, dup9);
1188 }
1189 if (src == cursor_ptr &&
1190 !(s->cr[0x0a] & 0x20)) {
1191 int line_start, line_last, h;
1192 /* draw the cursor */
1193 line_start = s->cr[0x0a] & 0x1f;
1194 line_last = s->cr[0x0b] & 0x1f;
1195 /* XXX: check that */
1196 if (line_last > cheight - 1)
1197 line_last = cheight - 1;
1198 if (line_last >= line_start && line_start < cheight) {
1199 h = line_last - line_start + 1;
1200 d = d1 + linesize * line_start;
17b0018b 1201 if (cw != 9) {
e89f66ec
FB
1202 vga_draw_glyph8(d, linesize,
1203 cursor_glyph, h, fgcol, bgcol);
1204 } else {
1205 vga_draw_glyph9(d, linesize,
1206 cursor_glyph, h, fgcol, bgcol, 1);
1207 }
1208 }
1209 }
1210 }
1211 d1 += x_incr;
1212 src += 4;
1213 ch_attr_ptr++;
1214 }
1215 if (cx_max != -1) {
1216 dpy_update(s->ds, cx_min * cw, cy * cheight,
1217 (cx_max - cx_min + 1) * cw, cheight);
1218 }
1219 dest += linesize * cheight;
1220 s1 += line_offset;
1221 }
1222}
1223
17b0018b
FB
1224enum {
1225 VGA_DRAW_LINE2,
1226 VGA_DRAW_LINE2D2,
1227 VGA_DRAW_LINE4,
1228 VGA_DRAW_LINE4D2,
1229 VGA_DRAW_LINE8D2,
1230 VGA_DRAW_LINE8,
1231 VGA_DRAW_LINE15,
1232 VGA_DRAW_LINE16,
4fa0f5d2 1233 VGA_DRAW_LINE24,
17b0018b
FB
1234 VGA_DRAW_LINE32,
1235 VGA_DRAW_LINE_NB,
1236};
1237
1238static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1239 vga_draw_line2_8,
1240 vga_draw_line2_16,
1241 vga_draw_line2_16,
1242 vga_draw_line2_32,
1243
17b0018b
FB
1244 vga_draw_line2d2_8,
1245 vga_draw_line2d2_16,
1246 vga_draw_line2d2_16,
1247 vga_draw_line2d2_32,
1248
e89f66ec
FB
1249 vga_draw_line4_8,
1250 vga_draw_line4_16,
1251 vga_draw_line4_16,
1252 vga_draw_line4_32,
1253
17b0018b
FB
1254 vga_draw_line4d2_8,
1255 vga_draw_line4d2_16,
1256 vga_draw_line4d2_16,
1257 vga_draw_line4d2_32,
1258
1259 vga_draw_line8d2_8,
1260 vga_draw_line8d2_16,
1261 vga_draw_line8d2_16,
1262 vga_draw_line8d2_32,
1263
e89f66ec
FB
1264 vga_draw_line8_8,
1265 vga_draw_line8_16,
1266 vga_draw_line8_16,
1267 vga_draw_line8_32,
1268
1269 vga_draw_line15_8,
1270 vga_draw_line15_15,
1271 vga_draw_line15_16,
1272 vga_draw_line15_32,
1273
1274 vga_draw_line16_8,
1275 vga_draw_line16_15,
1276 vga_draw_line16_16,
1277 vga_draw_line16_32,
1278
4fa0f5d2
FB
1279 vga_draw_line24_8,
1280 vga_draw_line24_15,
1281 vga_draw_line24_16,
1282 vga_draw_line24_32,
1283
e89f66ec
FB
1284 vga_draw_line32_8,
1285 vga_draw_line32_15,
1286 vga_draw_line32_16,
1287 vga_draw_line32_32,
1288};
1289
798b0c25
FB
1290static int vga_get_bpp(VGAState *s)
1291{
1292 int ret;
1293#ifdef CONFIG_BOCHS_VBE
1294 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1295 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1296 } else
1297#endif
1298 {
1299 ret = 0;
1300 }
1301 return ret;
1302}
1303
a130a41e
FB
1304static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1305{
1306 int width, height;
1307
1308 width = (s->cr[0x01] + 1) * 8;
1309 height = s->cr[0x12] |
1310 ((s->cr[0x07] & 0x02) << 7) |
1311 ((s->cr[0x07] & 0x40) << 3);
1312 height = (height + 1);
1313 *pwidth = width;
1314 *pheight = height;
1315}
1316
a8aa669b
FB
1317void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1318{
1319 int y;
1320 if (y1 >= VGA_MAX_HEIGHT)
1321 return;
1322 if (y2 >= VGA_MAX_HEIGHT)
1323 y2 = VGA_MAX_HEIGHT;
1324 for(y = y1; y < y2; y++) {
1325 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1326 }
1327}
1328
e89f66ec
FB
1329/*
1330 * graphic modes
e89f66ec
FB
1331 */
1332static void vga_draw_graphic(VGAState *s, int full_update)
1333{
17b0018b 1334 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
39cf7803 1335 int width, height, shift_control, line_offset, page0, page1, bwidth;
a07cf92a 1336 int disp_width, multi_scan, multi_run;
e89f66ec 1337 uint8_t *d;
39cf7803 1338 uint32_t v, addr1, addr;
e89f66ec 1339 vga_draw_line_func *vga_draw_line;
17b0018b 1340
e89f66ec
FB
1341 full_update |= update_basic_params(s);
1342
a130a41e 1343 s->get_resolution(s, &width, &height);
17b0018b 1344 disp_width = width;
09a79b49 1345
e89f66ec 1346 shift_control = (s->gr[0x05] >> 5) & 3;
a07cf92a
FB
1347 double_scan = (s->cr[0x09] & 0x80);
1348 if (shift_control > 1) {
1349 multi_scan = (s->cr[0x09] & 0x1f);
1350 } else {
1351 multi_scan = 0;
1352 }
1353 multi_run = multi_scan;
17b0018b
FB
1354 if (shift_control != s->shift_control ||
1355 double_scan != s->double_scan) {
e89f66ec
FB
1356 full_update = 1;
1357 s->shift_control = shift_control;
17b0018b 1358 s->double_scan = double_scan;
e89f66ec
FB
1359 }
1360
17b0018b
FB
1361 if (shift_control == 0) {
1362 full_update |= update_palette16(s);
1363 if (s->sr[0x01] & 8) {
1364 v = VGA_DRAW_LINE4D2;
1365 disp_width <<= 1;
1366 } else {
1367 v = VGA_DRAW_LINE4;
1368 }
1369 } else if (shift_control == 1) {
1370 full_update |= update_palette16(s);
1371 if (s->sr[0x01] & 8) {
1372 v = VGA_DRAW_LINE2D2;
1373 disp_width <<= 1;
1374 } else {
1375 v = VGA_DRAW_LINE2;
1376 }
1377 } else {
798b0c25
FB
1378 switch(s->get_bpp(s)) {
1379 default:
1380 case 0:
4fa0f5d2
FB
1381 full_update |= update_palette256(s);
1382 v = VGA_DRAW_LINE8D2;
798b0c25
FB
1383 break;
1384 case 8:
1385 full_update |= update_palette256(s);
1386 v = VGA_DRAW_LINE8;
1387 break;
1388 case 15:
1389 v = VGA_DRAW_LINE15;
1390 break;
1391 case 16:
1392 v = VGA_DRAW_LINE16;
1393 break;
1394 case 24:
1395 v = VGA_DRAW_LINE24;
1396 break;
1397 case 32:
1398 v = VGA_DRAW_LINE32;
1399 break;
4fa0f5d2 1400 }
17b0018b 1401 }
e89f66ec 1402 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
17b0018b
FB
1403
1404 if (disp_width != s->last_width ||
1405 height != s->last_height) {
1406 dpy_resize(s->ds, disp_width, height);
2aebb3eb
FB
1407 s->last_scr_width = disp_width;
1408 s->last_scr_height = height;
17b0018b
FB
1409 s->last_width = disp_width;
1410 s->last_height = height;
1411 full_update = 1;
1412 }
a8aa669b
FB
1413 if (s->cursor_invalidate)
1414 s->cursor_invalidate(s);
1415
e89f66ec 1416 line_offset = s->line_offset;
17b0018b
FB
1417#if 0
1418 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1419 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1420#endif
e89f66ec 1421 addr1 = (s->start_addr * 4);
39cf7803
FB
1422 bwidth = width * 4;
1423 y_start = -1;
e89f66ec
FB
1424 page_min = 0x7fffffff;
1425 page_max = -1;
1426 d = s->ds->data;
1427 linesize = s->ds->linesize;
17b0018b 1428 y1 = 0;
e89f66ec
FB
1429 for(y = 0; y < height; y++) {
1430 addr = addr1;
39cf7803 1431 if (!(s->cr[0x17] & 1)) {
17b0018b 1432 int shift;
e89f66ec 1433 /* CGA compatibility handling */
17b0018b
FB
1434 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1435 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1436 }
39cf7803 1437 if (!(s->cr[0x17] & 2)) {
17b0018b 1438 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1439 }
4fa0f5d2
FB
1440 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1441 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1442 update = full_update | cpu_physical_memory_is_dirty(page0) |
1443 cpu_physical_memory_is_dirty(page1);
1444 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1445 /* if wide line, can use another page */
4fa0f5d2 1446 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
39cf7803 1447 }
a8aa669b
FB
1448 /* explicit invalidation for the hardware cursor */
1449 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
e89f66ec 1450 if (update) {
39cf7803
FB
1451 if (y_start < 0)
1452 y_start = y;
e89f66ec
FB
1453 if (page0 < page_min)
1454 page_min = page0;
1455 if (page1 > page_max)
1456 page_max = page1;
1457 vga_draw_line(s, d, s->vram_ptr + addr, width);
a8aa669b
FB
1458 if (s->cursor_draw_line)
1459 s->cursor_draw_line(s, d, y);
39cf7803
FB
1460 } else {
1461 if (y_start >= 0) {
1462 /* flush to display */
1463 dpy_update(s->ds, 0, y_start,
17b0018b 1464 disp_width, y - y_start);
39cf7803
FB
1465 y_start = -1;
1466 }
e89f66ec 1467 }
a07cf92a
FB
1468 if (!multi_run) {
1469 if (!double_scan || (y & 1) != 0) {
1470 if (y1 == s->line_compare) {
1471 addr1 = 0;
1472 } else {
1473 mask = (s->cr[0x17] & 3) ^ 3;
1474 if ((y1 & mask) == mask)
1475 addr1 += line_offset;
1476 }
1477 y1++;
17b0018b 1478 }
a07cf92a
FB
1479 multi_run = multi_scan;
1480 } else {
1481 multi_run--;
17b0018b 1482 y1++;
e89f66ec
FB
1483 }
1484 d += linesize;
1485 }
39cf7803
FB
1486 if (y_start >= 0) {
1487 /* flush to display */
1488 dpy_update(s->ds, 0, y_start,
17b0018b 1489 disp_width, y - y_start);
39cf7803 1490 }
e89f66ec
FB
1491 /* reset modified pages */
1492 if (page_max != -1) {
4fa0f5d2 1493 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
e89f66ec 1494 }
a8aa669b 1495 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
e89f66ec
FB
1496}
1497
2aebb3eb
FB
1498static void vga_draw_blank(VGAState *s, int full_update)
1499{
1500 int i, w, val;
1501 uint8_t *d;
1502
1503 if (!full_update)
1504 return;
1505 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1506 return;
1507 if (s->ds->depth == 8)
1508 val = s->rgb_to_pixel(0, 0, 0);
1509 else
1510 val = 0;
1511 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1512 d = s->ds->data;
1513 for(i = 0; i < s->last_scr_height; i++) {
1514 memset(d, val, w);
1515 d += s->ds->linesize;
1516 }
1517 dpy_update(s->ds, 0, 0,
1518 s->last_scr_width, s->last_scr_height);
1519}
1520
1521#define GMODE_TEXT 0
1522#define GMODE_GRAPH 1
1523#define GMODE_BLANK 2
1524
e89f66ec
FB
1525void vga_update_display(void)
1526{
7b17d41e 1527 VGAState *s = vga_state;
e89f66ec
FB
1528 int full_update, graphic_mode;
1529
1530 if (s->ds->depth == 0) {
0f35920c 1531 /* nothing to do */
59a983b9
FB
1532 } else {
1533 switch(s->ds->depth) {
1534 case 8:
1535 s->rgb_to_pixel = rgb_to_pixel8_dup;
1536 break;
1537 case 15:
1538 s->rgb_to_pixel = rgb_to_pixel15_dup;
1539 break;
1540 default:
1541 case 16:
1542 s->rgb_to_pixel = rgb_to_pixel16_dup;
1543 break;
1544 case 32:
1545 s->rgb_to_pixel = rgb_to_pixel32_dup;
1546 break;
1547 }
1548
e89f66ec 1549 full_update = 0;
2aebb3eb
FB
1550 if (!(s->ar_index & 0x20)) {
1551 graphic_mode = GMODE_BLANK;
1552 } else {
1553 graphic_mode = s->gr[6] & 1;
1554 }
e89f66ec
FB
1555 if (graphic_mode != s->graphic_mode) {
1556 s->graphic_mode = graphic_mode;
1557 full_update = 1;
1558 }
2aebb3eb
FB
1559 switch(graphic_mode) {
1560 case GMODE_TEXT:
e89f66ec 1561 vga_draw_text(s, full_update);
2aebb3eb
FB
1562 break;
1563 case GMODE_GRAPH:
1564 vga_draw_graphic(s, full_update);
1565 break;
1566 case GMODE_BLANK:
1567 default:
1568 vga_draw_blank(s, full_update);
1569 break;
1570 }
e89f66ec
FB
1571 }
1572}
1573
a130a41e
FB
1574/* force a full display refresh */
1575void vga_invalidate_display(void)
1576{
1577 VGAState *s = vga_state;
1578
1579 s->last_width = -1;
1580 s->last_height = -1;
1581}
1582
59a983b9 1583static void vga_reset(VGAState *s)
e89f66ec
FB
1584{
1585 memset(s, 0, sizeof(VGAState));
a41bc9af 1586#ifdef CONFIG_S3VGA
e89f66ec
FB
1587 /* chip ID for 8c968 */
1588 s->cr[0x2d] = 0x88;
1589 s->cr[0x2e] = 0xb0;
1590 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1591 s->cr[0x30] = 0xe1;
a41bc9af 1592#endif
e89f66ec
FB
1593 s->graphic_mode = -1; /* force full update */
1594}
1595
59a983b9 1596static CPUReadMemoryFunc *vga_mem_read[3] = {
e89f66ec
FB
1597 vga_mem_readb,
1598 vga_mem_readw,
1599 vga_mem_readl,
1600};
1601
59a983b9 1602static CPUWriteMemoryFunc *vga_mem_write[3] = {
e89f66ec
FB
1603 vga_mem_writeb,
1604 vga_mem_writew,
1605 vga_mem_writel,
1606};
1607
b0a21b53
FB
1608static void vga_save(QEMUFile *f, void *opaque)
1609{
1610 VGAState *s = opaque;
1611 int i;
1612
1613 qemu_put_be32s(f, &s->latch);
1614 qemu_put_8s(f, &s->sr_index);
1615 qemu_put_buffer(f, s->sr, 8);
1616 qemu_put_8s(f, &s->gr_index);
1617 qemu_put_buffer(f, s->gr, 16);
1618 qemu_put_8s(f, &s->ar_index);
1619 qemu_put_buffer(f, s->ar, 21);
1620 qemu_put_be32s(f, &s->ar_flip_flop);
1621 qemu_put_8s(f, &s->cr_index);
1622 qemu_put_buffer(f, s->cr, 256);
1623 qemu_put_8s(f, &s->msr);
1624 qemu_put_8s(f, &s->fcr);
1625 qemu_put_8s(f, &s->st00);
1626 qemu_put_8s(f, &s->st01);
1627
1628 qemu_put_8s(f, &s->dac_state);
1629 qemu_put_8s(f, &s->dac_sub_index);
1630 qemu_put_8s(f, &s->dac_read_index);
1631 qemu_put_8s(f, &s->dac_write_index);
1632 qemu_put_buffer(f, s->dac_cache, 3);
1633 qemu_put_buffer(f, s->palette, 768);
1634
1635 qemu_put_be32s(f, &s->bank_offset);
1636#ifdef CONFIG_BOCHS_VBE
1637 qemu_put_byte(f, 1);
1638 qemu_put_be16s(f, &s->vbe_index);
1639 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1640 qemu_put_be16s(f, &s->vbe_regs[i]);
1641 qemu_put_be32s(f, &s->vbe_start_addr);
1642 qemu_put_be32s(f, &s->vbe_line_offset);
1643 qemu_put_be32s(f, &s->vbe_bank_mask);
1644#else
1645 qemu_put_byte(f, 0);
1646#endif
1647}
1648
1649static int vga_load(QEMUFile *f, void *opaque, int version_id)
1650{
1651 VGAState *s = opaque;
1652 int is_vbe, i;
1653
1654 if (version_id != 1)
1655 return -EINVAL;
1656
1657 qemu_get_be32s(f, &s->latch);
1658 qemu_get_8s(f, &s->sr_index);
1659 qemu_get_buffer(f, s->sr, 8);
1660 qemu_get_8s(f, &s->gr_index);
1661 qemu_get_buffer(f, s->gr, 16);
1662 qemu_get_8s(f, &s->ar_index);
1663 qemu_get_buffer(f, s->ar, 21);
1664 qemu_get_be32s(f, &s->ar_flip_flop);
1665 qemu_get_8s(f, &s->cr_index);
1666 qemu_get_buffer(f, s->cr, 256);
1667 qemu_get_8s(f, &s->msr);
1668 qemu_get_8s(f, &s->fcr);
1669 qemu_get_8s(f, &s->st00);
1670 qemu_get_8s(f, &s->st01);
1671
1672 qemu_get_8s(f, &s->dac_state);
1673 qemu_get_8s(f, &s->dac_sub_index);
1674 qemu_get_8s(f, &s->dac_read_index);
1675 qemu_get_8s(f, &s->dac_write_index);
1676 qemu_get_buffer(f, s->dac_cache, 3);
1677 qemu_get_buffer(f, s->palette, 768);
1678
1679 qemu_get_be32s(f, &s->bank_offset);
1680 is_vbe = qemu_get_byte(f);
1681#ifdef CONFIG_BOCHS_VBE
1682 if (!is_vbe)
1683 return -EINVAL;
1684 qemu_get_be16s(f, &s->vbe_index);
1685 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1686 qemu_get_be16s(f, &s->vbe_regs[i]);
1687 qemu_get_be32s(f, &s->vbe_start_addr);
1688 qemu_get_be32s(f, &s->vbe_line_offset);
1689 qemu_get_be32s(f, &s->vbe_bank_mask);
1690#else
1691 if (is_vbe)
1692 return -EINVAL;
1693#endif
1694
1695 /* force refresh */
1696 s->graphic_mode = -1;
1697 return 0;
1698}
1699
1078f663
FB
1700static void vga_map(PCIDevice *pci_dev, int region_num,
1701 uint32_t addr, uint32_t size, int type)
1702{
7b17d41e 1703 VGAState *s = vga_state;
1078f663
FB
1704
1705 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1706}
1707
798b0c25
FB
1708void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
1709 unsigned long vga_ram_offset, int vga_ram_size)
e89f66ec 1710{
17b0018b 1711 int i, j, v, b;
e89f66ec
FB
1712
1713 for(i = 0;i < 256; i++) {
1714 v = 0;
1715 for(j = 0; j < 8; j++) {
1716 v |= ((i >> j) & 1) << (j * 4);
1717 }
1718 expand4[i] = v;
1719
1720 v = 0;
1721 for(j = 0; j < 4; j++) {
1722 v |= ((i >> (2 * j)) & 3) << (j * 4);
1723 }
1724 expand2[i] = v;
1725 }
17b0018b
FB
1726 for(i = 0; i < 16; i++) {
1727 v = 0;
1728 for(j = 0; j < 4; j++) {
1729 b = ((i >> j) & 1);
1730 v |= b << (2 * j);
1731 v |= b << (2 * j + 1);
1732 }
1733 expand4to8[i] = v;
1734 }
e89f66ec
FB
1735
1736 vga_reset(s);
1737
1738 s->vram_ptr = vga_ram_base;
1739 s->vram_offset = vga_ram_offset;
1740 s->vram_size = vga_ram_size;
1741 s->ds = ds;
798b0c25
FB
1742 s->get_bpp = vga_get_bpp;
1743 s->get_offsets = vga_get_offsets;
a130a41e 1744 s->get_resolution = vga_get_resolution;
7b17d41e
FB
1745 /* XXX: currently needed for display */
1746 vga_state = s;
798b0c25
FB
1747}
1748
1749
1750int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1751 unsigned long vga_ram_offset, int vga_ram_size,
1752 int is_pci)
1753{
7b17d41e
FB
1754 VGAState *s;
1755
1756 s = qemu_mallocz(sizeof(VGAState));
1757 if (!s)
1758 return -1;
798b0c25
FB
1759
1760 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
e89f66ec 1761
b0a21b53
FB
1762 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1763
0f35920c 1764 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
e89f66ec 1765
0f35920c
FB
1766 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1767 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1768 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1769 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
e89f66ec 1770
0f35920c 1771 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
e89f66ec 1772
0f35920c
FB
1773 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1774 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1775 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1776 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
26aa7d72 1777 s->bank_offset = 0;
e89f66ec 1778
4fa0f5d2
FB
1779#ifdef CONFIG_BOCHS_VBE
1780 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
cae61cef 1781 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
09a79b49
FB
1782#if defined (TARGET_I386)
1783 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1784 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
4fa0f5d2 1785
09a79b49
FB
1786 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1787 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
646be93b
FB
1788
1789 /* old Bochs IO ports */
09a79b49
FB
1790 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1791 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
646be93b 1792
09a79b49
FB
1793 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1794 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
1795#else
1796 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1797 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1798
1799 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1800 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
4fa0f5d2 1801#endif
09a79b49 1802#endif /* CONFIG_BOCHS_VBE */
4fa0f5d2 1803
a4193c8a 1804 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
26aa7d72
FB
1805 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1806 vga_io_memory);
1078f663
FB
1807
1808 if (is_pci) {
1809 PCIDevice *d;
1810 uint8_t *pci_conf;
1811
1812 d = pci_register_device("VGA",
1813 sizeof(PCIDevice),
1814 0, -1,
1815 NULL, NULL);
1816 pci_conf = d->config;
1817 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1818 pci_conf[0x01] = 0x12;
1819 pci_conf[0x02] = 0x11;
1820 pci_conf[0x03] = 0x11;
1821 pci_conf[0x0a] = 0x00; // VGA controller
1822 pci_conf[0x0b] = 0x03;
1823 pci_conf[0x0e] = 0x00; // header_type
1824
1825 /* XXX: vga_ram_size must be a power of two */
1826 pci_register_io_region(d, 0, vga_ram_size,
1827 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1828 } else {
4fa0f5d2 1829#ifdef CONFIG_BOCHS_VBE
1078f663
FB
1830 /* XXX: use optimized standard vga accesses */
1831 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1832 vga_ram_size, vga_ram_offset);
7138fcfb 1833#endif
1078f663 1834 }
e89f66ec
FB
1835 return 0;
1836}
59a983b9
FB
1837
1838/********************************************************/
1839/* vga screen dump */
1840
1841static int vga_save_w, vga_save_h;
1842
1843static void vga_save_dpy_update(DisplayState *s,
1844 int x, int y, int w, int h)
1845{
1846}
1847
1848static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1849{
1850 s->linesize = w * 4;
1851 s->data = qemu_malloc(h * s->linesize);
1852 vga_save_w = w;
1853 vga_save_h = h;
1854}
1855
1856static void vga_save_dpy_refresh(DisplayState *s)
1857{
1858}
1859
1860static int ppm_save(const char *filename, uint8_t *data,
1861 int w, int h, int linesize)
1862{
1863 FILE *f;
1864 uint8_t *d, *d1;
1865 unsigned int v;
1866 int y, x;
1867
1868 f = fopen(filename, "wb");
1869 if (!f)
1870 return -1;
1871 fprintf(f, "P6\n%d %d\n%d\n",
1872 w, h, 255);
1873 d1 = data;
1874 for(y = 0; y < h; y++) {
1875 d = d1;
1876 for(x = 0; x < w; x++) {
1877 v = *(uint32_t *)d;
1878 fputc((v >> 16) & 0xff, f);
1879 fputc((v >> 8) & 0xff, f);
1880 fputc((v) & 0xff, f);
1881 d += 4;
1882 }
1883 d1 += linesize;
1884 }
1885 fclose(f);
1886 return 0;
1887}
1888
1889/* save the vga display in a PPM image even if no display is
1890 available */
1891void vga_screen_dump(const char *filename)
1892{
7b17d41e 1893 VGAState *s = vga_state;
59a983b9
FB
1894 DisplayState *saved_ds, ds1, *ds = &ds1;
1895
1896 /* XXX: this is a little hackish */
a130a41e 1897 vga_invalidate_display();
59a983b9
FB
1898 saved_ds = s->ds;
1899
1900 memset(ds, 0, sizeof(DisplayState));
1901 ds->dpy_update = vga_save_dpy_update;
1902 ds->dpy_resize = vga_save_dpy_resize;
1903 ds->dpy_refresh = vga_save_dpy_refresh;
1904 ds->depth = 32;
1905
1906 s->ds = ds;
1907 s->graphic_mode = -1;
1908 vga_update_display();
1909
1910 if (ds->data) {
1911 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
1912 s->ds->linesize);
1913 qemu_free(ds->data);
1914 }
1915 s->ds = saved_ds;
1916}