1 /*
2  * c64dtvblitter.c - C64DTV blitter
3  *
4  * Written by
5  *  M.Kiesel <mayne@users.sourceforge.net>
6  *  Hannu Nuotio <hannu.nuotio@tut.fi>
7  *  Daniel Kahlin <daniel@kahlin.net>
8  * Based on code by
9  *  Marco van den Heuvel <blackystardust68@yahoo.com>
10  *
11  * This file is part of VICE, the Versatile Commodore Emulator.
12  * See README for copyright notice.
13  *
14  *  This program is free software; you can redistribute it and/or modify
15  *  it under the terms of the GNU General Public License as published by
16  *  the Free Software Foundation; either version 2 of the License, or
17  *  (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27  *  02111-1307  USA.
28  *
29  */
30 
31 #include "vice.h"
32 
33 #include <string.h>
34 
35 #include "c64mem.h"
36 #include "c64dtvmem.h"
37 #include "c64dtvflash.h"
38 #include "c64dtvblitter.h"
39 #include "c64dtvdma.h"
40 #include "vicii-mem.h"
41 #include "cmdline.h"
42 #include "debug.h"
43 #include "lib.h"
44 #include "log.h"
45 #include "util.h"
46 #include "resources.h"
47 #include "maincpu.h"
48 #include "interrupt.h"
49 #include "snapshot.h"
50 
51 #ifdef DEBUG
52 static log_t c64dtvblitter_log = LOG_ERR;
53 #endif
54 
55 static unsigned int c64dtv_blitter_int_num;
56 
57 /* I/O of the blitter engine ($D3XX) */
58 uint8_t c64dtvmem_blitter[0x20];
59 
60 int blitter_active;
61 int blitter_on_irq;
62 
63 static int blit_sourceA_off;
64 static int blit_sourceB_off;
65 static int blit_dest_off;
66 static int blitter_busy;
67 static int blitter_irq;
68 
69 #ifdef DEBUG
70 static int blitter_log_enabled = 0;
71 #endif
72 
73 static uint8_t srca_data[4];
74 static int srca_data_offs;
75 static int srca_fetched;
76 static uint8_t srcb_data[4];
77 static int srcb_data_offs;
78 static uint8_t sourceA, sourceB;
79 static int blitter_count;
80 static enum { BLITTER_IDLE, BLITTER_READ_A, BLITTER_READ_B, BLITTER_WRITE } blitter_state;
81 static int sourceA_line_off;
82 static int sourceB_line_off;
83 static int dest_line_off;
84 static uint8_t lastA;
85 
86 
87 /* resource stuff */
88 static int dtvrevision;
89 static int have_blitter_bug;
90 
91 
92 #define GET_REG24(a) ((c64dtvmem_blitter[a + 2] << 16) | (c64dtvmem_blitter[a + 1] << 8) | c64dtvmem_blitter[a])
93 #define GET_REG16(a) ((c64dtvmem_blitter[a + 1] << 8) | c64dtvmem_blitter[a])
94 #define GET_REG8(a) (c64dtvmem_blitter[a])
95 
96 
97 /* shadow register fields */
98 static int reg03_sourceA_modulo;
99 static int reg05_sourceA_line_length;
100 static int reg07_sourceA_step;
101 static int reg0b_sourceB_modulo;
102 static int reg0d_sourceB_line_length;
103 static int reg0f_sourceB_step;
104 static int reg13_dest_modulo;
105 static int reg15_dest_line_length;
106 static int reg17_dest_step;
107 static int reg1a_sourceA_direction;
108 static int reg1a_sourceB_direction;
109 static int reg1a_dest_direction;
110 static int reg1b_force_sourceB_zero;
111 static int reg1b_write_if_sourceA_zero;
112 static int reg1b_write_if_sourceA_nonzero;
113 static int reg1e_sourceA_right_shift;
114 static int reg1e_mintermALU;
115 
116 
117 /* ------------------------------------------------------------------------- */
118 
c64dtvblitter_init(void)119 void c64dtvblitter_init(void)
120 {
121 #ifdef DEBUG
122     if (c64dtvblitter_log == LOG_ERR) {
123         c64dtvblitter_log = log_open("C64DTVBLITTER");
124     }
125 #endif
126 
127     /* init Blitter IRQ */
128     c64dtv_blitter_int_num = interrupt_cpu_status_int_new(maincpu_int_status, "C64DTVBLITTER");
129 }
130 
131 
c64dtvblitter_shutdown(void)132 void c64dtvblitter_shutdown(void)
133 {
134 }
135 
c64dtvblitter_reset(void)136 void c64dtvblitter_reset(void)
137 {
138     int i;
139 #ifdef DEBUG
140     if (blitter_log_enabled) {
141         log_message(c64dtvblitter_log, "reset");
142     }
143 #endif
144 
145     /* TODO move register file initialization somewhere else? */
146     for (i = 0; i < 0x20; ++i) {
147         c64dtvmem_blitter[i] = 0;
148     }
149 
150     c64dtvmem_blitter[0x07] = 0x10;
151     c64dtvmem_blitter[0x0f] = 0x10;
152     c64dtvmem_blitter[0x17] = 0x10;
153 
154     /* reset internal states */
155     blit_sourceA_off = 0;
156     blit_sourceB_off = 0;
157     blit_dest_off = 0;
158     blitter_busy = 0;
159     blitter_irq = 0;
160     blitter_on_irq = 0;
161     blitter_active = 0;
162 
163     blitter_count = 0;
164     blitter_state = BLITTER_IDLE;
165     srca_data_offs = -1;
166     srcb_data_offs = -1;
167     srca_fetched = 0;
168     sourceA = 0;
169     lastA = 0;
170     sourceB = 0;
171     sourceA_line_off = 0;
172     sourceB_line_off = 0;
173     dest_line_off = 0;
174 }
175 
176 /* ------------------------------------------------------------------------- */
177 /* blitter transfer state machine */
178 
do_blitter_read_a(void)179 static inline int do_blitter_read_a(void)
180 {
181     int was_read = 0;
182     int offs = (blit_sourceA_off >> 4) & 0x1ffffc;
183     int loffs = (blit_sourceA_off >> 4) & 0x000003;
184 
185     srca_fetched = 0;
186     if (offs != srca_data_offs) {
187         memcpy(srca_data, &mem_ram[offs], 4);
188         srca_data_offs = offs;
189         srca_fetched = 1;
190         was_read = 1;
191     }
192     sourceA = srca_data[loffs];
193     return was_read;
194 }
195 
do_blitter_read_b(void)196 static inline int do_blitter_read_b(void)
197 {
198     int was_read = 0;
199     int offs = (blit_sourceB_off >> 4) & 0x1ffffc;
200     int loffs = (blit_sourceB_off >> 4) & 0x000003;
201 
202     if (reg1b_force_sourceB_zero) {
203         sourceB = 0;
204         return 0;
205     }
206 
207     if (offs != srcb_data_offs) {
208         memcpy(srcb_data, &mem_ram[offs], 4);
209         srcb_data_offs = offs;
210         was_read = 1;
211     }
212     sourceB = srcb_data[loffs];
213     return was_read;
214 }
215 
216 
do_blitter_write(void)217 static inline int do_blitter_write(void)
218 {
219     int was_write = 0;
220     int offs = (blit_dest_off >> 4) & 0x1fffff;
221 
222     if ((reg1b_write_if_sourceA_zero && sourceA == 0) ||
223         (reg1b_write_if_sourceA_nonzero && sourceA != 0) ||
224         (have_blitter_bug && srca_fetched)) {
225         uint8_t dest;
226         uint8_t lastA_tmp = sourceA;
227         sourceA >>= reg1e_sourceA_right_shift;
228         sourceA |= lastA << (8 - reg1e_sourceA_right_shift);
229         lastA = lastA_tmp;
230 
231         dest = 0;
232         switch (reg1e_mintermALU) {
233             case 0: dest = sourceA & sourceB; break;
234             case 1: dest = ~(sourceA & sourceB); break;
235             case 2: dest = ~(sourceA | sourceB); break;
236             case 3: dest = sourceA | sourceB; break;
237             case 4: dest = sourceA ^ sourceB; break;
238             case 5: dest = ~(sourceA ^ sourceB); break;
239             case 6: dest = sourceA + sourceB; break;
240             case 7: dest = sourceA - sourceB; break;
241             default:
242                 break;
243         }
244         mem_ram[offs] = dest;
245         was_write = 1;
246     }
247 #ifdef DEBUG
248     if (blitter_log_enabled) {
249         log_message(c64dtvblitter_log,
250                 "Blitter: %s %x.%x/%x.%x to %x.%x, %d to go, minterm %d",
251                 was_write ? "transferred" : "skipped",
252                 (unsigned int)(blit_sourceA_off >> 4),
253                 (unsigned int)(blit_sourceA_off & 15),
254                 (unsigned int)(blit_sourceB_off >> 4),
255                 (unsigned int)(blit_sourceB_off & 15),
256                 (unsigned int)(blit_dest_off >> 4),
257                 (unsigned int)(blit_dest_off & 15),
258                 blitter_count - 1,
259                 reg1e_mintermALU);
260     }
261 #endif
262     return was_write;
263 }
264 
update_counters(void)265 static inline void update_counters(void)
266 {
267     if (sourceA_line_off >= reg05_sourceA_line_length) {
268         lastA = 0;
269         sourceA_line_off = 0;
270         blit_sourceA_off = ((blit_sourceA_off >> 4) + reg03_sourceA_modulo * reg1a_sourceA_direction) << 4;
271     } else {
272         sourceA_line_off++;
273         blit_sourceA_off += reg07_sourceA_step * reg1a_sourceA_direction;
274     }
275     if (sourceB_line_off >= reg0d_sourceB_line_length) {
276         sourceB_line_off = 0;
277         blit_sourceB_off = ((blit_sourceB_off >> 4) + reg0b_sourceB_modulo * reg1a_sourceB_direction) << 4;
278     } else {
279         sourceB_line_off++;
280         blit_sourceB_off += reg0f_sourceB_step * reg1a_sourceB_direction;
281     }
282     if (dest_line_off >= reg15_dest_line_length) {
283         dest_line_off = 0;
284         blit_dest_off = ((blit_dest_off >> 4) + reg13_dest_modulo * reg1a_dest_direction) << 4;
285     } else {
286         dest_line_off++;
287         blit_dest_off += reg17_dest_step * reg1a_dest_direction;
288     }
289 }
290 
291 /* 32 MHz processing clock */
292 #define SUBCYCLES 32
perform_blitter_cycle(void)293 static inline void perform_blitter_cycle(void)
294 {
295     int subcycle = 0;
296     while (subcycle < SUBCYCLES) {
297         switch (blitter_state) {
298             case BLITTER_IDLE:
299                 subcycle += SUBCYCLES;
300                 break;
301             case BLITTER_READ_A:
302                 if (blitter_count == 0) {
303                     blitter_state = BLITTER_IDLE;
304                     break;
305                 }
306 
307                 if (do_blitter_read_a()) {
308                     subcycle += SUBCYCLES;
309                 }
310                 blitter_state = BLITTER_READ_B;
311                 break;
312             case BLITTER_READ_B:
313                 if (do_blitter_read_b()) {
314                     subcycle += SUBCYCLES;
315                 }
316                 blitter_state = BLITTER_WRITE;
317                 break;
318             case BLITTER_WRITE:
319                 if (do_blitter_write()) {
320                     subcycle += SUBCYCLES;
321                 } else {
322                     subcycle += 1;
323                 }
324 
325                 update_counters();
326                 blitter_count--;
327 
328                 if (blitter_count == 0) {
329                     blitter_state = BLITTER_IDLE;
330                 } else {
331                     blitter_state = BLITTER_READ_A;
332                 }
333                 break;
334             default:
335 #ifdef DEBUG
336                 log_message(c64dtvblitter_log, "invalid state in perform_blitter_cycle()");
337 #endif
338                 blitter_state = BLITTER_IDLE;
339                 break;
340         }
341     }
342 }
343 
344 
345 /* ------------------------------------------------------------------------- */
346 
347 /* These are the $D3xx Blitter register engine handlers */
348 
c64dtvblitter_trigger_blitter(void)349 void c64dtvblitter_trigger_blitter(void)
350 {
351     if (!blitter_active) {
352         int sourceA_continue = GET_REG8(0x1f) & 0x02;
353         int sourceB_continue = GET_REG8(0x1f) & 0x04;
354         int dest_continue = GET_REG8(0x1f) & 0x08;
355 
356         /* last four bits of offsets are fractional */
357         if (!sourceA_continue) {
358             blit_sourceA_off = GET_REG24(0x00) & 0x3fffff;
359             blit_sourceA_off <<= 4;
360         }
361         if (!sourceB_continue) {
362             blit_sourceB_off = GET_REG24(0x08) & 0x3fffff;
363             blit_sourceB_off <<= 4;
364         }
365         if (!dest_continue) {
366             blit_dest_off = GET_REG24(0x10) & 0x3fffff;
367             blit_dest_off <<= 4;
368         }
369 
370 #ifdef DEBUG
371         if (blitter_log_enabled && (sourceA_continue || sourceB_continue || dest_continue)) {
372             log_message(c64dtvblitter_log, "sourceA cont %s, sourceB cont %s, dest cont %s", sourceA_continue ? "on" : "off", sourceB_continue ? "on" : "off", dest_continue ? "on" : "off");
373         }
374 #endif
375 
376         /* total number of bytes to transfer */
377         blitter_count = GET_REG16(0x18);
378 
379         /* initialize state variables */
380         sourceA_line_off = 0;
381         sourceB_line_off = 0;
382         dest_line_off = 0;
383         lastA = 0;
384         srca_data_offs = -1;
385         srcb_data_offs = -1;
386 
387         blitter_state = BLITTER_READ_A;
388 
389         if (GET_REG8(0x1a) & 0x80) {
390             blitter_irq = 1;
391         } else {
392             blitter_irq = 0;
393         }
394 
395         blitter_busy = 1;
396         blitter_active = 1;
397     }
398 }
399 
c64dtv_blitter_done(void)400 static inline void c64dtv_blitter_done(void)
401 {
402 #ifdef DEBUG
403     if (blitter_log_enabled) {
404         log_message(c64dtvblitter_log, "IRQ/Done");
405     }
406 #endif
407     if (blitter_irq) {
408         maincpu_set_irq(c64dtv_blitter_int_num, 1);
409         blitter_busy = 2;
410     }
411     blitter_busy &= 0xfe;
412     blitter_active = 0;
413 
414     /* Scheduled DMA */
415     if (dma_on_irq & 0x20) {
416         c64dtvdma_trigger_dma();
417     }
418 }
419 
420 
c64dtv_blitter_read(uint16_t addr)421 uint8_t c64dtv_blitter_read(uint16_t addr)
422 {
423     if (addr == 0x1f) {
424         return blitter_busy;
425         /* the default return value is 0x00 too but I have seen some strangeness
426            here.  I've seen something that looks like DMAed data. - tlr */
427     }
428     return 0x00;
429 }
430 
c64dtv_blitter_store(uint16_t addr,uint8_t value)431 void c64dtv_blitter_store(uint16_t addr, uint8_t value)
432 {
433     /* Store first, then check whether DMA access has been requested,
434        perform if necessary. */
435     c64dtvmem_blitter[addr] = value;
436 
437     switch (addr) {
438         case 0x03:
439         case 0x04:
440             reg03_sourceA_modulo = GET_REG16(0x03);
441             break;
442         case 0x05:
443         case 0x06:
444             reg05_sourceA_line_length = GET_REG16(0x05);
445             break;
446         case 0x07:
447             reg07_sourceA_step = GET_REG8(0x07);
448             break;
449         case 0x0b:
450         case 0x0c:
451             reg0b_sourceB_modulo = GET_REG16(0x0b);
452             break;
453         case 0x0d:
454         case 0x0e:
455             reg0d_sourceB_line_length = GET_REG16(0x0d);
456             break;
457         case 0x0f:
458             reg0f_sourceB_step = GET_REG8(0x0f);
459             break;
460         case 0x13:
461         case 0x14:
462             reg13_dest_modulo = GET_REG16(0x13);
463             break;
464         case 0x15:
465         case 0x16:
466             reg15_dest_line_length = GET_REG16(0x15);
467             break;
468         case 0x17:
469             reg17_dest_step = GET_REG8(0x17);
470             break;
471         case 0x1a:
472             reg1a_sourceA_direction = (GET_REG8(0x1a) & 0x02) ? +1 : -1;
473             reg1a_sourceB_direction = (GET_REG8(0x1a) & 0x04) ? +1 : -1;
474             reg1a_dest_direction = (GET_REG8(0x1a) & 0x08) ? +1 : -1;
475             break;
476         case 0x1b:
477             reg1b_force_sourceB_zero = GET_REG8(0x1b) & 0x01;
478             reg1b_write_if_sourceA_zero = GET_REG8(0x1b) & 0x02;
479             reg1b_write_if_sourceA_nonzero = GET_REG8(0x1b) & 0x04;
480 
481             /* zero and nonzero == 0 seems to do exactly the same as both ==1 */
482             if (!(reg1b_write_if_sourceA_zero || reg1b_write_if_sourceA_nonzero)) {
483                 reg1b_write_if_sourceA_zero = reg1b_write_if_sourceA_nonzero = 1;
484             }
485             break;
486         case 0x1e:
487             reg1e_sourceA_right_shift = GET_REG8(0x1e) & 0x07;
488             reg1e_mintermALU = (GET_REG8(0x1e) >> 3) & 0x07;
489             break;
490         default:
491             break;
492     }
493 
494     /* Blitter code */
495     blitter_on_irq = GET_REG8(0x1a) & 0x70;
496 
497     /* Clear Blitter IRQ */
498     if ((GET_REG8(0x1f) & 0x01) && (blitter_busy == 2)) {
499 #ifdef DEBUG
500         if (blitter_log_enabled) {
501             log_message(c64dtvblitter_log, "Clear IRQ (%i)", blitter_busy);
502         }
503 #endif
504         blitter_busy &= 0xfd;
505         maincpu_set_irq(c64dtv_blitter_int_num, 0);
506         blitter_irq = 0;
507         /* reset clear IRQ strobe bit */
508         c64dtvmem_blitter[0x1f] &= 0xfe;
509     }
510 
511     if (blitter_on_irq && (blitter_busy == 0)) {
512         blitter_busy = 1;
513 #ifdef DEBUG
514         if (blitter_log_enabled) {
515             log_message(c64dtvblitter_log, "Scheduled Blitter (%02x)",
516                     (unsigned int)blitter_on_irq);
517         }
518 #endif
519         return;
520     }
521 
522     /* Force Blitter start */
523     if (GET_REG8(0x1a) & 0x01) {
524         c64dtvblitter_trigger_blitter();
525         /* reset force start strobe bit */
526         c64dtvmem_blitter[0x1a] &= 0xfe;
527     }
528 }
529 
530 
c64dtvblitter_perform_blitter(void)531 void c64dtvblitter_perform_blitter(void)
532 {
533     perform_blitter_cycle();
534 
535     if (blitter_state == BLITTER_IDLE) {
536         c64dtv_blitter_done();
537     }
538 }
539 
540 /* ------------------------------------------------------------------------- */
set_dtvrevision(int val,void * param)541 static int set_dtvrevision(int val, void *param)
542 {
543     switch (val) {
544         default:
545         case 3:
546             dtvrevision = 3;
547             break;
548         case 2:
549             dtvrevision = 2;
550             break;
551     }
552     have_blitter_bug = (dtvrevision == 2) ? 1 : 0;
553     return 1;
554 }
555 
556 #ifdef DEBUG
set_blitter_log(int val,void * param)557 static int set_blitter_log(int val, void *param)
558 {
559     blitter_log_enabled = val ? 1 : 0;
560     return 0;
561 }
562 #endif
563 
564 static const resource_int_t resources_int[] = {
565     { "DtvRevision", 3, RES_EVENT_SAME, NULL,
566       &dtvrevision, set_dtvrevision, NULL },
567 #ifdef DEBUG
568     { "DtvBlitterLog", 0, RES_EVENT_NO, (resource_value_t)0,
569       &blitter_log_enabled, set_blitter_log, NULL },
570 #endif
571     RESOURCE_INT_LIST_END
572 };
573 
c64dtvblitter_resources_init(void)574 int c64dtvblitter_resources_init(void)
575 {
576     return resources_register_int(resources_int);
577 }
578 
c64dtvblitter_resources_shutdown(void)579 void c64dtvblitter_resources_shutdown(void)
580 {
581 }
582 
583 static const cmdline_option_t cmdline_options[] =
584 {
585     { "-dtvrev", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
586       NULL, NULL, "DtvRevision", NULL,
587       "<Revision>", "Specify DTV Revision (2: DTV2, 3: DTV3)" },
588 #ifdef DEBUG
589     { "-dtvblitterlog", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
590       NULL, NULL, "DtvBlitterLog", (resource_value_t)1,
591       NULL, "Enable DTV blitter logs." },
592     { "+dtvblitterlog", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
593       NULL, NULL, "DtvBlitterLog", (resource_value_t)0,
594       NULL, "Disable DTV blitter logs." },
595 #endif
596     CMDLINE_LIST_END
597 };
598 
c64dtvblitter_cmdline_options_init(void)599 int c64dtvblitter_cmdline_options_init(void)
600 {
601     return cmdline_register_options(cmdline_options);
602 }
603 
604 /* ------------------------------------------------------------------------- */
605 
606 /* C64DTVBLITTER snapshot module format:
607 
608    type  | name              | description
609    ---------------------------------------
610    ARRAY | regs              | 32 BYTES of register data
611    DWORD | source A off      | source A offset
612    DWORD | source B off      | source B offset
613    DWORD | dest off          | destination offset
614    DWORD | busy              | busy flag
615    DWORD | IRQ               | IRQ state
616    DWORD | on IRQ            | on IRQ flag
617    DWORD | active            | blitter active flag
618    ARRAY | source A data     | 4 BYTES of source A data
619    DWORD | source A data off | source A data offset
620    DWORD | source A fetched  | source A fetched counter
621    ARRAY | source B data     | 4 BYTES of source B data
622    DWORD | source B data off | source B data offset
623    BYTE  | source A          | source A
624    BYTE  | source B          | source B
625    DWORD | count             | blitter count
626    DWORD | state             | blitter state
627    DWORD | source A line off | source A line offset
628    DWORD | source B line off | source B line offset
629    DWORD | dest line off     | destination line offset
630    BYTE  | last A            | last A
631  */
632 
633 static const char snap_module_name[] = "C64DTVBLITTER";
634 #define SNAP_MAJOR 0
635 #define SNAP_MINOR 0
636 
637 /* static log_t c64_snapshot_log = LOG_ERR; */
638 
c64dtvblitter_snapshot_write_module(snapshot_t * s)639 int c64dtvblitter_snapshot_write_module(snapshot_t *s)
640 {
641     snapshot_module_t *m;
642 
643     /* Blitter module.  */
644     m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR);
645 
646     if (m == NULL) {
647         return -1;
648     }
649 
650     if (0
651         || SMW_BA(m, c64dtvmem_blitter, 0x20) < 0
652         || SMW_DW(m, blit_sourceA_off) < 0
653         || SMW_DW(m, blit_sourceB_off) < 0
654         || SMW_DW(m, blit_dest_off) < 0
655         || SMW_DW(m, blitter_busy) < 0
656         || SMW_DW(m, blitter_irq) < 0
657         || SMW_DW(m, blitter_on_irq) < 0
658         || SMW_DW(m, blitter_active) < 0
659         || SMW_BA(m, srca_data, 4) < 0
660         || SMW_DW(m, srca_data_offs) < 0
661         || SMW_DW(m, srca_fetched) < 0
662         || SMW_BA(m, srcb_data, 4) < 0
663         || SMW_DW(m, srcb_data_offs) < 0
664         || SMW_B(m, sourceA) < 0
665         || SMW_B(m, sourceB) < 0
666         || SMW_DW(m, blitter_count) < 0
667         || SMW_DW(m, blitter_state) < 0
668         || SMW_DW(m, sourceA_line_off) < 0
669         || SMW_DW(m, sourceB_line_off) < 0
670         || SMW_DW(m, dest_line_off) < 0
671         || SMW_B(m, lastA) < 0) {
672         snapshot_module_close(m);
673         return -1;
674     }
675 
676     return snapshot_module_close(m);
677 }
678 
c64dtvblitter_snapshot_read_module(snapshot_t * s)679 int c64dtvblitter_snapshot_read_module(snapshot_t *s)
680 {
681     uint8_t major_version, minor_version;
682     snapshot_module_t *m;
683     int temp_blitter_state, i;
684 
685     /* Blitter module.  */
686     m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version);
687 
688     if (m == NULL) {
689         return -1;
690     }
691 
692     /* Do not accept versions higher than current */
693     if (snapshot_version_is_bigger(major_version, minor_version, SNAP_MAJOR, SNAP_MINOR)) {
694         snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
695         goto fail;
696     }
697 
698     if (0
699         || SMR_BA(m, c64dtvmem_blitter, 0x20) < 0
700         || SMR_DW_INT(m, &blit_sourceA_off) < 0
701         || SMR_DW_INT(m, &blit_sourceB_off) < 0
702         || SMR_DW_INT(m, &blit_dest_off) < 0
703         || SMR_DW_INT(m, &blitter_busy) < 0
704         || SMR_DW_INT(m, &blitter_irq) < 0
705         || SMR_DW_INT(m, &blitter_on_irq) < 0
706         || SMR_DW_INT(m, &blitter_active) < 0
707         || SMR_BA(m, srca_data, 4) < 0
708         || SMR_DW_INT(m, &srca_data_offs) < 0
709         || SMR_DW_INT(m, &srca_fetched) < 0
710         || SMR_BA(m, srcb_data, 4) < 0
711         || SMR_DW_INT(m, &srcb_data_offs) < 0
712         || SMR_B(m, &sourceA) < 0
713         || SMR_B(m, &sourceB) < 0
714         || SMR_DW_INT(m, &blitter_count) < 0
715         || SMR_DW_INT(m, &temp_blitter_state) < 0
716         || SMR_DW_INT(m, &sourceA_line_off) < 0
717         || SMR_DW_INT(m, &sourceB_line_off) < 0
718         || SMR_DW_INT(m, &dest_line_off) < 0
719         || SMR_B(m, &lastA) < 0) {
720         goto fail;
721     }
722 
723     blitter_state = temp_blitter_state;
724 
725     for (i = 0; i < 0x20; ++i) {
726         c64dtv_blitter_store((uint16_t)i, c64dtvmem_blitter[i]);
727     }
728 
729     return snapshot_module_close(m);
730 
731 fail:
732     snapshot_module_close(m);
733     return -1;
734 }
735