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