]> git.proxmox.com Git - mirror_qemu.git/blame - hw/vga.c
tcg/tcg.h: fix a few typos
[mirror_qemu.git] / hw / vga.c
CommitLineData
e89f66ec 1/*
4fa0f5d2 2 * QEMU VGA Emulator.
5fafdf24 3 *
e89f66ec 4 * Copyright (c) 2003 Fabrice Bellard
5fafdf24 5 *
e89f66ec
FB
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 */
87ecb68b
PB
24#include "hw.h"
25#include "console.h"
26#include "pc.h"
27#include "pci.h"
798b0c25 28#include "vga_int.h"
94470844 29#include "pixel_ops.h"
cb5a7aa8 30#include "qemu-timer.h"
2bec46dc 31#include "kvm.h"
e89f66ec 32
e89f66ec 33//#define DEBUG_VGA
17b0018b 34//#define DEBUG_VGA_MEM
a41bc9af
FB
35//#define DEBUG_VGA_REG
36
4fa0f5d2
FB
37//#define DEBUG_BOCHS_VBE
38
9586fefe
AL
39#define GMODE_TEXT 0
40#define GMODE_GRAPH 1
41#define GMODE_BLANK 2
42
e89f66ec 43/* force some bits to zero */
798b0c25 44const uint8_t sr_mask[8] = {
9e622b15
BS
45 0x03,
46 0x3d,
47 0x0f,
48 0x3f,
49 0x0e,
50 0x00,
51 0x00,
52 0xff,
e89f66ec
FB
53};
54
798b0c25 55const uint8_t gr_mask[16] = {
9e622b15
BS
56 0x0f, /* 0x00 */
57 0x0f, /* 0x01 */
58 0x0f, /* 0x02 */
59 0x1f, /* 0x03 */
60 0x03, /* 0x04 */
61 0x7b, /* 0x05 */
62 0x0f, /* 0x06 */
63 0x0f, /* 0x07 */
64 0xff, /* 0x08 */
65 0x00, /* 0x09 */
66 0x00, /* 0x0a */
67 0x00, /* 0x0b */
68 0x00, /* 0x0c */
69 0x00, /* 0x0d */
70 0x00, /* 0x0e */
71 0x00, /* 0x0f */
e89f66ec
FB
72};
73
74#define cbswap_32(__x) \
75((uint32_t)( \
76 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
77 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
78 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
79 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
80
b8ed223b 81#ifdef WORDS_BIGENDIAN
e89f66ec
FB
82#define PAT(x) cbswap_32(x)
83#else
84#define PAT(x) (x)
85#endif
86
b8ed223b
FB
87#ifdef WORDS_BIGENDIAN
88#define BIG 1
89#else
90#define BIG 0
91#endif
92
93#ifdef WORDS_BIGENDIAN
94#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
95#else
96#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
97#endif
98
e89f66ec
FB
99static const uint32_t mask16[16] = {
100 PAT(0x00000000),
101 PAT(0x000000ff),
102 PAT(0x0000ff00),
103 PAT(0x0000ffff),
104 PAT(0x00ff0000),
105 PAT(0x00ff00ff),
106 PAT(0x00ffff00),
107 PAT(0x00ffffff),
108 PAT(0xff000000),
109 PAT(0xff0000ff),
110 PAT(0xff00ff00),
111 PAT(0xff00ffff),
112 PAT(0xffff0000),
113 PAT(0xffff00ff),
114 PAT(0xffffff00),
115 PAT(0xffffffff),
116};
117
118#undef PAT
119
b8ed223b 120#ifdef WORDS_BIGENDIAN
e89f66ec
FB
121#define PAT(x) (x)
122#else
123#define PAT(x) cbswap_32(x)
124#endif
125
126static const uint32_t dmask16[16] = {
127 PAT(0x00000000),
128 PAT(0x000000ff),
129 PAT(0x0000ff00),
130 PAT(0x0000ffff),
131 PAT(0x00ff0000),
132 PAT(0x00ff00ff),
133 PAT(0x00ffff00),
134 PAT(0x00ffffff),
135 PAT(0xff000000),
136 PAT(0xff0000ff),
137 PAT(0xff00ff00),
138 PAT(0xff00ffff),
139 PAT(0xffff0000),
140 PAT(0xffff00ff),
141 PAT(0xffffff00),
142 PAT(0xffffffff),
143};
144
145static const uint32_t dmask4[4] = {
146 PAT(0x00000000),
147 PAT(0x0000ffff),
148 PAT(0xffff0000),
149 PAT(0xffffffff),
150};
151
152static uint32_t expand4[256];
153static uint16_t expand2[256];
17b0018b 154static uint8_t expand4to8[16];
e89f66ec 155
95219897
PB
156static void vga_screen_dump(void *opaque, const char *filename);
157
cb5a7aa8 158static void vga_dumb_update_retrace_info(VGAState *s)
159{
160 (void) s;
161}
162
163static void vga_precise_update_retrace_info(VGAState *s)
164{
165 int htotal_chars;
166 int hretr_start_char;
167 int hretr_skew_chars;
168 int hretr_end_char;
169
170 int vtotal_lines;
171 int vretr_start_line;
172 int vretr_end_line;
173
174 int div2, sldiv2, dots;
175 int clocking_mode;
176 int clock_sel;
b0f74c87 177 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
cb5a7aa8 178 int64_t chars_per_sec;
179 struct vga_precise_retrace *r = &s->retrace_info.precise;
180
181 htotal_chars = s->cr[0x00] + 5;
182 hretr_start_char = s->cr[0x04];
183 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
184 hretr_end_char = s->cr[0x05] & 0x1f;
185
186 vtotal_lines = (s->cr[0x06]
187 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
188 ;
189 vretr_start_line = s->cr[0x10]
190 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
191 ;
192 vretr_end_line = s->cr[0x11] & 0xf;
193
194
195 div2 = (s->cr[0x17] >> 2) & 1;
196 sldiv2 = (s->cr[0x17] >> 3) & 1;
197
198 clocking_mode = (s->sr[0x01] >> 3) & 1;
199 clock_sel = (s->msr >> 2) & 3;
f87fc09b 200 dots = (s->msr & 1) ? 8 : 9;
cb5a7aa8 201
b0f74c87 202 chars_per_sec = clk_hz[clock_sel] / dots;
cb5a7aa8 203
204 htotal_chars <<= clocking_mode;
205
206 r->total_chars = vtotal_lines * htotal_chars;
cb5a7aa8 207 if (r->freq) {
208 r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
209 } else {
210 r->ticks_per_char = ticks_per_sec / chars_per_sec;
211 }
212
213 r->vstart = vretr_start_line;
214 r->vend = r->vstart + vretr_end_line + 1;
215
216 r->hstart = hretr_start_char + hretr_skew_chars;
217 r->hend = r->hstart + hretr_end_char + 1;
218 r->htotal = htotal_chars;
219
f87fc09b 220#if 0
cb5a7aa8 221 printf (
f87fc09b 222 "hz=%f\n"
cb5a7aa8 223 "htotal = %d\n"
224 "hretr_start = %d\n"
225 "hretr_skew = %d\n"
226 "hretr_end = %d\n"
227 "vtotal = %d\n"
228 "vretr_start = %d\n"
229 "vretr_end = %d\n"
230 "div2 = %d sldiv2 = %d\n"
231 "clocking_mode = %d\n"
232 "clock_sel = %d %d\n"
233 "dots = %d\n"
234 "ticks/char = %lld\n"
235 "\n",
f87fc09b 236 (double) ticks_per_sec / (r->ticks_per_char * r->total_chars),
cb5a7aa8 237 htotal_chars,
238 hretr_start_char,
239 hretr_skew_chars,
240 hretr_end_char,
241 vtotal_lines,
242 vretr_start_line,
243 vretr_end_line,
244 div2, sldiv2,
245 clocking_mode,
246 clock_sel,
b0f74c87 247 clk_hz[clock_sel],
cb5a7aa8 248 dots,
249 r->ticks_per_char
250 );
251#endif
252}
253
254static uint8_t vga_precise_retrace(VGAState *s)
255{
256 struct vga_precise_retrace *r = &s->retrace_info.precise;
257 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
258
259 if (r->total_chars) {
260 int cur_line, cur_line_char, cur_char;
261 int64_t cur_tick;
262
263 cur_tick = qemu_get_clock(vm_clock);
264
265 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
266 cur_line = cur_char / r->htotal;
267
268 if (cur_line >= r->vstart && cur_line <= r->vend) {
269 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
f87fc09b 270 } else {
271 cur_line_char = cur_char % r->htotal;
272 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
273 val |= ST01_DISP_ENABLE;
274 }
cb5a7aa8 275 }
276
277 return val;
278 } else {
279 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
280 }
281}
282
283static uint8_t vga_dumb_retrace(VGAState *s)
284{
285 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
286}
287
0f35920c 288static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
e89f66ec 289{
0f35920c 290 VGAState *s = opaque;
e89f66ec
FB
291 int val, index;
292
293 /* check port range access depending on color/monochrome mode */
294 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
295 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
296 val = 0xff;
297 } else {
298 switch(addr) {
299 case 0x3c0:
300 if (s->ar_flip_flop == 0) {
301 val = s->ar_index;
302 } else {
303 val = 0;
304 }
305 break;
306 case 0x3c1:
307 index = s->ar_index & 0x1f;
5fafdf24 308 if (index < 21)
e89f66ec
FB
309 val = s->ar[index];
310 else
311 val = 0;
312 break;
313 case 0x3c2:
314 val = s->st00;
315 break;
316 case 0x3c4:
317 val = s->sr_index;
318 break;
319 case 0x3c5:
320 val = s->sr[s->sr_index];
a41bc9af
FB
321#ifdef DEBUG_VGA_REG
322 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
323#endif
e89f66ec
FB
324 break;
325 case 0x3c7:
326 val = s->dac_state;
327 break;
e6eccb38
FB
328 case 0x3c8:
329 val = s->dac_write_index;
330 break;
e89f66ec
FB
331 case 0x3c9:
332 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
333 if (++s->dac_sub_index == 3) {
334 s->dac_sub_index = 0;
335 s->dac_read_index++;
336 }
337 break;
338 case 0x3ca:
339 val = s->fcr;
340 break;
341 case 0x3cc:
342 val = s->msr;
343 break;
344 case 0x3ce:
345 val = s->gr_index;
346 break;
347 case 0x3cf:
348 val = s->gr[s->gr_index];
a41bc9af
FB
349#ifdef DEBUG_VGA_REG
350 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
351#endif
e89f66ec
FB
352 break;
353 case 0x3b4:
354 case 0x3d4:
355 val = s->cr_index;
356 break;
357 case 0x3b5:
358 case 0x3d5:
359 val = s->cr[s->cr_index];
a41bc9af
FB
360#ifdef DEBUG_VGA_REG
361 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
a41bc9af 362#endif
e89f66ec
FB
363 break;
364 case 0x3ba:
365 case 0x3da:
366 /* just toggle to fool polling */
cb5a7aa8 367 val = s->st01 = s->retrace(s);
e89f66ec
FB
368 s->ar_flip_flop = 0;
369 break;
370 default:
371 val = 0x00;
372 break;
373 }
374 }
4fa0f5d2 375#if defined(DEBUG_VGA)
e89f66ec
FB
376 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
377#endif
378 return val;
379}
380
0f35920c 381static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
e89f66ec 382{
0f35920c 383 VGAState *s = opaque;
5467a722 384 int index;
e89f66ec
FB
385
386 /* check port range access depending on color/monochrome mode */
387 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
388 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
389 return;
390
391#ifdef DEBUG_VGA
392 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
393#endif
394
395 switch(addr) {
396 case 0x3c0:
397 if (s->ar_flip_flop == 0) {
398 val &= 0x3f;
399 s->ar_index = val;
9586fefe 400 vga_update_resolution(s);
e89f66ec
FB
401 } else {
402 index = s->ar_index & 0x1f;
403 switch(index) {
404 case 0x00 ... 0x0f:
405 s->ar[index] = val & 0x3f;
406 break;
407 case 0x10:
408 s->ar[index] = val & ~0x10;
409 break;
410 case 0x11:
411 s->ar[index] = val;
412 break;
413 case 0x12:
414 s->ar[index] = val & ~0xc0;
415 break;
416 case 0x13:
417 s->ar[index] = val & ~0xf0;
418 break;
419 case 0x14:
420 s->ar[index] = val & ~0xf0;
421 break;
422 default:
423 break;
424 }
425 }
426 s->ar_flip_flop ^= 1;
427 break;
428 case 0x3c2:
429 s->msr = val & ~0x10;
cb5a7aa8 430 s->update_retrace_info(s);
e89f66ec
FB
431 break;
432 case 0x3c4:
433 s->sr_index = val & 7;
434 break;
435 case 0x3c5:
a41bc9af
FB
436#ifdef DEBUG_VGA_REG
437 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
438#endif
e89f66ec 439 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
cb5a7aa8 440 if (s->sr_index == 1) s->update_retrace_info(s);
9586fefe 441 vga_update_resolution(s);
e89f66ec
FB
442 break;
443 case 0x3c7:
444 s->dac_read_index = val;
445 s->dac_sub_index = 0;
446 s->dac_state = 3;
447 break;
448 case 0x3c8:
449 s->dac_write_index = val;
450 s->dac_sub_index = 0;
451 s->dac_state = 0;
452 break;
453 case 0x3c9:
454 s->dac_cache[s->dac_sub_index] = val;
455 if (++s->dac_sub_index == 3) {
456 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
457 s->dac_sub_index = 0;
458 s->dac_write_index++;
459 }
460 break;
461 case 0x3ce:
462 s->gr_index = val & 0x0f;
463 break;
464 case 0x3cf:
a41bc9af
FB
465#ifdef DEBUG_VGA_REG
466 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
467#endif
e89f66ec 468 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
9586fefe 469 vga_update_resolution(s);
e89f66ec
FB
470 break;
471 case 0x3b4:
472 case 0x3d4:
473 s->cr_index = val;
474 break;
475 case 0x3b5:
476 case 0x3d5:
a41bc9af
FB
477#ifdef DEBUG_VGA_REG
478 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
479#endif
e89f66ec 480 /* handle CR0-7 protection */
f6c958c8 481 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
e89f66ec
FB
482 /* can always write bit 4 of CR7 */
483 if (s->cr_index == 7)
484 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
9586fefe 485 vga_update_resolution(s);
e89f66ec
FB
486 return;
487 }
488 switch(s->cr_index) {
489 case 0x01: /* horizontal display end */
490 case 0x07:
491 case 0x09:
492 case 0x0c:
493 case 0x0d:
e91c8a77 494 case 0x12: /* vertical display end */
e89f66ec
FB
495 s->cr[s->cr_index] = val;
496 break;
e89f66ec
FB
497 default:
498 s->cr[s->cr_index] = val;
499 break;
500 }
cb5a7aa8 501
502 switch(s->cr_index) {
503 case 0x00:
504 case 0x04:
505 case 0x05:
506 case 0x06:
507 case 0x07:
508 case 0x11:
509 case 0x17:
510 s->update_retrace_info(s);
511 break;
512 }
9586fefe 513 vga_update_resolution(s);
e89f66ec
FB
514 break;
515 case 0x3ba:
516 case 0x3da:
517 s->fcr = val & 0x10;
518 break;
519 }
520}
521
4fa0f5d2 522#ifdef CONFIG_BOCHS_VBE
09a79b49 523static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
4fa0f5d2 524{
0f35920c 525 VGAState *s = opaque;
4fa0f5d2 526 uint32_t val;
09a79b49
FB
527 val = s->vbe_index;
528 return val;
529}
4fa0f5d2 530
09a79b49
FB
531static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
532{
533 VGAState *s = opaque;
534 uint32_t val;
535
8454df8b
FB
536 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
537 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
538 switch(s->vbe_index) {
539 /* XXX: do not hardcode ? */
540 case VBE_DISPI_INDEX_XRES:
541 val = VBE_DISPI_MAX_XRES;
542 break;
543 case VBE_DISPI_INDEX_YRES:
544 val = VBE_DISPI_MAX_YRES;
545 break;
546 case VBE_DISPI_INDEX_BPP:
547 val = VBE_DISPI_MAX_BPP;
548 break;
549 default:
5fafdf24 550 val = s->vbe_regs[s->vbe_index];
8454df8b
FB
551 break;
552 }
553 } else {
5fafdf24 554 val = s->vbe_regs[s->vbe_index];
8454df8b
FB
555 }
556 } else {
09a79b49 557 val = 0;
8454df8b 558 }
4fa0f5d2 559#ifdef DEBUG_BOCHS_VBE
09a79b49 560 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
4fa0f5d2 561#endif
4fa0f5d2
FB
562 return val;
563}
564
09a79b49
FB
565static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
566{
567 VGAState *s = opaque;
568 s->vbe_index = val;
569}
570
571static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
4fa0f5d2 572{
0f35920c 573 VGAState *s = opaque;
4fa0f5d2 574
09a79b49 575 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
4fa0f5d2
FB
576#ifdef DEBUG_BOCHS_VBE
577 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
578#endif
579 switch(s->vbe_index) {
580 case VBE_DISPI_INDEX_ID:
cae61cef
FB
581 if (val == VBE_DISPI_ID0 ||
582 val == VBE_DISPI_ID1 ||
37dd208d
FB
583 val == VBE_DISPI_ID2 ||
584 val == VBE_DISPI_ID3 ||
585 val == VBE_DISPI_ID4) {
cae61cef
FB
586 s->vbe_regs[s->vbe_index] = val;
587 }
4fa0f5d2
FB
588 break;
589 case VBE_DISPI_INDEX_XRES:
cae61cef
FB
590 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
591 s->vbe_regs[s->vbe_index] = val;
592 }
9586fefe 593 vga_update_resolution(s);
4fa0f5d2
FB
594 break;
595 case VBE_DISPI_INDEX_YRES:
cae61cef
FB
596 if (val <= VBE_DISPI_MAX_YRES) {
597 s->vbe_regs[s->vbe_index] = val;
598 }
9586fefe 599 vga_update_resolution(s);
4fa0f5d2
FB
600 break;
601 case VBE_DISPI_INDEX_BPP:
602 if (val == 0)
603 val = 8;
5fafdf24 604 if (val == 4 || val == 8 || val == 15 ||
cae61cef
FB
605 val == 16 || val == 24 || val == 32) {
606 s->vbe_regs[s->vbe_index] = val;
607 }
9586fefe 608 vga_update_resolution(s);
4fa0f5d2
FB
609 break;
610 case VBE_DISPI_INDEX_BANK:
42fc925e
FB
611 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
612 val &= (s->vbe_bank_mask >> 2);
613 } else {
614 val &= s->vbe_bank_mask;
615 }
cae61cef 616 s->vbe_regs[s->vbe_index] = val;
26aa7d72 617 s->bank_offset = (val << 16);
4fa0f5d2
FB
618 break;
619 case VBE_DISPI_INDEX_ENABLE:
8454df8b
FB
620 if ((val & VBE_DISPI_ENABLED) &&
621 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
4fa0f5d2
FB
622 int h, shift_control;
623
5fafdf24 624 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
4fa0f5d2 625 s->vbe_regs[VBE_DISPI_INDEX_XRES];
5fafdf24 626 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
4fa0f5d2
FB
627 s->vbe_regs[VBE_DISPI_INDEX_YRES];
628 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
629 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
3b46e624 630
4fa0f5d2
FB
631 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
632 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
633 else
5fafdf24 634 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
4fa0f5d2
FB
635 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
636 s->vbe_start_addr = 0;
8454df8b 637
4fa0f5d2
FB
638 /* clear the screen (should be done in BIOS) */
639 if (!(val & VBE_DISPI_NOCLEARMEM)) {
5fafdf24 640 memset(s->vram_ptr, 0,
4fa0f5d2
FB
641 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
642 }
3b46e624 643
cae61cef
FB
644 /* we initialize the VGA graphic mode (should be done
645 in BIOS) */
646 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
4fa0f5d2
FB
647 s->cr[0x17] |= 3; /* no CGA modes */
648 s->cr[0x13] = s->vbe_line_offset >> 3;
649 /* width */
650 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
8454df8b 651 /* height (only meaningful if < 1024) */
4fa0f5d2
FB
652 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
653 s->cr[0x12] = h;
5fafdf24 654 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
4fa0f5d2
FB
655 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
656 /* line compare to 1023 */
657 s->cr[0x18] = 0xff;
658 s->cr[0x07] |= 0x10;
659 s->cr[0x09] |= 0x40;
3b46e624 660
4fa0f5d2
FB
661 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
662 shift_control = 0;
663 s->sr[0x01] &= ~8; /* no double line */
664 } else {
665 shift_control = 2;
646be93b 666 s->sr[4] |= 0x08; /* set chain 4 mode */
141253b2 667 s->sr[2] |= 0x0f; /* activate all planes */
4fa0f5d2
FB
668 }
669 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
670 s->cr[0x09] &= ~0x9f; /* no double scan */
cae61cef
FB
671 } else {
672 /* XXX: the bios should do that */
26aa7d72 673 s->bank_offset = 0;
cae61cef 674 }
37dd208d 675 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
141253b2 676 s->vbe_regs[s->vbe_index] = val;
9586fefe 677 vga_update_resolution(s);
cae61cef
FB
678 break;
679 case VBE_DISPI_INDEX_VIRT_WIDTH:
680 {
681 int w, h, line_offset;
682
683 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
684 return;
685 w = val;
686 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
687 line_offset = w >> 1;
688 else
689 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
690 h = s->vram_size / line_offset;
691 /* XXX: support weird bochs semantics ? */
692 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
693 return;
694 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
695 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
696 s->vbe_line_offset = line_offset;
697 }
9586fefe 698 vga_update_resolution(s);
cae61cef
FB
699 break;
700 case VBE_DISPI_INDEX_X_OFFSET:
701 case VBE_DISPI_INDEX_Y_OFFSET:
702 {
703 int x;
704 s->vbe_regs[s->vbe_index] = val;
705 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
706 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
707 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
708 s->vbe_start_addr += x >> 1;
709 else
710 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
711 s->vbe_start_addr >>= 2;
4fa0f5d2 712 }
9586fefe 713 vga_update_resolution(s);
4fa0f5d2
FB
714 break;
715 default:
716 break;
717 }
4fa0f5d2
FB
718 }
719}
720#endif
721
e89f66ec 722/* called for accesses between 0xa0000 and 0xc0000 */
798b0c25 723uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
e89f66ec 724{
a4193c8a 725 VGAState *s = opaque;
e89f66ec
FB
726 int memory_map_mode, plane;
727 uint32_t ret;
3b46e624 728
e89f66ec
FB
729 /* convert to VGA memory offset */
730 memory_map_mode = (s->gr[6] >> 2) & 3;
26aa7d72 731 addr &= 0x1ffff;
e89f66ec
FB
732 switch(memory_map_mode) {
733 case 0:
e89f66ec
FB
734 break;
735 case 1:
26aa7d72 736 if (addr >= 0x10000)
e89f66ec 737 return 0xff;
cae61cef 738 addr += s->bank_offset;
e89f66ec
FB
739 break;
740 case 2:
26aa7d72 741 addr -= 0x10000;
e89f66ec
FB
742 if (addr >= 0x8000)
743 return 0xff;
744 break;
745 default:
746 case 3:
26aa7d72 747 addr -= 0x18000;
c92b2e84
FB
748 if (addr >= 0x8000)
749 return 0xff;
e89f66ec
FB
750 break;
751 }
3b46e624 752
e89f66ec
FB
753 if (s->sr[4] & 0x08) {
754 /* chain 4 mode : simplest access */
755 ret = s->vram_ptr[addr];
756 } else if (s->gr[5] & 0x10) {
757 /* odd/even mode (aka text mode mapping) */
758 plane = (s->gr[4] & 2) | (addr & 1);
759 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
760 } else {
761 /* standard VGA latched access */
762 s->latch = ((uint32_t *)s->vram_ptr)[addr];
763
764 if (!(s->gr[5] & 0x08)) {
765 /* read mode 0 */
766 plane = s->gr[4];
b8ed223b 767 ret = GET_PLANE(s->latch, plane);
e89f66ec
FB
768 } else {
769 /* read mode 1 */
770 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
771 ret |= ret >> 16;
772 ret |= ret >> 8;
773 ret = (~ret) & 0xff;
774 }
775 }
776 return ret;
777}
778
a4193c8a 779static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
e89f66ec
FB
780{
781 uint32_t v;
09a79b49 782#ifdef TARGET_WORDS_BIGENDIAN
a4193c8a
FB
783 v = vga_mem_readb(opaque, addr) << 8;
784 v |= vga_mem_readb(opaque, addr + 1);
09a79b49 785#else
a4193c8a
FB
786 v = vga_mem_readb(opaque, addr);
787 v |= vga_mem_readb(opaque, addr + 1) << 8;
09a79b49 788#endif
e89f66ec
FB
789 return v;
790}
791
a4193c8a 792static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
e89f66ec
FB
793{
794 uint32_t v;
09a79b49 795#ifdef TARGET_WORDS_BIGENDIAN
a4193c8a
FB
796 v = vga_mem_readb(opaque, addr) << 24;
797 v |= vga_mem_readb(opaque, addr + 1) << 16;
798 v |= vga_mem_readb(opaque, addr + 2) << 8;
799 v |= vga_mem_readb(opaque, addr + 3);
09a79b49 800#else
a4193c8a
FB
801 v = vga_mem_readb(opaque, addr);
802 v |= vga_mem_readb(opaque, addr + 1) << 8;
803 v |= vga_mem_readb(opaque, addr + 2) << 16;
804 v |= vga_mem_readb(opaque, addr + 3) << 24;
09a79b49 805#endif
e89f66ec
FB
806 return v;
807}
808
e89f66ec 809/* called for accesses between 0xa0000 and 0xc0000 */
798b0c25 810void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
e89f66ec 811{
a4193c8a 812 VGAState *s = opaque;
546fa6ab 813 int memory_map_mode, plane, write_mode, b, func_select, mask;
e89f66ec
FB
814 uint32_t write_mask, bit_mask, set_mask;
815
17b0018b 816#ifdef DEBUG_VGA_MEM
e89f66ec
FB
817 printf("vga: [0x%x] = 0x%02x\n", addr, val);
818#endif
819 /* convert to VGA memory offset */
820 memory_map_mode = (s->gr[6] >> 2) & 3;
26aa7d72 821 addr &= 0x1ffff;
e89f66ec
FB
822 switch(memory_map_mode) {
823 case 0:
e89f66ec
FB
824 break;
825 case 1:
26aa7d72 826 if (addr >= 0x10000)
e89f66ec 827 return;
cae61cef 828 addr += s->bank_offset;
e89f66ec
FB
829 break;
830 case 2:
26aa7d72 831 addr -= 0x10000;
e89f66ec
FB
832 if (addr >= 0x8000)
833 return;
834 break;
835 default:
836 case 3:
26aa7d72 837 addr -= 0x18000;
c92b2e84
FB
838 if (addr >= 0x8000)
839 return;
e89f66ec
FB
840 break;
841 }
3b46e624 842
e89f66ec
FB
843 if (s->sr[4] & 0x08) {
844 /* chain 4 mode : simplest access */
845 plane = addr & 3;
546fa6ab
FB
846 mask = (1 << plane);
847 if (s->sr[2] & mask) {
e89f66ec 848 s->vram_ptr[addr] = val;
17b0018b 849#ifdef DEBUG_VGA_MEM
e89f66ec
FB
850 printf("vga: chain4: [0x%x]\n", addr);
851#endif
546fa6ab 852 s->plane_updated |= mask; /* only used to detect font change */
4fa0f5d2 853 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
854 }
855 } else if (s->gr[5] & 0x10) {
856 /* odd/even mode (aka text mode mapping) */
857 plane = (s->gr[4] & 2) | (addr & 1);
546fa6ab
FB
858 mask = (1 << plane);
859 if (s->sr[2] & mask) {
e89f66ec
FB
860 addr = ((addr & ~1) << 1) | plane;
861 s->vram_ptr[addr] = val;
17b0018b 862#ifdef DEBUG_VGA_MEM
e89f66ec
FB
863 printf("vga: odd/even: [0x%x]\n", addr);
864#endif
546fa6ab 865 s->plane_updated |= mask; /* only used to detect font change */
4fa0f5d2 866 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
867 }
868 } else {
869 /* standard VGA latched access */
870 write_mode = s->gr[5] & 3;
871 switch(write_mode) {
872 default:
873 case 0:
874 /* rotate */
875 b = s->gr[3] & 7;
876 val = ((val >> b) | (val << (8 - b))) & 0xff;
877 val |= val << 8;
878 val |= val << 16;
879
880 /* apply set/reset mask */
881 set_mask = mask16[s->gr[1]];
882 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
883 bit_mask = s->gr[8];
884 break;
885 case 1:
886 val = s->latch;
887 goto do_write;
888 case 2:
889 val = mask16[val & 0x0f];
890 bit_mask = s->gr[8];
891 break;
892 case 3:
893 /* rotate */
894 b = s->gr[3] & 7;
a41bc9af 895 val = (val >> b) | (val << (8 - b));
e89f66ec
FB
896
897 bit_mask = s->gr[8] & val;
898 val = mask16[s->gr[0]];
899 break;
900 }
901
902 /* apply logical operation */
903 func_select = s->gr[3] >> 3;
904 switch(func_select) {
905 case 0:
906 default:
907 /* nothing to do */
908 break;
909 case 1:
910 /* and */
911 val &= s->latch;
912 break;
913 case 2:
914 /* or */
915 val |= s->latch;
916 break;
917 case 3:
918 /* xor */
919 val ^= s->latch;
920 break;
921 }
922
923 /* apply bit mask */
924 bit_mask |= bit_mask << 8;
925 bit_mask |= bit_mask << 16;
926 val = (val & bit_mask) | (s->latch & ~bit_mask);
927
928 do_write:
929 /* mask data according to sr[2] */
546fa6ab
FB
930 mask = s->sr[2];
931 s->plane_updated |= mask; /* only used to detect font change */
932 write_mask = mask16[mask];
5fafdf24
TS
933 ((uint32_t *)s->vram_ptr)[addr] =
934 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
e89f66ec 935 (val & write_mask);
17b0018b 936#ifdef DEBUG_VGA_MEM
5fafdf24 937 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
e89f66ec
FB
938 addr * 4, write_mask, val);
939#endif
4fa0f5d2 940 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
e89f66ec
FB
941 }
942}
943
a4193c8a 944static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
e89f66ec 945{
09a79b49 946#ifdef TARGET_WORDS_BIGENDIAN
a4193c8a
FB
947 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
948 vga_mem_writeb(opaque, addr + 1, val & 0xff);
09a79b49 949#else
a4193c8a
FB
950 vga_mem_writeb(opaque, addr, val & 0xff);
951 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
09a79b49 952#endif
e89f66ec
FB
953}
954
a4193c8a 955static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
e89f66ec 956{
09a79b49 957#ifdef TARGET_WORDS_BIGENDIAN
a4193c8a
FB
958 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
959 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
960 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
961 vga_mem_writeb(opaque, addr + 3, val & 0xff);
09a79b49 962#else
a4193c8a
FB
963 vga_mem_writeb(opaque, addr, val & 0xff);
964 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
965 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
966 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
09a79b49 967#endif
e89f66ec
FB
968}
969
e89f66ec
FB
970typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
971 const uint8_t *font_ptr, int h,
972 uint32_t fgcol, uint32_t bgcol);
973typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
5fafdf24 974 const uint8_t *font_ptr, int h,
e89f66ec 975 uint32_t fgcol, uint32_t bgcol, int dup9);
5fafdf24 976typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
e89f66ec
FB
977 const uint8_t *s, int width);
978
e89f66ec
FB
979#define DEPTH 8
980#include "vga_template.h"
981
982#define DEPTH 15
983#include "vga_template.h"
984
a2502b58
BS
985#define BGR_FORMAT
986#define DEPTH 15
987#include "vga_template.h"
988
989#define DEPTH 16
990#include "vga_template.h"
991
992#define BGR_FORMAT
e89f66ec
FB
993#define DEPTH 16
994#include "vga_template.h"
995
996#define DEPTH 32
997#include "vga_template.h"
998
d3079cd2
FB
999#define BGR_FORMAT
1000#define DEPTH 32
1001#include "vga_template.h"
1002
17b0018b
FB
1003static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
1004{
1005 unsigned int col;
1006 col = rgb_to_pixel8(r, g, b);
1007 col |= col << 8;
1008 col |= col << 16;
1009 return col;
1010}
1011
1012static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
1013{
1014 unsigned int col;
1015 col = rgb_to_pixel15(r, g, b);
1016 col |= col << 16;
1017 return col;
1018}
1019
b29169d2
BS
1020static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
1021 unsigned int b)
1022{
1023 unsigned int col;
1024 col = rgb_to_pixel15bgr(r, g, b);
1025 col |= col << 16;
1026 return col;
1027}
1028
17b0018b
FB
1029static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1030{
1031 unsigned int col;
1032 col = rgb_to_pixel16(r, g, b);
1033 col |= col << 16;
1034 return col;
1035}
1036
b29169d2
BS
1037static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1038 unsigned int b)
1039{
1040 unsigned int col;
1041 col = rgb_to_pixel16bgr(r, g, b);
1042 col |= col << 16;
1043 return col;
1044}
1045
17b0018b
FB
1046static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1047{
1048 unsigned int col;
1049 col = rgb_to_pixel32(r, g, b);
1050 return col;
1051}
1052
d3079cd2
FB
1053static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1054{
1055 unsigned int col;
1056 col = rgb_to_pixel32bgr(r, g, b);
1057 return col;
1058}
1059
e89f66ec
FB
1060/* return true if the palette was modified */
1061static int update_palette16(VGAState *s)
1062{
17b0018b 1063 int full_update, i;
e89f66ec 1064 uint32_t v, col, *palette;
e89f66ec
FB
1065
1066 full_update = 0;
1067 palette = s->last_palette;
1068 for(i = 0; i < 16; i++) {
1069 v = s->ar[i];
1070 if (s->ar[0x10] & 0x80)
1071 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1072 else
1073 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1074 v = v * 3;
5fafdf24
TS
1075 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1076 c6_to_8(s->palette[v + 1]),
17b0018b
FB
1077 c6_to_8(s->palette[v + 2]));
1078 if (col != palette[i]) {
1079 full_update = 1;
1080 palette[i] = col;
e89f66ec 1081 }
17b0018b
FB
1082 }
1083 return full_update;
1084}
1085
1086/* return true if the palette was modified */
1087static int update_palette256(VGAState *s)
1088{
1089 int full_update, i;
1090 uint32_t v, col, *palette;
1091
1092 full_update = 0;
1093 palette = s->last_palette;
1094 v = 0;
1095 for(i = 0; i < 256; i++) {
37dd208d 1096 if (s->dac_8bit) {
5fafdf24
TS
1097 col = s->rgb_to_pixel(s->palette[v],
1098 s->palette[v + 1],
37dd208d
FB
1099 s->palette[v + 2]);
1100 } else {
5fafdf24
TS
1101 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1102 c6_to_8(s->palette[v + 1]),
37dd208d
FB
1103 c6_to_8(s->palette[v + 2]));
1104 }
e89f66ec
FB
1105 if (col != palette[i]) {
1106 full_update = 1;
1107 palette[i] = col;
1108 }
17b0018b 1109 v += 3;
e89f66ec
FB
1110 }
1111 return full_update;
1112}
1113
5fafdf24
TS
1114static void vga_get_offsets(VGAState *s,
1115 uint32_t *pline_offset,
83acc96b
FB
1116 uint32_t *pstart_addr,
1117 uint32_t *pline_compare)
e89f66ec 1118{
83acc96b 1119 uint32_t start_addr, line_offset, line_compare;
4fa0f5d2
FB
1120#ifdef CONFIG_BOCHS_VBE
1121 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1122 line_offset = s->vbe_line_offset;
1123 start_addr = s->vbe_start_addr;
83acc96b 1124 line_compare = 65535;
4fa0f5d2
FB
1125 } else
1126#endif
3b46e624 1127 {
4fa0f5d2
FB
1128 /* compute line_offset in bytes */
1129 line_offset = s->cr[0x13];
4fa0f5d2 1130 line_offset <<= 3;
08e48902 1131
4fa0f5d2
FB
1132 /* starting address */
1133 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
83acc96b
FB
1134
1135 /* line compare */
5fafdf24 1136 line_compare = s->cr[0x18] |
83acc96b
FB
1137 ((s->cr[0x07] & 0x10) << 4) |
1138 ((s->cr[0x09] & 0x40) << 3);
4fa0f5d2 1139 }
798b0c25
FB
1140 *pline_offset = line_offset;
1141 *pstart_addr = start_addr;
83acc96b 1142 *pline_compare = line_compare;
798b0c25
FB
1143}
1144
1145/* update start_addr and line_offset. Return TRUE if modified */
1146static int update_basic_params(VGAState *s)
1147{
1148 int full_update;
1149 uint32_t start_addr, line_offset, line_compare;
3b46e624 1150
798b0c25
FB
1151 full_update = 0;
1152
83acc96b 1153 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
e89f66ec
FB
1154
1155 if (line_offset != s->line_offset ||
1156 start_addr != s->start_addr ||
1157 line_compare != s->line_compare) {
1158 s->line_offset = line_offset;
1159 s->start_addr = start_addr;
1160 s->line_compare = line_compare;
1161 full_update = 1;
1162 }
1163 return full_update;
1164}
1165
b29169d2 1166#define NB_DEPTHS 7
d3079cd2
FB
1167
1168static inline int get_depth_index(DisplayState *s)
e89f66ec 1169{
0e1f5a0c 1170 switch(ds_get_bits_per_pixel(s)) {
e89f66ec
FB
1171 default:
1172 case 8:
1173 return 0;
1174 case 15:
8927bcfd 1175 return 1;
e89f66ec 1176 case 16:
8927bcfd 1177 return 2;
e89f66ec 1178 case 32:
7b5d76da
AL
1179 if (is_surface_bgr(s->surface))
1180 return 4;
1181 else
1182 return 3;
e89f66ec
FB
1183 }
1184}
1185
d3079cd2 1186static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
e89f66ec
FB
1187 vga_draw_glyph8_8,
1188 vga_draw_glyph8_16,
1189 vga_draw_glyph8_16,
1190 vga_draw_glyph8_32,
d3079cd2 1191 vga_draw_glyph8_32,
b29169d2
BS
1192 vga_draw_glyph8_16,
1193 vga_draw_glyph8_16,
e89f66ec
FB
1194};
1195
d3079cd2 1196static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
17b0018b
FB
1197 vga_draw_glyph16_8,
1198 vga_draw_glyph16_16,
1199 vga_draw_glyph16_16,
1200 vga_draw_glyph16_32,
d3079cd2 1201 vga_draw_glyph16_32,
b29169d2
BS
1202 vga_draw_glyph16_16,
1203 vga_draw_glyph16_16,
17b0018b
FB
1204};
1205
d3079cd2 1206static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
e89f66ec
FB
1207 vga_draw_glyph9_8,
1208 vga_draw_glyph9_16,
1209 vga_draw_glyph9_16,
1210 vga_draw_glyph9_32,
d3079cd2 1211 vga_draw_glyph9_32,
b29169d2
BS
1212 vga_draw_glyph9_16,
1213 vga_draw_glyph9_16,
e89f66ec 1214};
3b46e624 1215
e89f66ec
FB
1216static const uint8_t cursor_glyph[32 * 4] = {
1217 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1218 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1219 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1220 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1221 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1222 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1223 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1224 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1225 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1226 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1227 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1228 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1229 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1230 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1231 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1232 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3b46e624 1233};
e89f66ec 1234
4c5e8c5c
BS
1235static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight,
1236 int *pcwidth, int *pcheight)
1237{
1238 int width, cwidth, height, cheight;
1239
1240 /* total width & height */
1241 cheight = (s->cr[9] & 0x1f) + 1;
1242 cwidth = 8;
1243 if (!(s->sr[1] & 0x01))
1244 cwidth = 9;
1245 if (s->sr[1] & 0x08)
1246 cwidth = 16; /* NOTE: no 18 pixel wide */
1247 width = (s->cr[0x01] + 1);
1248 if (s->cr[0x06] == 100) {
1249 /* ugly hack for CGA 160x100x16 - explain me the logic */
1250 height = 100;
1251 } else {
1252 height = s->cr[0x12] |
1253 ((s->cr[0x07] & 0x02) << 7) |
1254 ((s->cr[0x07] & 0x40) << 3);
1255 height = (height + 1) / cheight;
1256 }
1257
1258 *pwidth = width;
1259 *pheight = height;
1260 *pcwidth = cwidth;
1261 *pcheight = cheight;
1262}
1263
7d957bd8
AL
1264typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1265
bdb19571
AL
1266static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1267 rgb_to_pixel8_dup,
1268 rgb_to_pixel15_dup,
1269 rgb_to_pixel16_dup,
1270 rgb_to_pixel32_dup,
1271 rgb_to_pixel32bgr_dup,
1272 rgb_to_pixel15bgr_dup,
1273 rgb_to_pixel16bgr_dup,
1274};
7d957bd8 1275
5fafdf24
TS
1276/*
1277 * Text mode update
e89f66ec
FB
1278 * Missing:
1279 * - double scan
5fafdf24 1280 * - double width
e89f66ec
FB
1281 * - underline
1282 * - flashing
1283 */
1284static void vga_draw_text(VGAState *s, int full_update)
1285{
1286 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1287 int cx_min, cx_max, linesize, x_incr;
1288 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1289 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1290 const uint8_t *font_ptr, *font_base[2];
1291 int dup9, line_offset, depth_index;
1292 uint32_t *palette;
1293 uint32_t *ch_attr_ptr;
1294 vga_draw_glyph8_func *vga_draw_glyph8;
1295 vga_draw_glyph9_func *vga_draw_glyph9;
1296
2bec46dc
AL
1297 vga_dirty_log_stop(s);
1298
e89f66ec
FB
1299 /* compute font data address (in plane 2) */
1300 v = s->sr[3];
1078f663 1301 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1302 if (offset != s->font_offsets[0]) {
1303 s->font_offsets[0] = offset;
1304 full_update = 1;
1305 }
1306 font_base[0] = s->vram_ptr + offset;
1307
1078f663 1308 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1309 font_base[1] = s->vram_ptr + offset;
1310 if (offset != s->font_offsets[1]) {
1311 s->font_offsets[1] = offset;
1312 full_update = 1;
1313 }
546fa6ab
FB
1314 if (s->plane_updated & (1 << 2)) {
1315 /* if the plane 2 was modified since the last display, it
1316 indicates the font may have been modified */
1317 s->plane_updated = 0;
1318 full_update = 1;
1319 }
e89f66ec
FB
1320
1321 line_offset = s->line_offset;
1322 s1 = s->vram_ptr + (s->start_addr * 4);
1323
4c5e8c5c 1324 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
0e1f5a0c 1325 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
3294b949
FB
1326 if ((height * width) > CH_ATTR_SIZE) {
1327 /* better than nothing: exit if transient size is too big */
1328 return;
1329 }
1330
7d957bd8
AL
1331 s->rgb_to_pixel =
1332 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1333 full_update |= update_palette16(s);
1334 palette = s->last_palette;
1335 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1336
e89f66ec
FB
1337 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1338 if (cursor_offset != s->cursor_offset ||
1339 s->cr[0xa] != s->cursor_start ||
1340 s->cr[0xb] != s->cursor_end) {
1341 /* if the cursor position changed, we update the old and new
1342 chars */
1343 if (s->cursor_offset < CH_ATTR_SIZE)
1344 s->last_ch_attr[s->cursor_offset] = -1;
1345 if (cursor_offset < CH_ATTR_SIZE)
1346 s->last_ch_attr[cursor_offset] = -1;
1347 s->cursor_offset = cursor_offset;
1348 s->cursor_start = s->cr[0xa];
1349 s->cursor_end = s->cr[0xb];
1350 }
39cf7803 1351 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
3b46e624 1352
d3079cd2 1353 depth_index = get_depth_index(s->ds);
17b0018b
FB
1354 if (cw == 16)
1355 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1356 else
1357 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec 1358 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
3b46e624 1359
0e1f5a0c
AL
1360 dest = ds_get_data(s->ds);
1361 linesize = ds_get_linesize(s->ds);
e89f66ec
FB
1362 ch_attr_ptr = s->last_ch_attr;
1363 for(cy = 0; cy < height; cy++) {
1364 d1 = dest;
1365 src = s1;
1366 cx_min = width;
1367 cx_max = -1;
1368 for(cx = 0; cx < width; cx++) {
1369 ch_attr = *(uint16_t *)src;
1370 if (full_update || ch_attr != *ch_attr_ptr) {
1371 if (cx < cx_min)
1372 cx_min = cx;
1373 if (cx > cx_max)
1374 cx_max = cx;
1375 *ch_attr_ptr = ch_attr;
1376#ifdef WORDS_BIGENDIAN
1377 ch = ch_attr >> 8;
1378 cattr = ch_attr & 0xff;
1379#else
1380 ch = ch_attr & 0xff;
1381 cattr = ch_attr >> 8;
1382#endif
1383 font_ptr = font_base[(cattr >> 3) & 1];
1384 font_ptr += 32 * 4 * ch;
1385 bgcol = palette[cattr >> 4];
1386 fgcol = palette[cattr & 0x0f];
17b0018b 1387 if (cw != 9) {
5fafdf24 1388 vga_draw_glyph8(d1, linesize,
e89f66ec
FB
1389 font_ptr, cheight, fgcol, bgcol);
1390 } else {
1391 dup9 = 0;
1392 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1393 dup9 = 1;
5fafdf24 1394 vga_draw_glyph9(d1, linesize,
e89f66ec
FB
1395 font_ptr, cheight, fgcol, bgcol, dup9);
1396 }
1397 if (src == cursor_ptr &&
1398 !(s->cr[0x0a] & 0x20)) {
1399 int line_start, line_last, h;
1400 /* draw the cursor */
1401 line_start = s->cr[0x0a] & 0x1f;
1402 line_last = s->cr[0x0b] & 0x1f;
1403 /* XXX: check that */
1404 if (line_last > cheight - 1)
1405 line_last = cheight - 1;
1406 if (line_last >= line_start && line_start < cheight) {
1407 h = line_last - line_start + 1;
1408 d = d1 + linesize * line_start;
17b0018b 1409 if (cw != 9) {
5fafdf24 1410 vga_draw_glyph8(d, linesize,
e89f66ec
FB
1411 cursor_glyph, h, fgcol, bgcol);
1412 } else {
5fafdf24 1413 vga_draw_glyph9(d, linesize,
e89f66ec
FB
1414 cursor_glyph, h, fgcol, bgcol, 1);
1415 }
1416 }
1417 }
1418 }
1419 d1 += x_incr;
1420 src += 4;
1421 ch_attr_ptr++;
1422 }
1423 if (cx_max != -1) {
5fafdf24 1424 dpy_update(s->ds, cx_min * cw, cy * cheight,
e89f66ec
FB
1425 (cx_max - cx_min + 1) * cw, cheight);
1426 }
1427 dest += linesize * cheight;
1428 s1 += line_offset;
1429 }
1430}
1431
17b0018b
FB
1432enum {
1433 VGA_DRAW_LINE2,
1434 VGA_DRAW_LINE2D2,
1435 VGA_DRAW_LINE4,
1436 VGA_DRAW_LINE4D2,
1437 VGA_DRAW_LINE8D2,
1438 VGA_DRAW_LINE8,
1439 VGA_DRAW_LINE15,
1440 VGA_DRAW_LINE16,
4fa0f5d2 1441 VGA_DRAW_LINE24,
17b0018b
FB
1442 VGA_DRAW_LINE32,
1443 VGA_DRAW_LINE_NB,
1444};
1445
d3079cd2 1446static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1447 vga_draw_line2_8,
1448 vga_draw_line2_16,
1449 vga_draw_line2_16,
1450 vga_draw_line2_32,
d3079cd2 1451 vga_draw_line2_32,
b29169d2
BS
1452 vga_draw_line2_16,
1453 vga_draw_line2_16,
e89f66ec 1454
17b0018b
FB
1455 vga_draw_line2d2_8,
1456 vga_draw_line2d2_16,
1457 vga_draw_line2d2_16,
1458 vga_draw_line2d2_32,
d3079cd2 1459 vga_draw_line2d2_32,
b29169d2
BS
1460 vga_draw_line2d2_16,
1461 vga_draw_line2d2_16,
17b0018b 1462
e89f66ec
FB
1463 vga_draw_line4_8,
1464 vga_draw_line4_16,
1465 vga_draw_line4_16,
1466 vga_draw_line4_32,
d3079cd2 1467 vga_draw_line4_32,
b29169d2
BS
1468 vga_draw_line4_16,
1469 vga_draw_line4_16,
e89f66ec 1470
17b0018b
FB
1471 vga_draw_line4d2_8,
1472 vga_draw_line4d2_16,
1473 vga_draw_line4d2_16,
1474 vga_draw_line4d2_32,
d3079cd2 1475 vga_draw_line4d2_32,
b29169d2
BS
1476 vga_draw_line4d2_16,
1477 vga_draw_line4d2_16,
17b0018b
FB
1478
1479 vga_draw_line8d2_8,
1480 vga_draw_line8d2_16,
1481 vga_draw_line8d2_16,
1482 vga_draw_line8d2_32,
d3079cd2 1483 vga_draw_line8d2_32,
b29169d2
BS
1484 vga_draw_line8d2_16,
1485 vga_draw_line8d2_16,
17b0018b 1486
e89f66ec
FB
1487 vga_draw_line8_8,
1488 vga_draw_line8_16,
1489 vga_draw_line8_16,
1490 vga_draw_line8_32,
d3079cd2 1491 vga_draw_line8_32,
b29169d2
BS
1492 vga_draw_line8_16,
1493 vga_draw_line8_16,
e89f66ec
FB
1494
1495 vga_draw_line15_8,
1496 vga_draw_line15_15,
1497 vga_draw_line15_16,
1498 vga_draw_line15_32,
d3079cd2 1499 vga_draw_line15_32bgr,
b29169d2
BS
1500 vga_draw_line15_15bgr,
1501 vga_draw_line15_16bgr,
e89f66ec
FB
1502
1503 vga_draw_line16_8,
1504 vga_draw_line16_15,
1505 vga_draw_line16_16,
1506 vga_draw_line16_32,
d3079cd2 1507 vga_draw_line16_32bgr,
b29169d2
BS
1508 vga_draw_line16_15bgr,
1509 vga_draw_line16_16bgr,
e89f66ec 1510
4fa0f5d2
FB
1511 vga_draw_line24_8,
1512 vga_draw_line24_15,
1513 vga_draw_line24_16,
1514 vga_draw_line24_32,
d3079cd2 1515 vga_draw_line24_32bgr,
b29169d2
BS
1516 vga_draw_line24_15bgr,
1517 vga_draw_line24_16bgr,
4fa0f5d2 1518
e89f66ec
FB
1519 vga_draw_line32_8,
1520 vga_draw_line32_15,
1521 vga_draw_line32_16,
1522 vga_draw_line32_32,
d3079cd2 1523 vga_draw_line32_32bgr,
b29169d2
BS
1524 vga_draw_line32_15bgr,
1525 vga_draw_line32_16bgr,
d3079cd2
FB
1526};
1527
798b0c25
FB
1528static int vga_get_bpp(VGAState *s)
1529{
1530 int ret;
1531#ifdef CONFIG_BOCHS_VBE
1532 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1533 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
5fafdf24 1534 } else
798b0c25
FB
1535#endif
1536 {
1537 ret = 0;
1538 }
1539 return ret;
1540}
1541
a130a41e
FB
1542static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1543{
1544 int width, height;
3b46e624 1545
8454df8b
FB
1546#ifdef CONFIG_BOCHS_VBE
1547 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1548 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1549 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
5fafdf24 1550 } else
8454df8b
FB
1551#endif
1552 {
1553 width = (s->cr[0x01] + 1) * 8;
5fafdf24
TS
1554 height = s->cr[0x12] |
1555 ((s->cr[0x07] & 0x02) << 7) |
8454df8b
FB
1556 ((s->cr[0x07] & 0x40) << 3);
1557 height = (height + 1);
1558 }
a130a41e
FB
1559 *pwidth = width;
1560 *pheight = height;
1561}
1562
a8aa669b
FB
1563void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1564{
1565 int y;
1566 if (y1 >= VGA_MAX_HEIGHT)
1567 return;
1568 if (y2 >= VGA_MAX_HEIGHT)
1569 y2 = VGA_MAX_HEIGHT;
1570 for(y = y1; y < y2; y++) {
1571 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1572 }
1573}
1574
2bec46dc
AL
1575static void vga_sync_dirty_bitmap(VGAState *s)
1576{
1577 if (s->map_addr)
1578 cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1579
1580 if (s->lfb_vram_mapped) {
1581 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1582 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1583 }
1584 vga_dirty_log_start(s);
1585}
1586
9586fefe 1587static void vga_update_resolution_graphics(VGAState *s)
e89f66ec 1588{
9586fefe
AL
1589 int depth = s->get_bpp(s);
1590 int width, height, shift_control, double_scan;
a07cf92a 1591 int disp_width, multi_scan, multi_run;
2bec46dc 1592
a130a41e 1593 s->get_resolution(s, &width, &height);
17b0018b 1594 disp_width = width;
09a79b49 1595
e89f66ec 1596 shift_control = (s->gr[0x05] >> 5) & 3;
f6c958c8 1597 double_scan = (s->cr[0x09] >> 7);
9586fefe 1598
17b0018b
FB
1599 if (shift_control != s->shift_control ||
1600 double_scan != s->double_scan) {
9586fefe 1601 s->want_full_update = 1;
e89f66ec 1602 s->shift_control = shift_control;
17b0018b 1603 s->double_scan = double_scan;
e89f66ec 1604 }
3b46e624 1605
aba35a6c 1606 if (shift_control == 0) {
1607 if (s->sr[0x01] & 8) {
1608 disp_width <<= 1;
1609 }
1610 } else if (shift_control == 1) {
1611 if (s->sr[0x01] & 8) {
1612 disp_width <<= 1;
1613 }
1614 }
9586fefe
AL
1615 disp_width = width;
1616
1617 if (shift_control != 1) {
1618 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1619 } else {
1620 /* in CGA modes, multi_scan is ignored */
1621 /* XXX: is it correct ? */
1622 multi_scan = double_scan;
1623 }
1624
1625 multi_run = multi_scan;
aba35a6c 1626
e3697092
AJ
1627 if (s->line_offset != s->last_line_offset ||
1628 disp_width != s->last_width ||
1629 height != s->last_height ||
9586fefe
AL
1630 s->last_depth != depth ||
1631 s->multi_run != multi_run ||
1632 s->multi_scan != multi_scan ||
1633 s->want_full_update) {
1634 if (s->ds->surface->pf.depth == 0) {
1635 goto dont_touch_display_surface;
1636 }
0da2ea1b 1637#if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
e3697092 1638 if (depth == 16 || depth == 32) {
0da2ea1b 1639#else
1640 if (depth == 32) {
1641#endif
b8c18e4c
AL
1642 qemu_free_displaysurface(s->ds);
1643 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1644 s->line_offset,
1645 s->vram_ptr + (s->start_addr * 4));
0da2ea1b 1646#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
b8c18e4c 1647 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
0da2ea1b 1648#endif
b8c18e4c 1649 dpy_resize(s->ds);
e3697092
AJ
1650 } else {
1651 qemu_console_resize(s->ds, disp_width, height);
1652 }
9586fefe 1653 dont_touch_display_surface:
e3697092
AJ
1654 s->last_scr_width = disp_width;
1655 s->last_scr_height = height;
1656 s->last_width = disp_width;
1657 s->last_height = height;
1658 s->last_line_offset = s->line_offset;
1659 s->last_depth = depth;
9586fefe
AL
1660 s->multi_run = multi_run;
1661 s->multi_scan = multi_scan;
1662 s->want_full_update = 1;
1663 }
1664}
1665
1666static void vga_update_resolution_text(VGAState *s)
1667{
1668 int width, height, cw, cheight;
1669
1670 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1671 if (width != s->last_width || height != s->last_height ||
1672 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1673 s->last_scr_width = width * cw;
1674 s->last_scr_height = height * cheight;
1675 if (s->ds->surface->pf.depth != 0) {
1676 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1677 } else {
1678 /*
1679 * curses expects width and height to be in character cell
1680 * dimensions, not pixels.
1681 */
1682 s->ds->surface->width = width;
1683 s->ds->surface->height = height;
1684 dpy_resize(s->ds);
1685 }
1686 s->last_depth = 0;
1687 s->last_width = width;
1688 s->last_height = height;
1689 s->last_ch = cheight;
1690 s->last_cw = cw;
1691 s->want_full_update = 1;
1692 }
1693}
1694
1695void vga_update_resolution(VGAState *s)
1696{
1697 int graphic_mode;
1698
1699 if (!(s->ar_index & 0x20)) {
1700 graphic_mode = GMODE_BLANK;
1701 } else {
1702 graphic_mode = s->gr[6] & 1;
1703 }
1704 if (graphic_mode != s->graphic_mode) {
1705 s->graphic_mode = graphic_mode;
1706 s->want_full_update = 1;
1707 }
1708 s->want_full_update |= update_basic_params(s);
1709 switch (graphic_mode) {
1710 case GMODE_TEXT:
1711 vga_update_resolution_text(s);
1712 break;
1713 case GMODE_GRAPH:
1714 vga_update_resolution_graphics(s);
1715 break;
1716 }
1717}
1718
1719/*
1720 * graphic modes
1721 */
1722static void vga_draw_graphic(VGAState *s, int full_update)
1723{
1724 int y1, y, update, linesize, y_start, mask;
1725 int width, height, line_offset, bwidth, bits;
1726 int multi_run;
1727 uint8_t *d;
1728 uint32_t v, addr1, addr;
1729 long page0, page1, page_min, page_max;
1730 vga_draw_line_func *vga_draw_line;
1731
1732 if (!full_update)
1733 vga_sync_dirty_bitmap(s);
1734
1735 s->get_resolution(s, &width, &height);
1736 multi_run = s->multi_run;
1737 if (is_buffer_shared(s->ds->surface) &&
e3697092
AJ
1738 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1739 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1740 dpy_setdata(s->ds);
1741 }
1742
1743 s->rgb_to_pixel =
1744 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1745
9586fefe 1746 if (s->shift_control == 0) {
17b0018b
FB
1747 full_update |= update_palette16(s);
1748 if (s->sr[0x01] & 8) {
1749 v = VGA_DRAW_LINE4D2;
17b0018b
FB
1750 } else {
1751 v = VGA_DRAW_LINE4;
1752 }
15342721 1753 bits = 4;
9586fefe 1754 } else if (s->shift_control == 1) {
17b0018b
FB
1755 full_update |= update_palette16(s);
1756 if (s->sr[0x01] & 8) {
1757 v = VGA_DRAW_LINE2D2;
17b0018b
FB
1758 } else {
1759 v = VGA_DRAW_LINE2;
1760 }
15342721 1761 bits = 4;
17b0018b 1762 } else {
798b0c25
FB
1763 switch(s->get_bpp(s)) {
1764 default:
1765 case 0:
4fa0f5d2
FB
1766 full_update |= update_palette256(s);
1767 v = VGA_DRAW_LINE8D2;
15342721 1768 bits = 4;
798b0c25
FB
1769 break;
1770 case 8:
1771 full_update |= update_palette256(s);
1772 v = VGA_DRAW_LINE8;
15342721 1773 bits = 8;
798b0c25
FB
1774 break;
1775 case 15:
1776 v = VGA_DRAW_LINE15;
15342721 1777 bits = 16;
798b0c25
FB
1778 break;
1779 case 16:
1780 v = VGA_DRAW_LINE16;
15342721 1781 bits = 16;
798b0c25
FB
1782 break;
1783 case 24:
1784 v = VGA_DRAW_LINE24;
15342721 1785 bits = 24;
798b0c25
FB
1786 break;
1787 case 32:
1788 v = VGA_DRAW_LINE32;
15342721 1789 bits = 32;
798b0c25 1790 break;
4fa0f5d2 1791 }
17b0018b 1792 }
d3079cd2 1793 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
17b0018b 1794
7d957bd8 1795 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
a8aa669b 1796 s->cursor_invalidate(s);
3b46e624 1797
e89f66ec 1798 line_offset = s->line_offset;
17b0018b 1799#if 0
f6c958c8 1800 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
1801 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1802#endif
e89f66ec 1803 addr1 = (s->start_addr * 4);
15342721 1804 bwidth = (width * bits + 7) / 8;
39cf7803 1805 y_start = -1;
e89f66ec
FB
1806 page_min = 0x7fffffff;
1807 page_max = -1;
0e1f5a0c
AL
1808 d = ds_get_data(s->ds);
1809 linesize = ds_get_linesize(s->ds);
17b0018b 1810 y1 = 0;
e89f66ec
FB
1811 for(y = 0; y < height; y++) {
1812 addr = addr1;
39cf7803 1813 if (!(s->cr[0x17] & 1)) {
17b0018b 1814 int shift;
e89f66ec 1815 /* CGA compatibility handling */
17b0018b
FB
1816 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1817 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1818 }
39cf7803 1819 if (!(s->cr[0x17] & 2)) {
17b0018b 1820 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1821 }
4fa0f5d2
FB
1822 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1823 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
5fafdf24 1824 update = full_update |
0a962c02
FB
1825 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1826 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
4fa0f5d2 1827 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1828 /* if wide line, can use another page */
5fafdf24 1829 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
0a962c02 1830 VGA_DIRTY_FLAG);
39cf7803 1831 }
a8aa669b
FB
1832 /* explicit invalidation for the hardware cursor */
1833 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
e89f66ec 1834 if (update) {
39cf7803
FB
1835 if (y_start < 0)
1836 y_start = y;
e89f66ec
FB
1837 if (page0 < page_min)
1838 page_min = page0;
1839 if (page1 > page_max)
1840 page_max = page1;
7d957bd8
AL
1841 if (!(is_buffer_shared(s->ds->surface))) {
1842 vga_draw_line(s, d, s->vram_ptr + addr, width);
1843 if (s->cursor_draw_line)
1844 s->cursor_draw_line(s, d, y);
1845 }
39cf7803
FB
1846 } else {
1847 if (y_start >= 0) {
1848 /* flush to display */
5fafdf24 1849 dpy_update(s->ds, 0, y_start,
9586fefe 1850 s->last_width, y - y_start);
39cf7803
FB
1851 y_start = -1;
1852 }
e89f66ec 1853 }
a07cf92a 1854 if (!multi_run) {
f6c958c8
FB
1855 mask = (s->cr[0x17] & 3) ^ 3;
1856 if ((y1 & mask) == mask)
1857 addr1 += line_offset;
1858 y1++;
9586fefe 1859 multi_run = s->multi_scan;
a07cf92a
FB
1860 } else {
1861 multi_run--;
e89f66ec 1862 }
f6c958c8
FB
1863 /* line compare acts on the displayed lines */
1864 if (y == s->line_compare)
1865 addr1 = 0;
e89f66ec
FB
1866 d += linesize;
1867 }
39cf7803
FB
1868 if (y_start >= 0) {
1869 /* flush to display */
5fafdf24 1870 dpy_update(s->ds, 0, y_start,
9586fefe 1871 s->last_width, y - y_start);
39cf7803 1872 }
e89f66ec
FB
1873 /* reset modified pages */
1874 if (page_max != -1) {
0a962c02
FB
1875 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1876 VGA_DIRTY_FLAG);
e89f66ec 1877 }
a8aa669b 1878 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
e89f66ec
FB
1879}
1880
2aebb3eb
FB
1881static void vga_draw_blank(VGAState *s, int full_update)
1882{
1883 int i, w, val;
1884 uint8_t *d;
1885
1886 if (!full_update)
1887 return;
1888 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1889 return;
2bec46dc
AL
1890 vga_dirty_log_stop(s);
1891
7d957bd8
AL
1892 s->rgb_to_pixel =
1893 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
0e1f5a0c 1894 if (ds_get_bits_per_pixel(s->ds) == 8)
2aebb3eb
FB
1895 val = s->rgb_to_pixel(0, 0, 0);
1896 else
1897 val = 0;
0e1f5a0c
AL
1898 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1899 d = ds_get_data(s->ds);
2aebb3eb
FB
1900 for(i = 0; i < s->last_scr_height; i++) {
1901 memset(d, val, w);
0e1f5a0c 1902 d += ds_get_linesize(s->ds);
2aebb3eb 1903 }
5fafdf24 1904 dpy_update(s->ds, 0, 0,
2aebb3eb
FB
1905 s->last_scr_width, s->last_scr_height);
1906}
1907
95219897 1908static void vga_update_display(void *opaque)
e89f66ec 1909{
95219897 1910 VGAState *s = (VGAState *)opaque;
9586fefe 1911 int full_update;
e89f66ec 1912
0e1f5a0c 1913 if (ds_get_bits_per_pixel(s->ds) == 0) {
0f35920c 1914 /* nothing to do */
59a983b9 1915 } else {
9586fefe
AL
1916 full_update = s->want_full_update;
1917 s->want_full_update = 0;
1918 switch(s->graphic_mode) {
2aebb3eb 1919 case GMODE_TEXT:
e89f66ec 1920 vga_draw_text(s, full_update);
2aebb3eb
FB
1921 break;
1922 case GMODE_GRAPH:
1923 vga_draw_graphic(s, full_update);
1924 break;
1925 case GMODE_BLANK:
1926 default:
1927 vga_draw_blank(s, full_update);
1928 break;
1929 }
e89f66ec
FB
1930 }
1931}
1932
a130a41e 1933/* force a full display refresh */
95219897 1934static void vga_invalidate_display(void *opaque)
a130a41e 1935{
95219897 1936 VGAState *s = (VGAState *)opaque;
3b46e624 1937
9586fefe
AL
1938 vga_update_resolution(s);
1939 s->want_full_update = 1;
a130a41e
FB
1940}
1941
4abc796d 1942void vga_reset(void *opaque)
e89f66ec 1943{
6e6b7363
BS
1944 VGAState *s = (VGAState *) opaque;
1945
1946 s->lfb_addr = 0;
1947 s->lfb_end = 0;
1948 s->map_addr = 0;
1949 s->map_end = 0;
1950 s->lfb_vram_mapped = 0;
1951 s->bios_offset = 0;
1952 s->bios_size = 0;
1953 s->sr_index = 0;
1954 memset(s->sr, '\0', sizeof(s->sr));
1955 s->gr_index = 0;
1956 memset(s->gr, '\0', sizeof(s->gr));
1957 s->ar_index = 0;
1958 memset(s->ar, '\0', sizeof(s->ar));
1959 s->ar_flip_flop = 0;
1960 s->cr_index = 0;
1961 memset(s->cr, '\0', sizeof(s->cr));
1962 s->msr = 0;
1963 s->fcr = 0;
1964 s->st00 = 0;
1965 s->st01 = 0;
1966 s->dac_state = 0;
1967 s->dac_sub_index = 0;
1968 s->dac_read_index = 0;
1969 s->dac_write_index = 0;
1970 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1971 s->dac_8bit = 0;
1972 memset(s->palette, '\0', sizeof(s->palette));
1973 s->bank_offset = 0;
1974#ifdef CONFIG_BOCHS_VBE
1975 s->vbe_index = 0;
1976 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1977 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1978 s->vbe_start_addr = 0;
1979 s->vbe_line_offset = 0;
1980 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1981#endif
1982 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
6e6b7363
BS
1983 s->shift_control = 0;
1984 s->double_scan = 0;
1985 s->line_offset = 0;
1986 s->line_compare = 0;
1987 s->start_addr = 0;
1988 s->plane_updated = 0;
1989 s->last_cw = 0;
1990 s->last_ch = 0;
1991 s->last_width = 0;
1992 s->last_height = 0;
1993 s->last_scr_width = 0;
1994 s->last_scr_height = 0;
1995 s->cursor_start = 0;
1996 s->cursor_end = 0;
1997 s->cursor_offset = 0;
1998 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1999 memset(s->last_palette, '\0', sizeof(s->last_palette));
2000 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
2001 switch (vga_retrace_method) {
2002 case VGA_RETRACE_DUMB:
2003 break;
2004 case VGA_RETRACE_PRECISE:
2005 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
2006 break;
2007 }
9586fefe 2008 vga_update_resolution(s);
e89f66ec
FB
2009}
2010
4d3b6f6e
AZ
2011#define TEXTMODE_X(x) ((x) % width)
2012#define TEXTMODE_Y(x) ((x) / width)
2013#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
2014 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
2015/* relay text rendering to the display driver
2016 * instead of doing a full vga_update_display() */
2017static void vga_update_text(void *opaque, console_ch_t *chardata)
2018{
2019 VGAState *s = (VGAState *) opaque;
9586fefe 2020 int i, cursor_offset, cursor_visible;
4d3b6f6e
AZ
2021 int cw, cheight, width, height, size, c_min, c_max;
2022 uint32_t *src;
2023 console_ch_t *dst, val;
2024 char msg_buffer[80];
9586fefe 2025 int full_update = s->want_full_update;
4d3b6f6e 2026
9586fefe
AL
2027 s->want_full_update = 0;
2028 switch (s->graphic_mode) {
4d3b6f6e
AZ
2029 case GMODE_TEXT:
2030 /* TODO: update palette */
4d3b6f6e 2031
9586fefe
AL
2032 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
2033
2034 if (s->ds->surface->width != width
2035 || s->ds->surface->height != height) {
2036 s->ds->surface->width = width;
2037 s->ds->surface->height = height;
2038 dpy_resize(s->ds);
4d3b6f6e
AZ
2039 }
2040
9586fefe 2041 /* total width & height */
4d3b6f6e
AZ
2042 size = (height * width);
2043 if (size > CH_ATTR_SIZE) {
2044 if (!full_update)
2045 return;
2046
363a37d5
BS
2047 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2048 width, height);
4d3b6f6e
AZ
2049 break;
2050 }
2051
4d3b6f6e
AZ
2052 /* Update "hardware" cursor */
2053 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2054 if (cursor_offset != s->cursor_offset ||
2055 s->cr[0xa] != s->cursor_start ||
2056 s->cr[0xb] != s->cursor_end || full_update) {
2057 cursor_visible = !(s->cr[0xa] & 0x20);
2058 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2059 dpy_cursor(s->ds,
2060 TEXTMODE_X(cursor_offset),
2061 TEXTMODE_Y(cursor_offset));
2062 else
2063 dpy_cursor(s->ds, -1, -1);
2064 s->cursor_offset = cursor_offset;
2065 s->cursor_start = s->cr[0xa];
2066 s->cursor_end = s->cr[0xb];
2067 }
2068
2069 src = (uint32_t *) s->vram_ptr + s->start_addr;
2070 dst = chardata;
2071
2072 if (full_update) {
2073 for (i = 0; i < size; src ++, dst ++, i ++)
2074 console_write_ch(dst, VMEM2CHTYPE(*src));
2075
2076 dpy_update(s->ds, 0, 0, width, height);
2077 } else {
2078 c_max = 0;
2079
2080 for (i = 0; i < size; src ++, dst ++, i ++) {
2081 console_write_ch(&val, VMEM2CHTYPE(*src));
2082 if (*dst != val) {
2083 *dst = val;
2084 c_max = i;
2085 break;
2086 }
2087 }
2088 c_min = i;
2089 for (; i < size; src ++, dst ++, i ++) {
2090 console_write_ch(&val, VMEM2CHTYPE(*src));
2091 if (*dst != val) {
2092 *dst = val;
2093 c_max = i;
2094 }
2095 }
2096
2097 if (c_min <= c_max) {
2098 i = TEXTMODE_Y(c_min);
2099 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2100 }
2101 }
2102
2103 return;
2104 case GMODE_GRAPH:
2105 if (!full_update)
2106 return;
2107
2108 s->get_resolution(s, &width, &height);
363a37d5
BS
2109 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2110 width, height);
4d3b6f6e
AZ
2111 break;
2112 case GMODE_BLANK:
2113 default:
2114 if (!full_update)
2115 return;
2116
363a37d5 2117 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
4d3b6f6e
AZ
2118 break;
2119 }
2120
2121 /* Display a message */
5228c2d3
AZ
2122 s->last_width = 60;
2123 s->last_height = height = 3;
4d3b6f6e 2124 dpy_cursor(s->ds, -1, -1);
7d957bd8
AL
2125 s->ds->surface->width = s->last_width;
2126 s->ds->surface->height = height;
2127 dpy_resize(s->ds);
4d3b6f6e 2128
5228c2d3 2129 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
4d3b6f6e
AZ
2130 console_write_ch(dst ++, ' ');
2131
2132 size = strlen(msg_buffer);
5228c2d3
AZ
2133 width = (s->last_width - size) / 2;
2134 dst = chardata + s->last_width + width;
4d3b6f6e
AZ
2135 for (i = 0; i < size; i ++)
2136 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2137
5228c2d3 2138 dpy_update(s->ds, 0, 0, s->last_width, height);
4d3b6f6e
AZ
2139}
2140
59a983b9 2141static CPUReadMemoryFunc *vga_mem_read[3] = {
e89f66ec
FB
2142 vga_mem_readb,
2143 vga_mem_readw,
2144 vga_mem_readl,
2145};
2146
59a983b9 2147static CPUWriteMemoryFunc *vga_mem_write[3] = {
e89f66ec
FB
2148 vga_mem_writeb,
2149 vga_mem_writew,
2150 vga_mem_writel,
2151};
2152
b0a21b53
FB
2153static void vga_save(QEMUFile *f, void *opaque)
2154{
2155 VGAState *s = opaque;
2156 int i;
2157
d2269f6f
FB
2158 if (s->pci_dev)
2159 pci_device_save(s->pci_dev, f);
2160
b0a21b53
FB
2161 qemu_put_be32s(f, &s->latch);
2162 qemu_put_8s(f, &s->sr_index);
2163 qemu_put_buffer(f, s->sr, 8);
2164 qemu_put_8s(f, &s->gr_index);
2165 qemu_put_buffer(f, s->gr, 16);
2166 qemu_put_8s(f, &s->ar_index);
2167 qemu_put_buffer(f, s->ar, 21);
bee8d684 2168 qemu_put_be32(f, s->ar_flip_flop);
b0a21b53
FB
2169 qemu_put_8s(f, &s->cr_index);
2170 qemu_put_buffer(f, s->cr, 256);
2171 qemu_put_8s(f, &s->msr);
2172 qemu_put_8s(f, &s->fcr);
bee8d684 2173 qemu_put_byte(f, s->st00);
b0a21b53
FB
2174 qemu_put_8s(f, &s->st01);
2175
2176 qemu_put_8s(f, &s->dac_state);
2177 qemu_put_8s(f, &s->dac_sub_index);
2178 qemu_put_8s(f, &s->dac_read_index);
2179 qemu_put_8s(f, &s->dac_write_index);
2180 qemu_put_buffer(f, s->dac_cache, 3);
2181 qemu_put_buffer(f, s->palette, 768);
2182
bee8d684 2183 qemu_put_be32(f, s->bank_offset);
b0a21b53
FB
2184#ifdef CONFIG_BOCHS_VBE
2185 qemu_put_byte(f, 1);
2186 qemu_put_be16s(f, &s->vbe_index);
2187 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2188 qemu_put_be16s(f, &s->vbe_regs[i]);
2189 qemu_put_be32s(f, &s->vbe_start_addr);
2190 qemu_put_be32s(f, &s->vbe_line_offset);
2191 qemu_put_be32s(f, &s->vbe_bank_mask);
2192#else
2193 qemu_put_byte(f, 0);
2194#endif
2195}
2196
2197static int vga_load(QEMUFile *f, void *opaque, int version_id)
2198{
2199 VGAState *s = opaque;
d2269f6f 2200 int is_vbe, i, ret;
b0a21b53 2201
d2269f6f 2202 if (version_id > 2)
b0a21b53
FB
2203 return -EINVAL;
2204
d2269f6f
FB
2205 if (s->pci_dev && version_id >= 2) {
2206 ret = pci_device_load(s->pci_dev, f);
2207 if (ret < 0)
2208 return ret;
2209 }
2210
b0a21b53
FB
2211 qemu_get_be32s(f, &s->latch);
2212 qemu_get_8s(f, &s->sr_index);
2213 qemu_get_buffer(f, s->sr, 8);
2214 qemu_get_8s(f, &s->gr_index);
2215 qemu_get_buffer(f, s->gr, 16);
2216 qemu_get_8s(f, &s->ar_index);
2217 qemu_get_buffer(f, s->ar, 21);
bee8d684 2218 s->ar_flip_flop=qemu_get_be32(f);
b0a21b53
FB
2219 qemu_get_8s(f, &s->cr_index);
2220 qemu_get_buffer(f, s->cr, 256);
2221 qemu_get_8s(f, &s->msr);
2222 qemu_get_8s(f, &s->fcr);
2223 qemu_get_8s(f, &s->st00);
2224 qemu_get_8s(f, &s->st01);
2225
2226 qemu_get_8s(f, &s->dac_state);
2227 qemu_get_8s(f, &s->dac_sub_index);
2228 qemu_get_8s(f, &s->dac_read_index);
2229 qemu_get_8s(f, &s->dac_write_index);
2230 qemu_get_buffer(f, s->dac_cache, 3);
2231 qemu_get_buffer(f, s->palette, 768);
2232
bee8d684 2233 s->bank_offset=qemu_get_be32(f);
b0a21b53
FB
2234 is_vbe = qemu_get_byte(f);
2235#ifdef CONFIG_BOCHS_VBE
2236 if (!is_vbe)
2237 return -EINVAL;
2238 qemu_get_be16s(f, &s->vbe_index);
2239 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2240 qemu_get_be16s(f, &s->vbe_regs[i]);
2241 qemu_get_be32s(f, &s->vbe_start_addr);
2242 qemu_get_be32s(f, &s->vbe_line_offset);
2243 qemu_get_be32s(f, &s->vbe_bank_mask);
2244#else
2245 if (is_vbe)
2246 return -EINVAL;
2247#endif
2248
2249 /* force refresh */
9586fefe
AL
2250 vga_update_resolution(s);
2251 s->want_full_update = 1;
b0a21b53
FB
2252 return 0;
2253}
2254
d2269f6f
FB
2255typedef struct PCIVGAState {
2256 PCIDevice dev;
2257 VGAState vga_state;
2258} PCIVGAState;
2259
2bec46dc
AL
2260void vga_dirty_log_start(VGAState *s)
2261{
2262 if (kvm_enabled() && s->map_addr)
2263 kvm_log_start(s->map_addr, s->map_end - s->map_addr);
2264
2265 if (kvm_enabled() && s->lfb_vram_mapped) {
2266 kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
2267 kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
2268 }
2269}
2270
2271void vga_dirty_log_stop(VGAState *s)
2272{
2273 if (kvm_enabled() && s->map_addr)
2274 kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
2275
2276 if (kvm_enabled() && s->lfb_vram_mapped) {
2277 kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
2278 kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
2279 }
2280}
2281
5fafdf24 2282static void vga_map(PCIDevice *pci_dev, int region_num,
1078f663
FB
2283 uint32_t addr, uint32_t size, int type)
2284{
d2269f6f
FB
2285 PCIVGAState *d = (PCIVGAState *)pci_dev;
2286 VGAState *s = &d->vga_state;
d5295253
FB
2287 if (region_num == PCI_ROM_SLOT) {
2288 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
2289 } else {
2290 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
2291 }
2bec46dc
AL
2292
2293 s->map_addr = addr;
2294 s->map_end = addr + VGA_RAM_SIZE;
2295
2296 vga_dirty_log_start(s);
1078f663
FB
2297}
2298
3023f332 2299void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
4efe2755 2300 ram_addr_t vga_ram_offset, int vga_ram_size)
e89f66ec 2301{
17b0018b 2302 int i, j, v, b;
e89f66ec
FB
2303
2304 for(i = 0;i < 256; i++) {
2305 v = 0;
2306 for(j = 0; j < 8; j++) {
2307 v |= ((i >> j) & 1) << (j * 4);
2308 }
2309 expand4[i] = v;
2310
2311 v = 0;
2312 for(j = 0; j < 4; j++) {
2313 v |= ((i >> (2 * j)) & 3) << (j * 4);
2314 }
2315 expand2[i] = v;
2316 }
17b0018b
FB
2317 for(i = 0; i < 16; i++) {
2318 v = 0;
2319 for(j = 0; j < 4; j++) {
2320 b = ((i >> j) & 1);
2321 v |= b << (2 * j);
2322 v |= b << (2 * j + 1);
2323 }
2324 expand4to8[i] = v;
2325 }
e89f66ec 2326
e89f66ec
FB
2327 s->vram_ptr = vga_ram_base;
2328 s->vram_offset = vga_ram_offset;
2329 s->vram_size = vga_ram_size;
798b0c25
FB
2330 s->get_bpp = vga_get_bpp;
2331 s->get_offsets = vga_get_offsets;
a130a41e 2332 s->get_resolution = vga_get_resolution;
d34cab9f
TS
2333 s->update = vga_update_display;
2334 s->invalidate = vga_invalidate_display;
2335 s->screen_dump = vga_screen_dump;
4d3b6f6e 2336 s->text_update = vga_update_text;
cb5a7aa8 2337 switch (vga_retrace_method) {
2338 case VGA_RETRACE_DUMB:
2339 s->retrace = vga_dumb_retrace;
2340 s->update_retrace_info = vga_dumb_update_retrace_info;
2341 break;
2342
2343 case VGA_RETRACE_PRECISE:
2344 s->retrace = vga_precise_retrace;
2345 s->update_retrace_info = vga_precise_update_retrace_info;
cb5a7aa8 2346 break;
2347 }
6e6b7363 2348 vga_reset(s);
798b0c25
FB
2349}
2350
d2269f6f 2351/* used by both ISA and PCI */
d34cab9f 2352void vga_init(VGAState *s)
798b0c25 2353{
d2269f6f 2354 int vga_io_memory;
7b17d41e 2355
4abc796d 2356 qemu_register_reset(vga_reset, s);
d2269f6f 2357 register_savevm("vga", 0, 2, vga_save, vga_load, s);
b0a21b53 2358
0f35920c 2359 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
e89f66ec 2360
0f35920c
FB
2361 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2362 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2363 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2364 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
e89f66ec 2365
0f35920c 2366 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
e89f66ec 2367
0f35920c
FB
2368 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2369 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2370 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2371 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
26aa7d72 2372 s->bank_offset = 0;
e89f66ec 2373
4fa0f5d2 2374#ifdef CONFIG_BOCHS_VBE
09a79b49
FB
2375#if defined (TARGET_I386)
2376 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2377 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
4fa0f5d2 2378
09a79b49
FB
2379 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2380 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
646be93b
FB
2381
2382 /* old Bochs IO ports */
09a79b49
FB
2383 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2384 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
646be93b 2385
09a79b49 2386 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
5fafdf24 2387 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
09a79b49
FB
2388#else
2389 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2390 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2391
2392 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2393 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
4fa0f5d2 2394#endif
09a79b49 2395#endif /* CONFIG_BOCHS_VBE */
4fa0f5d2 2396
a4193c8a 2397 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
5fafdf24 2398 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
26aa7d72 2399 vga_io_memory);
f65ed4c1 2400 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
d2269f6f
FB
2401}
2402
2abec30b
TS
2403/* Memory mapped interface */
2404static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2405{
2406 VGAState *s = opaque;
2407
8da3ff18 2408 return vga_ioport_read(s, addr >> s->it_shift) & 0xff;
2abec30b
TS
2409}
2410
2411static void vga_mm_writeb (void *opaque,
2412 target_phys_addr_t addr, uint32_t value)
2413{
2414 VGAState *s = opaque;
2415
8da3ff18 2416 vga_ioport_write(s, addr >> s->it_shift, value & 0xff);
2abec30b
TS
2417}
2418
2419static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2420{
2421 VGAState *s = opaque;
2422
8da3ff18 2423 return vga_ioport_read(s, addr >> s->it_shift) & 0xffff;
2abec30b
TS
2424}
2425
2426static void vga_mm_writew (void *opaque,
2427 target_phys_addr_t addr, uint32_t value)
2428{
2429 VGAState *s = opaque;
2430
8da3ff18 2431 vga_ioport_write(s, addr >> s->it_shift, value & 0xffff);
2abec30b
TS
2432}
2433
2434static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2435{
2436 VGAState *s = opaque;
2437
8da3ff18 2438 return vga_ioport_read(s, addr >> s->it_shift);
2abec30b
TS
2439}
2440
2441static void vga_mm_writel (void *opaque,
2442 target_phys_addr_t addr, uint32_t value)
2443{
2444 VGAState *s = opaque;
2445
8da3ff18 2446 vga_ioport_write(s, addr >> s->it_shift, value);
2abec30b
TS
2447}
2448
2449static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
2450 &vga_mm_readb,
2451 &vga_mm_readw,
2452 &vga_mm_readl,
2453};
2454
2455static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
2456 &vga_mm_writeb,
2457 &vga_mm_writew,
2458 &vga_mm_writel,
2459};
2460
2461static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2462 target_phys_addr_t ctrl_base, int it_shift)
2463{
2464 int s_ioport_ctrl, vga_io_memory;
2465
2abec30b
TS
2466 s->it_shift = it_shift;
2467 s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2468 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2469
2470 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2471
2472 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2473 s->bank_offset = 0;
2474 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
f65ed4c1 2475 qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
2abec30b
TS
2476}
2477
3023f332 2478int isa_vga_init(uint8_t *vga_ram_base,
d2269f6f
FB
2479 unsigned long vga_ram_offset, int vga_ram_size)
2480{
2481 VGAState *s;
2482
2483 s = qemu_mallocz(sizeof(VGAState));
d2269f6f 2484
3023f332 2485 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
d2269f6f 2486 vga_init(s);
1078f663 2487
3023f332
AL
2488 s->ds = graphic_console_init(s->update, s->invalidate,
2489 s->screen_dump, s->text_update, s);
d34cab9f 2490
4fa0f5d2 2491#ifdef CONFIG_BOCHS_VBE
d2269f6f 2492 /* XXX: use optimized standard vga accesses */
5fafdf24 2493 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
d2269f6f 2494 vga_ram_size, vga_ram_offset);
7138fcfb 2495#endif
d2269f6f
FB
2496 return 0;
2497}
2498
3023f332 2499int isa_vga_mm_init(uint8_t *vga_ram_base,
2abec30b
TS
2500 unsigned long vga_ram_offset, int vga_ram_size,
2501 target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
2502 int it_shift)
2503{
2504 VGAState *s;
2505
2506 s = qemu_mallocz(sizeof(VGAState));
2abec30b 2507
3023f332 2508 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
2abec30b
TS
2509 vga_mm_init(s, vram_base, ctrl_base, it_shift);
2510
3023f332
AL
2511 s->ds = graphic_console_init(s->update, s->invalidate,
2512 s->screen_dump, s->text_update, s);
2abec30b
TS
2513
2514#ifdef CONFIG_BOCHS_VBE
2515 /* XXX: use optimized standard vga accesses */
2516 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2517 vga_ram_size, vga_ram_offset);
2518#endif
2519 return 0;
2520}
2521
92a3ecda
AL
2522static void pci_vga_write_config(PCIDevice *d,
2523 uint32_t address, uint32_t val, int len)
2524{
2525 PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
2526 VGAState *s = &pvs->vga_state;
2527
2528 vga_dirty_log_stop(s);
2529 pci_default_write_config(d, address, val, len);
2530 vga_dirty_log_start(s);
2531}
2532
3023f332 2533int pci_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
d2269f6f
FB
2534 unsigned long vga_ram_offset, int vga_ram_size,
2535 unsigned long vga_bios_offset, int vga_bios_size)
2536{
2537 PCIVGAState *d;
2538 VGAState *s;
2539 uint8_t *pci_conf;
3b46e624 2540
5fafdf24 2541 d = (PCIVGAState *)pci_register_device(bus, "VGA",
d2269f6f 2542 sizeof(PCIVGAState),
92a3ecda 2543 -1, NULL, pci_vga_write_config);
d2269f6f
FB
2544 if (!d)
2545 return -1;
2546 s = &d->vga_state;
3b46e624 2547
3023f332 2548 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
d2269f6f 2549 vga_init(s);
d34cab9f 2550
3023f332
AL
2551 s->ds = graphic_console_init(s->update, s->invalidate,
2552 s->screen_dump, s->text_update, s);
d34cab9f 2553
d2269f6f 2554 s->pci_dev = &d->dev;
3b46e624 2555
d2269f6f 2556 pci_conf = d->dev.config;
4ebcf884
BS
2557 // dummy VGA (same as Bochs ID)
2558 pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
2559 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
173a543b 2560 pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
d2269f6f 2561 pci_conf[0x0e] = 0x00; // header_type
3b46e624 2562
d2269f6f 2563 /* XXX: vga_ram_size must be a power of two */
5fafdf24 2564 pci_register_io_region(&d->dev, 0, vga_ram_size,
d2269f6f
FB
2565 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2566 if (vga_bios_size != 0) {
2567 unsigned int bios_total_size;
2568 s->bios_offset = vga_bios_offset;
2569 s->bios_size = vga_bios_size;
2570 /* must be a power of two */
2571 bios_total_size = 1;
2572 while (bios_total_size < vga_bios_size)
2573 bios_total_size <<= 1;
5fafdf24 2574 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
d2269f6f 2575 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1078f663 2576 }
e89f66ec
FB
2577 return 0;
2578}
59a983b9
FB
2579
2580/********************************************************/
2581/* vga screen dump */
2582
5fafdf24 2583static void vga_save_dpy_update(DisplayState *s,
59a983b9
FB
2584 int x, int y, int w, int h)
2585{
2586}
2587
7d957bd8 2588static void vga_save_dpy_resize(DisplayState *s)
59a983b9 2589{
59a983b9
FB
2590}
2591
2592static void vga_save_dpy_refresh(DisplayState *s)
2593{
2594}
2595
e07d630a 2596int ppm_save(const char *filename, struct DisplaySurface *ds)
59a983b9
FB
2597{
2598 FILE *f;
2599 uint8_t *d, *d1;
e07d630a 2600 uint32_t v;
59a983b9 2601 int y, x;
e07d630a 2602 uint8_t r, g, b;
59a983b9
FB
2603
2604 f = fopen(filename, "wb");
2605 if (!f)
2606 return -1;
2607 fprintf(f, "P6\n%d %d\n%d\n",
e07d630a
AL
2608 ds->width, ds->height, 255);
2609 d1 = ds->data;
2610 for(y = 0; y < ds->height; y++) {
59a983b9 2611 d = d1;
e07d630a
AL
2612 for(x = 0; x < ds->width; x++) {
2613 if (ds->pf.bits_per_pixel == 32)
2614 v = *(uint32_t *)d;
2615 else
2616 v = (uint32_t) (*(uint16_t *)d);
2617 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2618 (ds->pf.rmax + 1);
2619 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2620 (ds->pf.gmax + 1);
2621 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2622 (ds->pf.bmax + 1);
2623 fputc(r, f);
2624 fputc(g, f);
2625 fputc(b, f);
2626 d += ds->pf.bytes_per_pixel;
59a983b9 2627 }
e07d630a 2628 d1 += ds->linesize;
59a983b9
FB
2629 }
2630 fclose(f);
2631 return 0;
2632}
2633
4c5e8c5c
BS
2634static void vga_screen_dump_blank(VGAState *s, const char *filename)
2635{
2636 FILE *f;
2637 unsigned int y, x, w, h;
2638
2639 w = s->last_scr_width * sizeof(uint32_t);
2640 h = s->last_scr_height;
2641
2642 f = fopen(filename, "wb");
2643 if (!f)
2644 return;
2645 fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
2646 for (y = 0; y < h; y++) {
2647 for (x = 0; x < w; x++) {
2648 fputc(0, f);
2649 }
2650 }
2651 fclose(f);
2652}
2653
2654static void vga_screen_dump_common(VGAState *s, const char *filename,
2655 int w, int h)
59a983b9 2656{
59a983b9 2657 DisplayState *saved_ds, ds1, *ds = &ds1;
7d957bd8 2658 DisplayChangeListener dcl;
3b46e624 2659
59a983b9 2660 /* XXX: this is a little hackish */
95219897 2661 vga_invalidate_display(s);
59a983b9
FB
2662 saved_ds = s->ds;
2663
2664 memset(ds, 0, sizeof(DisplayState));
7d957bd8
AL
2665 memset(&dcl, 0, sizeof(DisplayChangeListener));
2666 dcl.dpy_update = vga_save_dpy_update;
2667 dcl.dpy_resize = vga_save_dpy_resize;
2668 dcl.dpy_refresh = vga_save_dpy_refresh;
2669 register_displaychangelistener(ds, &dcl);
81f099ad 2670 ds->allocator = &default_allocator;
7b5d76da 2671 ds->surface = qemu_create_displaysurface(ds, w, h);
59a983b9
FB
2672
2673 s->ds = ds;
9586fefe
AL
2674 vga_update_resolution(s);
2675 s->want_full_update = 1;
95219897 2676 vga_update_display(s);
7d957bd8 2677
e07d630a 2678 ppm_save(filename, ds->surface);
7d957bd8 2679
7b5d76da 2680 qemu_free_displaysurface(ds);
59a983b9
FB
2681 s->ds = saved_ds;
2682}
4c5e8c5c
BS
2683
2684static void vga_screen_dump_graphic(VGAState *s, const char *filename)
2685{
2686 int w, h;
2687
2688 s->get_resolution(s, &w, &h);
2689 vga_screen_dump_common(s, filename, w, h);
2690}
2691
2692static void vga_screen_dump_text(VGAState *s, const char *filename)
2693{
2694 int w, h, cwidth, cheight;
2695
2696 vga_get_text_resolution(s, &w, &h, &cwidth, &cheight);
2697 vga_screen_dump_common(s, filename, w * cwidth, h * cheight);
2698}
2699
2700/* save the vga display in a PPM image even if no display is
2701 available */
2702static void vga_screen_dump(void *opaque, const char *filename)
2703{
2704 VGAState *s = (VGAState *)opaque;
2705
9586fefe
AL
2706 switch (s->graphic_mode) {
2707 case GMODE_TEXT:
4c5e8c5c 2708 vga_screen_dump_text(s, filename);
9586fefe
AL
2709 break;
2710 case GMODE_GRAPH:
2711 vga_screen_dump_graphic(s, filename);
2712 break;
2713 case GMODE_BLANK:
2714 default:
2715 vga_screen_dump_blank(s, filename);
2716 break;
2717 }
4c5e8c5c 2718}