1 /*
2  * tape.c - Tape unit emulation.
3  *
4  * Written by
5  *  Ettore Perazzoli <ettore@comm2000.it>
6  *  Andreas Boose <viceteam@t-online.de>
7  *
8  * Based on older code by
9  *  Jouko Valta <jopi@stekt.oulu.fi>
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 <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "datasette.h"
38 #include "lib.h"
39 #include "log.h"
40 #include "machine.h"
41 #include "maincpu.h"
42 #include "mem.h"
43 #include "network.h"
44 #include "t64.h"
45 #include "tap.h"
46 #include "tape-internal.h"
47 #include "tape.h"
48 #include "tapeimage.h"
49 #include "traps.h"
50 #include "types.h"
51 #include "uiapi.h"
52 #include "vice-event.h"
53 
54 /* #define DEBUG_TAPE */
55 
56 /* Cassette Format Constants */
57 #define CAS_TYPE_OFFSET 0
58 #define CAS_STAD_OFFSET 1       /* start address */
59 #define CAS_ENAD_OFFSET 3       /* end address */
60 #define CAS_NAME_OFFSET 5       /* filename */
61 
62 /* CPU addresses for tape routine variables.  */
63 static uint16_t buffer_pointer_addr;
64 static uint16_t st_addr;
65 static uint16_t verify_flag_addr;
66 static uint16_t stal_addr;
67 static uint16_t eal_addr;
68 static uint16_t kbd_buf_addr;
69 static uint16_t kbd_buf_pending_addr;
70 static int irqval;
71 static uint16_t irqtmp;
72 
73 /* Flag: has tape been initialized?  */
74 static int tape_is_initialized = 0;
75 
76 /* Tape traps to be installed.  */
77 static const trap_t *tape_traps;
78 
79 /* Logging goes here.  */
80 static log_t tape_log = LOG_ERR;
81 
82 /* The tape image for device 1. */
83 tape_image_t *tape_image_dev1 = NULL;
84 
85 /* ------------------------------------------------------------------------- */
86 
set_st(uint8_t b)87 static inline void set_st(uint8_t b)
88 {
89     mem_store(st_addr, (uint8_t)(mem_read(st_addr) | b));
90 }
91 
92 /* ------------------------------------------------------------------------- */
93 
tape_traps_install(void)94 void tape_traps_install(void)
95 {
96     const trap_t *p;
97 
98     if (tape_traps != NULL) {
99         for (p = tape_traps; p->func != NULL; p++) {
100             traps_add(p);
101         }
102     }
103 }
104 
tape_traps_deinstall(void)105 void tape_traps_deinstall(void)
106 {
107     const trap_t *p;
108 
109     if (tape_traps != NULL) {
110         for (p = tape_traps; p->func != NULL; p++) {
111             traps_remove(p);
112         }
113     }
114 }
115 
tape_init_vars(const tape_init_t * init)116 static void tape_init_vars(const tape_init_t *init)
117 {
118     /* Set addresses of tape routine variables.  */
119     st_addr = init->st_addr;
120     buffer_pointer_addr = init->buffer_pointer_addr;
121     verify_flag_addr = init->verify_flag_addr;
122     irqtmp = init->irqtmp;
123     irqval = init->irqval;
124     stal_addr = init->stal_addr;
125     eal_addr = init->eal_addr;
126 
127     kbd_buf_addr = init->kbd_buf_addr;
128     kbd_buf_pending_addr = init->kbd_buf_pending_addr;
129 
130     tape_traps = init->trap_list;
131 }
132 
133 /* Initialize the tape emulation, using the traps in `trap_list'.  */
134 /* FIXME: This should be passed through a struct.  */
tape_init(const tape_init_t * init)135 int tape_init(const tape_init_t *init)
136 {
137     if (tape_log == LOG_ERR) {
138         tape_log = log_open("Tape");
139     }
140 
141     tape_internal_init();
142     tape_image_init();
143 
144     lib_free(tape_image_dev1);
145     tape_image_dev1 = lib_calloc(1, sizeof(tape_image_t));
146 
147     tap_init(init);
148 
149     tape_init_vars(init);
150     tape_traps_install();
151 
152     tape_is_initialized = 1;
153     return 0;
154 }
155 
156 /* re-init the traps, needed to switch between different configurations in x128 */
tape_reinit(const tape_init_t * init)157 int tape_reinit(const tape_init_t *init)
158 {
159     if (tape_is_initialized == 0) {
160         return -1;
161     }
162 
163     tape_traps_deinstall();
164     tape_traps = NULL;
165 
166     tape_init_vars(init);
167     tape_traps_install();
168 
169     return 0;
170 }
171 
tape_shutdown(void)172 void tape_shutdown(void)
173 {
174     lib_free(tape_image_dev1);
175 }
176 
tape_deinstall(void)177 int tape_deinstall(void)
178 {
179     if (!tape_is_initialized) {
180         return -1;
181     }
182 
183     if (tape_image_dev1->name != NULL &&
184         tape_image_dev1->type == TAPE_TYPE_T64) {
185         tape_image_detach_internal(1);
186     }
187 
188     tape_traps_deinstall();
189 
190     tape_traps = NULL;
191 
192     tape_is_initialized = 0;
193 
194     return 0;
195 }
196 
197 /* ------------------------------------------------------------------------- */
198 
199 /* Tape traps.  These functions implement the standard kernal replacements
200    for the tape functions.  Every emulator can either use these traps, or
201    install its own ones, by passing an appropriate `trap_list' to
202    `tape_init()'.  */
203 
204 /* Find the next Tape Header and load it onto the Tape Buffer.  */
tape_find_header_trap(void)205 int tape_find_header_trap(void)
206 {
207     int err;
208     uint8_t *cassette_buffer;
209 
210     cassette_buffer = mem_ram + (mem_read(buffer_pointer_addr) | (mem_read((uint16_t)(buffer_pointer_addr + 1)) << 8));
211 
212     if (tape_image_dev1->name == NULL
213         || tape_image_dev1->type != TAPE_TYPE_T64) {
214         err = 1;
215     } else {
216         t64_t *t64;
217         t64_file_record_t *rec;
218 
219         t64 = (t64_t *)tape_image_dev1->data;
220         rec = NULL;
221 
222         err = 0;
223         do {
224             if (t64_seek_to_next_file(t64, 1) < 0) {
225                 err = 1;
226                 break;
227             }
228 
229             rec = t64_get_current_file_record(t64);
230         } while (rec->entry_type != T64_FILE_RECORD_NORMAL);
231 
232         if (!err) {
233             cassette_buffer[CAS_TYPE_OFFSET] = machine_tape_type_default();
234             cassette_buffer[CAS_STAD_OFFSET] = rec->start_addr & 0xff;
235             cassette_buffer[CAS_STAD_OFFSET + 1] = rec->start_addr >> 8;
236             cassette_buffer[CAS_ENAD_OFFSET] = rec->end_addr & 0xff;
237             cassette_buffer[CAS_ENAD_OFFSET + 1] = rec->end_addr >> 8;
238             memcpy(cassette_buffer + CAS_NAME_OFFSET,
239                    rec->cbm_name, T64_REC_CBMNAME_LEN);
240         }
241     }
242 
243     if (err) {
244         cassette_buffer[CAS_TYPE_OFFSET] = TAPE_CAS_TYPE_EOF;
245     }
246 
247     mem_store(st_addr, 0);      /* Clear the STATUS word.  */
248     mem_store(verify_flag_addr, 0);
249 
250     if (irqtmp) {
251         mem_store(irqtmp, (uint8_t)(irqval & 0xff));
252         mem_store((uint16_t)(irqtmp + 1), (uint8_t)((irqval >> 8) & 0xff));
253     }
254 
255     /* Check if STOP has been pressed.  */
256     {
257         int i, n = mem_read(kbd_buf_pending_addr);
258 
259         maincpu_set_carry(0);
260         for (i = 0; i < n; i++) {
261             if (mem_read((uint16_t)(kbd_buf_addr + i)) == 0x3) {
262                 maincpu_set_carry(1);
263                 break;
264             }
265         }
266     }
267 
268     maincpu_set_zero(1);
269     return 1;
270 }
271 
tape_find_header_trap_plus4(void)272 int tape_find_header_trap_plus4(void)
273 {
274     int err;
275     uint8_t *cassette_buffer;
276 
277     cassette_buffer = mem_ram + buffer_pointer_addr;
278 
279     if (tape_image_dev1->name == NULL
280         || tape_image_dev1->type != TAPE_TYPE_T64) {
281         err = 1;
282     } else {
283         t64_t *t64;
284         t64_file_record_t *rec;
285 
286         t64 = (t64_t *)tape_image_dev1->data;
287         rec = NULL;
288 
289         err = 0;
290         do {
291             if (t64_seek_to_next_file(t64, 1) < 0) {
292                 err = 1;
293                 break;
294             }
295 
296             rec = t64_get_current_file_record(t64);
297         } while (rec->entry_type != T64_FILE_RECORD_NORMAL);
298 
299         if (!err) {
300             mem_store(0xF8, TAPE_CAS_TYPE_BAS);
301             cassette_buffer[CAS_STAD_OFFSET - 1] = rec->start_addr & 0xff;
302             cassette_buffer[CAS_STAD_OFFSET] = rec->start_addr >> 8;
303             cassette_buffer[CAS_ENAD_OFFSET - 1] = rec->end_addr & 0xff;
304             cassette_buffer[CAS_ENAD_OFFSET] = rec->end_addr >> 8;
305             memcpy(cassette_buffer + CAS_NAME_OFFSET - 1,
306                    rec->cbm_name, T64_REC_CBMNAME_LEN);
307         }
308     }
309 
310     if (err) {
311         mem_store(0xF8, TAPE_CAS_TYPE_EOF);
312     }
313 
314     mem_store(0xb6, 0x33);
315     mem_store(0xb7, 0x03);
316 
317     mem_store(st_addr, 0);      /* Clear the STATUS word.  */
318     mem_store(verify_flag_addr, 0);
319 
320     /* Check if STOP has been pressed.  */
321     {
322         int i, n = mem_read(kbd_buf_pending_addr);
323 
324         maincpu_set_carry(0);
325         for (i = 0; i < n; i++) {
326             if (mem_read((uint16_t)(kbd_buf_addr + i)) == 0x3) {
327                 maincpu_set_carry(1);
328                 break;
329             }
330         }
331     }
332 
333     maincpu_set_zero(1);
334     return 1;
335 }
336 
337 /* Cassette Data transfer trap.
338 
339    XR flags the function to be performed on IRQ:
340 
341    08   Write tape
342    0a   Write tape leader
343    0c   Normal keyscan
344    0e   Read tape
345 
346    Luckily enough, these values are valid for all the machines.  */
tape_receive_trap(void)347 int tape_receive_trap(void)
348 {
349     int len;
350     uint16_t start, end;
351     uint8_t st;
352 
353     start = (mem_read(stal_addr) | (mem_read((uint16_t)(stal_addr + 1)) << 8));
354     end = (mem_read(eal_addr) | (mem_read((uint16_t)(eal_addr + 1)) << 8));
355 
356     switch (maincpu_get_x()) {
357         case 0x0e:
358             {
359                 int amount;
360 
361                 len = (int)(end - start);
362                 amount = t64_read((t64_t *)tape_image_dev1->data, mem_ram + (int)start, len);
363                 if (amount == len) {
364                     st = 0x40;  /* EOF */
365                 } else {
366                     st = 0x10;
367 
368                     log_warning(tape_log,
369                                 "Unexpected end of tape: file may be truncated.");
370                 }
371             }
372             break;
373         default:
374             log_error(tape_log, "Kernal command %x not supported.",
375                       maincpu_get_x());
376             st = 0x40;
377             break;
378     }
379 
380     /* Set registers and flags like the Kernal routine does.  */
381 
382     if (irqtmp) {
383         mem_store(irqtmp, (uint8_t)(irqval & 0xff));
384         mem_store((uint16_t)(irqtmp + 1), (uint8_t)((irqval >> 8) & 0xff));
385     }
386 
387     set_st(st);                 /* EOF and possible errors */
388 
389     maincpu_set_carry(0);
390     maincpu_set_interrupt(0);
391     return 1;
392 }
393 
tape_receive_trap_plus4(void)394 int tape_receive_trap_plus4(void)
395 {
396     uint16_t start, end, len;
397     uint8_t st;
398 
399     start = (mem_read(stal_addr) | (mem_read((uint16_t)(stal_addr + 1)) << 8));
400     end = (mem_read(eal_addr) | (mem_read((uint16_t)(eal_addr + 1)) << 8));
401 
402     /* Read block.  */
403     len = end - start;
404 
405     if (t64_read((t64_t *)tape_image_dev1->data,
406                  mem_ram + (int) start, (int)len) == (int) len) {
407         st = 0x40;      /* EOF */
408     } else {
409         st = 0x10;
410 
411         log_warning(tape_log,
412                     "Unexpected end of tape: file may be truncated.");
413     }
414 
415     /* Set registers and flags like the Kernal routine does.  */
416 
417 
418     set_st(st);                 /* EOF and possible errors */
419     return 1;
420 }
421 
tape_get_file_name(void)422 const char *tape_get_file_name(void)
423 {
424     if (tape_image_dev1 == NULL) {
425         return "";
426     }
427 
428     return tape_image_dev1->name;
429 }
430 
tape_tap_attached(void)431 int tape_tap_attached(void)
432 {
433     if (tape_image_dev1->name != NULL
434         && tape_image_dev1->type == TAPE_TYPE_TAP) {
435         return 1;
436     }
437 
438     return 0;
439 }
440 
441 /* ------------------------------------------------------------------------- */
442 
443 /* Detach.  */
tape_image_detach_internal(unsigned int unit)444 int tape_image_detach_internal(unsigned int unit)
445 {
446     int retval = 0;
447     char event_data[2];
448 
449     if (unit != 1) {
450         return -1;
451     }
452 
453     if (tape_image_dev1 == NULL || tape_image_dev1->name == NULL) {
454         return 0;
455     }
456 
457     switch (tape_image_dev1->type) {
458         case TAPE_TYPE_T64:
459             log_message(tape_log,
460                         "Detaching T64 image `%s'.", tape_image_dev1->name);
461             /* Tape detached: release play button.  */
462             datasette_set_tape_sense(0);
463             break;
464         case TAPE_TYPE_TAP:
465             log_message(tape_log,
466                         "Detaching TAP image `%s'.", tape_image_dev1->name);
467             datasette_set_tape_image(NULL);
468 
469             tape_traps_install();
470             break;
471         default:
472             log_error(tape_log, "Unknown tape type %u.",
473                       tape_image_dev1->type);
474     }
475 
476     retval = tape_image_close(tape_image_dev1);
477 
478     ui_display_tape_current_image("");
479 
480     event_data[0] = (char)unit;
481     event_data[1] = 0;
482 
483     event_record(EVENT_ATTACHTAPE, (void *)event_data, 2);
484 
485     return retval;
486 }
487 
tape_image_detach(unsigned int unit)488 int tape_image_detach(unsigned int unit)
489 {
490     char event_data[2];
491 
492     if (unit != 1) {
493         return -1;
494     }
495 
496     event_data[0] = (char)unit;
497     event_data[1] = 0;
498 
499     if (event_playback_active()) {
500         return -1;
501     }
502 
503     if (network_connected()) {
504         network_event_record(EVENT_ATTACHTAPE, (void *)event_data, 2);
505         return 0;
506     }
507 
508     return tape_image_detach_internal(unit);
509 }
510 
511 /* Attach.  */
tape_image_attach_internal(unsigned int unit,const char * name)512 static int tape_image_attach_internal(unsigned int unit, const char *name)
513 {
514     tape_image_t tape_image;
515 
516     if (unit != 1) {
517         return -1;
518     }
519 
520     if (!name || !*name) {
521         return -1;
522     }
523 
524     tape_image.name = lib_strdup(name);
525     tape_image.read_only = 0;
526 
527     if (tape_image_open(&tape_image) < 0) {
528         lib_free(tape_image.name);
529         log_error(tape_log, "Cannot open file `%s'", name);
530         return -1;
531     }
532 
533     tape_image_detach_internal(unit);
534 
535     memcpy(tape_image_dev1, &tape_image, sizeof(tape_image_t));
536 
537     ui_display_tape_current_image(tape_image_dev1->name);
538 
539     switch (tape_image_dev1->type) {
540         case TAPE_TYPE_T64:
541             log_message(tape_log, "T64 image '%s' attached.", name);
542             /* Tape attached: press play button.  */
543             datasette_set_tape_sense(1);
544             break;
545         case TAPE_TYPE_TAP:
546             datasette_set_tape_image((tap_t *)tape_image_dev1->data);
547             log_message(tape_log, "TAP image '%s' attached.", name);
548             log_message(tape_log, "TAP image version: %i, system: %i.",
549                         ((tap_t *)tape_image_dev1->data)->version,
550                         ((tap_t *)tape_image_dev1->data)->system);
551             tape_traps_deinstall();
552             break;
553         default:
554             log_error(tape_log, "Unknown tape type %u.",
555                       tape_image_dev1->type);
556             return -1;
557     }
558 
559     event_record_attach_image(unit, 0, name, tape_image.read_only);
560 
561     return 0;
562 }
563 
tape_image_attach(unsigned int unit,const char * name)564 int tape_image_attach(unsigned int unit, const char *name)
565 {
566     if (event_playback_active()) {
567         return -1;
568     }
569 
570     if (network_connected()) {
571         network_attach_image(unit, name);
572         return 0;
573     }
574 
575     return tape_image_attach_internal(unit, name);
576 }
577 
tape_image_event_playback(unsigned int unit,const char * filename)578 void tape_image_event_playback(unsigned int unit, const char *filename)
579 {
580     if (filename == NULL || filename[0] == 0) {
581         tape_image_detach_internal(unit);
582     } else {
583         tape_image_attach_internal(unit, filename);
584     }
585 }
586