Statistics
| Branch: | Revision:

root / hw / vga.c @ a8aa669b

History | View | Annotate | Download (53.1 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_S3
32
//#define DEBUG_BOCHS_VBE
33

    
34
/* S3 VGA is deprecated - another graphic card will be emulated */
35
//#define CONFIG_S3VGA
36

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

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

    
68
#define cbswap_32(__x) \
69
((uint32_t)( \
70
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
71
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
72
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
73
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
74

    
75
#ifdef WORDS_BIGENDIAN
76
#define PAT(x) cbswap_32(x)
77
#else
78
#define PAT(x) (x)
79
#endif
80

    
81
#ifdef WORDS_BIGENDIAN
82
#define BIG 1
83
#else
84
#define BIG 0
85
#endif
86

    
87
#ifdef WORDS_BIGENDIAN
88
#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
89
#else
90
#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
91
#endif
92

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

    
112
#undef PAT
113

    
114
#ifdef WORDS_BIGENDIAN
115
#define PAT(x) (x)
116
#else
117
#define PAT(x) cbswap_32(x)
118
#endif
119

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

    
139
static const uint32_t dmask4[4] = {
140
    PAT(0x00000000),
141
    PAT(0x0000ffff),
142
    PAT(0xffff0000),
143
    PAT(0xffffffff),
144
};
145

    
146
static uint32_t expand4[256];
147
static uint16_t expand2[256];
148
static uint8_t expand4to8[16];
149

    
150
VGAState *vga_state;
151
int vga_io_memory;
152

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

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

    
249
static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
250
{
251
    VGAState *s = opaque;
252
    int index;
253

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

    
259
#ifdef DEBUG_VGA
260
    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
261
#endif
262

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

    
360
#ifdef CONFIG_S3VGA
361
            /* S3 registers */
362
        case 0x2d:
363
        case 0x2e:
364
        case 0x2f:
365
        case 0x30:
366
            /* chip ID, cannot write */
367
            break;
368
        case 0x31:
369
            /* update start address */
370
            {
371
                int v;
372
                s->cr[s->cr_index] = val;
373
                v = (val >> 4) & 3;
374
                s->cr[0x69] = (s->cr[69] & ~0x03) | v;
375
            }
376
            break;
377
        case 0x51:
378
            /* update start address */
379
            {
380
                int v;
381
                s->cr[s->cr_index] = val;
382
                v = val & 3;
383
                s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
384
            }
385
            break;
386
#endif
387
        default:
388
            s->cr[s->cr_index] = val;
389
            break;
390
        }
391
#ifdef DEBUG_S3
392
        if (s->cr_index >= 0x20)
393
            printf("S3: CR write index=0x%x val=0x%x\n",
394
                   s->cr_index, val);
395
#endif
396
        break;
397
    case 0x3ba:
398
    case 0x3da:
399
        s->fcr = val & 0x10;
400
        break;
401
    }
402
}
403

    
404
#ifdef CONFIG_BOCHS_VBE
405
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
406
{
407
    VGAState *s = opaque;
408
    uint32_t val;
409
    val = s->vbe_index;
410
    return val;
411
}
412

    
413
static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
414
{
415
    VGAState *s = opaque;
416
    uint32_t val;
417

    
418
    if (s->vbe_index <= VBE_DISPI_INDEX_NB)
419
        val = s->vbe_regs[s->vbe_index];
420
    else
421
        val = 0;
422
#ifdef DEBUG_BOCHS_VBE
423
    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
424
#endif
425
    return val;
426
}
427

    
428
static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
429
{
430
    VGAState *s = opaque;
431
    s->vbe_index = val;
432
}
433

    
434
static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
435
{
436
    VGAState *s = opaque;
437

    
438
    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
439
#ifdef DEBUG_BOCHS_VBE
440
        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
441
#endif
442
        switch(s->vbe_index) {
443
        case VBE_DISPI_INDEX_ID:
444
            if (val == VBE_DISPI_ID0 ||
445
                val == VBE_DISPI_ID1 ||
446
                val == VBE_DISPI_ID2) {
447
                s->vbe_regs[s->vbe_index] = val;
448
            }
449
            break;
450
        case VBE_DISPI_INDEX_XRES:
451
            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
452
                s->vbe_regs[s->vbe_index] = val;
453
            }
454
            break;
455
        case VBE_DISPI_INDEX_YRES:
456
            if (val <= VBE_DISPI_MAX_YRES) {
457
                s->vbe_regs[s->vbe_index] = val;
458
            }
459
            break;
460
        case VBE_DISPI_INDEX_BPP:
461
            if (val == 0)
462
                val = 8;
463
            if (val == 4 || val == 8 || val == 15 || 
464
                val == 16 || val == 24 || val == 32) {
465
                s->vbe_regs[s->vbe_index] = val;
466
            }
467
            break;
468
        case VBE_DISPI_INDEX_BANK:
469
            val &= s->vbe_bank_mask;
470
            s->vbe_regs[s->vbe_index] = val;
471
            s->bank_offset = (val << 16);
472
            break;
473
        case VBE_DISPI_INDEX_ENABLE:
474
            if (val & VBE_DISPI_ENABLED) {
475
                int h, shift_control;
476

    
477
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 
478
                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
479
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = 
480
                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
481
                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
482
                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
483
                
484
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
485
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
486
                else
487
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * 
488
                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
489
                s->vbe_start_addr = 0;
490
                
491
                /* clear the screen (should be done in BIOS) */
492
                if (!(val & VBE_DISPI_NOCLEARMEM)) {
493
                    memset(s->vram_ptr, 0, 
494
                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
495
                }
496
                
497
                /* we initialize the VGA graphic mode (should be done
498
                   in BIOS) */
499
                s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
500
                s->cr[0x17] |= 3; /* no CGA modes */
501
                s->cr[0x13] = s->vbe_line_offset >> 3;
502
                /* width */
503
                s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
504
                /* height */
505
                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
506
                s->cr[0x12] = h;
507
                s->cr[0x07] = (s->cr[0x07] & ~0x42) | 
508
                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
509
                /* line compare to 1023 */
510
                s->cr[0x18] = 0xff;
511
                s->cr[0x07] |= 0x10;
512
                s->cr[0x09] |= 0x40;
513
                
514
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
515
                    shift_control = 0;
516
                    s->sr[0x01] &= ~8; /* no double line */
517
                } else {
518
                    shift_control = 2;
519
                    s->sr[4] |= 0x08; /* set chain 4 mode */
520
                    s->sr[2] |= 0x0f; /* activate all planes */
521
                }
522
                s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
523
                s->cr[0x09] &= ~0x9f; /* no double scan */
524
            } else {
525
                /* XXX: the bios should do that */
526
                s->bank_offset = 0;
527
            }
528
            s->vbe_regs[s->vbe_index] = val;
529
            break;
530
        case VBE_DISPI_INDEX_VIRT_WIDTH:
531
            {
532
                int w, h, line_offset;
533

    
534
                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
535
                    return;
536
                w = val;
537
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
538
                    line_offset = w >> 1;
539
                else
540
                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
541
                h = s->vram_size / line_offset;
542
                /* XXX: support weird bochs semantics ? */
543
                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
544
                    return;
545
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
546
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
547
                s->vbe_line_offset = line_offset;
548
            }
549
            break;
550
        case VBE_DISPI_INDEX_X_OFFSET:
551
        case VBE_DISPI_INDEX_Y_OFFSET:
552
            {
553
                int x;
554
                s->vbe_regs[s->vbe_index] = val;
555
                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
556
                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
557
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
558
                    s->vbe_start_addr += x >> 1;
559
                else
560
                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
561
                s->vbe_start_addr >>= 2;
562
            }
563
            break;
564
        default:
565
            break;
566
        }
567
    }
