xref: /qemu/hw/display/artist.c (revision b88651cb)
1 /*
2  * QEMU HP Artist Emulation
3  *
4  * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  */
8 
9 #include "qemu/osdep.h"
10 #include "qemu/error-report.h"
11 #include "qemu/log.h"
12 #include "qemu/module.h"
13 #include "qemu/units.h"
14 #include "qapi/error.h"
15 #include "hw/sysbus.h"
16 #include "hw/loader.h"
17 #include "hw/qdev-core.h"
18 #include "hw/qdev-properties.h"
19 #include "migration/vmstate.h"
20 #include "ui/console.h"
21 #include "trace.h"
22 #include "framebuffer.h"
23 #include "qom/object.h"
24 
25 #define TYPE_ARTIST "artist"
26 OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState, ARTIST)
27 
28 struct vram_buffer {
29     MemoryRegion mr;
30     uint8_t *data;
31     unsigned int size;
32     unsigned int width;
33     unsigned int height;
34 };
35 
36 struct ARTISTState {
37     SysBusDevice parent_obj;
38 
39     QemuConsole *con;
40     MemoryRegion vram_mem;
41     MemoryRegion mem_as_root;
42     MemoryRegion reg;
43     MemoryRegionSection fbsection;
44 
45     void *vram_int_mr;
46     AddressSpace as;
47 
48     struct vram_buffer vram_buffer[16];
49 
50     uint16_t width;
51     uint16_t height;
52     uint16_t depth;
53 
54     uint32_t fg_color;
55     uint32_t bg_color;
56 
57     uint32_t vram_char_y;
58     uint32_t vram_bitmask;
59 
60     uint32_t vram_start;
61     uint32_t vram_pos;
62 
63     uint32_t vram_size;
64 
65     uint32_t blockmove_source;
66     uint32_t blockmove_dest;
67     uint32_t blockmove_size;
68 
69     uint32_t line_size;
70     uint32_t line_end;
71     uint32_t line_xy;
72     uint32_t line_pattern_start;
73     uint32_t line_pattern_skip;
74 
75     uint32_t cursor_pos;
76     uint32_t cursor_cntrl;
77 
78     uint32_t cursor_height;
79     uint32_t cursor_width;
80 
81     uint32_t plane_mask;
82 
83     uint32_t reg_100080;
84     uint32_t reg_300200;
85     uint32_t reg_300208;
86     uint32_t reg_300218;
87 
88     uint32_t dst_bm_access;
89     uint32_t src_bm_access;
90     uint32_t control_plane;
91     uint32_t transfer_data;
92     uint32_t image_bitmap_op;
93 
94     uint32_t font_write1;
95     uint32_t font_write2;
96     uint32_t font_write_pos_y;
97 
98     int draw_line_pattern;
99 };
100 
101 typedef enum {
102     ARTIST_BUFFER_AP = 1,
103     ARTIST_BUFFER_OVERLAY = 2,
104     ARTIST_BUFFER_CURSOR1 = 6,
105     ARTIST_BUFFER_CURSOR2 = 7,
106     ARTIST_BUFFER_ATTRIBUTE = 13,
107     ARTIST_BUFFER_CMAP = 15,
108 } artist_buffer_t;
109 
110 typedef enum {
111     VRAM_IDX = 0x1004a0,
112     VRAM_BITMASK = 0x1005a0,
113     VRAM_WRITE_INCR_X = 0x100600,
114     VRAM_WRITE_INCR_X2 = 0x100604,
115     VRAM_WRITE_INCR_Y = 0x100620,
116     VRAM_START = 0x100800,
117     BLOCK_MOVE_SIZE = 0x100804,
118     BLOCK_MOVE_SOURCE = 0x100808,
119     TRANSFER_DATA = 0x100820,
120     FONT_WRITE_INCR_Y = 0x1008a0,
121     VRAM_START_TRIGGER = 0x100a00,
122     VRAM_SIZE_TRIGGER = 0x100a04,
123     FONT_WRITE_START = 0x100aa0,
124     BLOCK_MOVE_DEST_TRIGGER = 0x100b00,
125     BLOCK_MOVE_SIZE_TRIGGER = 0x100b04,
126     LINE_XY = 0x100ccc,
127     PATTERN_LINE_START = 0x100ecc,
128     LINE_SIZE = 0x100e04,
129     LINE_END = 0x100e44,
130     DST_SRC_BM_ACCESS = 0x118000,
131     DST_BM_ACCESS = 0x118004,
132     SRC_BM_ACCESS = 0x118008,
133     CONTROL_PLANE = 0x11800c,
134     FG_COLOR = 0x118010,
135     BG_COLOR = 0x118014,
136     PLANE_MASK = 0x118018,
137     IMAGE_BITMAP_OP = 0x11801c,
138     CURSOR_POS = 0x300100,
139     CURSOR_CTRL = 0x300104,
140 } artist_reg_t;
141 
142 typedef enum {
143     ARTIST_ROP_CLEAR = 0,
144     ARTIST_ROP_COPY = 3,
145     ARTIST_ROP_XOR = 6,
146     ARTIST_ROP_NOT_DST = 10,
147     ARTIST_ROP_SET = 15,
148 } artist_rop_t;
149 
150 #define REG_NAME(_x) case _x: return " "#_x;
151 static const char *artist_reg_name(uint64_t addr)
152 {
153     switch ((artist_reg_t)addr) {
154     REG_NAME(VRAM_IDX);
155     REG_NAME(VRAM_BITMASK);
156     REG_NAME(VRAM_WRITE_INCR_X);
157     REG_NAME(VRAM_WRITE_INCR_X2);
158     REG_NAME(VRAM_WRITE_INCR_Y);
159     REG_NAME(VRAM_START);
160     REG_NAME(BLOCK_MOVE_SIZE);
161     REG_NAME(BLOCK_MOVE_SOURCE);
162     REG_NAME(FG_COLOR);
163     REG_NAME(BG_COLOR);
164     REG_NAME(PLANE_MASK);
165     REG_NAME(VRAM_START_TRIGGER);
166     REG_NAME(VRAM_SIZE_TRIGGER);
167     REG_NAME(BLOCK_MOVE_DEST_TRIGGER);
168     REG_NAME(BLOCK_MOVE_SIZE_TRIGGER);
169     REG_NAME(TRANSFER_DATA);
170     REG_NAME(CONTROL_PLANE);
171     REG_NAME(IMAGE_BITMAP_OP);
172     REG_NAME(DST_SRC_BM_ACCESS);
173     REG_NAME(DST_BM_ACCESS);
174     REG_NAME(SRC_BM_ACCESS);
175     REG_NAME(CURSOR_POS);
176     REG_NAME(CURSOR_CTRL);
177     REG_NAME(LINE_XY);
178     REG_NAME(PATTERN_LINE_START);
179     REG_NAME(LINE_SIZE);
180     REG_NAME(LINE_END);
181     REG_NAME(FONT_WRITE_INCR_Y);
182     REG_NAME(FONT_WRITE_START);
183     }
184     return "";
185 }
186 #undef REG_NAME
187 
188 /* artist has a fixed line length of 2048 bytes. */
189 #define ADDR_TO_Y(addr) extract32(addr, 11, 11)
190 #define ADDR_TO_X(addr) extract32(addr, 0, 11)
191 
192 static int16_t artist_get_x(uint32_t reg)
193 {
194     return reg >> 16;
195 }
196 
197 static int16_t artist_get_y(uint32_t reg)
198 {
199     return reg & 0xffff;
200 }
201 
202 static void artist_invalidate_lines(struct vram_buffer *buf,
203                                     int starty, int height)
204 {
205     int start = starty * buf->width;
206     int size;
207 
208     if (starty + height > buf->height) {
209         height = buf->height - starty;
210     }
211 
212     size = height * buf->width;
213 
214     if (start + size <= buf->size) {
215         memory_region_set_dirty(&buf->mr, start, size);
216     }
217 }
218 
219 static int vram_write_bufidx(ARTISTState *s)
220 {
221     return (s->dst_bm_access >> 12) & 0x0f;
222 }
223 
224 static int vram_read_bufidx(ARTISTState *s)
225 {
226     return (s->src_bm_access >> 12) & 0x0f;
227 }
228 
229 static struct vram_buffer *vram_read_buffer(ARTISTState *s)
230 {
231     return &s->vram_buffer[vram_read_bufidx(s)];
232 }
233 
234 static struct vram_buffer *vram_write_buffer(ARTISTState *s)
235 {
236     return &s->vram_buffer[vram_write_bufidx(s)];
237 }
238 
239 static uint8_t artist_get_color(ARTISTState *s)
240 {
241     if (s->image_bitmap_op & 2) {
242         return s->fg_color;
243     } else {
244         return s->bg_color;
245     }
246 }
247 
248 static artist_rop_t artist_get_op(ARTISTState *s)
249 {
250     return (s->image_bitmap_op >> 8) & 0xf;
251 }
252 
253 static void artist_rop8(ARTISTState *s, struct vram_buffer *buf,
254                         unsigned int offset, uint8_t val)
255 {
256     const artist_rop_t op = artist_get_op(s);
257     uint8_t plane_mask;
258     uint8_t *dst;
259 
260     if (offset >= buf->size) {
261         qemu_log_mask(LOG_GUEST_ERROR,
262                       "rop8 offset:%u bufsize:%u\n", offset, buf->size);
263         return;
264     }
265     dst = buf->data + offset;
266     plane_mask = s->plane_mask & 0xff;
267 
268     switch (op) {
269     case ARTIST_ROP_CLEAR:
270         *dst &= ~plane_mask;
271         break;
272 
273     case ARTIST_ROP_COPY:
274         *dst = (*dst & ~plane_mask) | (val & plane_mask);
275         break;
276 
277     case ARTIST_ROP_XOR:
278         *dst ^= val & plane_mask;
279         break;
280 
281     case ARTIST_ROP_NOT_DST:
282         *dst ^= plane_mask;
283         break;
284 
285     case ARTIST_ROP_SET:
286         *dst |= plane_mask;
287         break;
288 
289     default:
290         qemu_log_mask(LOG_UNIMP, "%s: unsupported rop %d\n", __func__, op);
291         break;
292     }
293 }
294 
295 static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y)
296 {
297     /*
298      * Don't know whether these magic offset values are configurable via
299      * some register. They seem to be the same for all resolutions.
300      * The cursor values provided in the registers are:
301      * X-value: -295 (for HP-UX 11) and 338 (for HP-UX 10.20) up to 2265
302      * Y-value: 1146 down to 0
303      * The emulated Artist graphic is like a CRX graphic, and as such
304      * it's usually fixed at 1280x1024 pixels.
305      * Because of the maximum Y-value of 1146 you can not choose a higher
306      * vertical resolution on HP-UX (unless you disable the mouse).
307      */
308 
309     static int offset = 338;
310     int lx;
311 
312     /* ignore if uninitialized */
313     if (s->cursor_pos == 0) {
314         *x = *y = 0;
315         return;
316     }
317 
318     lx = artist_get_x(s->cursor_pos);
319     if (lx < offset) {
320         offset = lx;
321     }
322     *x = (lx - offset) / 2;
323 
324     *y = 1146 - artist_get_y(s->cursor_pos);
325 
326     /* subtract cursor offset from cursor control register */
327     *x -= (s->cursor_cntrl & 0xf0) >> 4;
328     *y -= (s->cursor_cntrl & 0x0f);
329 
330     if (*x > s->width) {
331         *x = s->width;
332     }
333 
334     if (*y > s->height) {
335         *y = s->height;
336     }
337 }
338 
339 static void artist_invalidate_cursor(ARTISTState *s)
340 {
341     int x, y;
342 
343     artist_get_cursor_pos(s, &x, &y);
344     artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP],
345                             y, s->cursor_height);
346 }
347 
348 static void block_move(ARTISTState *s,
349                        unsigned int source_x, unsigned int source_y,
350                        unsigned int dest_x,   unsigned int dest_y,
351                        unsigned int width,    unsigned int height)
352 {
353     struct vram_buffer *buf;
354     int line, endline, lineincr, startcolumn, endcolumn, columnincr, column;
355     unsigned int dst, src;
356 
357     trace_artist_block_move(source_x, source_y, dest_x, dest_y, width, height);
358 
359     if (s->control_plane != 0) {
360         /* We don't support CONTROL_PLANE accesses */
361         qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
362                       s->control_plane);
363         return;
364     }
365 
366     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
367     if (height > buf->height) {
368         height = buf->height;
369     }
370     if (width > buf->width) {
371         width = buf->width;
372     }
373 
374     if (dest_y > source_y) {
375         /* move down */
376         line = height - 1;
377         endline = -1;
378         lineincr = -1;
379     } else {
380         /* move up */
381         line = 0;
382         endline = height;
383         lineincr = 1;
384     }
385 
386     if (dest_x > source_x) {
387         /* move right */
388         startcolumn = width - 1;
389         endcolumn = -1;
390         columnincr = -1;
391     } else {
392         /* move left */
393         startcolumn = 0;
394         endcolumn = width;
395         columnincr = 1;
396     }
397 
398     for ( ; line != endline; line += lineincr) {
399         src = source_x + ((line + source_y) * buf->width) + startcolumn;
400         dst = dest_x + ((line + dest_y) * buf->width) + startcolumn;
401 
402         for (column = startcolumn; column != endcolumn; column += columnincr) {
403             if (dst >= buf->size || src >= buf->size) {
404                 continue;
405             }
406             artist_rop8(s, buf, dst, buf->data[src]);
407             src += columnincr;
408             dst += columnincr;
409         }
410     }
411 
412     artist_invalidate_lines(buf, dest_y, height);
413 }
414 
415 static void fill_window(ARTISTState *s,
416                         unsigned int startx, unsigned int starty,
417                         unsigned int width,  unsigned int height)
418 {
419     unsigned int offset;
420     uint8_t color = artist_get_color(s);
421     struct vram_buffer *buf;
422     int x, y;
423 
424     trace_artist_fill_window(startx, starty, width, height,
425                              s->image_bitmap_op, s->control_plane);
426 
427     if (s->control_plane != 0) {
428         /* We don't support CONTROL_PLANE accesses */
429         qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
430                       s->control_plane);
431         return;
432     }
433 
434     if (s->reg_100080 == 0x7d) {
435         /*
436          * Not sure what this register really does, but
437          * 0x7d seems to enable autoincremt of the Y axis
438          * by the current block move height.
439          */
440         height = artist_get_y(s->blockmove_size);
441         s->vram_start += height;
442     }
443 
444     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
445 
446     for (y = starty; y < starty + height; y++) {
447         offset = y * s->width;
448 
449         for (x = startx; x < startx + width; x++) {
450             artist_rop8(s, buf, offset + x, color);
451         }
452     }
453     artist_invalidate_lines(buf, starty, height);
454 }
455 
456 static void draw_line(ARTISTState *s,
457                       unsigned int x1, unsigned int y1,
458                       unsigned int x2, unsigned int y2,
459                       bool update_start, int skip_pix, int max_pix)
460 {
461     struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
462     uint8_t color;
463     int dx, dy, t, e, x, y, incy, diago, horiz;
464     bool c1;
465 
466     trace_artist_draw_line(x1, y1, x2, y2);
467 
468     if ((x1 >= buf->width && x2 >= buf->width) ||
469         (y1 >= buf->height && y2 >= buf->height)) {
470         return;
471     }
472 
473     if (update_start) {
474         s->vram_start = (x2 << 16) | y2;
475     }
476 
477     if (x2 > x1) {
478         dx = x2 - x1;
479     } else {
480         dx = x1 - x2;
481     }
482     if (y2 > y1) {
483         dy = y2 - y1;
484     } else {
485         dy = y1 - y2;
486     }
487 
488     c1 = false;
489     if (dy > dx) {
490         t = y2;
491         y2 = x2;
492         x2 = t;
493 
494         t = y1;
495         y1 = x1;
496         x1 = t;
497 
498         t = dx;
499         dx = dy;
500         dy = t;
501 
502         c1 = true;
503     }
504 
505     if (x1 > x2) {
506         t = y2;
507         y2 = y1;
508         y1 = t;
509 
510         t = x1;
511         x1 = x2;
512         x2 = t;
513     }
514 
515     horiz = dy << 1;
516     diago = (dy - dx) << 1;
517     e = (dy << 1) - dx;
518 
519     if (y1 <= y2) {
520         incy = 1;
521     } else {
522         incy = -1;
523     }
524     x = x1;
525     y = y1;
526     color = artist_get_color(s);
527 
528     do {
529         unsigned int ofs;
530 
531         if (c1) {
532             ofs = x * s->width + y;
533         } else {
534             ofs = y * s->width + x;
535         }
536 
537         if (skip_pix > 0) {
538             skip_pix--;
539         } else {
540             artist_rop8(s, buf, ofs, color);
541         }
542 
543         if (e > 0) {
544             y  += incy;
545             e  += diago;
546         } else {
547             e += horiz;
548         }
549         x++;
550     } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
551 
552     if (c1) {
553         artist_invalidate_lines(buf, x1, x2 - x1);
554     } else {
555         artist_invalidate_lines(buf, y1 > y2 ? y2 : y1, x2 - x1);
556     }
557 }
558 
559 static void draw_line_pattern_start(ARTISTState *s)
560 {
561     int startx = artist_get_x(s->vram_start);
562     int starty = artist_get_y(s->vram_start);
563     int endx = artist_get_x(s->blockmove_size);
564     int endy = artist_get_y(s->blockmove_size);
565     int pstart = s->line_pattern_start >> 16;
566 
567     draw_line(s, startx, starty, endx, endy, false, -1, pstart);
568     s->line_pattern_skip = pstart;
569 }
570 
571 static void draw_line_pattern_next(ARTISTState *s)
572 {
573     int startx = artist_get_x(s->vram_start);
574     int starty = artist_get_y(s->vram_start);
575     int endx = artist_get_x(s->blockmove_size);
576     int endy = artist_get_y(s->blockmove_size);
577     int line_xy = s->line_xy >> 16;
578 
579     draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip,
580               s->line_pattern_skip + line_xy);
581     s->line_pattern_skip += line_xy;
582     s->image_bitmap_op ^= 2;
583 }
584 
585 static void draw_line_size(ARTISTState *s, bool update_start)
586 {
587     int startx = artist_get_x(s->vram_start);
588     int starty = artist_get_y(s->vram_start);
589     int endx = artist_get_x(s->line_size);
590     int endy = artist_get_y(s->line_size);
591 
592     draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
593 }
594 
595 static void draw_line_xy(ARTISTState *s, bool update_start)
596 {
597     int startx = artist_get_x(s->vram_start);
598     int starty = artist_get_y(s->vram_start);
599     int sizex = artist_get_x(s->blockmove_size);
600     int sizey = artist_get_y(s->blockmove_size);
601     int linexy = s->line_xy >> 16;
602     int endx, endy;
603 
604     endx = startx;
605     endy = starty;
606 
607     if (sizex > 0) {
608         endx = startx + linexy;
609     }
610 
611     if (sizex < 0) {
612         endx = startx;
613         startx -= linexy;
614     }
615 
616     if (sizey > 0) {
617         endy = starty + linexy;
618     }
619 
620     if (sizey < 0) {
621         endy = starty;
622         starty -= linexy;
623     }
624 
625     if (startx < 0) {
626         startx = 0;
627     }
628 
629     if (endx < 0) {
630         endx = 0;
631     }
632 
633     if (starty < 0) {
634         starty = 0;
635     }
636 
637     if (endy < 0) {
638         endy = 0;
639     }
640 
641     draw_line(s, startx, starty, endx, endy, false, -1, -1);
642 }
643 
644 static void draw_line_end(ARTISTState *s, bool update_start)
645 {
646     int startx = artist_get_x(s->vram_start);
647     int starty = artist_get_y(s->vram_start);
648     int endx = artist_get_x(s->line_end);
649     int endy = artist_get_y(s->line_end);
650 
651     draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
652 }
653 
654 static void font_write16(ARTISTState *s, uint16_t val)
655 {
656     struct vram_buffer *buf;
657     uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color;
658     uint16_t mask;
659     int i;
660 
661     unsigned int startx = artist_get_x(s->vram_start);
662     unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y;
663     unsigned int offset = starty * s->width + startx;
664 
665     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
666 
667     if (startx >= buf->width || starty >= buf->height ||
668         offset + 16 >= buf->size) {
669         return;
670     }
671 
672     for (i = 0; i < 16; i++) {
673         mask = 1 << (15 - i);
674         if (val & mask) {
675             artist_rop8(s, buf, offset + i, color);
676         } else {
677             if (!(s->image_bitmap_op & 0x20000000)) {
678                 artist_rop8(s, buf, offset + i, s->bg_color);
679             }
680         }
681     }
682     artist_invalidate_lines(buf, starty, 1);
683 }
684 
685 static void font_write(ARTISTState *s, uint32_t val)
686 {
687     font_write16(s, val >> 16);
688     if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
689         s->vram_start += (s->blockmove_size & 0xffff0000);
690         return;
691     }
692 
693     font_write16(s, val & 0xffff);
694     if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
695         s->vram_start += (s->blockmove_size & 0xffff0000);
696         return;
697     }
698 }
699 
700 static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
701 {
702     /*
703      * FIXME: is there a qemu helper for this?
704      */
705 
706 #if !HOST_BIG_ENDIAN
707     addr ^= 3;
708 #endif
709 
710     switch (size) {
711     case 1:
712         *(uint8_t *)(out + (addr & 3)) = val;
713         break;
714 
715     case 2:
716         *(uint16_t *)(out + (addr & 2)) = val;
717         break;
718 
719     case 4:
720         *(uint32_t *)out = val;
721         break;
722 
723     default:
724         qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size);
725     }
726 }
727 
728 static void artist_vram_write4(ARTISTState *s, struct vram_buffer *buf,
729                                uint32_t offset, uint32_t data)
730 {
731     int i;
732     int mask = s->vram_bitmask >> 28;
733 
734     for (i = 0; i < 4; i++) {
735         if (!(s->image_bitmap_op & 0x20000000) || (mask & 8)) {
736             artist_rop8(s, buf, offset + i, data >> 24);
737             data <<= 8;
738             mask <<= 1;
739         }
740     }
741     memory_region_set_dirty(&buf->mr, offset, 3);
742 }
743 
744 static void artist_vram_write32(ARTISTState *s, struct vram_buffer *buf,
745                                 uint32_t offset, int size, uint32_t data,
746                                 int fg, int bg)
747 {
748     uint32_t mask, vram_bitmask = s->vram_bitmask >> ((4 - size) * 8);
749     int i, pix_count = size * 8;
750 
751     for (i = 0; i < pix_count && offset + i < buf->size; i++) {
752         mask = 1 << (pix_count - 1 - i);
753 
754         if (!(s->image_bitmap_op & 0x20000000) || (vram_bitmask & mask)) {
755             if (data & mask) {
756                 artist_rop8(s, buf, offset + i, fg);
757             } else {
758                 if (!(s->image_bitmap_op & 0x10000002)) {
759                     artist_rop8(s, buf, offset + i, bg);
760                 }
761             }
762         }
763     }
764     memory_region_set_dirty(&buf->mr, offset, pix_count);
765 }
766 
767 static int get_vram_offset(ARTISTState *s, struct vram_buffer *buf,
768                            int pos, int posy)
769 {
770     unsigned int posx, width;
771 
772     width = buf->width;
773     posx = ADDR_TO_X(pos);
774     posy += ADDR_TO_Y(pos);
775     return posy * width + posx;
776 }
777 
778 static int vram_bit_write(ARTISTState *s, uint32_t pos, int posy,
779                           uint32_t data, int size)
780 {
781     struct vram_buffer *buf = vram_write_buffer(s);
782 
783     switch (s->dst_bm_access >> 16) {
784     case 0x3ba0:
785     case 0xbbe0:
786         artist_vram_write4(s, buf, pos, bswap32(data));
787         pos += 4;
788         break;
789 
790     case 0x1360: /* linux */
791         artist_vram_write4(s, buf, get_vram_offset(s, buf, pos, posy), data);
792         pos += 4;
793         break;
794 
795     case 0x13a0:
796         artist_vram_write4(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
797                            data);
798         pos += 16;
799         break;
800 
801     case 0x2ea0:
802         artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
803                             size, data, s->fg_color, s->bg_color);
804         pos += 4;
805         break;
806 
807     case 0x28a0:
808         artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
809                             size, data, 1, 0);
810         pos += 4;
811         break;
812 
813     default:
814         qemu_log_mask(LOG_UNIMP, "%s: unknown dst bm access %08x\n",
815                       __func__, s->dst_bm_access);
816         break;
817     }
818 
819     if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 ||
820         vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) {
821         artist_invalidate_cursor(s);
822     }
823     return pos;
824 }
825 
826 static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
827                               unsigned size)
828 {
829     ARTISTState *s = opaque;
830 
831     s->vram_char_y = 0;
832     trace_artist_vram_write(size, addr, val);
833     vram_bit_write(opaque, addr, 0, val, size);
834 }
835 
836 static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
837 {
838     ARTISTState *s = opaque;
839     struct vram_buffer *buf;
840     unsigned int offset;
841     uint64_t val;
842 
843     buf = vram_read_buffer(s);
844     if (!buf->size) {
845         return 0;
846     }
847 
848     offset = get_vram_offset(s, buf, addr >> 2, 0);
849 
850     if (offset > buf->size) {
851         return 0;
852     }
853 
854     switch (s->src_bm_access >> 16) {
855     case 0x3ba0:
856         val = *(uint32_t *)(buf->data + offset);
857         break;
858 
859     case 0x13a0:
860     case 0x2ea0:
861         val = bswap32(*(uint32_t *)(buf->data + offset));
862         break;
863 
864     default:
865         qemu_log_mask(LOG_UNIMP, "%s: unknown src bm access %08x\n",
866                       __func__, s->dst_bm_access);
867         val = -1ULL;
868         break;
869     }
870     trace_artist_vram_read(size, addr, val);
871     return val;
872 }
873 
874 static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
875                              unsigned size)
876 {
877     ARTISTState *s = opaque;
878     int width, height;
879 
880     trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val);
881 
882     switch (addr & ~3ULL) {
883     case 0x100080:
884         combine_write_reg(addr, val, size, &s->reg_100080);
885         break;
886 
887     case FG_COLOR:
888         combine_write_reg(addr, val, size, &s->fg_color);
889         break;
890 
891     case BG_COLOR:
892         combine_write_reg(addr, val, size, &s->bg_color);
893         break;
894 
895     case VRAM_BITMASK:
896         combine_write_reg(addr, val, size, &s->vram_bitmask);
897         break;
898 
899     case VRAM_WRITE_INCR_Y:
900         vram_bit_write(s, s->vram_pos, s->vram_char_y++, val, size);
901         break;
902 
903     case VRAM_WRITE_INCR_X:
904     case VRAM_WRITE_INCR_X2:
905         s->vram_pos = vram_bit_write(s, s->vram_pos, s->vram_char_y, val, size);
906         break;
907 
908     case VRAM_IDX:
909         combine_write_reg(addr, val, size, &s->vram_pos);
910         s->vram_char_y = 0;
911         s->draw_line_pattern = 0;
912         break;
913 
914     case VRAM_START:
915         combine_write_reg(addr, val, size, &s->vram_start);
916         s->draw_line_pattern = 0;
917         break;
918 
919     case VRAM_START_TRIGGER:
920         combine_write_reg(addr, val, size, &s->vram_start);
921         fill_window(s, artist_get_x(s->vram_start),
922                     artist_get_y(s->vram_start),
923                     artist_get_x(s->blockmove_size),
924                     artist_get_y(s->blockmove_size));
925         break;
926 
927     case VRAM_SIZE_TRIGGER:
928         combine_write_reg(addr, val, size, &s->vram_size);
929 
930         if (size == 2 && !(addr & 2)) {
931             height = artist_get_y(s->blockmove_size);
932         } else {
933             height = artist_get_y(s->vram_size);
934         }
935 
936         if (size == 2 && (addr & 2)) {
937             width = artist_get_x(s->blockmove_size);
938         } else {
939             width = artist_get_x(s->vram_size);
940         }
941 
942         fill_window(s, artist_get_x(s->vram_start),
943                     artist_get_y(s->vram_start),
944                     width, height);
945         break;
946 
947     case LINE_XY:
948         combine_write_reg(addr, val, size, &s->line_xy);
949         if (s->draw_line_pattern) {
950             draw_line_pattern_next(s);
951         } else {
952             draw_line_xy(s, true);
953         }
954         break;
955 
956     case PATTERN_LINE_START:
957         combine_write_reg(addr, val, size, &s->line_pattern_start);
958         s->draw_line_pattern = 1;
959         draw_line_pattern_start(s);
960         break;
961 
962     case LINE_SIZE:
963         combine_write_reg(addr, val, size, &s->line_size);
964         draw_line_size(s, true);
965         break;
966 
967     case LINE_END:
968         combine_write_reg(addr, val, size, &s->line_end);
969         draw_line_end(s, true);
970         break;
971 
972     case BLOCK_MOVE_SIZE:
973         combine_write_reg(addr, val, size, &s->blockmove_size);
974         break;
975 
976     case BLOCK_MOVE_SOURCE:
977         combine_write_reg(addr, val, size, &s->blockmove_source);
978         break;
979 
980     case BLOCK_MOVE_DEST_TRIGGER:
981         combine_write_reg(addr, val, size, &s->blockmove_dest);
982 
983         block_move(s, artist_get_x(s->blockmove_source),
984                    artist_get_y(s->blockmove_source),
985                    artist_get_x(s->blockmove_dest),
986                    artist_get_y(s->blockmove_dest),
987                    artist_get_x(s->blockmove_size),
988                    artist_get_y(s->blockmove_size));
989         break;
990 
991     case BLOCK_MOVE_SIZE_TRIGGER:
992         combine_write_reg(addr, val, size, &s->blockmove_size);
993 
994         block_move(s,
995                    artist_get_x(s->blockmove_source),
996                    artist_get_y(s->blockmove_source),
997                    artist_get_x(s->vram_start),
998                    artist_get_y(s->vram_start),
999                    artist_get_x(s->blockmove_size),
1000                    artist_get_y(s->blockmove_size));
1001         break;
1002 
1003     case PLANE_MASK:
1004         combine_write_reg(addr, val, size, &s->plane_mask);
1005         break;
1006 
1007     case DST_SRC_BM_ACCESS:
1008         combine_write_reg(addr, val, size, &s->dst_bm_access);
1009         combine_write_reg(addr, val, size, &s->src_bm_access);
1010         break;
1011 
1012     case DST_BM_ACCESS:
1013         combine_write_reg(addr, val, size, &s->dst_bm_access);
1014         break;
1015 
1016     case SRC_BM_ACCESS:
1017         combine_write_reg(addr, val, size, &s->src_bm_access);
1018         break;
1019 
1020     case CONTROL_PLANE:
1021         combine_write_reg(addr, val, size, &s->control_plane);
1022         break;
1023 
1024     case TRANSFER_DATA:
1025         combine_write_reg(addr, val, size, &s->transfer_data);
1026         break;
1027 
1028     case 0x300200:
1029         combine_write_reg(addr, val, size, &s->reg_300200);
1030         break;
1031 
1032     case 0x300208:
1033         combine_write_reg(addr, val, size, &s->reg_300208);
1034         break;
1035 
1036     case 0x300218:
1037         combine_write_reg(addr, val, size, &s->reg_300218);
1038         break;
1039 
1040     case CURSOR_POS:
1041         artist_invalidate_cursor(s);
1042         combine_write_reg(addr, val, size, &s->cursor_pos);
1043         artist_invalidate_cursor(s);
1044         break;
1045 
1046     case CURSOR_CTRL:
1047         combine_write_reg(addr, val, size, &s->cursor_cntrl);
1048         break;
1049 
1050     case IMAGE_BITMAP_OP:
1051         combine_write_reg(addr, val, size, &s->image_bitmap_op);
1052         break;
1053 
1054     case FONT_WRITE_INCR_Y:
1055         combine_write_reg(addr, val, size, &s->font_write1);
1056         font_write(s, s->font_write1);
1057         break;
1058 
1059     case FONT_WRITE_START:
1060         combine_write_reg(addr, val, size, &s->font_write2);
1061         s->font_write_pos_y = 0;
1062         font_write(s, s->font_write2);
1063         break;
1064 
1065     case 300104:
1066         break;
1067 
1068     default:
1069         qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx
1070                       " val=%08" PRIx64 " size=%d\n",
1071                       __func__, addr, val, size);
1072         break;
1073     }
1074 }
1075 
1076 static uint64_t combine_read_reg(hwaddr addr, int size, void *in)
1077 {
1078     /*
1079      * FIXME: is there a qemu helper for this?
1080      */
1081 
1082 #if !HOST_BIG_ENDIAN
1083     addr ^= 3;
1084 #endif
1085 
1086     switch (size) {
1087     case 1:
1088         return *(uint8_t *)(in + (addr & 3));
1089 
1090     case 2:
1091         return *(uint16_t *)(in + (addr & 2));
1092 
1093     case 4:
1094         return *(uint32_t *)in;
1095 
1096     default:
1097         qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size);
1098         return 0;
1099     }
1100 }
1101 
1102 static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
1103 {
1104     ARTISTState *s = opaque;
1105     uint32_t val = 0;
1106 
1107     switch (addr & ~3ULL) {
1108         /* Unknown status registers */
1109     case 0:
1110         break;
1111 
1112     case 0x211110:
1113         val = (s->width << 16) | s->height;
1114         if (s->depth == 1) {
1115             val |= 1 << 31;
1116         }
1117         break;
1118 
1119     case 0x100000:
1120     case 0x300000:
1121     case 0x300004:
1122     case 0x300308:
1123     case 0x380000:
1124         break;
1125 
1126     case 0x300008:
1127     case 0x380008:
1128         /*
1129          * FIFO ready flag. we're not emulating the FIFOs
1130          * so we're always ready
1131          */
1132         val = 0x10;
1133         break;
1134 
1135     case 0x300200:
1136         val = s->reg_300200;
1137         break;
1138 
1139     case 0x300208:
1140         val = s->reg_300208;
1141         break;
1142 
1143     case 0x300218:
1144         val = s->reg_300218;
1145         break;
1146 
1147     case 0x30023c:
1148         val = 0xac4ffdac;
1149         break;
1150 
1151     case 0x380004:
1152         /* 0x02000000 Buserror */
1153         val = 0x6dc20006;
1154         break;
1155 
1156     default:
1157         qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx
1158                       " size %d\n", __func__, addr, size);
1159         break;
1160     }
1161     val = combine_read_reg(addr, size, &val);
1162     trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val);
1163     return val;
1164 }
1165 
1166 static const MemoryRegionOps artist_reg_ops = {
1167     .read = artist_reg_read,
1168     .write = artist_reg_write,
1169     .endianness = DEVICE_NATIVE_ENDIAN,
1170     .impl.min_access_size = 1,
1171     .impl.max_access_size = 4,
1172 };
1173 
1174 static const MemoryRegionOps artist_vram_ops = {
1175     .read = artist_vram_read,
1176     .write = artist_vram_write,
1177     .endianness = DEVICE_NATIVE_ENDIAN,
1178     .impl.min_access_size = 1,
1179     .impl.max_access_size = 4,
1180 };
1181 
1182 static void artist_draw_cursor(ARTISTState *s)
1183 {
1184     DisplaySurface *surface = qemu_console_surface(s->con);
1185     uint32_t *data = (uint32_t *)surface_data(surface);
1186     struct vram_buffer *cursor0, *cursor1 , *buf;
1187     int cx, cy, cursor_pos_x, cursor_pos_y;
1188 
1189     cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1];
1190     cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2];
1191     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1192 
1193     artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y);
1194 
1195     for (cy = 0; cy < s->cursor_height; cy++) {
1196 
1197         for (cx = 0; cx < s->cursor_width; cx++) {
1198 
1199             if (cursor_pos_y + cy < 0 ||
1200                 cursor_pos_x + cx < 0 ||
1201                 cursor_pos_y + cy > buf->height - 1 ||
1202                 cursor_pos_x + cx > buf->width) {
1203                 continue;
1204             }
1205 
1206             int dstoffset = (cursor_pos_y + cy) * s->width +
1207                 (cursor_pos_x + cx);
1208 
1209             if (cursor0->data[cy * cursor0->width + cx]) {
1210                 data[dstoffset] = 0;
1211             } else {
1212                 if (cursor1->data[cy * cursor1->width + cx]) {
1213                     data[dstoffset] = 0xffffff;
1214                 }
1215             }
1216         }
1217     }
1218 }
1219 
1220 static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
1221                              int width, int pitch)
1222 {
1223     ARTISTState *s = ARTIST(opaque);
1224     uint32_t *cmap, *data = (uint32_t *)d;
1225     int x;
1226 
1227     cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400);
1228 
1229     for (x = 0; x < s->width; x++) {
1230         *data++ = cmap[*src++];
1231     }
1232 }
1233 
1234 static void artist_update_display(void *opaque)
1235 {
1236     ARTISTState *s = opaque;
1237     DisplaySurface *surface = qemu_console_surface(s->con);
1238     int first = 0, last;
1239 
1240     framebuffer_update_display(surface, &s->fbsection, s->width, s->height,
1241                                s->width, s->width * 4, 0, 0, artist_draw_line,
1242                                s, &first, &last);
1243 
1244     artist_draw_cursor(s);
1245 
1246     if (first >= 0) {
1247         dpy_gfx_update(s->con, 0, first, s->width, last - first + 1);
1248     }
1249 }
1250 
1251 static void artist_invalidate(void *opaque)
1252 {
1253     ARTISTState *s = ARTIST(opaque);
1254     struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1255 
1256     memory_region_set_dirty(&buf->mr, 0, buf->size);
1257 }
1258 
1259 static const GraphicHwOps artist_ops = {
1260     .invalidate  = artist_invalidate,
1261     .gfx_update = artist_update_display,
1262 };
1263 
1264 static void artist_initfn(Object *obj)
1265 {
1266     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1267     ARTISTState *s = ARTIST(obj);
1268 
1269     memory_region_init_io(&s->reg, obj, &artist_reg_ops, s, "artist.reg",
1270                           4 * MiB);
1271     memory_region_init_io(&s->vram_mem, obj, &artist_vram_ops, s, "artist.vram",
1272                           8 * MiB);
1273     sysbus_init_mmio(sbd, &s->reg);
1274     sysbus_init_mmio(sbd, &s->vram_mem);
1275 }
1276 
1277 static void artist_create_buffer(ARTISTState *s, const char *name,
1278                                  hwaddr *offset, unsigned int idx,
1279                                  int width, int height)
1280 {
1281     struct vram_buffer *buf = s->vram_buffer + idx;
1282 
1283     memory_region_init_ram(&buf->mr, NULL, name, width * height,
1284                            &error_fatal);
1285     memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0);
1286 
1287     buf->data = memory_region_get_ram_ptr(&buf->mr);
1288     buf->size = height * width;
1289     buf->width = width;
1290     buf->height = height;
1291 
1292     *offset += buf->size;
1293 }
1294 
1295 static void artist_realizefn(DeviceState *dev, Error **errp)
1296 {
1297     ARTISTState *s = ARTIST(dev);
1298     struct vram_buffer *buf;
1299     hwaddr offset = 0;
1300 
1301     if (s->width > 2048 || s->height > 2048) {
1302         error_report("artist: screen size can not exceed 2048 x 2048 pixel.");
1303         s->width = MIN(s->width, 2048);
1304         s->height = MIN(s->height, 2048);
1305     }
1306 
1307     if (s->width < 640 || s->height < 480) {
1308         error_report("artist: minimum screen size is 640 x 480 pixel.");
1309         s->width = MAX(s->width, 640);
1310         s->height = MAX(s->height, 480);
1311     }
1312 
1313     memory_region_init(&s->mem_as_root, OBJECT(dev), "artist", ~0ull);
1314     address_space_init(&s->as, &s->mem_as_root, "artist");
1315 
1316     artist_create_buffer(s, "cmap", &offset, ARTIST_BUFFER_CMAP, 2048, 4);
1317     artist_create_buffer(s, "ap", &offset, ARTIST_BUFFER_AP,
1318                          s->width, s->height);
1319     artist_create_buffer(s, "cursor1", &offset, ARTIST_BUFFER_CURSOR1, 64, 64);
1320     artist_create_buffer(s, "cursor2", &offset, ARTIST_BUFFER_CURSOR2, 64, 64);
1321     artist_create_buffer(s, "attribute", &offset, ARTIST_BUFFER_ATTRIBUTE,
1322                          64, 64);
1323 
1324     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1325     framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0,
1326                                       buf->width, buf->height);
1327     /*
1328      * no idea whether the cursor is fixed size or not, so assume 32x32 which
1329      * seems sufficient for HP-UX X11.
1330      */
1331     s->cursor_height = 32;
1332     s->cursor_width = 32;
1333 
1334     /*
1335      * These two registers are not initialized by seabios's STI implementation.
1336      * Initialize them here to sane values so artist also works with older
1337      * (not-fixed) seabios versions.
1338      */
1339     s->image_bitmap_op = 0x23000300;
1340     s->plane_mask = 0xff;
1341 
1342     s->con = graphic_console_init(dev, 0, &artist_ops, s);
1343     qemu_console_resize(s->con, s->width, s->height);
1344 }
1345 
1346 static int vmstate_artist_post_load(void *opaque, int version_id)
1347 {
1348     artist_invalidate(opaque);
1349     return 0;
1350 }
1351 
1352 static const VMStateDescription vmstate_artist = {
1353     .name = "artist",
1354     .version_id = 2,
1355     .minimum_version_id = 2,
1356     .post_load = vmstate_artist_post_load,
1357     .fields = (VMStateField[]) {
1358         VMSTATE_UINT16(height, ARTISTState),
1359         VMSTATE_UINT16(width, ARTISTState),
1360         VMSTATE_UINT16(depth, ARTISTState),
1361         VMSTATE_UINT32(fg_color, ARTISTState),
1362         VMSTATE_UINT32(bg_color, ARTISTState),
1363         VMSTATE_UINT32(vram_char_y, ARTISTState),
1364         VMSTATE_UINT32(vram_bitmask, ARTISTState),
1365         VMSTATE_UINT32(vram_start, ARTISTState),
1366         VMSTATE_UINT32(vram_pos, ARTISTState),
1367         VMSTATE_UINT32(vram_size, ARTISTState),
1368         VMSTATE_UINT32(blockmove_source, ARTISTState),
1369         VMSTATE_UINT32(blockmove_dest, ARTISTState),
1370         VMSTATE_UINT32(blockmove_size, ARTISTState),
1371         VMSTATE_UINT32(line_size, ARTISTState),
1372         VMSTATE_UINT32(line_end, ARTISTState),
1373         VMSTATE_UINT32(line_xy, ARTISTState),
1374         VMSTATE_UINT32(cursor_pos, ARTISTState),
1375         VMSTATE_UINT32(cursor_cntrl, ARTISTState),
1376         VMSTATE_UINT32(cursor_height, ARTISTState),
1377         VMSTATE_UINT32(cursor_width, ARTISTState),
1378         VMSTATE_UINT32(plane_mask, ARTISTState),
1379         VMSTATE_UINT32(reg_100080, ARTISTState),
1380         VMSTATE_UINT32(reg_300200, ARTISTState),
1381         VMSTATE_UINT32(reg_300208, ARTISTState),
1382         VMSTATE_UINT32(reg_300218, ARTISTState),
1383         VMSTATE_UINT32(dst_bm_access, ARTISTState),
1384         VMSTATE_UINT32(src_bm_access, ARTISTState),
1385         VMSTATE_UINT32(control_plane, ARTISTState),
1386         VMSTATE_UINT32(transfer_data, ARTISTState),
1387         VMSTATE_UINT32(image_bitmap_op, ARTISTState),
1388         VMSTATE_UINT32(font_write1, ARTISTState),
1389         VMSTATE_UINT32(font_write2, ARTISTState),
1390         VMSTATE_UINT32(font_write_pos_y, ARTISTState),
1391         VMSTATE_END_OF_LIST()
1392     }
1393 };
1394 
1395 static Property artist_properties[] = {
1396     DEFINE_PROP_UINT16("width",        ARTISTState, width, 1280),
1397     DEFINE_PROP_UINT16("height",       ARTISTState, height, 1024),
1398     DEFINE_PROP_UINT16("depth",        ARTISTState, depth, 8),
1399     DEFINE_PROP_END_OF_LIST(),
1400 };
1401 
1402 static void artist_reset(DeviceState *qdev)
1403 {
1404 }
1405 
1406 static void artist_class_init(ObjectClass *klass, void *data)
1407 {
1408     DeviceClass *dc = DEVICE_CLASS(klass);
1409 
1410     dc->realize = artist_realizefn;
1411     dc->vmsd = &vmstate_artist;
1412     dc->reset = artist_reset;
1413     device_class_set_props(dc, artist_properties);
1414 }
1415 
1416 static const TypeInfo artist_info = {
1417     .name          = TYPE_ARTIST,
1418     .parent        = TYPE_SYS_BUS_DEVICE,
1419     .instance_size = sizeof(ARTISTState),
1420     .instance_init = artist_initfn,
1421     .class_init    = artist_class_init,
1422 };
1423 
1424 static void artist_register_types(void)
1425 {
1426     type_register_static(&artist_info);
1427 }
1428 
1429 type_init(artist_register_types)
1430