Statistics
| Branch: | Revision:

root / hw / vga.c @ 47d37dd9

History | View | Annotate | Download (70.9 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 "hw.h"
25
#include "console.h"
26
#include "pc.h"
27
#include "pci.h"
28
#include "vga_int.h"
29
#include "pixel_ops.h"
30
#include "qemu-timer.h"
31

    
32
//#define DEBUG_VGA
33
//#define DEBUG_VGA_MEM
34
//#define DEBUG_VGA_REG
35

    
36
//#define DEBUG_BOCHS_VBE
37

    
38
/* force some bits to zero */
39
const uint8_t sr_mask[8] = {
40
    0x03,
41
    0x3d,
42
    0x0f,
43
    0x3f,
44
    0x0e,
45
    0x00,
46
    0x00,
47
    0xff,
48
};
49

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

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

    
76
#ifdef HOST_WORDS_BIGENDIAN
77
#define PAT(x) cbswap_32(x)
78
#else
79
#define PAT(x) (x)
80
#endif
81

    
82
#ifdef HOST_WORDS_BIGENDIAN
83
#define BIG 1
84
#else
85
#define BIG 0
86
#endif
87

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

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

    
113
#undef PAT
114

    
115
#ifdef HOST_WORDS_BIGENDIAN
116
#define PAT(x) (x)
117
#else
118
#define PAT(x) cbswap_32(x)
119
#endif
120

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

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

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

    
151
typedef VGACommonState VGAState;
152

    
153
static void vga_screen_dump(void *opaque, const char *filename);
154
static char *screen_dump_filename;
155
static DisplayChangeListener *screen_dump_dcl;
156

    
157
static void vga_dumb_update_retrace_info(VGAState *s)
158
{
159
    (void) s;
160
}
161

    
162
static void vga_precise_update_retrace_info(VGAState *s)
163
{
164
    int htotal_chars;
165
    int hretr_start_char;
166
    int hretr_skew_chars;
167
    int hretr_end_char;
168

    
169
    int vtotal_lines;
170
    int vretr_start_line;
171
    int vretr_end_line;
172

    
173
    int div2, sldiv2, dots;
174
    int clocking_mode;
175
    int clock_sel;
176
    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
177
    int64_t chars_per_sec;
178
    struct vga_precise_retrace *r = &s->retrace_info.precise;
179

    
180
    htotal_chars = s->cr[0x00] + 5;
181
    hretr_start_char = s->cr[0x04];
182
    hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
183
    hretr_end_char = s->cr[0x05] & 0x1f;
184

    
185
    vtotal_lines = (s->cr[0x06]
186
                    | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
187
        ;
188
    vretr_start_line = s->cr[0x10]
189
        | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
190
        ;
191
    vretr_end_line = s->cr[0x11] & 0xf;
192

    
193

    
194
    div2 = (s->cr[0x17] >> 2) & 1;
195
    sldiv2 = (s->cr[0x17] >> 3) & 1;
196

    
197
    clocking_mode = (s->sr[0x01] >> 3) & 1;
198
    clock_sel = (s->msr >> 2) & 3;
199
    dots = (s->msr & 1) ? 8 : 9;
200

    
201
    chars_per_sec = clk_hz[clock_sel] / dots;
202

    
203
    htotal_chars <<= clocking_mode;
204

    
205
    r->total_chars = vtotal_lines * htotal_chars;
206
    if (r->freq) {
207
        r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
208
    } else {
209
        r->ticks_per_char = ticks_per_sec / chars_per_sec;
210
    }
211

    
212
    r->vstart = vretr_start_line;
213
    r->vend = r->vstart + vretr_end_line + 1;
214

    
215
    r->hstart = hretr_start_char + hretr_skew_chars;
216
    r->hend = r->hstart + hretr_end_char + 1;
217
    r->htotal = htotal_chars;
218

    
219
#if 0
220
    printf (
221
        "hz=%f\n"
222
        "htotal = %d\n"
223
        "hretr_start = %d\n"
224
        "hretr_skew = %d\n"
225
        "hretr_end = %d\n"
226
        "vtotal = %d\n"
227
        "vretr_start = %d\n"
228
        "vretr_end = %d\n"
229
        "div2 = %d sldiv2 = %d\n"
230
        "clocking_mode = %d\n"
231
        "clock_sel = %d %d\n"
232
        "dots = %d\n"
233
        "ticks/char = %lld\n"
234
        "\n",
235
        (double) ticks_per_sec / (r->ticks_per_char * r->total_chars),
236
        htotal_chars,
237
        hretr_start_char,
238
        hretr_skew_chars,
239
        hretr_end_char,
240
        vtotal_lines,
241
        vretr_start_line,
242
        vretr_end_line,
243
        div2, sldiv2,
244
        clocking_mode,
245
        clock_sel,
246
        clk_hz[clock_sel],
247
        dots,
248
        r->ticks_per_char
249
        );
250
#endif
251
}
252

    
253
static uint8_t vga_precise_retrace(VGAState *s)
254
{
255
    struct vga_precise_retrace *r = &s->retrace_info.precise;
256
    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
257

    
258
    if (r->total_chars) {
259
        int cur_line, cur_line_char, cur_char;
260
        int64_t cur_tick;
261

    
262
        cur_tick = qemu_get_clock(vm_clock);
263

    
264
        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
265
        cur_line = cur_char / r->htotal;
266

    
267
        if (cur_line >= r->vstart && cur_line <= r->vend) {
268
            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
269
        } else {
270
            cur_line_char = cur_char % r->htotal;
271
            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
272
                val |= ST01_DISP_ENABLE;
273
            }
274
        }
275

    
276
        return val;
277
    } else {
278
        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
279
    }
280
}
281

    
282
static uint8_t vga_dumb_retrace(VGAState *s)
283
{
284
    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
285
}
286

    
287
uint32_t vga_ioport_read(void *opaque, uint32_t addr)
288
{
289
    VGACommonState *s = opaque;
290
    int val, index;
291

    
292
    /* check port range access depending on color/monochrome mode */
293
    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
294
        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
295
        val = 0xff;
296
    } else {
297
        switch(addr) {
298
        case 0x3c0:
299
            if (s->ar_flip_flop == 0) {
300
                val = s->ar_index;
301
            } else {
302
                val = 0;
303
            }
304
            break;
305
        case 0x3c1:
306
            index = s->ar_index & 0x1f;
307
            if (index < 21)
308
                val = s->ar[index];
309
            else
310
                val = 0;
311
            break;
312
        case 0x3c2:
313
            val = s->st00;
314
            break;
315
        case 0x3c4:
316
            val = s->sr_index;
317
            break;
318
        case 0x3c5:
319
            val = s->sr[s->sr_index];
320
#ifdef DEBUG_VGA_REG
321
            printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
322
#endif
323
            break;
324
        case 0x3c7:
325
            val = s->dac_state;
326
            break;
327
        case 0x3c8:
328
            val = s->dac_write_index;
329
            break;
330
        case 0x3c9:
331
            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
332
            if (++s->dac_sub_index == 3) {
333
                s->dac_sub_index = 0;
334
                s->dac_read_index++;
335
            }
336
            break;
337
        case 0x3ca:
338
            val = s->fcr;
339
            break;
340
        case 0x3cc:
341
            val = s->msr;
342
            break;
343
        case 0x3ce:
344
            val = s->gr_index;
345
            break;
346
        case 0x3cf:
347
            val = s->gr[s->gr_index];
348
#ifdef DEBUG_VGA_REG
349
            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
350
#endif
351
            break;
352
        case 0x3b4:
353
        case 0x3d4:
354
            val = s->cr_index;
355
            break;
356
        case 0x3b5:
357
        case 0x3d5:
358
            val = s->cr[s->cr_index];
359
#ifdef DEBUG_VGA_REG
360
            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
361
#endif
362
            break;
363
        case 0x3ba:
364
        case 0x3da:
365
            /* just toggle to fool polling */
366
            val = s->st01 = s->retrace(s);
367
            s->ar_flip_flop = 0;
368
            break;
369
        default:
370
            val = 0x00;
371
            break;
372
        }
373
    }
374
#if defined(DEBUG_VGA)
375
    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
376
#endif
377
    return val;
378
}
379

    
380
void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
381
{
382
    VGACommonState *s = opaque;
383
    int index;
384

    
385
    /* check port range access depending on color/monochrome mode */
386
    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
387
        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
388
        return;
389

    
390
#ifdef DEBUG_VGA
391
    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
392
#endif
393

    
394
    switch(addr) {
395
    case 0x3c0:
396
        if (s->ar_flip_flop == 0) {
397
            val &= 0x3f;
398
            s->ar_index = val;
399
        } else {
400
            index = s->ar_index & 0x1f;
401
            switch(index) {
402
            case 0x00 ... 0x0f:
403
                s->ar[index] = val & 0x3f;
404
                break;
405
            case 0x10:
406
                s->ar[index] = val & ~0x10;
407
                break;
408
            case 0x11:
409
                s->ar[index] = val;
410
                break;
411
            case 0x12:
412
                s->ar[index] = val & ~0xc0;
413
                break;
414
            case 0x13:
415
                s->ar[index] = val & ~0xf0;
416
                break;
417
            case 0x14:
418
                s->ar[index] = val & ~0xf0;
419
                break;
420
            default:
421
                break;
422
            }
423
        }
424
        s->ar_flip_flop ^= 1;
425
        break;
426
    case 0x3c2:
427
        s->msr = val & ~0x10;
428
        s->update_retrace_info(s);
429
        break;
430
    case 0x3c4:
431
        s->sr_index = val & 7;
432
        break;
433
    case 0x3c5:
434
#ifdef DEBUG_VGA_REG
435
        printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
436
#endif
437
        s->sr[s->sr_index] = val & sr_mask[s->sr_index];
438
        if (s->sr_index == 1) s->update_retrace_info(s);
439
        break;
440
    case 0x3c7:
441
        s->dac_read_index = val;
442
        s->dac_sub_index = 0;
443
        s->dac_state = 3;
444
        break;
445
    case 0x3c8:
446
        s->dac_write_index = val;
447
        s->dac_sub_index = 0;
448
        s->dac_state = 0;
449
        break;
450
    case 0x3c9:
451
        s->dac_cache[s->dac_sub_index] = val;
452
        if (++s->dac_sub_index == 3) {
453
            memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
454
            s->dac_sub_index = 0;
455
            s->dac_write_index++;
456
        }
457
        break;
458
    case 0x3ce:
459
        s->gr_index = val & 0x0f;
460
        break;
461
    case 0x3cf:
462
#ifdef DEBUG_VGA_REG
463
        printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
464
#endif
465
        s->gr[s->gr_index] = val & gr_mask[s->gr_index];
466
        break;
467
    case 0x3b4:
468
    case 0x3d4:
469
        s->cr_index = val;
470
        break;
471
    case 0x3b5:
472
    case 0x3d5:
473
#ifdef DEBUG_VGA_REG
474
        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
475
#endif
476
        /* handle CR0-7 protection */
477
        if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
478
            /* can always write bit 4 of CR7 */
479
            if (s->cr_index == 7)
480
                s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
481
            return;
482
        }
483
        switch(s->cr_index) {
484
        case 0x01: /* horizontal display end */
485
        case 0x07:
486
        case 0x09:
487
        case 0x0c:
488
        case 0x0d:
489
        case 0x12: /* vertical display end */
490
            s->cr[s->cr_index] = val;
491
            break;
492
        default:
493
            s->cr[s->cr_index] = val;
494
            break;
495
        }
496

    
497
        switch(s->cr_index) {
498
        case 0x00:
499
        case 0x04:
500
        case 0x05:
501
        case 0x06:
502
        case 0x07:
503
        case 0x11:
504
        case 0x17:
505
            s->update_retrace_info(s);
506
            break;
507
        }
508
        break;
509
    case 0x3ba:
510
    case 0x3da:
511
        s->fcr = val & 0x10;
512
        break;
513
    }
