Statistics
| Branch: | Revision:

root / hw / vga.c @ e6eccb38

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[11] & 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
    /* XXX: TODO */
828
    return 0;
829
}
830

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1093
    full_update |= update_basic_params(s);
1094

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1501
static void vga_draw_blank(VGAState *s, int full_update)
1502
{
1503
    int i, w, val;
1504
    uint8_t *d;
1505

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

    
1524
#define GMODE_TEXT     0
1525
#define GMODE_GRAPH    1
1526
#define GMODE_BLANK 2 
1527

    
1528
void vga_update_display(void)
1529
{
1530
    VGAState *s = vga_state;
1531
    int full_update, graphic_mode;
1532

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

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

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

    
1599
static CPUReadMemoryFunc *vga_mem_read[3] = {
1600
    vga_mem_readb,
1601
    vga_mem_readw,
1602
    vga_mem_readl,
1603
};
1604

    
1605
static CPUWriteMemoryFunc *vga_mem_write[3] = {
1606
    vga_mem_writeb,
1607
    vga_mem_writew,
1608
    vga_mem_writel,
1609
};
1610

    
1611
static void vga_save(QEMUFile *f, void *opaque)
1612
{
1613
    VGAState *s = opaque;
1614
    int i;
1615

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

    
1631
    qemu_put_8s(f, &s->dac_state);
1632
    qemu_put_8s(f, &s->dac_sub_index);
1633
    qemu_put_8s(f, &s->dac_read_index);
1634
    qemu_put_8s(f, &s->dac_write_index);
1635
    qemu_put_buffer(f, s->dac_cache, 3);
1636
    qemu_put_buffer(f, s->palette, 768);
1637

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

    
1652
static int vga_load(QEMUFile *f, void *opaque, int version_id)
1653
{
1654
    VGAState *s = opaque;
1655
    int is_vbe, i;
1656

    
1657
    if (version_id != 1)
1658
        return -EINVAL;
1659

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

    
1675
    qemu_get_8s(f, &s->dac_state);
1676
    qemu_get_8s(f, &s->dac_sub_index);
1677
    qemu_get_8s(f, &s->dac_read_index);
1678
    qemu_get_8s(f, &s->dac_write_index);
1679
    qemu_get_buffer(f, s->dac_cache, 3);
1680
    qemu_get_buffer(f, s->palette, 768);
1681

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

    
1698
    /* force refresh */
1699
    s->graphic_mode = -1;
1700
    return 0;
1701
}
1702

    
1703
static void vga_map(PCIDevice *pci_dev, int region_num, 
1704
                    uint32_t addr, uint32_t size, int type)
1705
{
1706
    VGAState *s = vga_state;
1707

    
1708
    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1709
}
1710

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

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

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

    
1739
    vga_reset(s);
1740

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

    
1752

    
1753
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
1754
                   unsigned long vga_ram_offset, int vga_ram_size)
1755
{
1756
    VGAState *s;
1757

    
1758
    s = qemu_mallocz(sizeof(VGAState));
1759
    if (!s)
1760
        return -1;
1761

    
1762
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1763

    
1764
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1765

    
1766
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1767

    
1768
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1769
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1770
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1771
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1772

    
1773
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1774

    
1775
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1776
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1777
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1778
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1779
    s->bank_offset = 0;
1780

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

    
1788
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1789
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1790

    
1791
    /* old Bochs IO ports */
1792
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1793
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1794

    
1795
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1796
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
1797
#else
1798
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1799
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1800

    
1801
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1802
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1803
#endif
1804
#endif /* CONFIG_BOCHS_VBE */
1805

    
1806
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1807
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
1808
                                 vga_io_memory);
1809

    
1810
    if (bus) {
1811
        PCIDevice *d;
1812
        uint8_t *pci_conf;
1813

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

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

    
1839
/********************************************************/
1840
/* vga screen dump */
1841

    
1842
static int vga_save_w, vga_save_h;
1843

    
1844
static void vga_save_dpy_update(DisplayState *s, 
1845
                                int x, int y, int w, int h)
1846
{
1847
}
1848

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

    
1857
static void vga_save_dpy_refresh(DisplayState *s)
1858
{
1859
}
1860

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

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

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

    
1901
    memset(ds, 0, sizeof(DisplayState));
1902
    ds->dpy_update = vga_save_dpy_update;
1903
    ds->dpy_resize = vga_save_dpy_resize;
1904
    ds->dpy_refresh = vga_save_dpy_refresh;
1905
    ds->depth = 32;
1906

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