Statistics
| Branch: | Revision:

root / hw / vga.c @ 08e48902

History | View | Annotate | Download (52.6 kB)

1
/*
2
 * QEMU VGA Emulator.
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 "vl.h"
25
#include "vga_int.h"
26

    
27
//#define DEBUG_VGA
28
//#define DEBUG_VGA_MEM
29
//#define DEBUG_VGA_REG
30

    
31
//#define DEBUG_BOCHS_VBE
32

    
33
/* force some bits to zero */
34
const uint8_t sr_mask[8] = {
35
    (uint8_t)~0xfc,
36
    (uint8_t)~0xc2,
37
    (uint8_t)~0xf0,
38
    (uint8_t)~0xc0,
39
    (uint8_t)~0xf1,
40
    (uint8_t)~0xff,
41
    (uint8_t)~0xff,
42
    (uint8_t)~0x00,
43
};
44

    
45
const uint8_t gr_mask[16] = {
46
    (uint8_t)~0xf0, /* 0x00 */
47
    (uint8_t)~0xf0, /* 0x01 */
48
    (uint8_t)~0xf0, /* 0x02 */
49
    (uint8_t)~0xe0, /* 0x03 */
50
    (uint8_t)~0xfc, /* 0x04 */
51
    (uint8_t)~0x84, /* 0x05 */
52
    (uint8_t)~0xf0, /* 0x06 */
53
    (uint8_t)~0xf0, /* 0x07 */
54
    (uint8_t)~0x00, /* 0x08 */
55
    (uint8_t)~0xff, /* 0x09 */
56
    (uint8_t)~0xff, /* 0x0a */
57
    (uint8_t)~0xff, /* 0x0b */
58
    (uint8_t)~0xff, /* 0x0c */
59
    (uint8_t)~0xff, /* 0x0d */
60
    (uint8_t)~0xff, /* 0x0e */
61
    (uint8_t)~0xff, /* 0x0f */
62
};
63

    
64
#define cbswap_32(__x) \
65
((uint32_t)( \
66
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
67
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
68
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
69
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
70

    
71
#ifdef WORDS_BIGENDIAN
72
#define PAT(x) cbswap_32(x)
73
#else
74
#define PAT(x) (x)
75
#endif
76

    
77
#ifdef WORDS_BIGENDIAN
78
#define BIG 1
79
#else
80
#define BIG 0
81
#endif
82

    
83
#ifdef WORDS_BIGENDIAN
84
#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
85
#else
86
#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
87
#endif
88

    
89
static const uint32_t mask16[16] = {
90
    PAT(0x00000000),
91
    PAT(0x000000ff),
92
    PAT(0x0000ff00),
93
    PAT(0x0000ffff),
94
    PAT(0x00ff0000),
95
    PAT(0x00ff00ff),
96
    PAT(0x00ffff00),
97
    PAT(0x00ffffff),
98
    PAT(0xff000000),
99
    PAT(0xff0000ff),
100
    PAT(0xff00ff00),
101
    PAT(0xff00ffff),
102
    PAT(0xffff0000),
103
    PAT(0xffff00ff),
104
    PAT(0xffffff00),
105
    PAT(0xffffffff),
106
};
107

    
108
#undef PAT
109

    
110
#ifdef WORDS_BIGENDIAN
111
#define PAT(x) (x)
112
#else
113
#define PAT(x) cbswap_32(x)
114
#endif
115

    
116
static const uint32_t dmask16[16] = {
117
    PAT(0x00000000),
118
    PAT(0x000000ff),
119
    PAT(0x0000ff00),
120
    PAT(0x0000ffff),
121
    PAT(0x00ff0000),
122
    PAT(0x00ff00ff),
123
    PAT(0x00ffff00),
124
    PAT(0x00ffffff),
125
    PAT(0xff000000),
126
    PAT(0xff0000ff),
127
    PAT(0xff00ff00),
128
    PAT(0xff00ffff),
129
    PAT(0xffff0000),
130
    PAT(0xffff00ff),
131
    PAT(0xffffff00),
132
    PAT(0xffffffff),
133
};
134

    
135
static const uint32_t dmask4[4] = {
136
    PAT(0x00000000),
137
    PAT(0x0000ffff),
138
    PAT(0xffff0000),
139
    PAT(0xffffffff),
140
};
141

    
142
static uint32_t expand4[256];
143
static uint16_t expand2[256];
144
static uint8_t expand4to8[16];
145

    
146
VGAState *vga_state;
147
int vga_io_memory;
148

    
149
static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
150
{
151
    VGAState *s = opaque;
152
    int val, index;
153

    
154
    /* check port range access depending on color/monochrome mode */
155
    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
156
        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
157
        val = 0xff;
158
    } else {
159
        switch(addr) {
160
        case 0x3c0:
161
            if (s->ar_flip_flop == 0) {
162
                val = s->ar_index;
163
            } else {
164
                val = 0;
165
            }
166
            break;
167
        case 0x3c1:
168
            index = s->ar_index & 0x1f;
169
            if (index < 21) 
170
                val = s->ar[index];
171
            else
172
                val = 0;
173
            break;
174
        case 0x3c2:
175
            val = s->st00;
176
            break;
177
        case 0x3c4:
178
            val = s->sr_index;
179
            break;
180
        case 0x3c5:
181
            val = s->sr[s->sr_index];
182
#ifdef DEBUG_VGA_REG
183
            printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
184
#endif
185
            break;
186
        case 0x3c7:
187
            val = s->dac_state;
188
            break;
189
        case 0x3c8:
190
            val = s->dac_write_index;
191
            break;
192
        case 0x3c9:
193
            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
194
            if (++s->dac_sub_index == 3) {
195
                s->dac_sub_index = 0;
196
                s->dac_read_index++;
197
            }
198
            break;
199
        case 0x3ca:
200
            val = s->fcr;
201
            break;
202
        case 0x3cc:
203
            val = s->msr;
204
            break;
205
        case 0x3ce:
206
            val = s->gr_index;
207
            break;
208
        case 0x3cf:
209
            val = s->gr[s->gr_index];
210
#ifdef DEBUG_VGA_REG
211
            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
212
#endif
213
            break;
214
        case 0x3b4:
215
        case 0x3d4:
216
            val = s->cr_index;
217
            break;
218
        case 0x3b5:
219
        case 0x3d5:
220
            val = s->cr[s->cr_index];
221
#ifdef DEBUG_VGA_REG
222
            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
223
#endif
224
            break;
225
        case 0x3ba:
226
        case 0x3da:
227
            /* just toggle to fool polling */
228
            s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
229
            val = s->st01;
230
            s->ar_flip_flop = 0;
231
            break;
232
        default:
233
            val = 0x00;
234
            break;
235
        }
236
    }
237
#if defined(DEBUG_VGA)
238
    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
239
#endif
240
    return val;
241
}
242

    
243
static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
244
{
245
    VGAState *s = opaque;
246
    int index;
247

    
248
    /* check port range access depending on color/monochrome mode */
249
    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
250
        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
251
        return;
252

    
253
#ifdef DEBUG_VGA
254
    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
255
#endif
256

    
257
    switch(addr) {
258
    case 0x3c0:
259
        if (s->ar_flip_flop == 0) {
260
            val &= 0x3f;
261
            s->ar_index = val;
262
        } else {
263
            index = s->ar_index & 0x1f;
264
            switch(index) {
265
            case 0x00 ... 0x0f:
266
                s->ar[index] = val & 0x3f;
267
                break;
268
            case 0x10:
269
                s->ar[index] = val & ~0x10;
270
                break;
271
            case 0x11:
272
                s->ar[index] = val;
273
                break;
274
            case 0x12:
275
                s->ar[index] = val & ~0xc0;
276
                break;
277
            case 0x13:
278
                s->ar[index] = val & ~0xf0;
279
                break;
280
            case 0x14:
281
                s->ar[index] = val & ~0xf0;
282
                break;
283
            default:
284
                break;
285
            }
286
        }
287
        s->ar_flip_flop ^= 1;
288
        break;
289
    case 0x3c2:
290
        s->msr = val & ~0x10;
291
        break;
292
    case 0x3c4:
293
        s->sr_index = val & 7;
294
        break;
295
    case 0x3c5:
296
#ifdef DEBUG_VGA_REG
297
        printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
298
#endif
299
        s->sr[s->sr_index] = val & sr_mask[s->sr_index];
300
        break;
301
    case 0x3c7:
302
        s->dac_read_index = val;
303
        s->dac_sub_index = 0;
304
        s->dac_state = 3;
305
        break;
306
    case 0x3c8:
307
        s->dac_write_index = val;
308
        s->dac_sub_index = 0;
309
        s->dac_state = 0;
310
        break;
311
    case 0x3c9:
312
        s->dac_cache[s->dac_sub_index] = val;
313
        if (++s->dac_sub_index == 3) {
314
            memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
315
            s->dac_sub_index = 0;
316
            s->dac_write_index++;
317
        }
318
        break;
319
    case 0x3ce:
320
        s->gr_index = val & 0x0f;
321
        break;
322
    case 0x3cf:
323
#ifdef DEBUG_VGA_REG
324
        printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
325
#endif
326
        s->gr[s->gr_index] = val & gr_mask[s->gr_index];
327
        break;
328
    case 0x3b4:
329
    case 0x3d4:
330
        s->cr_index = val;
331
        break;
332
    case 0x3b5:
333
    case 0x3d5:
334
#ifdef DEBUG_VGA_REG
335
        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
336
#endif
337
        /* handle CR0-7 protection */
338
        if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
339
            /* can always write bit 4 of CR7 */
340
            if (s->cr_index == 7)
341
                s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
342
            return;
343
        }
344
        switch(s->cr_index) {
345
        case 0x01: /* horizontal display end */
346
        case 0x07:
347
        case 0x09:
348
        case 0x0c:
349
        case 0x0d:
350
        case 0x12: /* veritcal display end */
351
            s->cr[s->cr_index] = val;
352
            break;
353
        default:
354
            s->cr[s->cr_index] = val;
355
            break;
356
        }
357
        break;
358
    case 0x3ba:
359
    case 0x3da:
360
        s->fcr = val & 0x10;
361
        break;
362
    }
363
}
364

    
365
#ifdef CONFIG_BOCHS_VBE
366
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
367
{
368
    VGAState *s = opaque;
369
    uint32_t val;
370
    val = s->vbe_index;
371
    return val;
372
}
373

    
374
static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
375
{
376
    VGAState *s = opaque;
377
    uint32_t val;
378

    
379
    if (s->vbe_index <= VBE_DISPI_INDEX_NB)
380
        val = s->vbe_regs[s->vbe_index];
381
    else
382
        val = 0;
383
#ifdef DEBUG_BOCHS_VBE
384
    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
385
#endif
386
    return val;
387
}
388

    
389
static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
390
{
391
    VGAState *s = opaque;
392
    s->vbe_index = val;
393
}
394

    
395
static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
396
{
397
    VGAState *s = opaque;
398

    
399
    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
400
#ifdef DEBUG_BOCHS_VBE
401
        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
402
#endif
403
        switch(s->vbe_index) {
404
        case VBE_DISPI_INDEX_ID:
405
            if (val == VBE_DISPI_ID0 ||
406
                val == VBE_DISPI_ID1 ||
407
                val == VBE_DISPI_ID2) {
408
                s->vbe_regs[s->vbe_index] = val;
409
            }
410
            break;
411
        case VBE_DISPI_INDEX_XRES:
412
            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
413
                s->vbe_regs[s->vbe_index] = val;
414
            }
415
            break;
416
        case VBE_DISPI_INDEX_YRES:
417
            if (val <= VBE_DISPI_MAX_YRES) {
418
                s->vbe_regs[s->vbe_index] = val;
419
            }
420
            break;
421
        case VBE_DISPI_INDEX_BPP:
422
            if (val == 0)
423
                val = 8;
424
            if (val == 4 || val == 8 || val == 15 || 
425
                val == 16 || val == 24 || val == 32) {
426
                s->vbe_regs[s->vbe_index] = val;
427
            }
428
            break;
429
        case VBE_DISPI_INDEX_BANK:
430
            val &= s->vbe_bank_mask;
431
            s->vbe_regs[s->vbe_index] = val;
432
            s->bank_offset = (val << 16);
433
            break;
434
        case VBE_DISPI_INDEX_ENABLE:
435
            if (val & VBE_DISPI_ENABLED) {
436
                int h, shift_control;
437

    
438
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 
439
                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
440
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = 
441
                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
442
                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
443
                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
444
                
445
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
446
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
447
                else
448
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * 
449
                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
450
                s->vbe_start_addr = 0;
451
                
452
                /* clear the screen (should be done in BIOS) */
453
                if (!(val & VBE_DISPI_NOCLEARMEM)) {
454
                    memset(s->vram_ptr, 0, 
455
                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
456
                }
457
                
458
                /* we initialize the VGA graphic mode (should be done
459
                   in BIOS) */
460
                s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
461
                s->cr[0x17] |= 3; /* no CGA modes */
462
                s->cr[0x13] = s->vbe_line_offset >> 3;
463
                /* width */
464
                s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
465
                /* height */
466
                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
467
                s->cr[0x12] = h;
468
                s->cr[0x07] = (s->cr[0x07] & ~0x42) | 
469
                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
470
                /* line compare to 1023 */
471
                s->cr[0x18] = 0xff;
472
                s->cr[0x07] |= 0x10;
473
                s->cr[0x09] |= 0x40;
474
                
475
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
476
                    shift_control = 0;
477
                    s->sr[0x01] &= ~8; /* no double line */
478
                } else {
479
                    shift_control = 2;
480
                    s->sr[4] |= 0x08; /* set chain 4 mode */
481
                    s->sr[2] |= 0x0f; /* activate all planes */
482
                }
483
                s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
484
                s->cr[0x09] &= ~0x9f; /* no double scan */
485
            } else {
486
                /* XXX: the bios should do that */
487
                s->bank_offset = 0;
488
            }
489
            s->vbe_regs[s->vbe_index] = val;
490
            break;
491
        case VBE_DISPI_INDEX_VIRT_WIDTH:
492
            {
493
                int w, h, line_offset;
494

    
495
                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
496
                    return;
497
                w = val;
498
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
499
                    line_offset = w >> 1;
500
                else
501
                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
502
                h = s->vram_size / line_offset;
503
                /* XXX: support weird bochs semantics ? */
504
                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
505
                    return;
506
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
507
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
508
                s->vbe_line_offset = line_offset;
509
            }
510
            break;
511
        case VBE_DISPI_INDEX_X_OFFSET:
512
        case VBE_DISPI_INDEX_Y_OFFSET:
513
            {
514
                int x;
515
                s->vbe_regs[s->vbe_index] = val;
516
                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
517
                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
518
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
519
                    s->vbe_start_addr += x >> 1;
520
                else
521
                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
522
                s->vbe_start_addr >>= 2;
523
            }
524
            break;
525
        default:
526
            break;
527
        }