514
}
515

    
516
#ifdef CONFIG_BOCHS_VBE
517
static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
518
{
519
    VGAState *s = opaque;
520
    uint32_t val;
521
    val = s->vbe_index;
522
    return val;
523
}
524

    
525
static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
526
{
527
    VGAState *s = opaque;
528
    uint32_t val;
529

    
530
    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
531
        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
532
            switch(s->vbe_index) {
533
                /* XXX: do not hardcode ? */
534
            case VBE_DISPI_INDEX_XRES:
535
                val = VBE_DISPI_MAX_XRES;
536
                break;
537
            case VBE_DISPI_INDEX_YRES:
538
                val = VBE_DISPI_MAX_YRES;
539
                break;
540
            case VBE_DISPI_INDEX_BPP:
541
                val = VBE_DISPI_MAX_BPP;
542
                break;
543
            default:
544
                val = s->vbe_regs[s->vbe_index];
545
                break;
546
            }
547
        } else {
548
            val = s->vbe_regs[s->vbe_index];
549
        }
550
    } else {
551
        val = 0;
552
    }
553
#ifdef DEBUG_BOCHS_VBE
554
    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
555
#endif
556
    return val;
557
}
558

    
559
static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
560
{
561
    VGAState *s = opaque;
562
    s->vbe_index = val;
563
}
564

    
565
static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
566
{
567
    VGAState *s = opaque;
568

    
569
    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
570
#ifdef DEBUG_BOCHS_VBE
571
        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
572
#endif
573
        switch(s->vbe_index) {
574
        case VBE_DISPI_INDEX_ID:
575
            if (val == VBE_DISPI_ID0 ||
576
                val == VBE_DISPI_ID1 ||
577
                val == VBE_DISPI_ID2 ||
578
                val == VBE_DISPI_ID3 ||
579
                val == VBE_DISPI_ID4) {
580
                s->vbe_regs[s->vbe_index] = val;
581
            }
582
            break;
583
        case VBE_DISPI_INDEX_XRES:
584
            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
585
                s->vbe_regs[s->vbe_index] = val;
586
            }
587
            break;
588
        case VBE_DISPI_INDEX_YRES:
589
            if (val <= VBE_DISPI_MAX_YRES) {
590
                s->vbe_regs[s->vbe_index] = val;
591
            }
592
            break;
593
        case VBE_DISPI_INDEX_BPP:
594
            if (val == 0)
595
                val = 8;
596
            if (val == 4 || val == 8 || val == 15 ||
597
                val == 16 || val == 24 || val == 32) {
598
                s->vbe_regs[s->vbe_index] = val;
599
            }
600
            break;
601
        case VBE_DISPI_INDEX_BANK:
602
            if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
603
              val &= (s->vbe_bank_mask >> 2);
604
            } else {
605
              val &= s->vbe_bank_mask;
606
            }
607
            s->vbe_regs[s->vbe_index] = val;
608
            s->bank_offset = (val << 16);
609
            break;
610
        case VBE_DISPI_INDEX_ENABLE:
611
            if ((val & VBE_DISPI_ENABLED) &&
612
                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
613
                int h, shift_control;
614

    
615
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
616
                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
617
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
618
                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
619
                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
620
                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
621

    
622
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
623
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
624
                else
625
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
626
                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
627
                s->vbe_start_addr = 0;
628

    
629
                /* clear the screen (should be done in BIOS) */
630
                if (!(val & VBE_DISPI_NOCLEARMEM)) {
631
                    memset(s->vram_ptr, 0,
632
                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
633
                }
634

    
635
                /* we initialize the VGA graphic mode (should be done
636
                   in BIOS) */
637
                s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
638
                s->cr[0x17] |= 3; /* no CGA modes */
639
                s->cr[0x13] = s->vbe_line_offset >> 3;
640
                /* width */
641
                s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
642
                /* height (only meaningful if < 1024) */
643
                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
644
                s->cr[0x12] = h;
645
                s->cr[0x07] = (s->cr[0x07] & ~0x42) |
646
                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
647
                /* line compare to 1023 */
648
                s->cr[0x18] = 0xff;
649
                s->cr[0x07] |= 0x10;
650
                s->cr[0x09] |= 0x40;
651

    
652
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
653
                    shift_control = 0;
654
                    s->sr[0x01] &= ~8; /* no double line */
655
                } else {
656
                    shift_control = 2;
657
                    s->sr[4] |= 0x08; /* set chain 4 mode */
658
                    s->sr[2] |= 0x0f; /* activate all planes */
659
                }
660
                s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
661
                s->cr[0x09] &= ~0x9f; /* no double scan */
662
            } else {
663
                /* XXX: the bios should do that */
664
                s->bank_offset = 0;
665
            }
666
            s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
667
            s->vbe_regs[s->vbe_index] = val;
668
            break;
669
        case VBE_DISPI_INDEX_VIRT_WIDTH:
670
            {
671
                int w, h, line_offset;
672

    
673
                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
674
                    return;
675
                w = val;
676
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
677
                    line_offset = w >> 1;
678
                else
679
                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
680
                h = s->vram_size / line_offset;
681
                /* XXX: support weird bochs semantics ? */
682
                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
683
                    return;
684
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
685
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
686
                s->vbe_line_offset = line_offset;
687
            }
688
            break;
689
        case VBE_DISPI_INDEX_X_OFFSET:
690
        case VBE_DISPI_INDEX_Y_OFFSET:
691
            {
692
                int x;
693
                s->vbe_regs[s->vbe_index] = val;
694
                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
695
                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
696
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
697
                    s->vbe_start_addr += x >> 1;
698
                else
699
                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
700
                s->vbe_start_addr >>= 2;
701
            }
702
            break;
703
        default:
704
            break;
705
        }
706
    }
