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