|
|
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;
1.1.1.3 ! root 34: ram_addr_t vram_offset;
1.1 root 35: uint16_t width, height;
36: uint8_t r[256], g[256], b[256];
1.1.1.3 ! root 37: uint32_t palette[256];
1.1 root 38: uint8_t dac_index, dac_state;
39: } TCXState;
40:
1.1.1.2 root 41: static void tcx_screen_dump(void *opaque, const char *filename);
42:
1.1.1.3 ! root 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: }
! 63:
! 64: static void update_palette_entries(TCXState *s, int start, int end)
! 65: {
! 66: int i;
! 67: for(i = start; i < end; i++) {
! 68: switch(s->ds->depth) {
! 69: default:
! 70: case 8:
! 71: s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
! 72: break;
! 73: case 15:
! 74: s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
! 75: break;
! 76: case 16:
! 77: s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
! 78: break;
! 79: case 32:
! 80: s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
! 81: break;
! 82: }
! 83: }
! 84: }
! 85:
1.1 root 86: static void tcx_draw_line32(TCXState *s1, uint8_t *d,
87: const uint8_t *s, int width)
88: {
89: int x;
90: uint8_t val;
1.1.1.3 ! root 91: uint32_t *p = (uint32_t *)d;
1.1 root 92:
93: for(x = 0; x < width; x++) {
94: val = *s++;
1.1.1.3 ! root 95: *p++ = s1->palette[val];
1.1 root 96: }
97: }
98:
1.1.1.3 ! root 99: static void tcx_draw_line16(TCXState *s1, uint8_t *d,
1.1 root 100: const uint8_t *s, int width)
101: {
102: int x;
103: uint8_t val;
1.1.1.3 ! root 104: uint16_t *p = (uint16_t *)d;
1.1 root 105:
106: for(x = 0; x < width; x++) {
107: val = *s++;
1.1.1.3 ! root 108: *p++ = s1->palette[val];
1.1 root 109: }
110: }
111:
112: static void tcx_draw_line8(TCXState *s1, uint8_t *d,
113: const uint8_t *s, int width)
114: {
115: int x;
116: uint8_t val;
117:
118: for(x = 0; x < width; x++) {
119: val = *s++;
1.1.1.3 ! root 120: *d++ = s1->palette[val];
1.1 root 121: }
122: }
123:
124: /* Fixed line length 1024 allows us to do nice tricks not possible on
125: VGA... */
1.1.1.2 root 126: static void tcx_update_display(void *opaque)
1.1 root 127: {
128: TCXState *ts = opaque;
1.1.1.3 ! root 129: ram_addr_t page, page_min, page_max;
! 130: int y, y_start, dd, ds;
1.1 root 131: uint8_t *d, *s;
132: void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
133:
134: if (ts->ds->depth == 0)
135: return;
136: page = ts->vram_offset;
137: y_start = -1;
1.1.1.3 ! root 138: page_min = 0xffffffff;
! 139: page_max = 0;
1.1 root 140: d = ts->ds->data;
141: s = ts->vram;
142: dd = ts->ds->linesize;
143: ds = 1024;
144:
145: switch (ts->ds->depth) {
146: case 32:
147: f = tcx_draw_line32;
148: break;
1.1.1.3 ! root 149: case 15:
! 150: case 16:
! 151: f = tcx_draw_line16;
1.1 root 152: break;
153: default:
154: case 8:
155: f = tcx_draw_line8;
156: break;
157: case 0:
158: return;
159: }
160:
161: for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
162: if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
163: if (y_start < 0)
164: y_start = y;
165: if (page < page_min)
166: page_min = page;
167: if (page > page_max)
168: page_max = page;
169: f(ts, d, s, ts->width);
170: d += dd;
171: s += ds;
172: f(ts, d, s, ts->width);
173: d += dd;
174: s += ds;
175: f(ts, d, s, ts->width);
176: d += dd;
177: s += ds;
178: f(ts, d, s, ts->width);
179: d += dd;
180: s += ds;
181: } else {
182: if (y_start >= 0) {
183: /* flush to display */
184: dpy_update(ts->ds, 0, y_start,
185: ts->width, y - y_start);
186: y_start = -1;
187: }
188: d += dd * 4;
189: s += ds * 4;
190: }
191: }
192: if (y_start >= 0) {
193: /* flush to display */
194: dpy_update(ts->ds, 0, y_start,
195: ts->width, y - y_start);
196: }
197: /* reset modified pages */
1.1.1.3 ! root 198: if (page_min <= page_max) {
1.1 root 199: cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
200: VGA_DIRTY_FLAG);
201: }
202: }
203:
1.1.1.2 root 204: static void tcx_invalidate_display(void *opaque)
1.1 root 205: {
206: TCXState *s = opaque;
207: int i;
208:
209: for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
210: cpu_physical_memory_set_dirty(s->vram_offset + i);
211: }
212: }
213:
214: static void tcx_save(QEMUFile *f, void *opaque)
215: {
216: TCXState *s = opaque;
217:
218: qemu_put_be32s(f, (uint32_t *)&s->addr);
219: qemu_put_be32s(f, (uint32_t *)&s->vram);
220: qemu_put_be16s(f, (uint16_t *)&s->height);
221: qemu_put_be16s(f, (uint16_t *)&s->width);
222: qemu_put_buffer(f, s->r, 256);
223: qemu_put_buffer(f, s->g, 256);
224: qemu_put_buffer(f, s->b, 256);
225: qemu_put_8s(f, &s->dac_index);
226: qemu_put_8s(f, &s->dac_state);
227: }
228:
229: static int tcx_load(QEMUFile *f, void *opaque, int version_id)
230: {
231: TCXState *s = opaque;
232:
233: if (version_id != 1)
234: return -EINVAL;
235:
236: qemu_get_be32s(f, (uint32_t *)&s->addr);
237: qemu_get_be32s(f, (uint32_t *)&s->vram);
238: qemu_get_be16s(f, (uint16_t *)&s->height);
239: qemu_get_be16s(f, (uint16_t *)&s->width);
240: qemu_get_buffer(f, s->r, 256);
241: qemu_get_buffer(f, s->g, 256);
242: qemu_get_buffer(f, s->b, 256);
243: qemu_get_8s(f, &s->dac_index);
244: qemu_get_8s(f, &s->dac_state);
1.1.1.3 ! root 245: update_palette_entries(s, 0, 256);
1.1 root 246: return 0;
247: }
248:
249: static void tcx_reset(void *opaque)
250: {
251: TCXState *s = opaque;
252:
253: /* Initialize palette */
254: memset(s->r, 0, 256);
255: memset(s->g, 0, 256);
256: memset(s->b, 0, 256);
257: s->r[255] = s->g[255] = s->b[255] = 255;
1.1.1.3 ! root 258: update_palette_entries(s, 0, 256);
1.1 root 259: memset(s->vram, 0, MAXX*MAXY);
260: cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
261: VGA_DIRTY_FLAG);
262: s->dac_index = 0;
263: s->dac_state = 0;
264: }
265:
266: static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
267: {
268: return 0;
269: }
270:
271: static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
272: {
273: TCXState *s = opaque;
274: uint32_t saddr;
275:
276: saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2;
277: switch (saddr) {
278: case 0:
279: s->dac_index = val >> 24;
280: s->dac_state = 0;
281: break;
282: case 1:
283: switch (s->dac_state) {
284: case 0:
285: s->r[s->dac_index] = val >> 24;
1.1.1.3 ! root 286: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1 root 287: s->dac_state++;
288: break;
289: case 1:
290: s->g[s->dac_index] = val >> 24;
1.1.1.3 ! root 291: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1 root 292: s->dac_state++;
293: break;
294: case 2:
295: s->b[s->dac_index] = val >> 24;
1.1.1.3 ! root 296: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1 root 297: default:
298: s->dac_state = 0;
299: break;
300: }
301: break;
302: default:
303: break;
304: }
305: return;
306: }
307:
308: static CPUReadMemoryFunc *tcx_dac_read[3] = {
309: tcx_dac_readl,
310: tcx_dac_readl,
311: tcx_dac_readl,
312: };
313:
314: static CPUWriteMemoryFunc *tcx_dac_write[3] = {
315: tcx_dac_writel,
316: tcx_dac_writel,
317: tcx_dac_writel,
318: };
319:
1.1.1.2 root 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)
1.1 root 322: {
323: TCXState *s;
324: int io_memory;
325:
326: s = qemu_mallocz(sizeof(TCXState));
327: if (!s)
1.1.1.2 root 328: return;
1.1 root 329: s->ds = ds;
330: s->addr = addr;
331: s->vram = vram_base;
332: s->vram_offset = vram_offset;
333: s->width = width;
334: s->height = height;
335:
336: cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
337: 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:
1.1.1.2 root 340: graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
341: tcx_screen_dump, s);
1.1 root 342: register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
343: qemu_register_reset(tcx_reset, s);
344: tcx_reset(s);
345: dpy_resize(s->ds, width, height);
346: }
347:
1.1.1.2 root 348: static void tcx_screen_dump(void *opaque, const char *filename)
1.1 root 349: {
350: TCXState *s = opaque;
351: FILE *f;
352: uint8_t *d, *d1, v;
353: int y, x;
354:
355: f = fopen(filename, "wb");
356: if (!f)
357: return;
358: fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
359: d1 = s->vram;
360: for(y = 0; y < s->height; y++) {
361: d = d1;
362: for(x = 0; x < s->width; x++) {
363: v = *d;
364: fputc(s->r[v], f);
365: fputc(s->g[v], f);
366: fputc(s->b[v], f);
367: d++;
368: }
369: d1 += MAXX;
370: }
371: fclose(f);
372: return;
373: }
374:
375:
376:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.