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