Statistics
| Branch: | Revision:

root / hw / tcx.c @ f40070c3

History | View | Annotate | Download (18.7 kB)

1
/*
2
 * QEMU TCX Frame buffer
3
 *
4
 * Copyright (c) 2003-2005 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

    
25
#include "sun4m.h"
26
#include "console.h"
27
#include "pixel_ops.h"
28
#include "sysbus.h"
29

    
30
#define MAXX 1024
31
#define MAXY 768
32
#define TCX_DAC_NREGS 16
33
#define TCX_THC_NREGS_8  0x081c
34
#define TCX_THC_NREGS_24 0x1000
35
#define TCX_TEC_NREGS    0x1000
36

    
37
typedef struct TCXState {
38
    SysBusDevice busdev;
39
    target_phys_addr_t addr;
40
    DisplayState *ds;
41
    uint8_t *vram;
42
    uint32_t *vram24, *cplane;
43
    ram_addr_t vram_offset, vram24_offset, cplane_offset;
44
    uint16_t width, height, depth;
45
    uint8_t r[256], g[256], b[256];
46
    uint32_t palette[256];
47
    uint8_t dac_index, dac_state;
48
} TCXState;
49

    
50
static void tcx_screen_dump(void *opaque, const char *filename);
51
static void tcx24_screen_dump(void *opaque, const char *filename);
52
static void tcx_invalidate_display(void *opaque);
53
static void tcx24_invalidate_display(void *opaque);
54

    
55
static void update_palette_entries(TCXState *s, int start, int end)
56
{
57
    int i;
58
    for(i = start; i < end; i++) {
59
        switch(ds_get_bits_per_pixel(s->ds)) {
60
        default:
61
        case 8:
62
            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
63
            break;
64
        case 15:
65
            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
66
            break;
67
        case 16:
68
            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
69
            break;
70
        case 32:
71
            if (is_surface_bgr(s->ds->surface))
72
                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
73
            else
74
                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
75
            break;
76
        }
77
    }
78
    if (s->depth == 24)
79
        tcx24_invalidate_display(s);
80
    else
81
        tcx_invalidate_display(s);
82
}
83

    
84
static void tcx_draw_line32(TCXState *s1, uint8_t *d,
85
                            const uint8_t *s, int width)
86
{
87
    int x;
88
    uint8_t val;
89
    uint32_t *p = (uint32_t *)d;
90

    
91
    for(x = 0; x < width; x++) {
92
        val = *s++;
93
        *p++ = s1->palette[val];
94
    }
95
}
96

    
97
static void tcx_draw_line16(TCXState *s1, uint8_t *d,
98
                            const uint8_t *s, int width)
99
{
100
    int x;
101
    uint8_t val;
102
    uint16_t *p = (uint16_t *)d;
103

    
104
    for(x = 0; x < width; x++) {
105
        val = *s++;
106
        *p++ = s1->palette[val];
107
    }
108
}
109

    
110
static void tcx_draw_line8(TCXState *s1, uint8_t *d,
111
                           const uint8_t *s, int width)
112
{
113
    int x;
114
    uint8_t val;
115

    
116
    for(x = 0; x < width; x++) {
117
        val = *s++;
118
        *d++ = s1->palette[val];
119
    }
120
}
121

    
122
/*
123
  XXX Could be much more optimal:
124
  * detect if line/page/whole screen is in 24 bit mode
125
  * if destination is also BGR, use memcpy
126
  */
127
static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
128
                                     const uint8_t *s, int width,
129
                                     const uint32_t *cplane,
130
                                     const uint32_t *s24)
131
{
132
    int x, bgr, r, g, b;
133
    uint8_t val, *p8;
134
    uint32_t *p = (uint32_t *)d;
135
    uint32_t dval;
136

    
137
    bgr = is_surface_bgr(s1->ds->surface);
138
    for(x = 0; x < width; x++, s++, s24++) {
139
        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
140
            // 24-bit direct, BGR order
141
            p8 = (uint8_t *)s24;
142
            p8++;
143
            b = *p8++;
144
            g = *p8++;
145
            r = *p8++;
146
            if (bgr)
147
                dval = rgb_to_pixel32bgr(r, g, b);
148
            else
149
                dval = rgb_to_pixel32(r, g, b);
150
        } else {
151
            val = *s;
152
            dval = s1->palette[val];
153
        }
154
        *p++ = dval;
155
    }
