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