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