1420557e8Sbellard /* 26f7e9aecSbellard * QEMU TCX Frame buffer 3420557e8Sbellard * 46f7e9aecSbellard * Copyright (c) 2003-2005 Fabrice Bellard 5420557e8Sbellard * 6420557e8Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7420557e8Sbellard * of this software and associated documentation files (the "Software"), to deal 8420557e8Sbellard * in the Software without restriction, including without limitation the rights 9420557e8Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10420557e8Sbellard * copies of the Software, and to permit persons to whom the Software is 11420557e8Sbellard * furnished to do so, subject to the following conditions: 12420557e8Sbellard * 13420557e8Sbellard * The above copyright notice and this permission notice shall be included in 14420557e8Sbellard * all copies or substantial portions of the Software. 15420557e8Sbellard * 16420557e8Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17420557e8Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18420557e8Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19420557e8Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20420557e8Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21420557e8Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22420557e8Sbellard * THE SOFTWARE. 23420557e8Sbellard */ 24f40070c3SBlue Swirl 25077805faSPaolo Bonzini #include "qemu-common.h" 2628ecbaeeSPaolo Bonzini #include "ui/console.h" 2728ecbaeeSPaolo Bonzini #include "ui/pixel_ops.h" 28da87dd7bSMark Cave-Ayland #include "hw/loader.h" 2983c9f4caSPaolo Bonzini #include "hw/sysbus.h" 30420557e8Sbellard 31da87dd7bSMark Cave-Ayland #define TCX_ROM_FILE "QEMU,tcx.bin" 32da87dd7bSMark Cave-Ayland #define FCODE_MAX_ROM_SIZE 0x10000 33da87dd7bSMark Cave-Ayland 34420557e8Sbellard #define MAXX 1024 35420557e8Sbellard #define MAXY 768 366f7e9aecSbellard #define TCX_DAC_NREGS 16 37*55d7bfe2SMark Cave-Ayland #define TCX_THC_NREGS 0x1000 38*55d7bfe2SMark Cave-Ayland #define TCX_DHC_NREGS 0x4000 398508b89eSblueswir1 #define TCX_TEC_NREGS 0x1000 40*55d7bfe2SMark Cave-Ayland #define TCX_ALT_NREGS 0x8000 41*55d7bfe2SMark Cave-Ayland #define TCX_STIP_NREGS 0x800000 42*55d7bfe2SMark Cave-Ayland #define TCX_BLIT_NREGS 0x800000 43*55d7bfe2SMark Cave-Ayland #define TCX_RSTIP_NREGS 0x800000 44*55d7bfe2SMark Cave-Ayland #define TCX_RBLIT_NREGS 0x800000 45*55d7bfe2SMark Cave-Ayland 46*55d7bfe2SMark Cave-Ayland #define TCX_THC_MISC 0x818 47*55d7bfe2SMark Cave-Ayland #define TCX_THC_CURSXY 0x8fc 48*55d7bfe2SMark Cave-Ayland #define TCX_THC_CURSMASK 0x900 49*55d7bfe2SMark Cave-Ayland #define TCX_THC_CURSBITS 0x980 50420557e8Sbellard 5101774ddbSAndreas Färber #define TYPE_TCX "SUNW,tcx" 5201774ddbSAndreas Färber #define TCX(obj) OBJECT_CHECK(TCXState, (obj), TYPE_TCX) 5301774ddbSAndreas Färber 54420557e8Sbellard typedef struct TCXState { 5501774ddbSAndreas Färber SysBusDevice parent_obj; 5601774ddbSAndreas Färber 57c78f7137SGerd Hoffmann QemuConsole *con; 58*55d7bfe2SMark Cave-Ayland qemu_irq irq; 598d5f07faSbellard uint8_t *vram; 60eee0b836Sblueswir1 uint32_t *vram24, *cplane; 61da87dd7bSMark Cave-Ayland hwaddr prom_addr; 62da87dd7bSMark Cave-Ayland MemoryRegion rom; 63d08151bfSAvi Kivity MemoryRegion vram_mem; 64d08151bfSAvi Kivity MemoryRegion vram_8bit; 65d08151bfSAvi Kivity MemoryRegion vram_24bit; 66*55d7bfe2SMark Cave-Ayland MemoryRegion stip; 67*55d7bfe2SMark Cave-Ayland MemoryRegion blit; 68d08151bfSAvi Kivity MemoryRegion vram_cplane; 69*55d7bfe2SMark Cave-Ayland MemoryRegion rstip; 70*55d7bfe2SMark Cave-Ayland MemoryRegion rblit; 71d08151bfSAvi Kivity MemoryRegion tec; 72*55d7bfe2SMark Cave-Ayland MemoryRegion dac; 73*55d7bfe2SMark Cave-Ayland MemoryRegion thc; 74*55d7bfe2SMark Cave-Ayland MemoryRegion dhc; 75*55d7bfe2SMark Cave-Ayland MemoryRegion alt; 76d08151bfSAvi Kivity MemoryRegion thc24; 77*55d7bfe2SMark Cave-Ayland 78d08151bfSAvi Kivity ram_addr_t vram24_offset, cplane_offset; 79*55d7bfe2SMark Cave-Ayland uint32_t tmpblit; 80ee6847d1SGerd Hoffmann uint32_t vram_size; 81*55d7bfe2SMark Cave-Ayland uint32_t palette[260]; 82*55d7bfe2SMark Cave-Ayland uint8_t r[260], g[260], b[260]; 83427a66c3SBlue Swirl uint16_t width, height, depth; 846f7e9aecSbellard uint8_t dac_index, dac_state; 85*55d7bfe2SMark Cave-Ayland uint32_t thcmisc; 86*55d7bfe2SMark Cave-Ayland uint32_t cursmask[32]; 87*55d7bfe2SMark Cave-Ayland uint32_t cursbits[32]; 88*55d7bfe2SMark Cave-Ayland uint16_t cursx; 89*55d7bfe2SMark Cave-Ayland uint16_t cursy; 90420557e8Sbellard } TCXState; 91420557e8Sbellard 92d3ffcafeSBlue Swirl static void tcx_set_dirty(TCXState *s) 93d3ffcafeSBlue Swirl { 94fd4aa979SBlue Swirl memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY); 95d3ffcafeSBlue Swirl } 96d3ffcafeSBlue Swirl 97*55d7bfe2SMark Cave-Ayland static inline int tcx24_check_dirty(TCXState *s, ram_addr_t page, 98*55d7bfe2SMark Cave-Ayland ram_addr_t page24, ram_addr_t cpage) 99d3ffcafeSBlue Swirl { 100*55d7bfe2SMark Cave-Ayland int ret; 101*55d7bfe2SMark Cave-Ayland 102*55d7bfe2SMark Cave-Ayland ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE, 103*55d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 104*55d7bfe2SMark Cave-Ayland ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4, 105*55d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 106*55d7bfe2SMark Cave-Ayland ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4, 107*55d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 108*55d7bfe2SMark Cave-Ayland return ret; 109*55d7bfe2SMark Cave-Ayland } 110*55d7bfe2SMark Cave-Ayland 111*55d7bfe2SMark Cave-Ayland static inline void tcx24_reset_dirty(TCXState *ts, ram_addr_t page_min, 112*55d7bfe2SMark Cave-Ayland ram_addr_t page_max, ram_addr_t page24, 113*55d7bfe2SMark Cave-Ayland ram_addr_t cpage) 114*55d7bfe2SMark Cave-Ayland { 115*55d7bfe2SMark Cave-Ayland memory_region_reset_dirty(&ts->vram_mem, 116*55d7bfe2SMark Cave-Ayland page_min, 117*55d7bfe2SMark Cave-Ayland (page_max - page_min) + TARGET_PAGE_SIZE, 118*55d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 119*55d7bfe2SMark Cave-Ayland memory_region_reset_dirty(&ts->vram_mem, 120*55d7bfe2SMark Cave-Ayland page24 + page_min * 4, 121*55d7bfe2SMark Cave-Ayland (page_max - page_min) * 4 + TARGET_PAGE_SIZE, 122*55d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 123*55d7bfe2SMark Cave-Ayland memory_region_reset_dirty(&ts->vram_mem, 124*55d7bfe2SMark Cave-Ayland cpage + page_min * 4, 125*55d7bfe2SMark Cave-Ayland (page_max - page_min) * 4 + TARGET_PAGE_SIZE, 126*55d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 127d3ffcafeSBlue Swirl } 12895219897Spbrook 12921206a10Sbellard static void update_palette_entries(TCXState *s, int start, int end) 13021206a10Sbellard { 131c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(s->con); 13221206a10Sbellard int i; 133c78f7137SGerd Hoffmann 13421206a10Sbellard for (i = start; i < end; i++) { 135c78f7137SGerd Hoffmann switch (surface_bits_per_pixel(surface)) { 13621206a10Sbellard default: 13721206a10Sbellard case 8: 13821206a10Sbellard s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]); 13921206a10Sbellard break; 14021206a10Sbellard case 15: 14121206a10Sbellard s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]); 14221206a10Sbellard break; 14321206a10Sbellard case 16: 14421206a10Sbellard s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); 14521206a10Sbellard break; 14621206a10Sbellard case 32: 147c78f7137SGerd Hoffmann if (is_surface_bgr(surface)) { 1487b5d76daSaliguori s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]); 149c78f7137SGerd Hoffmann } else { 15021206a10Sbellard s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); 151c78f7137SGerd Hoffmann } 15221206a10Sbellard break; 15321206a10Sbellard } 15421206a10Sbellard } 155d3ffcafeSBlue Swirl tcx_set_dirty(s); 156d3ffcafeSBlue Swirl } 15721206a10Sbellard 158e80cfcfcSbellard static void tcx_draw_line32(TCXState *s1, uint8_t *d, 159e80cfcfcSbellard const uint8_t *s, int width) 160420557e8Sbellard { 161e80cfcfcSbellard int x; 162e80cfcfcSbellard uint8_t val; 1638bdc2159Sths uint32_t *p = (uint32_t *)d; 164e80cfcfcSbellard 165e80cfcfcSbellard for (x = 0; x < width; x++) { 166e80cfcfcSbellard val = *s++; 1678bdc2159Sths *p++ = s1->palette[val]; 168e80cfcfcSbellard } 169420557e8Sbellard } 170420557e8Sbellard 17121206a10Sbellard static void tcx_draw_line16(TCXState *s1, uint8_t *d, 172e80cfcfcSbellard const uint8_t *s, int width) 173e80cfcfcSbellard { 174e80cfcfcSbellard int x; 175e80cfcfcSbellard uint8_t val; 1768bdc2159Sths uint16_t *p = (uint16_t *)d; 1778d5f07faSbellard 178e80cfcfcSbellard for (x = 0; x < width; x++) { 179e80cfcfcSbellard val = *s++; 1808bdc2159Sths *p++ = s1->palette[val]; 181e80cfcfcSbellard } 182e80cfcfcSbellard } 183e80cfcfcSbellard 184e80cfcfcSbellard static void tcx_draw_line8(TCXState *s1, uint8_t *d, 185e80cfcfcSbellard const uint8_t *s, int width) 186e80cfcfcSbellard { 187e80cfcfcSbellard int x; 188e80cfcfcSbellard uint8_t val; 189e80cfcfcSbellard 190e80cfcfcSbellard for(x = 0; x < width; x++) { 191e80cfcfcSbellard val = *s++; 19221206a10Sbellard *d++ = s1->palette[val]; 193e80cfcfcSbellard } 194e80cfcfcSbellard } 195e80cfcfcSbellard 196*55d7bfe2SMark Cave-Ayland static void tcx_draw_cursor32(TCXState *s1, uint8_t *d, 197*55d7bfe2SMark Cave-Ayland int y, int width) 198*55d7bfe2SMark Cave-Ayland { 199*55d7bfe2SMark Cave-Ayland int x, len; 200*55d7bfe2SMark Cave-Ayland uint32_t mask, bits; 201*55d7bfe2SMark Cave-Ayland uint32_t *p = (uint32_t *)d; 202*55d7bfe2SMark Cave-Ayland 203*55d7bfe2SMark Cave-Ayland y = y - s1->cursy; 204*55d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 205*55d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 206*55d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 207*55d7bfe2SMark Cave-Ayland p = &p[s1->cursx]; 208*55d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 209*55d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 210*55d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 211*55d7bfe2SMark Cave-Ayland *p = s1->palette[259]; 212*55d7bfe2SMark Cave-Ayland } else { 213*55d7bfe2SMark Cave-Ayland *p = s1->palette[258]; 214*55d7bfe2SMark Cave-Ayland } 215*55d7bfe2SMark Cave-Ayland } 216*55d7bfe2SMark Cave-Ayland p++; 217*55d7bfe2SMark Cave-Ayland mask <<= 1; 218*55d7bfe2SMark Cave-Ayland bits <<= 1; 219*55d7bfe2SMark Cave-Ayland } 220*55d7bfe2SMark Cave-Ayland } 221*55d7bfe2SMark Cave-Ayland 222*55d7bfe2SMark Cave-Ayland static void tcx_draw_cursor16(TCXState *s1, uint8_t *d, 223*55d7bfe2SMark Cave-Ayland int y, int width) 224*55d7bfe2SMark Cave-Ayland { 225*55d7bfe2SMark Cave-Ayland int x, len; 226*55d7bfe2SMark Cave-Ayland uint32_t mask, bits; 227*55d7bfe2SMark Cave-Ayland uint16_t *p = (uint16_t *)d; 228*55d7bfe2SMark Cave-Ayland 229*55d7bfe2SMark Cave-Ayland y = y - s1->cursy; 230*55d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 231*55d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 232*55d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 233*55d7bfe2SMark Cave-Ayland p = &p[s1->cursx]; 234*55d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 235*55d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 236*55d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 237*55d7bfe2SMark Cave-Ayland *p = s1->palette[259]; 238*55d7bfe2SMark Cave-Ayland } else { 239*55d7bfe2SMark Cave-Ayland *p = s1->palette[258]; 240*55d7bfe2SMark Cave-Ayland } 241*55d7bfe2SMark Cave-Ayland } 242*55d7bfe2SMark Cave-Ayland p++; 243*55d7bfe2SMark Cave-Ayland mask <<= 1; 244*55d7bfe2SMark Cave-Ayland bits <<= 1; 245*55d7bfe2SMark Cave-Ayland } 246*55d7bfe2SMark Cave-Ayland } 247*55d7bfe2SMark Cave-Ayland 248*55d7bfe2SMark Cave-Ayland static void tcx_draw_cursor8(TCXState *s1, uint8_t *d, 249*55d7bfe2SMark Cave-Ayland int y, int width) 250*55d7bfe2SMark Cave-Ayland { 251*55d7bfe2SMark Cave-Ayland int x, len; 252*55d7bfe2SMark Cave-Ayland uint32_t mask, bits; 253*55d7bfe2SMark Cave-Ayland 254*55d7bfe2SMark Cave-Ayland y = y - s1->cursy; 255*55d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 256*55d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 257*55d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 258*55d7bfe2SMark Cave-Ayland d = &d[s1->cursx]; 259*55d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 260*55d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 261*55d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 262*55d7bfe2SMark Cave-Ayland *d = s1->palette[259]; 263*55d7bfe2SMark Cave-Ayland } else { 264*55d7bfe2SMark Cave-Ayland *d = s1->palette[258]; 265*55d7bfe2SMark Cave-Ayland } 266*55d7bfe2SMark Cave-Ayland } 267*55d7bfe2SMark Cave-Ayland d++; 268*55d7bfe2SMark Cave-Ayland mask <<= 1; 269*55d7bfe2SMark Cave-Ayland bits <<= 1; 270*55d7bfe2SMark Cave-Ayland } 271*55d7bfe2SMark Cave-Ayland } 272*55d7bfe2SMark Cave-Ayland 273688ea2ebSblueswir1 /* 274688ea2ebSblueswir1 XXX Could be much more optimal: 275688ea2ebSblueswir1 * detect if line/page/whole screen is in 24 bit mode 276688ea2ebSblueswir1 * if destination is also BGR, use memcpy 277688ea2ebSblueswir1 */ 278eee0b836Sblueswir1 static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, 279eee0b836Sblueswir1 const uint8_t *s, int width, 280eee0b836Sblueswir1 const uint32_t *cplane, 281eee0b836Sblueswir1 const uint32_t *s24) 282eee0b836Sblueswir1 { 283c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(s1->con); 2847b5d76daSaliguori int x, bgr, r, g, b; 285688ea2ebSblueswir1 uint8_t val, *p8; 286eee0b836Sblueswir1 uint32_t *p = (uint32_t *)d; 287eee0b836Sblueswir1 uint32_t dval; 288c78f7137SGerd Hoffmann bgr = is_surface_bgr(surface); 289eee0b836Sblueswir1 for(x = 0; x < width; x++, s++, s24++) { 290*55d7bfe2SMark Cave-Ayland if (be32_to_cpu(*cplane) & 0x03000000) { 291*55d7bfe2SMark Cave-Ayland /* 24-bit direct, BGR order */ 292688ea2ebSblueswir1 p8 = (uint8_t *)s24; 293688ea2ebSblueswir1 p8++; 294688ea2ebSblueswir1 b = *p8++; 295688ea2ebSblueswir1 g = *p8++; 296f7e683b8SBlue Swirl r = *p8; 2977b5d76daSaliguori if (bgr) 2987b5d76daSaliguori dval = rgb_to_pixel32bgr(r, g, b); 2997b5d76daSaliguori else 300688ea2ebSblueswir1 dval = rgb_to_pixel32(r, g, b); 301eee0b836Sblueswir1 } else { 302*55d7bfe2SMark Cave-Ayland /* 8-bit pseudocolor */ 303eee0b836Sblueswir1 val = *s; 304eee0b836Sblueswir1 dval = s1->palette[val]; 305eee0b836Sblueswir1 } 306eee0b836Sblueswir1 *p++ = dval; 307*55d7bfe2SMark Cave-Ayland cplane++; 308eee0b836Sblueswir1 } 309eee0b836Sblueswir1 } 310eee0b836Sblueswir1 311e80cfcfcSbellard /* Fixed line length 1024 allows us to do nice tricks not possible on 312e80cfcfcSbellard VGA... */ 313*55d7bfe2SMark Cave-Ayland 31495219897Spbrook static void tcx_update_display(void *opaque) 315e80cfcfcSbellard { 316e80cfcfcSbellard TCXState *ts = opaque; 317c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(ts->con); 318c227f099SAnthony Liguori ram_addr_t page, page_min, page_max; 319550be127Sbellard int y, y_start, dd, ds; 320e80cfcfcSbellard uint8_t *d, *s; 321b3ceef24Sblueswir1 void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); 322*55d7bfe2SMark Cave-Ayland void (*fc)(TCXState *s1, uint8_t *dst, int y, int width); 323e80cfcfcSbellard 324c78f7137SGerd Hoffmann if (surface_bits_per_pixel(surface) == 0) { 325e80cfcfcSbellard return; 326c78f7137SGerd Hoffmann } 327c78f7137SGerd Hoffmann 328d08151bfSAvi Kivity page = 0; 329e80cfcfcSbellard y_start = -1; 330c0c440f3SBlue Swirl page_min = -1; 331550be127Sbellard page_max = 0; 332c78f7137SGerd Hoffmann d = surface_data(surface); 3336f7e9aecSbellard s = ts->vram; 334c78f7137SGerd Hoffmann dd = surface_stride(surface); 335e80cfcfcSbellard ds = 1024; 336e80cfcfcSbellard 337c78f7137SGerd Hoffmann switch (surface_bits_per_pixel(surface)) { 338e80cfcfcSbellard case 32: 339e80cfcfcSbellard f = tcx_draw_line32; 340*55d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor32; 341e80cfcfcSbellard break; 34221206a10Sbellard case 15: 34321206a10Sbellard case 16: 34421206a10Sbellard f = tcx_draw_line16; 345*55d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor16; 346e80cfcfcSbellard break; 347e80cfcfcSbellard default: 348e80cfcfcSbellard case 8: 349e80cfcfcSbellard f = tcx_draw_line8; 350*55d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor8; 351e80cfcfcSbellard break; 352e80cfcfcSbellard case 0: 353e80cfcfcSbellard return; 354e80cfcfcSbellard } 355e80cfcfcSbellard 356*55d7bfe2SMark Cave-Ayland for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) { 357cd7a45c9SBlue Swirl if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE, 358cd7a45c9SBlue Swirl DIRTY_MEMORY_VGA)) { 359e80cfcfcSbellard if (y_start < 0) 360e80cfcfcSbellard y_start = y; 361e80cfcfcSbellard if (page < page_min) 362e80cfcfcSbellard page_min = page; 363e80cfcfcSbellard if (page > page_max) 364e80cfcfcSbellard page_max = page; 365*55d7bfe2SMark Cave-Ayland 3666f7e9aecSbellard f(ts, d, s, ts->width); 367*55d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 368*55d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 369*55d7bfe2SMark Cave-Ayland } 370e80cfcfcSbellard d += dd; 371e80cfcfcSbellard s += ds; 372*55d7bfe2SMark Cave-Ayland y++; 373*55d7bfe2SMark Cave-Ayland 3746f7e9aecSbellard f(ts, d, s, ts->width); 375*55d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 376*55d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 377*55d7bfe2SMark Cave-Ayland } 378e80cfcfcSbellard d += dd; 379e80cfcfcSbellard s += ds; 380*55d7bfe2SMark Cave-Ayland y++; 381*55d7bfe2SMark Cave-Ayland 3826f7e9aecSbellard f(ts, d, s, ts->width); 383*55d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 384*55d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 385*55d7bfe2SMark Cave-Ayland } 386e80cfcfcSbellard d += dd; 387e80cfcfcSbellard s += ds; 388*55d7bfe2SMark Cave-Ayland y++; 389*55d7bfe2SMark Cave-Ayland 3906f7e9aecSbellard f(ts, d, s, ts->width); 391*55d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 392*55d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 393*55d7bfe2SMark Cave-Ayland } 394e80cfcfcSbellard d += dd; 395e80cfcfcSbellard s += ds; 396*55d7bfe2SMark Cave-Ayland y++; 397e80cfcfcSbellard } else { 398e80cfcfcSbellard if (y_start >= 0) { 399e80cfcfcSbellard /* flush to display */ 400c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 4016f7e9aecSbellard ts->width, y - y_start); 402e80cfcfcSbellard y_start = -1; 403e80cfcfcSbellard } 404e80cfcfcSbellard d += dd * 4; 405e80cfcfcSbellard s += ds * 4; 406*55d7bfe2SMark Cave-Ayland y += 4; 407e80cfcfcSbellard } 408e80cfcfcSbellard } 409e80cfcfcSbellard if (y_start >= 0) { 410e80cfcfcSbellard /* flush to display */ 411c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 4126f7e9aecSbellard ts->width, y - y_start); 413e80cfcfcSbellard } 414e80cfcfcSbellard /* reset modified pages */ 415c0c440f3SBlue Swirl if (page_max >= page_min) { 416d08151bfSAvi Kivity memory_region_reset_dirty(&ts->vram_mem, 417f10acc8bSMark Cave-Ayland page_min, 418f10acc8bSMark Cave-Ayland (page_max - page_min) + TARGET_PAGE_SIZE, 419d08151bfSAvi Kivity DIRTY_MEMORY_VGA); 420e80cfcfcSbellard } 421e80cfcfcSbellard } 422e80cfcfcSbellard 423eee0b836Sblueswir1 static void tcx24_update_display(void *opaque) 424eee0b836Sblueswir1 { 425eee0b836Sblueswir1 TCXState *ts = opaque; 426c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(ts->con); 427c227f099SAnthony Liguori ram_addr_t page, page_min, page_max, cpage, page24; 428eee0b836Sblueswir1 int y, y_start, dd, ds; 429eee0b836Sblueswir1 uint8_t *d, *s; 430eee0b836Sblueswir1 uint32_t *cptr, *s24; 431eee0b836Sblueswir1 432c78f7137SGerd Hoffmann if (surface_bits_per_pixel(surface) != 32) { 433eee0b836Sblueswir1 return; 434c78f7137SGerd Hoffmann } 435c78f7137SGerd Hoffmann 436d08151bfSAvi Kivity page = 0; 437eee0b836Sblueswir1 page24 = ts->vram24_offset; 438eee0b836Sblueswir1 cpage = ts->cplane_offset; 439eee0b836Sblueswir1 y_start = -1; 440c0c440f3SBlue Swirl page_min = -1; 441eee0b836Sblueswir1 page_max = 0; 442c78f7137SGerd Hoffmann d = surface_data(surface); 443eee0b836Sblueswir1 s = ts->vram; 444eee0b836Sblueswir1 s24 = ts->vram24; 445eee0b836Sblueswir1 cptr = ts->cplane; 446c78f7137SGerd Hoffmann dd = surface_stride(surface); 447eee0b836Sblueswir1 ds = 1024; 448eee0b836Sblueswir1 449*55d7bfe2SMark Cave-Ayland for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE, 450eee0b836Sblueswir1 page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { 451*55d7bfe2SMark Cave-Ayland if (tcx24_check_dirty(ts, page, page24, cpage)) { 452eee0b836Sblueswir1 if (y_start < 0) 453eee0b836Sblueswir1 y_start = y; 454eee0b836Sblueswir1 if (page < page_min) 455eee0b836Sblueswir1 page_min = page; 456eee0b836Sblueswir1 if (page > page_max) 457eee0b836Sblueswir1 page_max = page; 458eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 459*55d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 460*55d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 461*55d7bfe2SMark Cave-Ayland } 462eee0b836Sblueswir1 d += dd; 463eee0b836Sblueswir1 s += ds; 464eee0b836Sblueswir1 cptr += ds; 465eee0b836Sblueswir1 s24 += ds; 466*55d7bfe2SMark Cave-Ayland y++; 467eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 468*55d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 469*55d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 470*55d7bfe2SMark Cave-Ayland } 471eee0b836Sblueswir1 d += dd; 472eee0b836Sblueswir1 s += ds; 473eee0b836Sblueswir1 cptr += ds; 474eee0b836Sblueswir1 s24 += ds; 475*55d7bfe2SMark Cave-Ayland y++; 476eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 477*55d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 478*55d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 479*55d7bfe2SMark Cave-Ayland } 480eee0b836Sblueswir1 d += dd; 481eee0b836Sblueswir1 s += ds; 482eee0b836Sblueswir1 cptr += ds; 483eee0b836Sblueswir1 s24 += ds; 484*55d7bfe2SMark Cave-Ayland y++; 485eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 486*55d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 487*55d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 488*55d7bfe2SMark Cave-Ayland } 489eee0b836Sblueswir1 d += dd; 490eee0b836Sblueswir1 s += ds; 491eee0b836Sblueswir1 cptr += ds; 492eee0b836Sblueswir1 s24 += ds; 493*55d7bfe2SMark Cave-Ayland y++; 494eee0b836Sblueswir1 } else { 495eee0b836Sblueswir1 if (y_start >= 0) { 496eee0b836Sblueswir1 /* flush to display */ 497c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 498eee0b836Sblueswir1 ts->width, y - y_start); 499eee0b836Sblueswir1 y_start = -1; 500eee0b836Sblueswir1 } 501eee0b836Sblueswir1 d += dd * 4; 502eee0b836Sblueswir1 s += ds * 4; 503eee0b836Sblueswir1 cptr += ds * 4; 504eee0b836Sblueswir1 s24 += ds * 4; 505*55d7bfe2SMark Cave-Ayland y += 4; 506eee0b836Sblueswir1 } 507eee0b836Sblueswir1 } 508eee0b836Sblueswir1 if (y_start >= 0) { 509eee0b836Sblueswir1 /* flush to display */ 510c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 511eee0b836Sblueswir1 ts->width, y - y_start); 512eee0b836Sblueswir1 } 513eee0b836Sblueswir1 /* reset modified pages */ 514c0c440f3SBlue Swirl if (page_max >= page_min) { 515*55d7bfe2SMark Cave-Ayland tcx24_reset_dirty(ts, page_min, page_max, page24, cpage); 516eee0b836Sblueswir1 } 517eee0b836Sblueswir1 } 518eee0b836Sblueswir1 51995219897Spbrook static void tcx_invalidate_display(void *opaque) 520420557e8Sbellard { 521420557e8Sbellard TCXState *s = opaque; 522420557e8Sbellard 523d3ffcafeSBlue Swirl tcx_set_dirty(s); 524c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 525e80cfcfcSbellard } 526e80cfcfcSbellard 527eee0b836Sblueswir1 static void tcx24_invalidate_display(void *opaque) 528eee0b836Sblueswir1 { 529eee0b836Sblueswir1 TCXState *s = opaque; 530eee0b836Sblueswir1 531d3ffcafeSBlue Swirl tcx_set_dirty(s); 532c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 533eee0b836Sblueswir1 } 534eee0b836Sblueswir1 535e59fb374SJuan Quintela static int vmstate_tcx_post_load(void *opaque, int version_id) 536e80cfcfcSbellard { 537e80cfcfcSbellard TCXState *s = opaque; 538e80cfcfcSbellard 53921206a10Sbellard update_palette_entries(s, 0, 256); 540d3ffcafeSBlue Swirl tcx_set_dirty(s); 541420557e8Sbellard return 0; 542420557e8Sbellard } 543420557e8Sbellard 544c0c41a4bSBlue Swirl static const VMStateDescription vmstate_tcx = { 545c0c41a4bSBlue Swirl .name ="tcx", 546c0c41a4bSBlue Swirl .version_id = 4, 547c0c41a4bSBlue Swirl .minimum_version_id = 4, 548752ff2faSJuan Quintela .post_load = vmstate_tcx_post_load, 549c0c41a4bSBlue Swirl .fields = (VMStateField[]) { 550c0c41a4bSBlue Swirl VMSTATE_UINT16(height, TCXState), 551c0c41a4bSBlue Swirl VMSTATE_UINT16(width, TCXState), 552c0c41a4bSBlue Swirl VMSTATE_UINT16(depth, TCXState), 553c0c41a4bSBlue Swirl VMSTATE_BUFFER(r, TCXState), 554c0c41a4bSBlue Swirl VMSTATE_BUFFER(g, TCXState), 555c0c41a4bSBlue Swirl VMSTATE_BUFFER(b, TCXState), 556c0c41a4bSBlue Swirl VMSTATE_UINT8(dac_index, TCXState), 557c0c41a4bSBlue Swirl VMSTATE_UINT8(dac_state, TCXState), 558c0c41a4bSBlue Swirl VMSTATE_END_OF_LIST() 559c0c41a4bSBlue Swirl } 560c0c41a4bSBlue Swirl }; 561c0c41a4bSBlue Swirl 5627f23f812SMichael S. Tsirkin static void tcx_reset(DeviceState *d) 563420557e8Sbellard { 56401774ddbSAndreas Färber TCXState *s = TCX(d); 565420557e8Sbellard 566e80cfcfcSbellard /* Initialize palette */ 567*55d7bfe2SMark Cave-Ayland memset(s->r, 0, 260); 568*55d7bfe2SMark Cave-Ayland memset(s->g, 0, 260); 569*55d7bfe2SMark Cave-Ayland memset(s->b, 0, 260); 570e80cfcfcSbellard s->r[255] = s->g[255] = s->b[255] = 255; 571*55d7bfe2SMark Cave-Ayland s->r[256] = s->g[256] = s->b[256] = 255; 572*55d7bfe2SMark Cave-Ayland s->r[258] = s->g[258] = s->b[258] = 255; 573*55d7bfe2SMark Cave-Ayland update_palette_entries(s, 0, 260); 574e80cfcfcSbellard memset(s->vram, 0, MAXX*MAXY); 575d08151bfSAvi Kivity memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4), 576d08151bfSAvi Kivity DIRTY_MEMORY_VGA); 5776f7e9aecSbellard s->dac_index = 0; 5786f7e9aecSbellard s->dac_state = 0; 579*55d7bfe2SMark Cave-Ayland s->cursx = 0xf000; /* Put cursor off screen */ 580*55d7bfe2SMark Cave-Ayland s->cursy = 0xf000; 581420557e8Sbellard } 582420557e8Sbellard 583a8170e5eSAvi Kivity static uint64_t tcx_dac_readl(void *opaque, hwaddr addr, 584d08151bfSAvi Kivity unsigned size) 5856f7e9aecSbellard { 586*55d7bfe2SMark Cave-Ayland TCXState *s = opaque; 587*55d7bfe2SMark Cave-Ayland uint32_t val = 0; 588*55d7bfe2SMark Cave-Ayland 589*55d7bfe2SMark Cave-Ayland switch (s->dac_state) { 590*55d7bfe2SMark Cave-Ayland case 0: 591*55d7bfe2SMark Cave-Ayland val = s->r[s->dac_index] << 24; 592*55d7bfe2SMark Cave-Ayland s->dac_state++; 593*55d7bfe2SMark Cave-Ayland break; 594*55d7bfe2SMark Cave-Ayland case 1: 595*55d7bfe2SMark Cave-Ayland val = s->g[s->dac_index] << 24; 596*55d7bfe2SMark Cave-Ayland s->dac_state++; 597*55d7bfe2SMark Cave-Ayland break; 598*55d7bfe2SMark Cave-Ayland case 2: 599*55d7bfe2SMark Cave-Ayland val = s->b[s->dac_index] << 24; 600*55d7bfe2SMark Cave-Ayland s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ 601*55d7bfe2SMark Cave-Ayland default: 602*55d7bfe2SMark Cave-Ayland s->dac_state = 0; 603*55d7bfe2SMark Cave-Ayland break; 604*55d7bfe2SMark Cave-Ayland } 605*55d7bfe2SMark Cave-Ayland 606*55d7bfe2SMark Cave-Ayland return val; 6076f7e9aecSbellard } 6086f7e9aecSbellard 609a8170e5eSAvi Kivity static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val, 610d08151bfSAvi Kivity unsigned size) 6116f7e9aecSbellard { 6126f7e9aecSbellard TCXState *s = opaque; 613*55d7bfe2SMark Cave-Ayland unsigned index; 6146f7e9aecSbellard 615e64d7d59Sblueswir1 switch (addr) { 616*55d7bfe2SMark Cave-Ayland case 0: /* Address */ 6176f7e9aecSbellard s->dac_index = val >> 24; 6186f7e9aecSbellard s->dac_state = 0; 6196f7e9aecSbellard break; 620*55d7bfe2SMark Cave-Ayland case 4: /* Pixel colours */ 621*55d7bfe2SMark Cave-Ayland case 12: /* Overlay (cursor) colours */ 622*55d7bfe2SMark Cave-Ayland if (addr & 8) { 623*55d7bfe2SMark Cave-Ayland index = (s->dac_index & 3) + 256; 624*55d7bfe2SMark Cave-Ayland } else { 625*55d7bfe2SMark Cave-Ayland index = s->dac_index; 626*55d7bfe2SMark Cave-Ayland } 6276f7e9aecSbellard switch (s->dac_state) { 6286f7e9aecSbellard case 0: 629*55d7bfe2SMark Cave-Ayland s->r[index] = val >> 24; 630*55d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 6316f7e9aecSbellard s->dac_state++; 6326f7e9aecSbellard break; 6336f7e9aecSbellard case 1: 634*55d7bfe2SMark Cave-Ayland s->g[index] = val >> 24; 635*55d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 6366f7e9aecSbellard s->dac_state++; 6376f7e9aecSbellard break; 6386f7e9aecSbellard case 2: 639*55d7bfe2SMark Cave-Ayland s->b[index] = val >> 24; 640*55d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 641*55d7bfe2SMark Cave-Ayland s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ 6426f7e9aecSbellard default: 6436f7e9aecSbellard s->dac_state = 0; 6446f7e9aecSbellard break; 6456f7e9aecSbellard } 6466f7e9aecSbellard break; 647*55d7bfe2SMark Cave-Ayland default: /* Control registers */ 6486f7e9aecSbellard break; 6496f7e9aecSbellard } 6506f7e9aecSbellard } 6516f7e9aecSbellard 652d08151bfSAvi Kivity static const MemoryRegionOps tcx_dac_ops = { 653d08151bfSAvi Kivity .read = tcx_dac_readl, 654d08151bfSAvi Kivity .write = tcx_dac_writel, 655d08151bfSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 656d08151bfSAvi Kivity .valid = { 657d08151bfSAvi Kivity .min_access_size = 4, 658d08151bfSAvi Kivity .max_access_size = 4, 659d08151bfSAvi Kivity }, 6606f7e9aecSbellard }; 6616f7e9aecSbellard 662*55d7bfe2SMark Cave-Ayland static uint64_t tcx_stip_readl(void *opaque, hwaddr addr, 663d08151bfSAvi Kivity unsigned size) 6648508b89eSblueswir1 { 6658508b89eSblueswir1 return 0; 6668508b89eSblueswir1 } 6678508b89eSblueswir1 668*55d7bfe2SMark Cave-Ayland static void tcx_stip_writel(void *opaque, hwaddr addr, 669d08151bfSAvi Kivity uint64_t val, unsigned size) 6708508b89eSblueswir1 { 671*55d7bfe2SMark Cave-Ayland TCXState *s = opaque; 672*55d7bfe2SMark Cave-Ayland int i; 673*55d7bfe2SMark Cave-Ayland uint32_t col; 674*55d7bfe2SMark Cave-Ayland 675*55d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 676*55d7bfe2SMark Cave-Ayland s->tmpblit = val; 677*55d7bfe2SMark Cave-Ayland } else { 678*55d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 679*55d7bfe2SMark Cave-Ayland col = cpu_to_be32(s->tmpblit); 680*55d7bfe2SMark Cave-Ayland if (s->depth == 24) { 681*55d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 682*55d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 683*55d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 684*55d7bfe2SMark Cave-Ayland s->vram24[addr + i] = col; 685*55d7bfe2SMark Cave-Ayland } 686*55d7bfe2SMark Cave-Ayland val <<= 1; 687*55d7bfe2SMark Cave-Ayland } 688*55d7bfe2SMark Cave-Ayland } else { 689*55d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 690*55d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 691*55d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 692*55d7bfe2SMark Cave-Ayland } 693*55d7bfe2SMark Cave-Ayland val <<= 1; 694*55d7bfe2SMark Cave-Ayland } 695*55d7bfe2SMark Cave-Ayland } 696*55d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, 32); 697*55d7bfe2SMark Cave-Ayland } 6988508b89eSblueswir1 } 6998508b89eSblueswir1 700*55d7bfe2SMark Cave-Ayland static void tcx_rstip_writel(void *opaque, hwaddr addr, 701*55d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 702*55d7bfe2SMark Cave-Ayland { 703*55d7bfe2SMark Cave-Ayland TCXState *s = opaque; 704*55d7bfe2SMark Cave-Ayland int i; 705*55d7bfe2SMark Cave-Ayland uint32_t col; 706*55d7bfe2SMark Cave-Ayland 707*55d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 708*55d7bfe2SMark Cave-Ayland s->tmpblit = val; 709*55d7bfe2SMark Cave-Ayland } else { 710*55d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 711*55d7bfe2SMark Cave-Ayland col = cpu_to_be32(s->tmpblit); 712*55d7bfe2SMark Cave-Ayland if (s->depth == 24) { 713*55d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 714*55d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 715*55d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 716*55d7bfe2SMark Cave-Ayland s->vram24[addr + i] = col; 717*55d7bfe2SMark Cave-Ayland s->cplane[addr + i] = col; 718*55d7bfe2SMark Cave-Ayland } 719*55d7bfe2SMark Cave-Ayland val <<= 1; 720*55d7bfe2SMark Cave-Ayland } 721*55d7bfe2SMark Cave-Ayland } else { 722*55d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 723*55d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 724*55d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 725*55d7bfe2SMark Cave-Ayland } 726*55d7bfe2SMark Cave-Ayland val <<= 1; 727*55d7bfe2SMark Cave-Ayland } 728*55d7bfe2SMark Cave-Ayland } 729*55d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, 32); 730*55d7bfe2SMark Cave-Ayland } 731*55d7bfe2SMark Cave-Ayland } 732*55d7bfe2SMark Cave-Ayland 733*55d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_stip_ops = { 734*55d7bfe2SMark Cave-Ayland .read = tcx_stip_readl, 735*55d7bfe2SMark Cave-Ayland .write = tcx_stip_writel, 736*55d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 737*55d7bfe2SMark Cave-Ayland .valid = { 738*55d7bfe2SMark Cave-Ayland .min_access_size = 4, 739*55d7bfe2SMark Cave-Ayland .max_access_size = 4, 740*55d7bfe2SMark Cave-Ayland }, 741*55d7bfe2SMark Cave-Ayland }; 742*55d7bfe2SMark Cave-Ayland 743*55d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_rstip_ops = { 744*55d7bfe2SMark Cave-Ayland .read = tcx_stip_readl, 745*55d7bfe2SMark Cave-Ayland .write = tcx_rstip_writel, 746*55d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 747*55d7bfe2SMark Cave-Ayland .valid = { 748*55d7bfe2SMark Cave-Ayland .min_access_size = 4, 749*55d7bfe2SMark Cave-Ayland .max_access_size = 4, 750*55d7bfe2SMark Cave-Ayland }, 751*55d7bfe2SMark Cave-Ayland }; 752*55d7bfe2SMark Cave-Ayland 753*55d7bfe2SMark Cave-Ayland static uint64_t tcx_blit_readl(void *opaque, hwaddr addr, 754*55d7bfe2SMark Cave-Ayland unsigned size) 755*55d7bfe2SMark Cave-Ayland { 756*55d7bfe2SMark Cave-Ayland return 0; 757*55d7bfe2SMark Cave-Ayland } 758*55d7bfe2SMark Cave-Ayland 759*55d7bfe2SMark Cave-Ayland static void tcx_blit_writel(void *opaque, hwaddr addr, 760*55d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 761*55d7bfe2SMark Cave-Ayland { 762*55d7bfe2SMark Cave-Ayland TCXState *s = opaque; 763*55d7bfe2SMark Cave-Ayland uint32_t adsr, len; 764*55d7bfe2SMark Cave-Ayland int i; 765*55d7bfe2SMark Cave-Ayland 766*55d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 767*55d7bfe2SMark Cave-Ayland s->tmpblit = val; 768*55d7bfe2SMark Cave-Ayland } else { 769*55d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 770*55d7bfe2SMark Cave-Ayland adsr = val & 0xffffff; 771*55d7bfe2SMark Cave-Ayland len = ((val >> 24) & 0x1f) + 1; 772*55d7bfe2SMark Cave-Ayland if (adsr == 0xffffff) { 773*55d7bfe2SMark Cave-Ayland memset(&s->vram[addr], s->tmpblit, len); 774*55d7bfe2SMark Cave-Ayland if (s->depth == 24) { 775*55d7bfe2SMark Cave-Ayland val = s->tmpblit & 0xffffff; 776*55d7bfe2SMark Cave-Ayland val = cpu_to_be32(val); 777*55d7bfe2SMark Cave-Ayland for (i = 0; i < len; i++) { 778*55d7bfe2SMark Cave-Ayland s->vram24[addr + i] = val; 779*55d7bfe2SMark Cave-Ayland } 780*55d7bfe2SMark Cave-Ayland } 781*55d7bfe2SMark Cave-Ayland } else { 782*55d7bfe2SMark Cave-Ayland memcpy(&s->vram[addr], &s->vram[adsr], len); 783*55d7bfe2SMark Cave-Ayland if (s->depth == 24) { 784*55d7bfe2SMark Cave-Ayland memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); 785*55d7bfe2SMark Cave-Ayland } 786*55d7bfe2SMark Cave-Ayland } 787*55d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, len); 788*55d7bfe2SMark Cave-Ayland } 789*55d7bfe2SMark Cave-Ayland } 790*55d7bfe2SMark Cave-Ayland 791*55d7bfe2SMark Cave-Ayland static void tcx_rblit_writel(void *opaque, hwaddr addr, 792*55d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 793*55d7bfe2SMark Cave-Ayland { 794*55d7bfe2SMark Cave-Ayland TCXState *s = opaque; 795*55d7bfe2SMark Cave-Ayland uint32_t adsr, len; 796*55d7bfe2SMark Cave-Ayland int i; 797*55d7bfe2SMark Cave-Ayland 798*55d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 799*55d7bfe2SMark Cave-Ayland s->tmpblit = val; 800*55d7bfe2SMark Cave-Ayland } else { 801*55d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 802*55d7bfe2SMark Cave-Ayland adsr = val & 0xffffff; 803*55d7bfe2SMark Cave-Ayland len = ((val >> 24) & 0x1f) + 1; 804*55d7bfe2SMark Cave-Ayland if (adsr == 0xffffff) { 805*55d7bfe2SMark Cave-Ayland memset(&s->vram[addr], s->tmpblit, len); 806*55d7bfe2SMark Cave-Ayland if (s->depth == 24) { 807*55d7bfe2SMark Cave-Ayland val = s->tmpblit & 0xffffff; 808*55d7bfe2SMark Cave-Ayland val = cpu_to_be32(val); 809*55d7bfe2SMark Cave-Ayland for (i = 0; i < len; i++) { 810*55d7bfe2SMark Cave-Ayland s->vram24[addr + i] = val; 811*55d7bfe2SMark Cave-Ayland s->cplane[addr + i] = val; 812*55d7bfe2SMark Cave-Ayland } 813*55d7bfe2SMark Cave-Ayland } 814*55d7bfe2SMark Cave-Ayland } else { 815*55d7bfe2SMark Cave-Ayland memcpy(&s->vram[addr], &s->vram[adsr], len); 816*55d7bfe2SMark Cave-Ayland if (s->depth == 24) { 817*55d7bfe2SMark Cave-Ayland memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); 818*55d7bfe2SMark Cave-Ayland memcpy(&s->cplane[addr], &s->cplane[adsr], len * 4); 819*55d7bfe2SMark Cave-Ayland } 820*55d7bfe2SMark Cave-Ayland } 821*55d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, len); 822*55d7bfe2SMark Cave-Ayland } 823*55d7bfe2SMark Cave-Ayland } 824*55d7bfe2SMark Cave-Ayland 825*55d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_blit_ops = { 826*55d7bfe2SMark Cave-Ayland .read = tcx_blit_readl, 827*55d7bfe2SMark Cave-Ayland .write = tcx_blit_writel, 828*55d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 829*55d7bfe2SMark Cave-Ayland .valid = { 830*55d7bfe2SMark Cave-Ayland .min_access_size = 4, 831*55d7bfe2SMark Cave-Ayland .max_access_size = 4, 832*55d7bfe2SMark Cave-Ayland }, 833*55d7bfe2SMark Cave-Ayland }; 834*55d7bfe2SMark Cave-Ayland 835*55d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_rblit_ops = { 836*55d7bfe2SMark Cave-Ayland .read = tcx_blit_readl, 837*55d7bfe2SMark Cave-Ayland .write = tcx_rblit_writel, 838*55d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 839*55d7bfe2SMark Cave-Ayland .valid = { 840*55d7bfe2SMark Cave-Ayland .min_access_size = 4, 841*55d7bfe2SMark Cave-Ayland .max_access_size = 4, 842*55d7bfe2SMark Cave-Ayland }, 843*55d7bfe2SMark Cave-Ayland }; 844*55d7bfe2SMark Cave-Ayland 845*55d7bfe2SMark Cave-Ayland static void tcx_invalidate_cursor_position(TCXState *s) 846*55d7bfe2SMark Cave-Ayland { 847*55d7bfe2SMark Cave-Ayland int ymin, ymax, start, end; 848*55d7bfe2SMark Cave-Ayland 849*55d7bfe2SMark Cave-Ayland /* invalidate only near the cursor */ 850*55d7bfe2SMark Cave-Ayland ymin = s->cursy; 851*55d7bfe2SMark Cave-Ayland if (ymin >= s->height) { 852*55d7bfe2SMark Cave-Ayland return; 853*55d7bfe2SMark Cave-Ayland } 854*55d7bfe2SMark Cave-Ayland ymax = MIN(s->height, ymin + 32); 855*55d7bfe2SMark Cave-Ayland start = ymin * 1024; 856*55d7bfe2SMark Cave-Ayland end = ymax * 1024; 857*55d7bfe2SMark Cave-Ayland 858*55d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, start, end-start); 859*55d7bfe2SMark Cave-Ayland } 860*55d7bfe2SMark Cave-Ayland 861*55d7bfe2SMark Cave-Ayland static uint64_t tcx_thc_readl(void *opaque, hwaddr addr, 862*55d7bfe2SMark Cave-Ayland unsigned size) 863*55d7bfe2SMark Cave-Ayland { 864*55d7bfe2SMark Cave-Ayland TCXState *s = opaque; 865*55d7bfe2SMark Cave-Ayland uint64_t val; 866*55d7bfe2SMark Cave-Ayland 867*55d7bfe2SMark Cave-Ayland if (addr == TCX_THC_MISC) { 868*55d7bfe2SMark Cave-Ayland val = s->thcmisc | 0x02000000; 869*55d7bfe2SMark Cave-Ayland } else { 870*55d7bfe2SMark Cave-Ayland val = 0; 871*55d7bfe2SMark Cave-Ayland } 872*55d7bfe2SMark Cave-Ayland return val; 873*55d7bfe2SMark Cave-Ayland } 874*55d7bfe2SMark Cave-Ayland 875*55d7bfe2SMark Cave-Ayland static void tcx_thc_writel(void *opaque, hwaddr addr, 876*55d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 877*55d7bfe2SMark Cave-Ayland { 878*55d7bfe2SMark Cave-Ayland TCXState *s = opaque; 879*55d7bfe2SMark Cave-Ayland 880*55d7bfe2SMark Cave-Ayland if (addr == TCX_THC_CURSXY) { 881*55d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 882*55d7bfe2SMark Cave-Ayland s->cursx = val >> 16; 883*55d7bfe2SMark Cave-Ayland s->cursy = val; 884*55d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 885*55d7bfe2SMark Cave-Ayland } else if (addr >= TCX_THC_CURSMASK && addr < TCX_THC_CURSMASK + 128) { 886*55d7bfe2SMark Cave-Ayland s->cursmask[(addr - TCX_THC_CURSMASK) >> 2] = val; 887*55d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 888*55d7bfe2SMark Cave-Ayland } else if (addr >= TCX_THC_CURSBITS && addr < TCX_THC_CURSBITS + 128) { 889*55d7bfe2SMark Cave-Ayland s->cursbits[(addr - TCX_THC_CURSBITS) >> 2] = val; 890*55d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 891*55d7bfe2SMark Cave-Ayland } else if (addr == TCX_THC_MISC) { 892*55d7bfe2SMark Cave-Ayland s->thcmisc = val; 893*55d7bfe2SMark Cave-Ayland } 894*55d7bfe2SMark Cave-Ayland 895*55d7bfe2SMark Cave-Ayland } 896*55d7bfe2SMark Cave-Ayland 897*55d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_thc_ops = { 898*55d7bfe2SMark Cave-Ayland .read = tcx_thc_readl, 899*55d7bfe2SMark Cave-Ayland .write = tcx_thc_writel, 900*55d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 901*55d7bfe2SMark Cave-Ayland .valid = { 902*55d7bfe2SMark Cave-Ayland .min_access_size = 4, 903*55d7bfe2SMark Cave-Ayland .max_access_size = 4, 904*55d7bfe2SMark Cave-Ayland }, 905*55d7bfe2SMark Cave-Ayland }; 906*55d7bfe2SMark Cave-Ayland 907*55d7bfe2SMark Cave-Ayland static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr, 908*55d7bfe2SMark Cave-Ayland unsigned size) 909*55d7bfe2SMark Cave-Ayland { 910*55d7bfe2SMark Cave-Ayland return 0; 911*55d7bfe2SMark Cave-Ayland } 912*55d7bfe2SMark Cave-Ayland 913*55d7bfe2SMark Cave-Ayland static void tcx_dummy_writel(void *opaque, hwaddr addr, 914*55d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 915*55d7bfe2SMark Cave-Ayland { 916*55d7bfe2SMark Cave-Ayland return; 917*55d7bfe2SMark Cave-Ayland } 918*55d7bfe2SMark Cave-Ayland 919*55d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_dummy_ops = { 920*55d7bfe2SMark Cave-Ayland .read = tcx_dummy_readl, 921*55d7bfe2SMark Cave-Ayland .write = tcx_dummy_writel, 922d08151bfSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 923d08151bfSAvi Kivity .valid = { 924d08151bfSAvi Kivity .min_access_size = 4, 925d08151bfSAvi Kivity .max_access_size = 4, 926d08151bfSAvi Kivity }, 9278508b89eSblueswir1 }; 9288508b89eSblueswir1 929380cd056SGerd Hoffmann static const GraphicHwOps tcx_ops = { 930380cd056SGerd Hoffmann .invalidate = tcx_invalidate_display, 931380cd056SGerd Hoffmann .gfx_update = tcx_update_display, 932380cd056SGerd Hoffmann }; 933380cd056SGerd Hoffmann 934380cd056SGerd Hoffmann static const GraphicHwOps tcx24_ops = { 935380cd056SGerd Hoffmann .invalidate = tcx24_invalidate_display, 936380cd056SGerd Hoffmann .gfx_update = tcx24_update_display, 937380cd056SGerd Hoffmann }; 938380cd056SGerd Hoffmann 93901b91ac2SMark Cave-Ayland static void tcx_initfn(Object *obj) 94001b91ac2SMark Cave-Ayland { 94101b91ac2SMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 94201b91ac2SMark Cave-Ayland TCXState *s = TCX(obj); 94301b91ac2SMark Cave-Ayland 94449946538SHu Tao memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE, 94549946538SHu Tao &error_abort); 94601b91ac2SMark Cave-Ayland memory_region_set_readonly(&s->rom, true); 94701b91ac2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rom); 94801b91ac2SMark Cave-Ayland 949*55d7bfe2SMark Cave-Ayland /* 2/STIP : Stippler */ 950*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->stip, OBJECT(s), &tcx_stip_ops, s, "tcx.stip", 951*55d7bfe2SMark Cave-Ayland TCX_STIP_NREGS); 952*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->stip); 953*55d7bfe2SMark Cave-Ayland 954*55d7bfe2SMark Cave-Ayland /* 3/BLIT : Blitter */ 955*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->blit, OBJECT(s), &tcx_blit_ops, s, "tcx.blit", 956*55d7bfe2SMark Cave-Ayland TCX_BLIT_NREGS); 957*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->blit); 958*55d7bfe2SMark Cave-Ayland 959*55d7bfe2SMark Cave-Ayland /* 5/RSTIP : Raw Stippler */ 960*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->rstip, OBJECT(s), &tcx_rstip_ops, s, "tcx.rstip", 961*55d7bfe2SMark Cave-Ayland TCX_RSTIP_NREGS); 962*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rstip); 963*55d7bfe2SMark Cave-Ayland 964*55d7bfe2SMark Cave-Ayland /* 6/RBLIT : Raw Blitter */ 965*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->rblit, OBJECT(s), &tcx_rblit_ops, s, "tcx.rblit", 966*55d7bfe2SMark Cave-Ayland TCX_RBLIT_NREGS); 967*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rblit); 968*55d7bfe2SMark Cave-Ayland 969*55d7bfe2SMark Cave-Ayland /* 7/TEC : ??? */ 970*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->tec, OBJECT(s), &tcx_dummy_ops, s, 971*55d7bfe2SMark Cave-Ayland "tcx.tec", TCX_TEC_NREGS); 972*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->tec); 973*55d7bfe2SMark Cave-Ayland 974*55d7bfe2SMark Cave-Ayland /* 8/CMAP : DAC */ 97501b91ac2SMark Cave-Ayland memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, 97601b91ac2SMark Cave-Ayland "tcx.dac", TCX_DAC_NREGS); 97701b91ac2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->dac); 97801b91ac2SMark Cave-Ayland 979*55d7bfe2SMark Cave-Ayland /* 9/THC : Cursor */ 980*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->thc, OBJECT(s), &tcx_thc_ops, s, "tcx.thc", 981*55d7bfe2SMark Cave-Ayland TCX_THC_NREGS); 982*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->thc); 98301b91ac2SMark Cave-Ayland 984*55d7bfe2SMark Cave-Ayland /* 11/DHC : ??? */ 985*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->dhc, OBJECT(s), &tcx_dummy_ops, s, "tcx.dhc", 986*55d7bfe2SMark Cave-Ayland TCX_DHC_NREGS); 987*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->dhc); 988*55d7bfe2SMark Cave-Ayland 989*55d7bfe2SMark Cave-Ayland /* 12/ALT : ??? */ 990*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->alt, OBJECT(s), &tcx_dummy_ops, s, "tcx.alt", 991*55d7bfe2SMark Cave-Ayland TCX_ALT_NREGS); 992*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->alt); 99301b91ac2SMark Cave-Ayland 99401b91ac2SMark Cave-Ayland return; 99501b91ac2SMark Cave-Ayland } 99601b91ac2SMark Cave-Ayland 997d4ad9decSMark Cave-Ayland static void tcx_realizefn(DeviceState *dev, Error **errp) 998f40070c3SBlue Swirl { 999d4ad9decSMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 100001774ddbSAndreas Färber TCXState *s = TCX(dev); 1001d08151bfSAvi Kivity ram_addr_t vram_offset = 0; 1002da87dd7bSMark Cave-Ayland int size, ret; 1003dc828ca1Spbrook uint8_t *vram_base; 1004da87dd7bSMark Cave-Ayland char *fcode_filename; 1005dc828ca1Spbrook 10063eadad55SPaolo Bonzini memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram", 100749946538SHu Tao s->vram_size * (1 + 4 + 4), &error_abort); 1008c5705a77SAvi Kivity vmstate_register_ram_global(&s->vram_mem); 1009d08151bfSAvi Kivity vram_base = memory_region_get_ram_ptr(&s->vram_mem); 1010e80cfcfcSbellard 1011*55d7bfe2SMark Cave-Ayland /* 10/ROM : FCode ROM */ 1012da87dd7bSMark Cave-Ayland vmstate_register_ram_global(&s->rom); 1013da87dd7bSMark Cave-Ayland fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE); 1014da87dd7bSMark Cave-Ayland if (fcode_filename) { 1015da87dd7bSMark Cave-Ayland ret = load_image_targphys(fcode_filename, s->prom_addr, 1016da87dd7bSMark Cave-Ayland FCODE_MAX_ROM_SIZE); 1017da87dd7bSMark Cave-Ayland if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { 1018d4ad9decSMark Cave-Ayland error_report("tcx: could not load prom '%s'", TCX_ROM_FILE); 1019da87dd7bSMark Cave-Ayland } 1020da87dd7bSMark Cave-Ayland } 1021da87dd7bSMark Cave-Ayland 1022*55d7bfe2SMark Cave-Ayland /* 0/DFB8 : 8-bit plane */ 1023eee0b836Sblueswir1 s->vram = vram_base; 1024ee6847d1SGerd Hoffmann size = s->vram_size; 10253eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit", 1026d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1027d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_8bit); 1028eee0b836Sblueswir1 vram_offset += size; 1029eee0b836Sblueswir1 vram_base += size; 1030eee0b836Sblueswir1 1031*55d7bfe2SMark Cave-Ayland /* 1/DFB24 : 24bit plane */ 1032ee6847d1SGerd Hoffmann size = s->vram_size * 4; 1033eee0b836Sblueswir1 s->vram24 = (uint32_t *)vram_base; 1034eee0b836Sblueswir1 s->vram24_offset = vram_offset; 10353eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", 1036d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1037d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_24bit); 1038eee0b836Sblueswir1 vram_offset += size; 1039eee0b836Sblueswir1 vram_base += size; 1040eee0b836Sblueswir1 1041*55d7bfe2SMark Cave-Ayland /* 4/RDFB32 : Raw Framebuffer */ 1042ee6847d1SGerd Hoffmann size = s->vram_size * 4; 1043eee0b836Sblueswir1 s->cplane = (uint32_t *)vram_base; 1044eee0b836Sblueswir1 s->cplane_offset = vram_offset; 10453eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", 1046d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1047d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_cplane); 1048f40070c3SBlue Swirl 1049*55d7bfe2SMark Cave-Ayland /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */ 1050*55d7bfe2SMark Cave-Ayland if (s->depth == 8) { 1051*55d7bfe2SMark Cave-Ayland memory_region_init_io(&s->thc24, OBJECT(s), &tcx_dummy_ops, s, 1052*55d7bfe2SMark Cave-Ayland "tcx.thc24", TCX_THC_NREGS); 1053*55d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->thc24); 1054eee0b836Sblueswir1 } 1055eee0b836Sblueswir1 1056*55d7bfe2SMark Cave-Ayland sysbus_init_irq(sbd, &s->irq); 1057*55d7bfe2SMark Cave-Ayland 1058*55d7bfe2SMark Cave-Ayland if (s->depth == 8) { 1059*55d7bfe2SMark Cave-Ayland s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); 1060*55d7bfe2SMark Cave-Ayland } else { 1061*55d7bfe2SMark Cave-Ayland s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); 1062*55d7bfe2SMark Cave-Ayland } 1063*55d7bfe2SMark Cave-Ayland s->thcmisc = 0; 1064*55d7bfe2SMark Cave-Ayland 1065c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 1066420557e8Sbellard } 1067420557e8Sbellard 1068999e12bbSAnthony Liguori static Property tcx_properties[] = { 1069c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT32("vram_size", TCXState, vram_size, -1), 107053dad499SGerd Hoffmann DEFINE_PROP_UINT16("width", TCXState, width, -1), 107153dad499SGerd Hoffmann DEFINE_PROP_UINT16("height", TCXState, height, -1), 107253dad499SGerd Hoffmann DEFINE_PROP_UINT16("depth", TCXState, depth, -1), 1073c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT64("prom_addr", TCXState, prom_addr, -1), 107453dad499SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 1075999e12bbSAnthony Liguori }; 1076999e12bbSAnthony Liguori 1077999e12bbSAnthony Liguori static void tcx_class_init(ObjectClass *klass, void *data) 1078999e12bbSAnthony Liguori { 107939bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1080999e12bbSAnthony Liguori 1081d4ad9decSMark Cave-Ayland dc->realize = tcx_realizefn; 108239bffca2SAnthony Liguori dc->reset = tcx_reset; 108339bffca2SAnthony Liguori dc->vmsd = &vmstate_tcx; 108439bffca2SAnthony Liguori dc->props = tcx_properties; 1085ee6847d1SGerd Hoffmann } 1086999e12bbSAnthony Liguori 10878c43a6f0SAndreas Färber static const TypeInfo tcx_info = { 108801774ddbSAndreas Färber .name = TYPE_TCX, 108939bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 109039bffca2SAnthony Liguori .instance_size = sizeof(TCXState), 109101b91ac2SMark Cave-Ayland .instance_init = tcx_initfn, 1092999e12bbSAnthony Liguori .class_init = tcx_class_init, 1093ee6847d1SGerd Hoffmann }; 1094ee6847d1SGerd Hoffmann 109583f7d43aSAndreas Färber static void tcx_register_types(void) 1096f40070c3SBlue Swirl { 109739bffca2SAnthony Liguori type_register_static(&tcx_info); 1098f40070c3SBlue Swirl } 1099f40070c3SBlue Swirl 110083f7d43aSAndreas Färber type_init(tcx_register_types) 1101