Statistics
| Branch: | Revision:

root / hw / vga.c @ 40545f84

History | View | Annotate | Download (54.2 kB)

1
/*
2
 * QEMU VGA Emulator.
3
 * 
4
 * Copyright (c) 2003 Fabrice Bellard
5
 * 
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "vl.h"
25
#include "vga_int.h"
26

    
27
//#define DEBUG_VGA
28
//#define DEBUG_VGA_MEM
29
//#define DEBUG_VGA_REG
30

    
31
//#define DEBUG_S3
32
//#define DEBUG_BOCHS_VBE
33

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

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

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

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

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

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

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

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

    
112
#undef PAT
113

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

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

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

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

    
150
VGAState *vga_state;
151
int vga_io_memory;
152

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
661
/* called for accesses between 0xa0000 and 0xc0000 */
662
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
663
{
664
    VGAState *s = opaque;
665
    int memory_map_mode, plane, write_mode, b, func_select, mask;
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
        mask = (1 << plane);
699
        if (s->sr[2] & mask) {
700
            s->vram_ptr[addr] = val;
701
#ifdef DEBUG_VGA_MEM
702
            printf("vga: chain4: [0x%x]\n", addr);
703
#endif
704
            s->plane_updated |= mask; /* only used to detect font change */
705
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
706
        }
707
    } else if (s->gr[5] & 0x10) {
708
        /* odd/even mode (aka text mode mapping) */
709
        plane = (s->gr[4] & 2) | (addr & 1);
710
        mask = (1 << plane);
711
        if (s->sr[2] & mask) {
712
            addr = ((addr & ~1) << 1) | plane;
713
            s->vram_ptr[addr] = val;
714
#ifdef DEBUG_VGA_MEM
715
            printf("vga: odd/even: [0x%x]\n", addr);
716
#endif
717
            s->plane_updated |= mask; /* only used to detect font change */
718
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
719
        }
720
    } else {
721
        /* standard VGA latched access */
722
        write_mode = s->gr[5] & 3;
723
        switch(write_mode) {
724
        default:
725
        case 0:
726
            /* rotate */
727
            b = s->gr[3] & 7;
728
            val = ((val >> b) | (val << (8 - b))) & 0xff;
729
            val |= val << 8;
730
            val |= val << 16;
731

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

    
749
            bit_mask = s->gr[8] & val;
750
            val = mask16[s->gr[0]];
751
            break;
752
        }
753

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

    
775
        /* apply bit mask */
776
        bit_mask |= bit_mask << 8;
777
        bit_mask |= bit_mask << 16;
778
        val = (val & bit_mask) | (s->latch & ~bit_mask);
779

    
780
    do_write:
781
        /* mask data according to sr[2] */
782
        mask = s->sr[2];
783
        s->plane_updated |= mask; /* only used to detect font change */
784
        write_mask = mask16[mask];
785
        ((uint32_t *)s->vram_ptr)[addr] = 
786
            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | 
787
            (val & write_mask);
788
#ifdef DEBUG_VGA_MEM
789
            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", 
790
                   addr * 4, write_mask, val);
791
#endif
792
            cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
793
    }
794
}
795

    
796
static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
797
{
798
#ifdef TARGET_WORDS_BIGENDIAN
799
    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
800
    vga_mem_writeb(opaque, addr + 1, val & 0xff);
801
#else
802
    vga_mem_writeb(opaque, addr, val & 0xff);
803
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
804
#endif
805
}
806

    
807
static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
808
{
809
#ifdef TARGET_WORDS_BIGENDIAN
810
    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
811
    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
812
    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
813
    vga_mem_writeb(opaque, addr + 3, val & 0xff);
814
#else
815
    vga_mem_writeb(opaque, addr, val & 0xff);
816
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
817
    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
818
    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
819
#endif
820
}
821

    
822
typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
823
                             const uint8_t *font_ptr, int h,
824
                             uint32_t fgcol, uint32_t bgcol);
825
typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
826
                                  const uint8_t *font_ptr, int h, 
827
                                  uint32_t fgcol, uint32_t bgcol, int dup9);
828
typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, 
829
                                const uint8_t *s, int width);
