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