Statistics
| Branch: | Revision:

root / hw / vga.c @ a130a41e

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1090
    full_update |= update_basic_params(s);
1091

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1343
    s->get_resolution(s, &width, &height);
1344
    disp_width = width;
1345

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1808
    if (is_pci) {
1809
        PCIDevice *d;
1810
        uint8_t *pci_conf;
1811

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

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

    
1838
/********************************************************/
1839
/* vga screen dump */
1840

    
1841
static int vga_save_w, vga_save_h;
1842

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

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

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

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

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

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

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

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