~jderose/ubuntu/raring/qemu/vde-again

« back to all changes in this revision

Viewing changes to hw/tcx.c

Tags: upstream-0.9.0+20070816
ImportĀ upstreamĀ versionĀ 0.9.0+20070816

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 * THE SOFTWARE.
23
23
 */
24
24
#include "vl.h"
 
25
#include "pixel_ops.h"
25
26
 
26
27
#define MAXX 1024
27
28
#define MAXY 768
28
29
#define TCX_DAC_NREGS 16
 
30
#define TCX_THC_NREGS_8  0x081c
 
31
#define TCX_THC_NREGS_24 0x1000
 
32
#define TCX_TEC_NREGS    0x1000
29
33
 
30
34
typedef struct TCXState {
31
 
    uint32_t addr;
 
35
    target_phys_addr_t addr;
32
36
    DisplayState *ds;
33
37
    uint8_t *vram;
34
 
    ram_addr_t vram_offset;
35
 
    uint16_t width, height;
 
38
    uint32_t *vram24, *cplane;
 
39
    ram_addr_t vram_offset, vram24_offset, cplane_offset;
 
40
    uint16_t width, height, depth;
36
41
    uint8_t r[256], g[256], b[256];
37
42
    uint32_t palette[256];
38
43
    uint8_t dac_index, dac_state;
39
44
} TCXState;
40
45
 
41
46
static void tcx_screen_dump(void *opaque, const char *filename);
42
 
 
43
 
/* XXX: unify with vga draw line functions */
44
 
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
45
 
{
46
 
    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
47
 
}
48
 
 
49
 
static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
50
 
{
51
 
    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
52
 
}
53
 
 
54
 
static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
55
 
{
56
 
    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
57
 
}
58
 
 
59
 
static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
60
 
{
61
 
    return (r << 16) | (g << 8) | b;
62
 
}
 
47
static void tcx24_screen_dump(void *opaque, const char *filename);
 
48
static void tcx_invalidate_display(void *opaque);
 
49
static void tcx24_invalidate_display(void *opaque);
63
50
 
64
51
static void update_palette_entries(TCXState *s, int start, int end)
65
52
{
71
58
            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
72
59
            break;
73
60
        case 15:
74
 
            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
 
61
            if (s->ds->bgr)
 
62
                s->palette[i] = rgb_to_pixel15bgr(s->r[i], s->g[i], s->b[i]);
 
63
            else
 
64
                s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
75
65
            break;
76
66
        case 16:
77
 
            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
 
67
            if (s->ds->bgr)
 
68
                s->palette[i] = rgb_to_pixel16bgr(s->r[i], s->g[i], s->b[i]);
 
69
            else
 
70
                s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
78
71
            break;
79
72
        case 32:
80
 
            s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
 
73
            if (s->ds->bgr)
 
74
                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
 
75
            else
 
76
                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
81
77
            break;
82
78
        }
83
79
    }
 
80
    if (s->depth == 24)
 
81
        tcx24_invalidate_display(s);
 
82
    else
 
83
        tcx_invalidate_display(s);
84
84
}
85
85
 
86
86
static void tcx_draw_line32(TCXState *s1, uint8_t *d, 
121
121
    }
122
122
}
123
123
 
 
124
static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
 
125
                                     const uint8_t *s, int width,
 
126
                                     const uint32_t *cplane,
 
127
                                     const uint32_t *s24)
 
128
{
 
129
    int x;
 
130
    uint8_t val;
 
131
    uint32_t *p = (uint32_t *)d;
 
132
    uint32_t dval;
 
133
 
 
134
    for(x = 0; x < width; x++, s++, s24++) {
 
135
        if ((bswap32(*cplane++) & 0xff000000) == 0x03000000) { // 24-bit direct
 
136
            dval = bswap32(*s24) & 0x00ffffff;
 
137
        } else {
 
138
            val = *s;
 
139
            dval = s1->palette[val];
 
140
        }
 
141
        *p++ = dval;
 
142
    }
 
143
}
 
144
 
 
145
static inline int check_dirty(TCXState *ts, ram_addr_t page, ram_addr_t page24,
 
146
                              ram_addr_t cpage)
 