156
}
157

    
158
static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
159
                              ram_addr_t cpage)
160
{
161
    int ret;
162
    unsigned int off;
163

    
164
    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
165
    for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
166
        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
167
        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
168
    }
169
    return ret;
170
}
171

    
172
static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
173
                               ram_addr_t page_max, ram_addr_t page24,
174
                              ram_addr_t cpage)
175
{
176
    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
177
                                    VGA_DIRTY_FLAG);
178
    page_min -= ts->vram_offset;
179
    page_max -= ts->vram_offset;
180
    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
181
                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
182
                                    VGA_DIRTY_FLAG);
183
    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
184
                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
185
                                    VGA_DIRTY_FLAG);
186
}
187

    
188
/* Fixed line length 1024 allows us to do nice tricks not possible on
189
   VGA... */
190
static void tcx_update_display(void *opaque)
191
{
192
    TCXState *ts = opaque;
193
    ram_addr_t page, page_min, page_max;
194
    int y, y_start, dd, ds;
195
    uint8_t *d, *s;
196
    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
197

    
198
    if (ds_get_bits_per_pixel(ts->ds) == 0)
199
        return;
200
    page = ts->vram_offset;
201
    y_start = -1;
202
    page_min = -1;
203
    page_max = 0;
204
    d = ds_get_data(ts->ds);
205
    s = ts->vram;
206
    dd = ds_get_linesize(ts->ds);
207
    ds = 1024;
208

    
209
    switch (ds_get_bits_per_pixel(ts->ds)) {
210
    case 32:
211
        f = tcx_draw_line32;
212
        break;
213
    case 15:
214
    case 16:
215
        f = tcx_draw_line16;
216
        break;
217
    default:
218
    case 8:
219
        f = tcx_draw_line8;
220
        break;
221
    case 0:
222
        return;
223
    }
224

    
225
    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
226
        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
227
            if (y_start < 0)
228
                y_start = y;
229
            if (page < page_min)
230
                page_min = page;
231
            if (page > page_max)
232
                page_max = page;
233
            f(ts, d, s, ts->width);
234
            d += dd;
235
            s += ds;
236
            f(ts, d, s, ts->width);
237
            d += dd;
238
            s += ds;
239
            f(ts, d, s, ts->width);
240
            d += dd;
241
            s += ds;
242
            f(ts, d, s, ts->width);
243
            d += dd;
244
            s += ds;
245
        } else {
246
            if (y_start >= 0) {
247
                /* flush to display */
248
                dpy_update(ts->ds, 0, y_start,
249
                           ts->width, y - y_start);
250
                y_start = -1;
251
            }
252
            d += dd * 4;
253
            s += ds * 4;
254
        }
255
    }
256
    if (y_start >= 0) {
257
        /* flush to display */
258
        dpy_update(ts->ds, 0, y_start,
259
                   ts->width, y - y_start);
260
    }
261
    /* reset modified pages */
262
    if (page_max >= page_min) {
263
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
264
                                        VGA_DIRTY_FLAG);
265
    }
