|
|
1.1 root 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:
1.1.1.2 ! root 40: static void tcx_screen_dump(void *opaque, const char *filename);
! 41:
1.1 root 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... */
1.1.1.2 ! root 86: static void tcx_update_display(void *opaque)
1.1 root 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:
1.1.1.2 ! root 163: static void tcx_invalidate_display(void *opaque)
1.1 root 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:
1.1.1.2 ! root 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)
1.1 root 276: {
277: TCXState *s;
278: int io_memory;
279:
280: s = qemu_mallocz(sizeof(TCXState));
281: if (!s)
1.1.1.2 ! root 282: return;
1.1 root 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:
1.1.1.2 ! root 294: graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
! 295: tcx_screen_dump, s);
1.1 root 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:
1.1.1.2 ! root 302: static void tcx_screen_dump(void *opaque, const char *filename)
1.1 root 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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.