568
}
569
#endif
570

    
571
/* called for accesses between 0xa0000 and 0xc0000 */
572
uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
573
{
574
    VGAState *s = opaque;
575
    int memory_map_mode, plane;
576
    uint32_t ret;
577
    
578
    /* convert to VGA memory offset */
579
    memory_map_mode = (s->gr[6] >> 2) & 3;
580
    addr &= 0x1ffff;
581
    switch(memory_map_mode) {
582
    case 0:
583
        break;
584
    case 1:
585
        if (addr >= 0x10000)
586
            return 0xff;
587
        addr += s->bank_offset;
588
        break;
589
    case 2:
590
        addr -= 0x10000;
591
        if (addr >= 0x8000)
592
            return 0xff;
593
        break;
594
    default:
595
    case 3:
596
        addr -= 0x18000;
597
        if (addr >= 0x8000)
598
            return 0xff;
599
        break;
600
    }
601
    
602
    if (s->sr[4] & 0x08) {
603
        /* chain 4 mode : simplest access */
604
        ret = s->vram_ptr[addr];
605
    } else if (s->gr[5] & 0x10) {
606
        /* odd/even mode (aka text mode mapping) */
607
        plane = (s->gr[4] & 2) | (addr & 1);
608
        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
609
    } else {
610
        /* standard VGA latched access */
611
        s->latch = ((uint32_t *)s->vram_ptr)[addr];
612

    
613
        if (!(s->gr[5] & 0x08)) {
614
            /* read mode 0 */
615
            plane = s->gr[4];
616
            ret = GET_PLANE(s->latch, plane);
617
        } else {
618
            /* read mode 1 */
619
            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
620
            ret |= ret >> 16;
621
            ret |= ret >> 8;
622
            ret = (~ret) & 0xff;
623
        }
624
    }
625
    return ret;
626
}
627

    
628
static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
629
{
630
    uint32_t v;
631
#ifdef TARGET_WORDS_BIGENDIAN
632
    v = vga_mem_readb(opaque, addr) << 8;
633
    v |= vga_mem_readb(opaque, addr + 1);
634
#else
635
    v = vga_mem_readb(opaque, addr);
636
    v |= vga_mem_readb(opaque, addr + 1) << 8;
637
#endif
638
    return v;
639
}
640

    
641
static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
642
{
643
    uint32_t v;
644
#ifdef TARGET_WORDS_BIGENDIAN
645
    v = vga_mem_readb(opaque, addr) << 24;
646
    v |= vga_mem_readb(opaque, addr + 1) << 16;
647
    v |= vga_mem_readb(opaque, addr + 2) << 8;
648
    v |= vga_mem_readb(opaque, addr + 3);
649
#else
650
    v = vga_mem_readb(opaque, addr);
651
    v |= vga_mem_readb(opaque, addr + 1) << 8;
652
    v |= vga_mem_readb(opaque, addr + 2) << 16;
653
    v |= vga_mem_readb(opaque, addr + 3) << 24;
654
#endif
655
    return v;
656
}
657

    
658
/* called for accesses between 0xa0000 and 0xc0000 */
659
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
660
{
661
    VGAState *s = opaque;
662
    int memory_map_mode, plane, write_mode, b, func_select;
663
    uint32_t write_mask, bit_mask, set_mask;
664

    
665
#ifdef DEBUG_VGA_MEM
666
    printf("vga: [0x%x] = 0x%02x\n", addr, val);
667
#endif
668
    /* convert to VGA memory offset */
669
    memory_map_mode = (s->gr[6] >> 2) & 3;
670
    addr &= 0x1ffff;
671
    switch(memory_map_mode) {
672
    case 0:
673
        break;
674
    case 1:
675
        if (addr >= 0x10000)
676
            return;
677
        addr += s->bank_offset;
678
        break;
679
    case 2:
680
        addr -= 0x10000;
681
        if (addr >= 0x8000)
682
            return;
683
        break;
684
    default:
685
    case 3:
686
        addr -= 0x18000;
687
        if (addr >= 0x8000)
688
            return;
689
        break;
690
    }
691
    
692
    if (s->sr[4] & 0x08) {
693
        /* chain 4 mode : simplest access */
694
        plane = addr & 3;
695
        if (s->sr[2] & (1 << plane)) {
696
            s->vram_ptr[addr] = val;
697
#ifdef DEBUG_VGA_MEM
698
            printf("vga: chain4: [0x%x]\n", addr);
699
#endif
700
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
701
        }
702
    } else if (s->gr[5] & 0x10) {
703
        /* odd/even mode (aka text mode mapping) */
704
        plane = (s->gr[4] & 2) | (addr & 1);
705
        if (s->sr[2] & (1 << plane)) {
706
            addr = ((addr & ~1) << 1) | plane;
707
            s->vram_ptr[addr] = val;
708
#ifdef DEBUG_VGA_MEM
709
            printf("vga: odd/even: [0x%x]\n", addr);
710
#endif
711
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
712
        }
713
    } else {
714
        /* standard VGA latched access */
715
        write_mode = s->gr[5] & 3;
716
        switch(write_mode) {
717
        default:
718
        case 0:
719
            /* rotate */
720
            b = s->gr[3] & 7;
721
            val = ((val >> b) | (val << (8 - b))) & 0xff;
722
            val |= val << 8;
723
            val |= val << 16;
724

    
725
            /* apply set/reset mask */
726
            set_mask = mask16[s->gr[1]];
727
            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
728
            bit_mask = s->gr[8];
729
            break;
730
        case 1:
731
            val = s->latch;
732
            goto do_write;
733
        case 2:
734
            val = mask16[val & 0x0f];
735
            bit_mask = s->gr[8];
736
            break;
737
        case 3:
738
            /* rotate */
739
            b = s->gr[3] & 7;
740
            val = (val >> b) | (val << (8 - b));
741

    
742
            bit_mask = s->gr[8] & val;
743
            val = mask16[s->gr[0]];
744
            break;
745
        }
746

    
747
        /* apply logical operation */
748
        func_select = s->gr[3] >> 3;
749
        switch(func_select) {
750
        case 0:
751
        default:
752
            /* nothing to do */
753
            break;
754
        case 1:
755
            /* and */
756
            val &= s->latch;
757
            break;
758
        case 2:
759
            /* or */
760
            val |= s->latch;
761
            break;
762
        case 3:
763
            /* xor */
764
            val ^= s->latch;
765
            break;
766
        }
767

    
768
        /* apply bit mask */
769
        bit_mask |= bit_mask << 8;
770
        bit_mask |= bit_mask << 16;
771
        val = (val & bit_mask) | (s->latch & ~bit_mask);
772

    
773
    do_write:
774
        /* mask data according to sr[2] */
775
        write_mask = mask16[s->sr[2]];
776
        ((uint32_t *)s->vram_ptr)[addr] = 
777
            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | 
778
            (val & write_mask);
779
#ifdef DEBUG_VGA_MEM
780
            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", 
781
                   addr * 4, write_mask, val);
782
#endif
783
            cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
784
    }
