1 /*
2 * vicii-draw-cycle.c - Cycle based rendering for the VIC-II emulation.
3 *
4 * Written by
5 * Daniel Kahlin <daniel@kahlin.net>
6 *
7 * This file is part of VICE, the Versatile Commodore Emulator.
8 * See README for copyright notice.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 * 02111-1307 USA.
24 *
25 */
26
27 #include "vice.h"
28
29 #include <string.h>
30
31 #include "types.h"
32 #include "snapshot.h"
33 #include "vicii-chip-model.h"
34 #include "vicii-draw-cycle.h"
35 #include "viciitypes.h"
36
37 /* disable for debugging */
38 #define DRAW_INLINE inline
39
40 /* colors */
41 #define COL_NONE 0x10
42 #define COL_VBUF_L 0x11
43 #define COL_VBUF_H 0x12
44 #define COL_CBUF 0x13
45 #define COL_CBUF_MC 0x14
46 #define COL_D02X_EXT 0x15
47 #define COL_D020 0x20
48 #define COL_D021 0x21
49 #define COL_D022 0x22
50 #define COL_D023 0x23
51 #define COL_D024 0x24
52 #define COL_D025 0x25
53 #define COL_D026 0x26
54 #define COL_D027 0x27
55 #define COL_D028 0x28
56 #define COL_D029 0x29
57 #define COL_D02A 0x2a
58 #define COL_D02B 0x2b
59 #define COL_D02C 0x2c
60 #define COL_D02D 0x2d
61 #define COL_D02E 0x2e
62
63 /* foreground/background graphics */
64
65 static uint8_t gbuf_pipe0_reg = 0;
66 static uint8_t cbuf_pipe0_reg = 0;
67 static uint8_t vbuf_pipe0_reg = 0;
68 static uint8_t gbuf_pipe1_reg = 0;
69 static uint8_t cbuf_pipe1_reg = 0;
70 static uint8_t vbuf_pipe1_reg = 0;
71
72 static uint8_t xscroll_pipe = 0;
73 static uint8_t vmode11_pipe = 0;
74 static uint8_t vmode16_pipe = 0;
75 static uint8_t vmode16_pipe2 = 0;
76
77 /* gbuf shift register */
78 static uint8_t gbuf_reg = 0;
79 static uint8_t gbuf_mc_flop = 0;
80 static uint8_t gbuf_pixel_reg = 0;
81
82 /* cbuf and vbuf registers */
83 static uint8_t cbuf_reg = 0;
84 static uint8_t vbuf_reg = 0;
85
86 static uint8_t dmli = 0;
87
88 /* sprites */
89 static int sprite_x_pipe[8];
90 static uint8_t sprite_pri_bits = 0;
91 static uint8_t sprite_mc_bits = 0;
92 static uint8_t sprite_expx_bits = 0;
93
94 static uint8_t sprite_pending_bits = 0;
95 static uint8_t sprite_active_bits = 0;
96 static uint8_t sprite_halt_bits = 0;
97
98 /* sbuf shift registers */
99 static uint32_t sbuf_reg[8];
100 static uint8_t sbuf_pixel_reg[8];
101 static uint8_t sbuf_expx_flops;
102 static uint8_t sbuf_mc_flops;
103
104 /* border */
105 static int border_state = 0;
106
107 /* pixel buffer */
108 static uint8_t render_buffer[8];
109 static uint8_t pri_buffer[8];
110
111 static uint8_t pixel_buffer[8];
112
113 /* color resolution registers */
114 static uint8_t cregs[0x2f];
115 static uint8_t last_color_reg;
116 static uint8_t last_color_value;
117
118 static unsigned int cycle_flags_pipe;
119
120
121 /**************************************************************************
122 *
123 * SECTION draw_graphics()
124 *
125 ******/
126
127 static const uint8_t colors[] = {
128 COL_D021, COL_D021, COL_CBUF, COL_CBUF, /* ECM=0 BMM=0 MCM=0 */
129 COL_D021, COL_D022, COL_D023, COL_CBUF_MC, /* ECM=0 BMM=0 MCM=1 */
130 COL_VBUF_L, COL_VBUF_L, COL_VBUF_H, COL_VBUF_H, /* ECM=0 BMM=1 MCM=0 */
131 COL_D021, COL_VBUF_H, COL_VBUF_L, COL_CBUF, /* ECM=0 BMM=1 MCM=1 */
132 COL_D02X_EXT, COL_D02X_EXT, COL_CBUF, COL_CBUF, /* ECM=1 BMM=0 MCM=0 */
133 COL_NONE, COL_NONE, COL_NONE, COL_NONE, /* ECM=1 BMM=0 MCM=1 */
134 COL_NONE, COL_NONE, COL_NONE, COL_NONE, /* ECM=1 BMM=1 MCM=0 */
135 COL_NONE, COL_NONE, COL_NONE, COL_NONE /* ECM=1 BMM=1 MCM=1 */
136 };
137
draw_graphics(int i)138 static DRAW_INLINE void draw_graphics(int i)
139 {
140 uint8_t px;
141 uint8_t cc;
142 uint8_t pixel_pri;
143 uint8_t vmode;
144
145 /* Load new gbuf/vbuf/cbuf values at offset == xscroll */
146 if (i == xscroll_pipe) {
147 /* latch values at time xs */
148 vbuf_reg = vbuf_pipe1_reg;
149 cbuf_reg = cbuf_pipe1_reg;
150 gbuf_reg = gbuf_pipe1_reg;
151 gbuf_mc_flop = 1;
152 }
153
154 /*
155 * read pixels depending on video mode
156 * mc pixels if MCM=1 and BMM=1, or MCM=1 and cbuf bit 3 = 1
157 */
158 if (vmode16_pipe2) {
159 if ((vmode11_pipe & 0x08) || (cbuf_reg & 0x08)) {
160 /* mc pixels */
161 if (gbuf_mc_flop) {
162 gbuf_pixel_reg = gbuf_reg >> 6;
163 }
164 } else {
165 /* hires pixels */
166 gbuf_pixel_reg = (gbuf_reg & 0x80) ? 3 : 0;
167 }
168 } else {
169 /*
170 * some kludge magic to fix $d023 glitch at MCM=0 -> 1 during
171 * MC and non-MC chars.
172 * This is rather ugly. There must be a simpler solution.
173 */
174 if ((vmode11_pipe & 0x08) || (cbuf_reg & 0x08)) {
175 /* hires pixels */
176 gbuf_pixel_reg = (gbuf_reg & 0x80) ? 2 : 0;
177 } else {
178 /* hires pixels */
179 gbuf_pixel_reg = (gbuf_reg & 0x80) ? 3 : 0;
180 }
181 }
182 px = gbuf_pixel_reg;
183
184 /* shift the graphics buffer */
185 gbuf_reg <<= 1;
186 gbuf_mc_flop ^= 1;
187
188 /* Determine pixel color and priority */
189 vmode = vmode11_pipe | vmode16_pipe;
190 pixel_pri = (px & 0x2);
191 cc = colors[vmode | px];
192
193 /* lookup colors and render pixel */
194 switch (cc) {
195 case COL_NONE:
196 cc = 0;
197 break;
198 case COL_VBUF_L:
199 cc = vbuf_reg & 0x0f;
200 break;
201 case COL_VBUF_H:
202 cc = vbuf_reg >> 4;
203 break;
204 case COL_CBUF:
205 cc = cbuf_reg;
206 break;
207 case COL_CBUF_MC:
208 cc = cbuf_reg & 0x07;
209 break;
210 case COL_D02X_EXT:
211 cc = COL_D021 + (vbuf_reg >> 6);
212 break;
213 default:
214 break;
215 }
216
217 render_buffer[i] = cc;
218 pri_buffer[i] = pixel_pri;
219 }
220
draw_graphics8(unsigned int cycle_flags)221 static DRAW_INLINE void draw_graphics8(unsigned int cycle_flags)
222 {
223 int vis_en;
224
225 vis_en = cycle_is_visible(cycle_flags);
226
227 /* render pixels */
228 /* pixel 0 */
229 draw_graphics(0);
230 /* pixel 1 */
231 draw_graphics(1);
232 /* pixel 2 */
233 draw_graphics(2);
234 /* pixel 3 */
235 draw_graphics(3);
236 /* pixel 4 */
237 vmode16_pipe = ( vicii.regs[0x16] & 0x10 ) >> 2;
238 if (vicii.color_latency) {
239 /* handle rising edge of internal signal */
240 vmode11_pipe |= ( vicii.regs[0x11] & 0x60 ) >> 2;
241 }
242 draw_graphics(4);
243 /* pixel 5 */
244 draw_graphics(5);
245 /* pixel 6 */
246 if (vicii.color_latency) {
247 /* handle falling edge of internal signal */
248 vmode11_pipe &= ( vicii.regs[0x11] & 0x60 ) >> 2;
249 }
250 draw_graphics(6);
251 /* pixel 7 */
252 if (vmode16_pipe && !vmode16_pipe2) {
253 gbuf_mc_flop = 0;
254 }
255 vmode16_pipe2 = vmode16_pipe;
256 draw_graphics(7);
257
258 if (!vicii.color_latency) {
259 vmode11_pipe = ( vicii.regs[0x11] & 0x60 ) >> 2;
260 }
261
262 /* shift and put the next data into the pipe. */
263 vbuf_pipe1_reg = vbuf_pipe0_reg;
264 cbuf_pipe1_reg = cbuf_pipe0_reg;
265 gbuf_pipe1_reg = gbuf_pipe0_reg;
266
267 /* this makes sure gbuf is 0 outside the visible area
268 It should probably be done somewhere around the fetch instead */
269 if (vis_en && vicii.vborder == 0) {
270 gbuf_pipe0_reg = vicii.gbuf;
271 xscroll_pipe = vicii.regs[0x16] & 0x07;
272 } else {
273 gbuf_pipe0_reg = 0;
274 }
275
276 /* Only update vbuf and cbuf registers in the display state. */
277 if (vis_en && vicii.vborder == 0) {
278 if (!vicii.idle_state) {
279 vbuf_pipe0_reg = vicii.vbuf[dmli];
280 cbuf_pipe0_reg = vicii.cbuf[dmli];
281 } else {
282 vbuf_pipe0_reg = 0;
283 cbuf_pipe0_reg = 0;
284 }
285 }
286
287 /* update display index in the visible region */
288 if (vis_en) {
289 dmli++;
290 } else {
291 dmli = 0;
292 }
293 }
294
295
296
297 /**************************************************************************
298 *
299 * SECTION draw_sprites()
300 *
301 ******/
get_trigger_candidates(int xpos)302 static DRAW_INLINE uint8_t get_trigger_candidates(int xpos)
303 {
304 int s;
305 uint8_t candidate_bits = 0;
306
307 /* check for partial xpos match */
308 for (s = 0; s < 8; s++) {
309 if ((xpos & 0x1f8) == (sprite_x_pipe[s] & 0x1f8)) {
310 candidate_bits |= 1 << s;
311 }
312 }
313 return candidate_bits;
314 }
315
trigger_sprites(int xpos,uint8_t candidate_bits)316 static DRAW_INLINE void trigger_sprites(int xpos, uint8_t candidate_bits)
317 {
318 int s;
319
320 /* do nothing if no sprites are candidates or pending */
321 if (!candidate_bits || !sprite_pending_bits) {
322 return;
323 }
324
325 /* check for pending */
326 for (s = 0; s < 8; s++) {
327 uint8_t m = 1 << s;
328
329 /* start rendering on position match */
330 if ((candidate_bits & m) && (sprite_pending_bits & m) && !(sprite_active_bits & m) && !(sprite_halt_bits & m)) {
331 if (xpos == sprite_x_pipe[s]) {
332 sbuf_expx_flops |= m;
333 sbuf_mc_flops |= m;
334 sprite_active_bits |= m;
335 }
336 }
337 }
338 }
339
draw_sprites(int i)340 static DRAW_INLINE void draw_sprites(int i)
341 {
342 int s;
343 int active_sprite;
344 uint8_t collision_mask;
345
346 /* do nothing if all sprites are inactive */
347 if (!sprite_active_bits) {
348 return;
349 }
350
351 /* check for active sprites */
352 active_sprite = -1;
353 collision_mask = 0;
354 for (s = 7; s >= 0; --s) {
355 uint8_t m = 1 << s;
356
357 if (sprite_active_bits & m) {
358 /* render pixels if shift register or pixel reg still contains data */
359 if (sbuf_reg[s] || sbuf_pixel_reg[s]) {
360 if (!(sprite_halt_bits & m)) {
361 if (sbuf_expx_flops & m) {
362 if (sprite_mc_bits & m) {
363 if (sbuf_mc_flops & m) {
364 /* fetch 2 bits */
365 sbuf_pixel_reg[s] = (uint8_t)((sbuf_reg[s] >> 22) & 0x03);
366 }
367 sbuf_mc_flops ^= m;
368 } else {
369 /* fetch 1 bit and make it 0 or 2 */
370 sbuf_pixel_reg[s] = (uint8_t)(((sbuf_reg[s] >> 23) & 0x01 ) << 1);
371 }
372 }
373
374 /* shift the sprite buffer and handle expansion flags */
375 if (sbuf_expx_flops & m) {
376 sbuf_reg[s] <<= 1;
377 }
378 if (sprite_expx_bits & m) {
379 sbuf_expx_flops ^= m;
380 } else {
381 sbuf_expx_flops |= m;
382 }
383 }
384
385 /*
386 * set collision mask bits and determine the highest
387 * priority sprite number that has a pixel.
388 */
389 if (sbuf_pixel_reg[s]) {
390 active_sprite = s;
391 collision_mask |= m;
392 }
393 } else {
394 sprite_active_bits &= ~m;
395 }
396 }
397 }
398
399 if (collision_mask) {
400 uint8_t pixel_pri = pri_buffer[i];
401 int as = active_sprite;
402 uint8_t spri = sprite_pri_bits & (1 << as);
403 if (!(pixel_pri && spri)) {
404 switch (sbuf_pixel_reg[as]) {
405 case 1:
406 render_buffer[i] = COL_D025;
407 break;
408 case 2:
409 render_buffer[i] = COL_D027 + as;
410 break;
411 case 3:
412 render_buffer[i] = COL_D026;
413 break;
414 default:
415 break;
416 }
417 }
418 /* if there was a foreground pixel, trigger collision */
419 if (pixel_pri) {
420 vicii.sprite_background_collisions |= collision_mask;
421 }
422 }
423
424 /* if 2 or more bits are set, trigger collisions */
425 if (collision_mask & (collision_mask - 1)) {
426 vicii.sprite_sprite_collisions |= collision_mask;
427 }
428 }
429
430
update_sprite_mc_bits_6569(void)431 static DRAW_INLINE void update_sprite_mc_bits_6569(void)
432 {
433 uint8_t next_mc_bits = vicii.regs[0x1c];
434 uint8_t toggled = next_mc_bits ^ sprite_mc_bits;
435
436 sbuf_mc_flops &= ~toggled;
437 sprite_mc_bits = next_mc_bits;
438 }
439
update_sprite_mc_bits_8565(void)440 static DRAW_INLINE void update_sprite_mc_bits_8565(void)
441 {
442 uint8_t next_mc_bits = vicii.regs[0x1c];
443 uint8_t toggled = next_mc_bits ^ sprite_mc_bits;
444
445 sbuf_mc_flops ^= toggled & (~sbuf_expx_flops);
446 sprite_mc_bits = next_mc_bits;
447 }
448
update_sprite_data(unsigned int cycle_flags)449 static DRAW_INLINE void update_sprite_data(unsigned int cycle_flags)
450 {
451 if (cycle_is_sprite_dma1_dma2(cycle_flags)) {
452 int s = cycle_get_sprite_num(cycle_flags);
453 sbuf_reg[s] = vicii.sprite[s].data;
454 }
455 }
456
update_sprite_xpos(void)457 static DRAW_INLINE void update_sprite_xpos(void)
458 {
459 int s;
460 for (s = 0; s < 8; s++) {
461 sprite_x_pipe[s] = vicii.sprite[s].x;
462 }
463 }
464
465
466
draw_sprites8(unsigned int cycle_flags)467 static DRAW_INLINE void draw_sprites8(unsigned int cycle_flags)
468 {
469 uint8_t candidate_bits;
470 uint8_t dma_cycle_0 = 0;
471 uint8_t dma_cycle_2 = 0;
472 int xpos;
473 int spr_en;
474
475 xpos = cycle_get_xpos(cycle_flags);
476
477 spr_en = cycle_is_check_spr_disp(cycle_flags);
478
479 if (cycle_is_sprite_ptr_dma0(cycle_flags)) {
480 dma_cycle_0 = 1 << cycle_get_sprite_num(cycle_flags);
481 }
482 if (cycle_is_sprite_dma1_dma2(cycle_flags)) {
483 dma_cycle_2 = 1 << cycle_get_sprite_num(cycle_flags);
484 }
485 candidate_bits = get_trigger_candidates(xpos);
486
487 /* process and render sprites */
488 /* pixel 0 */
489 trigger_sprites(xpos + 0, candidate_bits);
490 draw_sprites(0);
491 /* pixel 1 */
492 trigger_sprites(xpos + 1, candidate_bits);
493 draw_sprites(1);
494 /* pixel 2 */
495 sprite_active_bits &= ~dma_cycle_2;
496 trigger_sprites(xpos + 2, candidate_bits);
497 draw_sprites(2);
498 /* pixel 3 */
499 sprite_halt_bits |= dma_cycle_0;
500 trigger_sprites(xpos + 3, candidate_bits);
501 draw_sprites(3);
502 /* pixel 4 */
503 if (spr_en) {
504 sprite_pending_bits = vicii.sprite_display_bits;
505 }
506 update_sprite_data(cycle_flags);
507 trigger_sprites(xpos + 4, candidate_bits);
508 draw_sprites(4);
509 /* pixel 5 */
510 trigger_sprites(xpos + 5, candidate_bits);
511 draw_sprites(5);
512 /* pixel 6 */
513 if (!vicii.color_latency) {
514 update_sprite_mc_bits_8565();
515 }
516 sprite_pri_bits = vicii.regs[0x1b];
517 sprite_expx_bits = vicii.regs[0x1d];
518 trigger_sprites(xpos + 6, candidate_bits);
519 draw_sprites(6);
520 /* pixel 7 */
521 if (vicii.color_latency) {
522 update_sprite_mc_bits_6569();
523 }
524 sprite_halt_bits &= ~dma_cycle_2;
525 trigger_sprites(xpos + 7, candidate_bits);
526 draw_sprites(7);
527
528 /* pipe xpos */
529 update_sprite_xpos();
530 }
531
532
533 /**************************************************************************
534 *
535 * SECTION draw_border()
536 *
537 ******/
538
draw_border8(void)539 static DRAW_INLINE void draw_border8(void)
540 {
541 uint8_t csel = vicii.regs[0x16] & 0x8;
542
543 #if 1
544 /* early exit for the no border case */
545 if (!(border_state || vicii.main_border)) {
546 return;
547 }
548 /* early exit for the continuous border case */
549 if (border_state && vicii.main_border) {
550 memset(render_buffer, COL_D020, 8);
551 return;
552 }
553 #endif
554
555 /*
556 * normal border handling in case there was a transition
557 * (the code below can handle all border logic)
558 */
559 if (csel) {
560 if (border_state) {
561 memset(render_buffer, COL_D020, 8);
562 }
563 border_state = vicii.main_border;
564 } else {
565 if (border_state) {
566 memset(render_buffer, COL_D020, 7);
567 }
568 border_state = vicii.main_border;
569 if (border_state) {
570 render_buffer[7] = COL_D020;
571 }
572 }
573 }
574
575
576 /**************************************************************************
577 *
578 * SECTION draw_colors()
579 *
580 ******/
581
update_cregs(void)582 static DRAW_INLINE void update_cregs(void)
583 {
584 last_color_reg = vicii.last_color_reg;
585 last_color_value = vicii.last_color_value;
586 vicii.last_color_reg = 0xff;
587 }
588
draw_colors_6569(int offs,int i)589 static DRAW_INLINE void draw_colors_6569(int offs, int i)
590 {
591 int lookup_index;
592
593 /* resolve any unresolved colors */
594 lookup_index = (i + 1) & 0x07;
595 pixel_buffer[lookup_index] = cregs[pixel_buffer[lookup_index]];
596
597 /* draw pixel to buffer */
598 vicii.dbuf[offs + i] = pixel_buffer[i];
599
600 pixel_buffer[i] = render_buffer[i];
601 }
602
draw_colors_8565(int offs,int i)603 static DRAW_INLINE void draw_colors_8565(int offs, int i)
604 {
605 int lookup_index;
606
607 lookup_index = i;
608 /* resolve any unresolved colors */
609
610 /* special case for grey dot handling */
611 if (i == 0 && pixel_buffer[lookup_index] == last_color_reg) {
612 pixel_buffer[lookup_index] = 0x0f;
613 } else {
614 pixel_buffer[lookup_index] = cregs[pixel_buffer[lookup_index]];
615 }
616
617 /* draw pixel to buffer */
618 vicii.dbuf[offs + i] = pixel_buffer[i];
619
620 pixel_buffer[i] = render_buffer[i];
621 }
622
draw_colors8(void)623 static DRAW_INLINE void draw_colors8(void)
624 {
625 int offs = vicii.dbuf_offset;
626
627 /* guard (could possibly be removed) */
628 if (offs > VICII_DRAW_BUFFER_SIZE - 8) {
629 return;
630 }
631
632 /* update color register (if written) */
633 if (last_color_reg != 0xff) {
634 cregs[last_color_reg] = last_color_value;
635 }
636
637 /* render pixels */
638 if (vicii.color_latency) {
639 draw_colors_6569(offs, 0);
640 draw_colors_6569(offs, 1);
641 draw_colors_6569(offs, 2);
642 draw_colors_6569(offs, 3);
643 draw_colors_6569(offs, 4);
644 draw_colors_6569(offs, 5);
645 draw_colors_6569(offs, 6);
646 draw_colors_6569(offs, 7);
647 } else {
648 draw_colors_8565(offs, 0);
649 draw_colors_8565(offs, 1);
650 draw_colors_8565(offs, 2);
651 draw_colors_8565(offs, 3);
652 draw_colors_8565(offs, 4);
653 draw_colors_8565(offs, 5);
654 draw_colors_8565(offs, 6);
655 draw_colors_8565(offs, 7);
656 }
657 vicii.dbuf_offset += 8;
658
659 update_cregs();
660 }
661
662
663 /**************************************************************************
664 *
665 * SECTION vicii_draw_cycle()
666 *
667 ******/
668
vicii_draw_cycle(void)669 void vicii_draw_cycle(void)
670 {
671 /* reset rendering on raster cycle 1 */
672 if (vicii.raster_cycle == 1) {
673 vicii.dbuf_offset = 0;
674 }
675
676 draw_graphics8(cycle_flags_pipe);
677
678 draw_sprites8(cycle_flags_pipe);
679
680 draw_border8();
681
682 draw_colors8();
683
684 cycle_flags_pipe = vicii.cycle_flags;
685 }
686
687
vicii_draw_cycle_init(void)688 void vicii_draw_cycle_init(void)
689 {
690 int i;
691
692 /* initialize the draw buffer */
693 memset(vicii.dbuf, 0, VICII_DRAW_BUFFER_SIZE);
694 vicii.dbuf_offset = 0;
695
696 /* initialize the pixel ring buffer. */
697 memset(pixel_buffer, 0, sizeof(pixel_buffer));
698
699 /* clear cregs and fill 0x00-0x0f with 1:1 mapping */
700 memset(cregs, 0, sizeof(cregs));
701 for (i = 0; i < 0x10; i++) {
702 cregs[i] = i;
703 }
704 vicii.last_color_reg = 0xff;
705 last_color_reg = 0xff;
706
707 cycle_flags_pipe = 0;
708 }
709
710
711 /**************************************************************************
712 *
713 * SECTION snapshot
714 *
715 ******/
716
717 /* FIXME this is likely way more state than needed */
718
vicii_draw_cycle_snapshot_write(snapshot_module_t * m)719 int vicii_draw_cycle_snapshot_write(snapshot_module_t *m)
720 {
721 int i;
722
723 if (0
724 || SMW_B(m, gbuf_pipe0_reg) < 0
725 || SMW_B(m, cbuf_pipe0_reg) < 0
726 || SMW_B(m, vbuf_pipe0_reg) < 0
727 || SMW_B(m, gbuf_pipe1_reg) < 0
728 || SMW_B(m, cbuf_pipe1_reg) < 0
729 || SMW_B(m, vbuf_pipe1_reg) < 0
730 || SMW_B(m, xscroll_pipe) < 0
731 || SMW_B(m, vmode11_pipe) < 0
732 || SMW_B(m, vmode16_pipe) < 0
733 || SMW_B(m, vmode16_pipe2) < 0
734 || SMW_B(m, gbuf_reg) < 0
735 || SMW_B(m, gbuf_mc_flop) < 0
736 || SMW_B(m, gbuf_pixel_reg) < 0
737 || SMW_B(m, cbuf_reg) < 0
738 || SMW_B(m, vbuf_reg) < 0
739 || SMW_B(m, dmli) < 0) {
740 return -1;
741 }
742
743 for (i = 0; i < 8; i++) {
744 if (SMW_DW(m, (uint32_t)sprite_x_pipe[i]) < 0) {
745 return -1;
746 }
747 }
748
749 if (0
750 || SMW_B(m, sprite_pri_bits) < 0
751 || SMW_B(m, sprite_mc_bits) < 0
752 || SMW_B(m, sprite_expx_bits) < 0
753 || SMW_B(m, sprite_pending_bits) < 0
754 || SMW_B(m, sprite_active_bits) < 0
755 || SMW_B(m, sprite_halt_bits) < 0) {
756 return -1;
757 }
758
759 for (i = 0; i < 8; i++) {
760 if (SMW_DW(m, sbuf_reg[i]) < 0) {
761 return -1;
762 }
763 }
764
765 if (0
766 || SMW_BA(m, sbuf_pixel_reg, 8) < 0
767 || SMW_B(m, sbuf_expx_flops) < 0
768 || SMW_B(m, sbuf_mc_flops) < 0
769 || SMW_B(m, (uint8_t)border_state) < 0
770 || SMW_BA(m, render_buffer, 8) < 0
771 || SMW_BA(m, pri_buffer, 8) < 0
772 || SMW_BA(m, pixel_buffer, 8) < 0
773 || SMW_BA(m, cregs, 0x2f) < 0
774 || SMW_B(m, last_color_reg) < 0
775 || SMW_B(m, last_color_value) < 0
776 || SMW_DW(m, (uint32_t)cycle_flags_pipe) < 0) {
777 return -1;
778 }
779
780 return 0;
781 }
782
vicii_draw_cycle_snapshot_read(snapshot_module_t * m)783 int vicii_draw_cycle_snapshot_read(snapshot_module_t *m)
784 {
785 int i;
786
787 if (0
788 || SMR_B(m, &gbuf_pipe0_reg) < 0
789 || SMR_B(m, &cbuf_pipe0_reg) < 0
790 || SMR_B(m, &vbuf_pipe0_reg) < 0
791 || SMR_B(m, &gbuf_pipe1_reg) < 0
792 || SMR_B(m, &cbuf_pipe1_reg) < 0
793 || SMR_B(m, &vbuf_pipe1_reg) < 0
794 || SMR_B(m, &xscroll_pipe) < 0
795 || SMR_B(m, &vmode11_pipe) < 0
796 || SMR_B(m, &vmode16_pipe) < 0
797 || SMR_B(m, &vmode16_pipe2) < 0
798 || SMR_B(m, &gbuf_reg) < 0
799 || SMR_B(m, &gbuf_mc_flop) < 0
800 || SMR_B(m, &gbuf_pixel_reg) < 0
801 || SMR_B(m, &cbuf_reg) < 0
802 || SMR_B(m, &vbuf_reg) < 0
803 || SMR_B(m, &dmli) < 0) {
804 return -1;
805 }
806
807 for (i = 0; i < 8; i++) {
808 if (SMR_DW_INT(m, &sprite_x_pipe[i]) < 0) {
809 return -1;
810 }
811 }
812
813 if (0
814 || SMR_B(m, &sprite_pri_bits) < 0
815 || SMR_B(m, &sprite_mc_bits) < 0
816 || SMR_B(m, &sprite_expx_bits) < 0
817 || SMR_B(m, &sprite_pending_bits) < 0
818 || SMR_B(m, &sprite_active_bits) < 0
819 || SMR_B(m, &sprite_halt_bits) < 0) {
820 return -1;
821 }
822
823 for (i = 0; i < 8; i++) {
824 if (SMR_DW(m, &sbuf_reg[i]) < 0) {
825 return -1;
826 }
827 }
828
829 if (0
830 || SMR_BA(m, sbuf_pixel_reg, 8) < 0
831 || SMR_B(m, &sbuf_expx_flops) < 0
832 || SMR_B(m, &sbuf_mc_flops) < 0
833 || SMR_B_INT(m, &border_state) < 0
834 || SMR_BA(m, render_buffer, 8) < 0
835 || SMR_BA(m, pri_buffer, 8) < 0
836 || SMR_BA(m, pixel_buffer, 8) < 0
837 || SMR_BA(m, cregs, 0x2f) < 0
838 || SMR_B(m, &last_color_reg) < 0
839 || SMR_B(m, &last_color_value) < 0
840 || SMR_DW_UINT(m, &cycle_flags_pipe) < 0) {
841 return -1;
842 }
843
844 return 0;
845 }
846