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 2547df5154SPeter Maydell #include "qemu/osdep.h" 26da34e65cSMarkus Armbruster #include "qapi/error.h" 27077805faSPaolo Bonzini #include "qemu-common.h" 284771d756SPaolo Bonzini #include "cpu.h" /* FIXME shouldn't use TARGET_PAGE_SIZE */ 2928ecbaeeSPaolo Bonzini #include "ui/console.h" 3028ecbaeeSPaolo Bonzini #include "ui/pixel_ops.h" 31da87dd7bSMark Cave-Ayland #include "hw/loader.h" 3283c9f4caSPaolo Bonzini #include "hw/sysbus.h" 33d49b6836SMarkus Armbruster #include "qemu/error-report.h" 34420557e8Sbellard 35da87dd7bSMark Cave-Ayland #define TCX_ROM_FILE "QEMU,tcx.bin" 36da87dd7bSMark Cave-Ayland #define FCODE_MAX_ROM_SIZE 0x10000 37da87dd7bSMark Cave-Ayland 38420557e8Sbellard #define MAXX 1024 39420557e8Sbellard #define MAXY 768 406f7e9aecSbellard #define TCX_DAC_NREGS 16 4155d7bfe2SMark Cave-Ayland #define TCX_THC_NREGS 0x1000 4255d7bfe2SMark Cave-Ayland #define TCX_DHC_NREGS 0x4000 438508b89eSblueswir1 #define TCX_TEC_NREGS 0x1000 4455d7bfe2SMark Cave-Ayland #define TCX_ALT_NREGS 0x8000 4555d7bfe2SMark Cave-Ayland #define TCX_STIP_NREGS 0x800000 4655d7bfe2SMark Cave-Ayland #define TCX_BLIT_NREGS 0x800000 4755d7bfe2SMark Cave-Ayland #define TCX_RSTIP_NREGS 0x800000 4855d7bfe2SMark Cave-Ayland #define TCX_RBLIT_NREGS 0x800000 4955d7bfe2SMark Cave-Ayland 5055d7bfe2SMark Cave-Ayland #define TCX_THC_MISC 0x818 5155d7bfe2SMark Cave-Ayland #define TCX_THC_CURSXY 0x8fc 5255d7bfe2SMark Cave-Ayland #define TCX_THC_CURSMASK 0x900 5355d7bfe2SMark Cave-Ayland #define TCX_THC_CURSBITS 0x980 54420557e8Sbellard 5501774ddbSAndreas Färber #define TYPE_TCX "SUNW,tcx" 5601774ddbSAndreas Färber #define TCX(obj) OBJECT_CHECK(TCXState, (obj), TYPE_TCX) 5701774ddbSAndreas Färber 58420557e8Sbellard typedef struct TCXState { 5901774ddbSAndreas Färber SysBusDevice parent_obj; 6001774ddbSAndreas Färber 61c78f7137SGerd Hoffmann QemuConsole *con; 6255d7bfe2SMark Cave-Ayland qemu_irq irq; 638d5f07faSbellard uint8_t *vram; 64eee0b836Sblueswir1 uint32_t *vram24, *cplane; 65da87dd7bSMark Cave-Ayland hwaddr prom_addr; 66da87dd7bSMark Cave-Ayland MemoryRegion rom; 67d08151bfSAvi Kivity MemoryRegion vram_mem; 68d08151bfSAvi Kivity MemoryRegion vram_8bit; 69d08151bfSAvi Kivity MemoryRegion vram_24bit; 7055d7bfe2SMark Cave-Ayland MemoryRegion stip; 7155d7bfe2SMark Cave-Ayland MemoryRegion blit; 72d08151bfSAvi Kivity MemoryRegion vram_cplane; 7355d7bfe2SMark Cave-Ayland MemoryRegion rstip; 7455d7bfe2SMark Cave-Ayland MemoryRegion rblit; 75d08151bfSAvi Kivity MemoryRegion tec; 7655d7bfe2SMark Cave-Ayland MemoryRegion dac; 7755d7bfe2SMark Cave-Ayland MemoryRegion thc; 7855d7bfe2SMark Cave-Ayland MemoryRegion dhc; 7955d7bfe2SMark Cave-Ayland MemoryRegion alt; 80d08151bfSAvi Kivity MemoryRegion thc24; 8155d7bfe2SMark Cave-Ayland 82d08151bfSAvi Kivity ram_addr_t vram24_offset, cplane_offset; 8355d7bfe2SMark Cave-Ayland uint32_t tmpblit; 84ee6847d1SGerd Hoffmann uint32_t vram_size; 8555d7bfe2SMark Cave-Ayland uint32_t palette[260]; 8655d7bfe2SMark Cave-Ayland uint8_t r[260], g[260], b[260]; 87427a66c3SBlue Swirl uint16_t width, height, depth; 886f7e9aecSbellard uint8_t dac_index, dac_state; 8955d7bfe2SMark Cave-Ayland uint32_t thcmisc; 9055d7bfe2SMark Cave-Ayland uint32_t cursmask[32]; 9155d7bfe2SMark Cave-Ayland uint32_t cursbits[32]; 9255d7bfe2SMark Cave-Ayland uint16_t cursx; 9355d7bfe2SMark Cave-Ayland uint16_t cursy; 94420557e8Sbellard } TCXState; 95420557e8Sbellard 969800b3c2SMark Cave-Ayland static void tcx_set_dirty(TCXState *s, ram_addr_t addr, int len) 97d3ffcafeSBlue Swirl { 989800b3c2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, len); 994b865c28SMark Cave-Ayland 1004b865c28SMark Cave-Ayland if (s->depth == 24) { 1014b865c28SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, s->vram24_offset + addr * 4, 1024b865c28SMark Cave-Ayland len * 4); 1034b865c28SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, s->cplane_offset + addr * 4, 1044b865c28SMark Cave-Ayland len * 4); 1054b865c28SMark Cave-Ayland } 106d3ffcafeSBlue Swirl } 107d3ffcafeSBlue Swirl 108427ee02bSMark Cave-Ayland static int tcx_check_dirty(TCXState *s, ram_addr_t addr, int len) 109d3ffcafeSBlue Swirl { 11055d7bfe2SMark Cave-Ayland int ret; 11155d7bfe2SMark Cave-Ayland 112427ee02bSMark Cave-Ayland ret = memory_region_get_dirty(&s->vram_mem, addr, len, DIRTY_MEMORY_VGA); 113427ee02bSMark Cave-Ayland 114427ee02bSMark Cave-Ayland if (s->depth == 24) { 115427ee02bSMark Cave-Ayland ret |= memory_region_get_dirty(&s->vram_mem, 116427ee02bSMark Cave-Ayland s->vram24_offset + addr * 4, len * 4, 11755d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 118427ee02bSMark Cave-Ayland ret |= memory_region_get_dirty(&s->vram_mem, 119427ee02bSMark Cave-Ayland s->cplane_offset + addr * 4, len * 4, 12055d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 121427ee02bSMark Cave-Ayland } 122427ee02bSMark Cave-Ayland 12355d7bfe2SMark Cave-Ayland return ret; 12455d7bfe2SMark Cave-Ayland } 12555d7bfe2SMark Cave-Ayland 12636180430SMark Cave-Ayland static void tcx_reset_dirty(TCXState *s, ram_addr_t addr, int len) 12755d7bfe2SMark Cave-Ayland { 12836180430SMark Cave-Ayland memory_region_reset_dirty(&s->vram_mem, addr, len, DIRTY_MEMORY_VGA); 12936180430SMark Cave-Ayland 13036180430SMark Cave-Ayland if (s->depth == 24) { 13136180430SMark Cave-Ayland memory_region_reset_dirty(&s->vram_mem, s->vram24_offset + addr * 4, 13236180430SMark Cave-Ayland len * 4, DIRTY_MEMORY_VGA); 13336180430SMark Cave-Ayland memory_region_reset_dirty(&s->vram_mem, s->cplane_offset + addr * 4, 13436180430SMark Cave-Ayland len * 4, DIRTY_MEMORY_VGA); 13536180430SMark Cave-Ayland } 136d3ffcafeSBlue Swirl } 13795219897Spbrook 13821206a10Sbellard static void update_palette_entries(TCXState *s, int start, int end) 13921206a10Sbellard { 140c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(s->con); 14121206a10Sbellard int i; 142c78f7137SGerd Hoffmann 14321206a10Sbellard for (i = start; i < end; i++) { 144c78f7137SGerd Hoffmann switch (surface_bits_per_pixel(surface)) { 14521206a10Sbellard default: 14621206a10Sbellard case 8: 14721206a10Sbellard s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]); 14821206a10Sbellard break; 14921206a10Sbellard case 15: 15021206a10Sbellard s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]); 15121206a10Sbellard break; 15221206a10Sbellard case 16: 15321206a10Sbellard s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); 15421206a10Sbellard break; 15521206a10Sbellard case 32: 156c78f7137SGerd Hoffmann if (is_surface_bgr(surface)) { 1577b5d76daSaliguori s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]); 158c78f7137SGerd Hoffmann } else { 15921206a10Sbellard s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); 160c78f7137SGerd Hoffmann } 16121206a10Sbellard break; 16221206a10Sbellard } 16321206a10Sbellard } 1649800b3c2SMark Cave-Ayland tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem)); 165d3ffcafeSBlue Swirl } 16621206a10Sbellard 167e80cfcfcSbellard static void tcx_draw_line32(TCXState *s1, uint8_t *d, 168e80cfcfcSbellard const uint8_t *s, int width) 169420557e8Sbellard { 170e80cfcfcSbellard int x; 171e80cfcfcSbellard uint8_t val; 1728bdc2159Sths uint32_t *p = (uint32_t *)d; 173e80cfcfcSbellard 174e80cfcfcSbellard for (x = 0; x < width; x++) { 175e80cfcfcSbellard val = *s++; 1768bdc2159Sths *p++ = s1->palette[val]; 177e80cfcfcSbellard } 178420557e8Sbellard } 179420557e8Sbellard 18021206a10Sbellard static void tcx_draw_line16(TCXState *s1, uint8_t *d, 181e80cfcfcSbellard const uint8_t *s, int width) 182e80cfcfcSbellard { 183e80cfcfcSbellard int x; 184e80cfcfcSbellard uint8_t val; 1858bdc2159Sths uint16_t *p = (uint16_t *)d; 1868d5f07faSbellard 187e80cfcfcSbellard for (x = 0; x < width; x++) { 188e80cfcfcSbellard val = *s++; 1898bdc2159Sths *p++ = s1->palette[val]; 190e80cfcfcSbellard } 191e80cfcfcSbellard } 192e80cfcfcSbellard 193e80cfcfcSbellard static void tcx_draw_line8(TCXState *s1, uint8_t *d, 194e80cfcfcSbellard const uint8_t *s, int width) 195e80cfcfcSbellard { 196e80cfcfcSbellard int x; 197e80cfcfcSbellard uint8_t val; 198e80cfcfcSbellard 199e80cfcfcSbellard for(x = 0; x < width; x++) { 200e80cfcfcSbellard val = *s++; 20121206a10Sbellard *d++ = s1->palette[val]; 202e80cfcfcSbellard } 203e80cfcfcSbellard } 204e80cfcfcSbellard 20555d7bfe2SMark Cave-Ayland static void tcx_draw_cursor32(TCXState *s1, uint8_t *d, 20655d7bfe2SMark Cave-Ayland int y, int width) 20755d7bfe2SMark Cave-Ayland { 20855d7bfe2SMark Cave-Ayland int x, len; 20955d7bfe2SMark Cave-Ayland uint32_t mask, bits; 21055d7bfe2SMark Cave-Ayland uint32_t *p = (uint32_t *)d; 21155d7bfe2SMark Cave-Ayland 21255d7bfe2SMark Cave-Ayland y = y - s1->cursy; 21355d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 21455d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 21555d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 21655d7bfe2SMark Cave-Ayland p = &p[s1->cursx]; 21755d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 21855d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 21955d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 22055d7bfe2SMark Cave-Ayland *p = s1->palette[259]; 22155d7bfe2SMark Cave-Ayland } else { 22255d7bfe2SMark Cave-Ayland *p = s1->palette[258]; 22355d7bfe2SMark Cave-Ayland } 22455d7bfe2SMark Cave-Ayland } 22555d7bfe2SMark Cave-Ayland p++; 22655d7bfe2SMark Cave-Ayland mask <<= 1; 22755d7bfe2SMark Cave-Ayland bits <<= 1; 22855d7bfe2SMark Cave-Ayland } 22955d7bfe2SMark Cave-Ayland } 23055d7bfe2SMark Cave-Ayland 23155d7bfe2SMark Cave-Ayland static void tcx_draw_cursor16(TCXState *s1, uint8_t *d, 23255d7bfe2SMark Cave-Ayland int y, int width) 23355d7bfe2SMark Cave-Ayland { 23455d7bfe2SMark Cave-Ayland int x, len; 23555d7bfe2SMark Cave-Ayland uint32_t mask, bits; 23655d7bfe2SMark Cave-Ayland uint16_t *p = (uint16_t *)d; 23755d7bfe2SMark Cave-Ayland 23855d7bfe2SMark Cave-Ayland y = y - s1->cursy; 23955d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 24055d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 24155d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 24255d7bfe2SMark Cave-Ayland p = &p[s1->cursx]; 24355d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 24455d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 24555d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 24655d7bfe2SMark Cave-Ayland *p = s1->palette[259]; 24755d7bfe2SMark Cave-Ayland } else { 24855d7bfe2SMark Cave-Ayland *p = s1->palette[258]; 24955d7bfe2SMark Cave-Ayland } 25055d7bfe2SMark Cave-Ayland } 25155d7bfe2SMark Cave-Ayland p++; 25255d7bfe2SMark Cave-Ayland mask <<= 1; 25355d7bfe2SMark Cave-Ayland bits <<= 1; 25455d7bfe2SMark Cave-Ayland } 25555d7bfe2SMark Cave-Ayland } 25655d7bfe2SMark Cave-Ayland 25755d7bfe2SMark Cave-Ayland static void tcx_draw_cursor8(TCXState *s1, uint8_t *d, 25855d7bfe2SMark Cave-Ayland int y, int width) 25955d7bfe2SMark Cave-Ayland { 26055d7bfe2SMark Cave-Ayland int x, len; 26155d7bfe2SMark Cave-Ayland uint32_t mask, bits; 26255d7bfe2SMark Cave-Ayland 26355d7bfe2SMark Cave-Ayland y = y - s1->cursy; 26455d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 26555d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 26655d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 26755d7bfe2SMark Cave-Ayland d = &d[s1->cursx]; 26855d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 26955d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 27055d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 27155d7bfe2SMark Cave-Ayland *d = s1->palette[259]; 27255d7bfe2SMark Cave-Ayland } else { 27355d7bfe2SMark Cave-Ayland *d = s1->palette[258]; 27455d7bfe2SMark Cave-Ayland } 27555d7bfe2SMark Cave-Ayland } 27655d7bfe2SMark Cave-Ayland d++; 27755d7bfe2SMark Cave-Ayland mask <<= 1; 27855d7bfe2SMark Cave-Ayland bits <<= 1; 27955d7bfe2SMark Cave-Ayland } 28055d7bfe2SMark Cave-Ayland } 28155d7bfe2SMark Cave-Ayland 282688ea2ebSblueswir1 /* 283688ea2ebSblueswir1 XXX Could be much more optimal: 284688ea2ebSblueswir1 * detect if line/page/whole screen is in 24 bit mode 285688ea2ebSblueswir1 * if destination is also BGR, use memcpy 286688ea2ebSblueswir1 */ 287eee0b836Sblueswir1 static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, 288eee0b836Sblueswir1 const uint8_t *s, int width, 289eee0b836Sblueswir1 const uint32_t *cplane, 290eee0b836Sblueswir1 const uint32_t *s24) 291eee0b836Sblueswir1 { 292c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(s1->con); 2937b5d76daSaliguori int x, bgr, r, g, b; 294688ea2ebSblueswir1 uint8_t val, *p8; 295eee0b836Sblueswir1 uint32_t *p = (uint32_t *)d; 296eee0b836Sblueswir1 uint32_t dval; 297c78f7137SGerd Hoffmann bgr = is_surface_bgr(surface); 298eee0b836Sblueswir1 for(x = 0; x < width; x++, s++, s24++) { 29955d7bfe2SMark Cave-Ayland if (be32_to_cpu(*cplane) & 0x03000000) { 30055d7bfe2SMark Cave-Ayland /* 24-bit direct, BGR order */ 301688ea2ebSblueswir1 p8 = (uint8_t *)s24; 302688ea2ebSblueswir1 p8++; 303688ea2ebSblueswir1 b = *p8++; 304688ea2ebSblueswir1 g = *p8++; 305f7e683b8SBlue Swirl r = *p8; 3067b5d76daSaliguori if (bgr) 3077b5d76daSaliguori dval = rgb_to_pixel32bgr(r, g, b); 3087b5d76daSaliguori else 309688ea2ebSblueswir1 dval = rgb_to_pixel32(r, g, b); 310eee0b836Sblueswir1 } else { 31155d7bfe2SMark Cave-Ayland /* 8-bit pseudocolor */ 312eee0b836Sblueswir1 val = *s; 313eee0b836Sblueswir1 dval = s1->palette[val]; 314eee0b836Sblueswir1 } 315eee0b836Sblueswir1 *p++ = dval; 31655d7bfe2SMark Cave-Ayland cplane++; 317eee0b836Sblueswir1 } 318eee0b836Sblueswir1 } 319eee0b836Sblueswir1 320e80cfcfcSbellard /* Fixed line length 1024 allows us to do nice tricks not possible on 321e80cfcfcSbellard VGA... */ 32255d7bfe2SMark Cave-Ayland 32395219897Spbrook static void tcx_update_display(void *opaque) 324e80cfcfcSbellard { 325e80cfcfcSbellard TCXState *ts = opaque; 326c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(ts->con); 327c227f099SAnthony Liguori ram_addr_t page, page_min, page_max; 328550be127Sbellard int y, y_start, dd, ds; 329e80cfcfcSbellard uint8_t *d, *s; 330b3ceef24Sblueswir1 void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); 33155d7bfe2SMark Cave-Ayland void (*fc)(TCXState *s1, uint8_t *dst, int y, int width); 332e80cfcfcSbellard 333c78f7137SGerd Hoffmann if (surface_bits_per_pixel(surface) == 0) { 334e80cfcfcSbellard return; 335c78f7137SGerd Hoffmann } 336c78f7137SGerd Hoffmann 337d08151bfSAvi Kivity page = 0; 338e80cfcfcSbellard y_start = -1; 339c0c440f3SBlue Swirl page_min = -1; 340550be127Sbellard page_max = 0; 341c78f7137SGerd Hoffmann d = surface_data(surface); 3426f7e9aecSbellard s = ts->vram; 343c78f7137SGerd Hoffmann dd = surface_stride(surface); 344e80cfcfcSbellard ds = 1024; 345e80cfcfcSbellard 346c78f7137SGerd Hoffmann switch (surface_bits_per_pixel(surface)) { 347e80cfcfcSbellard case 32: 348e80cfcfcSbellard f = tcx_draw_line32; 34955d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor32; 350e80cfcfcSbellard break; 35121206a10Sbellard case 15: 35221206a10Sbellard case 16: 35321206a10Sbellard f = tcx_draw_line16; 35455d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor16; 355e80cfcfcSbellard break; 356e80cfcfcSbellard default: 357e80cfcfcSbellard case 8: 358e80cfcfcSbellard f = tcx_draw_line8; 35955d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor8; 360e80cfcfcSbellard break; 361e80cfcfcSbellard case 0: 362e80cfcfcSbellard return; 363e80cfcfcSbellard } 364e80cfcfcSbellard 3655299c0f2SPaolo Bonzini memory_region_sync_dirty_bitmap(&ts->vram_mem); 366*0a97c6c4SMark Cave-Ayland for (y = 0; y < ts->height; y++, page += ds) { 367*0a97c6c4SMark Cave-Ayland if (tcx_check_dirty(ts, page, ds)) { 368e80cfcfcSbellard if (y_start < 0) 369e80cfcfcSbellard y_start = y; 370e80cfcfcSbellard if (page < page_min) 371e80cfcfcSbellard page_min = page; 372e80cfcfcSbellard if (page > page_max) 373e80cfcfcSbellard page_max = page; 37455d7bfe2SMark Cave-Ayland 3756f7e9aecSbellard f(ts, d, s, ts->width); 37655d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 37755d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 37855d7bfe2SMark Cave-Ayland } 379e80cfcfcSbellard } else { 380e80cfcfcSbellard if (y_start >= 0) { 381e80cfcfcSbellard /* flush to display */ 382c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 3836f7e9aecSbellard ts->width, y - y_start); 384e80cfcfcSbellard y_start = -1; 385e80cfcfcSbellard } 386e80cfcfcSbellard } 387*0a97c6c4SMark Cave-Ayland s += ds; 388*0a97c6c4SMark Cave-Ayland d += dd; 389e80cfcfcSbellard } 390e80cfcfcSbellard if (y_start >= 0) { 391e80cfcfcSbellard /* flush to display */ 392c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 3936f7e9aecSbellard ts->width, y - y_start); 394e80cfcfcSbellard } 395e80cfcfcSbellard /* reset modified pages */ 396c0c440f3SBlue Swirl if (page_max >= page_min) { 39736180430SMark Cave-Ayland tcx_reset_dirty(ts, page_min, page_max - page_min); 398e80cfcfcSbellard } 399e80cfcfcSbellard } 400e80cfcfcSbellard 401eee0b836Sblueswir1 static void tcx24_update_display(void *opaque) 402eee0b836Sblueswir1 { 403eee0b836Sblueswir1 TCXState *ts = opaque; 404c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(ts->con); 40566dcabeaSMark Cave-Ayland ram_addr_t page, page_min, page_max; 406eee0b836Sblueswir1 int y, y_start, dd, ds; 407eee0b836Sblueswir1 uint8_t *d, *s; 408eee0b836Sblueswir1 uint32_t *cptr, *s24; 409eee0b836Sblueswir1 410c78f7137SGerd Hoffmann if (surface_bits_per_pixel(surface) != 32) { 411eee0b836Sblueswir1 return; 412c78f7137SGerd Hoffmann } 413c78f7137SGerd Hoffmann 414d08151bfSAvi Kivity page = 0; 415eee0b836Sblueswir1 y_start = -1; 416c0c440f3SBlue Swirl page_min = -1; 417eee0b836Sblueswir1 page_max = 0; 418c78f7137SGerd Hoffmann d = surface_data(surface); 419eee0b836Sblueswir1 s = ts->vram; 420eee0b836Sblueswir1 s24 = ts->vram24; 421eee0b836Sblueswir1 cptr = ts->cplane; 422c78f7137SGerd Hoffmann dd = surface_stride(surface); 423eee0b836Sblueswir1 ds = 1024; 424eee0b836Sblueswir1 4255299c0f2SPaolo Bonzini memory_region_sync_dirty_bitmap(&ts->vram_mem); 42666dcabeaSMark Cave-Ayland for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) { 427427ee02bSMark Cave-Ayland if (tcx_check_dirty(ts, page, TARGET_PAGE_SIZE)) { 428eee0b836Sblueswir1 if (y_start < 0) 429eee0b836Sblueswir1 y_start = y; 430eee0b836Sblueswir1 if (page < page_min) 431eee0b836Sblueswir1 page_min = page; 432eee0b836Sblueswir1 if (page > page_max) 433eee0b836Sblueswir1 page_max = page; 434eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 43555d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 43655d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 43755d7bfe2SMark Cave-Ayland } 438eee0b836Sblueswir1 d += dd; 439eee0b836Sblueswir1 s += ds; 440eee0b836Sblueswir1 cptr += ds; 441eee0b836Sblueswir1 s24 += ds; 44255d7bfe2SMark Cave-Ayland y++; 443eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 44455d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 44555d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 44655d7bfe2SMark Cave-Ayland } 447eee0b836Sblueswir1 d += dd; 448eee0b836Sblueswir1 s += ds; 449eee0b836Sblueswir1 cptr += ds; 450eee0b836Sblueswir1 s24 += ds; 45155d7bfe2SMark Cave-Ayland y++; 452eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 45355d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 45455d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 45555d7bfe2SMark Cave-Ayland } 456eee0b836Sblueswir1 d += dd; 457eee0b836Sblueswir1 s += ds; 458eee0b836Sblueswir1 cptr += ds; 459eee0b836Sblueswir1 s24 += ds; 46055d7bfe2SMark Cave-Ayland y++; 461eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 46255d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 46355d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 46455d7bfe2SMark Cave-Ayland } 465eee0b836Sblueswir1 d += dd; 466eee0b836Sblueswir1 s += ds; 467eee0b836Sblueswir1 cptr += ds; 468eee0b836Sblueswir1 s24 += ds; 46955d7bfe2SMark Cave-Ayland y++; 470eee0b836Sblueswir1 } else { 471eee0b836Sblueswir1 if (y_start >= 0) { 472eee0b836Sblueswir1 /* flush to display */ 473c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 474eee0b836Sblueswir1 ts->width, y - y_start); 475eee0b836Sblueswir1 y_start = -1; 476eee0b836Sblueswir1 } 477eee0b836Sblueswir1 d += dd * 4; 478eee0b836Sblueswir1 s += ds * 4; 479eee0b836Sblueswir1 cptr += ds * 4; 480eee0b836Sblueswir1 s24 += ds * 4; 48155d7bfe2SMark Cave-Ayland y += 4; 482eee0b836Sblueswir1 } 483eee0b836Sblueswir1 } 484eee0b836Sblueswir1 if (y_start >= 0) { 485eee0b836Sblueswir1 /* flush to display */ 486c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 487eee0b836Sblueswir1 ts->width, y - y_start); 488eee0b836Sblueswir1 } 489eee0b836Sblueswir1 /* reset modified pages */ 490c0c440f3SBlue Swirl if (page_max >= page_min) { 49136180430SMark Cave-Ayland tcx_reset_dirty(ts, page_min, page_max - page_min); 492eee0b836Sblueswir1 } 493eee0b836Sblueswir1 } 494eee0b836Sblueswir1 49595219897Spbrook static void tcx_invalidate_display(void *opaque) 496420557e8Sbellard { 497420557e8Sbellard TCXState *s = opaque; 498420557e8Sbellard 4999800b3c2SMark Cave-Ayland tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem)); 500c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 501e80cfcfcSbellard } 502e80cfcfcSbellard 503eee0b836Sblueswir1 static void tcx24_invalidate_display(void *opaque) 504eee0b836Sblueswir1 { 505eee0b836Sblueswir1 TCXState *s = opaque; 506eee0b836Sblueswir1 5079800b3c2SMark Cave-Ayland tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem)); 508c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 509eee0b836Sblueswir1 } 510eee0b836Sblueswir1 511e59fb374SJuan Quintela static int vmstate_tcx_post_load(void *opaque, int version_id) 512e80cfcfcSbellard { 513e80cfcfcSbellard TCXState *s = opaque; 514e80cfcfcSbellard 51521206a10Sbellard update_palette_entries(s, 0, 256); 5169800b3c2SMark Cave-Ayland tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem)); 517420557e8Sbellard return 0; 518420557e8Sbellard } 519420557e8Sbellard 520c0c41a4bSBlue Swirl static const VMStateDescription vmstate_tcx = { 521c0c41a4bSBlue Swirl .name ="tcx", 522c0c41a4bSBlue Swirl .version_id = 4, 523c0c41a4bSBlue Swirl .minimum_version_id = 4, 524752ff2faSJuan Quintela .post_load = vmstate_tcx_post_load, 525c0c41a4bSBlue Swirl .fields = (VMStateField[]) { 526c0c41a4bSBlue Swirl VMSTATE_UINT16(height, TCXState), 527c0c41a4bSBlue Swirl VMSTATE_UINT16(width, TCXState), 528c0c41a4bSBlue Swirl VMSTATE_UINT16(depth, TCXState), 529c0c41a4bSBlue Swirl VMSTATE_BUFFER(r, TCXState), 530c0c41a4bSBlue Swirl VMSTATE_BUFFER(g, TCXState), 531c0c41a4bSBlue Swirl VMSTATE_BUFFER(b, TCXState), 532c0c41a4bSBlue Swirl VMSTATE_UINT8(dac_index, TCXState), 533c0c41a4bSBlue Swirl VMSTATE_UINT8(dac_state, TCXState), 534c0c41a4bSBlue Swirl VMSTATE_END_OF_LIST() 535c0c41a4bSBlue Swirl } 536c0c41a4bSBlue Swirl }; 537c0c41a4bSBlue Swirl 5387f23f812SMichael S. Tsirkin static void tcx_reset(DeviceState *d) 539420557e8Sbellard { 54001774ddbSAndreas Färber TCXState *s = TCX(d); 541420557e8Sbellard 542e80cfcfcSbellard /* Initialize palette */ 54355d7bfe2SMark Cave-Ayland memset(s->r, 0, 260); 54455d7bfe2SMark Cave-Ayland memset(s->g, 0, 260); 54555d7bfe2SMark Cave-Ayland memset(s->b, 0, 260); 546e80cfcfcSbellard s->r[255] = s->g[255] = s->b[255] = 255; 54755d7bfe2SMark Cave-Ayland s->r[256] = s->g[256] = s->b[256] = 255; 54855d7bfe2SMark Cave-Ayland s->r[258] = s->g[258] = s->b[258] = 255; 54955d7bfe2SMark Cave-Ayland update_palette_entries(s, 0, 260); 550e80cfcfcSbellard memset(s->vram, 0, MAXX*MAXY); 551d08151bfSAvi Kivity memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4), 552d08151bfSAvi Kivity DIRTY_MEMORY_VGA); 5536f7e9aecSbellard s->dac_index = 0; 5546f7e9aecSbellard s->dac_state = 0; 55555d7bfe2SMark Cave-Ayland s->cursx = 0xf000; /* Put cursor off screen */ 55655d7bfe2SMark Cave-Ayland s->cursy = 0xf000; 557420557e8Sbellard } 558420557e8Sbellard 559a8170e5eSAvi Kivity static uint64_t tcx_dac_readl(void *opaque, hwaddr addr, 560d08151bfSAvi Kivity unsigned size) 5616f7e9aecSbellard { 56255d7bfe2SMark Cave-Ayland TCXState *s = opaque; 56355d7bfe2SMark Cave-Ayland uint32_t val = 0; 56455d7bfe2SMark Cave-Ayland 56555d7bfe2SMark Cave-Ayland switch (s->dac_state) { 56655d7bfe2SMark Cave-Ayland case 0: 56755d7bfe2SMark Cave-Ayland val = s->r[s->dac_index] << 24; 56855d7bfe2SMark Cave-Ayland s->dac_state++; 56955d7bfe2SMark Cave-Ayland break; 57055d7bfe2SMark Cave-Ayland case 1: 57155d7bfe2SMark Cave-Ayland val = s->g[s->dac_index] << 24; 57255d7bfe2SMark Cave-Ayland s->dac_state++; 57355d7bfe2SMark Cave-Ayland break; 57455d7bfe2SMark Cave-Ayland case 2: 57555d7bfe2SMark Cave-Ayland val = s->b[s->dac_index] << 24; 57655d7bfe2SMark Cave-Ayland s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ 57755d7bfe2SMark Cave-Ayland default: 57855d7bfe2SMark Cave-Ayland s->dac_state = 0; 57955d7bfe2SMark Cave-Ayland break; 58055d7bfe2SMark Cave-Ayland } 58155d7bfe2SMark Cave-Ayland 58255d7bfe2SMark Cave-Ayland return val; 5836f7e9aecSbellard } 5846f7e9aecSbellard 585a8170e5eSAvi Kivity static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val, 586d08151bfSAvi Kivity unsigned size) 5876f7e9aecSbellard { 5886f7e9aecSbellard TCXState *s = opaque; 58955d7bfe2SMark Cave-Ayland unsigned index; 5906f7e9aecSbellard 591e64d7d59Sblueswir1 switch (addr) { 59255d7bfe2SMark Cave-Ayland case 0: /* Address */ 5936f7e9aecSbellard s->dac_index = val >> 24; 5946f7e9aecSbellard s->dac_state = 0; 5956f7e9aecSbellard break; 59655d7bfe2SMark Cave-Ayland case 4: /* Pixel colours */ 59755d7bfe2SMark Cave-Ayland case 12: /* Overlay (cursor) colours */ 59855d7bfe2SMark Cave-Ayland if (addr & 8) { 59955d7bfe2SMark Cave-Ayland index = (s->dac_index & 3) + 256; 60055d7bfe2SMark Cave-Ayland } else { 60155d7bfe2SMark Cave-Ayland index = s->dac_index; 60255d7bfe2SMark Cave-Ayland } 6036f7e9aecSbellard switch (s->dac_state) { 6046f7e9aecSbellard case 0: 60555d7bfe2SMark Cave-Ayland s->r[index] = val >> 24; 60655d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 6076f7e9aecSbellard s->dac_state++; 6086f7e9aecSbellard break; 6096f7e9aecSbellard case 1: 61055d7bfe2SMark Cave-Ayland s->g[index] = val >> 24; 61155d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 6126f7e9aecSbellard s->dac_state++; 6136f7e9aecSbellard break; 6146f7e9aecSbellard case 2: 61555d7bfe2SMark Cave-Ayland s->b[index] = val >> 24; 61655d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 61755d7bfe2SMark Cave-Ayland s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ 6186f7e9aecSbellard default: 6196f7e9aecSbellard s->dac_state = 0; 6206f7e9aecSbellard break; 6216f7e9aecSbellard } 6226f7e9aecSbellard break; 62355d7bfe2SMark Cave-Ayland default: /* Control registers */ 6246f7e9aecSbellard break; 6256f7e9aecSbellard } 6266f7e9aecSbellard } 6276f7e9aecSbellard 628d08151bfSAvi Kivity static const MemoryRegionOps tcx_dac_ops = { 629d08151bfSAvi Kivity .read = tcx_dac_readl, 630d08151bfSAvi Kivity .write = tcx_dac_writel, 631d08151bfSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 632d08151bfSAvi Kivity .valid = { 633d08151bfSAvi Kivity .min_access_size = 4, 634d08151bfSAvi Kivity .max_access_size = 4, 635d08151bfSAvi Kivity }, 6366f7e9aecSbellard }; 6376f7e9aecSbellard 63855d7bfe2SMark Cave-Ayland static uint64_t tcx_stip_readl(void *opaque, hwaddr addr, 639d08151bfSAvi Kivity unsigned size) 6408508b89eSblueswir1 { 6418508b89eSblueswir1 return 0; 6428508b89eSblueswir1 } 6438508b89eSblueswir1 64455d7bfe2SMark Cave-Ayland static void tcx_stip_writel(void *opaque, hwaddr addr, 645d08151bfSAvi Kivity uint64_t val, unsigned size) 6468508b89eSblueswir1 { 64755d7bfe2SMark Cave-Ayland TCXState *s = opaque; 64855d7bfe2SMark Cave-Ayland int i; 64955d7bfe2SMark Cave-Ayland uint32_t col; 65055d7bfe2SMark Cave-Ayland 65155d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 65255d7bfe2SMark Cave-Ayland s->tmpblit = val; 65355d7bfe2SMark Cave-Ayland } else { 65455d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 65555d7bfe2SMark Cave-Ayland col = cpu_to_be32(s->tmpblit); 65655d7bfe2SMark Cave-Ayland if (s->depth == 24) { 65755d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 65855d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 65955d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 66055d7bfe2SMark Cave-Ayland s->vram24[addr + i] = col; 66155d7bfe2SMark Cave-Ayland } 66255d7bfe2SMark Cave-Ayland val <<= 1; 66355d7bfe2SMark Cave-Ayland } 66455d7bfe2SMark Cave-Ayland } else { 66555d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 66655d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 66755d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 66855d7bfe2SMark Cave-Ayland } 66955d7bfe2SMark Cave-Ayland val <<= 1; 67055d7bfe2SMark Cave-Ayland } 67155d7bfe2SMark Cave-Ayland } 67255d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, 32); 67355d7bfe2SMark Cave-Ayland } 6748508b89eSblueswir1 } 6758508b89eSblueswir1 67655d7bfe2SMark Cave-Ayland static void tcx_rstip_writel(void *opaque, hwaddr addr, 67755d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 67855d7bfe2SMark Cave-Ayland { 67955d7bfe2SMark Cave-Ayland TCXState *s = opaque; 68055d7bfe2SMark Cave-Ayland int i; 68155d7bfe2SMark Cave-Ayland uint32_t col; 68255d7bfe2SMark Cave-Ayland 68355d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 68455d7bfe2SMark Cave-Ayland s->tmpblit = val; 68555d7bfe2SMark Cave-Ayland } else { 68655d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 68755d7bfe2SMark Cave-Ayland col = cpu_to_be32(s->tmpblit); 68855d7bfe2SMark Cave-Ayland if (s->depth == 24) { 68955d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 69055d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 69155d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 69255d7bfe2SMark Cave-Ayland s->vram24[addr + i] = col; 69355d7bfe2SMark Cave-Ayland s->cplane[addr + i] = col; 69455d7bfe2SMark Cave-Ayland } 69555d7bfe2SMark Cave-Ayland val <<= 1; 69655d7bfe2SMark Cave-Ayland } 69755d7bfe2SMark Cave-Ayland } else { 69855d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 69955d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 70055d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 70155d7bfe2SMark Cave-Ayland } 70255d7bfe2SMark Cave-Ayland val <<= 1; 70355d7bfe2SMark Cave-Ayland } 70455d7bfe2SMark Cave-Ayland } 70555d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, 32); 70655d7bfe2SMark Cave-Ayland } 70755d7bfe2SMark Cave-Ayland } 70855d7bfe2SMark Cave-Ayland 70955d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_stip_ops = { 71055d7bfe2SMark Cave-Ayland .read = tcx_stip_readl, 71155d7bfe2SMark Cave-Ayland .write = tcx_stip_writel, 71255d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 71355d7bfe2SMark Cave-Ayland .valid = { 71455d7bfe2SMark Cave-Ayland .min_access_size = 4, 71555d7bfe2SMark Cave-Ayland .max_access_size = 4, 71655d7bfe2SMark Cave-Ayland }, 71755d7bfe2SMark Cave-Ayland }; 71855d7bfe2SMark Cave-Ayland 71955d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_rstip_ops = { 72055d7bfe2SMark Cave-Ayland .read = tcx_stip_readl, 72155d7bfe2SMark Cave-Ayland .write = tcx_rstip_writel, 72255d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 72355d7bfe2SMark Cave-Ayland .valid = { 72455d7bfe2SMark Cave-Ayland .min_access_size = 4, 72555d7bfe2SMark Cave-Ayland .max_access_size = 4, 72655d7bfe2SMark Cave-Ayland }, 72755d7bfe2SMark Cave-Ayland }; 72855d7bfe2SMark Cave-Ayland 72955d7bfe2SMark Cave-Ayland static uint64_t tcx_blit_readl(void *opaque, hwaddr addr, 73055d7bfe2SMark Cave-Ayland unsigned size) 73155d7bfe2SMark Cave-Ayland { 73255d7bfe2SMark Cave-Ayland return 0; 73355d7bfe2SMark Cave-Ayland } 73455d7bfe2SMark Cave-Ayland 73555d7bfe2SMark Cave-Ayland static void tcx_blit_writel(void *opaque, hwaddr addr, 73655d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 73755d7bfe2SMark Cave-Ayland { 73855d7bfe2SMark Cave-Ayland TCXState *s = opaque; 73955d7bfe2SMark Cave-Ayland uint32_t adsr, len; 74055d7bfe2SMark Cave-Ayland int i; 74155d7bfe2SMark Cave-Ayland 74255d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 74355d7bfe2SMark Cave-Ayland s->tmpblit = val; 74455d7bfe2SMark Cave-Ayland } else { 74555d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 74655d7bfe2SMark Cave-Ayland adsr = val & 0xffffff; 74755d7bfe2SMark Cave-Ayland len = ((val >> 24) & 0x1f) + 1; 74855d7bfe2SMark Cave-Ayland if (adsr == 0xffffff) { 74955d7bfe2SMark Cave-Ayland memset(&s->vram[addr], s->tmpblit, len); 75055d7bfe2SMark Cave-Ayland if (s->depth == 24) { 75155d7bfe2SMark Cave-Ayland val = s->tmpblit & 0xffffff; 75255d7bfe2SMark Cave-Ayland val = cpu_to_be32(val); 75355d7bfe2SMark Cave-Ayland for (i = 0; i < len; i++) { 75455d7bfe2SMark Cave-Ayland s->vram24[addr + i] = val; 75555d7bfe2SMark Cave-Ayland } 75655d7bfe2SMark Cave-Ayland } 75755d7bfe2SMark Cave-Ayland } else { 75855d7bfe2SMark Cave-Ayland memcpy(&s->vram[addr], &s->vram[adsr], len); 75955d7bfe2SMark Cave-Ayland if (s->depth == 24) { 76055d7bfe2SMark Cave-Ayland memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); 76155d7bfe2SMark Cave-Ayland } 76255d7bfe2SMark Cave-Ayland } 76355d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, len); 76455d7bfe2SMark Cave-Ayland } 76555d7bfe2SMark Cave-Ayland } 76655d7bfe2SMark Cave-Ayland 76755d7bfe2SMark Cave-Ayland static void tcx_rblit_writel(void *opaque, hwaddr addr, 76855d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 76955d7bfe2SMark Cave-Ayland { 77055d7bfe2SMark Cave-Ayland TCXState *s = opaque; 77155d7bfe2SMark Cave-Ayland uint32_t adsr, len; 77255d7bfe2SMark Cave-Ayland int i; 77355d7bfe2SMark Cave-Ayland 77455d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 77555d7bfe2SMark Cave-Ayland s->tmpblit = val; 77655d7bfe2SMark Cave-Ayland } else { 77755d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 77855d7bfe2SMark Cave-Ayland adsr = val & 0xffffff; 77955d7bfe2SMark Cave-Ayland len = ((val >> 24) & 0x1f) + 1; 78055d7bfe2SMark Cave-Ayland if (adsr == 0xffffff) { 78155d7bfe2SMark Cave-Ayland memset(&s->vram[addr], s->tmpblit, len); 78255d7bfe2SMark Cave-Ayland if (s->depth == 24) { 78355d7bfe2SMark Cave-Ayland val = s->tmpblit & 0xffffff; 78455d7bfe2SMark Cave-Ayland val = cpu_to_be32(val); 78555d7bfe2SMark Cave-Ayland for (i = 0; i < len; i++) { 78655d7bfe2SMark Cave-Ayland s->vram24[addr + i] = val; 78755d7bfe2SMark Cave-Ayland s->cplane[addr + i] = val; 78855d7bfe2SMark Cave-Ayland } 78955d7bfe2SMark Cave-Ayland } 79055d7bfe2SMark Cave-Ayland } else { 79155d7bfe2SMark Cave-Ayland memcpy(&s->vram[addr], &s->vram[adsr], len); 79255d7bfe2SMark Cave-Ayland if (s->depth == 24) { 79355d7bfe2SMark Cave-Ayland memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); 79455d7bfe2SMark Cave-Ayland memcpy(&s->cplane[addr], &s->cplane[adsr], len * 4); 79555d7bfe2SMark Cave-Ayland } 79655d7bfe2SMark Cave-Ayland } 79755d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, len); 79855d7bfe2SMark Cave-Ayland } 79955d7bfe2SMark Cave-Ayland } 80055d7bfe2SMark Cave-Ayland 80155d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_blit_ops = { 80255d7bfe2SMark Cave-Ayland .read = tcx_blit_readl, 80355d7bfe2SMark Cave-Ayland .write = tcx_blit_writel, 80455d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 80555d7bfe2SMark Cave-Ayland .valid = { 80655d7bfe2SMark Cave-Ayland .min_access_size = 4, 80755d7bfe2SMark Cave-Ayland .max_access_size = 4, 80855d7bfe2SMark Cave-Ayland }, 80955d7bfe2SMark Cave-Ayland }; 81055d7bfe2SMark Cave-Ayland 81155d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_rblit_ops = { 81255d7bfe2SMark Cave-Ayland .read = tcx_blit_readl, 81355d7bfe2SMark Cave-Ayland .write = tcx_rblit_writel, 81455d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 81555d7bfe2SMark Cave-Ayland .valid = { 81655d7bfe2SMark Cave-Ayland .min_access_size = 4, 81755d7bfe2SMark Cave-Ayland .max_access_size = 4, 81855d7bfe2SMark Cave-Ayland }, 81955d7bfe2SMark Cave-Ayland }; 82055d7bfe2SMark Cave-Ayland 82155d7bfe2SMark Cave-Ayland static void tcx_invalidate_cursor_position(TCXState *s) 82255d7bfe2SMark Cave-Ayland { 82355d7bfe2SMark Cave-Ayland int ymin, ymax, start, end; 82455d7bfe2SMark Cave-Ayland 82555d7bfe2SMark Cave-Ayland /* invalidate only near the cursor */ 82655d7bfe2SMark Cave-Ayland ymin = s->cursy; 82755d7bfe2SMark Cave-Ayland if (ymin >= s->height) { 82855d7bfe2SMark Cave-Ayland return; 82955d7bfe2SMark Cave-Ayland } 83055d7bfe2SMark Cave-Ayland ymax = MIN(s->height, ymin + 32); 83155d7bfe2SMark Cave-Ayland start = ymin * 1024; 83255d7bfe2SMark Cave-Ayland end = ymax * 1024; 83355d7bfe2SMark Cave-Ayland 83455d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, start, end-start); 83555d7bfe2SMark Cave-Ayland } 83655d7bfe2SMark Cave-Ayland 83755d7bfe2SMark Cave-Ayland static uint64_t tcx_thc_readl(void *opaque, hwaddr addr, 83855d7bfe2SMark Cave-Ayland unsigned size) 83955d7bfe2SMark Cave-Ayland { 84055d7bfe2SMark Cave-Ayland TCXState *s = opaque; 84155d7bfe2SMark Cave-Ayland uint64_t val; 84255d7bfe2SMark Cave-Ayland 84355d7bfe2SMark Cave-Ayland if (addr == TCX_THC_MISC) { 84455d7bfe2SMark Cave-Ayland val = s->thcmisc | 0x02000000; 84555d7bfe2SMark Cave-Ayland } else { 84655d7bfe2SMark Cave-Ayland val = 0; 84755d7bfe2SMark Cave-Ayland } 84855d7bfe2SMark Cave-Ayland return val; 84955d7bfe2SMark Cave-Ayland } 85055d7bfe2SMark Cave-Ayland 85155d7bfe2SMark Cave-Ayland static void tcx_thc_writel(void *opaque, hwaddr addr, 85255d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 85355d7bfe2SMark Cave-Ayland { 85455d7bfe2SMark Cave-Ayland TCXState *s = opaque; 85555d7bfe2SMark Cave-Ayland 85655d7bfe2SMark Cave-Ayland if (addr == TCX_THC_CURSXY) { 85755d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 85855d7bfe2SMark Cave-Ayland s->cursx = val >> 16; 85955d7bfe2SMark Cave-Ayland s->cursy = val; 86055d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 86155d7bfe2SMark Cave-Ayland } else if (addr >= TCX_THC_CURSMASK && addr < TCX_THC_CURSMASK + 128) { 86255d7bfe2SMark Cave-Ayland s->cursmask[(addr - TCX_THC_CURSMASK) >> 2] = val; 86355d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 86455d7bfe2SMark Cave-Ayland } else if (addr >= TCX_THC_CURSBITS && addr < TCX_THC_CURSBITS + 128) { 86555d7bfe2SMark Cave-Ayland s->cursbits[(addr - TCX_THC_CURSBITS) >> 2] = val; 86655d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 86755d7bfe2SMark Cave-Ayland } else if (addr == TCX_THC_MISC) { 86855d7bfe2SMark Cave-Ayland s->thcmisc = val; 86955d7bfe2SMark Cave-Ayland } 87055d7bfe2SMark Cave-Ayland 87155d7bfe2SMark Cave-Ayland } 87255d7bfe2SMark Cave-Ayland 87355d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_thc_ops = { 87455d7bfe2SMark Cave-Ayland .read = tcx_thc_readl, 87555d7bfe2SMark Cave-Ayland .write = tcx_thc_writel, 87655d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 87755d7bfe2SMark Cave-Ayland .valid = { 87855d7bfe2SMark Cave-Ayland .min_access_size = 4, 87955d7bfe2SMark Cave-Ayland .max_access_size = 4, 88055d7bfe2SMark Cave-Ayland }, 88155d7bfe2SMark Cave-Ayland }; 88255d7bfe2SMark Cave-Ayland 88355d7bfe2SMark Cave-Ayland static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr, 88455d7bfe2SMark Cave-Ayland unsigned size) 88555d7bfe2SMark Cave-Ayland { 88655d7bfe2SMark Cave-Ayland return 0; 88755d7bfe2SMark Cave-Ayland } 88855d7bfe2SMark Cave-Ayland 88955d7bfe2SMark Cave-Ayland static void tcx_dummy_writel(void *opaque, hwaddr addr, 89055d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 89155d7bfe2SMark Cave-Ayland { 89255d7bfe2SMark Cave-Ayland return; 89355d7bfe2SMark Cave-Ayland } 89455d7bfe2SMark Cave-Ayland 89555d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_dummy_ops = { 89655d7bfe2SMark Cave-Ayland .read = tcx_dummy_readl, 89755d7bfe2SMark Cave-Ayland .write = tcx_dummy_writel, 898d08151bfSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 899d08151bfSAvi Kivity .valid = { 900d08151bfSAvi Kivity .min_access_size = 4, 901d08151bfSAvi Kivity .max_access_size = 4, 902d08151bfSAvi Kivity }, 9038508b89eSblueswir1 }; 9048508b89eSblueswir1 905380cd056SGerd Hoffmann static const GraphicHwOps tcx_ops = { 906380cd056SGerd Hoffmann .invalidate = tcx_invalidate_display, 907380cd056SGerd Hoffmann .gfx_update = tcx_update_display, 908380cd056SGerd Hoffmann }; 909380cd056SGerd Hoffmann 910380cd056SGerd Hoffmann static const GraphicHwOps tcx24_ops = { 911380cd056SGerd Hoffmann .invalidate = tcx24_invalidate_display, 912380cd056SGerd Hoffmann .gfx_update = tcx24_update_display, 913380cd056SGerd Hoffmann }; 914380cd056SGerd Hoffmann 91501b91ac2SMark Cave-Ayland static void tcx_initfn(Object *obj) 91601b91ac2SMark Cave-Ayland { 91701b91ac2SMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 91801b91ac2SMark Cave-Ayland TCXState *s = TCX(obj); 91901b91ac2SMark Cave-Ayland 920b21de199SThomas Huth memory_region_init_ram(&s->rom, obj, "tcx.prom", FCODE_MAX_ROM_SIZE, 921f8ed85acSMarkus Armbruster &error_fatal); 92201b91ac2SMark Cave-Ayland memory_region_set_readonly(&s->rom, true); 92301b91ac2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rom); 92401b91ac2SMark Cave-Ayland 92555d7bfe2SMark Cave-Ayland /* 2/STIP : Stippler */ 926b21de199SThomas Huth memory_region_init_io(&s->stip, obj, &tcx_stip_ops, s, "tcx.stip", 92755d7bfe2SMark Cave-Ayland TCX_STIP_NREGS); 92855d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->stip); 92955d7bfe2SMark Cave-Ayland 93055d7bfe2SMark Cave-Ayland /* 3/BLIT : Blitter */ 931b21de199SThomas Huth memory_region_init_io(&s->blit, obj, &tcx_blit_ops, s, "tcx.blit", 93255d7bfe2SMark Cave-Ayland TCX_BLIT_NREGS); 93355d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->blit); 93455d7bfe2SMark Cave-Ayland 93555d7bfe2SMark Cave-Ayland /* 5/RSTIP : Raw Stippler */ 936b21de199SThomas Huth memory_region_init_io(&s->rstip, obj, &tcx_rstip_ops, s, "tcx.rstip", 93755d7bfe2SMark Cave-Ayland TCX_RSTIP_NREGS); 93855d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rstip); 93955d7bfe2SMark Cave-Ayland 94055d7bfe2SMark Cave-Ayland /* 6/RBLIT : Raw Blitter */ 941b21de199SThomas Huth memory_region_init_io(&s->rblit, obj, &tcx_rblit_ops, s, "tcx.rblit", 94255d7bfe2SMark Cave-Ayland TCX_RBLIT_NREGS); 94355d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rblit); 94455d7bfe2SMark Cave-Ayland 94555d7bfe2SMark Cave-Ayland /* 7/TEC : ??? */ 946b21de199SThomas Huth memory_region_init_io(&s->tec, obj, &tcx_dummy_ops, s, "tcx.tec", 947b21de199SThomas Huth TCX_TEC_NREGS); 94855d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->tec); 94955d7bfe2SMark Cave-Ayland 95055d7bfe2SMark Cave-Ayland /* 8/CMAP : DAC */ 951b21de199SThomas Huth memory_region_init_io(&s->dac, obj, &tcx_dac_ops, s, "tcx.dac", 952b21de199SThomas Huth TCX_DAC_NREGS); 95301b91ac2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->dac); 95401b91ac2SMark Cave-Ayland 95555d7bfe2SMark Cave-Ayland /* 9/THC : Cursor */ 956b21de199SThomas Huth memory_region_init_io(&s->thc, obj, &tcx_thc_ops, s, "tcx.thc", 95755d7bfe2SMark Cave-Ayland TCX_THC_NREGS); 95855d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->thc); 95901b91ac2SMark Cave-Ayland 96055d7bfe2SMark Cave-Ayland /* 11/DHC : ??? */ 961b21de199SThomas Huth memory_region_init_io(&s->dhc, obj, &tcx_dummy_ops, s, "tcx.dhc", 96255d7bfe2SMark Cave-Ayland TCX_DHC_NREGS); 96355d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->dhc); 96455d7bfe2SMark Cave-Ayland 96555d7bfe2SMark Cave-Ayland /* 12/ALT : ??? */ 966b21de199SThomas Huth memory_region_init_io(&s->alt, obj, &tcx_dummy_ops, s, "tcx.alt", 96755d7bfe2SMark Cave-Ayland TCX_ALT_NREGS); 96855d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->alt); 96901b91ac2SMark Cave-Ayland } 97001b91ac2SMark Cave-Ayland 971d4ad9decSMark Cave-Ayland static void tcx_realizefn(DeviceState *dev, Error **errp) 972f40070c3SBlue Swirl { 973d4ad9decSMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 97401774ddbSAndreas Färber TCXState *s = TCX(dev); 975d08151bfSAvi Kivity ram_addr_t vram_offset = 0; 976da87dd7bSMark Cave-Ayland int size, ret; 977dc828ca1Spbrook uint8_t *vram_base; 978da87dd7bSMark Cave-Ayland char *fcode_filename; 979dc828ca1Spbrook 9803eadad55SPaolo Bonzini memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram", 981f8ed85acSMarkus Armbruster s->vram_size * (1 + 4 + 4), &error_fatal); 982c5705a77SAvi Kivity vmstate_register_ram_global(&s->vram_mem); 98374259ae5SPaolo Bonzini memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA); 984d08151bfSAvi Kivity vram_base = memory_region_get_ram_ptr(&s->vram_mem); 985e80cfcfcSbellard 98655d7bfe2SMark Cave-Ayland /* 10/ROM : FCode ROM */ 987da87dd7bSMark Cave-Ayland vmstate_register_ram_global(&s->rom); 988da87dd7bSMark Cave-Ayland fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE); 989da87dd7bSMark Cave-Ayland if (fcode_filename) { 990da87dd7bSMark Cave-Ayland ret = load_image_targphys(fcode_filename, s->prom_addr, 991da87dd7bSMark Cave-Ayland FCODE_MAX_ROM_SIZE); 9928684e85cSShannon Zhao g_free(fcode_filename); 993da87dd7bSMark Cave-Ayland if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { 994d4ad9decSMark Cave-Ayland error_report("tcx: could not load prom '%s'", TCX_ROM_FILE); 995da87dd7bSMark Cave-Ayland } 996da87dd7bSMark Cave-Ayland } 997da87dd7bSMark Cave-Ayland 99855d7bfe2SMark Cave-Ayland /* 0/DFB8 : 8-bit plane */ 999eee0b836Sblueswir1 s->vram = vram_base; 1000ee6847d1SGerd Hoffmann size = s->vram_size; 10013eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit", 1002d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1003d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_8bit); 1004eee0b836Sblueswir1 vram_offset += size; 1005eee0b836Sblueswir1 vram_base += size; 1006eee0b836Sblueswir1 100755d7bfe2SMark Cave-Ayland /* 1/DFB24 : 24bit plane */ 1008ee6847d1SGerd Hoffmann size = s->vram_size * 4; 1009eee0b836Sblueswir1 s->vram24 = (uint32_t *)vram_base; 1010eee0b836Sblueswir1 s->vram24_offset = vram_offset; 10113eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", 1012d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1013d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_24bit); 1014eee0b836Sblueswir1 vram_offset += size; 1015eee0b836Sblueswir1 vram_base += size; 1016eee0b836Sblueswir1 101755d7bfe2SMark Cave-Ayland /* 4/RDFB32 : Raw Framebuffer */ 1018ee6847d1SGerd Hoffmann size = s->vram_size * 4; 1019eee0b836Sblueswir1 s->cplane = (uint32_t *)vram_base; 1020eee0b836Sblueswir1 s->cplane_offset = vram_offset; 10213eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", 1022d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1023d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_cplane); 1024f40070c3SBlue Swirl 102555d7bfe2SMark Cave-Ayland /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */ 102655d7bfe2SMark Cave-Ayland if (s->depth == 8) { 102755d7bfe2SMark Cave-Ayland memory_region_init_io(&s->thc24, OBJECT(s), &tcx_dummy_ops, s, 102855d7bfe2SMark Cave-Ayland "tcx.thc24", TCX_THC_NREGS); 102955d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->thc24); 1030eee0b836Sblueswir1 } 1031eee0b836Sblueswir1 103255d7bfe2SMark Cave-Ayland sysbus_init_irq(sbd, &s->irq); 103355d7bfe2SMark Cave-Ayland 103455d7bfe2SMark Cave-Ayland if (s->depth == 8) { 103555d7bfe2SMark Cave-Ayland s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); 103655d7bfe2SMark Cave-Ayland } else { 103755d7bfe2SMark Cave-Ayland s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); 103855d7bfe2SMark Cave-Ayland } 103955d7bfe2SMark Cave-Ayland s->thcmisc = 0; 104055d7bfe2SMark Cave-Ayland 1041c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 1042420557e8Sbellard } 1043420557e8Sbellard 1044999e12bbSAnthony Liguori static Property tcx_properties[] = { 1045c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT32("vram_size", TCXState, vram_size, -1), 104653dad499SGerd Hoffmann DEFINE_PROP_UINT16("width", TCXState, width, -1), 104753dad499SGerd Hoffmann DEFINE_PROP_UINT16("height", TCXState, height, -1), 104853dad499SGerd Hoffmann DEFINE_PROP_UINT16("depth", TCXState, depth, -1), 1049c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT64("prom_addr", TCXState, prom_addr, -1), 105053dad499SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 1051999e12bbSAnthony Liguori }; 1052999e12bbSAnthony Liguori 1053999e12bbSAnthony Liguori static void tcx_class_init(ObjectClass *klass, void *data) 1054999e12bbSAnthony Liguori { 105539bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1056999e12bbSAnthony Liguori 1057d4ad9decSMark Cave-Ayland dc->realize = tcx_realizefn; 105839bffca2SAnthony Liguori dc->reset = tcx_reset; 105939bffca2SAnthony Liguori dc->vmsd = &vmstate_tcx; 106039bffca2SAnthony Liguori dc->props = tcx_properties; 1061ee6847d1SGerd Hoffmann } 1062999e12bbSAnthony Liguori 10638c43a6f0SAndreas Färber static const TypeInfo tcx_info = { 106401774ddbSAndreas Färber .name = TYPE_TCX, 106539bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 106639bffca2SAnthony Liguori .instance_size = sizeof(TCXState), 106701b91ac2SMark Cave-Ayland .instance_init = tcx_initfn, 1068999e12bbSAnthony Liguori .class_init = tcx_class_init, 1069ee6847d1SGerd Hoffmann }; 1070ee6847d1SGerd Hoffmann 107183f7d43aSAndreas Färber static void tcx_register_types(void) 1072f40070c3SBlue Swirl { 107339bffca2SAnthony Liguori type_register_static(&tcx_info); 1074f40070c3SBlue Swirl } 1075f40070c3SBlue Swirl 107683f7d43aSAndreas Färber type_init(tcx_register_types) 1077