blob: 2e7de564fd406c8d73e0d71d798e89186dab81db [file] [log] [blame]
bellarde89f66e2003-08-04 23:30:47 +00001/*
bellard4fa0f5d2004-02-06 19:47:52 +00002 * QEMU VGA Emulator.
ths5fafdf22007-09-16 21:08:06 +00003 *
bellarde89f66e2003-08-04 23:30:47 +00004 * Copyright (c) 2003 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde89f66e2003-08-04 23:30:47 +00006 * 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 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "hw.h"
25#include "console.h"
26#include "pc.h"
27#include "pci.h"
bellard798b0c22004-06-05 10:30:49 +000028#include "vga_int.h"
blueswir194470842007-06-10 16:06:20 +000029#include "pixel_ops.h"
bellarde89f66e2003-08-04 23:30:47 +000030
bellarde89f66e2003-08-04 23:30:47 +000031//#define DEBUG_VGA
bellard17b00182003-08-08 23:50:57 +000032//#define DEBUG_VGA_MEM
bellarda41bc9a2004-01-04 15:55:00 +000033//#define DEBUG_VGA_REG
34
bellard4fa0f5d2004-02-06 19:47:52 +000035//#define DEBUG_BOCHS_VBE
36
bellarde89f66e2003-08-04 23:30:47 +000037/* force some bits to zero */
bellard798b0c22004-06-05 10:30:49 +000038const uint8_t sr_mask[8] = {
bellarde89f66e2003-08-04 23:30:47 +000039 (uint8_t)~0xfc,
40 (uint8_t)~0xc2,
41 (uint8_t)~0xf0,
42 (uint8_t)~0xc0,
43 (uint8_t)~0xf1,
44 (uint8_t)~0xff,
45 (uint8_t)~0xff,
46 (uint8_t)~0x00,
47};
48
bellard798b0c22004-06-05 10:30:49 +000049const uint8_t gr_mask[16] = {
bellarde89f66e2003-08-04 23:30:47 +000050 (uint8_t)~0xf0, /* 0x00 */
51 (uint8_t)~0xf0, /* 0x01 */
52 (uint8_t)~0xf0, /* 0x02 */
53 (uint8_t)~0xe0, /* 0x03 */
54 (uint8_t)~0xfc, /* 0x04 */
55 (uint8_t)~0x84, /* 0x05 */
56 (uint8_t)~0xf0, /* 0x06 */
57 (uint8_t)~0xf0, /* 0x07 */
58 (uint8_t)~0x00, /* 0x08 */
59 (uint8_t)~0xff, /* 0x09 */
60 (uint8_t)~0xff, /* 0x0a */
61 (uint8_t)~0xff, /* 0x0b */
62 (uint8_t)~0xff, /* 0x0c */
63 (uint8_t)~0xff, /* 0x0d */
64 (uint8_t)~0xff, /* 0x0e */
65 (uint8_t)~0xff, /* 0x0f */
66};
67
68#define cbswap_32(__x) \
69((uint32_t)( \
70 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
71 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
72 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
73 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
74
bellardb8ed2232003-10-30 22:10:22 +000075#ifdef WORDS_BIGENDIAN
bellarde89f66e2003-08-04 23:30:47 +000076#define PAT(x) cbswap_32(x)
77#else
78#define PAT(x) (x)
79#endif
80
bellardb8ed2232003-10-30 22:10:22 +000081#ifdef WORDS_BIGENDIAN
82#define BIG 1
83#else
84#define BIG 0
85#endif
86
87#ifdef WORDS_BIGENDIAN
88#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
89#else
90#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
91#endif
92
bellarde89f66e2003-08-04 23:30:47 +000093static const uint32_t mask16[16] = {
94 PAT(0x00000000),
95 PAT(0x000000ff),
96 PAT(0x0000ff00),
97 PAT(0x0000ffff),
98 PAT(0x00ff0000),
99 PAT(0x00ff00ff),
100 PAT(0x00ffff00),
101 PAT(0x00ffffff),
102 PAT(0xff000000),
103 PAT(0xff0000ff),
104 PAT(0xff00ff00),
105 PAT(0xff00ffff),
106 PAT(0xffff0000),
107 PAT(0xffff00ff),
108 PAT(0xffffff00),
109 PAT(0xffffffff),
110};
111
112#undef PAT
113
bellardb8ed2232003-10-30 22:10:22 +0000114#ifdef WORDS_BIGENDIAN
bellarde89f66e2003-08-04 23:30:47 +0000115#define PAT(x) (x)
116#else
117#define PAT(x) cbswap_32(x)
118#endif
119
120static const uint32_t dmask16[16] = {
121 PAT(0x00000000),
122 PAT(0x000000ff),
123 PAT(0x0000ff00),
124 PAT(0x0000ffff),
125 PAT(0x00ff0000),
126 PAT(0x00ff00ff),
127 PAT(0x00ffff00),
128 PAT(0x00ffffff),
129 PAT(0xff000000),
130 PAT(0xff0000ff),
131 PAT(0xff00ff00),
132 PAT(0xff00ffff),
133 PAT(0xffff0000),
134 PAT(0xffff00ff),
135 PAT(0xffffff00),
136 PAT(0xffffffff),
137};
138
139static const uint32_t dmask4[4] = {
140 PAT(0x00000000),
141 PAT(0x0000ffff),
142 PAT(0xffff0000),
143 PAT(0xffffffff),
144};
145
146static uint32_t expand4[256];
147static uint16_t expand2[256];
bellard17b00182003-08-08 23:50:57 +0000148static uint8_t expand4to8[16];
bellarde89f66e2003-08-04 23:30:47 +0000149
pbrook95219892006-04-09 01:06:34 +0000150static void vga_screen_dump(void *opaque, const char *filename);
151
bellard0f359202004-03-14 21:42:10 +0000152static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
bellarde89f66e2003-08-04 23:30:47 +0000153{
bellard0f359202004-03-14 21:42:10 +0000154 VGAState *s = opaque;
bellarde89f66e2003-08-04 23:30:47 +0000155 int val, index;
156
157 /* check port range access depending on color/monochrome mode */
158 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
159 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
160 val = 0xff;
161 } else {
162 switch(addr) {
163 case 0x3c0:
164 if (s->ar_flip_flop == 0) {
165 val = s->ar_index;
166 } else {
167 val = 0;
168 }
169 break;
170 case 0x3c1:
171 index = s->ar_index & 0x1f;
ths5fafdf22007-09-16 21:08:06 +0000172 if (index < 21)
bellarde89f66e2003-08-04 23:30:47 +0000173 val = s->ar[index];
174 else
175 val = 0;
176 break;
177 case 0x3c2:
178 val = s->st00;
179 break;
180 case 0x3c4:
181 val = s->sr_index;
182 break;
183 case 0x3c5:
184 val = s->sr[s->sr_index];
bellarda41bc9a2004-01-04 15:55:00 +0000185#ifdef DEBUG_VGA_REG
186 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
187#endif
bellarde89f66e2003-08-04 23:30:47 +0000188 break;
189 case 0x3c7:
190 val = s->dac_state;
191 break;
bellarde6eccb32004-06-26 16:12:26 +0000192 case 0x3c8:
193 val = s->dac_write_index;
194 break;
bellarde89f66e2003-08-04 23:30:47 +0000195 case 0x3c9:
196 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
197 if (++s->dac_sub_index == 3) {
198 s->dac_sub_index = 0;
199 s->dac_read_index++;
200 }
201 break;
202 case 0x3ca:
203 val = s->fcr;
204 break;
205 case 0x3cc:
206 val = s->msr;
207 break;
208 case 0x3ce:
209 val = s->gr_index;
210 break;
211 case 0x3cf:
212 val = s->gr[s->gr_index];
bellarda41bc9a2004-01-04 15:55:00 +0000213#ifdef DEBUG_VGA_REG
214 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
215#endif
bellarde89f66e2003-08-04 23:30:47 +0000216 break;
217 case 0x3b4:
218 case 0x3d4:
219 val = s->cr_index;
220 break;
221 case 0x3b5:
222 case 0x3d5:
223 val = s->cr[s->cr_index];
bellarda41bc9a2004-01-04 15:55:00 +0000224#ifdef DEBUG_VGA_REG
225 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
226#endif
bellarde89f66e2003-08-04 23:30:47 +0000227 break;
228 case 0x3ba:
229 case 0x3da:
230 /* just toggle to fool polling */
231 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
232 val = s->st01;
233 s->ar_flip_flop = 0;
234 break;
235 default:
236 val = 0x00;
237 break;
238 }
239 }
bellard4fa0f5d2004-02-06 19:47:52 +0000240#if defined(DEBUG_VGA)
bellarde89f66e2003-08-04 23:30:47 +0000241 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
242#endif
243 return val;
244}
245
bellard0f359202004-03-14 21:42:10 +0000246static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
bellarde89f66e2003-08-04 23:30:47 +0000247{
bellard0f359202004-03-14 21:42:10 +0000248 VGAState *s = opaque;
bellard5467a722004-04-25 17:59:00 +0000249 int index;
bellarde89f66e2003-08-04 23:30:47 +0000250
251 /* check port range access depending on color/monochrome mode */
252 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
253 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
254 return;
255
256#ifdef DEBUG_VGA
257 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
258#endif
259
260 switch(addr) {
261 case 0x3c0:
262 if (s->ar_flip_flop == 0) {
263 val &= 0x3f;
264 s->ar_index = val;
265 } else {
266 index = s->ar_index & 0x1f;
267 switch(index) {
268 case 0x00 ... 0x0f:
269 s->ar[index] = val & 0x3f;
270 break;
271 case 0x10:
272 s->ar[index] = val & ~0x10;
273 break;
274 case 0x11:
275 s->ar[index] = val;
276 break;
277 case 0x12:
278 s->ar[index] = val & ~0xc0;
279 break;
280 case 0x13:
281 s->ar[index] = val & ~0xf0;
282 break;
283 case 0x14:
284 s->ar[index] = val & ~0xf0;
285 break;
286 default:
287 break;
288 }
289 }
290 s->ar_flip_flop ^= 1;
291 break;
292 case 0x3c2:
293 s->msr = val & ~0x10;
294 break;
295 case 0x3c4:
296 s->sr_index = val & 7;
297 break;
298 case 0x3c5:
bellarda41bc9a2004-01-04 15:55:00 +0000299#ifdef DEBUG_VGA_REG
300 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
301#endif
bellarde89f66e2003-08-04 23:30:47 +0000302 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
303 break;
304 case 0x3c7:
305 s->dac_read_index = val;
306 s->dac_sub_index = 0;
307 s->dac_state = 3;
308 break;
309 case 0x3c8:
310 s->dac_write_index = val;
311 s->dac_sub_index = 0;
312 s->dac_state = 0;
313 break;
314 case 0x3c9:
315 s->dac_cache[s->dac_sub_index] = val;
316 if (++s->dac_sub_index == 3) {
317 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
318 s->dac_sub_index = 0;
319 s->dac_write_index++;
320 }
321 break;
322 case 0x3ce:
323 s->gr_index = val & 0x0f;
324 break;
325 case 0x3cf:
bellarda41bc9a2004-01-04 15:55:00 +0000326#ifdef DEBUG_VGA_REG
327 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
328#endif
bellarde89f66e2003-08-04 23:30:47 +0000329 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
330 break;
331 case 0x3b4:
332 case 0x3d4:
333 s->cr_index = val;
334 break;
335 case 0x3b5:
336 case 0x3d5:
bellarda41bc9a2004-01-04 15:55:00 +0000337#ifdef DEBUG_VGA_REG
338 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
339#endif
bellarde89f66e2003-08-04 23:30:47 +0000340 /* handle CR0-7 protection */
bellardf6c958c2004-11-07 22:57:20 +0000341 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
bellarde89f66e2003-08-04 23:30:47 +0000342 /* can always write bit 4 of CR7 */
343 if (s->cr_index == 7)
344 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
345 return;
346 }
347 switch(s->cr_index) {
348 case 0x01: /* horizontal display end */
349 case 0x07:
350 case 0x09:
351 case 0x0c:
352 case 0x0d:
thse91c8a72007-06-03 13:35:16 +0000353 case 0x12: /* vertical display end */
bellarde89f66e2003-08-04 23:30:47 +0000354 s->cr[s->cr_index] = val;
355 break;
bellarde89f66e2003-08-04 23:30:47 +0000356 default:
357 s->cr[s->cr_index] = val;
358 break;
359 }
360 break;
361 case 0x3ba:
362 case 0x3da:
363 s->fcr = val & 0x10;
364 break;
365 }
366}
367
bellard4fa0f5d2004-02-06 19:47:52 +0000368#ifdef CONFIG_BOCHS_VBE
bellard09a79b42004-05-26 22:58:01 +0000369static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
370{
371 VGAState *s = opaque;
372 uint32_t val;
373 val = s->vbe_index;
374 return val;
375}
376
377static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
bellard4fa0f5d2004-02-06 19:47:52 +0000378{
bellard0f359202004-03-14 21:42:10 +0000379 VGAState *s = opaque;
bellard4fa0f5d2004-02-06 19:47:52 +0000380 uint32_t val;
381
bellard8454df82006-06-13 16:37:40 +0000382 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
383 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
384 switch(s->vbe_index) {
385 /* XXX: do not hardcode ? */
386 case VBE_DISPI_INDEX_XRES:
387 val = VBE_DISPI_MAX_XRES;
388 break;
389 case VBE_DISPI_INDEX_YRES:
390 val = VBE_DISPI_MAX_YRES;
391 break;
392 case VBE_DISPI_INDEX_BPP:
393 val = VBE_DISPI_MAX_BPP;
394 break;
395 default:
ths5fafdf22007-09-16 21:08:06 +0000396 val = s->vbe_regs[s->vbe_index];
bellard8454df82006-06-13 16:37:40 +0000397 break;
398 }
399 } else {
ths5fafdf22007-09-16 21:08:06 +0000400 val = s->vbe_regs[s->vbe_index];
bellard8454df82006-06-13 16:37:40 +0000401 }
402 } else {
bellard09a79b42004-05-26 22:58:01 +0000403 val = 0;
bellard8454df82006-06-13 16:37:40 +0000404 }
bellard4fa0f5d2004-02-06 19:47:52 +0000405#ifdef DEBUG_BOCHS_VBE
bellard09a79b42004-05-26 22:58:01 +0000406 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
bellard4fa0f5d2004-02-06 19:47:52 +0000407#endif
bellard4fa0f5d2004-02-06 19:47:52 +0000408 return val;
409}
410
bellard09a79b42004-05-26 22:58:01 +0000411static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
412{
413 VGAState *s = opaque;
414 s->vbe_index = val;
415}
416
417static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
bellard4fa0f5d2004-02-06 19:47:52 +0000418{
bellard0f359202004-03-14 21:42:10 +0000419 VGAState *s = opaque;
bellard4fa0f5d2004-02-06 19:47:52 +0000420
bellard09a79b42004-05-26 22:58:01 +0000421 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
bellard4fa0f5d2004-02-06 19:47:52 +0000422#ifdef DEBUG_BOCHS_VBE
423 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
424#endif
425 switch(s->vbe_index) {
426 case VBE_DISPI_INDEX_ID:
bellardcae61ce2004-02-06 23:58:08 +0000427 if (val == VBE_DISPI_ID0 ||
428 val == VBE_DISPI_ID1 ||
bellard37dd2082006-09-21 21:46:53 +0000429 val == VBE_DISPI_ID2 ||
430 val == VBE_DISPI_ID3 ||
431 val == VBE_DISPI_ID4) {
bellardcae61ce2004-02-06 23:58:08 +0000432 s->vbe_regs[s->vbe_index] = val;
433 }
bellard4fa0f5d2004-02-06 19:47:52 +0000434 break;
435 case VBE_DISPI_INDEX_XRES:
bellardcae61ce2004-02-06 23:58:08 +0000436 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
437 s->vbe_regs[s->vbe_index] = val;
438 }
bellard4fa0f5d2004-02-06 19:47:52 +0000439 break;
440 case VBE_DISPI_INDEX_YRES:
bellardcae61ce2004-02-06 23:58:08 +0000441 if (val <= VBE_DISPI_MAX_YRES) {
442 s->vbe_regs[s->vbe_index] = val;
443 }
bellard4fa0f5d2004-02-06 19:47:52 +0000444 break;
445 case VBE_DISPI_INDEX_BPP:
446 if (val == 0)
447 val = 8;
ths5fafdf22007-09-16 21:08:06 +0000448 if (val == 4 || val == 8 || val == 15 ||
bellardcae61ce2004-02-06 23:58:08 +0000449 val == 16 || val == 24 || val == 32) {
450 s->vbe_regs[s->vbe_index] = val;
451 }
bellard4fa0f5d2004-02-06 19:47:52 +0000452 break;
453 case VBE_DISPI_INDEX_BANK:
bellard42fc9252006-09-25 21:41:20 +0000454 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
455 val &= (s->vbe_bank_mask >> 2);
456 } else {
457 val &= s->vbe_bank_mask;
458 }
bellardcae61ce2004-02-06 23:58:08 +0000459 s->vbe_regs[s->vbe_index] = val;
bellard26aa7d72004-04-28 22:26:05 +0000460 s->bank_offset = (val << 16);
bellard4fa0f5d2004-02-06 19:47:52 +0000461 break;
462 case VBE_DISPI_INDEX_ENABLE:
bellard8454df82006-06-13 16:37:40 +0000463 if ((val & VBE_DISPI_ENABLED) &&
464 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
bellard4fa0f5d2004-02-06 19:47:52 +0000465 int h, shift_control;
466
ths5fafdf22007-09-16 21:08:06 +0000467 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
bellard4fa0f5d2004-02-06 19:47:52 +0000468 s->vbe_regs[VBE_DISPI_INDEX_XRES];
ths5fafdf22007-09-16 21:08:06 +0000469 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
bellard4fa0f5d2004-02-06 19:47:52 +0000470 s->vbe_regs[VBE_DISPI_INDEX_YRES];
471 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
472 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
ths3b46e622007-09-17 08:09:54 +0000473
bellard4fa0f5d2004-02-06 19:47:52 +0000474 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
475 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
476 else
ths5fafdf22007-09-16 21:08:06 +0000477 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
bellard4fa0f5d2004-02-06 19:47:52 +0000478 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
479 s->vbe_start_addr = 0;
bellard8454df82006-06-13 16:37:40 +0000480
bellard4fa0f5d2004-02-06 19:47:52 +0000481 /* clear the screen (should be done in BIOS) */
482 if (!(val & VBE_DISPI_NOCLEARMEM)) {
ths5fafdf22007-09-16 21:08:06 +0000483 memset(s->vram_ptr, 0,
bellard4fa0f5d2004-02-06 19:47:52 +0000484 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
485 }
ths3b46e622007-09-17 08:09:54 +0000486
bellardcae61ce2004-02-06 23:58:08 +0000487 /* we initialize the VGA graphic mode (should be done
488 in BIOS) */
489 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
bellard4fa0f5d2004-02-06 19:47:52 +0000490 s->cr[0x17] |= 3; /* no CGA modes */
491 s->cr[0x13] = s->vbe_line_offset >> 3;
492 /* width */
493 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
bellard8454df82006-06-13 16:37:40 +0000494 /* height (only meaningful if < 1024) */
bellard4fa0f5d2004-02-06 19:47:52 +0000495 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
496 s->cr[0x12] = h;
ths5fafdf22007-09-16 21:08:06 +0000497 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
bellard4fa0f5d2004-02-06 19:47:52 +0000498 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
499 /* line compare to 1023 */
500 s->cr[0x18] = 0xff;
501 s->cr[0x07] |= 0x10;
502 s->cr[0x09] |= 0x40;
ths3b46e622007-09-17 08:09:54 +0000503
bellard4fa0f5d2004-02-06 19:47:52 +0000504 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
505 shift_control = 0;
506 s->sr[0x01] &= ~8; /* no double line */
507 } else {
508 shift_control = 2;
bellard646be932004-04-28 22:38:47 +0000509 s->sr[4] |= 0x08; /* set chain 4 mode */
bellard141253b2004-04-29 19:21:16 +0000510 s->sr[2] |= 0x0f; /* activate all planes */
bellard4fa0f5d2004-02-06 19:47:52 +0000511 }
512 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
513 s->cr[0x09] &= ~0x9f; /* no double scan */
bellardcae61ce2004-02-06 23:58:08 +0000514 } else {
515 /* XXX: the bios should do that */
bellard26aa7d72004-04-28 22:26:05 +0000516 s->bank_offset = 0;
bellardcae61ce2004-02-06 23:58:08 +0000517 }
bellard37dd2082006-09-21 21:46:53 +0000518 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
bellard141253b2004-04-29 19:21:16 +0000519 s->vbe_regs[s->vbe_index] = val;
bellardcae61ce2004-02-06 23:58:08 +0000520 break;
521 case VBE_DISPI_INDEX_VIRT_WIDTH:
522 {
523 int w, h, line_offset;
524
525 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
526 return;
527 w = val;
528 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
529 line_offset = w >> 1;
530 else
531 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
532 h = s->vram_size / line_offset;
533 /* XXX: support weird bochs semantics ? */
534 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
535 return;
536 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
537 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
538 s->vbe_line_offset = line_offset;
539 }
540 break;
541 case VBE_DISPI_INDEX_X_OFFSET:
542 case VBE_DISPI_INDEX_Y_OFFSET:
543 {
544 int x;
545 s->vbe_regs[s->vbe_index] = val;
546 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
547 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
548 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
549 s->vbe_start_addr += x >> 1;
550 else
551 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
552 s->vbe_start_addr >>= 2;
bellard4fa0f5d2004-02-06 19:47:52 +0000553 }
554 break;
555 default:
556 break;
557 }
bellard4fa0f5d2004-02-06 19:47:52 +0000558 }
559}
560#endif
561
bellarde89f66e2003-08-04 23:30:47 +0000562/* called for accesses between 0xa0000 and 0xc0000 */
bellard798b0c22004-06-05 10:30:49 +0000563uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
bellarde89f66e2003-08-04 23:30:47 +0000564{
bellarda4193c82004-06-03 14:01:43 +0000565 VGAState *s = opaque;
bellarde89f66e2003-08-04 23:30:47 +0000566 int memory_map_mode, plane;
567 uint32_t ret;
ths3b46e622007-09-17 08:09:54 +0000568
bellarde89f66e2003-08-04 23:30:47 +0000569 /* convert to VGA memory offset */
570 memory_map_mode = (s->gr[6] >> 2) & 3;
bellard26aa7d72004-04-28 22:26:05 +0000571 addr &= 0x1ffff;
bellarde89f66e2003-08-04 23:30:47 +0000572 switch(memory_map_mode) {
573 case 0:
bellarde89f66e2003-08-04 23:30:47 +0000574 break;
575 case 1:
bellard26aa7d72004-04-28 22:26:05 +0000576 if (addr >= 0x10000)
bellarde89f66e2003-08-04 23:30:47 +0000577 return 0xff;
bellardcae61ce2004-02-06 23:58:08 +0000578 addr += s->bank_offset;
bellarde89f66e2003-08-04 23:30:47 +0000579 break;
580 case 2:
bellard26aa7d72004-04-28 22:26:05 +0000581 addr -= 0x10000;
bellarde89f66e2003-08-04 23:30:47 +0000582 if (addr >= 0x8000)
583 return 0xff;
584 break;
585 default:
586 case 3:
bellard26aa7d72004-04-28 22:26:05 +0000587 addr -= 0x18000;
bellardc92b2e82004-01-27 00:14:11 +0000588 if (addr >= 0x8000)
589 return 0xff;
bellarde89f66e2003-08-04 23:30:47 +0000590 break;
591 }
ths3b46e622007-09-17 08:09:54 +0000592
bellarde89f66e2003-08-04 23:30:47 +0000593 if (s->sr[4] & 0x08) {
594 /* chain 4 mode : simplest access */
595 ret = s->vram_ptr[addr];
596 } else if (s->gr[5] & 0x10) {
597 /* odd/even mode (aka text mode mapping) */
598 plane = (s->gr[4] & 2) | (addr & 1);
599 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
600 } else {
601 /* standard VGA latched access */
602 s->latch = ((uint32_t *)s->vram_ptr)[addr];
603
604 if (!(s->gr[5] & 0x08)) {
605 /* read mode 0 */
606 plane = s->gr[4];
bellardb8ed2232003-10-30 22:10:22 +0000607 ret = GET_PLANE(s->latch, plane);
bellarde89f66e2003-08-04 23:30:47 +0000608 } else {
609 /* read mode 1 */
610 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
611 ret |= ret >> 16;
612 ret |= ret >> 8;
613 ret = (~ret) & 0xff;
614 }
615 }
616 return ret;
617}
618
bellarda4193c82004-06-03 14:01:43 +0000619static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
bellarde89f66e2003-08-04 23:30:47 +0000620{
621 uint32_t v;
bellard09a79b42004-05-26 22:58:01 +0000622#ifdef TARGET_WORDS_BIGENDIAN
bellarda4193c82004-06-03 14:01:43 +0000623 v = vga_mem_readb(opaque, addr) << 8;
624 v |= vga_mem_readb(opaque, addr + 1);
bellard09a79b42004-05-26 22:58:01 +0000625#else
bellarda4193c82004-06-03 14:01:43 +0000626 v = vga_mem_readb(opaque, addr);
627 v |= vga_mem_readb(opaque, addr + 1) << 8;
bellard09a79b42004-05-26 22:58:01 +0000628#endif
bellarde89f66e2003-08-04 23:30:47 +0000629 return v;
630}
631
bellarda4193c82004-06-03 14:01:43 +0000632static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
bellarde89f66e2003-08-04 23:30:47 +0000633{
634 uint32_t v;
bellard09a79b42004-05-26 22:58:01 +0000635#ifdef TARGET_WORDS_BIGENDIAN
bellarda4193c82004-06-03 14:01:43 +0000636 v = vga_mem_readb(opaque, addr) << 24;
637 v |= vga_mem_readb(opaque, addr + 1) << 16;
638 v |= vga_mem_readb(opaque, addr + 2) << 8;
639 v |= vga_mem_readb(opaque, addr + 3);
bellard09a79b42004-05-26 22:58:01 +0000640#else
bellarda4193c82004-06-03 14:01:43 +0000641 v = vga_mem_readb(opaque, addr);
642 v |= vga_mem_readb(opaque, addr + 1) << 8;
643 v |= vga_mem_readb(opaque, addr + 2) << 16;
644 v |= vga_mem_readb(opaque, addr + 3) << 24;
bellard09a79b42004-05-26 22:58:01 +0000645#endif
bellarde89f66e2003-08-04 23:30:47 +0000646 return v;
647}
648
bellarde89f66e2003-08-04 23:30:47 +0000649/* called for accesses between 0xa0000 and 0xc0000 */
bellard798b0c22004-06-05 10:30:49 +0000650void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
bellarde89f66e2003-08-04 23:30:47 +0000651{
bellarda4193c82004-06-03 14:01:43 +0000652 VGAState *s = opaque;
bellard546fa6a2004-11-14 17:52:01 +0000653 int memory_map_mode, plane, write_mode, b, func_select, mask;
bellarde89f66e2003-08-04 23:30:47 +0000654 uint32_t write_mask, bit_mask, set_mask;
655
bellard17b00182003-08-08 23:50:57 +0000656#ifdef DEBUG_VGA_MEM
bellarde89f66e2003-08-04 23:30:47 +0000657 printf("vga: [0x%x] = 0x%02x\n", addr, val);
658#endif
659 /* convert to VGA memory offset */
660 memory_map_mode = (s->gr[6] >> 2) & 3;
bellard26aa7d72004-04-28 22:26:05 +0000661 addr &= 0x1ffff;
bellarde89f66e2003-08-04 23:30:47 +0000662 switch(memory_map_mode) {
663 case 0:
bellarde89f66e2003-08-04 23:30:47 +0000664 break;
665 case 1:
bellard26aa7d72004-04-28 22:26:05 +0000666 if (addr >= 0x10000)
bellarde89f66e2003-08-04 23:30:47 +0000667 return;
bellardcae61ce2004-02-06 23:58:08 +0000668 addr += s->bank_offset;
bellarde89f66e2003-08-04 23:30:47 +0000669 break;
670 case 2:
bellard26aa7d72004-04-28 22:26:05 +0000671 addr -= 0x10000;
bellarde89f66e2003-08-04 23:30:47 +0000672 if (addr >= 0x8000)
673 return;
674 break;
675 default:
676 case 3:
bellard26aa7d72004-04-28 22:26:05 +0000677 addr -= 0x18000;
bellardc92b2e82004-01-27 00:14:11 +0000678 if (addr >= 0x8000)
679 return;
bellarde89f66e2003-08-04 23:30:47 +0000680 break;
681 }
ths3b46e622007-09-17 08:09:54 +0000682
bellarde89f66e2003-08-04 23:30:47 +0000683 if (s->sr[4] & 0x08) {
684 /* chain 4 mode : simplest access */
685 plane = addr & 3;
bellard546fa6a2004-11-14 17:52:01 +0000686 mask = (1 << plane);
687 if (s->sr[2] & mask) {
bellarde89f66e2003-08-04 23:30:47 +0000688 s->vram_ptr[addr] = val;
bellard17b00182003-08-08 23:50:57 +0000689#ifdef DEBUG_VGA_MEM
bellarde89f66e2003-08-04 23:30:47 +0000690 printf("vga: chain4: [0x%x]\n", addr);
691#endif
bellard546fa6a2004-11-14 17:52:01 +0000692 s->plane_updated |= mask; /* only used to detect font change */
bellard4fa0f5d2004-02-06 19:47:52 +0000693 cpu_physical_memory_set_dirty(s->vram_offset + addr);
bellarde89f66e2003-08-04 23:30:47 +0000694 }
695 } else if (s->gr[5] & 0x10) {
696 /* odd/even mode (aka text mode mapping) */
697 plane = (s->gr[4] & 2) | (addr & 1);
bellard546fa6a2004-11-14 17:52:01 +0000698 mask = (1 << plane);
699 if (s->sr[2] & mask) {
bellarde89f66e2003-08-04 23:30:47 +0000700 addr = ((addr & ~1) << 1) | plane;
701 s->vram_ptr[addr] = val;
bellard17b00182003-08-08 23:50:57 +0000702#ifdef DEBUG_VGA_MEM
bellarde89f66e2003-08-04 23:30:47 +0000703 printf("vga: odd/even: [0x%x]\n", addr);
704#endif
bellard546fa6a2004-11-14 17:52:01 +0000705 s->plane_updated |= mask; /* only used to detect font change */
bellard4fa0f5d2004-02-06 19:47:52 +0000706 cpu_physical_memory_set_dirty(s->vram_offset + addr);
bellarde89f66e2003-08-04 23:30:47 +0000707 }
708 } else {
709 /* standard VGA latched access */
710 write_mode = s->gr[5] & 3;
711 switch(write_mode) {
712 default:
713 case 0:
714 /* rotate */
715 b = s->gr[3] & 7;
716 val = ((val >> b) | (val << (8 - b))) & 0xff;
717 val |= val << 8;
718 val |= val << 16;
719
720 /* apply set/reset mask */
721 set_mask = mask16[s->gr[1]];
722 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
723 bit_mask = s->gr[8];
724 break;
725 case 1:
726 val = s->latch;
727 goto do_write;
728 case 2:
729 val = mask16[val & 0x0f];
730 bit_mask = s->gr[8];
731 break;
732 case 3:
733 /* rotate */
734 b = s->gr[3] & 7;
bellarda41bc9a2004-01-04 15:55:00 +0000735 val = (val >> b) | (val << (8 - b));
bellarde89f66e2003-08-04 23:30:47 +0000736
737 bit_mask = s->gr[8] & val;
738 val = mask16[s->gr[0]];
739 break;
740 }
741
742 /* apply logical operation */
743 func_select = s->gr[3] >> 3;
744 switch(func_select) {
745 case 0:
746 default:
747 /* nothing to do */
748 break;
749 case 1:
750 /* and */
751 val &= s->latch;
752 break;
753 case 2:
754 /* or */
755 val |= s->latch;
756 break;
757 case 3:
758 /* xor */
759 val ^= s->latch;
760 break;
761 }
762
763 /* apply bit mask */
764 bit_mask |= bit_mask << 8;
765 bit_mask |= bit_mask << 16;
766 val = (val & bit_mask) | (s->latch & ~bit_mask);
767
768 do_write:
769 /* mask data according to sr[2] */
bellard546fa6a2004-11-14 17:52:01 +0000770 mask = s->sr[2];
771 s->plane_updated |= mask; /* only used to detect font change */
772 write_mask = mask16[mask];
ths5fafdf22007-09-16 21:08:06 +0000773 ((uint32_t *)s->vram_ptr)[addr] =
774 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
bellarde89f66e2003-08-04 23:30:47 +0000775 (val & write_mask);
bellard17b00182003-08-08 23:50:57 +0000776#ifdef DEBUG_VGA_MEM
ths5fafdf22007-09-16 21:08:06 +0000777 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
bellarde89f66e2003-08-04 23:30:47 +0000778 addr * 4, write_mask, val);
779#endif
bellard4fa0f5d2004-02-06 19:47:52 +0000780 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
bellarde89f66e2003-08-04 23:30:47 +0000781 }
782}
783
bellarda4193c82004-06-03 14:01:43 +0000784static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
bellarde89f66e2003-08-04 23:30:47 +0000785{
bellard09a79b42004-05-26 22:58:01 +0000786#ifdef TARGET_WORDS_BIGENDIAN
bellarda4193c82004-06-03 14:01:43 +0000787 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
788 vga_mem_writeb(opaque, addr + 1, val & 0xff);
bellard09a79b42004-05-26 22:58:01 +0000789#else
bellarda4193c82004-06-03 14:01:43 +0000790 vga_mem_writeb(opaque, addr, val & 0xff);
791 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
bellard09a79b42004-05-26 22:58:01 +0000792#endif
bellarde89f66e2003-08-04 23:30:47 +0000793}
794
bellarda4193c82004-06-03 14:01:43 +0000795static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
bellarde89f66e2003-08-04 23:30:47 +0000796{
bellard09a79b42004-05-26 22:58:01 +0000797#ifdef TARGET_WORDS_BIGENDIAN
bellarda4193c82004-06-03 14:01:43 +0000798 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
799 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
800 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
801 vga_mem_writeb(opaque, addr + 3, val & 0xff);
bellard09a79b42004-05-26 22:58:01 +0000802#else
bellarda4193c82004-06-03 14:01:43 +0000803 vga_mem_writeb(opaque, addr, val & 0xff);
804 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
805 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
806 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
bellard09a79b42004-05-26 22:58:01 +0000807#endif
bellarde89f66e2003-08-04 23:30:47 +0000808}
809
bellarde89f66e2003-08-04 23:30:47 +0000810typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
811 const uint8_t *font_ptr, int h,
812 uint32_t fgcol, uint32_t bgcol);
813typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
ths5fafdf22007-09-16 21:08:06 +0000814 const uint8_t *font_ptr, int h,
bellarde89f66e2003-08-04 23:30:47 +0000815 uint32_t fgcol, uint32_t bgcol, int dup9);
ths5fafdf22007-09-16 21:08:06 +0000816typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
bellarde89f66e2003-08-04 23:30:47 +0000817 const uint8_t *s, int width);
818
bellarde89f66e2003-08-04 23:30:47 +0000819#define DEPTH 8
820#include "vga_template.h"
821
822#define DEPTH 15
823#include "vga_template.h"
824
blueswir1a2502b52007-06-10 17:01:00 +0000825#define BGR_FORMAT
826#define DEPTH 15
827#include "vga_template.h"
828
829#define DEPTH 16
830#include "vga_template.h"
831
832#define BGR_FORMAT
bellarde89f66e2003-08-04 23:30:47 +0000833#define DEPTH 16
834#include "vga_template.h"
835
836#define DEPTH 32
837#include "vga_template.h"
838
bellardd3079cd2006-05-10 22:17:36 +0000839#define BGR_FORMAT
840#define DEPTH 32
841#include "vga_template.h"
842
bellard17b00182003-08-08 23:50:57 +0000843static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
844{
845 unsigned int col;
846 col = rgb_to_pixel8(r, g, b);
847 col |= col << 8;
848 col |= col << 16;
849 return col;
850}
851
852static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
853{
854 unsigned int col;
855 col = rgb_to_pixel15(r, g, b);
856 col |= col << 16;
857 return col;
858}
859
blueswir1b29169d2007-06-10 16:07:38 +0000860static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
861 unsigned int b)
862{
863 unsigned int col;
864 col = rgb_to_pixel15bgr(r, g, b);
865 col |= col << 16;
866 return col;
867}
868
bellard17b00182003-08-08 23:50:57 +0000869static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
870{
871 unsigned int col;
872 col = rgb_to_pixel16(r, g, b);
873 col |= col << 16;
874 return col;
875}
876
blueswir1b29169d2007-06-10 16:07:38 +0000877static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
878 unsigned int b)
879{
880 unsigned int col;
881 col = rgb_to_pixel16bgr(r, g, b);
882 col |= col << 16;
883 return col;
884}
885
bellard17b00182003-08-08 23:50:57 +0000886static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
887{
888 unsigned int col;
889 col = rgb_to_pixel32(r, g, b);
890 return col;
891}
892
bellardd3079cd2006-05-10 22:17:36 +0000893static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
894{
895 unsigned int col;
896 col = rgb_to_pixel32bgr(r, g, b);
897 return col;
898}
899
bellarde89f66e2003-08-04 23:30:47 +0000900/* return true if the palette was modified */
901static int update_palette16(VGAState *s)
902{
bellard17b00182003-08-08 23:50:57 +0000903 int full_update, i;
bellarde89f66e2003-08-04 23:30:47 +0000904 uint32_t v, col, *palette;
bellarde89f66e2003-08-04 23:30:47 +0000905
906 full_update = 0;
907 palette = s->last_palette;
908 for(i = 0; i < 16; i++) {
909 v = s->ar[i];
910 if (s->ar[0x10] & 0x80)
911 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
912 else
913 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
914 v = v * 3;
ths5fafdf22007-09-16 21:08:06 +0000915 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
916 c6_to_8(s->palette[v + 1]),
bellard17b00182003-08-08 23:50:57 +0000917 c6_to_8(s->palette[v + 2]));
bellarde89f66e2003-08-04 23:30:47 +0000918 if (col != palette[i]) {
919 full_update = 1;
920 palette[i] = col;
921 }
922 }
923 return full_update;
924}
925
bellard17b00182003-08-08 23:50:57 +0000926/* return true if the palette was modified */
927static int update_palette256(VGAState *s)
928{
929 int full_update, i;
930 uint32_t v, col, *palette;
931
932 full_update = 0;
933 palette = s->last_palette;
934 v = 0;
935 for(i = 0; i < 256; i++) {
bellard37dd2082006-09-21 21:46:53 +0000936 if (s->dac_8bit) {
ths5fafdf22007-09-16 21:08:06 +0000937 col = s->rgb_to_pixel(s->palette[v],
938 s->palette[v + 1],
bellard37dd2082006-09-21 21:46:53 +0000939 s->palette[v + 2]);
940 } else {
ths5fafdf22007-09-16 21:08:06 +0000941 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
942 c6_to_8(s->palette[v + 1]),
bellard37dd2082006-09-21 21:46:53 +0000943 c6_to_8(s->palette[v + 2]));
944 }
bellard17b00182003-08-08 23:50:57 +0000945 if (col != palette[i]) {
946 full_update = 1;
947 palette[i] = col;
948 }
949 v += 3;
950 }
951 return full_update;
952}
953
ths5fafdf22007-09-16 21:08:06 +0000954static void vga_get_offsets(VGAState *s,
955 uint32_t *pline_offset,
bellard83acc962006-08-18 09:32:04 +0000956 uint32_t *pstart_addr,
957 uint32_t *pline_compare)
bellarde89f66e2003-08-04 23:30:47 +0000958{
bellard83acc962006-08-18 09:32:04 +0000959 uint32_t start_addr, line_offset, line_compare;
bellard4fa0f5d2004-02-06 19:47:52 +0000960#ifdef CONFIG_BOCHS_VBE
961 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
962 line_offset = s->vbe_line_offset;
963 start_addr = s->vbe_start_addr;
bellard83acc962006-08-18 09:32:04 +0000964 line_compare = 65535;
bellard4fa0f5d2004-02-06 19:47:52 +0000965 } else
bellarda41bc9a2004-01-04 15:55:00 +0000966#endif
ths3b46e622007-09-17 08:09:54 +0000967 {
bellard4fa0f5d2004-02-06 19:47:52 +0000968 /* compute line_offset in bytes */
969 line_offset = s->cr[0x13];
bellard4fa0f5d2004-02-06 19:47:52 +0000970 line_offset <<= 3;
bellard08e48902005-04-23 18:43:45 +0000971
bellard4fa0f5d2004-02-06 19:47:52 +0000972 /* starting address */
973 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
bellard83acc962006-08-18 09:32:04 +0000974
975 /* line compare */
ths5fafdf22007-09-16 21:08:06 +0000976 line_compare = s->cr[0x18] |
bellard83acc962006-08-18 09:32:04 +0000977 ((s->cr[0x07] & 0x10) << 4) |
978 ((s->cr[0x09] & 0x40) << 3);
bellard4fa0f5d2004-02-06 19:47:52 +0000979 }
bellard798b0c22004-06-05 10:30:49 +0000980 *pline_offset = line_offset;
981 *pstart_addr = start_addr;
bellard83acc962006-08-18 09:32:04 +0000982 *pline_compare = line_compare;
bellard798b0c22004-06-05 10:30:49 +0000983}
984
985/* update start_addr and line_offset. Return TRUE if modified */
986static int update_basic_params(VGAState *s)
987{
988 int full_update;
989 uint32_t start_addr, line_offset, line_compare;
ths3b46e622007-09-17 08:09:54 +0000990
bellard798b0c22004-06-05 10:30:49 +0000991 full_update = 0;
992
bellard83acc962006-08-18 09:32:04 +0000993 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
bellarde89f66e2003-08-04 23:30:47 +0000994
995 if (line_offset != s->line_offset ||
996 start_addr != s->start_addr ||
997 line_compare != s->line_compare) {
998 s->line_offset = line_offset;
999 s->start_addr = start_addr;
1000 s->line_compare = line_compare;
1001 full_update = 1;
1002 }
1003 return full_update;
1004}
1005
blueswir1b29169d2007-06-10 16:07:38 +00001006#define NB_DEPTHS 7
bellardd3079cd2006-05-10 22:17:36 +00001007
1008static inline int get_depth_index(DisplayState *s)
bellarde89f66e2003-08-04 23:30:47 +00001009{
bellardd3079cd2006-05-10 22:17:36 +00001010 switch(s->depth) {
bellarde89f66e2003-08-04 23:30:47 +00001011 default:
1012 case 8:
1013 return 0;
1014 case 15:
blueswir1b29169d2007-06-10 16:07:38 +00001015 if (s->bgr)
1016 return 5;
1017 else
1018 return 1;
bellarde89f66e2003-08-04 23:30:47 +00001019 case 16:
blueswir1b29169d2007-06-10 16:07:38 +00001020 if (s->bgr)
1021 return 6;
1022 else
1023 return 2;
bellarde89f66e2003-08-04 23:30:47 +00001024 case 32:
bellardd3079cd2006-05-10 22:17:36 +00001025 if (s->bgr)
1026 return 4;
1027 else
1028 return 3;
bellarde89f66e2003-08-04 23:30:47 +00001029 }
1030}
1031
bellardd3079cd2006-05-10 22:17:36 +00001032static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
bellarde89f66e2003-08-04 23:30:47 +00001033 vga_draw_glyph8_8,
1034 vga_draw_glyph8_16,
1035 vga_draw_glyph8_16,
1036 vga_draw_glyph8_32,
bellardd3079cd2006-05-10 22:17:36 +00001037 vga_draw_glyph8_32,
blueswir1b29169d2007-06-10 16:07:38 +00001038 vga_draw_glyph8_16,
1039 vga_draw_glyph8_16,
bellarde89f66e2003-08-04 23:30:47 +00001040};
1041
bellardd3079cd2006-05-10 22:17:36 +00001042static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
bellard17b00182003-08-08 23:50:57 +00001043 vga_draw_glyph16_8,
1044 vga_draw_glyph16_16,
1045 vga_draw_glyph16_16,
1046 vga_draw_glyph16_32,
bellardd3079cd2006-05-10 22:17:36 +00001047 vga_draw_glyph16_32,
blueswir1b29169d2007-06-10 16:07:38 +00001048 vga_draw_glyph16_16,
1049 vga_draw_glyph16_16,
bellard17b00182003-08-08 23:50:57 +00001050};
1051
bellardd3079cd2006-05-10 22:17:36 +00001052static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
bellarde89f66e2003-08-04 23:30:47 +00001053 vga_draw_glyph9_8,
1054 vga_draw_glyph9_16,
1055 vga_draw_glyph9_16,
1056 vga_draw_glyph9_32,
bellardd3079cd2006-05-10 22:17:36 +00001057 vga_draw_glyph9_32,
blueswir1b29169d2007-06-10 16:07:38 +00001058 vga_draw_glyph9_16,
1059 vga_draw_glyph9_16,
bellarde89f66e2003-08-04 23:30:47 +00001060};
ths3b46e622007-09-17 08:09:54 +00001061
bellarde89f66e2003-08-04 23:30:47 +00001062static const uint8_t cursor_glyph[32 * 4] = {
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 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1072 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1073 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1074 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1075 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1076 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1077 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1078 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
ths3b46e622007-09-17 08:09:54 +00001079};
bellarde89f66e2003-08-04 23:30:47 +00001080
ths5fafdf22007-09-16 21:08:06 +00001081/*
1082 * Text mode update
bellarde89f66e2003-08-04 23:30:47 +00001083 * Missing:
1084 * - double scan
ths5fafdf22007-09-16 21:08:06 +00001085 * - double width
bellarde89f66e2003-08-04 23:30:47 +00001086 * - underline
1087 * - flashing
1088 */
1089static void vga_draw_text(VGAState *s, int full_update)
1090{
1091 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1092 int cx_min, cx_max, linesize, x_incr;
1093 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1094 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1095 const uint8_t *font_ptr, *font_base[2];
1096 int dup9, line_offset, depth_index;
1097 uint32_t *palette;
1098 uint32_t *ch_attr_ptr;
1099 vga_draw_glyph8_func *vga_draw_glyph8;
1100 vga_draw_glyph9_func *vga_draw_glyph9;
1101
1102 full_update |= update_palette16(s);
1103 palette = s->last_palette;
ths3b46e622007-09-17 08:09:54 +00001104
bellarde89f66e2003-08-04 23:30:47 +00001105 /* compute font data address (in plane 2) */
1106 v = s->sr[3];
bellard1078f662004-05-20 12:46:38 +00001107 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
bellarde89f66e2003-08-04 23:30:47 +00001108 if (offset != s->font_offsets[0]) {
1109 s->font_offsets[0] = offset;
1110 full_update = 1;
1111 }
1112 font_base[0] = s->vram_ptr + offset;
1113
bellard1078f662004-05-20 12:46:38 +00001114 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
bellarde89f66e2003-08-04 23:30:47 +00001115 font_base[1] = s->vram_ptr + offset;
1116 if (offset != s->font_offsets[1]) {
1117 s->font_offsets[1] = offset;
1118 full_update = 1;
1119 }
bellard546fa6a2004-11-14 17:52:01 +00001120 if (s->plane_updated & (1 << 2)) {
1121 /* if the plane 2 was modified since the last display, it
1122 indicates the font may have been modified */
1123 s->plane_updated = 0;
1124 full_update = 1;
1125 }
bellarde89f66e2003-08-04 23:30:47 +00001126 full_update |= update_basic_params(s);
1127
1128 line_offset = s->line_offset;
1129 s1 = s->vram_ptr + (s->start_addr * 4);
1130
1131 /* total width & height */
1132 cheight = (s->cr[9] & 0x1f) + 1;
1133 cw = 8;
bellardeccabc62004-04-07 20:31:38 +00001134 if (!(s->sr[1] & 0x01))
bellarde89f66e2003-08-04 23:30:47 +00001135 cw = 9;
bellard17b00182003-08-08 23:50:57 +00001136 if (s->sr[1] & 0x08)
1137 cw = 16; /* NOTE: no 18 pixel wide */
bellarde89f66e2003-08-04 23:30:47 +00001138 x_incr = cw * ((s->ds->depth + 7) >> 3);
1139 width = (s->cr[0x01] + 1);
bellard17b00182003-08-08 23:50:57 +00001140 if (s->cr[0x06] == 100) {
1141 /* ugly hack for CGA 160x100x16 - explain me the logic */
1142 height = 100;
1143 } else {
ths5fafdf22007-09-16 21:08:06 +00001144 height = s->cr[0x12] |
1145 ((s->cr[0x07] & 0x02) << 7) |
bellard17b00182003-08-08 23:50:57 +00001146 ((s->cr[0x07] & 0x40) << 3);
1147 height = (height + 1) / cheight;
1148 }
bellard3294b942004-04-15 22:35:16 +00001149 if ((height * width) > CH_ATTR_SIZE) {
1150 /* better than nothing: exit if transient size is too big */
1151 return;
1152 }
1153
bellarde89f66e2003-08-04 23:30:47 +00001154 if (width != s->last_width || height != s->last_height ||
bellardeccabc62004-04-07 20:31:38 +00001155 cw != s->last_cw || cheight != s->last_ch) {
bellard2aebb3e2004-04-15 22:28:04 +00001156 s->last_scr_width = width * cw;
1157 s->last_scr_height = height * cheight;
1158 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
bellarde89f66e2003-08-04 23:30:47 +00001159 s->last_width = width;
1160 s->last_height = height;
1161 s->last_ch = cheight;
1162 s->last_cw = cw;
1163 full_update = 1;
1164 }
1165 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1166 if (cursor_offset != s->cursor_offset ||
1167 s->cr[0xa] != s->cursor_start ||
1168 s->cr[0xb] != s->cursor_end) {
1169 /* if the cursor position changed, we update the old and new
1170 chars */
1171 if (s->cursor_offset < CH_ATTR_SIZE)
1172 s->last_ch_attr[s->cursor_offset] = -1;
1173 if (cursor_offset < CH_ATTR_SIZE)
1174 s->last_ch_attr[cursor_offset] = -1;
1175 s->cursor_offset = cursor_offset;
1176 s->cursor_start = s->cr[0xa];
1177 s->cursor_end = s->cr[0xb];
1178 }
bellard39cf7802003-08-05 23:06:22 +00001179 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
ths3b46e622007-09-17 08:09:54 +00001180
bellardd3079cd2006-05-10 22:17:36 +00001181 depth_index = get_depth_index(s->ds);
bellard17b00182003-08-08 23:50:57 +00001182 if (cw == 16)
1183 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1184 else
1185 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
bellarde89f66e2003-08-04 23:30:47 +00001186 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
ths3b46e622007-09-17 08:09:54 +00001187
bellarde89f66e2003-08-04 23:30:47 +00001188 dest = s->ds->data;
1189 linesize = s->ds->linesize;
1190 ch_attr_ptr = s->last_ch_attr;
1191 for(cy = 0; cy < height; cy++) {
1192 d1 = dest;
1193 src = s1;
1194 cx_min = width;
1195 cx_max = -1;
1196 for(cx = 0; cx < width; cx++) {
1197 ch_attr = *(uint16_t *)src;
1198 if (full_update || ch_attr != *ch_attr_ptr) {
1199 if (cx < cx_min)
1200 cx_min = cx;
1201 if (cx > cx_max)
1202 cx_max = cx;
1203 *ch_attr_ptr = ch_attr;
1204#ifdef WORDS_BIGENDIAN
1205 ch = ch_attr >> 8;
1206 cattr = ch_attr & 0xff;
1207#else
1208 ch = ch_attr & 0xff;
1209 cattr = ch_attr >> 8;
1210#endif
1211 font_ptr = font_base[(cattr >> 3) & 1];
1212 font_ptr += 32 * 4 * ch;
1213 bgcol = palette[cattr >> 4];
1214 fgcol = palette[cattr & 0x0f];
bellard17b00182003-08-08 23:50:57 +00001215 if (cw != 9) {
ths5fafdf22007-09-16 21:08:06 +00001216 vga_draw_glyph8(d1, linesize,
bellarde89f66e2003-08-04 23:30:47 +00001217 font_ptr, cheight, fgcol, bgcol);
1218 } else {
1219 dup9 = 0;
1220 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1221 dup9 = 1;
ths5fafdf22007-09-16 21:08:06 +00001222 vga_draw_glyph9(d1, linesize,
bellarde89f66e2003-08-04 23:30:47 +00001223 font_ptr, cheight, fgcol, bgcol, dup9);
1224 }
1225 if (src == cursor_ptr &&
1226 !(s->cr[0x0a] & 0x20)) {
1227 int line_start, line_last, h;
1228 /* draw the cursor */
1229 line_start = s->cr[0x0a] & 0x1f;
1230 line_last = s->cr[0x0b] & 0x1f;
1231 /* XXX: check that */
1232 if (line_last > cheight - 1)
1233 line_last = cheight - 1;
1234 if (line_last >= line_start && line_start < cheight) {
1235 h = line_last - line_start + 1;
1236 d = d1 + linesize * line_start;
bellard17b00182003-08-08 23:50:57 +00001237 if (cw != 9) {
ths5fafdf22007-09-16 21:08:06 +00001238 vga_draw_glyph8(d, linesize,
bellarde89f66e2003-08-04 23:30:47 +00001239 cursor_glyph, h, fgcol, bgcol);
1240 } else {
ths5fafdf22007-09-16 21:08:06 +00001241 vga_draw_glyph9(d, linesize,
bellarde89f66e2003-08-04 23:30:47 +00001242 cursor_glyph, h, fgcol, bgcol, 1);
1243 }
1244 }
1245 }
1246 }
1247 d1 += x_incr;
1248 src += 4;
1249 ch_attr_ptr++;
1250 }
1251 if (cx_max != -1) {
ths5fafdf22007-09-16 21:08:06 +00001252 dpy_update(s->ds, cx_min * cw, cy * cheight,
bellarde89f66e2003-08-04 23:30:47 +00001253 (cx_max - cx_min + 1) * cw, cheight);
1254 }
1255 dest += linesize * cheight;
1256 s1 += line_offset;
1257 }
1258}
1259
bellard17b00182003-08-08 23:50:57 +00001260enum {
1261 VGA_DRAW_LINE2,
1262 VGA_DRAW_LINE2D2,
1263 VGA_DRAW_LINE4,
1264 VGA_DRAW_LINE4D2,
1265 VGA_DRAW_LINE8D2,
1266 VGA_DRAW_LINE8,
1267 VGA_DRAW_LINE15,
1268 VGA_DRAW_LINE16,
bellard4fa0f5d2004-02-06 19:47:52 +00001269 VGA_DRAW_LINE24,
bellard17b00182003-08-08 23:50:57 +00001270 VGA_DRAW_LINE32,
1271 VGA_DRAW_LINE_NB,
1272};
1273
bellardd3079cd2006-05-10 22:17:36 +00001274static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
bellarde89f66e2003-08-04 23:30:47 +00001275 vga_draw_line2_8,
1276 vga_draw_line2_16,
1277 vga_draw_line2_16,
1278 vga_draw_line2_32,
bellardd3079cd2006-05-10 22:17:36 +00001279 vga_draw_line2_32,
blueswir1b29169d2007-06-10 16:07:38 +00001280 vga_draw_line2_16,
1281 vga_draw_line2_16,
bellarde89f66e2003-08-04 23:30:47 +00001282
bellard17b00182003-08-08 23:50:57 +00001283 vga_draw_line2d2_8,
1284 vga_draw_line2d2_16,
1285 vga_draw_line2d2_16,
1286 vga_draw_line2d2_32,
bellardd3079cd2006-05-10 22:17:36 +00001287 vga_draw_line2d2_32,
blueswir1b29169d2007-06-10 16:07:38 +00001288 vga_draw_line2d2_16,
1289 vga_draw_line2d2_16,
bellard17b00182003-08-08 23:50:57 +00001290
bellarde89f66e2003-08-04 23:30:47 +00001291 vga_draw_line4_8,
1292 vga_draw_line4_16,
1293 vga_draw_line4_16,
1294 vga_draw_line4_32,
bellardd3079cd2006-05-10 22:17:36 +00001295 vga_draw_line4_32,
blueswir1b29169d2007-06-10 16:07:38 +00001296 vga_draw_line4_16,
1297 vga_draw_line4_16,
bellarde89f66e2003-08-04 23:30:47 +00001298
bellard17b00182003-08-08 23:50:57 +00001299 vga_draw_line4d2_8,
1300 vga_draw_line4d2_16,
1301 vga_draw_line4d2_16,
1302 vga_draw_line4d2_32,
bellardd3079cd2006-05-10 22:17:36 +00001303 vga_draw_line4d2_32,
blueswir1b29169d2007-06-10 16:07:38 +00001304 vga_draw_line4d2_16,
1305 vga_draw_line4d2_16,
bellard17b00182003-08-08 23:50:57 +00001306
1307 vga_draw_line8d2_8,
1308 vga_draw_line8d2_16,
1309 vga_draw_line8d2_16,
1310 vga_draw_line8d2_32,
bellardd3079cd2006-05-10 22:17:36 +00001311 vga_draw_line8d2_32,
blueswir1b29169d2007-06-10 16:07:38 +00001312 vga_draw_line8d2_16,
1313 vga_draw_line8d2_16,
bellard17b00182003-08-08 23:50:57 +00001314
bellarde89f66e2003-08-04 23:30:47 +00001315 vga_draw_line8_8,
1316 vga_draw_line8_16,
1317 vga_draw_line8_16,
1318 vga_draw_line8_32,
bellardd3079cd2006-05-10 22:17:36 +00001319 vga_draw_line8_32,
blueswir1b29169d2007-06-10 16:07:38 +00001320 vga_draw_line8_16,
1321 vga_draw_line8_16,
bellarde89f66e2003-08-04 23:30:47 +00001322
1323 vga_draw_line15_8,
1324 vga_draw_line15_15,
1325 vga_draw_line15_16,
1326 vga_draw_line15_32,
bellardd3079cd2006-05-10 22:17:36 +00001327 vga_draw_line15_32bgr,
blueswir1b29169d2007-06-10 16:07:38 +00001328 vga_draw_line15_15bgr,
1329 vga_draw_line15_16bgr,
bellarde89f66e2003-08-04 23:30:47 +00001330
1331 vga_draw_line16_8,
1332 vga_draw_line16_15,
1333 vga_draw_line16_16,
1334 vga_draw_line16_32,
bellardd3079cd2006-05-10 22:17:36 +00001335 vga_draw_line16_32bgr,
blueswir1b29169d2007-06-10 16:07:38 +00001336 vga_draw_line16_15bgr,
1337 vga_draw_line16_16bgr,
bellarde89f66e2003-08-04 23:30:47 +00001338
bellard4fa0f5d2004-02-06 19:47:52 +00001339 vga_draw_line24_8,
1340 vga_draw_line24_15,
1341 vga_draw_line24_16,
1342 vga_draw_line24_32,
bellardd3079cd2006-05-10 22:17:36 +00001343 vga_draw_line24_32bgr,
blueswir1b29169d2007-06-10 16:07:38 +00001344 vga_draw_line24_15bgr,
1345 vga_draw_line24_16bgr,
bellard4fa0f5d2004-02-06 19:47:52 +00001346
bellarde89f66e2003-08-04 23:30:47 +00001347 vga_draw_line32_8,
1348 vga_draw_line32_15,
1349 vga_draw_line32_16,
1350 vga_draw_line32_32,
bellardd3079cd2006-05-10 22:17:36 +00001351 vga_draw_line32_32bgr,
blueswir1b29169d2007-06-10 16:07:38 +00001352 vga_draw_line32_15bgr,
1353 vga_draw_line32_16bgr,
bellardd3079cd2006-05-10 22:17:36 +00001354};
1355
1356typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1357
1358static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1359 rgb_to_pixel8_dup,
1360 rgb_to_pixel15_dup,
1361 rgb_to_pixel16_dup,
1362 rgb_to_pixel32_dup,
1363 rgb_to_pixel32bgr_dup,
blueswir1b29169d2007-06-10 16:07:38 +00001364 rgb_to_pixel15bgr_dup,
1365 rgb_to_pixel16bgr_dup,
bellarde89f66e2003-08-04 23:30:47 +00001366};
1367
bellard798b0c22004-06-05 10:30:49 +00001368static int vga_get_bpp(VGAState *s)
1369{
1370 int ret;
1371#ifdef CONFIG_BOCHS_VBE
1372 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1373 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
ths5fafdf22007-09-16 21:08:06 +00001374 } else
bellard798b0c22004-06-05 10:30:49 +00001375#endif
1376 {
1377 ret = 0;
1378 }
1379 return ret;
1380}
1381
bellarda130a412004-06-08 00:59:19 +00001382static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1383{
1384 int width, height;
ths3b46e622007-09-17 08:09:54 +00001385
bellard8454df82006-06-13 16:37:40 +00001386#ifdef CONFIG_BOCHS_VBE
1387 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1388 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1389 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
ths5fafdf22007-09-16 21:08:06 +00001390 } else
bellard8454df82006-06-13 16:37:40 +00001391#endif
1392 {
1393 width = (s->cr[0x01] + 1) * 8;
ths5fafdf22007-09-16 21:08:06 +00001394 height = s->cr[0x12] |
1395 ((s->cr[0x07] & 0x02) << 7) |
bellard8454df82006-06-13 16:37:40 +00001396 ((s->cr[0x07] & 0x40) << 3);
1397 height = (height + 1);
1398 }
bellarda130a412004-06-08 00:59:19 +00001399 *pwidth = width;
1400 *pheight = height;
1401}
1402
bellarda8aa6692004-06-06 15:17:19 +00001403void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1404{
1405 int y;
1406 if (y1 >= VGA_MAX_HEIGHT)
1407 return;
1408 if (y2 >= VGA_MAX_HEIGHT)
1409 y2 = VGA_MAX_HEIGHT;
1410 for(y = y1; y < y2; y++) {
1411 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1412 }
1413}
1414
ths5fafdf22007-09-16 21:08:06 +00001415/*
bellarde89f66e2003-08-04 23:30:47 +00001416 * graphic modes
bellarde89f66e2003-08-04 23:30:47 +00001417 */
1418static void vga_draw_graphic(VGAState *s, int full_update)
1419{
bellard17b00182003-08-08 23:50:57 +00001420 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
aurel3215342722008-05-04 13:11:53 +00001421 int width, height, shift_control, line_offset, page0, page1, bwidth, bits;
bellarda07cf922003-09-30 21:29:03 +00001422 int disp_width, multi_scan, multi_run;
bellarde89f66e2003-08-04 23:30:47 +00001423 uint8_t *d;
bellard39cf7802003-08-05 23:06:22 +00001424 uint32_t v, addr1, addr;
bellarde89f66e2003-08-04 23:30:47 +00001425 vga_draw_line_func *vga_draw_line;
ths3b46e622007-09-17 08:09:54 +00001426
bellarde89f66e2003-08-04 23:30:47 +00001427 full_update |= update_basic_params(s);
1428
bellarda130a412004-06-08 00:59:19 +00001429 s->get_resolution(s, &width, &height);
bellard17b00182003-08-08 23:50:57 +00001430 disp_width = width;
bellard09a79b42004-05-26 22:58:01 +00001431
bellard17b00182003-08-08 23:50:57 +00001432 shift_control = (s->gr[0x05] >> 5) & 3;
bellardf6c958c2004-11-07 22:57:20 +00001433 double_scan = (s->cr[0x09] >> 7);
1434 if (shift_control != 1) {
1435 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
bellarda07cf922003-09-30 21:29:03 +00001436 } else {
bellardf6c958c2004-11-07 22:57:20 +00001437 /* in CGA modes, multi_scan is ignored */
1438 /* XXX: is it correct ? */
1439 multi_scan = double_scan;
bellarda07cf922003-09-30 21:29:03 +00001440 }
1441 multi_run = multi_scan;
bellard17b00182003-08-08 23:50:57 +00001442 if (shift_control != s->shift_control ||
1443 double_scan != s->double_scan) {
1444 full_update = 1;
1445 s->shift_control = shift_control;
1446 s->double_scan = double_scan;
1447 }
ths3b46e622007-09-17 08:09:54 +00001448
bellard17b00182003-08-08 23:50:57 +00001449 if (shift_control == 0) {
1450 full_update |= update_palette16(s);
1451 if (s->sr[0x01] & 8) {
1452 v = VGA_DRAW_LINE4D2;
1453 disp_width <<= 1;
1454 } else {
1455 v = VGA_DRAW_LINE4;
1456 }
aurel3215342722008-05-04 13:11:53 +00001457 bits = 4;
bellard17b00182003-08-08 23:50:57 +00001458 } else if (shift_control == 1) {
1459 full_update |= update_palette16(s);
1460 if (s->sr[0x01] & 8) {
1461 v = VGA_DRAW_LINE2D2;
1462 disp_width <<= 1;
1463 } else {
1464 v = VGA_DRAW_LINE2;
1465 }
aurel3215342722008-05-04 13:11:53 +00001466 bits = 4;
bellard17b00182003-08-08 23:50:57 +00001467 } else {
bellard798b0c22004-06-05 10:30:49 +00001468 switch(s->get_bpp(s)) {
1469 default:
1470 case 0:
bellard4fa0f5d2004-02-06 19:47:52 +00001471 full_update |= update_palette256(s);
1472 v = VGA_DRAW_LINE8D2;
aurel3215342722008-05-04 13:11:53 +00001473 bits = 4;
bellard798b0c22004-06-05 10:30:49 +00001474 break;
1475 case 8:
1476 full_update |= update_palette256(s);
1477 v = VGA_DRAW_LINE8;
aurel3215342722008-05-04 13:11:53 +00001478 bits = 8;
bellard798b0c22004-06-05 10:30:49 +00001479 break;
1480 case 15:
1481 v = VGA_DRAW_LINE15;
aurel3215342722008-05-04 13:11:53 +00001482 bits = 16;
bellard798b0c22004-06-05 10:30:49 +00001483 break;
1484 case 16:
1485 v = VGA_DRAW_LINE16;
aurel3215342722008-05-04 13:11:53 +00001486 bits = 16;
bellard798b0c22004-06-05 10:30:49 +00001487 break;
1488 case 24:
1489 v = VGA_DRAW_LINE24;
aurel3215342722008-05-04 13:11:53 +00001490 bits = 24;
bellard798b0c22004-06-05 10:30:49 +00001491 break;
1492 case 32:
1493 v = VGA_DRAW_LINE32;
aurel3215342722008-05-04 13:11:53 +00001494 bits = 32;
bellard798b0c22004-06-05 10:30:49 +00001495 break;
bellard4fa0f5d2004-02-06 19:47:52 +00001496 }
bellard17b00182003-08-08 23:50:57 +00001497 }
bellardd3079cd2006-05-10 22:17:36 +00001498 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
bellarde89f66e2003-08-04 23:30:47 +00001499
bellard17b00182003-08-08 23:50:57 +00001500 if (disp_width != s->last_width ||
bellarde89f66e2003-08-04 23:30:47 +00001501 height != s->last_height) {
bellard17b00182003-08-08 23:50:57 +00001502 dpy_resize(s->ds, disp_width, height);
bellard2aebb3e2004-04-15 22:28:04 +00001503 s->last_scr_width = disp_width;
1504 s->last_scr_height = height;
bellard17b00182003-08-08 23:50:57 +00001505 s->last_width = disp_width;
bellarde89f66e2003-08-04 23:30:47 +00001506 s->last_height = height;
1507 full_update = 1;
1508 }
bellarda8aa6692004-06-06 15:17:19 +00001509 if (s->cursor_invalidate)
1510 s->cursor_invalidate(s);
ths3b46e622007-09-17 08:09:54 +00001511
bellarde89f66e2003-08-04 23:30:47 +00001512 line_offset = s->line_offset;
bellard17b00182003-08-08 23:50:57 +00001513#if 0
bellardf6c958c2004-11-07 22:57:20 +00001514 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",
bellard17b00182003-08-08 23:50:57 +00001515 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1516#endif
bellarde89f66e2003-08-04 23:30:47 +00001517 addr1 = (s->start_addr * 4);
aurel3215342722008-05-04 13:11:53 +00001518 bwidth = (width * bits + 7) / 8;
bellard39cf7802003-08-05 23:06:22 +00001519 y_start = -1;
bellarde89f66e2003-08-04 23:30:47 +00001520 page_min = 0x7fffffff;
1521 page_max = -1;
1522 d = s->ds->data;
1523 linesize = s->ds->linesize;
bellard17b00182003-08-08 23:50:57 +00001524 y1 = 0;
bellarde89f66e2003-08-04 23:30:47 +00001525 for(y = 0; y < height; y++) {
1526 addr = addr1;
bellard39cf7802003-08-05 23:06:22 +00001527 if (!(s->cr[0x17] & 1)) {
bellard17b00182003-08-08 23:50:57 +00001528 int shift;
bellarde89f66e2003-08-04 23:30:47 +00001529 /* CGA compatibility handling */
bellard17b00182003-08-08 23:50:57 +00001530 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1531 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
bellarde89f66e2003-08-04 23:30:47 +00001532 }
bellard39cf7802003-08-05 23:06:22 +00001533 if (!(s->cr[0x17] & 2)) {
bellard17b00182003-08-08 23:50:57 +00001534 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
bellarde89f66e2003-08-04 23:30:47 +00001535 }
bellard4fa0f5d2004-02-06 19:47:52 +00001536 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1537 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
ths5fafdf22007-09-16 21:08:06 +00001538 update = full_update |
bellard0a962c02005-02-10 22:00:27 +00001539 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1540 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
bellard4fa0f5d2004-02-06 19:47:52 +00001541 if ((page1 - page0) > TARGET_PAGE_SIZE) {
bellard39cf7802003-08-05 23:06:22 +00001542 /* if wide line, can use another page */
ths5fafdf22007-09-16 21:08:06 +00001543 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
bellard0a962c02005-02-10 22:00:27 +00001544 VGA_DIRTY_FLAG);
bellard39cf7802003-08-05 23:06:22 +00001545 }
bellarda8aa6692004-06-06 15:17:19 +00001546 /* explicit invalidation for the hardware cursor */
1547 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
bellarde89f66e2003-08-04 23:30:47 +00001548 if (update) {
bellard39cf7802003-08-05 23:06:22 +00001549 if (y_start < 0)
1550 y_start = y;
bellarde89f66e2003-08-04 23:30:47 +00001551 if (page0 < page_min)
1552 page_min = page0;
1553 if (page1 > page_max)
1554 page_max = page1;
1555 vga_draw_line(s, d, s->vram_ptr + addr, width);
bellarda8aa6692004-06-06 15:17:19 +00001556 if (s->cursor_draw_line)
1557 s->cursor_draw_line(s, d, y);
bellard39cf7802003-08-05 23:06:22 +00001558 } else {
1559 if (y_start >= 0) {
1560 /* flush to display */
ths5fafdf22007-09-16 21:08:06 +00001561 dpy_update(s->ds, 0, y_start,
bellard17b00182003-08-08 23:50:57 +00001562 disp_width, y - y_start);
bellard39cf7802003-08-05 23:06:22 +00001563 y_start = -1;
1564 }
bellarde89f66e2003-08-04 23:30:47 +00001565 }
bellarda07cf922003-09-30 21:29:03 +00001566 if (!multi_run) {
bellardf6c958c2004-11-07 22:57:20 +00001567 mask = (s->cr[0x17] & 3) ^ 3;
1568 if ((y1 & mask) == mask)
1569 addr1 += line_offset;
1570 y1++;
bellarda07cf922003-09-30 21:29:03 +00001571 multi_run = multi_scan;
1572 } else {
1573 multi_run--;
bellarde89f66e2003-08-04 23:30:47 +00001574 }
bellardf6c958c2004-11-07 22:57:20 +00001575 /* line compare acts on the displayed lines */
1576 if (y == s->line_compare)
1577 addr1 = 0;
bellarde89f66e2003-08-04 23:30:47 +00001578 d += linesize;
1579 }
bellard39cf7802003-08-05 23:06:22 +00001580 if (y_start >= 0) {
1581 /* flush to display */
ths5fafdf22007-09-16 21:08:06 +00001582 dpy_update(s->ds, 0, y_start,
bellard17b00182003-08-08 23:50:57 +00001583 disp_width, y - y_start);
bellard39cf7802003-08-05 23:06:22 +00001584 }
bellarde89f66e2003-08-04 23:30:47 +00001585 /* reset modified pages */
1586 if (page_max != -1) {
bellard0a962c02005-02-10 22:00:27 +00001587 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1588 VGA_DIRTY_FLAG);
bellarde89f66e2003-08-04 23:30:47 +00001589 }
bellarda8aa6692004-06-06 15:17:19 +00001590 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
bellarde89f66e2003-08-04 23:30:47 +00001591}
1592
bellard2aebb3e2004-04-15 22:28:04 +00001593static void vga_draw_blank(VGAState *s, int full_update)
1594{
1595 int i, w, val;
1596 uint8_t *d;
1597
1598 if (!full_update)
1599 return;
1600 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1601 return;
ths5fafdf22007-09-16 21:08:06 +00001602 if (s->ds->depth == 8)
bellard2aebb3e2004-04-15 22:28:04 +00001603 val = s->rgb_to_pixel(0, 0, 0);
1604 else
1605 val = 0;
1606 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1607 d = s->ds->data;
1608 for(i = 0; i < s->last_scr_height; i++) {
1609 memset(d, val, w);
1610 d += s->ds->linesize;
1611 }
ths5fafdf22007-09-16 21:08:06 +00001612 dpy_update(s->ds, 0, 0,
bellard2aebb3e2004-04-15 22:28:04 +00001613 s->last_scr_width, s->last_scr_height);
1614}
1615
1616#define GMODE_TEXT 0
1617#define GMODE_GRAPH 1
ths5fafdf22007-09-16 21:08:06 +00001618#define GMODE_BLANK 2
bellard2aebb3e2004-04-15 22:28:04 +00001619
pbrook95219892006-04-09 01:06:34 +00001620static void vga_update_display(void *opaque)
bellarde89f66e2003-08-04 23:30:47 +00001621{
pbrook95219892006-04-09 01:06:34 +00001622 VGAState *s = (VGAState *)opaque;
bellarde89f66e2003-08-04 23:30:47 +00001623 int full_update, graphic_mode;
1624
1625 if (s->ds->depth == 0) {
bellard0f359202004-03-14 21:42:10 +00001626 /* nothing to do */
bellard59a983b2004-03-17 23:17:16 +00001627 } else {
ths5fafdf22007-09-16 21:08:06 +00001628 s->rgb_to_pixel =
bellardd3079cd2006-05-10 22:17:36 +00001629 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
ths3b46e622007-09-17 08:09:54 +00001630
bellarde89f66e2003-08-04 23:30:47 +00001631 full_update = 0;
bellard2aebb3e2004-04-15 22:28:04 +00001632 if (!(s->ar_index & 0x20)) {
1633 graphic_mode = GMODE_BLANK;
1634 } else {
1635 graphic_mode = s->gr[6] & 1;
1636 }
bellarde89f66e2003-08-04 23:30:47 +00001637 if (graphic_mode != s->graphic_mode) {
1638 s->graphic_mode = graphic_mode;
1639 full_update = 1;
1640 }
bellard2aebb3e2004-04-15 22:28:04 +00001641 switch(graphic_mode) {
1642 case GMODE_TEXT:
bellarde89f66e2003-08-04 23:30:47 +00001643 vga_draw_text(s, full_update);
bellard2aebb3e2004-04-15 22:28:04 +00001644 break;
1645 case GMODE_GRAPH:
1646 vga_draw_graphic(s, full_update);
1647 break;
1648 case GMODE_BLANK:
1649 default:
1650 vga_draw_blank(s, full_update);
1651 break;
1652 }
bellarde89f66e2003-08-04 23:30:47 +00001653 }
1654}
1655
bellarda130a412004-06-08 00:59:19 +00001656/* force a full display refresh */
pbrook95219892006-04-09 01:06:34 +00001657static void vga_invalidate_display(void *opaque)
bellarda130a412004-06-08 00:59:19 +00001658{
pbrook95219892006-04-09 01:06:34 +00001659 VGAState *s = (VGAState *)opaque;
ths3b46e622007-09-17 08:09:54 +00001660
bellarda130a412004-06-08 00:59:19 +00001661 s->last_width = -1;
1662 s->last_height = -1;
1663}
1664
bellard59a983b2004-03-17 23:17:16 +00001665static void vga_reset(VGAState *s)
bellarde89f66e2003-08-04 23:30:47 +00001666{
1667 memset(s, 0, sizeof(VGAState));
bellarde89f66e2003-08-04 23:30:47 +00001668 s->graphic_mode = -1; /* force full update */
1669}
1670
balrog4d3b6f62008-02-10 16:33:14 +00001671#define TEXTMODE_X(x) ((x) % width)
1672#define TEXTMODE_Y(x) ((x) / width)
1673#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1674 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1675/* relay text rendering to the display driver
1676 * instead of doing a full vga_update_display() */
1677static void vga_update_text(void *opaque, console_ch_t *chardata)
1678{
1679 VGAState *s = (VGAState *) opaque;
1680 int graphic_mode, i, cursor_offset, cursor_visible;
1681 int cw, cheight, width, height, size, c_min, c_max;
1682 uint32_t *src;
1683 console_ch_t *dst, val;
1684 char msg_buffer[80];
balrog5228c2d2008-02-11 00:09:42 +00001685 int full_update = 0;
balrog4d3b6f62008-02-10 16:33:14 +00001686
1687 if (!(s->ar_index & 0x20)) {
1688 graphic_mode = GMODE_BLANK;
1689 } else {
1690 graphic_mode = s->gr[6] & 1;
1691 }
1692 if (graphic_mode != s->graphic_mode) {
1693 s->graphic_mode = graphic_mode;
1694 full_update = 1;
1695 }
1696 if (s->last_width == -1) {
1697 s->last_width = 0;
1698 full_update = 1;
1699 }
1700
1701 switch (graphic_mode) {
1702 case GMODE_TEXT:
1703 /* TODO: update palette */
1704 full_update |= update_basic_params(s);
1705
1706 /* total width & height */
1707 cheight = (s->cr[9] & 0x1f) + 1;
1708 cw = 8;
1709 if (!(s->sr[1] & 0x01))
1710 cw = 9;
1711 if (s->sr[1] & 0x08)
1712 cw = 16; /* NOTE: no 18 pixel wide */
1713 width = (s->cr[0x01] + 1);
1714 if (s->cr[0x06] == 100) {
1715 /* ugly hack for CGA 160x100x16 - explain me the logic */
1716 height = 100;
1717 } else {
1718 height = s->cr[0x12] |
1719 ((s->cr[0x07] & 0x02) << 7) |
1720 ((s->cr[0x07] & 0x40) << 3);
1721 height = (height + 1) / cheight;
1722 }
1723
1724 size = (height * width);
1725 if (size > CH_ATTR_SIZE) {
1726 if (!full_update)
1727 return;
1728
1729 sprintf(msg_buffer, "%i x %i Text mode", width, height);
1730 break;
1731 }
1732
1733 if (width != s->last_width || height != s->last_height ||
1734 cw != s->last_cw || cheight != s->last_ch) {
1735 s->last_scr_width = width * cw;
1736 s->last_scr_height = height * cheight;
1737 dpy_resize(s->ds, width, height);
1738 s->last_width = width;
1739 s->last_height = height;
1740 s->last_ch = cheight;
1741 s->last_cw = cw;
1742 full_update = 1;
1743 }
1744
1745 /* Update "hardware" cursor */
1746 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1747 if (cursor_offset != s->cursor_offset ||
1748 s->cr[0xa] != s->cursor_start ||
1749 s->cr[0xb] != s->cursor_end || full_update) {
1750 cursor_visible = !(s->cr[0xa] & 0x20);
1751 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
1752 dpy_cursor(s->ds,
1753 TEXTMODE_X(cursor_offset),
1754 TEXTMODE_Y(cursor_offset));
1755 else
1756 dpy_cursor(s->ds, -1, -1);
1757 s->cursor_offset = cursor_offset;
1758 s->cursor_start = s->cr[0xa];
1759 s->cursor_end = s->cr[0xb];
1760 }
1761
1762 src = (uint32_t *) s->vram_ptr + s->start_addr;
1763 dst = chardata;
1764
1765 if (full_update) {
1766 for (i = 0; i < size; src ++, dst ++, i ++)
1767 console_write_ch(dst, VMEM2CHTYPE(*src));
1768
1769 dpy_update(s->ds, 0, 0, width, height);
1770 } else {
1771 c_max = 0;
1772
1773 for (i = 0; i < size; src ++, dst ++, i ++) {
1774 console_write_ch(&val, VMEM2CHTYPE(*src));
1775 if (*dst != val) {
1776 *dst = val;
1777 c_max = i;
1778 break;
1779 }
1780 }
1781 c_min = i;
1782 for (; i < size; src ++, dst ++, i ++) {
1783 console_write_ch(&val, VMEM2CHTYPE(*src));
1784 if (*dst != val) {
1785 *dst = val;
1786 c_max = i;
1787 }
1788 }
1789
1790 if (c_min <= c_max) {
1791 i = TEXTMODE_Y(c_min);
1792 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
1793 }
1794 }
1795
1796 return;
1797 case GMODE_GRAPH:
1798 if (!full_update)
1799 return;
1800
1801 s->get_resolution(s, &width, &height);
1802 sprintf(msg_buffer, "%i x %i Graphic mode", width, height);
1803 break;
1804 case GMODE_BLANK:
1805 default:
1806 if (!full_update)
1807 return;
1808
1809 sprintf(msg_buffer, "VGA Blank mode");
1810 break;
1811 }
1812
1813 /* Display a message */
balrog5228c2d2008-02-11 00:09:42 +00001814 s->last_width = 60;
1815 s->last_height = height = 3;
balrog4d3b6f62008-02-10 16:33:14 +00001816 dpy_cursor(s->ds, -1, -1);
balrog5228c2d2008-02-11 00:09:42 +00001817 dpy_resize(s->ds, s->last_width, height);
balrog4d3b6f62008-02-10 16:33:14 +00001818
balrog5228c2d2008-02-11 00:09:42 +00001819 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
balrog4d3b6f62008-02-10 16:33:14 +00001820 console_write_ch(dst ++, ' ');
1821
1822 size = strlen(msg_buffer);
balrog5228c2d2008-02-11 00:09:42 +00001823 width = (s->last_width - size) / 2;
1824 dst = chardata + s->last_width + width;
balrog4d3b6f62008-02-10 16:33:14 +00001825 for (i = 0; i < size; i ++)
1826 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
1827
balrog5228c2d2008-02-11 00:09:42 +00001828 dpy_update(s->ds, 0, 0, s->last_width, height);
balrog4d3b6f62008-02-10 16:33:14 +00001829}
1830
bellard59a983b2004-03-17 23:17:16 +00001831static CPUReadMemoryFunc *vga_mem_read[3] = {
bellarde89f66e2003-08-04 23:30:47 +00001832 vga_mem_readb,
1833 vga_mem_readw,
1834 vga_mem_readl,
1835};
1836
bellard59a983b2004-03-17 23:17:16 +00001837static CPUWriteMemoryFunc *vga_mem_write[3] = {
bellarde89f66e2003-08-04 23:30:47 +00001838 vga_mem_writeb,
1839 vga_mem_writew,
1840 vga_mem_writel,
1841};
1842
bellardb0a21b52004-03-31 18:58:38 +00001843static void vga_save(QEMUFile *f, void *opaque)
1844{
1845 VGAState *s = opaque;
1846 int i;
1847
bellardd2269f62006-08-17 10:44:00 +00001848 if (s->pci_dev)
1849 pci_device_save(s->pci_dev, f);
1850
bellardb0a21b52004-03-31 18:58:38 +00001851 qemu_put_be32s(f, &s->latch);
1852 qemu_put_8s(f, &s->sr_index);
1853 qemu_put_buffer(f, s->sr, 8);
1854 qemu_put_8s(f, &s->gr_index);
1855 qemu_put_buffer(f, s->gr, 16);
1856 qemu_put_8s(f, &s->ar_index);
1857 qemu_put_buffer(f, s->ar, 21);
thsbee8d682007-12-16 23:41:11 +00001858 qemu_put_be32(f, s->ar_flip_flop);
bellardb0a21b52004-03-31 18:58:38 +00001859 qemu_put_8s(f, &s->cr_index);
1860 qemu_put_buffer(f, s->cr, 256);
1861 qemu_put_8s(f, &s->msr);
1862 qemu_put_8s(f, &s->fcr);
thsbee8d682007-12-16 23:41:11 +00001863 qemu_put_byte(f, s->st00);
bellardb0a21b52004-03-31 18:58:38 +00001864 qemu_put_8s(f, &s->st01);
1865
1866 qemu_put_8s(f, &s->dac_state);
1867 qemu_put_8s(f, &s->dac_sub_index);
1868 qemu_put_8s(f, &s->dac_read_index);
1869 qemu_put_8s(f, &s->dac_write_index);
1870 qemu_put_buffer(f, s->dac_cache, 3);
1871 qemu_put_buffer(f, s->palette, 768);
1872
thsbee8d682007-12-16 23:41:11 +00001873 qemu_put_be32(f, s->bank_offset);
bellardb0a21b52004-03-31 18:58:38 +00001874#ifdef CONFIG_BOCHS_VBE
1875 qemu_put_byte(f, 1);
1876 qemu_put_be16s(f, &s->vbe_index);
1877 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1878 qemu_put_be16s(f, &s->vbe_regs[i]);
1879 qemu_put_be32s(f, &s->vbe_start_addr);
1880 qemu_put_be32s(f, &s->vbe_line_offset);
1881 qemu_put_be32s(f, &s->vbe_bank_mask);
1882#else
1883 qemu_put_byte(f, 0);
1884#endif
1885}
1886
1887static int vga_load(QEMUFile *f, void *opaque, int version_id)
1888{
1889 VGAState *s = opaque;
bellardd2269f62006-08-17 10:44:00 +00001890 int is_vbe, i, ret;
bellardb0a21b52004-03-31 18:58:38 +00001891
bellardd2269f62006-08-17 10:44:00 +00001892 if (version_id > 2)
bellardb0a21b52004-03-31 18:58:38 +00001893 return -EINVAL;
1894
bellardd2269f62006-08-17 10:44:00 +00001895 if (s->pci_dev && version_id >= 2) {
1896 ret = pci_device_load(s->pci_dev, f);
1897 if (ret < 0)
1898 return ret;
1899 }
1900
bellardb0a21b52004-03-31 18:58:38 +00001901 qemu_get_be32s(f, &s->latch);
1902 qemu_get_8s(f, &s->sr_index);
1903 qemu_get_buffer(f, s->sr, 8);
1904 qemu_get_8s(f, &s->gr_index);
1905 qemu_get_buffer(f, s->gr, 16);
1906 qemu_get_8s(f, &s->ar_index);
1907 qemu_get_buffer(f, s->ar, 21);
thsbee8d682007-12-16 23:41:11 +00001908 s->ar_flip_flop=qemu_get_be32(f);
bellardb0a21b52004-03-31 18:58:38 +00001909 qemu_get_8s(f, &s->cr_index);
1910 qemu_get_buffer(f, s->cr, 256);
1911 qemu_get_8s(f, &s->msr);
1912 qemu_get_8s(f, &s->fcr);
1913 qemu_get_8s(f, &s->st00);
1914 qemu_get_8s(f, &s->st01);
1915
1916 qemu_get_8s(f, &s->dac_state);
1917 qemu_get_8s(f, &s->dac_sub_index);
1918 qemu_get_8s(f, &s->dac_read_index);
1919 qemu_get_8s(f, &s->dac_write_index);
1920 qemu_get_buffer(f, s->dac_cache, 3);
1921 qemu_get_buffer(f, s->palette, 768);
1922
thsbee8d682007-12-16 23:41:11 +00001923 s->bank_offset=qemu_get_be32(f);
bellardb0a21b52004-03-31 18:58:38 +00001924 is_vbe = qemu_get_byte(f);
1925#ifdef CONFIG_BOCHS_VBE
1926 if (!is_vbe)
1927 return -EINVAL;
1928 qemu_get_be16s(f, &s->vbe_index);
1929 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1930 qemu_get_be16s(f, &s->vbe_regs[i]);
1931 qemu_get_be32s(f, &s->vbe_start_addr);
1932 qemu_get_be32s(f, &s->vbe_line_offset);
1933 qemu_get_be32s(f, &s->vbe_bank_mask);
1934#else
1935 if (is_vbe)
1936 return -EINVAL;
1937#endif
1938
1939 /* force refresh */
1940 s->graphic_mode = -1;
1941 return 0;
1942}
1943
bellardd2269f62006-08-17 10:44:00 +00001944typedef struct PCIVGAState {
1945 PCIDevice dev;
1946 VGAState vga_state;
1947} PCIVGAState;
1948
ths5fafdf22007-09-16 21:08:06 +00001949static void vga_map(PCIDevice *pci_dev, int region_num,
bellard1078f662004-05-20 12:46:38 +00001950 uint32_t addr, uint32_t size, int type)
1951{
bellardd2269f62006-08-17 10:44:00 +00001952 PCIVGAState *d = (PCIVGAState *)pci_dev;
1953 VGAState *s = &d->vga_state;
bellardd5295252005-07-03 14:00:51 +00001954 if (region_num == PCI_ROM_SLOT) {
1955 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
1956 } else {
1957 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1958 }
bellard1078f662004-05-20 12:46:38 +00001959}
1960
ths5fafdf22007-09-16 21:08:06 +00001961void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
bellard798b0c22004-06-05 10:30:49 +00001962 unsigned long vga_ram_offset, int vga_ram_size)
bellarde89f66e2003-08-04 23:30:47 +00001963{
bellard17b00182003-08-08 23:50:57 +00001964 int i, j, v, b;
bellarde89f66e2003-08-04 23:30:47 +00001965
1966 for(i = 0;i < 256; i++) {
1967 v = 0;
1968 for(j = 0; j < 8; j++) {
1969 v |= ((i >> j) & 1) << (j * 4);
1970 }
1971 expand4[i] = v;
1972
1973 v = 0;
1974 for(j = 0; j < 4; j++) {
1975 v |= ((i >> (2 * j)) & 3) << (j * 4);
1976 }
1977 expand2[i] = v;
1978 }
bellard17b00182003-08-08 23:50:57 +00001979 for(i = 0; i < 16; i++) {
1980 v = 0;
1981 for(j = 0; j < 4; j++) {
1982 b = ((i >> j) & 1);
1983 v |= b << (2 * j);
1984 v |= b << (2 * j + 1);
1985 }
1986 expand4to8[i] = v;
1987 }
bellarde89f66e2003-08-04 23:30:47 +00001988
1989 vga_reset(s);
1990
bellarde89f66e2003-08-04 23:30:47 +00001991 s->vram_ptr = vga_ram_base;
1992 s->vram_offset = vga_ram_offset;
1993 s->vram_size = vga_ram_size;
1994 s->ds = ds;
bellard798b0c22004-06-05 10:30:49 +00001995 s->get_bpp = vga_get_bpp;
1996 s->get_offsets = vga_get_offsets;
bellarda130a412004-06-08 00:59:19 +00001997 s->get_resolution = vga_get_resolution;
thsd34cab92007-04-02 01:10:46 +00001998 s->update = vga_update_display;
1999 s->invalidate = vga_invalidate_display;
2000 s->screen_dump = vga_screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00002001 s->text_update = vga_update_text;
bellard798b0c22004-06-05 10:30:49 +00002002}
2003
bellardd2269f62006-08-17 10:44:00 +00002004/* used by both ISA and PCI */
thsd34cab92007-04-02 01:10:46 +00002005void vga_init(VGAState *s)
bellard798b0c22004-06-05 10:30:49 +00002006{
bellardd2269f62006-08-17 10:44:00 +00002007 int vga_io_memory;
bellard7b17d412004-06-05 11:06:28 +00002008
bellardd2269f62006-08-17 10:44:00 +00002009 register_savevm("vga", 0, 2, vga_save, vga_load, s);
bellardb0a21b52004-03-31 18:58:38 +00002010
bellard0f359202004-03-14 21:42:10 +00002011 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
bellarde89f66e2003-08-04 23:30:47 +00002012
bellard0f359202004-03-14 21:42:10 +00002013 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2014 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2015 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2016 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
bellarde89f66e2003-08-04 23:30:47 +00002017
bellard0f359202004-03-14 21:42:10 +00002018 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
bellarde89f66e2003-08-04 23:30:47 +00002019
bellard0f359202004-03-14 21:42:10 +00002020 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2021 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2022 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2023 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
bellard26aa7d72004-04-28 22:26:05 +00002024 s->bank_offset = 0;
bellarde89f66e2003-08-04 23:30:47 +00002025
bellard4fa0f5d2004-02-06 19:47:52 +00002026#ifdef CONFIG_BOCHS_VBE
2027 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
bellardcae61ce2004-02-06 23:58:08 +00002028 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
bellard09a79b42004-05-26 22:58:01 +00002029#if defined (TARGET_I386)
2030 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2031 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
bellard4fa0f5d2004-02-06 19:47:52 +00002032
bellard09a79b42004-05-26 22:58:01 +00002033 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2034 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
bellard646be932004-04-28 22:38:47 +00002035
2036 /* old Bochs IO ports */
bellard09a79b42004-05-26 22:58:01 +00002037 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2038 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
bellard646be932004-04-28 22:38:47 +00002039
bellard09a79b42004-05-26 22:58:01 +00002040 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
ths5fafdf22007-09-16 21:08:06 +00002041 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
bellard09a79b42004-05-26 22:58:01 +00002042#else
2043 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2044 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2045
2046 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2047 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
bellard4fa0f5d2004-02-06 19:47:52 +00002048#endif
bellard09a79b42004-05-26 22:58:01 +00002049#endif /* CONFIG_BOCHS_VBE */
bellard4fa0f5d2004-02-06 19:47:52 +00002050
bellarda4193c82004-06-03 14:01:43 +00002051 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
ths5fafdf22007-09-16 21:08:06 +00002052 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
bellard26aa7d72004-04-28 22:26:05 +00002053 vga_io_memory);
bellardd2269f62006-08-17 10:44:00 +00002054}
bellard1078f662004-05-20 12:46:38 +00002055
ths2abec302007-04-29 01:47:26 +00002056/* Memory mapped interface */
2057static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2058{
2059 VGAState *s = opaque;
2060
2061 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xff;
2062}
2063
2064static void vga_mm_writeb (void *opaque,
2065 target_phys_addr_t addr, uint32_t value)
2066{
2067 VGAState *s = opaque;
2068
2069 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xff);
2070}
2071
2072static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2073{
2074 VGAState *s = opaque;
2075
2076 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xffff;
2077}
2078
2079static void vga_mm_writew (void *opaque,
2080 target_phys_addr_t addr, uint32_t value)
2081{
2082 VGAState *s = opaque;
2083
2084 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xffff);
2085}
2086
2087static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2088{
2089 VGAState *s = opaque;
2090
2091 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift);
2092}
2093
2094static void vga_mm_writel (void *opaque,
2095 target_phys_addr_t addr, uint32_t value)
2096{
2097 VGAState *s = opaque;
2098
2099 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value);
2100}
2101
2102static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
2103 &vga_mm_readb,
2104 &vga_mm_readw,
2105 &vga_mm_readl,
2106};
2107
2108static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
2109 &vga_mm_writeb,
2110 &vga_mm_writew,
2111 &vga_mm_writel,
2112};
2113
2114static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2115 target_phys_addr_t ctrl_base, int it_shift)
2116{
2117 int s_ioport_ctrl, vga_io_memory;
2118
2119 s->base_ctrl = ctrl_base;
2120 s->it_shift = it_shift;
2121 s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2122 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2123
2124 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2125
2126 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2127 s->bank_offset = 0;
2128 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
2129}
2130
ths5fafdf22007-09-16 21:08:06 +00002131int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
bellardd2269f62006-08-17 10:44:00 +00002132 unsigned long vga_ram_offset, int vga_ram_size)
2133{
2134 VGAState *s;
bellard1078f662004-05-20 12:46:38 +00002135
bellardd2269f62006-08-17 10:44:00 +00002136 s = qemu_mallocz(sizeof(VGAState));
2137 if (!s)
2138 return -1;
bellard1078f662004-05-20 12:46:38 +00002139
bellardd2269f62006-08-17 10:44:00 +00002140 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2141 vga_init(s);
2142
balrog4d3b6f62008-02-10 16:33:14 +00002143 graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump,
2144 s->text_update, s);
thsd34cab92007-04-02 01:10:46 +00002145
bellard4fa0f5d2004-02-06 19:47:52 +00002146#ifdef CONFIG_BOCHS_VBE
bellardd2269f62006-08-17 10:44:00 +00002147 /* XXX: use optimized standard vga accesses */
ths5fafdf22007-09-16 21:08:06 +00002148 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
bellardd2269f62006-08-17 10:44:00 +00002149 vga_ram_size, vga_ram_offset);
bellard4fa0f5d2004-02-06 19:47:52 +00002150#endif
bellardd2269f62006-08-17 10:44:00 +00002151 return 0;
2152}
2153
ths2abec302007-04-29 01:47:26 +00002154int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
2155 unsigned long vga_ram_offset, int vga_ram_size,
2156 target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
2157 int it_shift)
2158{
2159 VGAState *s;
2160
2161 s = qemu_mallocz(sizeof(VGAState));
2162 if (!s)
2163 return -1;
2164
2165 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2166 vga_mm_init(s, vram_base, ctrl_base, it_shift);
2167
balrog4d3b6f62008-02-10 16:33:14 +00002168 graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump,
2169 s->text_update, s);
ths2abec302007-04-29 01:47:26 +00002170
2171#ifdef CONFIG_BOCHS_VBE
2172 /* XXX: use optimized standard vga accesses */
2173 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2174 vga_ram_size, vga_ram_offset);
2175#endif
2176 return 0;
2177}
2178
ths5fafdf22007-09-16 21:08:06 +00002179int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
bellardd2269f62006-08-17 10:44:00 +00002180 unsigned long vga_ram_offset, int vga_ram_size,
2181 unsigned long vga_bios_offset, int vga_bios_size)
2182{
2183 PCIVGAState *d;
2184 VGAState *s;
2185 uint8_t *pci_conf;
ths3b46e622007-09-17 08:09:54 +00002186
ths5fafdf22007-09-16 21:08:06 +00002187 d = (PCIVGAState *)pci_register_device(bus, "VGA",
bellardd2269f62006-08-17 10:44:00 +00002188 sizeof(PCIVGAState),
2189 -1, NULL, NULL);
2190 if (!d)
2191 return -1;
2192 s = &d->vga_state;
ths3b46e622007-09-17 08:09:54 +00002193
bellardd2269f62006-08-17 10:44:00 +00002194 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2195 vga_init(s);
thsd34cab92007-04-02 01:10:46 +00002196
balrog4d3b6f62008-02-10 16:33:14 +00002197 graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump,
2198 s->text_update, s);
thsd34cab92007-04-02 01:10:46 +00002199
bellardd2269f62006-08-17 10:44:00 +00002200 s->pci_dev = &d->dev;
ths3b46e622007-09-17 08:09:54 +00002201
bellardd2269f62006-08-17 10:44:00 +00002202 pci_conf = d->dev.config;
2203 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2204 pci_conf[0x01] = 0x12;
2205 pci_conf[0x02] = 0x11;
2206 pci_conf[0x03] = 0x11;
ths5fafdf22007-09-16 21:08:06 +00002207 pci_conf[0x0a] = 0x00; // VGA controller
bellardd2269f62006-08-17 10:44:00 +00002208 pci_conf[0x0b] = 0x03;
2209 pci_conf[0x0e] = 0x00; // header_type
ths3b46e622007-09-17 08:09:54 +00002210
bellardd2269f62006-08-17 10:44:00 +00002211 /* XXX: vga_ram_size must be a power of two */
ths5fafdf22007-09-16 21:08:06 +00002212 pci_register_io_region(&d->dev, 0, vga_ram_size,
bellardd2269f62006-08-17 10:44:00 +00002213 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2214 if (vga_bios_size != 0) {
2215 unsigned int bios_total_size;
2216 s->bios_offset = vga_bios_offset;
2217 s->bios_size = vga_bios_size;
2218 /* must be a power of two */
2219 bios_total_size = 1;
2220 while (bios_total_size < vga_bios_size)
2221 bios_total_size <<= 1;
ths5fafdf22007-09-16 21:08:06 +00002222 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
bellardd2269f62006-08-17 10:44:00 +00002223 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
bellard1078f662004-05-20 12:46:38 +00002224 }
bellarde89f66e2003-08-04 23:30:47 +00002225 return 0;
2226}
bellard59a983b2004-03-17 23:17:16 +00002227
2228/********************************************************/
2229/* vga screen dump */
2230
2231static int vga_save_w, vga_save_h;
2232
ths5fafdf22007-09-16 21:08:06 +00002233static void vga_save_dpy_update(DisplayState *s,
bellard59a983b2004-03-17 23:17:16 +00002234 int x, int y, int w, int h)
2235{
2236}
2237
2238static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2239{
2240 s->linesize = w * 4;
2241 s->data = qemu_malloc(h * s->linesize);
2242 vga_save_w = w;
2243 vga_save_h = h;
2244}
2245
2246static void vga_save_dpy_refresh(DisplayState *s)
2247{
2248}
2249
ths5fafdf22007-09-16 21:08:06 +00002250int ppm_save(const char *filename, uint8_t *data,
balrogf707cfb2007-05-13 13:26:49 +00002251 int w, int h, int linesize)
bellard59a983b2004-03-17 23:17:16 +00002252{
2253 FILE *f;
2254 uint8_t *d, *d1;
2255 unsigned int v;
2256 int y, x;
2257
2258 f = fopen(filename, "wb");
2259 if (!f)
2260 return -1;
2261 fprintf(f, "P6\n%d %d\n%d\n",
2262 w, h, 255);
2263 d1 = data;
2264 for(y = 0; y < h; y++) {
2265 d = d1;
2266 for(x = 0; x < w; x++) {
2267 v = *(uint32_t *)d;
2268 fputc((v >> 16) & 0xff, f);
2269 fputc((v >> 8) & 0xff, f);
2270 fputc((v) & 0xff, f);
2271 d += 4;
2272 }
2273 d1 += linesize;
2274 }
2275 fclose(f);
2276 return 0;
2277}
2278
2279/* save the vga display in a PPM image even if no display is
2280 available */
pbrook95219892006-04-09 01:06:34 +00002281static void vga_screen_dump(void *opaque, const char *filename)
bellard59a983b2004-03-17 23:17:16 +00002282{
pbrook95219892006-04-09 01:06:34 +00002283 VGAState *s = (VGAState *)opaque;
bellard59a983b2004-03-17 23:17:16 +00002284 DisplayState *saved_ds, ds1, *ds = &ds1;
ths3b46e622007-09-17 08:09:54 +00002285
bellard59a983b2004-03-17 23:17:16 +00002286 /* XXX: this is a little hackish */
pbrook95219892006-04-09 01:06:34 +00002287 vga_invalidate_display(s);
bellard59a983b2004-03-17 23:17:16 +00002288 saved_ds = s->ds;
2289
2290 memset(ds, 0, sizeof(DisplayState));
2291 ds->dpy_update = vga_save_dpy_update;
2292 ds->dpy_resize = vga_save_dpy_resize;
2293 ds->dpy_refresh = vga_save_dpy_refresh;
2294 ds->depth = 32;
2295
2296 s->ds = ds;
2297 s->graphic_mode = -1;
pbrook95219892006-04-09 01:06:34 +00002298 vga_update_display(s);
ths3b46e622007-09-17 08:09:54 +00002299
bellard59a983b2004-03-17 23:17:16 +00002300 if (ds->data) {
ths5fafdf22007-09-16 21:08:06 +00002301 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
bellard59a983b2004-03-17 23:17:16 +00002302 s->ds->linesize);
2303 qemu_free(ds->data);
2304 }
2305 s->ds = saved_ds;
2306}