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