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