bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 1 | /* |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 2 | * QEMU TCX Frame buffer |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 3 | * |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 4 | * Copyright (c) 2003-2005 Fabrice Bellard |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 5 | * |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to deal |
| 8 | * in the Software without restriction, including without limitation the rights |
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | * copies of the Software, and to permit persons to whom the Software is |
| 11 | * furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in |
| 14 | * all copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | * THE SOFTWARE. |
| 23 | */ |
Blue Swirl | f40070c | 2009-07-12 19:21:36 +0000 | [diff] [blame] | 24 | |
Paolo Bonzini | 077805f | 2012-09-25 10:04:17 +0200 | [diff] [blame] | 25 | #include "qemu-common.h" |
Paolo Bonzini | 28ecbae | 2012-11-28 12:06:30 +0100 | [diff] [blame] | 26 | #include "ui/console.h" |
| 27 | #include "ui/pixel_ops.h" |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 28 | #include "hw/loader.h" |
Paolo Bonzini | 83c9f4c | 2013-02-04 15:40:22 +0100 | [diff] [blame] | 29 | #include "hw/sysbus.h" |
Markus Armbruster | d49b683 | 2015-03-17 18:29:20 +0100 | [diff] [blame] | 30 | #include "qemu/error-report.h" |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 31 | |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 32 | #define TCX_ROM_FILE "QEMU,tcx.bin" |
| 33 | #define FCODE_MAX_ROM_SIZE 0x10000 |
| 34 | |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 35 | #define MAXX 1024 |
| 36 | #define MAXY 768 |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 37 | #define TCX_DAC_NREGS 16 |
| 38 | #define TCX_THC_NREGS 0x1000 |
| 39 | #define TCX_DHC_NREGS 0x4000 |
blueswir1 | 8508b89 | 2007-05-06 17:39:55 +0000 | [diff] [blame] | 40 | #define TCX_TEC_NREGS 0x1000 |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 41 | #define TCX_ALT_NREGS 0x8000 |
| 42 | #define TCX_STIP_NREGS 0x800000 |
| 43 | #define TCX_BLIT_NREGS 0x800000 |
| 44 | #define TCX_RSTIP_NREGS 0x800000 |
| 45 | #define TCX_RBLIT_NREGS 0x800000 |
| 46 | |
| 47 | #define TCX_THC_MISC 0x818 |
| 48 | #define TCX_THC_CURSXY 0x8fc |
| 49 | #define TCX_THC_CURSMASK 0x900 |
| 50 | #define TCX_THC_CURSBITS 0x980 |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 51 | |
Andreas Färber | 01774dd | 2013-07-25 01:13:54 +0200 | [diff] [blame] | 52 | #define TYPE_TCX "SUNW,tcx" |
| 53 | #define TCX(obj) OBJECT_CHECK(TCXState, (obj), TYPE_TCX) |
| 54 | |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 55 | typedef struct TCXState { |
Andreas Färber | 01774dd | 2013-07-25 01:13:54 +0200 | [diff] [blame] | 56 | SysBusDevice parent_obj; |
| 57 | |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 58 | QemuConsole *con; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 59 | qemu_irq irq; |
bellard | 8d5f07f | 2004-10-04 21:23:09 +0000 | [diff] [blame] | 60 | uint8_t *vram; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 61 | uint32_t *vram24, *cplane; |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 62 | hwaddr prom_addr; |
| 63 | MemoryRegion rom; |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 64 | MemoryRegion vram_mem; |
| 65 | MemoryRegion vram_8bit; |
| 66 | MemoryRegion vram_24bit; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 67 | MemoryRegion stip; |
| 68 | MemoryRegion blit; |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 69 | MemoryRegion vram_cplane; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 70 | MemoryRegion rstip; |
| 71 | MemoryRegion rblit; |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 72 | MemoryRegion tec; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 73 | MemoryRegion dac; |
| 74 | MemoryRegion thc; |
| 75 | MemoryRegion dhc; |
| 76 | MemoryRegion alt; |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 77 | MemoryRegion thc24; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 78 | |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 79 | ram_addr_t vram24_offset, cplane_offset; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 80 | uint32_t tmpblit; |
Gerd Hoffmann | ee6847d | 2009-07-15 13:43:31 +0200 | [diff] [blame] | 81 | uint32_t vram_size; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 82 | uint32_t palette[260]; |
| 83 | uint8_t r[260], g[260], b[260]; |
Blue Swirl | 427a66c | 2011-08-07 19:13:24 +0000 | [diff] [blame] | 84 | uint16_t width, height, depth; |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 85 | uint8_t dac_index, dac_state; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 86 | uint32_t thcmisc; |
| 87 | uint32_t cursmask[32]; |
| 88 | uint32_t cursbits[32]; |
| 89 | uint16_t cursx; |
| 90 | uint16_t cursy; |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 91 | } TCXState; |
| 92 | |
Blue Swirl | d3ffcaf | 2009-07-16 13:45:57 +0000 | [diff] [blame] | 93 | static void tcx_set_dirty(TCXState *s) |
| 94 | { |
Blue Swirl | fd4aa97 | 2011-10-16 16:04:59 +0000 | [diff] [blame] | 95 | memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY); |
Blue Swirl | d3ffcaf | 2009-07-16 13:45:57 +0000 | [diff] [blame] | 96 | } |
| 97 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 98 | static inline int tcx24_check_dirty(TCXState *s, ram_addr_t page, |
| 99 | ram_addr_t page24, ram_addr_t cpage) |
Blue Swirl | d3ffcaf | 2009-07-16 13:45:57 +0000 | [diff] [blame] | 100 | { |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 101 | int ret; |
| 102 | |
| 103 | ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE, |
| 104 | DIRTY_MEMORY_VGA); |
| 105 | ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4, |
| 106 | DIRTY_MEMORY_VGA); |
| 107 | ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4, |
| 108 | DIRTY_MEMORY_VGA); |
| 109 | return ret; |
| 110 | } |
| 111 | |
| 112 | static inline void tcx24_reset_dirty(TCXState *ts, ram_addr_t page_min, |
| 113 | ram_addr_t page_max, ram_addr_t page24, |
| 114 | ram_addr_t cpage) |
| 115 | { |
| 116 | memory_region_reset_dirty(&ts->vram_mem, |
| 117 | page_min, |
| 118 | (page_max - page_min) + TARGET_PAGE_SIZE, |
| 119 | DIRTY_MEMORY_VGA); |
| 120 | memory_region_reset_dirty(&ts->vram_mem, |
| 121 | page24 + page_min * 4, |
| 122 | (page_max - page_min) * 4 + TARGET_PAGE_SIZE, |
| 123 | DIRTY_MEMORY_VGA); |
| 124 | memory_region_reset_dirty(&ts->vram_mem, |
| 125 | cpage + page_min * 4, |
| 126 | (page_max - page_min) * 4 + TARGET_PAGE_SIZE, |
| 127 | DIRTY_MEMORY_VGA); |
Blue Swirl | d3ffcaf | 2009-07-16 13:45:57 +0000 | [diff] [blame] | 128 | } |
pbrook | 9521989 | 2006-04-09 01:06:34 +0000 | [diff] [blame] | 129 | |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 130 | static void update_palette_entries(TCXState *s, int start, int end) |
| 131 | { |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 132 | DisplaySurface *surface = qemu_console_surface(s->con); |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 133 | int i; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 134 | |
| 135 | for (i = start; i < end; i++) { |
| 136 | switch (surface_bits_per_pixel(surface)) { |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 137 | default: |
| 138 | case 8: |
| 139 | s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]); |
| 140 | break; |
| 141 | case 15: |
aliguori | 8927bcf | 2009-01-15 22:07:16 +0000 | [diff] [blame] | 142 | s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]); |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 143 | break; |
| 144 | case 16: |
aliguori | 8927bcf | 2009-01-15 22:07:16 +0000 | [diff] [blame] | 145 | s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 146 | break; |
| 147 | case 32: |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 148 | if (is_surface_bgr(surface)) { |
aliguori | 7b5d76d | 2009-03-13 15:02:13 +0000 | [diff] [blame] | 149 | s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]); |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 150 | } else { |
aliguori | 7b5d76d | 2009-03-13 15:02:13 +0000 | [diff] [blame] | 151 | s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 152 | } |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 153 | break; |
| 154 | } |
| 155 | } |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 156 | tcx_set_dirty(s); |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 157 | } |
| 158 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 159 | static void tcx_draw_line32(TCXState *s1, uint8_t *d, |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 160 | const uint8_t *s, int width) |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 161 | { |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 162 | int x; |
| 163 | uint8_t val; |
ths | 8bdc215 | 2006-12-21 17:24:45 +0000 | [diff] [blame] | 164 | uint32_t *p = (uint32_t *)d; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 165 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 166 | for (x = 0; x < width; x++) { |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 167 | val = *s++; |
ths | 8bdc215 | 2006-12-21 17:24:45 +0000 | [diff] [blame] | 168 | *p++ = s1->palette[val]; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 169 | } |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 170 | } |
| 171 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 172 | static void tcx_draw_line16(TCXState *s1, uint8_t *d, |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 173 | const uint8_t *s, int width) |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 174 | { |
| 175 | int x; |
| 176 | uint8_t val; |
ths | 8bdc215 | 2006-12-21 17:24:45 +0000 | [diff] [blame] | 177 | uint16_t *p = (uint16_t *)d; |
bellard | 8d5f07f | 2004-10-04 21:23:09 +0000 | [diff] [blame] | 178 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 179 | for (x = 0; x < width; x++) { |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 180 | val = *s++; |
ths | 8bdc215 | 2006-12-21 17:24:45 +0000 | [diff] [blame] | 181 | *p++ = s1->palette[val]; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 182 | } |
| 183 | } |
| 184 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 185 | static void tcx_draw_line8(TCXState *s1, uint8_t *d, |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 186 | const uint8_t *s, int width) |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 187 | { |
| 188 | int x; |
| 189 | uint8_t val; |
| 190 | |
| 191 | for(x = 0; x < width; x++) { |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 192 | val = *s++; |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 193 | *d++ = s1->palette[val]; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 194 | } |
| 195 | } |
| 196 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 197 | static void tcx_draw_cursor32(TCXState *s1, uint8_t *d, |
| 198 | int y, int width) |
| 199 | { |
| 200 | int x, len; |
| 201 | uint32_t mask, bits; |
| 202 | uint32_t *p = (uint32_t *)d; |
| 203 | |
| 204 | y = y - s1->cursy; |
| 205 | mask = s1->cursmask[y]; |
| 206 | bits = s1->cursbits[y]; |
| 207 | len = MIN(width - s1->cursx, 32); |
| 208 | p = &p[s1->cursx]; |
| 209 | for (x = 0; x < len; x++) { |
| 210 | if (mask & 0x80000000) { |
| 211 | if (bits & 0x80000000) { |
| 212 | *p = s1->palette[259]; |
| 213 | } else { |
| 214 | *p = s1->palette[258]; |
| 215 | } |
| 216 | } |
| 217 | p++; |
| 218 | mask <<= 1; |
| 219 | bits <<= 1; |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | static void tcx_draw_cursor16(TCXState *s1, uint8_t *d, |
| 224 | int y, int width) |
| 225 | { |
| 226 | int x, len; |
| 227 | uint32_t mask, bits; |
| 228 | uint16_t *p = (uint16_t *)d; |
| 229 | |
| 230 | y = y - s1->cursy; |
| 231 | mask = s1->cursmask[y]; |
| 232 | bits = s1->cursbits[y]; |
| 233 | len = MIN(width - s1->cursx, 32); |
| 234 | p = &p[s1->cursx]; |
| 235 | for (x = 0; x < len; x++) { |
| 236 | if (mask & 0x80000000) { |
| 237 | if (bits & 0x80000000) { |
| 238 | *p = s1->palette[259]; |
| 239 | } else { |
| 240 | *p = s1->palette[258]; |
| 241 | } |
| 242 | } |
| 243 | p++; |
| 244 | mask <<= 1; |
| 245 | bits <<= 1; |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | static void tcx_draw_cursor8(TCXState *s1, uint8_t *d, |
| 250 | int y, int width) |
| 251 | { |
| 252 | int x, len; |
| 253 | uint32_t mask, bits; |
| 254 | |
| 255 | y = y - s1->cursy; |
| 256 | mask = s1->cursmask[y]; |
| 257 | bits = s1->cursbits[y]; |
| 258 | len = MIN(width - s1->cursx, 32); |
| 259 | d = &d[s1->cursx]; |
| 260 | for (x = 0; x < len; x++) { |
| 261 | if (mask & 0x80000000) { |
| 262 | if (bits & 0x80000000) { |
| 263 | *d = s1->palette[259]; |
| 264 | } else { |
| 265 | *d = s1->palette[258]; |
| 266 | } |
| 267 | } |
| 268 | d++; |
| 269 | mask <<= 1; |
| 270 | bits <<= 1; |
| 271 | } |
| 272 | } |
| 273 | |
blueswir1 | 688ea2e | 2008-07-24 11:26:38 +0000 | [diff] [blame] | 274 | /* |
| 275 | XXX Could be much more optimal: |
| 276 | * detect if line/page/whole screen is in 24 bit mode |
| 277 | * if destination is also BGR, use memcpy |
| 278 | */ |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 279 | static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, |
| 280 | const uint8_t *s, int width, |
| 281 | const uint32_t *cplane, |
| 282 | const uint32_t *s24) |
| 283 | { |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 284 | DisplaySurface *surface = qemu_console_surface(s1->con); |
aliguori | 7b5d76d | 2009-03-13 15:02:13 +0000 | [diff] [blame] | 285 | int x, bgr, r, g, b; |
blueswir1 | 688ea2e | 2008-07-24 11:26:38 +0000 | [diff] [blame] | 286 | uint8_t val, *p8; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 287 | uint32_t *p = (uint32_t *)d; |
| 288 | uint32_t dval; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 289 | bgr = is_surface_bgr(surface); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 290 | for(x = 0; x < width; x++, s++, s24++) { |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 291 | if (be32_to_cpu(*cplane) & 0x03000000) { |
| 292 | /* 24-bit direct, BGR order */ |
blueswir1 | 688ea2e | 2008-07-24 11:26:38 +0000 | [diff] [blame] | 293 | p8 = (uint8_t *)s24; |
| 294 | p8++; |
| 295 | b = *p8++; |
| 296 | g = *p8++; |
Blue Swirl | f7e683b | 2010-01-13 18:58:51 +0000 | [diff] [blame] | 297 | r = *p8; |
aliguori | 7b5d76d | 2009-03-13 15:02:13 +0000 | [diff] [blame] | 298 | if (bgr) |
| 299 | dval = rgb_to_pixel32bgr(r, g, b); |
| 300 | else |
| 301 | dval = rgb_to_pixel32(r, g, b); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 302 | } else { |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 303 | /* 8-bit pseudocolor */ |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 304 | val = *s; |
| 305 | dval = s1->palette[val]; |
| 306 | } |
| 307 | *p++ = dval; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 308 | cplane++; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 309 | } |
| 310 | } |
| 311 | |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 312 | /* Fixed line length 1024 allows us to do nice tricks not possible on |
| 313 | VGA... */ |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 314 | |
pbrook | 9521989 | 2006-04-09 01:06:34 +0000 | [diff] [blame] | 315 | static void tcx_update_display(void *opaque) |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 316 | { |
| 317 | TCXState *ts = opaque; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 318 | DisplaySurface *surface = qemu_console_surface(ts->con); |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 319 | ram_addr_t page, page_min, page_max; |
bellard | 550be12 | 2006-08-02 22:19:33 +0000 | [diff] [blame] | 320 | int y, y_start, dd, ds; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 321 | uint8_t *d, *s; |
blueswir1 | b3ceef2 | 2007-06-25 19:56:13 +0000 | [diff] [blame] | 322 | void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 323 | void (*fc)(TCXState *s1, uint8_t *dst, int y, int width); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 324 | |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 325 | if (surface_bits_per_pixel(surface) == 0) { |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 326 | return; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 327 | } |
| 328 | |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 329 | page = 0; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 330 | y_start = -1; |
Blue Swirl | c0c440f | 2009-04-27 18:10:37 +0000 | [diff] [blame] | 331 | page_min = -1; |
bellard | 550be12 | 2006-08-02 22:19:33 +0000 | [diff] [blame] | 332 | page_max = 0; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 333 | d = surface_data(surface); |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 334 | s = ts->vram; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 335 | dd = surface_stride(surface); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 336 | ds = 1024; |
| 337 | |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 338 | switch (surface_bits_per_pixel(surface)) { |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 339 | case 32: |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 340 | f = tcx_draw_line32; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 341 | fc = tcx_draw_cursor32; |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 342 | break; |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 343 | case 15: |
| 344 | case 16: |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 345 | f = tcx_draw_line16; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 346 | fc = tcx_draw_cursor16; |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 347 | break; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 348 | default: |
| 349 | case 8: |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 350 | f = tcx_draw_line8; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 351 | fc = tcx_draw_cursor8; |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 352 | break; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 353 | case 0: |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 354 | return; |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 355 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 356 | |
Paolo Bonzini | 5299c0f | 2015-04-22 13:12:40 +0200 | [diff] [blame] | 357 | memory_region_sync_dirty_bitmap(&ts->vram_mem); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 358 | for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) { |
Blue Swirl | cd7a45c | 2012-01-22 16:38:21 +0000 | [diff] [blame] | 359 | if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE, |
| 360 | DIRTY_MEMORY_VGA)) { |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 361 | if (y_start < 0) |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 362 | y_start = y; |
| 363 | if (page < page_min) |
| 364 | page_min = page; |
| 365 | if (page > page_max) |
| 366 | page_max = page; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 367 | |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 368 | f(ts, d, s, ts->width); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 369 | if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { |
| 370 | fc(ts, d, y, ts->width); |
| 371 | } |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 372 | d += dd; |
| 373 | s += ds; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 374 | y++; |
| 375 | |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 376 | f(ts, d, s, ts->width); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 377 | if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { |
| 378 | fc(ts, d, y, ts->width); |
| 379 | } |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 380 | d += dd; |
| 381 | s += ds; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 382 | y++; |
| 383 | |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 384 | f(ts, d, s, ts->width); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 385 | if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { |
| 386 | fc(ts, d, y, ts->width); |
| 387 | } |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 388 | d += dd; |
| 389 | s += ds; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 390 | y++; |
| 391 | |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 392 | f(ts, d, s, ts->width); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 393 | if (y >= ts->cursy && y < ts->cursy + 32 && ts->cursx < ts->width) { |
| 394 | fc(ts, d, y, ts->width); |
| 395 | } |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 396 | d += dd; |
| 397 | s += ds; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 398 | y++; |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 399 | } else { |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 400 | if (y_start >= 0) { |
| 401 | /* flush to display */ |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 402 | dpy_gfx_update(ts->con, 0, y_start, |
Gerd Hoffmann | a93a4a2 | 2012-09-28 15:02:08 +0200 | [diff] [blame] | 403 | ts->width, y - y_start); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 404 | y_start = -1; |
| 405 | } |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 406 | d += dd * 4; |
| 407 | s += ds * 4; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 408 | y += 4; |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 409 | } |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 410 | } |
| 411 | if (y_start >= 0) { |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 412 | /* flush to display */ |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 413 | dpy_gfx_update(ts->con, 0, y_start, |
Gerd Hoffmann | a93a4a2 | 2012-09-28 15:02:08 +0200 | [diff] [blame] | 414 | ts->width, y - y_start); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 415 | } |
| 416 | /* reset modified pages */ |
Blue Swirl | c0c440f | 2009-04-27 18:10:37 +0000 | [diff] [blame] | 417 | if (page_max >= page_min) { |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 418 | memory_region_reset_dirty(&ts->vram_mem, |
Mark Cave-Ayland | f10acc8 | 2013-06-02 17:23:00 +0100 | [diff] [blame] | 419 | page_min, |
| 420 | (page_max - page_min) + TARGET_PAGE_SIZE, |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 421 | DIRTY_MEMORY_VGA); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 422 | } |
| 423 | } |
| 424 | |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 425 | static void tcx24_update_display(void *opaque) |
| 426 | { |
| 427 | TCXState *ts = opaque; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 428 | DisplaySurface *surface = qemu_console_surface(ts->con); |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 429 | ram_addr_t page, page_min, page_max, cpage, page24; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 430 | int y, y_start, dd, ds; |
| 431 | uint8_t *d, *s; |
| 432 | uint32_t *cptr, *s24; |
| 433 | |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 434 | if (surface_bits_per_pixel(surface) != 32) { |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 435 | return; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 436 | } |
| 437 | |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 438 | page = 0; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 439 | page24 = ts->vram24_offset; |
| 440 | cpage = ts->cplane_offset; |
| 441 | y_start = -1; |
Blue Swirl | c0c440f | 2009-04-27 18:10:37 +0000 | [diff] [blame] | 442 | page_min = -1; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 443 | page_max = 0; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 444 | d = surface_data(surface); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 445 | s = ts->vram; |
| 446 | s24 = ts->vram24; |
| 447 | cptr = ts->cplane; |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 448 | dd = surface_stride(surface); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 449 | ds = 1024; |
| 450 | |
Paolo Bonzini | 5299c0f | 2015-04-22 13:12:40 +0200 | [diff] [blame] | 451 | memory_region_sync_dirty_bitmap(&ts->vram_mem); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 452 | for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE, |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 453 | page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 454 | if (tcx24_check_dirty(ts, page, page24, cpage)) { |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 455 | if (y_start < 0) |
| 456 | y_start = y; |
| 457 | if (page < page_min) |
| 458 | page_min = page; |
| 459 | if (page > page_max) |
| 460 | page_max = page; |
| 461 | tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 462 | if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { |
| 463 | tcx_draw_cursor32(ts, d, y, ts->width); |
| 464 | } |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 465 | d += dd; |
| 466 | s += ds; |
| 467 | cptr += ds; |
| 468 | s24 += ds; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 469 | y++; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 470 | tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 471 | if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { |
| 472 | tcx_draw_cursor32(ts, d, y, ts->width); |
| 473 | } |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 474 | d += dd; |
| 475 | s += ds; |
| 476 | cptr += ds; |
| 477 | s24 += ds; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 478 | y++; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 479 | tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 480 | if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { |
| 481 | tcx_draw_cursor32(ts, d, y, ts->width); |
| 482 | } |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 483 | d += dd; |
| 484 | s += ds; |
| 485 | cptr += ds; |
| 486 | s24 += ds; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 487 | y++; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 488 | tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 489 | if (y >= ts->cursy && y < ts->cursy+32 && ts->cursx < ts->width) { |
| 490 | tcx_draw_cursor32(ts, d, y, ts->width); |
| 491 | } |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 492 | d += dd; |
| 493 | s += ds; |
| 494 | cptr += ds; |
| 495 | s24 += ds; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 496 | y++; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 497 | } else { |
| 498 | if (y_start >= 0) { |
| 499 | /* flush to display */ |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 500 | dpy_gfx_update(ts->con, 0, y_start, |
Gerd Hoffmann | a93a4a2 | 2012-09-28 15:02:08 +0200 | [diff] [blame] | 501 | ts->width, y - y_start); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 502 | y_start = -1; |
| 503 | } |
| 504 | d += dd * 4; |
| 505 | s += ds * 4; |
| 506 | cptr += ds * 4; |
| 507 | s24 += ds * 4; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 508 | y += 4; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 509 | } |
| 510 | } |
| 511 | if (y_start >= 0) { |
| 512 | /* flush to display */ |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 513 | dpy_gfx_update(ts->con, 0, y_start, |
Gerd Hoffmann | a93a4a2 | 2012-09-28 15:02:08 +0200 | [diff] [blame] | 514 | ts->width, y - y_start); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 515 | } |
| 516 | /* reset modified pages */ |
Blue Swirl | c0c440f | 2009-04-27 18:10:37 +0000 | [diff] [blame] | 517 | if (page_max >= page_min) { |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 518 | tcx24_reset_dirty(ts, page_min, page_max, page24, cpage); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 519 | } |
| 520 | } |
| 521 | |
pbrook | 9521989 | 2006-04-09 01:06:34 +0000 | [diff] [blame] | 522 | static void tcx_invalidate_display(void *opaque) |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 523 | { |
| 524 | TCXState *s = opaque; |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 525 | |
Blue Swirl | d3ffcaf | 2009-07-16 13:45:57 +0000 | [diff] [blame] | 526 | tcx_set_dirty(s); |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 527 | qemu_console_resize(s->con, s->width, s->height); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 528 | } |
| 529 | |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 530 | static void tcx24_invalidate_display(void *opaque) |
| 531 | { |
| 532 | TCXState *s = opaque; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 533 | |
Blue Swirl | d3ffcaf | 2009-07-16 13:45:57 +0000 | [diff] [blame] | 534 | tcx_set_dirty(s); |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 535 | qemu_console_resize(s->con, s->width, s->height); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 536 | } |
| 537 | |
Juan Quintela | e59fb37 | 2009-09-29 22:48:21 +0200 | [diff] [blame] | 538 | static int vmstate_tcx_post_load(void *opaque, int version_id) |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 539 | { |
| 540 | TCXState *s = opaque; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 541 | |
bellard | 21206a1 | 2006-09-09 11:31:34 +0000 | [diff] [blame] | 542 | update_palette_entries(s, 0, 256); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 543 | tcx_set_dirty(s); |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 544 | return 0; |
| 545 | } |
| 546 | |
Blue Swirl | c0c41a4 | 2009-08-28 20:43:01 +0000 | [diff] [blame] | 547 | static const VMStateDescription vmstate_tcx = { |
| 548 | .name ="tcx", |
| 549 | .version_id = 4, |
| 550 | .minimum_version_id = 4, |
Juan Quintela | 752ff2f | 2009-09-10 03:04:30 +0200 | [diff] [blame] | 551 | .post_load = vmstate_tcx_post_load, |
Juan Quintela | 35d0845 | 2014-04-16 16:01:33 +0200 | [diff] [blame] | 552 | .fields = (VMStateField[]) { |
Blue Swirl | c0c41a4 | 2009-08-28 20:43:01 +0000 | [diff] [blame] | 553 | VMSTATE_UINT16(height, TCXState), |
| 554 | VMSTATE_UINT16(width, TCXState), |
| 555 | VMSTATE_UINT16(depth, TCXState), |
| 556 | VMSTATE_BUFFER(r, TCXState), |
| 557 | VMSTATE_BUFFER(g, TCXState), |
| 558 | VMSTATE_BUFFER(b, TCXState), |
| 559 | VMSTATE_UINT8(dac_index, TCXState), |
| 560 | VMSTATE_UINT8(dac_state, TCXState), |
| 561 | VMSTATE_END_OF_LIST() |
| 562 | } |
| 563 | }; |
| 564 | |
Michael S. Tsirkin | 7f23f81 | 2009-09-16 13:40:27 +0300 | [diff] [blame] | 565 | static void tcx_reset(DeviceState *d) |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 566 | { |
Andreas Färber | 01774dd | 2013-07-25 01:13:54 +0200 | [diff] [blame] | 567 | TCXState *s = TCX(d); |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 568 | |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 569 | /* Initialize palette */ |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 570 | memset(s->r, 0, 260); |
| 571 | memset(s->g, 0, 260); |
| 572 | memset(s->b, 0, 260); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 573 | s->r[255] = s->g[255] = s->b[255] = 255; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 574 | s->r[256] = s->g[256] = s->b[256] = 255; |
| 575 | s->r[258] = s->g[258] = s->b[258] = 255; |
| 576 | update_palette_entries(s, 0, 260); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 577 | memset(s->vram, 0, MAXX*MAXY); |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 578 | memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4), |
| 579 | DIRTY_MEMORY_VGA); |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 580 | s->dac_index = 0; |
| 581 | s->dac_state = 0; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 582 | s->cursx = 0xf000; /* Put cursor off screen */ |
| 583 | s->cursy = 0xf000; |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 584 | } |
| 585 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 586 | static uint64_t tcx_dac_readl(void *opaque, hwaddr addr, |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 587 | unsigned size) |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 588 | { |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 589 | TCXState *s = opaque; |
| 590 | uint32_t val = 0; |
| 591 | |
| 592 | switch (s->dac_state) { |
| 593 | case 0: |
| 594 | val = s->r[s->dac_index] << 24; |
| 595 | s->dac_state++; |
| 596 | break; |
| 597 | case 1: |
| 598 | val = s->g[s->dac_index] << 24; |
| 599 | s->dac_state++; |
| 600 | break; |
| 601 | case 2: |
| 602 | val = s->b[s->dac_index] << 24; |
| 603 | s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ |
| 604 | default: |
| 605 | s->dac_state = 0; |
| 606 | break; |
| 607 | } |
| 608 | |
| 609 | return val; |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 610 | } |
| 611 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 612 | static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val, |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 613 | unsigned size) |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 614 | { |
| 615 | TCXState *s = opaque; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 616 | unsigned index; |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 617 | |
blueswir1 | e64d7d5 | 2008-12-02 17:47:02 +0000 | [diff] [blame] | 618 | switch (addr) { |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 619 | case 0: /* Address */ |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 620 | s->dac_index = val >> 24; |
| 621 | s->dac_state = 0; |
| 622 | break; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 623 | case 4: /* Pixel colours */ |
| 624 | case 12: /* Overlay (cursor) colours */ |
| 625 | if (addr & 8) { |
| 626 | index = (s->dac_index & 3) + 256; |
| 627 | } else { |
| 628 | index = s->dac_index; |
| 629 | } |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 630 | switch (s->dac_state) { |
| 631 | case 0: |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 632 | s->r[index] = val >> 24; |
| 633 | update_palette_entries(s, index, index + 1); |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 634 | s->dac_state++; |
| 635 | break; |
| 636 | case 1: |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 637 | s->g[index] = val >> 24; |
| 638 | update_palette_entries(s, index, index + 1); |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 639 | s->dac_state++; |
| 640 | break; |
| 641 | case 2: |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 642 | s->b[index] = val >> 24; |
| 643 | update_palette_entries(s, index, index + 1); |
| 644 | s->dac_index = (s->dac_index + 1) & 0xff; /* Index autoincrement */ |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 645 | default: |
| 646 | s->dac_state = 0; |
| 647 | break; |
| 648 | } |
| 649 | break; |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 650 | default: /* Control registers */ |
blueswir1 | f930d07 | 2007-10-06 11:28:21 +0000 | [diff] [blame] | 651 | break; |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 652 | } |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 653 | } |
| 654 | |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 655 | static const MemoryRegionOps tcx_dac_ops = { |
| 656 | .read = tcx_dac_readl, |
| 657 | .write = tcx_dac_writel, |
| 658 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 659 | .valid = { |
| 660 | .min_access_size = 4, |
| 661 | .max_access_size = 4, |
| 662 | }, |
bellard | 6f7e9ae | 2005-03-13 09:43:36 +0000 | [diff] [blame] | 663 | }; |
| 664 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 665 | static uint64_t tcx_stip_readl(void *opaque, hwaddr addr, |
| 666 | unsigned size) |
| 667 | { |
| 668 | return 0; |
| 669 | } |
| 670 | |
| 671 | static void tcx_stip_writel(void *opaque, hwaddr addr, |
| 672 | uint64_t val, unsigned size) |
| 673 | { |
| 674 | TCXState *s = opaque; |
| 675 | int i; |
| 676 | uint32_t col; |
| 677 | |
| 678 | if (!(addr & 4)) { |
| 679 | s->tmpblit = val; |
| 680 | } else { |
| 681 | addr = (addr >> 3) & 0xfffff; |
| 682 | col = cpu_to_be32(s->tmpblit); |
| 683 | if (s->depth == 24) { |
| 684 | for (i = 0; i < 32; i++) { |
| 685 | if (val & 0x80000000) { |
| 686 | s->vram[addr + i] = s->tmpblit; |
| 687 | s->vram24[addr + i] = col; |
| 688 | } |
| 689 | val <<= 1; |
| 690 | } |
| 691 | } else { |
| 692 | for (i = 0; i < 32; i++) { |
| 693 | if (val & 0x80000000) { |
| 694 | s->vram[addr + i] = s->tmpblit; |
| 695 | } |
| 696 | val <<= 1; |
| 697 | } |
| 698 | } |
| 699 | memory_region_set_dirty(&s->vram_mem, addr, 32); |
| 700 | } |
| 701 | } |
| 702 | |
| 703 | static void tcx_rstip_writel(void *opaque, hwaddr addr, |
| 704 | uint64_t val, unsigned size) |
| 705 | { |
| 706 | TCXState *s = opaque; |
| 707 | int i; |
| 708 | uint32_t col; |
| 709 | |
| 710 | if (!(addr & 4)) { |
| 711 | s->tmpblit = val; |
| 712 | } else { |
| 713 | addr = (addr >> 3) & 0xfffff; |
| 714 | col = cpu_to_be32(s->tmpblit); |
| 715 | if (s->depth == 24) { |
| 716 | for (i = 0; i < 32; i++) { |
| 717 | if (val & 0x80000000) { |
| 718 | s->vram[addr + i] = s->tmpblit; |
| 719 | s->vram24[addr + i] = col; |
| 720 | s->cplane[addr + i] = col; |
| 721 | } |
| 722 | val <<= 1; |
| 723 | } |
| 724 | } else { |
| 725 | for (i = 0; i < 32; i++) { |
| 726 | if (val & 0x80000000) { |
| 727 | s->vram[addr + i] = s->tmpblit; |
| 728 | } |
| 729 | val <<= 1; |
| 730 | } |
| 731 | } |
| 732 | memory_region_set_dirty(&s->vram_mem, addr, 32); |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | static const MemoryRegionOps tcx_stip_ops = { |
| 737 | .read = tcx_stip_readl, |
| 738 | .write = tcx_stip_writel, |
| 739 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 740 | .valid = { |
| 741 | .min_access_size = 4, |
| 742 | .max_access_size = 4, |
| 743 | }, |
| 744 | }; |
| 745 | |
| 746 | static const MemoryRegionOps tcx_rstip_ops = { |
| 747 | .read = tcx_stip_readl, |
| 748 | .write = tcx_rstip_writel, |
| 749 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 750 | .valid = { |
| 751 | .min_access_size = 4, |
| 752 | .max_access_size = 4, |
| 753 | }, |
| 754 | }; |
| 755 | |
| 756 | static uint64_t tcx_blit_readl(void *opaque, hwaddr addr, |
| 757 | unsigned size) |
| 758 | { |
| 759 | return 0; |
| 760 | } |
| 761 | |
| 762 | static void tcx_blit_writel(void *opaque, hwaddr addr, |
| 763 | uint64_t val, unsigned size) |
| 764 | { |
| 765 | TCXState *s = opaque; |
| 766 | uint32_t adsr, len; |
| 767 | int i; |
| 768 | |
| 769 | if (!(addr & 4)) { |
| 770 | s->tmpblit = val; |
| 771 | } else { |
| 772 | addr = (addr >> 3) & 0xfffff; |
| 773 | adsr = val & 0xffffff; |
| 774 | len = ((val >> 24) & 0x1f) + 1; |
| 775 | if (adsr == 0xffffff) { |
| 776 | memset(&s->vram[addr], s->tmpblit, len); |
| 777 | if (s->depth == 24) { |
| 778 | val = s->tmpblit & 0xffffff; |
| 779 | val = cpu_to_be32(val); |
| 780 | for (i = 0; i < len; i++) { |
| 781 | s->vram24[addr + i] = val; |
| 782 | } |
| 783 | } |
| 784 | } else { |
| 785 | memcpy(&s->vram[addr], &s->vram[adsr], len); |
| 786 | if (s->depth == 24) { |
| 787 | memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); |
| 788 | } |
| 789 | } |
| 790 | memory_region_set_dirty(&s->vram_mem, addr, len); |
| 791 | } |
| 792 | } |
| 793 | |
| 794 | static void tcx_rblit_writel(void *opaque, hwaddr addr, |
| 795 | uint64_t val, unsigned size) |
| 796 | { |
| 797 | TCXState *s = opaque; |
| 798 | uint32_t adsr, len; |
| 799 | int i; |
| 800 | |
| 801 | if (!(addr & 4)) { |
| 802 | s->tmpblit = val; |
| 803 | } else { |
| 804 | addr = (addr >> 3) & 0xfffff; |
| 805 | adsr = val & 0xffffff; |
| 806 | len = ((val >> 24) & 0x1f) + 1; |
| 807 | if (adsr == 0xffffff) { |
| 808 | memset(&s->vram[addr], s->tmpblit, len); |
| 809 | if (s->depth == 24) { |
| 810 | val = s->tmpblit & 0xffffff; |
| 811 | val = cpu_to_be32(val); |
| 812 | for (i = 0; i < len; i++) { |
| 813 | s->vram24[addr + i] = val; |
| 814 | s->cplane[addr + i] = val; |
| 815 | } |
| 816 | } |
| 817 | } else { |
| 818 | memcpy(&s->vram[addr], &s->vram[adsr], len); |
| 819 | if (s->depth == 24) { |
| 820 | memcpy(&s->vram24[addr], &s->vram24[adsr], len * 4); |
| 821 | memcpy(&s->cplane[addr], &s->cplane[adsr], len * 4); |
| 822 | } |
| 823 | } |
| 824 | memory_region_set_dirty(&s->vram_mem, addr, len); |
| 825 | } |
| 826 | } |
| 827 | |
| 828 | static const MemoryRegionOps tcx_blit_ops = { |
| 829 | .read = tcx_blit_readl, |
| 830 | .write = tcx_blit_writel, |
| 831 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 832 | .valid = { |
| 833 | .min_access_size = 4, |
| 834 | .max_access_size = 4, |
| 835 | }, |
| 836 | }; |
| 837 | |
| 838 | static const MemoryRegionOps tcx_rblit_ops = { |
| 839 | .read = tcx_blit_readl, |
| 840 | .write = tcx_rblit_writel, |
| 841 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 842 | .valid = { |
| 843 | .min_access_size = 4, |
| 844 | .max_access_size = 4, |
| 845 | }, |
| 846 | }; |
| 847 | |
| 848 | static void tcx_invalidate_cursor_position(TCXState *s) |
| 849 | { |
| 850 | int ymin, ymax, start, end; |
| 851 | |
| 852 | /* invalidate only near the cursor */ |
| 853 | ymin = s->cursy; |
| 854 | if (ymin >= s->height) { |
| 855 | return; |
| 856 | } |
| 857 | ymax = MIN(s->height, ymin + 32); |
| 858 | start = ymin * 1024; |
| 859 | end = ymax * 1024; |
| 860 | |
| 861 | memory_region_set_dirty(&s->vram_mem, start, end-start); |
| 862 | } |
| 863 | |
| 864 | static uint64_t tcx_thc_readl(void *opaque, hwaddr addr, |
| 865 | unsigned size) |
| 866 | { |
| 867 | TCXState *s = opaque; |
| 868 | uint64_t val; |
| 869 | |
| 870 | if (addr == TCX_THC_MISC) { |
| 871 | val = s->thcmisc | 0x02000000; |
| 872 | } else { |
| 873 | val = 0; |
| 874 | } |
| 875 | return val; |
| 876 | } |
| 877 | |
| 878 | static void tcx_thc_writel(void *opaque, hwaddr addr, |
| 879 | uint64_t val, unsigned size) |
| 880 | { |
| 881 | TCXState *s = opaque; |
| 882 | |
| 883 | if (addr == TCX_THC_CURSXY) { |
| 884 | tcx_invalidate_cursor_position(s); |
| 885 | s->cursx = val >> 16; |
| 886 | s->cursy = val; |
| 887 | tcx_invalidate_cursor_position(s); |
| 888 | } else if (addr >= TCX_THC_CURSMASK && addr < TCX_THC_CURSMASK + 128) { |
| 889 | s->cursmask[(addr - TCX_THC_CURSMASK) >> 2] = val; |
| 890 | tcx_invalidate_cursor_position(s); |
| 891 | } else if (addr >= TCX_THC_CURSBITS && addr < TCX_THC_CURSBITS + 128) { |
| 892 | s->cursbits[(addr - TCX_THC_CURSBITS) >> 2] = val; |
| 893 | tcx_invalidate_cursor_position(s); |
| 894 | } else if (addr == TCX_THC_MISC) { |
| 895 | s->thcmisc = val; |
| 896 | } |
| 897 | |
| 898 | } |
| 899 | |
| 900 | static const MemoryRegionOps tcx_thc_ops = { |
| 901 | .read = tcx_thc_readl, |
| 902 | .write = tcx_thc_writel, |
| 903 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 904 | .valid = { |
| 905 | .min_access_size = 4, |
| 906 | .max_access_size = 4, |
| 907 | }, |
| 908 | }; |
| 909 | |
| 910 | static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr, |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 911 | unsigned size) |
blueswir1 | 8508b89 | 2007-05-06 17:39:55 +0000 | [diff] [blame] | 912 | { |
| 913 | return 0; |
| 914 | } |
| 915 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 916 | static void tcx_dummy_writel(void *opaque, hwaddr addr, |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 917 | uint64_t val, unsigned size) |
blueswir1 | 8508b89 | 2007-05-06 17:39:55 +0000 | [diff] [blame] | 918 | { |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 919 | return; |
blueswir1 | 8508b89 | 2007-05-06 17:39:55 +0000 | [diff] [blame] | 920 | } |
| 921 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 922 | static const MemoryRegionOps tcx_dummy_ops = { |
| 923 | .read = tcx_dummy_readl, |
| 924 | .write = tcx_dummy_writel, |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 925 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 926 | .valid = { |
| 927 | .min_access_size = 4, |
| 928 | .max_access_size = 4, |
| 929 | }, |
blueswir1 | 8508b89 | 2007-05-06 17:39:55 +0000 | [diff] [blame] | 930 | }; |
| 931 | |
Gerd Hoffmann | 380cd05 | 2013-03-13 14:04:18 +0100 | [diff] [blame] | 932 | static const GraphicHwOps tcx_ops = { |
| 933 | .invalidate = tcx_invalidate_display, |
| 934 | .gfx_update = tcx_update_display, |
| 935 | }; |
| 936 | |
| 937 | static const GraphicHwOps tcx24_ops = { |
| 938 | .invalidate = tcx24_invalidate_display, |
| 939 | .gfx_update = tcx24_update_display, |
| 940 | }; |
| 941 | |
Mark Cave-Ayland | 01b91ac | 2014-05-24 12:44:53 +0100 | [diff] [blame] | 942 | static void tcx_initfn(Object *obj) |
| 943 | { |
| 944 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); |
| 945 | TCXState *s = TCX(obj); |
| 946 | |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 947 | memory_region_init_ram(&s->rom, obj, "tcx.prom", FCODE_MAX_ROM_SIZE, |
Markus Armbruster | f8ed85a | 2015-09-11 16:51:43 +0200 | [diff] [blame] | 948 | &error_fatal); |
Mark Cave-Ayland | 01b91ac | 2014-05-24 12:44:53 +0100 | [diff] [blame] | 949 | memory_region_set_readonly(&s->rom, true); |
| 950 | sysbus_init_mmio(sbd, &s->rom); |
| 951 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 952 | /* 2/STIP : Stippler */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 953 | memory_region_init_io(&s->stip, obj, &tcx_stip_ops, s, "tcx.stip", |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 954 | TCX_STIP_NREGS); |
| 955 | sysbus_init_mmio(sbd, &s->stip); |
| 956 | |
| 957 | /* 3/BLIT : Blitter */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 958 | memory_region_init_io(&s->blit, obj, &tcx_blit_ops, s, "tcx.blit", |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 959 | TCX_BLIT_NREGS); |
| 960 | sysbus_init_mmio(sbd, &s->blit); |
| 961 | |
| 962 | /* 5/RSTIP : Raw Stippler */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 963 | memory_region_init_io(&s->rstip, obj, &tcx_rstip_ops, s, "tcx.rstip", |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 964 | TCX_RSTIP_NREGS); |
| 965 | sysbus_init_mmio(sbd, &s->rstip); |
| 966 | |
| 967 | /* 6/RBLIT : Raw Blitter */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 968 | memory_region_init_io(&s->rblit, obj, &tcx_rblit_ops, s, "tcx.rblit", |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 969 | TCX_RBLIT_NREGS); |
| 970 | sysbus_init_mmio(sbd, &s->rblit); |
| 971 | |
| 972 | /* 7/TEC : ??? */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 973 | memory_region_init_io(&s->tec, obj, &tcx_dummy_ops, s, "tcx.tec", |
| 974 | TCX_TEC_NREGS); |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 975 | sysbus_init_mmio(sbd, &s->tec); |
| 976 | |
| 977 | /* 8/CMAP : DAC */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 978 | memory_region_init_io(&s->dac, obj, &tcx_dac_ops, s, "tcx.dac", |
| 979 | TCX_DAC_NREGS); |
Mark Cave-Ayland | 01b91ac | 2014-05-24 12:44:53 +0100 | [diff] [blame] | 980 | sysbus_init_mmio(sbd, &s->dac); |
| 981 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 982 | /* 9/THC : Cursor */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 983 | memory_region_init_io(&s->thc, obj, &tcx_thc_ops, s, "tcx.thc", |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 984 | TCX_THC_NREGS); |
| 985 | sysbus_init_mmio(sbd, &s->thc); |
Mark Cave-Ayland | 01b91ac | 2014-05-24 12:44:53 +0100 | [diff] [blame] | 986 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 987 | /* 11/DHC : ??? */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 988 | memory_region_init_io(&s->dhc, obj, &tcx_dummy_ops, s, "tcx.dhc", |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 989 | TCX_DHC_NREGS); |
| 990 | sysbus_init_mmio(sbd, &s->dhc); |
| 991 | |
| 992 | /* 12/ALT : ??? */ |
Thomas Huth | b21de19 | 2015-10-15 10:54:15 +0200 | [diff] [blame] | 993 | memory_region_init_io(&s->alt, obj, &tcx_dummy_ops, s, "tcx.alt", |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 994 | TCX_ALT_NREGS); |
| 995 | sysbus_init_mmio(sbd, &s->alt); |
Mark Cave-Ayland | 01b91ac | 2014-05-24 12:44:53 +0100 | [diff] [blame] | 996 | } |
| 997 | |
Mark Cave-Ayland | d4ad9de | 2014-05-24 12:19:44 +0100 | [diff] [blame] | 998 | static void tcx_realizefn(DeviceState *dev, Error **errp) |
Blue Swirl | f40070c | 2009-07-12 19:21:36 +0000 | [diff] [blame] | 999 | { |
Mark Cave-Ayland | d4ad9de | 2014-05-24 12:19:44 +0100 | [diff] [blame] | 1000 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); |
Andreas Färber | 01774dd | 2013-07-25 01:13:54 +0200 | [diff] [blame] | 1001 | TCXState *s = TCX(dev); |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 1002 | ram_addr_t vram_offset = 0; |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 1003 | int size, ret; |
pbrook | dc828ca | 2009-04-09 22:21:07 +0000 | [diff] [blame] | 1004 | uint8_t *vram_base; |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 1005 | char *fcode_filename; |
pbrook | dc828ca | 2009-04-09 22:21:07 +0000 | [diff] [blame] | 1006 | |
Paolo Bonzini | 3eadad5 | 2013-06-06 21:25:08 -0400 | [diff] [blame] | 1007 | memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram", |
Markus Armbruster | f8ed85a | 2015-09-11 16:51:43 +0200 | [diff] [blame] | 1008 | s->vram_size * (1 + 4 + 4), &error_fatal); |
Avi Kivity | c5705a7 | 2011-12-20 15:59:12 +0200 | [diff] [blame] | 1009 | vmstate_register_ram_global(&s->vram_mem); |
Paolo Bonzini | 74259ae | 2015-03-23 10:47:45 +0100 | [diff] [blame] | 1010 | memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA); |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 1011 | vram_base = memory_region_get_ram_ptr(&s->vram_mem); |
bellard | e80cfcf | 2004-12-19 23:18:01 +0000 | [diff] [blame] | 1012 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 1013 | /* 10/ROM : FCode ROM */ |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 1014 | vmstate_register_ram_global(&s->rom); |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 1015 | fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE); |
| 1016 | if (fcode_filename) { |
| 1017 | ret = load_image_targphys(fcode_filename, s->prom_addr, |
| 1018 | FCODE_MAX_ROM_SIZE); |
Shannon Zhao | 8684e85 | 2015-05-28 19:13:45 +0800 | [diff] [blame] | 1019 | g_free(fcode_filename); |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 1020 | if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { |
Mark Cave-Ayland | d4ad9de | 2014-05-24 12:19:44 +0100 | [diff] [blame] | 1021 | error_report("tcx: could not load prom '%s'", TCX_ROM_FILE); |
Mark Cave-Ayland | da87dd7 | 2013-11-02 16:03:50 +0000 | [diff] [blame] | 1022 | } |
| 1023 | } |
| 1024 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 1025 | /* 0/DFB8 : 8-bit plane */ |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 1026 | s->vram = vram_base; |
Gerd Hoffmann | ee6847d | 2009-07-15 13:43:31 +0200 | [diff] [blame] | 1027 | size = s->vram_size; |
Paolo Bonzini | 3eadad5 | 2013-06-06 21:25:08 -0400 | [diff] [blame] | 1028 | memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit", |
Avi Kivity | d08151b | 2011-10-05 18:26:24 +0200 | [diff] [blame] | 1029 | &s->vram_mem, vram_offset, size); |
Mark Cave-Ayland | d4ad9de | 2014-05-24 12:19:44 +0100 | [diff] [blame] | 1030 | sysbus_init_mmio(sbd, &s->vram_8bit); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 1031 | vram_offset += size; |
| 1032 | vram_base += size; |
| 1033 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 1034 | /* 1/DFB24 : 24bit plane */ |
| 1035 | size = s->vram_size * 4; |
| 1036 | s->vram24 = (uint32_t *)vram_base; |
| 1037 | s->vram24_offset = vram_offset; |
| 1038 | memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", |
| 1039 | &s->vram_mem, vram_offset, size); |
| 1040 | sysbus_init_mmio(sbd, &s->vram_24bit); |
| 1041 | vram_offset += size; |
| 1042 | vram_base += size; |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 1043 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 1044 | /* 4/RDFB32 : Raw Framebuffer */ |
| 1045 | size = s->vram_size * 4; |
| 1046 | s->cplane = (uint32_t *)vram_base; |
| 1047 | s->cplane_offset = vram_offset; |
| 1048 | memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", |
| 1049 | &s->vram_mem, vram_offset, size); |
| 1050 | sysbus_init_mmio(sbd, &s->vram_cplane); |
Blue Swirl | f40070c | 2009-07-12 19:21:36 +0000 | [diff] [blame] | 1051 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 1052 | /* 9/THC24bits : NetBSD writes here even with 8-bit display: dummy */ |
| 1053 | if (s->depth == 8) { |
| 1054 | memory_region_init_io(&s->thc24, OBJECT(s), &tcx_dummy_ops, s, |
| 1055 | "tcx.thc24", TCX_THC_NREGS); |
| 1056 | sysbus_init_mmio(sbd, &s->thc24); |
blueswir1 | eee0b83 | 2007-04-21 19:45:49 +0000 | [diff] [blame] | 1057 | } |
| 1058 | |
Mark Cave-Ayland | 55d7bfe | 2014-09-13 10:44:07 +0100 | [diff] [blame] | 1059 | sysbus_init_irq(sbd, &s->irq); |
| 1060 | |
| 1061 | if (s->depth == 8) { |
| 1062 | s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); |
| 1063 | } else { |
| 1064 | s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); |
| 1065 | } |
| 1066 | s->thcmisc = 0; |
| 1067 | |
Gerd Hoffmann | c78f713 | 2013-03-05 15:24:14 +0100 | [diff] [blame] | 1068 | qemu_console_resize(s->con, s->width, s->height); |
bellard | 420557e | 2004-09-30 22:13:50 +0000 | [diff] [blame] | 1069 | } |
| 1070 | |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 1071 | static Property tcx_properties[] = { |
Paolo Bonzini | c7bcc85 | 2014-02-08 11:01:53 +0100 | [diff] [blame] | 1072 | DEFINE_PROP_UINT32("vram_size", TCXState, vram_size, -1), |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 1073 | DEFINE_PROP_UINT16("width", TCXState, width, -1), |
| 1074 | DEFINE_PROP_UINT16("height", TCXState, height, -1), |
| 1075 | DEFINE_PROP_UINT16("depth", TCXState, depth, -1), |
Paolo Bonzini | c7bcc85 | 2014-02-08 11:01:53 +0100 | [diff] [blame] | 1076 | DEFINE_PROP_UINT64("prom_addr", TCXState, prom_addr, -1), |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 1077 | DEFINE_PROP_END_OF_LIST(), |
| 1078 | }; |
| 1079 | |
| 1080 | static void tcx_class_init(ObjectClass *klass, void *data) |
| 1081 | { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 1082 | DeviceClass *dc = DEVICE_CLASS(klass); |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 1083 | |
Mark Cave-Ayland | d4ad9de | 2014-05-24 12:19:44 +0100 | [diff] [blame] | 1084 | dc->realize = tcx_realizefn; |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 1085 | dc->reset = tcx_reset; |
| 1086 | dc->vmsd = &vmstate_tcx; |
| 1087 | dc->props = tcx_properties; |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 1088 | } |
| 1089 | |
Andreas Färber | 8c43a6f | 2013-01-10 16:19:07 +0100 | [diff] [blame] | 1090 | static const TypeInfo tcx_info = { |
Andreas Färber | 01774dd | 2013-07-25 01:13:54 +0200 | [diff] [blame] | 1091 | .name = TYPE_TCX, |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 1092 | .parent = TYPE_SYS_BUS_DEVICE, |
| 1093 | .instance_size = sizeof(TCXState), |
Mark Cave-Ayland | 01b91ac | 2014-05-24 12:44:53 +0100 | [diff] [blame] | 1094 | .instance_init = tcx_initfn, |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 1095 | .class_init = tcx_class_init, |
Gerd Hoffmann | ee6847d | 2009-07-15 13:43:31 +0200 | [diff] [blame] | 1096 | }; |
| 1097 | |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 1098 | static void tcx_register_types(void) |
Blue Swirl | f40070c | 2009-07-12 19:21:36 +0000 | [diff] [blame] | 1099 | { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 1100 | type_register_static(&tcx_info); |
Blue Swirl | f40070c | 2009-07-12 19:21:36 +0000 | [diff] [blame] | 1101 | } |
| 1102 | |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 1103 | type_init(tcx_register_types) |