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