xref: /openbmc/qemu/hw/display/artist.c (revision b15e402f)
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/typedefs.h"
13 #include "qemu/log.h"
14 #include "qemu/module.h"
15 #include "qemu/units.h"
16 #include "qapi/error.h"
17 #include "hw/sysbus.h"
18 #include "hw/loader.h"
19 #include "hw/qdev-core.h"
20 #include "hw/qdev-properties.h"
21 #include "migration/vmstate.h"
22 #include "ui/console.h"
23 #include "trace.h"
24 #include "framebuffer.h"
25 
26 #define TYPE_ARTIST "artist"
27 #define ARTIST(obj) OBJECT_CHECK(ARTISTState, (obj), TYPE_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 typedef 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 
84     uint32_t cursor_height;
85     uint32_t cursor_width;
86 
87     uint32_t plane_mask;
88 
89     uint32_t reg_100080;
90     uint32_t reg_300200;
91     uint32_t reg_300208;
92     uint32_t reg_300218;
93 
94     uint32_t cmap_bm_access;
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 } ARTISTState;
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     CMAP_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(CMAP_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_pix_per_transfer(ARTISTState *s)
226 {
227     if (s->cmap_bm_access) {
228         return 1 << ((s->cmap_bm_access >> 27) & 0x0f);
229     } else {
230         return 1 << ((s->dst_bm_access >> 27) & 0x0f);
231     }
232 }
233 
234 static int vram_pixel_length(ARTISTState *s)
235 {
236     if (s->cmap_bm_access) {
237         return (s->cmap_bm_access >> 24) & 0x07;
238     } else {
239         return (s->dst_bm_access >> 24) & 0x07;
240     }
241 }
242 
243 static int vram_write_bufidx(ARTISTState *s)
244 {
245     if (s->cmap_bm_access) {
246         return (s->cmap_bm_access >> 12) & 0x0f;
247     } else {
248         return (s->dst_bm_access >> 12) & 0x0f;
249     }
250 }
251 
252 static int vram_read_bufidx(ARTISTState *s)
253 {
254     if (s->cmap_bm_access) {
255         return (s->cmap_bm_access >> 12) & 0x0f;
256     } else {
257         return (s->src_bm_access >> 12) & 0x0f;
258     }
259 }
260 
261 static struct vram_buffer *vram_read_buffer(ARTISTState *s)
262 {
263     return &s->vram_buffer[vram_read_bufidx(s)];
264 }
265 
266 static struct vram_buffer *vram_write_buffer(ARTISTState *s)
267 {
268     return &s->vram_buffer[vram_write_bufidx(s)];
269 }
270 
271 static uint8_t artist_get_color(ARTISTState *s)
272 {
273     if (s->image_bitmap_op & 2) {
274         return s->fg_color;
275     } else {
276         return s->bg_color;
277     }
278 }
279 
280 static artist_rop_t artist_get_op(ARTISTState *s)
281 {
282     return (s->image_bitmap_op >> 8) & 0xf;
283 }
284 
285 static void artist_rop8(ARTISTState *s, struct vram_buffer *buf,
286                         unsigned int offset, uint8_t val)
287 {
288     const artist_rop_t op = artist_get_op(s);
289     uint8_t plane_mask;
290     uint8_t *dst;
291 
292     if (offset >= buf->size) {
293         qemu_log_mask(LOG_GUEST_ERROR,
294                       "rop8 offset:%u bufsize:%u\n", offset, buf->size);
295         return;
296     }
297     dst = buf->data + offset;
298     plane_mask = s->plane_mask & 0xff;
299 
300     switch (op) {
301     case ARTIST_ROP_CLEAR:
302         *dst &= ~plane_mask;
303         break;
304 
305     case ARTIST_ROP_COPY:
306         *dst = (*dst & ~plane_mask) | (val & plane_mask);
307         break;
308 
309     case ARTIST_ROP_XOR:
310         *dst ^= val & plane_mask;
311         break;
312 
313     case ARTIST_ROP_NOT_DST:
314         *dst ^= plane_mask;
315         break;
316 
317     case ARTIST_ROP_SET:
318         *dst |= plane_mask;
319         break;
320 
321     default:
322         qemu_log_mask(LOG_UNIMP, "%s: unsupported rop %d\n", __func__, op);
323         break;
324     }
325 }
326 
327 static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y)
328 {
329     /*
330      * Don't know whether these magic offset values are configurable via
331      * some register. They are the same for all resolutions, so don't
332      * bother about it.
333      */
334 
335     *y = 0x47a - artist_get_y(s->cursor_pos);
336     *x = ((artist_get_x(s->cursor_pos) - 338) / 2);
337 
338     if (*x > s->width) {
339         *x = 0;
340     }
341 
342     if (*y > s->height) {
343         *y = 0;
344     }
345 }
346 
347 static void artist_invalidate_cursor(ARTISTState *s)
348 {
349     int x, y;
350     artist_get_cursor_pos(s, &x, &y);
351     artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP],
352                             y, s->cursor_height);
353 }
354 
355 static void vram_bit_write(ARTISTState *s, int posy, bool incr_x,
356                            int size, uint32_t data)
357 {
358     struct vram_buffer *buf;
359     uint32_t vram_bitmask = s->vram_bitmask;
360     int mask, i, pix_count, pix_length;
361     unsigned int posx, offset, width;
362     uint8_t *data8, *p;
363 
364     pix_count = vram_write_pix_per_transfer(s);
365     pix_length = vram_pixel_length(s);
366 
367     buf = vram_write_buffer(s);
368     width = buf->width;
369 
370     if (s->cmap_bm_access) {
371         offset = s->vram_pos;
372     } else {
373         posx = ADDR_TO_X(s->vram_pos >> 2);
374         posy += ADDR_TO_Y(s->vram_pos >> 2);
375         offset = posy * width + posx;
376     }
377 
378     if (!buf->size || offset >= buf->size) {
379         return;
380     }
381 
382     p = buf->data;
383 
384     if (pix_count > size * 8) {
385         pix_count = size * 8;
386     }
387 
388     switch (pix_length) {
389     case 0:
390         if (s->image_bitmap_op & 0x20000000) {
391             data &= vram_bitmask;
392         }
393 
394         for (i = 0; i < pix_count; i++) {
395             uint32_t off = offset + pix_count - 1 - i;
396             if (off < buf->size) {
397                 artist_rop8(s, buf, off,
398                             (data & 1) ? (s->plane_mask >> 24) : 0);
399             }
400             data >>= 1;
401         }
402         memory_region_set_dirty(&buf->mr, offset, pix_count);
403         break;
404 
405     case 3:
406         if (s->cmap_bm_access) {
407             if (offset + 3 < buf->size) {
408                 *(uint32_t *)(p + offset) = data;
409             }
410             break;
411         }
412         data8 = (uint8_t *)&data;
413 
414         for (i = 3; i >= 0; i--) {
415             if (!(s->image_bitmap_op & 0x20000000) ||
416                 s->vram_bitmask & (1 << (28 + i))) {
417                 uint32_t off = offset + 3 - i;
418                 if (off < buf->size) {
419                     artist_rop8(s, buf, off, data8[ROP8OFF(i)]);
420                 }
421             }
422         }
423         memory_region_set_dirty(&buf->mr, offset, 3);
424         break;
425 
426     case 6:
427         switch (size) {
428         default:
429         case 4:
430             vram_bitmask = s->vram_bitmask;
431             break;
432 
433         case 2:
434             vram_bitmask = s->vram_bitmask >> 16;
435             break;
436 
437         case 1:
438             vram_bitmask = s->vram_bitmask >> 24;
439             break;
440         }
441 
442         for (i = 0; i < pix_count && offset + i < buf->size; i++) {
443             mask = 1 << (pix_count - 1 - i);
444 
445             if (!(s->image_bitmap_op & 0x20000000) ||
446                 (vram_bitmask & mask)) {
447                 if (data & mask) {
448                     artist_rop8(s, buf, offset + i, s->fg_color);
449                 } else {
450                     if (!(s->image_bitmap_op & 0x10000002)) {
451                         artist_rop8(s, buf, offset + i, s->bg_color);
452                     }
453                 }
454             }
455         }
456         memory_region_set_dirty(&buf->mr, offset, pix_count);
457         break;
458 
459     default:
460         qemu_log_mask(LOG_UNIMP, "%s: unknown pixel length %d\n",
461                       __func__, pix_length);
462         break;
463     }
464 
465     if (incr_x) {
466         if (s->cmap_bm_access) {
467             s->vram_pos += 4;
468         } else {
469             s->vram_pos += pix_count << 2;
470         }
471     }
472 
473     if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 ||
474         vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) {
475         artist_invalidate_cursor(s);
476     }
477 }
478 
479 static void block_move(ARTISTState *s,
480                        unsigned int source_x, unsigned int source_y,
481                        unsigned int dest_x,   unsigned int dest_y,
482                        unsigned int width,    unsigned int height)
483 {
484     struct vram_buffer *buf;
485     int line, endline, lineincr, startcolumn, endcolumn, columnincr, column;
486     unsigned int dst, src;
487 
488     trace_artist_block_move(source_x, source_y, dest_x, dest_y, width, height);
489 
490     if (s->control_plane != 0) {
491         /* We don't support CONTROL_PLANE accesses */
492         qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
493                       s->control_plane);
494         return;
495     }
496 
497     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
498     if (height > buf->height) {
499         height = buf->height;
500     }
501     if (width > buf->width) {
502         width = buf->width;
503     }
504 
505     if (dest_y > source_y) {
506         /* move down */
507         line = height - 1;
508         endline = -1;
509         lineincr = -1;
510     } else {
511         /* move up */
512         line = 0;
513         endline = height;
514         lineincr = 1;
515     }
516 
517     if (dest_x > source_x) {
518         /* move right */
519         startcolumn = width - 1;
520         endcolumn = -1;
521         columnincr = -1;
522     } else {
523         /* move left */
524         startcolumn = 0;
525         endcolumn = width;
526         columnincr = 1;
527     }
528 
529     for ( ; line != endline; line += lineincr) {
530         src = source_x + ((line + source_y) * buf->width) + startcolumn;
531         dst = dest_x + ((line + dest_y) * buf->width) + startcolumn;
532 
533         for (column = startcolumn; column != endcolumn; column += columnincr) {
534             if (dst >= buf->size || src >= buf->size) {
535                 continue;
536             }
537             artist_rop8(s, buf, dst, buf->data[src]);
538             src += columnincr;
539             dst += columnincr;
540         }
541     }
542 
543     artist_invalidate_lines(buf, dest_y, height);
544 }
545 
546 static void fill_window(ARTISTState *s,
547                         unsigned int startx, unsigned int starty,
548                         unsigned int width,  unsigned int height)
549 {
550     unsigned int offset;
551     uint8_t color = artist_get_color(s);
552     struct vram_buffer *buf;
553     int x, y;
554 
555     trace_artist_fill_window(startx, starty, width, height,
556                              s->image_bitmap_op, s->control_plane);
557 
558     if (s->control_plane != 0) {
559         /* We don't support CONTROL_PLANE accesses */
560         qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
561                       s->control_plane);
562         return;
563     }
564 
565     if (s->reg_100080 == 0x7d) {
566         /*
567          * Not sure what this register really does, but
568          * 0x7d seems to enable autoincremt of the Y axis
569          * by the current block move height.
570          */
571         height = artist_get_y(s->blockmove_size);
572         s->vram_start += height;
573     }
574 
575     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
576 
577     for (y = starty; y < starty + height; y++) {
578         offset = y * s->width;
579 
580         for (x = startx; x < startx + width; x++) {
581             artist_rop8(s, buf, offset + x, color);
582         }
583     }
584     artist_invalidate_lines(buf, starty, height);
585 }
586 
587 static void draw_line(ARTISTState *s,
588                       unsigned int x1, unsigned int y1,
589                       unsigned int x2, unsigned int y2,
590                       bool update_start, int skip_pix, int max_pix)
591 {
592     struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
593     uint8_t color;
594     int dx, dy, t, e, x, y, incy, diago, horiz;
595     bool c1;
596 
597     trace_artist_draw_line(x1, y1, x2, y2);
598 
599     if ((x1 >= buf->width && x2 >= buf->width) ||
600         (y1 >= buf->height && y2 >= buf->height)) {
601 	return;
602     }
603 
604 
605     if (update_start) {
606         s->vram_start = (x2 << 16) | y2;
607     }
608 
609     if (x2 > x1) {
610         dx = x2 - x1;
611     } else {
612         dx = x1 - x2;
613     }
614     if (y2 > y1) {
615         dy = y2 - y1;
616     } else {
617         dy = y1 - y2;
618     }
619 
620     c1 = false;
621     if (dy > dx) {
622         t = y2;
623         y2 = x2;
624         x2 = t;
625 
626         t = y1;
627         y1 = x1;
628         x1 = t;
629 
630         t = dx;
631         dx = dy;
632         dy = t;
633 
634         c1 = true;
635     }
636 
637     if (x1 > x2) {
638         t = y2;
639         y2 = y1;
640         y1 = t;
641 
642         t = x1;
643         x1 = x2;
644         x2 = t;
645     }
646 
647     horiz = dy << 1;
648     diago = (dy - dx) << 1;
649     e = (dy << 1) - dx;
650 
651     if (y1 <= y2) {
652         incy = 1;
653     } else {
654         incy = -1;
655     }
656     x = x1;
657     y = y1;
658     color = artist_get_color(s);
659 
660     do {
661         unsigned int ofs;
662 
663         if (c1) {
664             ofs = x * s->width + y;
665         } else {
666             ofs = y * s->width + x;
667         }
668 
669         if (skip_pix > 0) {
670             skip_pix--;
671         } else {
672             artist_rop8(s, buf, ofs, color);
673         }
674 
675         if (e > 0) {
676             y  += incy;
677             e  += diago;
678         } else {
679             e += horiz;
680         }
681         x++;
682     } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
683     if (c1)
684         artist_invalidate_lines(buf, x, dy+1);
685     else
686         artist_invalidate_lines(buf, y, dx+1);
687 }
688 
689 static void draw_line_pattern_start(ARTISTState *s)
690 {
691 
692     int startx = artist_get_x(s->vram_start);
693     int starty = artist_get_y(s->vram_start);
694     int endx = artist_get_x(s->blockmove_size);
695     int endy = artist_get_y(s->blockmove_size);
696     int pstart = s->line_pattern_start >> 16;
697 
698     draw_line(s, startx, starty, endx, endy, false, -1, pstart);
699     s->line_pattern_skip = pstart;
700 }
701 
702 static void draw_line_pattern_next(ARTISTState *s)
703 {
704 
705     int startx = artist_get_x(s->vram_start);
706     int starty = artist_get_y(s->vram_start);
707     int endx = artist_get_x(s->blockmove_size);
708     int endy = artist_get_y(s->blockmove_size);
709     int line_xy = s->line_xy >> 16;
710 
711     draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip,
712               s->line_pattern_skip + line_xy);
713     s->line_pattern_skip += line_xy;
714     s->image_bitmap_op ^= 2;
715 }
716 
717 static void draw_line_size(ARTISTState *s, bool update_start)
718 {
719 
720     int startx = artist_get_x(s->vram_start);
721     int starty = artist_get_y(s->vram_start);
722     int endx = artist_get_x(s->line_size);
723     int endy = artist_get_y(s->line_size);
724 
725     draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
726 }
727 
728 static void draw_line_xy(ARTISTState *s, bool update_start)
729 {
730 
731     int startx = artist_get_x(s->vram_start);
732     int starty = artist_get_y(s->vram_start);
733     int sizex = artist_get_x(s->blockmove_size);
734     int sizey = artist_get_y(s->blockmove_size);
735     int linexy = s->line_xy >> 16;
736     int endx, endy;
737 
738     endx = startx;
739     endy = starty;
740 
741     if (sizex > 0) {
742         endx = startx + linexy;
743     }
744 
745     if (sizex < 0) {
746         endx = startx;
747         startx -= linexy;
748     }
749 
750     if (sizey > 0) {
751         endy = starty + linexy;
752     }
753 
754     if (sizey < 0) {
755         endy = starty;
756         starty -= linexy;
757     }
758 
759     if (startx < 0) {
760         startx = 0;
761     }
762 
763     if (endx < 0) {
764         endx = 0;
765     }
766 
767     if (starty < 0) {
768         starty = 0;
769     }
770 
771     if (endy < 0) {
772         endy = 0;
773     }
774 
775     draw_line(s, startx, starty, endx, endy, false, -1, -1);
776 }
777 
778 static void draw_line_end(ARTISTState *s, bool update_start)
779 {
780 
781     int startx = artist_get_x(s->vram_start);
782     int starty = artist_get_y(s->vram_start);
783     int endx = artist_get_x(s->line_end);
784     int endy = artist_get_y(s->line_end);
785 
786     draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
787 }
788 
789 static void font_write16(ARTISTState *s, uint16_t val)
790 {
791     struct vram_buffer *buf;
792     uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color;
793     uint16_t mask;
794     int i;
795 
796     unsigned int startx = artist_get_x(s->vram_start);
797     unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y;
798     unsigned int offset = starty * s->width + startx;
799 
800     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
801 
802     if (startx >= buf->width || starty >= buf->height ||
803         offset + 16 >= buf->size) {
804         return;
805     }
806 
807     for (i = 0; i < 16; i++) {
808         mask = 1 << (15 - i);
809         if (val & mask) {
810             artist_rop8(s, buf, offset + i, color);
811         } else {
812             if (!(s->image_bitmap_op & 0x20000000)) {
813                 artist_rop8(s, buf, offset + i, s->bg_color);
814             }
815         }
816     }
817     artist_invalidate_lines(buf, starty, 1);
818 }
819 
820 static void font_write(ARTISTState *s, uint32_t val)
821 {
822     font_write16(s, val >> 16);
823     if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
824         s->vram_start += (s->blockmove_size & 0xffff0000);
825         return;
826     }
827 
828     font_write16(s, val & 0xffff);
829     if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
830         s->vram_start += (s->blockmove_size & 0xffff0000);
831         return;
832     }
833 }
834 
835 static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
836 {
837     /*
838      * FIXME: is there a qemu helper for this?
839      */
840 
841 #ifndef HOST_WORDS_BIGENDIAN
842     addr ^= 3;
843 #endif
844 
845     switch (size) {
846     case 1:
847         *(uint8_t *)(out + (addr & 3)) = val;
848         break;
849 
850     case 2:
851         *(uint16_t *)(out + (addr & 2)) = val;
852         break;
853 
854     case 4:
855         *(uint32_t *)out = val;
856         break;
857 
858     default:
859         qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size);
860     }
861 }
862 
863 static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
864                              unsigned size)
865 {
866     ARTISTState *s = opaque;
867     int width, height;
868 
869     trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val);
870 
871     switch (addr & ~3ULL) {
872     case 0x100080:
873         combine_write_reg(addr, val, size, &s->reg_100080);
874         break;
875 
876     case FG_COLOR:
877         combine_write_reg(addr, val, size, &s->fg_color);
878         break;
879 
880     case BG_COLOR:
881         combine_write_reg(addr, val, size, &s->bg_color);
882         break;
883 
884     case VRAM_BITMASK:
885         combine_write_reg(addr, val, size, &s->vram_bitmask);
886         break;
887 
888     case VRAM_WRITE_INCR_Y:
889         vram_bit_write(s, s->vram_char_y++, false, size, val);
890         break;
891 
892     case VRAM_WRITE_INCR_X:
893     case VRAM_WRITE_INCR_X2:
894         vram_bit_write(s, s->vram_char_y, true, size, val);
895         break;
896 
897     case VRAM_IDX:
898         combine_write_reg(addr, val, size, &s->vram_pos);
899         s->vram_char_y = 0;
900         s->draw_line_pattern = 0;
901         break;
902 
903     case VRAM_START:
904         combine_write_reg(addr, val, size, &s->vram_start);
905         s->draw_line_pattern = 0;
906         break;
907 
908     case VRAM_START_TRIGGER:
909         combine_write_reg(addr, val, size, &s->vram_start);
910         fill_window(s, artist_get_x(s->vram_start),
911                     artist_get_y(s->vram_start),
912                     artist_get_x(s->blockmove_size),
913                     artist_get_y(s->blockmove_size));
914         break;
915 
916     case VRAM_SIZE_TRIGGER:
917         combine_write_reg(addr, val, size, &s->vram_size);
918 
919         if (size == 2 && !(addr & 2)) {
920             height = artist_get_y(s->blockmove_size);
921         } else {
922             height = artist_get_y(s->vram_size);
923         }
924 
925         if (size == 2 && (addr & 2)) {
926             width = artist_get_x(s->blockmove_size);
927         } else {
928             width = artist_get_x(s->vram_size);
929         }
930 
931         fill_window(s, artist_get_x(s->vram_start),
932                     artist_get_y(s->vram_start),
933                     width, height);
934         break;
935 
936     case LINE_XY:
937         combine_write_reg(addr, val, size, &s->line_xy);
938         if (s->draw_line_pattern) {
939             draw_line_pattern_next(s);
940         } else {
941             draw_line_xy(s, true);
942         }
943         break;
944 
945     case PATTERN_LINE_START:
946         combine_write_reg(addr, val, size, &s->line_pattern_start);
947         s->draw_line_pattern = 1;
948         draw_line_pattern_start(s);
949         break;
950 
951     case LINE_SIZE:
952         combine_write_reg(addr, val, size, &s->line_size);
953         draw_line_size(s, true);
954         break;
955 
956     case LINE_END:
957         combine_write_reg(addr, val, size, &s->line_end);
958         draw_line_end(s, true);
959         break;
960 
961     case BLOCK_MOVE_SIZE:
962         combine_write_reg(addr, val, size, &s->blockmove_size);
963         break;
964 
965     case BLOCK_MOVE_SOURCE:
966         combine_write_reg(addr, val, size, &s->blockmove_source);
967         break;
968 
969     case BLOCK_MOVE_DEST_TRIGGER:
970         combine_write_reg(addr, val, size, &s->blockmove_dest);
971 
972         block_move(s, artist_get_x(s->blockmove_source),
973                    artist_get_y(s->blockmove_source),
974                    artist_get_x(s->blockmove_dest),
975                    artist_get_y(s->blockmove_dest),
976                    artist_get_x(s->blockmove_size),
977                    artist_get_y(s->blockmove_size));
978         break;
979 
980     case BLOCK_MOVE_SIZE_TRIGGER:
981         combine_write_reg(addr, val, size, &s->blockmove_size);
982 
983         block_move(s,
984                    artist_get_x(s->blockmove_source),
985                    artist_get_y(s->blockmove_source),
986                    artist_get_x(s->vram_start),
987                    artist_get_y(s->vram_start),
988                    artist_get_x(s->blockmove_size),
989                    artist_get_y(s->blockmove_size));
990         break;
991 
992     case PLANE_MASK:
993         combine_write_reg(addr, val, size, &s->plane_mask);
994         break;
995 
996     case CMAP_BM_ACCESS:
997         combine_write_reg(addr, val, size, &s->cmap_bm_access);
998         break;
999 
1000     case DST_BM_ACCESS:
1001         combine_write_reg(addr, val, size, &s->dst_bm_access);
1002         s->cmap_bm_access = 0;
1003         break;
1004 
1005     case SRC_BM_ACCESS:
1006         combine_write_reg(addr, val, size, &s->src_bm_access);
1007         s->cmap_bm_access = 0;
1008         break;
1009 
1010     case CONTROL_PLANE:
1011         combine_write_reg(addr, val, size, &s->control_plane);
1012         break;
1013 
1014     case TRANSFER_DATA:
1015         combine_write_reg(addr, val, size, &s->transfer_data);
1016         break;
1017 
1018     case 0x300200:
1019         combine_write_reg(addr, val, size, &s->reg_300200);
1020         break;
1021 
1022     case 0x300208:
1023         combine_write_reg(addr, val, size, &s->reg_300208);
1024         break;
1025 
1026     case 0x300218:
1027         combine_write_reg(addr, val, size, &s->reg_300218);
1028         break;
1029 
1030     case CURSOR_POS:
1031         artist_invalidate_cursor(s);
1032         combine_write_reg(addr, val, size, &s->cursor_pos);
1033         artist_invalidate_cursor(s);
1034         break;
1035 
1036     case CURSOR_CTRL:
1037         break;
1038 
1039     case IMAGE_BITMAP_OP:
1040         combine_write_reg(addr, val, size, &s->image_bitmap_op);
1041         break;
1042 
1043     case FONT_WRITE_INCR_Y:
1044         combine_write_reg(addr, val, size, &s->font_write1);
1045         font_write(s, s->font_write1);
1046         break;
1047 
1048     case FONT_WRITE_START:
1049         combine_write_reg(addr, val, size, &s->font_write2);
1050         s->font_write_pos_y = 0;
1051         font_write(s, s->font_write2);
1052         break;
1053 
1054     case 300104:
1055         break;
1056 
1057     default:
1058         qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx
1059                       " val=%08" PRIx64 " size=%d\n",
1060                       __func__, addr, val, size);
1061         break;
1062     }
1063 }
1064 
1065 static uint64_t combine_read_reg(hwaddr addr, int size, void *in)
1066 {
1067     /*
1068      * FIXME: is there a qemu helper for this?
1069      */
1070 
1071 #ifndef HOST_WORDS_BIGENDIAN
1072     addr ^= 3;
1073 #endif
1074 
1075     switch (size) {
1076     case 1:
1077         return *(uint8_t *)(in + (addr & 3));
1078 
1079     case 2:
1080         return *(uint16_t *)(in + (addr & 2));
1081 
1082     case 4:
1083         return *(uint32_t *)in;
1084 
1085     default:
1086         qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size);
1087         return 0;
1088     }
1089 }
1090 
1091 static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
1092 {
1093     ARTISTState *s = opaque;
1094     uint32_t val = 0;
1095 
1096     switch (addr & ~3ULL) {
1097         /* Unknown status registers */
1098     case 0:
1099         break;
1100 
1101     case 0x211110:
1102         val = (s->width << 16) | s->height;
1103         if (s->depth == 1) {
1104             val |= 1 << 31;
1105         }
1106         break;
1107 
1108     case 0x100000:
1109     case 0x300000:
1110     case 0x300004:
1111     case 0x300308:
1112     case 0x380000:
1113         break;
1114 
1115     case 0x300008:
1116     case 0x380008:
1117         /*
1118          * FIFO ready flag. we're not emulating the FIFOs
1119          * so we're always ready
1120          */
1121         val = 0x10;
1122         break;
1123 
1124     case 0x300200:
1125         val = s->reg_300200;
1126         break;
1127 
1128     case 0x300208:
1129         val = s->reg_300208;
1130         break;
1131 
1132     case 0x300218:
1133         val = s->reg_300218;
1134         break;
1135 
1136     case 0x30023c:
1137         val = 0xac4ffdac;
1138         break;
1139 
1140     case 0x380004:
1141         /* 0x02000000 Buserror */
1142         val = 0x6dc20006;
1143         break;
1144 
1145     default:
1146         qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx
1147                       " size %d\n", __func__, addr, size);
1148         break;
1149     }
1150     val = combine_read_reg(addr, size, &val);
1151     trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val);
1152     return val;
1153 }
1154 
1155 static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
1156                               unsigned size)
1157 {
1158     ARTISTState *s = opaque;
1159     struct vram_buffer *buf;
1160     unsigned int posy, posx;
1161     unsigned int offset;
1162     trace_artist_vram_write(size, addr, val);
1163 
1164     if (s->cmap_bm_access) {
1165         buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1166         if (addr + 3 < buf->size) {
1167             *(uint32_t *)(buf->data + addr) = val;
1168         }
1169         return;
1170     }
1171 
1172     buf = vram_write_buffer(s);
1173     posy = ADDR_TO_Y(addr);
1174     posx = ADDR_TO_X(addr);
1175 
1176     if (!buf->size) {
1177         return;
1178     }
1179 
1180     if (posy > buf->height || posx > buf->width) {
1181         return;
1182     }
1183 
1184     offset = posy * buf->width + posx;
1185     if (offset >= buf->size) {
1186         return;
1187     }
1188 
1189     switch (size) {
1190     case 4:
1191         if (offset + 3 < buf->size) {
1192             *(uint32_t *)(buf->data + offset) = be32_to_cpu(val);
1193             memory_region_set_dirty(&buf->mr, offset, 4);
1194         }
1195         break;
1196     case 2:
1197         if (offset + 1 < buf->size) {
1198             *(uint16_t *)(buf->data + offset) = be16_to_cpu(val);
1199             memory_region_set_dirty(&buf->mr, offset, 2);
1200         }
1201         break;
1202     case 1:
1203         if (offset < buf->size) {
1204             *(uint8_t *)(buf->data + offset) = val;
1205             memory_region_set_dirty(&buf->mr, offset, 1);
1206         }
1207         break;
1208     default:
1209         break;
1210     }
1211 }
1212 
1213 static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
1214 {
1215     ARTISTState *s = opaque;
1216     struct vram_buffer *buf;
1217     uint64_t val;
1218     unsigned int posy, posx;
1219 
1220     if (s->cmap_bm_access) {
1221         buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1222         val = 0;
1223         if (addr < buf->size && addr + 3 < buf->size) {
1224             val = *(uint32_t *)(buf->data + addr);
1225         }
1226         trace_artist_vram_read(size, addr, 0, 0, val);
1227         return val;
1228     }
1229 
1230     buf = vram_read_buffer(s);
1231     if (!buf->size) {
1232         return 0;
1233     }
1234 
1235     posy = ADDR_TO_Y(addr);
1236     posx = ADDR_TO_X(addr);
1237 
1238     if (posy > buf->height || posx > buf->width) {
1239         return 0;
1240     }
1241 
1242     val = cpu_to_be32(*(uint32_t *)(buf->data + posy * buf->width + posx));
1243     trace_artist_vram_read(size, addr, posx, posy, val);
1244     return val;
1245 }
1246 
1247 static const MemoryRegionOps artist_reg_ops = {
1248     .read = artist_reg_read,
1249     .write = artist_reg_write,
1250     .endianness = DEVICE_NATIVE_ENDIAN,
1251     .impl.min_access_size = 1,
1252     .impl.max_access_size = 4,
1253 };
1254 
1255 static const MemoryRegionOps artist_vram_ops = {
1256     .read = artist_vram_read,
1257     .write = artist_vram_write,
1258     .endianness = DEVICE_NATIVE_ENDIAN,
1259     .impl.min_access_size = 1,
1260     .impl.max_access_size = 4,
1261 };
1262 
1263 static void artist_draw_cursor(ARTISTState *s)
1264 {
1265     DisplaySurface *surface = qemu_console_surface(s->con);
1266     uint32_t *data = (uint32_t *)surface_data(surface);
1267     struct vram_buffer *cursor0, *cursor1 , *buf;
1268     int cx, cy, cursor_pos_x, cursor_pos_y;
1269 
1270     cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1];
1271     cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2];
1272     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1273 
1274     artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y);
1275 
1276     for (cy = 0; cy < s->cursor_height; cy++) {
1277 
1278         for (cx = 0; cx < s->cursor_width; cx++) {
1279 
1280             if (cursor_pos_y + cy < 0 ||
1281                 cursor_pos_x + cx < 0 ||
1282                 cursor_pos_y + cy > buf->height - 1 ||
1283                 cursor_pos_x + cx > buf->width) {
1284                 continue;
1285             }
1286 
1287             int dstoffset = (cursor_pos_y + cy) * s->width +
1288                 (cursor_pos_x + cx);
1289 
1290             if (cursor0->data[cy * cursor0->width + cx]) {
1291                 data[dstoffset] = 0;
1292             } else {
1293                 if (cursor1->data[cy * cursor1->width + cx]) {
1294                     data[dstoffset] = 0xffffff;
1295                 }
1296             }
1297         }
1298     }
1299 }
1300 
1301 static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
1302                              int width, int pitch)
1303 {
1304     ARTISTState *s = ARTIST(opaque);
1305     uint32_t *cmap, *data = (uint32_t *)d;
1306     int x;
1307 
1308     cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400);
1309 
1310     for (x = 0; x < s->width; x++) {
1311         *data++ = cmap[*src++];
1312     }
1313 }
1314 
1315 static void artist_update_display(void *opaque)
1316 {
1317     ARTISTState *s = opaque;
1318     DisplaySurface *surface = qemu_console_surface(s->con);
1319     int first = 0, last;
1320 
1321 
1322     framebuffer_update_display(surface, &s->fbsection, s->width, s->height,
1323                                s->width, s->width * 4, 0, 0, artist_draw_line,
1324                                s, &first, &last);
1325 
1326     artist_draw_cursor(s);
1327 
1328     dpy_gfx_update(s->con, 0, 0, s->width, s->height);
1329 }
1330 
1331 static void artist_invalidate(void *opaque)
1332 {
1333     ARTISTState *s = ARTIST(opaque);
1334     struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
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, NULL, 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      * no idea whether the cursor is fixed size or not, so assume 32x32 which
1408      * seems sufficient for HP-UX X11.
1409      */
1410     s->cursor_height = 32;
1411     s->cursor_width = 32;
1412 
1413     s->con = graphic_console_init(dev, 0, &artist_ops, s);
1414     qemu_console_resize(s->con, s->width, s->height);
1415 }
1416 
1417 static int vmstate_artist_post_load(void *opaque, int version_id)
1418 {
1419     artist_invalidate(opaque);
1420     return 0;
1421 }
1422 
1423 static const VMStateDescription vmstate_artist = {
1424     .name = "artist",
1425     .version_id = 1,
1426     .minimum_version_id = 1,
1427     .post_load = vmstate_artist_post_load,
1428     .fields = (VMStateField[]) {
1429         VMSTATE_UINT16(height, ARTISTState),
1430         VMSTATE_UINT16(width, ARTISTState),
1431         VMSTATE_UINT16(depth, ARTISTState),
1432         VMSTATE_UINT32(fg_color, ARTISTState),
1433         VMSTATE_UINT32(bg_color, ARTISTState),
1434         VMSTATE_UINT32(vram_char_y, ARTISTState),
1435         VMSTATE_UINT32(vram_bitmask, ARTISTState),
1436         VMSTATE_UINT32(vram_start, ARTISTState),
1437         VMSTATE_UINT32(vram_pos, ARTISTState),
1438         VMSTATE_UINT32(vram_size, ARTISTState),
1439         VMSTATE_UINT32(blockmove_source, ARTISTState),
1440         VMSTATE_UINT32(blockmove_dest, ARTISTState),
1441         VMSTATE_UINT32(blockmove_size, ARTISTState),
1442         VMSTATE_UINT32(line_size, ARTISTState),
1443         VMSTATE_UINT32(line_end, ARTISTState),
1444         VMSTATE_UINT32(line_xy, ARTISTState),
1445         VMSTATE_UINT32(cursor_pos, ARTISTState),
1446         VMSTATE_UINT32(cursor_height, ARTISTState),
1447         VMSTATE_UINT32(cursor_width, ARTISTState),
1448         VMSTATE_UINT32(plane_mask, ARTISTState),
1449         VMSTATE_UINT32(reg_100080, ARTISTState),
1450         VMSTATE_UINT32(reg_300200, ARTISTState),
1451         VMSTATE_UINT32(reg_300208, ARTISTState),
1452         VMSTATE_UINT32(reg_300218, ARTISTState),
1453         VMSTATE_UINT32(cmap_bm_access, ARTISTState),
1454         VMSTATE_UINT32(dst_bm_access, ARTISTState),
1455         VMSTATE_UINT32(src_bm_access, ARTISTState),
1456         VMSTATE_UINT32(control_plane, ARTISTState),
1457         VMSTATE_UINT32(transfer_data, ARTISTState),
1458         VMSTATE_UINT32(image_bitmap_op, ARTISTState),
1459         VMSTATE_UINT32(font_write1, ARTISTState),
1460         VMSTATE_UINT32(font_write2, ARTISTState),
1461         VMSTATE_UINT32(font_write_pos_y, ARTISTState),
1462         VMSTATE_END_OF_LIST()
1463     }
1464 };
1465 
1466 static Property artist_properties[] = {
1467     DEFINE_PROP_UINT16("width",        ARTISTState, width, 1280),
1468     DEFINE_PROP_UINT16("height",       ARTISTState, height, 1024),
1469     DEFINE_PROP_UINT16("depth",        ARTISTState, depth, 8),
1470     DEFINE_PROP_END_OF_LIST(),
1471 };
1472 
1473 static void artist_reset(DeviceState *qdev)
1474 {
1475 }
1476 
1477 static void artist_class_init(ObjectClass *klass, void *data)
1478 {
1479     DeviceClass *dc = DEVICE_CLASS(klass);
1480 
1481     dc->realize = artist_realizefn;
1482     dc->vmsd = &vmstate_artist;
1483     dc->reset = artist_reset;
1484     device_class_set_props(dc, artist_properties);
1485 }
1486 
1487 static const TypeInfo artist_info = {
1488     .name          = TYPE_ARTIST,
1489     .parent        = TYPE_SYS_BUS_DEVICE,
1490     .instance_size = sizeof(ARTISTState),
1491     .instance_init = artist_initfn,
1492     .class_init    = artist_class_init,
1493 };
1494 
1495 static void artist_register_types(void)
1496 {
1497     type_register_static(&artist_info);
1498 }
1499 
1500 type_init(artist_register_types)
1501