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