528
    }
529
}
530
#endif
531

    
532
/* called for accesses between 0xa0000 and 0xc0000 */
533
uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
534
{
535
    VGAState *s = opaque;
536
    int memory_map_mode, plane;
537
    uint32_t ret;
538
    
539
    /* convert to VGA memory offset */
540
    memory_map_mode = (s->gr[6] >> 2) & 3;
541
    addr &= 0x1ffff;
542
    switch(memory_map_mode) {
543
    case 0:
544
        break;
545
    case 1:
546
        if (addr >= 0x10000)
547
            return 0xff;
548
        addr += s->bank_offset;
549
        break;
550
    case 2:
551
        addr -= 0x10000;
552
        if (addr >= 0x8000)
553
            return 0xff;
554
        break;
555
    default:
556
    case 3:
557
        addr -= 0x18000;
558
        if (addr >= 0x8000)
559
            return 0xff;
560
        break;
561
    }
562
    
563
    if (s->sr[4] & 0x08) {
564
        /* chain 4 mode : simplest access */
565
        ret = s->vram_ptr[addr];
566
    } else if (s->gr[5] & 0x10) {
567
        /* odd/even mode (aka text mode mapping) */
568
        plane = (s->gr[4] & 2) | (addr & 1);
569
        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
570
    } else {
571
        /* standard VGA latched access */
572
        s->latch = ((uint32_t *)s->vram_ptr)[addr];
573

    
574
        if (!(s->gr[5] & 0x08)) {
575
            /* read mode 0 */
576
            plane = s->gr[4];
577
            ret = GET_PLANE(s->latch, plane);
578
        } else {
579
            /* read mode 1 */
580
            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
581
            ret |= ret >> 16;
582
            ret |= ret >> 8;
583
            ret = (~ret) & 0xff;
584
        }
585
    }
586
    return ret;
587
}
588

    
589
static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
590
{
591
    uint32_t v;
592
#ifdef TARGET_WORDS_BIGENDIAN
593
    v = vga_mem_readb(opaque, addr) << 8;
594
    v |= vga_mem_readb(opaque, addr + 1);
595
#else
596
    v = vga_mem_readb(opaque, addr);
597
    v |= vga_mem_readb(opaque, addr + 1) << 8;
598
#endif
599
    return v;
600
}
601

    
602
static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
603
{
604
    uint32_t v;
605
#ifdef TARGET_WORDS_BIGENDIAN
606
    v = vga_mem_readb(opaque, addr) << 24;
607
    v |= vga_mem_readb(opaque, addr + 1) << 16;
608
    v |= vga_mem_readb(opaque, addr + 2) << 8;
609
    v |= vga_mem_readb(opaque, addr + 3);
610
#else
611
    v = vga_mem_readb(opaque, addr);
612
    v |= vga_mem_readb(opaque, addr + 1) << 8;
613
    v |= vga_mem_readb(opaque, addr + 2) << 16;
614
    v |= vga_mem_readb(opaque, addr + 3) << 24;
615
#endif
616
    return v;
617
}
618

    
619
/* called for accesses between 0xa0000 and 0xc0000 */
620
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
621
{
622
    VGAState *s = opaque;
623
    int memory_map_mode, plane, write_mode, b, func_select, mask;
624
    uint32_t write_mask, bit_mask, set_mask;
625

    
626
#ifdef DEBUG_VGA_MEM
627
    printf("vga: [0x%x] = 0x%02x\n", addr, val);
628
#endif
629
    /* convert to VGA memory offset */
630
    memory_map_mode = (s->gr[6] >> 2) & 3;
631
    addr &= 0x1ffff;
632
    switch(memory_map_mode) {
633
    case 0:
634
        break;
635
    case 1:
636
        if (addr >= 0x10000)
637
            return;
638
        addr += s->bank_offset;
639
        break;
640
    case 2:
641
        addr -= 0x10000;
642
        if (addr >= 0x8000)
643
            return;
644
        break;
645
    default:
646
    case 3:
647
        addr -= 0x18000;
648
        if (addr >= 0x8000)
649
            return;
650
        break;
651
    }
652
    
653
    if (s->sr[4] & 0x08) {
654
        /* chain 4 mode : simplest access */
655
        plane = addr & 3;
656
        mask = (1 << plane);
657
        if (s->sr[2] & mask) {
658
            s->vram_ptr[addr] = val;
659
#ifdef DEBUG_VGA_MEM
660
            printf("vga: chain4: [0x%x]\n", addr);
661
#endif
662
            s->plane_updated |= mask; /* only used to detect font change */
663
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
664
        }
665
    } else if (s->gr[5] & 0x10) {
666
        /* odd/even mode (aka text mode mapping) */
667
        plane = (s->gr[4] & 2) | (addr & 1);
668
        mask = (1 << plane);
669
        if (s->sr[2] & mask) {
670
            addr = ((addr & ~1) << 1) | plane;
671
            s->vram_ptr[addr] = val;
672
#ifdef DEBUG_VGA_MEM
673
            printf("vga: odd/even: [0x%x]\n", addr);
674
#endif
675
            s->plane_updated |= mask; /* only used to detect font change */
676
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
677
        }
678
    } else {
679
        /* standard VGA latched access */
680
        write_mode = s->gr[5] & 3;
681
        switch(write_mode) {
682
        default:
683
        case 0:
684
            /* rotate */
685
            b = s->gr[3] & 7;
686
            val = ((val >> b) | (val << (8 - b))) & 0xff;
687
            val |= val << 8;
688
            val |= val << 16;
689

    
690
            /* apply set/reset mask */
691
            set_mask = mask16[s->gr[1]];
692
            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
693
            bit_mask = s->gr[8];
694
            break;
695
        case 1:
696
            val = s->latch;
697
            goto do_write;
698
        case 2:
699
            val = mask16[val & 0x0f];
700
            bit_mask = s->gr[8];
701
            break;
702
        case 3:
703
            /* rotate */
704
            b = s->gr[3] & 7;
705
            val = (val >> b) | (val << (8 - b));
706

    
707
            bit_mask = s->gr[8] & val;
708
            val = mask16[s->gr[0]];
709
            break;
710
        }
711

    
712
        /* apply logical operation */
713
        func_select = s->gr[3] >> 3;
714
        switch(func_select) {
715
        case 0:
716
        default:
717
            /* nothing to do */
718
            break;
719
        case 1:
720
            /* and */
721
            val &= s->latch;
722
            break;
723
        case 2:
724
            /* or */
725
            val |= s->latch;
726
            break;
727
        case 3:
728
            /* xor */
729
            val ^= s->latch;
730
            break;
731
        }
732

    
733
        /* apply bit mask */
734
        bit_mask |= bit_mask << 8;
735
        bit_mask |= bit_mask << 16;
736
        val = (val & bit_mask) | (s->latch & ~bit_mask);
737

    
738
    do_write:
739
        /* mask data according to sr[2] */
740
        mask = s->sr[2];
741
        s->plane_updated |= mask; /* only used to detect font change */
742
        write_mask = mask16[mask];
743
        ((uint32_t *)s->vram_ptr)[addr] = 
744
            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | 
745
            (val & write_mask);
746
#ifdef DEBUG_VGA_MEM
747
            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", 
748
                   addr * 4, write_mask, val);
749
#endif
750
            cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
751
    }
