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"
12 #include "qemu/typedefs.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"
24 #include "hw/display/framebuffer.h"
26 #define TYPE_ARTIST "artist"
27 #define ARTIST(obj) OBJECT_CHECK(ARTISTState, (obj), TYPE_ARTIST)
29 #ifdef HOST_WORDS_BIGENDIAN
30 #define ROP8OFF(_i) (3 - (_i))
43 typedef struct ARTISTState
{
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
;
84 uint32_t cursor_height
;
85 uint32_t cursor_width
;
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
;
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 CMAP_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(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
);
185 REG_NAME(PATTERN_LINE_START
);
188 REG_NAME(FONT_WRITE_INCR_Y
);
189 REG_NAME(FONT_WRITE_START
);
195 static int16_t artist_get_x(uint32_t reg
)
200 static int16_t artist_get_y(uint32_t reg
)
205 static void artist_invalidate_lines(struct vram_buffer
*buf
,
206 int starty
, int height
)
208 int start
= starty
* buf
->width
;
209 int size
= height
* buf
->width
;
211 if (start
+ size
<= buf
->size
) {
212 memory_region_set_dirty(&buf
->mr
, start
, size
);
216 static int vram_write_pix_per_transfer(ARTISTState
*s
)
218 if (s
->cmap_bm_access
) {
219 return 1 << ((s
->cmap_bm_access
>> 27) & 0x0f);
221 return 1 << ((s
->dst_bm_access
>> 27) & 0x0f);
225 static int vram_pixel_length(ARTISTState
*s
)
227 if (s
->cmap_bm_access
) {
228 return (s
->cmap_bm_access
>> 24) & 0x07;
230 return (s
->dst_bm_access
>> 24) & 0x07;
234 static int vram_write_bufidx(ARTISTState
*s
)
236 if (s
->cmap_bm_access
) {
237 return (s
->cmap_bm_access
>> 12) & 0x0f;
239 return (s
->dst_bm_access
>> 12) & 0x0f;
243 static int vram_read_bufidx(ARTISTState
*s
)
245 if (s
->cmap_bm_access
) {
246 return (s
->cmap_bm_access
>> 12) & 0x0f;
248 return (s
->src_bm_access
>> 12) & 0x0f;
252 static struct vram_buffer
*vram_read_buffer(ARTISTState
*s
)
254 return &s
->vram_buffer
[vram_read_bufidx(s
)];
257 static struct vram_buffer
*vram_write_buffer(ARTISTState
*s
)
259 return &s
->vram_buffer
[vram_write_bufidx(s
)];
262 static uint8_t artist_get_color(ARTISTState
*s
)
264 if (s
->image_bitmap_op
& 2) {
271 static artist_rop_t
artist_get_op(ARTISTState
*s
)
273 return (s
->image_bitmap_op
>> 8) & 0xf;
276 static void artist_rop8(ARTISTState
*s
, uint8_t *dst
, uint8_t val
)
279 const artist_rop_t op
= artist_get_op(s
);
280 uint8_t plane_mask
= s
->plane_mask
& 0xff;
283 case ARTIST_ROP_CLEAR
:
287 case ARTIST_ROP_COPY
:
289 *dst
|= val
& plane_mask
;
293 *dst
^= val
& plane_mask
;
296 case ARTIST_ROP_NOT_DST
:
305 qemu_log_mask(LOG_UNIMP
, "%s: unsupported rop %d\n", __func__
, op
);
310 static void artist_get_cursor_pos(ARTISTState
*s
, int *x
, int *y
)
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
318 *y
= 0x47a - artist_get_y(s
->cursor_pos
);
319 *x
= ((artist_get_x(s
->cursor_pos
) - 338) / 2);
325 if (*y
> s
->height
) {
330 static void artist_invalidate_cursor(ARTISTState
*s
)
333 artist_get_cursor_pos(s
, &x
, &y
);
334 artist_invalidate_lines(&s
->vram_buffer
[ARTIST_BUFFER_AP
],
335 y
, s
->cursor_height
);
338 static void vram_bit_write(ARTISTState
*s
, int posx
, int posy
, bool incr_x
,
339 int size
, uint32_t data
)
341 struct vram_buffer
*buf
;
342 uint32_t vram_bitmask
= s
->vram_bitmask
;
343 int mask
, i
, pix_count
, pix_length
, offset
, height
, width
;
346 pix_count
= vram_write_pix_per_transfer(s
);
347 pix_length
= vram_pixel_length(s
);
349 buf
= vram_write_buffer(s
);
350 height
= buf
->height
;
353 if (s
->cmap_bm_access
) {
354 offset
= s
->vram_pos
;
356 offset
= posy
* width
+ posx
;
360 qemu_log("write to non-existent buffer\n");
366 if (pix_count
> size
* 8) {
367 pix_count
= size
* 8;
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
);
377 switch (pix_length
) {
379 if (s
->image_bitmap_op
& 0x20000000) {
380 data
&= vram_bitmask
;
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);
388 memory_region_set_dirty(&buf
->mr
, offset
, pix_count
);
392 if (s
->cmap_bm_access
) {
393 *(uint32_t *)(p
+ offset
) = data
;
396 data8
= (uint8_t *)&data
;
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
)]);
404 memory_region_set_dirty(&buf
->mr
, offset
, 3);
411 vram_bitmask
= s
->vram_bitmask
;
415 vram_bitmask
= s
->vram_bitmask
>> 16;
419 vram_bitmask
= s
->vram_bitmask
>> 24;
423 for (i
= 0; i
< pix_count
; i
++) {
424 mask
= 1 << (pix_count
- 1 - i
);
426 if (!(s
->image_bitmap_op
& 0x20000000) ||
427 (vram_bitmask
& mask
)) {
429 artist_rop8(s
, p
+ offset
+ i
, s
->fg_color
);
431 if (!(s
->image_bitmap_op
& 0x10000002)) {
432 artist_rop8(s
, p
+ offset
+ i
, s
->bg_color
);
437 memory_region_set_dirty(&buf
->mr
, offset
, pix_count
);
441 qemu_log_mask(LOG_UNIMP
, "%s: unknown pixel length %d\n",
442 __func__
, pix_length
);
447 if (s
->cmap_bm_access
) {
450 s
->vram_pos
+= pix_count
<< 2;
454 if (vram_write_bufidx(s
) == ARTIST_BUFFER_CURSOR1
||
455 vram_write_bufidx(s
) == ARTIST_BUFFER_CURSOR2
) {
456 artist_invalidate_cursor(s
);
460 static void block_move(ARTISTState
*s
, int source_x
, int source_y
, int dest_x
,
461 int dest_y
, int width
, int height
)
463 struct vram_buffer
*buf
;
464 int line
, endline
, lineincr
, startcolumn
, endcolumn
, columnincr
, column
;
467 trace_artist_block_move(source_x
, source_y
, dest_x
, dest_y
, width
, height
);
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__
,
476 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
478 if (dest_y
> source_y
) {
490 if (dest_x
> source_x
) {
492 startcolumn
= width
- 1;
502 for ( ; line
!= endline
; line
+= lineincr
) {
503 src
= source_x
+ ((line
+ source_y
) * buf
->width
);
504 dst
= dest_x
+ ((line
+ dest_y
) * buf
->width
);
506 for (column
= startcolumn
; column
!= endcolumn
; column
+= columnincr
) {
507 if (dst
+ column
> buf
->size
|| src
+ column
> buf
->size
) {
510 artist_rop8(s
, buf
->data
+ dst
+ column
, buf
->data
[src
+ column
]);
514 artist_invalidate_lines(buf
, dest_y
, height
);
517 static void fill_window(ARTISTState
*s
, int startx
, int starty
,
518 int width
, int height
)
521 uint8_t color
= artist_get_color(s
);
522 struct vram_buffer
*buf
;
525 trace_artist_fill_window(startx
, starty
, width
, height
,
526 s
->image_bitmap_op
, s
->control_plane
);
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__
,
535 if (s
->reg_100080
== 0x7d) {
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.
541 height
= artist_get_y(s
->blockmove_size
);
542 s
->vram_start
+= height
;
545 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
547 for (y
= starty
; y
< starty
+ height
; y
++) {
548 offset
= y
* s
->width
;
550 for (x
= startx
; x
< startx
+ width
; x
++) {
551 artist_rop8(s
, buf
->data
+ offset
+ x
, color
);
554 artist_invalidate_lines(buf
, starty
, height
);
557 static void draw_line(ARTISTState
*s
, int x1
, int y1
, int x2
, int y2
,
558 bool update_start
, int skip_pix
, int max_pix
)
560 struct vram_buffer
*buf
;
561 uint8_t color
= artist_get_color(s
);
562 int dx
, dy
, t
, e
, x
, y
, incy
, diago
, horiz
;
568 s
->vram_start
= (x2
<< 16) | y2
;
571 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
613 diago
= (dy
- dx
) << 1;
626 p
= buf
->data
+ x
* s
->width
+ y
;
628 p
= buf
->data
+ y
* s
->width
+ x
;
634 artist_rop8(s
, p
, color
);
638 artist_invalidate_lines(buf
, y
, 1);
645 } while (x
<= x2
&& (max_pix
== -1 || --max_pix
> 0));
648 static void draw_line_pattern_start(ARTISTState
*s
)
651 int startx
= artist_get_x(s
->vram_start
);
652 int starty
= artist_get_y(s
->vram_start
);
653 int endx
= artist_get_x(s
->blockmove_size
);
654 int endy
= artist_get_y(s
->blockmove_size
);
655 int pstart
= s
->line_pattern_start
>> 16;
657 trace_artist_draw_line(startx
, starty
, endx
, endy
);
658 draw_line(s
, startx
, starty
, endx
, endy
, false, -1, pstart
);
659 s
->line_pattern_skip
= pstart
;
662 static void draw_line_pattern_next(ARTISTState
*s
)
665 int startx
= artist_get_x(s
->vram_start
);
666 int starty
= artist_get_y(s
->vram_start
);
667 int endx
= artist_get_x(s
->blockmove_size
);
668 int endy
= artist_get_y(s
->blockmove_size
);
669 int line_xy
= s
->line_xy
>> 16;
671 trace_artist_draw_line(startx
, starty
, endx
, endy
);
672 draw_line(s
, startx
, starty
, endx
, endy
, false, s
->line_pattern_skip
,
673 s
->line_pattern_skip
+ line_xy
);
674 s
->line_pattern_skip
+= line_xy
;
675 s
->image_bitmap_op
^= 2;
678 static void draw_line_size(ARTISTState
*s
, bool update_start
)
681 int startx
= artist_get_x(s
->vram_start
);
682 int starty
= artist_get_y(s
->vram_start
);
683 int endx
= artist_get_x(s
->line_size
);
684 int endy
= artist_get_y(s
->line_size
);
686 trace_artist_draw_line(startx
, starty
, endx
, endy
);
687 draw_line(s
, startx
, starty
, endx
, endy
, update_start
, -1, -1);
690 static void draw_line_xy(ARTISTState
*s
, bool update_start
)
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;
704 endx
= startx
+ linexy
;
713 endy
= starty
+ linexy
;
746 trace_artist_draw_line(startx
, starty
, endx
, endy
);
747 draw_line(s
, startx
, starty
, endx
, endy
, false, -1, -1);
750 static void draw_line_end(ARTISTState
*s
, bool update_start
)
753 int startx
= artist_get_x(s
->vram_start
);
754 int starty
= artist_get_y(s
->vram_start
);
755 int endx
= artist_get_x(s
->line_end
);
756 int endy
= artist_get_y(s
->line_end
);
758 trace_artist_draw_line(startx
, starty
, endx
, endy
);
759 draw_line(s
, startx
, starty
, endx
, endy
, update_start
, -1, -1);
762 static void font_write16(ARTISTState
*s
, uint16_t val
)
764 struct vram_buffer
*buf
;
765 uint32_t color
= (s
->image_bitmap_op
& 2) ? s
->fg_color
: s
->bg_color
;
769 int startx
= artist_get_x(s
->vram_start
);
770 int starty
= artist_get_y(s
->vram_start
) + s
->font_write_pos_y
;
771 int offset
= starty
* s
->width
+ startx
;
773 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
775 if (offset
+ 16 > buf
->size
) {
779 for (i
= 0; i
< 16; i
++) {
780 mask
= 1 << (15 - i
);
782 artist_rop8(s
, buf
->data
+ offset
+ i
, color
);
784 if (!(s
->image_bitmap_op
& 0x20000000)) {
785 artist_rop8(s
, buf
->data
+ offset
+ i
, s
->bg_color
);
789 artist_invalidate_lines(buf
, starty
, 1);
792 static void font_write(ARTISTState
*s
, uint32_t val
)
794 font_write16(s
, val
>> 16);
795 if (++s
->font_write_pos_y
== artist_get_y(s
->blockmove_size
)) {
796 s
->vram_start
+= (s
->blockmove_size
& 0xffff0000);
800 font_write16(s
, val
& 0xffff);
801 if (++s
->font_write_pos_y
== artist_get_y(s
->blockmove_size
)) {
802 s
->vram_start
+= (s
->blockmove_size
& 0xffff0000);
807 static void combine_write_reg(hwaddr addr
, uint64_t val
, int size
, void *out
)
810 * FIXME: is there a qemu helper for this?
813 #ifndef HOST_WORDS_BIGENDIAN
819 *(uint8_t *)(out
+ (addr
& 3)) = val
;
823 *(uint16_t *)(out
+ (addr
& 2)) = val
;
827 *(uint32_t *)out
= val
;
831 qemu_log_mask(LOG_UNIMP
, "unsupported write size: %d\n", size
);
835 static void artist_reg_write(void *opaque
, hwaddr addr
, uint64_t val
,
838 ARTISTState
*s
= opaque
;
842 trace_artist_reg_write(size
, addr
, artist_reg_name(addr
& ~3ULL), val
);
844 switch (addr
& ~3ULL) {
846 combine_write_reg(addr
, val
, size
, &s
->reg_100080
);
850 combine_write_reg(addr
, val
, size
, &s
->fg_color
);
854 combine_write_reg(addr
, val
, size
, &s
->bg_color
);
858 combine_write_reg(addr
, val
, size
, &s
->vram_bitmask
);
861 case VRAM_WRITE_INCR_Y
:
862 posx
= (s
->vram_pos
>> 2) & 0x7ff;
863 posy
= (s
->vram_pos
>> 13) & 0x3ff;
864 vram_bit_write(s
, posx
, posy
+ s
->vram_char_y
++, false, size
, val
);
867 case VRAM_WRITE_INCR_X
:
868 case VRAM_WRITE_INCR_X2
:
869 posx
= (s
->vram_pos
>> 2) & 0x7ff;
870 posy
= (s
->vram_pos
>> 13) & 0x3ff;
871 vram_bit_write(s
, posx
, posy
+ s
->vram_char_y
, true, size
, val
);
875 combine_write_reg(addr
, val
, size
, &s
->vram_pos
);
877 s
->draw_line_pattern
= 0;
881 combine_write_reg(addr
, val
, size
, &s
->vram_start
);
882 s
->draw_line_pattern
= 0;
885 case VRAM_START_TRIGGER
:
886 combine_write_reg(addr
, val
, size
, &s
->vram_start
);
887 fill_window(s
, artist_get_x(s
->vram_start
),
888 artist_get_y(s
->vram_start
),
889 artist_get_x(s
->blockmove_size
),
890 artist_get_y(s
->blockmove_size
));
893 case VRAM_SIZE_TRIGGER
:
894 combine_write_reg(addr
, val
, size
, &s
->vram_size
);
896 if (size
== 2 && !(addr
& 2)) {
897 height
= artist_get_y(s
->blockmove_size
);
899 height
= artist_get_y(s
->vram_size
);
902 if (size
== 2 && (addr
& 2)) {
903 width
= artist_get_x(s
->blockmove_size
);
905 width
= artist_get_x(s
->vram_size
);
908 fill_window(s
, artist_get_x(s
->vram_start
),
909 artist_get_y(s
->vram_start
),
914 combine_write_reg(addr
, val
, size
, &s
->line_xy
);
915 if (s
->draw_line_pattern
) {
916 draw_line_pattern_next(s
);
918 draw_line_xy(s
, true);
922 case PATTERN_LINE_START
:
923 combine_write_reg(addr
, val
, size
, &s
->line_pattern_start
);
924 s
->draw_line_pattern
= 1;
925 draw_line_pattern_start(s
);
929 combine_write_reg(addr
, val
, size
, &s
->line_size
);
930 draw_line_size(s
, true);
934 combine_write_reg(addr
, val
, size
, &s
->line_end
);
935 draw_line_end(s
, true);
938 case BLOCK_MOVE_SIZE
:
939 combine_write_reg(addr
, val
, size
, &s
->blockmove_size
);
942 case BLOCK_MOVE_SOURCE
:
943 combine_write_reg(addr
, val
, size
, &s
->blockmove_source
);
946 case BLOCK_MOVE_DEST_TRIGGER
:
947 combine_write_reg(addr
, val
, size
, &s
->blockmove_dest
);
949 block_move(s
, artist_get_x(s
->blockmove_source
),
950 artist_get_y(s
->blockmove_source
),
951 artist_get_x(s
->blockmove_dest
),
952 artist_get_y(s
->blockmove_dest
),
953 artist_get_x(s
->blockmove_size
),
954 artist_get_y(s
->blockmove_size
));
957 case BLOCK_MOVE_SIZE_TRIGGER
:
958 combine_write_reg(addr
, val
, size
, &s
->blockmove_size
);
961 artist_get_x(s
->blockmove_source
),
962 artist_get_y(s
->blockmove_source
),
963 artist_get_x(s
->vram_start
),
964 artist_get_y(s
->vram_start
),
965 artist_get_x(s
->blockmove_size
),
966 artist_get_y(s
->blockmove_size
));
970 combine_write_reg(addr
, val
, size
, &s
->plane_mask
);
974 combine_write_reg(addr
, val
, size
, &s
->cmap_bm_access
);
978 combine_write_reg(addr
, val
, size
, &s
->dst_bm_access
);
979 s
->cmap_bm_access
= 0;
983 combine_write_reg(addr
, val
, size
, &s
->src_bm_access
);
984 s
->cmap_bm_access
= 0;
988 combine_write_reg(addr
, val
, size
, &s
->control_plane
);
992 combine_write_reg(addr
, val
, size
, &s
->transfer_data
);
996 combine_write_reg(addr
, val
, size
, &s
->reg_300200
);
1000 combine_write_reg(addr
, val
, size
, &s
->reg_300208
);
1004 combine_write_reg(addr
, val
, size
, &s
->reg_300218
);
1008 artist_invalidate_cursor(s
);
1009 combine_write_reg(addr
, val
, size
, &s
->cursor_pos
);
1010 artist_invalidate_cursor(s
);
1016 case IMAGE_BITMAP_OP
:
1017 combine_write_reg(addr
, val
, size
, &s
->image_bitmap_op
);
1020 case FONT_WRITE_INCR_Y
:
1021 combine_write_reg(addr
, val
, size
, &s
->font_write1
);
1022 font_write(s
, s
->font_write1
);
1025 case FONT_WRITE_START
:
1026 combine_write_reg(addr
, val
, size
, &s
->font_write2
);
1027 s
->font_write_pos_y
= 0;
1028 font_write(s
, s
->font_write2
);
1035 qemu_log_mask(LOG_UNIMP
, "%s: unknown register: reg=%08" HWADDR_PRIx
1036 " val=%08" PRIx64
" size=%d\n",
1037 __func__
, addr
, val
, size
);
1042 static uint64_t combine_read_reg(hwaddr addr
, int size
, void *in
)
1045 * FIXME: is there a qemu helper for this?
1048 #ifndef HOST_WORDS_BIGENDIAN
1054 return *(uint8_t *)(in
+ (addr
& 3));
1057 return *(uint16_t *)(in
+ (addr
& 2));
1060 return *(uint32_t *)in
;
1063 qemu_log_mask(LOG_UNIMP
, "unsupported read size: %d\n", size
);
1068 static uint64_t artist_reg_read(void *opaque
, hwaddr addr
, unsigned size
)
1070 ARTISTState
*s
= opaque
;
1073 switch (addr
& ~3ULL) {
1074 /* Unknown status registers */
1079 val
= (s
->width
<< 16) | s
->height
;
1080 if (s
->depth
== 1) {
1095 * FIFO ready flag. we're not emulating the FIFOs
1096 * so we're always ready
1102 val
= s
->reg_300200
;
1106 val
= s
->reg_300208
;
1110 val
= s
->reg_300218
;
1118 /* 0x02000000 Buserror */
1123 qemu_log_mask(LOG_UNIMP
, "%s: unknown register: %08" HWADDR_PRIx
1124 " size %d\n", __func__
, addr
, size
);
1127 val
= combine_read_reg(addr
, size
, &val
);
1128 trace_artist_reg_read(size
, addr
, artist_reg_name(addr
& ~3ULL), val
);
1132 static void artist_vram_write(void *opaque
, hwaddr addr
, uint64_t val
,
1135 ARTISTState
*s
= opaque
;
1136 struct vram_buffer
*buf
;
1137 int posy
= (addr
>> 11) & 0x3ff;
1138 int posx
= addr
& 0x7ff;
1140 trace_artist_vram_write(size
, addr
, val
);
1142 if (s
->cmap_bm_access
) {
1143 buf
= &s
->vram_buffer
[ARTIST_BUFFER_CMAP
];
1144 if (addr
+ 3 < buf
->size
) {
1145 *(uint32_t *)(buf
->data
+ addr
) = val
;
1150 buf
= vram_write_buffer(s
);
1155 if (posy
> buf
->height
|| posx
> buf
->width
) {
1159 offset
= posy
* buf
->width
+ posx
;
1162 *(uint32_t *)(buf
->data
+ offset
) = be32_to_cpu(val
);
1163 memory_region_set_dirty(&buf
->mr
, offset
, 4);
1166 *(uint16_t *)(buf
->data
+ offset
) = be16_to_cpu(val
);
1167 memory_region_set_dirty(&buf
->mr
, offset
, 2);
1170 *(uint8_t *)(buf
->data
+ offset
) = val
;
1171 memory_region_set_dirty(&buf
->mr
, offset
, 1);
1178 static uint64_t artist_vram_read(void *opaque
, hwaddr addr
, unsigned size
)
1180 ARTISTState
*s
= opaque
;
1181 struct vram_buffer
*buf
;
1185 if (s
->cmap_bm_access
) {
1186 buf
= &s
->vram_buffer
[ARTIST_BUFFER_CMAP
];
1187 val
= *(uint32_t *)(buf
->data
+ addr
);
1188 trace_artist_vram_read(size
, addr
, 0, 0, val
);
1192 buf
= vram_read_buffer(s
);
1197 posy
= (addr
>> 13) & 0x3ff;
1198 posx
= (addr
>> 2) & 0x7ff;
1200 if (posy
> buf
->height
|| posx
> buf
->width
) {
1204 val
= cpu_to_be32(*(uint32_t *)(buf
->data
+ posy
* buf
->width
+ posx
));
1205 trace_artist_vram_read(size
, addr
, posx
, posy
, val
);
1209 static const MemoryRegionOps artist_reg_ops
= {
1210 .read
= artist_reg_read
,
1211 .write
= artist_reg_write
,
1212 .endianness
= DEVICE_NATIVE_ENDIAN
,
1214 .min_access_size
= 1,
1215 .max_access_size
= 4,
1219 static const MemoryRegionOps artist_vram_ops
= {
1220 .read
= artist_vram_read
,
1221 .write
= artist_vram_write
,
1222 .endianness
= DEVICE_NATIVE_ENDIAN
,
1224 .min_access_size
= 1,
1225 .max_access_size
= 4,
1229 static void artist_draw_cursor(ARTISTState
*s
)
1231 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1232 uint32_t *data
= (uint32_t *)surface_data(surface
);
1233 struct vram_buffer
*cursor0
, *cursor1
, *buf
;
1234 int cx
, cy
, cursor_pos_x
, cursor_pos_y
;
1236 cursor0
= &s
->vram_buffer
[ARTIST_BUFFER_CURSOR1
];
1237 cursor1
= &s
->vram_buffer
[ARTIST_BUFFER_CURSOR2
];
1238 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
1240 artist_get_cursor_pos(s
, &cursor_pos_x
, &cursor_pos_y
);
1242 for (cy
= 0; cy
< s
->cursor_height
; cy
++) {
1244 for (cx
= 0; cx
< s
->cursor_width
; cx
++) {
1246 if (cursor_pos_y
+ cy
< 0 ||
1247 cursor_pos_x
+ cx
< 0 ||
1248 cursor_pos_y
+ cy
> buf
->height
- 1 ||
1249 cursor_pos_x
+ cx
> buf
->width
) {
1253 int dstoffset
= (cursor_pos_y
+ cy
) * s
->width
+
1254 (cursor_pos_x
+ cx
);
1256 if (cursor0
->data
[cy
* cursor0
->width
+ cx
]) {
1257 data
[dstoffset
] = 0;
1259 if (cursor1
->data
[cy
* cursor1
->width
+ cx
]) {
1260 data
[dstoffset
] = 0xffffff;
1267 static void artist_draw_line(void *opaque
, uint8_t *d
, const uint8_t *src
,
1268 int width
, int pitch
)
1270 ARTISTState
*s
= ARTIST(opaque
);
1271 uint32_t *cmap
, *data
= (uint32_t *)d
;
1274 cmap
= (uint32_t *)(s
->vram_buffer
[ARTIST_BUFFER_CMAP
].data
+ 0x400);
1276 for (x
= 0; x
< s
->width
; x
++) {
1277 *data
++ = cmap
[*src
++];
1281 static void artist_update_display(void *opaque
)
1283 ARTISTState
*s
= opaque
;
1284 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
1285 int first
= 0, last
;
1288 framebuffer_update_display(surface
, &s
->fbsection
, s
->width
, s
->height
,
1289 s
->width
, s
->width
* 4, 0, 0, artist_draw_line
,
1292 artist_draw_cursor(s
);
1294 dpy_gfx_update(s
->con
, 0, 0, s
->width
, s
->height
);
1297 static void artist_invalidate(void *opaque
)
1299 ARTISTState
*s
= ARTIST(opaque
);
1300 struct vram_buffer
*buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
1301 memory_region_set_dirty(&buf
->mr
, 0, buf
->size
);
1304 static const GraphicHwOps artist_ops
= {
1305 .invalidate
= artist_invalidate
,
1306 .gfx_update
= artist_update_display
,
1309 static void artist_initfn(Object
*obj
)
1311 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
1312 ARTISTState
*s
= ARTIST(obj
);
1314 memory_region_init_io(&s
->reg
, obj
, &artist_reg_ops
, s
, "artist.reg",
1316 memory_region_init_io(&s
->vram_mem
, obj
, &artist_vram_ops
, s
, "artist.vram",
1318 sysbus_init_mmio(sbd
, &s
->reg
);
1319 sysbus_init_mmio(sbd
, &s
->vram_mem
);
1322 static void artist_create_buffer(ARTISTState
*s
, const char *name
,
1323 hwaddr
*offset
, unsigned int idx
,
1324 int width
, int height
)
1326 struct vram_buffer
*buf
= s
->vram_buffer
+ idx
;
1328 memory_region_init_ram(&buf
->mr
, NULL
, name
, width
* height
,
1330 memory_region_add_subregion_overlap(&s
->mem_as_root
, *offset
, &buf
->mr
, 0);
1332 buf
->data
= memory_region_get_ram_ptr(&buf
->mr
);
1333 buf
->size
= height
* width
;
1335 buf
->height
= height
;
1337 *offset
+= buf
->size
;
1340 static void artist_realizefn(DeviceState
*dev
, Error
**errp
)
1342 ARTISTState
*s
= ARTIST(dev
);
1343 struct vram_buffer
*buf
;
1346 memory_region_init(&s
->mem_as_root
, OBJECT(dev
), "artist", ~0ull);
1347 address_space_init(&s
->as
, &s
->mem_as_root
, "artist");
1349 artist_create_buffer(s
, "cmap", &offset
, ARTIST_BUFFER_CMAP
, 2048, 4);
1350 artist_create_buffer(s
, "ap", &offset
, ARTIST_BUFFER_AP
,
1351 s
->width
, s
->height
);
1352 artist_create_buffer(s
, "cursor1", &offset
, ARTIST_BUFFER_CURSOR1
, 64, 64);
1353 artist_create_buffer(s
, "cursor2", &offset
, ARTIST_BUFFER_CURSOR2
, 64, 64);
1354 artist_create_buffer(s
, "attribute", &offset
, ARTIST_BUFFER_ATTRIBUTE
,
1357 buf
= &s
->vram_buffer
[ARTIST_BUFFER_AP
];
1358 framebuffer_update_memory_section(&s
->fbsection
, &buf
->mr
, 0,
1359 buf
->width
, buf
->height
);
1361 * no idea whether the cursor is fixed size or not, so assume 32x32 which
1362 * seems sufficient for HP-UX X11.
1364 s
->cursor_height
= 32;
1365 s
->cursor_width
= 32;
1367 s
->con
= graphic_console_init(DEVICE(dev
), 0, &artist_ops
, s
);
1368 qemu_console_resize(s
->con
, s
->width
, s
->height
);
1371 static int vmstate_artist_post_load(void *opaque
, int version_id
)
1373 artist_invalidate(opaque
);
1377 static const VMStateDescription vmstate_artist
= {
1380 .minimum_version_id
= 1,
1381 .post_load
= vmstate_artist_post_load
,
1382 .fields
= (VMStateField
[]) {
1383 VMSTATE_UINT16(height
, ARTISTState
),
1384 VMSTATE_UINT16(width
, ARTISTState
),
1385 VMSTATE_UINT16(depth
, ARTISTState
),
1386 VMSTATE_UINT32(fg_color
, ARTISTState
),
1387 VMSTATE_UINT32(bg_color
, ARTISTState
),
1388 VMSTATE_UINT32(vram_char_y
, ARTISTState
),
1389 VMSTATE_UINT32(vram_bitmask
, ARTISTState
),
1390 VMSTATE_UINT32(vram_start
, ARTISTState
),
1391 VMSTATE_UINT32(vram_pos
, ARTISTState
),
1392 VMSTATE_UINT32(vram_size
, ARTISTState
),
1393 VMSTATE_UINT32(blockmove_source
, ARTISTState
),
1394 VMSTATE_UINT32(blockmove_dest
, ARTISTState
),
1395 VMSTATE_UINT32(blockmove_size
, ARTISTState
),
1396 VMSTATE_UINT32(line_size
, ARTISTState
),
1397 VMSTATE_UINT32(line_end
, ARTISTState
),
1398 VMSTATE_UINT32(line_xy
, ARTISTState
),
1399 VMSTATE_UINT32(cursor_pos
, ARTISTState
),
1400 VMSTATE_UINT32(cursor_height
, ARTISTState
),
1401 VMSTATE_UINT32(cursor_width
, ARTISTState
),
1402 VMSTATE_UINT32(plane_mask
, ARTISTState
),
1403 VMSTATE_UINT32(reg_100080
, ARTISTState
),
1404 VMSTATE_UINT32(reg_300200
, ARTISTState
),
1405 VMSTATE_UINT32(reg_300208
, ARTISTState
),
1406 VMSTATE_UINT32(reg_300218
, ARTISTState
),
1407 VMSTATE_UINT32(cmap_bm_access
, ARTISTState
),
1408 VMSTATE_UINT32(dst_bm_access
, ARTISTState
),
1409 VMSTATE_UINT32(src_bm_access
, ARTISTState
),
1410 VMSTATE_UINT32(control_plane
, ARTISTState
),
1411 VMSTATE_UINT32(transfer_data
, ARTISTState
),
1412 VMSTATE_UINT32(image_bitmap_op
, ARTISTState
),
1413 VMSTATE_UINT32(font_write1
, ARTISTState
),
1414 VMSTATE_UINT32(font_write2
, ARTISTState
),
1415 VMSTATE_UINT32(font_write_pos_y
, ARTISTState
),
1416 VMSTATE_END_OF_LIST()
1420 static Property artist_properties
[] = {
1421 DEFINE_PROP_UINT16("width", ARTISTState
, width
, 1280),
1422 DEFINE_PROP_UINT16("height", ARTISTState
, height
, 1024),
1423 DEFINE_PROP_UINT16("depth", ARTISTState
, depth
, 8),
1424 DEFINE_PROP_END_OF_LIST(),
1427 static void artist_reset(DeviceState
*qdev
)
1431 static void artist_class_init(ObjectClass
*klass
, void *data
)
1433 DeviceClass
*dc
= DEVICE_CLASS(klass
);
1435 dc
->realize
= artist_realizefn
;
1436 dc
->vmsd
= &vmstate_artist
;
1437 dc
->reset
= artist_reset
;
1438 device_class_set_props(dc
, artist_properties
);
1441 static const TypeInfo artist_info
= {
1442 .name
= TYPE_ARTIST
,
1443 .parent
= TYPE_SYS_BUS_DEVICE
,
1444 .instance_size
= sizeof(ARTISTState
),
1445 .instance_init
= artist_initfn
,
1446 .class_init
= artist_class_init
,
1449 static void artist_register_types(void)
1451 type_register_static(&artist_info
);
1454 type_init(artist_register_types
)