707
}
708
#endif
709

    
710
/* called for accesses between 0xa0000 and 0xc0000 */
711
uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
712
{
713
    VGAState *s = opaque;
714
    int memory_map_mode, plane;
715
    uint32_t ret;
716

    
717
    /* convert to VGA memory offset */
718
    memory_map_mode = (s->gr[6] >> 2) & 3;
719
    addr &= 0x1ffff;
720
    switch(memory_map_mode) {
721
    case 0:
722
        break;
723
    case 1:
724
        if (addr >= 0x10000)
725
            return 0xff;
726
        addr += s->bank_offset;
727
        break;
728
    case 2:
729
        addr -= 0x10000;
730
        if (addr >= 0x8000)
731
            return 0xff;
732
        break;
733
    default:
734
    case 3:
735
        addr -= 0x18000;
736
        if (addr >= 0x8000)
737
            return 0xff;
738
        break;
739
    }
740

    
741
    if (s->sr[4] & 0x08) {
742
        /* chain 4 mode : simplest access */
743
        ret = s->vram_ptr[addr];
744
    } else if (s->gr[5] & 0x10) {
745
        /* odd/even mode (aka text mode mapping) */
746
        plane = (s->gr[4] & 2) | (addr & 1);
747
        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
748
    } else {
749
        /* standard VGA latched access */
750
        s->latch = ((uint32_t *)s->vram_ptr)[addr];
751

    
752
        if (!(s->gr[5] & 0x08)) {
753
            /* read mode 0 */
754
            plane = s->gr[4];
755
            ret = GET_PLANE(s->latch, plane);
756
        } else {
757
            /* read mode 1 */
758
            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
759
            ret |= ret >> 16;
760
            ret |= ret >> 8;
761
            ret = (~ret) & 0xff;
762
        }
763
    }
764
    return ret;
765
}
766

    
767
static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
768
{
769
    uint32_t v;
770
#ifdef TARGET_WORDS_BIGENDIAN
771
    v = vga_mem_readb(opaque, addr) << 8;
772
    v |= vga_mem_readb(opaque, addr + 1);
773
#else
774
    v = vga_mem_readb(opaque, addr);
775
    v |= vga_mem_readb(opaque, addr + 1) << 8;
776
#endif
777
    return v;
778
}
779

    
780
static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
781
{
782
    uint32_t v;
783
#ifdef TARGET_WORDS_BIGENDIAN
784
    v = vga_mem_readb(opaque, addr) << 24;
785
    v |= vga_mem_readb(opaque, addr + 1) << 16;
786
    v |= vga_mem_readb(opaque, addr + 2) << 8;
787
    v |= vga_mem_readb(opaque, addr + 3);
788
#else
789
    v = vga_mem_readb(opaque, addr);
790
    v |= vga_mem_readb(opaque, addr + 1) << 8;
791
    v |= vga_mem_readb(opaque, addr + 2) << 16;
792
    v |= vga_mem_readb(opaque, addr + 3) << 24;
793
#endif
794
    return v;
795
}
796

    
797
/* called for accesses between 0xa0000 and 0xc0000 */
798
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
799
{
800
    VGAState *s = opaque;
801
    int memory_map_mode, plane, write_mode, b, func_select, mask;
802
    uint32_t write_mask, bit_mask, set_mask;
803

    
804
#ifdef DEBUG_VGA_MEM
805
    printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
806
#endif
807
    /* convert to VGA memory offset */
808
    memory_map_mode = (s->gr[6] >> 2) & 3;
809
    addr &= 0x1ffff;
810
    switch(memory_map_mode) {
811
    case 0:
812
        break;
813
    case 1:
814
        if (addr >= 0x10000)
815
            return;
816
        addr += s->bank_offset;
817
        break;
818
    case 2:
819
        addr -= 0x10000;
820
        if (addr >= 0x8000)
821
            return;
822
        break;
823
    default:
824
    case 3:
825
        addr -= 0x18000;
826
        if (addr >= 0x8000)
827
            return;
828
        break;
829
    }
830

    
831
    if (s->sr[4] & 0x08) {
832
        /* chain 4 mode : simplest access */
833
        plane = addr & 3;
834
        mask = (1 << plane);
835
        if (s->sr[2] & mask) {
836
            s->vram_ptr[addr] = val;
837
#ifdef DEBUG_VGA_MEM
838
            printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
839
#endif
840
            s->plane_updated |= mask; /* only used to detect font change */
841
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
842
        }
843
    } else if (s->gr[5] & 0x10) {
844
        /* odd/even mode (aka text mode mapping) */
845
        plane = (s->gr[4] & 2) | (addr & 1);
846
        mask = (1 << plane);
847
        if (s->sr[2] & mask) {
848
            addr = ((addr & ~1) << 1) | plane;
849
            s->vram_ptr[addr] = val;
850
#ifdef DEBUG_VGA_MEM
851
            printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
852
#endif
853
            s->plane_updated |= mask; /* only used to detect font change */
854
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
855
        }
856
    } else {
857
        /* standard VGA latched access */
858
        write_mode = s->gr[5] & 3;
859
        switch(write_mode) {
860
        default:
861
        case 0:
862
            /* rotate */
863
            b = s->gr[3] & 7;
864
            val = ((val >> b) | (val << (8 - b))) & 0xff;
865
            val |= val << 8;
866
            val |= val << 16;
867

    
868
            /* apply set/reset mask */
869
            set_mask = mask16[s->gr[1]];
870
            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
871
            bit_mask = s->gr[8];
872
            break;
873
        case 1:
874
            val = s->latch;
875
            goto do_write;
876
        case 2:
877
            val = mask16[val & 0x0f];
878
            bit_mask = s->gr[8];
879
            break;
880
        case 3:
881
            /* rotate */
882
            b = s->gr[3] & 7;
883
            val = (val >> b) | (val << (8 - b));
884

    
885
            bit_mask = s->gr[8] & val;
886
            val = mask16[s->gr[0]];
887
            break;
888
        }
889

    
890
        /* apply logical operation */
891
        func_select = s->gr[3] >> 3;
892
        switch(func_select) {
893
        case 0:
894
        default:
895
            /* nothing to do */
896
            break;
897
        case 1:
898
            /* and */
899
            val &= s->latch;
900
            break;
901
        case 2:
902
            /* or */
903
            val |= s->latch;
904
            break;
905
        case 3:
906
            /* xor */
907
            val ^= s->latch;
908
            break;
909
        }
910

    
911
        /* apply bit mask */
912
        bit_mask |= bit_mask << 8;
913
        bit_mask |= bit_mask << 16;
914
        val = (val & bit_mask) | (s->latch & ~bit_mask);
915

    
916
    do_write:
917
        /* mask data according to sr[2] */
918
        mask = s->sr[2];
919
        s->plane_updated |= mask; /* only used to detect font change */
920
        write_mask = mask16[mask];
921
        ((uint32_t *)s->vram_ptr)[addr] =
922
            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
923
            (val & write_mask);
924
#ifdef DEBUG_VGA_MEM
925
        printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
926
               addr * 4, write_mask, val);
927
#endif
928
        cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
929
    }
930
}
931

    
932
static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
933
{
934
#ifdef TARGET_WORDS_BIGENDIAN
935
    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
936
    vga_mem_writeb(opaque, addr + 1, val & 0xff);
937
#else
938
    vga_mem_writeb(opaque, addr, val & 0xff);
939
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
940
#endif
941
}
942

    
943
static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
944
{
945
#ifdef TARGET_WORDS_BIGENDIAN
946
    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
947
    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
948
    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
949
    vga_mem_writeb(opaque, addr + 3, val & 0xff);
950
#else
951
    vga_mem_writeb(opaque, addr, val & 0xff);
952
    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
953
    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
954
    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
955
#endif
956
}
957

    
958
typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
959
                             const uint8_t *font_ptr, int h,
960
                             uint32_t fgcol, uint32_t bgcol);
961
typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
962
                                  const uint8_t *font_ptr, int h,
963
                                  uint32_t fgcol, uint32_t bgcol, int dup9);
964
typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
965
                                const uint8_t *s, int width);
966

    
967
#define DEPTH 8
968
#include "vga_template.h"
969

    
970
#define DEPTH 15
971
#include "vga_template.h"
972

    
973
#define BGR_FORMAT
974
#define DEPTH 15
975
#include "vga_template.h"
976

    
977
#define DEPTH 16
978
#include "vga_template.h"
979

    
980
#define BGR_FORMAT
981
#define DEPTH 16
982
#include "vga_template.h"
983

    
984
#define DEPTH 32
985
#include "vga_template.h"
986

    
987
#define BGR_FORMAT
988
#define DEPTH 32
989
#include "vga_template.h"
990

    
991
static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
992
{
993
    unsigned int col;
994
    col = rgb_to_pixel8(r, g, b);
995
    col |= col << 8;
996
    col |= col << 16;
997
    return col;
998
}
999

    
1000
static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
1001
{
1002
    unsigned int col;
1003
    col = rgb_to_pixel15(r, g, b);
1004
    col |= col << 16;
1005
    return col;
1006
}
1007

    
1008
static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
1009
                                          unsigned int b)
1010
{
1011
    unsigned int col;
1012
    col = rgb_to_pixel15bgr(r, g, b);
1013
    col |= col << 16;
1014
    return col;
1015
}
1016

    
1017
static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1018
{
1019
    unsigned int col;
1020
    col = rgb_to_pixel16(r, g, b);
1021
    col |= col << 16;
1022
    return col;
1023
}
1024

    
1025
static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1026
                                          unsigned int b)
1027
{
1028
    unsigned int col;
1029
    col = rgb_to_pixel16bgr(r, g, b);
1030
    col |= col << 16;
1031
    return col;
1032
}
1033

    
1034
static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1035
{
1036
    unsigned int col;
1037
    col = rgb_to_pixel32(r, g, b);
1038
    return col;
1039
}
1040

    
1041
static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1042
{
1043
    unsigned int col;
1044
    col = rgb_to_pixel32bgr(r, g, b);
1045
    return col;
1046
}
1047

    
1048
/* return true if the palette was modified */
1049
static int update_palette16(VGAState *s)
1050
{
1051
    int full_update, i;
1052
    uint32_t v, col, *palette;
1053

    
1054
    full_update = 0;
1055
    palette = s->last_palette;
1056
    for(i = 0; i < 16; i++) {
1057
        v = s->ar[i];
1058
        if (s->ar[0x10] & 0x80)
1059
            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1060
        else
1061
            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1062
        v = v * 3;
1063
        col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1064
                              c6_to_8(s->palette[v + 1]),
1065
                              c6_to_8(s->palette[v + 2]));
1066
        if (col != palette[i]) {
1067
            full_update = 1;
1068
            palette[i] = col;
1069
        }
1070
    }
1071
    return full_update;
1072
}
1073

    
1074
/* return true if the palette was modified */
1075
static int update_palette256(VGAState *s)
1076
{
1077
    int full_update, i;
1078
    uint32_t v, col, *palette;
1079

    
1080
    full_update = 0;
1081
    palette = s->last_palette;
1082
    v = 0;
1083
    for(i = 0; i < 256; i++) {
1084
        if (s->dac_8bit) {
1085
          col = s->rgb_to_pixel(s->palette[v],
1086
                                s->palette[v + 1],
1087
                                s->palette[v + 2]);
1088
        } else {
1089
          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1090
                                c6_to_8(s->palette[v + 1]),
1091
                                c6_to_8(s->palette[v + 2]));
1092
        }
1093
        if (col != palette[i]) {
1094
            full_update = 1;
1095
            palette[i] = col;
1096
        }
1097
        v += 3;
1098
    }
1099
    return full_update;
1100
}
1101

    
1102
static void vga_get_offsets(VGAState *s,
1103
                            uint32_t *pline_offset,
1104
                            uint32_t *pstart_addr,
1105
                            uint32_t *pline_compare)