266
}
267

    
268
static void tcx24_update_display(void *opaque)
269
{
270
    TCXState *ts = opaque;
271
    ram_addr_t page, page_min, page_max, cpage, page24;
272
    int y, y_start, dd, ds;
273
    uint8_t *d, *s;
274
    uint32_t *cptr, *s24;
275

    
276
    if (ds_get_bits_per_pixel(ts->ds) != 32)
277
            return;
278
    page = ts->vram_offset;
279
    page24 = ts->vram24_offset;
280
    cpage = ts->cplane_offset;
281
    y_start = -1;
282
    page_min = -1;
283
    page_max = 0;
284
    d = ds_get_data(ts->ds);
285
    s = ts->vram;
286
    s24 = ts->vram24;
287
    cptr = ts->cplane;
288
    dd = ds_get_linesize(ts->ds);
289
    ds = 1024;
290

    
291
    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
292
            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
293
        if (check_dirty(page, page24, cpage)) {
294
            if (y_start < 0)
295
                y_start = y;
296
            if (page < page_min)
297
                page_min = page;
298
            if (page > page_max)
299
                page_max = page;
300
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
301
            d += dd;
302
            s += ds;
303
            cptr += ds;
304
            s24 += ds;
305
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
306
            d += dd;
307
            s += ds;
308
            cptr += ds;
309
            s24 += ds;
310
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
311
            d += dd;
312
            s += ds;
313
            cptr += ds;
314
            s24 += ds;
315
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
316
            d += dd;
317
            s += ds;
318
            cptr += ds;
319
            s24 += ds;
320
        } else {
321
            if (y_start >= 0) {
322
                /* flush to display */
323
                dpy_update(ts->ds, 0, y_start,
324
                           ts->width, y - y_start);
325
                y_start = -1;
326
            }
327
            d += dd * 4;
328
            s += ds * 4;
329
            cptr += ds * 4;
330
            s24 += ds * 4;
331
        }
332
    }
333
    if (y_start >= 0) {
334
        /* flush to display */
335
        dpy_update(ts->ds, 0, y_start,
336
                   ts->width, y - y_start);
337
    }
338
    /* reset modified pages */
339
    if (page_max >= page_min) {
340
        reset_dirty(ts, page_min, page_max, page24, cpage);
341
    }
342
}
343

    
344
static void tcx_invalidate_display(void *opaque)
345
{
346
    TCXState *s = opaque;
347
    int i;
348

    
349
    for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
350
        cpu_physical_memory_set_dirty(s->vram_offset + i);
351
    }
352
}
353

    
354
static void tcx24_invalidate_display(void *opaque)
355
{
356
    TCXState *s = opaque;
357
    int i;
358

    
359
    tcx_invalidate_display(s);
360
    for (i = 0; i < MAXX*MAXY * 4; i += TARGET_PAGE_SIZE) {
361
        cpu_physical_memory_set_dirty(s->vram24_offset + i);
362
        cpu_physical_memory_set_dirty(s->cplane_offset + i);
363
    }
364
}
365

    
366
static void tcx_save(QEMUFile *f, void *opaque)
367
{
368
    TCXState *s = opaque;
369

    
370
    qemu_put_be16s(f, &s->height);
371
    qemu_put_be16s(f, &s->width);
372
    qemu_put_be16s(f, &s->depth);
373
    qemu_put_buffer(f, s->r, 256);
374
    qemu_put_buffer(f, s->g, 256);
375
    qemu_put_buffer(f, s->b, 256);
376
    qemu_put_8s(f, &s->dac_index);
377
    qemu_put_8s(f, &s->dac_state);
378
}
379

    
380
static int tcx_load(QEMUFile *f, void *opaque, int version_id)
381
{
382
    TCXState *s = opaque;
383
    uint32_t dummy;
384

    
385
    if (version_id != 3 && version_id != 4)
386
        return -EINVAL;
387

    
388
    if (version_id == 3) {
389
        qemu_get_be32s(f, &dummy);
390
        qemu_get_be32s(f, &dummy);
391
        qemu_get_be32s(f, &dummy);
392
    }
393
    qemu_get_be16s(f, &s->height);
394
    qemu_get_be16s(f, &s->width);
395
    qemu_get_be16s(f, &s->depth);
396
    qemu_get_buffer(f, s->r, 256);
397
    qemu_get_buffer(f, s->g, 256);
398
    qemu_get_buffer(f, s->b, 256);
399
    qemu_get_8s(f, &s->dac_index);
400
    qemu_get_8s(f, &s->dac_state);
401
    update_palette_entries(s, 0, 256);
402
    if (s->depth == 24)
403
        tcx24_invalidate_display(s);
404
    else
405
        tcx_invalidate_display(s);
406

    
407
    return 0;
408
}
409

    
410
static void tcx_reset(void *opaque)
411
{
412
    TCXState *s = opaque;
413

    
414
    /* Initialize palette */
415
    memset(s->r, 0, 256);
416
    memset(s->g, 0, 256);
417
    memset(s->b, 0, 256);
418
    s->r[255] = s->g[255] = s->b[255] = 255;
419
    update_palette_entries(s, 0, 256);
420
    memset(s->vram, 0, MAXX*MAXY);
421
    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
422
                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
423
    s->dac_index = 0;
424
    s->dac_state = 0;
425
}
426

    
427
static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
428
{
429
    return 0;
430
}
431

    
432
static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
433
{
434
    TCXState *s = opaque;
435

    
436
    switch (addr) {
437
    case 0:
438
        s->dac_index = val >> 24;
439
        s->dac_state = 0;
440
        break;
441
    case 4:
442
        switch (s->dac_state) {
443
        case 0:
444
            s->r[s->dac_index] = val >> 24;
445
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
446
            s->dac_state++;
447
            break;
448
        case 1:
449
            s->g[s->dac_index] = val >> 24;
450
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
451
            s->dac_state++;
452
            break;
453
        case 2:
454
            s->b[s->dac_index] = val >> 24;
455
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
456
            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
457
        default:
458
            s->dac_state = 0;
459
            break;
460
        }
461
        break;
462
    default:
463
        break;
464
    }
465
    return;
466
}
467

    
468
static CPUReadMemoryFunc *tcx_dac_read[3] = {
469
    NULL,
470
    NULL,
471
    tcx_dac_readl,
472
};
473

    
474
static CPUWriteMemoryFunc *tcx_dac_write[3] = {
475
    NULL,
476
    NULL,
477
    tcx_dac_writel,
478
};
479

    
480
static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
481
{
482
    return 0;
483
}
484

    
485
static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
486
                             uint32_t val)
