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" 30d49b6836SMarkus Armbruster #include "qemu/error-report.h" 31420557e8Sbellard 32da87dd7bSMark Cave-Ayland #define TCX_ROM_FILE "QEMU,tcx.bin" 33da87dd7bSMark Cave-Ayland #define FCODE_MAX_ROM_SIZE 0x10000 34da87dd7bSMark Cave-Ayland 35420557e8Sbellard #define MAXX 1024 36420557e8Sbellard #define MAXY 768 376f7e9aecSbellard #define TCX_DAC_NREGS 16 3855d7bfe2SMark Cave-Ayland #define TCX_THC_NREGS 0x1000 3955d7bfe2SMark Cave-Ayland #define TCX_DHC_NREGS 0x4000 408508b89eSblueswir1 #define TCX_TEC_NREGS 0x1000 4155d7bfe2SMark Cave-Ayland #define TCX_ALT_NREGS 0x8000 4255d7bfe2SMark Cave-Ayland #define TCX_STIP_NREGS 0x800000 4355d7bfe2SMark Cave-Ayland #define TCX_BLIT_NREGS 0x800000 4455d7bfe2SMark Cave-Ayland #define TCX_RSTIP_NREGS 0x800000 4555d7bfe2SMark Cave-Ayland #define TCX_RBLIT_NREGS 0x800000 4655d7bfe2SMark Cave-Ayland 4755d7bfe2SMark Cave-Ayland #define TCX_THC_MISC 0x818 4855d7bfe2SMark Cave-Ayland #define TCX_THC_CURSXY 0x8fc 4955d7bfe2SMark Cave-Ayland #define TCX_THC_CURSMASK 0x900 5055d7bfe2SMark Cave-Ayland #define TCX_THC_CURSBITS 0x980 51420557e8Sbellard 5201774ddbSAndreas Färber #define TYPE_TCX "SUNW,tcx" 5301774ddbSAndreas Färber #define TCX(obj) OBJECT_CHECK(TCXState, (obj), TYPE_TCX) 5401774ddbSAndreas Färber 55420557e8Sbellard typedef struct TCXState { 5601774ddbSAndreas Färber SysBusDevice parent_obj; 5701774ddbSAndreas Färber 58c78f7137SGerd Hoffmann QemuConsole *con; 5955d7bfe2SMark Cave-Ayland qemu_irq irq; 608d5f07faSbellard uint8_t *vram; 61eee0b836Sblueswir1 uint32_t *vram24, *cplane; 62da87dd7bSMark Cave-Ayland hwaddr prom_addr; 63da87dd7bSMark Cave-Ayland MemoryRegion rom; 64d08151bfSAvi Kivity MemoryRegion vram_mem; 65d08151bfSAvi Kivity MemoryRegion vram_8bit; 66d08151bfSAvi Kivity MemoryRegion vram_24bit; 6755d7bfe2SMark Cave-Ayland MemoryRegion stip; 6855d7bfe2SMark Cave-Ayland MemoryRegion blit; 69d08151bfSAvi Kivity MemoryRegion vram_cplane; 7055d7bfe2SMark Cave-Ayland MemoryRegion rstip; 7155d7bfe2SMark Cave-Ayland MemoryRegion rblit; 72d08151bfSAvi Kivity MemoryRegion tec; 7355d7bfe2SMark Cave-Ayland MemoryRegion dac; 7455d7bfe2SMark Cave-Ayland MemoryRegion thc; 7555d7bfe2SMark Cave-Ayland MemoryRegion dhc; 7655d7bfe2SMark Cave-Ayland MemoryRegion alt; 77d08151bfSAvi Kivity MemoryRegion thc24; 7855d7bfe2SMark Cave-Ayland 79d08151bfSAvi Kivity ram_addr_t vram24_offset, cplane_offset; 8055d7bfe2SMark Cave-Ayland uint32_t tmpblit; 81ee6847d1SGerd Hoffmann uint32_t vram_size; 8255d7bfe2SMark Cave-Ayland uint32_t palette[260]; 8355d7bfe2SMark Cave-Ayland uint8_t r[260], g[260], b[260]; 84427a66c3SBlue Swirl uint16_t width, height, depth; 856f7e9aecSbellard uint8_t dac_index, dac_state; 8655d7bfe2SMark Cave-Ayland uint32_t thcmisc; 8755d7bfe2SMark Cave-Ayland uint32_t cursmask[32]; 8855d7bfe2SMark Cave-Ayland uint32_t cursbits[32]; 8955d7bfe2SMark Cave-Ayland uint16_t cursx; 9055d7bfe2SMark Cave-Ayland uint16_t cursy; 91420557e8Sbellard } TCXState; 92420557e8Sbellard 93d3ffcafeSBlue Swirl static void tcx_set_dirty(TCXState *s) 94d3ffcafeSBlue Swirl { 95fd4aa979SBlue Swirl memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY); 96d3ffcafeSBlue Swirl } 97d3ffcafeSBlue Swirl 9855d7bfe2SMark Cave-Ayland static inline int tcx24_check_dirty(TCXState *s, ram_addr_t page, 9955d7bfe2SMark Cave-Ayland ram_addr_t page24, ram_addr_t cpage) 100d3ffcafeSBlue Swirl { 10155d7bfe2SMark Cave-Ayland int ret; 10255d7bfe2SMark Cave-Ayland 10355d7bfe2SMark Cave-Ayland ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE, 10455d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 10555d7bfe2SMark Cave-Ayland ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4, 10655d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 10755d7bfe2SMark Cave-Ayland ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4, 10855d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 10955d7bfe2SMark Cave-Ayland return ret; 11055d7bfe2SMark Cave-Ayland } 11155d7bfe2SMark Cave-Ayland 11255d7bfe2SMark Cave-Ayland static inline void tcx24_reset_dirty(TCXState *ts, ram_addr_t page_min, 11355d7bfe2SMark Cave-Ayland ram_addr_t page_max, ram_addr_t page24, 11455d7bfe2SMark Cave-Ayland ram_addr_t cpage) 11555d7bfe2SMark Cave-Ayland { 11655d7bfe2SMark Cave-Ayland memory_region_reset_dirty(&ts->vram_mem, 11755d7bfe2SMark Cave-Ayland page_min, 11855d7bfe2SMark Cave-Ayland (page_max - page_min) + TARGET_PAGE_SIZE, 11955d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 12055d7bfe2SMark Cave-Ayland memory_region_reset_dirty(&ts->vram_mem, 12155d7bfe2SMark Cave-Ayland page24 + page_min * 4, 12255d7bfe2SMark Cave-Ayland (page_max - page_min) * 4 + TARGET_PAGE_SIZE, 12355d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 12455d7bfe2SMark Cave-Ayland memory_region_reset_dirty(&ts->vram_mem, 12555d7bfe2SMark Cave-Ayland cpage + page_min * 4, 12655d7bfe2SMark Cave-Ayland (page_max - page_min) * 4 + TARGET_PAGE_SIZE, 12755d7bfe2SMark Cave-Ayland DIRTY_MEMORY_VGA); 128d3ffcafeSBlue Swirl } 12995219897Spbrook 13021206a10Sbellard static void update_palette_entries(TCXState *s, int start, int end) 13121206a10Sbellard { 132c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(s->con); 13321206a10Sbellard int i; 134c78f7137SGerd Hoffmann 13521206a10Sbellard for (i = start; i < end; i++) { 136c78f7137SGerd Hoffmann switch (surface_bits_per_pixel(surface)) { 13721206a10Sbellard default: 13821206a10Sbellard case 8: 13921206a10Sbellard s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]); 14021206a10Sbellard break; 14121206a10Sbellard case 15: 14221206a10Sbellard s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]); 14321206a10Sbellard break; 14421206a10Sbellard case 16: 14521206a10Sbellard s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); 14621206a10Sbellard break; 14721206a10Sbellard case 32: 148c78f7137SGerd Hoffmann if (is_surface_bgr(surface)) { 1497b5d76daSaliguori s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]); 150c78f7137SGerd Hoffmann } else { 15121206a10Sbellard s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); 152c78f7137SGerd Hoffmann } 15321206a10Sbellard break; 15421206a10Sbellard } 15521206a10Sbellard } 156d3ffcafeSBlue Swirl tcx_set_dirty(s); 157d3ffcafeSBlue Swirl } 15821206a10Sbellard 159e80cfcfcSbellard static void tcx_draw_line32(TCXState *s1, uint8_t *d, 160e80cfcfcSbellard const uint8_t *s, int width) 161420557e8Sbellard { 162e80cfcfcSbellard int x; 163e80cfcfcSbellard uint8_t val; 1648bdc2159Sths uint32_t *p = (uint32_t *)d; 165e80cfcfcSbellard 166e80cfcfcSbellard for (x = 0; x < width; x++) { 167e80cfcfcSbellard val = *s++; 1688bdc2159Sths *p++ = s1->palette[val]; 169e80cfcfcSbellard } 170420557e8Sbellard } 171420557e8Sbellard 17221206a10Sbellard static void tcx_draw_line16(TCXState *s1, uint8_t *d, 173e80cfcfcSbellard const uint8_t *s, int width) 174e80cfcfcSbellard { 175e80cfcfcSbellard int x; 176e80cfcfcSbellard uint8_t val; 1778bdc2159Sths uint16_t *p = (uint16_t *)d; 1788d5f07faSbellard 179e80cfcfcSbellard for (x = 0; x < width; x++) { 180e80cfcfcSbellard val = *s++; 1818bdc2159Sths *p++ = s1->palette[val]; 182e80cfcfcSbellard } 183e80cfcfcSbellard } 184e80cfcfcSbellard 185e80cfcfcSbellard static void tcx_draw_line8(TCXState *s1, uint8_t *d, 186e80cfcfcSbellard const uint8_t *s, int width) 187e80cfcfcSbellard { 188e80cfcfcSbellard int x; 189e80cfcfcSbellard uint8_t val; 190e80cfcfcSbellard 191e80cfcfcSbellard for(x = 0; x < width; x++) { 192e80cfcfcSbellard val = *s++; 19321206a10Sbellard *d++ = s1->palette[val]; 194e80cfcfcSbellard } 195e80cfcfcSbellard } 196e80cfcfcSbellard 19755d7bfe2SMark Cave-Ayland static void tcx_draw_cursor32(TCXState *s1, uint8_t *d, 19855d7bfe2SMark Cave-Ayland int y, int width) 19955d7bfe2SMark Cave-Ayland { 20055d7bfe2SMark Cave-Ayland int x, len; 20155d7bfe2SMark Cave-Ayland uint32_t mask, bits; 20255d7bfe2SMark Cave-Ayland uint32_t *p = (uint32_t *)d; 20355d7bfe2SMark Cave-Ayland 20455d7bfe2SMark Cave-Ayland y = y - s1->cursy; 20555d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 20655d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 20755d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 20855d7bfe2SMark Cave-Ayland p = &p[s1->cursx]; 20955d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 21055d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 21155d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 21255d7bfe2SMark Cave-Ayland *p = s1->palette[259]; 21355d7bfe2SMark Cave-Ayland } else { 21455d7bfe2SMark Cave-Ayland *p = s1->palette[258]; 21555d7bfe2SMark Cave-Ayland } 21655d7bfe2SMark Cave-Ayland } 21755d7bfe2SMark Cave-Ayland p++; 21855d7bfe2SMark Cave-Ayland mask <<= 1; 21955d7bfe2SMark Cave-Ayland bits <<= 1; 22055d7bfe2SMark Cave-Ayland } 22155d7bfe2SMark Cave-Ayland } 22255d7bfe2SMark Cave-Ayland 22355d7bfe2SMark Cave-Ayland static void tcx_draw_cursor16(TCXState *s1, uint8_t *d, 22455d7bfe2SMark Cave-Ayland int y, int width) 22555d7bfe2SMark Cave-Ayland { 22655d7bfe2SMark Cave-Ayland int x, len; 22755d7bfe2SMark Cave-Ayland uint32_t mask, bits; 22855d7bfe2SMark Cave-Ayland uint16_t *p = (uint16_t *)d; 22955d7bfe2SMark Cave-Ayland 23055d7bfe2SMark Cave-Ayland y = y - s1->cursy; 23155d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 23255d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 23355d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 23455d7bfe2SMark Cave-Ayland p = &p[s1->cursx]; 23555d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 23655d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 23755d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 23855d7bfe2SMark Cave-Ayland *p = s1->palette[259]; 23955d7bfe2SMark Cave-Ayland } else { 24055d7bfe2SMark Cave-Ayland *p = s1->palette[258]; 24155d7bfe2SMark Cave-Ayland } 24255d7bfe2SMark Cave-Ayland } 24355d7bfe2SMark Cave-Ayland p++; 24455d7bfe2SMark Cave-Ayland mask <<= 1; 24555d7bfe2SMark Cave-Ayland bits <<= 1; 24655d7bfe2SMark Cave-Ayland } 24755d7bfe2SMark Cave-Ayland } 24855d7bfe2SMark Cave-Ayland 24955d7bfe2SMark Cave-Ayland static void tcx_draw_cursor8(TCXState *s1, uint8_t *d, 25055d7bfe2SMark Cave-Ayland int y, int width) 25155d7bfe2SMark Cave-Ayland { 25255d7bfe2SMark Cave-Ayland int x, len; 25355d7bfe2SMark Cave-Ayland uint32_t mask, bits; 25455d7bfe2SMark Cave-Ayland 25555d7bfe2SMark Cave-Ayland y = y - s1->cursy; 25655d7bfe2SMark Cave-Ayland mask = s1->cursmask[y]; 25755d7bfe2SMark Cave-Ayland bits = s1->cursbits[y]; 25855d7bfe2SMark Cave-Ayland len = MIN(width - s1->cursx, 32); 25955d7bfe2SMark Cave-Ayland d = &d[s1->cursx]; 26055d7bfe2SMark Cave-Ayland for (x = 0; x < len; x++) { 26155d7bfe2SMark Cave-Ayland if (mask & 0x80000000) { 26255d7bfe2SMark Cave-Ayland if (bits & 0x80000000) { 26355d7bfe2SMark Cave-Ayland *d = s1->palette[259]; 26455d7bfe2SMark Cave-Ayland } else { 26555d7bfe2SMark Cave-Ayland *d = s1->palette[258]; 26655d7bfe2SMark Cave-Ayland } 26755d7bfe2SMark Cave-Ayland } 26855d7bfe2SMark Cave-Ayland d++; 26955d7bfe2SMark Cave-Ayland mask <<= 1; 27055d7bfe2SMark Cave-Ayland bits <<= 1; 27155d7bfe2SMark Cave-Ayland } 27255d7bfe2SMark Cave-Ayland } 27355d7bfe2SMark Cave-Ayland 274688ea2ebSblueswir1 /* 275688ea2ebSblueswir1 XXX Could be much more optimal: 276688ea2ebSblueswir1 * detect if line/page/whole screen is in 24 bit mode 277688ea2ebSblueswir1 * if destination is also BGR, use memcpy 278688ea2ebSblueswir1 */ 279eee0b836Sblueswir1 static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, 280eee0b836Sblueswir1 const uint8_t *s, int width, 281eee0b836Sblueswir1 const uint32_t *cplane, 282eee0b836Sblueswir1 const uint32_t *s24) 283eee0b836Sblueswir1 { 284c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(s1->con); 2857b5d76daSaliguori int x, bgr, r, g, b; 286688ea2ebSblueswir1 uint8_t val, *p8; 287eee0b836Sblueswir1 uint32_t *p = (uint32_t *)d; 288eee0b836Sblueswir1 uint32_t dval; 289c78f7137SGerd Hoffmann bgr = is_surface_bgr(surface); 290eee0b836Sblueswir1 for(x = 0; x < width; x++, s++, s24++) { 29155d7bfe2SMark Cave-Ayland if (be32_to_cpu(*cplane) & 0x03000000) { 29255d7bfe2SMark Cave-Ayland /* 24-bit direct, BGR order */ 293688ea2ebSblueswir1 p8 = (uint8_t *)s24; 294688ea2ebSblueswir1 p8++; 295688ea2ebSblueswir1 b = *p8++; 296688ea2ebSblueswir1 g = *p8++; 297f7e683b8SBlue Swirl r = *p8; 2987b5d76daSaliguori if (bgr) 2997b5d76daSaliguori dval = rgb_to_pixel32bgr(r, g, b); 3007b5d76daSaliguori else 301688ea2ebSblueswir1 dval = rgb_to_pixel32(r, g, b); 302eee0b836Sblueswir1 } else { 30355d7bfe2SMark Cave-Ayland /* 8-bit pseudocolor */ 304eee0b836Sblueswir1 val = *s; 305eee0b836Sblueswir1 dval = s1->palette[val]; 306eee0b836Sblueswir1 } 307eee0b836Sblueswir1 *p++ = dval; 30855d7bfe2SMark Cave-Ayland cplane++; 309eee0b836Sblueswir1 } 310eee0b836Sblueswir1 } 311eee0b836Sblueswir1 312e80cfcfcSbellard /* Fixed line length 1024 allows us to do nice tricks not possible on 313e80cfcfcSbellard VGA... */ 31455d7bfe2SMark Cave-Ayland 31595219897Spbrook static void tcx_update_display(void *opaque) 316e80cfcfcSbellard { 317e80cfcfcSbellard TCXState *ts = opaque; 318c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(ts->con); 319c227f099SAnthony Liguori ram_addr_t page, page_min, page_max; 320550be127Sbellard int y, y_start, dd, ds; 321e80cfcfcSbellard uint8_t *d, *s; 322b3ceef24Sblueswir1 void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); 32355d7bfe2SMark Cave-Ayland void (*fc)(TCXState *s1, uint8_t *dst, int y, int width); 324e80cfcfcSbellard 325c78f7137SGerd Hoffmann if (surface_bits_per_pixel(surface) == 0) { 326e80cfcfcSbellard return; 327c78f7137SGerd Hoffmann } 328c78f7137SGerd Hoffmann 329d08151bfSAvi Kivity page = 0; 330e80cfcfcSbellard y_start = -1; 331c0c440f3SBlue Swirl page_min = -1; 332550be127Sbellard page_max = 0; 333c78f7137SGerd Hoffmann d = surface_data(surface); 3346f7e9aecSbellard s = ts->vram; 335c78f7137SGerd Hoffmann dd = surface_stride(surface); 336e80cfcfcSbellard ds = 1024; 337e80cfcfcSbellard 338c78f7137SGerd Hoffmann switch (surface_bits_per_pixel(surface)) { 339e80cfcfcSbellard case 32: 340e80cfcfcSbellard f = tcx_draw_line32; 34155d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor32; 342e80cfcfcSbellard break; 34321206a10Sbellard case 15: 34421206a10Sbellard case 16: 34521206a10Sbellard f = tcx_draw_line16; 34655d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor16; 347e80cfcfcSbellard break; 348e80cfcfcSbellard default: 349e80cfcfcSbellard case 8: 350e80cfcfcSbellard f = tcx_draw_line8; 35155d7bfe2SMark Cave-Ayland fc = tcx_draw_cursor8; 352e80cfcfcSbellard break; 353e80cfcfcSbellard case 0: 354e80cfcfcSbellard return; 355e80cfcfcSbellard } 356e80cfcfcSbellard 3575299c0f2SPaolo Bonzini memory_region_sync_dirty_bitmap(&ts->vram_mem); 35855d7bfe2SMark Cave-Ayland for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) { 359cd7a45c9SBlue Swirl if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE, 360cd7a45c9SBlue Swirl DIRTY_MEMORY_VGA)) { 361e80cfcfcSbellard if (y_start < 0) 362e80cfcfcSbellard y_start = y; 363e80cfcfcSbellard if (page < page_min) 364e80cfcfcSbellard page_min = page; 365e80cfcfcSbellard if (page > page_max) 366e80cfcfcSbellard page_max = page; 36755d7bfe2SMark Cave-Ayland 3686f7e9aecSbellard f(ts, d, s, ts->width); 36955d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 37055d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 37155d7bfe2SMark Cave-Ayland } 372e80cfcfcSbellard d += dd; 373e80cfcfcSbellard s += ds; 37455d7bfe2SMark Cave-Ayland y++; 37555d7bfe2SMark Cave-Ayland 3766f7e9aecSbellard f(ts, d, s, ts->width); 37755d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 37855d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 37955d7bfe2SMark Cave-Ayland } 380e80cfcfcSbellard d += dd; 381e80cfcfcSbellard s += ds; 38255d7bfe2SMark Cave-Ayland y++; 38355d7bfe2SMark Cave-Ayland 3846f7e9aecSbellard f(ts, d, s, ts->width); 38555d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 38655d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 38755d7bfe2SMark Cave-Ayland } 388e80cfcfcSbellard d += dd; 389e80cfcfcSbellard s += ds; 39055d7bfe2SMark Cave-Ayland y++; 39155d7bfe2SMark Cave-Ayland 3926f7e9aecSbellard f(ts, d, s, ts->width); 39355d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { 39455d7bfe2SMark Cave-Ayland fc(ts, d, y, ts->width); 39555d7bfe2SMark Cave-Ayland } 396e80cfcfcSbellard d += dd; 397e80cfcfcSbellard s += ds; 39855d7bfe2SMark Cave-Ayland y++; 399e80cfcfcSbellard } else { 400e80cfcfcSbellard if (y_start >= 0) { 401e80cfcfcSbellard /* flush to display */ 402c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 4036f7e9aecSbellard ts->width, y - y_start); 404e80cfcfcSbellard y_start = -1; 405e80cfcfcSbellard } 406e80cfcfcSbellard d += dd * 4; 407e80cfcfcSbellard s += ds * 4; 40855d7bfe2SMark Cave-Ayland y += 4; 409e80cfcfcSbellard } 410e80cfcfcSbellard } 411e80cfcfcSbellard if (y_start >= 0) { 412e80cfcfcSbellard /* flush to display */ 413c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 4146f7e9aecSbellard ts->width, y - y_start); 415e80cfcfcSbellard } 416e80cfcfcSbellard /* reset modified pages */ 417c0c440f3SBlue Swirl if (page_max >= page_min) { 418d08151bfSAvi Kivity memory_region_reset_dirty(&ts->vram_mem, 419f10acc8bSMark Cave-Ayland page_min, 420f10acc8bSMark Cave-Ayland (page_max - page_min) + TARGET_PAGE_SIZE, 421d08151bfSAvi Kivity DIRTY_MEMORY_VGA); 422e80cfcfcSbellard } 423e80cfcfcSbellard } 424e80cfcfcSbellard 425eee0b836Sblueswir1 static void tcx24_update_display(void *opaque) 426eee0b836Sblueswir1 { 427eee0b836Sblueswir1 TCXState *ts = opaque; 428c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(ts->con); 429c227f099SAnthony Liguori ram_addr_t page, page_min, page_max, cpage, page24; 430eee0b836Sblueswir1 int y, y_start, dd, ds; 431eee0b836Sblueswir1 uint8_t *d, *s; 432eee0b836Sblueswir1 uint32_t *cptr, *s24; 433eee0b836Sblueswir1 434c78f7137SGerd Hoffmann if (surface_bits_per_pixel(surface) != 32) { 435eee0b836Sblueswir1 return; 436c78f7137SGerd Hoffmann } 437c78f7137SGerd Hoffmann 438d08151bfSAvi Kivity page = 0; 439eee0b836Sblueswir1 page24 = ts->vram24_offset; 440eee0b836Sblueswir1 cpage = ts->cplane_offset; 441eee0b836Sblueswir1 y_start = -1; 442c0c440f3SBlue Swirl page_min = -1; 443eee0b836Sblueswir1 page_max = 0; 444c78f7137SGerd Hoffmann d = surface_data(surface); 445eee0b836Sblueswir1 s = ts->vram; 446eee0b836Sblueswir1 s24 = ts->vram24; 447eee0b836Sblueswir1 cptr = ts->cplane; 448c78f7137SGerd Hoffmann dd = surface_stride(surface); 449eee0b836Sblueswir1 ds = 1024; 450eee0b836Sblueswir1 4515299c0f2SPaolo Bonzini memory_region_sync_dirty_bitmap(&ts->vram_mem); 45255d7bfe2SMark Cave-Ayland for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE, 453eee0b836Sblueswir1 page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { 45455d7bfe2SMark Cave-Ayland if (tcx24_check_dirty(ts, page, page24, cpage)) { 455eee0b836Sblueswir1 if (y_start < 0) 456eee0b836Sblueswir1 y_start = y; 457eee0b836Sblueswir1 if (page < page_min) 458eee0b836Sblueswir1 page_min = page; 459eee0b836Sblueswir1 if (page > page_max) 460eee0b836Sblueswir1 page_max = page; 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 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 47155d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 47255d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 47355d7bfe2SMark Cave-Ayland } 474eee0b836Sblueswir1 d += dd; 475eee0b836Sblueswir1 s += ds; 476eee0b836Sblueswir1 cptr += ds; 477eee0b836Sblueswir1 s24 += ds; 47855d7bfe2SMark Cave-Ayland y++; 479eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 48055d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 48155d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 48255d7bfe2SMark Cave-Ayland } 483eee0b836Sblueswir1 d += dd; 484eee0b836Sblueswir1 s += ds; 485eee0b836Sblueswir1 cptr += ds; 486eee0b836Sblueswir1 s24 += ds; 48755d7bfe2SMark Cave-Ayland y++; 488eee0b836Sblueswir1 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); 48955d7bfe2SMark Cave-Ayland if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { 49055d7bfe2SMark Cave-Ayland tcx_draw_cursor32(ts, d, y, ts->width); 49155d7bfe2SMark Cave-Ayland } 492eee0b836Sblueswir1 d += dd; 493eee0b836Sblueswir1 s += ds; 494eee0b836Sblueswir1 cptr += ds; 495eee0b836Sblueswir1 s24 += ds; 49655d7bfe2SMark Cave-Ayland y++; 497eee0b836Sblueswir1 } else { 498eee0b836Sblueswir1 if (y_start >= 0) { 499eee0b836Sblueswir1 /* flush to display */ 500c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 501eee0b836Sblueswir1 ts->width, y - y_start); 502eee0b836Sblueswir1 y_start = -1; 503eee0b836Sblueswir1 } 504eee0b836Sblueswir1 d += dd * 4; 505eee0b836Sblueswir1 s += ds * 4; 506eee0b836Sblueswir1 cptr += ds * 4; 507eee0b836Sblueswir1 s24 += ds * 4; 50855d7bfe2SMark Cave-Ayland y += 4; 509eee0b836Sblueswir1 } 510eee0b836Sblueswir1 } 511eee0b836Sblueswir1 if (y_start >= 0) { 512eee0b836Sblueswir1 /* flush to display */ 513c78f7137SGerd Hoffmann dpy_gfx_update(ts->con, 0, y_start, 514eee0b836Sblueswir1 ts->width, y - y_start); 515eee0b836Sblueswir1 } 516eee0b836Sblueswir1 /* reset modified pages */ 517c0c440f3SBlue Swirl if (page_max >= page_min) { 51855d7bfe2SMark Cave-Ayland tcx24_reset_dirty(ts, page_min, page_max, page24, cpage); 519eee0b836Sblueswir1 } 520eee0b836Sblueswir1 } 521eee0b836Sblueswir1 52295219897Spbrook static void tcx_invalidate_display(void *opaque) 523420557e8Sbellard { 524420557e8Sbellard TCXState *s = opaque; 525420557e8Sbellard 526d3ffcafeSBlue Swirl tcx_set_dirty(s); 527c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 528e80cfcfcSbellard } 529e80cfcfcSbellard 530eee0b836Sblueswir1 static void tcx24_invalidate_display(void *opaque) 531eee0b836Sblueswir1 { 532eee0b836Sblueswir1 TCXState *s = opaque; 533eee0b836Sblueswir1 534d3ffcafeSBlue Swirl tcx_set_dirty(s); 535c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 536eee0b836Sblueswir1 } 537eee0b836Sblueswir1 538e59fb374SJuan Quintela static int vmstate_tcx_post_load(void *opaque, int version_id) 539e80cfcfcSbellard { 540e80cfcfcSbellard TCXState *s = opaque; 541e80cfcfcSbellard 54221206a10Sbellard update_palette_entries(s, 0, 256); 543d3ffcafeSBlue Swirl tcx_set_dirty(s); 544420557e8Sbellard return 0; 545420557e8Sbellard } 546420557e8Sbellard 547c0c41a4bSBlue Swirl static const VMStateDescription vmstate_tcx = { 548c0c41a4bSBlue Swirl .name ="tcx", 549c0c41a4bSBlue Swirl .version_id = 4, 550c0c41a4bSBlue Swirl .minimum_version_id = 4, 551752ff2faSJuan Quintela .post_load = vmstate_tcx_post_load, 552c0c41a4bSBlue Swirl .fields = (VMStateField[]) { 553c0c41a4bSBlue Swirl VMSTATE_UINT16(height, TCXState), 554c0c41a4bSBlue Swirl VMSTATE_UINT16(width, TCXState), 555c0c41a4bSBlue Swirl VMSTATE_UINT16(depth, TCXState), 556c0c41a4bSBlue Swirl VMSTATE_BUFFER(r, TCXState), 557c0c41a4bSBlue Swirl VMSTATE_BUFFER(g, TCXState), 558c0c41a4bSBlue Swirl VMSTATE_BUFFER(b, TCXState), 559c0c41a4bSBlue Swirl VMSTATE_UINT8(dac_index, TCXState), 560c0c41a4bSBlue Swirl VMSTATE_UINT8(dac_state, TCXState), 561c0c41a4bSBlue Swirl VMSTATE_END_OF_LIST() 562c0c41a4bSBlue Swirl } 563c0c41a4bSBlue Swirl }; 564c0c41a4bSBlue Swirl 5657f23f812SMichael S. Tsirkin static void tcx_reset(DeviceState *d) 566420557e8Sbellard { 56701774ddbSAndreas Färber TCXState *s = TCX(d); 568420557e8Sbellard 569e80cfcfcSbellard /* Initialize palette */ 57055d7bfe2SMark Cave-Ayland memset(s->r, 0, 260); 57155d7bfe2SMark Cave-Ayland memset(s->g, 0, 260); 57255d7bfe2SMark Cave-Ayland memset(s->b, 0, 260); 573e80cfcfcSbellard s->r[255] = s->g[255] = s->b[255] = 255; 57455d7bfe2SMark Cave-Ayland s->r[256] = s->g[256] = s->b[256] = 255; 57555d7bfe2SMark Cave-Ayland s->r[258] = s->g[258] = s->b[258] = 255; 57655d7bfe2SMark Cave-Ayland update_palette_entries(s, 0, 260); 577e80cfcfcSbellard memset(s->vram, 0, MAXX*MAXY); 578d08151bfSAvi Kivity memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4), 579d08151bfSAvi Kivity DIRTY_MEMORY_VGA); 5806f7e9aecSbellard s->dac_index = 0; 5816f7e9aecSbellard s->dac_state = 0; 58255d7bfe2SMark Cave-Ayland s->cursx = 0xf000; /* Put cursor off screen */ 58355d7bfe2SMark Cave-Ayland s->cursy = 0xf000; 584420557e8Sbellard } 585420557e8Sbellard 586a8170e5eSAvi Kivity static uint64_t tcx_dac_readl(void *opaque, hwaddr addr, 587d08151bfSAvi Kivity unsigned size) 5886f7e9aecSbellard { 58955d7bfe2SMark Cave-Ayland TCXState *s = opaque; 59055d7bfe2SMark Cave-Ayland uint32_t val = 0; 59155d7bfe2SMark Cave-Ayland 59255d7bfe2SMark Cave-Ayland switch (s->dac_state) { 59355d7bfe2SMark Cave-Ayland case 0: 59455d7bfe2SMark Cave-Ayland val = s->r[s->dac_index] << 24; 59555d7bfe2SMark Cave-Ayland s->dac_state++; 59655d7bfe2SMark Cave-Ayland break; 59755d7bfe2SMark Cave-Ayland case 1: 59855d7bfe2SMark Cave-Ayland val = s->g[s->dac_index] << 24; 59955d7bfe2SMark Cave-Ayland s->dac_state++; 60055d7bfe2SMark Cave-Ayland break; 60155d7bfe2SMark Cave-Ayland case 2: 60255d7bfe2SMark Cave-Ayland val = s->b[s->dac_index] << 24; 60355d7bfe2SMark Cave-Ayland s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ 60455d7bfe2SMark Cave-Ayland default: 60555d7bfe2SMark Cave-Ayland s->dac_state = 0; 60655d7bfe2SMark Cave-Ayland break; 60755d7bfe2SMark Cave-Ayland } 60855d7bfe2SMark Cave-Ayland 60955d7bfe2SMark Cave-Ayland return val; 6106f7e9aecSbellard } 6116f7e9aecSbellard 612a8170e5eSAvi Kivity static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val, 613d08151bfSAvi Kivity unsigned size) 6146f7e9aecSbellard { 6156f7e9aecSbellard TCXState *s = opaque; 61655d7bfe2SMark Cave-Ayland unsigned index; 6176f7e9aecSbellard 618e64d7d59Sblueswir1 switch (addr) { 61955d7bfe2SMark Cave-Ayland case 0: /* Address */ 6206f7e9aecSbellard s->dac_index = val >> 24; 6216f7e9aecSbellard s->dac_state = 0; 6226f7e9aecSbellard break; 62355d7bfe2SMark Cave-Ayland case 4: /* Pixel colours */ 62455d7bfe2SMark Cave-Ayland case 12: /* Overlay (cursor) colours */ 62555d7bfe2SMark Cave-Ayland if (addr & 8) { 62655d7bfe2SMark Cave-Ayland index = (s->dac_index & 3) + 256; 62755d7bfe2SMark Cave-Ayland } else { 62855d7bfe2SMark Cave-Ayland index = s->dac_index; 62955d7bfe2SMark Cave-Ayland } 6306f7e9aecSbellard switch (s->dac_state) { 6316f7e9aecSbellard case 0: 63255d7bfe2SMark Cave-Ayland s->r[index] = val >> 24; 63355d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 6346f7e9aecSbellard s->dac_state++; 6356f7e9aecSbellard break; 6366f7e9aecSbellard case 1: 63755d7bfe2SMark Cave-Ayland s->g[index] = val >> 24; 63855d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 6396f7e9aecSbellard s->dac_state++; 6406f7e9aecSbellard break; 6416f7e9aecSbellard case 2: 64255d7bfe2SMark Cave-Ayland s->b[index] = val >> 24; 64355d7bfe2SMark Cave-Ayland update_palette_entries(s, index, index + 1); 64455d7bfe2SMark Cave-Ayland s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ 6456f7e9aecSbellard default: 6466f7e9aecSbellard s->dac_state = 0; 6476f7e9aecSbellard break; 6486f7e9aecSbellard } 6496f7e9aecSbellard break; 65055d7bfe2SMark Cave-Ayland default: /* Control registers */ 6516f7e9aecSbellard break; 6526f7e9aecSbellard } 6536f7e9aecSbellard } 6546f7e9aecSbellard 655d08151bfSAvi Kivity static const MemoryRegionOps tcx_dac_ops = { 656d08151bfSAvi Kivity .read = tcx_dac_readl, 657d08151bfSAvi Kivity .write = tcx_dac_writel, 658d08151bfSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 659d08151bfSAvi Kivity .valid = { 660d08151bfSAvi Kivity .min_access_size = 4, 661d08151bfSAvi Kivity .max_access_size = 4, 662d08151bfSAvi Kivity }, 6636f7e9aecSbellard }; 6646f7e9aecSbellard 66555d7bfe2SMark Cave-Ayland static uint64_t tcx_stip_readl(void *opaque, hwaddr addr, 666d08151bfSAvi Kivity unsigned size) 6678508b89eSblueswir1 { 6688508b89eSblueswir1 return 0; 6698508b89eSblueswir1 } 6708508b89eSblueswir1 67155d7bfe2SMark Cave-Ayland static void tcx_stip_writel(void *opaque, hwaddr addr, 672d08151bfSAvi Kivity uint64_t val, unsigned size) 6738508b89eSblueswir1 { 67455d7bfe2SMark Cave-Ayland TCXState *s = opaque; 67555d7bfe2SMark Cave-Ayland int i; 67655d7bfe2SMark Cave-Ayland uint32_t col; 67755d7bfe2SMark Cave-Ayland 67855d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 67955d7bfe2SMark Cave-Ayland s->tmpblit = val; 68055d7bfe2SMark Cave-Ayland } else { 68155d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 68255d7bfe2SMark Cave-Ayland col = cpu_to_be32(s->tmpblit); 68355d7bfe2SMark Cave-Ayland if (s->depth == 24) { 68455d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 68555d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 68655d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 68755d7bfe2SMark Cave-Ayland s->vram24[addr + i] = col; 68855d7bfe2SMark Cave-Ayland } 68955d7bfe2SMark Cave-Ayland val <<= 1; 69055d7bfe2SMark Cave-Ayland } 69155d7bfe2SMark Cave-Ayland } else { 69255d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 69355d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 69455d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 69555d7bfe2SMark Cave-Ayland } 69655d7bfe2SMark Cave-Ayland val <<= 1; 69755d7bfe2SMark Cave-Ayland } 69855d7bfe2SMark Cave-Ayland } 69955d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, 32); 70055d7bfe2SMark Cave-Ayland } 7018508b89eSblueswir1 } 7028508b89eSblueswir1 70355d7bfe2SMark Cave-Ayland static void tcx_rstip_writel(void *opaque, hwaddr addr, 70455d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 70555d7bfe2SMark Cave-Ayland { 70655d7bfe2SMark Cave-Ayland TCXState *s = opaque; 70755d7bfe2SMark Cave-Ayland int i; 70855d7bfe2SMark Cave-Ayland uint32_t col; 70955d7bfe2SMark Cave-Ayland 71055d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 71155d7bfe2SMark Cave-Ayland s->tmpblit = val; 71255d7bfe2SMark Cave-Ayland } else { 71355d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 71455d7bfe2SMark Cave-Ayland col = cpu_to_be32(s->tmpblit); 71555d7bfe2SMark Cave-Ayland if (s->depth == 24) { 71655d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 71755d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 71855d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 71955d7bfe2SMark Cave-Ayland s->vram24[addr + i] = col; 72055d7bfe2SMark Cave-Ayland s->cplane[addr + i] = col; 72155d7bfe2SMark Cave-Ayland } 72255d7bfe2SMark Cave-Ayland val <<= 1; 72355d7bfe2SMark Cave-Ayland } 72455d7bfe2SMark Cave-Ayland } else { 72555d7bfe2SMark Cave-Ayland for (i = 0; i < 32; i++) { 72655d7bfe2SMark Cave-Ayland if (val & 0x80000000) { 72755d7bfe2SMark Cave-Ayland s->vram[addr + i] = s->tmpblit; 72855d7bfe2SMark Cave-Ayland } 72955d7bfe2SMark Cave-Ayland val <<= 1; 73055d7bfe2SMark Cave-Ayland } 73155d7bfe2SMark Cave-Ayland } 73255d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, 32); 73355d7bfe2SMark Cave-Ayland } 73455d7bfe2SMark Cave-Ayland } 73555d7bfe2SMark Cave-Ayland 73655d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_stip_ops = { 73755d7bfe2SMark Cave-Ayland .read = tcx_stip_readl, 73855d7bfe2SMark Cave-Ayland .write = tcx_stip_writel, 73955d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 74055d7bfe2SMark Cave-Ayland .valid = { 74155d7bfe2SMark Cave-Ayland .min_access_size = 4, 74255d7bfe2SMark Cave-Ayland .max_access_size = 4, 74355d7bfe2SMark Cave-Ayland }, 74455d7bfe2SMark Cave-Ayland }; 74555d7bfe2SMark Cave-Ayland 74655d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_rstip_ops = { 74755d7bfe2SMark Cave-Ayland .read = tcx_stip_readl, 74855d7bfe2SMark Cave-Ayland .write = tcx_rstip_writel, 74955d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 75055d7bfe2SMark Cave-Ayland .valid = { 75155d7bfe2SMark Cave-Ayland .min_access_size = 4, 75255d7bfe2SMark Cave-Ayland .max_access_size = 4, 75355d7bfe2SMark Cave-Ayland }, 75455d7bfe2SMark Cave-Ayland }; 75555d7bfe2SMark Cave-Ayland 75655d7bfe2SMark Cave-Ayland static uint64_t tcx_blit_readl(void *opaque, hwaddr addr, 75755d7bfe2SMark Cave-Ayland unsigned size) 75855d7bfe2SMark Cave-Ayland { 75955d7bfe2SMark Cave-Ayland return 0; 76055d7bfe2SMark Cave-Ayland } 76155d7bfe2SMark Cave-Ayland 76255d7bfe2SMark Cave-Ayland static void tcx_blit_writel(void *opaque, hwaddr addr, 76355d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 76455d7bfe2SMark Cave-Ayland { 76555d7bfe2SMark Cave-Ayland TCXState *s = opaque; 76655d7bfe2SMark Cave-Ayland uint32_t adsr, len; 76755d7bfe2SMark Cave-Ayland int i; 76855d7bfe2SMark Cave-Ayland 76955d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 77055d7bfe2SMark Cave-Ayland s->tmpblit = val; 77155d7bfe2SMark Cave-Ayland } else { 77255d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 77355d7bfe2SMark Cave-Ayland adsr = val & 0xffffff; 77455d7bfe2SMark Cave-Ayland len = ((val >> 24) & 0x1f) + 1; 77555d7bfe2SMark Cave-Ayland if (adsr == 0xffffff) { 77655d7bfe2SMark Cave-Ayland memset(&s->vram[addr], s->tmpblit, len); 77755d7bfe2SMark Cave-Ayland if (s->depth == 24) { 77855d7bfe2SMark Cave-Ayland val = s->tmpblit & 0xffffff; 77955d7bfe2SMark Cave-Ayland val = cpu_to_be32(val); 78055d7bfe2SMark Cave-Ayland for (i = 0; i < len; i++) { 78155d7bfe2SMark Cave-Ayland s->vram24[addr + i] = val; 78255d7bfe2SMark Cave-Ayland } 78355d7bfe2SMark Cave-Ayland } 78455d7bfe2SMark Cave-Ayland } else { 78555d7bfe2SMark Cave-Ayland memcpy(&s->vram[addr], &s->vram[adsr], len); 78655d7bfe2SMark Cave-Ayland if (s->depth == 24) { 78755d7bfe2SMark Cave-Ayland memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); 78855d7bfe2SMark Cave-Ayland } 78955d7bfe2SMark Cave-Ayland } 79055d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, len); 79155d7bfe2SMark Cave-Ayland } 79255d7bfe2SMark Cave-Ayland } 79355d7bfe2SMark Cave-Ayland 79455d7bfe2SMark Cave-Ayland static void tcx_rblit_writel(void *opaque, hwaddr addr, 79555d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 79655d7bfe2SMark Cave-Ayland { 79755d7bfe2SMark Cave-Ayland TCXState *s = opaque; 79855d7bfe2SMark Cave-Ayland uint32_t adsr, len; 79955d7bfe2SMark Cave-Ayland int i; 80055d7bfe2SMark Cave-Ayland 80155d7bfe2SMark Cave-Ayland if (!(addr & 4)) { 80255d7bfe2SMark Cave-Ayland s->tmpblit = val; 80355d7bfe2SMark Cave-Ayland } else { 80455d7bfe2SMark Cave-Ayland addr = (addr >> 3) & 0xfffff; 80555d7bfe2SMark Cave-Ayland adsr = val & 0xffffff; 80655d7bfe2SMark Cave-Ayland len = ((val >> 24) & 0x1f) + 1; 80755d7bfe2SMark Cave-Ayland if (adsr == 0xffffff) { 80855d7bfe2SMark Cave-Ayland memset(&s->vram[addr], s->tmpblit, len); 80955d7bfe2SMark Cave-Ayland if (s->depth == 24) { 81055d7bfe2SMark Cave-Ayland val = s->tmpblit & 0xffffff; 81155d7bfe2SMark Cave-Ayland val = cpu_to_be32(val); 81255d7bfe2SMark Cave-Ayland for (i = 0; i < len; i++) { 81355d7bfe2SMark Cave-Ayland s->vram24[addr + i] = val; 81455d7bfe2SMark Cave-Ayland s->cplane[addr + i] = val; 81555d7bfe2SMark Cave-Ayland } 81655d7bfe2SMark Cave-Ayland } 81755d7bfe2SMark Cave-Ayland } else { 81855d7bfe2SMark Cave-Ayland memcpy(&s->vram[addr], &s->vram[adsr], len); 81955d7bfe2SMark Cave-Ayland if (s->depth == 24) { 82055d7bfe2SMark Cave-Ayland memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); 82155d7bfe2SMark Cave-Ayland memcpy(&s->cplane[addr], &s->cplane[adsr], len * 4); 82255d7bfe2SMark Cave-Ayland } 82355d7bfe2SMark Cave-Ayland } 82455d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, addr, len); 82555d7bfe2SMark Cave-Ayland } 82655d7bfe2SMark Cave-Ayland } 82755d7bfe2SMark Cave-Ayland 82855d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_blit_ops = { 82955d7bfe2SMark Cave-Ayland .read = tcx_blit_readl, 83055d7bfe2SMark Cave-Ayland .write = tcx_blit_writel, 83155d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 83255d7bfe2SMark Cave-Ayland .valid = { 83355d7bfe2SMark Cave-Ayland .min_access_size = 4, 83455d7bfe2SMark Cave-Ayland .max_access_size = 4, 83555d7bfe2SMark Cave-Ayland }, 83655d7bfe2SMark Cave-Ayland }; 83755d7bfe2SMark Cave-Ayland 83855d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_rblit_ops = { 83955d7bfe2SMark Cave-Ayland .read = tcx_blit_readl, 84055d7bfe2SMark Cave-Ayland .write = tcx_rblit_writel, 84155d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 84255d7bfe2SMark Cave-Ayland .valid = { 84355d7bfe2SMark Cave-Ayland .min_access_size = 4, 84455d7bfe2SMark Cave-Ayland .max_access_size = 4, 84555d7bfe2SMark Cave-Ayland }, 84655d7bfe2SMark Cave-Ayland }; 84755d7bfe2SMark Cave-Ayland 84855d7bfe2SMark Cave-Ayland static void tcx_invalidate_cursor_position(TCXState *s) 84955d7bfe2SMark Cave-Ayland { 85055d7bfe2SMark Cave-Ayland int ymin, ymax, start, end; 85155d7bfe2SMark Cave-Ayland 85255d7bfe2SMark Cave-Ayland /* invalidate only near the cursor */ 85355d7bfe2SMark Cave-Ayland ymin = s->cursy; 85455d7bfe2SMark Cave-Ayland if (ymin >= s->height) { 85555d7bfe2SMark Cave-Ayland return; 85655d7bfe2SMark Cave-Ayland } 85755d7bfe2SMark Cave-Ayland ymax = MIN(s->height, ymin + 32); 85855d7bfe2SMark Cave-Ayland start = ymin * 1024; 85955d7bfe2SMark Cave-Ayland end = ymax * 1024; 86055d7bfe2SMark Cave-Ayland 86155d7bfe2SMark Cave-Ayland memory_region_set_dirty(&s->vram_mem, start, end-start); 86255d7bfe2SMark Cave-Ayland } 86355d7bfe2SMark Cave-Ayland 86455d7bfe2SMark Cave-Ayland static uint64_t tcx_thc_readl(void *opaque, hwaddr addr, 86555d7bfe2SMark Cave-Ayland unsigned size) 86655d7bfe2SMark Cave-Ayland { 86755d7bfe2SMark Cave-Ayland TCXState *s = opaque; 86855d7bfe2SMark Cave-Ayland uint64_t val; 86955d7bfe2SMark Cave-Ayland 87055d7bfe2SMark Cave-Ayland if (addr == TCX_THC_MISC) { 87155d7bfe2SMark Cave-Ayland val = s->thcmisc | 0x02000000; 87255d7bfe2SMark Cave-Ayland } else { 87355d7bfe2SMark Cave-Ayland val = 0; 87455d7bfe2SMark Cave-Ayland } 87555d7bfe2SMark Cave-Ayland return val; 87655d7bfe2SMark Cave-Ayland } 87755d7bfe2SMark Cave-Ayland 87855d7bfe2SMark Cave-Ayland static void tcx_thc_writel(void *opaque, hwaddr addr, 87955d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 88055d7bfe2SMark Cave-Ayland { 88155d7bfe2SMark Cave-Ayland TCXState *s = opaque; 88255d7bfe2SMark Cave-Ayland 88355d7bfe2SMark Cave-Ayland if (addr == TCX_THC_CURSXY) { 88455d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 88555d7bfe2SMark Cave-Ayland s->cursx = val >> 16; 88655d7bfe2SMark Cave-Ayland s->cursy = val; 88755d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 88855d7bfe2SMark Cave-Ayland } else if (addr >= TCX_THC_CURSMASK && addr < TCX_THC_CURSMASK + 128) { 88955d7bfe2SMark Cave-Ayland s->cursmask[(addr - TCX_THC_CURSMASK) >> 2] = val; 89055d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 89155d7bfe2SMark Cave-Ayland } else if (addr >= TCX_THC_CURSBITS && addr < TCX_THC_CURSBITS + 128) { 89255d7bfe2SMark Cave-Ayland s->cursbits[(addr - TCX_THC_CURSBITS) >> 2] = val; 89355d7bfe2SMark Cave-Ayland tcx_invalidate_cursor_position(s); 89455d7bfe2SMark Cave-Ayland } else if (addr == TCX_THC_MISC) { 89555d7bfe2SMark Cave-Ayland s->thcmisc = val; 89655d7bfe2SMark Cave-Ayland } 89755d7bfe2SMark Cave-Ayland 89855d7bfe2SMark Cave-Ayland } 89955d7bfe2SMark Cave-Ayland 90055d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_thc_ops = { 90155d7bfe2SMark Cave-Ayland .read = tcx_thc_readl, 90255d7bfe2SMark Cave-Ayland .write = tcx_thc_writel, 90355d7bfe2SMark Cave-Ayland .endianness = DEVICE_NATIVE_ENDIAN, 90455d7bfe2SMark Cave-Ayland .valid = { 90555d7bfe2SMark Cave-Ayland .min_access_size = 4, 90655d7bfe2SMark Cave-Ayland .max_access_size = 4, 90755d7bfe2SMark Cave-Ayland }, 90855d7bfe2SMark Cave-Ayland }; 90955d7bfe2SMark Cave-Ayland 91055d7bfe2SMark Cave-Ayland static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr, 91155d7bfe2SMark Cave-Ayland unsigned size) 91255d7bfe2SMark Cave-Ayland { 91355d7bfe2SMark Cave-Ayland return 0; 91455d7bfe2SMark Cave-Ayland } 91555d7bfe2SMark Cave-Ayland 91655d7bfe2SMark Cave-Ayland static void tcx_dummy_writel(void *opaque, hwaddr addr, 91755d7bfe2SMark Cave-Ayland uint64_t val, unsigned size) 91855d7bfe2SMark Cave-Ayland { 91955d7bfe2SMark Cave-Ayland return; 92055d7bfe2SMark Cave-Ayland } 92155d7bfe2SMark Cave-Ayland 92255d7bfe2SMark Cave-Ayland static const MemoryRegionOps tcx_dummy_ops = { 92355d7bfe2SMark Cave-Ayland .read = tcx_dummy_readl, 92455d7bfe2SMark Cave-Ayland .write = tcx_dummy_writel, 925d08151bfSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 926d08151bfSAvi Kivity .valid = { 927d08151bfSAvi Kivity .min_access_size = 4, 928d08151bfSAvi Kivity .max_access_size = 4, 929d08151bfSAvi Kivity }, 9308508b89eSblueswir1 }; 9318508b89eSblueswir1 932380cd056SGerd Hoffmann static const GraphicHwOps tcx_ops = { 933380cd056SGerd Hoffmann .invalidate = tcx_invalidate_display, 934380cd056SGerd Hoffmann .gfx_update = tcx_update_display, 935380cd056SGerd Hoffmann }; 936380cd056SGerd Hoffmann 937380cd056SGerd Hoffmann static const GraphicHwOps tcx24_ops = { 938380cd056SGerd Hoffmann .invalidate = tcx24_invalidate_display, 939380cd056SGerd Hoffmann .gfx_update = tcx24_update_display, 940380cd056SGerd Hoffmann }; 941380cd056SGerd Hoffmann 94201b91ac2SMark Cave-Ayland static void tcx_initfn(Object *obj) 94301b91ac2SMark Cave-Ayland { 94401b91ac2SMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 94501b91ac2SMark Cave-Ayland TCXState *s = TCX(obj); 94601b91ac2SMark Cave-Ayland 94749946538SHu Tao memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE, 948*f8ed85acSMarkus Armbruster &error_fatal); 94901b91ac2SMark Cave-Ayland memory_region_set_readonly(&s->rom, true); 95001b91ac2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rom); 95101b91ac2SMark Cave-Ayland 95255d7bfe2SMark Cave-Ayland /* 2/STIP : Stippler */ 95355d7bfe2SMark Cave-Ayland memory_region_init_io(&s->stip, OBJECT(s), &tcx_stip_ops, s, "tcx.stip", 95455d7bfe2SMark Cave-Ayland TCX_STIP_NREGS); 95555d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->stip); 95655d7bfe2SMark Cave-Ayland 95755d7bfe2SMark Cave-Ayland /* 3/BLIT : Blitter */ 95855d7bfe2SMark Cave-Ayland memory_region_init_io(&s->blit, OBJECT(s), &tcx_blit_ops, s, "tcx.blit", 95955d7bfe2SMark Cave-Ayland TCX_BLIT_NREGS); 96055d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->blit); 96155d7bfe2SMark Cave-Ayland 96255d7bfe2SMark Cave-Ayland /* 5/RSTIP : Raw Stippler */ 96355d7bfe2SMark Cave-Ayland memory_region_init_io(&s->rstip, OBJECT(s), &tcx_rstip_ops, s, "tcx.rstip", 96455d7bfe2SMark Cave-Ayland TCX_RSTIP_NREGS); 96555d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rstip); 96655d7bfe2SMark Cave-Ayland 96755d7bfe2SMark Cave-Ayland /* 6/RBLIT : Raw Blitter */ 96855d7bfe2SMark Cave-Ayland memory_region_init_io(&s->rblit, OBJECT(s), &tcx_rblit_ops, s, "tcx.rblit", 96955d7bfe2SMark Cave-Ayland TCX_RBLIT_NREGS); 97055d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->rblit); 97155d7bfe2SMark Cave-Ayland 97255d7bfe2SMark Cave-Ayland /* 7/TEC : ??? */ 97355d7bfe2SMark Cave-Ayland memory_region_init_io(&s->tec, OBJECT(s), &tcx_dummy_ops, s, 97455d7bfe2SMark Cave-Ayland "tcx.tec", TCX_TEC_NREGS); 97555d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->tec); 97655d7bfe2SMark Cave-Ayland 97755d7bfe2SMark Cave-Ayland /* 8/CMAP : DAC */ 97801b91ac2SMark Cave-Ayland memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, 97901b91ac2SMark Cave-Ayland "tcx.dac", TCX_DAC_NREGS); 98001b91ac2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->dac); 98101b91ac2SMark Cave-Ayland 98255d7bfe2SMark Cave-Ayland /* 9/THC : Cursor */ 98355d7bfe2SMark Cave-Ayland memory_region_init_io(&s->thc, OBJECT(s), &tcx_thc_ops, s, "tcx.thc", 98455d7bfe2SMark Cave-Ayland TCX_THC_NREGS); 98555d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->thc); 98601b91ac2SMark Cave-Ayland 98755d7bfe2SMark Cave-Ayland /* 11/DHC : ??? */ 98855d7bfe2SMark Cave-Ayland memory_region_init_io(&s->dhc, OBJECT(s), &tcx_dummy_ops, s, "tcx.dhc", 98955d7bfe2SMark Cave-Ayland TCX_DHC_NREGS); 99055d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->dhc); 99155d7bfe2SMark Cave-Ayland 99255d7bfe2SMark Cave-Ayland /* 12/ALT : ??? */ 99355d7bfe2SMark Cave-Ayland memory_region_init_io(&s->alt, OBJECT(s), &tcx_dummy_ops, s, "tcx.alt", 99455d7bfe2SMark Cave-Ayland TCX_ALT_NREGS); 99555d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->alt); 99601b91ac2SMark Cave-Ayland 99701b91ac2SMark Cave-Ayland return; 99801b91ac2SMark Cave-Ayland } 99901b91ac2SMark Cave-Ayland 1000d4ad9decSMark Cave-Ayland static void tcx_realizefn(DeviceState *dev, Error **errp) 1001f40070c3SBlue Swirl { 1002d4ad9decSMark Cave-Ayland SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 100301774ddbSAndreas Färber TCXState *s = TCX(dev); 1004d08151bfSAvi Kivity ram_addr_t vram_offset = 0; 1005da87dd7bSMark Cave-Ayland int size, ret; 1006dc828ca1Spbrook uint8_t *vram_base; 1007da87dd7bSMark Cave-Ayland char *fcode_filename; 1008dc828ca1Spbrook 10093eadad55SPaolo Bonzini memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram", 1010*f8ed85acSMarkus Armbruster s->vram_size * (1 + 4 + 4), &error_fatal); 1011c5705a77SAvi Kivity vmstate_register_ram_global(&s->vram_mem); 101274259ae5SPaolo Bonzini memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA); 1013d08151bfSAvi Kivity vram_base = memory_region_get_ram_ptr(&s->vram_mem); 1014e80cfcfcSbellard 101555d7bfe2SMark Cave-Ayland /* 10/ROM : FCode ROM */ 1016da87dd7bSMark Cave-Ayland vmstate_register_ram_global(&s->rom); 1017da87dd7bSMark Cave-Ayland fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE); 1018da87dd7bSMark Cave-Ayland if (fcode_filename) { 1019da87dd7bSMark Cave-Ayland ret = load_image_targphys(fcode_filename, s->prom_addr, 1020da87dd7bSMark Cave-Ayland FCODE_MAX_ROM_SIZE); 10218684e85cSShannon Zhao g_free(fcode_filename); 1022da87dd7bSMark Cave-Ayland if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { 1023d4ad9decSMark Cave-Ayland error_report("tcx: could not load prom '%s'", TCX_ROM_FILE); 1024da87dd7bSMark Cave-Ayland } 1025da87dd7bSMark Cave-Ayland } 1026da87dd7bSMark Cave-Ayland 102755d7bfe2SMark Cave-Ayland /* 0/DFB8 : 8-bit plane */ 1028eee0b836Sblueswir1 s->vram = vram_base; 1029ee6847d1SGerd Hoffmann size = s->vram_size; 10303eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit", 1031d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1032d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_8bit); 1033eee0b836Sblueswir1 vram_offset += size; 1034eee0b836Sblueswir1 vram_base += size; 1035eee0b836Sblueswir1 103655d7bfe2SMark Cave-Ayland /* 1/DFB24 : 24bit plane */ 1037ee6847d1SGerd Hoffmann size = s->vram_size * 4; 1038eee0b836Sblueswir1 s->vram24 = (uint32_t *)vram_base; 1039eee0b836Sblueswir1 s->vram24_offset = vram_offset; 10403eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", 1041d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1042d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_24bit); 1043eee0b836Sblueswir1 vram_offset += size; 1044eee0b836Sblueswir1 vram_base += size; 1045eee0b836Sblueswir1 104655d7bfe2SMark Cave-Ayland /* 4/RDFB32 : Raw Framebuffer */ 1047ee6847d1SGerd Hoffmann size = s->vram_size * 4; 1048eee0b836Sblueswir1 s->cplane = (uint32_t *)vram_base; 1049eee0b836Sblueswir1 s->cplane_offset = vram_offset; 10503eadad55SPaolo Bonzini memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", 1051d08151bfSAvi Kivity &s->vram_mem, vram_offset, size); 1052d4ad9decSMark Cave-Ayland sysbus_init_mmio(sbd, &s->vram_cplane); 1053f40070c3SBlue Swirl 105455d7bfe2SMark Cave-Ayland /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */ 105555d7bfe2SMark Cave-Ayland if (s->depth == 8) { 105655d7bfe2SMark Cave-Ayland memory_region_init_io(&s->thc24, OBJECT(s), &tcx_dummy_ops, s, 105755d7bfe2SMark Cave-Ayland "tcx.thc24", TCX_THC_NREGS); 105855d7bfe2SMark Cave-Ayland sysbus_init_mmio(sbd, &s->thc24); 1059eee0b836Sblueswir1 } 1060eee0b836Sblueswir1 106155d7bfe2SMark Cave-Ayland sysbus_init_irq(sbd, &s->irq); 106255d7bfe2SMark Cave-Ayland 106355d7bfe2SMark Cave-Ayland if (s->depth == 8) { 106455d7bfe2SMark Cave-Ayland s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); 106555d7bfe2SMark Cave-Ayland } else { 106655d7bfe2SMark Cave-Ayland s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); 106755d7bfe2SMark Cave-Ayland } 106855d7bfe2SMark Cave-Ayland s->thcmisc = 0; 106955d7bfe2SMark Cave-Ayland 1070c78f7137SGerd Hoffmann qemu_console_resize(s->con, s->width, s->height); 1071420557e8Sbellard } 1072420557e8Sbellard 1073999e12bbSAnthony Liguori static Property tcx_properties[] = { 1074c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT32("vram_size", TCXState, vram_size, -1), 107553dad499SGerd Hoffmann DEFINE_PROP_UINT16("width", TCXState, width, -1), 107653dad499SGerd Hoffmann DEFINE_PROP_UINT16("height", TCXState, height, -1), 107753dad499SGerd Hoffmann DEFINE_PROP_UINT16("depth", TCXState, depth, -1), 1078c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT64("prom_addr", TCXState, prom_addr, -1), 107953dad499SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 1080999e12bbSAnthony Liguori }; 1081999e12bbSAnthony Liguori 1082999e12bbSAnthony Liguori static void tcx_class_init(ObjectClass *klass, void *data) 1083999e12bbSAnthony Liguori { 108439bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1085999e12bbSAnthony Liguori 1086d4ad9decSMark Cave-Ayland dc->realize = tcx_realizefn; 108739bffca2SAnthony Liguori dc->reset = tcx_reset; 108839bffca2SAnthony Liguori dc->vmsd = &vmstate_tcx; 108939bffca2SAnthony Liguori dc->props = tcx_properties; 1090ee6847d1SGerd Hoffmann } 1091999e12bbSAnthony Liguori 10928c43a6f0SAndreas Färber static const TypeInfo tcx_info = { 109301774ddbSAndreas Färber .name = TYPE_TCX, 109439bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 109539bffca2SAnthony Liguori .instance_size = sizeof(TCXState), 109601b91ac2SMark Cave-Ayland .instance_init = tcx_initfn, 1097999e12bbSAnthony Liguori .class_init = tcx_class_init, 1098ee6847d1SGerd Hoffmann }; 1099ee6847d1SGerd Hoffmann 110083f7d43aSAndreas Färber static void tcx_register_types(void) 1101f40070c3SBlue Swirl { 110239bffca2SAnthony Liguori type_register_static(&tcx_info); 1103f40070c3SBlue Swirl } 1104f40070c3SBlue Swirl 110583f7d43aSAndreas Färber type_init(tcx_register_types) 1106