2 * QEMU HP Artist Emulation
4 * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11 #include "qemu/error-report.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"
23 #include "framebuffer.h"
24 #include "qom/object.h"
26 #define TYPE_ARTIST "artist"
27 OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState
, ARTIST
)
29 #ifdef HOST_WORDS_BIGENDIAN
30 #define ROP8OFF(_i) (3 - (_i))
44 SysBusDevice parent_obj
;
47 MemoryRegion vram_mem
;
48 MemoryRegion mem_as_root
;
50 MemoryRegionSection fbsection
;
55 struct vram_buffer vram_buffer
[16];
65 uint32_t vram_bitmask
;
72 uint32_t blockmove_source
;
73 uint32_t blockmove_dest
;
74 uint32_t blockmove_size
;
79 uint32_t line_pattern_start
;
80 uint32_t line_pattern_skip
;
83 uint32_t cursor_cntrl
;
85 uint32_t cursor_height
;
86 uint32_t cursor_width
;
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
;
101 uint32_t font_write1
;
102 uint32_t font_write2
;
103 uint32_t font_write_pos_y
;
105 int draw_line_pattern
;
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,
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,
134 PATTERN_LINE_START
= 0x100ecc,
135 LINE_SIZE
= 0x100e04,
137 DST_SRC_BM_ACCESS
= 0x118000,
138 DST_BM_ACCESS
= 0x118004,
139 SRC_BM_ACCESS
= 0x118008,
140 CONTROL_PLANE
= 0x11800c,
143 PLANE_MASK
= 0x118018,
144 IMAGE_BITMAP_OP
= 0x11801c,
145 CURSOR_POS
= 0x300100,
146 CURSOR_CTRL
= 0x300104,
150 ARTIST_ROP_CLEAR
= 0,
153 ARTIST_ROP_NOT_DST
= 10,
157 #define REG_NAME(_x) case _x: return " "#_x;
158 static const char *artist_reg_name(uint64_t addr
)
160 switch ((artist_reg_t
)addr
) {
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
);
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
);
185 REG_NAME(PATTERN_LINE_START
);
188 REG_NAME(FONT_WRITE_INCR_Y
);
189 REG_NAME(FONT_WRITE_START
);
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)
199 static int16_t artist_get_x(uint32_t reg
)
204 static int16_t artist_get_y(uint32_t reg
)
209 static void artist_invalidate_lines(struct vram_buffer
*buf
,
210 int starty
, int height
)
212 int start
= starty
* buf
->width
;
215 if (starty
+ height
> buf
->height
)
216 height
= buf
->height
- starty
;
218 size
= height
* buf
->width
;
220 if (start
+ size
<= buf
->size
) {
221 memory_region_set_dirty(&buf
->mr
, start
, size
);
225 static int vram_write_bufidx(ARTISTState
*s
)
227 return (s
->dst_bm_access
>> 12) & 0x0f;
230 static int vram_read_bufidx(ARTISTState
*s
)
232 return (s
->src_bm_access
>> 12) & 0x0f;
235 static struct vram_buffer
*vram_read_buffer(ARTISTState
*s
)
237 return &s
->vram_buffer
[vram_read_bufidx(s
)];
240 static struct vram_buffer
*vram_write_buffer(ARTISTState
*s
)
242 return &s
->vram_buffer
[vram_write_bufidx(s
)];
245 static uint8_t artist_get_color(ARTISTState
*s
)
247 if (s
->image_bitmap_op
& 2) {
254 static artist_rop_t
artist_get_op(ARTISTState
*s
)
256 return (s
->image_bitmap_op
>> 8) & 0xf;
259 static void artist_rop8(ARTISTState
*s
, struct vram_buffer
*buf
,
260 unsigned int offset
, uint8_t val
)
262 const artist_rop_t op
= artist_get_op(s
);
266 if (offset
>= buf
->size
) {
267 qemu_log_mask(LOG_GUEST_ERROR
,
268 "rop8 offset:%u bufsize:%u\n", offset
, buf
->size
);
271 dst
= buf
->data
+ offset
;
272 plane_mask
= s
->plane_mask
& 0xff;
275 case ARTIST_ROP_CLEAR
:
279 case ARTIST_ROP_COPY
:
280 *dst
= (*dst
& ~plane_mask
) | (val
& plane_mask
);
284 *dst
^= val
& plane_mask
;
287 case ARTIST_ROP_NOT_DST
:
296 qemu_log_mask(LOG_UNIMP
, "%s: unsupported rop %d\n", __func__
, op
);
301 static void artist_get_cursor_pos(ARTISTState
*s
, int *x
, int *y
)
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).
315 static int offset
= 338;
318 /* ignore if uninitialized */
319 if (s
->cursor_pos
== 0) {
324 lx
= artist_get_x(s
->cursor_pos
);
327 *x
= (lx
- offset
) / 2;
329 *y
= 1146 - artist_get_y(s
->cursor_pos
);
331 /* subtract cursor offset from cursor control register */
332 *x
-= (s
->cursor_cntrl
& 0xf0) >> 4;
333 *y
-= (s
->cursor_cntrl
& 0x0f);
339 if (*y
> s
->height
) {
344 static void artist_invalidate_cursor(ARTISTState
*s
)
347 artist_get_cursor_pos(s
, &x
, &y
);
348 artist_invalidate_lines(&s
->vram_buffer
[ARTIST_BUFFER_AP
],
349 y
, s
->cursor_height
);
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
)
357 struct vram_buffer
*buf
;
358 int line
, endline
, lineincr
, startcolumn
, endcolumn
, columnincr
, column
;
359 unsigned int dst
, src
;
361 trace_artist_block_move(source_x
, source_y
, dest_x
, dest_y
, width
, height
);
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__
,
370 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
371 if (height
> buf
->height
) {
372 height
= buf
->height
;
374 if (width
> buf
->width
) {
378 if (dest_y
> source_y
) {
390 if (dest_x
> source_x
) {
392 startcolumn
= width
- 1;
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
;
406 for (column
= startcolumn
; column
!= endcolumn
; column
+= columnincr
) {
407 if (dst
>= buf
->size
|| src
>= buf
->size
) {
410 artist_rop8(s
, buf
, dst
, buf
->data
[src
]);
416 artist_invalidate_lines(buf
, dest_y
, height
);
419 static void fill_window(ARTISTState
*s
,
420 unsigned int startx
, unsigned int starty
,
421 unsigned int width
, unsigned int height
)
424 uint8_t color
= artist_get_color(s
);
425 struct vram_buffer
*buf
;
428 trace_artist_fill_window(startx
, starty
, width
, height
,
429 s
->image_bitmap_op
, s
->control_plane
);
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__
,
438 if (s
->reg_100080
== 0x7d) {
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.
444 height
= artist_get_y(s
->blockmove_size
);
445 s
->vram_start
+= height
;
448 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
450 for (y
= starty
; y
< starty
+ height
; y
++) {
451 offset
= y
* s
->width
;
453 for (x
= startx
; x
< startx
+ width
; x
++) {
454 artist_rop8(s
, buf
, offset
+ x
, color
);
457 artist_invalidate_lines(buf
, starty
, height
);
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
)
465 struct vram_buffer
*buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
467 int dx
, dy
, t
, e
, x
, y
, incy
, diago
, horiz
;
470 trace_artist_draw_line(x1
, y1
, x2
, y2
);
472 if ((x1
>= buf
->width
&& x2
>= buf
->width
) ||
473 (y1
>= buf
->height
&& y2
>= buf
->height
)) {
479 s
->vram_start
= (x2
<< 16) | y2
;
521 diago
= (dy
- dx
) << 1;
531 color
= artist_get_color(s
);
537 ofs
= x
* s
->width
+ y
;
539 ofs
= y
* s
->width
+ x
;
545 artist_rop8(s
, buf
, ofs
, color
);
555 } while (x
<= x2
&& (max_pix
== -1 || --max_pix
> 0));
558 artist_invalidate_lines(buf
, x1
, x2
- x1
);
560 artist_invalidate_lines(buf
, y1
> y2
? y2
: y1
, x2
- x1
);
563 static void draw_line_pattern_start(ARTISTState
*s
)
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;
572 draw_line(s
, startx
, starty
, endx
, endy
, false, -1, pstart
);
573 s
->line_pattern_skip
= pstart
;
576 static void draw_line_pattern_next(ARTISTState
*s
)
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;
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;
591 static void draw_line_size(ARTISTState
*s
, bool update_start
)
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
);
599 draw_line(s
, startx
, starty
, endx
, endy
, update_start
, -1, -1);
602 static void draw_line_xy(ARTISTState
*s
, bool update_start
)
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;
616 endx
= startx
+ linexy
;
625 endy
= starty
+ linexy
;
649 draw_line(s
, startx
, starty
, endx
, endy
, false, -1, -1);
652 static void draw_line_end(ARTISTState
*s
, bool update_start
)
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
);
660 draw_line(s
, startx
, starty
, endx
, endy
, update_start
, -1, -1);
663 static void font_write16(ARTISTState
*s
, uint16_t val
)
665 struct vram_buffer
*buf
;
666 uint32_t color
= (s
->image_bitmap_op
& 2) ? s
->fg_color
: s
->bg_color
;
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
;
674 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
676 if (startx
>= buf
->width
|| starty
>= buf
->height
||
677 offset
+ 16 >= buf
->size
) {
681 for (i
= 0; i
< 16; i
++) {
682 mask
= 1 << (15 - i
);
684 artist_rop8(s
, buf
, offset
+ i
, color
);
686 if (!(s
->image_bitmap_op
& 0x20000000)) {
687 artist_rop8(s
, buf
, offset
+ i
, s
->bg_color
);
691 artist_invalidate_lines(buf
, starty
, 1);
694 static void font_write(ARTISTState
*s
, uint32_t val
)
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);
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);
709 static void combine_write_reg(hwaddr addr
, uint64_t val
, int size
, void *out
)
712 * FIXME: is there a qemu helper for this?
715 #ifndef HOST_WORDS_BIGENDIAN
721 *(uint8_t *)(out
+ (addr
& 3)) = val
;
725 *(uint16_t *)(out
+ (addr
& 2)) = val
;
729 *(uint32_t *)out
= val
;
733 qemu_log_mask(LOG_UNIMP
, "unsupported write size: %d\n", size
);
737 static void artist_vram_write4(ARTISTState
*s
, struct vram_buffer
*buf
,
738 uint32_t offset
, uint32_t data
)
741 int mask
= s
->vram_bitmask
>> 28;
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);
750 memory_region_set_dirty(&buf
->mr
, offset
, 3);
753 static void artist_vram_write32(ARTISTState
*s
, struct vram_buffer
*buf
,
754 uint32_t offset
, int size
, uint32_t data
,
757 uint32_t mask
, vram_bitmask
= s
->vram_bitmask
>> ((4 - size
) * 8);
758 int i
, pix_count
= size
* 8;
760 for (i
= 0; i
< pix_count
&& offset
+ i
< buf
->size
; i
++) {
761 mask
= 1 << (pix_count
- 1 - i
);
763 if (!(s
->image_bitmap_op
& 0x20000000) || (vram_bitmask
& mask
)) {
765 artist_rop8(s
, buf
, offset
+ i
, fg
);
767 if (!(s
->image_bitmap_op
& 0x10000002)) {
768 artist_rop8(s
, buf
, offset
+ i
, bg
);
773 memory_region_set_dirty(&buf
->mr
, offset
, pix_count
);
776 static int get_vram_offset(ARTISTState
*s
, struct vram_buffer
*buf
,
779 unsigned int posx
, width
;
782 posx
= ADDR_TO_X(pos
);
783 posy
+= ADDR_TO_Y(pos
);
784 return posy
* width
+ posx
;
787 static int vram_bit_write(ARTISTState
*s
, uint32_t pos
, int posy
,
788 uint32_t data
, int size
)
790 struct vram_buffer
*buf
= vram_write_buffer(s
);
792 switch (s
->dst_bm_access
>> 16) {
795 artist_vram_write4(s
, buf
, pos
, bswap32(data
));
799 case 0x1360: /* linux */
800 artist_vram_write4(s
, buf
, get_vram_offset(s
, buf
, pos
, posy
), data
);
805 artist_vram_write4(s
, buf
, get_vram_offset(s
, buf
, pos
>> 2, posy
),
811 artist_vram_write32(s
, buf
, get_vram_offset(s
, buf
, pos
>> 2, posy
),
812 size
, data
, s
->fg_color
, s
->bg_color
);
817 artist_vram_write32(s
, buf
, get_vram_offset(s
, buf
, pos
>> 2, posy
),
823 qemu_log_mask(LOG_UNIMP
, "%s: unknown dst bm access %08x\n",
824 __func__
, s
->dst_bm_access
);
828 if (vram_write_bufidx(s
) == ARTIST_BUFFER_CURSOR1
||
829 vram_write_bufidx(s
) == ARTIST_BUFFER_CURSOR2
) {
830 artist_invalidate_cursor(s
);
835 static void artist_vram_write(void *opaque
, hwaddr addr
, uint64_t val
,
838 ARTISTState
*s
= opaque
;
840 trace_artist_vram_write(size
, addr
, val
);
841 vram_bit_write(opaque
, addr
, 0, val
, size
);
844 static uint64_t artist_vram_read(void *opaque
, hwaddr addr
, unsigned size
)
846 ARTISTState
*s
= opaque
;
847 struct vram_buffer
*buf
;
851 buf
= vram_read_buffer(s
);
856 offset
= get_vram_offset(s
, buf
, addr
>> 2, 0);
858 if (offset
> buf
->size
) {
862 switch (s
->src_bm_access
>> 16) {
864 val
= *(uint32_t *)(buf
->data
+ offset
);
869 val
= bswap32(*(uint32_t *)(buf
->data
+ offset
));
873 qemu_log_mask(LOG_UNIMP
, "%s: unknown src bm access %08x\n",
874 __func__
, s
->dst_bm_access
);
878 trace_artist_vram_read(size
, addr
, val
);
882 static void artist_reg_write(void *opaque
, hwaddr addr
, uint64_t val
,
885 ARTISTState
*s
= opaque
;
888 trace_artist_reg_write(size
, addr
, artist_reg_name(addr
& ~3ULL), val
);
890 switch (addr
& ~3ULL) {
892 combine_write_reg(addr
, val
, size
, &s
->reg_100080
);
896 combine_write_reg(addr
, val
, size
, &s
->fg_color
);
900 combine_write_reg(addr
, val
, size
, &s
->bg_color
);
904 combine_write_reg(addr
, val
, size
, &s
->vram_bitmask
);
907 case VRAM_WRITE_INCR_Y
:
908 vram_bit_write(s
, s
->vram_pos
, s
->vram_char_y
++, val
, size
);
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
);
917 combine_write_reg(addr
, val
, size
, &s
->vram_pos
);
919 s
->draw_line_pattern
= 0;
923 combine_write_reg(addr
, val
, size
, &s
->vram_start
);
924 s
->draw_line_pattern
= 0;
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
));
935 case VRAM_SIZE_TRIGGER
:
936 combine_write_reg(addr
, val
, size
, &s
->vram_size
);
938 if (size
== 2 && !(addr
& 2)) {
939 height
= artist_get_y(s
->blockmove_size
);
941 height
= artist_get_y(s
->vram_size
);
944 if (size
== 2 && (addr
& 2)) {
945 width
= artist_get_x(s
->blockmove_size
);
947 width
= artist_get_x(s
->vram_size
);
950 fill_window(s
, artist_get_x(s
->vram_start
),
951 artist_get_y(s
->vram_start
),
956 combine_write_reg(addr
, val
, size
, &s
->line_xy
);
957 if (s
->draw_line_pattern
) {
958 draw_line_pattern_next(s
);
960 draw_line_xy(s
, true);
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
);
971 combine_write_reg(addr
, val
, size
, &s
->line_size
);
972 draw_line_size(s
, true);
976 combine_write_reg(addr
, val
, size
, &s
->line_end
);
977 draw_line_end(s
, true);
980 case BLOCK_MOVE_SIZE
:
981 combine_write_reg(addr
, val
, size
, &s
->blockmove_size
);
984 case BLOCK_MOVE_SOURCE
:
985 combine_write_reg(addr
, val
, size
, &s
->blockmove_source
);
988 case BLOCK_MOVE_DEST_TRIGGER
:
989 combine_write_reg(addr
, val
, size
, &s
->blockmove_dest
);
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
));
999 case BLOCK_MOVE_SIZE_TRIGGER
:
1000 combine_write_reg(addr
, val
, size
, &s
->blockmove_size
);
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
));
1012 combine_write_reg(addr
, val
, size
, &s
->plane_mask
);
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
);
1021 combine_write_reg(addr
, val
, size
, &s
->dst_bm_access
);
1025 combine_write_reg(addr
, val
, size
, &s
->src_bm_access
);
1029 combine_write_reg(addr
, val
, size
, &s
->control_plane
);
1033 combine_write_reg(addr
, val
, size
, &s
->transfer_data
);
1037 combine_write_reg(addr
, val
, size
, &s
->reg_300200
);
1041 combine_write_reg(addr
, val
, size
, &s
->reg_300208
);
1045 combine_write_reg(addr
, val
, size
, &s
->reg_300218
);
1049 artist_invalidate_cursor(s
);
1050 combine_write_reg(addr
, val
, size
, &s
->cursor_pos
);
1051 artist_invalidate_cursor(s
);
1055 combine_write_reg(addr
, val
, size
, &s
->cursor_cntrl
);
1058 case IMAGE_BITMAP_OP
:
1059 combine_write_reg(addr
, val
, size
, &s
->image_bitmap_op
);
1062 case FONT_WRITE_INCR_Y
:
1063 combine_write_reg(addr
, val
, size
, &s
->font_write1
);
1064 font_write(s
, s
->font_write1
);
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
);
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
);
1084 static uint64_t combine_read_reg(hwaddr addr
, int size
, void *in
)
1087 * FIXME: is there a qemu helper for this?
1090 #ifndef HOST_WORDS_BIGENDIAN
1096 return *(uint8_t *)(in
+ (addr
& 3));
1099 return *(uint16_t *)(in
+ (addr
& 2));
1102 return *(uint32_t *)in
;
1105 qemu_log_mask(LOG_UNIMP
, "unsupported read size: %d\n", size
);
1110 static uint64_t artist_reg_read(void *opaque
, hwaddr addr
, unsigned size
)
1112 ARTISTState
*s
= opaque
;
1115 switch (addr
& ~3ULL) {
1116 /* Unknown status registers */
1121 val
= (s
->width
<< 16) | s
->height
;
1122 if (s
->depth
== 1) {
1137 * FIFO ready flag. we're not emulating the FIFOs
1138 * so we're always ready
1144 val
= s
->reg_300200
;
1148 val
= s
->reg_300208
;
1152 val
= s
->reg_300218
;
1160 /* 0x02000000 Buserror */
1165 qemu_log_mask(LOG_UNIMP
, "%s: unknown register: %08" HWADDR_PRIx
1166 " size %d\n", __func__
, addr
, size
);
1169 val
= combine_read_reg(addr
, size
, &val
);
1170 trace_artist_reg_read(size
, addr
, artist_reg_name(addr
& ~3ULL), val
);
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,
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,
1190 static void artist_draw_cursor(ARTISTState
*s
)
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
;
1197 cursor0
= &s
->vram_buffer
[ARTIST_BUFFER_CURSOR1
];
1198 cursor1
= &s
->vram_buffer
[ARTIST_BUFFER_CURSOR2
];
1199 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
1201 artist_get_cursor_pos(s
, &cursor_pos_x
, &cursor_pos_y
);
1203 for (cy
= 0; cy
< s
->cursor_height
; cy
++) {
1205 for (cx
= 0; cx
< s
->cursor_width
; cx
++) {
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
) {
1214 int dstoffset
= (cursor_pos_y
+ cy
) * s
->width
+
1215 (cursor_pos_x
+ cx
);
1217 if (cursor0
->data
[cy
* cursor0
->width
+ cx
]) {
1218 data
[dstoffset
] = 0;
1220 if (cursor1
->data
[cy
* cursor1
->width
+ cx
]) {
1221 data
[dstoffset
] = 0xffffff;
1228 static void artist_draw_line(void *opaque
, uint8_t *d
, const uint8_t *src
,
1229 int width
, int pitch
)
1231 ARTISTState
*s
= ARTIST(opaque
);
1232 uint32_t *cmap
, *data
= (uint32_t *)d
;
1235 cmap
= (uint32_t *)(s
->vram_buffer
[ARTIST_BUFFER_CMAP
].data
+ 0x400);
1237 for (x
= 0; x
< s
->width
; x
++) {
1238 *data
++ = cmap
[*src
++];
1242 static void artist_update_display(void *opaque
)
1244 ARTISTState
*s
= opaque
;
1245 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1246 int first
= 0, last
;
1249 framebuffer_update_display(surface
, &s
->fbsection
, s
->width
, s
->height
,
1250 s
->width
, s
->width
* 4, 0, 0, artist_draw_line
,
1253 artist_draw_cursor(s
);
1255 dpy_gfx_update(s
->con
, 0, 0, s
->width
, s
->height
);
1258 static void artist_invalidate(void *opaque
)
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
);
1265 static const GraphicHwOps artist_ops
= {
1266 .invalidate
= artist_invalidate
,
1267 .gfx_update
= artist_update_display
,
1270 static void artist_initfn(Object
*obj
)
1272 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
1273 ARTISTState
*s
= ARTIST(obj
);
1275 memory_region_init_io(&s
->reg
, obj
, &artist_reg_ops
, s
, "artist.reg",
1277 memory_region_init_io(&s
->vram_mem
, obj
, &artist_vram_ops
, s
, "artist.vram",
1279 sysbus_init_mmio(sbd
, &s
->reg
);
1280 sysbus_init_mmio(sbd
, &s
->vram_mem
);
1283 static void artist_create_buffer(ARTISTState
*s
, const char *name
,
1284 hwaddr
*offset
, unsigned int idx
,
1285 int width
, int height
)
1287 struct vram_buffer
*buf
= s
->vram_buffer
+ idx
;
1289 memory_region_init_ram(&buf
->mr
, NULL
, name
, width
* height
,
1291 memory_region_add_subregion_overlap(&s
->mem_as_root
, *offset
, &buf
->mr
, 0);
1293 buf
->data
= memory_region_get_ram_ptr(&buf
->mr
);
1294 buf
->size
= height
* width
;
1296 buf
->height
= height
;
1298 *offset
+= buf
->size
;
1301 static void artist_realizefn(DeviceState
*dev
, Error
**errp
)
1303 ARTISTState
*s
= ARTIST(dev
);
1304 struct vram_buffer
*buf
;
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);
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);
1319 memory_region_init(&s
->mem_as_root
, OBJECT(dev
), "artist", ~0ull);
1320 address_space_init(&s
->as
, &s
->mem_as_root
, "artist");
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
,
1330 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
1331 framebuffer_update_memory_section(&s
->fbsection
, &buf
->mr
, 0,
1332 buf
->width
, buf
->height
);
1334 * no idea whether the cursor is fixed size or not, so assume 32x32 which
1335 * seems sufficient for HP-UX X11.
1337 s
->cursor_height
= 32;
1338 s
->cursor_width
= 32;
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.
1345 s
->image_bitmap_op
= 0x23000300;
1346 s
->plane_mask
= 0xff;
1348 s
->con
= graphic_console_init(dev
, 0, &artist_ops
, s
);
1349 qemu_console_resize(s
->con
, s
->width
, s
->height
);
1352 static int vmstate_artist_post_load(void *opaque
, int version_id
)
1354 artist_invalidate(opaque
);
1358 static const VMStateDescription vmstate_artist
= {
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()
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(),
1408 static void artist_reset(DeviceState
*qdev
)
1412 static void artist_class_init(ObjectClass
*klass
, void *data
)
1414 DeviceClass
*dc
= DEVICE_CLASS(klass
);
1416 dc
->realize
= artist_realizefn
;
1417 dc
->vmsd
= &vmstate_artist
;
1418 dc
->reset
= artist_reset
;
1419 device_class_set_props(dc
, artist_properties
);
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
,
1430 static void artist_register_types(void)
1432 type_register_static(&artist_info
);
1435 type_init(artist_register_types
)