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