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