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