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