752
}
753

    
754
static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
755
{
756
#ifdef TARGET_WORDS_BIGENDIAN
757
    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
758
    vga_mem_writeb(opaque, addr + 1, val & 0xff);
759
#else
760
    vga_mem_writeb(opaque, addr, val & 0xff);
761
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
762
#endif
763
}
764

    
765
static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
766
{
767
#ifdef TARGET_WORDS_BIGENDIAN
768
    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
769
    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
770
    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
771
    vga_mem_writeb(opaque, addr + 3, val & 0xff);
772
#else
773
    vga_mem_writeb(opaque, addr, val & 0xff);
774
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
775
    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
776
    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
777
#endif
778
}
779

    
780
typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
781
                             const uint8_t *font_ptr, int h,
782
                             uint32_t fgcol, uint32_t bgcol);
783
typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
784
                                  const uint8_t *font_ptr, int h, 
785
                                  uint32_t fgcol, uint32_t bgcol, int dup9);
786
typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, 
787
                                const uint8_t *s, int width);
788

    
789
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
790
{
791
    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
792
}
793

    
794
static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
795
{
796
    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
797
}
798

    
799
static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
800
{
801
    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
802
}
803

    
804
static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
805
{
806
    return (r << 16) | (g << 8) | b;
807
}
808

    
809
#define DEPTH 8
810
#include "vga_template.h"
811

    
812
#define DEPTH 15
813
#include "vga_template.h"
814

    
815
#define DEPTH 16
816
#include "vga_template.h"
817

    
818
#define DEPTH 32
819
#include "vga_template.h"
820

    
821
static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
822
{
823
    unsigned int col;
824
    col = rgb_to_pixel8(r, g, b);
825
    col |= col << 8;
826
    col |= col << 16;
827
    return col;
828
}
829

    
830
static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
831
{
832
    unsigned int col;
833
    col = rgb_to_pixel15(r, g, b);
834
    col |= col << 16;
835
    return col;
836
}
837

    
838
static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
839
{
840
    unsigned int col;
841
    col = rgb_to_pixel16(r, g, b);
842
    col |= col << 16;
843
    return col;
844
}
845

    
846
static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
847
{
848
    unsigned int col;
849
    col = rgb_to_pixel32(r, g, b);
850
    return col;
851
}
852

    
853
/* return true if the palette was modified */
854
static int update_palette16(VGAState *s)
855
{
856
    int full_update, i;
857
    uint32_t v, col, *palette;
858

    
859
    full_update = 0;
860
    palette = s->last_palette;
861
    for(i = 0; i < 16; i++) {
862
        v = s->ar[i];
863
        if (s->ar[0x10] & 0x80)
864
            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
865
        else
866
            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
867
        v = v * 3;
868
        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
869
                              c6_to_8(s->palette[v + 1]), 
870
                              c6_to_8(s->palette[v + 2]));
871
        if (col != palette[i]) {
872
            full_update = 1;
873
            palette[i] = col;
874
        }
875
    }
