Statistics
| Branch: | Revision:

root / hw / vga.c @ 78895427

History | View | Annotate | Download (68.4 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
#include "kvm.h"
32

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

    
37
//#define DEBUG_BOCHS_VBE
38

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

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

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

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

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

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

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

    
114
#undef PAT
115

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

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

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

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

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

    
156
static void vga_dumb_update_retrace_info(VGACommonState *s)
157
{
158
    (void) s;
159
}
160

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

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

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

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

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

    
195

    
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 = get_ticks_per_sec() / (r->total_chars * r->freq);
208
    } else {
209
        r->ticks_per_char = get_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
    div2 = (s->cr[0x17] >> 2) & 1;
221
    sldiv2 = (s->cr[0x17] >> 3) & 1;
222
    printf (
223
        "hz=%f\n"
224
        "htotal = %d\n"
225
        "hretr_start = %d\n"
226
        "hretr_skew = %d\n"
227
        "hretr_end = %d\n"
228
        "vtotal = %d\n"
229
        "vretr_start = %d\n"
230
        "vretr_end = %d\n"
231
        "div2 = %d sldiv2 = %d\n"
232
        "clocking_mode = %d\n"
233
        "clock_sel = %d %d\n"
234
        "dots = %d\n"
235
        "ticks/char = %" PRId64 "\n"
236
        "\n",
237
        (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
238
        htotal_chars,
239
        hretr_start_char,
240
        hretr_skew_chars,
241
        hretr_end_char,
242
        vtotal_lines,
243
        vretr_start_line,
244
        vretr_end_line,
245
        div2, sldiv2,
246
        clocking_mode,
247
        clock_sel,
248
        clk_hz[clock_sel],
249
        dots,
250
        r->ticks_per_char
251
        );
252
#endif
253
}
254

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

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

    
264
        cur_tick = qemu_get_clock(vm_clock);
265

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

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

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

    
284
static uint8_t vga_dumb_retrace(VGACommonState *s)
285
{
286
    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
287
}
288

    
289
int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
290
{
291
    if (s->msr & MSR_COLOR_EMULATION) {
292
        /* Color */
293
        return (addr >= 0x3b0 && addr <= 0x3bf);
294
    } else {
295
        /* Monochrome */
296
        return (addr >= 0x3d0 && addr <= 0x3df);
297
    }
298
}
299

    
300
uint32_t vga_ioport_read(void *opaque, uint32_t addr)
301
{
302
    VGACommonState *s = opaque;
303
    int val, index;
304

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

    
391
void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
392
{
393
    VGACommonState *s = opaque;
394
    int index;
395

    
396
    /* check port range access depending on color/monochrome mode */
397
    if (vga_ioport_invalid(s, addr)) {
398
        return;
399
    }
400
#ifdef DEBUG_VGA
401
    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
402
#endif
403

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

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

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

    
523
static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
524
{
525
    VGACommonState *s = opaque;
526
    uint32_t val;
527

    
528
    if (s->vbe_index < VBE_DISPI_INDEX_NB) {
529
        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
530
            switch(s->vbe_index) {
531
                /* XXX: do not hardcode ? */
532
            case VBE_DISPI_INDEX_XRES:
533
                val = VBE_DISPI_MAX_XRES;
534
                break;
535
            case VBE_DISPI_INDEX_YRES:
536
                val = VBE_DISPI_MAX_YRES;
537
                break;
538
            case VBE_DISPI_INDEX_BPP:
539
                val = VBE_DISPI_MAX_BPP;
540
                break;
541
            default:
542
                val = s->vbe_regs[s->vbe_index];
543
                break;
544
            }
545
        } else {
546
            val = s->vbe_regs[s->vbe_index];
547
        }
548
    } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
549
        val = s->vram_size / (64 * 1024);
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
    VGACommonState *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
    VGACommonState *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
    VGACommonState *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
    VGACommonState *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(VGACommonState *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(VGACommonState *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(VGACommonState *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(VGACommonState *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(VGACommonState *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 * const 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 * const 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 * const 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(VGACommonState *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 * const 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(VGACommonState *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, line, line1;
1276
    uint32_t offset, fgcol, bgcol, v, cursor_offset;
1277
    uint8_t *d1, *d, *src, *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

    
1310
    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1311
    if ((height * width) > CH_ATTR_SIZE) {
1312
        /* better than nothing: exit if transient size is too big */
1313
        return;
1314
    }
1315

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

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

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

    
1357
    dest = ds_get_data(s->ds);
1358
    linesize = ds_get_linesize(s->ds);
1359
    ch_attr_ptr = s->last_ch_attr;
1360
    line = 0;
1361
    offset = s->start_addr * 4;
1362
    for(cy = 0; cy < height; cy++) {
1363
        d1 = dest;
1364
        src = s->vram_ptr + offset;
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
        line1 = line + cheight;
1428
        offset += line_offset;
1429
        if (line < s->line_compare && line1 >= s->line_compare) {
1430
            offset = 0;
1431
        }
1432
        line = line1;
1433
    }
1434
}
1435

    
1436
enum {
1437
    VGA_DRAW_LINE2,
1438
    VGA_DRAW_LINE2D2,
1439
    VGA_DRAW_LINE4,
1440
    VGA_DRAW_LINE4D2,
1441
    VGA_DRAW_LINE8D2,
1442
    VGA_DRAW_LINE8,
1443
    VGA_DRAW_LINE15,
1444
    VGA_DRAW_LINE16,
1445
    VGA_DRAW_LINE24,
1446
    VGA_DRAW_LINE32,
1447
    VGA_DRAW_LINE_NB,
1448
};
1449

    
1450
static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1451
    vga_draw_line2_8,
1452
    vga_draw_line2_16,
1453
    vga_draw_line2_16,
1454
    vga_draw_line2_32,
1455
    vga_draw_line2_32,
1456
    vga_draw_line2_16,
1457
    vga_draw_line2_16,
1458

    
1459
    vga_draw_line2d2_8,
1460
    vga_draw_line2d2_16,
1461
    vga_draw_line2d2_16,
1462
    vga_draw_line2d2_32,
1463
    vga_draw_line2d2_32,
1464
    vga_draw_line2d2_16,
1465
    vga_draw_line2d2_16,
1466

    
1467
    vga_draw_line4_8,
1468
    vga_draw_line4_16,
1469
    vga_draw_line4_16,
1470
    vga_draw_line4_32,
1471
    vga_draw_line4_32,
1472
    vga_draw_line4_16,
1473
    vga_draw_line4_16,
1474

    
1475
    vga_draw_line4d2_8,
1476
    vga_draw_line4d2_16,
1477
    vga_draw_line4d2_16,
1478
    vga_draw_line4d2_32,
1479
    vga_draw_line4d2_32,
1480
    vga_draw_line4d2_16,
1481
    vga_draw_line4d2_16,
1482

    
1483
    vga_draw_line8d2_8,
1484
    vga_draw_line8d2_16,
1485
    vga_draw_line8d2_16,
1486
    vga_draw_line8d2_32,
1487
    vga_draw_line8d2_32,
1488
    vga_draw_line8d2_16,
1489
    vga_draw_line8d2_16,
1490

    
1491
    vga_draw_line8_8,
1492
    vga_draw_line8_16,
1493
    vga_draw_line8_16,
1494
    vga_draw_line8_32,
1495
    vga_draw_line8_32,
1496
    vga_draw_line8_16,
1497
    vga_draw_line8_16,
1498

    
1499
    vga_draw_line15_8,
1500
    vga_draw_line15_15,
1501
    vga_draw_line15_16,
1502
    vga_draw_line15_32,
1503
    vga_draw_line15_32bgr,
1504
    vga_draw_line15_15bgr,
1505
    vga_draw_line15_16bgr,
1506

    
1507
    vga_draw_line16_8,
1508
    vga_draw_line16_15,
1509
    vga_draw_line16_16,
1510
    vga_draw_line16_32,
1511
    vga_draw_line16_32bgr,
1512
    vga_draw_line16_15bgr,
1513
    vga_draw_line16_16bgr,
1514

    
1515
    vga_draw_line24_8,
1516
    vga_draw_line24_15,
1517
    vga_draw_line24_16,
1518
    vga_draw_line24_32,
1519
    vga_draw_line24_32bgr,
1520
    vga_draw_line24_15bgr,
1521
    vga_draw_line24_16bgr,
1522

    
1523
    vga_draw_line32_8,
1524
    vga_draw_line32_15,
1525
    vga_draw_line32_16,
1526
    vga_draw_line32_32,
1527
    vga_draw_line32_32bgr,
1528
    vga_draw_line32_15bgr,
1529
    vga_draw_line32_16bgr,
1530
};
1531

    
1532
static int vga_get_bpp(VGACommonState *s)
1533
{
1534
    int ret;
1535
#ifdef CONFIG_BOCHS_VBE
1536
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1537
        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1538
    } else
1539
#endif
1540
    {
1541
        ret = 0;
1542
    }
1543
    return ret;
1544
}
1545

    
1546
static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1547
{
1548
    int width, height;
1549

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

    
1567
void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1568
{
1569
    int y;
1570
    if (y1 >= VGA_MAX_HEIGHT)
1571
        return;
1572
    if (y2 >= VGA_MAX_HEIGHT)
1573
        y2 = VGA_MAX_HEIGHT;
1574
    for(y = y1; y < y2; y++) {
1575
        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1576
    }
1577
}
1578

    
1579
static void vga_sync_dirty_bitmap(VGACommonState *s)
1580
{
1581
    if (s->map_addr)
1582
        cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1583

    
1584
    if (s->lfb_vram_mapped) {
1585
        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1586
        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1587
    }
1588

    
1589
#ifdef CONFIG_BOCHS_VBE
1590
    if (s->vbe_mapped) {
1591
        cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1592
                                       VBE_DISPI_LFB_PHYSICAL_ADDRESS + s->vram_size);
1593
    }
1594
#endif
1595

    
1596
}
1597

    
1598
void vga_dirty_log_start(VGACommonState *s)
1599
{
1600
    if (kvm_enabled() && s->map_addr)
1601
        kvm_log_start(s->map_addr, s->map_end - s->map_addr);
1602

    
1603
    if (kvm_enabled() && s->lfb_vram_mapped) {
1604
        kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
1605
        kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
1606
    }
1607

    
1608
#ifdef CONFIG_BOCHS_VBE
1609
    if (kvm_enabled() && s->vbe_mapped) {
1610
        kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
1611
    }
1612
#endif
1613
}
1614

    
1615
void vga_dirty_log_stop(VGACommonState *s)
1616
{
1617
    if (kvm_enabled() && s->map_addr)
1618
        kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
1619

    
1620
    if (kvm_enabled() && s->lfb_vram_mapped) {
1621
        kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
1622
        kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
1623
    }
1624

    
1625
#ifdef CONFIG_BOCHS_VBE
1626
    if (kvm_enabled() && s->vbe_mapped) {
1627
        kvm_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
1628
    }
1629
#endif
1630
}
1631

    
1632
void vga_dirty_log_restart(VGACommonState *s)
1633
{
1634
    vga_dirty_log_stop(s);
1635
    vga_dirty_log_start(s);
1636
}
1637

    
1638
/*
1639
 * graphic modes
1640
 */
1641
static void vga_draw_graphic(VGACommonState *s, int full_update)
1642
{
1643
    int y1, y, update, linesize, y_start, double_scan, mask, depth;
1644
    int width, height, shift_control, line_offset, bwidth, bits;
1645
    ram_addr_t page0, page1, page_min, page_max;
1646
    int disp_width, multi_scan, multi_run;
1647
    uint8_t *d;
1648
    uint32_t v, addr1, addr;
1649
    vga_draw_line_func *vga_draw_line;
1650

    
1651
    full_update |= update_basic_params(s);
1652

    
1653
    if (!full_update)
1654
        vga_sync_dirty_bitmap(s);
1655

    
1656
    s->get_resolution(s, &width, &height);
1657
    disp_width = width;
1658

    
1659
    shift_control = (s->gr[0x05] >> 5) & 3;
1660
    double_scan = (s->cr[0x09] >> 7);
1661
    if (shift_control != 1) {
1662
        multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1663
    } else {
1664
        /* in CGA modes, multi_scan is ignored */
1665
        /* XXX: is it correct ? */
1666
        multi_scan = double_scan;
1667
    }
1668
    multi_run = multi_scan;
1669
    if (shift_control != s->shift_control ||
1670
        double_scan != s->double_scan) {
1671
        full_update = 1;
1672
        s->shift_control = shift_control;
1673
        s->double_scan = double_scan;
1674
    }
1675

    
1676
    if (shift_control == 0) {
1677
        if (s->sr[0x01] & 8) {
1678
            disp_width <<= 1;
1679
        }
1680
    } else if (shift_control == 1) {
1681
        if (s->sr[0x01] & 8) {
1682
            disp_width <<= 1;
1683
        }
1684
    }
1685

    
1686
    depth = s->get_bpp(s);
1687
    if (s->line_offset != s->last_line_offset ||
1688
        disp_width != s->last_width ||
1689
        height != s->last_height ||
1690
        s->last_depth != depth) {
1691
#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1692
        if (depth == 16 || depth == 32) {
1693
#else
1694
        if (depth == 32) {
1695
#endif
1696
            qemu_free_displaysurface(s->ds);
1697
            s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1698
                    s->line_offset,
1699
                    s->vram_ptr + (s->start_addr * 4));
1700
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1701
            s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1702
#endif
1703
            dpy_resize(s->ds);
1704
        } else {
1705
            qemu_console_resize(s->ds, disp_width, height);
1706
        }
1707
        s->last_scr_width = disp_width;
1708
        s->last_scr_height = height;
1709
        s->last_width = disp_width;
1710
        s->last_height = height;
1711
        s->last_line_offset = s->line_offset;
1712
        s->last_depth = depth;
1713
        full_update = 1;
1714
    } else if (is_buffer_shared(s->ds->surface) &&
1715
               (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1716
        s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1717
        dpy_setdata(s->ds);
1718
    }
1719

    
1720
    s->rgb_to_pixel =
1721
        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1722

    
1723
    if (shift_control == 0) {
1724
        full_update |= update_palette16(s);
1725
        if (s->sr[0x01] & 8) {
1726
            v = VGA_DRAW_LINE4D2;
1727
        } else {
1728
            v = VGA_DRAW_LINE4;
1729
        }
1730
        bits = 4;
1731
    } else if (shift_control == 1) {
1732
        full_update |= update_palette16(s);
1733
        if (s->sr[0x01] & 8) {
1734
            v = VGA_DRAW_LINE2D2;
1735
        } else {
1736
            v = VGA_DRAW_LINE2;
1737
        }
1738
        bits = 4;
1739
    } else {
1740
        switch(s->get_bpp(s)) {
1741
        default:
1742
        case 0:
1743
            full_update |= update_palette256(s);
1744
            v = VGA_DRAW_LINE8D2;
1745
            bits = 4;
1746
            break;
1747
        case 8:
1748
            full_update |= update_palette256(s);
1749
            v = VGA_DRAW_LINE8;
1750
            bits = 8;
1751
            break;
1752
        case 15:
1753
            v = VGA_DRAW_LINE15;
1754
            bits = 16;
1755
            break;
1756
        case 16:
1757
            v = VGA_DRAW_LINE16;
1758
            bits = 16;
1759
            break;
1760
        case 24:
1761
            v = VGA_DRAW_LINE24;
1762
            bits = 24;
1763
            break;
1764
        case 32:
1765
            v = VGA_DRAW_LINE32;
1766
            bits = 32;
1767
            break;
1768
        }
1769
    }
1770
    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1771

    
1772
    if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1773
        s->cursor_invalidate(s);
1774

    
1775
    line_offset = s->line_offset;
1776
#if 0
1777
    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",
1778
           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1779
#endif
1780
    addr1 = (s->start_addr * 4);
1781
    bwidth = (width * bits + 7) / 8;
1782
    y_start = -1;
1783
    page_min = -1;
1784
    page_max = 0;
1785
    d = ds_get_data(s->ds);
1786
    linesize = ds_get_linesize(s->ds);
1787
    y1 = 0;
1788
    for(y = 0; y < height; y++) {
1789
        addr = addr1;
1790
        if (!(s->cr[0x17] & 1)) {
1791
            int shift;
1792
            /* CGA compatibility handling */
1793
            shift = 14 + ((s->cr[0x17] >> 6) & 1);
1794
            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1795
        }
1796
        if (!(s->cr[0x17] & 2)) {
1797
            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1798
        }
1799
        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1800
        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1801
        update = full_update |
1802
            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1803
            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1804
        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1805
            /* if wide line, can use another page */
1806
            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1807
                                                    VGA_DIRTY_FLAG);
1808
        }
1809
        /* explicit invalidation for the hardware cursor */
1810
        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1811
        if (update) {
1812
            if (y_start < 0)
1813
                y_start = y;
1814
            if (page0 < page_min)
1815
                page_min = page0;
1816
            if (page1 > page_max)
1817
                page_max = page1;
1818
            if (!(is_buffer_shared(s->ds->surface))) {
1819
                vga_draw_line(s, d, s->vram_ptr + addr, width);
1820
                if (s->cursor_draw_line)
1821
                    s->cursor_draw_line(s, d, y);
1822
            }
1823
        } else {
1824
            if (y_start >= 0) {
1825
                /* flush to display */
1826
                dpy_update(s->ds, 0, y_start,
1827
                           disp_width, y - y_start);
1828
                y_start = -1;
1829
            }
1830
        }
1831
        if (!multi_run) {
1832
            mask = (s->cr[0x17] & 3) ^ 3;
1833
            if ((y1 & mask) == mask)
1834
                addr1 += line_offset;
1835
            y1++;
1836
            multi_run = multi_scan;
1837
        } else {
1838
            multi_run--;
1839
        }
1840
        /* line compare acts on the displayed lines */
1841
        if (y == s->line_compare)
1842
            addr1 = 0;
1843
        d += linesize;
1844
    }
1845
    if (y_start >= 0) {
1846
        /* flush to display */
1847
        dpy_update(s->ds, 0, y_start,
1848
                   disp_width, y - y_start);
1849
    }
1850
    /* reset modified pages */
1851
    if (page_max >= page_min) {
1852
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1853
                                        VGA_DIRTY_FLAG);
1854
    }
1855
    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1856
}
1857

    
1858
static void vga_draw_blank(VGACommonState *s, int full_update)
1859
{
1860
    int i, w, val;
1861
    uint8_t *d;
1862

    
1863
    if (!full_update)
1864
        return;
1865
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1866
        return;
1867

    
1868
    s->rgb_to_pixel =
1869
        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1870
    if (ds_get_bits_per_pixel(s->ds) == 8)
1871
        val = s->rgb_to_pixel(0, 0, 0);
1872
    else
1873
        val = 0;
1874
    w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1875
    d = ds_get_data(s->ds);
1876
    for(i = 0; i < s->last_scr_height; i++) {
1877
        memset(d, val, w);
1878
        d += ds_get_linesize(s->ds);
1879
    }
1880
    dpy_update(s->ds, 0, 0,
1881
               s->last_scr_width, s->last_scr_height);
1882
}
1883

    
1884
#define GMODE_TEXT     0
1885
#define GMODE_GRAPH    1
1886
#define GMODE_BLANK 2
1887

    
1888
static void vga_update_display(void *opaque)
1889
{
1890
    VGACommonState *s = opaque;
1891
    int full_update, graphic_mode;
1892

    
1893
    if (ds_get_bits_per_pixel(s->ds) == 0) {
1894
        /* nothing to do */
1895
    } else {
1896
        full_update = 0;
1897
        if (!(s->ar_index & 0x20)) {
1898
            graphic_mode = GMODE_BLANK;
1899
        } else {
1900
            graphic_mode = s->gr[6] & 1;
1901
        }
1902
        if (graphic_mode != s->graphic_mode) {
1903
            s->graphic_mode = graphic_mode;
1904
            full_update = 1;
1905
        }
1906
        switch(graphic_mode) {
1907
        case GMODE_TEXT:
1908
            vga_draw_text(s, full_update);
1909
            break;
1910
        case GMODE_GRAPH:
1911
            vga_draw_graphic(s, full_update);
1912
            break;
1913
        case GMODE_BLANK:
1914
        default:
1915
            vga_draw_blank(s, full_update);
1916
            break;
1917
        }
1918
    }
1919
}
1920

    
1921
/* force a full display refresh */
1922
static void vga_invalidate_display(void *opaque)
1923
{
1924
    VGACommonState *s = opaque;
1925

    
1926
    s->last_width = -1;
1927
    s->last_height = -1;
1928
}
1929

    
1930
void vga_common_reset(VGACommonState *s)
1931
{
1932
    s->lfb_addr = 0;
1933
    s->lfb_end = 0;
1934
    s->map_addr = 0;
1935
    s->map_end = 0;
1936
    s->lfb_vram_mapped = 0;
1937
    s->sr_index = 0;
1938
    memset(s->sr, '\0', sizeof(s->sr));
1939
    s->gr_index = 0;
1940
    memset(s->gr, '\0', sizeof(s->gr));
1941
    s->ar_index = 0;
1942
    memset(s->ar, '\0', sizeof(s->ar));
1943
    s->ar_flip_flop = 0;
1944
    s->cr_index = 0;
1945
    memset(s->cr, '\0', sizeof(s->cr));
1946
    s->msr = 0;
1947
    s->fcr = 0;
1948
    s->st00 = 0;
1949
    s->st01 = 0;
1950
    s->dac_state = 0;
1951
    s->dac_sub_index = 0;
1952
    s->dac_read_index = 0;
1953
    s->dac_write_index = 0;
1954
    memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1955
    s->dac_8bit = 0;
1956
    memset(s->palette, '\0', sizeof(s->palette));
1957
    s->bank_offset = 0;
1958
#ifdef CONFIG_BOCHS_VBE
1959
    s->vbe_index = 0;
1960
    memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1961
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1962
    s->vbe_start_addr = 0;
1963
    s->vbe_line_offset = 0;
1964
    s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1965
#endif
1966
    memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1967
    s->graphic_mode = -1; /* force full update */
1968
    s->shift_control = 0;
1969
    s->double_scan = 0;
1970
    s->line_offset = 0;
1971
    s->line_compare = 0;
1972
    s->start_addr = 0;
1973
    s->plane_updated = 0;
1974
    s->last_cw = 0;
1975
    s->last_ch = 0;
1976
    s->last_width = 0;
1977
    s->last_height = 0;
1978
    s->last_scr_width = 0;
1979
    s->last_scr_height = 0;
1980
    s->cursor_start = 0;
1981
    s->cursor_end = 0;
1982
    s->cursor_offset = 0;
1983
    memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1984
    memset(s->last_palette, '\0', sizeof(s->last_palette));
1985
    memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1986
    switch (vga_retrace_method) {
1987
    case VGA_RETRACE_DUMB:
1988
        break;
1989
    case VGA_RETRACE_PRECISE:
1990
        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1991
        break;
1992
    }
1993
}
1994

    
1995
static void vga_reset(void *opaque)
1996
{
1997
    VGACommonState *s =  opaque;
1998
    vga_common_reset(s);
1999
}
2000

    
2001
#define TEXTMODE_X(x)        ((x) % width)
2002
#define TEXTMODE_Y(x)        ((x) / width)
2003
#define VMEM2CHTYPE(v)        ((v & 0xff0007ff) | \
2004
        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
2005
/* relay text rendering to the display driver
2006
 * instead of doing a full vga_update_display() */
2007
static void vga_update_text(void *opaque, console_ch_t *chardata)
2008
{
2009
    VGACommonState *s =  opaque;
2010
    int graphic_mode, i, cursor_offset, cursor_visible;
2011
    int cw, cheight, width, height, size, c_min, c_max;
2012
    uint32_t *src;
2013
    console_ch_t *dst, val;
2014
    char msg_buffer[80];
2015
    int full_update = 0;
2016

    
2017
    if (!(s->ar_index & 0x20)) {
2018
        graphic_mode = GMODE_BLANK;
2019
    } else {
2020
        graphic_mode = s->gr[6] & 1;
2021
    }
2022
    if (graphic_mode != s->graphic_mode) {
2023
        s->graphic_mode = graphic_mode;
2024
        full_update = 1;
2025
    }
2026
    if (s->last_width == -1) {
2027
        s->last_width = 0;
2028
        full_update = 1;
2029
    }
2030

    
2031
    switch (graphic_mode) {
2032
    case GMODE_TEXT:
2033
        /* TODO: update palette */
2034
        full_update |= update_basic_params(s);
2035

    
2036
        /* total width & height */
2037
        cheight = (s->cr[9] & 0x1f) + 1;
2038
        cw = 8;
2039
        if (!(s->sr[1] & 0x01))
2040
            cw = 9;
2041
        if (s->sr[1] & 0x08)
2042
            cw = 16; /* NOTE: no 18 pixel wide */
2043
        width = (s->cr[0x01] + 1);
2044
        if (s->cr[0x06] == 100) {
2045
            /* ugly hack for CGA 160x100x16 - explain me the logic */
2046
            height = 100;
2047
        } else {
2048
            height = s->cr[0x12] | 
2049
                ((s->cr[0x07] & 0x02) << 7) | 
2050
                ((s->cr[0x07] & 0x40) << 3);
2051
            height = (height + 1) / cheight;
2052
        }
2053

    
2054
        size = (height * width);
2055
        if (size > CH_ATTR_SIZE) {
2056
            if (!full_update)
2057
                return;
2058

    
2059
            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2060
                     width, height);
2061
            break;
2062
        }
2063

    
2064
        if (width != s->last_width || height != s->last_height ||
2065
            cw != s->last_cw || cheight != s->last_ch) {
2066
            s->last_scr_width = width * cw;
2067
            s->last_scr_height = height * cheight;
2068
            s->ds->surface->width = width;
2069
            s->ds->surface->height = height;
2070
            dpy_resize(s->ds);
2071
            s->last_width = width;
2072
            s->last_height = height;
2073
            s->last_ch = cheight;
2074
            s->last_cw = cw;
2075
            full_update = 1;
2076
        }
2077

    
2078
        /* Update "hardware" cursor */
2079
        cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2080
        if (cursor_offset != s->cursor_offset ||
2081
            s->cr[0xa] != s->cursor_start ||
2082
            s->cr[0xb] != s->cursor_end || full_update) {
2083
            cursor_visible = !(s->cr[0xa] & 0x20);
2084
            if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2085
                dpy_cursor(s->ds,
2086
                           TEXTMODE_X(cursor_offset),
2087
                           TEXTMODE_Y(cursor_offset));
2088
            else
2089
                dpy_cursor(s->ds, -1, -1);
2090
            s->cursor_offset = cursor_offset;
2091
            s->cursor_start = s->cr[0xa];
2092
            s->cursor_end = s->cr[0xb];
2093
        }
2094

    
2095
        src = (uint32_t *) s->vram_ptr + s->start_addr;
2096
        dst = chardata;
2097

    
2098
        if (full_update) {
2099
            for (i = 0; i < size; src ++, dst ++, i ++)
2100
                console_write_ch(dst, VMEM2CHTYPE(*src));
2101

    
2102
            dpy_update(s->ds, 0, 0, width, height);
2103
        } else {
2104
            c_max = 0;
2105

    
2106
            for (i = 0; i < size; src ++, dst ++, i ++) {
2107
                console_write_ch(&val, VMEM2CHTYPE(*src));
2108
                if (*dst != val) {
2109
                    *dst = val;
2110
                    c_max = i;
2111
                    break;
2112
                }
2113
            }
2114
            c_min = i;
2115
            for (; i < size; src ++, dst ++, i ++) {
2116
                console_write_ch(&val, VMEM2CHTYPE(*src));
2117
                if (*dst != val) {
2118
                    *dst = val;
2119
                    c_max = i;
2120
                }
2121
            }
2122

    
2123
            if (c_min <= c_max) {
2124
                i = TEXTMODE_Y(c_min);
2125
                dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2126
            }
2127
        }
2128

    
2129
        return;
2130
    case GMODE_GRAPH:
2131
        if (!full_update)
2132
            return;
2133

    
2134
        s->get_resolution(s, &width, &height);
2135
        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2136
                 width, height);
2137
        break;
2138
    case GMODE_BLANK:
2139
    default:
2140
        if (!full_update)
2141
            return;
2142

    
2143
        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2144
        break;
2145
    }
2146

    
2147
    /* Display a message */
2148
    s->last_width = 60;
2149
    s->last_height = height = 3;
2150
    dpy_cursor(s->ds, -1, -1);
2151
    s->ds->surface->width = s->last_width;
2152
    s->ds->surface->height = height;
2153
    dpy_resize(s->ds);
2154

    
2155
    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2156
        console_write_ch(dst ++, ' ');
2157

    
2158
    size = strlen(msg_buffer);
2159
    width = (s->last_width - size) / 2;
2160
    dst = chardata + s->last_width + width;
2161
    for (i = 0; i < size; i ++)
2162
        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2163

    
2164
    dpy_update(s->ds, 0, 0, s->last_width, height);
2165
}
2166

    
2167
CPUReadMemoryFunc * const vga_mem_read[3] = {
2168
    vga_mem_readb,
2169
    vga_mem_readw,
2170
    vga_mem_readl,
2171
};
2172

    
2173
CPUWriteMemoryFunc * const vga_mem_write[3] = {
2174
    vga_mem_writeb,
2175
    vga_mem_writew,
2176
    vga_mem_writel,
2177
};
2178

    
2179
static int vga_common_post_load(void *opaque, int version_id)
2180
{
2181
    VGACommonState *s = opaque;
2182

    
2183
    /* force refresh */
2184
    s->graphic_mode = -1;
2185
    return 0;
2186
}
2187

    
2188
const VMStateDescription vmstate_vga_common = {
2189
    .name = "vga",
2190
    .version_id = 2,
2191
    .minimum_version_id = 2,
2192
    .minimum_version_id_old = 2,
2193
    .post_load = vga_common_post_load,
2194
    .fields      = (VMStateField []) {
2195
        VMSTATE_UINT32(latch, VGACommonState),
2196
        VMSTATE_UINT8(sr_index, VGACommonState),
2197
        VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2198
        VMSTATE_UINT8(gr_index, VGACommonState),
2199
        VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2200
        VMSTATE_UINT8(ar_index, VGACommonState),
2201
        VMSTATE_BUFFER(ar, VGACommonState),
2202
        VMSTATE_INT32(ar_flip_flop, VGACommonState),
2203
        VMSTATE_UINT8(cr_index, VGACommonState),
2204
        VMSTATE_BUFFER(cr, VGACommonState),
2205
        VMSTATE_UINT8(msr, VGACommonState),
2206
        VMSTATE_UINT8(fcr, VGACommonState),
2207
        VMSTATE_UINT8(st00, VGACommonState),
2208
        VMSTATE_UINT8(st01, VGACommonState),
2209

    
2210
        VMSTATE_UINT8(dac_state, VGACommonState),
2211
        VMSTATE_UINT8(dac_sub_index, VGACommonState),
2212
        VMSTATE_UINT8(dac_read_index, VGACommonState),
2213
        VMSTATE_UINT8(dac_write_index, VGACommonState),
2214
        VMSTATE_BUFFER(dac_cache, VGACommonState),
2215
        VMSTATE_BUFFER(palette, VGACommonState),
2216

    
2217
        VMSTATE_INT32(bank_offset, VGACommonState),
2218
        VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2219
#ifdef CONFIG_BOCHS_VBE
2220
        VMSTATE_UINT16(vbe_index, VGACommonState),
2221
        VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2222
        VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2223
        VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2224
        VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2225
#endif
2226
        VMSTATE_END_OF_LIST()
2227
    }
2228
};
2229

    
2230
void vga_common_init(VGACommonState *s, int vga_ram_size)
2231
{
2232
    int i, j, v, b;
2233

    
2234
    for(i = 0;i < 256; i++) {
2235
        v = 0;
2236
        for(j = 0; j < 8; j++) {
2237
            v |= ((i >> j) & 1) << (j * 4);
2238
        }
2239
        expand4[i] = v;
2240

    
2241
        v = 0;
2242
        for(j = 0; j < 4; j++) {
2243
            v |= ((i >> (2 * j)) & 3) << (j * 4);
2244
        }
2245
        expand2[i] = v;
2246
    }
2247
    for(i = 0; i < 16; i++) {
2248
        v = 0;
2249
        for(j = 0; j < 4; j++) {
2250
            b = ((i >> j) & 1);
2251
            v |= b << (2 * j);
2252
            v |= b << (2 * j + 1);
2253
        }
2254
        expand4to8[i] = v;
2255
    }
2256

    
2257
#ifdef CONFIG_BOCHS_VBE
2258
    s->is_vbe_vmstate = 1;
2259
#else
2260
    s->is_vbe_vmstate = 0;
2261
#endif
2262
    s->vram_offset = qemu_ram_alloc(NULL, "vga.vram", vga_ram_size);
2263
    s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
2264
    s->vram_size = vga_ram_size;
2265
    s->get_bpp = vga_get_bpp;
2266
    s->get_offsets = vga_get_offsets;
2267
    s->get_resolution = vga_get_resolution;
2268
    s->update = vga_update_display;
2269
    s->invalidate = vga_invalidate_display;
2270
    s->screen_dump = vga_screen_dump;
2271
    s->text_update = vga_update_text;
2272
    switch (vga_retrace_method) {
2273
    case VGA_RETRACE_DUMB:
2274
        s->retrace = vga_dumb_retrace;
2275
        s->update_retrace_info = vga_dumb_update_retrace_info;
2276
        break;
2277

    
2278
    case VGA_RETRACE_PRECISE:
2279
        s->retrace = vga_precise_retrace;
2280
        s->update_retrace_info = vga_precise_update_retrace_info;
2281
        break;
2282
    }
2283
}
2284

    
2285
/* used by both ISA and PCI */
2286
void vga_init(VGACommonState *s)
2287
{
2288
    int vga_io_memory;
2289

    
2290
    qemu_register_reset(vga_reset, s);
2291

    
2292
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2293

    
2294
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2295
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2296
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2297
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2298

    
2299
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2300

    
2301
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2302
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2303
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2304
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2305
    s->bank_offset = 0;
2306

    
2307
#ifdef CONFIG_BOCHS_VBE
2308
#if defined (TARGET_I386)
2309
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2310
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2311

    
2312
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2313
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2314
#else
2315
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2316
    register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2317

    
2318
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2319
    register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2320
#endif
2321
#endif /* CONFIG_BOCHS_VBE */
2322

    
2323
    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
2324
    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2325
                                 vga_io_memory);
2326
    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
2327
}
2328

    
2329
void vga_init_vbe(VGACommonState *s)
2330
{
2331
#ifdef CONFIG_BOCHS_VBE
2332
    /* XXX: use optimized standard vga accesses */
2333
    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2334
                                 VGA_RAM_SIZE, s->vram_offset);
2335
    s->vbe_mapped = 1;
2336
#endif 
2337
}
2338
/********************************************************/
2339
/* vga screen dump */
2340

    
2341
static void vga_save_dpy_update(DisplayState *ds,
2342
                                int x, int y, int w, int h)
2343
{
2344
    if (screen_dump_filename) {
2345
        ppm_save(screen_dump_filename, ds->surface);
2346
        screen_dump_filename = NULL;
2347
    }
2348
}
2349

    
2350
static void vga_save_dpy_resize(DisplayState *s)
2351
{
2352
}
2353

    
2354
static void vga_save_dpy_refresh(DisplayState *s)
2355
{
2356
}
2357

    
2358
int ppm_save(const char *filename, struct DisplaySurface *ds)
2359
{
2360
    FILE *f;
2361
    uint8_t *d, *d1;
2362
    uint32_t v;
2363
    int y, x;
2364
    uint8_t r, g, b;
2365

    
2366
    f = fopen(filename, "wb");
2367
    if (!f)
2368
        return -1;
2369
    fprintf(f, "P6\n%d %d\n%d\n",
2370
            ds->width, ds->height, 255);
2371
    d1 = ds->data;
2372
    for(y = 0; y < ds->height; y++) {
2373
        d = d1;
2374
        for(x = 0; x < ds->width; x++) {
2375
            if (ds->pf.bits_per_pixel == 32)
2376
                v = *(uint32_t *)d;
2377
            else
2378
                v = (uint32_t) (*(uint16_t *)d);
2379
            r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2380
                (ds->pf.rmax + 1);
2381
            g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2382
                (ds->pf.gmax + 1);
2383
            b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2384
                (ds->pf.bmax + 1);
2385
            fputc(r, f);
2386
            fputc(g, f);
2387
            fputc(b, f);
2388
            d += ds->pf.bytes_per_pixel;
2389
        }
2390
        d1 += ds->linesize;
2391
    }
2392
    fclose(f);
2393
    return 0;
2394
}
2395

    
2396
static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
2397
{
2398
    DisplayChangeListener *dcl;
2399

    
2400
    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
2401
    dcl->dpy_update = vga_save_dpy_update;
2402
    dcl->dpy_resize = vga_save_dpy_resize;
2403
    dcl->dpy_refresh = vga_save_dpy_refresh;
2404
    register_displaychangelistener(ds, dcl);
2405
    return dcl;
2406
}
2407

    
2408
/* save the vga display in a PPM image even if no display is
2409
   available */
2410
static void vga_screen_dump(void *opaque, const char *filename)
2411
{
2412
    VGACommonState *s = opaque;
2413

    
2414
    if (!screen_dump_dcl)
2415
        screen_dump_dcl = vga_screen_dump_init(s->ds);
2416

    
2417
    screen_dump_filename = (char *)filename;
2418
    vga_invalidate_display(s);
2419
    vga_hw_update();
2420
}
2421