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