487
{
488
}
489

    
490
static CPUReadMemoryFunc *tcx_dummy_read[3] = {
491
    NULL,
492
    NULL,
493
    tcx_dummy_readl,
494
};
495

    
496
static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
497
    NULL,
498
    NULL,
499
    tcx_dummy_writel,
500
};
501

    
502
void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height,
503
              int depth)
504
{
505
    DeviceState *dev;
506
    SysBusDevice *s;
507

    
508
    dev = qdev_create(NULL, "SUNW,tcx");
509
    qdev_set_prop_int(dev, "addr", addr);
510
    qdev_set_prop_int(dev, "vram_size", vram_size);
511
    qdev_set_prop_int(dev, "width", width);
512
    qdev_set_prop_int(dev, "height", height);
513
    qdev_set_prop_int(dev, "depth", depth);
514
    qdev_init(dev);
515
    s = sysbus_from_qdev(dev);
516
    /* 8-bit plane */
517
    sysbus_mmio_map(s, 0, addr + 0x00800000ULL);
518
    /* DAC */
519
    sysbus_mmio_map(s, 1, addr + 0x00200000ULL);
520
    /* TEC (dummy) */
521
    sysbus_mmio_map(s, 2, addr + 0x00700000ULL);
522
    /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */
523
    sysbus_mmio_map(s, 3, addr + 0x00301000ULL);
524
    if (depth == 24) {
525
        /* 24-bit plane */
526
        sysbus_mmio_map(s, 4, addr + 0x02000000ULL);
527
        /* Control plane */
528
        sysbus_mmio_map(s, 5, addr + 0x0a000000ULL);
529
    } else {
530
        /* THC 8 bit (dummy) */
531
        sysbus_mmio_map(s, 4, addr + 0x00300000ULL);
532
    }
533
}
534

    
535
static void tcx_init1(SysBusDevice *dev)
536
{
537
    TCXState *s = FROM_SYSBUS(TCXState, dev);
538
    int io_memory, dummy_memory;
539
    ram_addr_t vram_offset;
540
    int size, vram_size;
541
    uint8_t *vram_base;
542

    
543
    vram_size = qdev_get_prop_int(&dev->qdev, "vram_size", -1);
544

    
545
    vram_offset = qemu_ram_alloc(vram_size * (1 + 4 + 4));
546
    vram_base = qemu_get_ram_ptr(vram_offset);
547
    s->addr = qdev_get_prop_int(&dev->qdev, "addr", -1);
548
    s->vram_offset = vram_offset;
549
    s->width = qdev_get_prop_int(&dev->qdev, "width", -1);
550
    s->height = qdev_get_prop_int(&dev->qdev, "height", -1);
551
    s->depth = qdev_get_prop_int(&dev->qdev, "depth", -1);
552

    
553
    /* 8-bit plane */
554
    s->vram = vram_base;
555
    size = vram_size;
556
    sysbus_init_mmio(dev, size, s->vram_offset);
557
    vram_offset += size;
558
    vram_base += size;
559

    
560
    /* DAC */
561
    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s);