785
}
786

    
787
static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
788
{
789
#ifdef TARGET_WORDS_BIGENDIAN
790
    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
791
    vga_mem_writeb(opaque, addr + 1, val & 0xff);
792
#else
793
    vga_mem_writeb(opaque, addr, val & 0xff);
794
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
795
#endif
796
}
797

    
798
static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
799
{
800
#ifdef TARGET_WORDS_BIGENDIAN
801
    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
802
    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
803
    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
804
    vga_mem_writeb(opaque, addr + 3, val & 0xff);
805
#else
806
    vga_mem_writeb(opaque, addr, val & 0xff);
807
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
808
    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
809
    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
810
#endif
811
}
812

    
813
typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
814
                             const uint8_t *font_ptr, int h,
815
                             uint32_t fgcol, uint32_t bgcol);
816
typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
817
                                  const uint8_t *font_ptr, int h, 
818
                                  uint32_t fgcol, uint32_t bgcol, int dup9);
819
typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, 
820
                                const uint8_t *s, int width);
821

    
822
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
823
{
824
    /* XXX: TODO */
825
    return 0;
826
}
827

    
828
static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
829
{
830
    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
831
}
832

    
833
static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
834
{
835
    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
836
}
837

    
838
static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
839
{
840
    return (r << 16) | (g << 8) | b;
841
}
842

    
843
#define DEPTH 8
844
#include "vga_template.h"
845

    
846
#define DEPTH 15
847
#include "vga_template.h"
848

    
849
#define DEPTH 16
850
#include "vga_template.h"
851

    
852
#define DEPTH 32
853
#include "vga_template.h"
854

    
855
static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
856
{
857
    unsigned int col;
858
    col = rgb_to_pixel8(r, g, b);
859
    col |= col << 8;
860
    col |= col << 16;
861
    return col;
862
}
863

    
864
static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
865
{
866
    unsigned int col;
867
    col = rgb_to_pixel15(r, g, b);
868
    col |= col << 16;
869
    return col;
870
}
871

    
872
static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
873
{
874
    unsigned int col;
875
    col = rgb_to_pixel16(r, g, b);
876
    col |= col << 16;
877
    return col;
878
}
879

    
880
static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
881
{
882
    unsigned int col;
883
    col = rgb_to_pixel32(r, g, b);
884
    return col;
885
}
886

    
887
/* return true if the palette was modified */
888
static int update_palette16(VGAState *s)
889
{
890
    int full_update, i;
891
    uint32_t v, col, *palette;
892

    
893
    full_update = 0;
894
    palette = s->last_palette;
895
    for(i = 0; i < 16; i++) {
896
        v = s->ar[i];
897
        if (s->ar[0x10] & 0x80)
898
            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
899
        else
900
            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
901
        v = v * 3;
902
        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
903
                              c6_to_8(s->palette[v + 1]), 
904
                              c6_to_8(s->palette[v + 2]));
905
        if (col != palette[i]) {
906
            full_update = 1;
907
            palette[i] = col;
908
        }
909
    }
910
    return full_update;
911
}
912

    
913
/* return true if the palette was modified */
914
static int update_palette256(VGAState *s)
915
{
916
    int full_update, i;
917
    uint32_t v, col, *palette;
918

    
919
    full_update = 0;
920
    palette = s->last_palette;
921
    v = 0;
922
    for(i = 0; i < 256; i++) {
923
        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
924
                              c6_to_8(s->palette[v + 1]), 
925
                              c6_to_8(s->palette[v + 2]));
926
        if (col != palette[i]) {
927
            full_update = 1;
928
            palette[i] = col;
929
        }
930
        v += 3;
931
    }
932
    return full_update;
933
}
934

    
935
static void vga_get_offsets(VGAState *s, 
936
                            uint32_t *pline_offset, 
937
                            uint32_t *pstart_addr)
938
{
939
    uint32_t start_addr, line_offset;
940
#ifdef CONFIG_BOCHS_VBE
941
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
942
        line_offset = s->vbe_line_offset;
943
        start_addr = s->vbe_start_addr;
944
    } else
945
#endif
946
    {  
947
        /* compute line_offset in bytes */
948
        line_offset = s->cr[0x13];
949
#ifdef CONFIG_S3VGA
950
        {
951
            uinr32_t v;
952
            v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
953
            if (v == 0)
954
                v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
955
            line_offset |= (v << 8);
956
        }
957
#endif
958
        line_offset <<= 3;
959
        
960
        /* starting address */
961
        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
962
#ifdef CONFIG_S3VGA
963
        start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
964
#endif
965
    }
966
    *pline_offset = line_offset;
967
    *pstart_addr = start_addr;
