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