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