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