830

    
831
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
832
{
833
    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
834
}
835

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

    
841
static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
842
{
843
    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
844
}
845

    
846
static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
847
{
848
    return (r << 16) | (g << 8) | b;
849
}
850

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

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

    
857
#define DEPTH 16
858
#include "vga_template.h"
859

    
860
#define DEPTH 32
861
#include "vga_template.h"
862

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

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

    
880
static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
881
{
882
    unsigned int col;
883
    col = rgb_to_pixel16(r, g, b);
884
    col |= col << 16;
885
    return col;
886
}
887

    
888
static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
889
{
890
    unsigned int col;
891
    col = rgb_to_pixel32(r, g, b);
892
    return col;
893
}
894

    
895
/* return true if the palette was modified */
896
static int update_palette16(VGAState *s)
897
{
898
    int full_update, i;
899
    uint32_t v, col, *palette;
900

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

    
921
/* return true if the palette was modified */
922
static int update_palette256(VGAState *s)
923
{
924
    int full_update, i;
925
    uint32_t v, col, *palette;
926

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

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

    
978
/* update start_addr and line_offset. Return TRUE if modified */
979
static int update_basic_params(VGAState *s)
980
{
981
    int full_update;
982
    uint32_t start_addr, line_offset, line_compare;
983
    
984
    full_update = 0;
985

    
986
    s->get_offsets(s, &line_offset, &start_addr);
987
    /* line compare */
988
    line_compare = s->cr[0x18] | 
989
        ((s->cr[0x07] & 0x10) << 4) |
990
        ((s->cr[0x09] & 0x40) << 3);
991

    
992
    if (line_offset != s->line_offset ||
993
        start_addr != s->start_addr ||
994
        line_compare != s->line_compare) {
995
        s->line_offset = line_offset;
996
        s->start_addr = start_addr;
997
        s->line_compare = line_compare;
998
        full_update = 1;
999
    }
1000
    return full_update;
1001
}
1002

    
1003
static inline int get_depth_index(int depth)
1004
{
1005
    switch(depth) {
1006
    default:
1007
    case 8:
1008
        return 0;
1009
    case 15:
1010
        return 1;
1011
    case 16:
1012
        return 2;
1013
    case 32:
1014
        return 3;
1015
    }
1016
}
1017

    
1018
static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1019
    vga_draw_glyph8_8,
1020
    vga_draw_glyph8_16,
1021
    vga_draw_glyph8_16,
1022
    vga_draw_glyph8_32,
1023
};
1024

    
1025
static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1026
    vga_draw_glyph16_8,
1027
    vga_draw_glyph16_16,
1028
    vga_draw_glyph16_16,
1029
    vga_draw_glyph16_32,
1030
};
1031

    
1032
static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1033
    vga_draw_glyph9_8,
1034
    vga_draw_glyph9_16,
1035
    vga_draw_glyph9_16,
1036
    vga_draw_glyph9_32,
1037
};
1038
    
1039
static const uint8_t cursor_glyph[32 * 4] = {
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
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1052
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1053
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1054
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1055
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1056
};    
1057

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

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

    
1091
    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1092
    font_base[1] = s->vram_ptr + offset;
1093
    if (offset != s->font_offsets[1]) {
1094
        s->font_offsets[1] = offset;
1095
        full_update = 1;
1096
    }
1097
    if (s->plane_updated & (1 << 2)) {
1098
        /* if the plane 2 was modified since the last display, it
1099
           indicates the font may have been modified */
1100
        s->plane_updated = 0;
1101
        full_update = 1;
1102
    }
1103
    full_update |= update_basic_params(s);
1104

    
1105
    line_offset = s->line_offset;
1106
    s1 = s->vram_ptr + (s->start_addr * 4);
1107

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

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

    
1237
enum {
1238
    VGA_DRAW_LINE2,
1239
    VGA_DRAW_LINE2D2,
1240
    VGA_DRAW_LINE4,
1241
    VGA_DRAW_LINE4D2,
1242
    VGA_DRAW_LINE8D2,
1243
    VGA_DRAW_LINE8,
1244
    VGA_DRAW_LINE15,
1245
    VGA_DRAW_LINE16,
1246
    VGA_DRAW_LINE24,
1247
    VGA_DRAW_LINE32,
1248
    VGA_DRAW_LINE_NB,
1249
};
1250

    
1251
static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1252
    vga_draw_line2_8,
1253
    vga_draw_line2_16,
1254
    vga_draw_line2_16,
1255
    vga_draw_line2_32,
1256

    
1257
    vga_draw_line2d2_8,
1258
    vga_draw_line2d2_16,
1259
    vga_draw_line2d2_16,
1260
    vga_draw_line2d2_32,
1261

    
1262
    vga_draw_line4_8,
