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