hw/mips/cps: Expose input clock and connect it to CPU cores
[qemu/ar7.git] / hw / display / artist.c
blobed0e637f250c972c920956bafeb7603324e1830a
1 /*
2 * QEMU HP Artist Emulation
4 * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 */
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11 #include "qemu/error-report.h"
12 #include "qemu/typedefs.h"
13 #include "qemu/log.h"
14 #include "qemu/module.h"
15 #include "qemu/units.h"
16 #include "qapi/error.h"
17 #include "hw/sysbus.h"
18 #include "hw/loader.h"
19 #include "hw/qdev-core.h"
20 #include "hw/qdev-properties.h"
21 #include "migration/vmstate.h"
22 #include "ui/console.h"
23 #include "trace.h"
24 #include "framebuffer.h"
25 #include "qom/object.h"
27 #define TYPE_ARTIST "artist"
28 OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState, ARTIST)
30 #ifdef HOST_WORDS_BIGENDIAN
31 #define ROP8OFF(_i) (3 - (_i))
32 #else
33 #define ROP8OFF
34 #endif
36 struct vram_buffer {
37 MemoryRegion mr;
38 uint8_t *data;
39 unsigned int size;
40 unsigned int width;
41 unsigned int height;
44 struct ARTISTState {
45 SysBusDevice parent_obj;
47 QemuConsole *con;
48 MemoryRegion vram_mem;
49 MemoryRegion mem_as_root;
50 MemoryRegion reg;
51 MemoryRegionSection fbsection;
53 void *vram_int_mr;
54 AddressSpace as;
56 struct vram_buffer vram_buffer[16];
58 uint16_t width;
59 uint16_t height;
60 uint16_t depth;
62 uint32_t fg_color;
63 uint32_t bg_color;
65 uint32_t vram_char_y;
66 uint32_t vram_bitmask;
68 uint32_t vram_start;
69 uint32_t vram_pos;
71 uint32_t vram_size;
73 uint32_t blockmove_source;
74 uint32_t blockmove_dest;
75 uint32_t blockmove_size;
77 uint32_t line_size;
78 uint32_t line_end;
79 uint32_t line_xy;
80 uint32_t line_pattern_start;
81 uint32_t line_pattern_skip;
83 uint32_t cursor_pos;
85 uint32_t cursor_height;
86 uint32_t cursor_width;
88 uint32_t plane_mask;
90 uint32_t reg_100080;
91 uint32_t reg_300200;
92 uint32_t reg_300208;
93 uint32_t reg_300218;
95 uint32_t cmap_bm_access;
96 uint32_t dst_bm_access;
97 uint32_t src_bm_access;
98 uint32_t control_plane;
99 uint32_t transfer_data;
100 uint32_t image_bitmap_op;
102 uint32_t font_write1;
103 uint32_t font_write2;
104 uint32_t font_write_pos_y;
106 int draw_line_pattern;
109 typedef enum {
110 ARTIST_BUFFER_AP = 1,
111 ARTIST_BUFFER_OVERLAY = 2,
112 ARTIST_BUFFER_CURSOR1 = 6,
113 ARTIST_BUFFER_CURSOR2 = 7,
114 ARTIST_BUFFER_ATTRIBUTE = 13,
115 ARTIST_BUFFER_CMAP = 15,
116 } artist_buffer_t;
118 typedef enum {
119 VRAM_IDX = 0x1004a0,
120 VRAM_BITMASK = 0x1005a0,
121 VRAM_WRITE_INCR_X = 0x100600,
122 VRAM_WRITE_INCR_X2 = 0x100604,
123 VRAM_WRITE_INCR_Y = 0x100620,
124 VRAM_START = 0x100800,
125 BLOCK_MOVE_SIZE = 0x100804,
126 BLOCK_MOVE_SOURCE = 0x100808,
127 TRANSFER_DATA = 0x100820,
128 FONT_WRITE_INCR_Y = 0x1008a0,
129 VRAM_START_TRIGGER = 0x100a00,
130 VRAM_SIZE_TRIGGER = 0x100a04,
131 FONT_WRITE_START = 0x100aa0,
132 BLOCK_MOVE_DEST_TRIGGER = 0x100b00,
133 BLOCK_MOVE_SIZE_TRIGGER = 0x100b04,
134 LINE_XY = 0x100ccc,
135 PATTERN_LINE_START = 0x100ecc,
136 LINE_SIZE = 0x100e04,
137 LINE_END = 0x100e44,
138 CMAP_BM_ACCESS = 0x118000,
139 DST_BM_ACCESS = 0x118004,
140 SRC_BM_ACCESS = 0x118008,
141 CONTROL_PLANE = 0x11800c,
142 FG_COLOR = 0x118010,
143 BG_COLOR = 0x118014,
144 PLANE_MASK = 0x118018,
145 IMAGE_BITMAP_OP = 0x11801c,
146 CURSOR_POS = 0x300100,
147 CURSOR_CTRL = 0x300104,
148 } artist_reg_t;
150 typedef enum {
151 ARTIST_ROP_CLEAR = 0,
152 ARTIST_ROP_COPY = 3,
153 ARTIST_ROP_XOR = 6,
154 ARTIST_ROP_NOT_DST = 10,
155 ARTIST_ROP_SET = 15,
156 } artist_rop_t;
158 #define REG_NAME(_x) case _x: return " "#_x;
159 static const char *artist_reg_name(uint64_t addr)
161 switch ((artist_reg_t)addr) {
162 REG_NAME(VRAM_IDX);
163 REG_NAME(VRAM_BITMASK);
164 REG_NAME(VRAM_WRITE_INCR_X);
165 REG_NAME(VRAM_WRITE_INCR_X2);
166 REG_NAME(VRAM_WRITE_INCR_Y);
167 REG_NAME(VRAM_START);
168 REG_NAME(BLOCK_MOVE_SIZE);
169 REG_NAME(BLOCK_MOVE_SOURCE);
170 REG_NAME(FG_COLOR);
171 REG_NAME(BG_COLOR);
172 REG_NAME(PLANE_MASK);
173 REG_NAME(VRAM_START_TRIGGER);
174 REG_NAME(VRAM_SIZE_TRIGGER);
175 REG_NAME(BLOCK_MOVE_DEST_TRIGGER);
176 REG_NAME(BLOCK_MOVE_SIZE_TRIGGER);
177 REG_NAME(TRANSFER_DATA);
178 REG_NAME(CONTROL_PLANE);
179 REG_NAME(IMAGE_BITMAP_OP);
180 REG_NAME(CMAP_BM_ACCESS);
181 REG_NAME(DST_BM_ACCESS);
182 REG_NAME(SRC_BM_ACCESS);
183 REG_NAME(CURSOR_POS);
184 REG_NAME(CURSOR_CTRL);
185 REG_NAME(LINE_XY);
186 REG_NAME(PATTERN_LINE_START);
187 REG_NAME(LINE_SIZE);
188 REG_NAME(LINE_END);
189 REG_NAME(FONT_WRITE_INCR_Y);
190 REG_NAME(FONT_WRITE_START);
192 return "";
194 #undef REG_NAME
196 /* artist has a fixed line length of 2048 bytes. */
197 #define ADDR_TO_Y(addr) extract32(addr, 11, 11)
198 #define ADDR_TO_X(addr) extract32(addr, 0, 11)
200 static int16_t artist_get_x(uint32_t reg)
202 return reg >> 16;
205 static int16_t artist_get_y(uint32_t reg)
207 return reg & 0xffff;
210 static void artist_invalidate_lines(struct vram_buffer *buf,
211 int starty, int height)
213 int start = starty * buf->width;
214 int size;
216 if (starty + height > buf->height)
217 height = buf->height - starty;
219 size = height * buf->width;
221 if (start + size <= buf->size) {
222 memory_region_set_dirty(&buf->mr, start, size);
226 static int vram_write_pix_per_transfer(ARTISTState *s)
228 if (s->cmap_bm_access) {
229 return 1 << ((s->cmap_bm_access >> 27) & 0x0f);
230 } else {
231 return 1 << ((s->dst_bm_access >> 27) & 0x0f);
235 static int vram_pixel_length(ARTISTState *s)
237 if (s->cmap_bm_access) {
238 return (s->cmap_bm_access >> 24) & 0x07;
239 } else {
240 return (s->dst_bm_access >> 24) & 0x07;
244 static int vram_write_bufidx(ARTISTState *s)
246 if (s->cmap_bm_access) {
247 return (s->cmap_bm_access >> 12) & 0x0f;
248 } else {
249 return (s->dst_bm_access >> 12) & 0x0f;
253 static int vram_read_bufidx(ARTISTState *s)
255 if (s->cmap_bm_access) {
256 return (s->cmap_bm_access >> 12) & 0x0f;
257 } else {
258 return (s->src_bm_access >> 12) & 0x0f;
262 static struct vram_buffer *vram_read_buffer(ARTISTState *s)
264 return &s->vram_buffer[vram_read_bufidx(s)];
267 static struct vram_buffer *vram_write_buffer(ARTISTState *s)
269 return &s->vram_buffer[vram_write_bufidx(s)];
272 static uint8_t artist_get_color(ARTISTState *s)
274 if (s->image_bitmap_op & 2) {
275 return s->fg_color;
276 } else {
277 return s->bg_color;
281 static artist_rop_t artist_get_op(ARTISTState *s)
283 return (s->image_bitmap_op >> 8) & 0xf;
286 static void artist_rop8(ARTISTState *s, struct vram_buffer *buf,
287 unsigned int offset, uint8_t val)
289 const artist_rop_t op = artist_get_op(s);
290 uint8_t plane_mask;
291 uint8_t *dst;
293 if (offset >= buf->size) {
294 qemu_log_mask(LOG_GUEST_ERROR,
295 "rop8 offset:%u bufsize:%u\n", offset, buf->size);
296 return;
298 dst = buf->data + offset;
299 plane_mask = s->plane_mask & 0xff;
301 switch (op) {
302 case ARTIST_ROP_CLEAR:
303 *dst &= ~plane_mask;
304 break;
306 case ARTIST_ROP_COPY:
307 *dst = (*dst & ~plane_mask) | (val & plane_mask);
308 break;
310 case ARTIST_ROP_XOR:
311 *dst ^= val & plane_mask;
312 break;
314 case ARTIST_ROP_NOT_DST:
315 *dst ^= plane_mask;
316 break;
318 case ARTIST_ROP_SET:
319 *dst |= plane_mask;
320 break;
322 default:
323 qemu_log_mask(LOG_UNIMP, "%s: unsupported rop %d\n", __func__, op);
324 break;
328 static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y)
331 * Don't know whether these magic offset values are configurable via
332 * some register. They are the same for all resolutions, so don't
333 * bother about it.
336 *y = 0x47a - artist_get_y(s->cursor_pos);
337 *x = ((artist_get_x(s->cursor_pos) - 338) / 2);
339 if (*x > s->width) {
340 *x = 0;
343 if (*y > s->height) {
344 *y = 0;
348 static void artist_invalidate_cursor(ARTISTState *s)
350 int x, y;
351 artist_get_cursor_pos(s, &x, &y);
352 artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP],
353 y, s->cursor_height);
356 static void vram_bit_write(ARTISTState *s, int posy, bool incr_x,
357 int size, uint32_t data)
359 struct vram_buffer *buf;
360 uint32_t vram_bitmask = s->vram_bitmask;
361 int mask, i, pix_count, pix_length;
362 unsigned int posx, offset, width;
363 uint8_t *data8, *p;
365 pix_count = vram_write_pix_per_transfer(s);
366 pix_length = vram_pixel_length(s);
368 buf = vram_write_buffer(s);
369 width = buf->width;
371 if (s->cmap_bm_access) {
372 offset = s->vram_pos;
373 } else {
374 posx = ADDR_TO_X(s->vram_pos >> 2);
375 posy += ADDR_TO_Y(s->vram_pos >> 2);
376 offset = posy * width + posx;
379 if (!buf->size || offset >= buf->size) {
380 return;
383 p = buf->data;
385 if (pix_count > size * 8) {
386 pix_count = size * 8;
389 switch (pix_length) {
390 case 0:
391 if (s->image_bitmap_op & 0x20000000) {
392 data &= vram_bitmask;
395 for (i = 0; i < pix_count; i++) {
396 uint32_t off = offset + pix_count - 1 - i;
397 if (off < buf->size) {
398 artist_rop8(s, buf, off,
399 (data & 1) ? (s->plane_mask >> 24) : 0);
401 data >>= 1;
403 memory_region_set_dirty(&buf->mr, offset, pix_count);
404 break;
406 case 3:
407 if (s->cmap_bm_access) {
408 if (offset + 3 < buf->size) {
409 *(uint32_t *)(p + offset) = data;
411 break;
413 data8 = (uint8_t *)&data;
415 for (i = 3; i >= 0; i--) {
416 if (!(s->image_bitmap_op & 0x20000000) ||
417 s->vram_bitmask & (1 << (28 + i))) {
418 uint32_t off = offset + 3 - i;
419 if (off < buf->size) {
420 artist_rop8(s, buf, off, data8[ROP8OFF(i)]);
424 memory_region_set_dirty(&buf->mr, offset, 3);
425 break;
427 case 6:
428 switch (size) {
429 default:
430 case 4:
431 vram_bitmask = s->vram_bitmask;
432 break;
434 case 2:
435 vram_bitmask = s->vram_bitmask >> 16;
436 break;
438 case 1:
439 vram_bitmask = s->vram_bitmask >> 24;
440 break;
443 for (i = 0; i < pix_count && offset + i < buf->size; i++) {
444 mask = 1 << (pix_count - 1 - i);
446 if (!(s->image_bitmap_op & 0x20000000) ||
447 (vram_bitmask & mask)) {
448 if (data & mask) {
449 artist_rop8(s, buf, offset + i, s->fg_color);
450 } else {
451 if (!(s->image_bitmap_op & 0x10000002)) {
452 artist_rop8(s, buf, offset + i, s->bg_color);
457 memory_region_set_dirty(&buf->mr, offset, pix_count);
458 break;
460 default:
461 qemu_log_mask(LOG_UNIMP, "%s: unknown pixel length %d\n",
462 __func__, pix_length);
463 break;
466 if (incr_x) {
467 if (s->cmap_bm_access) {
468 s->vram_pos += 4;
469 } else {
470 s->vram_pos += pix_count << 2;
474 if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 ||
475 vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) {
476 artist_invalidate_cursor(s);
480 static void block_move(ARTISTState *s,
481 unsigned int source_x, unsigned int source_y,
482 unsigned int dest_x, unsigned int dest_y,
483 unsigned int width, unsigned int height)
485 struct vram_buffer *buf;
486 int line, endline, lineincr, startcolumn, endcolumn, columnincr, column;
487 unsigned int dst, src;
489 trace_artist_block_move(source_x, source_y, dest_x, dest_y, width, height);
491 if (s->control_plane != 0) {
492 /* We don't support CONTROL_PLANE accesses */
493 qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
494 s->control_plane);
495 return;
498 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
499 if (height > buf->height) {
500 height = buf->height;
502 if (width > buf->width) {
503 width = buf->width;
506 if (dest_y > source_y) {
507 /* move down */
508 line = height - 1;
509 endline = -1;
510 lineincr = -1;
511 } else {
512 /* move up */
513 line = 0;
514 endline = height;
515 lineincr = 1;
518 if (dest_x > source_x) {
519 /* move right */
520 startcolumn = width - 1;
521 endcolumn = -1;
522 columnincr = -1;
523 } else {
524 /* move left */
525 startcolumn = 0;
526 endcolumn = width;
527 columnincr = 1;
530 for ( ; line != endline; line += lineincr) {
531 src = source_x + ((line + source_y) * buf->width) + startcolumn;
532 dst = dest_x + ((line + dest_y) * buf->width) + startcolumn;
534 for (column = startcolumn; column != endcolumn; column += columnincr) {
535 if (dst >= buf->size || src >= buf->size) {
536 continue;
538 artist_rop8(s, buf, dst, buf->data[src]);
539 src += columnincr;
540 dst += columnincr;
544 artist_invalidate_lines(buf, dest_y, height);
547 static void fill_window(ARTISTState *s,
548 unsigned int startx, unsigned int starty,
549 unsigned int width, unsigned int height)
551 unsigned int offset;
552 uint8_t color = artist_get_color(s);
553 struct vram_buffer *buf;
554 int x, y;
556 trace_artist_fill_window(startx, starty, width, height,
557 s->image_bitmap_op, s->control_plane);
559 if (s->control_plane != 0) {
560 /* We don't support CONTROL_PLANE accesses */
561 qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
562 s->control_plane);
563 return;
566 if (s->reg_100080 == 0x7d) {
568 * Not sure what this register really does, but
569 * 0x7d seems to enable autoincremt of the Y axis
570 * by the current block move height.
572 height = artist_get_y(s->blockmove_size);
573 s->vram_start += height;
576 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
578 for (y = starty; y < starty + height; y++) {
579 offset = y * s->width;
581 for (x = startx; x < startx + width; x++) {
582 artist_rop8(s, buf, offset + x, color);
585 artist_invalidate_lines(buf, starty, height);
588 static void draw_line(ARTISTState *s,
589 unsigned int x1, unsigned int y1,
590 unsigned int x2, unsigned int y2,
591 bool update_start, int skip_pix, int max_pix)
593 struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
594 uint8_t color;
595 int dx, dy, t, e, x, y, incy, diago, horiz;
596 bool c1;
598 trace_artist_draw_line(x1, y1, x2, y2);
600 if ((x1 >= buf->width && x2 >= buf->width) ||
601 (y1 >= buf->height && y2 >= buf->height)) {
602 return;
606 if (update_start) {
607 s->vram_start = (x2 << 16) | y2;
610 if (x2 > x1) {
611 dx = x2 - x1;
612 } else {
613 dx = x1 - x2;
615 if (y2 > y1) {
616 dy = y2 - y1;
617 } else {
618 dy = y1 - y2;
621 c1 = false;
622 if (dy > dx) {
623 t = y2;
624 y2 = x2;
625 x2 = t;
627 t = y1;
628 y1 = x1;
629 x1 = t;
631 t = dx;
632 dx = dy;
633 dy = t;
635 c1 = true;
638 if (x1 > x2) {
639 t = y2;
640 y2 = y1;
641 y1 = t;
643 t = x1;
644 x1 = x2;
645 x2 = t;
648 horiz = dy << 1;
649 diago = (dy - dx) << 1;
650 e = (dy << 1) - dx;
652 if (y1 <= y2) {
653 incy = 1;
654 } else {
655 incy = -1;
657 x = x1;
658 y = y1;
659 color = artist_get_color(s);
661 do {
662 unsigned int ofs;
664 if (c1) {
665 ofs = x * s->width + y;
666 } else {
667 ofs = y * s->width + x;
670 if (skip_pix > 0) {
671 skip_pix--;
672 } else {
673 artist_rop8(s, buf, ofs, color);
676 if (e > 0) {
677 y += incy;
678 e += diago;
679 } else {
680 e += horiz;
682 x++;
683 } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
684 if (c1)
685 artist_invalidate_lines(buf, x, dy+1);
686 else
687 artist_invalidate_lines(buf, y, dx+1);
690 static void draw_line_pattern_start(ARTISTState *s)
693 int startx = artist_get_x(s->vram_start);
694 int starty = artist_get_y(s->vram_start);
695 int endx = artist_get_x(s->blockmove_size);
696 int endy = artist_get_y(s->blockmove_size);
697 int pstart = s->line_pattern_start >> 16;
699 draw_line(s, startx, starty, endx, endy, false, -1, pstart);
700 s->line_pattern_skip = pstart;
703 static void draw_line_pattern_next(ARTISTState *s)
706 int startx = artist_get_x(s->vram_start);
707 int starty = artist_get_y(s->vram_start);
708 int endx = artist_get_x(s->blockmove_size);
709 int endy = artist_get_y(s->blockmove_size);
710 int line_xy = s->line_xy >> 16;
712 draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip,
713 s->line_pattern_skip + line_xy);
714 s->line_pattern_skip += line_xy;
715 s->image_bitmap_op ^= 2;
718 static void draw_line_size(ARTISTState *s, bool update_start)
721 int startx = artist_get_x(s->vram_start);
722 int starty = artist_get_y(s->vram_start);
723 int endx = artist_get_x(s->line_size);
724 int endy = artist_get_y(s->line_size);
726 draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
729 static void draw_line_xy(ARTISTState *s, bool update_start)
732 int startx = artist_get_x(s->vram_start);
733 int starty = artist_get_y(s->vram_start);
734 int sizex = artist_get_x(s->blockmove_size);
735 int sizey = artist_get_y(s->blockmove_size);
736 int linexy = s->line_xy >> 16;
737 int endx, endy;
739 endx = startx;
740 endy = starty;
742 if (sizex > 0) {
743 endx = startx + linexy;
746 if (sizex < 0) {
747 endx = startx;
748 startx -= linexy;
751 if (sizey > 0) {
752 endy = starty + linexy;
755 if (sizey < 0) {
756 endy = starty;
757 starty -= linexy;
760 if (startx < 0) {
761 startx = 0;
764 if (endx < 0) {
765 endx = 0;
768 if (starty < 0) {
769 starty = 0;
772 if (endy < 0) {
773 endy = 0;
776 draw_line(s, startx, starty, endx, endy, false, -1, -1);
779 static void draw_line_end(ARTISTState *s, bool update_start)
782 int startx = artist_get_x(s->vram_start);
783 int starty = artist_get_y(s->vram_start);
784 int endx = artist_get_x(s->line_end);
785 int endy = artist_get_y(s->line_end);
787 draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
790 static void font_write16(ARTISTState *s, uint16_t val)
792 struct vram_buffer *buf;
793 uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color;
794 uint16_t mask;
795 int i;
797 unsigned int startx = artist_get_x(s->vram_start);
798 unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y;
799 unsigned int offset = starty * s->width + startx;
801 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
803 if (startx >= buf->width || starty >= buf->height ||
804 offset + 16 >= buf->size) {
805 return;
808 for (i = 0; i < 16; i++) {
809 mask = 1 << (15 - i);
810 if (val & mask) {
811 artist_rop8(s, buf, offset + i, color);
812 } else {
813 if (!(s->image_bitmap_op & 0x20000000)) {
814 artist_rop8(s, buf, offset + i, s->bg_color);
818 artist_invalidate_lines(buf, starty, 1);
821 static void font_write(ARTISTState *s, uint32_t val)
823 font_write16(s, val >> 16);
824 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
825 s->vram_start += (s->blockmove_size & 0xffff0000);
826 return;
829 font_write16(s, val & 0xffff);
830 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
831 s->vram_start += (s->blockmove_size & 0xffff0000);
832 return;
836 static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
839 * FIXME: is there a qemu helper for this?
842 #ifndef HOST_WORDS_BIGENDIAN
843 addr ^= 3;
844 #endif
846 switch (size) {
847 case 1:
848 *(uint8_t *)(out + (addr & 3)) = val;
849 break;
851 case 2:
852 *(uint16_t *)(out + (addr & 2)) = val;
853 break;
855 case 4:
856 *(uint32_t *)out = val;
857 break;
859 default:
860 qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size);
864 static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
865 unsigned size)
867 ARTISTState *s = opaque;
868 int width, height;
870 trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val);
872 switch (addr & ~3ULL) {
873 case 0x100080:
874 combine_write_reg(addr, val, size, &s->reg_100080);
875 break;
877 case FG_COLOR:
878 combine_write_reg(addr, val, size, &s->fg_color);
879 break;
881 case BG_COLOR:
882 combine_write_reg(addr, val, size, &s->bg_color);
883 break;
885 case VRAM_BITMASK:
886 combine_write_reg(addr, val, size, &s->vram_bitmask);
887 break;
889 case VRAM_WRITE_INCR_Y:
890 vram_bit_write(s, s->vram_char_y++, false, size, val);
891 break;
893 case VRAM_WRITE_INCR_X:
894 case VRAM_WRITE_INCR_X2:
895 vram_bit_write(s, s->vram_char_y, true, size, val);
896 break;
898 case VRAM_IDX:
899 combine_write_reg(addr, val, size, &s->vram_pos);
900 s->vram_char_y = 0;
901 s->draw_line_pattern = 0;
902 break;
904 case VRAM_START:
905 combine_write_reg(addr, val, size, &s->vram_start);
906 s->draw_line_pattern = 0;
907 break;
909 case VRAM_START_TRIGGER:
910 combine_write_reg(addr, val, size, &s->vram_start);
911 fill_window(s, artist_get_x(s->vram_start),
912 artist_get_y(s->vram_start),
913 artist_get_x(s->blockmove_size),
914 artist_get_y(s->blockmove_size));
915 break;
917 case VRAM_SIZE_TRIGGER:
918 combine_write_reg(addr, val, size, &s->vram_size);
920 if (size == 2 && !(addr & 2)) {
921 height = artist_get_y(s->blockmove_size);
922 } else {
923 height = artist_get_y(s->vram_size);
926 if (size == 2 && (addr & 2)) {
927 width = artist_get_x(s->blockmove_size);
928 } else {
929 width = artist_get_x(s->vram_size);
932 fill_window(s, artist_get_x(s->vram_start),
933 artist_get_y(s->vram_start),
934 width, height);
935 break;
937 case LINE_XY:
938 combine_write_reg(addr, val, size, &s->line_xy);
939 if (s->draw_line_pattern) {
940 draw_line_pattern_next(s);
941 } else {
942 draw_line_xy(s, true);
944 break;
946 case PATTERN_LINE_START:
947 combine_write_reg(addr, val, size, &s->line_pattern_start);
948 s->draw_line_pattern = 1;
949 draw_line_pattern_start(s);
950 break;
952 case LINE_SIZE:
953 combine_write_reg(addr, val, size, &s->line_size);
954 draw_line_size(s, true);
955 break;
957 case LINE_END:
958 combine_write_reg(addr, val, size, &s->line_end);
959 draw_line_end(s, true);
960 break;
962 case BLOCK_MOVE_SIZE:
963 combine_write_reg(addr, val, size, &s->blockmove_size);
964 break;
966 case BLOCK_MOVE_SOURCE:
967 combine_write_reg(addr, val, size, &s->blockmove_source);
968 break;
970 case BLOCK_MOVE_DEST_TRIGGER:
971 combine_write_reg(addr, val, size, &s->blockmove_dest);
973 block_move(s, artist_get_x(s->blockmove_source),
974 artist_get_y(s->blockmove_source),
975 artist_get_x(s->blockmove_dest),
976 artist_get_y(s->blockmove_dest),
977 artist_get_x(s->blockmove_size),
978 artist_get_y(s->blockmove_size));
979 break;
981 case BLOCK_MOVE_SIZE_TRIGGER:
982 combine_write_reg(addr, val, size, &s->blockmove_size);
984 block_move(s,
985 artist_get_x(s->blockmove_source),
986 artist_get_y(s->blockmove_source),
987 artist_get_x(s->vram_start),
988 artist_get_y(s->vram_start),
989 artist_get_x(s->blockmove_size),
990 artist_get_y(s->blockmove_size));
991 break;
993 case PLANE_MASK:
994 combine_write_reg(addr, val, size, &s->plane_mask);
995 break;
997 case CMAP_BM_ACCESS:
998 combine_write_reg(addr, val, size, &s->cmap_bm_access);
999 break;
1001 case DST_BM_ACCESS:
1002 combine_write_reg(addr, val, size, &s->dst_bm_access);
1003 s->cmap_bm_access = 0;
1004 break;
1006 case SRC_BM_ACCESS:
1007 combine_write_reg(addr, val, size, &s->src_bm_access);
1008 s->cmap_bm_access = 0;
1009 break;
1011 case CONTROL_PLANE:
1012 combine_write_reg(addr, val, size, &s->control_plane);
1013 break;
1015 case TRANSFER_DATA:
1016 combine_write_reg(addr, val, size, &s->transfer_data);
1017 break;
1019 case 0x300200:
1020 combine_write_reg(addr, val, size, &s->reg_300200);
1021 break;
1023 case 0x300208:
1024 combine_write_reg(addr, val, size, &s->reg_300208);
1025 break;
1027 case 0x300218:
1028 combine_write_reg(addr, val, size, &s->reg_300218);
1029 break;
1031 case CURSOR_POS:
1032 artist_invalidate_cursor(s);
1033 combine_write_reg(addr, val, size, &s->cursor_pos);
1034 artist_invalidate_cursor(s);
1035 break;
1037 case CURSOR_CTRL:
1038 break;
1040 case IMAGE_BITMAP_OP:
1041 combine_write_reg(addr, val, size, &s->image_bitmap_op);
1042 break;
1044 case FONT_WRITE_INCR_Y:
1045 combine_write_reg(addr, val, size, &s->font_write1);
1046 font_write(s, s->font_write1);
1047 break;
1049 case FONT_WRITE_START:
1050 combine_write_reg(addr, val, size, &s->font_write2);
1051 s->font_write_pos_y = 0;
1052 font_write(s, s->font_write2);
1053 break;
1055 case 300104:
1056 break;
1058 default:
1059 qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx
1060 " val=%08" PRIx64 " size=%d\n",
1061 __func__, addr, val, size);
1062 break;
1066 static uint64_t combine_read_reg(hwaddr addr, int size, void *in)
1069 * FIXME: is there a qemu helper for this?
1072 #ifndef HOST_WORDS_BIGENDIAN
1073 addr ^= 3;
1074 #endif
1076 switch (size) {
1077 case 1:
1078 return *(uint8_t *)(in + (addr & 3));
1080 case 2:
1081 return *(uint16_t *)(in + (addr & 2));
1083 case 4:
1084 return *(uint32_t *)in;
1086 default:
1087 qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size);
1088 return 0;
1092 static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
1094 ARTISTState *s = opaque;
1095 uint32_t val = 0;
1097 switch (addr & ~3ULL) {
1098 /* Unknown status registers */
1099 case 0:
1100 break;
1102 case 0x211110:
1103 val = (s->width << 16) | s->height;
1104 if (s->depth == 1) {
1105 val |= 1 << 31;
1107 break;
1109 case 0x100000:
1110 case 0x300000:
1111 case 0x300004:
1112 case 0x300308:
1113 case 0x380000:
1114 break;
1116 case 0x300008:
1117 case 0x380008:
1119 * FIFO ready flag. we're not emulating the FIFOs
1120 * so we're always ready
1122 val = 0x10;
1123 break;
1125 case 0x300200:
1126 val = s->reg_300200;
1127 break;
1129 case 0x300208:
1130 val = s->reg_300208;
1131 break;
1133 case 0x300218:
1134 val = s->reg_300218;
1135 break;
1137 case 0x30023c:
1138 val = 0xac4ffdac;
1139 break;
1141 case 0x380004:
1142 /* 0x02000000 Buserror */
1143 val = 0x6dc20006;
1144 break;
1146 default:
1147 qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx
1148 " size %d\n", __func__, addr, size);
1149 break;
1151 val = combine_read_reg(addr, size, &val);
1152 trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val);
1153 return val;
1156 static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
1157 unsigned size)
1159 ARTISTState *s = opaque;
1160 struct vram_buffer *buf;
1161 unsigned int posy, posx;
1162 unsigned int offset;
1163 trace_artist_vram_write(size, addr, val);
1165 if (s->cmap_bm_access) {
1166 buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1167 if (addr + 3 < buf->size) {
1168 *(uint32_t *)(buf->data + addr) = val;
1170 return;
1173 buf = vram_write_buffer(s);
1174 posy = ADDR_TO_Y(addr);
1175 posx = ADDR_TO_X(addr);
1177 if (!buf->size) {
1178 return;
1181 if (posy > buf->height || posx > buf->width) {
1182 return;
1185 offset = posy * buf->width + posx;
1186 if (offset >= buf->size) {
1187 return;
1190 switch (size) {
1191 case 4:
1192 if (offset + 3 < buf->size) {
1193 *(uint32_t *)(buf->data + offset) = be32_to_cpu(val);
1194 memory_region_set_dirty(&buf->mr, offset, 4);
1196 break;
1197 case 2:
1198 if (offset + 1 < buf->size) {
1199 *(uint16_t *)(buf->data + offset) = be16_to_cpu(val);
1200 memory_region_set_dirty(&buf->mr, offset, 2);
1202 break;
1203 case 1:
1204 if (offset < buf->size) {
1205 *(uint8_t *)(buf->data + offset) = val;
1206 memory_region_set_dirty(&buf->mr, offset, 1);
1208 break;
1209 default:
1210 break;
1214 static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
1216 ARTISTState *s = opaque;
1217 struct vram_buffer *buf;
1218 uint64_t val;
1219 unsigned int posy, posx;
1221 if (s->cmap_bm_access) {
1222 buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1223 val = 0;
1224 if (addr < buf->size && addr + 3 < buf->size) {
1225 val = *(uint32_t *)(buf->data + addr);
1227 trace_artist_vram_read(size, addr, 0, 0, val);
1228 return val;
1231 buf = vram_read_buffer(s);
1232 if (!buf->size) {
1233 return 0;
1236 posy = ADDR_TO_Y(addr);
1237 posx = ADDR_TO_X(addr);
1239 if (posy > buf->height || posx > buf->width) {
1240 return 0;
1243 val = cpu_to_be32(*(uint32_t *)(buf->data + posy * buf->width + posx));
1244 trace_artist_vram_read(size, addr, posx, posy, val);
1245 return val;
1248 static const MemoryRegionOps artist_reg_ops = {
1249 .read = artist_reg_read,
1250 .write = artist_reg_write,
1251 .endianness = DEVICE_NATIVE_ENDIAN,
1252 .impl.min_access_size = 1,
1253 .impl.max_access_size = 4,
1256 static const MemoryRegionOps artist_vram_ops = {
1257 .read = artist_vram_read,
1258 .write = artist_vram_write,
1259 .endianness = DEVICE_NATIVE_ENDIAN,
1260 .impl.min_access_size = 1,
1261 .impl.max_access_size = 4,
1264 static void artist_draw_cursor(ARTISTState *s)
1266 DisplaySurface *surface = qemu_console_surface(s->con);
1267 uint32_t *data = (uint32_t *)surface_data(surface);
1268 struct vram_buffer *cursor0, *cursor1 , *buf;
1269 int cx, cy, cursor_pos_x, cursor_pos_y;
1271 cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1];
1272 cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2];
1273 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1275 artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y);
1277 for (cy = 0; cy < s->cursor_height; cy++) {
1279 for (cx = 0; cx < s->cursor_width; cx++) {
1281 if (cursor_pos_y + cy < 0 ||
1282 cursor_pos_x + cx < 0 ||
1283 cursor_pos_y + cy > buf->height - 1 ||
1284 cursor_pos_x + cx > buf->width) {
1285 continue;
1288 int dstoffset = (cursor_pos_y + cy) * s->width +
1289 (cursor_pos_x + cx);
1291 if (cursor0->data[cy * cursor0->width + cx]) {
1292 data[dstoffset] = 0;
1293 } else {
1294 if (cursor1->data[cy * cursor1->width + cx]) {
1295 data[dstoffset] = 0xffffff;
1302 static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
1303 int width, int pitch)
1305 ARTISTState *s = ARTIST(opaque);
1306 uint32_t *cmap, *data = (uint32_t *)d;
1307 int x;
1309 cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400);
1311 for (x = 0; x < s->width; x++) {
1312 *data++ = cmap[*src++];
1316 static void artist_update_display(void *opaque)
1318 ARTISTState *s = opaque;
1319 DisplaySurface *surface = qemu_console_surface(s->con);
1320 int first = 0, last;
1323 framebuffer_update_display(surface, &s->fbsection, s->width, s->height,
1324 s->width, s->width * 4, 0, 0, artist_draw_line,
1325 s, &first, &last);
1327 artist_draw_cursor(s);
1329 dpy_gfx_update(s->con, 0, 0, s->width, s->height);
1332 static void artist_invalidate(void *opaque)
1334 ARTISTState *s = ARTIST(opaque);
1335 struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1336 memory_region_set_dirty(&buf->mr, 0, buf->size);
1339 static const GraphicHwOps artist_ops = {
1340 .invalidate = artist_invalidate,
1341 .gfx_update = artist_update_display,
1344 static void artist_initfn(Object *obj)
1346 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1347 ARTISTState *s = ARTIST(obj);
1349 memory_region_init_io(&s->reg, obj, &artist_reg_ops, s, "artist.reg",
1350 4 * MiB);
1351 memory_region_init_io(&s->vram_mem, obj, &artist_vram_ops, s, "artist.vram",
1352 8 * MiB);
1353 sysbus_init_mmio(sbd, &s->reg);
1354 sysbus_init_mmio(sbd, &s->vram_mem);
1357 static void artist_create_buffer(ARTISTState *s, const char *name,
1358 hwaddr *offset, unsigned int idx,
1359 int width, int height)
1361 struct vram_buffer *buf = s->vram_buffer + idx;
1363 memory_region_init_ram(&buf->mr, NULL, name, width * height,
1364 &error_fatal);
1365 memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0);
1367 buf->data = memory_region_get_ram_ptr(&buf->mr);
1368 buf->size = height * width;
1369 buf->width = width;
1370 buf->height = height;
1372 *offset += buf->size;
1375 static void artist_realizefn(DeviceState *dev, Error **errp)
1377 ARTISTState *s = ARTIST(dev);
1378 struct vram_buffer *buf;
1379 hwaddr offset = 0;
1381 if (s->width > 2048 || s->height > 2048) {
1382 error_report("artist: screen size can not exceed 2048 x 2048 pixel.");
1383 s->width = MIN(s->width, 2048);
1384 s->height = MIN(s->height, 2048);
1387 if (s->width < 640 || s->height < 480) {
1388 error_report("artist: minimum screen size is 640 x 480 pixel.");
1389 s->width = MAX(s->width, 640);
1390 s->height = MAX(s->height, 480);
1393 memory_region_init(&s->mem_as_root, OBJECT(dev), "artist", ~0ull);
1394 address_space_init(&s->as, &s->mem_as_root, "artist");
1396 artist_create_buffer(s, "cmap", &offset, ARTIST_BUFFER_CMAP, 2048, 4);
1397 artist_create_buffer(s, "ap", &offset, ARTIST_BUFFER_AP,
1398 s->width, s->height);
1399 artist_create_buffer(s, "cursor1", &offset, ARTIST_BUFFER_CURSOR1, 64, 64);
1400 artist_create_buffer(s, "cursor2", &offset, ARTIST_BUFFER_CURSOR2, 64, 64);
1401 artist_create_buffer(s, "attribute", &offset, ARTIST_BUFFER_ATTRIBUTE,
1402 64, 64);
1404 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1405 framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0,
1406 buf->width, buf->height);
1408 * no idea whether the cursor is fixed size or not, so assume 32x32 which
1409 * seems sufficient for HP-UX X11.
1411 s->cursor_height = 32;
1412 s->cursor_width = 32;
1414 s->con = graphic_console_init(dev, 0, &artist_ops, s);
1415 qemu_console_resize(s->con, s->width, s->height);
1418 static int vmstate_artist_post_load(void *opaque, int version_id)
1420 artist_invalidate(opaque);
1421 return 0;
1424 static const VMStateDescription vmstate_artist = {
1425 .name = "artist",
1426 .version_id = 1,
1427 .minimum_version_id = 1,
1428 .post_load = vmstate_artist_post_load,
1429 .fields = (VMStateField[]) {
1430 VMSTATE_UINT16(height, ARTISTState),
1431 VMSTATE_UINT16(width, ARTISTState),
1432 VMSTATE_UINT16(depth, ARTISTState),
1433 VMSTATE_UINT32(fg_color, ARTISTState),
1434 VMSTATE_UINT32(bg_color, ARTISTState),
1435 VMSTATE_UINT32(vram_char_y, ARTISTState),
1436 VMSTATE_UINT32(vram_bitmask, ARTISTState),
1437 VMSTATE_UINT32(vram_start, ARTISTState),
1438 VMSTATE_UINT32(vram_pos, ARTISTState),
1439 VMSTATE_UINT32(vram_size, ARTISTState),
1440 VMSTATE_UINT32(blockmove_source, ARTISTState),
1441 VMSTATE_UINT32(blockmove_dest, ARTISTState),
1442 VMSTATE_UINT32(blockmove_size, ARTISTState),
1443 VMSTATE_UINT32(line_size, ARTISTState),
1444 VMSTATE_UINT32(line_end, ARTISTState),
1445 VMSTATE_UINT32(line_xy, ARTISTState),
1446 VMSTATE_UINT32(cursor_pos, ARTISTState),
1447 VMSTATE_UINT32(cursor_height, ARTISTState),
1448 VMSTATE_UINT32(cursor_width, ARTISTState),
1449 VMSTATE_UINT32(plane_mask, ARTISTState),
1450 VMSTATE_UINT32(reg_100080, ARTISTState),
1451 VMSTATE_UINT32(reg_300200, ARTISTState),
1452 VMSTATE_UINT32(reg_300208, ARTISTState),
1453 VMSTATE_UINT32(reg_300218, ARTISTState),
1454 VMSTATE_UINT32(cmap_bm_access, ARTISTState),
1455 VMSTATE_UINT32(dst_bm_access, ARTISTState),
1456 VMSTATE_UINT32(src_bm_access, ARTISTState),
1457 VMSTATE_UINT32(control_plane, ARTISTState),
1458 VMSTATE_UINT32(transfer_data, ARTISTState),
1459 VMSTATE_UINT32(image_bitmap_op, ARTISTState),
1460 VMSTATE_UINT32(font_write1, ARTISTState),
1461 VMSTATE_UINT32(font_write2, ARTISTState),
1462 VMSTATE_UINT32(font_write_pos_y, ARTISTState),
1463 VMSTATE_END_OF_LIST()
1467 static Property artist_properties[] = {
1468 DEFINE_PROP_UINT16("width", ARTISTState, width, 1280),
1469 DEFINE_PROP_UINT16("height", ARTISTState, height, 1024),
1470 DEFINE_PROP_UINT16("depth", ARTISTState, depth, 8),
1471 DEFINE_PROP_END_OF_LIST(),
1474 static void artist_reset(DeviceState *qdev)
1478 static void artist_class_init(ObjectClass *klass, void *data)
1480 DeviceClass *dc = DEVICE_CLASS(klass);
1482 dc->realize = artist_realizefn;
1483 dc->vmsd = &vmstate_artist;
1484 dc->reset = artist_reset;
1485 device_class_set_props(dc, artist_properties);
1488 static const TypeInfo artist_info = {
1489 .name = TYPE_ARTIST,
1490 .parent = TYPE_SYS_BUS_DEVICE,
1491 .instance_size = sizeof(ARTISTState),
1492 .instance_init = artist_initfn,
1493 .class_init = artist_class_init,
1496 static void artist_register_types(void)
1498 type_register_static(&artist_info);
1501 type_init(artist_register_types)