1106
{
1107
    uint32_t start_addr, line_offset, line_compare;
1108
#ifdef CONFIG_BOCHS_VBE
1109
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1110
        line_offset = s->vbe_line_offset;
1111
        start_addr = s->vbe_start_addr;
1112
        line_compare = 65535;
1113
    } else
1114
#endif
1115
    {
1116
        /* compute line_offset in bytes */
1117
        line_offset = s->cr[0x13];
1118
        line_offset <<= 3;
1119

    
1120
        /* starting address */
1121
        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1122

    
1123
        /* line compare */
1124
        line_compare = s->cr[0x18] |
1125
            ((s->cr[0x07] & 0x10) << 4) |
1126
            ((s->cr[0x09] & 0x40) << 3);
1127
    }
1128
    *pline_offset = line_offset;
1129
    *pstart_addr = start_addr;
1130
    *pline_compare = line_compare;
1131
}
1132

    
1133
/* update start_addr and line_offset. Return TRUE if modified */
1134
static int update_basic_params(VGAState *s)
1135
{
1136
    int full_update;
1137
    uint32_t start_addr, line_offset, line_compare;
1138

    
1139
    full_update = 0;
1140

    
1141
    s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1142

    
1143
    if (line_offset != s->line_offset ||
1144
        start_addr != s->start_addr ||
1145
        line_compare != s->line_compare) {
1146
        s->line_offset = line_offset;
1147
        s->start_addr = start_addr;
1148
        s->line_compare = line_compare;
1149
        full_update = 1;
1150
    }
1151
    return full_update;
1152
}
1153

    
1154
#define NB_DEPTHS 7
1155

    
1156
static inline int get_depth_index(DisplayState *s)
1157
{
1158
    switch(ds_get_bits_per_pixel(s)) {
1159
    default:
1160
    case 8:
1161
        return 0;
1162
    case 15:
1163
        return 1;
1164
    case 16:
1165
        return 2;
1166
    case 32:
1167
        if (is_surface_bgr(s->surface))
1168
            return 4;
1169
        else
1170
            return 3;
1171
    }
1172
}
1173

    
1174
static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1175
    vga_draw_glyph8_8,
1176
    vga_draw_glyph8_16,
1177
    vga_draw_glyph8_16,
1178
    vga_draw_glyph8_32,
1179
    vga_draw_glyph8_32,
1180
    vga_draw_glyph8_16,
1181
    vga_draw_glyph8_16,
1182
};
1183

    
1184
static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1185
    vga_draw_glyph16_8,
1186
    vga_draw_glyph16_16,
1187
    vga_draw_glyph16_16,
1188
    vga_draw_glyph16_32,
1189
    vga_draw_glyph16_32,
1190
    vga_draw_glyph16_16,
1191
    vga_draw_glyph16_16,
1192
};
1193

    
1194
static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1195
    vga_draw_glyph9_8,
1196
    vga_draw_glyph9_16,
1197
    vga_draw_glyph9_16,
1198
    vga_draw_glyph9_32,
1199
    vga_draw_glyph9_32,
1200
    vga_draw_glyph9_16,
1201
    vga_draw_glyph9_16,
1202
};
1203

    
1204
static const uint8_t cursor_glyph[32 * 4] = {
1205
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1206
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1207
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1208
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1209
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1210
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1211
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1212
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1213
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1214
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1215
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1216
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1217
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1218
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1219
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1220
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1221
};
1222

    
1223
static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight,
1224
                                    int *pcwidth, int *pcheight)
1225
{
1226
    int width, cwidth, height, cheight;
1227

    
1228
    /* total width & height */
1229
    cheight = (s->cr[9] & 0x1f) + 1;
1230
    cwidth = 8;
1231
    if (!(s->sr[1] & 0x01))
1232
        cwidth = 9;
1233
    if (s->sr[1] & 0x08)
1234
        cwidth = 16; /* NOTE: no 18 pixel wide */
1235
    width = (s->cr[0x01] + 1);
1236
    if (s->cr[0x06] == 100) {
1237
        /* ugly hack for CGA 160x100x16 - explain me the logic */
1238
        height = 100;
1239
    } else {
1240
        height = s->cr[0x12] |
1241
            ((s->cr[0x07] & 0x02) << 7) |
1242
            ((s->cr[0x07] & 0x40) << 3);
1243
        height = (height + 1) / cheight;
1244
    }
1245

    
1246
    *pwidth = width;
1247
    *pheight = height;
1248
    *pcwidth = cwidth;
1249
    *pcheight = cheight;
1250
}
1251

    
1252
typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1253

    
1254
static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1255
    rgb_to_pixel8_dup,
1256
    rgb_to_pixel15_dup,
1257
    rgb_to_pixel16_dup,
1258
    rgb_to_pixel32_dup,
1259
    rgb_to_pixel32bgr_dup,
1260
    rgb_to_pixel15bgr_dup,
1261
    rgb_to_pixel16bgr_dup,
1262
};
1263

    
1264
/*
1265
 * Text mode update
1266
 * Missing:
1267
 * - double scan
1268
 * - double width
1269
 * - underline
1270
 * - flashing
1271
 */
1272
static void vga_draw_text(VGAState *s, int full_update)
1273
{
1274
    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1275
    int cx_min, cx_max, linesize, x_incr;
1276
    uint32_t offset, fgcol, bgcol, v, cursor_offset;
1277
    uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1278
    const uint8_t *font_ptr, *font_base[2];
1279
    int dup9, line_offset, depth_index;
1280
    uint32_t *palette;
1281
    uint32_t *ch_attr_ptr;
1282
    vga_draw_glyph8_func *vga_draw_glyph8;
1283
    vga_draw_glyph9_func *vga_draw_glyph9;
1284

    
1285
    /* compute font data address (in plane 2) */
1286
    v = s->sr[3];
1287
    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1288
    if (offset != s->font_offsets[0]) {
1289
        s->font_offsets[0] = offset;
1290
        full_update = 1;
1291
    }
1292
    font_base[0] = s->vram_ptr + offset;
1293

    
1294
    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1295
    font_base[1] = s->vram_ptr + offset;
1296
    if (offset != s->font_offsets[1]) {
1297
        s->font_offsets[1] = offset;
1298
        full_update = 1;
1299
    }
1300
    if (s->plane_updated & (1 << 2)) {
1301
        /* if the plane 2 was modified since the last display, it
1302
           indicates the font may have been modified */
1303
        s->plane_updated = 0;
1304
        full_update = 1;
1305
    }
1306
    full_update |= update_basic_params(s);
1307

    
1308
    line_offset = s->line_offset;
1309
    s1 = s->vram_ptr + (s->start_addr * 4);
1310

    
1311
    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1312
    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1313
    if ((height * width) > CH_ATTR_SIZE) {
1314
        /* better than nothing: exit if transient size is too big */
1315
        return;
1316
    }
1317

    
1318
    if (width != s->last_width || height != s->last_height ||
1319
        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1320
        s->last_scr_width = width * cw;
1321
        s->last_scr_height = height * cheight;
1322
        qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1323
        s->last_depth = 0;
1324
        s->last_width = width;
1325
        s->last_height = height;
1326
        s->last_ch = cheight;
1327
        s->last_cw = cw;
1328
        full_update = 1;
1329
    }
1330
    s->rgb_to_pixel =
1331
        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1332
    full_update |= update_palette16(s);
1333
    palette = s->last_palette;
1334
    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1335

    
1336
    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1337
    if (cursor_offset != s->cursor_offset ||
1338
        s->cr[0xa] != s->cursor_start ||
1339
        s->cr[0xb] != s->cursor_end) {
1340
      /* if the cursor position changed, we update the old and new
1341
         chars */
1342
        if (s->cursor_offset < CH_ATTR_SIZE)
1343
            s->last_ch_attr[s->cursor_offset] = -1;
1344
        if (cursor_offset < CH_ATTR_SIZE)
1345
            s->last_ch_attr[cursor_offset] = -1;
1346
        s->cursor_offset = cursor_offset;
1347
        s->cursor_start = s->cr[0xa];
1348
        s->cursor_end = s->cr[0xb];
1349
    }
1350
    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1351

    
1352
    depth_index = get_depth_index(s->ds);
1353
    if (cw == 16)
1354
        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1355
    else
1356
        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1357
    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1358

    
1359
    dest = ds_get_data(s->ds);
1360
    linesize = ds_get_linesize(s->ds);
1361
    ch_attr_ptr = s->last_ch_attr;
1362
    for(cy = 0; cy < height; cy++) {
1363
        d1 = dest;
1364
        src = s1;
1365
        cx_min = width;
1366
        cx_max = -1;
1367
        for(cx = 0; cx < width; cx++) {
1368
            ch_attr = *(uint16_t *)src;
1369
            if (full_update || ch_attr != *ch_attr_ptr) {
1370
                if (cx < cx_min)
1371
                    cx_min = cx;
1372
                if (cx > cx_max)
1373
                    cx_max = cx;
1374
                *ch_attr_ptr = ch_attr;
1375
#ifdef HOST_WORDS_BIGENDIAN
1376
                ch = ch_attr >> 8;
1377
                cattr = ch_attr & 0xff;
1378
#else
1379
                ch = ch_attr & 0xff;
1380
                cattr = ch_attr >> 8;
1381
#endif
1382
                font_ptr = font_base[(cattr >> 3) & 1];
1383
                font_ptr += 32 * 4 * ch;
1384
                bgcol = palette[cattr >> 4];
1385
                fgcol = palette[cattr & 0x0f];
1386
                if (cw != 9) {
1387
                    vga_draw_glyph8(d1, linesize,
1388
                                    font_ptr, cheight, fgcol, bgcol);
1389
                } else {
1390
                    dup9 = 0;
1391
                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1392
                        dup9 = 1;
1393
                    vga_draw_glyph9(d1, linesize,
1394
                                    font_ptr, cheight, fgcol, bgcol, dup9);
1395
                }
1396
                if (src == cursor_ptr &&
1397
                    !(s->cr[0x0a] & 0x20)) {
1398
                    int line_start, line_last, h;
1399
                    /* draw the cursor */
1400
                    line_start = s->cr[0x0a] & 0x1f;
1401
                    line_last = s->cr[0x0b] & 0x1f;
1402
                    /* XXX: check that */
1403
                    if (line_last > cheight - 1)
1404
                        line_last = cheight - 1;
1405
                    if (line_last >= line_start && line_start < cheight) {
1406
                        h = line_last - line_start + 1;
1407
                        d = d1 + linesize * line_start;
1408
                        if (cw != 9) {
1409
                            vga_draw_glyph8(d, linesize,
1410
                                            cursor_glyph, h, fgcol, bgcol);
1411
                        } else {
1412
                            vga_draw_glyph9(d, linesize,
1413
                                            cursor_glyph, h, fgcol, bgcol, 1);
1414
                        }
1415
                    }
1416
                }
1417
            }
1418
            d1 += x_incr;
1419
            src += 4;
1420
            ch_attr_ptr++;
1421
        }
1422
        if (cx_max != -1) {
1423
            dpy_update(s->ds, cx_min * cw, cy * cheight,
1424
                       (cx_max - cx_min + 1) * cw, cheight);
1425
        }
1426
        dest += linesize * cheight;
1427
        s1 += line_offset;
1428
    }
1429
}
1430

    
1431
enum {
1432
    VGA_DRAW_LINE2,
1433
    VGA_DRAW_LINE2D2,
1434
    VGA_DRAW_LINE4,
1435
    VGA_DRAW_LINE4D2,
1436
    VGA_DRAW_LINE8D2,
1437
    VGA_DRAW_LINE8,
1438
    VGA_DRAW_LINE15,
1439
    VGA_DRAW_LINE16,
1440
    VGA_DRAW_LINE24,
1441
    VGA_DRAW_LINE32,
1442
    VGA_DRAW_LINE_NB,
1443
};
1444

    
1445
static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1446
    vga_draw_line2_8,
