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