Statistics
| Branch: | Revision:

root / hw / vga.c @ 95219897

History | View | Annotate | Download (53.5 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 void vga_screen_dump(void *opaque, const char *filename);
150

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
811
#define DEPTH 8
812
#include "vga_template.h"
813

    
814
#define DEPTH 15
815
#include "vga_template.h"
816

    
817
#define DEPTH 16
818
#include "vga_template.h"
819

    
820
#define DEPTH 32
821
#include "vga_template.h"
822

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
980
static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
981
    vga_draw_glyph9_8,
982
    vga_draw_glyph9_16,
983
    vga_draw_glyph9_16,
984
    vga_draw_glyph9_32,
985
};
986
    
987
static const uint8_t cursor_glyph[32 * 4] = {
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
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1003
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1004
};    
1005

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

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

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

    
1053
    line_offset = s->line_offset;
1054
    s1 = s->vram_ptr + (s->start_addr * 4);
1055

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

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

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

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

    
1205
    vga_draw_line2d2_8,
1206
    vga_draw_line2d2_16,
1207
    vga_draw_line2d2_16,
1208
    vga_draw_line2d2_32,
1209

    
1210
    vga_draw_line4_8,
1211
    vga_draw_line4_16,
1212
    vga_draw_line4_16,
1213
    vga_draw_line4_32,
1214

    
1215
    vga_draw_line4d2_8,
1216
    vga_draw_line4d2_16,
1217
    vga_draw_line4d2_16,
1218
    vga_draw_line4d2_32,
1219

    
1220
    vga_draw_line8d2_8,
1221
    vga_draw_line8d2_16,
1222
    vga_draw_line8d2_16,
1223
    vga_draw_line8d2_32,
1224

    
1225
    vga_draw_line8_8,
1226
    vga_draw_line8_16,
1227
    vga_draw_line8_16,
1228
    vga_draw_line8_32,
1229

    
1230
    vga_draw_line15_8,
1231
    vga_draw_line15_15,
1232
    vga_draw_line15_16,
1233
    vga_draw_line15_32,
1234

    
1235
    vga_draw_line16_8,
1236
    vga_draw_line16_15,
1237
    vga_draw_line16_16,
1238
    vga_draw_line16_32,
1239

    
1240
    vga_draw_line24_8,
1241
    vga_draw_line24_15,
1242
    vga_draw_line24_16,
1243
    vga_draw_line24_32,
1244

    
1245
    vga_draw_line32_8,
1246
    vga_draw_line32_15,
1247
    vga_draw_line32_16,
1248
    vga_draw_line32_32,
1249
};
1250

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

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

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

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

    
1304
    s->get_resolution(s, &width, &height);
1305
    disp_width = width;
1306

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

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

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

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

    
1483
#define GMODE_TEXT     0
1484
#define GMODE_GRAPH    1
1485
#define GMODE_BLANK 2 
1486

    
1487
static void vga_update_display(void *opaque)
1488
{
1489
    VGAState *s = (VGAState *)opaque;
1490
    int full_update, graphic_mode;
1491

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

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

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

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

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

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

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

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

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

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

    
1609
    if (version_id != 1)
1610
        return -EINVAL;
1611

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

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

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

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

    
1655
static void vga_map(PCIDevice *pci_dev, int region_num, 
1656
                    uint32_t addr, uint32_t size, int type)
1657
{
1658
    VGAState *s = vga_state;
1659
    if (region_num == PCI_ROM_SLOT) {
1660
        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
1661
    } else {
1662
        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1663
    }
1664
}
1665

    
1666
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
1667
                     unsigned long vga_ram_offset, int vga_ram_size)
1668
{
1669
    int i, j, v, b;
1670

    
1671
    for(i = 0;i < 256; i++) {
1672
        v = 0;
1673
        for(j = 0; j < 8; j++) {
1674
            v |= ((i >> j) & 1) << (j * 4);
1675
        }
1676
        expand4[i] = v;
1677

    
1678
        v = 0;
1679
        for(j = 0; j < 4; j++) {
1680
            v |= ((i >> (2 * j)) & 3) << (j * 4);
1681
        }
1682
        expand2[i] = v;
1683
    }
1684
    for(i = 0; i < 16; i++) {
1685
        v = 0;
1686
        for(j = 0; j < 4; j++) {
1687
            b = ((i >> j) & 1);
1688
            v |= b << (2 * j);
1689
            v |= b << (2 * j + 1);
1690
        }
1691
        expand4to8[i] = v;
1692
    }
1693

    
1694
    vga_reset(s);
1695

    
1696
    s->vram_ptr = vga_ram_base;
1697
    s->vram_offset = vga_ram_offset;
1698
    s->vram_size = vga_ram_size;
1699
    s->ds = ds;
1700
    s->get_bpp = vga_get_bpp;
1701
    s->get_offsets = vga_get_offsets;
1702
    s->get_resolution = vga_get_resolution;
1703
    graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
1704
                         vga_screen_dump, s);
1705
    /* XXX: currently needed for display */
1706
    vga_state = s;
1707
}
1708

    
1709

    
1710
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
1711
                   unsigned long vga_ram_offset, int vga_ram_size,
