]> git.proxmox.com Git - qemu.git/blame - hw/vga.c
qdev: add return value to init() callbacks.
[qemu.git] / hw / vga.c
CommitLineData
e89f66ec 1/*
4fa0f5d2 2 * QEMU VGA Emulator.
5fafdf24 3 *
e89f66ec 4 * Copyright (c) 2003 Fabrice Bellard
5fafdf24 5 *
e89f66ec
FB
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
87ecb68b
PB
24#include "hw.h"
25#include "console.h"
26#include "pc.h"
27#include "pci.h"
798b0c25 28#include "vga_int.h"
94470844 29#include "pixel_ops.h"
cb5a7aa8 30#include "qemu-timer.h"
2bec46dc 31#include "kvm.h"
e89f66ec 32
e89f66ec 33//#define DEBUG_VGA
17b0018b 34//#define DEBUG_VGA_MEM
a41bc9af
FB
35//#define DEBUG_VGA_REG
36
4fa0f5d2
FB
37//#define DEBUG_BOCHS_VBE
38
e89f66ec 39/* force some bits to zero */
798b0c25 40const uint8_t sr_mask[8] = {
9e622b15
BS
41 0x03,
42 0x3d,
43 0x0f,
44 0x3f,
45 0x0e,
46 0x00,
47 0x00,
48 0xff,
e89f66ec
FB
49};
50
798b0c25 51const uint8_t gr_mask[16] = {
9e622b15
BS
52 0x0f, /* 0x00 */
53 0x0f, /* 0x01 */
54 0x0f, /* 0x02 */
55 0x1f, /* 0x03 */
56 0x03, /* 0x04 */
57 0x7b, /* 0x05 */
58 0x0f, /* 0x06 */
59 0x0f, /* 0x07 */
60 0xff, /* 0x08 */
61 0x00, /* 0x09 */
62 0x00, /* 0x0a */
63 0x00, /* 0x0b */
64 0x00, /* 0x0c */
65 0x00, /* 0x0d */
66 0x00, /* 0x0e */
67 0x00, /* 0x0f */
e89f66ec
FB
68};
69
70#define cbswap_32(__x) \
71((uint32_t)( \
72 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
73 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
74 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
75 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
76
e2542fe2 77#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
78#define PAT(x) cbswap_32(x)
79#else
80#define PAT(x) (x)
81#endif
82
e2542fe2 83#ifdef HOST_WORDS_BIGENDIAN
b8ed223b
FB
84#define BIG 1
85#else
86#define BIG 0
87#endif
88
e2542fe2 89#ifdef HOST_WORDS_BIGENDIAN
b8ed223b
FB
90#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
91#else
92#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
93#endif
94
e89f66ec
FB
95static const uint32_t mask16[16] = {
96 PAT(0x00000000),
97 PAT(0x000000ff),
98 PAT(0x0000ff00),
99 PAT(0x0000ffff),
100 PAT(0x00ff0000),
101 PAT(0x00ff00ff),
102 PAT(0x00ffff00),
103 PAT(0x00ffffff),
104 PAT(0xff000000),
105 PAT(0xff0000ff),
106 PAT(0xff00ff00),
107 PAT(0xff00ffff),
108 PAT(0xffff0000),
109 PAT(0xffff00ff),
110 PAT(0xffffff00),
111 PAT(0xffffffff),
112};
113
114#undef PAT
115
e2542fe2 116#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
117#define PAT(x) (x)
118#else
119#define PAT(x) cbswap_32(x)
120#endif
121
122static const uint32_t dmask16[16] = {
123 PAT(0x00000000),
124 PAT(0x000000ff),
125 PAT(0x0000ff00),
126 PAT(0x0000ffff),
127 PAT(0x00ff0000),
128 PAT(0x00ff00ff),
129 PAT(0x00ffff00),
130 PAT(0x00ffffff),
131 PAT(0xff000000),
132 PAT(0xff0000ff),
133 PAT(0xff00ff00),
134 PAT(0xff00ffff),
135 PAT(0xffff0000),
136 PAT(0xffff00ff),
137 PAT(0xffffff00),
138 PAT(0xffffffff),
139};
140
141static const uint32_t dmask4[4] = {
142 PAT(0x00000000),
143 PAT(0x0000ffff),
144 PAT(0xffff0000),
145 PAT(0xffffffff),
146};
147
148static uint32_t expand4[256];
149static uint16_t expand2[256];
17b0018b 150static uint8_t expand4to8[16];
e89f66ec 151
95219897 152static void vga_screen_dump(void *opaque, const char *filename);
04a52b41
SS
153static char *screen_dump_filename;
154static DisplayChangeListener *screen_dump_dcl;
95219897 155
cb5a7aa8 156static void vga_dumb_update_retrace_info(VGAState *s)
157{
158 (void) s;
159}
160
161static void vga_precise_update_retrace_info(VGAState *s)
162{
163 int htotal_chars;
164 int hretr_start_char;
165 int hretr_skew_chars;
166 int hretr_end_char;
167
168 int vtotal_lines;
169 int vretr_start_line;
170 int vretr_end_line;
171
172 int div2, sldiv2, dots;
173 int clocking_mode;
174 int clock_sel;
b0f74c87 175 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
cb5a7aa8 176 int64_t chars_per_sec;
177 struct vga_precise_retrace *r = &s->retrace_info.precise;
178
179 htotal_chars = s->cr[0x00] + 5;
180 hretr_start_char = s->cr[0x04];
181 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
182 hretr_end_char = s->cr[0x05] & 0x1f;
183
184 vtotal_lines = (s->cr[0x06]
185 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
186 ;
187 vretr_start_line = s->cr[0x10]
188 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
189 ;
190 vretr_end_line = s->cr[0x11] & 0xf;
191
192
193 div2 = (s->cr[0x17] >> 2) & 1;
194 sldiv2 = (s->cr[0x17] >> 3) & 1;
195
196 clocking_mode = (s->sr[0x01] >> 3) & 1;
197 clock_sel = (s->msr >> 2) & 3;
f87fc09b 198 dots = (s->msr & 1) ? 8 : 9;
cb5a7aa8 199
b0f74c87 200 chars_per_sec = clk_hz[clock_sel] / dots;
cb5a7aa8 201
202 htotal_chars <<= clocking_mode;
203
204 r->total_chars = vtotal_lines * htotal_chars;
cb5a7aa8 205 if (r->freq) {
206 r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
207 } else {
208 r->ticks_per_char = ticks_per_sec / chars_per_sec;
209 }
210
211 r->vstart = vretr_start_line;
212 r->vend = r->vstart + vretr_end_line + 1;
213
214 r->hstart = hretr_start_char + hretr_skew_chars;
215 r->hend = r->hstart + hretr_end_char + 1;
216 r->htotal = htotal_chars;
217
f87fc09b 218#if 0
cb5a7aa8 219 printf (
f87fc09b 220 "hz=%f\n"
cb5a7aa8 221 "htotal = %d\n"
222 "hretr_start = %d\n"
223 "hretr_skew = %d\n"
224 "hretr_end = %d\n"
225 "vtotal = %d\n"
226 "vretr_start = %d\n"
227 "vretr_end = %d\n"
228 "div2 = %d sldiv2 = %d\n"
229 "clocking_mode = %d\n"
230 "clock_sel = %d %d\n"
231 "dots = %d\n"
232 "ticks/char = %lld\n"
233 "\n",
f87fc09b 234 (double) ticks_per_sec / (r->ticks_per_char * r->total_chars),
cb5a7aa8 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,
b0f74c87 245 clk_hz[clock_sel],
cb5a7aa8 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;
f87fc09b 268 } else {
269 cur_line_char = cur_char % r->htotal;
270 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
271 val |= ST01_DISP_ENABLE;
272 }
cb5a7aa8 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
0bf9e31a 804 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
e89f66ec
FB
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
0bf9e31a 837 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
e89f66ec 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
0bf9e31a 850 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
e89f66ec 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
0bf9e31a
BS
924 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
925 addr * 4, write_mask, val);
e89f66ec 926#endif
0bf9e31a 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{
0e1f5a0c 1157 switch(ds_get_bits_per_pixel(s)) {
e89f66ec
FB
1158 default:
1159 case 8:
1160 return 0;
1161 case 15:
8927bcfd 1162 return 1;
e89f66ec 1163 case 16:
8927bcfd 1164 return 2;
e89f66ec 1165 case 32:
7b5d76da
AL
1166 if (is_surface_bgr(s->surface))
1167 return 4;
1168 else
1169 return 3;
e89f66ec
FB
1170 }
1171}
1172
d3079cd2 1173static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
e89f66ec
FB
1174 vga_draw_glyph8_8,
1175 vga_draw_glyph8_16,
1176 vga_draw_glyph8_16,
1177 vga_draw_glyph8_32,
d3079cd2 1178 vga_draw_glyph8_32,
b29169d2
BS
1179 vga_draw_glyph8_16,
1180 vga_draw_glyph8_16,
e89f66ec
FB
1181};
1182
d3079cd2 1183static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
17b0018b
FB
1184 vga_draw_glyph16_8,
1185 vga_draw_glyph16_16,
1186 vga_draw_glyph16_16,
1187 vga_draw_glyph16_32,
d3079cd2 1188 vga_draw_glyph16_32,
b29169d2
BS
1189 vga_draw_glyph16_16,
1190 vga_draw_glyph16_16,
17b0018b
FB
1191};
1192
d3079cd2 1193static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
e89f66ec
FB
1194 vga_draw_glyph9_8,
1195 vga_draw_glyph9_16,
1196 vga_draw_glyph9_16,
1197 vga_draw_glyph9_32,
d3079cd2 1198 vga_draw_glyph9_32,
b29169d2
BS
1199 vga_draw_glyph9_16,
1200 vga_draw_glyph9_16,
e89f66ec 1201};
3b46e624 1202
e89f66ec
FB
1203static const uint8_t cursor_glyph[32 * 4] = {
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,
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,
3b46e624 1220};
e89f66ec 1221
4c5e8c5c
BS
1222static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight,
1223 int *pcwidth, int *pcheight)
1224{
1225 int width, cwidth, height, cheight;
1226
1227 /* total width & height */
1228 cheight = (s->cr[9] & 0x1f) + 1;
1229 cwidth = 8;
1230 if (!(s->sr[1] & 0x01))
1231 cwidth = 9;
1232 if (s->sr[1] & 0x08)
1233 cwidth = 16; /* NOTE: no 18 pixel wide */
1234 width = (s->cr[0x01] + 1);
1235 if (s->cr[0x06] == 100) {
1236 /* ugly hack for CGA 160x100x16 - explain me the logic */
1237 height = 100;
1238 } else {
1239 height = s->cr[0x12] |
1240 ((s->cr[0x07] & 0x02) << 7) |
1241 ((s->cr[0x07] & 0x40) << 3);
1242 height = (height + 1) / cheight;
1243 }
1244
1245 *pwidth = width;
1246 *pheight = height;
1247 *pcwidth = cwidth;
1248 *pcheight = cheight;
1249}
1250
7d957bd8
AL
1251typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1252
bdb19571
AL
1253static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1254 rgb_to_pixel8_dup,
1255 rgb_to_pixel15_dup,
1256 rgb_to_pixel16_dup,
1257 rgb_to_pixel32_dup,
1258 rgb_to_pixel32bgr_dup,
1259 rgb_to_pixel15bgr_dup,
1260 rgb_to_pixel16bgr_dup,
1261};
7d957bd8 1262
5fafdf24
TS
1263/*
1264 * Text mode update
e89f66ec
FB
1265 * Missing:
1266 * - double scan
5fafdf24 1267 * - double width
e89f66ec
FB
1268 * - underline
1269 * - flashing
1270 */
1271static void vga_draw_text(VGAState *s, int full_update)
1272{
1273 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1274 int cx_min, cx_max, linesize, x_incr;
1275 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1276 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1277 const uint8_t *font_ptr, *font_base[2];
1278 int dup9, line_offset, depth_index;
1279 uint32_t *palette;
1280 uint32_t *ch_attr_ptr;
1281 vga_draw_glyph8_func *vga_draw_glyph8;
1282 vga_draw_glyph9_func *vga_draw_glyph9;
1283
e89f66ec
FB
1284 /* compute font data address (in plane 2) */
1285 v = s->sr[3];
1078f663 1286 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1287 if (offset != s->font_offsets[0]) {
1288 s->font_offsets[0] = offset;
1289 full_update = 1;
1290 }
1291 font_base[0] = s->vram_ptr + offset;
1292
1078f663 1293 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
e89f66ec
FB
1294 font_base[1] = s->vram_ptr + offset;
1295 if (offset != s->font_offsets[1]) {
1296 s->font_offsets[1] = offset;
1297 full_update = 1;
1298 }
546fa6ab
FB
1299 if (s->plane_updated & (1 << 2)) {
1300 /* if the plane 2 was modified since the last display, it
1301 indicates the font may have been modified */
1302 s->plane_updated = 0;
1303 full_update = 1;
1304 }
799e709b 1305 full_update |= update_basic_params(s);
e89f66ec
FB
1306
1307 line_offset = s->line_offset;
1308 s1 = s->vram_ptr + (s->start_addr * 4);
1309
4c5e8c5c 1310 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
0e1f5a0c 1311 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
3294b949
FB
1312 if ((height * width) > CH_ATTR_SIZE) {
1313 /* better than nothing: exit if transient size is too big */
1314 return;
1315 }
1316
799e709b
AL
1317 if (width != s->last_width || height != s->last_height ||
1318 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1319 s->last_scr_width = width * cw;
1320 s->last_scr_height = height * cheight;
1321 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1322 s->last_depth = 0;
1323 s->last_width = width;
1324 s->last_height = height;
1325 s->last_ch = cheight;
1326 s->last_cw = cw;
1327 full_update = 1;
1328 }
7d957bd8
AL
1329 s->rgb_to_pixel =
1330 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1331 full_update |= update_palette16(s);
1332 palette = s->last_palette;
1333 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1334
e89f66ec
FB
1335 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1336 if (cursor_offset != s->cursor_offset ||
1337 s->cr[0xa] != s->cursor_start ||
1338 s->cr[0xb] != s->cursor_end) {
1339 /* if the cursor position changed, we update the old and new
1340 chars */
1341 if (s->cursor_offset < CH_ATTR_SIZE)
1342 s->last_ch_attr[s->cursor_offset] = -1;
1343 if (cursor_offset < CH_ATTR_SIZE)
1344 s->last_ch_attr[cursor_offset] = -1;
1345 s->cursor_offset = cursor_offset;
1346 s->cursor_start = s->cr[0xa];
1347 s->cursor_end = s->cr[0xb];
1348 }
39cf7803 1349 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
3b46e624 1350
d3079cd2 1351 depth_index = get_depth_index(s->ds);
17b0018b
FB
1352 if (cw == 16)
1353 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1354 else
1355 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec 1356 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
3b46e624 1357
0e1f5a0c
AL
1358 dest = ds_get_data(s->ds);
1359 linesize = ds_get_linesize(s->ds);
e89f66ec
FB
1360 ch_attr_ptr = s->last_ch_attr;
1361 for(cy = 0; cy < height; cy++) {
1362 d1 = dest;
1363 src = s1;
1364 cx_min = width;
1365 cx_max = -1;
1366 for(cx = 0; cx < width; cx++) {
1367 ch_attr = *(uint16_t *)src;
1368 if (full_update || ch_attr != *ch_attr_ptr) {
1369 if (cx < cx_min)
1370 cx_min = cx;
1371 if (cx > cx_max)
1372 cx_max = cx;
1373 *ch_attr_ptr = ch_attr;
e2542fe2 1374#ifdef HOST_WORDS_BIGENDIAN
e89f66ec
FB
1375 ch = ch_attr >> 8;
1376 cattr = ch_attr & 0xff;
1377#else
1378 ch = ch_attr & 0xff;
1379 cattr = ch_attr >> 8;
1380#endif
1381 font_ptr = font_base[(cattr >> 3) & 1];
1382 font_ptr += 32 * 4 * ch;
1383 bgcol = palette[cattr >> 4];
1384 fgcol = palette[cattr & 0x0f];
17b0018b 1385 if (cw != 9) {
5fafdf24 1386 vga_draw_glyph8(d1, linesize,
e89f66ec
FB
1387 font_ptr, cheight, fgcol, bgcol);
1388 } else {
1389 dup9 = 0;
1390 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1391 dup9 = 1;
5fafdf24 1392 vga_draw_glyph9(d1, linesize,
e89f66ec
FB
1393 font_ptr, cheight, fgcol, bgcol, dup9);
1394 }
1395 if (src == cursor_ptr &&
1396 !(s->cr[0x0a] & 0x20)) {
1397 int line_start, line_last, h;
1398 /* draw the cursor */
1399 line_start = s->cr[0x0a] & 0x1f;
1400 line_last = s->cr[0x0b] & 0x1f;
1401 /* XXX: check that */
1402 if (line_last > cheight - 1)
1403 line_last = cheight - 1;
1404 if (line_last >= line_start && line_start < cheight) {
1405 h = line_last - line_start + 1;
1406 d = d1 + linesize * line_start;
17b0018b 1407 if (cw != 9) {
5fafdf24 1408 vga_draw_glyph8(d, linesize,
e89f66ec
FB
1409 cursor_glyph, h, fgcol, bgcol);
1410 } else {
5fafdf24 1411 vga_draw_glyph9(d, linesize,
e89f66ec
FB
1412 cursor_glyph, h, fgcol, bgcol, 1);
1413 }
1414 }
1415 }
1416 }
1417 d1 += x_incr;
1418 src += 4;
1419 ch_attr_ptr++;
1420 }
1421 if (cx_max != -1) {
5fafdf24 1422 dpy_update(s->ds, cx_min * cw, cy * cheight,
e89f66ec
FB
1423 (cx_max - cx_min + 1) * cw, cheight);
1424 }
1425 dest += linesize * cheight;
1426 s1 += line_offset;
1427 }
1428}
1429
17b0018b
FB
1430enum {
1431 VGA_DRAW_LINE2,
1432 VGA_DRAW_LINE2D2,
1433 VGA_DRAW_LINE4,
1434 VGA_DRAW_LINE4D2,
1435 VGA_DRAW_LINE8D2,
1436 VGA_DRAW_LINE8,
1437 VGA_DRAW_LINE15,
1438 VGA_DRAW_LINE16,
4fa0f5d2 1439 VGA_DRAW_LINE24,
17b0018b
FB
1440 VGA_DRAW_LINE32,
1441 VGA_DRAW_LINE_NB,
1442};
1443
d3079cd2 1444static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1445 vga_draw_line2_8,
1446 vga_draw_line2_16,
1447 vga_draw_line2_16,
1448 vga_draw_line2_32,
d3079cd2 1449 vga_draw_line2_32,
b29169d2
BS
1450 vga_draw_line2_16,
1451 vga_draw_line2_16,
e89f66ec 1452
17b0018b
FB
1453 vga_draw_line2d2_8,
1454 vga_draw_line2d2_16,
1455 vga_draw_line2d2_16,
1456 vga_draw_line2d2_32,
d3079cd2 1457 vga_draw_line2d2_32,
b29169d2
BS
1458 vga_draw_line2d2_16,
1459 vga_draw_line2d2_16,
17b0018b 1460
e89f66ec
FB
1461 vga_draw_line4_8,
1462 vga_draw_line4_16,
1463 vga_draw_line4_16,
1464 vga_draw_line4_32,
d3079cd2 1465 vga_draw_line4_32,
b29169d2
BS
1466 vga_draw_line4_16,
1467 vga_draw_line4_16,
e89f66ec 1468
17b0018b
FB
1469 vga_draw_line4d2_8,
1470 vga_draw_line4d2_16,
1471 vga_draw_line4d2_16,
1472 vga_draw_line4d2_32,
d3079cd2 1473 vga_draw_line4d2_32,
b29169d2
BS
1474 vga_draw_line4d2_16,
1475 vga_draw_line4d2_16,
17b0018b
FB
1476
1477 vga_draw_line8d2_8,
1478 vga_draw_line8d2_16,
1479 vga_draw_line8d2_16,
1480 vga_draw_line8d2_32,
d3079cd2 1481 vga_draw_line8d2_32,
b29169d2
BS
1482 vga_draw_line8d2_16,
1483 vga_draw_line8d2_16,
17b0018b 1484
e89f66ec
FB
1485 vga_draw_line8_8,
1486 vga_draw_line8_16,
1487 vga_draw_line8_16,
1488 vga_draw_line8_32,
d3079cd2 1489 vga_draw_line8_32,
b29169d2
BS
1490 vga_draw_line8_16,
1491 vga_draw_line8_16,
e89f66ec
FB
1492
1493 vga_draw_line15_8,
1494 vga_draw_line15_15,
1495 vga_draw_line15_16,
1496 vga_draw_line15_32,
d3079cd2 1497 vga_draw_line15_32bgr,
b29169d2
BS
1498 vga_draw_line15_15bgr,
1499 vga_draw_line15_16bgr,
e89f66ec
FB
1500
1501 vga_draw_line16_8,
1502 vga_draw_line16_15,
1503 vga_draw_line16_16,
1504 vga_draw_line16_32,
d3079cd2 1505 vga_draw_line16_32bgr,
b29169d2
BS
1506 vga_draw_line16_15bgr,
1507 vga_draw_line16_16bgr,
e89f66ec 1508
4fa0f5d2
FB
1509 vga_draw_line24_8,
1510 vga_draw_line24_15,
1511 vga_draw_line24_16,
1512 vga_draw_line24_32,
d3079cd2 1513 vga_draw_line24_32bgr,
b29169d2
BS
1514 vga_draw_line24_15bgr,
1515 vga_draw_line24_16bgr,
4fa0f5d2 1516
e89f66ec
FB
1517 vga_draw_line32_8,
1518 vga_draw_line32_15,
1519 vga_draw_line32_16,
1520 vga_draw_line32_32,
d3079cd2 1521 vga_draw_line32_32bgr,
b29169d2
BS
1522 vga_draw_line32_15bgr,
1523 vga_draw_line32_16bgr,
d3079cd2
FB
1524};
1525
798b0c25
FB
1526static int vga_get_bpp(VGAState *s)
1527{
1528 int ret;
1529#ifdef CONFIG_BOCHS_VBE
1530 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1531 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
5fafdf24 1532 } else
798b0c25
FB
1533#endif
1534 {
1535 ret = 0;
1536 }
1537 return ret;
1538}
1539
a130a41e
FB
1540static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1541{
1542 int width, height;
3b46e624 1543
8454df8b
FB
1544#ifdef CONFIG_BOCHS_VBE
1545 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1546 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1547 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
5fafdf24 1548 } else
8454df8b
FB
1549#endif
1550 {
1551 width = (s->cr[0x01] + 1) * 8;
5fafdf24
TS
1552 height = s->cr[0x12] |
1553 ((s->cr[0x07] & 0x02) << 7) |
8454df8b
FB
1554 ((s->cr[0x07] & 0x40) << 3);
1555 height = (height + 1);
1556 }
a130a41e
FB
1557 *pwidth = width;
1558 *pheight = height;
1559}
1560
a8aa669b
FB
1561void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1562{
1563 int y;
1564 if (y1 >= VGA_MAX_HEIGHT)
1565 return;
1566 if (y2 >= VGA_MAX_HEIGHT)
1567 y2 = VGA_MAX_HEIGHT;
1568 for(y = y1; y < y2; y++) {
1569 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1570 }
1571}
1572
2bec46dc
AL
1573static void vga_sync_dirty_bitmap(VGAState *s)
1574{
1575 if (s->map_addr)
1576 cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1577
1578 if (s->lfb_vram_mapped) {
1579 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1580 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1581 }
2bec46dc
AL
1582}
1583
799e709b
AL
1584/*
1585 * graphic modes
1586 */
1587static void vga_draw_graphic(VGAState *s, int full_update)
e89f66ec 1588{
12c7e75a
AK
1589 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1590 int width, height, shift_control, line_offset, bwidth, bits;
1591 ram_addr_t page0, page1, page_min, page_max;
a07cf92a 1592 int disp_width, multi_scan, multi_run;
799e709b
AL
1593 uint8_t *d;
1594 uint32_t v, addr1, addr;
1595 vga_draw_line_func *vga_draw_line;
1596
1597 full_update |= update_basic_params(s);
1598
1599 if (!full_update)
1600 vga_sync_dirty_bitmap(s);
2bec46dc 1601
a130a41e 1602 s->get_resolution(s, &width, &height);
17b0018b 1603 disp_width = width;
09a79b49 1604
e89f66ec 1605 shift_control = (s->gr[0x05] >> 5) & 3;
f6c958c8 1606 double_scan = (s->cr[0x09] >> 7);
799e709b
AL
1607 if (shift_control != 1) {
1608 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1609 } else {
1610 /* in CGA modes, multi_scan is ignored */
1611 /* XXX: is it correct ? */
1612 multi_scan = double_scan;
1613 }
1614 multi_run = multi_scan;
17b0018b
FB
1615 if (shift_control != s->shift_control ||
1616 double_scan != s->double_scan) {
799e709b 1617 full_update = 1;
e89f66ec 1618 s->shift_control = shift_control;
17b0018b 1619 s->double_scan = double_scan;
e89f66ec 1620 }
3b46e624 1621
aba35a6c 1622 if (shift_control == 0) {
1623 if (s->sr[0x01] & 8) {
1624 disp_width <<= 1;
1625 }
1626 } else if (shift_control == 1) {
1627 if (s->sr[0x01] & 8) {
1628 disp_width <<= 1;
1629 }
1630 }
1631
799e709b 1632 depth = s->get_bpp(s);
e3697092
AJ
1633 if (s->line_offset != s->last_line_offset ||
1634 disp_width != s->last_width ||
1635 height != s->last_height ||
799e709b 1636 s->last_depth != depth) {
e2542fe2 1637#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
e3697092 1638 if (depth == 16 || depth == 32) {
0da2ea1b 1639#else
1640 if (depth == 32) {
1641#endif
b8c18e4c
AL
1642 qemu_free_displaysurface(s->ds);
1643 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1644 s->line_offset,
1645 s->vram_ptr + (s->start_addr * 4));
e2542fe2 1646#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
b8c18e4c 1647 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
0da2ea1b 1648#endif
b8c18e4c 1649 dpy_resize(s->ds);
e3697092
AJ
1650 } else {
1651 qemu_console_resize(s->ds, disp_width, height);
1652 }
1653 s->last_scr_width = disp_width;
1654 s->last_scr_height = height;
1655 s->last_width = disp_width;
1656 s->last_height = height;
1657 s->last_line_offset = s->line_offset;
1658 s->last_depth = depth;
799e709b
AL
1659 full_update = 1;
1660 } else if (is_buffer_shared(s->ds->surface) &&
e3697092
AJ
1661 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1662 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1663 dpy_setdata(s->ds);
1664 }
1665
1666 s->rgb_to_pixel =
1667 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1668
799e709b 1669 if (shift_control == 0) {
17b0018b
FB
1670 full_update |= update_palette16(s);
1671 if (s->sr[0x01] & 8) {
1672 v = VGA_DRAW_LINE4D2;
17b0018b
FB
1673 } else {
1674 v = VGA_DRAW_LINE4;
1675 }
15342721 1676 bits = 4;
799e709b 1677 } else if (shift_control == 1) {
17b0018b
FB
1678 full_update |= update_palette16(s);
1679 if (s->sr[0x01] & 8) {
1680 v = VGA_DRAW_LINE2D2;
17b0018b
FB
1681 } else {
1682 v = VGA_DRAW_LINE2;
1683 }
15342721 1684 bits = 4;
17b0018b 1685 } else {
798b0c25
FB
1686 switch(s->get_bpp(s)) {
1687 default:
1688 case 0:
4fa0f5d2
FB
1689 full_update |= update_palette256(s);
1690 v = VGA_DRAW_LINE8D2;
15342721 1691 bits = 4;
798b0c25
FB
1692 break;
1693 case 8:
1694 full_update |= update_palette256(s);
1695 v = VGA_DRAW_LINE8;
15342721 1696 bits = 8;
798b0c25
FB
1697 break;
1698 case 15:
1699 v = VGA_DRAW_LINE15;
15342721 1700 bits = 16;
798b0c25
FB
1701 break;
1702 case 16:
1703 v = VGA_DRAW_LINE16;
15342721 1704 bits = 16;
798b0c25
FB
1705 break;
1706 case 24:
1707 v = VGA_DRAW_LINE24;
15342721 1708 bits = 24;
798b0c25
FB
1709 break;
1710 case 32:
1711 v = VGA_DRAW_LINE32;
15342721 1712 bits = 32;
798b0c25 1713 break;
4fa0f5d2 1714 }
17b0018b 1715 }
d3079cd2 1716 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
17b0018b 1717
7d957bd8 1718 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
a8aa669b 1719 s->cursor_invalidate(s);
3b46e624 1720
e89f66ec 1721 line_offset = s->line_offset;
17b0018b 1722#if 0
f6c958c8 1723 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
1724 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1725#endif
e89f66ec 1726 addr1 = (s->start_addr * 4);
15342721 1727 bwidth = (width * bits + 7) / 8;
39cf7803 1728 y_start = -1;
12c7e75a
AK
1729 page_min = -1;
1730 page_max = 0;
0e1f5a0c
AL
1731 d = ds_get_data(s->ds);
1732 linesize = ds_get_linesize(s->ds);
17b0018b 1733 y1 = 0;
e89f66ec
FB
1734 for(y = 0; y < height; y++) {
1735 addr = addr1;
39cf7803 1736 if (!(s->cr[0x17] & 1)) {
17b0018b 1737 int shift;
e89f66ec 1738 /* CGA compatibility handling */
17b0018b
FB
1739 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1740 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1741 }
39cf7803 1742 if (!(s->cr[0x17] & 2)) {
17b0018b 1743 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1744 }
4fa0f5d2
FB
1745 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1746 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
5fafdf24 1747 update = full_update |
0a962c02
FB
1748 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1749 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
4fa0f5d2 1750 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1751 /* if wide line, can use another page */
5fafdf24 1752 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
0a962c02 1753 VGA_DIRTY_FLAG);
39cf7803 1754 }
a8aa669b
FB
1755 /* explicit invalidation for the hardware cursor */
1756 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
e89f66ec 1757 if (update) {
39cf7803
FB
1758 if (y_start < 0)
1759 y_start = y;
e89f66ec
FB
1760 if (page0 < page_min)
1761 page_min = page0;
1762 if (page1 > page_max)
1763 page_max = page1;
7d957bd8
AL
1764 if (!(is_buffer_shared(s->ds->surface))) {
1765 vga_draw_line(s, d, s->vram_ptr + addr, width);
1766 if (s->cursor_draw_line)
1767 s->cursor_draw_line(s, d, y);
1768 }
39cf7803
FB
1769 } else {
1770 if (y_start >= 0) {
1771 /* flush to display */
5fafdf24 1772 dpy_update(s->ds, 0, y_start,
799e709b 1773 disp_width, y - y_start);
39cf7803
FB
1774 y_start = -1;
1775 }
e89f66ec 1776 }
a07cf92a 1777 if (!multi_run) {
f6c958c8
FB
1778 mask = (s->cr[0x17] & 3) ^ 3;
1779 if ((y1 & mask) == mask)
1780 addr1 += line_offset;
1781 y1++;
799e709b 1782 multi_run = multi_scan;
a07cf92a
FB
1783 } else {
1784 multi_run--;
e89f66ec 1785 }
f6c958c8
FB
1786 /* line compare acts on the displayed lines */
1787 if (y == s->line_compare)
1788 addr1 = 0;
e89f66ec
FB
1789 d += linesize;
1790 }
39cf7803
FB
1791 if (y_start >= 0) {
1792 /* flush to display */
5fafdf24 1793 dpy_update(s->ds, 0, y_start,
799e709b 1794 disp_width, y - y_start);
39cf7803 1795 }
e89f66ec 1796 /* reset modified pages */
12c7e75a 1797 if (page_max >= page_min) {
0a962c02
FB
1798 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1799 VGA_DIRTY_FLAG);
e89f66ec 1800 }
a8aa669b 1801 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
e89f66ec
FB
1802}
1803
2aebb3eb
FB
1804static void vga_draw_blank(VGAState *s, int full_update)
1805{
1806 int i, w, val;
1807 uint8_t *d;
1808
1809 if (!full_update)
1810 return;
1811 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1812 return;
2bec46dc 1813
7d957bd8
AL
1814 s->rgb_to_pixel =
1815 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
0e1f5a0c 1816 if (ds_get_bits_per_pixel(s->ds) == 8)
2aebb3eb
FB
1817 val = s->rgb_to_pixel(0, 0, 0);
1818 else
1819 val = 0;
0e1f5a0c
AL
1820 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1821 d = ds_get_data(s->ds);
2aebb3eb
FB
1822 for(i = 0; i < s->last_scr_height; i++) {
1823 memset(d, val, w);
0e1f5a0c 1824 d += ds_get_linesize(s->ds);
2aebb3eb 1825 }
5fafdf24 1826 dpy_update(s->ds, 0, 0,
2aebb3eb
FB
1827 s->last_scr_width, s->last_scr_height);
1828}
1829
799e709b
AL
1830#define GMODE_TEXT 0
1831#define GMODE_GRAPH 1
1832#define GMODE_BLANK 2
1833
95219897 1834static void vga_update_display(void *opaque)
e89f66ec 1835{
95219897 1836 VGAState *s = (VGAState *)opaque;
799e709b 1837 int full_update, graphic_mode;
e89f66ec 1838
0e1f5a0c 1839 if (ds_get_bits_per_pixel(s->ds) == 0) {
0f35920c 1840 /* nothing to do */
59a983b9 1841 } else {
0bd8246b
SS
1842 full_update = s->full_update;
1843 s->full_update = 0;
799e709b
AL
1844 if (!(s->ar_index & 0x20)) {
1845 graphic_mode = GMODE_BLANK;
1846 } else {
1847 graphic_mode = s->gr[6] & 1;
1848 }
1849 if (graphic_mode != s->graphic_mode) {
1850 s->graphic_mode = graphic_mode;
1851 full_update = 1;
1852 }
1853 switch(graphic_mode) {
2aebb3eb 1854 case GMODE_TEXT:
e89f66ec 1855 vga_draw_text(s, full_update);
2aebb3eb
FB
1856 break;
1857 case GMODE_GRAPH:
1858 vga_draw_graphic(s, full_update);
1859 break;
1860 case GMODE_BLANK:
1861 default:
1862 vga_draw_blank(s, full_update);
1863 break;
1864 }
e89f66ec
FB
1865 }
1866}
1867
a130a41e 1868/* force a full display refresh */
95219897 1869static void vga_invalidate_display(void *opaque)
a130a41e 1870{
95219897 1871 VGAState *s = (VGAState *)opaque;
3b46e624 1872
0bd8246b 1873 s->full_update = 1;
a130a41e
FB
1874}
1875
4abc796d 1876void vga_reset(void *opaque)
e89f66ec 1877{
6e6b7363
BS
1878 VGAState *s = (VGAState *) opaque;
1879
1880 s->lfb_addr = 0;
1881 s->lfb_end = 0;
1882 s->map_addr = 0;
1883 s->map_end = 0;
1884 s->lfb_vram_mapped = 0;
1885 s->bios_offset = 0;
1886 s->bios_size = 0;
1887 s->sr_index = 0;
1888 memset(s->sr, '\0', sizeof(s->sr));
1889 s->gr_index = 0;
1890 memset(s->gr, '\0', sizeof(s->gr));
1891 s->ar_index = 0;
1892 memset(s->ar, '\0', sizeof(s->ar));
1893 s->ar_flip_flop = 0;
1894 s->cr_index = 0;
1895 memset(s->cr, '\0', sizeof(s->cr));
1896 s->msr = 0;
1897 s->fcr = 0;
1898 s->st00 = 0;
1899 s->st01 = 0;
1900 s->dac_state = 0;
1901 s->dac_sub_index = 0;
1902 s->dac_read_index = 0;
1903 s->dac_write_index = 0;
1904 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1905 s->dac_8bit = 0;
1906 memset(s->palette, '\0', sizeof(s->palette));
1907 s->bank_offset = 0;
1908#ifdef CONFIG_BOCHS_VBE
1909 s->vbe_index = 0;
1910 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1911 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1912 s->vbe_start_addr = 0;
1913 s->vbe_line_offset = 0;
1914 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1915#endif
1916 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
799e709b 1917 s->graphic_mode = -1; /* force full update */
6e6b7363
BS
1918 s->shift_control = 0;
1919 s->double_scan = 0;
1920 s->line_offset = 0;
1921 s->line_compare = 0;
1922 s->start_addr = 0;
1923 s->plane_updated = 0;
1924 s->last_cw = 0;
1925 s->last_ch = 0;
1926 s->last_width = 0;
1927 s->last_height = 0;
1928 s->last_scr_width = 0;
1929 s->last_scr_height = 0;
1930 s->cursor_start = 0;
1931 s->cursor_end = 0;
1932 s->cursor_offset = 0;
1933 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1934 memset(s->last_palette, '\0', sizeof(s->last_palette));
1935 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1936 switch (vga_retrace_method) {
1937 case VGA_RETRACE_DUMB:
1938 break;
1939 case VGA_RETRACE_PRECISE:
1940 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1941 break;
1942 }
e89f66ec
FB
1943}
1944
4d3b6f6e
AZ
1945#define TEXTMODE_X(x) ((x) % width)
1946#define TEXTMODE_Y(x) ((x) / width)
1947#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1948 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1949/* relay text rendering to the display driver
1950 * instead of doing a full vga_update_display() */
1951static void vga_update_text(void *opaque, console_ch_t *chardata)
1952{
1953 VGAState *s = (VGAState *) opaque;
799e709b 1954 int graphic_mode, i, cursor_offset, cursor_visible;
4d3b6f6e
AZ
1955 int cw, cheight, width, height, size, c_min, c_max;
1956 uint32_t *src;
1957 console_ch_t *dst, val;
1958 char msg_buffer[80];
799e709b
AL
1959 int full_update = 0;
1960
1961 if (!(s->ar_index & 0x20)) {
1962 graphic_mode = GMODE_BLANK;
1963 } else {
1964 graphic_mode = s->gr[6] & 1;
1965 }
1966 if (graphic_mode != s->graphic_mode) {
1967 s->graphic_mode = graphic_mode;
1968 full_update = 1;
1969 }
1970 if (s->last_width == -1) {
1971 s->last_width = 0;
1972 full_update = 1;
1973 }
4d3b6f6e 1974
799e709b 1975 switch (graphic_mode) {
4d3b6f6e
AZ
1976 case GMODE_TEXT:
1977 /* TODO: update palette */
799e709b 1978 full_update |= update_basic_params(s);
4d3b6f6e 1979
799e709b
AL
1980 /* total width & height */
1981 cheight = (s->cr[9] & 0x1f) + 1;
1982 cw = 8;
1983 if (!(s->sr[1] & 0x01))
1984 cw = 9;
1985 if (s->sr[1] & 0x08)
1986 cw = 16; /* NOTE: no 18 pixel wide */
1987 width = (s->cr[0x01] + 1);
1988 if (s->cr[0x06] == 100) {
1989 /* ugly hack for CGA 160x100x16 - explain me the logic */
1990 height = 100;
1991 } else {
1992 height = s->cr[0x12] |
1993 ((s->cr[0x07] & 0x02) << 7) |
1994 ((s->cr[0x07] & 0x40) << 3);
1995 height = (height + 1) / cheight;
4d3b6f6e
AZ
1996 }
1997
1998 size = (height * width);
1999 if (size > CH_ATTR_SIZE) {
2000 if (!full_update)
2001 return;
2002
363a37d5
BS
2003 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2004 width, height);
4d3b6f6e
AZ
2005 break;
2006 }
2007
799e709b
AL
2008 if (width != s->last_width || height != s->last_height ||
2009 cw != s->last_cw || cheight != s->last_ch) {
2010 s->last_scr_width = width * cw;
2011 s->last_scr_height = height * cheight;
2012 s->ds->surface->width = width;
2013 s->ds->surface->height = height;
2014 dpy_resize(s->ds);
2015 s->last_width = width;
2016 s->last_height = height;
2017 s->last_ch = cheight;
2018 s->last_cw = cw;
2019 full_update = 1;
2020 }
2021
4d3b6f6e
AZ
2022 /* Update "hardware" cursor */
2023 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2024 if (cursor_offset != s->cursor_offset ||
2025 s->cr[0xa] != s->cursor_start ||
2026 s->cr[0xb] != s->cursor_end || full_update) {
2027 cursor_visible = !(s->cr[0xa] & 0x20);
2028 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2029 dpy_cursor(s->ds,
2030 TEXTMODE_X(cursor_offset),
2031 TEXTMODE_Y(cursor_offset));
2032 else
2033 dpy_cursor(s->ds, -1, -1);
2034 s->cursor_offset = cursor_offset;
2035 s->cursor_start = s->cr[0xa];
2036 s->cursor_end = s->cr[0xb];
2037 }
2038
2039 src = (uint32_t *) s->vram_ptr + s->start_addr;
2040 dst = chardata;
2041
2042 if (full_update) {
2043 for (i = 0; i < size; src ++, dst ++, i ++)
2044 console_write_ch(dst, VMEM2CHTYPE(*src));
2045
2046 dpy_update(s->ds, 0, 0, width, height);
2047 } else {
2048 c_max = 0;
2049
2050 for (i = 0; i < size; src ++, dst ++, i ++) {
2051 console_write_ch(&val, VMEM2CHTYPE(*src));
2052 if (*dst != val) {
2053 *dst = val;
2054 c_max = i;
2055 break;
2056 }
2057 }
2058 c_min = i;
2059 for (; i < size; src ++, dst ++, i ++) {
2060 console_write_ch(&val, VMEM2CHTYPE(*src));
2061 if (*dst != val) {
2062 *dst = val;
2063 c_max = i;
2064 }
2065 }
2066
2067 if (c_min <= c_max) {
2068 i = TEXTMODE_Y(c_min);
2069 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2070 }
2071 }
2072
2073 return;
2074 case GMODE_GRAPH:
2075 if (!full_update)
2076 return;
2077
2078 s->get_resolution(s, &width, &height);
363a37d5
BS
2079 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2080 width, height);
4d3b6f6e
AZ
2081 break;
2082 case GMODE_BLANK:
2083 default:
2084 if (!full_update)
2085 return;
2086
363a37d5 2087 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
4d3b6f6e
AZ
2088 break;
2089 }
2090
2091 /* Display a message */
5228c2d3
AZ
2092 s->last_width = 60;
2093 s->last_height = height = 3;
4d3b6f6e 2094 dpy_cursor(s->ds, -1, -1);
7d957bd8
AL
2095 s->ds->surface->width = s->last_width;
2096 s->ds->surface->height = height;
2097 dpy_resize(s->ds);
4d3b6f6e 2098
5228c2d3 2099 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
4d3b6f6e
AZ
2100 console_write_ch(dst ++, ' ');
2101
2102 size = strlen(msg_buffer);
5228c2d3
AZ
2103 width = (s->last_width - size) / 2;
2104 dst = chardata + s->last_width + width;
4d3b6f6e
AZ
2105 for (i = 0; i < size; i ++)
2106 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2107
5228c2d3 2108 dpy_update(s->ds, 0, 0, s->last_width, height);
4d3b6f6e
AZ
2109}
2110
d60efc6b 2111static CPUReadMemoryFunc * const vga_mem_read[3] = {
e89f66ec
FB
2112 vga_mem_readb,
2113 vga_mem_readw,
2114 vga_mem_readl,
2115};
2116
d60efc6b 2117static CPUWriteMemoryFunc * const vga_mem_write[3] = {
e89f66ec
FB
2118 vga_mem_writeb,
2119 vga_mem_writew,
2120 vga_mem_writel,
2121};
2122
b0a21b53
FB
2123static void vga_save(QEMUFile *f, void *opaque)
2124{
2125 VGAState *s = opaque;
2126 int i;
2127
d2269f6f
FB
2128 if (s->pci_dev)
2129 pci_device_save(s->pci_dev, f);
2130
b0a21b53
FB
2131 qemu_put_be32s(f, &s->latch);
2132 qemu_put_8s(f, &s->sr_index);
2133 qemu_put_buffer(f, s->sr, 8);
2134 qemu_put_8s(f, &s->gr_index);
2135 qemu_put_buffer(f, s->gr, 16);
2136 qemu_put_8s(f, &s->ar_index);
2137 qemu_put_buffer(f, s->ar, 21);
bee8d684 2138 qemu_put_be32(f, s->ar_flip_flop);
b0a21b53
FB
2139 qemu_put_8s(f, &s->cr_index);
2140 qemu_put_buffer(f, s->cr, 256);
2141 qemu_put_8s(f, &s->msr);
2142 qemu_put_8s(f, &s->fcr);
bee8d684 2143 qemu_put_byte(f, s->st00);
b0a21b53
FB
2144 qemu_put_8s(f, &s->st01);
2145
2146 qemu_put_8s(f, &s->dac_state);
2147 qemu_put_8s(f, &s->dac_sub_index);
2148 qemu_put_8s(f, &s->dac_read_index);
2149 qemu_put_8s(f, &s->dac_write_index);
2150 qemu_put_buffer(f, s->dac_cache, 3);
2151 qemu_put_buffer(f, s->palette, 768);
2152
bee8d684 2153 qemu_put_be32(f, s->bank_offset);
b0a21b53
FB
2154#ifdef CONFIG_BOCHS_VBE
2155 qemu_put_byte(f, 1);
2156 qemu_put_be16s(f, &s->vbe_index);
2157 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2158 qemu_put_be16s(f, &s->vbe_regs[i]);
2159 qemu_put_be32s(f, &s->vbe_start_addr);
2160 qemu_put_be32s(f, &s->vbe_line_offset);
2161 qemu_put_be32s(f, &s->vbe_bank_mask);
2162#else
2163 qemu_put_byte(f, 0);
2164#endif
2165}
2166
2167static int vga_load(QEMUFile *f, void *opaque, int version_id)
2168{
2169 VGAState *s = opaque;
d2269f6f 2170 int is_vbe, i, ret;
b0a21b53 2171
d2269f6f 2172 if (version_id > 2)
b0a21b53
FB
2173 return -EINVAL;
2174
d2269f6f
FB
2175 if (s->pci_dev && version_id >= 2) {
2176 ret = pci_device_load(s->pci_dev, f);
2177 if (ret < 0)
2178 return ret;
2179 }
2180
b0a21b53
FB
2181 qemu_get_be32s(f, &s->latch);
2182 qemu_get_8s(f, &s->sr_index);
2183 qemu_get_buffer(f, s->sr, 8);
2184 qemu_get_8s(f, &s->gr_index);
2185 qemu_get_buffer(f, s->gr, 16);
2186 qemu_get_8s(f, &s->ar_index);
2187 qemu_get_buffer(f, s->ar, 21);
bee8d684 2188 s->ar_flip_flop=qemu_get_be32(f);
b0a21b53
FB
2189 qemu_get_8s(f, &s->cr_index);
2190 qemu_get_buffer(f, s->cr, 256);
2191 qemu_get_8s(f, &s->msr);
2192 qemu_get_8s(f, &s->fcr);
2193 qemu_get_8s(f, &s->st00);
2194 qemu_get_8s(f, &s->st01);
2195
2196 qemu_get_8s(f, &s->dac_state);
2197 qemu_get_8s(f, &s->dac_sub_index);
2198 qemu_get_8s(f, &s->dac_read_index);
2199 qemu_get_8s(f, &s->dac_write_index);
2200 qemu_get_buffer(f, s->dac_cache, 3);
2201 qemu_get_buffer(f, s->palette, 768);
2202
bee8d684 2203 s->bank_offset=qemu_get_be32(f);
b0a21b53
FB
2204 is_vbe = qemu_get_byte(f);
2205#ifdef CONFIG_BOCHS_VBE
2206 if (!is_vbe)
2207 return -EINVAL;
2208 qemu_get_be16s(f, &s->vbe_index);
2209 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2210 qemu_get_be16s(f, &s->vbe_regs[i]);
2211 qemu_get_be32s(f, &s->vbe_start_addr);
2212 qemu_get_be32s(f, &s->vbe_line_offset);
2213 qemu_get_be32s(f, &s->vbe_bank_mask);
2214#else
2215 if (is_vbe)
2216 return -EINVAL;
2217#endif
2218
2219 /* force refresh */
799e709b 2220 s->graphic_mode = -1;
b0a21b53
FB
2221 return 0;
2222}
2223
d2269f6f
FB
2224typedef struct PCIVGAState {
2225 PCIDevice dev;
2226 VGAState vga_state;
2227} PCIVGAState;
2228
2bec46dc
AL
2229void vga_dirty_log_start(VGAState *s)
2230{
2231 if (kvm_enabled() && s->map_addr)
2232 kvm_log_start(s->map_addr, s->map_end - s->map_addr);
2233
2234 if (kvm_enabled() && s->lfb_vram_mapped) {
2235 kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
2236 kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
2237 }
2238}
2239
5fafdf24 2240static void vga_map(PCIDevice *pci_dev, int region_num,
1078f663
FB
2241 uint32_t addr, uint32_t size, int type)
2242{
d2269f6f
FB
2243 PCIVGAState *d = (PCIVGAState *)pci_dev;
2244 VGAState *s = &d->vga_state;
d5295253
FB
2245 if (region_num == PCI_ROM_SLOT) {
2246 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
2247 } else {
2248 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
e7f3dcc4
AL
2249 s->map_addr = addr;
2250 s->map_end = addr + s->vram_size;
2251 vga_dirty_log_start(s);
d5295253 2252 }
1078f663
FB
2253}
2254
b584726d 2255void vga_common_init(VGAState *s, int vga_ram_size)
e89f66ec 2256{
17b0018b 2257 int i, j, v, b;
e89f66ec
FB
2258
2259 for(i = 0;i < 256; i++) {
2260 v = 0;
2261 for(j = 0; j < 8; j++) {
2262 v |= ((i >> j) & 1) << (j * 4);
2263 }
2264 expand4[i] = v;
2265
2266 v = 0;
2267 for(j = 0; j < 4; j++) {
2268 v |= ((i >> (2 * j)) & 3) << (j * 4);
2269 }
2270 expand2[i] = v;
2271 }
17b0018b
FB
2272 for(i = 0; i < 16; i++) {
2273 v = 0;
2274 for(j = 0; j < 4; j++) {
2275 b = ((i >> j) & 1);
2276 v |= b << (2 * j);
2277 v |= b << (2 * j + 1);
2278 }
2279 expand4to8[i] = v;
2280 }
e89f66ec 2281
b584726d
PB
2282 s->vram_offset = qemu_ram_alloc(vga_ram_size);
2283 s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
e89f66ec 2284 s->vram_size = vga_ram_size;
798b0c25
FB
2285 s->get_bpp = vga_get_bpp;
2286 s->get_offsets = vga_get_offsets;
a130a41e 2287 s->get_resolution = vga_get_resolution;
d34cab9f
TS
2288 s->update = vga_update_display;
2289 s->invalidate = vga_invalidate_display;
2290 s->screen_dump = vga_screen_dump;
4d3b6f6e 2291 s->text_update = vga_update_text;
cb5a7aa8 2292 switch (vga_retrace_method) {
2293 case VGA_RETRACE_DUMB:
2294 s->retrace = vga_dumb_retrace;
2295 s->update_retrace_info = vga_dumb_update_retrace_info;
2296 break;
2297
2298 case VGA_RETRACE_PRECISE:
2299 s->retrace = vga_precise_retrace;
2300 s->update_retrace_info = vga_precise_update_retrace_info;
cb5a7aa8 2301 break;
2302 }
6e6b7363 2303 vga_reset(s);
798b0c25
FB
2304}
2305
d2269f6f 2306/* used by both ISA and PCI */
d34cab9f 2307void vga_init(VGAState *s)
798b0c25 2308{
d2269f6f 2309 int vga_io_memory;
7b17d41e 2310
a08d4367 2311 qemu_register_reset(vga_reset, s);
d2269f6f 2312 register_savevm("vga", 0, 2, vga_save, vga_load, s);
b0a21b53 2313
0f35920c 2314 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
e89f66ec 2315
0f35920c
FB
2316 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2317 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2318 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2319 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
e89f66ec 2320
0f35920c 2321 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
e89f66ec 2322
0f35920c
FB
2323 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2324 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2325 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2326 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
26aa7d72 2327 s->bank_offset = 0;
e89f66ec 2328
4fa0f5d2 2329#ifdef CONFIG_BOCHS_VBE
09a79b49
FB
2330#if defined (TARGET_I386)
2331 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2332 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
4fa0f5d2 2333
09a79b49
FB
2334 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2335 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
646be93b
FB
2336
2337 /* old Bochs IO ports */
09a79b49
FB
2338 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2339 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
646be93b 2340
09a79b49 2341 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
5fafdf24 2342 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
09a79b49
FB
2343#else
2344 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2345 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2346
2347 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2348 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
4fa0f5d2 2349#endif
09a79b49 2350#endif /* CONFIG_BOCHS_VBE */
4fa0f5d2 2351
1eed09cb 2352 vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
5fafdf24 2353 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
26aa7d72 2354 vga_io_memory);
f65ed4c1 2355 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
d2269f6f
FB
2356}
2357
2abec30b
TS
2358/* Memory mapped interface */
2359static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2360{
2361 VGAState *s = opaque;
2362
8da3ff18 2363 return vga_ioport_read(s, addr >> s->it_shift) & 0xff;
2abec30b
TS
2364}
2365
2366static void vga_mm_writeb (void *opaque,
2367 target_phys_addr_t addr, uint32_t value)
2368{
2369 VGAState *s = opaque;
2370
8da3ff18 2371 vga_ioport_write(s, addr >> s->it_shift, value & 0xff);
2abec30b
TS
2372}
2373
2374static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2375{
2376 VGAState *s = opaque;
2377
8da3ff18 2378 return vga_ioport_read(s, addr >> s->it_shift) & 0xffff;
2abec30b
TS
2379}
2380
2381static void vga_mm_writew (void *opaque,
2382 target_phys_addr_t addr, uint32_t value)
2383{
2384 VGAState *s = opaque;
2385
8da3ff18 2386 vga_ioport_write(s, addr >> s->it_shift, value & 0xffff);
2abec30b
TS
2387}
2388
2389static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2390{
2391 VGAState *s = opaque;
2392
8da3ff18 2393 return vga_ioport_read(s, addr >> s->it_shift);
2abec30b
TS
2394}
2395
2396static void vga_mm_writel (void *opaque,
2397 target_phys_addr_t addr, uint32_t value)
2398{
2399 VGAState *s = opaque;
2400
8da3ff18 2401 vga_ioport_write(s, addr >> s->it_shift, value);
2abec30b
TS
2402}
2403
d60efc6b 2404static CPUReadMemoryFunc * const vga_mm_read_ctrl[] = {
2abec30b
TS
2405 &vga_mm_readb,
2406 &vga_mm_readw,
2407 &vga_mm_readl,
2408};
2409
d60efc6b 2410static CPUWriteMemoryFunc * const vga_mm_write_ctrl[] = {
2abec30b
TS
2411 &vga_mm_writeb,
2412 &vga_mm_writew,
2413 &vga_mm_writel,
2414};
2415
2416static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2417 target_phys_addr_t ctrl_base, int it_shift)
2418{
2419 int s_ioport_ctrl, vga_io_memory;
2420
2abec30b 2421 s->it_shift = it_shift;
1eed09cb
AK
2422 s_ioport_ctrl = cpu_register_io_memory(vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2423 vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
2abec30b
TS
2424
2425 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2426
2427 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2428 s->bank_offset = 0;
2429 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
f65ed4c1 2430 qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
2abec30b
TS
2431}
2432
fbe1b595 2433int isa_vga_init(void)
d2269f6f
FB
2434{
2435 VGAState *s;
2436
2437 s = qemu_mallocz(sizeof(VGAState));
d2269f6f 2438
fbe1b595 2439 vga_common_init(s, VGA_RAM_SIZE);
d2269f6f 2440 vga_init(s);
1078f663 2441
3023f332
AL
2442 s->ds = graphic_console_init(s->update, s->invalidate,
2443 s->screen_dump, s->text_update, s);
d34cab9f 2444
4fa0f5d2 2445#ifdef CONFIG_BOCHS_VBE
d2269f6f 2446 /* XXX: use optimized standard vga accesses */
5fafdf24 2447 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
fbe1b595 2448 VGA_RAM_SIZE, s->vram_offset);
7138fcfb 2449#endif
d2269f6f
FB
2450 return 0;
2451}
2452
fbe1b595 2453int isa_vga_mm_init(target_phys_addr_t vram_base,
b584726d 2454 target_phys_addr_t ctrl_base, int it_shift)
2abec30b
TS
2455{
2456 VGAState *s;
2457
2458 s = qemu_mallocz(sizeof(VGAState));
2abec30b 2459
fbe1b595 2460 vga_common_init(s, VGA_RAM_SIZE);
2abec30b
TS
2461 vga_mm_init(s, vram_base, ctrl_base, it_shift);
2462
3023f332
AL
2463 s->ds = graphic_console_init(s->update, s->invalidate,
2464 s->screen_dump, s->text_update, s);
2abec30b
TS
2465
2466#ifdef CONFIG_BOCHS_VBE
2467 /* XXX: use optimized standard vga accesses */
2468 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
fbe1b595 2469 VGA_RAM_SIZE, s->vram_offset);
2abec30b
TS
2470#endif
2471 return 0;
2472}
2473
92a3ecda
AL
2474static void pci_vga_write_config(PCIDevice *d,
2475 uint32_t address, uint32_t val, int len)
2476{
2477 PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
2478 VGAState *s = &pvs->vga_state;
2479
92a3ecda 2480 pci_default_write_config(d, address, val, len);
e7f3dcc4
AL
2481 if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
2482 s->map_addr = 0;
92a3ecda
AL
2483}
2484
81a322d4 2485static int pci_vga_initfn(PCIDevice *dev)
d2269f6f 2486{
a414c306
GH
2487 PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
2488 VGAState *s = &d->vga_state;
2489 uint8_t *pci_conf = d->dev.config;
2490
2491 // vga + console init
2492 vga_common_init(s, VGA_RAM_SIZE);
2493 vga_init(s);
2494 s->pci_dev = &d->dev;
2495 s->ds = graphic_console_init(s->update, s->invalidate,
2496 s->screen_dump, s->text_update, s);
2497
2498 // dummy VGA (same as Bochs ID)
2499 pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
2500 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
2501 pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
2502 pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
2503
2504 /* XXX: VGA_RAM_SIZE must be a power of two */
2505 pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
2506 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2507
2508 if (s->bios_size) {
d2269f6f 2509 unsigned int bios_total_size;
d2269f6f
FB
2510 /* must be a power of two */
2511 bios_total_size = 1;
a414c306 2512 while (bios_total_size < s->bios_size)
d2269f6f 2513 bios_total_size <<= 1;
28c2c264 2514 pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
a414c306 2515 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
81a322d4
GH
2516 }
2517 return 0;
a414c306
GH
2518}
2519
2520int pci_vga_init(PCIBus *bus,
2521 unsigned long vga_bios_offset, int vga_bios_size)
2522{
2523 PCIDevice *dev;
2524
2525 dev = pci_create("VGA", NULL);
2526 qdev_prop_set_uint32(&dev->qdev, "bios-offset", vga_bios_offset);
2527 qdev_prop_set_uint32(&dev->qdev, "bios-size", vga_bios_offset);
2528 qdev_init(&dev->qdev);
2529
e89f66ec
FB
2530 return 0;
2531}
59a983b9 2532
a414c306
GH
2533static PCIDeviceInfo vga_info = {
2534 .qdev.name = "VGA",
2535 .qdev.size = sizeof(PCIVGAState),
2536 .init = pci_vga_initfn,
2537 .config_write = pci_vga_write_config,
2538 .qdev.props = (Property[]) {
df59cbc6
GH
2539 DEFINE_PROP_HEX32("bios-offset", PCIVGAState, vga_state.bios_offset, 0),
2540 DEFINE_PROP_HEX32("bios-size", PCIVGAState, vga_state.bios_size, 0),
2541 DEFINE_PROP_END_OF_LIST(),
a414c306
GH
2542 }
2543};
2544
2545static void vga_register(void)
2546{
2547 pci_qdev_register(&vga_info);
2548}
2549device_init(vga_register);
2550
59a983b9
FB
2551/********************************************************/
2552/* vga screen dump */
2553
04a52b41 2554static void vga_save_dpy_update(DisplayState *ds,
59a983b9
FB
2555 int x, int y, int w, int h)
2556{
04a52b41
SS
2557 if (screen_dump_filename) {
2558 ppm_save(screen_dump_filename, ds->surface);
2559 screen_dump_filename = NULL;
2560 }
59a983b9
FB
2561}
2562
7d957bd8 2563static void vga_save_dpy_resize(DisplayState *s)
59a983b9 2564{
59a983b9
FB
2565}
2566
2567static void vga_save_dpy_refresh(DisplayState *s)
2568{
2569}
2570
e07d630a 2571int ppm_save(const char *filename, struct DisplaySurface *ds)
59a983b9
FB
2572{
2573 FILE *f;
2574 uint8_t *d, *d1;
e07d630a 2575 uint32_t v;
59a983b9 2576 int y, x;
e07d630a 2577 uint8_t r, g, b;
59a983b9
FB
2578
2579 f = fopen(filename, "wb");
2580 if (!f)
2581 return -1;
2582 fprintf(f, "P6\n%d %d\n%d\n",
e07d630a
AL
2583 ds->width, ds->height, 255);
2584 d1 = ds->data;
2585 for(y = 0; y < ds->height; y++) {
59a983b9 2586 d = d1;
e07d630a
AL
2587 for(x = 0; x < ds->width; x++) {
2588 if (ds->pf.bits_per_pixel == 32)
2589 v = *(uint32_t *)d;
2590 else
2591 v = (uint32_t) (*(uint16_t *)d);
2592 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2593 (ds->pf.rmax + 1);
2594 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2595 (ds->pf.gmax + 1);
2596 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2597 (ds->pf.bmax + 1);
2598 fputc(r, f);
2599 fputc(g, f);
2600 fputc(b, f);
2601 d += ds->pf.bytes_per_pixel;
59a983b9 2602 }
e07d630a 2603 d1 += ds->linesize;
59a983b9
FB
2604 }
2605 fclose(f);
2606 return 0;
2607}
2608
04a52b41 2609static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
4c5e8c5c 2610{
04a52b41 2611 DisplayChangeListener *dcl;
4c5e8c5c 2612
04a52b41
SS
2613 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
2614 dcl->dpy_update = vga_save_dpy_update;
2615 dcl->dpy_resize = vga_save_dpy_resize;
2616 dcl->dpy_refresh = vga_save_dpy_refresh;
2617 register_displaychangelistener(ds, dcl);
2618 return dcl;
4c5e8c5c
BS
2619}
2620
2621/* save the vga display in a PPM image even if no display is
2622 available */
2623static void vga_screen_dump(void *opaque, const char *filename)
2624{
2625 VGAState *s = (VGAState *)opaque;
2626
04a52b41
SS
2627 if (!screen_dump_dcl)
2628 screen_dump_dcl = vga_screen_dump_init(s->ds);
2629
2630 screen_dump_filename = (char *)filename;
9d1b494a 2631 vga_invalidate_display(s);
04a52b41 2632 vga_hw_update();
4c5e8c5c 2633}
04a52b41 2634