Statistics
| Branch: | Revision:

root / hw / vga.c @ 977d5710

History | View | Annotate | Download (54 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 | cpu_physical_memory_is_dirty(page0) |
1458
            cpu_physical_memory_is_dirty(page1);
1459
        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1460
            /* if wide line, can use another page */
1461
            update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1462
        }
1463
        /* explicit invalidation for the hardware cursor */
1464
        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1465
        if (update) {
1466
            if (y_start < 0)
1467
                y_start = y;
1468
            if (page0 < page_min)
1469
                page_min = page0;
1470
            if (page1 > page_max)
1471
                page_max = page1;
1472
            vga_draw_line(s, d, s->vram_ptr + addr, width);
1473
            if (s->cursor_draw_line)
1474
                s->cursor_draw_line(s, d, y);
1475
        } else {
1476
            if (y_start >= 0) {
1477
                /* flush to display */
1478
                dpy_update(s->ds, 0, y_start, 
1479
                           disp_width, y - y_start);
1480
                y_start = -1;
1481
            }
1482
        }
1483
        if (!multi_run) {
1484
            mask = (s->cr[0x17] & 3) ^ 3;
1485
            if ((y1 & mask) == mask)
1486
                addr1 += line_offset;
1487
            y1++;
1488
            multi_run = multi_scan;
1489
        } else {
1490
            multi_run--;
1491
        }
1492
        /* line compare acts on the displayed lines */
1493
        if (y == s->line_compare)
1494
            addr1 = 0;
1495
        d += linesize;
1496
    }
1497
    if (y_start >= 0) {
1498
        /* flush to display */
1499
        dpy_update(s->ds, 0, y_start, 
1500
                   disp_width, y - y_start);
1501
    }
1502
    /* reset modified pages */
1503
    if (page_max != -1) {
1504
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1505
    }
1506
    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1507
}
1508

    
1509
static void vga_draw_blank(VGAState *s, int full_update)
1510
{
1511
    int i, w, val;
1512
    uint8_t *d;
1513

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

    
1532
#define GMODE_TEXT     0
1533
#define GMODE_GRAPH    1
1534
#define GMODE_BLANK 2 
1535

    
1536
void vga_update_display(void)
1537
{
1538
    VGAState *s = vga_state;
1539
    int full_update, graphic_mode;
1540

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

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

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

    
1607
static CPUReadMemoryFunc *vga_mem_read[3] = {
1608
    vga_mem_readb,
1609
    vga_mem_readw,
1610
    vga_mem_readl,
1611
};
1612

    
1613
static CPUWriteMemoryFunc *vga_mem_write[3] = {
1614
    vga_mem_writeb,
1615
    vga_mem_writew,
1616
    vga_mem_writel,
1617
};
1618

    
1619
static void vga_save(QEMUFile *f, void *opaque)
1620
{
1621
    VGAState *s = opaque;
1622
    int i;
1623

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

    
1639
    qemu_put_8s(f, &s->dac_state);
1640
    qemu_put_8s(f, &s->dac_sub_index);
1641
    qemu_put_8s(f, &s->dac_read_index);
1642
    qemu_put_8s(f, &s->dac_write_index);
1643
    qemu_put_buffer(f, s->dac_cache, 3);
1644
    qemu_put_buffer(f, s->palette, 768);
1645

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

    
1660
static int vga_load(QEMUFile *f, void *opaque, int version_id)
1661
{
1662
    VGAState *s = opaque;
1663
    int is_vbe, i;
1664

    
1665
    if (version_id != 1)
1666
        return -EINVAL;
1667

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

    
1683
    qemu_get_8s(f, &s->dac_state);
1684
    qemu_get_8s(f, &s->dac_sub_index);
1685
    qemu_get_8s(f, &s->dac_read_index);
1686
    qemu_get_8s(f, &s->dac_write_index);
1687
    qemu_get_buffer(f, s->dac_cache, 3);
1688
    qemu_get_buffer(f, s->palette, 768);
1689

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

    
1706
    /* force refresh */
1707
    s->graphic_mode = -1;
1708
    return 0;
1709
}
1710

    
1711
static void vga_map(PCIDevice *pci_dev, int region_num, 
1712
                    uint32_t addr, uint32_t size, int type)
1713
{
1714
    VGAState *s = vga_state;
1715

    
1716
    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1717
}
1718

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

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

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

    
1747
    vga_reset(s);
1748

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

    
1760

    
1761
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
1762
                   unsigned long vga_ram_offset, int vga_ram_size)
1763
{
1764
    VGAState *s;
1765

    
1766
    s = qemu_mallocz(sizeof(VGAState));
1767
    if (!s)
1768
        return -1;
1769

    
1770
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1771

    
1772
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1773

    
1774
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1775

    
1776
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1777
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1778
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1779
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1780

    
1781
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1782

    
1783
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1784
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1785
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1786
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1787
    s->bank_offset = 0;
1788

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

    
1796
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1797
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1798

    
1799
    /* old Bochs IO ports */
1800
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1801
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1802

    
1803
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1804
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
1805
#else
1806
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1807
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1808

    
1809
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1810
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1811
#endif
1812
#endif /* CONFIG_BOCHS_VBE */
1813

    
1814
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1815
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
1816
                                 vga_io_memory);
1817

    
1818
    if (bus) {
1819
        PCIDevice *d;
1820
        uint8_t *pci_conf;
1821

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

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

    
1847
/********************************************************/
1848
/* vga screen dump */
1849

    
1850
static int vga_save_w, vga_save_h;
1851

    
1852
static void vga_save_dpy_update(DisplayState *s, 
1853
                                int x, int y, int w, int h)
1854
{
1855
}
1856

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

    
1865
static void vga_save_dpy_refresh(DisplayState *s)
1866
{
1867
}
1868

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

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

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

    
1909
    memset(ds, 0, sizeof(DisplayState));
1910
    ds->dpy_update = vga_save_dpy_update;
1911
    ds->dpy_resize = vga_save_dpy_resize;
1912
    ds->dpy_refresh = vga_save_dpy_refresh;
1913
    ds->depth = 32;
1914

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