Statistics
| Branch: | Revision:

root / hw / vga.c @ 0986ac3b

History | View | Annotate | Download (55.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_BOCHS_VBE
32

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

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

    
64
#define cbswap_32(__x) \
65
((uint32_t)( \
66
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
67
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
68
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
69
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
70

    
71
#ifdef WORDS_BIGENDIAN
72
#define PAT(x) cbswap_32(x)
73
#else
74
#define PAT(x) (x)
75
#endif
76

    
77
#ifdef WORDS_BIGENDIAN
78
#define BIG 1
79
#else
80
#define BIG 0
81
#endif
82

    
83
#ifdef WORDS_BIGENDIAN
84
#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
85
#else
86
#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
87
#endif
88

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

    
108
#undef PAT
109

    
110
#ifdef WORDS_BIGENDIAN
111
#define PAT(x) (x)
112
#else
113
#define PAT(x) cbswap_32(x)
114
#endif
115

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

    
135
static const uint32_t dmask4[4] = {
136
    PAT(0x00000000),
137
    PAT(0x0000ffff),
138
    PAT(0xffff0000),
139
    PAT(0xffffffff),
140
};
141

    
142
static uint32_t expand4[256];
143
static uint16_t expand2[256];
144
static uint8_t expand4to8[16];
145

    
146
VGAState *vga_state;
147
int vga_io_memory;
148

    
149
static void vga_screen_dump(void *opaque, const char *filename);
150

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

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

    
245
static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
246
{
247
    VGAState *s = opaque;
248
    int index;
249

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

    
255
#ifdef DEBUG_VGA
256
    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
257
#endif
258

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

    
367
#ifdef CONFIG_BOCHS_VBE
368
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
369
{
370
    VGAState *s = opaque;
371
    uint32_t val;
372
    val = s->vbe_index;
373
    return val;
374
}
375

    
376
static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
377
{
378
    VGAState *s = opaque;
379
    uint32_t val;
380

    
381
    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
382
        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
383
            switch(s->vbe_index) {
384
                /* XXX: do not hardcode ? */
385
            case VBE_DISPI_INDEX_XRES:
386
                val = VBE_DISPI_MAX_XRES;
387
                break;
388
            case VBE_DISPI_INDEX_YRES:
389
                val = VBE_DISPI_MAX_YRES;
390
                break;
391
            case VBE_DISPI_INDEX_BPP:
392
                val = VBE_DISPI_MAX_BPP;
393
                break;
394
            default:
395
                val = s->vbe_regs[s->vbe_index]; 
396
                break;
397
            }
398
        } else {
399
            val = s->vbe_regs[s->vbe_index]; 
400
        }
401
    } else {
402
        val = 0;
403
    }
404
#ifdef DEBUG_BOCHS_VBE
405
    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
406
#endif
407
    return val;
408
}
409

    
410
static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
411
{
412
    VGAState *s = opaque;
413
    s->vbe_index = val;
414
}
415

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

    
420
    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
421
#ifdef DEBUG_BOCHS_VBE
422
        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
423
#endif
424
        switch(s->vbe_index) {
425
        case VBE_DISPI_INDEX_ID:
426
            if (val == VBE_DISPI_ID0 ||
427
                val == VBE_DISPI_ID1 ||
428
                val == VBE_DISPI_ID2) {
429
                s->vbe_regs[s->vbe_index] = val;
430
            }
431
            break;
432
        case VBE_DISPI_INDEX_XRES:
433
            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
434
                s->vbe_regs[s->vbe_index] = val;
435
            }
436
            break;
437
        case VBE_DISPI_INDEX_YRES:
438
            if (val <= VBE_DISPI_MAX_YRES) {
439
                s->vbe_regs[s->vbe_index] = val;
440
            }
441
            break;
442
        case VBE_DISPI_INDEX_BPP:
443
            if (val == 0)
444
                val = 8;
445
            if (val == 4 || val == 8 || val == 15 || 
446
                val == 16 || val == 24 || val == 32) {
447
                s->vbe_regs[s->vbe_index] = val;
448
            }
449
            break;
450
        case VBE_DISPI_INDEX_BANK:
451
            val &= s->vbe_bank_mask;
452
            s->vbe_regs[s->vbe_index] = val;
453
            s->bank_offset = (val << 16);
454
            break;
455
        case VBE_DISPI_INDEX_ENABLE:
456
            if ((val & VBE_DISPI_ENABLED) &&
457
                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
458
                int h, shift_control;
459

    
460
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 
461
                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
462
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = 
463
                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
464
                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
465
                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
466
                
467
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
468
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
469
                else
470
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * 
471
                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
472
                s->vbe_start_addr = 0;
473

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

    
517
                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
518
                    return;
519
                w = val;
520
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
521
                    line_offset = w >> 1;
522
                else
523
                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
524
                h = s->vram_size / line_offset;
525
                /* XXX: support weird bochs semantics ? */
526
                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
527
                    return;
528
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
529
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
530
                s->vbe_line_offset = line_offset;
531
            }
532
            break;
533
        case VBE_DISPI_INDEX_X_OFFSET:
534
        case VBE_DISPI_INDEX_Y_OFFSET:
535
            {
536
                int x;
537
                s->vbe_regs[s->vbe_index] = val;
538
                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
539
                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
540
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
541
                    s->vbe_start_addr += x >> 1;
542
                else
543
                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
544
                s->vbe_start_addr >>= 2;
545
            }
546
            break;
547
        default:
548
            break;
549
        }
550
    }
