Statistics
| Branch: | Revision:

root / hw / tcx.c @ 95219897

History | View | Annotate | Download (7.9 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
#include "vl.h"
25

    
26
#define MAXX 1024
27
#define MAXY 768
28
#define TCX_DAC_NREGS 16
29

    
30
typedef struct TCXState {
31
    uint32_t addr;
32
    DisplayState *ds;
33
    uint8_t *vram;
34
    unsigned long vram_offset;
35
    uint16_t width, height;
36
    uint8_t r[256], g[256], b[256];
37
    uint8_t dac_index, dac_state;
38
} TCXState;
39

    
40
static void tcx_screen_dump(void *opaque, const char *filename);
41

    
42
static void tcx_draw_line32(TCXState *s1, uint8_t *d, 
43
                            const uint8_t *s, int width)
44
{
45
    int x;
46
    uint8_t val;
47

    
48
    for(x = 0; x < width; x++) {
49
        val = *s++;
50
        *d++ = s1->b[val];
51
        *d++ = s1->g[val];
52
        *d++ = s1->r[val];
53
        d++;
54
    }
55
}
56

    
57
static void tcx_draw_line24(TCXState *s1, uint8_t *d, 
58
                            const uint8_t *s, int width)
59
{
60
    int x;
61
    uint8_t val;
62

    
63
    for(x = 0; x < width; x++) {
64
        val = *s++;
65
        *d++ = s1->b[val];
66
        *d++ = s1->g[val];
67
        *d++ = s1->r[val];
68
    }
69
}
70

    
71
static void tcx_draw_line8(TCXState *s1, uint8_t *d, 
72
                           const uint8_t *s, int width)
73
{
74
    int x;
75
    uint8_t val;
76

    
77
    for(x = 0; x < width; x++) {
78
        val = *s++;
79
        /* XXX translate between palettes? */
80
        *d++ = val;
81
    }
82
}
83

    
84
/* Fixed line length 1024 allows us to do nice tricks not possible on
85
   VGA... */
86
static void tcx_update_display(void *opaque)
87
{
88
    TCXState *ts = opaque;
89
    uint32_t page;
90
    int y, page_min, page_max, y_start, dd, ds;
91
    uint8_t *d, *s;
92
    void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
93

    
94
    if (ts->ds->depth == 0)
95
        return;
96
    page = ts->vram_offset;
97
    y_start = -1;
98
    page_min = 0x7fffffff;
99
    page_max = -1;
100
    d = ts->ds->data;
101
    s = ts->vram;
102
    dd = ts->ds->linesize;
103
    ds = 1024;
104

    
105
    switch (ts->ds->depth) {
106
    case 32:
107
        f = tcx_draw_line32;
108
        break;
109
    case 24:
110
        f = tcx_draw_line24;
111
        break;
112
    default:
113
    case 8:
114
        f = tcx_draw_line8;
115
        break;
116
    case 0:
117
        return;
118
    }
119
    
120
    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
121
        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
122
            if (y_start < 0)
123
                y_start = y;
124
            if (page < page_min)
125
                page_min = page;
126
            if (page > page_max)
127
                page_max = page;
128
            f(ts, d, s, ts->width);
129
            d += dd;
130
            s += ds;
131
            f(ts, d, s, ts->width);
132
            d += dd;
133
            s += ds;
134
            f(ts, d, s, ts->width);
135
            d += dd;
136
            s += ds;
137
            f(ts, d, s, ts->width);
138
            d += dd;
139
            s += ds;
140
        } else {
141
            if (y_start >= 0) {
142
                /* flush to display */
143
                dpy_update(ts->ds, 0, y_start, 
144
                           ts->width, y - y_start);
145
                y_start = -1;
146
            }
147
            d += dd * 4;
148
            s += ds * 4;
149
        }
150
    }
151
    if (y_start >= 0) {
152
        /* flush to display */
153
        dpy_update(ts->ds, 0, y_start, 
154
                   ts->width, y - y_start);
155
    }
156
    /* reset modified pages */
157
    if (page_max != -1) {
158
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
159
                                        VGA_DIRTY_FLAG);
160
    }
161
}
162

    
163
static void tcx_invalidate_display(void *opaque)
164
{
165
    TCXState *s = opaque;
166
    int i;
167

    
168
    for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
169
        cpu_physical_memory_set_dirty(s->vram_offset + i);
170
    }