876
    return full_update;
877
}
878

    
879
/* return true if the palette was modified */
880
static int update_palette256(VGAState *s)
881
{
882
    int full_update, i;
883
    uint32_t v, col, *palette;
884

    
885
    full_update = 0;
886
    palette = s->last_palette;
887
    v = 0;
888
    for(i = 0; i < 256; i++) {
889
        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
890
                              c6_to_8(s->palette[v + 1]), 
891
                              c6_to_8(s->palette[v + 2]));
892
        if (col != palette[i]) {
893
            full_update = 1;
894
            palette[i] = col;
895
        }
896
        v += 3;
897
    }
898
    return full_update;
899
}
900

    
901
static void vga_get_offsets(VGAState *s, 
902
                            uint32_t *pline_offset, 
903
                            uint32_t *pstart_addr)
904
{
905
    uint32_t start_addr, line_offset;
906
#ifdef CONFIG_BOCHS_VBE
907
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
908
        line_offset = s->vbe_line_offset;
909
        start_addr = s->vbe_start_addr;
910
    } else
911
#endif
912
    {  
913
        /* compute line_offset in bytes */
914
        line_offset = s->cr[0x13];
915
        line_offset <<= 3;
916

    
917
        /* starting address */
918
        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
919
    }
920
    *pline_offset = line_offset;
921
    *pstart_addr = start_addr;
922
}
923

    
924
/* update start_addr and line_offset. Return TRUE if modified */
925
static int update_basic_params(VGAState *s)
926
{
927
    int full_update;
928
    uint32_t start_addr, line_offset, line_compare;
929
    
930
    full_update = 0;
931

    
932
    s->get_offsets(s, &line_offset, &start_addr);
933
    /* line compare */
934
    line_compare = s->cr[0x18] | 
935
        ((s->cr[0x07] & 0x10) << 4) |
936
        ((s->cr[0x09] & 0x40) << 3);
937

    
938
    if (line_offset != s->line_offset ||
939
        start_addr != s->start_addr ||
940
        line_compare != s->line_compare) {
941
        s->line_offset = line_offset;
942
        s->start_addr = start_addr;
943
        s->line_compare = line_compare;
944
        full_update = 1;
945
    }
946
    return full_update;
947
}
948

    
949
static inline int get_depth_index(int depth)
950
{
951
    switch(depth) {
952
    default:
953
    case 8:
954
        return 0;
955
    case 15:
956
        return 1;
957
    case 16:
958
        return 2;
959
    case 32:
960
        return 3;
961
    }
962
}
963

    
964
static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
965
    vga_draw_glyph8_8,
966
    vga_draw_glyph8_16,
967
    vga_draw_glyph8_16,
968
    vga_draw_glyph8_32,
969
};
970

    
971
static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
972
    vga_draw_glyph16_8,
973
    vga_draw_glyph16_16,
974
    vga_draw_glyph16_16,
975
    vga_draw_glyph16_32,
976
};
977

    
978
static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
979
    vga_draw_glyph9_8,
980
    vga_draw_glyph9_16,
981
    vga_draw_glyph9_16,
982
    vga_draw_glyph9_32,
983
};
984
    
985
static const uint8_t cursor_glyph[32 * 4] = {
986
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
987
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
988
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
989
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
990
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
991
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
992
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
993
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
994
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
995
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
996
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
997
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
998
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
999
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1000
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1001
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1002
};    
1003

    
1004
/* 
1005
 * Text mode update 
1006
 * Missing:
1007
 * - double scan
1008
 * - double width 
1009
 * - underline
1010
 * - flashing
1011
 */