551
}
552
#endif
553

    
554
/* called for accesses between 0xa0000 and 0xc0000 */
555
uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
556
{
557
    VGAState *s = opaque;
558
    int memory_map_mode, plane;
559
    uint32_t ret;
560
    
561
    /* convert to VGA memory offset */
562
    memory_map_mode = (s->gr[6] >> 2) & 3;
563
    addr &= 0x1ffff;
564
    switch(memory_map_mode) {
565
    case 0:
566
        break;
567
    case 1:
568
        if (addr >= 0x10000)
569
            return 0xff;
570
        addr += s->bank_offset;
571
        break;
572
    case 2:
573
        addr -= 0x10000;
574
        if (addr >= 0x8000)
575
            return 0xff;
576
        break;
577
    default:
578
    case 3:
579
        addr -= 0x18000;
580
        if (addr >= 0x8000)
581
            return 0xff;
582
        break;
583
    }
584
    
585
    if (s->sr[4] & 0x08) {
586
        /* chain 4 mode : simplest access */
587
        ret = s->vram_ptr[addr];
588
    } else if (s->gr[5] & 0x10) {
589
        /* odd/even mode (aka text mode mapping) */
590
        plane = (s->gr[4] & 2) | (addr & 1);
591
        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
592
    } else {
593
        /* standard VGA latched access */
594
        s->latch = ((uint32_t *)s->vram_ptr)[addr];
595

    
596
        if (!(s->gr[5] & 0x08)) {
597
            /* read mode 0 */
598
            plane = s->gr[4];
599
            ret = GET_PLANE(s->latch, plane);
600
        } else {
601
            /* read mode 1 */
602
            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
603
            ret |= ret >> 16;
604
            ret |= ret >> 8;
605
            ret = (~ret) & 0xff;
606
        }
607
    }
608
    return ret;
609
}
610

    
611
static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
612
{
613
    uint32_t v;
614
#ifdef TARGET_WORDS_BIGENDIAN
615
    v = vga_mem_readb(opaque, addr) << 8;
616
    v |= vga_mem_readb(opaque, addr + 1);
617
#else
618
    v = vga_mem_readb(opaque, addr);
619
    v |= vga_mem_readb(opaque, addr + 1) << 8;
620
#endif
621
    return v;
622
}
623

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

    
641
/* called for accesses between 0xa0000 and 0xc0000 */
642
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
643
{
644
    VGAState *s = opaque;
645
    int memory_map_mode, plane, write_mode, b, func_select, mask;
646
    uint32_t write_mask, bit_mask, set_mask;
647

    
648
#ifdef DEBUG_VGA_MEM
649
    printf("vga: [0x%x] = 0x%02x\n", addr, val);
650
#endif
651
    /* convert to VGA memory offset */
652
    memory_map_mode = (s->gr[6] >> 2) & 3;
653
    addr &= 0x1ffff;
654
    switch(memory_map_mode) {
655
    case 0:
656
        break;
657
    case 1:
658
        if (addr >= 0x10000)
659
            return;
660
        addr += s->bank_offset;
661
        break;
662
    case 2:
663
        addr -= 0x10000;
664
        if (addr >= 0x8000)
665
            return;
666
        break;
667
    default:
668
    case 3:
669
        addr -= 0x18000;
670
        if (addr >= 0x8000)
671
            return;
672
        break;
673
    }
674
    
675
    if (s->sr[4] & 0x08) {
676
        /* chain 4 mode : simplest access */
677
        plane = addr & 3;
678
        mask = (1 << plane);
679
        if (s->sr[2] & mask) {
680
            s->vram_ptr[addr] = val;
681
#ifdef DEBUG_VGA_MEM
682
            printf("vga: chain4: [0x%x]\n", addr);
683
#endif
684
            s->plane_updated |= mask; /* only used to detect font change */
685
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
686
        }
687
    } else if (s->gr[5] & 0x10) {
688
        /* odd/even mode (aka text mode mapping) */
689
        plane = (s->gr[4] & 2) | (addr & 1);
690
        mask = (1 << plane);
691
        if (s->sr[2] & mask) {
692
            addr = ((addr & ~1) << 1) | plane;
693
            s->vram_ptr[addr] = val;
694
#ifdef DEBUG_VGA_MEM
695
            printf("vga: odd/even: [0x%x]\n", addr);
696
#endif
697
            s->plane_updated |= mask; /* only used to detect font change */
698
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
699
        }
700
    } else {
701
        /* standard VGA latched access */
702
        write_mode = s->gr[5] & 3;
703
        switch(write_mode) {
704
        default:
705
        case 0:
706
            /* rotate */
707
            b = s->gr[3] & 7;
708
            val = ((val >> b) | (val << (8 - b))) & 0xff;
709
            val |= val << 8;
710
            val |= val << 16;
711

    
712
            /* apply set/reset mask */
713
            set_mask = mask16[s->gr[1]];
714
            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
715
            bit_mask = s->gr[8];
716
            break;
717
        case 1:
718
            val = s->latch;
719
            goto do_write;
720
        case 2:
721
            val = mask16[val & 0x0f];
722
            bit_mask = s->gr[8];
723
            break;
724
        case 3:
725
            /* rotate */
726
            b = s->gr[3] & 7;
727
            val = (val >> b) | (val << (8 - b));
728

    
729
            bit_mask = s->gr[8] & val;
730
            val = mask16[s->gr[0]];
731
            break;
732
        }
733

    
734
        /* apply logical operation */
735
        func_select = s->gr[3] >> 3;
736
        switch(func_select) {
737
        case 0:
738
        default:
739
            /* nothing to do */
740
            break;
741
        case 1:
742
            /* and */
743
            val &= s->latch;
744
            break;
745
        case 2:
746
            /* or */
747
            val |= s->latch;
748
            break;
749
        case 3:
750
            /* xor */
751
            val ^= s->latch;
752
            break;
753
        }
754

    
755
        /* apply bit mask */
756
        bit_mask |= bit_mask << 8;
757
        bit_mask |= bit_mask << 16;
758
        val = (val & bit_mask) | (s->latch & ~bit_mask);
759

    
760
    do_write:
761
        /* mask data according to sr[2] */
762
        mask = s->sr[2];
763
        s->plane_updated |= mask; /* only used to detect font change */
764
        write_mask = mask16[mask];
765
        ((uint32_t *)s->vram_ptr)[addr] = 
766
            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | 
767
            (val & write_mask);
768
#ifdef DEBUG_VGA_MEM
769
            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", 
770
                   addr * 4, write_mask, val);
771
#endif
772
            cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
773
    }
