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