qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hppa: Add emulation of Artist graphics

This adds emulation of Artist graphics good enough to get a text
console on both Linux and HP-UX. The X11 server from HP-UX also works.

Adjust boot-serial-test to disable graphics, so that SeaBIOS outputs
to the serial port, as expected by the test.

Signed-off-by: Sven Schnelle <svens@stackframe.org>
Message-Id: <20191220211512.3289-6-svens@stackframe.org>
[rth: Merge Helge's test for machine->enable_graphics]
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

authored by

Sven Schnelle and committed by
Richard Henderson
4765384c 346e78f6

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