xref: /openbmc/qemu/hw/display/artist.c (revision e0cf02ce680f11893aca9642e76d6ae68b9375af)
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             artist_invalidate_lines(buf, y, 1);
666             y  += incy;
667             e  += diago;
668         } else {
669             e += horiz;
670         }
671         x++;
672     } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
673 }
674 
675 static void draw_line_pattern_start(ARTISTState *s)
676 {
677 
678     int startx = artist_get_x(s->vram_start);
679     int starty = artist_get_y(s->vram_start);
680     int endx = artist_get_x(s->blockmove_size);
681     int endy = artist_get_y(s->blockmove_size);
682     int pstart = s->line_pattern_start >> 16;
683 
684     draw_line(s, startx, starty, endx, endy, false, -1, pstart);
685     s->line_pattern_skip = pstart;
686 }
687 
688 static void draw_line_pattern_next(ARTISTState *s)
689 {
690 
691     int startx = artist_get_x(s->vram_start);
692     int starty = artist_get_y(s->vram_start);
693     int endx = artist_get_x(s->blockmove_size);
694     int endy = artist_get_y(s->blockmove_size);
695     int line_xy = s->line_xy >> 16;
696 
697     draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip,
698               s->line_pattern_skip + line_xy);
699     s->line_pattern_skip += line_xy;
700     s->image_bitmap_op ^= 2;
701 }
702 
703 static void draw_line_size(ARTISTState *s, bool update_start)
704 {
705 
706     int startx = artist_get_x(s->vram_start);
707     int starty = artist_get_y(s->vram_start);
708     int endx = artist_get_x(s->line_size);
709     int endy = artist_get_y(s->line_size);
710 
711     draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
712 }
713 
714 static void draw_line_xy(ARTISTState *s, bool update_start)
715 {
716 
717     int startx = artist_get_x(s->vram_start);
718     int starty = artist_get_y(s->vram_start);
719     int sizex = artist_get_x(s->blockmove_size);
720     int sizey = artist_get_y(s->blockmove_size);
721     int linexy = s->line_xy >> 16;
722     int endx, endy;
723 
724     endx = startx;
725     endy = starty;
726 
727     if (sizex > 0) {
728         endx = startx + linexy;
729     }
730 
731     if (sizex < 0) {
732         endx = startx;
733         startx -= linexy;
734     }
735 
736     if (sizey > 0) {
737         endy = starty + linexy;
738     }
739 
740     if (sizey < 0) {
741         endy = starty;
742         starty -= linexy;
743     }
744 
745     if (startx < 0) {
746         startx = 0;
747     }
748 
749     if (endx < 0) {
750         endx = 0;
751     }
752 
753     if (starty < 0) {
754         starty = 0;
755     }
756 
757     if (endy < 0) {
758         endy = 0;
759     }
760 
761     draw_line(s, startx, starty, endx, endy, false, -1, -1);
762 }
763 
764 static void draw_line_end(ARTISTState *s, bool update_start)
765 {
766 
767     int startx = artist_get_x(s->vram_start);
768     int starty = artist_get_y(s->vram_start);
769     int endx = artist_get_x(s->line_end);
770     int endy = artist_get_y(s->line_end);
771 
772     draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
773 }
774 
775 static void font_write16(ARTISTState *s, uint16_t val)
776 {
777     struct vram_buffer *buf;
778     uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color;
779     uint16_t mask;
780     int i;
781 
782     unsigned int startx = artist_get_x(s->vram_start);
783     unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y;
784     unsigned int offset = starty * s->width + startx;
785 
786     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
787 
788     if (startx >= buf->width || starty >= buf->height ||
789         offset + 16 >= buf->size) {
790         return;
791     }
792 
793     for (i = 0; i < 16; i++) {
794         mask = 1 << (15 - i);
795         if (val & mask) {
796             artist_rop8(s, buf, offset + i, color);
797         } else {
798             if (!(s->image_bitmap_op & 0x20000000)) {
799                 artist_rop8(s, buf, offset + i, s->bg_color);
800             }
801         }
802     }
803     artist_invalidate_lines(buf, starty, 1);
804 }
805 
806 static void font_write(ARTISTState *s, uint32_t val)
807 {
808     font_write16(s, val >> 16);
809     if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
810         s->vram_start += (s->blockmove_size & 0xffff0000);
811         return;
812     }
813 
814     font_write16(s, val & 0xffff);
815     if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
816         s->vram_start += (s->blockmove_size & 0xffff0000);
817         return;
818     }
819 }
820 
821 static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
822 {
823     /*
824      * FIXME: is there a qemu helper for this?
825      */
826 
827 #ifndef HOST_WORDS_BIGENDIAN
828     addr ^= 3;
829 #endif
830 
831     switch (size) {
832     case 1:
833         *(uint8_t *)(out + (addr & 3)) = val;
834         break;
835 
836     case 2:
837         *(uint16_t *)(out + (addr & 2)) = val;
838         break;
839 
840     case 4:
841         *(uint32_t *)out = val;
842         break;
843 
844     default:
845         qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size);
846     }
847 }
848 
849 static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
850                              unsigned size)
851 {
852     ARTISTState *s = opaque;
853     int posx, posy;
854     int width, height;
855 
856     trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val);
857 
858     switch (addr & ~3ULL) {
859     case 0x100080:
860         combine_write_reg(addr, val, size, &s->reg_100080);
861         break;
862 
863     case FG_COLOR:
864         combine_write_reg(addr, val, size, &s->fg_color);
865         break;
866 
867     case BG_COLOR:
868         combine_write_reg(addr, val, size, &s->bg_color);
869         break;
870 
871     case VRAM_BITMASK:
872         combine_write_reg(addr, val, size, &s->vram_bitmask);
873         break;
874 
875     case VRAM_WRITE_INCR_Y:
876         posx = (s->vram_pos >> 2) & 0x7ff;
877         posy = (s->vram_pos >> 13) & 0x3ff;
878         vram_bit_write(s, posx, posy + s->vram_char_y++, false, size, val);
879         break;
880 
881     case VRAM_WRITE_INCR_X:
882     case VRAM_WRITE_INCR_X2:
883         posx = (s->vram_pos >> 2) & 0x7ff;
884         posy = (s->vram_pos >> 13) & 0x3ff;
885         vram_bit_write(s, posx, posy + s->vram_char_y, true, size, val);
886         break;
887 
888     case VRAM_IDX:
889         combine_write_reg(addr, val, size, &s->vram_pos);
890         s->vram_char_y = 0;
891         s->draw_line_pattern = 0;
892         break;
893 
894     case VRAM_START:
895         combine_write_reg(addr, val, size, &s->vram_start);
896         s->draw_line_pattern = 0;
897         break;
898 
899     case VRAM_START_TRIGGER:
900         combine_write_reg(addr, val, size, &s->vram_start);
901         fill_window(s, artist_get_x(s->vram_start),
902                     artist_get_y(s->vram_start),
903                     artist_get_x(s->blockmove_size),
904                     artist_get_y(s->blockmove_size));
905         break;
906 
907     case VRAM_SIZE_TRIGGER:
908         combine_write_reg(addr, val, size, &s->vram_size);
909 
910         if (size == 2 && !(addr & 2)) {
911             height = artist_get_y(s->blockmove_size);
912         } else {
913             height = artist_get_y(s->vram_size);
914         }
915 
916         if (size == 2 && (addr & 2)) {
917             width = artist_get_x(s->blockmove_size);
918         } else {
919             width = artist_get_x(s->vram_size);
920         }
921 
922         fill_window(s, artist_get_x(s->vram_start),
923                     artist_get_y(s->vram_start),
924                     width, height);
925         break;
926 
927     case LINE_XY:
928         combine_write_reg(addr, val, size, &s->line_xy);
929         if (s->draw_line_pattern) {
930             draw_line_pattern_next(s);
931         } else {
932             draw_line_xy(s, true);
933         }
934         break;
935 
936     case PATTERN_LINE_START:
937         combine_write_reg(addr, val, size, &s->line_pattern_start);
938         s->draw_line_pattern = 1;
939         draw_line_pattern_start(s);
940         break;
941 
942     case LINE_SIZE:
943         combine_write_reg(addr, val, size, &s->line_size);
944         draw_line_size(s, true);
945         break;
946 
947     case LINE_END:
948         combine_write_reg(addr, val, size, &s->line_end);
949         draw_line_end(s, true);
950         break;
951 
952     case BLOCK_MOVE_SIZE:
953         combine_write_reg(addr, val, size, &s->blockmove_size);
954         break;
955 
956     case BLOCK_MOVE_SOURCE:
957         combine_write_reg(addr, val, size, &s->blockmove_source);
958         break;
959 
960     case BLOCK_MOVE_DEST_TRIGGER:
961         combine_write_reg(addr, val, size, &s->blockmove_dest);
962 
963         block_move(s, artist_get_x(s->blockmove_source),
964                    artist_get_y(s->blockmove_source),
965                    artist_get_x(s->blockmove_dest),
966                    artist_get_y(s->blockmove_dest),
967                    artist_get_x(s->blockmove_size),
968                    artist_get_y(s->blockmove_size));
969         break;
970 
971     case BLOCK_MOVE_SIZE_TRIGGER:
972         combine_write_reg(addr, val, size, &s->blockmove_size);
973 
974         block_move(s,
975                    artist_get_x(s->blockmove_source),
976                    artist_get_y(s->blockmove_source),
977                    artist_get_x(s->vram_start),
978                    artist_get_y(s->vram_start),
979                    artist_get_x(s->blockmove_size),
980                    artist_get_y(s->blockmove_size));
981         break;
982 
983     case PLANE_MASK:
984         combine_write_reg(addr, val, size, &s->plane_mask);
985         break;
986 
987     case CMAP_BM_ACCESS:
988         combine_write_reg(addr, val, size, &s->cmap_bm_access);
989         break;
990 
991     case DST_BM_ACCESS:
992         combine_write_reg(addr, val, size, &s->dst_bm_access);
993         s->cmap_bm_access = 0;
994         break;
995 
996     case SRC_BM_ACCESS:
997         combine_write_reg(addr, val, size, &s->src_bm_access);
998         s->cmap_bm_access = 0;
999         break;
1000 
1001     case CONTROL_PLANE:
1002         combine_write_reg(addr, val, size, &s->control_plane);
1003         break;
1004 
1005     case TRANSFER_DATA:
1006         combine_write_reg(addr, val, size, &s->transfer_data);
1007         break;
1008 
1009     case 0x300200:
1010         combine_write_reg(addr, val, size, &s->reg_300200);
1011         break;
1012 
1013     case 0x300208:
1014         combine_write_reg(addr, val, size, &s->reg_300208);
1015         break;
1016 
1017     case 0x300218:
1018         combine_write_reg(addr, val, size, &s->reg_300218);
1019         break;
1020 
1021     case CURSOR_POS:
1022         artist_invalidate_cursor(s);
1023         combine_write_reg(addr, val, size, &s->cursor_pos);
1024         artist_invalidate_cursor(s);
1025         break;
1026 
1027     case CURSOR_CTRL:
1028         break;
1029 
1030     case IMAGE_BITMAP_OP:
1031         combine_write_reg(addr, val, size, &s->image_bitmap_op);
1032         break;
1033 
1034     case FONT_WRITE_INCR_Y:
1035         combine_write_reg(addr, val, size, &s->font_write1);
1036         font_write(s, s->font_write1);
1037         break;
1038 
1039     case FONT_WRITE_START:
1040         combine_write_reg(addr, val, size, &s->font_write2);
1041         s->font_write_pos_y = 0;
1042         font_write(s, s->font_write2);
1043         break;
1044 
1045     case 300104:
1046         break;
1047 
1048     default:
1049         qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx
1050                       " val=%08" PRIx64 " size=%d\n",
1051                       __func__, addr, val, size);
1052         break;
1053     }
1054 }
1055 
1056 static uint64_t combine_read_reg(hwaddr addr, int size, void *in)
1057 {
1058     /*
1059      * FIXME: is there a qemu helper for this?
1060      */
1061 
1062 #ifndef HOST_WORDS_BIGENDIAN
1063     addr ^= 3;
1064 #endif
1065 
1066     switch (size) {
1067     case 1:
1068         return *(uint8_t *)(in + (addr & 3));
1069 
1070     case 2:
1071         return *(uint16_t *)(in + (addr & 2));
1072 
1073     case 4:
1074         return *(uint32_t *)in;
1075 
1076     default:
1077         qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size);
1078         return 0;
1079     }
1080 }
1081 
1082 static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
1083 {
1084     ARTISTState *s = opaque;
1085     uint32_t val = 0;
1086 
1087     switch (addr & ~3ULL) {
1088         /* Unknown status registers */
1089     case 0:
1090         break;
1091 
1092     case 0x211110:
1093         val = (s->width << 16) | s->height;
1094         if (s->depth == 1) {
1095             val |= 1 << 31;
1096         }
1097         break;
1098 
1099     case 0x100000:
1100     case 0x300000:
1101     case 0x300004:
1102     case 0x300308:
1103     case 0x380000:
1104         break;
1105 
1106     case 0x300008:
1107     case 0x380008:
1108         /*
1109          * FIFO ready flag. we're not emulating the FIFOs
1110          * so we're always ready
1111          */
1112         val = 0x10;
1113         break;
1114 
1115     case 0x300200:
1116         val = s->reg_300200;
1117         break;
1118 
1119     case 0x300208:
1120         val = s->reg_300208;
1121         break;
1122 
1123     case 0x300218:
1124         val = s->reg_300218;
1125         break;
1126 
1127     case 0x30023c:
1128         val = 0xac4ffdac;
1129         break;
1130 
1131     case 0x380004:
1132         /* 0x02000000 Buserror */
1133         val = 0x6dc20006;
1134         break;
1135 
1136     default:
1137         qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx
1138                       " size %d\n", __func__, addr, size);
1139         break;
1140     }
1141     val = combine_read_reg(addr, size, &val);
1142     trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val);
1143     return val;
1144 }
1145 
1146 static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
1147                               unsigned size)
1148 {
1149     ARTISTState *s = opaque;
1150     struct vram_buffer *buf;
1151     int posy = (addr >> 11) & 0x3ff;
1152     int posx = addr & 0x7ff;
1153     unsigned int offset;
1154     trace_artist_vram_write(size, addr, val);
1155 
1156     if (s->cmap_bm_access) {
1157         buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1158         if (addr + 3 < buf->size) {
1159             *(uint32_t *)(buf->data + addr) = val;
1160         }
1161         return;
1162     }
1163 
1164     buf = vram_write_buffer(s);
1165     if (!buf->size) {
1166         return;
1167     }
1168 
1169     if (posy > buf->height || posx > buf->width) {
1170         return;
1171     }
1172 
1173     offset = posy * buf->width + posx;
1174     if (offset >= buf->size) {
1175         return;
1176     }
1177 
1178     switch (size) {
1179     case 4:
1180         if (offset + 3 < buf->size) {
1181             *(uint32_t *)(buf->data + offset) = be32_to_cpu(val);
1182             memory_region_set_dirty(&buf->mr, offset, 4);
1183         }
1184         break;
1185     case 2:
1186         if (offset + 1 < buf->size) {
1187             *(uint16_t *)(buf->data + offset) = be16_to_cpu(val);
1188             memory_region_set_dirty(&buf->mr, offset, 2);
1189         }
1190         break;
1191     case 1:
1192         if (offset < buf->size) {
1193             *(uint8_t *)(buf->data + offset) = val;
1194             memory_region_set_dirty(&buf->mr, offset, 1);
1195         }
1196         break;
1197     default:
1198         break;
1199     }
1200 }
1201 
1202 static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
1203 {
1204     ARTISTState *s = opaque;
1205     struct vram_buffer *buf;
1206     uint64_t val;
1207     int posy, posx;
1208 
1209     if (s->cmap_bm_access) {
1210         buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1211         val = 0;
1212         if (addr < buf->size && addr + 3 < buf->size) {
1213             val = *(uint32_t *)(buf->data + addr);
1214         }
1215         trace_artist_vram_read(size, addr, 0, 0, val);
1216         return val;
1217     }
1218 
1219     buf = vram_read_buffer(s);
1220     if (!buf->size) {
1221         return 0;
1222     }
1223 
1224     posy = (addr >> 13) & 0x3ff;
1225     posx = (addr >> 2) & 0x7ff;
1226 
1227     if (posy > buf->height || posx > buf->width) {
1228         return 0;
1229     }
1230 
1231     val = cpu_to_be32(*(uint32_t *)(buf->data + posy * buf->width + posx));
1232     trace_artist_vram_read(size, addr, posx, posy, val);
1233     return val;
1234 }
1235 
1236 static const MemoryRegionOps artist_reg_ops = {
1237     .read = artist_reg_read,
1238     .write = artist_reg_write,
1239     .endianness = DEVICE_NATIVE_ENDIAN,
1240     .impl.min_access_size = 1,
1241     .impl.max_access_size = 4,
1242 };
1243 
1244 static const MemoryRegionOps artist_vram_ops = {
1245     .read = artist_vram_read,
1246     .write = artist_vram_write,
1247     .endianness = DEVICE_NATIVE_ENDIAN,
1248     .impl.min_access_size = 1,
1249     .impl.max_access_size = 4,
1250 };
1251 
1252 static void artist_draw_cursor(ARTISTState *s)
1253 {
1254     DisplaySurface *surface = qemu_console_surface(s->con);
1255     uint32_t *data = (uint32_t *)surface_data(surface);
1256     struct vram_buffer *cursor0, *cursor1 , *buf;
1257     int cx, cy, cursor_pos_x, cursor_pos_y;
1258 
1259     cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1];
1260     cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2];
1261     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1262 
1263     artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y);
1264 
1265     for (cy = 0; cy < s->cursor_height; cy++) {
1266 
1267         for (cx = 0; cx < s->cursor_width; cx++) {
1268 
1269             if (cursor_pos_y + cy < 0 ||
1270                 cursor_pos_x + cx < 0 ||
1271                 cursor_pos_y + cy > buf->height - 1 ||
1272                 cursor_pos_x + cx > buf->width) {
1273                 continue;
1274             }
1275 
1276             int dstoffset = (cursor_pos_y + cy) * s->width +
1277                 (cursor_pos_x + cx);
1278 
1279             if (cursor0->data[cy * cursor0->width + cx]) {
1280                 data[dstoffset] = 0;
1281             } else {
1282                 if (cursor1->data[cy * cursor1->width + cx]) {
1283                     data[dstoffset] = 0xffffff;
1284                 }
1285             }
1286         }
1287     }
1288 }
1289 
1290 static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
1291                              int width, int pitch)
1292 {
1293     ARTISTState *s = ARTIST(opaque);
1294     uint32_t *cmap, *data = (uint32_t *)d;
1295     int x;
1296 
1297     cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400);
1298 
1299     for (x = 0; x < s->width; x++) {
1300         *data++ = cmap[*src++];
1301     }
1302 }
1303 
1304 static void artist_update_display(void *opaque)
1305 {
1306     ARTISTState *s = opaque;
1307     DisplaySurface *surface = qemu_console_surface(s->con);
1308     int first = 0, last;
1309 
1310 
1311     framebuffer_update_display(surface, &s->fbsection, s->width, s->height,
1312                                s->width, s->width * 4, 0, 0, artist_draw_line,
1313                                s, &first, &last);
1314 
1315     artist_draw_cursor(s);
1316 
1317     dpy_gfx_update(s->con, 0, 0, s->width, s->height);
1318 }
1319 
1320 static void artist_invalidate(void *opaque)
1321 {
1322     ARTISTState *s = ARTIST(opaque);
1323     struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1324     memory_region_set_dirty(&buf->mr, 0, buf->size);
1325 }
1326 
1327 static const GraphicHwOps artist_ops = {
1328     .invalidate  = artist_invalidate,
1329     .gfx_update = artist_update_display,
1330 };
1331 
1332 static void artist_initfn(Object *obj)
1333 {
1334     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1335     ARTISTState *s = ARTIST(obj);
1336 
1337     memory_region_init_io(&s->reg, obj, &artist_reg_ops, s, "artist.reg",
1338                           4 * MiB);
1339     memory_region_init_io(&s->vram_mem, obj, &artist_vram_ops, s, "artist.vram",
1340                           8 * MiB);
1341     sysbus_init_mmio(sbd, &s->reg);
1342     sysbus_init_mmio(sbd, &s->vram_mem);
1343 }
1344 
1345 static void artist_create_buffer(ARTISTState *s, const char *name,
1346                                  hwaddr *offset, unsigned int idx,
1347                                  int width, int height)
1348 {
1349     struct vram_buffer *buf = s->vram_buffer + idx;
1350 
1351     memory_region_init_ram(&buf->mr, NULL, name, width * height,
1352                            &error_fatal);
1353     memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0);
1354 
1355     buf->data = memory_region_get_ram_ptr(&buf->mr);
1356     buf->size = height * width;
1357     buf->width = width;
1358     buf->height = height;
1359 
1360     *offset += buf->size;
1361 }
1362 
1363 static void artist_realizefn(DeviceState *dev, Error **errp)
1364 {
1365     ARTISTState *s = ARTIST(dev);
1366     struct vram_buffer *buf;
1367     hwaddr offset = 0;
1368 
1369     memory_region_init(&s->mem_as_root, OBJECT(dev), "artist", ~0ull);
1370     address_space_init(&s->as, &s->mem_as_root, "artist");
1371 
1372     artist_create_buffer(s, "cmap", &offset, ARTIST_BUFFER_CMAP, 2048, 4);
1373     artist_create_buffer(s, "ap", &offset, ARTIST_BUFFER_AP,
1374                          s->width, s->height);
1375     artist_create_buffer(s, "cursor1", &offset, ARTIST_BUFFER_CURSOR1, 64, 64);
1376     artist_create_buffer(s, "cursor2", &offset, ARTIST_BUFFER_CURSOR2, 64, 64);
1377     artist_create_buffer(s, "attribute", &offset, ARTIST_BUFFER_ATTRIBUTE,
1378                          64, 64);
1379 
1380     buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1381     framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0,
1382                                       buf->width, buf->height);
1383     /*
1384      * no idea whether the cursor is fixed size or not, so assume 32x32 which
1385      * seems sufficient for HP-UX X11.
1386      */
1387     s->cursor_height = 32;
1388     s->cursor_width = 32;
1389 
1390     s->con = graphic_console_init(dev, 0, &artist_ops, s);
1391     qemu_console_resize(s->con, s->width, s->height);
1392 }
1393 
1394 static int vmstate_artist_post_load(void *opaque, int version_id)
1395 {
1396     artist_invalidate(opaque);
1397     return 0;
1398 }
1399 
1400 static const VMStateDescription vmstate_artist = {
1401     .name = "artist",
1402     .version_id = 1,
1403     .minimum_version_id = 1,
1404     .post_load = vmstate_artist_post_load,
1405     .fields = (VMStateField[]) {
1406         VMSTATE_UINT16(height, ARTISTState),
1407         VMSTATE_UINT16(width, ARTISTState),
1408         VMSTATE_UINT16(depth, ARTISTState),
1409         VMSTATE_UINT32(fg_color, ARTISTState),
1410         VMSTATE_UINT32(bg_color, ARTISTState),
1411         VMSTATE_UINT32(vram_char_y, ARTISTState),
1412         VMSTATE_UINT32(vram_bitmask, ARTISTState),
1413         VMSTATE_UINT32(vram_start, ARTISTState),
1414         VMSTATE_UINT32(vram_pos, ARTISTState),
1415         VMSTATE_UINT32(vram_size, ARTISTState),
1416         VMSTATE_UINT32(blockmove_source, ARTISTState),
1417         VMSTATE_UINT32(blockmove_dest, ARTISTState),
1418         VMSTATE_UINT32(blockmove_size, ARTISTState),
1419         VMSTATE_UINT32(line_size, ARTISTState),
1420         VMSTATE_UINT32(line_end, ARTISTState),
1421         VMSTATE_UINT32(line_xy, ARTISTState),
1422         VMSTATE_UINT32(cursor_pos, ARTISTState),
1423         VMSTATE_UINT32(cursor_height, ARTISTState),
1424         VMSTATE_UINT32(cursor_width, ARTISTState),
1425         VMSTATE_UINT32(plane_mask, ARTISTState),
1426         VMSTATE_UINT32(reg_100080, ARTISTState),
1427         VMSTATE_UINT32(reg_300200, ARTISTState),
1428         VMSTATE_UINT32(reg_300208, ARTISTState),
1429         VMSTATE_UINT32(reg_300218, ARTISTState),
1430         VMSTATE_UINT32(cmap_bm_access, ARTISTState),
1431         VMSTATE_UINT32(dst_bm_access, ARTISTState),
1432         VMSTATE_UINT32(src_bm_access, ARTISTState),
1433         VMSTATE_UINT32(control_plane, ARTISTState),
1434         VMSTATE_UINT32(transfer_data, ARTISTState),
1435         VMSTATE_UINT32(image_bitmap_op, ARTISTState),
1436         VMSTATE_UINT32(font_write1, ARTISTState),
1437         VMSTATE_UINT32(font_write2, ARTISTState),
1438         VMSTATE_UINT32(font_write_pos_y, ARTISTState),
1439         VMSTATE_END_OF_LIST()
1440     }
1441 };
1442 
1443 static Property artist_properties[] = {
1444     DEFINE_PROP_UINT16("width",        ARTISTState, width, 1280),
1445     DEFINE_PROP_UINT16("height",       ARTISTState, height, 1024),
1446     DEFINE_PROP_UINT16("depth",        ARTISTState, depth, 8),
1447     DEFINE_PROP_END_OF_LIST(),
1448 };
1449 
1450 static void artist_reset(DeviceState *qdev)
1451 {
1452 }
1453 
1454 static void artist_class_init(ObjectClass *klass, void *data)
1455 {
1456     DeviceClass *dc = DEVICE_CLASS(klass);
1457 
1458     dc->realize = artist_realizefn;
1459     dc->vmsd = &vmstate_artist;
1460     dc->reset = artist_reset;
1461     device_class_set_props(dc, artist_properties);
1462 }
1463 
1464 static const TypeInfo artist_info = {
1465     .name          = TYPE_ARTIST,
1466     .parent        = TYPE_SYS_BUS_DEVICE,
1467     .instance_size = sizeof(ARTISTState),
1468     .instance_init = artist_initfn,
1469     .class_init    = artist_class_init,
1470 };
1471 
1472 static void artist_register_types(void)
1473 {
1474     type_register_static(&artist_info);
1475 }
1476 
1477 type_init(artist_register_types)
1478