147
{
 
148
    int ret;
 
149
    unsigned int off;
 
150
 
 
151
    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
 
152
    for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
 
153
        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
 
154
        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
 
155
    }
 
156
    return ret;
 
157
}
 
158
 
 
159
static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
 
160
                               ram_addr_t page_max, ram_addr_t page24,
 
161
                              ram_addr_t cpage)
 
162
{
 
163
    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
 
164
                                    VGA_DIRTY_FLAG);
 
165
    page_min -= ts->vram_offset;
 
166
    page_max -= ts->vram_offset;
 
167
    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
 
168
                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
 
169
                                    VGA_DIRTY_FLAG);
 
170
    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
 
171
                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
 
172
                                    VGA_DIRTY_FLAG);
 
173
}
 
174
 
124
175
/* Fixed line length 1024 allows us to do nice tricks not possible on
125
176
   VGA... */
126
177
static void tcx_update_display(void *opaque)
129
180
    ram_addr_t page, page_min, page_max;
130
181
    int y, y_start, dd, ds;
131
182
    uint8_t *d, *s;
132
 
    void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
 
183
    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
133
184
 
134
185
    if (ts->ds->depth == 0)
135
186
        return;
201
252
    }
202
253
}
203
254
 
 
255
static void tcx24_update_display(void *opaque)
 
256
{
 
257
    TCXState *ts = opaque;
 
258
    ram_addr_t page, page_min, page_max, cpage, page24;
 
259
    int y, y_start, dd, ds;
 
260
    uint8_t *d, *s;
 
261
    uint32_t *cptr, *s24;
 
262
 
 
263
    if (ts->ds->depth != 32)
 
264
            return;
 
265
    page = ts->vram_offset;
 
266
    page24 = ts->vram24_offset;
 
267
    cpage = ts->cplane_offset;
 
268
    y_start = -1;
 
269
    page_min = 0xffffffff;
 
270
    page_max = 0;
 
271
    d = ts->ds->data;
 
272
    s = ts->vram;
 
273
    s24 = ts->vram24;
 
274
    cptr = ts->cplane;
 
275
    dd = ts->ds->linesize;
 
276
    ds = 1024;
 
277
 
 
278
    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
 
279
            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
 
280
        if (check_dirty(ts, page, page24, cpage)) {
 
281
            if (y_start < 0)
 
282
                y_start = y;
 
283
            if (page < page_min)
 
284
                page_min = page;
 
285
            if (page > page_max)
 
286
                page_max = page;
 
287
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
 
288
            d += dd;
 
289
            s += ds;
 
290
            cptr += ds;
 
291
            s24 += ds;
 
292
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
 
293
            d += dd;
 
294
            s += ds;
 
295
            cptr += ds;
 
296
            s24 += ds;
 
297
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
 
298
            d += dd;
 
299
            s += ds;
 
300
            cptr += ds;
 
301
            s24 += ds;
 
302
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
 
303
            d += dd;
 
304
            s += ds;
 
305
            cptr += ds;
 
306
            s24 += ds;
 
307
        } else {
 
308
            if (y_start >= 0) {
 
309
                /* flush to display */
 
310
                dpy_update(ts->ds, 0, y_start,
 
311
                           ts->width, y - y_start);
 
312
                y_start = -1;
 
313
            }
 
314
            d += dd * 4;
 
315
            s += ds * 4;
 
316
            cptr += ds * 4;
 
317
            s24 += ds * 4;
 
318
        }
 
319
    }
 
320
    if (y_start >= 0) {
 
321
        /* flush to display */
 
322
        dpy_update(ts->ds, 0, y_start,
 
323
                   ts->width, y - y_start);
 
324
    }
 
325
    /* reset modified pages */
 
326
    if (page_min <= page_max) {
 
327
        reset_dirty(ts, page_min, page_max, page24, cpage);
 
328
    }
 
329
}
 
330
 
204
331
static void tcx_invalidate_display(void *opaque)
205
332
{
206
333
    TCXState *s = opaque;
211
338
    }
212
339
}
213
340
 
 
341
static void tcx24_invalidate_display(void *opaque)
 