1012
static void vga_draw_text(VGAState *s, int full_update)
1013
{
1014
    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1015
    int cx_min, cx_max, linesize, x_incr;
1016
    uint32_t offset, fgcol, bgcol, v, cursor_offset;
1017
    uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1018
    const uint8_t *font_ptr, *font_base[2];
1019
    int dup9, line_offset, depth_index;
1020
    uint32_t *palette;
1021
    uint32_t *ch_attr_ptr;
1022
    vga_draw_glyph8_func *vga_draw_glyph8;
1023
    vga_draw_glyph9_func *vga_draw_glyph9;
1024

    
1025
    full_update |= update_palette16(s);
1026
    palette = s->last_palette;
1027
    
1028
    /* compute font data address (in plane 2) */
1029
    v = s->sr[3];
1030
    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1031
    if (offset != s->font_offsets[0]) {
1032
        s->font_offsets[0] = offset;
1033
        full_update = 1;
1034
    }
1035
    font_base[0] = s->vram_ptr + offset;
1036

    
1037
    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1038
    font_base[1] = s->vram_ptr + offset;
1039
    if (offset != s->font_offsets[1]) {
1040
        s->font_offsets[1] = offset;
1041
        full_update = 1;
1042
    }
1043
    if (s->plane_updated & (1 << 2)) {
1044
        /* if the plane 2 was modified since the last display, it
1045
           indicates the font may have been modified */
1046
        s->plane_updated = 0;
1047
        full_update = 1;
1048
    }
1049
    full_update |= update_basic_params(s);
1050

    
1051
    line_offset = s->line_offset;
1052
    s1 = s->vram_ptr + (s->start_addr * 4);
1053

    
1054
    /* total width & height */
1055
    cheight = (s->cr[9] & 0x1f) + 1;
1056
    cw = 8;
1057
    if (!(s->sr[1] & 0x01))
1058
        cw = 9;
1059
    if (s->sr[1] & 0x08)
1060
        cw = 16; /* NOTE: no 18 pixel wide */
1061
    x_incr = cw * ((s->ds->depth + 7) >> 3);
1062
    width = (s->cr[0x01] + 1);
1063
    if (s->cr[0x06] == 100) {
1064
        /* ugly hack for CGA 160x100x16 - explain me the logic */
1065
        height = 100;
1066
    } else {
1067
        height = s->cr[0x12] | 
1068
            ((s->cr[0x07] & 0x02) << 7) | 
1069
            ((s->cr[0x07] & 0x40) << 3);
1070
        height = (height + 1) / cheight;
1071
    }
1072
    if ((height * width) > CH_ATTR_SIZE) {
1073
        /* better than nothing: exit if transient size is too big */
1074
        return;
1075
    }
1076

    
1077
    if (width != s->last_width || height != s->last_height ||
1078
        cw != s->last_cw || cheight != s->last_ch) {
1079
        s->last_scr_width = width * cw;
1080
        s->last_scr_height = height * cheight;
1081
        dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1082
        s->last_width = width;
1083
        s->last_height = height;
1084
        s->last_ch = cheight;
1085
        s->last_cw = cw;
1086
        full_update = 1;
1087
    }
1088
    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1089
    if (cursor_offset != s->cursor_offset ||
1090
        s->cr[0xa] != s->cursor_start ||
1091
        s->cr[0xb] != s->cursor_end) {
1092
      /* if the cursor position changed, we update the old and new
1093
         chars */
1094
        if (s->cursor_offset < CH_ATTR_SIZE)
1095
            s->last_ch_attr[s->cursor_offset] = -1;
1096
        if (cursor_offset < CH_ATTR_SIZE)
1097
            s->last_ch_attr[cursor_offset] = -1;
1098
        s->cursor_offset = cursor_offset;
1099
        s->cursor_start = s->cr[0xa];
1100
        s->cursor_end = s->cr[0xb];
1101
    }
1102
    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1103
    
1104
    depth_index = get_depth_index(s->ds->depth);
1105
    if (cw == 16)
1106
        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1107
    else
1108
        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1109
    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1110
    
1111
    dest = s->ds->data;
1112
    linesize = s->ds->linesize;
1113
    ch_attr_ptr = s->last_ch_attr;
1114
    for(cy = 0; cy < height; cy++) {
1115
        d1 = dest;
1116
        src = s1;
1117
        cx_min = width;
1118
        cx_max = -1;
1119
        for(cx = 0; cx < width; cx++) {
1120
            ch_attr = *(uint16_t *)src;
1121
            if (full_update || ch_attr != *ch_attr_ptr) {
1122
                if (cx < cx_min)
1123
                    cx_min = cx;
1124
                if (cx > cx_max)
1125
                    cx_max = cx;
1126
                *ch_attr_ptr = ch_attr;
1127
#ifdef WORDS_BIGENDIAN
1128
                ch = ch_attr >> 8;
1129
                cattr = ch_attr & 0xff;
1130
#else
1131
                ch = ch_attr & 0xff;
1132
                cattr = ch_attr >> 8;
1133
#endif
1134
                font_ptr = font_base[(cattr >> 3) & 1];
1135
                font_ptr += 32 * 4 * ch;
1136
                bgcol = palette[cattr >> 4];
1137
                fgcol = palette[cattr & 0x0f];
1138
                if (cw != 9) {
1139
                    vga_draw_glyph8(d1, linesize, 
1140
                                    font_ptr, cheight, fgcol, bgcol);
1141
                } else {
1142
                    dup9 = 0;
1143
                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1144
                        dup9 = 1;
1145
                    vga_draw_glyph9(d1, linesize, 
1146
                                    font_ptr, cheight, fgcol, bgcol, dup9);
1147
                }
1148
                if (src == cursor_ptr &&
1149
                    !(s->cr[0x0a] & 0x20)) {
1150
                    int line_start, line_last, h;
1151
                    /* draw the cursor */
1152
                    line_start = s->cr[0x0a] & 0x1f;
1153
                    line_last = s->cr[0x0b] & 0x1f;
1154
                    /* XXX: check that */
1155
                    if (line_last > cheight - 1)
1156
                        line_last = cheight - 1;
1157
                    if (line_last >= line_start && line_start < cheight) {
1158
                        h = line_last - line_start + 1;
1159
                        d = d1 + linesize * line_start;
1160
                        if (cw != 9) {
1161
                            vga_draw_glyph8(d, linesize, 
1162
                                            cursor_glyph, h, fgcol, bgcol);
1163
                        } else {
1164
                            vga_draw_glyph9(d, linesize, 
1165
                                            cursor_glyph, h, fgcol, bgcol, 1);
1166
                        }
1167
                    }
1168
                }
1169
            }
1170
            d1 += x_incr;
1171
            src += 4;
1172
            ch_attr_ptr++;
1173
        }
1174
        if (cx_max != -1) {
1175
            dpy_update(s->ds, cx_min * cw, cy * cheight, 
1176
                       (cx_max - cx_min + 1) * cw, cheight);
1177
        }
1178
        dest += linesize * cheight;
1179
        s1 += line_offset;
1180
    }
1181
}
1182

    
1183
enum {
1184
    VGA_DRAW_LINE2,
1185
    VGA_DRAW_LINE2D2,
1186
    VGA_DRAW_LINE4,
1187
    VGA_DRAW_LINE4D2,
1188
    VGA_DRAW_LINE8D2,
1189
    VGA_DRAW_LINE8,
1190
    VGA_DRAW_LINE15,
1191
    VGA_DRAW_LINE16,
1192
    VGA_DRAW_LINE24,
1193
    VGA_DRAW_LINE32,
1194
    VGA_DRAW_LINE_NB,
1195
};
1196

    
1197
static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1198
    vga_draw_line2_8,
1199
    vga_draw_line2_16,
1200
    vga_draw_line2_16,
1201
    vga_draw_line2_32,
1202

    
1203
    vga_draw_line2d2_8,
1204
    vga_draw_line2d2_16,
1205
    vga_draw_line2d2_16,
1206
    vga_draw_line2d2_32,
1207

    
1208
    vga_draw_line4_8,
1209
    vga_draw_line4_16,
1210
    vga_draw_line4_16,
