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