xref: /openbmc/qemu/hw/display/artist.c (revision 3615cea4714f94d1db61bd6618a3a66a6b014f9d)
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-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"
25 
26 #define TYPE_ARTIST "artist"
27 OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState, ARTIST)
28 
29 #ifdef HOST_WORDS_BIGENDIAN
30 #define ROP8OFF(_i) (3 - (_i))
31 #else
32 #define ROP8OFF
33 #endif
34 
35 struct vram_buffer {
36     MemoryRegion mr;
37     uint8_t *data;
38     unsigned int size;
39     unsigned int width;
40     unsigned int height;
41 };
42 
43 struct ARTISTState {
44     SysBusDevice parent_obj;
45 
46     QemuConsole *con;
47     MemoryRegion vram_mem;
48     MemoryRegion mem_as_root;
49     MemoryRegion reg;
50     MemoryRegionSection fbsection;
51 
52     void *vram_int_mr;
53     AddressSpace as;
54 
55     struct vram_buffer vram_buffer[16];
56 
57     uint16_t width;
58     uint16_t height;
59     uint16_t depth;
60 
61     uint32_t fg_color;
62     uint32_t bg_color;
63 
64     uint32_t vram_char_y;
65     uint32_t vram_bitmask;
66 
67     uint32_t vram_start;
68     uint32_t vram_pos;
69 
70     uint32_t vram_size;
71 
72     uint32_t blockmove_source;
73     uint32_t blockmove_dest;
74     uint32_t blockmove_size;
75 
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;
81 
82     uint32_t cursor_pos;
83     uint32_t cursor_cntrl;
84 
85     uint32_t cursor_height;
86     uint32_t cursor_width;
87 
88     uint32_t plane_mask;
89 
90     uint32_t reg_100080;
91     uint32_t reg_300200;
92     uint32_t reg_300208;
93     uint32_t reg_300218;
94 
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;
100 
101     uint32_t font_write1;
102     uint32_t font_write2;
103     uint32_t font_write_pos_y;
104 
105     int draw_line_pattern;
106 };
107 
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;
116 
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     DST_SRC_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;
148 
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;
156 
157 #define REG_NAME(_x) case _x: return " "#_x;
158 static const char *artist_reg_name(uint64_t addr)
159 {
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(DST_SRC_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);
190     }
191     return "";
192 }
193 #undef REG_NAME
194 
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)
198 
199 static int16_t artist_get_x(uint32_t reg)
200 {
201     return reg >> 16;
202 }
203 
204 static int16_t artist_get_y(uint32_t reg)
205 {
206     return reg & 0xffff;
207 }
208 
209 static void artist_invalidate_lines(struct vram_buffer *buf,
210                                     int starty, int height)
211 {
212     int start = starty * buf->width;
213     int size;
214 
215     if (starty + height > buf->height)
216         height = buf->height - starty;
217 
218     size = height * buf->width;
219 
220     if (start + size <= buf->size) {
221         memory_region_set_dirty(&buf->mr, start, size);
222     }
223 }
224 
225 static int vram_write_bufidx(ARTISTState *s)
226 {
227     return (s->dst_bm_access >> 12) & 0x0f;
228 }
229 
230 static int vram_read_bufidx(ARTISTState *s)
231 {
232     return (s->src_bm_access >> 12) & 0x0f;
233 }
234 
235 static struct vram_buffer *vram_read_buffer(ARTISTState *s)
236 {
237     return &s->vram_buffer[vram_read_bufidx(s)];
238 }
239 
240 static struct vram_buffer *vram_write_buffer(ARTISTState *s)
241 {
242     return &s->vram_buffer[vram_write_bufidx(s)];
243 }
244 
245 static uint8_t artist_get_color(ARTISTState *s)
246 {
247     if (s->image_bitmap_op & 2) {
248         return s->fg_color;
249     } else {
250         return s->bg_color;
251     }
252 }
253 
254 static artist_rop_t artist_get_op(ARTISTState *s)
255 {
256     return (s->image_bitmap_op >> 8) & 0xf;
257 }
258 
259 static void artist_rop8(ARTISTState *s, struct vram_buffer *buf,
260                         unsigned int offset, uint8_t val)
261 {
262     const artist_rop_t op = artist_get_op(s);
263     uint8_t plane_mask;
264     uint8_t *dst;
265 
266     if (offset >= buf->size) {
267         qemu_log_mask(LOG_GUEST_ERROR,
268                       "rop8 offset:%u bufsize:%u\n", offset, buf->size);
269         return;
270     }
271     dst = buf->data + offset;
272     plane_mask = s->plane_mask & 0xff;
273 
274     switch (op) {
275     case ARTIST_ROP_CLEAR:
276         *dst &= ~plane_mask;
277         break;
278 
279     case ARTIST_ROP_COPY:
280         *dst = (*dst & ~plane_mask) | (val & plane_mask);
281         break;
282 
283     case ARTIST_ROP_XOR:
284         *dst ^= val & plane_mask;
285         break;
286 
287     case ARTIST_ROP_NOT_DST:
288         *dst ^= plane_mask;
289         break;
290 
291     case ARTIST_ROP_SET:
292         *dst |= plane_mask;
293         break;
294 
295     default:
296         qemu_log_mask(LOG_UNIMP, "%s: unsupported rop %d\n", __func__, op);
297         break;
298     }
299 }
300 
301 static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y)
302 {
303     /*
304      * Don't know whether these magic offset values are configurable via
305      * some register. They seem to be the same for all resolutions.
306      * The cursor values provided in the registers are:
307      * X-value: -295 (for HP-UX 11) and 338 (for HP-UX 10.20) up to 2265
308      * Y-value: 1146 down to 0
309      * The emulated Artist graphic is like a CRX graphic, and as such
310      * it's usually fixed at 1280x1024 pixels.
311      * Because of the maximum Y-value of 1146 you can not choose a higher
312      * vertical resolution on HP-UX (unless you disable the mouse).
313      */
314 
315     static int offset = 338;
316     int lx;
317 
318     /* ignore if uninitialized */
319     if (s->cursor_pos == 0) {
320         *x = *y = 0;
321         return;
322     }
323 
324     lx = artist_get_x(s->cursor_pos);
325     if (lx < offset)
326         offset = lx;
327     *x = (lx - offset) / 2;
328 
329     *y = 1146 - artist_get_y(s->cursor_pos);
330 
331     /* subtract cursor offset from cursor control register */
332     *x -= (s->cursor_cntrl & 0xf0) >> 4;
333     *y -= (s->cursor_cntrl & 0x0f);
334 
335     if (*x > s->width) {
336         *x = s->width;
337     }
338 
339     if (*y > s->height) {
340         *y = s->height;
341     }
342 }
343 
344 static void artist_invalidate_cursor(ARTISTState *s)
345 {
346     int x, y;
347     artist_get_cursor_pos(s, &x, &y);
348     artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP],
349                             y, s->cursor_height);
350 }
351 
352 static void block_move(ARTISTState *s,
353                        unsigned int source_x, unsigned int source_y,
354                        unsigned int dest_x,   unsigned int dest_y,
355                        unsigned int width,    unsigned int height)
356 {
357     struct vram_buffer *buf;
358     int line, endline, lineincr, startcolumn, endcolumn, columnincr, column;
359     unsigned int dst, src;
360 
361     trace_artist_block_move(source_x, source_y, dest_x, dest_y, width, height);
362 
363     if (s->control_plane != 0) {
364         /* We don't support CONTROL_PLANE accesses */
365         qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
366                       s->control_plane);
367         return;
368     }
369 
370     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
371     if (height > buf->height) {
372         height = buf->height;
373     }
374     if (width > buf->width) {
375         width = buf->width;
376     }
377 
378     if (dest_y > source_y) {
379         /* move down */
380         line = height - 1;
381         endline = -1;
382         lineincr = -1;
383     } else {
384         /* move up */
385         line = 0;
386         endline = height;
387         lineincr = 1;
388     }
389 
390     if (dest_x > source_x) {
391         /* move right */
392         startcolumn = width - 1;
393         endcolumn = -1;
394         columnincr = -1;
395     } else {
396         /* move left */
397         startcolumn = 0;
398         endcolumn = width;
399         columnincr = 1;
400     }
401 
402     for ( ; line != endline; line += lineincr) {
403         src = source_x + ((line + source_y) * buf->width) + startcolumn;
404         dst = dest_x + ((line + dest_y) * buf->width) + startcolumn;
405 
406         for (column = startcolumn; column != endcolumn; column += columnincr) {
407             if (dst >= buf->size || src >= buf->size) {
408                 continue;
409             }
410             artist_rop8(s, buf, dst, buf->data[src]);
411             src += columnincr;
412             dst += columnincr;
413         }
414     }
415 
416     artist_invalidate_lines(buf, dest_y, height);
417 }
418 
419 static void fill_window(ARTISTState *s,
420                         unsigned int startx, unsigned int starty,
421                         unsigned int width,  unsigned int height)
422 {
423     unsigned int offset;
424     uint8_t color = artist_get_color(s);
425     struct vram_buffer *buf;
426     int x, y;
427 
428     trace_artist_fill_window(startx, starty, width, height,
429                              s->image_bitmap_op, s->control_plane);
430 
431     if (s->control_plane != 0) {
432         /* We don't support CONTROL_PLANE accesses */
433         qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
434                       s->control_plane);
435         return;
436     }
437 
438     if (s->reg_100080 == 0x7d) {
439         /*
440          * Not sure what this register really does, but
441          * 0x7d seems to enable autoincremt of the Y axis
442          * by the current block move height.
443          */
444         height = artist_get_y(s->blockmove_size);
445         s->vram_start += height;
446     }
447 
448     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
449 
450     for (y = starty; y < starty + height; y++) {
451         offset = y * s->width;
452 
453         for (x = startx; x < startx + width; x++) {
454             artist_rop8(s, buf, offset + x, color);
455         }
456     }
457     artist_invalidate_lines(buf, starty, height);
458 }
459 
460 static void draw_line(ARTISTState *s,
461                       unsigned int x1, unsigned int y1,
462                       unsigned int x2, unsigned int y2,
463                       bool update_start, int skip_pix, int max_pix)
464 {
465     struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
466     uint8_t color;
467     int dx, dy, t, e, x, y, incy, diago, horiz;
468     bool c1;
469 
470     trace_artist_draw_line(x1, y1, x2, y2);
471 
472     if ((x1 >= buf->width && x2 >= buf->width) ||
473         (y1 >= buf->height && y2 >= buf->height)) {
474 	return;
475     }
476 
477 
478     if (update_start) {
479         s->vram_start = (x2 << 16) | y2;
480     }
481 
482     if (x2 > x1) {
483         dx = x2 - x1;
484     } else {
485         dx = x1 - x2;
486     }
487     if (y2 > y1) {
488         dy = y2 - y1;
489     } else {
490         dy = y1 - y2;
491     }
492 
493     c1 = false;
494     if (dy > dx) {
495         t = y2;
496         y2 = x2;
497         x2 = t;
498 
499         t = y1;
500         y1 = x1;
501         x1 = t;
502 
503         t = dx;
504         dx = dy;
505         dy = t;
506 
507         c1 = true;
508     }
509 
510     if (x1 > x2) {
511         t = y2;
512         y2 = y1;
513         y1 = t;
514 
515         t = x1;
516         x1 = x2;
517         x2 = t;
518     }
519 
520     horiz = dy << 1;
521     diago = (dy - dx) << 1;
522     e = (dy << 1) - dx;
523 
524     if (y1 <= y2) {
525         incy = 1;
526     } else {
527         incy = -1;
528     }
529     x = x1;
530     y = y1;
531     color = artist_get_color(s);
532 
533     do {
534         unsigned int ofs;
535 
536         if (c1) {
537             ofs = x * s->width + y;
538         } else {
539             ofs = y * s->width + x;
540         }
541 
542         if (skip_pix > 0) {
543             skip_pix--;
544         } else {
545             artist_rop8(s, buf, ofs, color);
546         }
547 
548         if (e > 0) {
549             y  += incy;
550             e  += diago;
551         } else {
552             e += horiz;
553         }
554         x++;
555     } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
556     if (c1)
557         artist_invalidate_lines(buf, x, dy+1);
558     else
559         artist_invalidate_lines(buf, y, dx+1);
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 #ifndef HOST_WORDS_BIGENDIAN
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 #ifndef HOST_WORDS_BIGENDIAN
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