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