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