968
}
969

    
970
/* update start_addr and line_offset. Return TRUE if modified */
971
static int update_basic_params(VGAState *s)
972
{
973
    int full_update;
974
    uint32_t start_addr, line_offset, line_compare;
975
    
976
    full_update = 0;
977

    
978
    s->get_offsets(s, &line_offset, &start_addr);
979
    /* line compare */
980
    line_compare = s->cr[0x18] | 
981
        ((s->cr[0x07] & 0x10) << 4) |
982
        ((s->cr[0x09] & 0x40) << 3);
983

    
984
    if (line_offset != s->line_offset ||
985
        start_addr != s->start_addr ||
986
        line_compare != s->line_compare) {
987
        s->line_offset = line_offset;
988
        s->start_addr = start_addr;
989
        s->line_compare = line_compare;
990
        full_update = 1;
991
    }
992
    return full_update;
993
}
994

    
995
static inline int get_depth_index(int depth)
996
{
997
    switch(depth) {
998
    default:
999
    case 8:
1000
        return 0;
1001
    case 15:
1002
        return 1;
1003
    case 16:
1004
        return 2;
1005
    case 32:
1006
        return 3;
1007
    }
1008
}
1009

    
1010
static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1011
    vga_draw_glyph8_8,
1012
    vga_draw_glyph8_16,
1013
    vga_draw_glyph8_16,
1014
    vga_draw_glyph8_32,
1015
};
1016

    
1017
static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1018
    vga_draw_glyph16_8,
1019
    vga_draw_glyph16_16,
1020
    vga_draw_glyph16_16,
1021
    vga_draw_glyph16_32,
1022
};
1023

    
1024
static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1025
    vga_draw_glyph9_8,
1026
    vga_draw_glyph9_16,
1027
    vga_draw_glyph9_16,
1028
    vga_draw_glyph9_32,
1029
};
1030
    
1031
static const uint8_t cursor_glyph[32 * 4] = {
1032
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1033
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1034
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1035
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1036
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1037
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1038
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1039
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1040
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1041
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1042
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1043
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1044
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1045
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1046
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1047
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1048
};    
1049

    
1050
/* 
1051
 * Text mode update 
1052
 * Missing:
1053
 * - double scan
1054
 * - double width 
1055
 * - underline
1056
 * - flashing
1057
 */
1058
static void vga_draw_text(VGAState *s, int full_update)
1059
{
1060
    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1061
    int cx_min, cx_max, linesize, x_incr;
1062
    uint32_t offset, fgcol, bgcol, v, cursor_offset;
1063
    uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1064
    const uint8_t *font_ptr, *font_base[2];
1065
    int dup9, line_offset, depth_index;
1066
    uint32_t *palette;
1067
    uint32_t *ch_attr_ptr;
1068
    vga_draw_glyph8_func *vga_draw_glyph8;
1069
    vga_draw_glyph9_func *vga_draw_glyph9;
1070

    
1071
    full_update |= update_palette16(s);
1072
    palette = s->last_palette;
1073
    
1074
    /* compute font data address (in plane 2) */
1075
    v = s->sr[3];
1076
    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1077
    if (offset != s->font_offsets[0]) {
1078
        s->font_offsets[0] = offset;
1079
        full_update = 1;
1080
    }
1081
    font_base[0] = s->vram_ptr + offset;
1082

    
1083
    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1084
    font_base[1] = s->vram_ptr + offset;
1085
    if (offset != s->font_offsets[1]) {
1086
        s->font_offsets[1] = offset;
1087
        full_update = 1;
1088
    }
1089

    
1090
    full_update |= update_basic_params(s);
1091

    
1092
    line_offset = s->line_offset;
1093
    s1 = s->vram_ptr + (s->start_addr * 4);
1094

    
1095
    /* total width & height */
1096
    cheight = (s->cr[9] & 0x1f) + 1;
1097
    cw = 8;
1098
    if (!(s->sr[1] & 0x01))
1099
        cw = 9;
1100
    if (s->sr[1] & 0x08)
1101
        cw = 16; /* NOTE: no 18 pixel wide */
1102
    x_incr = cw * ((s->ds->depth + 7) >> 3);
1103
    width = (s->cr[0x01] + 1);
1104
    if (s->cr[0x06] == 100) {
1105
        /* ugly hack for CGA 160x100x16 - explain me the logic */
1106
        height = 100;
1107
    } else {
1108
        height = s->cr[0x12] | 
1109
            ((s->cr[0x07] & 0x02) << 7) | 
1110
            ((s->cr[0x07] & 0x40) << 3);
1111
        height = (height + 1) / cheight;
1112
    }
1113
    if ((height * width) > CH_ATTR_SIZE) {
1114
        /* better than nothing: exit if transient size is too big */
1115
        return;
1116
    }
1117

    
1118
    if (width != s->last_width || height != s->last_height ||
1119
        cw != s->last_cw || cheight != s->last_ch) {
1120
        s->last_scr_width = width * cw;
1121
        s->last_scr_height = height * cheight;
1122
        dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1123
        s->last_width = width;
1124
        s->last_height = height;
1125
        s->last_ch = cheight;
1126
        s->last_cw = cw;
1127
        full_update = 1;
1128
    }
1129
    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1130
    if (cursor_offset != s->cursor_offset ||
1131
        s->cr[0xa] != s->cursor_start ||
1132
        s->cr[0xb] != s->cursor_end) {
1133
      /* if the cursor position changed, we update the old and new
1134
         chars */
1135
        if (s->cursor_offset < CH_ATTR_SIZE)
1136
            s->last_ch_attr[s->cursor_offset] = -1;
1137
        if (cursor_offset < CH_ATTR_SIZE)
1138
            s->last_ch_attr[cursor_offset] = -1;
1139
        s->cursor_offset = cursor_offset;
1140
        s->cursor_start = s->cr[0xa];
1141
        s->cursor_end = s->cr[0xb];
1142
    }
1143
    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1144
    
1145
    depth_index = get_depth_index(s->ds->depth);
1146
    if (cw == 16)
1147
        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1148
    else
1149
        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1150
    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1151
    
1152
    dest = s->ds->data;
1153
    linesize = s->ds->linesize;
1154
    ch_attr_ptr = s->last_ch_attr;
1155
    for(cy = 0; cy < height; cy++) {
1156
        d1 = dest;
1157
        src = s1;
1158
        cx_min = width;
1159
        cx_max = -1;
1160
        for(cx = 0; cx < width; cx++) {
1161
            ch_attr = *(uint16_t *)src;
1162
            if (full_update || ch_attr != *ch_attr_ptr) {
1163
                if (cx < cx_min)
1164
                    cx_min = cx;
1165
                if (cx > cx_max)
1166
                    cx_max = cx;
1167
                *ch_attr_ptr = ch_attr;
1168
#ifdef WORDS_BIGENDIAN
1169
                ch = ch_attr >> 8;
1170
                cattr = ch_attr & 0xff;
1171
#else
1172
                ch = ch_attr & 0xff;
1173
                cattr = ch_attr >> 8;
1174
#endif
1175
                font_ptr = font_base[(cattr >> 3) & 1];
1176
                font_ptr += 32 * 4 * ch;
1177
                bgcol = palette[cattr >> 4];
1178
                fgcol = palette[cattr & 0x0f];
1179
                if (cw != 9) {
1180
                    vga_draw_glyph8(d1, linesize, 
1181
                                    font_ptr, cheight, fgcol, bgcol);
1182
                } else {
1183
                    dup9 = 0;
1184
                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1185
                        dup9 = 1;
1186
                    vga_draw_glyph9(d1, linesize, 
1187
                                    font_ptr, cheight, fgcol, bgcol, dup9);
1188
                }
1189
                if (src == cursor_ptr &&
1190
                    !(s->cr[0x0a] & 0x20)) {
1191
                    int line_start, line_last, h;
1192
                    /* draw the cursor */
1193
                    line_start = s->cr[0x0a] & 0x1f;
1194
                    line_last = s->cr[0x0b] & 0x1f;
1195
                    /* XXX: check that */
1196
                    if (line_last > cheight - 1)
1197
                        line_last = cheight - 1;
1198
                    if (line_last >= line_start && line_start < cheight) {
1199
                        h = line_last - line_start + 1;
1200
                        d = d1 + linesize * line_start;
1201
                        if (cw != 9) {
1202
                            vga_draw_glyph8(d, linesize, 
1203
                                            cursor_glyph, h, fgcol, bgcol);
1204
                        } else {
1205
                            vga_draw_glyph9(d, linesize, 
1206
                                            cursor_glyph, h, fgcol, bgcol, 1);
1207
                        }
1208
                    }
1209
                }
1210
            }
1211
            d1 += x_incr;
1212
            src += 4;
1213
            ch_attr_ptr++;
1214
        }
1215
        if (cx_max != -1) {
1216
            dpy_update(s->ds, cx_min * cw, cy * cheight, 
1217
                       (cx_max - cx_min + 1) * cw, cheight);
1218
        }
1219
        dest += linesize * cheight;
1220
        s1 += line_offset;
1221
    }
1222
}
1223

    
1224
enum {
1225
    VGA_DRAW_LINE2,
1226
    VGA_DRAW_LINE2D2,
1227
    VGA_DRAW_LINE4,
1228
    VGA_DRAW_LINE4D2,
1229
    VGA_DRAW_LINE8D2,
1230
    VGA_DRAW_LINE8,
1231
    VGA_DRAW_LINE15,
1232
    VGA_DRAW_LINE16,
1233
    VGA_DRAW_LINE24,
1234
    VGA_DRAW_LINE32,
1235
    VGA_DRAW_LINE_NB,
1236
};
1237

    
1238
static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1239
    vga_draw_line2_8,
