]> git.proxmox.com Git - mirror_qemu.git/blame - hw/tcx.c
monitor: Add port write command
[mirror_qemu.git] / hw / tcx.c
CommitLineData
420557e8 1/*
6f7e9aec 2 * QEMU TCX Frame buffer
5fafdf24 3 *
6f7e9aec 4 * Copyright (c) 2003-2005 Fabrice Bellard
5fafdf24 5 *
420557e8
FB
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 */
f40070c3 24
87ecb68b
PB
25#include "sun4m.h"
26#include "console.h"
94470844 27#include "pixel_ops.h"
f40070c3 28#include "sysbus.h"
420557e8 29
420557e8
FB
30#define MAXX 1024
31#define MAXY 768
6f7e9aec 32#define TCX_DAC_NREGS 16
8508b89e
BS
33#define TCX_THC_NREGS_8 0x081c
34#define TCX_THC_NREGS_24 0x1000
35#define TCX_TEC_NREGS 0x1000
420557e8 36
420557e8 37typedef struct TCXState {
f40070c3 38 SysBusDevice busdev;
5dcb6b91 39 target_phys_addr_t addr;
420557e8 40 DisplayState *ds;
8d5f07fa 41 uint8_t *vram;
eee0b836
BS
42 uint32_t *vram24, *cplane;
43 ram_addr_t vram_offset, vram24_offset, cplane_offset;
44 uint16_t width, height, depth;
e80cfcfc 45 uint8_t r[256], g[256], b[256];
21206a10 46 uint32_t palette[256];
6f7e9aec 47 uint8_t dac_index, dac_state;
420557e8
FB
48} TCXState;
49
95219897 50static void tcx_screen_dump(void *opaque, const char *filename);
eee0b836 51static void tcx24_screen_dump(void *opaque, const char *filename);
d3ffcafe
BS
52
53static void tcx_set_dirty(TCXState *s)
54{
55 unsigned int i;
56
57 for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
58 cpu_physical_memory_set_dirty(s->vram_offset + i);
59 }
60}
61
62static void tcx24_set_dirty(TCXState *s)
63{
64 unsigned int i;
65
66 for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
67 cpu_physical_memory_set_dirty(s->vram24_offset + i);
68 cpu_physical_memory_set_dirty(s->cplane_offset + i);
69 }
70}
95219897 71
21206a10
FB
72static void update_palette_entries(TCXState *s, int start, int end)
73{
74 int i;
75 for(i = start; i < end; i++) {
0e1f5a0c 76 switch(ds_get_bits_per_pixel(s->ds)) {
21206a10
FB
77 default:
78 case 8:
79 s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
80 break;
81 case 15:
8927bcfd 82 s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
21206a10
FB
83 break;
84 case 16:
8927bcfd 85 s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
21206a10
FB
86 break;
87 case 32:
7b5d76da
AL
88 if (is_surface_bgr(s->ds->surface))
89 s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
90 else
91 s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
21206a10
FB
92 break;
93 }
94 }
d3ffcafe
BS
95 if (s->depth == 24) {
96 tcx24_set_dirty(s);
97 } else {
98 tcx_set_dirty(s);
99 }
21206a10
FB
100}
101
5fafdf24 102static void tcx_draw_line32(TCXState *s1, uint8_t *d,
f930d07e 103 const uint8_t *s, int width)
420557e8 104{
e80cfcfc
FB
105 int x;
106 uint8_t val;
8bdc2159 107 uint32_t *p = (uint32_t *)d;
e80cfcfc
FB
108
109 for(x = 0; x < width; x++) {
f930d07e 110 val = *s++;
8bdc2159 111 *p++ = s1->palette[val];
e80cfcfc 112 }
420557e8
FB
113}
114
5fafdf24 115static void tcx_draw_line16(TCXState *s1, uint8_t *d,
f930d07e 116 const uint8_t *s, int width)
e80cfcfc
FB
117{
118 int x;
119 uint8_t val;
8bdc2159 120 uint16_t *p = (uint16_t *)d;
8d5f07fa 121
e80cfcfc 122 for(x = 0; x < width; x++) {
f930d07e 123 val = *s++;
8bdc2159 124 *p++ = s1->palette[val];
e80cfcfc
FB
125 }
126}
127
5fafdf24 128static void tcx_draw_line8(TCXState *s1, uint8_t *d,
f930d07e 129 const uint8_t *s, int width)
420557e8 130{
e80cfcfc
FB
131 int x;
132 uint8_t val;
133
134 for(x = 0; x < width; x++) {
f930d07e 135 val = *s++;
21206a10 136 *d++ = s1->palette[val];
420557e8 137 }
420557e8
FB
138}
139
688ea2eb
BS
140/*
141 XXX Could be much more optimal:
142 * detect if line/page/whole screen is in 24 bit mode
143 * if destination is also BGR, use memcpy
144 */
eee0b836
BS
145static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
146 const uint8_t *s, int width,
147 const uint32_t *cplane,
148 const uint32_t *s24)
149{
7b5d76da 150 int x, bgr, r, g, b;
688ea2eb 151 uint8_t val, *p8;
eee0b836
BS
152 uint32_t *p = (uint32_t *)d;
153 uint32_t dval;
154
7b5d76da 155 bgr = is_surface_bgr(s1->ds->surface);
eee0b836 156 for(x = 0; x < width; x++, s++, s24++) {
688ea2eb
BS
157 if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
158 // 24-bit direct, BGR order
159 p8 = (uint8_t *)s24;
160 p8++;
161 b = *p8++;
162 g = *p8++;
163 r = *p8++;
7b5d76da
AL
164 if (bgr)
165 dval = rgb_to_pixel32bgr(r, g, b);
166 else
167 dval = rgb_to_pixel32(r, g, b);
eee0b836
BS
168 } else {
169 val = *s;
170 dval = s1->palette[val];
171 }
172 *p++ = dval;
173 }
174}
175
22548760 176static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
eee0b836
BS
177 ram_addr_t cpage)
178{
179 int ret;
180 unsigned int off;
181
182 ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
183 for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
184 ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
185 ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
186 }
187 return ret;
188}
189
190static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
191 ram_addr_t page_max, ram_addr_t page24,
192 ram_addr_t cpage)
193{
194 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
195 VGA_DIRTY_FLAG);
196 page_min -= ts->vram_offset;
197 page_max -= ts->vram_offset;
198 cpu_physical_memory_reset_dirty(page24 + page_min * 4,
199 page24 + page_max * 4 + TARGET_PAGE_SIZE,
200 VGA_DIRTY_FLAG);
201 cpu_physical_memory_reset_dirty(cpage + page_min * 4,
202 cpage + page_max * 4 + TARGET_PAGE_SIZE,
203 VGA_DIRTY_FLAG);
204}
205
e80cfcfc
FB
206/* Fixed line length 1024 allows us to do nice tricks not possible on
207 VGA... */
95219897 208static void tcx_update_display(void *opaque)
420557e8 209{
e80cfcfc 210 TCXState *ts = opaque;
550be127
FB
211 ram_addr_t page, page_min, page_max;
212 int y, y_start, dd, ds;
e80cfcfc 213 uint8_t *d, *s;
b3ceef24 214 void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
e80cfcfc 215
0e1f5a0c 216 if (ds_get_bits_per_pixel(ts->ds) == 0)
f930d07e 217 return;
6f7e9aec 218 page = ts->vram_offset;
e80cfcfc 219 y_start = -1;
c0c440f3 220 page_min = -1;
550be127 221 page_max = 0;
0e1f5a0c 222 d = ds_get_data(ts->ds);
6f7e9aec 223 s = ts->vram;
0e1f5a0c 224 dd = ds_get_linesize(ts->ds);
e80cfcfc
FB
225 ds = 1024;
226
0e1f5a0c 227 switch (ds_get_bits_per_pixel(ts->ds)) {
e80cfcfc 228 case 32:
f930d07e
BS
229 f = tcx_draw_line32;
230 break;
21206a10
FB
231 case 15:
232 case 16:
f930d07e
BS
233 f = tcx_draw_line16;
234 break;
e80cfcfc
FB
235 default:
236 case 8:
f930d07e
BS
237 f = tcx_draw_line8;
238 break;
e80cfcfc 239 case 0:
f930d07e 240 return;
e80cfcfc 241 }
3b46e624 242
6f7e9aec 243 for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
f930d07e
BS
244 if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
245 if (y_start < 0)
e80cfcfc
FB
246 y_start = y;
247 if (page < page_min)
248 page_min = page;
249 if (page > page_max)
250 page_max = page;
f930d07e
BS
251 f(ts, d, s, ts->width);
252 d += dd;
253 s += ds;
254 f(ts, d, s, ts->width);
255 d += dd;
256 s += ds;
257 f(ts, d, s, ts->width);
258 d += dd;
259 s += ds;
260 f(ts, d, s, ts->width);
261 d += dd;
262 s += ds;
263 } else {
e80cfcfc
FB
264 if (y_start >= 0) {
265 /* flush to display */
5fafdf24 266 dpy_update(ts->ds, 0, y_start,
6f7e9aec 267 ts->width, y - y_start);
e80cfcfc
FB
268 y_start = -1;
269 }
f930d07e
BS
270 d += dd * 4;
271 s += ds * 4;
272 }
e80cfcfc
FB
273 }
274 if (y_start >= 0) {
f930d07e
BS
275 /* flush to display */
276 dpy_update(ts->ds, 0, y_start,
277 ts->width, y - y_start);
e80cfcfc
FB
278 }
279 /* reset modified pages */
c0c440f3 280 if (page_max >= page_min) {
0a962c02
FB
281 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
282 VGA_DIRTY_FLAG);
e80cfcfc 283 }
420557e8
FB
284}
285
eee0b836
BS
286static void tcx24_update_display(void *opaque)
287{
288 TCXState *ts = opaque;
289 ram_addr_t page, page_min, page_max, cpage, page24;
290 int y, y_start, dd, ds;
291 uint8_t *d, *s;
292 uint32_t *cptr, *s24;
293
0e1f5a0c 294 if (ds_get_bits_per_pixel(ts->ds) != 32)
eee0b836
BS
295 return;
296 page = ts->vram_offset;
297 page24 = ts->vram24_offset;
298 cpage = ts->cplane_offset;
299 y_start = -1;
c0c440f3 300 page_min = -1;
eee0b836 301 page_max = 0;
0e1f5a0c 302 d = ds_get_data(ts->ds);
eee0b836
BS
303 s = ts->vram;
304 s24 = ts->vram24;
305 cptr = ts->cplane;
0e1f5a0c 306 dd = ds_get_linesize(ts->ds);
eee0b836
BS
307 ds = 1024;
308
309 for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
310 page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
22548760 311 if (check_dirty(page, page24, cpage)) {
eee0b836
BS
312 if (y_start < 0)
313 y_start = y;
314 if (page < page_min)
315 page_min = page;
316 if (page > page_max)
317 page_max = page;
318 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
319 d += dd;
320 s += ds;
321 cptr += ds;
322 s24 += ds;
323 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
324 d += dd;
325 s += ds;
326 cptr += ds;
327 s24 += ds;
328 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
329 d += dd;
330 s += ds;
331 cptr += ds;
332 s24 += ds;
333 tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
334 d += dd;
335 s += ds;
336 cptr += ds;
337 s24 += ds;
338 } else {
339 if (y_start >= 0) {
340 /* flush to display */
341 dpy_update(ts->ds, 0, y_start,
342 ts->width, y - y_start);
343 y_start = -1;
344 }
345 d += dd * 4;
346 s += ds * 4;
347 cptr += ds * 4;
348 s24 += ds * 4;
349 }
350 }
351 if (y_start >= 0) {
352 /* flush to display */
353 dpy_update(ts->ds, 0, y_start,
354 ts->width, y - y_start);
355 }
356 /* reset modified pages */
c0c440f3 357 if (page_max >= page_min) {
eee0b836
BS
358 reset_dirty(ts, page_min, page_max, page24, cpage);
359 }
360}
361
95219897 362static void tcx_invalidate_display(void *opaque)
420557e8 363{
e80cfcfc 364 TCXState *s = opaque;
e80cfcfc 365
d3ffcafe
BS
366 tcx_set_dirty(s);
367 qemu_console_resize(s->ds, s->width, s->height);
420557e8
FB
368}
369
eee0b836
BS
370static void tcx24_invalidate_display(void *opaque)
371{
372 TCXState *s = opaque;
eee0b836 373
d3ffcafe
BS
374 tcx_set_dirty(s);
375 tcx24_set_dirty(s);
376 qemu_console_resize(s->ds, s->width, s->height);
eee0b836
BS
377}
378
e80cfcfc 379static void tcx_save(QEMUFile *f, void *opaque)
420557e8
FB
380{
381 TCXState *s = opaque;
3b46e624 382
b6c4f71f
BS
383 qemu_put_be16s(f, &s->height);
384 qemu_put_be16s(f, &s->width);
385 qemu_put_be16s(f, &s->depth);
e80cfcfc
FB
386 qemu_put_buffer(f, s->r, 256);
387 qemu_put_buffer(f, s->g, 256);
388 qemu_put_buffer(f, s->b, 256);
6f7e9aec
FB
389 qemu_put_8s(f, &s->dac_index);
390 qemu_put_8s(f, &s->dac_state);
420557e8
FB
391}
392
e80cfcfc 393static int tcx_load(QEMUFile *f, void *opaque, int version_id)
420557e8 394{
e80cfcfc 395 TCXState *s = opaque;
fda77c2d
BS
396 uint32_t dummy;
397
398 if (version_id != 3 && version_id != 4)
e80cfcfc
FB
399 return -EINVAL;
400
fda77c2d 401 if (version_id == 3) {
b6c4f71f
BS
402 qemu_get_be32s(f, &dummy);
403 qemu_get_be32s(f, &dummy);
404 qemu_get_be32s(f, &dummy);
fda77c2d 405 }
b6c4f71f
BS
406 qemu_get_be16s(f, &s->height);
407 qemu_get_be16s(f, &s->width);
408 qemu_get_be16s(f, &s->depth);
e80cfcfc
FB
409 qemu_get_buffer(f, s->r, 256);
410 qemu_get_buffer(f, s->g, 256);
411 qemu_get_buffer(f, s->b, 256);
6f7e9aec
FB
412 qemu_get_8s(f, &s->dac_index);
413 qemu_get_8s(f, &s->dac_state);
21206a10 414 update_palette_entries(s, 0, 256);
d3ffcafe
BS
415 if (s->depth == 24) {
416 tcx24_set_dirty(s);
417 } else {
418 tcx_set_dirty(s);
419 }
5425a216 420
e80cfcfc 421 return 0;
420557e8
FB
422}
423
e80cfcfc 424static void tcx_reset(void *opaque)
420557e8 425{
e80cfcfc
FB
426 TCXState *s = opaque;
427
428 /* Initialize palette */
429 memset(s->r, 0, 256);
430 memset(s->g, 0, 256);
431 memset(s->b, 0, 256);
432 s->r[255] = s->g[255] = s->b[255] = 255;
21206a10 433 update_palette_entries(s, 0, 256);
e80cfcfc 434 memset(s->vram, 0, MAXX*MAXY);
eee0b836
BS
435 cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
436 MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
6f7e9aec
FB
437 s->dac_index = 0;
438 s->dac_state = 0;
439}
440
441static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
442{
443 return 0;
444}
445
446static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
447{
448 TCXState *s = opaque;
6f7e9aec 449
e64d7d59 450 switch (addr) {
6f7e9aec 451 case 0:
f930d07e
BS
452 s->dac_index = val >> 24;
453 s->dac_state = 0;
454 break;
e64d7d59 455 case 4:
f930d07e
BS
456 switch (s->dac_state) {
457 case 0:
458 s->r[s->dac_index] = val >> 24;
21206a10 459 update_palette_entries(s, s->dac_index, s->dac_index + 1);
f930d07e
BS
460 s->dac_state++;
461 break;
462 case 1:
463 s->g[s->dac_index] = val >> 24;
21206a10 464 update_palette_entries(s, s->dac_index, s->dac_index + 1);
f930d07e
BS
465 s->dac_state++;
466 break;
467 case 2:
468 s->b[s->dac_index] = val >> 24;
21206a10 469 update_palette_entries(s, s->dac_index, s->dac_index + 1);
5c8cdbf8 470 s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
f930d07e
BS
471 default:
472 s->dac_state = 0;
473 break;
474 }
475 break;
6f7e9aec 476 default:
f930d07e 477 break;
6f7e9aec
FB
478 }
479 return;
420557e8
FB
480}
481
6f7e9aec 482static CPUReadMemoryFunc *tcx_dac_read[3] = {
7c560456
BS
483 NULL,
484 NULL,
6f7e9aec
FB
485 tcx_dac_readl,
486};
487
488static CPUWriteMemoryFunc *tcx_dac_write[3] = {
7c560456
BS
489 NULL,
490 NULL,
6f7e9aec
FB
491 tcx_dac_writel,
492};
493
8508b89e
BS
494static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
495{
496 return 0;
497}
498
499static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
500 uint32_t val)
501{
502}
503
504static CPUReadMemoryFunc *tcx_dummy_read[3] = {
7c560456
BS
505 NULL,
506 NULL,
8508b89e
BS
507 tcx_dummy_readl,
508};
509
510static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
7c560456
BS
511 NULL,
512 NULL,
8508b89e
BS
513 tcx_dummy_writel,
514};
515
dc828ca1 516void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height,
eee0b836 517 int depth)
420557e8 518{
f40070c3
BS
519 DeviceState *dev;
520 SysBusDevice *s;
521
522 dev = qdev_create(NULL, "SUNW,tcx");
523 qdev_set_prop_int(dev, "addr", addr);
524 qdev_set_prop_int(dev, "vram_size", vram_size);
525 qdev_set_prop_int(dev, "width", width);
526 qdev_set_prop_int(dev, "height", height);
527 qdev_set_prop_int(dev, "depth", depth);
528 qdev_init(dev);
529 s = sysbus_from_qdev(dev);
530 /* 8-bit plane */
531 sysbus_mmio_map(s, 0, addr + 0x00800000ULL);
532 /* DAC */
533 sysbus_mmio_map(s, 1, addr + 0x00200000ULL);
534 /* TEC (dummy) */
535 sysbus_mmio_map(s, 2, addr + 0x00700000ULL);
536 /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */
537 sysbus_mmio_map(s, 3, addr + 0x00301000ULL);
538 if (depth == 24) {
539 /* 24-bit plane */
540 sysbus_mmio_map(s, 4, addr + 0x02000000ULL);
541 /* Control plane */
542 sysbus_mmio_map(s, 5, addr + 0x0a000000ULL);
543 } else {
544 /* THC 8 bit (dummy) */
545 sysbus_mmio_map(s, 4, addr + 0x00300000ULL);
546 }
547}
548
549static void tcx_init1(SysBusDevice *dev)
550{
551 TCXState *s = FROM_SYSBUS(TCXState, dev);
8508b89e 552 int io_memory, dummy_memory;
dc828ca1 553 ram_addr_t vram_offset;
f40070c3 554 int size, vram_size;
dc828ca1
PB
555 uint8_t *vram_base;
556
f40070c3
BS
557 vram_size = qdev_get_prop_int(&dev->qdev, "vram_size", -1);
558
520860ef 559 vram_offset = qemu_ram_alloc(vram_size * (1 + 4 + 4));
dc828ca1 560 vram_base = qemu_get_ram_ptr(vram_offset);
f40070c3 561 s->addr = qdev_get_prop_int(&dev->qdev, "addr", -1);
e80cfcfc 562 s->vram_offset = vram_offset;
f40070c3
BS
563 s->width = qdev_get_prop_int(&dev->qdev, "width", -1);
564 s->height = qdev_get_prop_int(&dev->qdev, "height", -1);
565 s->depth = qdev_get_prop_int(&dev->qdev, "depth", -1);
eee0b836 566
f40070c3 567 /* 8-bit plane */
eee0b836
BS
568 s->vram = vram_base;
569 size = vram_size;
f40070c3 570 sysbus_init_mmio(dev, size, s->vram_offset);
eee0b836
BS
571 vram_offset += size;
572 vram_base += size;
e80cfcfc 573
f40070c3 574 /* DAC */
1eed09cb 575 io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s);
f40070c3 576 sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
eee0b836 577
f40070c3 578 /* TEC (dummy) */
1eed09cb 579 dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
8508b89e 580 s);
f40070c3
BS
581 sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
582 /* THC: NetBSD writes here even with 8-bit display: dummy */
583 sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
584
585 if (s->depth == 24) {
586 /* 24-bit plane */
eee0b836
BS
587 size = vram_size * 4;
588 s->vram24 = (uint32_t *)vram_base;
589 s->vram24_offset = vram_offset;
f40070c3 590 sysbus_init_mmio(dev, size, vram_offset);
eee0b836
BS
591 vram_offset += size;
592 vram_base += size;
593
f40070c3 594 /* Control plane */
eee0b836
BS
595 size = vram_size * 4;
596 s->cplane = (uint32_t *)vram_base;
597 s->cplane_offset = vram_offset;
f40070c3
BS
598 sysbus_init_mmio(dev, size, vram_offset);
599
3023f332
AL
600 s->ds = graphic_console_init(tcx24_update_display,
601 tcx24_invalidate_display,
602 tcx24_screen_dump, NULL, s);
eee0b836 603 } else {
f40070c3
BS
604 /* THC 8 bit (dummy) */
605 sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
606
3023f332
AL
607 s->ds = graphic_console_init(tcx_update_display,
608 tcx_invalidate_display,
609 tcx_screen_dump, NULL, s);
eee0b836 610 }
e80cfcfc 611
f40070c3 612 register_savevm("tcx", -1, 4, tcx_save, tcx_load, s);
a08d4367 613 qemu_register_reset(tcx_reset, s);
e80cfcfc 614 tcx_reset(s);
f40070c3 615 qemu_console_resize(s->ds, s->width, s->height);
420557e8
FB
616}
617
95219897 618static void tcx_screen_dump(void *opaque, const char *filename)
8d5f07fa 619{
e80cfcfc 620 TCXState *s = opaque;
8d5f07fa 621 FILE *f;
e80cfcfc 622 uint8_t *d, *d1, v;
8d5f07fa
FB
623 int y, x;
624
625 f = fopen(filename, "wb");
626 if (!f)
e80cfcfc 627 return;
6f7e9aec
FB
628 fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
629 d1 = s->vram;
630 for(y = 0; y < s->height; y++) {
8d5f07fa 631 d = d1;
6f7e9aec 632 for(x = 0; x < s->width; x++) {
8d5f07fa 633 v = *d;
e80cfcfc
FB
634 fputc(s->r[v], f);
635 fputc(s->g[v], f);
636 fputc(s->b[v], f);
8d5f07fa
FB
637 d++;
638 }
e80cfcfc 639 d1 += MAXX;
8d5f07fa
FB
640 }
641 fclose(f);
642 return;
643}
644
eee0b836
BS
645static void tcx24_screen_dump(void *opaque, const char *filename)
646{
647 TCXState *s = opaque;
648 FILE *f;
649 uint8_t *d, *d1, v;
650 uint32_t *s24, *cptr, dval;
651 int y, x;
8d5f07fa 652
eee0b836
BS
653 f = fopen(filename, "wb");
654 if (!f)
655 return;
656 fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
657 d1 = s->vram;
658 s24 = s->vram24;
659 cptr = s->cplane;
660 for(y = 0; y < s->height; y++) {
661 d = d1;
662 for(x = 0; x < s->width; x++, d++, s24++) {
663 if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
664 dval = *s24 & 0x00ffffff;
665 fputc((dval >> 16) & 0xff, f);
666 fputc((dval >> 8) & 0xff, f);
667 fputc(dval & 0xff, f);
668 } else {
669 v = *d;
670 fputc(s->r[v], f);
671 fputc(s->g[v], f);
672 fputc(s->b[v], f);
673 }
674 }
675 d1 += MAXX;
676 }
677 fclose(f);
678 return;
679}
f40070c3
BS
680
681static void tcx_register_devices(void)
682{
683 sysbus_register_dev("SUNW,tcx", sizeof(TCXState), tcx_init1);
684}
685
686device_init(tcx_register_devices)