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