1240
    vga_draw_line2_16,
1241
    vga_draw_line2_16,
1242
    vga_draw_line2_32,
1243

    
1244
    vga_draw_line2d2_8,
1245
    vga_draw_line2d2_16,
1246
    vga_draw_line2d2_16,
1247
    vga_draw_line2d2_32,
1248

    
1249
    vga_draw_line4_8,
1250
    vga_draw_line4_16,
1251
    vga_draw_line4_16,
1252
    vga_draw_line4_32,
1253

    
1254
    vga_draw_line4d2_8,
1255
    vga_draw_line4d2_16,
1256
    vga_draw_line4d2_16,
1257
    vga_draw_line4d2_32,
1258

    
1259
    vga_draw_line8d2_8,
1260
    vga_draw_line8d2_16,
1261
    vga_draw_line8d2_16,
1262
    vga_draw_line8d2_32,
1263

    
1264
    vga_draw_line8_8,
1265
    vga_draw_line8_16,
1266
    vga_draw_line8_16,
1267
    vga_draw_line8_32,
1268

    
1269
    vga_draw_line15_8,
1270
    vga_draw_line15_15,
1271
    vga_draw_line15_16,
1272
    vga_draw_line15_32,
1273

    
1274
    vga_draw_line16_8,
1275
    vga_draw_line16_15,
1276
    vga_draw_line16_16,
1277
    vga_draw_line16_32,
1278

    
1279
    vga_draw_line24_8,
1280
    vga_draw_line24_15,
1281
    vga_draw_line24_16,
1282
    vga_draw_line24_32,
1283

    
1284
    vga_draw_line32_8,
1285
    vga_draw_line32_15,
1286
    vga_draw_line32_16,
1287
    vga_draw_line32_32,
1288
};
1289

    
1290
static int vga_get_bpp(VGAState *s)
1291
{
1292
    int ret;
1293
#ifdef CONFIG_BOCHS_VBE
1294
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1295
        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1296
    } else 
1297
#endif
1298
    {
1299
        ret = 0;
1300
    }
1301
    return ret;
1302
}
1303

    
1304
void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1305
{
1306
    int y;
1307
    if (y1 >= VGA_MAX_HEIGHT)
1308
        return;
1309
    if (y2 >= VGA_MAX_HEIGHT)
1310
        y2 = VGA_MAX_HEIGHT;
1311
    for(y = y1; y < y2; y++) {
1312
        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1313
    }
1314
}
1315

    
1316
/* 
1317
 * graphic modes
1318
 */
