exec/memory: Use struct Object typedef
[qemu/ar7.git] / hw / display / artist.c
blobaa7bd594aac0d09e144d48904a1b31dd5f65954b
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/log.h"
13 #include "qemu/module.h"
14 #include "qemu/units.h"
15 #include "qapi/error.h"
16 #include "hw/sysbus.h"
17 #include "hw/loader.h"
18 #include "hw/qdev-core.h"
19 #include "hw/qdev-properties.h"
20 #include "migration/vmstate.h"
21 #include "ui/console.h"
22 #include "trace.h"
23 #include "framebuffer.h"
24 #include "qom/object.h"
26 #define TYPE_ARTIST "artist"
27 OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState, ARTIST)
29 #ifdef HOST_WORDS_BIGENDIAN
30 #define ROP8OFF(_i) (3 - (_i))
31 #else
32 #define ROP8OFF
33 #endif
35 struct vram_buffer {
36 MemoryRegion mr;
37 uint8_t *data;
38 unsigned int size;
39 unsigned int width;
40 unsigned int height;
43 struct ARTISTState {
44 SysBusDevice parent_obj;
46 QemuConsole *con;
47 MemoryRegion vram_mem;
48 MemoryRegion mem_as_root;
49 MemoryRegion reg;
50 MemoryRegionSection fbsection;
52 void *vram_int_mr;
53 AddressSpace as;
55 struct vram_buffer vram_buffer[16];
57 uint16_t width;
58 uint16_t height;
59 uint16_t depth;
61 uint32_t fg_color;
62 uint32_t bg_color;
64 uint32_t vram_char_y;
65 uint32_t vram_bitmask;
67 uint32_t vram_start;
68 uint32_t vram_pos;
70 uint32_t vram_size;
72 uint32_t blockmove_source;
73 uint32_t blockmove_dest;
74 uint32_t blockmove_size;
76 uint32_t line_size;
77 uint32_t line_end;
78 uint32_t line_xy;
79 uint32_t line_pattern_start;
80 uint32_t line_pattern_skip;
82 uint32_t cursor_pos;
84 uint32_t cursor_height;
85 uint32_t cursor_width;
87 uint32_t plane_mask;
89 uint32_t reg_100080;
90 uint32_t reg_300200;
91 uint32_t reg_300208;
92 uint32_t reg_300218;
94 uint32_t cmap_bm_access;
95 uint32_t dst_bm_access;
96 uint32_t src_bm_access;
97 uint32_t control_plane;
98 uint32_t transfer_data;
99 uint32_t image_bitmap_op;
101 uint32_t font_write1;
102 uint32_t font_write2;
103 uint32_t font_write_pos_y;
105 int draw_line_pattern;
108 typedef enum {
109 ARTIST_BUFFER_AP = 1,
110 ARTIST_BUFFER_OVERLAY = 2,
111 ARTIST_BUFFER_CURSOR1 = 6,
112 ARTIST_BUFFER_CURSOR2 = 7,
113 ARTIST_BUFFER_ATTRIBUTE = 13,
114 ARTIST_BUFFER_CMAP = 15,
115 } artist_buffer_t;
117 typedef enum {
118 VRAM_IDX = 0x1004a0,
119 VRAM_BITMASK = 0x1005a0,
120 VRAM_WRITE_INCR_X = 0x100600,
121 VRAM_WRITE_INCR_X2 = 0x100604,
122 VRAM_WRITE_INCR_Y = 0x100620,
123 VRAM_START = 0x100800,
124 BLOCK_MOVE_SIZE = 0x100804,
125 BLOCK_MOVE_SOURCE = 0x100808,
126 TRANSFER_DATA = 0x100820,
127 FONT_WRITE_INCR_Y = 0x1008a0,
128 VRAM_START_TRIGGER = 0x100a00,
129 VRAM_SIZE_TRIGGER = 0x100a04,
130 FONT_WRITE_START = 0x100aa0,
131 BLOCK_MOVE_DEST_TRIGGER = 0x100b00,
132 BLOCK_MOVE_SIZE_TRIGGER = 0x100b04,
133 LINE_XY = 0x100ccc,
134 PATTERN_LINE_START = 0x100ecc,
135 LINE_SIZE = 0x100e04,
136 LINE_END = 0x100e44,
137 CMAP_BM_ACCESS = 0x118000,
138 DST_BM_ACCESS = 0x118004,
139 SRC_BM_ACCESS = 0x118008,
140 CONTROL_PLANE = 0x11800c,
141 FG_COLOR = 0x118010,
142 BG_COLOR = 0x118014,
143 PLANE_MASK = 0x118018,
144 IMAGE_BITMAP_OP = 0x11801c,
145 CURSOR_POS = 0x300100,
146 CURSOR_CTRL = 0x300104,
147 } artist_reg_t;
149 typedef enum {
150 ARTIST_ROP_CLEAR = 0,
151 ARTIST_ROP_COPY = 3,
152 ARTIST_ROP_XOR = 6,
153 ARTIST_ROP_NOT_DST = 10,
154 ARTIST_ROP_SET = 15,
155 } artist_rop_t;
157 #define REG_NAME(_x) case _x: return " "#_x;
158 static const char *artist_reg_name(uint64_t addr)
160 switch ((artist_reg_t)addr) {
161 REG_NAME(VRAM_IDX);
162 REG_NAME(VRAM_BITMASK);
163 REG_NAME(VRAM_WRITE_INCR_X);
164 REG_NAME(VRAM_WRITE_INCR_X2);
165 REG_NAME(VRAM_WRITE_INCR_Y);
166 REG_NAME(VRAM_START);
167 REG_NAME(BLOCK_MOVE_SIZE);
168 REG_NAME(BLOCK_MOVE_SOURCE);
169 REG_NAME(FG_COLOR);
170 REG_NAME(BG_COLOR);
171 REG_NAME(PLANE_MASK);
172 REG_NAME(VRAM_START_TRIGGER);
173 REG_NAME(VRAM_SIZE_TRIGGER);
174 REG_NAME(BLOCK_MOVE_DEST_TRIGGER);
175 REG_NAME(BLOCK_MOVE_SIZE_TRIGGER);
176 REG_NAME(TRANSFER_DATA);
177 REG_NAME(CONTROL_PLANE);
178 REG_NAME(IMAGE_BITMAP_OP);
179 REG_NAME(CMAP_BM_ACCESS);
180 REG_NAME(DST_BM_ACCESS);
181 REG_NAME(SRC_BM_ACCESS);
182 REG_NAME(CURSOR_POS);
183 REG_NAME(CURSOR_CTRL);
184 REG_NAME(LINE_XY);
185 REG_NAME(PATTERN_LINE_START);
186 REG_NAME(LINE_SIZE);
187 REG_NAME(LINE_END);
188 REG_NAME(FONT_WRITE_INCR_Y);
189 REG_NAME(FONT_WRITE_START);
191 return "";
193 #undef REG_NAME
195 /* artist has a fixed line length of 2048 bytes. */
196 #define ADDR_TO_Y(addr) extract32(addr, 11, 11)
197 #define ADDR_TO_X(addr) extract32(addr, 0, 11)
199 static int16_t artist_get_x(uint32_t reg)
201 return reg >> 16;
204 static int16_t artist_get_y(uint32_t reg)
206 return reg & 0xffff;
209 static void artist_invalidate_lines(struct vram_buffer *buf,
210 int starty, int height)
212 int start = starty * buf->width;
213 int size;
215 if (starty + height > buf->height)
216 height = buf->height - starty;
218 size = height * buf->width;
220 if (start + size <= buf->size) {
221 memory_region_set_dirty(&buf->mr, start, size);
225 static int vram_write_pix_per_transfer(ARTISTState *s)
227 if (s->cmap_bm_access) {
228 return 1 << ((s->cmap_bm_access >> 27) & 0x0f);
229 } else {
230 return 1 << ((s->dst_bm_access >> 27) & 0x0f);
234 static int vram_pixel_length(ARTISTState *s)
236 if (s->cmap_bm_access) {
237 return (s->cmap_bm_access >> 24) & 0x07;
238 } else {
239 return (s->dst_bm_access >> 24) & 0x07;
243 static int vram_write_bufidx(ARTISTState *s)
245 if (s->cmap_bm_access) {
246 return (s->cmap_bm_access >> 12) & 0x0f;
247 } else {
248 return (s->dst_bm_access >> 12) & 0x0f;
252 static int vram_read_bufidx(ARTISTState *s)
254 if (s->cmap_bm_access) {
255 return (s->cmap_bm_access >> 12) & 0x0f;
256 } else {
257 return (s->src_bm_access >> 12) & 0x0f;
261 static struct vram_buffer *vram_read_buffer(ARTISTState *s)
263 return &s->vram_buffer[vram_read_bufidx(s)];
266 static struct vram_buffer *vram_write_buffer(ARTISTState *s)
268 return &s->vram_buffer[vram_write_bufidx(s)];
271 static uint8_t artist_get_color(ARTISTState *s)
273 if (s->image_bitmap_op & 2) {
274 return s->fg_color;
275 } else {
276 return s->bg_color;
280 static artist_rop_t artist_get_op(ARTISTState *s)
282 return (s->image_bitmap_op >> 8) & 0xf;
285 static void artist_rop8(ARTISTState *s, struct vram_buffer *buf,
286 unsigned int offset, uint8_t val)
288 const artist_rop_t op = artist_get_op(s);
289 uint8_t plane_mask;
290 uint8_t *dst;
292 if (offset >= buf->size) {
293 qemu_log_mask(LOG_GUEST_ERROR,
294 "rop8 offset:%u bufsize:%u\n", offset, buf->size);
295 return;
297 dst = buf->data + offset;
298 plane_mask = s->plane_mask & 0xff;
300 switch (op) {
301 case ARTIST_ROP_CLEAR:
302 *dst &= ~plane_mask;
303 break;
305 case ARTIST_ROP_COPY:
306 *dst = (*dst & ~plane_mask) | (val & plane_mask);
307 break;
309 case ARTIST_ROP_XOR:
310 *dst ^= val & plane_mask;
311 break;
313 case ARTIST_ROP_NOT_DST:
314 *dst ^= plane_mask;
315 break;
317 case ARTIST_ROP_SET:
318 *dst |= plane_mask;
319 break;
321 default:
322 qemu_log_mask(LOG_UNIMP, "%s: unsupported rop %d\n", __func__, op);
323 break;
327 static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y)
330 * Don't know whether these magic offset values are configurable via
331 * some register. They are the same for all resolutions, so don't
332 * bother about it.
335 *y = 0x47a - artist_get_y(s->cursor_pos);
336 *x = ((artist_get_x(s->cursor_pos) - 338) / 2);
338 if (*x > s->width) {
339 *x = 0;
342 if (*y > s->height) {
343 *y = 0;
347 static void artist_invalidate_cursor(ARTISTState *s)
349 int x, y;
350 artist_get_cursor_pos(s, &x, &y);
351 artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP],
352 y, s->cursor_height);
355 static void vram_bit_write(ARTISTState *s, int posy, bool incr_x,
356 int size, uint32_t data)
358 struct vram_buffer *buf;
359 uint32_t vram_bitmask = s->vram_bitmask;
360 int mask, i, pix_count, pix_length;
361 unsigned int posx, offset, width;
362 uint8_t *data8, *p;
364 pix_count = vram_write_pix_per_transfer(s);
365 pix_length = vram_pixel_length(s);
367 buf = vram_write_buffer(s);
368 width = buf->width;
370 if (s->cmap_bm_access) {
371 offset = s->vram_pos;
372 } else {
373 posx = ADDR_TO_X(s->vram_pos >> 2);
374 posy += ADDR_TO_Y(s->vram_pos >> 2);
375 offset = posy * width + posx;
378 if (!buf->size || offset >= buf->size) {
379 return;
382 p = buf->data;
384 if (pix_count > size * 8) {
385 pix_count = size * 8;
388 switch (pix_length) {
389 case 0:
390 if (s->image_bitmap_op & 0x20000000) {
391 data &= vram_bitmask;
394 for (i = 0; i < pix_count; i++) {
395 uint32_t off = offset + pix_count - 1 - i;
396 if (off < buf->size) {
397 artist_rop8(s, buf, off,
398 (data & 1) ? (s->plane_mask >> 24) : 0);
400 data >>= 1;
402 memory_region_set_dirty(&buf->mr, offset, pix_count);
403 break;
405 case 3:
406 if (s->cmap_bm_access) {
407 if (offset + 3 < buf->size) {
408 *(uint32_t *)(p + offset) = data;
410 break;
412 data8 = (uint8_t *)&data;
414 for (i = 3; i >= 0; i--) {
415 if (!(s->image_bitmap_op & 0x20000000) ||
416 s->vram_bitmask & (1 << (28 + i))) {
417 uint32_t off = offset + 3 - i;
418 if (off < buf->size) {
419 artist_rop8(s, buf, off, data8[ROP8OFF(i)]);
423 memory_region_set_dirty(&buf->mr, offset, 3);
424 break;
426 case 6:
427 switch (size) {
428 default:
429 case 4:
430 vram_bitmask = s->vram_bitmask;
431 break;
433 case 2:
434 vram_bitmask = s->vram_bitmask >> 16;
435 break;
437 case 1:
438 vram_bitmask = s->vram_bitmask >> 24;
439 break;
442 for (i = 0; i < pix_count && offset + i < buf->size; i++) {
443 mask = 1 << (pix_count - 1 - i);
445 if (!(s->image_bitmap_op & 0x20000000) ||
446 (vram_bitmask & mask)) {
447 if (data & mask) {
448 artist_rop8(s, buf, offset + i, s->fg_color);
449 } else {
450 if (!(s->image_bitmap_op & 0x10000002)) {
451 artist_rop8(s, buf, offset + i, s->bg_color);
456 memory_region_set_dirty(&buf->mr, offset, pix_count);
457 break;
459 default:
460 qemu_log_mask(LOG_UNIMP, "%s: unknown pixel length %d\n",
461 __func__, pix_length);
462 break;
465 if (incr_x) {
466 if (s->cmap_bm_access) {
467 s->vram_pos += 4;
468 } else {
469 s->vram_pos += pix_count << 2;
473 if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 ||
474 vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) {
475 artist_invalidate_cursor(s);
479 static void block_move(ARTISTState *s,
480 unsigned int source_x, unsigned int source_y,
481 unsigned int dest_x, unsigned int dest_y,
482 unsigned int width, unsigned int height)
484 struct vram_buffer *buf;
485 int line, endline, lineincr, startcolumn, endcolumn, columnincr, column;
486 unsigned int dst, src;
488 trace_artist_block_move(source_x, source_y, dest_x, dest_y, width, height);
490 if (s->control_plane != 0) {
491 /* We don't support CONTROL_PLANE accesses */
492 qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
493 s->control_plane);
494 return;
497 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
498 if (height > buf->height) {
499 height = buf->height;
501 if (width > buf->width) {
502 width = buf->width;
505 if (dest_y > source_y) {
506 /* move down */
507 line = height - 1;
508 endline = -1;
509 lineincr = -1;
510 } else {
511 /* move up */
512 line = 0;
513 endline = height;
514 lineincr = 1;
517 if (dest_x > source_x) {
518 /* move right */
519 startcolumn = width - 1;
520 endcolumn = -1;
521 columnincr = -1;
522 } else {
523 /* move left */
524 startcolumn = 0;
525 endcolumn = width;
526 columnincr = 1;
529 for ( ; line != endline; line += lineincr) {
530 src = source_x + ((line + source_y) * buf->width) + startcolumn;
531 dst = dest_x + ((line + dest_y) * buf->width) + startcolumn;
533 for (column = startcolumn; column != endcolumn; column += columnincr) {
534 if (dst >= buf->size || src >= buf->size) {
535 continue;
537 artist_rop8(s, buf, dst, buf->data[src]);
538 src += columnincr;
539 dst += columnincr;
543 artist_invalidate_lines(buf, dest_y, height);
546 static void fill_window(ARTISTState *s,
547 unsigned int startx, unsigned int starty,
548 unsigned int width, unsigned int height)
550 unsigned int offset;
551 uint8_t color = artist_get_color(s);
552 struct vram_buffer *buf;
553 int x, y;
555 trace_artist_fill_window(startx, starty, width, height,
556 s->image_bitmap_op, s->control_plane);
558 if (s->control_plane != 0) {
559 /* We don't support CONTROL_PLANE accesses */
560 qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
561 s->control_plane);
562 return;
565 if (s->reg_100080 == 0x7d) {
567 * Not sure what this register really does, but
568 * 0x7d seems to enable autoincremt of the Y axis
569 * by the current block move height.
571 height = artist_get_y(s->blockmove_size);
572 s->vram_start += height;
575 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
577 for (y = starty; y < starty + height; y++) {
578 offset = y * s->width;
580 for (x = startx; x < startx + width; x++) {
581 artist_rop8(s, buf, offset + x, color);
584 artist_invalidate_lines(buf, starty, height);
587 static void draw_line(ARTISTState *s,
588 unsigned int x1, unsigned int y1,
589 unsigned int x2, unsigned int y2,
590 bool update_start, int skip_pix, int max_pix)
592 struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
593 uint8_t color;
594 int dx, dy, t, e, x, y, incy, diago, horiz;
595 bool c1;
597 trace_artist_draw_line(x1, y1, x2, y2);
599 if ((x1 >= buf->width && x2 >= buf->width) ||
600 (y1 >= buf->height && y2 >= buf->height)) {
601 return;
605 if (update_start) {
606 s->vram_start = (x2 << 16) | y2;
609 if (x2 > x1) {
610 dx = x2 - x1;
611 } else {
612 dx = x1 - x2;
614 if (y2 > y1) {
615 dy = y2 - y1;
616 } else {
617 dy = y1 - y2;
620 c1 = false;
621 if (dy > dx) {
622 t = y2;
623 y2 = x2;
624 x2 = t;
626 t = y1;
627 y1 = x1;
628 x1 = t;
630 t = dx;
631 dx = dy;
632 dy = t;
634 c1 = true;
637 if (x1 > x2) {
638 t = y2;
639 y2 = y1;
640 y1 = t;
642 t = x1;
643 x1 = x2;
644 x2 = t;
647 horiz = dy << 1;
648 diago = (dy - dx) << 1;
649 e = (dy << 1) - dx;
651 if (y1 <= y2) {
652 incy = 1;
653 } else {
654 incy = -1;
656 x = x1;
657 y = y1;
658 color = artist_get_color(s);
660 do {
661 unsigned int ofs;
663 if (c1) {
664 ofs = x * s->width + y;
665 } else {
666 ofs = y * s->width + x;
669 if (skip_pix > 0) {
670 skip_pix--;
671 } else {
672 artist_rop8(s, buf, ofs, color);
675 if (e > 0) {
676 y += incy;
677 e += diago;
678 } else {
679 e += horiz;
681 x++;
682 } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
683 if (c1)
684 artist_invalidate_lines(buf, x, dy+1);
685 else
686 artist_invalidate_lines(buf, y, dx+1);
689 static void draw_line_pattern_start(ARTISTState *s)
692 int startx = artist_get_x(s->vram_start);
693 int starty = artist_get_y(s->vram_start);
694 int endx = artist_get_x(s->blockmove_size);
695 int endy = artist_get_y(s->blockmove_size);
696 int pstart = s->line_pattern_start >> 16;
698 draw_line(s, startx, starty, endx, endy, false, -1, pstart);
699 s->line_pattern_skip = pstart;
702 static void draw_line_pattern_next(ARTISTState *s)
705 int startx = artist_get_x(s->vram_start);
706 int starty = artist_get_y(s->vram_start);
707 int endx = artist_get_x(s->blockmove_size);
708 int endy = artist_get_y(s->blockmove_size);
709 int line_xy = s->line_xy >> 16;
711 draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip,
712 s->line_pattern_skip + line_xy);
713 s->line_pattern_skip += line_xy;
714 s->image_bitmap_op ^= 2;
717 static void draw_line_size(ARTISTState *s, bool update_start)
720 int startx = artist_get_x(s->vram_start);
721 int starty = artist_get_y(s->vram_start);
722 int endx = artist_get_x(s->line_size);
723 int endy = artist_get_y(s->line_size);
725 draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
728 static void draw_line_xy(ARTISTState *s, bool update_start)
731 int startx = artist_get_x(s->vram_start);
732 int starty = artist_get_y(s->vram_start);
733 int sizex = artist_get_x(s->blockmove_size);
734 int sizey = artist_get_y(s->blockmove_size);
735 int linexy = s->line_xy >> 16;
736 int endx, endy;
738 endx = startx;
739 endy = starty;
741 if (sizex > 0) {
742 endx = startx + linexy;
745 if (sizex < 0) {
746 endx = startx;
747 startx -= linexy;
750 if (sizey > 0) {
751 endy = starty + linexy;
754 if (sizey < 0) {
755 endy = starty;
756 starty -= linexy;
759 if (startx < 0) {
760 startx = 0;
763 if (endx < 0) {
764 endx = 0;
767 if (starty < 0) {
768 starty = 0;
771 if (endy < 0) {
772 endy = 0;
775 draw_line(s, startx, starty, endx, endy, false, -1, -1);
778 static void draw_line_end(ARTISTState *s, bool update_start)
781 int startx = artist_get_x(s->vram_start);
782 int starty = artist_get_y(s->vram_start);
783 int endx = artist_get_x(s->line_end);
784 int endy = artist_get_y(s->line_end);
786 draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
789 static void font_write16(ARTISTState *s, uint16_t val)
791 struct vram_buffer *buf;
792 uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color;
793 uint16_t mask;
794 int i;
796 unsigned int startx = artist_get_x(s->vram_start);
797 unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y;
798 unsigned int offset = starty * s->width + startx;
800 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
802 if (startx >= buf->width || starty >= buf->height ||
803 offset + 16 >= buf->size) {
804 return;
807 for (i = 0; i < 16; i++) {
808 mask = 1 << (15 - i);
809 if (val & mask) {
810 artist_rop8(s, buf, offset + i, color);
811 } else {
812 if (!(s->image_bitmap_op & 0x20000000)) {
813 artist_rop8(s, buf, offset + i, s->bg_color);
817 artist_invalidate_lines(buf, starty, 1);
820 static void font_write(ARTISTState *s, uint32_t val)
822 font_write16(s, val >> 16);
823 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
824 s->vram_start += (s->blockmove_size & 0xffff0000);
825 return;
828 font_write16(s, val & 0xffff);
829 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
830 s->vram_start += (s->blockmove_size & 0xffff0000);
831 return;
835 static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
838 * FIXME: is there a qemu helper for this?
841 #ifndef HOST_WORDS_BIGENDIAN
842 addr ^= 3;
843 #endif
845 switch (size) {
846 case 1:
847 *(uint8_t *)(out + (addr & 3)) = val;
848 break;
850 case 2:
851 *(uint16_t *)(out + (addr & 2)) = val;
852 break;
854 case 4:
855 *(uint32_t *)out = val;
856 break;
858 default:
859 qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size);
863 static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
864 unsigned size)
866 ARTISTState *s = opaque;
867 int width, height;
869 trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val);
871 switch (addr & ~3ULL) {
872 case 0x100080:
873 combine_write_reg(addr, val, size, &s->reg_100080);
874 break;
876 case FG_COLOR:
877 combine_write_reg(addr, val, size, &s->fg_color);
878 break;
880 case BG_COLOR:
881 combine_write_reg(addr, val, size, &s->bg_color);
882 break;
884 case VRAM_BITMASK:
885 combine_write_reg(addr, val, size, &s->vram_bitmask);
886 break;
888 case VRAM_WRITE_INCR_Y:
889 vram_bit_write(s, s->vram_char_y++, false, size, val);
890 break;
892 case VRAM_WRITE_INCR_X:
893 case VRAM_WRITE_INCR_X2:
894 vram_bit_write(s, s->vram_char_y, true, size, val);
895 break;
897 case VRAM_IDX:
898 combine_write_reg(addr, val, size, &s->vram_pos);
899 s->vram_char_y = 0;
900 s->draw_line_pattern = 0;
901 break;
903 case VRAM_START:
904 combine_write_reg(addr, val, size, &s->vram_start);
905 s->draw_line_pattern = 0;
906 break;
908 case VRAM_START_TRIGGER:
909 combine_write_reg(addr, val, size, &s->vram_start);
910 fill_window(s, artist_get_x(s->vram_start),
911 artist_get_y(s->vram_start),
912 artist_get_x(s->blockmove_size),
913 artist_get_y(s->blockmove_size));
914 break;
916 case VRAM_SIZE_TRIGGER:
917 combine_write_reg(addr, val, size, &s->vram_size);
919 if (size == 2 && !(addr & 2)) {
920 height = artist_get_y(s->blockmove_size);
921 } else {
922 height = artist_get_y(s->vram_size);
925 if (size == 2 && (addr & 2)) {
926 width = artist_get_x(s->blockmove_size);
927 } else {
928 width = artist_get_x(s->vram_size);
931 fill_window(s, artist_get_x(s->vram_start),
932 artist_get_y(s->vram_start),
933 width, height);
934 break;
936 case LINE_XY:
937 combine_write_reg(addr, val, size, &s->line_xy);
938 if (s->draw_line_pattern) {
939 draw_line_pattern_next(s);
940 } else {
941 draw_line_xy(s, true);
943 break;
945 case PATTERN_LINE_START:
946 combine_write_reg(addr, val, size, &s->line_pattern_start);
947 s->draw_line_pattern = 1;
948 draw_line_pattern_start(s);
949 break;
951 case LINE_SIZE:
952 combine_write_reg(addr, val, size, &s->line_size);
953 draw_line_size(s, true);
954 break;
956 case LINE_END:
957 combine_write_reg(addr, val, size, &s->line_end);
958 draw_line_end(s, true);
959 break;
961 case BLOCK_MOVE_SIZE:
962 combine_write_reg(addr, val, size, &s->blockmove_size);
963 break;
965 case BLOCK_MOVE_SOURCE:
966 combine_write_reg(addr, val, size, &s->blockmove_source);
967 break;
969 case BLOCK_MOVE_DEST_TRIGGER:
970 combine_write_reg(addr, val, size, &s->blockmove_dest);
972 block_move(s, artist_get_x(s->blockmove_source),
973 artist_get_y(s->blockmove_source),
974 artist_get_x(s->blockmove_dest),
975 artist_get_y(s->blockmove_dest),
976 artist_get_x(s->blockmove_size),
977 artist_get_y(s->blockmove_size));
978 break;
980 case BLOCK_MOVE_SIZE_TRIGGER:
981 combine_write_reg(addr, val, size, &s->blockmove_size);
983 block_move(s,
984 artist_get_x(s->blockmove_source),
985 artist_get_y(s->blockmove_source),
986 artist_get_x(s->vram_start),
987 artist_get_y(s->vram_start),
988 artist_get_x(s->blockmove_size),
989 artist_get_y(s->blockmove_size));
990 break;
992 case PLANE_MASK:
993 combine_write_reg(addr, val, size, &s->plane_mask);
994 break;
996 case CMAP_BM_ACCESS:
997 combine_write_reg(addr, val, size, &s->cmap_bm_access);
998 break;
1000 case DST_BM_ACCESS:
1001 combine_write_reg(addr, val, size, &s->dst_bm_access);
1002 s->cmap_bm_access = 0;
1003 break;
1005 case SRC_BM_ACCESS:
1006 combine_write_reg(addr, val, size, &s->src_bm_access);
1007 s->cmap_bm_access = 0;
1008 break;
1010 case CONTROL_PLANE:
1011 combine_write_reg(addr, val, size, &s->control_plane);
1012 break;
1014 case TRANSFER_DATA:
1015 combine_write_reg(addr, val, size, &s->transfer_data);
1016 break;
1018 case 0x300200:
1019 combine_write_reg(addr, val, size, &s->reg_300200);
1020 break;
1022 case 0x300208:
1023 combine_write_reg(addr, val, size, &s->reg_300208);
1024 break;
1026 case 0x300218:
1027 combine_write_reg(addr, val, size, &s->reg_300218);
1028 break;
1030 case CURSOR_POS:
1031 artist_invalidate_cursor(s);
1032 combine_write_reg(addr, val, size, &s->cursor_pos);
1033 artist_invalidate_cursor(s);
1034 break;
1036 case CURSOR_CTRL:
1037 break;
1039 case IMAGE_BITMAP_OP:
1040 combine_write_reg(addr, val, size, &s->image_bitmap_op);
1041 break;
1043 case FONT_WRITE_INCR_Y:
1044 combine_write_reg(addr, val, size, &s->font_write1);
1045 font_write(s, s->font_write1);
1046 break;
1048 case FONT_WRITE_START:
1049 combine_write_reg(addr, val, size, &s->font_write2);
1050 s->font_write_pos_y = 0;
1051 font_write(s, s->font_write2);
1052 break;
1054 case 300104:
1055 break;
1057 default:
1058 qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx
1059 " val=%08" PRIx64 " size=%d\n",
1060 __func__, addr, val, size);
1061 break;
1065 static uint64_t combine_read_reg(hwaddr addr, int size, void *in)
1068 * FIXME: is there a qemu helper for this?
1071 #ifndef HOST_WORDS_BIGENDIAN
1072 addr ^= 3;
1073 #endif
1075 switch (size) {
1076 case 1:
1077 return *(uint8_t *)(in + (addr & 3));
1079 case 2:
1080 return *(uint16_t *)(in + (addr & 2));
1082 case 4:
1083 return *(uint32_t *)in;
1085 default:
1086 qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size);
1087 return 0;
1091 static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
1093 ARTISTState *s = opaque;
1094 uint32_t val = 0;
1096 switch (addr & ~3ULL) {
1097 /* Unknown status registers */
1098 case 0:
1099 break;
1101 case 0x211110:
1102 val = (s->width << 16) | s->height;
1103 if (s->depth == 1) {
1104 val |= 1 << 31;
1106 break;
1108 case 0x100000:
1109 case 0x300000:
1110 case 0x300004:
1111 case 0x300308:
1112 case 0x380000:
1113 break;
1115 case 0x300008:
1116 case 0x380008:
1118 * FIFO ready flag. we're not emulating the FIFOs
1119 * so we're always ready
1121 val = 0x10;
1122 break;
1124 case 0x300200:
1125 val = s->reg_300200;
1126 break;
1128 case 0x300208:
1129 val = s->reg_300208;
1130 break;
1132 case 0x300218:
1133 val = s->reg_300218;
1134 break;
1136 case 0x30023c:
1137 val = 0xac4ffdac;
1138 break;
1140 case 0x380004:
1141 /* 0x02000000 Buserror */
1142 val = 0x6dc20006;
1143 break;
1145 default:
1146 qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx
1147 " size %d\n", __func__, addr, size);
1148 break;
1150 val = combine_read_reg(addr, size, &val);
1151 trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val);
1152 return val;
1155 static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
1156 unsigned size)
1158 ARTISTState *s = opaque;
1159 struct vram_buffer *buf;
1160 unsigned int posy, posx;
1161 unsigned int offset;
1162 trace_artist_vram_write(size, addr, val);
1164 if (s->cmap_bm_access) {
1165 buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1166 if (addr + 3 < buf->size) {
1167 *(uint32_t *)(buf->data + addr) = val;
1169 return;
1172 buf = vram_write_buffer(s);
1173 posy = ADDR_TO_Y(addr);
1174 posx = ADDR_TO_X(addr);
1176 if (!buf->size) {
1177 return;
1180 if (posy > buf->height || posx > buf->width) {
1181 return;
1184 offset = posy * buf->width + posx;
1185 if (offset >= buf->size) {
1186 return;
1189 switch (size) {
1190 case 4:
1191 if (offset + 3 < buf->size) {
1192 *(uint32_t *)(buf->data + offset) = be32_to_cpu(val);
1193 memory_region_set_dirty(&buf->mr, offset, 4);
1195 break;
1196 case 2:
1197 if (offset + 1 < buf->size) {
1198 *(uint16_t *)(buf->data + offset) = be16_to_cpu(val);
1199 memory_region_set_dirty(&buf->mr, offset, 2);
1201 break;
1202 case 1:
1203 if (offset < buf->size) {
1204 *(uint8_t *)(buf->data + offset) = val;
1205 memory_region_set_dirty(&buf->mr, offset, 1);
1207 break;
1208 default:
1209 break;
1213 static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
1215 ARTISTState *s = opaque;
1216 struct vram_buffer *buf;
1217 uint64_t val;
1218 unsigned int posy, posx;
1220 if (s->cmap_bm_access) {
1221 buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1222 val = 0;
1223 if (addr < buf->size && addr + 3 < buf->size) {
1224 val = *(uint32_t *)(buf->data + addr);
1226 trace_artist_vram_read(size, addr, 0, 0, val);
1227 return val;
1230 buf = vram_read_buffer(s);
1231 if (!buf->size) {
1232 return 0;
1235 posy = ADDR_TO_Y(addr);
1236 posx = ADDR_TO_X(addr);
1238 if (posy > buf->height || posx > buf->width) {
1239 return 0;
1242 val = cpu_to_be32(*(uint32_t *)(buf->data + posy * buf->width + posx));
1243 trace_artist_vram_read(size, addr, posx, posy, val);
1244 return val;
1247 static const MemoryRegionOps artist_reg_ops = {
1248 .read = artist_reg_read,
1249 .write = artist_reg_write,
1250 .endianness = DEVICE_NATIVE_ENDIAN,
1251 .impl.min_access_size = 1,
1252 .impl.max_access_size = 4,
1255 static const MemoryRegionOps artist_vram_ops = {
1256 .read = artist_vram_read,
1257 .write = artist_vram_write,
1258 .endianness = DEVICE_NATIVE_ENDIAN,
1259 .impl.min_access_size = 1,
1260 .impl.max_access_size = 4,
1263 static void artist_draw_cursor(ARTISTState *s)
1265 DisplaySurface *surface = qemu_console_surface(s->con);
1266 uint32_t *data = (uint32_t *)surface_data(surface);
1267 struct vram_buffer *cursor0, *cursor1 , *buf;
1268 int cx, cy, cursor_pos_x, cursor_pos_y;
1270 cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1];
1271 cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2];
1272 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1274 artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y);
1276 for (cy = 0; cy < s->cursor_height; cy++) {
1278 for (cx = 0; cx < s->cursor_width; cx++) {
1280 if (cursor_pos_y + cy < 0 ||
1281 cursor_pos_x + cx < 0 ||
1282 cursor_pos_y + cy > buf->height - 1 ||
1283 cursor_pos_x + cx > buf->width) {
1284 continue;
1287 int dstoffset = (cursor_pos_y + cy) * s->width +
1288 (cursor_pos_x + cx);
1290 if (cursor0->data[cy * cursor0->width + cx]) {
1291 data[dstoffset] = 0;
1292 } else {
1293 if (cursor1->data[cy * cursor1->width + cx]) {
1294 data[dstoffset] = 0xffffff;
1301 static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
1302 int width, int pitch)
1304 ARTISTState *s = ARTIST(opaque);
1305 uint32_t *cmap, *data = (uint32_t *)d;
1306 int x;
1308 cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400);
1310 for (x = 0; x < s->width; x++) {
1311 *data++ = cmap[*src++];
1315 static void artist_update_display(void *opaque)
1317 ARTISTState *s = opaque;
1318 DisplaySurface *surface = qemu_console_surface(s->con);
1319 int first = 0, last;
1322 framebuffer_update_display(surface, &s->fbsection, s->width, s->height,
1323 s->width, s->width * 4, 0, 0, artist_draw_line,
1324 s, &first, &last);
1326 artist_draw_cursor(s);
1328 dpy_gfx_update(s->con, 0, 0, s->width, s->height);
1331 static void artist_invalidate(void *opaque)
1333 ARTISTState *s = ARTIST(opaque);
1334 struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1335 memory_region_set_dirty(&buf->mr, 0, buf->size);
1338 static const GraphicHwOps artist_ops = {
1339 .invalidate = artist_invalidate,
1340 .gfx_update = artist_update_display,
1343 static void artist_initfn(Object *obj)
1345 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1346 ARTISTState *s = ARTIST(obj);
1348 memory_region_init_io(&s->reg, obj, &artist_reg_ops, s, "artist.reg",
1349 4 * MiB);
1350 memory_region_init_io(&s->vram_mem, obj, &artist_vram_ops, s, "artist.vram",
1351 8 * MiB);
1352 sysbus_init_mmio(sbd, &s->reg);
1353 sysbus_init_mmio(sbd, &s->vram_mem);
1356 static void artist_create_buffer(ARTISTState *s, const char *name,
1357 hwaddr *offset, unsigned int idx,
1358 int width, int height)
1360 struct vram_buffer *buf = s->vram_buffer + idx;
1362 memory_region_init_ram(&buf->mr, NULL, name, width * height,
1363 &error_fatal);
1364 memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0);
1366 buf->data = memory_region_get_ram_ptr(&buf->mr);
1367 buf->size = height * width;
1368 buf->width = width;
1369 buf->height = height;
1371 *offset += buf->size;
1374 static void artist_realizefn(DeviceState *dev, Error **errp)
1376 ARTISTState *s = ARTIST(dev);
1377 struct vram_buffer *buf;
1378 hwaddr offset = 0;
1380 if (s->width > 2048 || s->height > 2048) {
1381 error_report("artist: screen size can not exceed 2048 x 2048 pixel.");
1382 s->width = MIN(s->width, 2048);
1383 s->height = MIN(s->height, 2048);
1386 if (s->width < 640 || s->height < 480) {
1387 error_report("artist: minimum screen size is 640 x 480 pixel.");
1388 s->width = MAX(s->width, 640);
1389 s->height = MAX(s->height, 480);
1392 memory_region_init(&s->mem_as_root, OBJECT(dev), "artist", ~0ull);
1393 address_space_init(&s->as, &s->mem_as_root, "artist");
1395 artist_create_buffer(s, "cmap", &offset, ARTIST_BUFFER_CMAP, 2048, 4);
1396 artist_create_buffer(s, "ap", &offset, ARTIST_BUFFER_AP,
1397 s->width, s->height);
1398 artist_create_buffer(s, "cursor1", &offset, ARTIST_BUFFER_CURSOR1, 64, 64);
1399 artist_create_buffer(s, "cursor2", &offset, ARTIST_BUFFER_CURSOR2, 64, 64);
1400 artist_create_buffer(s, "attribute", &offset, ARTIST_BUFFER_ATTRIBUTE,
1401 64, 64);
1403 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1404 framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0,
1405 buf->width, buf->height);
1407 * no idea whether the cursor is fixed size or not, so assume 32x32 which
1408 * seems sufficient for HP-UX X11.
1410 s->cursor_height = 32;
1411 s->cursor_width = 32;
1413 s->con = graphic_console_init(dev, 0, &artist_ops, s);
1414 qemu_console_resize(s->con, s->width, s->height);
1417 static int vmstate_artist_post_load(void *opaque, int version_id)
1419 artist_invalidate(opaque);
1420 return 0;
1423 static const VMStateDescription vmstate_artist = {
1424 .name = "artist",
1425 .version_id = 1,
1426 .minimum_version_id = 1,
1427 .post_load = vmstate_artist_post_load,
1428 .fields = (VMStateField[]) {
1429 VMSTATE_UINT16(height, ARTISTState),
1430 VMSTATE_UINT16(width, ARTISTState),
1431 VMSTATE_UINT16(depth, ARTISTState),
1432 VMSTATE_UINT32(fg_color, ARTISTState),
1433 VMSTATE_UINT32(bg_color, ARTISTState),
1434 VMSTATE_UINT32(vram_char_y, ARTISTState),
1435 VMSTATE_UINT32(vram_bitmask, ARTISTState),
1436 VMSTATE_UINT32(vram_start, ARTISTState),
1437 VMSTATE_UINT32(vram_pos, ARTISTState),
1438 VMSTATE_UINT32(vram_size, ARTISTState),
1439 VMSTATE_UINT32(blockmove_source, ARTISTState),
1440 VMSTATE_UINT32(blockmove_dest, ARTISTState),
1441 VMSTATE_UINT32(blockmove_size, ARTISTState),
1442 VMSTATE_UINT32(line_size, ARTISTState),
1443 VMSTATE_UINT32(line_end, ARTISTState),
1444 VMSTATE_UINT32(line_xy, ARTISTState),
1445 VMSTATE_UINT32(cursor_pos, ARTISTState),
1446 VMSTATE_UINT32(cursor_height, ARTISTState),
1447 VMSTATE_UINT32(cursor_width, ARTISTState),
1448 VMSTATE_UINT32(plane_mask, ARTISTState),
1449 VMSTATE_UINT32(reg_100080, ARTISTState),
1450 VMSTATE_UINT32(reg_300200, ARTISTState),
1451 VMSTATE_UINT32(reg_300208, ARTISTState),
1452 VMSTATE_UINT32(reg_300218, ARTISTState),
1453 VMSTATE_UINT32(cmap_bm_access, ARTISTState),
1454 VMSTATE_UINT32(dst_bm_access, ARTISTState),
1455 VMSTATE_UINT32(src_bm_access, ARTISTState),
1456 VMSTATE_UINT32(control_plane, ARTISTState),
1457 VMSTATE_UINT32(transfer_data, ARTISTState),
1458 VMSTATE_UINT32(image_bitmap_op, ARTISTState),
1459 VMSTATE_UINT32(font_write1, ARTISTState),
1460 VMSTATE_UINT32(font_write2, ARTISTState),
1461 VMSTATE_UINT32(font_write_pos_y, ARTISTState),
1462 VMSTATE_END_OF_LIST()
1466 static Property artist_properties[] = {
1467 DEFINE_PROP_UINT16("width", ARTISTState, width, 1280),
1468 DEFINE_PROP_UINT16("height", ARTISTState, height, 1024),
1469 DEFINE_PROP_UINT16("depth", ARTISTState, depth, 8),
1470 DEFINE_PROP_END_OF_LIST(),
1473 static void artist_reset(DeviceState *qdev)
1477 static void artist_class_init(ObjectClass *klass, void *data)
1479 DeviceClass *dc = DEVICE_CLASS(klass);
1481 dc->realize = artist_realizefn;
1482 dc->vmsd = &vmstate_artist;
1483 dc->reset = artist_reset;
1484 device_class_set_props(dc, artist_properties);
1487 static const TypeInfo artist_info = {
1488 .name = TYPE_ARTIST,
1489 .parent = TYPE_SYS_BUS_DEVICE,
1490 .instance_size = sizeof(ARTISTState),
1491 .instance_init = artist_initfn,
1492 .class_init = artist_class_init,
1495 static void artist_register_types(void)
1497 type_register_static(&artist_info);
1500 type_init(artist_register_types)