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