1263
    vga_draw_line4_16,
1264
    vga_draw_line4_16,
1265
    vga_draw_line4_32,
1266

    
1267
    vga_draw_line4d2_8,
1268
    vga_draw_line4d2_16,
1269
    vga_draw_line4d2_16,
1270
    vga_draw_line4d2_32,
1271

    
1272
    vga_draw_line8d2_8,
1273
    vga_draw_line8d2_16,
1274
    vga_draw_line8d2_16,
1275
    vga_draw_line8d2_32,
1276

    
1277
    vga_draw_line8_8,
1278
    vga_draw_line8_16,
1279
    vga_draw_line8_16,
1280
    vga_draw_line8_32,
1281

    
1282
    vga_draw_line15_8,
1283
    vga_draw_line15_15,
1284
    vga_draw_line15_16,
1285
    vga_draw_line15_32,
1286

    
1287
    vga_draw_line16_8,
1288
    vga_draw_line16_15,
1289
    vga_draw_line16_16,
1290
    vga_draw_line16_32,
1291

    
1292
    vga_draw_line24_8,
1293
    vga_draw_line24_15,
1294
    vga_draw_line24_16,
1295
    vga_draw_line24_32,
1296

    
1297
    vga_draw_line32_8,
1298
    vga_draw_line32_15,
1299
    vga_draw_line32_16,
1300
    vga_draw_line32_32,
1301
};
1302

    
1303
static int vga_get_bpp(VGAState *s)
1304
{
1305
    int ret;
1306
#ifdef CONFIG_BOCHS_VBE
1307
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1308
        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1309
    } else 
1310
#endif
1311
    {
1312
        ret = 0;
1313
    }
1314
    return ret;
1315
}
1316

    
1317
static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1318
{
1319
    int width, height;
1320
    
1321
    width = (s->cr[0x01] + 1) * 8;
1322
    height = s->cr[0x12] | 
1323
        ((s->cr[0x07] & 0x02) << 7) | 
1324
        ((s->cr[0x07] & 0x40) << 3);
1325
    height = (height + 1);
1326
    *pwidth = width;
1327
    *pheight = height;
1328
}
1329

    
1330
void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1331
{
1332
    int y;
1333
    if (y1 >= VGA_MAX_HEIGHT)
1334
        return;
1335
    if (y2 >= VGA_MAX_HEIGHT)
1336
        y2 = VGA_MAX_HEIGHT;
1337
    for(y = y1; y < y2; y++) {
1338
        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1339
    }
1340
}
1341

    
1342
/* 
1343
 * graphic modes
1344
 */