1447
    vga_draw_line2_16,
1448
    vga_draw_line2_16,
1449
    vga_draw_line2_32,
1450
    vga_draw_line2_32,
1451
    vga_draw_line2_16,
1452
    vga_draw_line2_16,
1453

    
1454
    vga_draw_line2d2_8,
1455
    vga_draw_line2d2_16,
1456
    vga_draw_line2d2_16,
1457
    vga_draw_line2d2_32,
1458
    vga_draw_line2d2_32,
1459
    vga_draw_line2d2_16,
1460
    vga_draw_line2d2_16,
1461

    
1462
    vga_draw_line4_8,
1463
    vga_draw_line4_16,
1464
    vga_draw_line4_16,
1465
    vga_draw_line4_32,
1466
    vga_draw_line4_32,
1467
    vga_draw_line4_16,
1468
    vga_draw_line4_16,
1469

    
1470
    vga_draw_line4d2_8,
1471
    vga_draw_line4d2_16,
1472
    vga_draw_line4d2_16,
1473
    vga_draw_line4d2_32,
1474
    vga_draw_line4d2_32,
1475
    vga_draw_line4d2_16,
1476
    vga_draw_line4d2_16,
1477

    
1478
    vga_draw_line8d2_8,
1479
    vga_draw_line8d2_16,
1480
    vga_draw_line8d2_16,
1481
    vga_draw_line8d2_32,
1482
    vga_draw_line8d2_32,
1483
    vga_draw_line8d2_16,
1484
    vga_draw_line8d2_16,
1485

    
1486
    vga_draw_line8_8,
1487
    vga_draw_line8_16,
1488
    vga_draw_line8_16,
1489
    vga_draw_line8_32,
1490
    vga_draw_line8_32,
1491
    vga_draw_line8_16,
1492
    vga_draw_line8_16,
1493

    
1494
    vga_draw_line15_8,
1495
    vga_draw_line15_15,
1496
    vga_draw_line15_16,
1497
    vga_draw_line15_32,
1498
    vga_draw_line15_32bgr,
1499
    vga_draw_line15_15bgr,
1500
    vga_draw_line15_16bgr,
1501

    
1502
    vga_draw_line16_8,
1503
    vga_draw_line16_15,
1504
    vga_draw_line16_16,
1505
    vga_draw_line16_32,
1506
    vga_draw_line16_32bgr,
1507
    vga_draw_line16_15bgr,
1508
    vga_draw_line16_16bgr,
1509

    
1510
    vga_draw_line24_8,
1511
    vga_draw_line24_15,
1512
    vga_draw_line24_16,
1513
    vga_draw_line24_32,
1514
    vga_draw_line24_32bgr,
1515
    vga_draw_line24_15bgr,
1516
    vga_draw_line24_16bgr,
1517

    
1518
    vga_draw_line32_8,
1519
    vga_draw_line32_15,
1520
    vga_draw_line32_16,
1521
    vga_draw_line32_32,
1522
    vga_draw_line32_32bgr,
1523
    vga_draw_line32_15bgr,
1524
    vga_draw_line32_16bgr,
1525
};
1526

    
1527
static int vga_get_bpp(VGAState *s)
1528
{
1529
    int ret;
1530
#ifdef CONFIG_BOCHS_VBE
1531
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1532
        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1533
    } else
1534
#endif
1535
    {
1536
        ret = 0;
1537
    }
1538
    return ret;
1539
}
1540

    
1541
static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1542
{
1543
    int width, height;
1544

    
1545
#ifdef CONFIG_BOCHS_VBE
1546
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1547
        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1548
        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1549
    } else
1550
#endif
1551
    {
1552
        width = (s->cr[0x01] + 1) * 8;
1553
        height = s->cr[0x12] |
1554
            ((s->cr[0x07] & 0x02) << 7) |
1555
            ((s->cr[0x07] & 0x40) << 3);
1556
        height = (height + 1);
1557
    }
1558
    *pwidth = width;
1559
    *pheight = height;
1560
}
1561

    
1562
void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1563
{
1564
    int y;
1565
    if (y1 >= VGA_MAX_HEIGHT)
1566
        return;
1567
    if (y2 >= VGA_MAX_HEIGHT)
1568
        y2 = VGA_MAX_HEIGHT;
1569
    for(y = y1; y < y2; y++) {
1570
        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1571
    }
1572
}
1573

    
1574
static void vga_sync_dirty_bitmap(VGAState *s)
1575
{
1576
    if (s->map_addr)
1577
        cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1578

    
1579
    if (s->lfb_vram_mapped) {
1580
        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1581
        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1582
    }
1583
}
1584

    
1585
/*
1586
 * graphic modes
1587
 */