1211
    vga_draw_line4_32,
1212

    
1213
    vga_draw_line4d2_8,
1214
    vga_draw_line4d2_16,
1215
    vga_draw_line4d2_16,
1216
    vga_draw_line4d2_32,
1217

    
1218
    vga_draw_line8d2_8,
1219
    vga_draw_line8d2_16,
1220
    vga_draw_line8d2_16,
1221
    vga_draw_line8d2_32,
1222

    
1223
    vga_draw_line8_8,
1224
    vga_draw_line8_16,
1225
    vga_draw_line8_16,
1226
    vga_draw_line8_32,
1227

    
1228
    vga_draw_line15_8,
1229
    vga_draw_line15_15,
1230
    vga_draw_line15_16,
1231
    vga_draw_line15_32,
1232

    
1233
    vga_draw_line16_8,
1234
    vga_draw_line16_15,
1235
    vga_draw_line16_16,
1236
    vga_draw_line16_32,
1237

    
1238
    vga_draw_line24_8,
1239
    vga_draw_line24_15,
1240
    vga_draw_line24_16,
1241
    vga_draw_line24_32,
1242

    
1243
    vga_draw_line32_8,
1244
    vga_draw_line32_15,
1245
    vga_draw_line32_16,
1246
    vga_draw_line32_32,
1247
};
1248

    
1249
static int vga_get_bpp(VGAState *s)
1250
{
1251
    int ret;
1252
#ifdef CONFIG_BOCHS_VBE
1253
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1254
        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1255
    } else 
1256
#endif
1257
    {
1258
        ret = 0;
1259
    }
1260
    return ret;
1261
}
1262

    
1263
static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1264
{
1265
    int width, height;
1266
    
1267
    width = (s->cr[0x01] + 1) * 8;
1268
    height = s->cr[0x12] | 
1269
        ((s->cr[0x07] & 0x02) << 7) | 
1270
        ((s->cr[0x07] & 0x40) << 3);
1271
    height = (height + 1);
1272
    *pwidth = width;
1273
    *pheight = height;
1274
}
1275

    
1276
void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1277
{
1278
    int y;
1279
    if (y1 >= VGA_MAX_HEIGHT)
1280
        return;
1281
    if (y2 >= VGA_MAX_HEIGHT)
1282
        y2 = VGA_MAX_HEIGHT;
1283
    for(y = y1; y < y2; y++) {
1284
        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1285
    }
1286
}
1287

    
1288
/* 
1289
 * graphic modes
1290
 */
1291
static void vga_draw_graphic(VGAState *s, int full_update)
1292
{
1293
    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1294
    int width, height, shift_control, line_offset, page0, page1, bwidth;
1295
    int disp_width, multi_scan, multi_run;
1296
    uint8_t *d;
1297
    uint32_t v, addr1, addr;
1298
    vga_draw_line_func *vga_draw_line;
1299
    
1300
    full_update |= update_basic_params(s);
1301

    
1302
    s->get_resolution(s, &width, &height);
1303
    disp_width = width;
1304

    
1305
    shift_control = (s->gr[0x05] >> 5) & 3;
1306
    double_scan = (s->cr[0x09] >> 7);
1307
    if (shift_control != 1) {
1308
        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1309
    } else {
1310
        /* in CGA modes, multi_scan is ignored */
1311
        /* XXX: is it correct ? */
1312
        multi_scan = double_scan;
1313
    }
1314
    multi_run = multi_scan;
1315
    if (shift_control != s->shift_control ||
1316
        double_scan != s->double_scan) {
1317
        full_update = 1;
1318
        s->shift_control = shift_control;
1319
        s->double_scan = double_scan;
1320
    }
1321
    
1322
    if (shift_control == 0) {
1323
        full_update |= update_palette16(s);
1324
        if (s->sr[0x01] & 8) {
1325
            v = VGA_DRAW_LINE4D2;
1326
            disp_width <<= 1;
1327
        } else {
1328
            v = VGA_DRAW_LINE4;
1329
        }
1330
    } else if (shift_control == 1) {
1331
        full_update |= update_palette16(s);
1332
        if (s->sr[0x01] & 8) {
1333
            v = VGA_DRAW_LINE2D2;
1334
            disp_width <<= 1;
1335
        } else {
1336
            v = VGA_DRAW_LINE2;
1337
        }
1338
    } else {
1339
        switch(s->get_bpp(s)) {
1340
        default:
1341
        case 0:
1342
            full_update |= update_palette256(s);
1343
            v = VGA_DRAW_LINE8D2;
1344
            break;
1345
        case 8:
1346
            full_update |= update_palette256(s);
1347
            v = VGA_DRAW_LINE8;
1348
            break;
1349
        case 15:
1350
            v = VGA_DRAW_LINE15;
1351
            break;
1352
        case 16:
1353
            v = VGA_DRAW_LINE16;
1354
            break;
1355
        case 24:
1356
            v = VGA_DRAW_LINE24;
1357
            break;
1358
        case 32:
1359
            v = VGA_DRAW_LINE32;
1360
            break;
1361
        }
1362
    }
1363
    vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1364

    
1365
    if (disp_width != s->last_width ||
1366
        height != s->last_height) {
1367
        dpy_resize(s->ds, disp_width, height);
1368
        s->last_scr_width = disp_width;
1369
        s->last_scr_height = height;
1370
        s->last_width = disp_width;
1371
        s->last_height = height;
1372
        full_update = 1;
1373
    }
1374
    if (s->cursor_invalidate)
1375
        s->cursor_invalidate(s);
1376
    
1377
    line_offset = s->line_offset;
1378
#if 0
1379
    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",
1380
           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1381
#endif
1382
    addr1 = (s->start_addr * 4);
1383
    bwidth = width * 4;
1384
    y_start = -1;
1385
    page_min = 0x7fffffff;
1386
    page_max = -1;
1387
    d = s->ds->data;
1388
    linesize = s->ds->linesize;
1389
    y1 = 0;
1390
    for(y = 0; y < height; y++) {
1391
        addr = addr1;
1392
        if (!(s->cr[0x17] & 1)) {
1393
            int shift;
1394
            /* CGA compatibility handling */
1395
            shift = 14 + ((s->cr[0x17] >> 6) & 1);
1396
            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1397
        }
1398
        if (!(s->cr[0x17] & 2)) {
1399
            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1400
        }
1401
        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1402
        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1403
        update = full_update | 
1404
            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1405
            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1406
        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1407
            /* if wide line, can use another page */
1408
            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, 
1409
                                                    VGA_DIRTY_FLAG);
1410
        }
1411
        /* explicit invalidation for the hardware cursor */
1412
        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1413
        if (update) {
1414
            if (y_start < 0)
1415
                y_start = y;
1416
            if (page0 < page_min)
1417
                page_min = page0;
1418
            if (page1 > page_max)
1419
                page_max = page1;
1420
            vga_draw_line(s, d, s->vram_ptr + addr, width);
1421
            if (s->cursor_draw_line)
1422
                s->cursor_draw_line(s, d, y);
1423
        } else {
1424
            if (y_start >= 0) {
1425
                /* flush to display */
1426
                dpy_update(s->ds, 0, y_start, 
1427
                           disp_width, y - y_start);
1428
                y_start = -1;
1429
            }
1430
        }
1431
        if (!multi_run) {
1432
            mask = (s->cr[0x17] & 3) ^ 3;
1433
            if ((y1 & mask) == mask)
1434
                addr1 += line_offset;
1435
            y1++;
1436
            multi_run = multi_scan;
1437
        } else {
1438
            multi_run--;
1439
        }