342
{
 
343
    TCXState *s = opaque;
 
344
    int i;
 
345
 
 
346
    tcx_invalidate_display(s);
 
347
    for (i = 0; i < MAXX*MAXY * 4; i += TARGET_PAGE_SIZE) {
 
348
        cpu_physical_memory_set_dirty(s->vram24_offset + i);
 
349
        cpu_physical_memory_set_dirty(s->cplane_offset + i);
 
350
    }
 
351
}
 
352
 
214
353
static void tcx_save(QEMUFile *f, void *opaque)
215
354
{
216
355
    TCXState *s = opaque;
217
356
    
218
 
    qemu_put_be32s(f, (uint32_t *)&s->addr);
219
 
    qemu_put_be32s(f, (uint32_t *)&s->vram);
220
357
    qemu_put_be16s(f, (uint16_t *)&s->height);
221
358
    qemu_put_be16s(f, (uint16_t *)&s->width);
 
359
    qemu_put_be16s(f, (uint16_t *)&s->depth);
222
360
    qemu_put_buffer(f, s->r, 256);
223
361
    qemu_put_buffer(f, s->g, 256);
224
362
    qemu_put_buffer(f, s->b, 256);
229
367
static int tcx_load(QEMUFile *f, void *opaque, int version_id)
230
368
{
231
369
    TCXState *s = opaque;
232
 
    
233
 
    if (version_id != 1)
 
370
    uint32_t dummy;
 
371
 
 
372
    if (version_id != 3 && version_id != 4)
234
373
        return -EINVAL;
235
374
 
236
 
    qemu_get_be32s(f, (uint32_t *)&s->addr);
237
 
    qemu_get_be32s(f, (uint32_t *)&s->vram);
 
375
    if (version_id == 3) {
 
376
        qemu_get_be32s(f, (uint32_t *)&dummy);
 
377
        qemu_get_be32s(f, (uint32_t *)&dummy);
 
378
        qemu_get_be32s(f, (uint32_t *)&dummy);
 
379
    }
238
380
    qemu_get_be16s(f, (uint16_t *)&s->height);
239
381
    qemu_get_be16s(f, (uint16_t *)&s->width);
 
382
    qemu_get_be16s(f, (uint16_t *)&s->depth);
240
383
    qemu_get_buffer(f, s->r, 256);
241
384
    qemu_get_buffer(f, s->g, 256);
242
385
    qemu_get_buffer(f, s->b, 256);
243
386
    qemu_get_8s(f, &s->dac_index);
244
387
    qemu_get_8s(f, &s->dac_state);
245
388
    update_palette_entries(s, 0, 256);
 
389
    if (s->depth == 24)
 
390
        tcx24_invalidate_display(s);
 
391
    else
 
392
        tcx_invalidate_display(s);
 
393
 
246
394
    return 0;
247
395
}
248
396
 
257
405
    s->r[255] = s->g[255] = s->b[255] = 255;
258
406
    update_palette_entries(s, 0, 256);
259
407
    memset(s->vram, 0, MAXX*MAXY);
260
 
    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
261
 
                                    VGA_DIRTY_FLAG);
 
408
    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
 
409
                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
262
410
    s->dac_index = 0;
263
411
    s->dac_state = 0;
264
412
}
294
442
        case 2:
295
443
            s->b[s->dac_index] = val >> 24;
296
444
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
 
445
            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
297
446
        default:
298
447
            s->dac_state = 0;
299
448
            break;
317
466
    tcx_dac_writel,
318
467
};
319
468
 
320
 
void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
321
 
              unsigned long vram_offset, int vram_size, int width, int height)
 
469
static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
 
470
{
 
471
    return 0;
 
472
}
 
473
 
 
474
static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
 
475
                             uint32_t val)
 
476
{
 
477
}
 
478
 
 
479
static CPUReadMemoryFunc *tcx_dummy_read[3] = {
 
480
    tcx_dummy_readl,
 
481
    tcx_dummy_readl,
 
482
    tcx_dummy_readl,
 
483
};
 
484
 
 
485
static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
 
486
    tcx_dummy_writel,
 
487
    tcx_dummy_writel,
 