1588
static void vga_draw_graphic(VGAState *s, int full_update)
1589
{
1590
    int y1, y, update, linesize, y_start, double_scan, mask, depth;
1591
    int width, height, shift_control, line_offset, bwidth, bits;
1592
    ram_addr_t page0, page1, page_min, page_max;
1593
    int disp_width, multi_scan, multi_run;
1594
    uint8_t *d;
1595
    uint32_t v, addr1, addr;
1596
    vga_draw_line_func *vga_draw_line;
1597

    
1598
    full_update |= update_basic_params(s);
1599

    
1600
    if (!full_update)
1601
        vga_sync_dirty_bitmap(s);
1602

    
1603
    s->get_resolution(s, &width, &height);
1604
    disp_width = width;
1605

    
1606
    shift_control = (s->gr[0x05] >> 5) & 3;
1607
    double_scan = (s->cr[0x09] >> 7);
1608
    if (shift_control != 1) {
1609
        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1610
    } else {
1611
        /* in CGA modes, multi_scan is ignored */
1612
        /* XXX: is it correct ? */
1613
        multi_scan = double_scan;
1614
    }
1615
    multi_run = multi_scan;
1616
    if (shift_control != s->shift_control ||
1617
        double_scan != s->double_scan) {
1618
        full_update = 1;
1619
        s->shift_control = shift_control;
1620
        s->double_scan = double_scan;
1621
    }
1622

    
1623
    if (shift_control == 0) {
1624
        if (s->sr[0x01] & 8) {
1625
            disp_width <<= 1;
1626
        }
1627
    } else if (shift_control == 1) {
1628
        if (s->sr[0x01] & 8) {
1629
            disp_width <<= 1;
1630
        }
1631
    }
1632

    
1633
    depth = s->get_bpp(s);
1634
    if (s->line_offset != s->last_line_offset ||
1635
        disp_width != s->last_width ||
1636
        height != s->last_height ||
1637
        s->last_depth != depth) {
1638
#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1639
        if (depth == 16 || depth == 32) {
1640
#else
1641
        if (depth == 32) {
1642
#endif
1643
            qemu_free_displaysurface(s->ds);
1644
            s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1645
                    s->line_offset,
1646
                    s->vram_ptr + (s->start_addr * 4));
1647
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1648
            s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1649
#endif
1650
            dpy_resize(s->ds);
1651
        } else {
1652
            qemu_console_resize(s->ds, disp_width, height);
1653
        }
1654
        s->last_scr_width = disp_width;
1655
        s->last_scr_height = height;
1656
        s->last_width = disp_width;
1657
        s->last_height = height;
1658
        s->last_line_offset = s->line_offset;
1659
        s->last_depth = depth;
1660
        full_update = 1;
1661
    } else if (is_buffer_shared(s->ds->surface) &&
1662
               (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1663
        s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1664
        dpy_setdata(s->ds);
1665
    }
1666

    
1667
    s->rgb_to_pixel =
1668
        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1669

    
1670
    if (shift_control == 0) {
1671
        full_update |= update_palette16(s);
1672
        if (s->sr[0x01] & 8) {
1673
            v = VGA_DRAW_LINE4D2;
1674
        } else {
1675
            v = VGA_DRAW_LINE4;
1676
        }
1677
        bits = 4;
1678
    } else if (shift_control == 1) {
1679
        full_update |= update_palette16(s);
1680
        if (s->sr[0x01] & 8) {
1681
            v = VGA_DRAW_LINE2D2;
1682
        } else {
1683
            v = VGA_DRAW_LINE2;
1684
        }
1685
        bits = 4;
1686
    } else {
1687
        switch(s->get_bpp(s)) {
1688
        default:
1689
        case 0:
1690
            full_update |= update_palette256(s);
1691
            v = VGA_DRAW_LINE8D2;
1692
            bits = 4;
1693
            break;
1694
        case 8:
1695
            full_update |= update_palette256(s);
1696
            v = VGA_DRAW_LINE8;
1697
            bits = 8;
1698
            break;
1699
        case 15:
1700
            v = VGA_DRAW_LINE15;
1701
            bits = 16;
1702
            break;
1703
        case 16:
1704
            v = VGA_DRAW_LINE16;
1705
            bits = 16;
1706
            break;
1707
        case 24:
1708
            v = VGA_DRAW_LINE24;
1709
            bits = 24;
1710
            break;
1711
        case 32:
1712
            v = VGA_DRAW_LINE32;
1713
            bits = 32;
1714
            break;
1715
        }
1716
    }
1717
    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1718

    
1719
    if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1720
        s->cursor_invalidate(s);
1721

    
1722
    line_offset = s->line_offset;
1723
#if 0
1724
    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",
1725
           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1726
#endif
1727
    addr1 = (s->start_addr * 4);
1728
    bwidth = (width * bits + 7) / 8;
1729
    y_start = -1;
1730
    page_min = -1;
1731
    page_max = 0;
1732
    d = ds_get_data(s->ds);
1733
    linesize = ds_get_linesize(s->ds);
1734
    y1 = 0;
1735
    for(y = 0; y < height; y++) {
1736
        addr = addr1;
1737
        if (!(s->cr[0x17] & 1)) {
1738
            int shift;
1739
            /* CGA compatibility handling */
1740
            shift = 14 + ((s->cr[0x17] >> 6) & 1);
1741
            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1742
        }
1743
        if (!(s->cr[0x17] & 2)) {
1744
            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1745
        }
1746
        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1747
        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1748
        update = full_update |
1749
            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1750
            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1751
        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1752
            /* if wide line, can use another page */
1753
            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1754
                                                    VGA_DIRTY_FLAG);
1755
        }
1756
        /* explicit invalidation for the hardware cursor */
1757
        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1758
        if (update) {
1759
            if (y_start < 0)
1760
                y_start = y;
1761
            if (page0 < page_min)
1762
                page_min = page0;
1763
            if (page1 > page_max)
1764
                page_max = page1;
1765
            if (!(is_buffer_shared(s->ds->surface))) {
1766
                vga_draw_line(s, d, s->vram_ptr + addr, width);
1767
                if (s->cursor_draw_line)
1768
                    s->cursor_draw_line(s, d, y);
1769
            }
1770
        } else {
1771
            if (y_start >= 0) {
1772
                /* flush to display */
1773
                dpy_update(s->ds, 0, y_start,
1774
                           disp_width, y - y_start);
1775
                y_start = -1;
1776
            }
1777
        }
1778
        if (!multi_run) {
1779
            mask = (s->cr[0x17] & 3) ^ 3;
1780
            if ((y1 & mask) == mask)
1781
                addr1 += line_offset;
1782
            y1++;
1783
            multi_run = multi_scan;
1784
        } else {
1785
            multi_run--;
1786
        }
1787
        /* line compare acts on the displayed lines */
1788
        if (y == s->line_compare)
1789
            addr1 = 0;
1790
        d += linesize;
1791
    }
1792
    if (y_start >= 0) {
1793
        /* flush to display */
1794
        dpy_update(s->ds, 0, y_start,
1795
                   disp_width, y - y_start);
1796
    }
1797
    /* reset modified pages */
1798
    if (page_max >= page_min) {
1799
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1800
                                        VGA_DIRTY_FLAG);
1801
    }
1802
    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1803
}
1804

    
1805
static void vga_draw_blank(VGAState *s, int full_update)
1806
{
1807
    int i, w, val;
1808
    uint8_t *d;
1809

    
1810
    if (!full_update)
1811
        return;
1812
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1813
        return;
1814

    
1815
    s->rgb_to_pixel =
1816
        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1817
    if (ds_get_bits_per_pixel(s->ds) == 8)
1818
        val = s->rgb_to_pixel(0, 0, 0);
1819
    else
1820
        val = 0;
1821
    w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1822
    d = ds_get_data(s->ds);
1823
    for(i = 0; i < s->last_scr_height; i++) {
1824
        memset(d, val, w);
1825
        d += ds_get_linesize(s->ds);
1826
    }
1827
    dpy_update(s->ds, 0, 0,
1828
               s->last_scr_width, s->last_scr_height);
1829
}
1830

    
1831
#define GMODE_TEXT     0
1832
#define GMODE_GRAPH    1
1833
#define GMODE_BLANK 2
1834

    
1835
static void vga_update_display(void *opaque)
1836
{
1837
    VGAState *s = opaque;
1838
    int full_update, graphic_mode;
1839

    
1840
    if (ds_get_bits_per_pixel(s->ds) == 0) {
1841
        /* nothing to do */
1842
    } else {
1843
        full_update = s->full_update;
1844
        s->full_update = 0;
1845
        if (!(s->ar_index & 0x20)) {
1846
            graphic_mode = GMODE_BLANK;
1847
        } else {
1848
            graphic_mode = s->gr[6] & 1;
1849
        }
1850
        if (graphic_mode != s->graphic_mode) {
1851
            s->graphic_mode = graphic_mode;
1852
            full_update = 1;
1853
        }
1854
        switch(graphic_mode) {
1855
        case GMODE_TEXT:
1856
            vga_draw_text(s, full_update);
1857
            break;
1858
        case GMODE_GRAPH:
1859
            vga_draw_graphic(s, full_update);
1860
            break;
1861
        case GMODE_BLANK:
1862
        default:
1863
            vga_draw_blank(s, full_update);
1864
            break;
1865
        }
1866
    }
1867
}
1868

    
1869
/* force a full display refresh */
1870
static void vga_invalidate_display(void *opaque)
1871
{
1872
    VGAState *s = opaque;
1873

    
1874
    s->full_update = 1;
1875
}
1876

    
1877
void vga_common_reset(VGACommonState *s)
1878
{
1879
    s->lfb_addr = 0;
1880
    s->lfb_end = 0;
1881
    s->map_addr = 0;
1882
    s->map_end = 0;
1883
    s->lfb_vram_mapped = 0;
1884
    s->bios_offset = 0;
1885
    s->bios_size = 0;
1886
    s->sr_index = 0;
1887
    memset(s->sr, '\0', sizeof(s->sr));
1888
    s->gr_index = 0;
1889
    memset(s->gr, '\0', sizeof(s->gr));
1890
    s->ar_index = 0;
1891
    memset(s->ar, '\0', sizeof(s->ar));
1892
    s->ar_flip_flop = 0;
1893
    s->cr_index = 0;
1894
    memset(s->cr, '\0', sizeof(s->cr));
1895
    s->msr = 0;
1896
    s->fcr = 0;
1897
    s->st00 = 0;
1898
    s->st01 = 0;
1899
    s->dac_state = 0;
1900
    s->dac_sub_index = 0;
1901
    s->dac_read_index = 0;
1902
    s->dac_write_index = 0;
1903
    memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1904
    s->dac_8bit = 0;
1905
    memset(s->palette, '\0', sizeof(s->palette));
1906
    s->bank_offset = 0;
1907
#ifdef CONFIG_BOCHS_VBE
1908
    s->vbe_index = 0;
1909
    memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1910
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1911
    s->vbe_start_addr = 0;
1912
    s->vbe_line_offset = 0;
1913
    s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1914
#endif
1915
    memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1916
    s->graphic_mode = -1; /* force full update */
1917
    s->shift_control = 0;
1918
    s->double_scan = 0;
1919
    s->line_offset = 0;
1920
    s->line_compare = 0;
1921
    s->start_addr = 0;
1922
    s->plane_updated = 0;
1923
    s->last_cw = 0;
1924
    s->last_ch = 0;
1925
    s->last_width = 0;
1926
    s->last_height = 0;
1927
    s->last_scr_width = 0;
1928
    s->last_scr_height = 0;
1929
    s->cursor_start = 0;
1930
    s->cursor_end = 0;
1931
    s->cursor_offset = 0;
1932
    memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1933
    memset(s->last_palette, '\0', sizeof(s->last_palette));
1934
    memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1935
    switch (vga_retrace_method) {
1936
    case VGA_RETRACE_DUMB:
1937
        break;
1938
    case VGA_RETRACE_PRECISE:
1939
        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1940
        break;
1941
    }
1942
}
1943

    
1944
static void vga_reset(void *opaque)
1945
{
1946
    VGAState *s =  opaque;
1947
    vga_common_reset(s);
1948
}
1949

    
1950
#define TEXTMODE_X(x)        ((x) % width)
1951
#define TEXTMODE_Y(x)        ((x) / width)
1952
#define VMEM2CHTYPE(v)        ((v & 0xff0007ff) | \
1953
        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1954
/* relay text rendering to the display driver
1955
 * instead of doing a full vga_update_display() */
