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