1712
                   unsigned long vga_bios_offset, int vga_bios_size)
1713
{
1714
    VGAState *s;
1715

    
1716
    s = qemu_mallocz(sizeof(VGAState));
1717
    if (!s)
1718
        return -1;
1719

    
1720
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1721

    
1722
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1723

    
1724
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1725

    
1726
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1727
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1728
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1729
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1730

    
1731
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1732

    
1733
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1734
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1735
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1736
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1737
    s->bank_offset = 0;
1738

    
1739
#ifdef CONFIG_BOCHS_VBE
1740
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1741
    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1742
#if defined (TARGET_I386)
1743
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1744
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1745

    
1746
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1747
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1748

    
1749
    /* old Bochs IO ports */
1750
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1751
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1752

    
1753
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1754
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
1755
#else
1756
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1757
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1758

    
1759
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1760
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1761
#endif
1762
#endif /* CONFIG_BOCHS_VBE */
1763

    
1764
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1765
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
1766
                                 vga_io_memory);
1767

    
1768
    if (bus) {
1769
        PCIDevice *d;
1770
        uint8_t *pci_conf;
1771

    
1772
        d = pci_register_device(bus, "VGA", 
1773
                                sizeof(PCIDevice),
1774
                                -1, NULL, NULL);
1775
        pci_conf = d->config;
1776
        pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1777
        pci_conf[0x01] = 0x12;
1778
        pci_conf[0x02] = 0x11;
1779
        pci_conf[0x03] = 0x11;
1780
        pci_conf[0x0a] = 0x00; // VGA controller 
1781
        pci_conf[0x0b] = 0x03;
1782
        pci_conf[0x0e] = 0x00; // header_type
1783

    
1784
        /* XXX: vga_ram_size must be a power of two */
1785
        pci_register_io_region(d, 0, vga_ram_size, 
1786
                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1787
        if (vga_bios_size != 0) {
1788
            unsigned int bios_total_size;
1789
            s->bios_offset = vga_bios_offset;
1790
            s->bios_size = vga_bios_size;
1791
            /* must be a power of two */
1792
            bios_total_size = 1;
1793
            while (bios_total_size < vga_bios_size)
1794
                bios_total_size <<= 1;
1795
            pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size, 
1796
                                   PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1797
        }
1798
    } else {
1799
#ifdef CONFIG_BOCHS_VBE
1800
        /* XXX: use optimized standard vga accesses */
1801
        cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
1802
                                     vga_ram_size, vga_ram_offset);
1803
#endif
1804
    }
1805
    return 0;
1806
}
1807

    
1808
/********************************************************/
1809
/* vga screen dump */
1810

    
1811
static int vga_save_w, vga_save_h;
1812

    
1813
static void vga_save_dpy_update(DisplayState *s, 
1814
                                int x, int y, int w, int h)
1815
{
1816
}
1817

    
1818
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1819
{
1820
    s->linesize = w * 4;
1821
    s->data = qemu_malloc(h * s->linesize);
1822
    vga_save_w = w;
1823
    vga_save_h = h;
1824
}
1825

    
1826
static void vga_save_dpy_refresh(DisplayState *s)
1827
{
1828
}
1829

    
1830
static int ppm_save(const char *filename, uint8_t *data, 
1831
                    int w, int h, int linesize)
1832
{
1833
    FILE *f;
1834
    uint8_t *d, *d1;
1835
    unsigned int v;
1836
    int y, x;
1837

    
1838
    f = fopen(filename, "wb");
1839
    if (!f)
1840
        return -1;
1841
    fprintf(f, "P6\n%d %d\n%d\n",
1842
            w, h, 255);
1843
    d1 = data;
1844
    for(y = 0; y < h; y++) {
1845
        d = d1;
1846
        for(x = 0; x < w; x++) {
1847
            v = *(uint32_t *)d;
1848
            fputc((v >> 16) & 0xff, f);
1849
            fputc((v >> 8) & 0xff, f);
1850
            fputc((v) & 0xff, f);
1851
            d += 4;
1852
        }
1853
        d1 += linesize;
1854
    }
1855
    fclose(f);
1856
    return 0;
1857
}
1858

    
1859
/* save the vga display in a PPM image even if no display is
1860
   available */
1861
static void vga_screen_dump(void *opaque, const char *filename)
1862
{
1863
    VGAState *s = (VGAState *)opaque;
1864
    DisplayState *saved_ds, ds1, *ds = &ds1;
1865
    
1866
    /* XXX: this is a little hackish */
1867
    vga_invalidate_display(s);
1868
    saved_ds = s->ds;
1869

    
1870
    memset(ds, 0, sizeof(DisplayState));
1871
    ds->dpy_update = vga_save_dpy_update;
1872
    ds->dpy_resize = vga_save_dpy_resize;
1873
    ds->dpy_refresh = vga_save_dpy_refresh;
1874
    ds->depth = 32;
1875

    
1876
    s->ds = ds;
1877
    s->graphic_mode = -1;
1878
    vga_update_display(s);
1879
    
1880
    if (ds->data) {
1881
        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
1882
                 s->ds->linesize);
1883
        qemu_free(ds->data);
1884
    }
1885
    s->ds = saved_ds;
1886
}