774
}
775

    
776
static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
777
{
778
#ifdef TARGET_WORDS_BIGENDIAN
779
    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
780
    vga_mem_writeb(opaque, addr + 1, val & 0xff);
781
#else
782
    vga_mem_writeb(opaque, addr, val & 0xff);
783
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
784
#endif
785
}
786

    
787
static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
788
{
789
#ifdef TARGET_WORDS_BIGENDIAN
790
    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
791
    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
792
    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
793
    vga_mem_writeb(opaque, addr + 3, val & 0xff);
794
#else
795
    vga_mem_writeb(opaque, addr, val & 0xff);
796
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
797
    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
798
    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
799
#endif
800
}
801

    
802
typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
803
                             const uint8_t *font_ptr, int h,
804
                             uint32_t fgcol, uint32_t bgcol);
805
typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
806
                                  const uint8_t *font_ptr, int h, 
807
                                  uint32_t fgcol, uint32_t bgcol, int dup9);
808
typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, 
809
                                const uint8_t *s, int width);
810

    
811
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
812
{
813
    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
814
}
815

    
816
static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
817
{
818
    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
819
}
820

    
821
static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
822
{
823
    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
824
}
825

    
826
static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
827
{
828
    return (r << 16) | (g << 8) | b;
829
}
830

    
831
static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b)
832
{
833
    return (b << 16) | (g << 8) | r;
834
}
835

    
836
#define DEPTH 8
837
#include "vga_template.h"
838

    
839
#define DEPTH 15
840
#include "vga_template.h"
841

    
842
#define DEPTH 16
843
#include "vga_template.h"
844

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

    
848
#define BGR_FORMAT
849
#define DEPTH 32
850
#include "vga_template.h"
851

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

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

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

    
877
static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
878
{
879
    unsigned int col;
880
    col = rgb_to_pixel32(r, g, b);
881
    return col;
882
}
883

    
884
static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
885
{
886
    unsigned int col;
887
    col = rgb_to_pixel32bgr(r, g, b);
888
    return col;
889
}
890

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

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

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

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

    
939
static void vga_get_offsets(VGAState *s, 
940
                            uint32_t *pline_offset, 
941
                            uint32_t *pstart_addr)
