cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

artist.c (38735B)


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