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