1319
static void vga_draw_graphic(VGAState *s, int full_update)
1320
{
1321
    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1322
    int width, height, shift_control, line_offset, page0, page1, bwidth;
1323
    int disp_width, multi_scan, multi_run;
1324
    uint8_t *d;
1325
    uint32_t v, addr1, addr;
1326
    vga_draw_line_func *vga_draw_line;
1327
    
1328
    full_update |= update_basic_params(s);
1329

    
1330
    width = (s->cr[0x01] + 1) * 8;
1331
    height = s->cr[0x12] | 
1332
        ((s->cr[0x07] & 0x02) << 7) | 
1333
        ((s->cr[0x07] & 0x40) << 3);
1334
    height = (height + 1);
1335
    disp_width = width;
1336

    
1337
    shift_control = (s->gr[0x05] >> 5) & 3;
1338
    double_scan = (s->cr[0x09] & 0x80);
1339
    if (shift_control > 1) {
1340
        multi_scan = (s->cr[0x09] & 0x1f);
1341
    } else {
1342
        multi_scan = 0;
1343
    }
1344
    multi_run = multi_scan;
1345
    if (shift_control != s->shift_control ||
1346
        double_scan != s->double_scan) {
1347
        full_update = 1;
1348
        s->shift_control = shift_control;
1349
        s->double_scan = double_scan;
1350
    }
1351
    
1352
    if (shift_control == 0) {
1353
        full_update |= update_palette16(s);
1354
        if (s->sr[0x01] & 8) {
1355
            v = VGA_DRAW_LINE4D2;
1356
            disp_width <<= 1;
1357
        } else {
1358
            v = VGA_DRAW_LINE4;
1359
        }
1360
    } else if (shift_control == 1) {
1361
        full_update |= update_palette16(s);
1362
        if (s->sr[0x01] & 8) {
1363
            v = VGA_DRAW_LINE2D2;
1364
            disp_width <<= 1;
1365
        } else {
1366
            v = VGA_DRAW_LINE2;
1367
        }
1368
    } else {
1369
        switch(s->get_bpp(s)) {
1370
        default:
1371
        case 0:
1372
            full_update |= update_palette256(s);
1373
            v = VGA_DRAW_LINE8D2;
1374
            break;
1375
        case 8:
1376
            full_update |= update_palette256(s);
1377
            v = VGA_DRAW_LINE8;
1378
            break;
1379
        case 15:
1380
            v = VGA_DRAW_LINE15;
1381
            break;
1382
        case 16:
1383
            v = VGA_DRAW_LINE16;
1384
            break;
1385
        case 24:
1386
            v = VGA_DRAW_LINE24;
1387
            break;
1388
        case 32:
1389
            v = VGA_DRAW_LINE32;
1390
            break;
1391
        }
1392
    }
1393
    vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1394

    
1395
    if (disp_width != s->last_width ||
1396
        height != s->last_height) {
1397
        dpy_resize(s->ds, disp_width, height);
1398
        s->last_scr_width = disp_width;
1399
        s->last_scr_height = height;
1400
        s->last_width = disp_width;
1401
        s->last_height = height;
1402
        full_update = 1;
1403
    }
1404
    if (s->cursor_invalidate)
1405
        s->cursor_invalidate(s);
1406
    
1407
    line_offset = s->line_offset;
1408
#if 0
1409
    printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1410
           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1411
#endif
1412
    addr1 = (s->start_addr * 4);
1413
    bwidth = width * 4;
1414
    y_start = -1;
1415
    page_min = 0x7fffffff;
1416
    page_max = -1;
1417
    d = s->ds->data;
1418
    linesize = s->ds->linesize;
1419
    y1 = 0;
1420
    for(y = 0; y < height; y++) {
1421
        addr = addr1;
1422
        if (!(s->cr[0x17] & 1)) {
1423
            int shift;
1424
            /* CGA compatibility handling */
1425
            shift = 14 + ((s->cr[0x17] >> 6) & 1);
1426
            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1427
        }
1428
        if (!(s->cr[0x17] & 2)) {
1429
            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1430
        }
1431
        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1432
        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1433
        update = full_update | cpu_physical_memory_is_dirty(page0) |
1434
            cpu_physical_memory_is_dirty(page1);
1435
        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1436
            /* if wide line, can use another page */
1437
            update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1438
        }
1439
        /* explicit invalidation for the hardware cursor */
1440
        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1441
        if (update) {
1442
            if (y_start < 0)
1443
                y_start = y;
1444
            if (page0 < page_min)
1445
                page_min = page0;
1446
            if (page1 > page_max)
1447
                page_max = page1;
1448
            vga_draw_line(s, d, s->vram_ptr + addr, width);
1449
            if (s->cursor_draw_line)
1450
                s->cursor_draw_line(s, d, y);
1451
        } else {
1452
            if (y_start >= 0) {
1453
                /* flush to display */
1454
                dpy_update(s->ds, 0, y_start, 
1455
                           disp_width, y - y_start);
1456
                y_start = -1;
1457
            }
1458
        }
1459
        if (!multi_run) {
1460
            if (!double_scan || (y & 1) != 0) {
1461
                if (y1 == s->line_compare) {
1462
                    addr1 = 0;
1463
                } else {
1464
                    mask = (s->cr[0x17] & 3) ^ 3;
1465
                    if ((y1 & mask) == mask)
1466
                        addr1 += line_offset;
1467
                }
1468
                y1++;
1469
            }
1470
            multi_run = multi_scan;
1471
        } else {
1472
            multi_run--;
1473
            y1++;
1474
        }
1475
        d += linesize;
1476
    }
1477
    if (y_start >= 0) {
1478
        /* flush to display */
1479
        dpy_update(s->ds, 0, y_start, 
1480
                   disp_width, y - y_start);
1481
    }
1482
    /* reset modified pages */
1483
    if (page_max != -1) {
1484
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1485
    }
