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