942
{
943
    uint32_t start_addr, line_offset;
944
#ifdef CONFIG_BOCHS_VBE
945
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
946
        line_offset = s->vbe_line_offset;
947
        start_addr = s->vbe_start_addr;
948
    } else
949
#endif
950
    {  
951
        /* compute line_offset in bytes */
952
        line_offset = s->cr[0x13];
953
        line_offset <<= 3;
954

    
955
        /* starting address */
956
        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
957
    }
958
    *pline_offset = line_offset;
959
    *pstart_addr = start_addr;
960
}
961

    
962
/* update start_addr and line_offset. Return TRUE if modified */
963
static int update_basic_params(VGAState *s)
964
{
965
    int full_update;
966
    uint32_t start_addr, line_offset, line_compare;
967
    
968
    full_update = 0;
969

    
970
    s->get_offsets(s, &line_offset, &start_addr);
971
    /* line compare */
972
    line_compare = s->cr[0x18] | 
973
        ((s->cr[0x07] & 0x10) << 4) |
974
        ((s->cr[0x09] & 0x40) << 3);
975

    
976
    if (line_offset != s->line_offset ||
977
        start_addr != s->start_addr ||
978
        line_compare != s->line_compare) {
979
        s->line_offset = line_offset;
980
        s->start_addr = start_addr;
981
        s->line_compare = line_compare;
982
        full_update = 1;
983
    }
984
    return full_update;
985
}
986

    
987
#define NB_DEPTHS 5
988

    
989
static inline int get_depth_index(DisplayState *s)
990
{
991
    switch(s->depth) {
992
    default:
993
    case 8:
994
        return 0;
995
    case 15:
996
        return 1;
997
    case 16:
998
        return 2;
999
    case 32:
1000
        if (s->bgr)
1001
            return 4;
1002
        else
1003
            return 3;
1004
    }
1005
}
1006

    
1007
static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1008
    vga_draw_glyph8_8,
1009
    vga_draw_glyph8_16,
1010
    vga_draw_glyph8_16,
1011
    vga_draw_glyph8_32,
1012
    vga_draw_glyph8_32,
1013
};
1014

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

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

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

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

    
1083
    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1084
    font_base[1] = s->vram_ptr + offset;
1085
    if (offset != s->font_offsets[1]) {
1086
        s->font_offsets[1] = offset;
1087
        full_update = 1;
1088
    }
1089
    if (s->plane_updated & (1 << 2)) {
1090
        /* if the plane 2 was modified since the last display, it
1091
           indicates the font may have been modified */
1092
        s->plane_updated = 0;
1093
        full_update = 1;
1094
    }
1095
    full_update |= update_basic_params(s);
1096

    
1097
    line_offset = s->line_offset;
1098
    s1 = s->vram_ptr + (s->start_addr * 4);
1099

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

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

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

    
1243
static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1244
    vga_draw_line2_8,
1245
    vga_draw_line2_16,
1246
    vga_draw_line2_16,
1247
    vga_draw_line2_32,
1248
    vga_draw_line2_32,
1249

    
1250
    vga_draw_line2d2_8,
