]> git.proxmox.com Git - mirror_qemu.git/blame - hw/display/artist.c
various: Remove unnecessary OBJECT() cast
[mirror_qemu.git] / hw / display / artist.c
CommitLineData
4765384c
SS
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
35struct vram_buffer {
36 MemoryRegion mr;
37 uint8_t *data;
38 int size;
39 int width;
40 int height;
41};
42
43typedef 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
108typedef 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
117typedef 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
149typedef 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;
158static 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
195static int16_t artist_get_x(uint32_t reg)
196{
197 return reg >> 16;
198}
199
200static int16_t artist_get_y(uint32_t reg)
201{
202 return reg & 0xffff;
203}
204
205static 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
216static 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
225static 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
234static 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
243static 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
252static struct vram_buffer *vram_read_buffer(ARTISTState *s)
253{
254 return &s->vram_buffer[vram_read_bufidx(s)];
255}
256
257static struct vram_buffer *vram_write_buffer(ARTISTState *s)
258{
259 return &s->vram_buffer[vram_write_bufidx(s)];
260}
261
262static 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
271static artist_rop_t artist_get_op(ARTISTState *s)
272{
273 return (s->image_bitmap_op >> 8) & 0xf;
274}
275
276static 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
310static 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
330static 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
338static 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
460static 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
517static 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
557static 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;
0814343c 561 uint8_t color;
4765384c
SS
562 int dx, dy, t, e, x, y, incy, diago, horiz;
563 bool c1;
564 uint8_t *p;
565
5646bca3 566 trace_artist_draw_line(x1, y1, x2, y2);
4765384c
SS
567
568 if (update_start) {
569 s->vram_start = (x2 << 16) | y2;
570 }
571
4765384c
SS
572 if (x2 > x1) {
573 dx = x2 - x1;
574 } else {
575 dx = x1 - x2;
576 }
577 if (y2 > y1) {
578 dy = y2 - y1;
579 } else {
580 dy = y1 - y2;
581 }
b0f6455f
PMD
582 if (!dx || !dy) {
583 return;
584 }
0814343c
PMD
585
586 c1 = false;
4765384c
SS
587 if (dy > dx) {
588 t = y2;
589 y2 = x2;
590 x2 = t;
591
592 t = y1;
593 y1 = x1;
594 x1 = t;
595
596 t = dx;
597 dx = dy;
598 dy = t;
599
600 c1 = true;
601 }
602
603 if (x1 > x2) {
604 t = y2;
605 y2 = y1;
606 y1 = t;
607
608 t = x1;
609 x1 = x2;
610 x2 = t;
611 }
612
613 horiz = dy << 1;
614 diago = (dy - dx) << 1;
615 e = (dy << 1) - dx;
616
617 if (y1 <= y2) {
618 incy = 1;
619 } else {
620 incy = -1;
621 }
622 x = x1;
623 y = y1;
0814343c
PMD
624 color = artist_get_color(s);
625 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
4765384c
SS
626
627 do {
628 if (c1) {
629 p = buf->data + x * s->width + y;
630 } else {
631 p = buf->data + y * s->width + x;
632 }
633
634 if (skip_pix > 0) {
635 skip_pix--;
636 } else {
637 artist_rop8(s, p, color);
638 }
639
640 if (e > 0) {
641 artist_invalidate_lines(buf, y, 1);
642 y += incy;
643 e += diago;
644 } else {
645 e += horiz;
646 }
647 x++;
648 } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
649}
650
651static void draw_line_pattern_start(ARTISTState *s)
652{
653
654 int startx = artist_get_x(s->vram_start);
655 int starty = artist_get_y(s->vram_start);
656 int endx = artist_get_x(s->blockmove_size);
657 int endy = artist_get_y(s->blockmove_size);
658 int pstart = s->line_pattern_start >> 16;
659
4765384c
SS
660 draw_line(s, startx, starty, endx, endy, false, -1, pstart);
661 s->line_pattern_skip = pstart;
662}
663
664static void draw_line_pattern_next(ARTISTState *s)
665{
666
667 int startx = artist_get_x(s->vram_start);
668 int starty = artist_get_y(s->vram_start);
669 int endx = artist_get_x(s->blockmove_size);
670 int endy = artist_get_y(s->blockmove_size);
671 int line_xy = s->line_xy >> 16;
672
4765384c
SS
673 draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip,
674 s->line_pattern_skip + line_xy);
675 s->line_pattern_skip += line_xy;
676 s->image_bitmap_op ^= 2;
677}
678
679static void draw_line_size(ARTISTState *s, bool update_start)
680{
681
682 int startx = artist_get_x(s->vram_start);
683 int starty = artist_get_y(s->vram_start);
684 int endx = artist_get_x(s->line_size);
685 int endy = artist_get_y(s->line_size);
686
4765384c
SS
687 draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
688}
689
690static 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
4765384c
SS
737 draw_line(s, startx, starty, endx, endy, false, -1, -1);
738}
739
740static void draw_line_end(ARTISTState *s, bool update_start)
741{
742
743 int startx = artist_get_x(s->vram_start);
744 int starty = artist_get_y(s->vram_start);
745 int endx = artist_get_x(s->line_end);
746 int endy = artist_get_y(s->line_end);
747
4765384c
SS
748 draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
749}
750
751static void font_write16(ARTISTState *s, uint16_t val)
752{
753 struct vram_buffer *buf;
754 uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color;
755 uint16_t mask;
756 int i;
757
758 int startx = artist_get_x(s->vram_start);
759 int starty = artist_get_y(s->vram_start) + s->font_write_pos_y;
760 int offset = starty * s->width + startx;
761
762 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
763
764 if (offset + 16 > buf->size) {
765 return;
766 }
767
768 for (i = 0; i < 16; i++) {
769 mask = 1 << (15 - i);
770 if (val & mask) {
771 artist_rop8(s, buf->data + offset + i, color);
772 } else {
773 if (!(s->image_bitmap_op & 0x20000000)) {
774 artist_rop8(s, buf->data + offset + i, s->bg_color);
775 }
776 }
777 }
778 artist_invalidate_lines(buf, starty, 1);
779}
780
781static void font_write(ARTISTState *s, uint32_t val)
782{
783 font_write16(s, val >> 16);
784 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
785 s->vram_start += (s->blockmove_size & 0xffff0000);
786 return;
787 }
788
789 font_write16(s, val & 0xffff);
790 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
791 s->vram_start += (s->blockmove_size & 0xffff0000);
792 return;
793 }
794}
795
796static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
797{
798 /*
799 * FIXME: is there a qemu helper for this?
800 */
801
802#ifndef HOST_WORDS_BIGENDIAN
803 addr ^= 3;
804#endif
805
806 switch (size) {
807 case 1:
808 *(uint8_t *)(out + (addr & 3)) = val;
809 break;
810
811 case 2:
812 *(uint16_t *)(out + (addr & 2)) = val;
813 break;
814
815 case 4:
816 *(uint32_t *)out = val;
817 break;
818
819 default:
820 qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size);
821 }
822}
823
824static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
825 unsigned size)
826{
827 ARTISTState *s = opaque;
828 int posx, posy;
829 int width, height;
830
831 trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val);
832
833 switch (addr & ~3ULL) {
834 case 0x100080:
835 combine_write_reg(addr, val, size, &s->reg_100080);
836 break;
837
838 case FG_COLOR:
839 combine_write_reg(addr, val, size, &s->fg_color);
840 break;
841
842 case BG_COLOR:
843 combine_write_reg(addr, val, size, &s->bg_color);
844 break;
845
846 case VRAM_BITMASK:
847 combine_write_reg(addr, val, size, &s->vram_bitmask);
848 break;
849
850 case VRAM_WRITE_INCR_Y:
851 posx = (s->vram_pos >> 2) & 0x7ff;
852 posy = (s->vram_pos >> 13) & 0x3ff;
853 vram_bit_write(s, posx, posy + s->vram_char_y++, false, size, val);
854 break;
855
856 case VRAM_WRITE_INCR_X:
857 case VRAM_WRITE_INCR_X2:
858 posx = (s->vram_pos >> 2) & 0x7ff;
859 posy = (s->vram_pos >> 13) & 0x3ff;
860 vram_bit_write(s, posx, posy + s->vram_char_y, true, size, val);
861 break;
862
863 case VRAM_IDX:
864 combine_write_reg(addr, val, size, &s->vram_pos);
865 s->vram_char_y = 0;
866 s->draw_line_pattern = 0;
867 break;
868
869 case VRAM_START:
870 combine_write_reg(addr, val, size, &s->vram_start);
871 s->draw_line_pattern = 0;
872 break;
873
874 case VRAM_START_TRIGGER:
875 combine_write_reg(addr, val, size, &s->vram_start);
876 fill_window(s, artist_get_x(s->vram_start),
877 artist_get_y(s->vram_start),
878 artist_get_x(s->blockmove_size),
879 artist_get_y(s->blockmove_size));
880 break;
881
882 case VRAM_SIZE_TRIGGER:
883 combine_write_reg(addr, val, size, &s->vram_size);
884
885 if (size == 2 && !(addr & 2)) {
886 height = artist_get_y(s->blockmove_size);
887 } else {
888 height = artist_get_y(s->vram_size);
889 }
890
891 if (size == 2 && (addr & 2)) {
892 width = artist_get_x(s->blockmove_size);
893 } else {
894 width = artist_get_x(s->vram_size);
895 }
896
897 fill_window(s, artist_get_x(s->vram_start),
898 artist_get_y(s->vram_start),
899 width, height);
900 break;
901
902 case LINE_XY:
903 combine_write_reg(addr, val, size, &s->line_xy);
904 if (s->draw_line_pattern) {
905 draw_line_pattern_next(s);
906 } else {
907 draw_line_xy(s, true);
908 }
909 break;
910
911 case PATTERN_LINE_START:
912 combine_write_reg(addr, val, size, &s->line_pattern_start);
913 s->draw_line_pattern = 1;
914 draw_line_pattern_start(s);
915 break;
916
917 case LINE_SIZE:
918 combine_write_reg(addr, val, size, &s->line_size);
919 draw_line_size(s, true);
920 break;
921
922 case LINE_END:
923 combine_write_reg(addr, val, size, &s->line_end);
924 draw_line_end(s, true);
925 break;
926
927 case BLOCK_MOVE_SIZE:
928 combine_write_reg(addr, val, size, &s->blockmove_size);
929 break;
930
931 case BLOCK_MOVE_SOURCE:
932 combine_write_reg(addr, val, size, &s->blockmove_source);
933 break;
934
935 case BLOCK_MOVE_DEST_TRIGGER:
936 combine_write_reg(addr, val, size, &s->blockmove_dest);
937
938 block_move(s, artist_get_x(s->blockmove_source),
939 artist_get_y(s->blockmove_source),
940 artist_get_x(s->blockmove_dest),
941 artist_get_y(s->blockmove_dest),
942 artist_get_x(s->blockmove_size),
943 artist_get_y(s->blockmove_size));
944 break;
945
946 case BLOCK_MOVE_SIZE_TRIGGER:
947 combine_write_reg(addr, val, size, &s->blockmove_size);
948
949 block_move(s,
950 artist_get_x(s->blockmove_source),
951 artist_get_y(s->blockmove_source),
952 artist_get_x(s->vram_start),
953 artist_get_y(s->vram_start),
954 artist_get_x(s->blockmove_size),
955 artist_get_y(s->blockmove_size));
956 break;
957
958 case PLANE_MASK:
959 combine_write_reg(addr, val, size, &s->plane_mask);
960 break;
961
962 case CMAP_BM_ACCESS:
963 combine_write_reg(addr, val, size, &s->cmap_bm_access);
964 break;
965
966 case DST_BM_ACCESS:
967 combine_write_reg(addr, val, size, &s->dst_bm_access);
968 s->cmap_bm_access = 0;
969 break;
970
971 case SRC_BM_ACCESS:
972 combine_write_reg(addr, val, size, &s->src_bm_access);
973 s->cmap_bm_access = 0;
974 break;
975
976 case CONTROL_PLANE:
977 combine_write_reg(addr, val, size, &s->control_plane);
978 break;
979
980 case TRANSFER_DATA:
981 combine_write_reg(addr, val, size, &s->transfer_data);
982 break;
983
984 case 0x300200:
985 combine_write_reg(addr, val, size, &s->reg_300200);
986 break;
987
988 case 0x300208:
989 combine_write_reg(addr, val, size, &s->reg_300208);
990 break;
991
992 case 0x300218:
993 combine_write_reg(addr, val, size, &s->reg_300218);
994 break;
995
996 case CURSOR_POS:
997 artist_invalidate_cursor(s);
998 combine_write_reg(addr, val, size, &s->cursor_pos);
999 artist_invalidate_cursor(s);
1000 break;
1001
1002 case CURSOR_CTRL:
1003 break;
1004
1005 case IMAGE_BITMAP_OP:
1006 combine_write_reg(addr, val, size, &s->image_bitmap_op);
1007 break;
1008
1009 case FONT_WRITE_INCR_Y:
1010 combine_write_reg(addr, val, size, &s->font_write1);
1011 font_write(s, s->font_write1);
1012 break;
1013
1014 case FONT_WRITE_START:
1015 combine_write_reg(addr, val, size, &s->font_write2);
1016 s->font_write_pos_y = 0;
1017 font_write(s, s->font_write2);
1018 break;
1019
1020 case 300104:
1021 break;
1022
1023 default:
1024 qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx
1025 " val=%08" PRIx64 " size=%d\n",
1026 __func__, addr, val, size);
1027 break;
1028 }
1029}
1030
1031static uint64_t combine_read_reg(hwaddr addr, int size, void *in)
1032{
1033 /*
1034 * FIXME: is there a qemu helper for this?
1035 */
1036
1037#ifndef HOST_WORDS_BIGENDIAN
1038 addr ^= 3;
1039#endif
1040
1041 switch (size) {
1042 case 1:
1043 return *(uint8_t *)(in + (addr & 3));
1044
1045 case 2:
1046 return *(uint16_t *)(in + (addr & 2));
1047
1048 case 4:
1049 return *(uint32_t *)in;
1050
1051 default:
1052 qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size);
1053 return 0;
1054 }
1055}
1056
1057static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
1058{
1059 ARTISTState *s = opaque;
1060 uint32_t val = 0;
1061
1062 switch (addr & ~3ULL) {
1063 /* Unknown status registers */
1064 case 0:
1065 break;
1066
1067 case 0x211110:
1068 val = (s->width << 16) | s->height;
1069 if (s->depth == 1) {
1070 val |= 1 << 31;
1071 }
1072 break;
1073
1074 case 0x100000:
1075 case 0x300000:
1076 case 0x300004:
1077 case 0x300308:
1078 case 0x380000:
1079 break;
1080
1081 case 0x300008:
1082 case 0x380008:
1083 /*
1084 * FIFO ready flag. we're not emulating the FIFOs
1085 * so we're always ready
1086 */
1087 val = 0x10;
1088 break;
1089
1090 case 0x300200:
1091 val = s->reg_300200;
1092 break;
1093
1094 case 0x300208:
1095 val = s->reg_300208;
1096 break;
1097
1098 case 0x300218:
1099 val = s->reg_300218;
1100 break;
1101
1102 case 0x30023c:
1103 val = 0xac4ffdac;
1104 break;
1105
1106 case 0x380004:
1107 /* 0x02000000 Buserror */
1108 val = 0x6dc20006;
1109 break;
1110
1111 default:
1112 qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx
1113 " size %d\n", __func__, addr, size);
1114 break;
1115 }
1116 val = combine_read_reg(addr, size, &val);
1117 trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val);
1118 return val;
1119}
1120
1121static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
1122 unsigned size)
1123{
1124 ARTISTState *s = opaque;
1125 struct vram_buffer *buf;
1126 int posy = (addr >> 11) & 0x3ff;
1127 int posx = addr & 0x7ff;
1128 uint32_t offset;
1129 trace_artist_vram_write(size, addr, val);
1130
1131 if (s->cmap_bm_access) {
1132 buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1133 if (addr + 3 < buf->size) {
1134 *(uint32_t *)(buf->data + addr) = val;
1135 }
1136 return;
1137 }
1138
1139 buf = vram_write_buffer(s);
1140 if (!buf->size) {
1141 return;
1142 }
1143
1144 if (posy > buf->height || posx > buf->width) {
1145 return;
1146 }
1147
1148 offset = posy * buf->width + posx;
1149 switch (size) {
1150 case 4:
1151 *(uint32_t *)(buf->data + offset) = be32_to_cpu(val);
1152 memory_region_set_dirty(&buf->mr, offset, 4);
1153 break;
1154 case 2:
1155 *(uint16_t *)(buf->data + offset) = be16_to_cpu(val);
1156 memory_region_set_dirty(&buf->mr, offset, 2);
1157 break;
1158 case 1:
1159 *(uint8_t *)(buf->data + offset) = val;
1160 memory_region_set_dirty(&buf->mr, offset, 1);
1161 break;
1162 default:
1163 break;
1164 }
1165}
1166
1167static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
1168{
1169 ARTISTState *s = opaque;
1170 struct vram_buffer *buf;
1171 uint64_t val;
1172 int posy, posx;
1173
1174 if (s->cmap_bm_access) {
1175 buf = &s->vram_buffer[ARTIST_BUFFER_CMAP];
1176 val = *(uint32_t *)(buf->data + addr);
1177 trace_artist_vram_read(size, addr, 0, 0, val);
1178 return 0;
1179 }
1180
1181 buf = vram_read_buffer(s);
1182 if (!buf->size) {
1183 return 0;
1184 }
1185
1186 posy = (addr >> 13) & 0x3ff;
1187 posx = (addr >> 2) & 0x7ff;
1188
1189 if (posy > buf->height || posx > buf->width) {
1190 return 0;
1191 }
1192
1193 val = cpu_to_be32(*(uint32_t *)(buf->data + posy * buf->width + posx));
1194 trace_artist_vram_read(size, addr, posx, posy, val);
1195 return val;
1196}
1197
1198static const MemoryRegionOps artist_reg_ops = {
1199 .read = artist_reg_read,
1200 .write = artist_reg_write,
1201 .endianness = DEVICE_NATIVE_ENDIAN,
1202 .valid = {
1203 .min_access_size = 1,
1204 .max_access_size = 4,
1205 },
1206};
1207
1208static const MemoryRegionOps artist_vram_ops = {
1209 .read = artist_vram_read,
1210 .write = artist_vram_write,
1211 .endianness = DEVICE_NATIVE_ENDIAN,
1212 .valid = {
1213 .min_access_size = 1,
1214 .max_access_size = 4,
1215 },
1216};
1217
1218static void artist_draw_cursor(ARTISTState *s)
1219{
1220 DisplaySurface *surface = qemu_console_surface(s->con);
1221 uint32_t *data = (uint32_t *)surface_data(surface);
1222 struct vram_buffer *cursor0, *cursor1 , *buf;
1223 int cx, cy, cursor_pos_x, cursor_pos_y;
1224
1225 cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1];
1226 cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2];
1227 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1228
1229 artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y);
1230
1231 for (cy = 0; cy < s->cursor_height; cy++) {
1232
1233 for (cx = 0; cx < s->cursor_width; cx++) {
1234
1235 if (cursor_pos_y + cy < 0 ||
1236 cursor_pos_x + cx < 0 ||
1237 cursor_pos_y + cy > buf->height - 1 ||
1238 cursor_pos_x + cx > buf->width) {
1239 continue;
1240 }
1241
1242 int dstoffset = (cursor_pos_y + cy) * s->width +
1243 (cursor_pos_x + cx);
1244
1245 if (cursor0->data[cy * cursor0->width + cx]) {
1246 data[dstoffset] = 0;
1247 } else {
1248 if (cursor1->data[cy * cursor1->width + cx]) {
1249 data[dstoffset] = 0xffffff;
1250 }
1251 }
1252 }
1253 }
1254}
1255
1256static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
1257 int width, int pitch)
1258{
1259 ARTISTState *s = ARTIST(opaque);
1260 uint32_t *cmap, *data = (uint32_t *)d;
1261 int x;
1262
1263 cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400);
1264
1265 for (x = 0; x < s->width; x++) {
1266 *data++ = cmap[*src++];
1267 }
1268}
1269
1270static void artist_update_display(void *opaque)
1271{
1272 ARTISTState *s = opaque;
1273 DisplaySurface *surface = qemu_console_surface(s->con);
1274 int first = 0, last;
1275
1276
1277 framebuffer_update_display(surface, &s->fbsection, s->width, s->height,
1278 s->width, s->width * 4, 0, 0, artist_draw_line,
1279 s, &first, &last);
1280
1281 artist_draw_cursor(s);
1282
1283 dpy_gfx_update(s->con, 0, 0, s->width, s->height);
1284}
1285
1286static void artist_invalidate(void *opaque)
1287{
1288 ARTISTState *s = ARTIST(opaque);
1289 struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1290 memory_region_set_dirty(&buf->mr, 0, buf->size);
1291}
1292
1293static const GraphicHwOps artist_ops = {
1294 .invalidate = artist_invalidate,
1295 .gfx_update = artist_update_display,
1296};
1297
1298static void artist_initfn(Object *obj)
1299{
1300 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1301 ARTISTState *s = ARTIST(obj);
1302
1303 memory_region_init_io(&s->reg, obj, &artist_reg_ops, s, "artist.reg",
1304 4 * MiB);
1305 memory_region_init_io(&s->vram_mem, obj, &artist_vram_ops, s, "artist.vram",
1306 8 * MiB);
1307 sysbus_init_mmio(sbd, &s->reg);
1308 sysbus_init_mmio(sbd, &s->vram_mem);
1309}
1310
1311static void artist_create_buffer(ARTISTState *s, const char *name,
1312 hwaddr *offset, unsigned int idx,
1313 int width, int height)
1314{
1315 struct vram_buffer *buf = s->vram_buffer + idx;
1316
1317 memory_region_init_ram(&buf->mr, NULL, name, width * height,
1318 &error_fatal);
1319 memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0);
1320
1321 buf->data = memory_region_get_ram_ptr(&buf->mr);
1322 buf->size = height * width;
1323 buf->width = width;
1324 buf->height = height;
1325
1326 *offset += buf->size;
1327}
1328
1329static void artist_realizefn(DeviceState *dev, Error **errp)
1330{
1331 ARTISTState *s = ARTIST(dev);
1332 struct vram_buffer *buf;
1333 hwaddr offset = 0;
1334
1335 memory_region_init(&s->mem_as_root, OBJECT(dev), "artist", ~0ull);
1336 address_space_init(&s->as, &s->mem_as_root, "artist");
1337
1338 artist_create_buffer(s, "cmap", &offset, ARTIST_BUFFER_CMAP, 2048, 4);
1339 artist_create_buffer(s, "ap", &offset, ARTIST_BUFFER_AP,
1340 s->width, s->height);
1341 artist_create_buffer(s, "cursor1", &offset, ARTIST_BUFFER_CURSOR1, 64, 64);
1342 artist_create_buffer(s, "cursor2", &offset, ARTIST_BUFFER_CURSOR2, 64, 64);
1343 artist_create_buffer(s, "attribute", &offset, ARTIST_BUFFER_ATTRIBUTE,
1344 64, 64);
1345
1346 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1347 framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0,
1348 buf->width, buf->height);
1349 /*
1350 * no idea whether the cursor is fixed size or not, so assume 32x32 which
1351 * seems sufficient for HP-UX X11.
1352 */
1353 s->cursor_height = 32;
1354 s->cursor_width = 32;
1355
1356 s->con = graphic_console_init(DEVICE(dev), 0, &artist_ops, s);
1357 qemu_console_resize(s->con, s->width, s->height);
1358}
1359
1360static int vmstate_artist_post_load(void *opaque, int version_id)
1361{
1362 artist_invalidate(opaque);
1363 return 0;
1364}
1365
1366static const VMStateDescription vmstate_artist = {
1367 .name = "artist",
1368 .version_id = 1,
1369 .minimum_version_id = 1,
1370 .post_load = vmstate_artist_post_load,
1371 .fields = (VMStateField[]) {
1372 VMSTATE_UINT16(height, ARTISTState),
1373 VMSTATE_UINT16(width, ARTISTState),
1374 VMSTATE_UINT16(depth, ARTISTState),
1375 VMSTATE_UINT32(fg_color, ARTISTState),
1376 VMSTATE_UINT32(bg_color, ARTISTState),
1377 VMSTATE_UINT32(vram_char_y, ARTISTState),
1378 VMSTATE_UINT32(vram_bitmask, ARTISTState),
1379 VMSTATE_UINT32(vram_start, ARTISTState),
1380 VMSTATE_UINT32(vram_pos, ARTISTState),
1381 VMSTATE_UINT32(vram_size, ARTISTState),
1382 VMSTATE_UINT32(blockmove_source, ARTISTState),
1383 VMSTATE_UINT32(blockmove_dest, ARTISTState),
1384 VMSTATE_UINT32(blockmove_size, ARTISTState),
1385 VMSTATE_UINT32(line_size, ARTISTState),
1386 VMSTATE_UINT32(line_end, ARTISTState),
1387 VMSTATE_UINT32(line_xy, ARTISTState),
1388 VMSTATE_UINT32(cursor_pos, ARTISTState),
1389 VMSTATE_UINT32(cursor_height, ARTISTState),
1390 VMSTATE_UINT32(cursor_width, ARTISTState),
1391 VMSTATE_UINT32(plane_mask, ARTISTState),
1392 VMSTATE_UINT32(reg_100080, ARTISTState),
1393 VMSTATE_UINT32(reg_300200, ARTISTState),
1394 VMSTATE_UINT32(reg_300208, ARTISTState),
1395 VMSTATE_UINT32(reg_300218, ARTISTState),
1396 VMSTATE_UINT32(cmap_bm_access, ARTISTState),
1397 VMSTATE_UINT32(dst_bm_access, ARTISTState),
1398 VMSTATE_UINT32(src_bm_access, ARTISTState),
1399 VMSTATE_UINT32(control_plane, ARTISTState),
1400 VMSTATE_UINT32(transfer_data, ARTISTState),
1401 VMSTATE_UINT32(image_bitmap_op, ARTISTState),
1402 VMSTATE_UINT32(font_write1, ARTISTState),
1403 VMSTATE_UINT32(font_write2, ARTISTState),
1404 VMSTATE_UINT32(font_write_pos_y, ARTISTState),
1405 VMSTATE_END_OF_LIST()
1406 }
1407};
1408
1409static Property artist_properties[] = {
1410 DEFINE_PROP_UINT16("width", ARTISTState, width, 1280),
1411 DEFINE_PROP_UINT16("height", ARTISTState, height, 1024),
1412 DEFINE_PROP_UINT16("depth", ARTISTState, depth, 8),
1413 DEFINE_PROP_END_OF_LIST(),
1414};
1415
1416static void artist_reset(DeviceState *qdev)
1417{
1418}
1419
1420static void artist_class_init(ObjectClass *klass, void *data)
1421{
1422 DeviceClass *dc = DEVICE_CLASS(klass);
1423
1424 dc->realize = artist_realizefn;
1425 dc->vmsd = &vmstate_artist;
1426 dc->reset = artist_reset;
1427 device_class_set_props(dc, artist_properties);
1428}
1429
1430static const TypeInfo artist_info = {
1431 .name = TYPE_ARTIST,
1432 .parent = TYPE_SYS_BUS_DEVICE,
1433 .instance_size = sizeof(ARTISTState),
1434 .instance_init = artist_initfn,
1435 .class_init = artist_class_init,
1436};
1437
1438static void artist_register_types(void)
1439{
1440 type_register_static(&artist_info);
1441}
1442
1443type_init(artist_register_types)