1345
static void vga_draw_graphic(VGAState *s, int full_update)
1346
{
1347
    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1348
    int width, height, shift_control, line_offset, page0, page1, bwidth;
1349
    int disp_width, multi_scan, multi_run;
1350
    uint8_t *d;
1351
    uint32_t v, addr1, addr;
1352
    vga_draw_line_func *vga_draw_line;
1353
    
1354
    full_update |= update_basic_params(s);
1355

    
1356
    s->get_resolution(s, &width, &height);
1357
    disp_width = width;
1358

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

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

    
1512
static void vga_draw_blank(VGAState *s, int full_update)
1513
{
1514
    int i, w, val;
1515
    uint8_t *d;
1516

    
1517
    if (!full_update)
1518
        return;
1519
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1520
        return;
1521
    if (s->ds->depth == 8) 
1522
        val = s->rgb_to_pixel(0, 0, 0);
1523
    else
1524
        val = 0;
1525
    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1526
    d = s->ds->data;
1527
    for(i = 0; i < s->last_scr_height; i++) {
1528
        memset(d, val, w);
1529
        d += s->ds->linesize;
1530
    }
1531
    dpy_update(s->ds, 0, 0, 
1532
               s->last_scr_width, s->last_scr_height);
1533
}
1534

    
1535
#define GMODE_TEXT     0
1536
#define GMODE_GRAPH    1
1537
#define GMODE_BLANK 2 
1538

    
1539
void vga_update_display(void)
1540
{
1541
    VGAState *s = vga_state;
1542
    int full_update, graphic_mode;
1543

    
1544
    if (s->ds->depth == 0) {
1545
        /* nothing to do */
1546
    } else {
1547
        switch(s->ds->depth) {
1548
        case 8:
1549
            s->rgb_to_pixel = rgb_to_pixel8_dup;
1550
            break;
1551
        case 15:
1552
            s->rgb_to_pixel = rgb_to_pixel15_dup;
1553
            break;
1554
        default:
1555
        case 16:
1556
            s->rgb_to_pixel = rgb_to_pixel16_dup;
1557
            break;
1558
        case 32:
1559
            s->rgb_to_pixel = rgb_to_pixel32_dup;
1560
            break;
1561
        }
1562
        
1563
        full_update = 0;
1564
        if (!(s->ar_index & 0x20)) {
1565
            graphic_mode = GMODE_BLANK;
1566
        } else {
1567
            graphic_mode = s->gr[6] & 1;
1568
        }
1569
        if (graphic_mode != s->graphic_mode) {
1570
            s->graphic_mode = graphic_mode;
1571
            full_update = 1;
1572
        }
1573
        switch(graphic_mode) {
1574
        case GMODE_TEXT:
1575
            vga_draw_text(s, full_update);
1576
            break;
1577
        case GMODE_GRAPH:
1578
            vga_draw_graphic(s, full_update);
1579
            break;
1580
        case GMODE_BLANK:
1581
        default:
1582
            vga_draw_blank(s, full_update);
1583
            break;
1584
        }
1585
    }
1586
}
1587

    
1588
/* force a full display refresh */
1589
void vga_invalidate_display(void)
1590
{
1591
    VGAState *s = vga_state;
1592
    
1593
    s->last_width = -1;
1594
    s->last_height = -1;
1595
}
1596

    
1597
static void vga_reset(VGAState *s)
1598
{
1599
    memset(s, 0, sizeof(VGAState));
1600
#ifdef CONFIG_S3VGA
1601
    /* chip ID for 8c968 */
1602
    s->cr[0x2d] = 0x88;
1603
    s->cr[0x2e] = 0xb0;
1604
    s->cr[0x2f] = 0x01; /* XXX: check revision code */
1605
    s->cr[0x30] = 0xe1;
1606
#endif
1607
    s->graphic_mode = -1; /* force full update */
1608
}
1609

    
1610
static CPUReadMemoryFunc *vga_mem_read[3] = {
1611
    vga_mem_readb,
1612
    vga_mem_readw,
1613
    vga_mem_readl,
1614
};
1615

    
1616
static CPUWriteMemoryFunc *vga_mem_write[3] = {
1617
    vga_mem_writeb,
1618
    vga_mem_writew,
1619
    vga_mem_writel,
1620
};
1621

    
1622
static void vga_save(QEMUFile *f, void *opaque)
1623
{
1624
    VGAState *s = opaque;
1625
    int i;
1626

    
1627
    qemu_put_be32s(f, &s->latch);
1628
    qemu_put_8s(f, &s->sr_index);
1629
    qemu_put_buffer(f, s->sr, 8);
1630
    qemu_put_8s(f, &s->gr_index);
1631
    qemu_put_buffer(f, s->gr, 16);
1632
    qemu_put_8s(f, &s->ar_index);
1633
    qemu_put_buffer(f, s->ar, 21);
1634
    qemu_put_be32s(f, &s->ar_flip_flop);
1635
    qemu_put_8s(f, &s->cr_index);
1636
    qemu_put_buffer(f, s->cr, 256);
1637
    qemu_put_8s(f, &s->msr);
1638
    qemu_put_8s(f, &s->fcr);
1639
    qemu_put_8s(f, &s->st00);
1640
    qemu_put_8s(f, &s->st01);
1641

    
1642
    qemu_put_8s(f, &s->dac_state);
1643
    qemu_put_8s(f, &s->dac_sub_index);
1644
    qemu_put_8s(f, &s->dac_read_index);
1645
    qemu_put_8s(f, &s->dac_write_index);
1646
    qemu_put_buffer(f, s->dac_cache, 3);
1647
    qemu_put_buffer(f, s->palette, 768);
1648

    
1649
    qemu_put_be32s(f, &s->bank_offset);
1650
#ifdef CONFIG_BOCHS_VBE
1651
    qemu_put_byte(f, 1);
1652
    qemu_put_be16s(f, &s->vbe_index);
1653
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1654
        qemu_put_be16s(f, &s->vbe_regs[i]);
1655
    qemu_put_be32s(f, &s->vbe_start_addr);
1656
    qemu_put_be32s(f, &s->vbe_line_offset);
1657
    qemu_put_be32s(f, &s->vbe_bank_mask);
1658
#else
1659
    qemu_put_byte(f, 0);
1660
#endif
1661
}
1662

    
1663
static int vga_load(QEMUFile *f, void *opaque, int version_id)
1664
{
1665
    VGAState *s = opaque;
1666
    int is_vbe, i;
1667

    
1668
    if (version_id != 1)
1669
        return -EINVAL;
1670

    
1671
    qemu_get_be32s(f, &s->latch);
1672
    qemu_get_8s(f, &s->sr_index);
1673
    qemu_get_buffer(f, s->sr, 8);
1674
    qemu_get_8s(f, &s->gr_index);
1675
    qemu_get_buffer(f, s->gr, 16);
1676
    qemu_get_8s(f, &s->ar_index);
1677
    qemu_get_buffer(f, s->ar, 21);
1678
    qemu_get_be32s(f, &s->ar_flip_flop);
1679
    qemu_get_8s(f, &s->cr_index);
1680
    qemu_get_buffer(f, s->cr, 256);
1681
    qemu_get_8s(f, &s->msr);
1682
    qemu_get_8s(f, &s->fcr);
1683
    qemu_get_8s(f, &s->st00);
1684
    qemu_get_8s(f, &s->st01);
1685

    
1686
    qemu_get_8s(f, &s->dac_state);
1687
    qemu_get_8s(f, &s->dac_sub_index);
1688
    qemu_get_8s(f, &s->dac_read_index);
1689
    qemu_get_8s(f, &s->dac_write_index);
1690
    qemu_get_buffer(f, s->dac_cache, 3);
1691
    qemu_get_buffer(f, s->palette, 768);
1692

    
1693
    qemu_get_be32s(f, &s->bank_offset);
1694
    is_vbe = qemu_get_byte(f);
1695
#ifdef CONFIG_BOCHS_VBE
1696
    if (!is_vbe)
1697
        return -EINVAL;
1698
    qemu_get_be16s(f, &s->vbe_index);
1699
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1700
        qemu_get_be16s(f, &s->vbe_regs[i]);
1701
    qemu_get_be32s(f, &s->vbe_start_addr);
1702
    qemu_get_be32s(f, &s->vbe_line_offset);
1703
    qemu_get_be32s(f, &s->vbe_bank_mask);
1704
#else
1705
    if (is_vbe)
1706
        return -EINVAL;
1707
#endif
1708

    
1709
    /* force refresh */
1710
    s->graphic_mode = -1;
1711
    return 0;
1712
}
1713

    
1714
static void vga_map(PCIDevice *pci_dev, int region_num, 
1715
                    uint32_t addr, uint32_t size, int type)
1716
{
1717
    VGAState *s = vga_state;
1718

    
1719
    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1720
}
1721

    
1722
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
1723
                     unsigned long vga_ram_offset, int vga_ram_size)
