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