1440
        /* line compare acts on the displayed lines */
1441
        if (y == s->line_compare)
1442
            addr1 = 0;
1443
        d += linesize;
1444
    }
1445
    if (y_start >= 0) {
1446
        /* flush to display */
1447
        dpy_update(s->ds, 0, y_start, 
1448
                   disp_width, y - y_start);
1449
    }
1450
    /* reset modified pages */
1451
    if (page_max != -1) {
1452
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1453
                                        VGA_DIRTY_FLAG);
1454
    }
1455
    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1456
}
1457

    
1458
static void vga_draw_blank(VGAState *s, int full_update)
1459
{
1460
    int i, w, val;
1461
    uint8_t *d;
1462

    
1463
    if (!full_update)
1464
        return;
1465
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1466
        return;
1467
    if (s->ds->depth == 8) 
1468
        val = s->rgb_to_pixel(0, 0, 0);
1469
    else
1470
        val = 0;
1471
    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1472
    d = s->ds->data;
1473
    for(i = 0; i < s->last_scr_height; i++) {
1474
        memset(d, val, w);
1475
        d += s->ds->linesize;
1476
    }
1477
    dpy_update(s->ds, 0, 0, 
1478
               s->last_scr_width, s->last_scr_height);
1479
}
1480

    
1481
#define GMODE_TEXT     0
1482
#define GMODE_GRAPH    1
1483
#define GMODE_BLANK 2 
1484

    
1485
void vga_update_display(void)
1486
{
1487
    VGAState *s = vga_state;
1488
    int full_update, graphic_mode;
1489

    
1490
    if (s->ds->depth == 0) {
1491
        /* nothing to do */
1492
    } else {
1493
        switch(s->ds->depth) {
1494
        case 8:
1495
            s->rgb_to_pixel = rgb_to_pixel8_dup;
1496
            break;
1497
        case 15:
1498
            s->rgb_to_pixel = rgb_to_pixel15_dup;
1499
            break;
1500
        default:
1501
        case 16:
1502
            s->rgb_to_pixel = rgb_to_pixel16_dup;
1503
            break;
1504
        case 32:
1505
            s->rgb_to_pixel = rgb_to_pixel32_dup;
1506
            break;
1507
        }
1508
        
1509
        full_update = 0;
1510
        if (!(s->ar_index & 0x20)) {
1511
            graphic_mode = GMODE_BLANK;
1512
        } else {
1513
            graphic_mode = s->gr[6] & 1;
1514
        }
1515
        if (graphic_mode != s->graphic_mode) {
1516
            s->graphic_mode = graphic_mode;
1517
            full_update = 1;
1518
        }
1519
        switch(graphic_mode) {
1520
        case GMODE_TEXT:
1521
            vga_draw_text(s, full_update);
1522
            break;
1523
        case GMODE_GRAPH:
1524
            vga_draw_graphic(s, full_update);
1525
            break;
1526
        case GMODE_BLANK:
1527
        default:
1528
            vga_draw_blank(s, full_update);
1529
            break;
1530
        }
1531
    }
1532
}
1533

    
1534
/* force a full display refresh */
1535
void vga_invalidate_display(void)
1536
{
1537
    VGAState *s = vga_state;
1538
    
1539
    s->last_width = -1;
1540
    s->last_height = -1;
1541
}
1542

    
1543
static void vga_reset(VGAState *s)
1544
{
1545
    memset(s, 0, sizeof(VGAState));
1546
    s->graphic_mode = -1; /* force full update */
1547
}
1548

    
1549
static CPUReadMemoryFunc *vga_mem_read[3] = {
1550
    vga_mem_readb,
1551
    vga_mem_readw,
1552
    vga_mem_readl,
1553
};
1554

    
1555
static CPUWriteMemoryFunc *vga_mem_write[3] = {
1556
    vga_mem_writeb,
1557
    vga_mem_writew,
1558
    vga_mem_writel,
1559
};
1560

    
1561
static void vga_save(QEMUFile *f, void *opaque)
1562
{
1563
    VGAState *s = opaque;
1564
    int i;
1565

    
1566
    qemu_put_be32s(f, &s->latch);
1567
    qemu_put_8s(f, &s->sr_index);
1568
    qemu_put_buffer(f, s->sr, 8);
1569
    qemu_put_8s(f, &s->gr_index);
1570
    qemu_put_buffer(f, s->gr, 16);
1571
    qemu_put_8s(f, &s->ar_index);
1572
    qemu_put_buffer(f, s->ar, 21);
1573
    qemu_put_be32s(f, &s->ar_flip_flop);
1574
    qemu_put_8s(f, &s->cr_index);
1575
    qemu_put_buffer(f, s->cr, 256);
1576
    qemu_put_8s(f, &s->msr);
1577
    qemu_put_8s(f, &s->fcr);
1578
    qemu_put_8s(f, &s->st00);
1579
    qemu_put_8s(f, &s->st01);
1580

    
1581
    qemu_put_8s(f, &s->dac_state);
1582
    qemu_put_8s(f, &s->dac_sub_index);
1583
    qemu_put_8s(f, &s->dac_read_index);
1584
    qemu_put_8s(f, &s->dac_write_index);
1585
    qemu_put_buffer(f, s->dac_cache, 3);
1586
    qemu_put_buffer(f, s->palette, 768);
1587

    
1588
    qemu_put_be32s(f, &s->bank_offset);
1589
#ifdef CONFIG_BOCHS_VBE
1590
    qemu_put_byte(f, 1);
1591
    qemu_put_be16s(f, &s->vbe_index);
1592
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1593
        qemu_put_be16s(f, &s->vbe_regs[i]);
1594
    qemu_put_be32s(f, &s->vbe_start_addr);
1595
    qemu_put_be32s(f, &s->vbe_line_offset);
1596
    qemu_put_be32s(f, &s->vbe_bank_mask);
1597
#else
1598
    qemu_put_byte(f, 0);
1599
#endif
1600
}
1601

    
1602
static int vga_load(QEMUFile *f, void *opaque, int version_id)
1603
{
1604
    VGAState *s = opaque;
1605
    int is_vbe, i;
1606

    
1607
    if (version_id != 1)
1608
        return -EINVAL;
1609

    
1610
    qemu_get_be32s(f, &s->latch);
1611
    qemu_get_8s(f, &s->sr_index);
1612
    qemu_get_buffer(f, s->sr, 8);
1613
    qemu_get_8s(f, &s->gr_index);
1614
    qemu_get_buffer(f, s->gr, 16);
1615
    qemu_get_8s(f, &s->ar_index);
1616
    qemu_get_buffer(f, s->ar, 21);
1617
    qemu_get_be32s(f, &s->ar_flip_flop);
1618
    qemu_get_8s(f, &s->cr_index);
1619
    qemu_get_buffer(f, s->cr, 256);
1620
    qemu_get_8s(f, &s->msr);
1621
    qemu_get_8s(f, &s->fcr);
1622
    qemu_get_8s(f, &s->st00);
1623
    qemu_get_8s(f, &s->st01);
1624

    
1625
    qemu_get_8s(f, &s->dac_state);
1626
    qemu_get_8s(f, &s->dac_sub_index);
1627
    qemu_get_8s(f, &s->dac_read_index);
1628
    qemu_get_8s(f, &s->dac_write_index);
1629
    qemu_get_buffer(f, s->dac_cache, 3);
1630
    qemu_get_buffer(f, s->palette, 768);
1631

    
1632
    qemu_get_be32s(f, &s->bank_offset);
1633
    is_vbe = qemu_get_byte(f);
1634
#ifdef CONFIG_BOCHS_VBE
1635
    if (!is_vbe)
1636
        return -EINVAL;
1637
    qemu_get_be16s(f, &s->vbe_index);
1638
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1639
        qemu_get_be16s(f, &s->vbe_regs[i]);
1640
    qemu_get_be32s(f, &s->vbe_start_addr);
1641
    qemu_get_be32s(f, &s->vbe_line_offset);
1642
    qemu_get_be32s(f, &s->vbe_bank_mask);
1643
#else
1644
    if (is_vbe)
1645
        return -EINVAL;
1646
#endif
1647

    
1648
    /* force refresh */
1649
    s->graphic_mode = -1;
1650
    return 0;
1651
}
1652

    
1653
static void vga_map(PCIDevice *pci_dev, int region_num, 
1654
                    uint32_t addr, uint32_t size, int type)
