]> git.proxmox.com Git - qemu.git/blame - hw/vga.c
cygwin host support (Paul Brook)
[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);
0a962c02
FB
1457 update = full_update |
1458 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1459 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
4fa0f5d2 1460 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1461 /* if wide line, can use another page */
0a962c02
FB
1462 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1463 VGA_DIRTY_FLAG);
39cf7803 1464 }
a8aa669b
FB
1465 /* explicit invalidation for the hardware cursor */
1466 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
e89f66ec 1467 if (update) {
39cf7803
FB
1468 if (y_start < 0)
1469 y_start = y;
e89f66ec
FB
1470 if (page0 < page_min)
1471 page_min = page0;
1472 if (page1 > page_max)
1473 page_max = page1;
1474 vga_draw_line(s, d, s->vram_ptr + addr, width);
a8aa669b
FB
1475 if (s->cursor_draw_line)
1476 s->cursor_draw_line(s, d, y);
39cf7803
FB
1477 } else {
1478 if (y_start >= 0) {
1479 /* flush to display */
1480 dpy_update(s->ds, 0, y_start,
17b0018b 1481 disp_width, y - y_start);
39cf7803
FB
1482 y_start = -1;
1483 }
e89f66ec 1484 }
a07cf92a 1485 if (!multi_run) {
f6c958c8
FB
1486 mask = (s->cr[0x17] & 3) ^ 3;
1487 if ((y1 & mask) == mask)
1488 addr1 += line_offset;
1489 y1++;
a07cf92a
FB
1490 multi_run = multi_scan;
1491 } else {
1492 multi_run--;
e89f66ec 1493 }
f6c958c8
FB
1494 /* line compare acts on the displayed lines */
1495 if (y == s->line_compare)
1496 addr1 = 0;
e89f66ec
FB
1497 d += linesize;
1498 }
39cf7803
FB
1499 if (y_start >= 0) {
1500 /* flush to display */
1501 dpy_update(s->ds, 0, y_start,
17b0018b 1502 disp_width, y - y_start);
39cf7803 1503 }
e89f66ec
FB
1504 /* reset modified pages */
1505 if (page_max != -1) {
0a962c02
FB
1506 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1507 VGA_DIRTY_FLAG);
e89f66ec 1508 }
a8aa669b 1509 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
e89f66ec
FB
1510}
1511
2aebb3eb
FB
1512static void vga_draw_blank(VGAState *s, int full_update)
1513{
1514 int i, w, val;
1515 uint8_t *d;
1516
1517 if (!full_update)
1518 return;
1519 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1520 return;
1521 if (s->ds->depth == 8)
1522 val = s->rgb_to_pixel(0, 0, 0);
1523 else
1524 val = 0;
1525 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1526 d = s->ds->data;
1527 for(i = 0; i < s->last_scr_height; i++) {
1528 memset(d, val, w);
1529 d += s->ds->linesize;
1530 }
1531 dpy_update(s->ds, 0, 0,
1532 s->last_scr_width, s->last_scr_height);
1533}
1534
1535#define GMODE_TEXT 0
1536#define GMODE_GRAPH 1
1537#define GMODE_BLANK 2
1538
e89f66ec
FB
1539void vga_update_display(void)
1540{
7b17d41e 1541 VGAState *s = vga_state;
e89f66ec
FB
1542 int full_update, graphic_mode;
1543
1544 if (s->ds->depth == 0) {
0f35920c 1545 /* nothing to do */
59a983b9
FB
1546 } else {
1547 switch(s->ds->depth) {
1548 case 8:
1549 s->rgb_to_pixel = rgb_to_pixel8_dup;
1550 break;
1551 case 15:
1552 s->rgb_to_pixel = rgb_to_pixel15_dup;
1553 break;
1554 default:
1555 case 16:
1556 s->rgb_to_pixel = rgb_to_pixel16_dup;
1557 break;
1558 case 32:
1559 s->rgb_to_pixel = rgb_to_pixel32_dup;
1560 break;
1561 }
1562
e89f66ec 1563 full_update = 0;
2aebb3eb
FB
1564 if (!(s->ar_index & 0x20)) {
1565 graphic_mode = GMODE_BLANK;
1566 } else {
1567 graphic_mode = s->gr[6] & 1;
1568 }
e89f66ec
FB
1569 if (graphic_mode != s->graphic_mode) {
1570 s->graphic_mode = graphic_mode;
1571 full_update = 1;
1572 }
2aebb3eb
FB
1573 switch(graphic_mode) {
1574 case GMODE_TEXT:
e89f66ec 1575 vga_draw_text(s, full_update);
2aebb3eb
FB
1576 break;
1577 case GMODE_GRAPH:
1578 vga_draw_graphic(s, full_update);
1579 break;
1580 case GMODE_BLANK:
1581 default:
1582 vga_draw_blank(s, full_update);
1583 break;
1584 }
e89f66ec
FB
1585 }
1586}
1587
a130a41e
FB
1588/* force a full display refresh */
1589void vga_invalidate_display(void)
1590{
1591 VGAState *s = vga_state;
1592
1593 s->last_width = -1;
1594 s->last_height = -1;
1595}
1596
59a983b9 1597static void vga_reset(VGAState *s)
e89f66ec
FB
1598{
1599 memset(s, 0, sizeof(VGAState));
a41bc9af 1600#ifdef CONFIG_S3VGA
e89f66ec
FB
1601 /* chip ID for 8c968 */
1602 s->cr[0x2d] = 0x88;
1603 s->cr[0x2e] = 0xb0;
1604 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1605 s->cr[0x30] = 0xe1;
a41bc9af 1606#endif
e89f66ec
FB
1607 s->graphic_mode = -1; /* force full update */
1608}
1609
59a983b9 1610static CPUReadMemoryFunc *vga_mem_read[3] = {
e89f66ec
FB
1611 vga_mem_readb,
1612 vga_mem_readw,
1613 vga_mem_readl,
1614};
1615
59a983b9 1616static CPUWriteMemoryFunc *vga_mem_write[3] = {
e89f66ec
FB
1617 vga_mem_writeb,
1618 vga_mem_writew,
1619 vga_mem_writel,
1620};
1621
b0a21b53
FB
1622static void vga_save(QEMUFile *f, void *opaque)
1623{
1624 VGAState *s = opaque;
1625 int i;
1626
1627 qemu_put_be32s(f, &s->latch);
1628 qemu_put_8s(f, &s->sr_index);
1629 qemu_put_buffer(f, s->sr, 8);
1630 qemu_put_8s(f, &s->gr_index);
1631 qemu_put_buffer(f, s->gr, 16);
1632 qemu_put_8s(f, &s->ar_index);
1633 qemu_put_buffer(f, s->ar, 21);
1634 qemu_put_be32s(f, &s->ar_flip_flop);
1635 qemu_put_8s(f, &s->cr_index);
1636 qemu_put_buffer(f, s->cr, 256);
1637 qemu_put_8s(f, &s->msr);
1638 qemu_put_8s(f, &s->fcr);
1639 qemu_put_8s(f, &s->st00);
1640 qemu_put_8s(f, &s->st01);
1641
1642 qemu_put_8s(f, &s->dac_state);
1643 qemu_put_8s(f, &s->dac_sub_index);
1644 qemu_put_8s(f, &s->dac_read_index);
1645 qemu_put_8s(f, &s->dac_write_index);
1646 qemu_put_buffer(f, s->dac_cache, 3);
1647 qemu_put_buffer(f, s->palette, 768);
1648
1649 qemu_put_be32s(f, &s->bank_offset);
1650#ifdef CONFIG_BOCHS_VBE
1651 qemu_put_byte(f, 1);
1652 qemu_put_be16s(f, &s->vbe_index);
1653 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1654 qemu_put_be16s(f, &s->vbe_regs[i]);
1655 qemu_put_be32s(f, &s->vbe_start_addr);
1656 qemu_put_be32s(f, &s->vbe_line_offset);
1657 qemu_put_be32s(f, &s->vbe_bank_mask);
1658#else
1659 qemu_put_byte(f, 0);
1660#endif
1661}
1662
1663static int vga_load(QEMUFile *f, void *opaque, int version_id)
1664{
1665 VGAState *s = opaque;
1666 int is_vbe, i;
1667
1668 if (version_id != 1)
1669 return -EINVAL;
1670
1671 qemu_get_be32s(f, &s->latch);
1672 qemu_get_8s(f, &s->sr_index);
1673 qemu_get_buffer(f, s->sr, 8);
1674 qemu_get_8s(f, &s->gr_index);
1675 qemu_get_buffer(f, s->gr, 16);
1676 qemu_get_8s(f, &s->ar_index);
1677 qemu_get_buffer(f, s->ar, 21);
1678 qemu_get_be32s(f, &s->ar_flip_flop);
1679 qemu_get_8s(f, &s->cr_index);
1680 qemu_get_buffer(f, s->cr, 256);
1681 qemu_get_8s(f, &s->msr);
1682 qemu_get_8s(f, &s->fcr);
1683 qemu_get_8s(f, &s->st00);
1684 qemu_get_8s(f, &s->st01);
1685
1686 qemu_get_8s(f, &s->dac_state);
1687 qemu_get_8s(f, &s->dac_sub_index);
1688 qemu_get_8s(f, &s->dac_read_index);
1689 qemu_get_8s(f, &s->dac_write_index);
1690 qemu_get_buffer(f, s->dac_cache, 3);
1691 qemu_get_buffer(f, s->palette, 768);
1692
1693 qemu_get_be32s(f, &s->bank_offset);
1694 is_vbe = qemu_get_byte(f);
1695#ifdef CONFIG_BOCHS_VBE
1696 if (!is_vbe)
1697 return -EINVAL;
1698 qemu_get_be16s(f, &s->vbe_index);
1699 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1700 qemu_get_be16s(f, &s->vbe_regs[i]);
1701 qemu_get_be32s(f, &s->vbe_start_addr);
1702 qemu_get_be32s(f, &s->vbe_line_offset);
1703 qemu_get_be32s(f, &s->vbe_bank_mask);
1704#else
1705 if (is_vbe)
1706 return -EINVAL;
1707#endif
1708
1709 /* force refresh */
1710 s->graphic_mode = -1;
1711 return 0;
1712}
1713
1078f663
FB
1714static void vga_map(PCIDevice *pci_dev, int region_num,
1715 uint32_t addr, uint32_t size, int type)
1716{
7b17d41e 1717 VGAState *s = vga_state;
1078f663
FB
1718
1719 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1720}
1721
798b0c25
FB
1722void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
1723 unsigned long vga_ram_offset, int vga_ram_size)
e89f66ec 1724{
17b0018b 1725 int i, j, v, b;
e89f66ec
FB
1726
1727 for(i = 0;i < 256; i++) {
1728 v = 0;
1729 for(j = 0; j < 8; j++) {
1730 v |= ((i >> j) & 1) << (j * 4);
1731 }
1732 expand4[i] = v;
1733
1734 v = 0;
1735 for(j = 0; j < 4; j++) {
1736 v |= ((i >> (2 * j)) & 3) << (j * 4);
1737 }
1738 expand2[i] = v;
1739 }
17b0018b
FB
1740 for(i = 0; i < 16; i++) {
1741 v = 0;
1742 for(j = 0; j < 4; j++) {
1743 b = ((i >> j) & 1);
1744 v |= b << (2 * j);
1745 v |= b << (2 * j + 1);
1746 }
1747 expand4to8[i] = v;
1748 }
e89f66ec
FB
1749
1750 vga_reset(s);
1751
1752 s->vram_ptr = vga_ram_base;
1753 s->vram_offset = vga_ram_offset;
1754 s->vram_size = vga_ram_size;
1755 s->ds = ds;
798b0c25
FB
1756 s->get_bpp = vga_get_bpp;
1757 s->get_offsets = vga_get_offsets;
a130a41e 1758 s->get_resolution = vga_get_resolution;
7b17d41e
FB
1759 /* XXX: currently needed for display */
1760 vga_state = s;
798b0c25
FB
1761}
1762
1763
46e50e9d
FB
1764int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
1765 unsigned long vga_ram_offset, int vga_ram_size)
798b0c25 1766{
7b17d41e
FB
1767 VGAState *s;
1768
1769 s = qemu_mallocz(sizeof(VGAState));
1770 if (!s)
1771 return -1;
798b0c25
FB
1772
1773 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
e89f66ec 1774
b0a21b53
FB
1775 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1776
0f35920c 1777 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
e89f66ec 1778
0f35920c
FB
1779 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1780 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1781 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1782 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
e89f66ec 1783
0f35920c 1784 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
e89f66ec 1785
0f35920c
FB
1786 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1787 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1788 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1789 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
26aa7d72 1790 s->bank_offset = 0;
e89f66ec 1791
4fa0f5d2
FB
1792#ifdef CONFIG_BOCHS_VBE
1793 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
cae61cef 1794 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
09a79b49
FB
1795#if defined (TARGET_I386)
1796 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1797 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
4fa0f5d2 1798
09a79b49
FB
1799 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1800 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
646be93b
FB
1801
1802 /* old Bochs IO ports */
09a79b49
FB
1803 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1804 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
646be93b 1805
09a79b49
FB
1806 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1807 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
1808#else
1809 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1810 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1811
1812 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1813 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
4fa0f5d2 1814#endif
09a79b49 1815#endif /* CONFIG_BOCHS_VBE */
4fa0f5d2 1816
a4193c8a 1817 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
26aa7d72
FB
1818 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1819 vga_io_memory);
1078f663 1820
46e50e9d 1821 if (bus) {
1078f663
FB
1822 PCIDevice *d;
1823 uint8_t *pci_conf;
1824
46e50e9d 1825 d = pci_register_device(bus, "VGA",
1078f663 1826 sizeof(PCIDevice),
46e50e9d 1827 -1, NULL, NULL);
1078f663
FB
1828 pci_conf = d->config;
1829 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1830 pci_conf[0x01] = 0x12;
1831 pci_conf[0x02] = 0x11;
1832 pci_conf[0x03] = 0x11;
1833 pci_conf[0x0a] = 0x00; // VGA controller
1834 pci_conf[0x0b] = 0x03;
1835 pci_conf[0x0e] = 0x00; // header_type
1836
1837 /* XXX: vga_ram_size must be a power of two */
1838 pci_register_io_region(d, 0, vga_ram_size,
1839 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1840 } else {
4fa0f5d2 1841#ifdef CONFIG_BOCHS_VBE
1078f663
FB
1842 /* XXX: use optimized standard vga accesses */
1843 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1844 vga_ram_size, vga_ram_offset);
7138fcfb 1845#endif
1078f663 1846 }
e89f66ec
FB
1847 return 0;
1848}
59a983b9
FB
1849
1850/********************************************************/
1851/* vga screen dump */
1852
1853static int vga_save_w, vga_save_h;
1854
1855static void vga_save_dpy_update(DisplayState *s,
1856 int x, int y, int w, int h)
1857{
1858}
1859
1860static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1861{
1862 s->linesize = w * 4;
1863 s->data = qemu_malloc(h * s->linesize);
1864 vga_save_w = w;
1865 vga_save_h = h;
1866}
1867
1868static void vga_save_dpy_refresh(DisplayState *s)
1869{
1870}
1871
1872static int ppm_save(const char *filename, uint8_t *data,
1873 int w, int h, int linesize)
1874{
1875 FILE *f;
1876 uint8_t *d, *d1;
1877 unsigned int v;
1878 int y, x;
1879
1880 f = fopen(filename, "wb");
1881 if (!f)
1882 return -1;
1883 fprintf(f, "P6\n%d %d\n%d\n",
1884 w, h, 255);
1885 d1 = data;
1886 for(y = 0; y < h; y++) {
1887 d = d1;
1888 for(x = 0; x < w; x++) {
1889 v = *(uint32_t *)d;
1890 fputc((v >> 16) & 0xff, f);
1891 fputc((v >> 8) & 0xff, f);
1892 fputc((v) & 0xff, f);
1893 d += 4;
1894 }
1895 d1 += linesize;
1896 }
1897 fclose(f);
1898 return 0;
1899}
1900
1901/* save the vga display in a PPM image even if no display is
1902 available */
1903void vga_screen_dump(const char *filename)
1904{
7b17d41e 1905 VGAState *s = vga_state;
59a983b9
FB
1906 DisplayState *saved_ds, ds1, *ds = &ds1;
1907
1908 /* XXX: this is a little hackish */
a130a41e 1909 vga_invalidate_display();
59a983b9
FB
1910 saved_ds = s->ds;
1911
1912 memset(ds, 0, sizeof(DisplayState));
1913 ds->dpy_update = vga_save_dpy_update;
1914 ds->dpy_resize = vga_save_dpy_resize;
1915 ds->dpy_refresh = vga_save_dpy_refresh;
1916 ds->depth = 32;
1917
1918 s->ds = ds;
1919 s->graphic_mode = -1;
1920 vga_update_display();
1921
1922 if (ds->data) {
1923 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
1924 s->ds->linesize);
1925 qemu_free(ds->data);
1926 }
1927 s->ds = saved_ds;
1928}