1 /*
2 * QEMU HP Artist Emulation
3 *
4 * Copyright (c) 2019-2022 Sven Schnelle <svens@stackframe.org>
5 * Copyright (c) 2022 Helge Deller <deller@gmx.de>
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 */
9
10 #include "qemu/osdep.h"
11 #include "qemu/error-report.h"
12 #include "qemu/log.h"
13 #include "qemu/module.h"
14 #include "qemu/units.h"
15 #include "qapi/error.h"
16 #include "hw/sysbus.h"
17 #include "hw/loader.h"
18 #include "hw/qdev-core.h"
19 #include "hw/qdev-properties.h"
20 #include "migration/vmstate.h"
21 #include "ui/console.h"
22 #include "trace.h"
23 #include "framebuffer.h"
24 #include "qom/object.h"
25
26 #define TYPE_ARTIST "artist"
27 OBJECT_DECLARE_SIMPLE_TYPE(ARTISTState, ARTIST)
28
29 struct vram_buffer {
30 MemoryRegion mr;
31 uint8_t *data;
32 unsigned int size;
33 unsigned int width;
34 unsigned int height;
35 };
36
37 struct ARTISTState {
38 SysBusDevice parent_obj;
39
40 QemuConsole *con;
41 MemoryRegion vram_mem;
42 MemoryRegion mem_as_root;
43 MemoryRegion reg;
44 MemoryRegionSection fbsection;
45
46 void *vram_int_mr;
47 AddressSpace as;
48
49 struct vram_buffer vram_buffer[16];
50
51 bool disable;
52 uint16_t width;
53 uint16_t height;
54 uint16_t depth;
55
56 uint32_t fg_color;
57 uint32_t bg_color;
58
59 uint32_t vram_char_y;
60 uint32_t vram_bitmask;
61
62 uint32_t vram_start;
63 uint32_t vram_pos;
64
65 uint32_t vram_size;
66
67 uint32_t blockmove_source;
68 uint32_t blockmove_dest;
69 uint32_t blockmove_size;
70
71 uint32_t line_size;
72 uint32_t line_end;
73 uint32_t line_xy;
74 uint32_t line_pattern_start;
75 uint32_t line_pattern_skip;
76
77 uint32_t cursor_pos;
78 uint32_t cursor_cntrl;
79
80 uint32_t cursor_height;
81 uint32_t cursor_width;
82
83 uint32_t plane_mask;
84
85 uint32_t reg_100080;
86 uint32_t horiz_backporch;
87 uint32_t active_lines_low;
88 uint32_t misc_video;
89 uint32_t misc_ctrl;
90
91 uint32_t dst_bm_access;
92 uint32_t src_bm_access;
93 uint32_t control_plane;
94 uint32_t transfer_data;
95 uint32_t image_bitmap_op;
96
97 uint32_t font_write1;
98 uint32_t font_write2;
99 uint32_t font_write_pos_y;
100
101 int draw_line_pattern;
102 };
103
104 /* hardware allows up to 64x64, but we emulate 32x32 only. */
105 #define NGLE_MAX_SPRITE_SIZE 32
106
107 typedef enum {
108 ARTIST_BUFFER_AP = 1,
109 ARTIST_BUFFER_OVERLAY = 2,
110 ARTIST_BUFFER_CURSOR1 = 6,
111 ARTIST_BUFFER_CURSOR2 = 7,
112 ARTIST_BUFFER_ATTRIBUTE = 13,
113 ARTIST_BUFFER_CMAP = 15,
114 } artist_buffer_t;
115
116 typedef enum {
117 VRAM_IDX = 0x1004a0,
118 VRAM_BITMASK = 0x1005a0,
119 VRAM_WRITE_INCR_X = 0x100600,
120 VRAM_WRITE_INCR_X2 = 0x100604,
121 VRAM_WRITE_INCR_Y = 0x100620,
122 VRAM_START = 0x100800,
123 BLOCK_MOVE_SIZE = 0x100804,
124 BLOCK_MOVE_SOURCE = 0x100808,
125 TRANSFER_DATA = 0x100820,
126 FONT_WRITE_INCR_Y = 0x1008a0,
127 VRAM_START_TRIGGER = 0x100a00,
128 VRAM_SIZE_TRIGGER = 0x100a04,
129 FONT_WRITE_START = 0x100aa0,
130 BLOCK_MOVE_DEST_TRIGGER = 0x100b00,
131 BLOCK_MOVE_SIZE_TRIGGER = 0x100b04,
132 LINE_XY = 0x100ccc,
133 PATTERN_LINE_START = 0x100ecc,
134 LINE_SIZE = 0x100e04,
135 LINE_END = 0x100e44,
136 DST_SRC_BM_ACCESS = 0x118000,
137 DST_BM_ACCESS = 0x118004,
138 SRC_BM_ACCESS = 0x118008,
139 CONTROL_PLANE = 0x11800c,
140 FG_COLOR = 0x118010,
141 BG_COLOR = 0x118014,
142 PLANE_MASK = 0x118018,
143 IMAGE_BITMAP_OP = 0x11801c,
144 CURSOR_POS = 0x300100, /* reg17 */
145 CURSOR_CTRL = 0x300104, /* reg18 */
146 MISC_VIDEO = 0x300218, /* reg21 */
147 MISC_CTRL = 0x300308, /* reg27 */
148 HORIZ_BACKPORCH = 0x300200, /* reg19 */
149 ACTIVE_LINES_LOW = 0x300208,/* reg20 */
150 FIFO1 = 0x300008, /* reg34 */
151 FIFO2 = 0x380008,
152 } artist_reg_t;
153
154 typedef enum {
155 ARTIST_ROP_CLEAR = 0,
156 ARTIST_ROP_COPY = 3,
157 ARTIST_ROP_XOR = 6,
158 ARTIST_ROP_NOT_DST = 10,
159 ARTIST_ROP_SET = 15,
160 } artist_rop_t;
161
162 #define REG_NAME(_x) case _x: return " "#_x;
artist_reg_name(uint64_t addr)163 static const char *artist_reg_name(uint64_t addr)
164 {
165 switch ((artist_reg_t)addr) {
166 REG_NAME(VRAM_IDX);
167 REG_NAME(VRAM_BITMASK);
168 REG_NAME(VRAM_WRITE_INCR_X);
169 REG_NAME(VRAM_WRITE_INCR_X2);
170 REG_NAME(VRAM_WRITE_INCR_Y);
171 REG_NAME(VRAM_START);
172 REG_NAME(BLOCK_MOVE_SIZE);
173 REG_NAME(BLOCK_MOVE_SOURCE);
174 REG_NAME(FG_COLOR);
175 REG_NAME(BG_COLOR);
176 REG_NAME(PLANE_MASK);
177 REG_NAME(VRAM_START_TRIGGER);
178 REG_NAME(VRAM_SIZE_TRIGGER);
179 REG_NAME(BLOCK_MOVE_DEST_TRIGGER);
180 REG_NAME(BLOCK_MOVE_SIZE_TRIGGER);
181 REG_NAME(TRANSFER_DATA);
182 REG_NAME(CONTROL_PLANE);
183 REG_NAME(IMAGE_BITMAP_OP);
184 REG_NAME(DST_SRC_BM_ACCESS);
185 REG_NAME(DST_BM_ACCESS);
186 REG_NAME(SRC_BM_ACCESS);
187 REG_NAME(CURSOR_POS);
188 REG_NAME(CURSOR_CTRL);
189 REG_NAME(HORIZ_BACKPORCH);
190 REG_NAME(ACTIVE_LINES_LOW);
191 REG_NAME(MISC_VIDEO);
192 REG_NAME(MISC_CTRL);
193 REG_NAME(LINE_XY);
194 REG_NAME(PATTERN_LINE_START);
195 REG_NAME(LINE_SIZE);
196 REG_NAME(LINE_END);
197 REG_NAME(FONT_WRITE_INCR_Y);
198 REG_NAME(FONT_WRITE_START);
199 REG_NAME(FIFO1);
200 REG_NAME(FIFO2);
201 }
202 return "";
203 }
204 #undef REG_NAME
205
206 static void artist_invalidate(void *opaque);
207
208 /* artist has a fixed line length of 2048 bytes. */
209 #define ADDR_TO_Y(addr) extract32(addr, 11, 11)
210 #define ADDR_TO_X(addr) extract32(addr, 0, 11)
211
artist_get_x(uint32_t reg)212 static int16_t artist_get_x(uint32_t reg)
213 {
214 return reg >> 16;
215 }
216
artist_get_y(uint32_t reg)217 static int16_t artist_get_y(uint32_t reg)
218 {
219 return reg & 0xffff;
220 }
221
artist_invalidate_lines(struct vram_buffer * buf,int starty,int height)222 static void artist_invalidate_lines(struct vram_buffer *buf,
223 int starty, int height)
224 {
225 int start = starty * buf->width;
226 int size;
227
228 if (starty + height > buf->height) {
229 height = buf->height - starty;
230 }
231
232 size = height * buf->width;
233
234 if (start + size <= buf->size) {
235 memory_region_set_dirty(&buf->mr, start, size);
236 }
237 }
238
vram_write_bufidx(ARTISTState * s)239 static int vram_write_bufidx(ARTISTState *s)
240 {
241 return (s->dst_bm_access >> 12) & 0x0f;
242 }
243
vram_read_bufidx(ARTISTState * s)244 static int vram_read_bufidx(ARTISTState *s)
245 {
246 return (s->src_bm_access >> 12) & 0x0f;
247 }
248
vram_read_buffer(ARTISTState * s)249 static struct vram_buffer *vram_read_buffer(ARTISTState *s)
250 {
251 return &s->vram_buffer[vram_read_bufidx(s)];
252 }
253
vram_write_buffer(ARTISTState * s)254 static struct vram_buffer *vram_write_buffer(ARTISTState *s)
255 {
256 return &s->vram_buffer[vram_write_bufidx(s)];
257 }
258
artist_get_color(ARTISTState * s)259 static uint8_t artist_get_color(ARTISTState *s)
260 {
261 if (s->image_bitmap_op & 2) {
262 return s->fg_color;
263 } else {
264 return s->bg_color;
265 }
266 }
267
artist_get_op(ARTISTState * s)268 static artist_rop_t artist_get_op(ARTISTState *s)
269 {
270 return (s->image_bitmap_op >> 8) & 0xf;
271 }
272
artist_rop8(ARTISTState * s,struct vram_buffer * buf,unsigned int offset,uint8_t val)273 static void artist_rop8(ARTISTState *s, struct vram_buffer *buf,
274 unsigned int offset, uint8_t val)
275 {
276 const artist_rop_t op = artist_get_op(s);
277 uint8_t plane_mask;
278 uint8_t *dst;
279
280 if (offset >= buf->size) {
281 qemu_log_mask(LOG_GUEST_ERROR,
282 "rop8 offset:%u bufsize:%u\n", offset, buf->size);
283 return;
284 }
285 dst = buf->data + offset;
286 plane_mask = s->plane_mask & 0xff;
287
288 switch (op) {
289 case ARTIST_ROP_CLEAR:
290 *dst &= ~plane_mask;
291 break;
292
293 case ARTIST_ROP_COPY:
294 *dst = (*dst & ~plane_mask) | (val & plane_mask);
295 break;
296
297 case ARTIST_ROP_XOR:
298 *dst ^= val & plane_mask;
299 break;
300
301 case ARTIST_ROP_NOT_DST:
302 *dst ^= plane_mask;
303 break;
304
305 case ARTIST_ROP_SET:
306 *dst |= plane_mask;
307 break;
308
309 default:
310 qemu_log_mask(LOG_UNIMP, "%s: unsupported rop %d\n", __func__, op);
311 break;
312 }
313 }
314
artist_get_cursor_pos(ARTISTState * s,int * x,int * y)315 static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y)
316 {
317 /*
318 * The emulated Artist graphic is like a CRX graphic, and as such
319 * it's usually fixed at 1280x1024 pixels.
320 * Other resolutions may work, but no guarantee.
321 */
322
323 unsigned int hbp_times_vi, horizBackPorch;
324 int16_t xHi, xLo;
325 const int videoInterleave = 4;
326 const int pipelineDelay = 4;
327
328 /* ignore if uninitialized */
329 if (s->cursor_pos == 0) {
330 *x = *y = 0;
331 return;
332 }
333
334 /*
335 * Calculate X position based on backporch and interleave values.
336 * Based on code from Xorg X11R6.6
337 */
338 horizBackPorch = ((s->horiz_backporch & 0xff0000) >> 16) +
339 ((s->horiz_backporch & 0xff00) >> 8) + 2;
340 hbp_times_vi = horizBackPorch * videoInterleave;
341 xHi = s->cursor_pos >> 19;
342 *x = ((xHi + pipelineDelay) * videoInterleave) - hbp_times_vi;
343
344 xLo = (s->cursor_pos >> 16) & 0x07;
345 *x += ((xLo - hbp_times_vi) & (videoInterleave - 1)) + 8 - 1;
346
347 /* subtract cursor offset from cursor control register */
348 *x -= (s->cursor_cntrl & 0xf0) >> 4;
349
350 /* Calculate Y position */
351 *y = s->height - artist_get_y(s->cursor_pos);
352 *y -= (s->cursor_cntrl & 0x0f);
353
354 if (*x > s->width) {
355 *x = s->width;
356 }
357
358 if (*y > s->height) {
359 *y = s->height;
360 }
361 }
362
cursor_visible(ARTISTState * s)363 static inline bool cursor_visible(ARTISTState *s)
364 {
365 /* cursor is visible if bit 0x80 is set in cursor_cntrl */
366 return s->cursor_cntrl & 0x80;
367 }
368
artist_invalidate_cursor(ARTISTState * s)369 static void artist_invalidate_cursor(ARTISTState *s)
370 {
371 int x, y;
372
373 if (!cursor_visible(s)) {
374 return;
375 }
376
377 artist_get_cursor_pos(s, &x, &y);
378 artist_invalidate_lines(&s->vram_buffer[ARTIST_BUFFER_AP],
379 y, s->cursor_height);
380 }
381
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)382 static void block_move(ARTISTState *s,
383 unsigned int source_x, unsigned int source_y,
384 unsigned int dest_x, unsigned int dest_y,
385 unsigned int width, unsigned int height)
386 {
387 struct vram_buffer *buf;
388 int line, endline, lineincr, startcolumn, endcolumn, columnincr, column;
389 unsigned int dst, src;
390
391 trace_artist_block_move(source_x, source_y, dest_x, dest_y, width, height);
392
393 if (s->control_plane != 0) {
394 /* We don't support CONTROL_PLANE accesses */
395 qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
396 s->control_plane);
397 return;
398 }
399
400 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
401 if (height > buf->height) {
402 height = buf->height;
403 }
404 if (width > buf->width) {
405 width = buf->width;
406 }
407
408 if (dest_y > source_y) {
409 /* move down */
410 line = height - 1;
411 endline = -1;
412 lineincr = -1;
413 } else {
414 /* move up */
415 line = 0;
416 endline = height;
417 lineincr = 1;
418 }
419
420 if (dest_x > source_x) {
421 /* move right */
422 startcolumn = width - 1;
423 endcolumn = -1;
424 columnincr = -1;
425 } else {
426 /* move left */
427 startcolumn = 0;
428 endcolumn = width;
429 columnincr = 1;
430 }
431
432 for ( ; line != endline; line += lineincr) {
433 src = source_x + ((line + source_y) * buf->width) + startcolumn;
434 dst = dest_x + ((line + dest_y) * buf->width) + startcolumn;
435
436 for (column = startcolumn; column != endcolumn; column += columnincr) {
437 if (dst >= buf->size || src >= buf->size) {
438 continue;
439 }
440 artist_rop8(s, buf, dst, buf->data[src]);
441 src += columnincr;
442 dst += columnincr;
443 }
444 }
445
446 artist_invalidate_lines(buf, dest_y, height);
447 }
448
fill_window(ARTISTState * s,unsigned int startx,unsigned int starty,unsigned int width,unsigned int height)449 static void fill_window(ARTISTState *s,
450 unsigned int startx, unsigned int starty,
451 unsigned int width, unsigned int height)
452 {
453 unsigned int offset;
454 uint8_t color = artist_get_color(s);
455 struct vram_buffer *buf;
456 int x, y;
457
458 trace_artist_fill_window(startx, starty, width, height,
459 s->image_bitmap_op, s->control_plane);
460
461 if (s->control_plane != 0) {
462 /* We don't support CONTROL_PLANE accesses */
463 qemu_log_mask(LOG_UNIMP, "%s: CONTROL_PLANE: %08x\n", __func__,
464 s->control_plane);
465 return;
466 }
467
468 if (s->reg_100080 == 0x7d) {
469 /*
470 * Not sure what this register really does, but
471 * 0x7d seems to enable autoincremt of the Y axis
472 * by the current block move height.
473 */
474 height = artist_get_y(s->blockmove_size);
475 s->vram_start += height;
476 }
477
478 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
479
480 for (y = starty; y < starty + height; y++) {
481 offset = y * s->width;
482
483 for (x = startx; x < startx + width; x++) {
484 artist_rop8(s, buf, offset + x, color);
485 }
486 }
487 artist_invalidate_lines(buf, starty, height);
488 }
489
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)490 static void draw_line(ARTISTState *s,
491 unsigned int x1, unsigned int y1,
492 unsigned int x2, unsigned int y2,
493 bool update_start, int skip_pix, int max_pix)
494 {
495 struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
496 uint8_t color;
497 int dx, dy, t, e, x, y, incy, diago, horiz;
498 bool c1;
499
500 trace_artist_draw_line(x1, y1, x2, y2);
501
502 if ((x1 >= buf->width && x2 >= buf->width) ||
503 (y1 >= buf->height && y2 >= buf->height)) {
504 return;
505 }
506
507 if (update_start) {
508 s->vram_start = (x2 << 16) | y2;
509 }
510
511 if (x2 > x1) {
512 dx = x2 - x1;
513 } else {
514 dx = x1 - x2;
515 }
516 if (y2 > y1) {
517 dy = y2 - y1;
518 } else {
519 dy = y1 - y2;
520 }
521
522 c1 = false;
523 if (dy > dx) {
524 t = y2;
525 y2 = x2;
526 x2 = t;
527
528 t = y1;
529 y1 = x1;
530 x1 = t;
531
532 t = dx;
533 dx = dy;
534 dy = t;
535
536 c1 = true;
537 }
538
539 if (x1 > x2) {
540 t = y2;
541 y2 = y1;
542 y1 = t;
543
544 t = x1;
545 x1 = x2;
546 x2 = t;
547 }
548
549 horiz = dy << 1;
550 diago = (dy - dx) << 1;
551 e = (dy << 1) - dx;
552
553 if (y1 <= y2) {
554 incy = 1;
555 } else {
556 incy = -1;
557 }
558 x = x1;
559 y = y1;
560 color = artist_get_color(s);
561
562 do {
563 unsigned int ofs;
564
565 if (c1) {
566 ofs = x * s->width + y;
567 } else {
568 ofs = y * s->width + x;
569 }
570
571 if (skip_pix > 0) {
572 skip_pix--;
573 } else {
574 artist_rop8(s, buf, ofs, color);
575 }
576
577 if (e > 0) {
578 y += incy;
579 e += diago;
580 } else {
581 e += horiz;
582 }
583 x++;
584 } while (x <= x2 && (max_pix == -1 || --max_pix > 0));
585
586 if (c1) {
587 artist_invalidate_lines(buf, x1, x2 - x1);
588 } else {
589 artist_invalidate_lines(buf, y1 > y2 ? y2 : y1, x2 - x1);
590 }
591 }
592
draw_line_pattern_start(ARTISTState * s)593 static void draw_line_pattern_start(ARTISTState *s)
594 {
595 int startx = artist_get_x(s->vram_start);
596 int starty = artist_get_y(s->vram_start);
597 int endx = artist_get_x(s->blockmove_size);
598 int endy = artist_get_y(s->blockmove_size);
599 int pstart = s->line_pattern_start >> 16;
600
601 draw_line(s, startx, starty, endx, endy, false, -1, pstart);
602 s->line_pattern_skip = pstart;
603 }
604
draw_line_pattern_next(ARTISTState * s)605 static void draw_line_pattern_next(ARTISTState *s)
606 {
607 int startx = artist_get_x(s->vram_start);
608 int starty = artist_get_y(s->vram_start);
609 int endx = artist_get_x(s->blockmove_size);
610 int endy = artist_get_y(s->blockmove_size);
611 int line_xy = s->line_xy >> 16;
612
613 draw_line(s, startx, starty, endx, endy, false, s->line_pattern_skip,
614 s->line_pattern_skip + line_xy);
615 s->line_pattern_skip += line_xy;
616 s->image_bitmap_op ^= 2;
617 }
618
draw_line_size(ARTISTState * s,bool update_start)619 static void draw_line_size(ARTISTState *s, bool update_start)
620 {
621 int startx = artist_get_x(s->vram_start);
622 int starty = artist_get_y(s->vram_start);
623 int endx = artist_get_x(s->line_size);
624 int endy = artist_get_y(s->line_size);
625
626 draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
627 }
628
draw_line_xy(ARTISTState * s,bool update_start)629 static void draw_line_xy(ARTISTState *s, bool update_start)
630 {
631 int startx = artist_get_x(s->vram_start);
632 int starty = artist_get_y(s->vram_start);
633 int sizex = artist_get_x(s->blockmove_size);
634 int sizey = artist_get_y(s->blockmove_size);
635 int linexy = s->line_xy >> 16;
636 int endx, endy;
637
638 endx = startx;
639 endy = starty;
640
641 if (sizex > 0) {
642 endx = startx + linexy;
643 }
644
645 if (sizex < 0) {
646 endx = startx;
647 startx -= linexy;
648 }
649
650 if (sizey > 0) {
651 endy = starty + linexy;
652 }
653
654 if (sizey < 0) {
655 endy = starty;
656 starty -= linexy;
657 }
658
659 if (startx < 0) {
660 startx = 0;
661 }
662
663 if (endx < 0) {
664 endx = 0;
665 }
666
667 if (starty < 0) {
668 starty = 0;
669 }
670
671 if (endy < 0) {
672 endy = 0;
673 }
674
675 draw_line(s, startx, starty, endx, endy, false, -1, -1);
676 }
677
draw_line_end(ARTISTState * s,bool update_start)678 static void draw_line_end(ARTISTState *s, bool update_start)
679 {
680 int startx = artist_get_x(s->vram_start);
681 int starty = artist_get_y(s->vram_start);
682 int endx = artist_get_x(s->line_end);
683 int endy = artist_get_y(s->line_end);
684
685 draw_line(s, startx, starty, endx, endy, update_start, -1, -1);
686 }
687
font_write16(ARTISTState * s,uint16_t val)688 static void font_write16(ARTISTState *s, uint16_t val)
689 {
690 struct vram_buffer *buf;
691 uint32_t color = (s->image_bitmap_op & 2) ? s->fg_color : s->bg_color;
692 uint16_t mask;
693 int i;
694
695 unsigned int startx = artist_get_x(s->vram_start);
696 unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y;
697 unsigned int offset = starty * s->width + startx;
698
699 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
700
701 if (startx >= buf->width || starty >= buf->height ||
702 offset + 16 >= buf->size) {
703 return;
704 }
705
706 for (i = 0; i < 16; i++) {
707 mask = 1 << (15 - i);
708 if (val & mask) {
709 artist_rop8(s, buf, offset + i, color);
710 } else {
711 if (!(s->image_bitmap_op & 0x20000000)) {
712 artist_rop8(s, buf, offset + i, s->bg_color);
713 }
714 }
715 }
716 artist_invalidate_lines(buf, starty, 1);
717 }
718
font_write(ARTISTState * s,uint32_t val)719 static void font_write(ARTISTState *s, uint32_t val)
720 {
721 font_write16(s, val >> 16);
722 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
723 s->vram_start += (s->blockmove_size & 0xffff0000);
724 return;
725 }
726
727 font_write16(s, val & 0xffff);
728 if (++s->font_write_pos_y == artist_get_y(s->blockmove_size)) {
729 s->vram_start += (s->blockmove_size & 0xffff0000);
730 return;
731 }
732 }
733
combine_write_reg(hwaddr addr,uint64_t val,int size,void * out)734 static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out)
735 {
736 /*
737 * FIXME: is there a qemu helper for this?
738 */
739
740 #if !HOST_BIG_ENDIAN
741 addr ^= 3;
742 #endif
743
744 switch (size) {
745 case 1:
746 *(uint8_t *)(out + (addr & 3)) = val;
747 break;
748
749 case 2:
750 *(uint16_t *)(out + (addr & 2)) = val;
751 break;
752
753 case 4:
754 *(uint32_t *)out = val;
755 break;
756
757 default:
758 qemu_log_mask(LOG_UNIMP, "unsupported write size: %d\n", size);
759 }
760 }
761
artist_vram_write4(ARTISTState * s,struct vram_buffer * buf,uint32_t offset,uint32_t data)762 static void artist_vram_write4(ARTISTState *s, struct vram_buffer *buf,
763 uint32_t offset, uint32_t data)
764 {
765 int i;
766 int mask = s->vram_bitmask >> 28;
767
768 for (i = 0; i < 4; i++) {
769 if (!(s->image_bitmap_op & 0x20000000) || (mask & 8)) {
770 artist_rop8(s, buf, offset + i, data >> 24);
771 data <<= 8;
772 mask <<= 1;
773 }
774 }
775 memory_region_set_dirty(&buf->mr, offset, 3);
776 }
777
artist_vram_write32(ARTISTState * s,struct vram_buffer * buf,uint32_t offset,int size,uint32_t data,int fg,int bg)778 static void artist_vram_write32(ARTISTState *s, struct vram_buffer *buf,
779 uint32_t offset, int size, uint32_t data,
780 int fg, int bg)
781 {
782 uint32_t mask, vram_bitmask = s->vram_bitmask >> ((4 - size) * 8);
783 int i, pix_count = size * 8;
784
785 for (i = 0; i < pix_count && offset + i < buf->size; i++) {
786 mask = 1 << (pix_count - 1 - i);
787
788 if (!(s->image_bitmap_op & 0x20000000) || (vram_bitmask & mask)) {
789 if (data & mask) {
790 artist_rop8(s, buf, offset + i, fg);
791 } else {
792 if (!(s->image_bitmap_op & 0x10000002)) {
793 artist_rop8(s, buf, offset + i, bg);
794 }
795 }
796 }
797 }
798 memory_region_set_dirty(&buf->mr, offset, pix_count);
799 }
800
get_vram_offset(ARTISTState * s,struct vram_buffer * buf,int pos,int posy)801 static int get_vram_offset(ARTISTState *s, struct vram_buffer *buf,
802 int pos, int posy)
803 {
804 unsigned int posx, width;
805
806 width = buf->width;
807 posx = ADDR_TO_X(pos);
808 posy += ADDR_TO_Y(pos);
809 return posy * width + posx;
810 }
811
vram_bit_write(ARTISTState * s,uint32_t pos,int posy,uint32_t data,int size)812 static int vram_bit_write(ARTISTState *s, uint32_t pos, int posy,
813 uint32_t data, int size)
814 {
815 struct vram_buffer *buf = vram_write_buffer(s);
816
817 switch (s->dst_bm_access >> 16) {
818 case 0x3ba0:
819 case 0xbbe0:
820 artist_vram_write4(s, buf, pos, bswap32(data));
821 pos += 4;
822 break;
823
824 case 0x1360: /* linux */
825 artist_vram_write4(s, buf, get_vram_offset(s, buf, pos, posy), data);
826 pos += 4;
827 break;
828
829 case 0x13a0:
830 artist_vram_write4(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
831 data);
832 pos += 16;
833 break;
834
835 case 0x2ea0:
836 artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
837 size, data, s->fg_color, s->bg_color);
838 pos += 4;
839 break;
840
841 case 0x28a0:
842 artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy),
843 size, data, 1, 0);
844 pos += 4;
845 break;
846
847 default:
848 qemu_log_mask(LOG_UNIMP, "%s: unknown dst bm access %08x\n",
849 __func__, s->dst_bm_access);
850 break;
851 }
852
853 if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 ||
854 vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) {
855 artist_invalidate_cursor(s);
856 }
857 return pos;
858 }
859
artist_vram_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)860 static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
861 unsigned size)
862 {
863 ARTISTState *s = opaque;
864
865 s->vram_char_y = 0;
866 trace_artist_vram_write(size, addr, val);
867 vram_bit_write(opaque, addr, 0, val, size);
868 }
869
artist_vram_read(void * opaque,hwaddr addr,unsigned size)870 static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
871 {
872 ARTISTState *s = opaque;
873 struct vram_buffer *buf;
874 unsigned int offset;
875 uint64_t val;
876
877 buf = vram_read_buffer(s);
878 if (!buf->size) {
879 return 0;
880 }
881
882 offset = get_vram_offset(s, buf, addr >> 2, 0);
883
884 if (offset > buf->size) {
885 return 0;
886 }
887
888 switch (s->src_bm_access >> 16) {
889 case 0x3ba0:
890 val = *(uint32_t *)(buf->data + offset);
891 break;
892
893 case 0x13a0:
894 case 0x2ea0:
895 val = bswap32(*(uint32_t *)(buf->data + offset));
896 break;
897
898 default:
899 qemu_log_mask(LOG_UNIMP, "%s: unknown src bm access %08x\n",
900 __func__, s->dst_bm_access);
901 val = -1ULL;
902 break;
903 }
904 trace_artist_vram_read(size, addr, val);
905 return val;
906 }
907
artist_reg_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)908 static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val,
909 unsigned size)
910 {
911 ARTISTState *s = opaque;
912 int width, height;
913 uint64_t oldval;
914
915 trace_artist_reg_write(size, addr, artist_reg_name(addr & ~3ULL), val);
916
917 switch (addr & ~3ULL) {
918 case 0x100080:
919 combine_write_reg(addr, val, size, &s->reg_100080);
920 break;
921
922 case FG_COLOR:
923 combine_write_reg(addr, val, size, &s->fg_color);
924 break;
925
926 case BG_COLOR:
927 combine_write_reg(addr, val, size, &s->bg_color);
928 break;
929
930 case VRAM_BITMASK:
931 combine_write_reg(addr, val, size, &s->vram_bitmask);
932 break;
933
934 case VRAM_WRITE_INCR_Y:
935 vram_bit_write(s, s->vram_pos, s->vram_char_y++, val, size);
936 break;
937
938 case VRAM_WRITE_INCR_X:
939 case VRAM_WRITE_INCR_X2:
940 s->vram_pos = vram_bit_write(s, s->vram_pos, s->vram_char_y, val, size);
941 break;
942
943 case VRAM_IDX:
944 combine_write_reg(addr, val, size, &s->vram_pos);
945 s->vram_char_y = 0;
946 s->draw_line_pattern = 0;
947 break;
948
949 case VRAM_START:
950 combine_write_reg(addr, val, size, &s->vram_start);
951 s->draw_line_pattern = 0;
952 break;
953
954 case VRAM_START_TRIGGER:
955 combine_write_reg(addr, val, size, &s->vram_start);
956 fill_window(s, artist_get_x(s->vram_start),
957 artist_get_y(s->vram_start),
958 artist_get_x(s->blockmove_size),
959 artist_get_y(s->blockmove_size));
960 break;
961
962 case VRAM_SIZE_TRIGGER:
963 combine_write_reg(addr, val, size, &s->vram_size);
964
965 if (size == 2 && !(addr & 2)) {
966 height = artist_get_y(s->blockmove_size);
967 } else {
968 height = artist_get_y(s->vram_size);
969 }
970
971 if (size == 2 && (addr & 2)) {
972 width = artist_get_x(s->blockmove_size);
973 } else {
974 width = artist_get_x(s->vram_size);
975 }
976
977 fill_window(s, artist_get_x(s->vram_start),
978 artist_get_y(s->vram_start),
979 width, height);
980 break;
981
982 case LINE_XY:
983 combine_write_reg(addr, val, size, &s->line_xy);
984 if (s->draw_line_pattern) {
985 draw_line_pattern_next(s);
986 } else {
987 draw_line_xy(s, true);
988 }
989 break;
990
991 case PATTERN_LINE_START:
992 combine_write_reg(addr, val, size, &s->line_pattern_start);
993 s->draw_line_pattern = 1;
994 draw_line_pattern_start(s);
995 break;
996
997 case LINE_SIZE:
998 combine_write_reg(addr, val, size, &s->line_size);
999 draw_line_size(s, true);
1000 break;
1001
1002 case LINE_END:
1003 combine_write_reg(addr, val, size, &s->line_end);
1004 draw_line_end(s, true);
1005 break;
1006
1007 case BLOCK_MOVE_SIZE:
1008 combine_write_reg(addr, val, size, &s->blockmove_size);
1009 break;
1010
1011 case BLOCK_MOVE_SOURCE:
1012 combine_write_reg(addr, val, size, &s->blockmove_source);
1013 break;
1014
1015 case BLOCK_MOVE_DEST_TRIGGER:
1016 combine_write_reg(addr, val, size, &s->blockmove_dest);
1017
1018 block_move(s, artist_get_x(s->blockmove_source),
1019 artist_get_y(s->blockmove_source),
1020 artist_get_x(s->blockmove_dest),
1021 artist_get_y(s->blockmove_dest),
1022 artist_get_x(s->blockmove_size),
1023 artist_get_y(s->blockmove_size));
1024 break;
1025
1026 case BLOCK_MOVE_SIZE_TRIGGER:
1027 combine_write_reg(addr, val, size, &s->blockmove_size);
1028
1029 block_move(s,
1030 artist_get_x(s->blockmove_source),
1031 artist_get_y(s->blockmove_source),
1032 artist_get_x(s->vram_start),
1033 artist_get_y(s->vram_start),
1034 artist_get_x(s->blockmove_size),
1035 artist_get_y(s->blockmove_size));
1036 break;
1037
1038 case PLANE_MASK:
1039 combine_write_reg(addr, val, size, &s->plane_mask);
1040 break;
1041
1042 case DST_SRC_BM_ACCESS:
1043 combine_write_reg(addr, val, size, &s->dst_bm_access);
1044 combine_write_reg(addr, val, size, &s->src_bm_access);
1045 break;
1046
1047 case DST_BM_ACCESS:
1048 combine_write_reg(addr, val, size, &s->dst_bm_access);
1049 break;
1050
1051 case SRC_BM_ACCESS:
1052 combine_write_reg(addr, val, size, &s->src_bm_access);
1053 break;
1054
1055 case CONTROL_PLANE:
1056 combine_write_reg(addr, val, size, &s->control_plane);
1057 break;
1058
1059 case TRANSFER_DATA:
1060 combine_write_reg(addr, val, size, &s->transfer_data);
1061 break;
1062
1063 case HORIZ_BACKPORCH:
1064 /* overwrite HP-UX settings to fix X cursor position. */
1065 val = (NGLE_MAX_SPRITE_SIZE << 16) + (NGLE_MAX_SPRITE_SIZE << 8);
1066 combine_write_reg(addr, val, size, &s->horiz_backporch);
1067 break;
1068
1069 case ACTIVE_LINES_LOW:
1070 combine_write_reg(addr, val, size, &s->active_lines_low);
1071 break;
1072
1073 case MISC_VIDEO:
1074 oldval = s->misc_video;
1075 combine_write_reg(addr, val, size, &s->misc_video);
1076 /* Invalidate and hide screen if graphics signal is turned off. */
1077 if (((oldval & 0x0A000000) == 0x0A000000) &&
1078 ((val & 0x0A000000) != 0x0A000000)) {
1079 artist_invalidate(s);
1080 }
1081 /* Invalidate and redraw screen if graphics signal is turned back on. */
1082 if (((oldval & 0x0A000000) != 0x0A000000) &&
1083 ((val & 0x0A000000) == 0x0A000000)) {
1084 artist_invalidate(s);
1085 }
1086 break;
1087
1088 case MISC_CTRL:
1089 combine_write_reg(addr, val, size, &s->misc_ctrl);
1090 break;
1091
1092 case CURSOR_POS:
1093 artist_invalidate_cursor(s);
1094 combine_write_reg(addr, val, size, &s->cursor_pos);
1095 artist_invalidate_cursor(s);
1096 break;
1097
1098 case CURSOR_CTRL:
1099 combine_write_reg(addr, val, size, &s->cursor_cntrl);
1100 break;
1101
1102 case IMAGE_BITMAP_OP:
1103 combine_write_reg(addr, val, size, &s->image_bitmap_op);
1104 break;
1105
1106 case FONT_WRITE_INCR_Y:
1107 combine_write_reg(addr, val, size, &s->font_write1);
1108 font_write(s, s->font_write1);
1109 break;
1110
1111 case FONT_WRITE_START:
1112 combine_write_reg(addr, val, size, &s->font_write2);
1113 s->font_write_pos_y = 0;
1114 font_write(s, s->font_write2);
1115 break;
1116
1117 case 300104:
1118 break;
1119
1120 default:
1121 qemu_log_mask(LOG_UNIMP, "%s: unknown register: reg=%08" HWADDR_PRIx
1122 " val=%08" PRIx64 " size=%d\n",
1123 __func__, addr, val, size);
1124 break;
1125 }
1126 }
1127
combine_read_reg(hwaddr addr,int size,void * in)1128 static uint64_t combine_read_reg(hwaddr addr, int size, void *in)
1129 {
1130 /*
1131 * FIXME: is there a qemu helper for this?
1132 */
1133
1134 #if !HOST_BIG_ENDIAN
1135 addr ^= 3;
1136 #endif
1137
1138 switch (size) {
1139 case 1:
1140 return *(uint8_t *)(in + (addr & 3));
1141
1142 case 2:
1143 return *(uint16_t *)(in + (addr & 2));
1144
1145 case 4:
1146 return *(uint32_t *)in;
1147
1148 default:
1149 qemu_log_mask(LOG_UNIMP, "unsupported read size: %d\n", size);
1150 return 0;
1151 }
1152 }
1153
artist_reg_read(void * opaque,hwaddr addr,unsigned size)1154 static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
1155 {
1156 ARTISTState *s = opaque;
1157 uint32_t val = 0;
1158
1159 switch (addr & ~3ULL) {
1160 /* Unknown status registers */
1161 case 0:
1162 break;
1163
1164 case 0x211110:
1165 val = (s->width << 16) | s->height;
1166 if (s->depth == 1) {
1167 val |= 1 << 31;
1168 }
1169 break;
1170
1171 case 0x100000:
1172 case 0x300000:
1173 case 0x300004:
1174 case 0x380000:
1175 break;
1176
1177 case FIFO1:
1178 case FIFO2:
1179 /*
1180 * FIFO ready flag. we're not emulating the FIFOs
1181 * so we're always ready
1182 */
1183 val = 0x10;
1184 break;
1185
1186 case HORIZ_BACKPORCH:
1187 val = s->horiz_backporch;
1188 break;
1189
1190 case ACTIVE_LINES_LOW:
1191 val = s->active_lines_low;
1192 /* activeLinesLo for cursor is in reg20.b.b0 */
1193 val &= ~(0xff << 24);
1194 val |= (s->height & 0xff) << 24;
1195 break;
1196
1197 case MISC_VIDEO:
1198 /* emulate V-blank */
1199 s->misc_video ^= 0x00040000;
1200 /* activeLinesHi for cursor is in reg21.b.b2 */
1201 val = s->misc_video;
1202 val &= ~0xff00UL;
1203 val |= (s->height & 0xff00);
1204 break;
1205
1206 case MISC_CTRL:
1207 val = s->misc_ctrl;
1208 break;
1209
1210 case 0x30023c:
1211 val = 0xac4ffdac;
1212 break;
1213
1214 case 0x380004:
1215 /* magic number detected by SeaBIOS-hppa */
1216 val = s->disable ? 0 : 0x6dc20006;
1217 break;
1218
1219 default:
1220 qemu_log_mask(LOG_UNIMP, "%s: unknown register: %08" HWADDR_PRIx
1221 " size %d\n", __func__, addr, size);
1222 break;
1223 }
1224 val = combine_read_reg(addr, size, &val);
1225 trace_artist_reg_read(size, addr, artist_reg_name(addr & ~3ULL), val);
1226 return val;
1227 }
1228
1229 static const MemoryRegionOps artist_reg_ops = {
1230 .read = artist_reg_read,
1231 .write = artist_reg_write,
1232 .endianness = DEVICE_NATIVE_ENDIAN,
1233 .impl.min_access_size = 1,
1234 .impl.max_access_size = 4,
1235 };
1236
1237 static const MemoryRegionOps artist_vram_ops = {
1238 .read = artist_vram_read,
1239 .write = artist_vram_write,
1240 .endianness = DEVICE_NATIVE_ENDIAN,
1241 .impl.min_access_size = 1,
1242 .impl.max_access_size = 4,
1243 };
1244
artist_draw_cursor(ARTISTState * s)1245 static void artist_draw_cursor(ARTISTState *s)
1246 {
1247 DisplaySurface *surface = qemu_console_surface(s->con);
1248 uint32_t *data = (uint32_t *)surface_data(surface);
1249 struct vram_buffer *cursor0, *cursor1 , *buf;
1250 int cx, cy, cursor_pos_x, cursor_pos_y;
1251
1252 if (!cursor_visible(s)) {
1253 return;
1254 }
1255
1256 cursor0 = &s->vram_buffer[ARTIST_BUFFER_CURSOR1];
1257 cursor1 = &s->vram_buffer[ARTIST_BUFFER_CURSOR2];
1258 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1259
1260 artist_get_cursor_pos(s, &cursor_pos_x, &cursor_pos_y);
1261
1262 for (cy = 0; cy < s->cursor_height; cy++) {
1263
1264 for (cx = 0; cx < s->cursor_width; cx++) {
1265
1266 if (cursor_pos_y + cy < 0 ||
1267 cursor_pos_x + cx < 0 ||
1268 cursor_pos_y + cy > buf->height - 1 ||
1269 cursor_pos_x + cx > buf->width) {
1270 continue;
1271 }
1272
1273 int dstoffset = (cursor_pos_y + cy) * s->width +
1274 (cursor_pos_x + cx);
1275
1276 if (cursor0->data[cy * cursor0->width + cx]) {
1277 data[dstoffset] = 0;
1278 } else {
1279 if (cursor1->data[cy * cursor1->width + cx]) {
1280 data[dstoffset] = 0xffffff;
1281 }
1282 }
1283 }
1284 }
1285 }
1286
artist_screen_enabled(ARTISTState * s)1287 static bool artist_screen_enabled(ARTISTState *s)
1288 {
1289 /* We could check for (s->misc_ctrl & 0x00800000) too... */
1290 return ((s->misc_video & 0x0A000000) == 0x0A000000);
1291 }
1292
artist_draw_line(void * opaque,uint8_t * d,const uint8_t * src,int width,int pitch)1293 static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
1294 int width, int pitch)
1295 {
1296 ARTISTState *s = ARTIST(opaque);
1297 uint32_t *cmap, *data = (uint32_t *)d;
1298 int x;
1299
1300 if (!artist_screen_enabled(s)) {
1301 /* clear screen */
1302 memset(data, 0, s->width * sizeof(uint32_t));
1303 return;
1304 }
1305
1306 cmap = (uint32_t *)(s->vram_buffer[ARTIST_BUFFER_CMAP].data + 0x400);
1307
1308 for (x = 0; x < s->width; x++) {
1309 *data++ = cmap[*src++];
1310 }
1311 }
1312
artist_update_display(void * opaque)1313 static void artist_update_display(void *opaque)
1314 {
1315 ARTISTState *s = opaque;
1316 DisplaySurface *surface = qemu_console_surface(s->con);
1317 int first = 0, last;
1318
1319 framebuffer_update_display(surface, &s->fbsection, s->width, s->height,
1320 s->width, s->width * 4, 0, 0, artist_draw_line,
1321 s, &first, &last);
1322
1323 artist_draw_cursor(s);
1324
1325 if (first >= 0) {
1326 dpy_gfx_update(s->con, 0, first, s->width, last - first + 1);
1327 }
1328 }
1329
artist_invalidate(void * opaque)1330 static void artist_invalidate(void *opaque)
1331 {
1332 ARTISTState *s = ARTIST(opaque);
1333 struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1334
1335 memory_region_set_dirty(&buf->mr, 0, buf->size);
1336 }
1337
1338 static const GraphicHwOps artist_ops = {
1339 .invalidate = artist_invalidate,
1340 .gfx_update = artist_update_display,
1341 };
1342
artist_initfn(Object * obj)1343 static void artist_initfn(Object *obj)
1344 {
1345 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1346 ARTISTState *s = ARTIST(obj);
1347
1348 memory_region_init_io(&s->reg, obj, &artist_reg_ops, s, "artist.reg",
1349 4 * MiB);
1350 memory_region_init_io(&s->vram_mem, obj, &artist_vram_ops, s, "artist.vram",
1351 8 * MiB);
1352 sysbus_init_mmio(sbd, &s->reg);
1353 sysbus_init_mmio(sbd, &s->vram_mem);
1354 }
1355
artist_create_buffer(ARTISTState * s,const char * name,hwaddr * offset,unsigned int idx,int width,int height)1356 static void artist_create_buffer(ARTISTState *s, const char *name,
1357 hwaddr *offset, unsigned int idx,
1358 int width, int height)
1359 {
1360 struct vram_buffer *buf = s->vram_buffer + idx;
1361
1362 memory_region_init_ram(&buf->mr, OBJECT(s), name, width * height,
1363 &error_fatal);
1364 memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0);
1365
1366 buf->data = memory_region_get_ram_ptr(&buf->mr);
1367 buf->size = height * width;
1368 buf->width = width;
1369 buf->height = height;
1370
1371 *offset += buf->size;
1372 }
1373
artist_realizefn(DeviceState * dev,Error ** errp)1374 static void artist_realizefn(DeviceState *dev, Error **errp)
1375 {
1376 ARTISTState *s = ARTIST(dev);
1377 struct vram_buffer *buf;
1378 hwaddr offset = 0;
1379
1380 if (s->width > 2048 || s->height > 2048) {
1381 error_report("artist: screen size can not exceed 2048 x 2048 pixel.");
1382 s->width = MIN(s->width, 2048);
1383 s->height = MIN(s->height, 2048);
1384 }
1385
1386 if (s->width < 640 || s->height < 480) {
1387 error_report("artist: minimum screen size is 640 x 480 pixel.");
1388 s->width = MAX(s->width, 640);
1389 s->height = MAX(s->height, 480);
1390 }
1391
1392 memory_region_init(&s->mem_as_root, OBJECT(dev), "artist", ~0ull);
1393 address_space_init(&s->as, &s->mem_as_root, "artist");
1394
1395 artist_create_buffer(s, "cmap", &offset, ARTIST_BUFFER_CMAP, 2048, 4);
1396 artist_create_buffer(s, "ap", &offset, ARTIST_BUFFER_AP,
1397 s->width, s->height);
1398 artist_create_buffer(s, "cursor1", &offset, ARTIST_BUFFER_CURSOR1, 64, 64);
1399 artist_create_buffer(s, "cursor2", &offset, ARTIST_BUFFER_CURSOR2, 64, 64);
1400 artist_create_buffer(s, "attribute", &offset, ARTIST_BUFFER_ATTRIBUTE,
1401 64, 64);
1402
1403 buf = &s->vram_buffer[ARTIST_BUFFER_AP];
1404 framebuffer_update_memory_section(&s->fbsection, &buf->mr, 0,
1405 buf->width, buf->height);
1406 /*
1407 * Artist cursor max size
1408 */
1409 s->cursor_height = NGLE_MAX_SPRITE_SIZE;
1410 s->cursor_width = NGLE_MAX_SPRITE_SIZE;
1411
1412 /*
1413 * These two registers are not initialized by seabios's STI implementation.
1414 * Initialize them here to sane values so artist also works with older
1415 * (not-fixed) seabios versions.
1416 */
1417 s->image_bitmap_op = 0x23000300;
1418 s->plane_mask = 0xff;
1419
1420 /* enable screen */
1421 s->misc_video |= 0x0A000000;
1422 s->misc_ctrl |= 0x00800000;
1423
1424 s->con = graphic_console_init(dev, 0, &artist_ops, s);
1425 qemu_console_resize(s->con, s->width, s->height);
1426 }
1427
vmstate_artist_post_load(void * opaque,int version_id)1428 static int vmstate_artist_post_load(void *opaque, int version_id)
1429 {
1430 artist_invalidate(opaque);
1431 return 0;
1432 }
1433
1434 static const VMStateDescription vmstate_artist = {
1435 .name = "artist",
1436 .version_id = 3,
1437 .minimum_version_id = 2,
1438 .post_load = vmstate_artist_post_load,
1439 .fields = (const VMStateField[]) {
1440 VMSTATE_UINT16(height, ARTISTState),
1441 VMSTATE_UINT16(width, ARTISTState),
1442 VMSTATE_UINT16(depth, ARTISTState),
1443 VMSTATE_UINT32(fg_color, ARTISTState),
1444 VMSTATE_UINT32(bg_color, ARTISTState),
1445 VMSTATE_UINT32(vram_char_y, ARTISTState),
1446 VMSTATE_UINT32(vram_bitmask, ARTISTState),
1447 VMSTATE_UINT32(vram_start, ARTISTState),
1448 VMSTATE_UINT32(vram_pos, ARTISTState),
1449 VMSTATE_UINT32(vram_size, ARTISTState),
1450 VMSTATE_UINT32(blockmove_source, ARTISTState),
1451 VMSTATE_UINT32(blockmove_dest, ARTISTState),
1452 VMSTATE_UINT32(blockmove_size, ARTISTState),
1453 VMSTATE_UINT32(line_size, ARTISTState),
1454 VMSTATE_UINT32(line_end, ARTISTState),
1455 VMSTATE_UINT32(line_xy, ARTISTState),
1456 VMSTATE_UINT32(cursor_pos, ARTISTState),
1457 VMSTATE_UINT32(cursor_cntrl, ARTISTState),
1458 VMSTATE_UINT32(cursor_height, ARTISTState),
1459 VMSTATE_UINT32(cursor_width, ARTISTState),
1460 VMSTATE_UINT32(plane_mask, ARTISTState),
1461 VMSTATE_UINT32(reg_100080, ARTISTState),
1462 VMSTATE_UINT32(horiz_backporch, ARTISTState),
1463 VMSTATE_UINT32(active_lines_low, ARTISTState),
1464 VMSTATE_UINT32(misc_video, ARTISTState),
1465 VMSTATE_UINT32(misc_ctrl, ARTISTState),
1466 VMSTATE_UINT32(dst_bm_access, ARTISTState),
1467 VMSTATE_UINT32(src_bm_access, ARTISTState),
1468 VMSTATE_UINT32(control_plane, ARTISTState),
1469 VMSTATE_UINT32(transfer_data, ARTISTState),
1470 VMSTATE_UINT32(image_bitmap_op, ARTISTState),
1471 VMSTATE_UINT32(font_write1, ARTISTState),
1472 VMSTATE_UINT32(font_write2, ARTISTState),
1473 VMSTATE_UINT32(font_write_pos_y, ARTISTState),
1474 VMSTATE_BOOL(disable, ARTISTState),
1475 VMSTATE_END_OF_LIST()
1476 }
1477 };
1478
1479 static const Property artist_properties[] = {
1480 DEFINE_PROP_UINT16("width", ARTISTState, width, 1280),
1481 DEFINE_PROP_UINT16("height", ARTISTState, height, 1024),
1482 DEFINE_PROP_UINT16("depth", ARTISTState, depth, 8),
1483 DEFINE_PROP_BOOL("disable", ARTISTState, disable, false),
1484 };
1485
artist_reset(DeviceState * qdev)1486 static void artist_reset(DeviceState *qdev)
1487 {
1488 }
1489
artist_class_init(ObjectClass * klass,const void * data)1490 static void artist_class_init(ObjectClass *klass, const void *data)
1491 {
1492 DeviceClass *dc = DEVICE_CLASS(klass);
1493
1494 dc->realize = artist_realizefn;
1495 dc->vmsd = &vmstate_artist;
1496 device_class_set_legacy_reset(dc, artist_reset);
1497 device_class_set_props(dc, artist_properties);
1498 }
1499
1500 static const TypeInfo artist_info = {
1501 .name = TYPE_ARTIST,
1502 .parent = TYPE_SYS_BUS_DEVICE,
1503 .instance_size = sizeof(ARTISTState),
1504 .instance_init = artist_initfn,
1505 .class_init = artist_class_init,
1506 };
1507
artist_register_types(void)1508 static void artist_register_types(void)
1509 {
1510 type_register_static(&artist_info);
1511 }
1512
1513 type_init(artist_register_types)
1514