1655
{
1656
    VGAState *s = vga_state;
1657

    
1658
    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1659
}
1660

    
1661
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
1662
                     unsigned long vga_ram_offset, int vga_ram_size)
1663
{
1664
    int i, j, v, b;
1665

    
1666
    for(i = 0;i < 256; i++) {
1667
        v = 0;
1668
        for(j = 0; j < 8; j++) {
1669
            v |= ((i >> j) & 1) << (j * 4);
1670
        }
1671
        expand4[i] = v;
1672

    
1673
        v = 0;
1674
        for(j = 0; j < 4; j++) {
1675
            v |= ((i >> (2 * j)) & 3) << (j * 4);
1676
        }
1677
        expand2[i] = v;
1678
    }
1679
    for(i = 0; i < 16; i++) {
1680
        v = 0;
1681
        for(j = 0; j < 4; j++) {
1682
            b = ((i >> j) & 1);
1683
            v |= b << (2 * j);
1684
            v |= b << (2 * j + 1);
1685
        }
1686
        expand4to8[i] = v;
1687
    }
1688

    
1689
    vga_reset(s);
1690

    
1691
    s->vram_ptr = vga_ram_base;
1692
    s->vram_offset = vga_ram_offset;
1693
    s->vram_size = vga_ram_size;
1694
    s->ds = ds;
1695
    s->get_bpp = vga_get_bpp;
1696
    s->get_offsets = vga_get_offsets;
1697
    s->get_resolution = vga_get_resolution;
1698
    /* XXX: currently needed for display */
1699
    vga_state = s;
1700
}
1701

    
1702

    
1703
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
1704
                   unsigned long vga_ram_offset, int vga_ram_size)
1705
{
1706
    VGAState *s;
1707

    
1708
    s = qemu_mallocz(sizeof(VGAState));
1709
    if (!s)
1710
        return -1;
1711

    
1712
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1713

    
1714
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1715

    
1716
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1717

    
1718
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1719
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1720
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1721
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1722

    
1723
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1724

    
1725
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1726
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1727
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1728
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1729
    s->bank_offset = 0;
1730

    
1731
#ifdef CONFIG_BOCHS_VBE
1732
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1733
    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1734
#if defined (TARGET_I386)
1735
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1736
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1737

    
1738
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1739
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1740

    
1741
    /* old Bochs IO ports */
1742
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1743
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1744

    
1745
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1746
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
1747
#else
1748
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1749
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1750

    
1751
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1752
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1753
#endif
1754
#endif /* CONFIG_BOCHS_VBE */
1755

    
1756
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1757
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
1758
                                 vga_io_memory);
1759

    
1760
    if (bus) {
1761
        PCIDevice *d;
1762
        uint8_t *pci_conf;
1763

    
1764
        d = pci_register_device(bus, "VGA", 
1765
                                sizeof(PCIDevice),
1766
                                -1, NULL, NULL);
1767
        pci_conf = d->config;
1768
        pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1769
        pci_conf[0x01] = 0x12;
1770
        pci_conf[0x02] = 0x11;
1771
        pci_conf[0x03] = 0x11;
1772
        pci_conf[0x0a] = 0x00; // VGA controller 
1773
        pci_conf[0x0b] = 0x03;
1774
        pci_conf[0x0e] = 0x00; // header_type
1775

    
1776
        /* XXX: vga_ram_size must be a power of two */
1777
        pci_register_io_region(d, 0, vga_ram_size, 
1778
                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1779
    } else {
1780
#ifdef CONFIG_BOCHS_VBE
1781
        /* XXX: use optimized standard vga accesses */
1782
        cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
1783
                                     vga_ram_size, vga_ram_offset);
1784
#endif
1785
    }
1786
    return 0;
1787
}
1788

    
1789
/********************************************************/
1790
/* vga screen dump */
1791

    
1792
static int vga_save_w, vga_save_h;
1793

    
1794
static void vga_save_dpy_update(DisplayState *s, 
1795
                                int x, int y, int w, int h)
1796
{
1797
}
1798

    
1799
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1800
{
1801
    s->linesize = w * 4;
1802
    s->data = qemu_malloc(h * s->linesize);
1803
    vga_save_w = w;
1804
    vga_save_h = h;
1805
}
1806

    
1807
static void vga_save_dpy_refresh(DisplayState *s)
1808
{
1809
}
1810

    
1811
static int ppm_save(const char *filename, uint8_t *data, 
1812
                    int w, int h, int linesize)
1813
{
1814
    FILE *f;
1815
    uint8_t *d, *d1;
1816
    unsigned int v;
1817
    int y, x;
1818

    
1819
    f = fopen(filename, "wb");
1820
    if (!f)
1821
        return -1;
1822
    fprintf(f, "P6\n%d %d\n%d\n",
1823
            w, h, 255);
1824
    d1 = data;
1825
    for(y = 0; y < h; y++) {
1826
        d = d1;
1827
        for(x = 0; x < w; x++) {
1828
            v = *(uint32_t *)d;
1829
            fputc((v >> 16) & 0xff, f);
1830
            fputc((v >> 8) & 0xff, f);
1831
            fputc((v) & 0xff, f);
1832
            d += 4;
1833
        }
1834
        d1 += linesize;
1835
    }
1836
    fclose(f);
1837
    return 0;
1838
}
1839

    
1840
/* save the vga display in a PPM image even if no display is
1841
   available */
1842
void vga_screen_dump(const char *filename)
1843
{
1844
    VGAState *s = vga_state;
1845
    DisplayState *saved_ds, ds1, *ds = &ds1;
1846
    
1847
    /* XXX: this is a little hackish */
1848
    vga_invalidate_display();
1849
    saved_ds = s->ds;
1850

    
1851
    memset(ds, 0, sizeof(DisplayState));
1852
    ds->dpy_update = vga_save_dpy_update;
1853
    ds->dpy_resize = vga_save_dpy_resize;
1854
    ds->dpy_refresh = vga_save_dpy_refresh;
1855
    ds->depth = 32;
1856

    
1857
    s->ds = ds;
1858
    s->graphic_mode = -1;
1859
    vga_update_display();
1860
    
1861
    if (ds->data) {
1862
        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
1863
                 s->ds->linesize);
1864
        qemu_free(ds->data);
1865
    }
1866
    s->ds = saved_ds;
1867
}