1251
    vga_draw_line2d2_16,
1252
    vga_draw_line2d2_16,
1253
    vga_draw_line2d2_32,
1254
    vga_draw_line2d2_32,
1255

    
1256
    vga_draw_line4_8,
1257
    vga_draw_line4_16,
1258
    vga_draw_line4_16,
1259
    vga_draw_line4_32,
1260
    vga_draw_line4_32,
1261

    
1262
    vga_draw_line4d2_8,
1263
    vga_draw_line4d2_16,
1264
    vga_draw_line4d2_16,
1265
    vga_draw_line4d2_32,
1266
    vga_draw_line4d2_32,
1267

    
1268
    vga_draw_line8d2_8,
1269
    vga_draw_line8d2_16,
1270
    vga_draw_line8d2_16,
1271
    vga_draw_line8d2_32,
1272
    vga_draw_line8d2_32,
1273

    
1274
    vga_draw_line8_8,
1275
    vga_draw_line8_16,
1276
    vga_draw_line8_16,
1277
    vga_draw_line8_32,
1278
    vga_draw_line8_32,
1279

    
1280
    vga_draw_line15_8,
1281
    vga_draw_line15_15,
1282
    vga_draw_line15_16,
1283
    vga_draw_line15_32,
1284
    vga_draw_line15_32bgr,
1285

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

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

    
1298
    vga_draw_line32_8,
1299
    vga_draw_line32_15,
1300
    vga_draw_line32_16,
1301
    vga_draw_line32_32,
1302
    vga_draw_line32_32bgr,
1303
};
1304

    
1305
typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1306

    
1307
static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1308
    rgb_to_pixel8_dup,
1309
    rgb_to_pixel15_dup,
1310
    rgb_to_pixel16_dup,
1311
    rgb_to_pixel32_dup,
1312
    rgb_to_pixel32bgr_dup,
1313
};
1314

    
1315
static int vga_get_bpp(VGAState *s)
1316
{
1317
    int ret;
1318
#ifdef CONFIG_BOCHS_VBE
1319
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1320
        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1321
    } else 
1322
#endif
1323
    {
1324
        ret = 0;
1325
    }
1326
    return ret;
1327
}
1328

    
1329
static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1330
{
1331
    int width, height;
1332
    
1333
#ifdef CONFIG_BOCHS_VBE
1334
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1335
        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1336
        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1337
    } else 
1338
#endif
1339
    {
1340
        width = (s->cr[0x01] + 1) * 8;
1341
        height = s->cr[0x12] | 
1342
            ((s->cr[0x07] & 0x02) << 7) | 
1343
            ((s->cr[0x07] & 0x40) << 3);
1344
        height = (height + 1);
1345
    }
1346
    *pwidth = width;
1347
    *pheight = height;
1348
}
1349

    
1350
void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1351
{
1352
    int y;
1353
    if (y1 >= VGA_MAX_HEIGHT)
1354
        return;
1355
    if (y2 >= VGA_MAX_HEIGHT)
1356
        y2 = VGA_MAX_HEIGHT;
1357
    for(y = y1; y < y2; y++) {
1358
        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1359
    }
1360
}
1361

    
1362
/* 
1363
 * graphic modes
1364
 */