171
}
172

    
173
static void tcx_save(QEMUFile *f, void *opaque)
174
{
175
    TCXState *s = opaque;
176
    
177
    qemu_put_be32s(f, (uint32_t *)&s->addr);
178
    qemu_put_be32s(f, (uint32_t *)&s->vram);
179
    qemu_put_be16s(f, (uint16_t *)&s->height);
180
    qemu_put_be16s(f, (uint16_t *)&s->width);
181
    qemu_put_buffer(f, s->r, 256);
182
    qemu_put_buffer(f, s->g, 256);
183
    qemu_put_buffer(f, s->b, 256);
184
    qemu_put_8s(f, &s->dac_index);
185
    qemu_put_8s(f, &s->dac_state);
186
}
187

    
188
static int tcx_load(QEMUFile *f, void *opaque, int version_id)
189
{
190
    TCXState *s = opaque;
191
    
192
    if (version_id != 1)
193
        return -EINVAL;
194

    
195
    qemu_get_be32s(f, (uint32_t *)&s->addr);
196
    qemu_get_be32s(f, (uint32_t *)&s->vram);
197
    qemu_get_be16s(f, (uint16_t *)&s->height);
198
    qemu_get_be16s(f, (uint16_t *)&s->width);
199
    qemu_get_buffer(f, s->r, 256);
200
    qemu_get_buffer(f, s->g, 256);
201
    qemu_get_buffer(f, s->b, 256);
202
    qemu_get_8s(f, &s->dac_index);
203
    qemu_get_8s(f, &s->dac_state);
204
    return 0;
205
}
206

    
207
static void tcx_reset(void *opaque)
208
{
209
    TCXState *s = opaque;
210

    
211
    /* Initialize palette */
212
    memset(s->r, 0, 256);
213
    memset(s->g, 0, 256);
214
    memset(s->b, 0, 256);
215
    s->r[255] = s->g[255] = s->b[255] = 255;
216
    memset(s->vram, 0, MAXX*MAXY);
217
    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
218
                                    VGA_DIRTY_FLAG);
219
    s->dac_index = 0;
220
    s->dac_state = 0;
221
}
222

    
223
static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
224
{
225
    return 0;
226
}
227

    
228
static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
229
{
230
    TCXState *s = opaque;
231
    uint32_t saddr;
232

    
233
    saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2;
234
    switch (saddr) {
235
    case 0:
236
        s->dac_index = val >> 24;
237
        s->dac_state = 0;
238
        break;
239
    case 1:
240
        switch (s->dac_state) {
241
        case 0:
242
            s->r[s->dac_index] = val >> 24;
243
            s->dac_state++;
244
            break;
245
        case 1:
246
            s->g[s->dac_index] = val >> 24;
247
            s->dac_state++;
248
            break;
249
        case 2:
250
            s->b[s->dac_index] = val >> 24;
251
        default:
252
            s->dac_state = 0;
253
            break;
254
        }
255
        break;
256
    default:
257
        break;
258
    }
259
    return;
260
}
261

    
262
static CPUReadMemoryFunc *tcx_dac_read[3] = {
263
    tcx_dac_readl,
264
    tcx_dac_readl,
265
    tcx_dac_readl,
266
};
267

    
268
static CPUWriteMemoryFunc *tcx_dac_write[3] = {
269
    tcx_dac_writel,
270
    tcx_dac_writel,
271
    tcx_dac_writel,
272
};
273

    
274
void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
275
              unsigned long vram_offset, int vram_size, int width, int height)
276
{
277
    TCXState *s;
278
    int io_memory;
279

    
280
    s = qemu_mallocz(sizeof(TCXState));
281
    if (!s)
282
        return;
283
    s->ds = ds;
284
    s->addr = addr;
285
    s->vram = vram_base;
286
    s->vram_offset = vram_offset;
287
    s->width = width;
288
    s->height = height;
289

    
290
    cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
291
    io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
292
    cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory);
293

    
294
    graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
295
                         tcx_screen_dump, s);
296
    register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
297
    qemu_register_reset(tcx_reset, s);
298
    tcx_reset(s);
299
    dpy_resize(s->ds, width, height);
300
}
301

    
302
static void tcx_screen_dump(void *opaque, const char *filename)
303
{
304
    TCXState *s = opaque;
305
    FILE *f;
306
    uint8_t *d, *d1, v;
307
    int y, x;
308

    
309
    f = fopen(filename, "wb");
310
    if (!f)
311
        return;
312
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
313
    d1 = s->vram;
314
    for(y = 0; y < s->height; y++) {
315
        d = d1;
316
        for(x = 0; x < s->width; x++) {
317
            v = *d;
318
            fputc(s->r[v], f);
319
            fputc(s->g[v], f);
320
            fputc(s->b[v], f);
321
            d++;
322
        }
323
        d1 += MAXX;
324
    }
325
    fclose(f);
326
    return;
327
}
328

    
329

    
330