488
    tcx_dummy_writel,
 
489
};
 
490
 
 
491
void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base,
 
492
              unsigned long vram_offset, int vram_size, int width, int height,
 
493
              int depth)
322
494
{
323
495
    TCXState *s;
324
 
    int io_memory;
 
496
    int io_memory, dummy_memory;
 
497
    int size;
325
498
 
326
499
    s = qemu_mallocz(sizeof(TCXState));
327
500
    if (!s)
328
501
        return;
329
502
    s->ds = ds;
330
503
    s->addr = addr;
331
 
    s->vram = vram_base;
332
504
    s->vram_offset = vram_offset;
333
505
    s->width = width;
334
506
    s->height = height;
335
 
 
336
 
    cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
 
507
    s->depth = depth;
 
508
 
 
509
    // 8-bit plane
 
510
    s->vram = vram_base;
 
511
    size = vram_size;
 
512
    cpu_register_physical_memory(addr + 0x00800000ULL, size, vram_offset);
 
513
    vram_offset += size;
 
514
    vram_base += size;
 
515
 
337
516
    io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
338
 
    cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory);
339
 
 
340
 
    graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
341
 
                         tcx_screen_dump, s);
342
 
    register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
 
517
    cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, io_memory);
 
518
 
 
519
    dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write,
 
520
                                          s);
 
521
    cpu_register_physical_memory(addr + 0x00700000ULL, TCX_TEC_NREGS,
 
522
                                 dummy_memory);
 
523
    if (depth == 24) {
 
524
        // 24-bit plane
 
525
        size = vram_size * 4;
 
526
        s->vram24 = (uint32_t *)vram_base;
 
527
        s->vram24_offset = vram_offset;
 
528
        cpu_register_physical_memory(addr + 0x02000000ULL, size, vram_offset);
 
529
        vram_offset += size;
 
530
        vram_base += size;
 
531
 
 
532
        // Control plane
 
533
        size = vram_size * 4;
 
534
        s->cplane = (uint32_t *)vram_base;
 
535
        s->cplane_offset = vram_offset;
 
536
        cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset);
 
537
        graphic_console_init(s->ds, tcx24_update_display,
 
538
                             tcx24_invalidate_display, tcx24_screen_dump, s);
 
539
    } else {
 
540
        cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8,
 
541
                                     dummy_memory);
 
542
        graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
 
543
                             tcx_screen_dump, s);
 
544
    }
 
545
    // NetBSD writes here even with 8-bit display
 
546
    cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24,
 
547
                                 dummy_memory);
 
548
 
 
549
    register_savevm("tcx", addr, 4, tcx_save, tcx_load, s);
343
550
    qemu_register_reset(tcx_reset, s);
344
551
    tcx_reset(s);
345
552
    dpy_resize(s->ds, width, height);
372
579
    return;
373
580
}
374
581
 
375
 
 
376
 
 
 
582
static void tcx24_screen_dump(void *opaque, const char *filename)
 
583
{
 
584
    TCXState *s = opaque;
 
585
    FILE *f;
 
586
    uint8_t *d, *d1, v;
 
587
    uint32_t *s24, *cptr, dval;
 
588
    int y, x;
 
589
 
 
590
    f = fopen(filename, "wb");
 
591
    if (!f)
 
592
        return;
 
593
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
 
594
    d1 = s->vram;
 
595
    s24 = s->vram24;
 
596
    cptr = s->cplane;
 
597
    for(y = 0; y < s->height; y++) {
 
598
        d = d1;
 
599
        for(x = 0; x < s->width; x++, d++, s24++) {
 
600
            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
 
601
                dval = *s24 & 0x00ffffff;
 
602
                fputc((dval >> 16) & 0xff, f);
 
603
                fputc((dval >> 8) & 0xff, f);
 
604
                fputc(dval & 0xff, f);
 
605
            } else {
 
606
                v = *d;
 
607
                fputc(s->r[v], f);
 
608
                fputc(s->g[v], f);
 
609
                fputc(s->b[v], f);
 
610
            }
 
611
        }
 
612
        d1 += MAXX;
 
613
    }
 
614
    fclose(f);
 
615
    return;
 
616
}