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