Statistics
| Branch: | Revision:

root / hw / vga.c @ e0fe67aa

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_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 0x3c8:
194
            val = s->dac_write_index;
195
            break;
196
        case 0x3c9:
197
            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
198
            if (++s->dac_sub_index == 3) {
199
                s->dac_sub_index = 0;
200
                s->dac_read_index++;
201
            }
202
            break;
203
        case 0x3ca:
204
            val = s->fcr;
205
            break;
206
        case 0x3cc:
207
            val = s->msr;
208
            break;
209
        case 0x3ce:
210
            val = s->gr_index;
211
            break;
212
        case 0x3cf:
213
            val = s->gr[s->gr_index];
214
#ifdef DEBUG_VGA_REG
215
            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
216
#endif
217
            break;
218
        case 0x3b4:
219
        case 0x3d4:
220
            val = s->cr_index;
221
            break;
222
        case 0x3b5:
223
        case 0x3d5:
224
            val = s->cr[s->cr_index];
225
#ifdef DEBUG_VGA_REG
226
            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
227
#endif
228
#ifdef DEBUG_S3
229
            if (s->cr_index >= 0x20)
230
                printf("S3: CR read index=0x%x val=0x%x\n",
231
                       s->cr_index, val);
232
#endif
233
            break;
234
        case 0x3ba:
235
        case 0x3da:
236
            /* just toggle to fool polling */
237
            s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
238
            val = s->st01;
239
            s->ar_flip_flop = 0;
240
            break;
241
        default:
242
            val = 0x00;
243
            break;
244
        }
245
    }
246
#if defined(DEBUG_VGA)
247
    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
248
#endif
249
    return val;
250
}
251

    
252
static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
253
{
254
    VGAState *s = opaque;
255
    int index;
256

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

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

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

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

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

    
416
static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
417
{
418
    VGAState *s = opaque;
419
    uint32_t val;
420

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

    
431
static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
432
{
433
    VGAState *s = opaque;
434
    s->vbe_index = val;
435
}
436

    
437
static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
438
{
439
    VGAState *s = opaque;
440

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

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

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

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

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

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

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

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

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

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

    
745
            bit_mask = s->gr[8] & val;
746
            val = mask16[s->gr[0]];
747
            break;
748
        }
749

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

    
771
        /* apply bit mask */
772
        bit_mask |= bit_mask << 8;
773
        bit_mask |= bit_mask << 16;
774
        val = (val & bit_mask) | (s->latch & ~bit_mask);
775

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

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

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

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

    
825
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
826
{
827
    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
828
}
829

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

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

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

    
845
#define DEPTH 8
846
#include "vga_template.h"
847

    
848
#define DEPTH 15
849
#include "vga_template.h"
850

    
851
#define DEPTH 16
852
#include "vga_template.h"
853

    
854
#define DEPTH 32
855
#include "vga_template.h"
856

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1026
static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1027
    vga_draw_glyph9_8,
1028
    vga_draw_glyph9_16,
1029
    vga_draw_glyph9_16,
1030
    vga_draw_glyph9_32,
1031
};
1032
    
1033
static const uint8_t cursor_glyph[32 * 4] = {
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
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1049
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1050
};    
1051

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

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

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

    
1092
    full_update |= update_basic_params(s);
1093

    
1094
    line_offset = s->line_offset;
1095
    s1 = s->vram_ptr + (s->start_addr * 4);
1096

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

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

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

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

    
1246
    vga_draw_line2d2_8,
1247
    vga_draw_line2d2_16,
1248
    vga_draw_line2d2_16,
1249
    vga_draw_line2d2_32,
1250

    
1251
    vga_draw_line4_8,
1252
    vga_draw_line4_16,
1253
    vga_draw_line4_16,
1254
    vga_draw_line4_32,
1255

    
1256
    vga_draw_line4d2_8,
1257
    vga_draw_line4d2_16,
1258
    vga_draw_line4d2_16,
1259
    vga_draw_line4d2_32,
1260

    
1261
    vga_draw_line8d2_8,
1262
    vga_draw_line8d2_16,
1263
    vga_draw_line8d2_16,
1264
    vga_draw_line8d2_32,
1265

    
1266
    vga_draw_line8_8,
1267
    vga_draw_line8_16,
1268
    vga_draw_line8_16,
1269
    vga_draw_line8_32,
1270

    
1271
    vga_draw_line15_8,
1272
    vga_draw_line15_15,
1273
    vga_draw_line15_16,
1274
    vga_draw_line15_32,
1275

    
1276
    vga_draw_line16_8,
1277
    vga_draw_line16_15,
1278
    vga_draw_line16_16,
1279
    vga_draw_line16_32,
1280

    
1281
    vga_draw_line24_8,
1282
    vga_draw_line24_15,
1283
    vga_draw_line24_16,
1284
    vga_draw_line24_32,
1285

    
1286
    vga_draw_line32_8,
1287
    vga_draw_line32_15,
1288
    vga_draw_line32_16,
1289
    vga_draw_line32_32,
1290
};
1291

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

    
1306
static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1307
{
1308
    int width, height;
1309
    
1310
    width = (s->cr[0x01] + 1) * 8;
1311
    height = s->cr[0x12] | 
1312
        ((s->cr[0x07] & 0x02) << 7) | 
1313
        ((s->cr[0x07] & 0x40) << 3);
1314
    height = (height + 1);
1315
    *pwidth = width;
1316
    *pheight = height;
1317
}
1318

    
1319
void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1320
{
1321
    int y;
1322
    if (y1 >= VGA_MAX_HEIGHT)
1323
        return;
1324
    if (y2 >= VGA_MAX_HEIGHT)
1325
        y2 = VGA_MAX_HEIGHT;
1326
    for(y = y1; y < y2; y++) {
1327
        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1328
    }
1329
}
1330

    
1331
/* 
1332
 * graphic modes
1333
 */
