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