562
    sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
563

    
564
    /* TEC (dummy) */
565
    dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
566
                                          s);
567
    sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
568
    /* THC: NetBSD writes here even with 8-bit display: dummy */
569
    sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
570

    
571
    if (s->depth == 24) {
572
        /* 24-bit plane */
573
        size = vram_size * 4;
574
        s->vram24 = (uint32_t *)vram_base;
575
        s->vram24_offset = vram_offset;
576
        sysbus_init_mmio(dev, size, vram_offset);
577
        vram_offset += size;
578
        vram_base += size;
579

    
580
        /* Control plane */
581
        size = vram_size * 4;
582
        s->cplane = (uint32_t *)vram_base;
583
        s->cplane_offset = vram_offset;
584
        sysbus_init_mmio(dev, size, vram_offset);
585

    
586
        s->ds = graphic_console_init(tcx24_update_display,
587
                                     tcx24_invalidate_display,
588
                                     tcx24_screen_dump, NULL, s);
589
    } else {
590
        /* THC 8 bit (dummy) */
591
        sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
592

    
593
        s->ds = graphic_console_init(tcx_update_display,
594
                                     tcx_invalidate_display,
595
                                     tcx_screen_dump, NULL, s);
596
    }
597

    
598
    register_savevm("tcx", -1, 4, tcx_save, tcx_load, s);
599
    qemu_register_reset(tcx_reset, s);
600
    tcx_reset(s);
601
    qemu_console_resize(s->ds, s->width, s->height);
602
}
603

    
604
static void tcx_screen_dump(void *opaque, const char *filename)
605
{
606
    TCXState *s = opaque;
607
    FILE *f;
608
    uint8_t *d, *d1, v;
609
    int y, x;
610

    
611
    f = fopen(filename, "wb");
612
    if (!f)
613
        return;
614
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
615
    d1 = s->vram;
616
    for(y = 0; y < s->height; y++) {
617
        d = d1;
618
        for(x = 0; x < s->width; x++) {
619
            v = *d;
620
            fputc(s->r[v], f);
621
            fputc(s->g[v], f);
622
            fputc(s->b[v], f);
623
            d++;
624
        }
625
        d1 += MAXX;
626
    }
627
    fclose(f);
628
    return;
629
}
630

    
631
static void tcx24_screen_dump(void *opaque, const char *filename)
632
{
633
    TCXState *s = opaque;
634
    FILE *f;
635
    uint8_t *d, *d1, v;
636
    uint32_t *s24, *cptr, dval;
637
    int y, x;
638

    
639
    f = fopen(filename, "wb");
640
    if (!f)
641
        return;
642
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
643
    d1 = s->vram;
644
    s24 = s->vram24;
645
    cptr = s->cplane;
646
    for(y = 0; y < s->height; y++) {
647
        d = d1;
648
        for(x = 0; x < s->width; x++, d++, s24++) {
649
            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
650
                dval = *s24 & 0x00ffffff;
651
                fputc((dval >> 16) & 0xff, f);
652
                fputc((dval >> 8) & 0xff, f);
653
                fputc(dval & 0xff, f);
654
            } else {
655
                v = *d;
656
                fputc(s->r[v], f);
657
                fputc(s->g[v], f);
658
                fputc(s->b[v], f);
659
            }
660
        }
661
        d1 += MAXX;
662
    }
663
    fclose(f);
664
    return;
665
}
666

    
667
static void tcx_register_devices(void)
668
{
669
    sysbus_register_dev("SUNW,tcx", sizeof(TCXState), tcx_init1);
670
}
671

    
672
device_init(tcx_register_devices)