1334
static void vga_draw_graphic(VGAState *s, int full_update)
1335
{
1336
    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1337
    int width, height, shift_control, line_offset, page0, page1, bwidth;
1338
    int disp_width, multi_scan, multi_run;
1339
    uint8_t *d;
1340
    uint32_t v, addr1, addr;
1341
    vga_draw_line_func *vga_draw_line;
1342
    
1343
    full_update |= update_basic_params(s);
1344

    
1345
    s->get_resolution(s, &width, &height);
1346
    disp_width = width;
1347

    
1348
    shift_control = (s->gr[0x05] >> 5) & 3;
1349
    double_scan = (s->cr[0x09] >> 7);
1350
    if (shift_control != 1) {
1351
        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1352
    } else {
1353
        /* in CGA modes, multi_scan is ignored */
1354
        /* XXX: is it correct ? */
1355
        multi_scan = double_scan;
1356
    }
1357
    multi_run = multi_scan;
1358
    if (shift_control != s->shift_control ||
1359
        double_scan != s->double_scan) {
1360
        full_update = 1;
1361
        s->shift_control = shift_control;
1362
        s->double_scan = double_scan;
1363
    }
1364
    
1365
    if (shift_control == 0) {
1366
        full_update |= update_palette16(s);
1367
        if (s->sr[0x01] & 8) {
1368
            v = VGA_DRAW_LINE4D2;
1369
            disp_width <<= 1;
1370
        } else {
1371
            v = VGA_DRAW_LINE4;
1372
        }
1373
    } else if (shift_control == 1) {
1374
        full_update |= update_palette16(s);
1375
        if (s->sr[0x01] & 8) {
1376
            v = VGA_DRAW_LINE2D2;
1377
            disp_width <<= 1;
1378
        } else {
1379
            v = VGA_DRAW_LINE2;
1380
        }
1381
    } else {
1382
        switch(s->get_bpp(s)) {
1383
        default:
1384
        case 0:
1385
            full_update |= update_palette256(s);
1386
            v = VGA_DRAW_LINE8D2;
1387
            break;
1388
        case 8:
1389
            full_update |= update_palette256(s);
1390
            v = VGA_DRAW_LINE8;
1391
            break;
1392
        case 15:
1393
            v = VGA_DRAW_LINE15;
1394
            break;
1395
        case 16:
1396
            v = VGA_DRAW_LINE16;
1397
            break;
1398
        case 24:
1399
            v = VGA_DRAW_LINE24;
1400
            break;
1401
        case 32:
1402
            v = VGA_DRAW_LINE32;
1403
            break;
1404
        }
1405
    }
1406
    vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1407

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

    
1498
static void vga_draw_blank(VGAState *s, int full_update)
1499
{
1500
    int i, w, val;
1501
    uint8_t *d;
1502

    
1503
    if (!full_update)
1504
        return;
1505
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1506
        return;
1507
    if (s->ds->depth == 8) 
1508
        val = s->rgb_to_pixel(0, 0, 0);
1509
    else
1510
        val = 0;
1511
    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1512
    d = s->ds->data;
1513
    for(i = 0; i < s->last_scr_height; i++) {
1514
        memset(d, val, w);
1515
        d += s->ds->linesize;
1516
    }
1517
    dpy_update(s->ds, 0, 0, 
1518
               s->last_scr_width, s->last_scr_height);
1519
}
1520

    
1521
#define GMODE_TEXT     0
1522
#define GMODE_GRAPH    1
1523
#define GMODE_BLANK 2 
1524

    
1525
void vga_update_display(void)
1526
{
1527
    VGAState *s = vga_state;
1528
    int full_update, graphic_mode;
1529

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

    
1574
/* force a full display refresh */
1575
void vga_invalidate_display(void)
1576
{
1577
    VGAState *s = vga_state;
1578
    
1579
    s->last_width = -1;
1580
    s->last_height = -1;
1581
}
1582

    
1583
static void vga_reset(VGAState *s)
1584
{
1585
    memset(s, 0, sizeof(VGAState));
1586
#ifdef CONFIG_S3VGA
1587
    /* chip ID for 8c968 */
1588
    s->cr[0x2d] = 0x88;
1589
    s->cr[0x2e] = 0xb0;
1590
    s->cr[0x2f] = 0x01; /* XXX: check revision code */
1591
    s->cr[0x30] = 0xe1;
1592
#endif
1593
    s->graphic_mode = -1; /* force full update */
1594
}
1595

    
1596
static CPUReadMemoryFunc *vga_mem_read[3] = {
1597
    vga_mem_readb,
1598
    vga_mem_readw,
1599
    vga_mem_readl,
1600
};
1601

    
1602
static CPUWriteMemoryFunc *vga_mem_write[3] = {
1603
    vga_mem_writeb,
1604
    vga_mem_writew,
1605
    vga_mem_writel,
1606
};
1607

    
1608
static void vga_save(QEMUFile *f, void *opaque)
1609
{
1610
    VGAState *s = opaque;
1611
    int i;
1612

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

    
1628
    qemu_put_8s(f, &s->dac_state);
1629
    qemu_put_8s(f, &s->dac_sub_index);
1630
    qemu_put_8s(f, &s->dac_read_index);
1631
    qemu_put_8s(f, &s->dac_write_index);
1632
    qemu_put_buffer(f, s->dac_cache, 3);
1633
    qemu_put_buffer(f, s->palette, 768);
1634

    
1635
    qemu_put_be32s(f, &s->bank_offset);
1636
#ifdef CONFIG_BOCHS_VBE
1637
    qemu_put_byte(f, 1);
1638
    qemu_put_be16s(f, &s->vbe_index);
1639
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1640
        qemu_put_be16s(f, &s->vbe_regs[i]);
1641
    qemu_put_be32s(f, &s->vbe_start_addr);
1642
    qemu_put_be32s(f, &s->vbe_line_offset);
1643
    qemu_put_be32s(f, &s->vbe_bank_mask);
1644
#else
1645
    qemu_put_byte(f, 0);
1646
#endif
1647
}
1648

    
1649
static int vga_load(QEMUFile *f, void *opaque, int version_id)
1650
{
1651
    VGAState *s = opaque;
1652
    int is_vbe, i;
1653

    
1654
    if (version_id != 1)
1655
        return -EINVAL;
1656

    
1657
    qemu_get_be32s(f, &s->latch);
1658
    qemu_get_8s(f, &s->sr_index);
1659
    qemu_get_buffer(f, s->sr, 8);
1660
    qemu_get_8s(f, &s->gr_index);
1661
    qemu_get_buffer(f, s->gr, 16);
1662
    qemu_get_8s(f, &s->ar_index);
1663
    qemu_get_buffer(f, s->ar, 21);
1664
    qemu_get_be32s(f, &s->ar_flip_flop);
1665
    qemu_get_8s(f, &s->cr_index);
1666
    qemu_get_buffer(f, s->cr, 256);
1667
    qemu_get_8s(f, &s->msr);
1668
    qemu_get_8s(f, &s->fcr);
1669
    qemu_get_8s(f, &s->st00);
1670
    qemu_get_8s(f, &s->st01);
1671

    
1672
    qemu_get_8s(f, &s->dac_state);
1673
    qemu_get_8s(f, &s->dac_sub_index);
1674
    qemu_get_8s(f, &s->dac_read_index);
1675
    qemu_get_8s(f, &s->dac_write_index);
1676
    qemu_get_buffer(f, s->dac_cache, 3);
1677
    qemu_get_buffer(f, s->palette, 768);
1678

    
1679
    qemu_get_be32s(f, &s->bank_offset);
1680
    is_vbe = qemu_get_byte(f);
1681
#ifdef CONFIG_BOCHS_VBE
1682
    if (!is_vbe)
1683
        return -EINVAL;
1684
    qemu_get_be16s(f, &s->vbe_index);
1685
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1686
        qemu_get_be16s(f, &s->vbe_regs[i]);
1687
    qemu_get_be32s(f, &s->vbe_start_addr);
1688
    qemu_get_be32s(f, &s->vbe_line_offset);
1689
    qemu_get_be32s(f, &s->vbe_bank_mask);
1690
#else
1691
    if (is_vbe)
1692
        return -EINVAL;
1693
#endif
1694

    
1695
    /* force refresh */
1696
    s->graphic_mode = -1;
1697
    return 0;
1698
}
1699

    
1700
static void vga_map(PCIDevice *pci_dev, int region_num, 
1701
                    uint32_t addr, uint32_t size, int type)
1702
{
1703
    VGAState *s = vga_state;
1704

    
1705
    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1706
}
1707

    
1708
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
1709
                     unsigned long vga_ram_offset, int vga_ram_size)
1710
{
1711
    int i, j, v, b;
1712

    
1713
    for(i = 0;i < 256; i++) {
1714
        v = 0;
1715
        for(j = 0; j < 8; j++) {
1716
            v |= ((i >> j) & 1) << (j * 4);
1717
        }
1718
        expand4[i] = v;
1719

    
1720
        v = 0;
1721
        for(j = 0; j < 4; j++) {
1722
            v |= ((i >> (2 * j)) & 3) << (j * 4);
1723
        }
1724
        expand2[i] = v;
1725
    }
1726
    for(i = 0; i < 16; i++) {
1727
        v = 0;
1728
        for(j = 0; j < 4; j++) {
1729
            b = ((i >> j) & 1);
1730
            v |= b << (2 * j);
1731
            v |= b << (2 * j + 1);
1732
        }
1733
        expand4to8[i] = v;
1734
    }
1735

    
1736
    vga_reset(s);
1737

    
1738
    s->vram_ptr = vga_ram_base;
1739
    s->vram_offset = vga_ram_offset;
1740
    s->vram_size = vga_ram_size;
1741
    s->ds = ds;
1742
    s->get_bpp = vga_get_bpp;
1743
    s->get_offsets = vga_get_offsets;
1744
    s->get_resolution = vga_get_resolution;
1745
    /* XXX: currently needed for display */
1746
    vga_state = s;
1747
}
1748

    
1749

    
1750
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
1751
                   unsigned long vga_ram_offset, int vga_ram_size)