1486
    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1487
}
1488

    
1489
static void vga_draw_blank(VGAState *s, int full_update)
1490
{
1491
    int i, w, val;
1492
    uint8_t *d;
1493

    
1494
    if (!full_update)
1495
        return;
1496
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1497
        return;
1498
    if (s->ds->depth == 8) 
1499
        val = s->rgb_to_pixel(0, 0, 0);
1500
    else
1501
        val = 0;
1502
    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1503
    d = s->ds->data;
1504
    for(i = 0; i < s->last_scr_height; i++) {
1505
        memset(d, val, w);
1506
        d += s->ds->linesize;
1507
    }
1508
    dpy_update(s->ds, 0, 0, 
1509
               s->last_scr_width, s->last_scr_height);
1510
}
1511

    
1512
#define GMODE_TEXT     0
1513
#define GMODE_GRAPH    1
1514
#define GMODE_BLANK 2 
1515

    
1516
void vga_update_display(void)
1517
{
1518
    VGAState *s = vga_state;
1519
    int full_update, graphic_mode;
1520

    
1521
    if (s->ds->depth == 0) {
1522
        /* nothing to do */
1523
    } else {
1524
        switch(s->ds->depth) {
1525
        case 8:
1526
            s->rgb_to_pixel = rgb_to_pixel8_dup;
1527
            break;
1528
        case 15:
1529
            s->rgb_to_pixel = rgb_to_pixel15_dup;
1530
            break;
1531
        default:
1532
        case 16:
1533
            s->rgb_to_pixel = rgb_to_pixel16_dup;
1534
            break;
1535
        case 32:
1536
            s->rgb_to_pixel = rgb_to_pixel32_dup;
1537
            break;
1538
        }
1539
        
1540
        full_update = 0;
1541
        if (!(s->ar_index & 0x20)) {
1542
            graphic_mode = GMODE_BLANK;
1543
        } else {
1544
            graphic_mode = s->gr[6] & 1;
1545
        }
1546
        if (graphic_mode != s->graphic_mode) {
1547
            s->graphic_mode = graphic_mode;
1548
            full_update = 1;
1549
        }
1550
        switch(graphic_mode) {
1551
        case GMODE_TEXT:
1552
            vga_draw_text(s, full_update);
1553
            break;
1554
        case GMODE_GRAPH:
1555
            vga_draw_graphic(s, full_update);
1556
            break;
1557
        case GMODE_BLANK:
1558
        default:
1559
            vga_draw_blank(s, full_update);
1560
            break;
1561
        }
1562
    }
1563
}
1564

    
1565
static void vga_reset(VGAState *s)
1566
{
1567
    memset(s, 0, sizeof(VGAState));
1568
#ifdef CONFIG_S3VGA
1569
    /* chip ID for 8c968 */
1570
    s->cr[0x2d] = 0x88;
1571
    s->cr[0x2e] = 0xb0;
1572
    s->cr[0x2f] = 0x01; /* XXX: check revision code */
1573
    s->cr[0x30] = 0xe1;
1574
#endif
1575
    s->graphic_mode = -1; /* force full update */
1576
}
1577

    
1578
static CPUReadMemoryFunc *vga_mem_read[3] = {
1579
    vga_mem_readb,
1580
    vga_mem_readw,
1581
    vga_mem_readl,
1582
};
1583

    
1584
static CPUWriteMemoryFunc *vga_mem_write[3] = {
1585
    vga_mem_writeb,
1586
    vga_mem_writew,
1587
    vga_mem_writel,
1588
};
1589

    
1590
static void vga_save(QEMUFile *f, void *opaque)
1591
{
1592
    VGAState *s = opaque;
1593
    int i;
1594

    
1595
    qemu_put_be32s(f, &s->latch);
1596
    qemu_put_8s(f, &s->sr_index);
1597
    qemu_put_buffer(f, s->sr, 8);
1598
    qemu_put_8s(f, &s->gr_index);
1599
    qemu_put_buffer(f, s->gr, 16);
1600
    qemu_put_8s(f, &s->ar_index);
1601
    qemu_put_buffer(f, s->ar, 21);
1602
    qemu_put_be32s(f, &s->ar_flip_flop);
1603
    qemu_put_8s(f, &s->cr_index);
1604
    qemu_put_buffer(f, s->cr, 256);
1605
    qemu_put_8s(f, &s->msr);
1606
    qemu_put_8s(f, &s->fcr);
1607
    qemu_put_8s(f, &s->st00);
1608
    qemu_put_8s(f, &s->st01);
1609

    
1610
    qemu_put_8s(f, &s->dac_state);
1611
    qemu_put_8s(f, &s->dac_sub_index);
1612
    qemu_put_8s(f, &s->dac_read_index);
1613
    qemu_put_8s(f, &s->dac_write_index);
1614
    qemu_put_buffer(f, s->dac_cache, 3);
1615
    qemu_put_buffer(f, s->palette, 768);
1616

    
1617
    qemu_put_be32s(f, &s->bank_offset);
1618
#ifdef CONFIG_BOCHS_VBE
1619
    qemu_put_byte(f, 1);
1620
    qemu_put_be16s(f, &s->vbe_index);
1621
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1622
        qemu_put_be16s(f, &s->vbe_regs[i]);
1623
    qemu_put_be32s(f, &s->vbe_start_addr);
1624
    qemu_put_be32s(f, &s->vbe_line_offset);
1625
    qemu_put_be32s(f, &s->vbe_bank_mask);
1626
#else
1627
    qemu_put_byte(f, 0);
1628
#endif
1629
}
1630

    
1631
static int vga_load(QEMUFile *f, void *opaque, int version_id)
1632
{
1633
    VGAState *s = opaque;
1634
    int is_vbe, i;
1635

    
1636
    if (version_id != 1)
1637
        return -EINVAL;
1638

    
1639
    qemu_get_be32s(f, &s->latch);
1640
    qemu_get_8s(f, &s->sr_index);
1641
    qemu_get_buffer(f, s->sr, 8);
1642
    qemu_get_8s(f, &s->gr_index);
1643
    qemu_get_buffer(f, s->gr, 16);
1644
    qemu_get_8s(f, &s->ar_index);
1645
    qemu_get_buffer(f, s->ar, 21);
1646
    qemu_get_be32s(f, &s->ar_flip_flop);
1647
    qemu_get_8s(f, &s->cr_index);
1648
    qemu_get_buffer(f, s->cr, 256);
1649
    qemu_get_8s(f, &s->msr);
1650
    qemu_get_8s(f, &s->fcr);
1651
    qemu_get_8s(f, &s->st00);
1652
    qemu_get_8s(f, &s->st01);
1653

    
1654
    qemu_get_8s(f, &s->dac_state);
1655
    qemu_get_8s(f, &s->dac_sub_index);
1656
    qemu_get_8s(f, &s->dac_read_index);
1657
    qemu_get_8s(f, &s->dac_write_index);
1658
    qemu_get_buffer(f, s->dac_cache, 3);
1659
    qemu_get_buffer(f, s->palette, 768);
1660

    
1661
    qemu_get_be32s(f, &s->bank_offset);
1662
    is_vbe = qemu_get_byte(f);
1663
#ifdef CONFIG_BOCHS_VBE
1664
    if (!is_vbe)
1665
        return -EINVAL;
1666
    qemu_get_be16s(f, &s->vbe_index);
1667
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1668
        qemu_get_be16s(f, &s->vbe_regs[i]);
1669
    qemu_get_be32s(f, &s->vbe_start_addr);
1670
    qemu_get_be32s(f, &s->vbe_line_offset);
1671
    qemu_get_be32s(f, &s->vbe_bank_mask);
1672
#else
1673
    if (is_vbe)
1674
        return -EINVAL;
1675
#endif
1676

    
1677
    /* force refresh */
1678
    s->graphic_mode = -1;
1679
    return 0;
1680
}
1681

    
1682
static void vga_map(PCIDevice *pci_dev, int region_num, 
1683
                    uint32_t addr, uint32_t size, int type)
