qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

artist.c (40211B)


      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;
    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 
    211 static int16_t artist_get_x(uint32_t reg)
    212 {
    213     return reg >> 16;
    214 }
    215 
    216 static int16_t artist_get_y(uint32_t reg)
    217 {
    218     return reg & 0xffff;
    219 }
    220 
    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 
    238 static int vram_write_bufidx(ARTISTState *s)
    239 {
    240     return (s->dst_bm_access >> 12) & 0x0f;
    241 }
    242 
    243 static int vram_read_bufidx(ARTISTState *s)
    244 {
    245     return (s->src_bm_access >> 12) & 0x0f;
    246 }
    247 
    248 static struct vram_buffer *vram_read_buffer(ARTISTState *s)
    249 {
    250     return &s->vram_buffer[vram_read_bufidx(s)];
    251 }
    252 
    253 static struct vram_buffer *vram_write_buffer(ARTISTState *s)
    254 {
    255     return &s->vram_buffer[vram_write_bufidx(s)];
    256 }
    257 
    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 
    267 static artist_rop_t artist_get_op(ARTISTState *s)
    268 {
    269     return (s->image_bitmap_op >> 8) & 0xf;
    270 }
    271 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 = (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 
   1484 static void artist_reset(DeviceState *qdev)
   1485 {
   1486 }
   1487 
   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     dc->reset = 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 
   1506 static void artist_register_types(void)
   1507 {
   1508     type_register_static(&artist_info);
   1509 }
   1510 
   1511 type_init(artist_register_types)