1752
{
1753
    VGAState *s;
1754

    
1755
    s = qemu_mallocz(sizeof(VGAState));
1756
    if (!s)
1757
        return -1;
1758

    
1759
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1760

    
1761
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1762

    
1763
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1764

    
1765
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1766
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1767
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1768
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1769

    
1770
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1771

    
1772
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1773
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1774
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1775
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1776
    s->bank_offset = 0;
1777

    
1778
#ifdef CONFIG_BOCHS_VBE
1779
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1780
    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1781
#if defined (TARGET_I386)
1782
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1783
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1784

    
1785
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1786
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1787

    
1788
    /* old Bochs IO ports */
1789
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1790
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1791

    
1792
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1793
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
1794
#else
1795
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1796
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1797

    
1798
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1799
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1800
#endif
1801
#endif /* CONFIG_BOCHS_VBE */
1802

    
1803
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1804
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
1805
                                 vga_io_memory);
1806

    
1807
    if (bus) {
1808
        PCIDevice *d;
1809
        uint8_t *pci_conf;
1810

    
1811
        d = pci_register_device(bus, "VGA", 
1812
                                sizeof(PCIDevice),
1813
                                -1, NULL, NULL);
1814
        pci_conf = d->config;
1815
        pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1816
        pci_conf[0x01] = 0x12;
1817
        pci_conf[0x02] = 0x11;
1818
        pci_conf[0x03] = 0x11;
1819
        pci_conf[0x0a] = 0x00; // VGA controller 
1820
        pci_conf[0x0b] = 0x03;
1821
        pci_conf[0x0e] = 0x00; // header_type
1822

    
1823
        /* XXX: vga_ram_size must be a power of two */
1824
        pci_register_io_region(d, 0, vga_ram_size, 
1825
                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1826
    } else {
1827
#ifdef CONFIG_BOCHS_VBE
1828
        /* XXX: use optimized standard vga accesses */
1829
        cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
1830
                                     vga_ram_size, vga_ram_offset);
1831
#endif
1832
    }
