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