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