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