1365
static void vga_draw_graphic(VGAState *s, int full_update)
1366
{
1367
    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1368
    int width, height, shift_control, line_offset, page0, page1, bwidth;
1369
    int disp_width, multi_scan, multi_run;
1370
    uint8_t *d;
1371
    uint32_t v, addr1, addr;
1372
    vga_draw_line_func *vga_draw_line;
1373
    
1374
    full_update |= update_basic_params(s);
1375

    
1376
    s->get_resolution(s, &width, &height);
1377
    disp_width = width;
1378

    
1379
    shift_control = (s->gr[0x05] >> 5) & 3;
1380
    double_scan = (s->cr[0x09] >> 7);
1381
    if (shift_control != 1) {
1382
        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1383
    } else {
1384
        /* in CGA modes, multi_scan is ignored */
1385
        /* XXX: is it correct ? */
1386
        multi_scan = double_scan;
1387
    }
1388
    multi_run = multi_scan;
1389
    if (shift_control != s->shift_control ||
1390
        double_scan != s->double_scan) {
1391
        full_update = 1;
1392
        s->shift_control = shift_control;
1393
        s->double_scan = double_scan;
1394
    }
1395
    
1396
    if (shift_control == 0) {
1397
        full_update |= update_palette16(s);
1398
        if (s->sr[0x01] & 8) {
1399
            v = VGA_DRAW_LINE4D2;
1400
            disp_width <<= 1;
1401
        } else {
1402
            v = VGA_DRAW_LINE4;
1403
        }
1404
    } else if (shift_control == 1) {
1405
        full_update |= update_palette16(s);
1406
        if (s->sr[0x01] & 8) {
1407
            v = VGA_DRAW_LINE2D2;
1408
            disp_width <<= 1;
1409
        } else {
1410
            v = VGA_DRAW_LINE2;
1411
        }
1412
    } else {
1413
        switch(s->get_bpp(s)) {
1414
        default:
1415
        case 0:
1416
            full_update |= update_palette256(s);
1417
            v = VGA_DRAW_LINE8D2;
1418
            break;
1419
        case 8:
1420
            full_update |= update_palette256(s);
1421
            v = VGA_DRAW_LINE8;
1422
            break;
1423
        case 15:
1424
            v = VGA_DRAW_LINE15;
1425
            break;
1426
        case 16:
1427
            v = VGA_DRAW_LINE16;
1428
            break;
1429
        case 24:
1430
            v = VGA_DRAW_LINE24;
1431
            break;
1432
        case 32:
1433
            v = VGA_DRAW_LINE32;
1434
            break;
1435
        }
1436
    }
1437
    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1438

    
1439
    if (disp_width != s->last_width ||
1440
        height != s->last_height) {
1441
        dpy_resize(s->ds, disp_width, height);
1442
        s->last_scr_width = disp_width;
1443
        s->last_scr_height = height;
1444
        s->last_width = disp_width;
1445
        s->last_height = height;
1446
        full_update = 1;
1447
    }
1448
    if (s->cursor_invalidate)
1449
        s->cursor_invalidate(s);
1450
    
1451
    line_offset = s->line_offset;
1452
#if 0
1453
    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",
1454
           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1455
#endif
1456
    addr1 = (s->start_addr * 4);
1457
    bwidth = width * 4;
1458
    y_start = -1;
1459
    page_min = 0x7fffffff;
1460
    page_max = -1;
1461
    d = s->ds->data;
1462
    linesize = s->ds->linesize;
1463
    y1 = 0;
1464
    for(y = 0; y < height; y++) {
1465
        addr = addr1;
1466
        if (!(s->cr[0x17] & 1)) {
1467
            int shift;
1468
            /* CGA compatibility handling */
1469
            shift = 14 + ((s->cr[0x17] >> 6) & 1);
1470
            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1471
        }
1472
        if (!(s->cr[0x17] & 2)) {
1473
            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1474
        }
1475
        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1476
        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1477
        update = full_update | 
1478
            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1479
            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1480
        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1481
            /* if wide line, can use another page */
1482
            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, 
1483
                                                    VGA_DIRTY_FLAG);
1484
        }
1485
        /* explicit invalidation for the hardware cursor */
1486
        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1487
        if (update) {
1488
            if (y_start < 0)
1489
                y_start = y;
1490
            if (page0 < page_min)
1491
                page_min = page0;
1492
            if (page1 > page_max)
1493
                page_max = page1;
1494
            vga_draw_line(s, d, s->vram_ptr + addr, width);
1495
            if (s->cursor_draw_line)
1496
                s->cursor_draw_line(s, d, y);
1497
        } else {
1498
            if (y_start >= 0) {
1499
                /* flush to display */
1500
                dpy_update(s->ds, 0, y_start, 
1501
                           disp_width, y - y_start);
1502
                y_start = -1;
1503
            }
1504
        }
1505
        if (!multi_run) {
1506
            mask = (s->cr[0x17] & 3) ^ 3;
1507
            if ((y1 & mask) == mask)
1508
                addr1 += line_offset;
1509
            y1++;
1510
            multi_run = multi_scan;
1511
        } else {
1512
            multi_run--;
1513
        }
1514
        /* line compare acts on the displayed lines */
1515
        if (y == s->line_compare)
1516
            addr1 = 0;
1517
        d += linesize;
1518
    }
1519
    if (y_start >= 0) {
1520
        /* flush to display */
1521
        dpy_update(s->ds, 0, y_start, 
1522
                   disp_width, y - y_start);
1523
    }
