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