1724
{
1725
    int i, j, v, b;
1726

    
1727
    for(i = 0;i < 256; i++) {
1728
        v = 0;
1729
        for(j = 0; j < 8; j++) {
1730
            v |= ((i >> j) & 1) << (j * 4);
1731
        }
1732
        expand4[i] = v;
1733

    
1734
        v = 0;
1735
        for(j = 0; j < 4; j++) {
1736
            v |= ((i >> (2 * j)) & 3) << (j * 4);
1737
        }
1738
        expand2[i] = v;
1739
    }
1740
    for(i = 0; i < 16; i++) {
1741
        v = 0;
1742
        for(j = 0; j < 4; j++) {
1743
            b = ((i >> j) & 1);
1744
            v |= b << (2 * j);
1745
            v |= b << (2 * j + 1);
1746
        }
1747
        expand4to8[i] = v;
1748
    }
1749

    
1750
    vga_reset(s);
1751

    
1752
    s->vram_ptr = vga_ram_base;
1753
    s->vram_offset = vga_ram_offset;
1754
    s->vram_size = vga_ram_size;
1755
    s->ds = ds;
1756
    s->get_bpp = vga_get_bpp;
1757
    s->get_offsets = vga_get_offsets;
1758
    s->get_resolution = vga_get_resolution;
1759
    /* XXX: currently needed for display */
1760
    vga_state = s;
1761
}
1762

    
1763

    
1764
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
1765
                   unsigned long vga_ram_offset, int vga_ram_size)
