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