|
|
1.1 root 1: /*
2: * QEMU TCX Frame buffer
1.1.1.4 root 3: *
1.1 root 4: * Copyright (c) 2003-2005 Fabrice Bellard
1.1.1.4 root 5: *
1.1 root 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: */
1.1.1.6 root 24:
1.1.1.4 root 25: #include "console.h"
26: #include "pixel_ops.h"
1.1.1.6 root 27: #include "sysbus.h"
28: #include "qdev-addr.h"
1.1 root 29:
30: #define MAXX 1024
31: #define MAXY 768
32: #define TCX_DAC_NREGS 16
1.1.1.4 root 33: #define TCX_THC_NREGS_8 0x081c
34: #define TCX_THC_NREGS_24 0x1000
35: #define TCX_TEC_NREGS 0x1000
1.1 root 36:
37: typedef struct TCXState {
1.1.1.6 root 38: SysBusDevice busdev;
1.1.1.4 root 39: target_phys_addr_t addr;
1.1 root 40: DisplayState *ds;
41: uint8_t *vram;
1.1.1.4 root 42: uint32_t *vram24, *cplane;
1.1.1.10! root 43: MemoryRegion vram_mem;
! 44: MemoryRegion vram_8bit;
! 45: MemoryRegion vram_24bit;
! 46: MemoryRegion vram_cplane;
! 47: MemoryRegion dac;
! 48: MemoryRegion tec;
! 49: MemoryRegion thc24;
! 50: MemoryRegion thc8;
! 51: ram_addr_t vram24_offset, cplane_offset;
1.1.1.6 root 52: uint32_t vram_size;
1.1.1.3 root 53: uint32_t palette[256];
1.1.1.10! root 54: uint8_t r[256], g[256], b[256];
! 55: uint16_t width, height, depth;
1.1 root 56: uint8_t dac_index, dac_state;
57: } TCXState;
58:
1.1.1.2 root 59: static void tcx_screen_dump(void *opaque, const char *filename);
1.1.1.4 root 60: static void tcx24_screen_dump(void *opaque, const char *filename);
1.1.1.6 root 61:
62: static void tcx_set_dirty(TCXState *s)
63: {
64: unsigned int i;
65:
66: for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
1.1.1.10! root 67: memory_region_set_dirty(&s->vram_mem, i);
1.1.1.6 root 68: }
69: }
70:
71: static void tcx24_set_dirty(TCXState *s)
72: {
73: unsigned int i;
74:
75: for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
1.1.1.10! root 76: memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
! 77: memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
1.1.1.6 root 78: }
79: }
1.1.1.3 root 80:
81: static void update_palette_entries(TCXState *s, int start, int end)
82: {
83: int i;
84: for(i = start; i < end; i++) {
1.1.1.5 root 85: switch(ds_get_bits_per_pixel(s->ds)) {
1.1.1.3 root 86: default:
87: case 8:
88: s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
89: break;
90: case 15:
1.1.1.5 root 91: s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
1.1.1.3 root 92: break;
93: case 16:
1.1.1.5 root 94: s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
1.1.1.3 root 95: break;
96: case 32:
1.1.1.6 root 97: if (is_surface_bgr(s->ds->surface))
98: s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
99: else
100: s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
1.1.1.3 root 101: break;
102: }
103: }
1.1.1.6 root 104: if (s->depth == 24) {
105: tcx24_set_dirty(s);
106: } else {
107: tcx_set_dirty(s);
108: }
1.1.1.3 root 109: }
110:
1.1.1.4 root 111: static void tcx_draw_line32(TCXState *s1, uint8_t *d,
112: const uint8_t *s, int width)
1.1 root 113: {
114: int x;
115: uint8_t val;
1.1.1.3 root 116: uint32_t *p = (uint32_t *)d;
1.1 root 117:
118: for(x = 0; x < width; x++) {
1.1.1.4 root 119: val = *s++;
1.1.1.3 root 120: *p++ = s1->palette[val];
1.1 root 121: }
122: }
123:
1.1.1.4 root 124: static void tcx_draw_line16(TCXState *s1, uint8_t *d,
125: const uint8_t *s, int width)
1.1 root 126: {
127: int x;
128: uint8_t val;
1.1.1.3 root 129: uint16_t *p = (uint16_t *)d;
1.1 root 130:
131: for(x = 0; x < width; x++) {
1.1.1.4 root 132: val = *s++;
1.1.1.3 root 133: *p++ = s1->palette[val];
1.1 root 134: }
135: }
136:
1.1.1.4 root 137: static void tcx_draw_line8(TCXState *s1, uint8_t *d,
138: const uint8_t *s, int width)
1.1 root 139: {
140: int x;
141: uint8_t val;
142:
143: for(x = 0; x < width; x++) {
1.1.1.4 root 144: val = *s++;
1.1.1.3 root 145: *d++ = s1->palette[val];
1.1 root 146: }
147: }
148:
1.1.1.5 root 149: /*
150: XXX Could be much more optimal:
151: * detect if line/page/whole screen is in 24 bit mode
152: * if destination is also BGR, use memcpy
153: */
1.1.1.4 root 154: static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
155: const uint8_t *s, int width,
156: const uint32_t *cplane,
157: const uint32_t *s24)
158: {
1.1.1.6 root 159: int x, bgr, r, g, b;
1.1.1.5 root 160: uint8_t val, *p8;
1.1.1.4 root 161: uint32_t *p = (uint32_t *)d;
162: uint32_t dval;
163:
1.1.1.6 root 164: bgr = is_surface_bgr(s1->ds->surface);
1.1.1.4 root 165: for(x = 0; x < width; x++, s++, s24++) {
1.1.1.5 root 166: if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
167: // 24-bit direct, BGR order
168: p8 = (uint8_t *)s24;
169: p8++;
170: b = *p8++;
171: g = *p8++;
1.1.1.8 root 172: r = *p8;
1.1.1.6 root 173: if (bgr)
174: dval = rgb_to_pixel32bgr(r, g, b);
175: else
176: dval = rgb_to_pixel32(r, g, b);
1.1.1.4 root 177: } else {
178: val = *s;
179: dval = s1->palette[val];
180: }
181: *p++ = dval;
182: }
183: }
184:
1.1.1.10! root 185: static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
1.1.1.4 root 186: ram_addr_t cpage)
187: {
188: int ret;
189: unsigned int off;
190:
1.1.1.10! root 191: ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
1.1.1.4 root 192: for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
1.1.1.10! root 193: ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
! 194: DIRTY_MEMORY_VGA);
! 195: ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
! 196: DIRTY_MEMORY_VGA);
1.1.1.4 root 197: }
198: return ret;
199: }
200:
201: static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
202: ram_addr_t page_max, ram_addr_t page24,
203: ram_addr_t cpage)
204: {
1.1.1.10! root 205: memory_region_reset_dirty(&ts->vram_mem,
! 206: page_min, page_max + TARGET_PAGE_SIZE,
! 207: DIRTY_MEMORY_VGA);
! 208: memory_region_reset_dirty(&ts->vram_mem,
! 209: page24 + page_min * 4,
! 210: page24 + page_max * 4 + TARGET_PAGE_SIZE,
! 211: DIRTY_MEMORY_VGA);
! 212: memory_region_reset_dirty(&ts->vram_mem,
! 213: cpage + page_min * 4,
! 214: cpage + page_max * 4 + TARGET_PAGE_SIZE,
! 215: DIRTY_MEMORY_VGA);
1.1.1.4 root 216: }
217:
1.1 root 218: /* Fixed line length 1024 allows us to do nice tricks not possible on
219: VGA... */
1.1.1.2 root 220: static void tcx_update_display(void *opaque)
1.1 root 221: {
222: TCXState *ts = opaque;
1.1.1.3 root 223: ram_addr_t page, page_min, page_max;
224: int y, y_start, dd, ds;
1.1 root 225: uint8_t *d, *s;
1.1.1.4 root 226: void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
1.1 root 227:
1.1.1.5 root 228: if (ds_get_bits_per_pixel(ts->ds) == 0)
1.1.1.4 root 229: return;
1.1.1.10! root 230: page = 0;
1.1 root 231: y_start = -1;
1.1.1.6 root 232: page_min = -1;
1.1.1.3 root 233: page_max = 0;
1.1.1.5 root 234: d = ds_get_data(ts->ds);
1.1 root 235: s = ts->vram;
1.1.1.5 root 236: dd = ds_get_linesize(ts->ds);
1.1 root 237: ds = 1024;
238:
1.1.1.5 root 239: switch (ds_get_bits_per_pixel(ts->ds)) {
1.1 root 240: case 32:
1.1.1.4 root 241: f = tcx_draw_line32;
242: break;
1.1.1.3 root 243: case 15:
244: case 16:
1.1.1.4 root 245: f = tcx_draw_line16;
246: break;
1.1 root 247: default:
248: case 8:
1.1.1.4 root 249: f = tcx_draw_line8;
250: break;
1.1 root 251: case 0:
1.1.1.4 root 252: return;
1.1 root 253: }
1.1.1.4 root 254:
1.1 root 255: for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
1.1.1.10! root 256: if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
1.1.1.4 root 257: if (y_start < 0)
1.1 root 258: y_start = y;
259: if (page < page_min)
260: page_min = page;
261: if (page > page_max)
262: page_max = page;
1.1.1.4 root 263: f(ts, d, s, ts->width);
264: d += dd;
265: s += ds;
266: f(ts, d, s, ts->width);
267: d += dd;
268: s += ds;
269: f(ts, d, s, ts->width);
270: d += dd;
271: s += ds;
272: f(ts, d, s, ts->width);
273: d += dd;
274: s += ds;
275: } else {
1.1 root 276: if (y_start >= 0) {
277: /* flush to display */
1.1.1.4 root 278: dpy_update(ts->ds, 0, y_start,
1.1 root 279: ts->width, y - y_start);
280: y_start = -1;
281: }
1.1.1.4 root 282: d += dd * 4;
283: s += ds * 4;
284: }
1.1 root 285: }
286: if (y_start >= 0) {
1.1.1.4 root 287: /* flush to display */
288: dpy_update(ts->ds, 0, y_start,
289: ts->width, y - y_start);
1.1 root 290: }
291: /* reset modified pages */
1.1.1.6 root 292: if (page_max >= page_min) {
1.1.1.10! root 293: memory_region_reset_dirty(&ts->vram_mem,
! 294: page_min, page_max + TARGET_PAGE_SIZE,
! 295: DIRTY_MEMORY_VGA);
1.1 root 296: }
297: }
298:
1.1.1.4 root 299: static void tcx24_update_display(void *opaque)
300: {
301: TCXState *ts = opaque;
302: ram_addr_t page, page_min, page_max, cpage, page24;
303: int y, y_start, dd, ds;
304: uint8_t *d, *s;
305: uint32_t *cptr, *s24;
306:
1.1.1.5 root 307: if (ds_get_bits_per_pixel(ts->ds) != 32)
1.1.1.4 root 308: return;
1.1.1.10! root 309: page = 0;
1.1.1.4 root 310: page24 = ts->vram24_offset;
311: cpage = ts->cplane_offset;
312: y_start = -1;
1.1.1.6 root 313: page_min = -1;
1.1.1.4 root 314: page_max = 0;
1.1.1.5 root 315: d = ds_get_data(ts->ds);
1.1.1.4 root 316: s = ts->vram;
317: s24 = ts->vram24;
318: cptr = ts->cplane;
1.1.1.5 root 319: dd = ds_get_linesize(ts->ds);
1.1.1.4 root 320: ds = 1024;
321:
322: for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
323: page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
1.1.1.10! root 324: if (check_dirty(ts, page, page24, cpage)) {
1.1.1.4 root 325: if (y_start < 0)
326: y_start = y;
327: if (page < page_min)
328: page_min = page;
329: if (page > page_max)
330: page_max = page;
331: tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
332: d += dd;
333: s += ds;
334: cptr += ds;
335: s24 += ds;
336: tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
337: d += dd;
338: s += ds;
339: cptr += ds;
340: s24 += ds;
341: tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
342: d += dd;
343: s += ds;
344: cptr += ds;
345: s24 += ds;
346: tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
347: d += dd;
348: s += ds;
349: cptr += ds;
350: s24 += ds;
351: } else {
352: if (y_start >= 0) {
353: /* flush to display */
354: dpy_update(ts->ds, 0, y_start,
355: ts->width, y - y_start);
356: y_start = -1;
357: }
358: d += dd * 4;
359: s += ds * 4;
360: cptr += ds * 4;
361: s24 += ds * 4;
362: }
363: }
364: if (y_start >= 0) {
365: /* flush to display */
366: dpy_update(ts->ds, 0, y_start,
367: ts->width, y - y_start);
368: }
369: /* reset modified pages */
1.1.1.6 root 370: if (page_max >= page_min) {
1.1.1.4 root 371: reset_dirty(ts, page_min, page_max, page24, cpage);
372: }
373: }
374:
1.1.1.2 root 375: static void tcx_invalidate_display(void *opaque)
1.1 root 376: {
377: TCXState *s = opaque;
378:
1.1.1.6 root 379: tcx_set_dirty(s);
380: qemu_console_resize(s->ds, s->width, s->height);
1.1.1.4 root 381: }
382:
383: static void tcx24_invalidate_display(void *opaque)
384: {
385: TCXState *s = opaque;
386:
1.1.1.6 root 387: tcx_set_dirty(s);
388: tcx24_set_dirty(s);
389: qemu_console_resize(s->ds, s->width, s->height);
1.1 root 390: }
391:
1.1.1.7 root 392: static int vmstate_tcx_post_load(void *opaque, int version_id)
1.1 root 393: {
394: TCXState *s = opaque;
1.1.1.4 root 395:
1.1.1.3 root 396: update_palette_entries(s, 0, 256);
1.1.1.6 root 397: if (s->depth == 24) {
398: tcx24_set_dirty(s);
399: } else {
400: tcx_set_dirty(s);
401: }
1.1.1.4 root 402:
1.1 root 403: return 0;
404: }
405:
1.1.1.7 root 406: static const VMStateDescription vmstate_tcx = {
407: .name ="tcx",
408: .version_id = 4,
409: .minimum_version_id = 4,
410: .minimum_version_id_old = 4,
411: .post_load = vmstate_tcx_post_load,
412: .fields = (VMStateField []) {
413: VMSTATE_UINT16(height, TCXState),
414: VMSTATE_UINT16(width, TCXState),
415: VMSTATE_UINT16(depth, TCXState),
416: VMSTATE_BUFFER(r, TCXState),
417: VMSTATE_BUFFER(g, TCXState),
418: VMSTATE_BUFFER(b, TCXState),
419: VMSTATE_UINT8(dac_index, TCXState),
420: VMSTATE_UINT8(dac_state, TCXState),
421: VMSTATE_END_OF_LIST()
422: }
423: };
424:
425: static void tcx_reset(DeviceState *d)
1.1 root 426: {
1.1.1.7 root 427: TCXState *s = container_of(d, TCXState, busdev.qdev);
1.1 root 428:
429: /* Initialize palette */
430: memset(s->r, 0, 256);
431: memset(s->g, 0, 256);
432: memset(s->b, 0, 256);
433: s->r[255] = s->g[255] = s->b[255] = 255;
1.1.1.3 root 434: update_palette_entries(s, 0, 256);
1.1 root 435: memset(s->vram, 0, MAXX*MAXY);
1.1.1.10! root 436: memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
! 437: DIRTY_MEMORY_VGA);
1.1 root 438: s->dac_index = 0;
439: s->dac_state = 0;
440: }
441:
1.1.1.10! root 442: static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr,
! 443: unsigned size)
1.1 root 444: {
445: return 0;
446: }
447:
1.1.1.10! root 448: static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val,
! 449: unsigned size)
1.1 root 450: {
451: TCXState *s = opaque;
452:
1.1.1.5 root 453: switch (addr) {
1.1 root 454: case 0:
1.1.1.4 root 455: s->dac_index = val >> 24;
456: s->dac_state = 0;
457: break;
1.1.1.5 root 458: case 4:
1.1.1.4 root 459: switch (s->dac_state) {
460: case 0:
461: s->r[s->dac_index] = val >> 24;
1.1.1.3 root 462: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1.1.4 root 463: s->dac_state++;
464: break;
465: case 1:
466: s->g[s->dac_index] = val >> 24;
1.1.1.3 root 467: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1.1.4 root 468: s->dac_state++;
469: break;
470: case 2:
471: s->b[s->dac_index] = val >> 24;
1.1.1.3 root 472: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1.1.4 root 473: s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
474: default:
475: s->dac_state = 0;
476: break;
477: }
478: break;
1.1 root 479: default:
1.1.1.4 root 480: break;
1.1 root 481: }
482: return;
483: }
484:
1.1.1.10! root 485: static const MemoryRegionOps tcx_dac_ops = {
! 486: .read = tcx_dac_readl,
! 487: .write = tcx_dac_writel,
! 488: .endianness = DEVICE_NATIVE_ENDIAN,
! 489: .valid = {
! 490: .min_access_size = 4,
! 491: .max_access_size = 4,
! 492: },
1.1 root 493: };
494:
1.1.1.10! root 495: static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr,
! 496: unsigned size)
1.1.1.4 root 497: {
498: return 0;
499: }
500:
1.1.1.10! root 501: static void dummy_writel(void *opaque, target_phys_addr_t addr,
! 502: uint64_t val, unsigned size)
1.1.1.4 root 503: {
504: }
505:
1.1.1.10! root 506: static const MemoryRegionOps dummy_ops = {
! 507: .read = dummy_readl,
! 508: .write = dummy_writel,
! 509: .endianness = DEVICE_NATIVE_ENDIAN,
! 510: .valid = {
! 511: .min_access_size = 4,
! 512: .max_access_size = 4,
! 513: },
1.1.1.4 root 514: };
515:
1.1.1.7 root 516: static int tcx_init1(SysBusDevice *dev)
1.1.1.6 root 517: {
518: TCXState *s = FROM_SYSBUS(TCXState, dev);
1.1.1.10! root 519: ram_addr_t vram_offset = 0;
1.1.1.4 root 520: int size;
1.1.1.6 root 521: uint8_t *vram_base;
1.1 root 522:
1.1.1.10! root 523: memory_region_init_ram(&s->vram_mem, NULL, "tcx.vram",
! 524: s->vram_size * (1 + 4 + 4));
! 525: vram_base = memory_region_get_ram_ptr(&s->vram_mem);
1.1.1.4 root 526:
1.1.1.6 root 527: /* 8-bit plane */
1.1.1.4 root 528: s->vram = vram_base;
1.1.1.6 root 529: size = s->vram_size;
1.1.1.10! root 530: memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
! 531: &s->vram_mem, vram_offset, size);
! 532: sysbus_init_mmio_region(dev, &s->vram_8bit);
1.1.1.4 root 533: vram_offset += size;
534: vram_base += size;
1.1 root 535:
1.1.1.6 root 536: /* DAC */
1.1.1.10! root 537: memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
! 538: sysbus_init_mmio_region(dev, &s->dac);
1.1 root 539:
1.1.1.6 root 540: /* TEC (dummy) */
1.1.1.10! root 541: memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
! 542: sysbus_init_mmio_region(dev, &s->tec);
1.1.1.6 root 543: /* THC: NetBSD writes here even with 8-bit display: dummy */
1.1.1.10! root 544: memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
! 545: TCX_THC_NREGS_24);
! 546: sysbus_init_mmio_region(dev, &s->thc24);
1.1.1.6 root 547:
548: if (s->depth == 24) {
549: /* 24-bit plane */
550: size = s->vram_size * 4;
1.1.1.4 root 551: s->vram24 = (uint32_t *)vram_base;
552: s->vram24_offset = vram_offset;
1.1.1.10! root 553: memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
! 554: &s->vram_mem, vram_offset, size);
! 555: sysbus_init_mmio_region(dev, &s->vram_24bit);
1.1.1.4 root 556: vram_offset += size;
557: vram_base += size;
558:
1.1.1.6 root 559: /* Control plane */
560: size = s->vram_size * 4;
1.1.1.4 root 561: s->cplane = (uint32_t *)vram_base;
562: s->cplane_offset = vram_offset;
1.1.1.10! root 563: memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
! 564: &s->vram_mem, vram_offset, size);
! 565: sysbus_init_mmio_region(dev, &s->vram_cplane);
1.1.1.6 root 566:
1.1.1.5 root 567: s->ds = graphic_console_init(tcx24_update_display,
568: tcx24_invalidate_display,
569: tcx24_screen_dump, NULL, s);
1.1.1.4 root 570: } else {
1.1.1.6 root 571: /* THC 8 bit (dummy) */
1.1.1.10! root 572: memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
! 573: TCX_THC_NREGS_8);
! 574: sysbus_init_mmio_region(dev, &s->thc8);
1.1.1.6 root 575:
1.1.1.5 root 576: s->ds = graphic_console_init(tcx_update_display,
577: tcx_invalidate_display,
578: tcx_screen_dump, NULL, s);
1.1.1.4 root 579: }
580:
1.1.1.6 root 581: qemu_console_resize(s->ds, s->width, s->height);
1.1.1.7 root 582: return 0;
1.1 root 583: }
584:
1.1.1.2 root 585: static void tcx_screen_dump(void *opaque, const char *filename)
1.1 root 586: {
587: TCXState *s = opaque;
588: FILE *f;
589: uint8_t *d, *d1, v;
590: int y, x;
591:
592: f = fopen(filename, "wb");
593: if (!f)
594: return;
595: fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
596: d1 = s->vram;
597: for(y = 0; y < s->height; y++) {
598: d = d1;
599: for(x = 0; x < s->width; x++) {
600: v = *d;
601: fputc(s->r[v], f);
602: fputc(s->g[v], f);
603: fputc(s->b[v], f);
604: d++;
605: }
606: d1 += MAXX;
607: }
608: fclose(f);
609: return;
610: }
611:
1.1.1.4 root 612: static void tcx24_screen_dump(void *opaque, const char *filename)
613: {
614: TCXState *s = opaque;
615: FILE *f;
616: uint8_t *d, *d1, v;
617: uint32_t *s24, *cptr, dval;
618: int y, x;
1.1 root 619:
1.1.1.4 root 620: f = fopen(filename, "wb");
621: if (!f)
622: return;
623: fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
624: d1 = s->vram;
625: s24 = s->vram24;
626: cptr = s->cplane;
627: for(y = 0; y < s->height; y++) {
628: d = d1;
629: for(x = 0; x < s->width; x++, d++, s24++) {
630: if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
631: dval = *s24 & 0x00ffffff;
632: fputc((dval >> 16) & 0xff, f);
633: fputc((dval >> 8) & 0xff, f);
634: fputc(dval & 0xff, f);
635: } else {
636: v = *d;
637: fputc(s->r[v], f);
638: fputc(s->g[v], f);
639: fputc(s->b[v], f);
640: }
641: }
642: d1 += MAXX;
643: }
644: fclose(f);
645: return;
646: }
1.1.1.6 root 647:
648: static SysBusDeviceInfo tcx_info = {
649: .init = tcx_init1,
650: .qdev.name = "SUNW,tcx",
651: .qdev.size = sizeof(TCXState),
1.1.1.7 root 652: .qdev.reset = tcx_reset,
653: .qdev.vmsd = &vmstate_tcx,
1.1.1.6 root 654: .qdev.props = (Property[]) {
1.1.1.7 root 655: DEFINE_PROP_TADDR("addr", TCXState, addr, -1),
656: DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
657: DEFINE_PROP_UINT16("width", TCXState, width, -1),
658: DEFINE_PROP_UINT16("height", TCXState, height, -1),
659: DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
660: DEFINE_PROP_END_OF_LIST(),
1.1.1.6 root 661: }
662: };
663:
664: static void tcx_register_devices(void)
665: {
666: sysbus_register_withprop(&tcx_info);
667: }
668:
669: device_init(tcx_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.