1766
{
1767
    VGAState *s;
1768

    
1769
    s = qemu_mallocz(sizeof(VGAState));
1770
    if (!s)
1771
        return -1;
1772

    
1773
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1774

    
1775
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1776

    
1777
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1778

    
1779
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1780
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1781
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1782
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1783

    
1784
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1785

    
1786
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1787
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1788
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1789
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1790
    s->bank_offset = 0;
1791

    
1792
#ifdef CONFIG_BOCHS_VBE
1793
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1794
    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1795
#if defined (TARGET_I386)
1796
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1797
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1798

    
1799
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1800
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1801

    
1802
    /* old Bochs IO ports */
1803
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1804
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1805

    
1806
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1807
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
1808
#else
1809
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1810
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1811

    
1812
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1813
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1814
#endif
1815
#endif /* CONFIG_BOCHS_VBE */
1816

    
1817
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1818
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
1819
                                 vga_io_memory);
1820

    
1821
    if (bus) {
1822
        PCIDevice *d;
1823
        uint8_t *pci_conf;
1824

    
1825
        d = pci_register_device(bus, "VGA", 
1826
                                sizeof(PCIDevice),
1827
                                -1, NULL, NULL);
1828
        pci_conf = d->config;
1829
        pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1830
        pci_conf[0x01] = 0x12;
1831
        pci_conf[0x02] = 0x11;
1832
        pci_conf[0x03] = 0x11;
1833
        pci_conf[0x0a] = 0x00; // VGA controller 
1834
        pci_conf[0x0b] = 0x03;
1835
        pci_conf[0x0e] = 0x00; // header_type
1836

    
1837
        /* XXX: vga_ram_size must be a power of two */
1838
        pci_register_io_region(d, 0, vga_ram_size, 
1839
                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1840
    } else {
1841
#ifdef CONFIG_BOCHS_VBE
1842
        /* XXX: use optimized standard vga accesses */
1843
        cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
1844
                                     vga_ram_size, vga_ram_offset);
1845
#endif
1846
    }
1847
    return 0;
1848
}
1849

    
1850
/********************************************************/
1851
/* vga screen dump */
1852

    
1853
static int vga_save_w, vga_save_h;
1854

    
1855
static void vga_save_dpy_update(DisplayState *s, 
1856
                                int x, int y, int w, int h)
1857
{
1858
}
1859

    
1860
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1861
{
1862
    s->linesize = w * 4;
1863
    s->data = qemu_malloc(h * s->linesize);
1864
    vga_save_w = w;
1865
    vga_save_h = h;
1866
}
1867

    
1868
static void vga_save_dpy_refresh(DisplayState *s)
1869
{
1870
}
1871

    
1872
static int ppm_save(const char *filename, uint8_t *data, 
1873
                    int w, int h, int linesize)
1874
{
1875
    FILE *f;
1876
    uint8_t *d, *d1;
1877
    unsigned int v;
1878
    int y, x;
1879

    
1880
    f = fopen(filename, "wb");
1881
    if (!f)
1882
        return -1;
1883
    fprintf(f, "P6\n%d %d\n%d\n",
1884
            w, h, 255);
1885
    d1 = data;
1886
    for(y = 0; y < h; y++) {
1887
        d = d1;
1888
        for(x = 0; x < w; x++) {
1889
            v = *(uint32_t *)d;
1890
            fputc((v >> 16) & 0xff, f);
1891
            fputc((v >> 8) & 0xff, f);
1892
            fputc((v) & 0xff, f);
1893
            d += 4;
1894
        }
1895
        d1 += linesize;
1896
    }
1897
    fclose(f);
1898
    return 0;
1899
}
1900

    
1901
/* save the vga display in a PPM image even if no display is
1902
   available */
1903
void vga_screen_dump(const char *filename)
1904
{
1905
    VGAState *s = vga_state;
1906
    DisplayState *saved_ds, ds1, *ds = &ds1;
1907
    
1908
    /* XXX: this is a little hackish */
1909
    vga_invalidate_display();
1910
    saved_ds = s->ds;
1911

    
1912
    memset(ds, 0, sizeof(DisplayState));
1913
    ds->dpy_update = vga_save_dpy_update;
1914
    ds->dpy_resize = vga_save_dpy_resize;
1915
    ds->dpy_refresh = vga_save_dpy_refresh;
1916
    ds->depth = 32;
1917

    
1918
    s->ds = ds;
1919
    s->graphic_mode = -1;
1920
    vga_update_display();
1921
    
1922
    if (ds->data) {
1923
        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
1924
                 s->ds->linesize);
1925
        qemu_free(ds->data);
1926
    }
1927
    s->ds = saved_ds;
1928
}