1956
static void vga_update_text(void *opaque, console_ch_t *chardata)
1957
{
1958
    VGAState *s =  opaque;
1959
    int graphic_mode, i, cursor_offset, cursor_visible;
1960
    int cw, cheight, width, height, size, c_min, c_max;
1961
    uint32_t *src;
1962
    console_ch_t *dst, val;
1963
    char msg_buffer[80];
1964
    int full_update = 0;
1965

    
1966
    if (!(s->ar_index & 0x20)) {
1967
        graphic_mode = GMODE_BLANK;
1968
    } else {
1969
        graphic_mode = s->gr[6] & 1;
1970
    }
1971
    if (graphic_mode != s->graphic_mode) {
1972
        s->graphic_mode = graphic_mode;
1973
        full_update = 1;
1974
    }
1975
    if (s->last_width == -1) {
1976
        s->last_width = 0;
1977
        full_update = 1;
1978
    }
1979

    
1980
    switch (graphic_mode) {
1981
    case GMODE_TEXT:
1982
        /* TODO: update palette */
1983
        full_update |= update_basic_params(s);
1984

    
1985
        /* total width & height */
1986
        cheight = (s->cr[9] & 0x1f) + 1;
1987
        cw = 8;
1988
        if (!(s->sr[1] & 0x01))
1989
            cw = 9;
1990
        if (s->sr[1] & 0x08)
1991
            cw = 16; /* NOTE: no 18 pixel wide */
1992
        width = (s->cr[0x01] + 1);
1993
        if (s->cr[0x06] == 100) {
1994
            /* ugly hack for CGA 160x100x16 - explain me the logic */
1995
            height = 100;
1996
        } else {
1997
            height = s->cr[0x12] | 
1998
                ((s->cr[0x07] & 0x02) << 7) | 
1999
                ((s->cr[0x07] & 0x40) << 3);
2000
            height = (height + 1) / cheight;
2001
        }
2002

    
2003
        size = (height * width);
2004
        if (size > CH_ATTR_SIZE) {
2005
            if (!full_update)
2006
                return;
2007

    
2008
            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2009
                     width, height);
2010
            break;
2011
        }
2012

    
2013
        if (width != s->last_width || height != s->last_height ||
2014
            cw != s->last_cw || cheight != s->last_ch) {
2015
            s->last_scr_width = width * cw;
2016
            s->last_scr_height = height * cheight;
2017
            s->ds->surface->width = width;
2018
            s->ds->surface->height = height;
2019
            dpy_resize(s->ds);
2020
            s->last_width = width;
2021
            s->last_height = height;
2022
            s->last_ch = cheight;
2023
            s->last_cw = cw;
2024
            full_update = 1;
2025
        }
2026

    
2027
        /* Update "hardware" cursor */
2028
        cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2029
        if (cursor_offset != s->cursor_offset ||
2030
            s->cr[0xa] != s->cursor_start ||
2031
            s->cr[0xb] != s->cursor_end || full_update) {
2032
            cursor_visible = !(s->cr[0xa] & 0x20);
2033
            if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2034
                dpy_cursor(s->ds,
2035
                           TEXTMODE_X(cursor_offset),
2036
                           TEXTMODE_Y(cursor_offset));
2037
            else
2038
                dpy_cursor(s->ds, -1, -1);
2039
            s->cursor_offset = cursor_offset;
2040
            s->cursor_start = s->cr[0xa];
2041
            s->cursor_end = s->cr[0xb];
2042
        }
2043

    
2044
        src = (uint32_t *) s->vram_ptr + s->start_addr;
2045
        dst = chardata;
2046

    
2047
        if (full_update) {
2048
            for (i = 0; i < size; src ++, dst ++, i ++)
2049
                console_write_ch(dst, VMEM2CHTYPE(*src));
2050

    
2051
            dpy_update(s->ds, 0, 0, width, height);
2052
        } else {
2053
            c_max = 0;
2054

    
2055
            for (i = 0; i < size; src ++, dst ++, i ++) {
2056
                console_write_ch(&val, VMEM2CHTYPE(*src));
2057
                if (*dst != val) {
2058
                    *dst = val;
2059
                    c_max = i;
2060
                    break;
2061
                }
2062
            }
2063
            c_min = i;
2064
            for (; i < size; src ++, dst ++, i ++) {
2065
                console_write_ch(&val, VMEM2CHTYPE(*src));
2066
                if (*dst != val) {
2067
                    *dst = val;
2068
                    c_max = i;
2069
                }
2070
            }
2071

    
2072
            if (c_min <= c_max) {
2073
                i = TEXTMODE_Y(c_min);
2074
                dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2075
            }
2076
        }
2077

    
2078
        return;
2079
    case GMODE_GRAPH:
2080
        if (!full_update)
2081
            return;
2082

    
2083
        s->get_resolution(s, &width, &height);
2084
        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2085
                 width, height);
2086
        break;
2087
    case GMODE_BLANK:
2088
    default:
2089
        if (!full_update)
2090
            return;
2091

    
2092
        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2093
        break;
2094
    }
2095

    
2096
    /* Display a message */
2097
    s->last_width = 60;
2098
    s->last_height = height = 3;
2099
    dpy_cursor(s->ds, -1, -1);
2100
    s->ds->surface->width = s->last_width;
2101
    s->ds->surface->height = height;
2102
    dpy_resize(s->ds);
2103

    
2104
    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2105
        console_write_ch(dst ++, ' ');
2106

    
2107
    size = strlen(msg_buffer);
2108
    width = (s->last_width - size) / 2;
2109
    dst = chardata + s->last_width + width;
2110
    for (i = 0; i < size; i ++)
2111
        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2112

    
2113
    dpy_update(s->ds, 0, 0, s->last_width, height);
2114
}
2115

    
2116
static CPUReadMemoryFunc * const vga_mem_read[3] = {
2117
    vga_mem_readb,
2118
    vga_mem_readw,
2119
    vga_mem_readl,
2120
};
2121

    
2122
static CPUWriteMemoryFunc * const vga_mem_write[3] = {
2123
    vga_mem_writeb,
2124
    vga_mem_writew,
2125
    vga_mem_writel,
2126
};
2127

    
2128
void vga_common_save(QEMUFile *f, void *opaque)
2129
{
2130
    VGACommonState *s = opaque;
2131
    int i;
2132

    
2133
    qemu_put_be32s(f, &s->latch);
2134
    qemu_put_8s(f, &s->sr_index);
2135
    qemu_put_buffer(f, s->sr, 8);
2136
    qemu_put_8s(f, &s->gr_index);
2137
    qemu_put_buffer(f, s->gr, 16);
2138
    qemu_put_8s(f, &s->ar_index);
2139
    qemu_put_buffer(f, s->ar, 21);
2140
    qemu_put_be32(f, s->ar_flip_flop);
2141
    qemu_put_8s(f, &s->cr_index);
2142
    qemu_put_buffer(f, s->cr, 256);
2143
    qemu_put_8s(f, &s->msr);
2144
    qemu_put_8s(f, &s->fcr);
2145
    qemu_put_byte(f, s->st00);
2146
    qemu_put_8s(f, &s->st01);
2147

    
2148
    qemu_put_8s(f, &s->dac_state);
2149
    qemu_put_8s(f, &s->dac_sub_index);
2150
    qemu_put_8s(f, &s->dac_read_index);
2151
    qemu_put_8s(f, &s->dac_write_index);
2152
    qemu_put_buffer(f, s->dac_cache, 3);
2153
    qemu_put_buffer(f, s->palette, 768);
2154

    
2155
    qemu_put_be32(f, s->bank_offset);
2156
#ifdef CONFIG_BOCHS_VBE
2157
    qemu_put_byte(f, 1);
2158
    qemu_put_be16s(f, &s->vbe_index);
2159
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2160
        qemu_put_be16s(f, &s->vbe_regs[i]);
2161
    qemu_put_be32s(f, &s->vbe_start_addr);
2162
    qemu_put_be32s(f, &s->vbe_line_offset);
2163
    qemu_put_be32s(f, &s->vbe_bank_mask);
2164
#else
2165
    qemu_put_byte(f, 0);
2166
#endif
2167
}
2168

    
2169
int vga_common_load(QEMUFile *f, void *opaque, int version_id)
2170
{
2171
    VGACommonState *s = opaque;
2172
    int is_vbe, i;
2173

    
2174
    if (version_id > 2)
2175
        return -EINVAL;
2176

    
2177
    qemu_get_be32s(f, &s->latch);
2178
    qemu_get_8s(f, &s->sr_index);
2179
    qemu_get_buffer(f, s->sr, 8);
2180
    qemu_get_8s(f, &s->gr_index);
2181
    qemu_get_buffer(f, s->gr, 16);
2182
    qemu_get_8s(f, &s->ar_index);
2183
    qemu_get_buffer(f, s->ar, 21);
2184
    s->ar_flip_flop=qemu_get_be32(f);
2185
    qemu_get_8s(f, &s->cr_index);
2186
    qemu_get_buffer(f, s->cr, 256);
2187
    qemu_get_8s(f, &s->msr);
2188
    qemu_get_8s(f, &s->fcr);
2189
    qemu_get_8s(f, &s->st00);
2190
    qemu_get_8s(f, &s->st01);
2191

    
2192
    qemu_get_8s(f, &s->dac_state);
2193
    qemu_get_8s(f, &s->dac_sub_index);
2194
    qemu_get_8s(f, &s->dac_read_index);
2195
    qemu_get_8s(f, &s->dac_write_index);
2196
    qemu_get_buffer(f, s->dac_cache, 3);
2197
    qemu_get_buffer(f, s->palette, 768);
2198

    
2199
    s->bank_offset=qemu_get_be32(f);
2200
    is_vbe = qemu_get_byte(f);
2201
#ifdef CONFIG_BOCHS_VBE
2202
    if (!is_vbe)
2203
        return -EINVAL;
2204
    qemu_get_be16s(f, &s->vbe_index);
2205
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2206
        qemu_get_be16s(f, &s->vbe_regs[i]);
2207
    qemu_get_be32s(f, &s->vbe_start_addr);
2208
    qemu_get_be32s(f, &s->vbe_line_offset);
2209
    qemu_get_be32s(f, &s->vbe_bank_mask);
2210
#else
2211
    if (is_vbe)
2212
        return -EINVAL;
2213
#endif
2214

    
2215
    /* force refresh */
2216
    s->graphic_mode = -1;
2217
    return 0;
2218
}
2219

    
2220
void vga_common_init(VGACommonState *s, int vga_ram_size)
2221
{
2222
    int i, j, v, b;
2223

    
2224
    for(i = 0;i < 256; i++) {
2225
        v = 0;
2226
        for(j = 0; j < 8; j++) {
2227
            v |= ((i >> j) & 1) << (j * 4);
2228
        }
2229
        expand4[i] = v;
2230

    
2231
        v = 0;
2232
        for(j = 0; j < 4; j++) {
2233
            v |= ((i >> (2 * j)) & 3) << (j * 4);
2234
        }
2235
        expand2[i] = v;
2236
    }
2237
    for(i = 0; i < 16; i++) {
2238
        v = 0;
2239
        for(j = 0; j < 4; j++) {
2240
            b = ((i >> j) & 1);
2241
            v |= b << (2 * j);
2242
            v |= b << (2 * j + 1);
2243
        }
2244
        expand4to8[i] = v;
2245
    }
2246

    
2247
    s->vram_offset = qemu_ram_alloc(vga_ram_size);
2248
    s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
2249
    s->vram_size = vga_ram_size;
2250
    s->get_bpp = vga_get_bpp;
2251
    s->get_offsets = vga_get_offsets;
2252
    s->get_resolution = vga_get_resolution;
2253
    s->update = vga_update_display;
2254
    s->invalidate = vga_invalidate_display;
2255
    s->screen_dump = vga_screen_dump;
2256
    s->text_update = vga_update_text;
2257
    switch (vga_retrace_method) {
2258
    case VGA_RETRACE_DUMB:
2259
        s->retrace = vga_dumb_retrace;
2260
        s->update_retrace_info = vga_dumb_update_retrace_info;
2261
        break;
2262

    
2263
    case VGA_RETRACE_PRECISE:
2264
        s->retrace = vga_precise_retrace;
2265
        s->update_retrace_info = vga_precise_update_retrace_info;
2266
        break;
2267
    }
2268
    vga_reset(s);
2269
}
2270

    
2271
/* used by both ISA and PCI */
2272
void vga_init(VGAState *s)
2273
{
2274
    int vga_io_memory;
2275

    
2276
    qemu_register_reset(vga_reset, s);
2277

    
2278
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2279

    
2280
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2281
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2282
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2283
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2284

    
2285
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2286

    
2287
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2288
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2289
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2290
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2291
    s->bank_offset = 0;
2292

    
2293
#ifdef CONFIG_BOCHS_VBE
2294
#if defined (TARGET_I386)
2295
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2296
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2297

    
2298
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2299
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2300

    
2301
    /* old Bochs IO ports */
2302
    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2303
    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2304

    
2305
    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2306
    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2307
#else
2308
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2309
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2310

    
2311
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2312
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2313
#endif
2314
#endif /* CONFIG_BOCHS_VBE */
2315

    
2316
    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
2317
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2318
                                 vga_io_memory);
