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