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 y += incy; 666 e += diago; 667 } else { 668 e += horiz; 669 } 670 x++; 671 } while (x <= x2 && (max_pix == -1 || --max_pix > 0)); 672 if (c1) 673 artist_invalidate_lines(buf, x, dy+1); 674 else 675 artist_invalidate_lines(buf, y, dx+1); 676 } 677 678 static void draw_line_pattern_start(ARTISTState *s) 679 { 680 681 int startx = artist_get_x(s->vram_start); 682 int starty = artist_get_y(s->vram_start); 683 int endx = artist_get_x(s->blockmove_size); 684 int endy = artist_get_y(s->blockmove_size); 685 int pstart = s->line_pattern_start >> 16; 686 687 draw_line(s, startx, starty, endx, endy, false, -1, pstart); 688 s->line_pattern_skip = pstart; 689 } 690 691 static void draw_line_pattern_next(ARTISTState *s) 692 { 693 694 int startx = artist_get_x(s->vram_start); 695 int starty = artist_get_y(s->vram_start); 696 int endx = artist_get_x(s->blockmove_size); 697 int endy = artist_get_y(s->blockmove_size); 698 int line_xy = s->line_xy >> 16; 699 700 draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip, 701 s->line_pattern_skip + line_xy); 702 s->line_pattern_skip += line_xy; 703 s->image_bitmap_op ^= 2; 704 } 705 706 static void draw_line_size(ARTISTState *s, bool update_start) 707 { 708 709 int startx = artist_get_x(s->vram_start); 710 int starty = artist_get_y(s->vram_start); 711 int endx = artist_get_x(s->line_size); 712 int endy = artist_get_y(s->line_size); 713 714 draw_line(s, startx, starty, endx, endy, update_start, -1, -1); 715 } 716 717 static void draw_line_xy(ARTISTState *s, bool update_start) 718 { 719 720 int startx = artist_get_x(s->vram_start); 721 int starty = artist_get_y(s->vram_start); 722 int sizex = artist_get_x(s->blockmove_size); 723 int sizey = artist_get_y(s->blockmove_size); 724 int linexy = s->line_xy >> 16; 725 int endx, endy; 726 727 endx = startx; 728 endy = starty; 729 730 if (sizex > 0) { 731 endx = startx + linexy; 732 } 733 734 if (sizex < 0) { 735 endx = startx; 736 startx -= linexy; 737 } 738 739 if (sizey > 0) { 740 endy = starty + linexy; 741 } 742 743 if (sizey < 0) { 744 endy = starty; 745 starty -= linexy; 746 } 747 748 if (startx < 0) { 749 startx = 0; 750 } 751 752 if (endx < 0) { 753 endx = 0; 754 } 755 756 if (starty < 0) { 757 starty = 0; 758 } 759 760 if (endy < 0) { 761 endy = 0; 762 } 763 764 draw_line(s, startx, starty, endx, endy, false, -1, -1); 765 } 766 767 static void draw_line_end(ARTISTState *s, bool update_start) 768 { 769 770 int startx = artist_get_x(s->vram_start); 771 int starty = artist_get_y(s->vram_start); 772 int endx = artist_get_x(s->line_end); 773 int endy = artist_get_y(s->line_end); 774 775 draw_line(s, startx, starty, endx, endy, update_start, -1, -1); 776 } 777 778 static void font_write16(ARTISTState *s, uint16_t val) 779 { 780 struct vram_buffer *buf; 781 uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color; 782 uint16_t mask; 783 int i; 784 785 unsigned int startx = artist_get_x(s->vram_start); 786 unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y; 787 unsigned int offset = starty * s->width + startx; 788 789 buf = &s->vram_buffer[ARTIST_BUFFER_AP]; 790 791 if (startx >= buf->width || starty >= buf->height || 792 offset + 16 >= buf->size) { 793 return; 794 } 795 796 for (i = 0; i < 16; i++) { 797 mask = 1 << (15 - i); 798 if (val & mask) { 799 artist_rop8(s, buf, offset + i, color); 800 } else { 801 if (!(s->image_bitmap_op & 0x20000000)) { 802 artist_rop8(s, buf, offset + i, s->bg_color); 803 } 804 } 805 } 806 artist_invalidate_lines(buf, starty, 1); 807 } 808 809 static void font_write(ARTISTState *s, uint32_t val) 810 { 811 font_write16(s, val >> 16); 812 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) { 813 s->vram_start += (s->blockmove_size & 0xffff0000); 814 return; 815 } 816 817 font_write16(s, val & 0xffff); 818 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) { 819 s->vram_start += (s->blockmove_size & 0xffff0000); 820 return; 821 } 822 } 823 824 static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out) 825 { 826 /* 827 * FIXME: is there a qemu helper for this? 828 */ 829 830 #ifndef HOST_WORDS_BIGENDIAN 831 addr ^= 3; 832 #endif 833 834 switch (size) { 835 case 1: 836 *(uint8_t *)(out + (addr & 3)) = val; 837 break; 838 839 case 2: 840 *(uint16_t *)(out + (addr & 2)) = val; 841 break; 842 843 case 4: 844 *(uint32_t *)out = val; 845 break; 846 847 default: 848 qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size); 849 } 850 } 851 852 static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, 853 unsigned size) 854 { 855 ARTISTState *s = opaque; 856 int posx, posy; 857 int width, height; 858 859 trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val); 860 861 switch (addr & ~3ULL) { 862 case 0x100080: 863 combine_write_reg(addr, val, size, &s->reg_100080); 864 break; 865 866 case FG_COLOR: 867 combine_write_reg(addr, val, size, &s->fg_color); 868 break; 869 870 case BG_COLOR: 871 combine_write_reg(addr, val, size, &s->bg_color); 872 break; 873 874 case VRAM_BITMASK: 875 combine_write_reg(addr, val, size, &s->vram_bitmask); 876 break; 877 878 case VRAM_WRITE_INCR_Y: 879 posx = (s->vram_pos >> 2) & 0x7ff; 880 posy = (s->vram_pos >> 13) & 0x3ff; 881 vram_bit_write(s, posx, posy + s->vram_char_y++, false, size, val); 882 break; 883 884 case VRAM_WRITE_INCR_X: 885 case VRAM_WRITE_INCR_X2: 886 posx = (s->vram_pos >> 2) & 0x7ff; 887 posy = (s->vram_pos >> 13) & 0x3ff; 888 vram_bit_write(s, posx, posy + s->vram_char_y, true, size, val); 889 break; 890 891 case VRAM_IDX: 892 combine_write_reg(addr, val, size, &s->vram_pos); 893 s->vram_char_y = 0; 894 s->draw_line_pattern = 0; 895 break; 896 897 case VRAM_START: 898 combine_write_reg(addr, val, size, &s->vram_start); 899 s->draw_line_pattern = 0; 900 break; 901 902 case VRAM_START_TRIGGER: 903 combine_write_reg(addr, val, size, &s->vram_start); 904 fill_window(s, artist_get_x(s->vram_start), 905 artist_get_y(s->vram_start), 906 artist_get_x(s->blockmove_size), 907 artist_get_y(s->blockmove_size)); 908 break; 909 910 case VRAM_SIZE_TRIGGER: 911 combine_write_reg(addr, val, size, &s->vram_size); 912 913 if (size == 2 && !(addr & 2)) { 914 height = artist_get_y(s->blockmove_size); 915 } else { 916 height = artist_get_y(s->vram_size); 917 } 918 919 if (size == 2 && (addr & 2)) { 920 width = artist_get_x(s->blockmove_size); 921 } else { 922 width = artist_get_x(s->vram_size); 923 } 924 925 fill_window(s, artist_get_x(s->vram_start), 926 artist_get_y(s->vram_start), 927 width, height); 928 break; 929 930 case LINE_XY: 931 combine_write_reg(addr, val, size, &s->line_xy); 932 if (s->draw_line_pattern) { 933 draw_line_pattern_next(s); 934 } else { 935 draw_line_xy(s, true); 936 } 937 break; 938 939 case PATTERN_LINE_START: 940 combine_write_reg(addr, val, size, &s->line_pattern_start); 941 s->draw_line_pattern = 1; 942 draw_line_pattern_start(s); 943 break; 944 945 case LINE_SIZE: 946 combine_write_reg(addr, val, size, &s->line_size); 947 draw_line_size(s, true); 948 break; 949 950 case LINE_END: 951 combine_write_reg(addr, val, size, &s->line_end); 952 draw_line_end(s, true); 953 break; 954 955 case BLOCK_MOVE_SIZE: 956 combine_write_reg(addr, val, size, &s->blockmove_size); 957 break; 958 959 case BLOCK_MOVE_SOURCE: 960 combine_write_reg(addr, val, size, &s->blockmove_source); 961 break; 962 963 case BLOCK_MOVE_DEST_TRIGGER: 964 combine_write_reg(addr, val, size, &s->blockmove_dest); 965 966 block_move(s, artist_get_x(s->blockmove_source), 967 artist_get_y(s->blockmove_source), 968 artist_get_x(s->blockmove_dest), 969 artist_get_y(s->blockmove_dest), 970 artist_get_x(s->blockmove_size), 971 artist_get_y(s->blockmove_size)); 972 break; 973 974 case BLOCK_MOVE_SIZE_TRIGGER: 975 combine_write_reg(addr, val, size, &s->blockmove_size); 976 977 block_move(s, 978 artist_get_x(s->blockmove_source), 979 artist_get_y(s->blockmove_source), 980 artist_get_x(s->vram_start), 981 artist_get_y(s->vram_start), 982 artist_get_x(s->blockmove_size), 983 artist_get_y(s->blockmove_size)); 984 break; 985 986 case PLANE_MASK: 987 combine_write_reg(addr, val, size, &s->plane_mask); 988 break; 989 990 case CMAP_BM_ACCESS: 991 combine_write_reg(addr, val, size, &s->cmap_bm_access); 992 break; 993 994 case DST_BM_ACCESS: 995 combine_write_reg(addr, val, size, &s->dst_bm_access); 996 s->cmap_bm_access = 0; 997 break; 998 999 case SRC_BM_ACCESS: 1000 combine_write_reg(addr, val, size, &s->src_bm_access); 1001 s->cmap_bm_access = 0; 1002 break; 1003 1004 case CONTROL_PLANE: 1005 combine_write_reg(addr, val, size, &s->control_plane); 1006 break; 1007 1008 case TRANSFER_DATA: 1009 combine_write_reg(addr, val, size, &s->transfer_data); 1010 break; 1011 1012 case 0x300200: 1013 combine_write_reg(addr, val, size, &s->reg_300200); 1014 break; 1015 1016 case 0x300208: 1017 combine_write_reg(addr, val, size, &s->reg_300208); 1018 break; 1019 1020 case 0x300218: 1021 combine_write_reg(addr, val, size, &s->reg_300218); 1022 break; 1023 1024 case CURSOR_POS: 1025 artist_invalidate_cursor(s); 1026 combine_write_reg(addr, val, size, &s->cursor_pos); 1027 artist_invalidate_cursor(s); 1028 break; 1029 1030 case CURSOR_CTRL: 1031 break; 1032 1033 case IMAGE_BITMAP_OP: 1034 combine_write_reg(addr, val, size, &s->image_bitmap_op); 1035 break; 1036 1037 case FONT_WRITE_INCR_Y: 1038 combine_write_reg(addr, val, size, &s->font_write1); 1039 font_write(s, s->font_write1); 1040 break; 1041 1042 case FONT_WRITE_START: 1043 combine_write_reg(addr, val, size, &s->font_write2); 1044 s->font_write_pos_y = 0; 1045 font_write(s, s->font_write2); 1046 break; 1047 1048 case 300104: 1049 break; 1050 1051 default: 1052 qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx 1053 " val=%08" PRIx64 " size=%d\n", 1054 __func__, addr, val, size); 1055 break; 1056 } 1057 } 1058 1059 static uint64_t combine_read_reg(hwaddr addr, int size, void *in) 1060 { 1061 /* 1062 * FIXME: is there a qemu helper for this? 1063 */ 1064 1065 #ifndef HOST_WORDS_BIGENDIAN 1066 addr ^= 3; 1067 #endif 1068 1069 switch (size) { 1070 case 1: 1071 return *(uint8_t *)(in + (addr & 3)); 1072 1073 case 2: 1074 return *(uint16_t *)(in + (addr & 2)); 1075 1076 case 4: 1077 return *(uint32_t *)in; 1078 1079 default: 1080 qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size); 1081 return 0; 1082 } 1083 } 1084 1085 static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size) 1086 { 1087 ARTISTState *s = opaque; 1088 uint32_t val = 0; 1089 1090 switch (addr & ~3ULL) { 1091 /* Unknown status registers */ 1092 case 0: 1093 break; 1094 1095 case 0x211110: 1096 val = (s->width << 16) | s->height; 1097 if (s->depth == 1) { 1098 val |= 1 << 31; 1099 } 1100 break; 1101 1102 case 0x100000: 1103 case 0x300000: 1104 case 0x300004: 1105 case 0x300308: 1106 case 0x380000: 1107 break; 1108 1109 case 0x300008: 1110 case 0x380008: 1111 /* 1112 * FIFO ready flag. we're not emulating the FIFOs 1113 * so we're always ready 1114 */ 1115 val = 0x10; 1116 break; 1117 1118 case 0x300200: 1119 val = s->reg_300200; 1120 break; 1121 1122 case 0x300208: 1123 val = s->reg_300208; 1124 break; 1125 1126 case 0x300218: 1127 val = s->reg_300218; 1128 break; 1129 1130 case 0x30023c: 1131 val = 0xac4ffdac; 1132 break; 1133 1134 case 0x380004: 1135 /* 0x02000000 Buserror */ 1136 val = 0x6dc20006; 1137 break; 1138 1139 default: 1140 qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx 1141 " size %d\n", __func__, addr, size); 1142 break; 1143 } 1144 val = combine_read_reg(addr, size, &val); 1145 trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val); 1146 return val; 1147 } 1148 1149 static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val, 1150 unsigned size) 1151 { 1152 ARTISTState *s = opaque; 1153 struct vram_buffer *buf; 1154 int posy = (addr >> 11) & 0x3ff; 1155 int posx = addr & 0x7ff; 1156 unsigned int offset; 1157 trace_artist_vram_write(size, addr, val); 1158 1159 if (s->cmap_bm_access) { 1160 buf = &s->vram_buffer[ARTIST_BUFFER_CMAP]; 1161 if (addr + 3 < buf->size) { 1162 *(uint32_t *)(buf->data + addr) = val; 1163 } 1164 return; 1165 } 1166 1167 buf = vram_write_buffer(s); 1168 if (!buf->size) { 1169 return; 1170 } 1171 1172 if (posy > buf->height || posx > buf->width) { 1173 return; 1174 } 1175 1176 offset = posy * buf->width + posx; 1177 if (offset >= buf->size) { 1178 return; 1179 } 1180 1181 switch (size) { 1182 case 4: 1183 if (offset + 3 < buf->size) { 1184 *(uint32_t *)(buf->data + offset) = be32_to_cpu(val); 1185 memory_region_set_dirty(&buf->mr, offset, 4); 1186 } 1187 break; 1188 case 2: 1189 if (offset + 1 < buf->size) { 1190 *(uint16_t *)(buf->data + offset) = be16_to_cpu(val); 1191 memory_region_set_dirty(&buf->mr, offset, 2); 1192 } 1193 break; 1194 case 1: 1195 if (offset < buf->size) { 1196 *(uint8_t *)(buf->data + offset) = val; 1197 memory_region_set_dirty(&buf->mr, offset, 1); 1198 } 1199 break; 1200 default: 1201 break; 1202 } 1203 } 1204 1205 static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size) 1206 { 1207 ARTISTState *s = opaque; 1208 struct vram_buffer *buf; 1209 uint64_t val; 1210 int posy, posx; 1211 1212 if (s->cmap_bm_access) { 1213 buf = &s->vram_buffer[ARTIST_BUFFER_CMAP]; 1214 val = 0; 1215 if (addr < buf->size && addr + 3 < buf->size) { 1216 val = *(uint32_t *)(buf->data + addr); 1217 } 1218 trace_artist_vram_read(size, addr, 0, 0, val); 1219 return val; 1220 } 1221 1222 buf = vram_read_buffer(s); 1223 if (!buf->size) { 1224 return 0; 1225 } 1226 1227 posy = (addr >> 13) & 0x3ff; 1228 posx = (addr >> 2) & 0x7ff; 1229 1230 if (posy > buf->height || posx > buf->width) { 1231 return 0; 1232 } 1233 1234 val = cpu_to_be32(*(uint32_t *)(buf->data + posy * buf->width + posx)); 1235 trace_artist_vram_read(size, addr, posx, posy, val); 1236 return val; 1237 } 1238 1239 static const MemoryRegionOps artist_reg_ops = { 1240 .read = artist_reg_read, 1241 .write = artist_reg_write, 1242 .endianness = DEVICE_NATIVE_ENDIAN, 1243 .impl.min_access_size = 1, 1244 .impl.max_access_size = 4, 1245 }; 1246 1247 static const MemoryRegionOps artist_vram_ops = { 1248 .read = artist_vram_read, 1249 .write = artist_vram_write, 1250 .endianness = DEVICE_NATIVE_ENDIAN, 1251 .impl.min_access_size = 1, 1252 .impl.max_access_size = 4, 1253 }; 1254 1255 static void artist_draw_cursor(ARTISTState *s) 1256 { 1257 DisplaySurface *surface = qemu_console_surface(s->con); 1258 uint32_t *data = (uint32_t *)surface_data(surface); 1259 struct vram_buffer *cursor0, *cursor1 , *buf; 1260 int cx, cy, cursor_pos_x, cursor_pos_y; 1261 1262 cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1]; 1263 cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2]; 1264 buf = &s->vram_buffer[ARTIST_BUFFER_AP]; 1265 1266 artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y); 1267 1268 for (cy = 0; cy < s->cursor_height; cy++) { 1269 1270 for (cx = 0; cx < s->cursor_width; cx++) { 1271 1272 if (cursor_pos_y + cy < 0 || 1273 cursor_pos_x + cx < 0 || 1274 cursor_pos_y + cy > buf->height - 1 || 1275 cursor_pos_x + cx > buf->width) { 1276 continue; 1277 } 1278 1279 int dstoffset = (cursor_pos_y + cy) * s->width + 1280 (cursor_pos_x + cx); 1281 1282 if (cursor0->data[cy * cursor0->width + cx]) { 1283 data[dstoffset] = 0; 1284 } else { 1285 if (cursor1->data[cy * cursor1->width + cx]) { 1286 data[dstoffset] = 0xffffff; 1287 } 1288 } 1289 } 1290 } 1291 } 1292 1293 static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src, 1294 int width, int pitch) 1295 { 1296 ARTISTState *s = ARTIST(opaque); 1297 uint32_t *cmap, *data = (uint32_t *)d; 1298 int x; 1299 1300 cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400); 1301 1302 for (x = 0; x < s->width; x++) { 1303 *data++ = cmap[*src++]; 1304 } 1305 } 1306 1307 static void artist_update_display(void *opaque) 1308 { 1309 ARTISTState *s = opaque; 1310 DisplaySurface *surface = qemu_console_surface(s->con); 1311 int first = 0, last; 1312 1313 1314 framebuffer_update_display(surface, &s->fbsection, s->width, s->height, 1315 s->width, s->width * 4, 0, 0, artist_draw_line, 1316 s, &first, &last); 1317 1318 artist_draw_cursor(s); 1319 1320 dpy_gfx_update(s->con, 0, 0, s->width, s->height); 1321 } 1322 1323 static void artist_invalidate(void *opaque) 1324 { 1325 ARTISTState *s = ARTIST(opaque); 1326 struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP]; 1327 memory_region_set_dirty(&buf->mr, 0, buf->size); 1328 } 1329 1330 static const GraphicHwOps artist_ops = { 1331 .invalidate = artist_invalidate, 1332 .gfx_update = artist_update_display, 1333 }; 1334 1335 static void artist_initfn(Object *obj) 1336 { 1337 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 1338 ARTISTState *s = ARTIST(obj); 1339 1340 memory_region_init_io(&s->reg, obj, &artist_reg_ops, s, "artist.reg", 1341 4 * MiB); 1342 memory_region_init_io(&s->vram_mem, obj, &artist_vram_ops, s, "artist.vram", 1343 8 * MiB); 1344 sysbus_init_mmio(sbd, &s->reg); 1345 sysbus_init_mmio(sbd, &s->vram_mem); 1346 } 1347 1348 static void artist_create_buffer(ARTISTState *s, const char *name, 1349 hwaddr *offset, unsigned int idx, 1350 int width, int height) 1351 { 1352 struct vram_buffer *buf = s->vram_buffer + idx; 1353 1354 memory_region_init_ram(&buf->mr, NULL, name, width * height, 1355 &error_fatal); 1356 memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0); 1357 1358 buf->data = memory_region_get_ram_ptr(&buf->mr); 1359 buf->size = height * width; 1360 buf->width = width; 1361 buf->height = height; 1362 1363 *offset += buf->size; 1364 } 1365 1366 static void artist_realizefn(DeviceState *dev, Error **errp) 1367 { 1368 ARTISTState *s = ARTIST(dev); 1369 struct vram_buffer *buf; 1370 hwaddr offset = 0; 1371 1372 memory_region_init(&s->mem_as_root, OBJECT(dev), "artist", ~0ull); 1373 address_space_init(&s->as, &s->mem_as_root, "artist"); 1374 1375 artist_create_buffer(s, "cmap", &offset, ARTIST_BUFFER_CMAP, 2048, 4); 1376 artist_create_buffer(s, "ap", &offset, ARTIST_BUFFER_AP, 1377 s->width, s->height); 1378 artist_create_buffer(s, "cursor1", &offset, ARTIST_BUFFER_CURSOR1, 64, 64); 1379 artist_create_buffer(s, "cursor2", &offset, ARTIST_BUFFER_CURSOR2, 64, 64); 1380 artist_create_buffer(s, "attribute", &offset, ARTIST_BUFFER_ATTRIBUTE, 1381 64, 64); 1382 1383 buf = &s->vram_buffer[ARTIST_BUFFER_AP]; 1384 framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0, 1385 buf->width, buf->height); 1386 /* 1387 * no idea whether the cursor is fixed size or not, so assume 32x32 which 1388 * seems sufficient for HP-UX X11. 1389 */ 1390 s->cursor_height = 32; 1391 s->cursor_width = 32; 1392 1393 s->con = graphic_console_init(dev, 0, &artist_ops, s); 1394 qemu_console_resize(s->con, s->width, s->height); 1395 } 1396 1397 static int vmstate_artist_post_load(void *opaque, int version_id) 1398 { 1399 artist_invalidate(opaque); 1400 return 0; 1401 } 1402 1403 static const VMStateDescription vmstate_artist = { 1404 .name = "artist", 1405 .version_id = 1, 1406 .minimum_version_id = 1, 1407 .post_load = vmstate_artist_post_load, 1408 .fields = (VMStateField[]) { 1409 VMSTATE_UINT16(height, ARTISTState), 1410 VMSTATE_UINT16(width, ARTISTState), 1411 VMSTATE_UINT16(depth, ARTISTState), 1412 VMSTATE_UINT32(fg_color, ARTISTState), 1413 VMSTATE_UINT32(bg_color, ARTISTState), 1414 VMSTATE_UINT32(vram_char_y, ARTISTState), 1415 VMSTATE_UINT32(vram_bitmask, ARTISTState), 1416 VMSTATE_UINT32(vram_start, ARTISTState), 1417 VMSTATE_UINT32(vram_pos, ARTISTState), 1418 VMSTATE_UINT32(vram_size, ARTISTState), 1419 VMSTATE_UINT32(blockmove_source, ARTISTState), 1420 VMSTATE_UINT32(blockmove_dest, ARTISTState), 1421 VMSTATE_UINT32(blockmove_size, ARTISTState), 1422 VMSTATE_UINT32(line_size, ARTISTState), 1423 VMSTATE_UINT32(line_end, ARTISTState), 1424 VMSTATE_UINT32(line_xy, ARTISTState), 1425 VMSTATE_UINT32(cursor_pos, ARTISTState), 1426 VMSTATE_UINT32(cursor_height, ARTISTState), 1427 VMSTATE_UINT32(cursor_width, ARTISTState), 1428 VMSTATE_UINT32(plane_mask, ARTISTState), 1429 VMSTATE_UINT32(reg_100080, ARTISTState), 1430 VMSTATE_UINT32(reg_300200, ARTISTState), 1431 VMSTATE_UINT32(reg_300208, ARTISTState), 1432 VMSTATE_UINT32(reg_300218, ARTISTState), 1433 VMSTATE_UINT32(cmap_bm_access, ARTISTState), 1434 VMSTATE_UINT32(dst_bm_access, ARTISTState), 1435 VMSTATE_UINT32(src_bm_access, ARTISTState), 1436 VMSTATE_UINT32(control_plane, ARTISTState), 1437 VMSTATE_UINT32(transfer_data, ARTISTState), 1438 VMSTATE_UINT32(image_bitmap_op, ARTISTState), 1439 VMSTATE_UINT32(font_write1, ARTISTState), 1440 VMSTATE_UINT32(font_write2, ARTISTState), 1441 VMSTATE_UINT32(font_write_pos_y, ARTISTState), 1442 VMSTATE_END_OF_LIST() 1443 } 1444 }; 1445 1446 static Property artist_properties[] = { 1447 DEFINE_PROP_UINT16("width", ARTISTState, width, 1280), 1448 DEFINE_PROP_UINT16("height", ARTISTState, height, 1024), 1449 DEFINE_PROP_UINT16("depth", ARTISTState, depth, 8), 1450 DEFINE_PROP_END_OF_LIST(), 1451 }; 1452 1453 static void artist_reset(DeviceState *qdev) 1454 { 1455 } 1456 1457 static void artist_class_init(ObjectClass *klass, void *data) 1458 { 1459 DeviceClass *dc = DEVICE_CLASS(klass); 1460 1461 dc->realize = artist_realizefn; 1462 dc->vmsd = &vmstate_artist; 1463 dc->reset = artist_reset; 1464 device_class_set_props(dc, artist_properties); 1465 } 1466 1467 static const TypeInfo artist_info = { 1468 .name = TYPE_ARTIST, 1469 .parent = TYPE_SYS_BUS_DEVICE, 1470 .instance_size = sizeof(ARTISTState), 1471 .instance_init = artist_initfn, 1472 .class_init = artist_class_init, 1473 }; 1474 1475 static void artist_register_types(void) 1476 { 1477 type_register_static(&artist_info); 1478 } 1479 1480 type_init(artist_register_types) 1481