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