2319
    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
2320
}
2321

    
2322
/* Memory mapped interface */
2323
static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2324
{
2325
    VGAState *s = opaque;
2326

    
2327
    return vga_ioport_read(s, addr >> s->it_shift) & 0xff;
2328
}
2329

    
2330
static void vga_mm_writeb (void *opaque,
2331
                           target_phys_addr_t addr, uint32_t value)
2332
{
2333
    VGAState *s = opaque;
2334

    
2335
    vga_ioport_write(s, addr >> s->it_shift, value & 0xff);
2336
}
2337

    
2338
static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2339
{
2340
    VGAState *s = opaque;
2341

    
2342
    return vga_ioport_read(s, addr >> s->it_shift) & 0xffff;
2343
}
2344

    
2345
static void vga_mm_writew (void *opaque,
2346
                           target_phys_addr_t addr, uint32_t value)
2347
{
2348
    VGAState *s = opaque;
2349

    
2350
    vga_ioport_write(s, addr >> s->it_shift, value & 0xffff);
2351
}
2352

    
2353
static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2354
{
2355
    VGAState *s = opaque;
2356

    
2357
    return vga_ioport_read(s, addr >> s->it_shift);
2358
}
2359

    
2360
static void vga_mm_writel (void *opaque,
2361
                           target_phys_addr_t addr, uint32_t value)
2362
{
2363
    VGAState *s = opaque;
2364

    
2365
    vga_ioport_write(s, addr >> s->it_shift, value);
2366
}
2367

    
2368
static CPUReadMemoryFunc * const vga_mm_read_ctrl[] = {
2369
    &vga_mm_readb,
2370
    &vga_mm_readw,
2371
    &vga_mm_readl,
2372
};
2373

    
2374
static CPUWriteMemoryFunc * const vga_mm_write_ctrl[] = {
2375
    &vga_mm_writeb,
2376
    &vga_mm_writew,
2377
    &vga_mm_writel,
2378
};
2379

    
2380
static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2381
                        target_phys_addr_t ctrl_base, int it_shift)
2382
{
2383
    int s_ioport_ctrl, vga_io_memory;
2384

    
2385
    s->it_shift = it_shift;
2386
    s_ioport_ctrl = cpu_register_io_memory(vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2387
    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
2388

    
2389
    register_savevm("vga", 0, 2, vga_common_save, vga_common_load, s);
2390

    
2391
    cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2392
    s->bank_offset = 0;
2393
    cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
2394
    qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
2395
}
2396

    
2397
int isa_vga_init(void)
2398
{
2399
    VGAState *s;
2400

    
2401
    s = qemu_mallocz(sizeof(VGAState));
2402

    
2403
    vga_common_init(s, VGA_RAM_SIZE);
2404
    vga_init(s);
2405
    register_savevm("vga", 0, 2, vga_common_save, vga_common_load, s);
2406

    
2407
    s->ds = graphic_console_init(s->update, s->invalidate,
2408
                                 s->screen_dump, s->text_update, s);
2409

    
2410
#ifdef CONFIG_BOCHS_VBE
2411
    /* XXX: use optimized standard vga accesses */
2412
    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2413
                                 VGA_RAM_SIZE, s->vram_offset);
2414
#endif
2415
    return 0;
2416
}
2417

    
2418
int isa_vga_mm_init(target_phys_addr_t vram_base,
2419
                    target_phys_addr_t ctrl_base, int it_shift)
2420
{
2421
    VGAState *s;
2422

    
2423
    s = qemu_mallocz(sizeof(VGAState));
2424

    
2425
    vga_common_init(s, VGA_RAM_SIZE);
2426
    vga_mm_init(s, vram_base, ctrl_base, it_shift);
2427

    
2428
    s->ds = graphic_console_init(s->update, s->invalidate,
2429
                                 s->screen_dump, s->text_update, s);
2430

    
2431
#ifdef CONFIG_BOCHS_VBE
2432
    /* XXX: use optimized standard vga accesses */
2433
    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2434
                                 VGA_RAM_SIZE, s->vram_offset);
2435
#endif
2436
    return 0;
2437
}
2438

    
2439
/********************************************************/
2440
/* vga screen dump */
2441

    
2442
static void vga_save_dpy_update(DisplayState *ds,
2443
                                int x, int y, int w, int h)
2444
{
2445
    if (screen_dump_filename) {
2446
        ppm_save(screen_dump_filename, ds->surface);
2447
        screen_dump_filename = NULL;
2448
    }
2449
}
2450

    
2451
static void vga_save_dpy_resize(DisplayState *s)
2452
{
2453
}
2454

    
2455
static void vga_save_dpy_refresh(DisplayState *s)
2456
{
2457
}
2458

    
2459
int ppm_save(const char *filename, struct DisplaySurface *ds)
2460
{
2461
    FILE *f;
2462
    uint8_t *d, *d1;
2463
    uint32_t v;
2464
    int y, x;
2465
    uint8_t r, g, b;
2466

    
2467
    f = fopen(filename, "wb");
2468
    if (!f)
2469
        return -1;
2470
    fprintf(f, "P6\n%d %d\n%d\n",
2471
            ds->width, ds->height, 255);
2472
    d1 = ds->data;
2473
    for(y = 0; y < ds->height; y++) {
2474
        d = d1;
2475
        for(x = 0; x < ds->width; x++) {
2476
            if (ds->pf.bits_per_pixel == 32)
2477
                v = *(uint32_t *)d;
2478
            else
2479
                v = (uint32_t) (*(uint16_t *)d);
2480
            r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2481
                (ds->pf.rmax + 1);
2482
            g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2483
                (ds->pf.gmax + 1);
2484
            b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2485
                (ds->pf.bmax + 1);
2486
            fputc(r, f);
2487
            fputc(g, f);
2488
            fputc(b, f);
2489
            d += ds->pf.bytes_per_pixel;
2490
        }
2491
        d1 += ds->linesize;
2492
    }
2493
    fclose(f);
2494
    return 0;
2495
}
2496

    
2497
static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
2498
{
2499
    DisplayChangeListener *dcl;
2500

    
2501
    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
2502
    dcl->dpy_update = vga_save_dpy_update;
2503
    dcl->dpy_resize = vga_save_dpy_resize;
2504
    dcl->dpy_refresh = vga_save_dpy_refresh;
2505
    register_displaychangelistener(ds, dcl);
2506
    return dcl;
2507
}
2508

    
2509
/* save the vga display in a PPM image even if no display is
2510
   available */
2511
static void vga_screen_dump(void *opaque, const char *filename)
2512
{
2513
    VGAState *s = opaque;
2514

    
2515
    if (!screen_dump_dcl)
2516
        screen_dump_dcl = vga_screen_dump_init(s->ds);
2517

    
2518
    screen_dump_filename = (char *)filename;
2519
    vga_invalidate_display(s);
2520
    vga_hw_update();
2521
}
2522