]> git.proxmox.com Git - mirror_qemu.git/blame - hw/vga.c
io port API change
[mirror_qemu.git] / hw / vga.c
CommitLineData
e89f66ec 1/*
4fa0f5d2 2 * QEMU VGA Emulator.
e89f66ec
FB
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
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 */
24#include <stdlib.h>
25#include <stdio.h>
26#include <stdarg.h>
27#include <string.h>
28#include <getopt.h>
29#include <inttypes.h>
30#include <unistd.h>
31#include <sys/mman.h>
32#include <fcntl.h>
33#include <signal.h>
34#include <time.h>
35#include <sys/time.h>
36#include <malloc.h>
37#include <termios.h>
38#include <sys/poll.h>
39#include <errno.h>
40#include <sys/wait.h>
41#include <netinet/in.h>
42
b9f19507
FB
43#define NO_THUNK_TYPE_SIZE
44#include "thunk.h"
45
6180a181
FB
46#include "cpu.h"
47#include "exec-all.h"
e89f66ec
FB
48
49#include "vl.h"
50
e89f66ec 51//#define DEBUG_VGA
17b0018b 52//#define DEBUG_VGA_MEM
a41bc9af
FB
53//#define DEBUG_VGA_REG
54
55//#define DEBUG_S3
4fa0f5d2
FB
56//#define DEBUG_BOCHS_VBE
57
a41bc9af 58#define CONFIG_S3VGA
e89f66ec
FB
59
60#define MSR_COLOR_EMULATION 0x01
61#define MSR_PAGE_SELECT 0x20
62
63#define ST01_V_RETRACE 0x08
64#define ST01_DISP_ENABLE 0x01
65
4fa0f5d2
FB
66/* bochs VBE support */
67#define CONFIG_BOCHS_VBE
68
69#define VBE_DISPI_MAX_XRES 1024
70#define VBE_DISPI_MAX_YRES 768
71
72#define VBE_DISPI_INDEX_ID 0x0
73#define VBE_DISPI_INDEX_XRES 0x1
74#define VBE_DISPI_INDEX_YRES 0x2
75#define VBE_DISPI_INDEX_BPP 0x3
76#define VBE_DISPI_INDEX_ENABLE 0x4
77#define VBE_DISPI_INDEX_BANK 0x5
78#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
79#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
80#define VBE_DISPI_INDEX_X_OFFSET 0x8
81#define VBE_DISPI_INDEX_Y_OFFSET 0x9
82#define VBE_DISPI_INDEX_NB 0xa
83
84#define VBE_DISPI_ID0 0xB0C0
85#define VBE_DISPI_ID1 0xB0C1
86#define VBE_DISPI_ID2 0xB0C2
87
88#define VBE_DISPI_DISABLED 0x00
89#define VBE_DISPI_ENABLED 0x01
90#define VBE_DISPI_LFB_ENABLED 0x40
91#define VBE_DISPI_NOCLEARMEM 0x80
92
93#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
94
e89f66ec
FB
95typedef struct VGAState {
96 uint8_t *vram_ptr;
97 unsigned long vram_offset;
98 unsigned int vram_size;
99 uint32_t latch;
100 uint8_t sr_index;
101 uint8_t sr[8];
102 uint8_t gr_index;
103 uint8_t gr[16];
104 uint8_t ar_index;
105 uint8_t ar[21];
106 int ar_flip_flop;
107 uint8_t cr_index;
108 uint8_t cr[256]; /* CRT registers */
109 uint8_t msr; /* Misc Output Register */
110 uint8_t fcr; /* Feature Control Register */
111 uint8_t st00; /* status 0 */
112 uint8_t st01; /* status 1 */
113 uint8_t dac_state;
114 uint8_t dac_sub_index;
115 uint8_t dac_read_index;
116 uint8_t dac_write_index;
117 uint8_t dac_cache[3]; /* used when writing */
118 uint8_t palette[768];
cae61cef 119 uint32_t bank_offset;
4fa0f5d2
FB
120#ifdef CONFIG_BOCHS_VBE
121 uint16_t vbe_index;
122 uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
123 uint32_t vbe_start_addr;
124 uint32_t vbe_line_offset;
cae61cef 125 uint32_t vbe_bank_mask;
4fa0f5d2 126#endif
e89f66ec 127 /* display refresh support */
e89f66ec
FB
128 DisplayState *ds;
129 uint32_t font_offsets[2];
130 int graphic_mode;
17b0018b
FB
131 uint8_t shift_control;
132 uint8_t double_scan;
e89f66ec
FB
133 uint32_t line_offset;
134 uint32_t line_compare;
135 uint32_t start_addr;
136 uint8_t last_cw, last_ch;
137 uint32_t last_width, last_height;
138 uint8_t cursor_start, cursor_end;
139 uint32_t cursor_offset;
17b0018b 140 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
39cf7803 141 /* tell for each page if it has been updated since the last time */
e89f66ec 142 uint32_t last_palette[256];
17b0018b 143#define CH_ATTR_SIZE (160 * 100)
e89f66ec
FB
144 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
145} VGAState;
146
147/* force some bits to zero */
148static const uint8_t sr_mask[8] = {
149 (uint8_t)~0xfc,
150 (uint8_t)~0xc2,
151 (uint8_t)~0xf0,
152 (uint8_t)~0xc0,
153 (uint8_t)~0xf1,
154 (uint8_t)~0xff,
155 (uint8_t)~0xff,
156 (uint8_t)~0x00,
157};
158
159static const uint8_t gr_mask[16] = {
160 (uint8_t)~0xf0, /* 0x00 */
161 (uint8_t)~0xf0, /* 0x01 */
162 (uint8_t)~0xf0, /* 0x02 */
163 (uint8_t)~0xe0, /* 0x03 */
164 (uint8_t)~0xfc, /* 0x04 */
165 (uint8_t)~0x84, /* 0x05 */
166 (uint8_t)~0xf0, /* 0x06 */
167 (uint8_t)~0xf0, /* 0x07 */
168 (uint8_t)~0x00, /* 0x08 */
169 (uint8_t)~0xff, /* 0x09 */
170 (uint8_t)~0xff, /* 0x0a */
171 (uint8_t)~0xff, /* 0x0b */
172 (uint8_t)~0xff, /* 0x0c */
173 (uint8_t)~0xff, /* 0x0d */
174 (uint8_t)~0xff, /* 0x0e */
175 (uint8_t)~0xff, /* 0x0f */
176};
177
178#define cbswap_32(__x) \
179((uint32_t)( \
180 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
181 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
182 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
183 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
184
b8ed223b 185#ifdef WORDS_BIGENDIAN
e89f66ec
FB
186#define PAT(x) cbswap_32(x)
187#else
188#define PAT(x) (x)
189#endif
190
b8ed223b
FB
191#ifdef WORDS_BIGENDIAN
192#define BIG 1
193#else
194#define BIG 0
195#endif
196
197#ifdef WORDS_BIGENDIAN
198#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
199#else
200#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
201#endif
202
e89f66ec
FB
203static const uint32_t mask16[16] = {
204 PAT(0x00000000),
205 PAT(0x000000ff),
206 PAT(0x0000ff00),
207 PAT(0x0000ffff),
208 PAT(0x00ff0000),
209 PAT(0x00ff00ff),
210 PAT(0x00ffff00),
211 PAT(0x00ffffff),
212 PAT(0xff000000),
213 PAT(0xff0000ff),
214 PAT(0xff00ff00),
215 PAT(0xff00ffff),
216 PAT(0xffff0000),
217 PAT(0xffff00ff),
218 PAT(0xffffff00),
219 PAT(0xffffffff),
220};
221
222#undef PAT
223
b8ed223b 224#ifdef WORDS_BIGENDIAN
e89f66ec
FB
225#define PAT(x) (x)
226#else
227#define PAT(x) cbswap_32(x)
228#endif
229
230static const uint32_t dmask16[16] = {
231 PAT(0x00000000),
232 PAT(0x000000ff),
233 PAT(0x0000ff00),
234 PAT(0x0000ffff),
235 PAT(0x00ff0000),
236 PAT(0x00ff00ff),
237 PAT(0x00ffff00),
238 PAT(0x00ffffff),
239 PAT(0xff000000),
240 PAT(0xff0000ff),
241 PAT(0xff00ff00),
242 PAT(0xff00ffff),
243 PAT(0xffff0000),
244 PAT(0xffff00ff),
245 PAT(0xffffff00),
246 PAT(0xffffffff),
247};
248
249static const uint32_t dmask4[4] = {
250 PAT(0x00000000),
251 PAT(0x0000ffff),
252 PAT(0xffff0000),
253 PAT(0xffffffff),
254};
255
256static uint32_t expand4[256];
257static uint16_t expand2[256];
17b0018b 258static uint8_t expand4to8[16];
e89f66ec
FB
259
260VGAState vga_state;
261int vga_io_memory;
262
7138fcfb 263static uint32_t vga_ioport_read(CPUState *env, uint32_t addr)
e89f66ec
FB
264{
265 VGAState *s = &vga_state;
266 int val, index;
267
268 /* check port range access depending on color/monochrome mode */
269 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
270 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
271 val = 0xff;
272 } else {
273 switch(addr) {
274 case 0x3c0:
275 if (s->ar_flip_flop == 0) {
276 val = s->ar_index;
277 } else {
278 val = 0;
279 }
280 break;
281 case 0x3c1:
282 index = s->ar_index & 0x1f;
283 if (index < 21)
284 val = s->ar[index];
285 else
286 val = 0;
287 break;
288 case 0x3c2:
289 val = s->st00;
290 break;
291 case 0x3c4:
292 val = s->sr_index;
293 break;
294 case 0x3c5:
295 val = s->sr[s->sr_index];
a41bc9af
FB
296#ifdef DEBUG_VGA_REG
297 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
298#endif
e89f66ec
FB
299 break;
300 case 0x3c7:
301 val = s->dac_state;
302 break;
303 case 0x3c9:
304 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
305 if (++s->dac_sub_index == 3) {
306 s->dac_sub_index = 0;
307 s->dac_read_index++;
308 }
309 break;
310 case 0x3ca:
311 val = s->fcr;
312 break;
313 case 0x3cc:
314 val = s->msr;
315 break;
316 case 0x3ce:
317 val = s->gr_index;
318 break;
319 case 0x3cf:
320 val = s->gr[s->gr_index];
a41bc9af
FB
321#ifdef DEBUG_VGA_REG
322 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
323#endif
e89f66ec
FB
324 break;
325 case 0x3b4:
326 case 0x3d4:
327 val = s->cr_index;
328 break;
329 case 0x3b5:
330 case 0x3d5:
331 val = s->cr[s->cr_index];
a41bc9af
FB
332#ifdef DEBUG_VGA_REG
333 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
334#endif
335#ifdef DEBUG_S3
336 if (s->cr_index >= 0x20)
337 printf("S3: CR read index=0x%x val=0x%x\n",
338 s->cr_index, val);
339#endif
e89f66ec
FB
340 break;
341 case 0x3ba:
342 case 0x3da:
343 /* just toggle to fool polling */
344 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
345 val = s->st01;
346 s->ar_flip_flop = 0;
347 break;
348 default:
349 val = 0x00;
350 break;
351 }
352 }
4fa0f5d2 353#if defined(DEBUG_VGA)
e89f66ec
FB
354 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
355#endif
356 return val;
357}
358
7138fcfb 359static void vga_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
e89f66ec
FB
360{
361 VGAState *s = &vga_state;
362 int index, v;
363
364 /* check port range access depending on color/monochrome mode */
365 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
366 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
367 return;
368
369#ifdef DEBUG_VGA
370 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
371#endif
372
373 switch(addr) {
374 case 0x3c0:
375 if (s->ar_flip_flop == 0) {
376 val &= 0x3f;
377 s->ar_index = val;
378 } else {
379 index = s->ar_index & 0x1f;
380 switch(index) {
381 case 0x00 ... 0x0f:
382 s->ar[index] = val & 0x3f;
383 break;
384 case 0x10:
385 s->ar[index] = val & ~0x10;
386 break;
387 case 0x11:
388 s->ar[index] = val;
389 break;
390 case 0x12:
391 s->ar[index] = val & ~0xc0;
392 break;
393 case 0x13:
394 s->ar[index] = val & ~0xf0;
395 break;
396 case 0x14:
397 s->ar[index] = val & ~0xf0;
398 break;
399 default:
400 break;
401 }
402 }
403 s->ar_flip_flop ^= 1;
404 break;
405 case 0x3c2:
406 s->msr = val & ~0x10;
407 break;
408 case 0x3c4:
409 s->sr_index = val & 7;
410 break;
411 case 0x3c5:
a41bc9af
FB
412#ifdef DEBUG_VGA_REG
413 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
414#endif
e89f66ec
FB
415 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
416 break;
417 case 0x3c7:
418 s->dac_read_index = val;
419 s->dac_sub_index = 0;
420 s->dac_state = 3;
421 break;
422 case 0x3c8:
423 s->dac_write_index = val;
424 s->dac_sub_index = 0;
425 s->dac_state = 0;
426 break;
427 case 0x3c9:
428 s->dac_cache[s->dac_sub_index] = val;
429 if (++s->dac_sub_index == 3) {
430 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
431 s->dac_sub_index = 0;
432 s->dac_write_index++;
433 }
434 break;
435 case 0x3ce:
436 s->gr_index = val & 0x0f;
437 break;
438 case 0x3cf:
a41bc9af
FB
439#ifdef DEBUG_VGA_REG
440 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
441#endif
e89f66ec
FB
442 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
443 break;
444 case 0x3b4:
445 case 0x3d4:
446 s->cr_index = val;
447 break;
448 case 0x3b5:
449 case 0x3d5:
a41bc9af
FB
450#ifdef DEBUG_VGA_REG
451 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
452#endif
e89f66ec
FB
453 /* handle CR0-7 protection */
454 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
455 /* can always write bit 4 of CR7 */
456 if (s->cr_index == 7)
457 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
458 return;
459 }
460 switch(s->cr_index) {
461 case 0x01: /* horizontal display end */
462 case 0x07:
463 case 0x09:
464 case 0x0c:
465 case 0x0d:
466 case 0x12: /* veritcal display end */
467 s->cr[s->cr_index] = val;
468 break;
469
a41bc9af 470#ifdef CONFIG_S3VGA
e89f66ec
FB
471 /* S3 registers */
472 case 0x2d:
473 case 0x2e:
474 case 0x2f:
475 case 0x30:
476 /* chip ID, cannot write */
477 break;
478 case 0x31:
479 /* update start address */
480 s->cr[s->cr_index] = val;
481 v = (val >> 4) & 3;
482 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
483 break;
484 case 0x51:
485 /* update start address */
486 s->cr[s->cr_index] = val;
487 v = val & 3;
488 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
489 break;
a41bc9af 490#endif
e89f66ec
FB
491 default:
492 s->cr[s->cr_index] = val;
493 break;
494 }
a41bc9af
FB
495#ifdef DEBUG_S3
496 if (s->cr_index >= 0x20)
497 printf("S3: CR write index=0x%x val=0x%x\n",
498 s->cr_index, val);
499#endif
e89f66ec
FB
500 break;
501 case 0x3ba:
502 case 0x3da:
503 s->fcr = val & 0x10;
504 break;
505 }
506}
507
4fa0f5d2
FB
508#ifdef CONFIG_BOCHS_VBE
509static uint32_t vbe_ioport_read(CPUState *env, uint32_t addr)
510{
511 VGAState *s = &vga_state;
512 uint32_t val;
513
514 addr &= 1;
515 if (addr == 0) {
516 val = s->vbe_index;
517 } else {
518 if (s->vbe_index <= VBE_DISPI_INDEX_NB)
519 val = s->vbe_regs[s->vbe_index];
520 else
521 val = 0;
522#ifdef DEBUG_BOCHS_VBE
523 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
524#endif
525 }
526 return val;
527}
528
529static void vbe_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
530{
531 VGAState *s = &vga_state;
532
533 addr &= 1;
534 if (addr == 0) {
535 s->vbe_index = val;
536 } else if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
537#ifdef DEBUG_BOCHS_VBE
538 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
539#endif
540 switch(s->vbe_index) {
541 case VBE_DISPI_INDEX_ID:
cae61cef
FB
542 if (val == VBE_DISPI_ID0 ||
543 val == VBE_DISPI_ID1 ||
544 val == VBE_DISPI_ID2) {
545 s->vbe_regs[s->vbe_index] = val;
546 }
4fa0f5d2
FB
547 break;
548 case VBE_DISPI_INDEX_XRES:
cae61cef
FB
549 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
550 s->vbe_regs[s->vbe_index] = val;
551 }
4fa0f5d2
FB
552 break;
553 case VBE_DISPI_INDEX_YRES:
cae61cef
FB
554 if (val <= VBE_DISPI_MAX_YRES) {
555 s->vbe_regs[s->vbe_index] = val;
556 }
4fa0f5d2
FB
557 break;
558 case VBE_DISPI_INDEX_BPP:
559 if (val == 0)
560 val = 8;
cae61cef
FB
561 if (val == 4 || val == 8 || val == 15 ||
562 val == 16 || val == 24 || val == 32) {
563 s->vbe_regs[s->vbe_index] = val;
564 }
4fa0f5d2
FB
565 break;
566 case VBE_DISPI_INDEX_BANK:
cae61cef
FB
567 val &= s->vbe_bank_mask;
568 s->vbe_regs[s->vbe_index] = val;
569 s->bank_offset = (val << 16) - 0xa0000;
4fa0f5d2
FB
570 break;
571 case VBE_DISPI_INDEX_ENABLE:
572 if (val & VBE_DISPI_ENABLED) {
573 int h, shift_control;
574
575 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
576 s->vbe_regs[VBE_DISPI_INDEX_XRES];
577 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
578 s->vbe_regs[VBE_DISPI_INDEX_YRES];
579 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
580 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
581
582 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
583 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
584 else
585 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
586 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
587 s->vbe_start_addr = 0;
588
589 /* clear the screen (should be done in BIOS) */
590 if (!(val & VBE_DISPI_NOCLEARMEM)) {
591 memset(s->vram_ptr, 0,
592 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
593 }
594
cae61cef
FB
595 /* we initialize the VGA graphic mode (should be done
596 in BIOS) */
597 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
4fa0f5d2
FB
598 s->cr[0x17] |= 3; /* no CGA modes */
599 s->cr[0x13] = s->vbe_line_offset >> 3;
600 /* width */
601 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
602 /* height */
603 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
604 s->cr[0x12] = h;
605 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
606 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
607 /* line compare to 1023 */
608 s->cr[0x18] = 0xff;
609 s->cr[0x07] |= 0x10;
610 s->cr[0x09] |= 0x40;
611
612 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
613 shift_control = 0;
614 s->sr[0x01] &= ~8; /* no double line */
615 } else {
616 shift_control = 2;
617 }
618 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
619 s->cr[0x09] &= ~0x9f; /* no double scan */
cae61cef
FB
620 s->vbe_regs[s->vbe_index] = val;
621 } else {
622 /* XXX: the bios should do that */
623 s->bank_offset = -0xa0000;
624 }
625 break;
626 case VBE_DISPI_INDEX_VIRT_WIDTH:
627 {
628 int w, h, line_offset;
629
630 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
631 return;
632 w = val;
633 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
634 line_offset = w >> 1;
635 else
636 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
637 h = s->vram_size / line_offset;
638 /* XXX: support weird bochs semantics ? */
639 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
640 return;
641 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
642 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
643 s->vbe_line_offset = line_offset;
644 }
645 break;
646 case VBE_DISPI_INDEX_X_OFFSET:
647 case VBE_DISPI_INDEX_Y_OFFSET:
648 {
649 int x;
650 s->vbe_regs[s->vbe_index] = val;
651 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
652 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
653 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
654 s->vbe_start_addr += x >> 1;
655 else
656 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
657 s->vbe_start_addr >>= 2;
4fa0f5d2
FB
658 }
659 break;
660 default:
661 break;
662 }
4fa0f5d2
FB
663 }
664}
665#endif
666
e89f66ec
FB
667/* called for accesses between 0xa0000 and 0xc0000 */
668static uint32_t vga_mem_readb(uint32_t addr)
669{
670 VGAState *s = &vga_state;
671 int memory_map_mode, plane;
672 uint32_t ret;
673
674 /* convert to VGA memory offset */
675 memory_map_mode = (s->gr[6] >> 2) & 3;
676 switch(memory_map_mode) {
677 case 0:
678 addr -= 0xa0000;
679 break;
680 case 1:
cae61cef 681 if (addr >= 0xb0000)
e89f66ec 682 return 0xff;
cae61cef 683 addr += s->bank_offset;
e89f66ec
FB
684 break;
685 case 2:
686 addr -= 0xb0000;
687 if (addr >= 0x8000)
688 return 0xff;
689 break;
690 default:
691 case 3:
692 addr -= 0xb8000;
c92b2e84
FB
693 if (addr >= 0x8000)
694 return 0xff;
e89f66ec
FB
695 break;
696 }
697
698 if (s->sr[4] & 0x08) {
699 /* chain 4 mode : simplest access */
700 ret = s->vram_ptr[addr];
701 } else if (s->gr[5] & 0x10) {
702 /* odd/even mode (aka text mode mapping) */
703 plane = (s->gr[4] & 2) | (addr & 1);
704 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
705 } else {
706 /* standard VGA latched access */
707 s->latch = ((uint32_t *)s->vram_ptr)[addr];
708
709 if (!(s->gr[5] & 0x08)) {
710 /* read mode 0 */
711 plane = s->gr[4];
b8ed223b 712 ret = GET_PLANE(s->latch, plane);
e89f66ec
FB
713 } else {
714 /* read mode 1 */
715 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
716 ret |= ret >> 16;
717 ret |= ret >> 8;
718 ret = (~ret) & 0xff;
719 }
720 }
721 return ret;
722}
723
724static uint32_t vga_mem_readw(uint32_t addr)
725{
726 uint32_t v;
727 v = vga_mem_readb(addr);
728 v |= vga_mem_readb(addr + 1) << 8;
729 return v;
730}
731
732static uint32_t vga_mem_readl(uint32_t addr)
733{
734 uint32_t v;
735 v = vga_mem_readb(addr);
736 v |= vga_mem_readb(addr + 1) << 8;
737 v |= vga_mem_readb(addr + 2) << 16;
738 v |= vga_mem_readb(addr + 3) << 24;
739 return v;
740}
741
e89f66ec 742/* called for accesses between 0xa0000 and 0xc0000 */
4fa0f5d2 743void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
e89f66ec
FB
744{
745 VGAState *s = &vga_state;
746 int memory_map_mode, plane, write_mode, b, func_select;
747 uint32_t write_mask, bit_mask, set_mask;
748
17b0018b 749#ifdef DEBUG_VGA_MEM
e89f66ec
FB
750 printf("vga: [0x%x] = 0x%02x\n", addr, val);
751#endif
752 /* convert to VGA memory offset */
753 memory_map_mode = (s->gr[6] >> 2) & 3;
754 switch(memory_map_mode) {
755 case 0:
756 addr -= 0xa0000;
757 break;
758 case 1:
cae61cef 759 if (addr >= 0xb0000)
e89f66ec 760 return;
cae61cef 761 addr += s->bank_offset;
e89f66ec
FB
762 break;
763 case 2:
764 addr -= 0xb0000;
765 if (addr >= 0x8000)
766 return;
767 break;
768 default:
769 case 3:
770 addr -= 0xb8000;
c92b2e84
FB
771 if (addr >= 0x8000)
772 return;
e89f66ec
FB
773 break;
774 }
775
776 if (s->sr[4] & 0x08) {
777 /* chain 4 mode : simplest access */
778 plane = addr & 3;
779 if (s->sr[2] & (1 << plane)) {
780 s->vram_ptr[addr] = val;
17b0018b 781#ifdef DEBUG_VGA_MEM
e89f66ec
FB
782 printf("vga: chain4: [0x%x]\n", addr);
783#endif
4fa0f5d2 784 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
785 }
786 } else if (s->gr[5] & 0x10) {
787 /* odd/even mode (aka text mode mapping) */
788 plane = (s->gr[4] & 2) | (addr & 1);
789 if (s->sr[2] & (1 << plane)) {
790 addr = ((addr & ~1) << 1) | plane;
791 s->vram_ptr[addr] = val;
17b0018b 792#ifdef DEBUG_VGA_MEM
e89f66ec
FB
793 printf("vga: odd/even: [0x%x]\n", addr);
794#endif
4fa0f5d2 795 cpu_physical_memory_set_dirty(s->vram_offset + addr);
e89f66ec
FB
796 }
797 } else {
798 /* standard VGA latched access */
799 write_mode = s->gr[5] & 3;
800 switch(write_mode) {
801 default:
802 case 0:
803 /* rotate */
804 b = s->gr[3] & 7;
805 val = ((val >> b) | (val << (8 - b))) & 0xff;
806 val |= val << 8;
807 val |= val << 16;
808
809 /* apply set/reset mask */
810 set_mask = mask16[s->gr[1]];
811 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
812 bit_mask = s->gr[8];
813 break;
814 case 1:
815 val = s->latch;
816 goto do_write;
817 case 2:
818 val = mask16[val & 0x0f];
819 bit_mask = s->gr[8];
820 break;
821 case 3:
822 /* rotate */
823 b = s->gr[3] & 7;
a41bc9af 824 val = (val >> b) | (val << (8 - b));
e89f66ec
FB
825
826 bit_mask = s->gr[8] & val;
827 val = mask16[s->gr[0]];
828 break;
829 }
830
831 /* apply logical operation */
832 func_select = s->gr[3] >> 3;
833 switch(func_select) {
834 case 0:
835 default:
836 /* nothing to do */
837 break;
838 case 1:
839 /* and */
840 val &= s->latch;
841 break;
842 case 2:
843 /* or */
844 val |= s->latch;
845 break;
846 case 3:
847 /* xor */
848 val ^= s->latch;
849 break;
850 }
851
852 /* apply bit mask */
853 bit_mask |= bit_mask << 8;
854 bit_mask |= bit_mask << 16;
855 val = (val & bit_mask) | (s->latch & ~bit_mask);
856
857 do_write:
858 /* mask data according to sr[2] */
859 write_mask = mask16[s->sr[2]];
860 ((uint32_t *)s->vram_ptr)[addr] =
861 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
862 (val & write_mask);
17b0018b 863#ifdef DEBUG_VGA_MEM
e89f66ec
FB
864 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
865 addr * 4, write_mask, val);
866#endif
4fa0f5d2 867 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
e89f66ec
FB
868 }
869}
870
4fa0f5d2 871void vga_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
e89f66ec 872{
4fa0f5d2
FB
873 vga_mem_writeb(addr, val & 0xff, vaddr);
874 vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr);
e89f66ec
FB
875}
876
4fa0f5d2 877void vga_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
e89f66ec 878{
4fa0f5d2
FB
879 vga_mem_writeb(addr, val & 0xff, vaddr);
880 vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr);
881 vga_mem_writeb(addr + 2, (val >> 16) & 0xff, vaddr);
882 vga_mem_writeb(addr + 3, (val >> 24) & 0xff, vaddr);
e89f66ec
FB
883}
884
e89f66ec
FB
885typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
886 const uint8_t *font_ptr, int h,
887 uint32_t fgcol, uint32_t bgcol);
888typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
889 const uint8_t *font_ptr, int h,
890 uint32_t fgcol, uint32_t bgcol, int dup9);
891typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
892 const uint8_t *s, int width);
893
894static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
895{
896 /* XXX: TODO */
897 return 0;
898}
899
900static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
901{
902 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
903}
904
905static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
906{
907 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
908}
909
910static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
911{
912 return (r << 16) | (g << 8) | b;
913}
914
915#define DEPTH 8
916#include "vga_template.h"
917
918#define DEPTH 15
919#include "vga_template.h"
920
921#define DEPTH 16
922#include "vga_template.h"
923
924#define DEPTH 32
925#include "vga_template.h"
926
927static inline int c6_to_8(int v)
928{
929 int b;
930 v &= 0x3f;
931 b = v & 1;
932 return (v << 2) | (b << 1) | b;
933}
934
17b0018b
FB
935static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
936{
937 unsigned int col;
938 col = rgb_to_pixel8(r, g, b);
939 col |= col << 8;
940 col |= col << 16;
941 return col;
942}
943
944static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
945{
946 unsigned int col;
947 col = rgb_to_pixel15(r, g, b);
948 col |= col << 16;
949 return col;
950}
951
952static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
953{
954 unsigned int col;
955 col = rgb_to_pixel16(r, g, b);
956 col |= col << 16;
957 return col;
958}
959
960static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
961{
962 unsigned int col;
963 col = rgb_to_pixel32(r, g, b);
964 return col;
965}
966
e89f66ec
FB
967/* return true if the palette was modified */
968static int update_palette16(VGAState *s)
969{
17b0018b 970 int full_update, i;
e89f66ec 971 uint32_t v, col, *palette;
e89f66ec
FB
972
973 full_update = 0;
974 palette = s->last_palette;
975 for(i = 0; i < 16; i++) {
976 v = s->ar[i];
977 if (s->ar[0x10] & 0x80)
978 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
979 else
980 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
981 v = v * 3;
17b0018b
FB
982 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
983 c6_to_8(s->palette[v + 1]),
984 c6_to_8(s->palette[v + 2]));
985 if (col != palette[i]) {
986 full_update = 1;
987 palette[i] = col;
e89f66ec 988 }
17b0018b
FB
989 }
990 return full_update;
991}
992
993/* return true if the palette was modified */
994static int update_palette256(VGAState *s)
995{
996 int full_update, i;
997 uint32_t v, col, *palette;
998
999 full_update = 0;
1000 palette = s->last_palette;
1001 v = 0;
1002 for(i = 0; i < 256; i++) {
1003 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1004 c6_to_8(s->palette[v + 1]),
1005 c6_to_8(s->palette[v + 2]));
e89f66ec
FB
1006 if (col != palette[i]) {
1007 full_update = 1;
1008 palette[i] = col;
1009 }
17b0018b 1010 v += 3;
e89f66ec
FB
1011 }
1012 return full_update;
1013}
1014
1015/* update start_addr and line_offset. Return TRUE if modified */
1016static int update_basic_params(VGAState *s)
1017{
1018 int full_update;
1019 uint32_t start_addr, line_offset, line_compare, v;
1020
1021 full_update = 0;
4fa0f5d2
FB
1022
1023#ifdef CONFIG_BOCHS_VBE
1024 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1025 line_offset = s->vbe_line_offset;
1026 start_addr = s->vbe_start_addr;
1027 } else
1028#endif
1029 {
1030 /* compute line_offset in bytes */
1031 line_offset = s->cr[0x13];
a41bc9af 1032#ifdef CONFIG_S3VGA
4fa0f5d2
FB
1033 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
1034 if (v == 0)
1035 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
1036 line_offset |= (v << 8);
a41bc9af 1037#endif
4fa0f5d2
FB
1038 line_offset <<= 3;
1039
1040 /* starting address */
1041 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
a41bc9af 1042#ifdef CONFIG_S3VGA
4fa0f5d2 1043 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
a41bc9af 1044#endif
4fa0f5d2
FB
1045 }
1046
e89f66ec
FB
1047 /* line compare */
1048 line_compare = s->cr[0x18] |
1049 ((s->cr[0x07] & 0x10) << 4) |
1050 ((s->cr[0x09] & 0x40) << 3);
1051
1052 if (line_offset != s->line_offset ||
1053 start_addr != s->start_addr ||
1054 line_compare != s->line_compare) {
1055 s->line_offset = line_offset;
1056 s->start_addr = start_addr;
1057 s->line_compare = line_compare;
1058 full_update = 1;
1059 }
1060 return full_update;
1061}
1062
1063static inline int get_depth_index(int depth)
1064{
1065 switch(depth) {
1066 default:
1067 case 8:
1068 return 0;
1069 case 15:
1070 return 1;
1071 case 16:
1072 return 2;
1073 case 32:
1074 return 3;
1075 }
1076}
1077
1078static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1079 vga_draw_glyph8_8,
1080 vga_draw_glyph8_16,
1081 vga_draw_glyph8_16,
1082 vga_draw_glyph8_32,
1083};
1084
17b0018b
FB
1085static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1086 vga_draw_glyph16_8,
1087 vga_draw_glyph16_16,
1088 vga_draw_glyph16_16,
1089 vga_draw_glyph16_32,
1090};
1091
e89f66ec
FB
1092static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1093 vga_draw_glyph9_8,
1094 vga_draw_glyph9_16,
1095 vga_draw_glyph9_16,
1096 vga_draw_glyph9_32,
1097};
1098
1099static const uint8_t cursor_glyph[32 * 4] = {
1100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1102 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1103 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1104 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1105 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1106 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1109 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1110 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1112 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1113 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1116};
1117
1118/*
1119 * Text mode update
1120 * Missing:
1121 * - double scan
1122 * - double width
1123 * - underline
1124 * - flashing
1125 */
1126static void vga_draw_text(VGAState *s, int full_update)
1127{
1128 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1129 int cx_min, cx_max, linesize, x_incr;
1130 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1131 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1132 const uint8_t *font_ptr, *font_base[2];
1133 int dup9, line_offset, depth_index;
1134 uint32_t *palette;
1135 uint32_t *ch_attr_ptr;
1136 vga_draw_glyph8_func *vga_draw_glyph8;
1137 vga_draw_glyph9_func *vga_draw_glyph9;
1138
1139 full_update |= update_palette16(s);
1140 palette = s->last_palette;
1141
1142 /* compute font data address (in plane 2) */
1143 v = s->sr[3];
1144 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1145 if (offset != s->font_offsets[0]) {
1146 s->font_offsets[0] = offset;
1147 full_update = 1;
1148 }
1149 font_base[0] = s->vram_ptr + offset;
1150
1151 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1152 font_base[1] = s->vram_ptr + offset;
1153 if (offset != s->font_offsets[1]) {
1154 s->font_offsets[1] = offset;
1155 full_update = 1;
1156 }
1157
1158 full_update |= update_basic_params(s);
1159
1160 line_offset = s->line_offset;
1161 s1 = s->vram_ptr + (s->start_addr * 4);
1162
1163 /* total width & height */
1164 cheight = (s->cr[9] & 0x1f) + 1;
1165 cw = 8;
1166 if (s->sr[1] & 0x01)
1167 cw = 9;
17b0018b
FB
1168 if (s->sr[1] & 0x08)
1169 cw = 16; /* NOTE: no 18 pixel wide */
e89f66ec
FB
1170 x_incr = cw * ((s->ds->depth + 7) >> 3);
1171 width = (s->cr[0x01] + 1);
17b0018b
FB
1172 if (s->cr[0x06] == 100) {
1173 /* ugly hack for CGA 160x100x16 - explain me the logic */
1174 height = 100;
1175 } else {
1176 height = s->cr[0x12] |
1177 ((s->cr[0x07] & 0x02) << 7) |
1178 ((s->cr[0x07] & 0x40) << 3);
1179 height = (height + 1) / cheight;
1180 }
e89f66ec
FB
1181 if (width != s->last_width || height != s->last_height ||
1182 cw != s->last_cw || cw != s->last_cw) {
1183 dpy_resize(s->ds, width * cw, height * cheight);
1184 s->last_width = width;
1185 s->last_height = height;
1186 s->last_ch = cheight;
1187 s->last_cw = cw;
1188 full_update = 1;
1189 }
1190 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1191 if (cursor_offset != s->cursor_offset ||
1192 s->cr[0xa] != s->cursor_start ||
1193 s->cr[0xb] != s->cursor_end) {
1194 /* if the cursor position changed, we update the old and new
1195 chars */
1196 if (s->cursor_offset < CH_ATTR_SIZE)
1197 s->last_ch_attr[s->cursor_offset] = -1;
1198 if (cursor_offset < CH_ATTR_SIZE)
1199 s->last_ch_attr[cursor_offset] = -1;
1200 s->cursor_offset = cursor_offset;
1201 s->cursor_start = s->cr[0xa];
1202 s->cursor_end = s->cr[0xb];
1203 }
39cf7803 1204 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
e89f66ec
FB
1205
1206 depth_index = get_depth_index(s->ds->depth);
17b0018b
FB
1207 if (cw == 16)
1208 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1209 else
1210 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
e89f66ec
FB
1211 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1212
1213 dest = s->ds->data;
1214 linesize = s->ds->linesize;
1215 ch_attr_ptr = s->last_ch_attr;
1216 for(cy = 0; cy < height; cy++) {
1217 d1 = dest;
1218 src = s1;
1219 cx_min = width;
1220 cx_max = -1;
1221 for(cx = 0; cx < width; cx++) {
1222 ch_attr = *(uint16_t *)src;
1223 if (full_update || ch_attr != *ch_attr_ptr) {
1224 if (cx < cx_min)
1225 cx_min = cx;
1226 if (cx > cx_max)
1227 cx_max = cx;
1228 *ch_attr_ptr = ch_attr;
1229#ifdef WORDS_BIGENDIAN
1230 ch = ch_attr >> 8;
1231 cattr = ch_attr & 0xff;
1232#else
1233 ch = ch_attr & 0xff;
1234 cattr = ch_attr >> 8;
1235#endif
1236 font_ptr = font_base[(cattr >> 3) & 1];
1237 font_ptr += 32 * 4 * ch;
1238 bgcol = palette[cattr >> 4];
1239 fgcol = palette[cattr & 0x0f];
17b0018b 1240 if (cw != 9) {
e89f66ec
FB
1241 vga_draw_glyph8(d1, linesize,
1242 font_ptr, cheight, fgcol, bgcol);
1243 } else {
1244 dup9 = 0;
1245 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1246 dup9 = 1;
1247 vga_draw_glyph9(d1, linesize,
1248 font_ptr, cheight, fgcol, bgcol, dup9);
1249 }
1250 if (src == cursor_ptr &&
1251 !(s->cr[0x0a] & 0x20)) {
1252 int line_start, line_last, h;
1253 /* draw the cursor */
1254 line_start = s->cr[0x0a] & 0x1f;
1255 line_last = s->cr[0x0b] & 0x1f;
1256 /* XXX: check that */
1257 if (line_last > cheight - 1)
1258 line_last = cheight - 1;
1259 if (line_last >= line_start && line_start < cheight) {
1260 h = line_last - line_start + 1;
1261 d = d1 + linesize * line_start;
17b0018b 1262 if (cw != 9) {
e89f66ec
FB
1263 vga_draw_glyph8(d, linesize,
1264 cursor_glyph, h, fgcol, bgcol);
1265 } else {
1266 vga_draw_glyph9(d, linesize,
1267 cursor_glyph, h, fgcol, bgcol, 1);
1268 }
1269 }
1270 }
1271 }
1272 d1 += x_incr;
1273 src += 4;
1274 ch_attr_ptr++;
1275 }
1276 if (cx_max != -1) {
1277 dpy_update(s->ds, cx_min * cw, cy * cheight,
1278 (cx_max - cx_min + 1) * cw, cheight);
1279 }
1280 dest += linesize * cheight;
1281 s1 += line_offset;
1282 }
1283}
1284
17b0018b
FB
1285enum {
1286 VGA_DRAW_LINE2,
1287 VGA_DRAW_LINE2D2,
1288 VGA_DRAW_LINE4,
1289 VGA_DRAW_LINE4D2,
1290 VGA_DRAW_LINE8D2,
1291 VGA_DRAW_LINE8,
1292 VGA_DRAW_LINE15,
1293 VGA_DRAW_LINE16,
4fa0f5d2 1294 VGA_DRAW_LINE24,
17b0018b
FB
1295 VGA_DRAW_LINE32,
1296 VGA_DRAW_LINE_NB,
1297};
1298
1299static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
e89f66ec
FB
1300 vga_draw_line2_8,
1301 vga_draw_line2_16,
1302 vga_draw_line2_16,
1303 vga_draw_line2_32,
1304
17b0018b
FB
1305 vga_draw_line2d2_8,
1306 vga_draw_line2d2_16,
1307 vga_draw_line2d2_16,
1308 vga_draw_line2d2_32,
1309
e89f66ec
FB
1310 vga_draw_line4_8,
1311 vga_draw_line4_16,
1312 vga_draw_line4_16,
1313 vga_draw_line4_32,
1314
17b0018b
FB
1315 vga_draw_line4d2_8,
1316 vga_draw_line4d2_16,
1317 vga_draw_line4d2_16,
1318 vga_draw_line4d2_32,
1319
1320 vga_draw_line8d2_8,
1321 vga_draw_line8d2_16,
1322 vga_draw_line8d2_16,
1323 vga_draw_line8d2_32,
1324
e89f66ec
FB
1325 vga_draw_line8_8,
1326 vga_draw_line8_16,
1327 vga_draw_line8_16,
1328 vga_draw_line8_32,
1329
1330 vga_draw_line15_8,
1331 vga_draw_line15_15,
1332 vga_draw_line15_16,
1333 vga_draw_line15_32,
1334
1335 vga_draw_line16_8,
1336 vga_draw_line16_15,
1337 vga_draw_line16_16,
1338 vga_draw_line16_32,
1339
4fa0f5d2
FB
1340 vga_draw_line24_8,
1341 vga_draw_line24_15,
1342 vga_draw_line24_16,
1343 vga_draw_line24_32,
1344
e89f66ec
FB
1345 vga_draw_line32_8,
1346 vga_draw_line32_15,
1347 vga_draw_line32_16,
1348 vga_draw_line32_32,
1349};
1350
1351/*
1352 * graphic modes
1353 * Missing:
1354 * - double scan
1355 * - double width
1356 */
1357static void vga_draw_graphic(VGAState *s, int full_update)
1358{
17b0018b 1359 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
39cf7803 1360 int width, height, shift_control, line_offset, page0, page1, bwidth;
a07cf92a 1361 int disp_width, multi_scan, multi_run;
e89f66ec 1362 uint8_t *d;
39cf7803 1363 uint32_t v, addr1, addr;
e89f66ec 1364 vga_draw_line_func *vga_draw_line;
17b0018b 1365
e89f66ec
FB
1366 full_update |= update_basic_params(s);
1367
39cf7803 1368 width = (s->cr[0x01] + 1) * 8;
e89f66ec
FB
1369 height = s->cr[0x12] |
1370 ((s->cr[0x07] & 0x02) << 7) |
1371 ((s->cr[0x07] & 0x40) << 3);
1372 height = (height + 1);
17b0018b
FB
1373 disp_width = width;
1374
e89f66ec 1375 shift_control = (s->gr[0x05] >> 5) & 3;
a07cf92a
FB
1376 double_scan = (s->cr[0x09] & 0x80);
1377 if (shift_control > 1) {
1378 multi_scan = (s->cr[0x09] & 0x1f);
1379 } else {
1380 multi_scan = 0;
1381 }
1382 multi_run = multi_scan;
17b0018b
FB
1383 if (shift_control != s->shift_control ||
1384 double_scan != s->double_scan) {
e89f66ec
FB
1385 full_update = 1;
1386 s->shift_control = shift_control;
17b0018b 1387 s->double_scan = double_scan;
e89f66ec
FB
1388 }
1389
17b0018b
FB
1390 if (shift_control == 0) {
1391 full_update |= update_palette16(s);
1392 if (s->sr[0x01] & 8) {
1393 v = VGA_DRAW_LINE4D2;
1394 disp_width <<= 1;
1395 } else {
1396 v = VGA_DRAW_LINE4;
1397 }
1398 } else if (shift_control == 1) {
1399 full_update |= update_palette16(s);
1400 if (s->sr[0x01] & 8) {
1401 v = VGA_DRAW_LINE2D2;
1402 disp_width <<= 1;
1403 } else {
1404 v = VGA_DRAW_LINE2;
1405 }
1406 } else {
4fa0f5d2
FB
1407#ifdef CONFIG_BOCHS_VBE
1408 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1409 switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) {
1410 default:
1411 case 8:
1412 full_update |= update_palette256(s);
1413 v = VGA_DRAW_LINE8;
1414 break;
1415 case 15:
1416 v = VGA_DRAW_LINE15;
1417 break;
1418 case 16:
1419 v = VGA_DRAW_LINE16;
1420 break;
1421 case 24:
1422 v = VGA_DRAW_LINE24;
1423 break;
1424 case 32:
1425 v = VGA_DRAW_LINE32;
1426 break;
1427 }
1428 } else
1429#endif
1430 {
1431 full_update |= update_palette256(s);
1432 v = VGA_DRAW_LINE8D2;
1433 }
17b0018b 1434 }
e89f66ec 1435 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
17b0018b
FB
1436
1437 if (disp_width != s->last_width ||
1438 height != s->last_height) {
1439 dpy_resize(s->ds, disp_width, height);
1440 s->last_width = disp_width;
1441 s->last_height = height;
1442 full_update = 1;
1443 }
1444
e89f66ec 1445 line_offset = s->line_offset;
17b0018b
FB
1446#if 0
1447 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1448 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1449#endif
e89f66ec 1450 addr1 = (s->start_addr * 4);
39cf7803
FB
1451 bwidth = width * 4;
1452 y_start = -1;
e89f66ec
FB
1453 page_min = 0x7fffffff;
1454 page_max = -1;
1455 d = s->ds->data;
1456 linesize = s->ds->linesize;
17b0018b 1457 y1 = 0;
e89f66ec
FB
1458 for(y = 0; y < height; y++) {
1459 addr = addr1;
39cf7803 1460 if (!(s->cr[0x17] & 1)) {
17b0018b 1461 int shift;
e89f66ec 1462 /* CGA compatibility handling */
17b0018b
FB
1463 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1464 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
e89f66ec 1465 }
39cf7803 1466 if (!(s->cr[0x17] & 2)) {
17b0018b 1467 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
e89f66ec 1468 }
4fa0f5d2
FB
1469 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1470 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1471 update = full_update | cpu_physical_memory_is_dirty(page0) |
1472 cpu_physical_memory_is_dirty(page1);
1473 if ((page1 - page0) > TARGET_PAGE_SIZE) {
39cf7803 1474 /* if wide line, can use another page */
4fa0f5d2 1475 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
39cf7803 1476 }
e89f66ec 1477 if (update) {
39cf7803
FB
1478 if (y_start < 0)
1479 y_start = y;
e89f66ec
FB
1480 if (page0 < page_min)
1481 page_min = page0;
1482 if (page1 > page_max)
1483 page_max = page1;
1484 vga_draw_line(s, d, s->vram_ptr + addr, width);
39cf7803
FB
1485 } else {
1486 if (y_start >= 0) {
1487 /* flush to display */
1488 dpy_update(s->ds, 0, y_start,
17b0018b 1489 disp_width, y - y_start);
39cf7803
FB
1490 y_start = -1;
1491 }
e89f66ec 1492 }
a07cf92a
FB
1493 if (!multi_run) {
1494 if (!double_scan || (y & 1) != 0) {
1495 if (y1 == s->line_compare) {
1496 addr1 = 0;
1497 } else {
1498 mask = (s->cr[0x17] & 3) ^ 3;
1499 if ((y1 & mask) == mask)
1500 addr1 += line_offset;
1501 }
1502 y1++;
17b0018b 1503 }
a07cf92a
FB
1504 multi_run = multi_scan;
1505 } else {
1506 multi_run--;
17b0018b 1507 y1++;
e89f66ec
FB
1508 }
1509 d += linesize;
1510 }
39cf7803
FB
1511 if (y_start >= 0) {
1512 /* flush to display */
1513 dpy_update(s->ds, 0, y_start,
17b0018b 1514 disp_width, y - y_start);
39cf7803 1515 }
e89f66ec
FB
1516 /* reset modified pages */
1517 if (page_max != -1) {
4fa0f5d2 1518 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
e89f66ec
FB
1519 }
1520}
1521
1522/* draw text terminal (very limited, just for simple boot debug
1523 messages) */
1524static int last_cursor_pos;
1525
1526void vga_draw_dumb(VGAState *s)
1527{
1528 int c, i, cursor_pos, eol;
1529
1530 cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8);
1531 eol = 0;
1532 for(i = last_cursor_pos; i < cursor_pos; i++) {
1533 /* XXX: should use vga RAM */
1534 c = phys_ram_base[0xb8000 + (i) * 2];
1535 if (c >= ' ') {
1536 putchar(c);
1537 eol = 0;
1538 } else {
1539 if (!eol)
1540 putchar('\n');
1541 eol = 1;
1542 }
1543 }
1544 fflush(stdout);
1545 last_cursor_pos = cursor_pos;
1546}
1547
1548void vga_update_display(void)
1549{
1550 VGAState *s = &vga_state;
1551 int full_update, graphic_mode;
1552
1553 if (s->ds->depth == 0) {
1554 vga_draw_dumb(s);
1555 } else {
1556 full_update = 0;
1557 graphic_mode = s->gr[6] & 1;
1558 if (graphic_mode != s->graphic_mode) {
1559 s->graphic_mode = graphic_mode;
1560 full_update = 1;
1561 }
1562 if (graphic_mode)
1563 vga_draw_graphic(s, full_update);
1564 else
1565 vga_draw_text(s, full_update);
1566 }
1567}
1568
1569void vga_reset(VGAState *s)
1570{
1571 memset(s, 0, sizeof(VGAState));
a41bc9af 1572#ifdef CONFIG_S3VGA
e89f66ec
FB
1573 /* chip ID for 8c968 */
1574 s->cr[0x2d] = 0x88;
1575 s->cr[0x2e] = 0xb0;
1576 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1577 s->cr[0x30] = 0xe1;
a41bc9af 1578#endif
e89f66ec
FB
1579 s->graphic_mode = -1; /* force full update */
1580}
1581
1582CPUReadMemoryFunc *vga_mem_read[3] = {
1583 vga_mem_readb,
1584 vga_mem_readw,
1585 vga_mem_readl,
1586};
1587
1588CPUWriteMemoryFunc *vga_mem_write[3] = {
1589 vga_mem_writeb,
1590 vga_mem_writew,
1591 vga_mem_writel,
1592};
1593
7138fcfb
FB
1594int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1595 unsigned long vga_ram_offset, int vga_ram_size)
e89f66ec
FB
1596{
1597 VGAState *s = &vga_state;
17b0018b 1598 int i, j, v, b;
e89f66ec
FB
1599
1600 for(i = 0;i < 256; i++) {
1601 v = 0;
1602 for(j = 0; j < 8; j++) {
1603 v |= ((i >> j) & 1) << (j * 4);
1604 }
1605 expand4[i] = v;
1606
1607 v = 0;
1608 for(j = 0; j < 4; j++) {
1609 v |= ((i >> (2 * j)) & 3) << (j * 4);
1610 }
1611 expand2[i] = v;
1612 }
17b0018b
FB
1613 for(i = 0; i < 16; i++) {
1614 v = 0;
1615 for(j = 0; j < 4; j++) {
1616 b = ((i >> j) & 1);
1617 v |= b << (2 * j);
1618 v |= b << (2 * j + 1);
1619 }
1620 expand4to8[i] = v;
1621 }
e89f66ec
FB
1622
1623 vga_reset(s);
1624
17b0018b
FB
1625 switch(ds->depth) {
1626 case 8:
1627 s->rgb_to_pixel = rgb_to_pixel8_dup;
1628 break;
1629 case 15:
1630 s->rgb_to_pixel = rgb_to_pixel15_dup;
1631 break;
1632 default:
1633 case 16:
1634 s->rgb_to_pixel = rgb_to_pixel16_dup;
1635 break;
1636 case 32:
1637 s->rgb_to_pixel = rgb_to_pixel32_dup;
1638 break;
1639 }
1640
e89f66ec
FB
1641 s->vram_ptr = vga_ram_base;
1642 s->vram_offset = vga_ram_offset;
1643 s->vram_size = vga_ram_size;
1644 s->ds = ds;
1645
1646 register_ioport_write(0x3c0, 16, vga_ioport_write, 1);
1647
1648 register_ioport_write(0x3b4, 2, vga_ioport_write, 1);
1649 register_ioport_write(0x3d4, 2, vga_ioport_write, 1);
1650 register_ioport_write(0x3ba, 1, vga_ioport_write, 1);
1651 register_ioport_write(0x3da, 1, vga_ioport_write, 1);
1652
1653 register_ioport_read(0x3c0, 16, vga_ioport_read, 1);
1654
1655 register_ioport_read(0x3b4, 2, vga_ioport_read, 1);
1656 register_ioport_read(0x3d4, 2, vga_ioport_read, 1);
1657 register_ioport_read(0x3ba, 1, vga_ioport_read, 1);
1658 register_ioport_read(0x3da, 1, vga_ioport_read, 1);
cae61cef 1659 s->bank_offset = -0xa0000;
e89f66ec 1660
4fa0f5d2
FB
1661#ifdef CONFIG_BOCHS_VBE
1662 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
cae61cef 1663 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
4fa0f5d2
FB
1664 register_ioport_read(0x1ce, 1, vbe_ioport_read, 2);
1665 register_ioport_read(0x1cf, 1, vbe_ioport_read, 2);
1666
1667 register_ioport_write(0x1ce, 1, vbe_ioport_write, 2);
1668 register_ioport_write(0x1cf, 1, vbe_ioport_write, 2);
1669#endif
1670
e89f66ec 1671 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
7138fcfb
FB
1672#if defined (TARGET_I386)
1673 cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory);
4fa0f5d2
FB
1674#ifdef CONFIG_BOCHS_VBE
1675 /* XXX: use optimized standard vga accesses */
1676 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1677 vga_ram_size, vga_ram_offset);
1678#endif
7138fcfb
FB
1679#elif defined (TARGET_PPC)
1680 cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory);
1681#endif
e89f66ec
FB
1682 return 0;
1683}