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