14765384cSSven Schnelle /*
24765384cSSven Schnelle * QEMU HP Artist Emulation
34765384cSSven Schnelle *
49ef2c6b4SHelge Deller * Copyright (c) 2019-2022 Sven Schnelle <svens@stackframe.org>
59ef2c6b4SHelge Deller * Copyright (c) 2022 Helge Deller <deller@gmx.de>
64765384cSSven Schnelle *
74765384cSSven Schnelle * This work is licensed under the terms of the GNU GPL, version 2 or later.
84765384cSSven Schnelle */
94765384cSSven Schnelle
104765384cSSven Schnelle #include "qemu/osdep.h"
114765384cSSven Schnelle #include "qemu/error-report.h"
124765384cSSven Schnelle #include "qemu/log.h"
134765384cSSven Schnelle #include "qemu/module.h"
144765384cSSven Schnelle #include "qemu/units.h"
154765384cSSven Schnelle #include "qapi/error.h"
164765384cSSven Schnelle #include "hw/sysbus.h"
174765384cSSven Schnelle #include "hw/loader.h"
184765384cSSven Schnelle #include "hw/qdev-core.h"
194765384cSSven Schnelle #include "hw/qdev-properties.h"
204765384cSSven Schnelle #include "migration/vmstate.h"
214765384cSSven Schnelle #include "ui/console.h"
224765384cSSven Schnelle #include "trace.h"
2363dc3465SPhilippe Mathieu-Daudé #include "framebuffer.h"
24db1015e9SEduardo Habkost #include "qom/object.h"
254765384cSSven Schnelle
264765384cSSven Schnelle #define TYPE_ARTIST "artist"
278063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState, ARTIST)
284765384cSSven Schnelle
294765384cSSven Schnelle struct vram_buffer {
304765384cSSven Schnelle MemoryRegion mr;
314765384cSSven Schnelle uint8_t *data;
32a501bfc9SHelge Deller unsigned int size;
33a501bfc9SHelge Deller unsigned int width;
34a501bfc9SHelge Deller unsigned int height;
354765384cSSven Schnelle };
364765384cSSven Schnelle
37db1015e9SEduardo Habkost struct ARTISTState {
384765384cSSven Schnelle SysBusDevice parent_obj;
394765384cSSven Schnelle
404765384cSSven Schnelle QemuConsole *con;
414765384cSSven Schnelle MemoryRegion vram_mem;
424765384cSSven Schnelle MemoryRegion mem_as_root;
434765384cSSven Schnelle MemoryRegion reg;
444765384cSSven Schnelle MemoryRegionSection fbsection;
454765384cSSven Schnelle
464765384cSSven Schnelle void *vram_int_mr;
474765384cSSven Schnelle AddressSpace as;
484765384cSSven Schnelle
494765384cSSven Schnelle struct vram_buffer vram_buffer[16];
504765384cSSven Schnelle
514765384cSSven Schnelle uint16_t width;
524765384cSSven Schnelle uint16_t height;
534765384cSSven Schnelle uint16_t depth;
544765384cSSven Schnelle
554765384cSSven Schnelle uint32_t fg_color;
564765384cSSven Schnelle uint32_t bg_color;
574765384cSSven Schnelle
584765384cSSven Schnelle uint32_t vram_char_y;
594765384cSSven Schnelle uint32_t vram_bitmask;
604765384cSSven Schnelle
614765384cSSven Schnelle uint32_t vram_start;
624765384cSSven Schnelle uint32_t vram_pos;
634765384cSSven Schnelle
644765384cSSven Schnelle uint32_t vram_size;
654765384cSSven Schnelle
664765384cSSven Schnelle uint32_t blockmove_source;
674765384cSSven Schnelle uint32_t blockmove_dest;
684765384cSSven Schnelle uint32_t blockmove_size;
694765384cSSven Schnelle
704765384cSSven Schnelle uint32_t line_size;
714765384cSSven Schnelle uint32_t line_end;
724765384cSSven Schnelle uint32_t line_xy;
734765384cSSven Schnelle uint32_t line_pattern_start;
744765384cSSven Schnelle uint32_t line_pattern_skip;
754765384cSSven Schnelle
764765384cSSven Schnelle uint32_t cursor_pos;
773615cea4SHelge Deller uint32_t cursor_cntrl;
784765384cSSven Schnelle
794765384cSSven Schnelle uint32_t cursor_height;
804765384cSSven Schnelle uint32_t cursor_width;
814765384cSSven Schnelle
824765384cSSven Schnelle uint32_t plane_mask;
834765384cSSven Schnelle
844765384cSSven Schnelle uint32_t reg_100080;
85e9683fbcSHelge Deller uint32_t horiz_backporch;
86e9683fbcSHelge Deller uint32_t active_lines_low;
87e9683fbcSHelge Deller uint32_t misc_video;
88e9683fbcSHelge Deller uint32_t misc_ctrl;
894765384cSSven Schnelle
904765384cSSven Schnelle uint32_t dst_bm_access;
914765384cSSven Schnelle uint32_t src_bm_access;
924765384cSSven Schnelle uint32_t control_plane;
934765384cSSven Schnelle uint32_t transfer_data;
944765384cSSven Schnelle uint32_t image_bitmap_op;
954765384cSSven Schnelle
964765384cSSven Schnelle uint32_t font_write1;
974765384cSSven Schnelle uint32_t font_write2;
984765384cSSven Schnelle uint32_t font_write_pos_y;
994765384cSSven Schnelle
1004765384cSSven Schnelle int draw_line_pattern;
101db1015e9SEduardo Habkost };
1024765384cSSven Schnelle
1037e50730cSHelge Deller /* hardware allows up to 64x64, but we emulate 32x32 only. */
1047e50730cSHelge Deller #define NGLE_MAX_SPRITE_SIZE 32
1057e50730cSHelge Deller
1064765384cSSven Schnelle typedef enum {
1074765384cSSven Schnelle ARTIST_BUFFER_AP = 1,
1084765384cSSven Schnelle ARTIST_BUFFER_OVERLAY = 2,
1094765384cSSven Schnelle ARTIST_BUFFER_CURSOR1 = 6,
1104765384cSSven Schnelle ARTIST_BUFFER_CURSOR2 = 7,
1114765384cSSven Schnelle ARTIST_BUFFER_ATTRIBUTE = 13,
1124765384cSSven Schnelle ARTIST_BUFFER_CMAP = 15,
1134765384cSSven Schnelle } artist_buffer_t;
1144765384cSSven Schnelle
1154765384cSSven Schnelle typedef enum {
1164765384cSSven Schnelle VRAM_IDX = 0x1004a0,
1174765384cSSven Schnelle VRAM_BITMASK = 0x1005a0,
1184765384cSSven Schnelle VRAM_WRITE_INCR_X = 0x100600,
1194765384cSSven Schnelle VRAM_WRITE_INCR_X2 = 0x100604,
1204765384cSSven Schnelle VRAM_WRITE_INCR_Y = 0x100620,
1214765384cSSven Schnelle VRAM_START = 0x100800,
1224765384cSSven Schnelle BLOCK_MOVE_SIZE = 0x100804,
1234765384cSSven Schnelle BLOCK_MOVE_SOURCE = 0x100808,
1244765384cSSven Schnelle TRANSFER_DATA = 0x100820,
1254765384cSSven Schnelle FONT_WRITE_INCR_Y = 0x1008a0,
1264765384cSSven Schnelle VRAM_START_TRIGGER = 0x100a00,
1274765384cSSven Schnelle VRAM_SIZE_TRIGGER = 0x100a04,
1284765384cSSven Schnelle FONT_WRITE_START = 0x100aa0,
1294765384cSSven Schnelle BLOCK_MOVE_DEST_TRIGGER = 0x100b00,
1304765384cSSven Schnelle BLOCK_MOVE_SIZE_TRIGGER = 0x100b04,
1314765384cSSven Schnelle LINE_XY = 0x100ccc,
1324765384cSSven Schnelle PATTERN_LINE_START = 0x100ecc,
1334765384cSSven Schnelle LINE_SIZE = 0x100e04,
1344765384cSSven Schnelle LINE_END = 0x100e44,
1353b21d998SSven Schnelle DST_SRC_BM_ACCESS = 0x118000,
1364765384cSSven Schnelle DST_BM_ACCESS = 0x118004,
1374765384cSSven Schnelle SRC_BM_ACCESS = 0x118008,
1384765384cSSven Schnelle CONTROL_PLANE = 0x11800c,
1394765384cSSven Schnelle FG_COLOR = 0x118010,
1404765384cSSven Schnelle BG_COLOR = 0x118014,
1414765384cSSven Schnelle PLANE_MASK = 0x118018,
1424765384cSSven Schnelle IMAGE_BITMAP_OP = 0x11801c,
143e9683fbcSHelge Deller CURSOR_POS = 0x300100, /* reg17 */
144e9683fbcSHelge Deller CURSOR_CTRL = 0x300104, /* reg18 */
145e9683fbcSHelge Deller MISC_VIDEO = 0x300218, /* reg21 */
146e9683fbcSHelge Deller MISC_CTRL = 0x300308, /* reg27 */
147e9683fbcSHelge Deller HORIZ_BACKPORCH = 0x300200, /* reg19 */
148e9683fbcSHelge Deller ACTIVE_LINES_LOW = 0x300208,/* reg20 */
149e9683fbcSHelge Deller FIFO1 = 0x300008, /* reg34 */
150e9683fbcSHelge Deller FIFO2 = 0x380008,
1514765384cSSven Schnelle } artist_reg_t;
1524765384cSSven Schnelle
1534765384cSSven Schnelle typedef enum {
1544765384cSSven Schnelle ARTIST_ROP_CLEAR = 0,
1554765384cSSven Schnelle ARTIST_ROP_COPY = 3,
1564765384cSSven Schnelle ARTIST_ROP_XOR = 6,
1574765384cSSven Schnelle ARTIST_ROP_NOT_DST = 10,
1584765384cSSven Schnelle ARTIST_ROP_SET = 15,
1594765384cSSven Schnelle } artist_rop_t;
1604765384cSSven Schnelle
1614765384cSSven Schnelle #define REG_NAME(_x) case _x: return " "#_x;
artist_reg_name(uint64_t addr)1624765384cSSven Schnelle static const char *artist_reg_name(uint64_t addr)
1634765384cSSven Schnelle {
1644765384cSSven Schnelle switch ((artist_reg_t)addr) {
1654765384cSSven Schnelle REG_NAME(VRAM_IDX);
1664765384cSSven Schnelle REG_NAME(VRAM_BITMASK);
1674765384cSSven Schnelle REG_NAME(VRAM_WRITE_INCR_X);
1684765384cSSven Schnelle REG_NAME(VRAM_WRITE_INCR_X2);
1694765384cSSven Schnelle REG_NAME(VRAM_WRITE_INCR_Y);
1704765384cSSven Schnelle REG_NAME(VRAM_START);
1714765384cSSven Schnelle REG_NAME(BLOCK_MOVE_SIZE);
1724765384cSSven Schnelle REG_NAME(BLOCK_MOVE_SOURCE);
1734765384cSSven Schnelle REG_NAME(FG_COLOR);
1744765384cSSven Schnelle REG_NAME(BG_COLOR);
1754765384cSSven Schnelle REG_NAME(PLANE_MASK);
1764765384cSSven Schnelle REG_NAME(VRAM_START_TRIGGER);
1774765384cSSven Schnelle REG_NAME(VRAM_SIZE_TRIGGER);
1784765384cSSven Schnelle REG_NAME(BLOCK_MOVE_DEST_TRIGGER);
1794765384cSSven Schnelle REG_NAME(BLOCK_MOVE_SIZE_TRIGGER);
1804765384cSSven Schnelle REG_NAME(TRANSFER_DATA);
1814765384cSSven Schnelle REG_NAME(CONTROL_PLANE);
1824765384cSSven Schnelle REG_NAME(IMAGE_BITMAP_OP);
1833b21d998SSven Schnelle REG_NAME(DST_SRC_BM_ACCESS);
1844765384cSSven Schnelle REG_NAME(DST_BM_ACCESS);
1854765384cSSven Schnelle REG_NAME(SRC_BM_ACCESS);
1864765384cSSven Schnelle REG_NAME(CURSOR_POS);
1874765384cSSven Schnelle REG_NAME(CURSOR_CTRL);
188e9683fbcSHelge Deller REG_NAME(HORIZ_BACKPORCH);
189e9683fbcSHelge Deller REG_NAME(ACTIVE_LINES_LOW);
190e9683fbcSHelge Deller REG_NAME(MISC_VIDEO);
191e9683fbcSHelge Deller REG_NAME(MISC_CTRL);
1924765384cSSven Schnelle REG_NAME(LINE_XY);
1934765384cSSven Schnelle REG_NAME(PATTERN_LINE_START);
1944765384cSSven Schnelle REG_NAME(LINE_SIZE);
1954765384cSSven Schnelle REG_NAME(LINE_END);
1964765384cSSven Schnelle REG_NAME(FONT_WRITE_INCR_Y);
1974765384cSSven Schnelle REG_NAME(FONT_WRITE_START);
198e9683fbcSHelge Deller REG_NAME(FIFO1);
199e9683fbcSHelge Deller REG_NAME(FIFO2);
2004765384cSSven Schnelle }
2014765384cSSven Schnelle return "";
2024765384cSSven Schnelle }
2034765384cSSven Schnelle #undef REG_NAME
2044765384cSSven Schnelle
205caca6e61SHelge Deller static void artist_invalidate(void *opaque);
206caca6e61SHelge Deller
207c7050f3fSHelge Deller /* artist has a fixed line length of 2048 bytes. */
20832a2b033SHelge Deller #define ADDR_TO_Y(addr) extract32(addr, 11, 11)
209c7050f3fSHelge Deller #define ADDR_TO_X(addr) extract32(addr, 0, 11)
210c7050f3fSHelge Deller
artist_get_x(uint32_t reg)2114765384cSSven Schnelle static int16_t artist_get_x(uint32_t reg)
2124765384cSSven Schnelle {
2134765384cSSven Schnelle return reg >> 16;
2144765384cSSven Schnelle }
2154765384cSSven Schnelle
artist_get_y(uint32_t reg)2164765384cSSven Schnelle static int16_t artist_get_y(uint32_t reg)
2174765384cSSven Schnelle {
2184765384cSSven Schnelle return reg & 0xffff;
2194765384cSSven Schnelle }
2204765384cSSven Schnelle
artist_invalidate_lines(struct vram_buffer * buf,int starty,int height)2214765384cSSven Schnelle static void artist_invalidate_lines(struct vram_buffer *buf,
2224765384cSSven Schnelle int starty, int height)
2234765384cSSven Schnelle {
2244765384cSSven Schnelle int start = starty * buf->width;
2252f8cd515SSven Schnelle int size;
2262f8cd515SSven Schnelle
2275d61789eSMark Cave-Ayland if (starty + height > buf->height) {
2282f8cd515SSven Schnelle height = buf->height - starty;
2295d61789eSMark Cave-Ayland }
2302f8cd515SSven Schnelle
2312f8cd515SSven Schnelle size = height * buf->width;
2324765384cSSven Schnelle
2334765384cSSven Schnelle if (start + size <= buf->size) {
2344765384cSSven Schnelle memory_region_set_dirty(&buf->mr, start, size);
2354765384cSSven Schnelle }
2364765384cSSven Schnelle }
2374765384cSSven Schnelle
vram_write_bufidx(ARTISTState * s)2384765384cSSven Schnelle static int vram_write_bufidx(ARTISTState *s)
2394765384cSSven Schnelle {
2404765384cSSven Schnelle return (s->dst_bm_access >> 12) & 0x0f;
2414765384cSSven Schnelle }
2424765384cSSven Schnelle
vram_read_bufidx(ARTISTState * s)2434765384cSSven Schnelle static int vram_read_bufidx(ARTISTState *s)
2444765384cSSven Schnelle {
2454765384cSSven Schnelle return (s->src_bm_access >> 12) & 0x0f;
2464765384cSSven Schnelle }
2474765384cSSven Schnelle
vram_read_buffer(ARTISTState * s)2484765384cSSven Schnelle static struct vram_buffer *vram_read_buffer(ARTISTState *s)
2494765384cSSven Schnelle {
2504765384cSSven Schnelle return &s->vram_buffer[vram_read_bufidx(s)];
2514765384cSSven Schnelle }
2524765384cSSven Schnelle
vram_write_buffer(ARTISTState * s)2534765384cSSven Schnelle static struct vram_buffer *vram_write_buffer(ARTISTState *s)
2544765384cSSven Schnelle {
2554765384cSSven Schnelle return &s->vram_buffer[vram_write_bufidx(s)];
2564765384cSSven Schnelle }
2574765384cSSven Schnelle
artist_get_color(ARTISTState * s)2584765384cSSven Schnelle static uint8_t artist_get_color(ARTISTState *s)
2594765384cSSven Schnelle {
2604765384cSSven Schnelle if (s->image_bitmap_op & 2) {
2614765384cSSven Schnelle return s->fg_color;
2624765384cSSven Schnelle } else {
2634765384cSSven Schnelle return s->bg_color;
2644765384cSSven Schnelle }
2654765384cSSven Schnelle }
2664765384cSSven Schnelle
artist_get_op(ARTISTState * s)2674765384cSSven Schnelle static artist_rop_t artist_get_op(ARTISTState *s)
2684765384cSSven Schnelle {
2694765384cSSven Schnelle return (s->image_bitmap_op >> 8) & 0xf;
2704765384cSSven Schnelle }
2714765384cSSven Schnelle
artist_rop8(ARTISTState * s,struct vram_buffer * buf,unsigned int offset,uint8_t val)27284a7b774SPhilippe Mathieu-Daudé static void artist_rop8(ARTISTState *s, struct vram_buffer *buf,
273a501bfc9SHelge Deller unsigned int offset, uint8_t val)
2744765384cSSven Schnelle {
2754765384cSSven Schnelle const artist_rop_t op = artist_get_op(s);
27684a7b774SPhilippe Mathieu-Daudé uint8_t plane_mask;
27784a7b774SPhilippe Mathieu-Daudé uint8_t *dst;
27884a7b774SPhilippe Mathieu-Daudé
279a501bfc9SHelge Deller if (offset >= buf->size) {
28084a7b774SPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR,
281a501bfc9SHelge Deller "rop8 offset:%u bufsize:%u\n", offset, buf->size);
28284a7b774SPhilippe Mathieu-Daudé return;
28384a7b774SPhilippe Mathieu-Daudé }
28484a7b774SPhilippe Mathieu-Daudé dst = buf->data + offset;
28584a7b774SPhilippe Mathieu-Daudé plane_mask = s->plane_mask & 0xff;
2864765384cSSven Schnelle
2874765384cSSven Schnelle switch (op) {
2884765384cSSven Schnelle case ARTIST_ROP_CLEAR:
2894765384cSSven Schnelle *dst &= ~plane_mask;
2904765384cSSven Schnelle break;
2914765384cSSven Schnelle
2924765384cSSven Schnelle case ARTIST_ROP_COPY:
293a501bfc9SHelge Deller *dst = (*dst & ~plane_mask) | (val & plane_mask);
2944765384cSSven Schnelle break;
2954765384cSSven Schnelle
2964765384cSSven Schnelle case ARTIST_ROP_XOR:
2974765384cSSven Schnelle *dst ^= val & plane_mask;
2984765384cSSven Schnelle break;
2994765384cSSven Schnelle
3004765384cSSven Schnelle case ARTIST_ROP_NOT_DST:
3014765384cSSven Schnelle *dst ^= plane_mask;
3024765384cSSven Schnelle break;
3034765384cSSven Schnelle
3044765384cSSven Schnelle case ARTIST_ROP_SET:
3054765384cSSven Schnelle *dst |= plane_mask;
3064765384cSSven Schnelle break;
3074765384cSSven Schnelle
3084765384cSSven Schnelle default:
3094765384cSSven Schnelle qemu_log_mask(LOG_UNIMP, "%s: unsupported rop %d\n", __func__, op);
3104765384cSSven Schnelle break;
3114765384cSSven Schnelle }
3124765384cSSven Schnelle }
3134765384cSSven Schnelle
artist_get_cursor_pos(ARTISTState * s,int * x,int * y)3144765384cSSven Schnelle static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y)
3154765384cSSven Schnelle {
3164765384cSSven Schnelle /*
3173615cea4SHelge Deller * The emulated Artist graphic is like a CRX graphic, and as such
3183615cea4SHelge Deller * it's usually fixed at 1280x1024 pixels.
3199ef2c6b4SHelge Deller * Other resolutions may work, but no guarantee.
3204765384cSSven Schnelle */
3214765384cSSven Schnelle
3229ef2c6b4SHelge Deller unsigned int hbp_times_vi, horizBackPorch;
3239ef2c6b4SHelge Deller int16_t xHi, xLo;
3249ef2c6b4SHelge Deller const int videoInterleave = 4;
3259ef2c6b4SHelge Deller const int pipelineDelay = 4;
3263615cea4SHelge Deller
3273615cea4SHelge Deller /* ignore if uninitialized */
3283615cea4SHelge Deller if (s->cursor_pos == 0) {
3293615cea4SHelge Deller *x = *y = 0;
3303615cea4SHelge Deller return;
3313615cea4SHelge Deller }
3323615cea4SHelge Deller
3339ef2c6b4SHelge Deller /*
3349ef2c6b4SHelge Deller * Calculate X position based on backporch and interleave values.
3359ef2c6b4SHelge Deller * Based on code from Xorg X11R6.6
3369ef2c6b4SHelge Deller */
3379ef2c6b4SHelge Deller horizBackPorch = ((s->horiz_backporch & 0xff0000) >> 16) +
3389ef2c6b4SHelge Deller ((s->horiz_backporch & 0xff00) >> 8) + 2;
3399ef2c6b4SHelge Deller hbp_times_vi = horizBackPorch * videoInterleave;
3409ef2c6b4SHelge Deller xHi = s->cursor_pos >> 19;
3419ef2c6b4SHelge Deller *x = ((xHi + pipelineDelay) * videoInterleave) - hbp_times_vi;
3429ef2c6b4SHelge Deller
3439ef2c6b4SHelge Deller xLo = (s->cursor_pos >> 16) & 0x07;
3449ef2c6b4SHelge Deller *x += ((xLo - hbp_times_vi) & (videoInterleave - 1)) + 8 - 1;
3453615cea4SHelge Deller
3463615cea4SHelge Deller /* subtract cursor offset from cursor control register */
3473615cea4SHelge Deller *x -= (s->cursor_cntrl & 0xf0) >> 4;
348482afe02SHelge Deller
3499ef2c6b4SHelge Deller /* Calculate Y position */
350482afe02SHelge Deller *y = s->height - artist_get_y(s->cursor_pos);
3513615cea4SHelge Deller *y -= (s->cursor_cntrl & 0x0f);
3524765384cSSven Schnelle
3534765384cSSven Schnelle if (*x > s->width) {
3543615cea4SHelge Deller *x = s->width;
3554765384cSSven Schnelle }
3564765384cSSven Schnelle
3574765384cSSven Schnelle if (*y > s->height) {
3583615cea4SHelge Deller *y = s->height;
3594765384cSSven Schnelle }
3604765384cSSven Schnelle }
3614765384cSSven Schnelle
cursor_visible(ARTISTState * s)362a377b574SHelge Deller static inline bool cursor_visible(ARTISTState *s)
363a377b574SHelge Deller {
364a377b574SHelge Deller /* cursor is visible if bit 0x80 is set in cursor_cntrl */
365a377b574SHelge Deller return s->cursor_cntrl & 0x80;
366a377b574SHelge Deller }
367a377b574SHelge Deller
artist_invalidate_cursor(ARTISTState * s)3684765384cSSven Schnelle static void artist_invalidate_cursor(ARTISTState *s)
3694765384cSSven Schnelle {
3704765384cSSven Schnelle int x, y;
3715d61789eSMark Cave-Ayland
372a377b574SHelge Deller if (!cursor_visible(s)) {
373a377b574SHelge Deller return;
374a377b574SHelge Deller }
375a377b574SHelge Deller
3764765384cSSven Schnelle artist_get_cursor_pos(s, &x, &y);
3774765384cSSven Schnelle artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP],
3784765384cSSven Schnelle y, s->cursor_height);
3794765384cSSven Schnelle }
3804765384cSSven Schnelle
block_move(ARTISTState * s,unsigned int source_x,unsigned int source_y,unsigned int dest_x,unsigned int dest_y,unsigned int width,unsigned int height)381a501bfc9SHelge Deller static void block_move(ARTISTState *s,
382a501bfc9SHelge Deller unsigned int source_x, unsigned int source_y,
383a501bfc9SHelge Deller unsigned int dest_x, unsigned int dest_y,
384a501bfc9SHelge Deller unsigned int width, unsigned int height)
3854765384cSSven Schnelle {
3864765384cSSven Schnelle struct vram_buffer *buf;
3874765384cSSven Schnelle int line, endline, lineincr, startcolumn, endcolumn, columnincr, column;
388a501bfc9SHelge Deller unsigned int dst, src;
3894765384cSSven Schnelle
3904765384cSSven Schnelle trace_artist_block_move(source_x, source_y, dest_x, dest_y, width, height);
3914765384cSSven Schnelle
3924765384cSSven Schnelle if (s->control_plane != 0) {
3934765384cSSven Schnelle /* We don't support CONTROL_PLANE accesses */
3944765384cSSven Schnelle qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
3954765384cSSven Schnelle s->control_plane);
3964765384cSSven Schnelle return;
3974765384cSSven Schnelle }
3984765384cSSven Schnelle
3994765384cSSven Schnelle buf = &s->vram_buffer[ARTIST_BUFFER_AP];
400a501bfc9SHelge Deller if (height > buf->height) {
401a501bfc9SHelge Deller height = buf->height;
402a501bfc9SHelge Deller }
403a501bfc9SHelge Deller if (width > buf->width) {
404a501bfc9SHelge Deller width = buf->width;
405a501bfc9SHelge Deller }
4064765384cSSven Schnelle
4074765384cSSven Schnelle if (dest_y > source_y) {
4084765384cSSven Schnelle /* move down */
4094765384cSSven Schnelle line = height - 1;
4104765384cSSven Schnelle endline = -1;
4114765384cSSven Schnelle lineincr = -1;
4124765384cSSven Schnelle } else {
4134765384cSSven Schnelle /* move up */
4144765384cSSven Schnelle line = 0;
4154765384cSSven Schnelle endline = height;
4164765384cSSven Schnelle lineincr = 1;
4174765384cSSven Schnelle }
4184765384cSSven Schnelle
4194765384cSSven Schnelle if (dest_x > source_x) {
4204765384cSSven Schnelle /* move right */
4214765384cSSven Schnelle startcolumn = width - 1;
4224765384cSSven Schnelle endcolumn = -1;
4234765384cSSven Schnelle columnincr = -1;
4244765384cSSven Schnelle } else {
4254765384cSSven Schnelle /* move left */
4264765384cSSven Schnelle startcolumn = 0;
4274765384cSSven Schnelle endcolumn = width;
4284765384cSSven Schnelle columnincr = 1;
4294765384cSSven Schnelle }
4304765384cSSven Schnelle
4314765384cSSven Schnelle for ( ; line != endline; line += lineincr) {
432a501bfc9SHelge Deller src = source_x + ((line + source_y) * buf->width) + startcolumn;
433a501bfc9SHelge Deller dst = dest_x + ((line + dest_y) * buf->width) + startcolumn;
4344765384cSSven Schnelle
4354765384cSSven Schnelle for (column = startcolumn; column != endcolumn; column += columnincr) {
436a501bfc9SHelge Deller if (dst >= buf->size || src >= buf->size) {
4374765384cSSven Schnelle continue;
4384765384cSSven Schnelle }
439a501bfc9SHelge Deller artist_rop8(s, buf, dst, buf->data[src]);
440a501bfc9SHelge Deller src += columnincr;
441a501bfc9SHelge Deller dst += columnincr;
4424765384cSSven Schnelle }
4434765384cSSven Schnelle }
4444765384cSSven Schnelle
4454765384cSSven Schnelle artist_invalidate_lines(buf, dest_y, height);
4464765384cSSven Schnelle }
4474765384cSSven Schnelle
fill_window(ARTISTState * s,unsigned int startx,unsigned int starty,unsigned int width,unsigned int height)448a501bfc9SHelge Deller static void fill_window(ARTISTState *s,
449a501bfc9SHelge Deller unsigned int startx, unsigned int starty,
450a501bfc9SHelge Deller unsigned int width, unsigned int height)
4514765384cSSven Schnelle {
452a501bfc9SHelge Deller unsigned int offset;
4534765384cSSven Schnelle uint8_t color = artist_get_color(s);
4544765384cSSven Schnelle struct vram_buffer *buf;
4554765384cSSven Schnelle int x, y;
4564765384cSSven Schnelle
4574765384cSSven Schnelle trace_artist_fill_window(startx, starty, width, height,
4584765384cSSven Schnelle s->image_bitmap_op, s->control_plane);
4594765384cSSven Schnelle
4604765384cSSven Schnelle if (s->control_plane != 0) {
4614765384cSSven Schnelle /* We don't support CONTROL_PLANE accesses */
4624765384cSSven Schnelle qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
4634765384cSSven Schnelle s->control_plane);
4644765384cSSven Schnelle return;
4654765384cSSven Schnelle }
4664765384cSSven Schnelle
4674765384cSSven Schnelle if (s->reg_100080 == 0x7d) {
4684765384cSSven Schnelle /*
4694765384cSSven Schnelle * Not sure what this register really does, but
4704765384cSSven Schnelle * 0x7d seems to enable autoincremt of the Y axis
4714765384cSSven Schnelle * by the current block move height.
4724765384cSSven Schnelle */
4734765384cSSven Schnelle height = artist_get_y(s->blockmove_size);
4744765384cSSven Schnelle s->vram_start += height;
4754765384cSSven Schnelle }
4764765384cSSven Schnelle
4774765384cSSven Schnelle buf = &s->vram_buffer[ARTIST_BUFFER_AP];
4784765384cSSven Schnelle
4794765384cSSven Schnelle for (y = starty; y < starty + height; y++) {
4804765384cSSven Schnelle offset = y * s->width;
4814765384cSSven Schnelle
4824765384cSSven Schnelle for (x = startx; x < startx + width; x++) {
48384a7b774SPhilippe Mathieu-Daudé artist_rop8(s, buf, offset + x, color);
4844765384cSSven Schnelle }
4854765384cSSven Schnelle }
4864765384cSSven Schnelle artist_invalidate_lines(buf, starty, height);
4874765384cSSven Schnelle }
4884765384cSSven Schnelle
draw_line(ARTISTState * s,unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2,bool update_start,int skip_pix,int max_pix)489a501bfc9SHelge Deller static void draw_line(ARTISTState *s,
490a501bfc9SHelge Deller unsigned int x1, unsigned int y1,
491a501bfc9SHelge Deller unsigned int x2, unsigned int y2,
4924765384cSSven Schnelle bool update_start, int skip_pix, int max_pix)
4934765384cSSven Schnelle {
494b87a7355SPhilippe Mathieu-Daudé struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
4950814343cSPhilippe Mathieu-Daudé uint8_t color;
4964765384cSSven Schnelle int dx, dy, t, e, x, y, incy, diago, horiz;
4974765384cSSven Schnelle bool c1;
4984765384cSSven Schnelle
4995646bca3SPhilippe Mathieu-Daudé trace_artist_draw_line(x1, y1, x2, y2);
5004765384cSSven Schnelle
501a501bfc9SHelge Deller if ((x1 >= buf->width && x2 >= buf->width) ||
502a501bfc9SHelge Deller (y1 >= buf->height && y2 >= buf->height)) {
503b87a7355SPhilippe Mathieu-Daudé return;
504b87a7355SPhilippe Mathieu-Daudé }
505b87a7355SPhilippe Mathieu-Daudé
5064765384cSSven Schnelle if (update_start) {
5074765384cSSven Schnelle s->vram_start = (x2 << 16) | y2;
5084765384cSSven Schnelle }
5094765384cSSven Schnelle
5104765384cSSven Schnelle if (x2 > x1) {
5114765384cSSven Schnelle dx = x2 - x1;
5124765384cSSven Schnelle } else {
5134765384cSSven Schnelle dx = x1 - x2;
5144765384cSSven Schnelle }
5154765384cSSven Schnelle if (y2 > y1) {
5164765384cSSven Schnelle dy = y2 - y1;
5174765384cSSven Schnelle } else {
5184765384cSSven Schnelle dy = y1 - y2;
5194765384cSSven Schnelle }
5200814343cSPhilippe Mathieu-Daudé
5210814343cSPhilippe Mathieu-Daudé c1 = false;
5224765384cSSven Schnelle if (dy > dx) {
5234765384cSSven Schnelle t = y2;
5244765384cSSven Schnelle y2 = x2;
5254765384cSSven Schnelle x2 = t;
5264765384cSSven Schnelle
5274765384cSSven Schnelle t = y1;
5284765384cSSven Schnelle y1 = x1;
5294765384cSSven Schnelle x1 = t;
5304765384cSSven Schnelle
5314765384cSSven Schnelle t = dx;
5324765384cSSven Schnelle dx = dy;
5334765384cSSven Schnelle dy = t;
5344765384cSSven Schnelle
5354765384cSSven Schnelle c1 = true;
5364765384cSSven Schnelle }
5374765384cSSven Schnelle
5384765384cSSven Schnelle if (x1 > x2) {
5394765384cSSven Schnelle t = y2;
5404765384cSSven Schnelle y2 = y1;
5414765384cSSven Schnelle y1 = t;
5424765384cSSven Schnelle
5434765384cSSven Schnelle t = x1;
5444765384cSSven Schnelle x1 = x2;
5454765384cSSven Schnelle x2 = t;
5464765384cSSven Schnelle }
5474765384cSSven Schnelle
5484765384cSSven Schnelle horiz = dy << 1;
5494765384cSSven Schnelle diago = (dy - dx) << 1;
5504765384cSSven Schnelle e = (dy << 1) - dx;
5514765384cSSven Schnelle
5524765384cSSven Schnelle if (y1 <= y2) {
5534765384cSSven Schnelle incy = 1;
5544765384cSSven Schnelle } else {
5554765384cSSven Schnelle incy = -1;
5564765384cSSven Schnelle }
5574765384cSSven Schnelle x = x1;
5584765384cSSven Schnelle y = y1;
5590814343cSPhilippe Mathieu-Daudé color = artist_get_color(s);
5604765384cSSven Schnelle
5614765384cSSven Schnelle do {
562a501bfc9SHelge Deller unsigned int ofs;
56384a7b774SPhilippe Mathieu-Daudé
5644765384cSSven Schnelle if (c1) {
56584a7b774SPhilippe Mathieu-Daudé ofs = x * s->width + y;
5664765384cSSven Schnelle } else {
56784a7b774SPhilippe Mathieu-Daudé ofs = y * s->width + x;
5684765384cSSven Schnelle }
5694765384cSSven Schnelle
5704765384cSSven Schnelle if (skip_pix > 0) {
5714765384cSSven Schnelle skip_pix--;
5724765384cSSven Schnelle } else {
57384a7b774SPhilippe Mathieu-Daudé artist_rop8(s, buf, ofs, color);
5744765384cSSven Schnelle }
5754765384cSSven Schnelle
5764765384cSSven Schnelle if (e > 0) {
5774765384cSSven Schnelle y += incy;
5784765384cSSven Schnelle e += diago;
5794765384cSSven Schnelle } else {
5804765384cSSven Schnelle e += horiz;
5814765384cSSven Schnelle }
5824765384cSSven Schnelle x++;
5834765384cSSven Schnelle } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
584d449eee3SSven Schnelle
5855d61789eSMark Cave-Ayland if (c1) {
586d449eee3SSven Schnelle artist_invalidate_lines(buf, x1, x2 - x1);
5875d61789eSMark Cave-Ayland } else {
588d449eee3SSven Schnelle artist_invalidate_lines(buf, y1 > y2 ? y2 : y1, x2 - x1);
5894765384cSSven Schnelle }
5905d61789eSMark Cave-Ayland }
5914765384cSSven Schnelle
draw_line_pattern_start(ARTISTState * s)5924765384cSSven Schnelle static void draw_line_pattern_start(ARTISTState *s)
5934765384cSSven Schnelle {
5944765384cSSven Schnelle int startx = artist_get_x(s->vram_start);
5954765384cSSven Schnelle int starty = artist_get_y(s->vram_start);
5964765384cSSven Schnelle int endx = artist_get_x(s->blockmove_size);
5974765384cSSven Schnelle int endy = artist_get_y(s->blockmove_size);
5984765384cSSven Schnelle int pstart = s->line_pattern_start >> 16;
5994765384cSSven Schnelle
6004765384cSSven Schnelle draw_line(s, startx, starty, endx, endy, false, -1, pstart);
6014765384cSSven Schnelle s->line_pattern_skip = pstart;
6024765384cSSven Schnelle }
6034765384cSSven Schnelle
draw_line_pattern_next(ARTISTState * s)6044765384cSSven Schnelle static void draw_line_pattern_next(ARTISTState *s)
6054765384cSSven Schnelle {
6064765384cSSven Schnelle int startx = artist_get_x(s->vram_start);
6074765384cSSven Schnelle int starty = artist_get_y(s->vram_start);
6084765384cSSven Schnelle int endx = artist_get_x(s->blockmove_size);
6094765384cSSven Schnelle int endy = artist_get_y(s->blockmove_size);
6104765384cSSven Schnelle int line_xy = s->line_xy >> 16;
6114765384cSSven Schnelle
6124765384cSSven Schnelle draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip,
6134765384cSSven Schnelle s->line_pattern_skip + line_xy);
6144765384cSSven Schnelle s->line_pattern_skip += line_xy;
6154765384cSSven Schnelle s->image_bitmap_op ^= 2;
6164765384cSSven Schnelle }
6174765384cSSven Schnelle
draw_line_size(ARTISTState * s,bool update_start)6184765384cSSven Schnelle static void draw_line_size(ARTISTState *s, bool update_start)
6194765384cSSven Schnelle {
6204765384cSSven Schnelle int startx = artist_get_x(s->vram_start);
6214765384cSSven Schnelle int starty = artist_get_y(s->vram_start);
6224765384cSSven Schnelle int endx = artist_get_x(s->line_size);
6234765384cSSven Schnelle int endy = artist_get_y(s->line_size);
6244765384cSSven Schnelle
6254765384cSSven Schnelle draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
6264765384cSSven Schnelle }
6274765384cSSven Schnelle
draw_line_xy(ARTISTState * s,bool update_start)6284765384cSSven Schnelle static void draw_line_xy(ARTISTState *s, bool update_start)
6294765384cSSven Schnelle {
6304765384cSSven Schnelle int startx = artist_get_x(s->vram_start);
6314765384cSSven Schnelle int starty = artist_get_y(s->vram_start);
6324765384cSSven Schnelle int sizex = artist_get_x(s->blockmove_size);
6334765384cSSven Schnelle int sizey = artist_get_y(s->blockmove_size);
6344765384cSSven Schnelle int linexy = s->line_xy >> 16;
6354765384cSSven Schnelle int endx, endy;
6364765384cSSven Schnelle
6374765384cSSven Schnelle endx = startx;
6384765384cSSven Schnelle endy = starty;
6394765384cSSven Schnelle
6404765384cSSven Schnelle if (sizex > 0) {
6414765384cSSven Schnelle endx = startx + linexy;
6424765384cSSven Schnelle }
6434765384cSSven Schnelle
6444765384cSSven Schnelle if (sizex < 0) {
6454765384cSSven Schnelle endx = startx;
6464765384cSSven Schnelle startx -= linexy;
6474765384cSSven Schnelle }
6484765384cSSven Schnelle
6494765384cSSven Schnelle if (sizey > 0) {
6504765384cSSven Schnelle endy = starty + linexy;
6514765384cSSven Schnelle }
6524765384cSSven Schnelle
6534765384cSSven Schnelle if (sizey < 0) {
6544765384cSSven Schnelle endy = starty;
6554765384cSSven Schnelle starty -= linexy;
6564765384cSSven Schnelle }
6574765384cSSven Schnelle
6584765384cSSven Schnelle if (startx < 0) {
6594765384cSSven Schnelle startx = 0;
6604765384cSSven Schnelle }
6614765384cSSven Schnelle
6624765384cSSven Schnelle if (endx < 0) {
6634765384cSSven Schnelle endx = 0;
6644765384cSSven Schnelle }
6654765384cSSven Schnelle
6664765384cSSven Schnelle if (starty < 0) {
6674765384cSSven Schnelle starty = 0;
6684765384cSSven Schnelle }
6694765384cSSven Schnelle
6704765384cSSven Schnelle if (endy < 0) {
6714765384cSSven Schnelle endy = 0;
6724765384cSSven Schnelle }
6734765384cSSven Schnelle
6744765384cSSven Schnelle draw_line(s, startx, starty, endx, endy, false, -1, -1);
6754765384cSSven Schnelle }
6764765384cSSven Schnelle
draw_line_end(ARTISTState * s,bool update_start)6774765384cSSven Schnelle static void draw_line_end(ARTISTState *s, bool update_start)
6784765384cSSven Schnelle {
6794765384cSSven Schnelle int startx = artist_get_x(s->vram_start);
6804765384cSSven Schnelle int starty = artist_get_y(s->vram_start);
6814765384cSSven Schnelle int endx = artist_get_x(s->line_end);
6824765384cSSven Schnelle int endy = artist_get_y(s->line_end);
6834765384cSSven Schnelle
6844765384cSSven Schnelle draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
6854765384cSSven Schnelle }
6864765384cSSven Schnelle
font_write16(ARTISTState * s,uint16_t val)6874765384cSSven Schnelle static void font_write16(ARTISTState *s, uint16_t val)
6884765384cSSven Schnelle {
6894765384cSSven Schnelle struct vram_buffer *buf;
6904765384cSSven Schnelle uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color;
6914765384cSSven Schnelle uint16_t mask;
6924765384cSSven Schnelle int i;
6934765384cSSven Schnelle
694a501bfc9SHelge Deller unsigned int startx = artist_get_x(s->vram_start);
695a501bfc9SHelge Deller unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y;
696a501bfc9SHelge Deller unsigned int offset = starty * s->width + startx;
6974765384cSSven Schnelle
6984765384cSSven Schnelle buf = &s->vram_buffer[ARTIST_BUFFER_AP];
6994765384cSSven Schnelle
700a501bfc9SHelge Deller if (startx >= buf->width || starty >= buf->height ||
701a501bfc9SHelge Deller offset + 16 >= buf->size) {
7024765384cSSven Schnelle return;
7034765384cSSven Schnelle }
7044765384cSSven Schnelle
7054765384cSSven Schnelle for (i = 0; i < 16; i++) {
7064765384cSSven Schnelle mask = 1 << (15 - i);
7074765384cSSven Schnelle if (val & mask) {
70884a7b774SPhilippe Mathieu-Daudé artist_rop8(s, buf, offset + i, color);
7094765384cSSven Schnelle } else {
7104765384cSSven Schnelle if (!(s->image_bitmap_op & 0x20000000)) {
71184a7b774SPhilippe Mathieu-Daudé artist_rop8(s, buf, offset + i, s->bg_color);
7124765384cSSven Schnelle }
7134765384cSSven Schnelle }
7144765384cSSven Schnelle }
7154765384cSSven Schnelle artist_invalidate_lines(buf, starty, 1);
7164765384cSSven Schnelle }
7174765384cSSven Schnelle
font_write(ARTISTState * s,uint32_t val)7184765384cSSven Schnelle static void font_write(ARTISTState *s, uint32_t val)
7194765384cSSven Schnelle {
7204765384cSSven Schnelle font_write16(s, val >> 16);
7214765384cSSven Schnelle if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
7224765384cSSven Schnelle s->vram_start += (s->blockmove_size & 0xffff0000);
7234765384cSSven Schnelle return;
7244765384cSSven Schnelle }
7254765384cSSven Schnelle
7264765384cSSven Schnelle font_write16(s, val & 0xffff);
7274765384cSSven Schnelle if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
7284765384cSSven Schnelle s->vram_start += (s->blockmove_size & 0xffff0000);
7294765384cSSven Schnelle return;
7304765384cSSven Schnelle }
7314765384cSSven Schnelle }
7324765384cSSven Schnelle
combine_write_reg(hwaddr addr,uint64_t val,int size,void * out)7334765384cSSven Schnelle static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
7344765384cSSven Schnelle {
7354765384cSSven Schnelle /*
7364765384cSSven Schnelle * FIXME: is there a qemu helper for this?
7374765384cSSven Schnelle */
7384765384cSSven Schnelle
739e03b5686SMarc-André Lureau #if !HOST_BIG_ENDIAN
7404765384cSSven Schnelle addr ^= 3;
7414765384cSSven Schnelle #endif
7424765384cSSven Schnelle
7434765384cSSven Schnelle switch (size) {
7444765384cSSven Schnelle case 1:
7454765384cSSven Schnelle *(uint8_t *)(out + (addr & 3)) = val;
7464765384cSSven Schnelle break;
7474765384cSSven Schnelle
7484765384cSSven Schnelle case 2:
7494765384cSSven Schnelle *(uint16_t *)(out + (addr & 2)) = val;
7504765384cSSven Schnelle break;
7514765384cSSven Schnelle
7524765384cSSven Schnelle case 4:
7534765384cSSven Schnelle *(uint32_t *)out = val;
7544765384cSSven Schnelle break;
7554765384cSSven Schnelle
7564765384cSSven Schnelle default:
7574765384cSSven Schnelle qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size);
7584765384cSSven Schnelle }
7594765384cSSven Schnelle }
7604765384cSSven Schnelle
artist_vram_write4(ARTISTState * s,struct vram_buffer * buf,uint32_t offset,uint32_t data)7613b21d998SSven Schnelle static void artist_vram_write4(ARTISTState *s, struct vram_buffer *buf,
7623b21d998SSven Schnelle uint32_t offset, uint32_t data)
7633b21d998SSven Schnelle {
7643b21d998SSven Schnelle int i;
7653b21d998SSven Schnelle int mask = s->vram_bitmask >> 28;
7663b21d998SSven Schnelle
7673b21d998SSven Schnelle for (i = 0; i < 4; i++) {
7683b21d998SSven Schnelle if (!(s->image_bitmap_op & 0x20000000) || (mask & 8)) {
7693b21d998SSven Schnelle artist_rop8(s, buf, offset + i, data >> 24);
7703b21d998SSven Schnelle data <<= 8;
7713b21d998SSven Schnelle mask <<= 1;
7723b21d998SSven Schnelle }
7733b21d998SSven Schnelle }
7743b21d998SSven Schnelle memory_region_set_dirty(&buf->mr, offset, 3);
7753b21d998SSven Schnelle }
7763b21d998SSven Schnelle
artist_vram_write32(ARTISTState * s,struct vram_buffer * buf,uint32_t offset,int size,uint32_t data,int fg,int bg)7773b21d998SSven Schnelle static void artist_vram_write32(ARTISTState *s, struct vram_buffer *buf,
7783b21d998SSven Schnelle uint32_t offset, int size, uint32_t data,
7793b21d998SSven Schnelle int fg, int bg)
7803b21d998SSven Schnelle {
7813b21d998SSven Schnelle uint32_t mask, vram_bitmask = s->vram_bitmask >> ((4 - size) * 8);
7823b21d998SSven Schnelle int i, pix_count = size * 8;
7833b21d998SSven Schnelle
7843b21d998SSven Schnelle for (i = 0; i < pix_count && offset + i < buf->size; i++) {
7853b21d998SSven Schnelle mask = 1 << (pix_count - 1 - i);
7863b21d998SSven Schnelle
7873b21d998SSven Schnelle if (!(s->image_bitmap_op & 0x20000000) || (vram_bitmask & mask)) {
7883b21d998SSven Schnelle if (data & mask) {
7893b21d998SSven Schnelle artist_rop8(s, buf, offset + i, fg);
7903b21d998SSven Schnelle } else {
7913b21d998SSven Schnelle if (!(s->image_bitmap_op & 0x10000002)) {
7923b21d998SSven Schnelle artist_rop8(s, buf, offset + i, bg);
7933b21d998SSven Schnelle }
7943b21d998SSven Schnelle }
7953b21d998SSven Schnelle }
7963b21d998SSven Schnelle }
7973b21d998SSven Schnelle memory_region_set_dirty(&buf->mr, offset, pix_count);
7983b21d998SSven Schnelle }
7993b21d998SSven Schnelle
get_vram_offset(ARTISTState * s,struct vram_buffer * buf,int pos,int posy)8003b21d998SSven Schnelle static int get_vram_offset(ARTISTState *s, struct vram_buffer *buf,
8013b21d998SSven Schnelle int pos, int posy)
8023b21d998SSven Schnelle {
8033b21d998SSven Schnelle unsigned int posx, width;
8043b21d998SSven Schnelle
8053b21d998SSven Schnelle width = buf->width;
8063b21d998SSven Schnelle posx = ADDR_TO_X(pos);
8073b21d998SSven Schnelle posy += ADDR_TO_Y(pos);
8083b21d998SSven Schnelle return posy * width + posx;
8093b21d998SSven Schnelle }
8103b21d998SSven Schnelle
vram_bit_write(ARTISTState * s,uint32_t pos,int posy,uint32_t data,int size)8113b21d998SSven Schnelle static int vram_bit_write(ARTISTState *s, uint32_t pos, int posy,
8123b21d998SSven Schnelle uint32_t data, int size)
8133b21d998SSven Schnelle {
8143b21d998SSven Schnelle struct vram_buffer *buf = vram_write_buffer(s);
8153b21d998SSven Schnelle
8163b21d998SSven Schnelle switch (s->dst_bm_access >> 16) {
8173b21d998SSven Schnelle case 0x3ba0:
8183b21d998SSven Schnelle case 0xbbe0:
8193b21d998SSven Schnelle artist_vram_write4(s, buf, pos, bswap32(data));
8203b21d998SSven Schnelle pos += 4;
8213b21d998SSven Schnelle break;
8223b21d998SSven Schnelle
8233b21d998SSven Schnelle case 0x1360: /* linux */
8243b21d998SSven Schnelle artist_vram_write4(s, buf, get_vram_offset(s, buf, pos, posy), data);
8253b21d998SSven Schnelle pos += 4;
8263b21d998SSven Schnelle break;
8273b21d998SSven Schnelle
8283b21d998SSven Schnelle case 0x13a0:
8293b21d998SSven Schnelle artist_vram_write4(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
8303b21d998SSven Schnelle data);
8313b21d998SSven Schnelle pos += 16;
8323b21d998SSven Schnelle break;
8333b21d998SSven Schnelle
8343b21d998SSven Schnelle case 0x2ea0:
8353b21d998SSven Schnelle artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
8363b21d998SSven Schnelle size, data, s->fg_color, s->bg_color);
8373b21d998SSven Schnelle pos += 4;
8383b21d998SSven Schnelle break;
8393b21d998SSven Schnelle
8403b21d998SSven Schnelle case 0x28a0:
8413b21d998SSven Schnelle artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
8423b21d998SSven Schnelle size, data, 1, 0);
8433b21d998SSven Schnelle pos += 4;
8443b21d998SSven Schnelle break;
8453b21d998SSven Schnelle
8463b21d998SSven Schnelle default:
8473b21d998SSven Schnelle qemu_log_mask(LOG_UNIMP, "%s: unknown dst bm access %08x\n",
8483b21d998SSven Schnelle __func__, s->dst_bm_access);
8493b21d998SSven Schnelle break;
8503b21d998SSven Schnelle }
8513b21d998SSven Schnelle
8523b21d998SSven Schnelle if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 ||
8533b21d998SSven Schnelle vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) {
8543b21d998SSven Schnelle artist_invalidate_cursor(s);
8553b21d998SSven Schnelle }
8563b21d998SSven Schnelle return pos;
8573b21d998SSven Schnelle }
8583b21d998SSven Schnelle
artist_vram_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)8593b21d998SSven Schnelle static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
8603b21d998SSven Schnelle unsigned size)
8613b21d998SSven Schnelle {
8623b21d998SSven Schnelle ARTISTState *s = opaque;
8635d61789eSMark Cave-Ayland
8643b21d998SSven Schnelle s->vram_char_y = 0;
8653b21d998SSven Schnelle trace_artist_vram_write(size, addr, val);
8663b21d998SSven Schnelle vram_bit_write(opaque, addr, 0, val, size);
8673b21d998SSven Schnelle }
8683b21d998SSven Schnelle
artist_vram_read(void * opaque,hwaddr addr,unsigned size)8693b21d998SSven Schnelle static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
8703b21d998SSven Schnelle {
8713b21d998SSven Schnelle ARTISTState *s = opaque;
8723b21d998SSven Schnelle struct vram_buffer *buf;
8733b21d998SSven Schnelle unsigned int offset;
8743b21d998SSven Schnelle uint64_t val;
8753b21d998SSven Schnelle
8763b21d998SSven Schnelle buf = vram_read_buffer(s);
8773b21d998SSven Schnelle if (!buf->size) {
8783b21d998SSven Schnelle return 0;
8793b21d998SSven Schnelle }
8803b21d998SSven Schnelle
8813b21d998SSven Schnelle offset = get_vram_offset(s, buf, addr >> 2, 0);
8823b21d998SSven Schnelle
8833b21d998SSven Schnelle if (offset > buf->size) {
8843b21d998SSven Schnelle return 0;
8853b21d998SSven Schnelle }
8863b21d998SSven Schnelle
8873b21d998SSven Schnelle switch (s->src_bm_access >> 16) {
8883b21d998SSven Schnelle case 0x3ba0:
8893b21d998SSven Schnelle val = *(uint32_t *)(buf->data + offset);
8903b21d998SSven Schnelle break;
8913b21d998SSven Schnelle
8923b21d998SSven Schnelle case 0x13a0:
8933b21d998SSven Schnelle case 0x2ea0:
8943b21d998SSven Schnelle val = bswap32(*(uint32_t *)(buf->data + offset));
8953b21d998SSven Schnelle break;
8963b21d998SSven Schnelle
8973b21d998SSven Schnelle default:
8983b21d998SSven Schnelle qemu_log_mask(LOG_UNIMP, "%s: unknown src bm access %08x\n",
8993b21d998SSven Schnelle __func__, s->dst_bm_access);
9003b21d998SSven Schnelle val = -1ULL;
9013b21d998SSven Schnelle break;
9023b21d998SSven Schnelle }
9033b21d998SSven Schnelle trace_artist_vram_read(size, addr, val);
9043b21d998SSven Schnelle return val;
9053b21d998SSven Schnelle }
9063b21d998SSven Schnelle
artist_reg_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)9074765384cSSven Schnelle static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
9084765384cSSven Schnelle unsigned size)
9094765384cSSven Schnelle {
9104765384cSSven Schnelle ARTISTState *s = opaque;
9114765384cSSven Schnelle int width, height;
912caca6e61SHelge Deller uint64_t oldval;
9134765384cSSven Schnelle
9144765384cSSven Schnelle trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val);
9154765384cSSven Schnelle
9164765384cSSven Schnelle switch (addr & ~3ULL) {
9174765384cSSven Schnelle case 0x100080:
9184765384cSSven Schnelle combine_write_reg(addr, val, size, &s->reg_100080);
9194765384cSSven Schnelle break;
9204765384cSSven Schnelle
9214765384cSSven Schnelle case FG_COLOR:
9224765384cSSven Schnelle combine_write_reg(addr, val, size, &s->fg_color);
9234765384cSSven Schnelle break;
9244765384cSSven Schnelle
9254765384cSSven Schnelle case BG_COLOR:
9264765384cSSven Schnelle combine_write_reg(addr, val, size, &s->bg_color);
9274765384cSSven Schnelle break;
9284765384cSSven Schnelle
9294765384cSSven Schnelle case VRAM_BITMASK:
9304765384cSSven Schnelle combine_write_reg(addr, val, size, &s->vram_bitmask);
9314765384cSSven Schnelle break;
9324765384cSSven Schnelle
9334765384cSSven Schnelle case VRAM_WRITE_INCR_Y:
9343b21d998SSven Schnelle vram_bit_write(s, s->vram_pos, s->vram_char_y++, val, size);
9354765384cSSven Schnelle break;
9364765384cSSven Schnelle
9374765384cSSven Schnelle case VRAM_WRITE_INCR_X:
9384765384cSSven Schnelle case VRAM_WRITE_INCR_X2:
9393b21d998SSven Schnelle s->vram_pos = vram_bit_write(s, s->vram_pos, s->vram_char_y, val, size);
9404765384cSSven Schnelle break;
9414765384cSSven Schnelle
9424765384cSSven Schnelle case VRAM_IDX:
9434765384cSSven Schnelle combine_write_reg(addr, val, size, &s->vram_pos);
9444765384cSSven Schnelle s->vram_char_y = 0;
9454765384cSSven Schnelle s->draw_line_pattern = 0;
9464765384cSSven Schnelle break;
9474765384cSSven Schnelle
9484765384cSSven Schnelle case VRAM_START:
9494765384cSSven Schnelle combine_write_reg(addr, val, size, &s->vram_start);
9504765384cSSven Schnelle s->draw_line_pattern = 0;
9514765384cSSven Schnelle break;
9524765384cSSven Schnelle
9534765384cSSven Schnelle case VRAM_START_TRIGGER:
9544765384cSSven Schnelle combine_write_reg(addr, val, size, &s->vram_start);
9554765384cSSven Schnelle fill_window(s, artist_get_x(s->vram_start),
9564765384cSSven Schnelle artist_get_y(s->vram_start),
9574765384cSSven Schnelle artist_get_x(s->blockmove_size),
9584765384cSSven Schnelle artist_get_y(s->blockmove_size));
9594765384cSSven Schnelle break;
9604765384cSSven Schnelle
9614765384cSSven Schnelle case VRAM_SIZE_TRIGGER:
9624765384cSSven Schnelle combine_write_reg(addr, val, size, &s->vram_size);
9634765384cSSven Schnelle
9644765384cSSven Schnelle if (size == 2 && !(addr & 2)) {
9654765384cSSven Schnelle height = artist_get_y(s->blockmove_size);
9664765384cSSven Schnelle } else {
9674765384cSSven Schnelle height = artist_get_y(s->vram_size);
9684765384cSSven Schnelle }
9694765384cSSven Schnelle
9704765384cSSven Schnelle if (size == 2 && (addr & 2)) {
9714765384cSSven Schnelle width = artist_get_x(s->blockmove_size);
9724765384cSSven Schnelle } else {
9734765384cSSven Schnelle width = artist_get_x(s->vram_size);
9744765384cSSven Schnelle }
9754765384cSSven Schnelle
9764765384cSSven Schnelle fill_window(s, artist_get_x(s->vram_start),
9774765384cSSven Schnelle artist_get_y(s->vram_start),
9784765384cSSven Schnelle width, height);
9794765384cSSven Schnelle break;
9804765384cSSven Schnelle
9814765384cSSven Schnelle case LINE_XY:
9824765384cSSven Schnelle combine_write_reg(addr, val, size, &s->line_xy);
9834765384cSSven Schnelle if (s->draw_line_pattern) {
9844765384cSSven Schnelle draw_line_pattern_next(s);
9854765384cSSven Schnelle } else {
9864765384cSSven Schnelle draw_line_xy(s, true);
9874765384cSSven Schnelle }
9884765384cSSven Schnelle break;
9894765384cSSven Schnelle
9904765384cSSven Schnelle case PATTERN_LINE_START:
9914765384cSSven Schnelle combine_write_reg(addr, val, size, &s->line_pattern_start);
9924765384cSSven Schnelle s->draw_line_pattern = 1;
9934765384cSSven Schnelle draw_line_pattern_start(s);
9944765384cSSven Schnelle break;
9954765384cSSven Schnelle
9964765384cSSven Schnelle case LINE_SIZE:
9974765384cSSven Schnelle combine_write_reg(addr, val, size, &s->line_size);
9984765384cSSven Schnelle draw_line_size(s, true);
9994765384cSSven Schnelle break;
10004765384cSSven Schnelle
10014765384cSSven Schnelle case LINE_END:
10024765384cSSven Schnelle combine_write_reg(addr, val, size, &s->line_end);
10034765384cSSven Schnelle draw_line_end(s, true);
10044765384cSSven Schnelle break;
10054765384cSSven Schnelle
10064765384cSSven Schnelle case BLOCK_MOVE_SIZE:
10074765384cSSven Schnelle combine_write_reg(addr, val, size, &s->blockmove_size);
10084765384cSSven Schnelle break;
10094765384cSSven Schnelle
10104765384cSSven Schnelle case BLOCK_MOVE_SOURCE:
10114765384cSSven Schnelle combine_write_reg(addr, val, size, &s->blockmove_source);
10124765384cSSven Schnelle break;
10134765384cSSven Schnelle
10144765384cSSven Schnelle case BLOCK_MOVE_DEST_TRIGGER:
10154765384cSSven Schnelle combine_write_reg(addr, val, size, &s->blockmove_dest);
10164765384cSSven Schnelle
10174765384cSSven Schnelle block_move(s, artist_get_x(s->blockmove_source),
10184765384cSSven Schnelle artist_get_y(s->blockmove_source),
10194765384cSSven Schnelle artist_get_x(s->blockmove_dest),
10204765384cSSven Schnelle artist_get_y(s->blockmove_dest),
10214765384cSSven Schnelle artist_get_x(s->blockmove_size),
10224765384cSSven Schnelle artist_get_y(s->blockmove_size));
10234765384cSSven Schnelle break;
10244765384cSSven Schnelle
10254765384cSSven Schnelle case BLOCK_MOVE_SIZE_TRIGGER:
10264765384cSSven Schnelle combine_write_reg(addr, val, size, &s->blockmove_size);
10274765384cSSven Schnelle
10284765384cSSven Schnelle block_move(s,
10294765384cSSven Schnelle artist_get_x(s->blockmove_source),
10304765384cSSven Schnelle artist_get_y(s->blockmove_source),
10314765384cSSven Schnelle artist_get_x(s->vram_start),
10324765384cSSven Schnelle artist_get_y(s->vram_start),
10334765384cSSven Schnelle artist_get_x(s->blockmove_size),
10344765384cSSven Schnelle artist_get_y(s->blockmove_size));
10354765384cSSven Schnelle break;
10364765384cSSven Schnelle
10374765384cSSven Schnelle case PLANE_MASK:
10384765384cSSven Schnelle combine_write_reg(addr, val, size, &s->plane_mask);
10394765384cSSven Schnelle break;
10404765384cSSven Schnelle
10413b21d998SSven Schnelle case DST_SRC_BM_ACCESS:
10423b21d998SSven Schnelle combine_write_reg(addr, val, size, &s->dst_bm_access);
10433b21d998SSven Schnelle combine_write_reg(addr, val, size, &s->src_bm_access);
10444765384cSSven Schnelle break;
10454765384cSSven Schnelle
10464765384cSSven Schnelle case DST_BM_ACCESS:
10474765384cSSven Schnelle combine_write_reg(addr, val, size, &s->dst_bm_access);
10484765384cSSven Schnelle break;
10494765384cSSven Schnelle
10504765384cSSven Schnelle case SRC_BM_ACCESS:
10514765384cSSven Schnelle combine_write_reg(addr, val, size, &s->src_bm_access);
10524765384cSSven Schnelle break;
10534765384cSSven Schnelle
10544765384cSSven Schnelle case CONTROL_PLANE:
10554765384cSSven Schnelle combine_write_reg(addr, val, size, &s->control_plane);
10564765384cSSven Schnelle break;
10574765384cSSven Schnelle
10584765384cSSven Schnelle case TRANSFER_DATA:
10594765384cSSven Schnelle combine_write_reg(addr, val, size, &s->transfer_data);
10604765384cSSven Schnelle break;
10614765384cSSven Schnelle
1062e9683fbcSHelge Deller case HORIZ_BACKPORCH:
10639ef2c6b4SHelge Deller /* overwrite HP-UX settings to fix X cursor position. */
10649ef2c6b4SHelge Deller val = (NGLE_MAX_SPRITE_SIZE << 16) + (NGLE_MAX_SPRITE_SIZE << 8);
1065e9683fbcSHelge Deller combine_write_reg(addr, val, size, &s->horiz_backporch);
10664765384cSSven Schnelle break;
10674765384cSSven Schnelle
1068e9683fbcSHelge Deller case ACTIVE_LINES_LOW:
1069e9683fbcSHelge Deller combine_write_reg(addr, val, size, &s->active_lines_low);
10704765384cSSven Schnelle break;
10714765384cSSven Schnelle
1072e9683fbcSHelge Deller case MISC_VIDEO:
1073caca6e61SHelge Deller oldval = s->misc_video;
1074e9683fbcSHelge Deller combine_write_reg(addr, val, size, &s->misc_video);
1075caca6e61SHelge Deller /* Invalidate and hide screen if graphics signal is turned off. */
1076caca6e61SHelge Deller if (((oldval & 0x0A000000) == 0x0A000000) &&
1077caca6e61SHelge Deller ((val & 0x0A000000) != 0x0A000000)) {
1078caca6e61SHelge Deller artist_invalidate(s);
1079caca6e61SHelge Deller }
1080caca6e61SHelge Deller /* Invalidate and redraw screen if graphics signal is turned back on. */
1081caca6e61SHelge Deller if (((oldval & 0x0A000000) != 0x0A000000) &&
1082caca6e61SHelge Deller ((val & 0x0A000000) == 0x0A000000)) {
1083caca6e61SHelge Deller artist_invalidate(s);
1084caca6e61SHelge Deller }
1085e9683fbcSHelge Deller break;
1086e9683fbcSHelge Deller
1087e9683fbcSHelge Deller case MISC_CTRL:
1088e9683fbcSHelge Deller combine_write_reg(addr, val, size, &s->misc_ctrl);
10894765384cSSven Schnelle break;
10904765384cSSven Schnelle
10914765384cSSven Schnelle case CURSOR_POS:
10924765384cSSven Schnelle artist_invalidate_cursor(s);
10934765384cSSven Schnelle combine_write_reg(addr, val, size, &s->cursor_pos);
10944765384cSSven Schnelle artist_invalidate_cursor(s);
10954765384cSSven Schnelle break;
10964765384cSSven Schnelle
10974765384cSSven Schnelle case CURSOR_CTRL:
10983615cea4SHelge Deller combine_write_reg(addr, val, size, &s->cursor_cntrl);
10994765384cSSven Schnelle break;
11004765384cSSven Schnelle
11014765384cSSven Schnelle case IMAGE_BITMAP_OP:
11024765384cSSven Schnelle combine_write_reg(addr, val, size, &s->image_bitmap_op);
11034765384cSSven Schnelle break;
11044765384cSSven Schnelle
11054765384cSSven Schnelle case FONT_WRITE_INCR_Y:
11064765384cSSven Schnelle combine_write_reg(addr, val, size, &s->font_write1);
11074765384cSSven Schnelle font_write(s, s->font_write1);
11084765384cSSven Schnelle break;
11094765384cSSven Schnelle
11104765384cSSven Schnelle case FONT_WRITE_START:
11114765384cSSven Schnelle combine_write_reg(addr, val, size, &s->font_write2);
11124765384cSSven Schnelle s->font_write_pos_y = 0;
11134765384cSSven Schnelle font_write(s, s->font_write2);
11144765384cSSven Schnelle break;
11154765384cSSven Schnelle
11164765384cSSven Schnelle case 300104:
11174765384cSSven Schnelle break;
11184765384cSSven Schnelle
11194765384cSSven Schnelle default:
11204765384cSSven Schnelle qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx
11214765384cSSven Schnelle " val=%08" PRIx64 " size=%d\n",
11224765384cSSven Schnelle __func__, addr, val, size);
11234765384cSSven Schnelle break;
11244765384cSSven Schnelle }
11254765384cSSven Schnelle }
11264765384cSSven Schnelle
combine_read_reg(hwaddr addr,int size,void * in)11274765384cSSven Schnelle static uint64_t combine_read_reg(hwaddr addr, int size, void *in)
11284765384cSSven Schnelle {
11294765384cSSven Schnelle /*
11304765384cSSven Schnelle * FIXME: is there a qemu helper for this?
11314765384cSSven Schnelle */
11324765384cSSven Schnelle
1133e03b5686SMarc-André Lureau #if !HOST_BIG_ENDIAN
11344765384cSSven Schnelle addr ^= 3;
11354765384cSSven Schnelle #endif
11364765384cSSven Schnelle
11374765384cSSven Schnelle switch (size) {
11384765384cSSven Schnelle case 1:
11394765384cSSven Schnelle return *(uint8_t *)(in + (addr & 3));
11404765384cSSven Schnelle
11414765384cSSven Schnelle case 2:
11424765384cSSven Schnelle return *(uint16_t *)(in + (addr & 2));
11434765384cSSven Schnelle
11444765384cSSven Schnelle case 4:
11454765384cSSven Schnelle return *(uint32_t *)in;
11464765384cSSven Schnelle
11474765384cSSven Schnelle default:
11484765384cSSven Schnelle qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size);
11494765384cSSven Schnelle return 0;
11504765384cSSven Schnelle }
11514765384cSSven Schnelle }
11524765384cSSven Schnelle
artist_reg_read(void * opaque,hwaddr addr,unsigned size)11534765384cSSven Schnelle static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
11544765384cSSven Schnelle {
11554765384cSSven Schnelle ARTISTState *s = opaque;
11564765384cSSven Schnelle uint32_t val = 0;
11574765384cSSven Schnelle
11584765384cSSven Schnelle switch (addr & ~3ULL) {
11594765384cSSven Schnelle /* Unknown status registers */
11604765384cSSven Schnelle case 0:
11614765384cSSven Schnelle break;
11624765384cSSven Schnelle
11634765384cSSven Schnelle case 0x211110:
11644765384cSSven Schnelle val = (s->width << 16) | s->height;
11654765384cSSven Schnelle if (s->depth == 1) {
11664765384cSSven Schnelle val |= 1 << 31;
11674765384cSSven Schnelle }
11684765384cSSven Schnelle break;
11694765384cSSven Schnelle
11704765384cSSven Schnelle case 0x100000:
11714765384cSSven Schnelle case 0x300000:
11724765384cSSven Schnelle case 0x300004:
11734765384cSSven Schnelle case 0x380000:
11744765384cSSven Schnelle break;
11754765384cSSven Schnelle
1176e9683fbcSHelge Deller case FIFO1:
1177e9683fbcSHelge Deller case FIFO2:
11784765384cSSven Schnelle /*
11794765384cSSven Schnelle * FIFO ready flag. we're not emulating the FIFOs
11804765384cSSven Schnelle * so we're always ready
11814765384cSSven Schnelle */
11824765384cSSven Schnelle val = 0x10;
11834765384cSSven Schnelle break;
11844765384cSSven Schnelle
1185e9683fbcSHelge Deller case HORIZ_BACKPORCH:
1186e9683fbcSHelge Deller val = s->horiz_backporch;
11874765384cSSven Schnelle break;
11884765384cSSven Schnelle
1189e9683fbcSHelge Deller case ACTIVE_LINES_LOW:
1190e9683fbcSHelge Deller val = s->active_lines_low;
1191e9683fbcSHelge Deller /* activeLinesLo for cursor is in reg20.b.b0 */
1192482afe02SHelge Deller val &= ~(0xff << 24);
1193482afe02SHelge Deller val |= (s->height & 0xff) << 24;
11944765384cSSven Schnelle break;
11954765384cSSven Schnelle
1196e9683fbcSHelge Deller case MISC_VIDEO:
1197e9683fbcSHelge Deller /* emulate V-blank */
1198482afe02SHelge Deller s->misc_video ^= 0x00040000;
1199e9683fbcSHelge Deller /* activeLinesHi for cursor is in reg21.b.b2 */
1200482afe02SHelge Deller val = s->misc_video;
1201482afe02SHelge Deller val &= ~0xff00UL;
1202482afe02SHelge Deller val |= (s->height & 0xff00);
1203e9683fbcSHelge Deller break;
1204e9683fbcSHelge Deller
1205e9683fbcSHelge Deller case MISC_CTRL:
1206e9683fbcSHelge Deller val = s->misc_ctrl;
12074765384cSSven Schnelle break;
12084765384cSSven Schnelle
12094765384cSSven Schnelle case 0x30023c:
12104765384cSSven Schnelle val = 0xac4ffdac;
12114765384cSSven Schnelle break;
12124765384cSSven Schnelle
12134765384cSSven Schnelle case 0x380004:
12144765384cSSven Schnelle /* 0x02000000 Buserror */
12154765384cSSven Schnelle val = 0x6dc20006;
12164765384cSSven Schnelle break;
12174765384cSSven Schnelle
12184765384cSSven Schnelle default:
12194765384cSSven Schnelle qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx
12204765384cSSven Schnelle " size %d\n", __func__, addr, size);
12214765384cSSven Schnelle break;
12224765384cSSven Schnelle }
12234765384cSSven Schnelle val = combine_read_reg(addr, size, &val);
12244765384cSSven Schnelle trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val);
12254765384cSSven Schnelle return val;
12264765384cSSven Schnelle }
12274765384cSSven Schnelle
12284765384cSSven Schnelle static const MemoryRegionOps artist_reg_ops = {
12294765384cSSven Schnelle .read = artist_reg_read,
12304765384cSSven Schnelle .write = artist_reg_write,
12314765384cSSven Schnelle .endianness = DEVICE_NATIVE_ENDIAN,
1232e0cf02ceSHelge Deller .impl.min_access_size = 1,
1233e0cf02ceSHelge Deller .impl.max_access_size = 4,
12344765384cSSven Schnelle };
12354765384cSSven Schnelle
12364765384cSSven Schnelle static const MemoryRegionOps artist_vram_ops = {
12374765384cSSven Schnelle .read = artist_vram_read,
12384765384cSSven Schnelle .write = artist_vram_write,
12394765384cSSven Schnelle .endianness = DEVICE_NATIVE_ENDIAN,
1240e0cf02ceSHelge Deller .impl.min_access_size = 1,
1241e0cf02ceSHelge Deller .impl.max_access_size = 4,
12424765384cSSven Schnelle };
12434765384cSSven Schnelle
artist_draw_cursor(ARTISTState * s)12444765384cSSven Schnelle static void artist_draw_cursor(ARTISTState *s)
12454765384cSSven Schnelle {
12464765384cSSven Schnelle DisplaySurface *surface = qemu_console_surface(s->con);
12474765384cSSven Schnelle uint32_t *data = (uint32_t *)surface_data(surface);
12484765384cSSven Schnelle struct vram_buffer *cursor0, *cursor1 , *buf;
12494765384cSSven Schnelle int cx, cy, cursor_pos_x, cursor_pos_y;
12504765384cSSven Schnelle
1251a377b574SHelge Deller if (!cursor_visible(s)) {
1252a377b574SHelge Deller return;
1253a377b574SHelge Deller }
1254a377b574SHelge Deller
12554765384cSSven Schnelle cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1];
12564765384cSSven Schnelle cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2];
12574765384cSSven Schnelle buf = &s->vram_buffer[ARTIST_BUFFER_AP];
12584765384cSSven Schnelle
12594765384cSSven Schnelle artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y);
12604765384cSSven Schnelle
12614765384cSSven Schnelle for (cy = 0; cy < s->cursor_height; cy++) {
12624765384cSSven Schnelle
12634765384cSSven Schnelle for (cx = 0; cx < s->cursor_width; cx++) {
12644765384cSSven Schnelle
12654765384cSSven Schnelle if (cursor_pos_y + cy < 0 ||
12664765384cSSven Schnelle cursor_pos_x + cx < 0 ||
12674765384cSSven Schnelle cursor_pos_y + cy > buf->height - 1 ||
12684765384cSSven Schnelle cursor_pos_x + cx > buf->width) {
12694765384cSSven Schnelle continue;
12704765384cSSven Schnelle }
12714765384cSSven Schnelle
12724765384cSSven Schnelle int dstoffset = (cursor_pos_y + cy) * s->width +
12734765384cSSven Schnelle (cursor_pos_x + cx);
12744765384cSSven Schnelle
12754765384cSSven Schnelle if (cursor0->data[cy * cursor0->width + cx]) {
12764765384cSSven Schnelle data[dstoffset] = 0;
12774765384cSSven Schnelle } else {
12784765384cSSven Schnelle if (cursor1->data[cy * cursor1->width + cx]) {
12794765384cSSven Schnelle data[dstoffset] = 0xffffff;
12804765384cSSven Schnelle }
12814765384cSSven Schnelle }
12824765384cSSven Schnelle }
12834765384cSSven Schnelle }
12844765384cSSven Schnelle }
12854765384cSSven Schnelle
artist_screen_enabled(ARTISTState * s)1286caca6e61SHelge Deller static bool artist_screen_enabled(ARTISTState *s)
1287caca6e61SHelge Deller {
1288caca6e61SHelge Deller /* We could check for (s->misc_ctrl & 0x00800000) too... */
1289caca6e61SHelge Deller return ((s->misc_video & 0x0A000000) == 0x0A000000);
1290caca6e61SHelge Deller }
1291caca6e61SHelge Deller
artist_draw_line(void * opaque,uint8_t * d,const uint8_t * src,int width,int pitch)12924765384cSSven Schnelle static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
12934765384cSSven Schnelle int width, int pitch)
12944765384cSSven Schnelle {
12954765384cSSven Schnelle ARTISTState *s = ARTIST(opaque);
12964765384cSSven Schnelle uint32_t *cmap, *data = (uint32_t *)d;
12974765384cSSven Schnelle int x;
12984765384cSSven Schnelle
1299caca6e61SHelge Deller if (!artist_screen_enabled(s)) {
1300caca6e61SHelge Deller /* clear screen */
1301caca6e61SHelge Deller memset(data, 0, s->width * sizeof(uint32_t));
1302caca6e61SHelge Deller return;
1303caca6e61SHelge Deller }
1304caca6e61SHelge Deller
13054765384cSSven Schnelle cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400);
13064765384cSSven Schnelle
13074765384cSSven Schnelle for (x = 0; x < s->width; x++) {
13084765384cSSven Schnelle *data++ = cmap[*src++];
13094765384cSSven Schnelle }
13104765384cSSven Schnelle }
13114765384cSSven Schnelle
artist_update_display(void * opaque)13124765384cSSven Schnelle static void artist_update_display(void *opaque)
13134765384cSSven Schnelle {
13144765384cSSven Schnelle ARTISTState *s = opaque;
13154765384cSSven Schnelle DisplaySurface *surface = qemu_console_surface(s->con);
13164765384cSSven Schnelle int first = 0, last;
13174765384cSSven Schnelle
13184765384cSSven Schnelle framebuffer_update_display(surface, &s->fbsection, s->width, s->height,
13194765384cSSven Schnelle s->width, s->width * 4, 0, 0, artist_draw_line,
13204765384cSSven Schnelle s, &first, &last);
13214765384cSSven Schnelle
13224765384cSSven Schnelle artist_draw_cursor(s);
13234765384cSSven Schnelle
13241f110516SMark Cave-Ayland if (first >= 0) {
13251f110516SMark Cave-Ayland dpy_gfx_update(s->con, 0, first, s->width, last - first + 1);
13261f110516SMark Cave-Ayland }
13274765384cSSven Schnelle }
13284765384cSSven Schnelle
artist_invalidate(void * opaque)13294765384cSSven Schnelle static void artist_invalidate(void *opaque)
13304765384cSSven Schnelle {
13314765384cSSven Schnelle ARTISTState *s = ARTIST(opaque);
13324765384cSSven Schnelle struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
13335d61789eSMark Cave-Ayland
13344765384cSSven Schnelle memory_region_set_dirty(&buf->mr, 0, buf->size);
13354765384cSSven Schnelle }
13364765384cSSven Schnelle
13374765384cSSven Schnelle static const GraphicHwOps artist_ops = {
13384765384cSSven Schnelle .invalidate = artist_invalidate,
13394765384cSSven Schnelle .gfx_update = artist_update_display,
13404765384cSSven Schnelle };
13414765384cSSven Schnelle
artist_initfn(Object * obj)13424765384cSSven Schnelle static void artist_initfn(Object *obj)
13434765384cSSven Schnelle {
13444765384cSSven Schnelle SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
13454765384cSSven Schnelle ARTISTState *s = ARTIST(obj);
13464765384cSSven Schnelle
13474765384cSSven Schnelle memory_region_init_io(&s->reg, obj, &artist_reg_ops, s, "artist.reg",
13484765384cSSven Schnelle 4 * MiB);
13494765384cSSven Schnelle memory_region_init_io(&s->vram_mem, obj, &artist_vram_ops, s, "artist.vram",
13504765384cSSven Schnelle 8 * MiB);
13514765384cSSven Schnelle sysbus_init_mmio(sbd, &s->reg);
13524765384cSSven Schnelle sysbus_init_mmio(sbd, &s->vram_mem);
13534765384cSSven Schnelle }
13544765384cSSven Schnelle
artist_create_buffer(ARTISTState * s,const char * name,hwaddr * offset,unsigned int idx,int width,int height)13554765384cSSven Schnelle static void artist_create_buffer(ARTISTState *s, const char *name,
13564765384cSSven Schnelle hwaddr *offset, unsigned int idx,
13574765384cSSven Schnelle int width, int height)
13584765384cSSven Schnelle {
13594765384cSSven Schnelle struct vram_buffer *buf = s->vram_buffer + idx;
13604765384cSSven Schnelle
136139fbaecaSMark Cave-Ayland memory_region_init_ram(&buf->mr, OBJECT(s), name, width * height,
13624765384cSSven Schnelle &error_fatal);
13634765384cSSven Schnelle memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0);
13644765384cSSven Schnelle
13654765384cSSven Schnelle buf->data = memory_region_get_ram_ptr(&buf->mr);
13664765384cSSven Schnelle buf->size = height * width;
13674765384cSSven Schnelle buf->width = width;
13684765384cSSven Schnelle buf->height = height;
13694765384cSSven Schnelle
13704765384cSSven Schnelle *offset += buf->size;
13714765384cSSven Schnelle }
13724765384cSSven Schnelle
artist_realizefn(DeviceState * dev,Error ** errp)13734765384cSSven Schnelle static void artist_realizefn(DeviceState *dev, Error **errp)
13744765384cSSven Schnelle {
13754765384cSSven Schnelle ARTISTState *s = ARTIST(dev);
13764765384cSSven Schnelle struct vram_buffer *buf;
13774765384cSSven Schnelle hwaddr offset = 0;
13784765384cSSven Schnelle
137995aad497SHelge Deller if (s->width > 2048 || s->height > 2048) {
138095aad497SHelge Deller error_report("artist: screen size can not exceed 2048 x 2048 pixel.");
138195aad497SHelge Deller s->width = MIN(s->width, 2048);
138295aad497SHelge Deller s->height = MIN(s->height, 2048);
138395aad497SHelge Deller }
138495aad497SHelge Deller
138595aad497SHelge Deller if (s->width < 640 || s->height < 480) {
138695aad497SHelge Deller error_report("artist: minimum screen size is 640 x 480 pixel.");
138795aad497SHelge Deller s->width = MAX(s->width, 640);
138895aad497SHelge Deller s->height = MAX(s->height, 480);
138995aad497SHelge Deller }
139095aad497SHelge Deller
13914765384cSSven Schnelle memory_region_init(&s->mem_as_root, OBJECT(dev), "artist", ~0ull);
13924765384cSSven Schnelle address_space_init(&s->as, &s->mem_as_root, "artist");
13934765384cSSven Schnelle
13944765384cSSven Schnelle artist_create_buffer(s, "cmap", &offset, ARTIST_BUFFER_CMAP, 2048, 4);
13954765384cSSven Schnelle artist_create_buffer(s, "ap", &offset, ARTIST_BUFFER_AP,
13964765384cSSven Schnelle s->width, s->height);
13974765384cSSven Schnelle artist_create_buffer(s, "cursor1", &offset, ARTIST_BUFFER_CURSOR1, 64, 64);
13984765384cSSven Schnelle artist_create_buffer(s, "cursor2", &offset, ARTIST_BUFFER_CURSOR2, 64, 64);
13994765384cSSven Schnelle artist_create_buffer(s, "attribute", &offset, ARTIST_BUFFER_ATTRIBUTE,
14004765384cSSven Schnelle 64, 64);
14014765384cSSven Schnelle
14024765384cSSven Schnelle buf = &s->vram_buffer[ARTIST_BUFFER_AP];
14034765384cSSven Schnelle framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0,
14044765384cSSven Schnelle buf->width, buf->height);
14054765384cSSven Schnelle /*
14067e50730cSHelge Deller * Artist cursor max size
14074765384cSSven Schnelle */
14087e50730cSHelge Deller s->cursor_height = NGLE_MAX_SPRITE_SIZE;
14097e50730cSHelge Deller s->cursor_width = NGLE_MAX_SPRITE_SIZE;
14104765384cSSven Schnelle
14113b21d998SSven Schnelle /*
14123b21d998SSven Schnelle * These two registers are not initialized by seabios's STI implementation.
14133b21d998SSven Schnelle * Initialize them here to sane values so artist also works with older
14143b21d998SSven Schnelle * (not-fixed) seabios versions.
14153b21d998SSven Schnelle */
14163b21d998SSven Schnelle s->image_bitmap_op = 0x23000300;
14173b21d998SSven Schnelle s->plane_mask = 0xff;
14183b21d998SSven Schnelle
1419caca6e61SHelge Deller /* enable screen */
1420caca6e61SHelge Deller s->misc_video |= 0x0A000000;
1421caca6e61SHelge Deller s->misc_ctrl |= 0x00800000;
1422caca6e61SHelge Deller
14238e5c952bSPhilippe Mathieu-Daudé s->con = graphic_console_init(dev, 0, &artist_ops, s);
14244765384cSSven Schnelle qemu_console_resize(s->con, s->width, s->height);
14254765384cSSven Schnelle }
14264765384cSSven Schnelle
vmstate_artist_post_load(void * opaque,int version_id)14274765384cSSven Schnelle static int vmstate_artist_post_load(void *opaque, int version_id)
14284765384cSSven Schnelle {
14294765384cSSven Schnelle artist_invalidate(opaque);
14304765384cSSven Schnelle return 0;
14314765384cSSven Schnelle }
14324765384cSSven Schnelle
14334765384cSSven Schnelle static const VMStateDescription vmstate_artist = {
14344765384cSSven Schnelle .name = "artist",
14353615cea4SHelge Deller .version_id = 2,
14363615cea4SHelge Deller .minimum_version_id = 2,
14374765384cSSven Schnelle .post_load = vmstate_artist_post_load,
1438f0613160SRichard Henderson .fields = (const VMStateField[]) {
14394765384cSSven Schnelle VMSTATE_UINT16(height, ARTISTState),
14404765384cSSven Schnelle VMSTATE_UINT16(width, ARTISTState),
14414765384cSSven Schnelle VMSTATE_UINT16(depth, ARTISTState),
14424765384cSSven Schnelle VMSTATE_UINT32(fg_color, ARTISTState),
14434765384cSSven Schnelle VMSTATE_UINT32(bg_color, ARTISTState),
14444765384cSSven Schnelle VMSTATE_UINT32(vram_char_y, ARTISTState),
14454765384cSSven Schnelle VMSTATE_UINT32(vram_bitmask, ARTISTState),
14464765384cSSven Schnelle VMSTATE_UINT32(vram_start, ARTISTState),
14474765384cSSven Schnelle VMSTATE_UINT32(vram_pos, ARTISTState),
14484765384cSSven Schnelle VMSTATE_UINT32(vram_size, ARTISTState),
14494765384cSSven Schnelle VMSTATE_UINT32(blockmove_source, ARTISTState),
14504765384cSSven Schnelle VMSTATE_UINT32(blockmove_dest, ARTISTState),
14514765384cSSven Schnelle VMSTATE_UINT32(blockmove_size, ARTISTState),
14524765384cSSven Schnelle VMSTATE_UINT32(line_size, ARTISTState),
14534765384cSSven Schnelle VMSTATE_UINT32(line_end, ARTISTState),
14544765384cSSven Schnelle VMSTATE_UINT32(line_xy, ARTISTState),
14554765384cSSven Schnelle VMSTATE_UINT32(cursor_pos, ARTISTState),
14563615cea4SHelge Deller VMSTATE_UINT32(cursor_cntrl, ARTISTState),
14574765384cSSven Schnelle VMSTATE_UINT32(cursor_height, ARTISTState),
14584765384cSSven Schnelle VMSTATE_UINT32(cursor_width, ARTISTState),
14594765384cSSven Schnelle VMSTATE_UINT32(plane_mask, ARTISTState),
14604765384cSSven Schnelle VMSTATE_UINT32(reg_100080, ARTISTState),
1461e9683fbcSHelge Deller VMSTATE_UINT32(horiz_backporch, ARTISTState),
1462e9683fbcSHelge Deller VMSTATE_UINT32(active_lines_low, ARTISTState),
1463e9683fbcSHelge Deller VMSTATE_UINT32(misc_video, ARTISTState),
1464e9683fbcSHelge Deller VMSTATE_UINT32(misc_ctrl, ARTISTState),
14654765384cSSven Schnelle VMSTATE_UINT32(dst_bm_access, ARTISTState),
14664765384cSSven Schnelle VMSTATE_UINT32(src_bm_access, ARTISTState),
14674765384cSSven Schnelle VMSTATE_UINT32(control_plane, ARTISTState),
14684765384cSSven Schnelle VMSTATE_UINT32(transfer_data, ARTISTState),
14694765384cSSven Schnelle VMSTATE_UINT32(image_bitmap_op, ARTISTState),
14704765384cSSven Schnelle VMSTATE_UINT32(font_write1, ARTISTState),
14714765384cSSven Schnelle VMSTATE_UINT32(font_write2, ARTISTState),
14724765384cSSven Schnelle VMSTATE_UINT32(font_write_pos_y, ARTISTState),
14734765384cSSven Schnelle VMSTATE_END_OF_LIST()
14744765384cSSven Schnelle }
14754765384cSSven Schnelle };
14764765384cSSven Schnelle
14774765384cSSven Schnelle static Property artist_properties[] = {
14784765384cSSven Schnelle DEFINE_PROP_UINT16("width", ARTISTState, width, 1280),
14794765384cSSven Schnelle DEFINE_PROP_UINT16("height", ARTISTState, height, 1024),
14804765384cSSven Schnelle DEFINE_PROP_UINT16("depth", ARTISTState, depth, 8),
14814765384cSSven Schnelle DEFINE_PROP_END_OF_LIST(),
14824765384cSSven Schnelle };
14834765384cSSven Schnelle
artist_reset(DeviceState * qdev)14844765384cSSven Schnelle static void artist_reset(DeviceState *qdev)
14854765384cSSven Schnelle {
14864765384cSSven Schnelle }
14874765384cSSven Schnelle
artist_class_init(ObjectClass * klass,void * data)14884765384cSSven Schnelle static void artist_class_init(ObjectClass *klass, void *data)
14894765384cSSven Schnelle {
14904765384cSSven Schnelle DeviceClass *dc = DEVICE_CLASS(klass);
14914765384cSSven Schnelle
14924765384cSSven Schnelle dc->realize = artist_realizefn;
14934765384cSSven Schnelle dc->vmsd = &vmstate_artist;
1494*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, artist_reset);
14954765384cSSven Schnelle device_class_set_props(dc, artist_properties);
14964765384cSSven Schnelle }
14974765384cSSven Schnelle
14984765384cSSven Schnelle static const TypeInfo artist_info = {
14994765384cSSven Schnelle .name = TYPE_ARTIST,
15004765384cSSven Schnelle .parent = TYPE_SYS_BUS_DEVICE,
15014765384cSSven Schnelle .instance_size = sizeof(ARTISTState),
15024765384cSSven Schnelle .instance_init = artist_initfn,
15034765384cSSven Schnelle .class_init = artist_class_init,
15044765384cSSven Schnelle };
15054765384cSSven Schnelle
artist_register_types(void)15064765384cSSven Schnelle static void artist_register_types(void)
15074765384cSSven Schnelle {
15084765384cSSven Schnelle type_register_static(&artist_info);
15094765384cSSven Schnelle }
15104765384cSSven Schnelle
15114765384cSSven Schnelle type_init(artist_register_types)
1512