2 * QEMU HP Artist Emulation
4 * Copyright (c) 2019-2022 Sven Schnelle <svens@stackframe.org>
5 * Copyright (c) 2022 Helge Deller <deller@gmx.de>
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 #include "qemu/osdep.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
)
38 SysBusDevice parent_obj
;
41 MemoryRegion vram_mem
;
42 MemoryRegion mem_as_root
;
44 MemoryRegionSection fbsection
;
49 struct vram_buffer vram_buffer
[16];
59 uint32_t vram_bitmask
;
66 uint32_t blockmove_source
;
67 uint32_t blockmove_dest
;
68 uint32_t blockmove_size
;
73 uint32_t line_pattern_start
;
74 uint32_t line_pattern_skip
;
77 uint32_t cursor_cntrl
;
79 uint32_t cursor_height
;
80 uint32_t cursor_width
;
85 uint32_t horiz_backporch
;
86 uint32_t active_lines_low
;
90 uint32_t dst_bm_access
;
91 uint32_t src_bm_access
;
92 uint32_t control_plane
;
93 uint32_t transfer_data
;
94 uint32_t image_bitmap_op
;
98 uint32_t font_write_pos_y
;
100 int draw_line_pattern
;
103 /* hardware allows up to 64x64, but we emulate 32x32 only. */
104 #define NGLE_MAX_SPRITE_SIZE 32
107 ARTIST_BUFFER_AP
= 1,
108 ARTIST_BUFFER_OVERLAY
= 2,
109 ARTIST_BUFFER_CURSOR1
= 6,
110 ARTIST_BUFFER_CURSOR2
= 7,
111 ARTIST_BUFFER_ATTRIBUTE
= 13,
112 ARTIST_BUFFER_CMAP
= 15,
117 VRAM_BITMASK
= 0x1005a0,
118 VRAM_WRITE_INCR_X
= 0x100600,
119 VRAM_WRITE_INCR_X2
= 0x100604,
120 VRAM_WRITE_INCR_Y
= 0x100620,
121 VRAM_START
= 0x100800,
122 BLOCK_MOVE_SIZE
= 0x100804,
123 BLOCK_MOVE_SOURCE
= 0x100808,
124 TRANSFER_DATA
= 0x100820,
125 FONT_WRITE_INCR_Y
= 0x1008a0,
126 VRAM_START_TRIGGER
= 0x100a00,
127 VRAM_SIZE_TRIGGER
= 0x100a04,
128 FONT_WRITE_START
= 0x100aa0,
129 BLOCK_MOVE_DEST_TRIGGER
= 0x100b00,
130 BLOCK_MOVE_SIZE_TRIGGER
= 0x100b04,
132 PATTERN_LINE_START
= 0x100ecc,
133 LINE_SIZE
= 0x100e04,
135 DST_SRC_BM_ACCESS
= 0x118000,
136 DST_BM_ACCESS
= 0x118004,
137 SRC_BM_ACCESS
= 0x118008,
138 CONTROL_PLANE
= 0x11800c,
141 PLANE_MASK
= 0x118018,
142 IMAGE_BITMAP_OP
= 0x11801c,
143 CURSOR_POS
= 0x300100, /* reg17 */
144 CURSOR_CTRL
= 0x300104, /* reg18 */
145 MISC_VIDEO
= 0x300218, /* reg21 */
146 MISC_CTRL
= 0x300308, /* reg27 */
147 HORIZ_BACKPORCH
= 0x300200, /* reg19 */
148 ACTIVE_LINES_LOW
= 0x300208,/* reg20 */
149 FIFO1
= 0x300008, /* reg34 */
154 ARTIST_ROP_CLEAR
= 0,
157 ARTIST_ROP_NOT_DST
= 10,
161 #define REG_NAME(_x) case _x: return " "#_x;
162 static const char *artist_reg_name(uint64_t addr
)
164 switch ((artist_reg_t
)addr
) {
166 REG_NAME(VRAM_BITMASK
);
167 REG_NAME(VRAM_WRITE_INCR_X
);
168 REG_NAME(VRAM_WRITE_INCR_X2
);
169 REG_NAME(VRAM_WRITE_INCR_Y
);
170 REG_NAME(VRAM_START
);
171 REG_NAME(BLOCK_MOVE_SIZE
);
172 REG_NAME(BLOCK_MOVE_SOURCE
);
175 REG_NAME(PLANE_MASK
);
176 REG_NAME(VRAM_START_TRIGGER
);
177 REG_NAME(VRAM_SIZE_TRIGGER
);
178 REG_NAME(BLOCK_MOVE_DEST_TRIGGER
);
179 REG_NAME(BLOCK_MOVE_SIZE_TRIGGER
);
180 REG_NAME(TRANSFER_DATA
);
181 REG_NAME(CONTROL_PLANE
);
182 REG_NAME(IMAGE_BITMAP_OP
);
183 REG_NAME(DST_SRC_BM_ACCESS
);
184 REG_NAME(DST_BM_ACCESS
);
185 REG_NAME(SRC_BM_ACCESS
);
186 REG_NAME(CURSOR_POS
);
187 REG_NAME(CURSOR_CTRL
);
188 REG_NAME(HORIZ_BACKPORCH
);
189 REG_NAME(ACTIVE_LINES_LOW
);
190 REG_NAME(MISC_VIDEO
);
193 REG_NAME(PATTERN_LINE_START
);
196 REG_NAME(FONT_WRITE_INCR_Y
);
197 REG_NAME(FONT_WRITE_START
);
205 static void artist_invalidate(void *opaque
);
207 /* artist has a fixed line length of 2048 bytes. */
208 #define ADDR_TO_Y(addr) extract32(addr, 11, 11)
209 #define ADDR_TO_X(addr) extract32(addr, 0, 11)
211 static int16_t artist_get_x(uint32_t reg
)
216 static int16_t artist_get_y(uint32_t reg
)
221 static void artist_invalidate_lines(struct vram_buffer
*buf
,
222 int starty
, int height
)
224 int start
= starty
* buf
->width
;
227 if (starty
+ height
> buf
->height
) {
228 height
= buf
->height
- starty
;
231 size
= height
* buf
->width
;
233 if (start
+ size
<= buf
->size
) {
234 memory_region_set_dirty(&buf
->mr
, start
, size
);
238 static int vram_write_bufidx(ARTISTState
*s
)
240 return (s
->dst_bm_access
>> 12) & 0x0f;
243 static int vram_read_bufidx(ARTISTState
*s
)
245 return (s
->src_bm_access
>> 12) & 0x0f;
248 static struct vram_buffer
*vram_read_buffer(ARTISTState
*s
)
250 return &s
->vram_buffer
[vram_read_bufidx(s
)];
253 static struct vram_buffer
*vram_write_buffer(ARTISTState
*s
)
255 return &s
->vram_buffer
[vram_write_bufidx(s
)];
258 static uint8_t artist_get_color(ARTISTState
*s
)
260 if (s
->image_bitmap_op
& 2) {
267 static artist_rop_t
artist_get_op(ARTISTState
*s
)
269 return (s
->image_bitmap_op
>> 8) & 0xf;
272 static void artist_rop8(ARTISTState
*s
, struct vram_buffer
*buf
,
273 unsigned int offset
, uint8_t val
)
275 const artist_rop_t op
= artist_get_op(s
);
279 if (offset
>= buf
->size
) {
280 qemu_log_mask(LOG_GUEST_ERROR
,
281 "rop8 offset:%u bufsize:%u\n", offset
, buf
->size
);
284 dst
= buf
->data
+ offset
;
285 plane_mask
= s
->plane_mask
& 0xff;
288 case ARTIST_ROP_CLEAR
:
292 case ARTIST_ROP_COPY
:
293 *dst
= (*dst
& ~plane_mask
) | (val
& plane_mask
);
297 *dst
^= val
& plane_mask
;
300 case ARTIST_ROP_NOT_DST
:
309 qemu_log_mask(LOG_UNIMP
, "%s: unsupported rop %d\n", __func__
, op
);
314 static void artist_get_cursor_pos(ARTISTState
*s
, int *x
, int *y
)
317 * The emulated Artist graphic is like a CRX graphic, and as such
318 * it's usually fixed at 1280x1024 pixels.
319 * Other resolutions may work, but no guarantee.
322 unsigned int hbp_times_vi
, horizBackPorch
;
324 const int videoInterleave
= 4;
325 const int pipelineDelay
= 4;
327 /* ignore if uninitialized */
328 if (s
->cursor_pos
== 0) {
334 * Calculate X position based on backporch and interleave values.
335 * Based on code from Xorg X11R6.6
337 horizBackPorch
= ((s
->horiz_backporch
& 0xff0000) >> 16) +
338 ((s
->horiz_backporch
& 0xff00) >> 8) + 2;
339 hbp_times_vi
= horizBackPorch
* videoInterleave
;
340 xHi
= s
->cursor_pos
>> 19;
341 *x
= ((xHi
+ pipelineDelay
) * videoInterleave
) - hbp_times_vi
;
343 xLo
= (s
->cursor_pos
>> 16) & 0x07;
344 *x
+= ((xLo
- hbp_times_vi
) & (videoInterleave
- 1)) + 8 - 1;
346 /* subtract cursor offset from cursor control register */
347 *x
-= (s
->cursor_cntrl
& 0xf0) >> 4;
349 /* Calculate Y position */
350 *y
= s
->height
- artist_get_y(s
->cursor_pos
);
351 *y
-= (s
->cursor_cntrl
& 0x0f);
357 if (*y
> s
->height
) {
362 static inline bool cursor_visible(ARTISTState
*s
)
364 /* cursor is visible if bit 0x80 is set in cursor_cntrl */
365 return s
->cursor_cntrl
& 0x80;
368 static void artist_invalidate_cursor(ARTISTState
*s
)
372 if (!cursor_visible(s
)) {
376 artist_get_cursor_pos(s
, &x
, &y
);
377 artist_invalidate_lines(&s
->vram_buffer
[ARTIST_BUFFER_AP
],
378 y
, s
->cursor_height
);
381 static void block_move(ARTISTState
*s
,
382 unsigned int source_x
, unsigned int source_y
,
383 unsigned int dest_x
, unsigned int dest_y
,
384 unsigned int width
, unsigned int height
)
386 struct vram_buffer
*buf
;
387 int line
, endline
, lineincr
, startcolumn
, endcolumn
, columnincr
, column
;
388 unsigned int dst
, src
;
390 trace_artist_block_move(source_x
, source_y
, dest_x
, dest_y
, width
, height
);
392 if (s
->control_plane
!= 0) {
393 /* We don't support CONTROL_PLANE accesses */
394 qemu_log_mask(LOG_UNIMP
, "%s: CONTROL_PLANE: %08x\n", __func__
,
399 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
400 if (height
> buf
->height
) {
401 height
= buf
->height
;
403 if (width
> buf
->width
) {
407 if (dest_y
> source_y
) {
419 if (dest_x
> source_x
) {
421 startcolumn
= width
- 1;
431 for ( ; line
!= endline
; line
+= lineincr
) {
432 src
= source_x
+ ((line
+ source_y
) * buf
->width
) + startcolumn
;
433 dst
= dest_x
+ ((line
+ dest_y
) * buf
->width
) + startcolumn
;
435 for (column
= startcolumn
; column
!= endcolumn
; column
+= columnincr
) {
436 if (dst
>= buf
->size
|| src
>= buf
->size
) {
439 artist_rop8(s
, buf
, dst
, buf
->data
[src
]);
445 artist_invalidate_lines(buf
, dest_y
, height
);
448 static void fill_window(ARTISTState
*s
,
449 unsigned int startx
, unsigned int starty
,
450 unsigned int width
, unsigned int height
)
453 uint8_t color
= artist_get_color(s
);
454 struct vram_buffer
*buf
;
457 trace_artist_fill_window(startx
, starty
, width
, height
,
458 s
->image_bitmap_op
, s
->control_plane
);
460 if (s
->control_plane
!= 0) {
461 /* We don't support CONTROL_PLANE accesses */
462 qemu_log_mask(LOG_UNIMP
, "%s: CONTROL_PLANE: %08x\n", __func__
,
467 if (s
->reg_100080
== 0x7d) {
469 * Not sure what this register really does, but
470 * 0x7d seems to enable autoincremt of the Y axis
471 * by the current block move height.
473 height
= artist_get_y(s
->blockmove_size
);
474 s
->vram_start
+= height
;
477 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
479 for (y
= starty
; y
< starty
+ height
; y
++) {
480 offset
= y
* s
->width
;
482 for (x
= startx
; x
< startx
+ width
; x
++) {
483 artist_rop8(s
, buf
, offset
+ x
, color
);
486 artist_invalidate_lines(buf
, starty
, height
);
489 static void draw_line(ARTISTState
*s
,
490 unsigned int x1
, unsigned int y1
,
491 unsigned int x2
, unsigned int y2
,
492 bool update_start
, int skip_pix
, int max_pix
)
494 struct vram_buffer
*buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
496 int dx
, dy
, t
, e
, x
, y
, incy
, diago
, horiz
;
499 trace_artist_draw_line(x1
, y1
, x2
, y2
);
501 if ((x1
>= buf
->width
&& x2
>= buf
->width
) ||
502 (y1
>= buf
->height
&& y2
>= buf
->height
)) {
507 s
->vram_start
= (x2
<< 16) | y2
;
549 diago
= (dy
- dx
) << 1;
559 color
= artist_get_color(s
);
565 ofs
= x
* s
->width
+ y
;
567 ofs
= y
* s
->width
+ x
;
573 artist_rop8(s
, buf
, ofs
, color
);
583 } while (x
<= x2
&& (max_pix
== -1 || --max_pix
> 0));
586 artist_invalidate_lines(buf
, x1
, x2
- x1
);
588 artist_invalidate_lines(buf
, y1
> y2
? y2
: y1
, x2
- x1
);
592 static void draw_line_pattern_start(ARTISTState
*s
)
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
->blockmove_size
);
597 int endy
= artist_get_y(s
->blockmove_size
);
598 int pstart
= s
->line_pattern_start
>> 16;
600 draw_line(s
, startx
, starty
, endx
, endy
, false, -1, pstart
);
601 s
->line_pattern_skip
= pstart
;
604 static void draw_line_pattern_next(ARTISTState
*s
)
606 int startx
= artist_get_x(s
->vram_start
);
607 int starty
= artist_get_y(s
->vram_start
);
608 int endx
= artist_get_x(s
->blockmove_size
);
609 int endy
= artist_get_y(s
->blockmove_size
);
610 int line_xy
= s
->line_xy
>> 16;
612 draw_line(s
, startx
, starty
, endx
, endy
, false, s
->line_pattern_skip
,
613 s
->line_pattern_skip
+ line_xy
);
614 s
->line_pattern_skip
+= line_xy
;
615 s
->image_bitmap_op
^= 2;
618 static void draw_line_size(ARTISTState
*s
, bool update_start
)
620 int startx
= artist_get_x(s
->vram_start
);
621 int starty
= artist_get_y(s
->vram_start
);
622 int endx
= artist_get_x(s
->line_size
);
623 int endy
= artist_get_y(s
->line_size
);
625 draw_line(s
, startx
, starty
, endx
, endy
, update_start
, -1, -1);
628 static void draw_line_xy(ARTISTState
*s
, bool update_start
)
630 int startx
= artist_get_x(s
->vram_start
);
631 int starty
= artist_get_y(s
->vram_start
);
632 int sizex
= artist_get_x(s
->blockmove_size
);
633 int sizey
= artist_get_y(s
->blockmove_size
);
634 int linexy
= s
->line_xy
>> 16;
641 endx
= startx
+ linexy
;
650 endy
= starty
+ linexy
;
674 draw_line(s
, startx
, starty
, endx
, endy
, false, -1, -1);
677 static void draw_line_end(ARTISTState
*s
, bool update_start
)
679 int startx
= artist_get_x(s
->vram_start
);
680 int starty
= artist_get_y(s
->vram_start
);
681 int endx
= artist_get_x(s
->line_end
);
682 int endy
= artist_get_y(s
->line_end
);
684 draw_line(s
, startx
, starty
, endx
, endy
, update_start
, -1, -1);
687 static void font_write16(ARTISTState
*s
, uint16_t val
)
689 struct vram_buffer
*buf
;
690 uint32_t color
= (s
->image_bitmap_op
& 2) ? s
->fg_color
: s
->bg_color
;
694 unsigned int startx
= artist_get_x(s
->vram_start
);
695 unsigned int starty
= artist_get_y(s
->vram_start
) + s
->font_write_pos_y
;
696 unsigned int offset
= starty
* s
->width
+ startx
;
698 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
700 if (startx
>= buf
->width
|| starty
>= buf
->height
||
701 offset
+ 16 >= buf
->size
) {
705 for (i
= 0; i
< 16; i
++) {
706 mask
= 1 << (15 - i
);
708 artist_rop8(s
, buf
, offset
+ i
, color
);
710 if (!(s
->image_bitmap_op
& 0x20000000)) {
711 artist_rop8(s
, buf
, offset
+ i
, s
->bg_color
);
715 artist_invalidate_lines(buf
, starty
, 1);
718 static void font_write(ARTISTState
*s
, uint32_t val
)
720 font_write16(s
, val
>> 16);
721 if (++s
->font_write_pos_y
== artist_get_y(s
->blockmove_size
)) {
722 s
->vram_start
+= (s
->blockmove_size
& 0xffff0000);
726 font_write16(s
, val
& 0xffff);
727 if (++s
->font_write_pos_y
== artist_get_y(s
->blockmove_size
)) {
728 s
->vram_start
+= (s
->blockmove_size
& 0xffff0000);
733 static void combine_write_reg(hwaddr addr
, uint64_t val
, int size
, void *out
)
736 * FIXME: is there a qemu helper for this?
745 *(uint8_t *)(out
+ (addr
& 3)) = val
;
749 *(uint16_t *)(out
+ (addr
& 2)) = val
;
753 *(uint32_t *)out
= val
;
757 qemu_log_mask(LOG_UNIMP
, "unsupported write size: %d\n", size
);
761 static void artist_vram_write4(ARTISTState
*s
, struct vram_buffer
*buf
,
762 uint32_t offset
, uint32_t data
)
765 int mask
= s
->vram_bitmask
>> 28;
767 for (i
= 0; i
< 4; i
++) {
768 if (!(s
->image_bitmap_op
& 0x20000000) || (mask
& 8)) {
769 artist_rop8(s
, buf
, offset
+ i
, data
>> 24);
774 memory_region_set_dirty(&buf
->mr
, offset
, 3);
777 static void artist_vram_write32(ARTISTState
*s
, struct vram_buffer
*buf
,
778 uint32_t offset
, int size
, uint32_t data
,
781 uint32_t mask
, vram_bitmask
= s
->vram_bitmask
>> ((4 - size
) * 8);
782 int i
, pix_count
= size
* 8;
784 for (i
= 0; i
< pix_count
&& offset
+ i
< buf
->size
; i
++) {
785 mask
= 1 << (pix_count
- 1 - i
);
787 if (!(s
->image_bitmap_op
& 0x20000000) || (vram_bitmask
& mask
)) {
789 artist_rop8(s
, buf
, offset
+ i
, fg
);
791 if (!(s
->image_bitmap_op
& 0x10000002)) {
792 artist_rop8(s
, buf
, offset
+ i
, bg
);
797 memory_region_set_dirty(&buf
->mr
, offset
, pix_count
);
800 static int get_vram_offset(ARTISTState
*s
, struct vram_buffer
*buf
,
803 unsigned int posx
, width
;
806 posx
= ADDR_TO_X(pos
);
807 posy
+= ADDR_TO_Y(pos
);
808 return posy
* width
+ posx
;
811 static int vram_bit_write(ARTISTState
*s
, uint32_t pos
, int posy
,
812 uint32_t data
, int size
)
814 struct vram_buffer
*buf
= vram_write_buffer(s
);
816 switch (s
->dst_bm_access
>> 16) {
819 artist_vram_write4(s
, buf
, pos
, bswap32(data
));
823 case 0x1360: /* linux */
824 artist_vram_write4(s
, buf
, get_vram_offset(s
, buf
, pos
, posy
), data
);
829 artist_vram_write4(s
, buf
, get_vram_offset(s
, buf
, pos
>> 2, posy
),
835 artist_vram_write32(s
, buf
, get_vram_offset(s
, buf
, pos
>> 2, posy
),
836 size
, data
, s
->fg_color
, s
->bg_color
);
841 artist_vram_write32(s
, buf
, get_vram_offset(s
, buf
, pos
>> 2, posy
),
847 qemu_log_mask(LOG_UNIMP
, "%s: unknown dst bm access %08x\n",
848 __func__
, s
->dst_bm_access
);
852 if (vram_write_bufidx(s
) == ARTIST_BUFFER_CURSOR1
||
853 vram_write_bufidx(s
) == ARTIST_BUFFER_CURSOR2
) {
854 artist_invalidate_cursor(s
);
859 static void artist_vram_write(void *opaque
, hwaddr addr
, uint64_t val
,
862 ARTISTState
*s
= opaque
;
865 trace_artist_vram_write(size
, addr
, val
);
866 vram_bit_write(opaque
, addr
, 0, val
, size
);
869 static uint64_t artist_vram_read(void *opaque
, hwaddr addr
, unsigned size
)
871 ARTISTState
*s
= opaque
;
872 struct vram_buffer
*buf
;
876 buf
= vram_read_buffer(s
);
881 offset
= get_vram_offset(s
, buf
, addr
>> 2, 0);
883 if (offset
> buf
->size
) {
887 switch (s
->src_bm_access
>> 16) {
889 val
= *(uint32_t *)(buf
->data
+ offset
);
894 val
= bswap32(*(uint32_t *)(buf
->data
+ offset
));
898 qemu_log_mask(LOG_UNIMP
, "%s: unknown src bm access %08x\n",
899 __func__
, s
->dst_bm_access
);
903 trace_artist_vram_read(size
, addr
, val
);
907 static void artist_reg_write(void *opaque
, hwaddr addr
, uint64_t val
,
910 ARTISTState
*s
= opaque
;
914 trace_artist_reg_write(size
, addr
, artist_reg_name(addr
& ~3ULL), val
);
916 switch (addr
& ~3ULL) {
918 combine_write_reg(addr
, val
, size
, &s
->reg_100080
);
922 combine_write_reg(addr
, val
, size
, &s
->fg_color
);
926 combine_write_reg(addr
, val
, size
, &s
->bg_color
);
930 combine_write_reg(addr
, val
, size
, &s
->vram_bitmask
);
933 case VRAM_WRITE_INCR_Y
:
934 vram_bit_write(s
, s
->vram_pos
, s
->vram_char_y
++, val
, size
);
937 case VRAM_WRITE_INCR_X
:
938 case VRAM_WRITE_INCR_X2
:
939 s
->vram_pos
= vram_bit_write(s
, s
->vram_pos
, s
->vram_char_y
, val
, size
);
943 combine_write_reg(addr
, val
, size
, &s
->vram_pos
);
945 s
->draw_line_pattern
= 0;
949 combine_write_reg(addr
, val
, size
, &s
->vram_start
);
950 s
->draw_line_pattern
= 0;
953 case VRAM_START_TRIGGER
:
954 combine_write_reg(addr
, val
, size
, &s
->vram_start
);
955 fill_window(s
, artist_get_x(s
->vram_start
),
956 artist_get_y(s
->vram_start
),
957 artist_get_x(s
->blockmove_size
),
958 artist_get_y(s
->blockmove_size
));
961 case VRAM_SIZE_TRIGGER
:
962 combine_write_reg(addr
, val
, size
, &s
->vram_size
);
964 if (size
== 2 && !(addr
& 2)) {
965 height
= artist_get_y(s
->blockmove_size
);
967 height
= artist_get_y(s
->vram_size
);
970 if (size
== 2 && (addr
& 2)) {
971 width
= artist_get_x(s
->blockmove_size
);
973 width
= artist_get_x(s
->vram_size
);
976 fill_window(s
, artist_get_x(s
->vram_start
),
977 artist_get_y(s
->vram_start
),
982 combine_write_reg(addr
, val
, size
, &s
->line_xy
);
983 if (s
->draw_line_pattern
) {
984 draw_line_pattern_next(s
);
986 draw_line_xy(s
, true);
990 case PATTERN_LINE_START
:
991 combine_write_reg(addr
, val
, size
, &s
->line_pattern_start
);
992 s
->draw_line_pattern
= 1;
993 draw_line_pattern_start(s
);
997 combine_write_reg(addr
, val
, size
, &s
->line_size
);
998 draw_line_size(s
, true);
1002 combine_write_reg(addr
, val
, size
, &s
->line_end
);
1003 draw_line_end(s
, true);
1006 case BLOCK_MOVE_SIZE
:
1007 combine_write_reg(addr
, val
, size
, &s
->blockmove_size
);
1010 case BLOCK_MOVE_SOURCE
:
1011 combine_write_reg(addr
, val
, size
, &s
->blockmove_source
);
1014 case BLOCK_MOVE_DEST_TRIGGER
:
1015 combine_write_reg(addr
, val
, size
, &s
->blockmove_dest
);
1017 block_move(s
, artist_get_x(s
->blockmove_source
),
1018 artist_get_y(s
->blockmove_source
),
1019 artist_get_x(s
->blockmove_dest
),
1020 artist_get_y(s
->blockmove_dest
),
1021 artist_get_x(s
->blockmove_size
),
1022 artist_get_y(s
->blockmove_size
));
1025 case BLOCK_MOVE_SIZE_TRIGGER
:
1026 combine_write_reg(addr
, val
, size
, &s
->blockmove_size
);
1029 artist_get_x(s
->blockmove_source
),
1030 artist_get_y(s
->blockmove_source
),
1031 artist_get_x(s
->vram_start
),
1032 artist_get_y(s
->vram_start
),
1033 artist_get_x(s
->blockmove_size
),
1034 artist_get_y(s
->blockmove_size
));
1038 combine_write_reg(addr
, val
, size
, &s
->plane_mask
);
1041 case DST_SRC_BM_ACCESS
:
1042 combine_write_reg(addr
, val
, size
, &s
->dst_bm_access
);
1043 combine_write_reg(addr
, val
, size
, &s
->src_bm_access
);
1047 combine_write_reg(addr
, val
, size
, &s
->dst_bm_access
);
1051 combine_write_reg(addr
, val
, size
, &s
->src_bm_access
);
1055 combine_write_reg(addr
, val
, size
, &s
->control_plane
);
1059 combine_write_reg(addr
, val
, size
, &s
->transfer_data
);
1062 case HORIZ_BACKPORCH
:
1063 /* overwrite HP-UX settings to fix X cursor position. */
1064 val
= (NGLE_MAX_SPRITE_SIZE
<< 16) + (NGLE_MAX_SPRITE_SIZE
<< 8);
1065 combine_write_reg(addr
, val
, size
, &s
->horiz_backporch
);
1068 case ACTIVE_LINES_LOW
:
1069 combine_write_reg(addr
, val
, size
, &s
->active_lines_low
);
1073 oldval
= s
->misc_video
;
1074 combine_write_reg(addr
, val
, size
, &s
->misc_video
);
1075 /* Invalidate and hide screen if graphics signal is turned off. */
1076 if (((oldval
& 0x0A000000) == 0x0A000000) &&
1077 ((val
& 0x0A000000) != 0x0A000000)) {
1078 artist_invalidate(s
);
1080 /* Invalidate and redraw screen if graphics signal is turned back on. */
1081 if (((oldval
& 0x0A000000) != 0x0A000000) &&
1082 ((val
& 0x0A000000) == 0x0A000000)) {
1083 artist_invalidate(s
);
1088 combine_write_reg(addr
, val
, size
, &s
->misc_ctrl
);
1092 artist_invalidate_cursor(s
);
1093 combine_write_reg(addr
, val
, size
, &s
->cursor_pos
);
1094 artist_invalidate_cursor(s
);
1098 combine_write_reg(addr
, val
, size
, &s
->cursor_cntrl
);
1101 case IMAGE_BITMAP_OP
:
1102 combine_write_reg(addr
, val
, size
, &s
->image_bitmap_op
);
1105 case FONT_WRITE_INCR_Y
:
1106 combine_write_reg(addr
, val
, size
, &s
->font_write1
);
1107 font_write(s
, s
->font_write1
);
1110 case FONT_WRITE_START
:
1111 combine_write_reg(addr
, val
, size
, &s
->font_write2
);
1112 s
->font_write_pos_y
= 0;
1113 font_write(s
, s
->font_write2
);
1120 qemu_log_mask(LOG_UNIMP
, "%s: unknown register: reg=%08" HWADDR_PRIx
1121 " val=%08" PRIx64
" size=%d\n",
1122 __func__
, addr
, val
, size
);
1127 static uint64_t combine_read_reg(hwaddr addr
, int size
, void *in
)
1130 * FIXME: is there a qemu helper for this?
1133 #if !HOST_BIG_ENDIAN
1139 return *(uint8_t *)(in
+ (addr
& 3));
1142 return *(uint16_t *)(in
+ (addr
& 2));
1145 return *(uint32_t *)in
;
1148 qemu_log_mask(LOG_UNIMP
, "unsupported read size: %d\n", size
);
1153 static uint64_t artist_reg_read(void *opaque
, hwaddr addr
, unsigned size
)
1155 ARTISTState
*s
= opaque
;
1158 switch (addr
& ~3ULL) {
1159 /* Unknown status registers */
1164 val
= (s
->width
<< 16) | s
->height
;
1165 if (s
->depth
== 1) {
1179 * FIFO ready flag. we're not emulating the FIFOs
1180 * so we're always ready
1185 case HORIZ_BACKPORCH
:
1186 val
= s
->horiz_backporch
;
1189 case ACTIVE_LINES_LOW
:
1190 val
= s
->active_lines_low
;
1191 /* activeLinesLo for cursor is in reg20.b.b0 */
1192 val
&= ~(0xff << 24);
1193 val
|= (s
->height
& 0xff) << 24;
1197 /* emulate V-blank */
1198 s
->misc_video
^= 0x00040000;
1199 /* activeLinesHi for cursor is in reg21.b.b2 */
1200 val
= s
->misc_video
;
1202 val
|= (s
->height
& 0xff00);
1214 /* 0x02000000 Buserror */
1219 qemu_log_mask(LOG_UNIMP
, "%s: unknown register: %08" HWADDR_PRIx
1220 " size %d\n", __func__
, addr
, size
);
1223 val
= combine_read_reg(addr
, size
, &val
);
1224 trace_artist_reg_read(size
, addr
, artist_reg_name(addr
& ~3ULL), val
);
1228 static const MemoryRegionOps artist_reg_ops
= {
1229 .read
= artist_reg_read
,
1230 .write
= artist_reg_write
,
1231 .endianness
= DEVICE_NATIVE_ENDIAN
,
1232 .impl
.min_access_size
= 1,
1233 .impl
.max_access_size
= 4,
1236 static const MemoryRegionOps artist_vram_ops
= {
1237 .read
= artist_vram_read
,
1238 .write
= artist_vram_write
,
1239 .endianness
= DEVICE_NATIVE_ENDIAN
,
1240 .impl
.min_access_size
= 1,
1241 .impl
.max_access_size
= 4,
1244 static void artist_draw_cursor(ARTISTState
*s
)
1246 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1247 uint32_t *data
= (uint32_t *)surface_data(surface
);
1248 struct vram_buffer
*cursor0
, *cursor1
, *buf
;
1249 int cx
, cy
, cursor_pos_x
, cursor_pos_y
;
1251 if (!cursor_visible(s
)) {
1255 cursor0
= &s
->vram_buffer
[ARTIST_BUFFER_CURSOR1
];
1256 cursor1
= &s
->vram_buffer
[ARTIST_BUFFER_CURSOR2
];
1257 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
1259 artist_get_cursor_pos(s
, &cursor_pos_x
, &cursor_pos_y
);
1261 for (cy
= 0; cy
< s
->cursor_height
; cy
++) {
1263 for (cx
= 0; cx
< s
->cursor_width
; cx
++) {
1265 if (cursor_pos_y
+ cy
< 0 ||
1266 cursor_pos_x
+ cx
< 0 ||
1267 cursor_pos_y
+ cy
> buf
->height
- 1 ||
1268 cursor_pos_x
+ cx
> buf
->width
) {
1272 int dstoffset
= (cursor_pos_y
+ cy
) * s
->width
+
1273 (cursor_pos_x
+ cx
);
1275 if (cursor0
->data
[cy
* cursor0
->width
+ cx
]) {
1276 data
[dstoffset
] = 0;
1278 if (cursor1
->data
[cy
* cursor1
->width
+ cx
]) {
1279 data
[dstoffset
] = 0xffffff;
1286 static bool artist_screen_enabled(ARTISTState
*s
)
1288 /* We could check for (s->misc_ctrl & 0x00800000) too... */
1289 return ((s
->misc_video
& 0x0A000000) == 0x0A000000);
1292 static void artist_draw_line(void *opaque
, uint8_t *d
, const uint8_t *src
,
1293 int width
, int pitch
)
1295 ARTISTState
*s
= ARTIST(opaque
);
1296 uint32_t *cmap
, *data
= (uint32_t *)d
;
1299 if (!artist_screen_enabled(s
)) {
1301 memset(data
, 0, s
->width
* sizeof(uint32_t));
1305 cmap
= (uint32_t *)(s
->vram_buffer
[ARTIST_BUFFER_CMAP
].data
+ 0x400);
1307 for (x
= 0; x
< s
->width
; x
++) {
1308 *data
++ = cmap
[*src
++];
1312 static void artist_update_display(void *opaque
)
1314 ARTISTState
*s
= opaque
;
1315 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1316 int first
= 0, last
;
1318 framebuffer_update_display(surface
, &s
->fbsection
, s
->width
, s
->height
,
1319 s
->width
, s
->width
* 4, 0, 0, artist_draw_line
,
1322 artist_draw_cursor(s
);
1325 dpy_gfx_update(s
->con
, 0, first
, s
->width
, last
- first
+ 1);
1329 static void artist_invalidate(void *opaque
)
1331 ARTISTState
*s
= ARTIST(opaque
);
1332 struct vram_buffer
*buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
1334 memory_region_set_dirty(&buf
->mr
, 0, buf
->size
);
1337 static const GraphicHwOps artist_ops
= {
1338 .invalidate
= artist_invalidate
,
1339 .gfx_update
= artist_update_display
,
1342 static void artist_initfn(Object
*obj
)
1344 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
1345 ARTISTState
*s
= ARTIST(obj
);
1347 memory_region_init_io(&s
->reg
, obj
, &artist_reg_ops
, s
, "artist.reg",
1349 memory_region_init_io(&s
->vram_mem
, obj
, &artist_vram_ops
, s
, "artist.vram",
1351 sysbus_init_mmio(sbd
, &s
->reg
);
1352 sysbus_init_mmio(sbd
, &s
->vram_mem
);
1355 static void artist_create_buffer(ARTISTState
*s
, const char *name
,
1356 hwaddr
*offset
, unsigned int idx
,
1357 int width
, int height
)
1359 struct vram_buffer
*buf
= s
->vram_buffer
+ idx
;
1361 memory_region_init_ram(&buf
->mr
, NULL
, name
, width
* height
,
1363 memory_region_add_subregion_overlap(&s
->mem_as_root
, *offset
, &buf
->mr
, 0);
1365 buf
->data
= memory_region_get_ram_ptr(&buf
->mr
);
1366 buf
->size
= height
* width
;
1368 buf
->height
= height
;
1370 *offset
+= buf
->size
;
1373 static void artist_realizefn(DeviceState
*dev
, Error
**errp
)
1375 ARTISTState
*s
= ARTIST(dev
);
1376 struct vram_buffer
*buf
;
1379 if (s
->width
> 2048 || s
->height
> 2048) {
1380 error_report("artist: screen size can not exceed 2048 x 2048 pixel.");
1381 s
->width
= MIN(s
->width
, 2048);
1382 s
->height
= MIN(s
->height
, 2048);
1385 if (s
->width
< 640 || s
->height
< 480) {
1386 error_report("artist: minimum screen size is 640 x 480 pixel.");
1387 s
->width
= MAX(s
->width
, 640);
1388 s
->height
= MAX(s
->height
, 480);
1391 memory_region_init(&s
->mem_as_root
, OBJECT(dev
), "artist", ~0ull);
1392 address_space_init(&s
->as
, &s
->mem_as_root
, "artist");
1394 artist_create_buffer(s
, "cmap", &offset
, ARTIST_BUFFER_CMAP
, 2048, 4);
1395 artist_create_buffer(s
, "ap", &offset
, ARTIST_BUFFER_AP
,
1396 s
->width
, s
->height
);
1397 artist_create_buffer(s
, "cursor1", &offset
, ARTIST_BUFFER_CURSOR1
, 64, 64);
1398 artist_create_buffer(s
, "cursor2", &offset
, ARTIST_BUFFER_CURSOR2
, 64, 64);
1399 artist_create_buffer(s
, "attribute", &offset
, ARTIST_BUFFER_ATTRIBUTE
,
1402 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
1403 framebuffer_update_memory_section(&s
->fbsection
, &buf
->mr
, 0,
1404 buf
->width
, buf
->height
);
1406 * Artist cursor max size
1408 s
->cursor_height
= NGLE_MAX_SPRITE_SIZE
;
1409 s
->cursor_width
= NGLE_MAX_SPRITE_SIZE
;
1412 * These two registers are not initialized by seabios's STI implementation.
1413 * Initialize them here to sane values so artist also works with older
1414 * (not-fixed) seabios versions.
1416 s
->image_bitmap_op
= 0x23000300;
1417 s
->plane_mask
= 0xff;
1420 s
->misc_video
|= 0x0A000000;
1421 s
->misc_ctrl
|= 0x00800000;
1423 s
->con
= graphic_console_init(dev
, 0, &artist_ops
, s
);
1424 qemu_console_resize(s
->con
, s
->width
, s
->height
);
1427 static int vmstate_artist_post_load(void *opaque
, int version_id
)
1429 artist_invalidate(opaque
);
1433 static const VMStateDescription vmstate_artist
= {
1436 .minimum_version_id
= 2,
1437 .post_load
= vmstate_artist_post_load
,
1438 .fields
= (VMStateField
[]) {
1439 VMSTATE_UINT16(height
, ARTISTState
),
1440 VMSTATE_UINT16(width
, ARTISTState
),
1441 VMSTATE_UINT16(depth
, ARTISTState
),
1442 VMSTATE_UINT32(fg_color
, ARTISTState
),
1443 VMSTATE_UINT32(bg_color
, ARTISTState
),
1444 VMSTATE_UINT32(vram_char_y
, ARTISTState
),
1445 VMSTATE_UINT32(vram_bitmask
, ARTISTState
),
1446 VMSTATE_UINT32(vram_start
, ARTISTState
),
1447 VMSTATE_UINT32(vram_pos
, ARTISTState
),
1448 VMSTATE_UINT32(vram_size
, ARTISTState
),
1449 VMSTATE_UINT32(blockmove_source
, ARTISTState
),
1450 VMSTATE_UINT32(blockmove_dest
, ARTISTState
),
1451 VMSTATE_UINT32(blockmove_size
, ARTISTState
),
1452 VMSTATE_UINT32(line_size
, ARTISTState
),
1453 VMSTATE_UINT32(line_end
, ARTISTState
),
1454 VMSTATE_UINT32(line_xy
, ARTISTState
),
1455 VMSTATE_UINT32(cursor_pos
, ARTISTState
),
1456 VMSTATE_UINT32(cursor_cntrl
, ARTISTState
),
1457 VMSTATE_UINT32(cursor_height
, ARTISTState
),
1458 VMSTATE_UINT32(cursor_width
, ARTISTState
),
1459 VMSTATE_UINT32(plane_mask
, ARTISTState
),
1460 VMSTATE_UINT32(reg_100080
, ARTISTState
),
1461 VMSTATE_UINT32(horiz_backporch
, ARTISTState
),
1462 VMSTATE_UINT32(active_lines_low
, ARTISTState
),
1463 VMSTATE_UINT32(misc_video
, ARTISTState
),
1464 VMSTATE_UINT32(misc_ctrl
, ARTISTState
),
1465 VMSTATE_UINT32(dst_bm_access
, ARTISTState
),
1466 VMSTATE_UINT32(src_bm_access
, ARTISTState
),
1467 VMSTATE_UINT32(control_plane
, ARTISTState
),
1468 VMSTATE_UINT32(transfer_data
, ARTISTState
),
1469 VMSTATE_UINT32(image_bitmap_op
, ARTISTState
),
1470 VMSTATE_UINT32(font_write1
, ARTISTState
),
1471 VMSTATE_UINT32(font_write2
, ARTISTState
),
1472 VMSTATE_UINT32(font_write_pos_y
, ARTISTState
),
1473 VMSTATE_END_OF_LIST()
1477 static Property artist_properties
[] = {
1478 DEFINE_PROP_UINT16("width", ARTISTState
, width
, 1280),
1479 DEFINE_PROP_UINT16("height", ARTISTState
, height
, 1024),
1480 DEFINE_PROP_UINT16("depth", ARTISTState
, depth
, 8),
1481 DEFINE_PROP_END_OF_LIST(),
1484 static void artist_reset(DeviceState
*qdev
)
1488 static void artist_class_init(ObjectClass
*klass
, void *data
)
1490 DeviceClass
*dc
= DEVICE_CLASS(klass
);
1492 dc
->realize
= artist_realizefn
;
1493 dc
->vmsd
= &vmstate_artist
;
1494 dc
->reset
= artist_reset
;
1495 device_class_set_props(dc
, artist_properties
);
1498 static const TypeInfo artist_info
= {
1499 .name
= TYPE_ARTIST
,
1500 .parent
= TYPE_SYS_BUS_DEVICE
,
1501 .instance_size
= sizeof(ARTISTState
),
1502 .instance_init
= artist_initfn
,
1503 .class_init
= artist_class_init
,
1506 static void artist_register_types(void)
1508 type_register_static(&artist_info
);
1511 type_init(artist_register_types
)