1684
{
1685
    VGAState *s = vga_state;
1686

    
1687
    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1688
}
1689

    
1690
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
1691
                     unsigned long vga_ram_offset, int vga_ram_size)
1692
{
1693
    int i, j, v, b;
1694

    
1695
    for(i = 0;i < 256; i++) {
1696
        v = 0;
1697
        for(j = 0; j < 8; j++) {
1698
            v |= ((i >> j) & 1) << (j * 4);
1699
        }
1700
        expand4[i] = v;
1701

    
1702
        v = 0;
1703
        for(j = 0; j < 4; j++) {
1704
            v |= ((i >> (2 * j)) & 3) << (j * 4);
1705
        }
1706
        expand2[i] = v;
1707
    }
1708
    for(i = 0; i < 16; i++) {
1709
        v = 0;
1710
        for(j = 0; j < 4; j++) {
1711
            b = ((i >> j) & 1);
1712
            v |= b << (2 * j);
1713
            v |= b << (2 * j + 1);
1714
        }
1715
        expand4to8[i] = v;
1716
    }
1717

    
1718
    vga_reset(s);
1719

    
1720
    s->vram_ptr = vga_ram_base;
1721
    s->vram_offset = vga_ram_offset;
1722
    s->vram_size = vga_ram_size;
1723
    s->ds = ds;
1724
    s->get_bpp = vga_get_bpp;
1725
    s->get_offsets = vga_get_offsets;
1726
    /* XXX: currently needed for display */
1727
    vga_state = s;
1728
}
1729

    
1730

    
1731
int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, 
1732
                   unsigned long vga_ram_offset, int vga_ram_size, 
1733
                   int is_pci)
1734
{
1735
    VGAState *s;
1736

    
1737
    s = qemu_mallocz(sizeof(VGAState));
1738
    if (!s)
1739
        return -1;
1740

    
1741
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1742

    
1743
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1744

    
1745
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1746

    
1747
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1748
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1749
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1750
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1751

    
1752
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1753

    
1754
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1755
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1756
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1757
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1758
    s->bank_offset = 0;
1759

    
1760
#ifdef CONFIG_BOCHS_VBE
1761
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1762
    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1763
#if defined (TARGET_I386)
1764
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1765
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1766

    
1767
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1768
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1769

    
1770
    /* old Bochs IO ports */
1771
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1772
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1773

    
1774
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1775
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
1776
#else
1777
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1778
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1779

    
1780
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1781
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1782
#endif
1783
#endif /* CONFIG_BOCHS_VBE */
1784

    
1785
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1786
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
1787
                                 vga_io_memory);
1788

    
1789
    if (is_pci) {
1790
        PCIDevice *d;
1791
        uint8_t *pci_conf;
1792

    
1793
        d = pci_register_device("VGA", 
1794
                                sizeof(PCIDevice),
1795
                                0, -1, 
1796
                                NULL, NULL);
1797
        pci_conf = d->config;
1798
        pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1799
        pci_conf[0x01] = 0x12;
1800
        pci_conf[0x02] = 0x11;
1801
        pci_conf[0x03] = 0x11;
1802
        pci_conf[0x0a] = 0x00; // VGA controller 
1803
        pci_conf[0x0b] = 0x03;
1804
        pci_conf[0x0e] = 0x00; // header_type
1805

    
1806
        /* XXX: vga_ram_size must be a power of two */
1807
        pci_register_io_region(d, 0, vga_ram_size, 
1808
                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1809
    } else {
1810
#ifdef CONFIG_BOCHS_VBE
1811
        /* XXX: use optimized standard vga accesses */
1812
        cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
1813
                                     vga_ram_size, vga_ram_offset);
1814
#endif
1815
    }
1816
    return 0;
1817
}
1818

    
1819
/********************************************************/
1820
/* vga screen dump */
1821

    
1822
static int vga_save_w, vga_save_h;
1823

    
1824
static void vga_save_dpy_update(DisplayState *s, 
1825
                                int x, int y, int w, int h)
1826
{
1827
}
1828

    
1829
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1830
{
1831
    s->linesize = w * 4;
1832
    s->data = qemu_malloc(h * s->linesize);
1833
    vga_save_w = w;
1834
    vga_save_h = h;
1835
}
1836

    
1837
static void vga_save_dpy_refresh(DisplayState *s)
1838
{
1839
}
1840

    
1841
static int ppm_save(const char *filename, uint8_t *data, 
1842
                    int w, int h, int linesize)
1843
{
1844
    FILE *f;
1845
    uint8_t *d, *d1;
1846
    unsigned int v;
1847
    int y, x;
1848

    
1849
    f = fopen(filename, "wb");
1850
    if (!f)
1851
        return -1;
1852
    fprintf(f, "P6\n%d %d\n%d\n",
1853
            w, h, 255);
1854
    d1 = data;
1855
    for(y = 0; y < h; y++) {
1856
        d = d1;
1857
        for(x = 0; x < w; x++) {
1858
            v = *(uint32_t *)d;
1859
            fputc((v >> 16) & 0xff, f);
1860
            fputc((v >> 8) & 0xff, f);
1861
            fputc((v) & 0xff, f);
1862
            d += 4;
1863
        }
1864
        d1 += linesize;
1865
    }
1866
    fclose(f);
1867
    return 0;
1868
}
1869

    
1870
/* save the vga display in a PPM image even if no display is
1871
   available */
1872
void vga_screen_dump(const char *filename)
1873
{
1874
    VGAState *s = vga_state;
1875
    DisplayState *saved_ds, ds1, *ds = &ds1;
1876
    
1877
    /* XXX: this is a little hackish */
1878
    s->last_width = -1;
1879
    s->last_height = -1;
1880
    saved_ds = s->ds;
1881

    
1882
    memset(ds, 0, sizeof(DisplayState));
1883
    ds->dpy_update = vga_save_dpy_update;
1884
    ds->dpy_resize = vga_save_dpy_resize;
1885
    ds->dpy_refresh = vga_save_dpy_refresh;
1886
    ds->depth = 32;
1887

    
1888
    s->ds = ds;
1889
    s->graphic_mode = -1;
1890
    vga_update_display();
1891
    
1892
    if (ds->data) {
1893
        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
1894
                 s->ds->linesize);
1895
        qemu_free(ds->data);
1896
    }
1897
    s->ds = saved_ds;
1898
}