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