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