|
|
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 "sun4m.h"
26: #include "console.h"
27: #include "pixel_ops.h"
1.1.1.6 ! root 28: #include "sysbus.h"
! 29: #include "qdev-addr.h"
1.1 root 30:
31: #define MAXX 1024
32: #define MAXY 768
33: #define TCX_DAC_NREGS 16
1.1.1.4 root 34: #define TCX_THC_NREGS_8 0x081c
35: #define TCX_THC_NREGS_24 0x1000
36: #define TCX_TEC_NREGS 0x1000
1.1 root 37:
38: typedef struct TCXState {
1.1.1.6 ! root 39: SysBusDevice busdev;
1.1.1.4 root 40: target_phys_addr_t addr;
1.1 root 41: DisplayState *ds;
42: uint8_t *vram;
1.1.1.4 root 43: uint32_t *vram24, *cplane;
44: ram_addr_t vram_offset, vram24_offset, cplane_offset;
1.1.1.6 ! root 45: uint32_t vram_size;
1.1.1.4 root 46: uint16_t width, height, depth;
1.1 root 47: uint8_t r[256], g[256], b[256];
1.1.1.3 root 48: uint32_t palette[256];
1.1 root 49: uint8_t dac_index, dac_state;
50: } TCXState;
51:
1.1.1.2 root 52: static void tcx_screen_dump(void *opaque, const char *filename);
1.1.1.4 root 53: static void tcx24_screen_dump(void *opaque, const char *filename);
1.1.1.6 ! root 54:
! 55: static void tcx_set_dirty(TCXState *s)
! 56: {
! 57: unsigned int i;
! 58:
! 59: for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
! 60: cpu_physical_memory_set_dirty(s->vram_offset + i);
! 61: }
! 62: }
! 63:
! 64: static void tcx24_set_dirty(TCXState *s)
! 65: {
! 66: unsigned int i;
! 67:
! 68: for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
! 69: cpu_physical_memory_set_dirty(s->vram24_offset + i);
! 70: cpu_physical_memory_set_dirty(s->cplane_offset + i);
! 71: }
! 72: }
1.1.1.3 root 73:
74: static void update_palette_entries(TCXState *s, int start, int end)
75: {
76: int i;
77: for(i = start; i < end; i++) {
1.1.1.5 root 78: switch(ds_get_bits_per_pixel(s->ds)) {
1.1.1.3 root 79: default:
80: case 8:
81: s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
82: break;
83: case 15:
1.1.1.5 root 84: s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
1.1.1.3 root 85: break;
86: case 16:
1.1.1.5 root 87: s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
1.1.1.3 root 88: break;
89: case 32:
1.1.1.6 ! root 90: if (is_surface_bgr(s->ds->surface))
! 91: s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
! 92: else
! 93: s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
1.1.1.3 root 94: break;
95: }
96: }
1.1.1.6 ! root 97: if (s->depth == 24) {
! 98: tcx24_set_dirty(s);
! 99: } else {
! 100: tcx_set_dirty(s);
! 101: }
1.1.1.3 root 102: }
103:
1.1.1.4 root 104: static void tcx_draw_line32(TCXState *s1, uint8_t *d,
105: const uint8_t *s, int width)
1.1 root 106: {
107: int x;
108: uint8_t val;
1.1.1.3 root 109: uint32_t *p = (uint32_t *)d;
1.1 root 110:
111: for(x = 0; x < width; x++) {
1.1.1.4 root 112: val = *s++;
1.1.1.3 root 113: *p++ = s1->palette[val];
1.1 root 114: }
115: }
116:
1.1.1.4 root 117: static void tcx_draw_line16(TCXState *s1, uint8_t *d,
118: const uint8_t *s, int width)
1.1 root 119: {
120: int x;
121: uint8_t val;
1.1.1.3 root 122: uint16_t *p = (uint16_t *)d;
1.1 root 123:
124: for(x = 0; x < width; x++) {
1.1.1.4 root 125: val = *s++;
1.1.1.3 root 126: *p++ = s1->palette[val];
1.1 root 127: }
128: }
129:
1.1.1.4 root 130: static void tcx_draw_line8(TCXState *s1, uint8_t *d,
131: const uint8_t *s, int width)
1.1 root 132: {
133: int x;
134: uint8_t val;
135:
136: for(x = 0; x < width; x++) {
1.1.1.4 root 137: val = *s++;
1.1.1.3 root 138: *d++ = s1->palette[val];
1.1 root 139: }
140: }
141:
1.1.1.5 root 142: /*
143: XXX Could be much more optimal:
144: * detect if line/page/whole screen is in 24 bit mode
145: * if destination is also BGR, use memcpy
146: */
1.1.1.4 root 147: static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
148: const uint8_t *s, int width,
149: const uint32_t *cplane,
150: const uint32_t *s24)
151: {
1.1.1.6 ! root 152: int x, bgr, r, g, b;
1.1.1.5 root 153: uint8_t val, *p8;
1.1.1.4 root 154: uint32_t *p = (uint32_t *)d;
155: uint32_t dval;
156:
1.1.1.6 ! root 157: bgr = is_surface_bgr(s1->ds->surface);
1.1.1.4 root 158: for(x = 0; x < width; x++, s++, s24++) {
1.1.1.5 root 159: if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
160: // 24-bit direct, BGR order
161: p8 = (uint8_t *)s24;
162: p8++;
163: b = *p8++;
164: g = *p8++;
165: r = *p8++;
1.1.1.6 ! root 166: if (bgr)
! 167: dval = rgb_to_pixel32bgr(r, g, b);
! 168: else
! 169: dval = rgb_to_pixel32(r, g, b);
1.1.1.4 root 170: } else {
171: val = *s;
172: dval = s1->palette[val];
173: }
174: *p++ = dval;
175: }
176: }
177:
1.1.1.5 root 178: static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
1.1.1.4 root 179: ram_addr_t cpage)
180: {
181: int ret;
182: unsigned int off;
183:
184: ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
185: for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
186: ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
187: ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
188: }
189: return ret;
190: }
191:
192: static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
193: ram_addr_t page_max, ram_addr_t page24,
194: ram_addr_t cpage)
195: {
196: cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
197: VGA_DIRTY_FLAG);
198: page_min -= ts->vram_offset;
199: page_max -= ts->vram_offset;
200: cpu_physical_memory_reset_dirty(page24 + page_min * 4,
201: page24 + page_max * 4 + TARGET_PAGE_SIZE,
202: VGA_DIRTY_FLAG);
203: cpu_physical_memory_reset_dirty(cpage + page_min * 4,
204: cpage + page_max * 4 + TARGET_PAGE_SIZE,
205: VGA_DIRTY_FLAG);
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 root 220: page = ts->vram_offset;
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.4 root 246: if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
247: if (y_start < 0)
1.1 root 248: y_start = y;
249: if (page < page_min)
250: page_min = page;
251: if (page > page_max)
252: page_max = page;
1.1.1.4 root 253: f(ts, d, s, ts->width);
254: d += dd;
255: s += ds;
256: f(ts, d, s, ts->width);
257: d += dd;
258: s += ds;
259: f(ts, d, s, ts->width);
260: d += dd;
261: s += ds;
262: f(ts, d, s, ts->width);
263: d += dd;
264: s += ds;
265: } else {
1.1 root 266: if (y_start >= 0) {
267: /* flush to display */
1.1.1.4 root 268: dpy_update(ts->ds, 0, y_start,
1.1 root 269: ts->width, y - y_start);
270: y_start = -1;
271: }
1.1.1.4 root 272: d += dd * 4;
273: s += ds * 4;
274: }
1.1 root 275: }
276: if (y_start >= 0) {
1.1.1.4 root 277: /* flush to display */
278: dpy_update(ts->ds, 0, y_start,
279: ts->width, y - y_start);
1.1 root 280: }
281: /* reset modified pages */
1.1.1.6 ! root 282: if (page_max >= page_min) {
1.1 root 283: cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
284: VGA_DIRTY_FLAG);
285: }
286: }
287:
1.1.1.4 root 288: static void tcx24_update_display(void *opaque)
289: {
290: TCXState *ts = opaque;
291: ram_addr_t page, page_min, page_max, cpage, page24;
292: int y, y_start, dd, ds;
293: uint8_t *d, *s;
294: uint32_t *cptr, *s24;
295:
1.1.1.5 root 296: if (ds_get_bits_per_pixel(ts->ds) != 32)
1.1.1.4 root 297: return;
298: page = ts->vram_offset;
299: page24 = ts->vram24_offset;
300: cpage = ts->cplane_offset;
301: y_start = -1;
1.1.1.6 ! root 302: page_min = -1;
1.1.1.4 root 303: page_max = 0;
1.1.1.5 root 304: d = ds_get_data(ts->ds);
1.1.1.4 root 305: s = ts->vram;
306: s24 = ts->vram24;
307: cptr = ts->cplane;
1.1.1.5 root 308: dd = ds_get_linesize(ts->ds);
1.1.1.4 root 309: ds = 1024;
310:
311: for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
312: page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
1.1.1.5 root 313: if (check_dirty(page, page24, cpage)) {
1.1.1.4 root 314: if (y_start < 0)
315: y_start = y;
316: if (page < page_min)
317: page_min = page;
318: if (page > page_max)
319: page_max = page;
320: tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
321: d += dd;
322: s += ds;
323: cptr += ds;
324: s24 += ds;
325: tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
326: d += dd;
327: s += ds;
328: cptr += ds;
329: s24 += ds;
330: tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
331: d += dd;
332: s += ds;
333: cptr += ds;
334: s24 += ds;
335: tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
336: d += dd;
337: s += ds;
338: cptr += ds;
339: s24 += ds;
340: } else {
341: if (y_start >= 0) {
342: /* flush to display */
343: dpy_update(ts->ds, 0, y_start,
344: ts->width, y - y_start);
345: y_start = -1;
346: }
347: d += dd * 4;
348: s += ds * 4;
349: cptr += ds * 4;
350: s24 += ds * 4;
351: }
352: }
353: if (y_start >= 0) {
354: /* flush to display */
355: dpy_update(ts->ds, 0, y_start,
356: ts->width, y - y_start);
357: }
358: /* reset modified pages */
1.1.1.6 ! root 359: if (page_max >= page_min) {
1.1.1.4 root 360: reset_dirty(ts, page_min, page_max, page24, cpage);
361: }
362: }
363:
1.1.1.2 root 364: static void tcx_invalidate_display(void *opaque)
1.1 root 365: {
366: TCXState *s = opaque;
367:
1.1.1.6 ! root 368: tcx_set_dirty(s);
! 369: qemu_console_resize(s->ds, s->width, s->height);
1.1.1.4 root 370: }
371:
372: static void tcx24_invalidate_display(void *opaque)
373: {
374: TCXState *s = opaque;
375:
1.1.1.6 ! root 376: tcx_set_dirty(s);
! 377: tcx24_set_dirty(s);
! 378: qemu_console_resize(s->ds, s->width, s->height);
1.1 root 379: }
380:
381: static void tcx_save(QEMUFile *f, void *opaque)
382: {
383: TCXState *s = opaque;
1.1.1.4 root 384:
1.1.1.5 root 385: qemu_put_be16s(f, &s->height);
386: qemu_put_be16s(f, &s->width);
387: qemu_put_be16s(f, &s->depth);
1.1 root 388: qemu_put_buffer(f, s->r, 256);
389: qemu_put_buffer(f, s->g, 256);
390: qemu_put_buffer(f, s->b, 256);
391: qemu_put_8s(f, &s->dac_index);
392: qemu_put_8s(f, &s->dac_state);
393: }
394:
395: static int tcx_load(QEMUFile *f, void *opaque, int version_id)
396: {
397: TCXState *s = opaque;
1.1.1.4 root 398: uint32_t dummy;
399:
400: if (version_id != 3 && version_id != 4)
1.1 root 401: return -EINVAL;
402:
1.1.1.4 root 403: if (version_id == 3) {
1.1.1.5 root 404: qemu_get_be32s(f, &dummy);
405: qemu_get_be32s(f, &dummy);
406: qemu_get_be32s(f, &dummy);
407: }
408: qemu_get_be16s(f, &s->height);
409: qemu_get_be16s(f, &s->width);
410: qemu_get_be16s(f, &s->depth);
1.1 root 411: qemu_get_buffer(f, s->r, 256);
412: qemu_get_buffer(f, s->g, 256);
413: qemu_get_buffer(f, s->b, 256);
414: qemu_get_8s(f, &s->dac_index);
415: qemu_get_8s(f, &s->dac_state);
1.1.1.3 root 416: update_palette_entries(s, 0, 256);
1.1.1.6 ! root 417: if (s->depth == 24) {
! 418: tcx24_set_dirty(s);
! 419: } else {
! 420: tcx_set_dirty(s);
! 421: }
1.1.1.4 root 422:
1.1 root 423: return 0;
424: }
425:
426: static void tcx_reset(void *opaque)
427: {
428: TCXState *s = opaque;
429:
430: /* Initialize palette */
431: memset(s->r, 0, 256);
432: memset(s->g, 0, 256);
433: memset(s->b, 0, 256);
434: s->r[255] = s->g[255] = s->b[255] = 255;
1.1.1.3 root 435: update_palette_entries(s, 0, 256);
1.1 root 436: memset(s->vram, 0, MAXX*MAXY);
1.1.1.4 root 437: cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
438: MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
1.1 root 439: s->dac_index = 0;
440: s->dac_state = 0;
441: }
442:
443: static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
444: {
445: return 0;
446: }
447:
448: static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
449: {
450: TCXState *s = opaque;
451:
1.1.1.5 root 452: switch (addr) {
1.1 root 453: case 0:
1.1.1.4 root 454: s->dac_index = val >> 24;
455: s->dac_state = 0;
456: break;
1.1.1.5 root 457: case 4:
1.1.1.4 root 458: switch (s->dac_state) {
459: case 0:
460: s->r[s->dac_index] = val >> 24;
1.1.1.3 root 461: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1.1.4 root 462: s->dac_state++;
463: break;
464: case 1:
465: s->g[s->dac_index] = val >> 24;
1.1.1.3 root 466: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1.1.4 root 467: s->dac_state++;
468: break;
469: case 2:
470: s->b[s->dac_index] = val >> 24;
1.1.1.3 root 471: update_palette_entries(s, s->dac_index, s->dac_index + 1);
1.1.1.4 root 472: s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
473: default:
474: s->dac_state = 0;
475: break;
476: }
477: break;
1.1 root 478: default:
1.1.1.4 root 479: break;
1.1 root 480: }
481: return;
482: }
483:
484: static CPUReadMemoryFunc *tcx_dac_read[3] = {
1.1.1.4 root 485: NULL,
486: NULL,
1.1 root 487: tcx_dac_readl,
488: };
489:
490: static CPUWriteMemoryFunc *tcx_dac_write[3] = {
1.1.1.4 root 491: NULL,
492: NULL,
1.1 root 493: tcx_dac_writel,
494: };
495:
1.1.1.4 root 496: static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
497: {
498: return 0;
499: }
500:
501: static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
502: uint32_t val)
503: {
504: }
505:
506: static CPUReadMemoryFunc *tcx_dummy_read[3] = {
507: NULL,
508: NULL,
509: tcx_dummy_readl,
510: };
511:
512: static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
513: NULL,
514: NULL,
515: tcx_dummy_writel,
516: };
517:
1.1.1.6 ! root 518: void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height,
1.1.1.4 root 519: int depth)
1.1 root 520: {
1.1.1.6 ! root 521: DeviceState *dev;
! 522: SysBusDevice *s;
! 523:
! 524: dev = qdev_create(NULL, "SUNW,tcx");
! 525: qdev_prop_set_taddr(dev, "addr", addr);
! 526: qdev_prop_set_uint32(dev, "vram_size", vram_size);
! 527: qdev_prop_set_uint16(dev, "width", width);
! 528: qdev_prop_set_uint16(dev, "height", height);
! 529: qdev_prop_set_uint16(dev, "depth", depth);
! 530: qdev_init(dev);
! 531: s = sysbus_from_qdev(dev);
! 532: /* 8-bit plane */
! 533: sysbus_mmio_map(s, 0, addr + 0x00800000ULL);
! 534: /* DAC */
! 535: sysbus_mmio_map(s, 1, addr + 0x00200000ULL);
! 536: /* TEC (dummy) */
! 537: sysbus_mmio_map(s, 2, addr + 0x00700000ULL);
! 538: /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */
! 539: sysbus_mmio_map(s, 3, addr + 0x00301000ULL);
! 540: if (depth == 24) {
! 541: /* 24-bit plane */
! 542: sysbus_mmio_map(s, 4, addr + 0x02000000ULL);
! 543: /* Control plane */
! 544: sysbus_mmio_map(s, 5, addr + 0x0a000000ULL);
! 545: } else {
! 546: /* THC 8 bit (dummy) */
! 547: sysbus_mmio_map(s, 4, addr + 0x00300000ULL);
! 548: }
! 549: }
! 550:
! 551: static void tcx_init1(SysBusDevice *dev)
! 552: {
! 553: TCXState *s = FROM_SYSBUS(TCXState, dev);
1.1.1.4 root 554: int io_memory, dummy_memory;
1.1.1.6 ! root 555: ram_addr_t vram_offset;
1.1.1.4 root 556: int size;
1.1.1.6 ! root 557: uint8_t *vram_base;
1.1 root 558:
1.1.1.6 ! root 559: vram_offset = qemu_ram_alloc(s->vram_size * (1 + 4 + 4));
! 560: vram_base = qemu_get_ram_ptr(vram_offset);
1.1 root 561: s->vram_offset = vram_offset;
1.1.1.4 root 562:
1.1.1.6 ! root 563: /* 8-bit plane */
1.1.1.4 root 564: s->vram = vram_base;
1.1.1.6 ! root 565: size = s->vram_size;
! 566: sysbus_init_mmio(dev, size, s->vram_offset);
1.1.1.4 root 567: vram_offset += size;
568: vram_base += size;
1.1 root 569:
1.1.1.6 ! root 570: /* DAC */
! 571: io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s);
! 572: sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
1.1 root 573:
1.1.1.6 ! root 574: /* TEC (dummy) */
! 575: dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
1.1.1.4 root 576: s);
1.1.1.6 ! root 577: sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
! 578: /* THC: NetBSD writes here even with 8-bit display: dummy */
! 579: sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
! 580:
! 581: if (s->depth == 24) {
! 582: /* 24-bit plane */
! 583: size = s->vram_size * 4;
1.1.1.4 root 584: s->vram24 = (uint32_t *)vram_base;
585: s->vram24_offset = vram_offset;
1.1.1.6 ! root 586: sysbus_init_mmio(dev, size, vram_offset);
1.1.1.4 root 587: vram_offset += size;
588: vram_base += size;
589:
1.1.1.6 ! root 590: /* Control plane */
! 591: size = s->vram_size * 4;
1.1.1.4 root 592: s->cplane = (uint32_t *)vram_base;
593: s->cplane_offset = vram_offset;
1.1.1.6 ! root 594: sysbus_init_mmio(dev, size, vram_offset);
! 595:
1.1.1.5 root 596: s->ds = graphic_console_init(tcx24_update_display,
597: tcx24_invalidate_display,
598: tcx24_screen_dump, NULL, s);
1.1.1.4 root 599: } else {
1.1.1.6 ! root 600: /* THC 8 bit (dummy) */
! 601: sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
! 602:
1.1.1.5 root 603: s->ds = graphic_console_init(tcx_update_display,
604: tcx_invalidate_display,
605: tcx_screen_dump, NULL, s);
1.1.1.4 root 606: }
607:
1.1.1.6 ! root 608: register_savevm("tcx", -1, 4, tcx_save, tcx_load, s);
1.1 root 609: qemu_register_reset(tcx_reset, s);
610: tcx_reset(s);
1.1.1.6 ! root 611: qemu_console_resize(s->ds, s->width, s->height);
1.1 root 612: }
613:
1.1.1.2 root 614: static void tcx_screen_dump(void *opaque, const char *filename)
1.1 root 615: {
616: TCXState *s = opaque;
617: FILE *f;
618: uint8_t *d, *d1, v;
619: int y, x;
620:
621: f = fopen(filename, "wb");
622: if (!f)
623: return;
624: fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
625: d1 = s->vram;
626: for(y = 0; y < s->height; y++) {
627: d = d1;
628: for(x = 0; x < s->width; x++) {
629: v = *d;
630: fputc(s->r[v], f);
631: fputc(s->g[v], f);
632: fputc(s->b[v], f);
633: d++;
634: }
635: d1 += MAXX;
636: }
637: fclose(f);
638: return;
639: }
640:
1.1.1.4 root 641: static void tcx24_screen_dump(void *opaque, const char *filename)
642: {
643: TCXState *s = opaque;
644: FILE *f;
645: uint8_t *d, *d1, v;
646: uint32_t *s24, *cptr, dval;
647: int y, x;
1.1 root 648:
1.1.1.4 root 649: f = fopen(filename, "wb");
650: if (!f)
651: return;
652: fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
653: d1 = s->vram;
654: s24 = s->vram24;
655: cptr = s->cplane;
656: for(y = 0; y < s->height; y++) {
657: d = d1;
658: for(x = 0; x < s->width; x++, d++, s24++) {
659: if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
660: dval = *s24 & 0x00ffffff;
661: fputc((dval >> 16) & 0xff, f);
662: fputc((dval >> 8) & 0xff, f);
663: fputc(dval & 0xff, f);
664: } else {
665: v = *d;
666: fputc(s->r[v], f);
667: fputc(s->g[v], f);
668: fputc(s->b[v], f);
669: }
670: }
671: d1 += MAXX;
672: }
673: fclose(f);
674: return;
675: }
1.1.1.6 ! root 676:
! 677: static SysBusDeviceInfo tcx_info = {
! 678: .init = tcx_init1,
! 679: .qdev.name = "SUNW,tcx",
! 680: .qdev.size = sizeof(TCXState),
! 681: .qdev.props = (Property[]) {
! 682: {
! 683: .name = "addr",
! 684: .info = &qdev_prop_taddr,
! 685: .offset = offsetof(TCXState, addr),
! 686: .defval = (target_phys_addr_t[]) { -1 },
! 687: },{
! 688: .name = "vram_size",
! 689: .info = &qdev_prop_hex32,
! 690: .offset = offsetof(TCXState, vram_size),
! 691: .defval = (uint32_t[]) { -1 },
! 692: },{
! 693: .name = "width",
! 694: .info = &qdev_prop_uint16,
! 695: .offset = offsetof(TCXState, width),
! 696: .defval = (uint16_t[]) { -1 },
! 697: },{
! 698: .name = "height",
! 699: .info = &qdev_prop_uint16,
! 700: .offset = offsetof(TCXState, height),
! 701: .defval = (uint16_t[]) { -1 },
! 702: },{
! 703: .name = "depth",
! 704: .info = &qdev_prop_uint16,
! 705: .offset = offsetof(TCXState, depth),
! 706: .defval = (uint16_t[]) { -1 },
! 707: },
! 708: {/* end of list */}
! 709: }
! 710: };
! 711:
! 712: static void tcx_register_devices(void)
! 713: {
! 714: sysbus_register_withprop(&tcx_info);
! 715: }
! 716:
! 717: device_init(tcx_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.