1524
    /* reset modified pages */
1525
    if (page_max != -1) {
1526
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1527
                                        VGA_DIRTY_FLAG);
1528
    }
1529
    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1530
}
1531

    
1532
static void vga_draw_blank(VGAState *s, int full_update)
1533
{
1534
    int i, w, val;
1535
    uint8_t *d;
1536

    
1537
    if (!full_update)
1538
        return;
1539
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1540
        return;
1541
    if (s->ds->depth == 8) 
1542
        val = s->rgb_to_pixel(0, 0, 0);
1543
    else
1544
        val = 0;
1545
    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1546
    d = s->ds->data;
1547
    for(i = 0; i < s->last_scr_height; i++) {
1548
        memset(d, val, w);
1549
        d += s->ds->linesize;
1550
    }
1551
    dpy_update(s->ds, 0, 0, 
1552
               s->last_scr_width, s->last_scr_height);
1553
}
1554

    
1555
#define GMODE_TEXT     0
1556
#define GMODE_GRAPH    1
1557
#define GMODE_BLANK 2 
1558

    
1559
static void vga_update_display(void *opaque)
1560
{
1561
    VGAState *s = (VGAState *)opaque;
1562
    int full_update, graphic_mode;
1563

    
1564
    if (s->ds->depth == 0) {
1565
        /* nothing to do */
1566
    } else {
1567
        s->rgb_to_pixel = 
1568
            rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1569
        
1570
        full_update = 0;
1571
        if (!(s->ar_index & 0x20)) {
1572
            graphic_mode = GMODE_BLANK;
1573
        } else {
1574
            graphic_mode = s->gr[6] & 1;
1575
        }
1576
        if (graphic_mode != s->graphic_mode) {
1577
            s->graphic_mode = graphic_mode;
1578
            full_update = 1;
1579
        }
1580
        switch(graphic_mode) {
1581
        case GMODE_TEXT:
1582
            vga_draw_text(s, full_update);
1583
            break;
1584
        case GMODE_GRAPH:
1585
            vga_draw_graphic(s, full_update);
1586
            break;
1587
        case GMODE_BLANK:
1588
        default:
1589
            vga_draw_blank(s, full_update);
1590
            break;
1591
        }
1592
    }
1593
}
1594

    
1595
/* force a full display refresh */
1596
static void vga_invalidate_display(void *opaque)
1597
{
1598
    VGAState *s = (VGAState *)opaque;
1599
    
1600
    s->last_width = -1;
1601
    s->last_height = -1;
1602
}
1603

    
1604
static void vga_reset(VGAState *s)
1605
{
1606
    memset(s, 0, sizeof(VGAState));
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
    if (region_num == PCI_ROM_SLOT) {
1719
        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
1720
    } else {
1721
        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1722
    }
1723
}
1724

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

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

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

    
1753
    vga_reset(s);
1754

    
1755
    s->vram_ptr = vga_ram_base;
1756
    s->vram_offset = vga_ram_offset;
1757
    s->vram_size = vga_ram_size;
1758
    s->ds = ds;
1759
    s->get_bpp = vga_get_bpp;
1760
    s->get_offsets = vga_get_offsets;
1761
    s->get_resolution = vga_get_resolution;
1762
    graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
1763
                         vga_screen_dump, s);
1764
    /* XXX: currently needed for display */
1765
    vga_state = s;
1766
}
1767

    
1768

    
1769
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
1770
                   unsigned long vga_ram_offset, int vga_ram_size,
1771
                   unsigned long vga_bios_offset, int vga_bios_size)
1772
{
1773
    VGAState *s;
1774

    
1775
    s = qemu_mallocz(sizeof(VGAState));
1776
    if (!s)
1777
        return -1;
1778

    
1779
    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1780

    
1781
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1782

    
1783
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1784

    
1785
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1786
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1787
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1788
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1789

    
1790
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1791

    
1792
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1793
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1794
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1795
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1796
    s->bank_offset = 0;
1797

    
1798
#ifdef CONFIG_BOCHS_VBE
1799
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1800
    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1801
#if defined (TARGET_I386)
1802
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1803
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1804

    
1805
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1806
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1807

    
1808
    /* old Bochs IO ports */
1809
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1810
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1811

    
1812
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1813
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
1814
#else
1815
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1816
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1817

    
1818
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1819
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1820
#endif
1821
#endif /* CONFIG_BOCHS_VBE */
1822

    
1823
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1824
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
1825
                                 vga_io_memory);
