]> git.proxmox.com Git - mirror_qemu.git/blob - hw/display/artist.c
80cd66e41dcd4454f7aff0c665a8c1efd238f468
[mirror_qemu.git] / hw / display / artist.c
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)