1833
    return 0;
1834
}
1835

    
1836
/********************************************************/
1837
/* vga screen dump */
1838

    
1839
static int vga_save_w, vga_save_h;
1840

    
1841
static void vga_save_dpy_update(DisplayState *s, 
1842
                                int x, int y, int w, int h)
1843
{
1844
}
1845

    
1846
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1847
{
1848
    s->linesize = w * 4;
1849
    s->data = qemu_malloc(h * s->linesize);
1850
    vga_save_w = w;
1851
    vga_save_h = h;
1852
}
1853

    
1854
static void vga_save_dpy_refresh(DisplayState *s)
1855
{
1856
}
1857

    
1858
static int ppm_save(const char *filename, uint8_t *data, 
1859
                    int w, int h, int linesize)
1860
{
1861
    FILE *f;
1862
    uint8_t *d, *d1;
1863
    unsigned int v;
1864
    int y, x;
1865

    
1866
    f = fopen(filename, "wb");
1867
    if (!f)
1868
        return -1;
1869
    fprintf(f, "P6\n%d %d\n%d\n",
1870
            w, h, 255);
1871
    d1 = data;
1872
    for(y = 0; y < h; y++) {
1873
        d = d1;
1874
        for(x = 0; x < w; x++) {
1875
            v = *(uint32_t *)d;
1876
            fputc((v >> 16) & 0xff, f);
1877
            fputc((v >> 8) & 0xff, f);
1878
            fputc((v) & 0xff, f);
1879
            d += 4;
1880
        }
1881
        d1 += linesize;
1882
    }
1883
    fclose(f);
1884
    return 0;
1885
}
1886

    
1887
/* save the vga display in a PPM image even if no display is
1888
   available */
1889
void vga_screen_dump(const char *filename)
1890
{
1891
    VGAState *s = vga_state;
1892
    DisplayState *saved_ds, ds1, *ds = &ds1;
1893
    
1894
    /* XXX: this is a little hackish */
1895
    vga_invalidate_display();
1896
    saved_ds = s->ds;
1897

    
1898
    memset(ds, 0, sizeof(DisplayState));
1899
    ds->dpy_update = vga_save_dpy_update;
1900
    ds->dpy_resize = vga_save_dpy_resize;
1901
    ds->dpy_refresh = vga_save_dpy_refresh;
1902
    ds->depth = 32;
1903

    
1904
    s->ds = ds;
1905
    s->graphic_mode = -1;
1906
    vga_update_display();
1907
    
1908
    if (ds->data) {
1909
        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
1910
                 s->ds->linesize);
1911
        qemu_free(ds->data);
1912
    }
1913
    s->ds = saved_ds;
1914
}