1826

    
1827
    if (bus) {
1828
        PCIDevice *d;
1829
        uint8_t *pci_conf;
1830

    
1831
        d = pci_register_device(bus, "VGA", 
1832
                                sizeof(PCIDevice),
1833
                                -1, NULL, NULL);
1834
        pci_conf = d->config;
1835
        pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1836
        pci_conf[0x01] = 0x12;
1837
        pci_conf[0x02] = 0x11;
1838
        pci_conf[0x03] = 0x11;
1839
        pci_conf[0x0a] = 0x00; // VGA controller 
1840
        pci_conf[0x0b] = 0x03;
1841
        pci_conf[0x0e] = 0x00; // header_type
1842

    
1843
        /* XXX: vga_ram_size must be a power of two */
1844
        pci_register_io_region(d, 0, vga_ram_size, 
1845
                               PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1846
        if (vga_bios_size != 0) {
1847
            unsigned int bios_total_size;
1848
            s->bios_offset = vga_bios_offset;
1849
            s->bios_size = vga_bios_size;
1850
            /* must be a power of two */
1851
            bios_total_size = 1;
1852
            while (bios_total_size < vga_bios_size)
1853
                bios_total_size <<= 1;
1854
            pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size, 
1855
                                   PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1856
        }
1857
    } else {
1858
#ifdef CONFIG_BOCHS_VBE
1859
        /* XXX: use optimized standard vga accesses */
1860
        cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
1861
                                     vga_ram_size, vga_ram_offset);
1862
#endif
1863
    }
1864
    return 0;
1865
}
1866

    
1867
/********************************************************/
1868
/* vga screen dump */
1869

    
1870
static int vga_save_w, vga_save_h;
1871

    
1872
static void vga_save_dpy_update(DisplayState *s, 
1873
                                int x, int y, int w, int h)
1874
{
1875
}
1876

    
1877
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1878
{
1879
    s->linesize = w * 4;
1880
    s->data = qemu_malloc(h * s->linesize);
1881
    vga_save_w = w;
1882
    vga_save_h = h;
1883
}
1884

    
1885
static void vga_save_dpy_refresh(DisplayState *s)
1886
{
1887
}
1888

    
1889
static int ppm_save(const char *filename, uint8_t *data, 
1890
                    int w, int h, int linesize)
1891
{
1892
    FILE *f;
1893
    uint8_t *d, *d1;
1894
    unsigned int v;
1895
    int y, x;
1896

    
1897
    f = fopen(filename, "wb");
1898
    if (!f)
1899
        return -1;
1900
    fprintf(f, "P6\n%d %d\n%d\n",
1901
            w, h, 255);
1902
    d1 = data;
1903
    for(y = 0; y < h; y++) {
1904
        d = d1;
1905
        for(x = 0; x < w; x++) {
1906
            v = *(uint32_t *)d;
1907
            fputc((v >> 16) & 0xff, f);
1908
            fputc((v >> 8) & 0xff, f);
1909
            fputc((v) & 0xff, f);
1910
            d += 4;
1911
        }
1912
        d1 += linesize;
1913
    }
1914
    fclose(f);
1915
    return 0;
1916
}
1917

    
1918
/* save the vga display in a PPM image even if no display is
1919
   available */
1920
static void vga_screen_dump(void *opaque, const char *filename)
1921
{
1922
    VGAState *s = (VGAState *)opaque;
1923
    DisplayState *saved_ds, ds1, *ds = &ds1;
1924
    
1925
    /* XXX: this is a little hackish */
1926
    vga_invalidate_display(s);
1927
    saved_ds = s->ds;
1928

    
1929
    memset(ds, 0, sizeof(DisplayState));
1930
    ds->dpy_update = vga_save_dpy_update;
1931
    ds->dpy_resize = vga_save_dpy_resize;
1932
    ds->dpy_refresh = vga_save_dpy_refresh;
1933
    ds->depth = 32;
1934

    
1935
    s->ds = ds;
1936
    s->graphic_mode = -1;
1937
    vga_update_display(s);
1938
    
1939
    if (ds->data) {
1940
        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
1941
                 s->ds->linesize);
1942
        qemu_free(ds->data);
1943
    }
1944
    s->ds = saved_ds;
1945
}