This source file includes following definitions.
- _sim_tape_io_flush
- sim_tape_attach
- sim_tape_attach_ex
- sim_tape_detach
- sim_tape_attach_help
- sim_tape_data_trace
- sim_tape_rdlntf
- sim_tape_rdlntr
- sim_tape_rdrecf
- sim_tape_rdrecf_a
- sim_tape_rdrecr
- sim_tape_rdrecr_a
- sim_tape_wrrecf
- sim_tape_wrrecf_a
- sim_tape_wrdata
- sim_tape_wrtmk
- sim_tape_wrtmk_a
- sim_tape_wreom
- sim_tape_wreom_a
- sim_tape_wreomrw
- sim_tape_wreomrw_a
- sim_tape_wrgap
- sim_tape_wrgap_a
- sim_tape_sprecf
- sim_tape_sprecf_a
- sim_tape_sprecsf
- sim_tape_sprecsf_a
- sim_tape_sprecr
- sim_tape_sprecr_a
- sim_tape_sprecsr
- sim_tape_sprecsr_a
- sim_tape_spfilebyrecf
- sim_tape_spfilef
- sim_tape_spfilef_a
- sim_tape_spfilebyrecr
- sim_tape_spfilebyrecr_a
- sim_tape_spfiler
- sim_tape_spfiler_a
- sim_tape_rewind
- sim_tape_rewind_a
- sim_tape_reset
- sim_tape_bot
- sim_tape_eot
- sim_tape_wrp
- sim_tape_ioerr
- sim_tape_set_fmt
- sim_tape_show_fmt
- sim_tape_tpc_map
- sim_tape_simh_check
- sim_tape_e11_check
- sim_tape_tpc_fnd
- sim_tape_set_capac
- sim_tape_show_capac
- sim_tape_set_dens
- sim_tape_show_dens
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 #include "sim_defs.h"
73 #include "sim_tape.h"
74 #include <ctype.h>
75 #include <signal.h>
76
77 #define FREE(p) do \
78 { \
79 free((p)); \
80 (p) = NULL; \
81 } while(0)
82
83 struct sim_tape_fmt {
84 const char *name;
85 int32 uflags;
86 t_addr bot;
87 };
88
89 static struct sim_tape_fmt fmts[MTUF_N_FMT] = {
90 { "SIMH", 0, sizeof (t_mtrlnt) - 1 },
91 { "E11", 0, sizeof (t_mtrlnt) - 1 },
92 { "TPC", UNIT_RO, sizeof (t_tpclnt) - 1 },
93 { "P7B", 0, 0 },
94
95 { NULL, 0, 0 }
96 };
97
98 static const uint32 bpi [] = {
99 0,
100 200,
101 556,
102 800,
103 1600,
104 6250
105 };
106
107 #define BPI_COUNT (sizeof (bpi) / sizeof (bpi [0]))
108
109 static t_stat sim_tape_ioerr (UNIT *uptr);
110 static t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat);
111 static uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map, uint32 mapsize);
112 static t_stat sim_tape_simh_check (UNIT *uptr);
113 static t_stat sim_tape_e11_check (UNIT *uptr);
114 static t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map);
115 static void sim_tape_data_trace (UNIT *uptr, const uint8 *data, size_t len, const char* txt, int detail, uint32 reason);
116
117 struct tape_context {
118 DEVICE *dptr;
119 uint32 dbit;
120 uint32 auto_format;
121 };
122 #define tape_ctx up8
123
124
125
126
127
128 static void _sim_tape_io_flush (UNIT *uptr)
129 {
130 (void)fflush (uptr->fileref);
131 }
132
133
134
135 t_stat sim_tape_attach (UNIT *uptr, CONST char *cptr)
136 {
137 DEVICE *dptr;
138
139 if ((dptr = find_dev_from_unit (uptr)) == NULL)
140 return SCPE_NOATT;
141 return sim_tape_attach_ex (uptr, cptr, (dptr->flags & DEV_DEBUG) ? 0xFFFFFFFF : 0, 0);
142 }
143
144 t_stat sim_tape_attach_ex (UNIT *uptr, const char *cptr, uint32 dbit, int completion_delay)
145 {
146 struct tape_context *ctx;
147 uint32 objc;
148 DEVICE *dptr;
149 char gbuf[CBUFSIZE];
150 t_stat r;
151 t_bool auto_format = FALSE;
152
153 if ((dptr = find_dev_from_unit (uptr)) == NULL)
154 return SCPE_NOATT;
155 if (sim_switches & SWMASK ('F')) {
156 cptr = get_glyph (cptr, gbuf, 0);
157 if (*cptr == 0)
158 return SCPE_2FARG;
159 if (sim_tape_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK)
160 return sim_messagef (SCPE_ARG, "Invalid Tape Format: %s\n", gbuf);
161 sim_switches = sim_switches & ~(SWMASK ('F'));
162 auto_format = TRUE;
163 }
164 if (MT_GET_FMT (uptr) == MTUF_F_TPC)
165 sim_switches |= SWMASK ('R');
166 r = attach_unit (uptr, (CONST char *)cptr);
167 if (r != SCPE_OK)
168 return sim_messagef (r, "Can't open tape image: %s\n", cptr);
169 switch (MT_GET_FMT (uptr)) {
170
171 case MTUF_F_STD:
172 if (SCPE_OK != sim_tape_simh_check (uptr)) {
173 sim_tape_detach (uptr);
174 return SCPE_FMT;
175 }
176 break;
177
178 case MTUF_F_E11:
179 if (SCPE_OK != sim_tape_e11_check (uptr)) {
180 sim_tape_detach (uptr);
181 return SCPE_FMT;
182 }
183 break;
184
185 case MTUF_F_TPC:
186 objc = sim_tape_tpc_map (uptr, NULL, 0);
187 if (objc == 0) {
188 sim_tape_detach (uptr);
189 return SCPE_FMT;
190 }
191 uptr->filebuf = calloc (objc + 1, sizeof (t_addr));
192 if (uptr->filebuf == NULL) {
193 sim_tape_detach (uptr);
194 return SCPE_MEM;
195 }
196 uptr->hwmark = objc + 1;
197 sim_tape_tpc_map (uptr, (t_addr *) uptr->filebuf, objc);
198 break;
199
200 default:
201 break;
202 }
203
204 uptr->tape_ctx = ctx = (struct tape_context *)calloc(1, sizeof(struct tape_context));
205 if (!ctx)
206 {
207 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
208 __func__, __FILE__, __LINE__);
209 #if defined(USE_BACKTRACE)
210 # if defined(SIGUSR2)
211 (void)raise(SIGUSR2);
212
213 # endif
214 #endif
215 abort();
216 }
217 ctx->dptr = dptr;
218 ctx->dbit = dbit;
219 ctx->auto_format = auto_format;
220
221 sim_tape_rewind (uptr);
222
223 uptr->io_flush = _sim_tape_io_flush;
224
225 return SCPE_OK;
226 }
227
228
229
230 t_stat sim_tape_detach (UNIT *uptr)
231 {
232 struct tape_context *ctx;
233 uint32 f = 0;
234 t_stat r;
235 t_bool auto_format = FALSE;
236
237 if (uptr == NULL)
238 return SCPE_IERR;
239
240 if (!(uptr->flags & UNIT_ATT))
241 return SCPE_UNATT;
242
243 ctx = (struct tape_context *)uptr->tape_ctx;
244 f = MT_GET_FMT (uptr);
245
246 if (uptr->io_flush)
247 uptr->io_flush (uptr);
248 if (ctx)
249 auto_format = ctx->auto_format;
250
251 r = detach_unit (uptr);
252 if (r != SCPE_OK)
253 return r;
254 switch (f) {
255
256 case MTUF_F_TPC:
257 if (uptr->filebuf)
258 FREE (uptr->filebuf);
259 uptr->filebuf = NULL;
260 uptr->hwmark = 0;
261 break;
262
263 default:
264 break;
265 }
266
267 sim_tape_rewind (uptr);
268 FREE (uptr->tape_ctx);
269 uptr->tape_ctx = NULL;
270 uptr->io_flush = NULL;
271 if (auto_format)
272 sim_tape_set_fmt (uptr, 0, "SIMH", NULL);
273 return SCPE_OK;
274 }
275
276 t_stat sim_tape_attach_help(FILE *st, DEVICE *dptr, const UNIT *uptr, int32 flag, const char *cptr)
277 {
278 fprintf (st, "%s Tape Attach Help\n\n", dptr->name);
279 if (0 == (uptr-dptr->units)) {
280 if (dptr->numunits > 1) {
281 uint32 i;
282
283 for (i=0; i < dptr->numunits; ++i)
284 if (dptr->units[i].flags & UNIT_ATTABLE)
285 fprintf (st, " sim> ATTACH {switches} %s%lu tapefile\n\n", dptr->name, (unsigned long)i);
286 }
287 else
288 fprintf (st, " sim> ATTACH {switches} %s tapefile\n\n", dptr->name);
289 }
290 else
291 fprintf (st, " sim> ATTACH {switches} %s tapefile\n\n", dptr->name);
292 fprintf (st, "Attach command switches\n");
293 fprintf (st, " -R Attach Read Only.\n");
294 fprintf (st, " -E Must Exist (if not specified an attempt to create the indicated\n");
295 fprintf (st, " virtual tape will be attempted).\n");
296 fprintf (st, " -F Open the indicated tape container in a specific format (default\n");
297 fprintf (st, " is SIMH, alternatives are E11, TPC and P7B)\n");
298 return SCPE_OK;
299 }
300
301 static void sim_tape_data_trace(UNIT *uptr, const uint8 *data, size_t len, const char* txt, int detail, uint32 reason)
302 {
303 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
304
305 if (ctx == NULL)
306 return;
307 if (sim_deb && (ctx->dptr->dctrl & reason))
308 sim_data_trace(ctx->dptr, uptr, (detail ? data : NULL), "", len, txt, reason);
309 }
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396 static t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc)
397 {
398 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
399 uint8 c;
400 t_bool all_eof;
401 uint32 f = MT_GET_FMT (uptr);
402 t_mtrlnt sbc;
403 t_tpclnt tpcbc;
404 t_mtrlnt buffer [256];
405 size_t bufcntr, bufcap;
406 int32 runaway_counter, sizeof_gap;
407 t_stat r = MTSE_OK;
408
409 MT_CLR_PNU (uptr);
410
411 if ((uptr->flags & UNIT_ATT) == 0)
412 return MTSE_UNATT;
413 if (ctx == NULL)
414 return sim_messagef (SCPE_IERR, "Bad Attach\n");
415
416 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
417
418 switch (f) {
419
420 case MTUF_F_STD:
421 case MTUF_F_E11:
422 runaway_counter = 25 * 12 * bpi [MT_DENS (uptr->dynflags)];
423
424 if (runaway_counter == 0) {
425 sizeof_gap = 0;
426 runaway_counter = INT_MAX;
427 }
428 else
429 sizeof_gap = sizeof (t_mtrlnt);
430
431 bufcntr = 0;
432 bufcap = 0;
433
434 do {
435 if (bufcntr == bufcap) {
436 if (feof (uptr->fileref)) {
437 if (sizeof_gap > 0)
438 r = MTSE_RUNAWAY;
439 else
440 r = MTSE_EOM;
441 break;
442 }
443
444 else if (bufcap == 0)
445 bufcap = 1;
446
447 else
448 bufcap = sizeof (buffer)
449 / sizeof (buffer [0]);
450
451 bufcap = sim_fread (buffer,
452 sizeof (t_mtrlnt),
453 bufcap,
454 uptr->fileref);
455
456 if (ferror (uptr->fileref)) {
457 if (bufcntr == 0)
458 MT_SET_PNU (uptr);
459
460 r = sim_tape_ioerr (uptr);
461 break;
462 }
463
464 else if (bufcap == 0
465 || buffer [0] == MTR_EOM)
466 if (bufcntr == 0) {
467 MT_SET_PNU (uptr);
468 r = MTSE_EOM;
469 break;
470 }
471
472 else {
473 if (sizeof_gap > 0)
474 r = MTSE_RUNAWAY;
475 else
476 r = MTSE_EOM;
477 break;
478 }
479
480 else
481 bufcntr = 0;
482 }
483
484 *bc = buffer [bufcntr++];
485
486 if (*bc == MTR_EOM) {
487 if (sizeof_gap > 0)
488 r = MTSE_RUNAWAY;
489 else
490 r = MTSE_EOM;
491 break;
492 }
493
494 uptr->pos = uptr->pos + sizeof (t_mtrlnt);
495
496 if (*bc == MTR_TMK) {
497 r = MTSE_TMK;
498 break;
499 }
500
501 else if (*bc == MTR_GAP)
502 runaway_counter -= sizeof_gap;
503
504 else if (*bc == MTR_FHGAP) {
505 uptr->pos = uptr->pos - sizeof (t_mtrlnt) / 2;
506 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
507 bufcntr = bufcap;
508
509 *bc = MTR_GAP;
510 runaway_counter -= sizeof_gap / 2;
511 }
512
513 else {
514 if (bufcntr < bufcap)
515 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
516
517 sbc = MTR_L (*bc);
518 uptr->pos = uptr->pos + sizeof (t_mtrlnt)
519 + (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc);
520 }
521 }
522 while (*bc == MTR_GAP && runaway_counter > 0);
523
524 if (r == MTSE_OK && runaway_counter <= 0)
525 r = MTSE_RUNAWAY;
526
527 break;
528
529 case MTUF_F_TPC:
530 (void)sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
531 *bc = tpcbc;
532 if (ferror (uptr->fileref)) {
533 MT_SET_PNU (uptr);
534 return sim_tape_ioerr (uptr);
535 }
536 if (feof (uptr->fileref)) {
537 MT_SET_PNU (uptr);
538 r = MTSE_EOM;
539 break;
540 }
541 uptr->pos = uptr->pos + sizeof (t_tpclnt);
542 if (tpcbc == TPC_TMK)
543 r = MTSE_TMK;
544 uptr->pos = uptr->pos + ((tpcbc + 1) & ~1);
545 break;
546
547 case MTUF_F_P7B:
548 for (sbc = 0, all_eof = 1; ; sbc++) {
549 (void)sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
550 if (ferror (uptr->fileref)) {
551 MT_SET_PNU (uptr);
552 return sim_tape_ioerr (uptr);
553 }
554 if (feof (uptr->fileref)) {
555 if (sbc == 0)
556 return MTSE_EOM;
557 break;
558 }
559 if ((sbc != 0) && (c & P7B_SOR))
560 break;
561 if ((c & P7B_DPAR) != P7B_EOF)
562 all_eof = 0;
563 }
564 *bc = sbc;
565 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
566 uptr->pos = uptr->pos + sbc;
567 if (all_eof)
568 r = MTSE_TMK;
569 break;
570
571 default:
572 return MTSE_FMT;
573 }
574 #if defined(TESTING)
575 sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %lld, lnt: %lld, pos: %" T_ADDR_FMT "u\n",
576 (long long)r, (long long)*bc, uptr->pos);
577 #endif
578 return r;
579 }
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610 static t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc)
611 {
612 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
613 uint8 c;
614 t_bool all_eof;
615 uint32 f = MT_GET_FMT (uptr);
616 t_addr ppos;
617 t_mtrlnt sbc;
618 t_tpclnt tpcbc;
619 t_mtrlnt buffer [256];
620 size_t bufcntr, bufcap;
621 int32 runaway_counter, sizeof_gap;
622 t_stat r = MTSE_OK;
623
624 MT_CLR_PNU (uptr);
625 *bc = 0;
626
627 if ((uptr->flags & UNIT_ATT) == 0)
628 return MTSE_UNATT;
629 if (ctx == NULL)
630 return sim_messagef (SCPE_IERR, "Bad Attach\n");
631
632 if (sim_tape_bot (uptr))
633 return MTSE_BOT;
634
635 switch (f) {
636
637 case MTUF_F_STD:
638 case MTUF_F_E11:
639 runaway_counter = 25 * 12 * bpi [MT_DENS (uptr->dynflags)];
640
641 if (runaway_counter == 0) {
642 sizeof_gap = 0;
643 runaway_counter = INT_MAX;
644 }
645
646 else
647 sizeof_gap = sizeof (t_mtrlnt);
648
649 bufcntr = 0;
650 bufcap = 1;
651
652 do {
653 if (bufcntr == 0) {
654 if (sim_tape_bot (uptr)) {
655 r = MTSE_BOT;
656 break;
657 }
658
659 else if (uptr->pos < sizeof (buffer))
660 bufcap = (size_t) uptr->pos
661 / sizeof (t_mtrlnt);
662
663 (void)sim_fseek (uptr->fileref,
664 uptr->pos - bufcap * sizeof (t_mtrlnt),
665 SEEK_SET);
666
667 bufcntr = sim_fread (buffer, sizeof (t_mtrlnt),
668 bufcap, uptr->fileref);
669
670 if (ferror (uptr->fileref)) {
671 MT_SET_PNU (uptr);
672 r = sim_tape_ioerr (uptr);
673 break;
674 }
675
676 else
677 bufcap = sizeof (buffer)
678 / sizeof (buffer [0]);
679 }
680
681 *bc = buffer [--bufcntr];
682
683 uptr->pos = uptr->pos - sizeof (t_mtrlnt);
684
685 if (*bc == MTR_TMK) {
686 r = MTSE_TMK;
687 break;
688 }
689
690 else if (*bc == MTR_GAP)
691 runaway_counter -= sizeof_gap;
692
693 else if ((*bc & MTR_M_RHGAP) == MTR_RHGAP
694 || *bc == MTR_RRGAP) {
695 uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2;
696 bufcntr = 0;
697
698 *bc = MTR_GAP;
699 runaway_counter -= sizeof_gap / 2;
700 }
701
702 else {
703 sbc = MTR_L (*bc);
704 uptr->pos = uptr->pos - sizeof (t_mtrlnt)
705 - (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc);
706 (void)sim_fseek (uptr->fileref,
707 uptr->pos + sizeof (t_mtrlnt), SEEK_SET);
708 }
709 }
710 while (*bc == MTR_GAP && runaway_counter > 0);
711
712 if (r == MTSE_OK && runaway_counter <= 0)
713 r = MTSE_RUNAWAY;
714
715 break;
716
717 case MTUF_F_TPC:
718 ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf);
719 (void)sim_fseek (uptr->fileref, ppos, SEEK_SET);
720 (void)sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
721 *bc = tpcbc;
722 if (ferror (uptr->fileref))
723 return sim_tape_ioerr (uptr);
724 if (feof (uptr->fileref)) {
725 r = MTSE_EOM;
726 break;
727 }
728 uptr->pos = ppos;
729 if (*bc == MTR_TMK) {
730 r = MTSE_TMK;
731 break;
732 }
733 (void)sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET);
734 break;
735
736 case MTUF_F_P7B:
737 for (sbc = 1, all_eof = 1; (t_addr) sbc <= uptr->pos ; sbc++) {
738 (void)sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET);
739 (void)sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
740 if (ferror (uptr->fileref))
741 return sim_tape_ioerr (uptr);
742 if (feof (uptr->fileref)) {
743 r = MTSE_EOM;
744 break;
745 }
746 if ((c & P7B_DPAR) != P7B_EOF)
747 all_eof = 0;
748 if (c & P7B_SOR)
749 break;
750 }
751 uptr->pos = uptr->pos - sbc;
752 *bc = sbc;
753 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
754 if (all_eof)
755 r = MTSE_TMK;
756 break;
757
758 default:
759 return MTSE_FMT;
760 }
761 sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %lld, lnt: %lld, pos: %" T_ADDR_FMT "u\n",
762 (long long)r, (long long)*bc, uptr->pos);
763 return r;
764 }
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787 t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
788 {
789 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
790 uint32 f = MT_GET_FMT (uptr);
791 t_mtrlnt i, tbc, rbc;
792 t_addr opos;
793 t_stat st;
794
795 if (ctx == NULL)
796 return sim_messagef (SCPE_IERR, "Bad Attach\n");
797 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rdrecf(unit=%d, buf=%p, max=%lld)\n",
798 (int)(uptr-ctx->dptr->units), buf, (long long)max);
799
800 opos = uptr->pos;
801 if (MTSE_OK != (st = sim_tape_rdlntf (uptr, &tbc)))
802 return st;
803 *bc = rbc = MTR_L (tbc);
804 if (rbc > max) {
805 MT_SET_PNU (uptr);
806 uptr->pos = opos;
807 return MTSE_INVRL;
808 }
809 i = (t_mtrlnt)sim_fread (buf, sizeof (uint8), rbc, uptr->fileref);
810 if (ferror (uptr->fileref)) {
811 MT_SET_PNU (uptr);
812 uptr->pos = opos;
813 return sim_tape_ioerr (uptr);
814 }
815 for ( ; i < rbc; i++)
816 buf[i] = 0;
817 if (f == MTUF_F_P7B)
818 buf[0] = buf[0] & P7B_DPAR;
819 sim_tape_data_trace(uptr, buf, rbc, "Record Read", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
820 return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
821 }
822
823 t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback)
824 {
825 t_stat r = SCPE_OK;
826 r = sim_tape_rdrecf (uptr, buf, bc, max);
827 return r;
828 }
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852 t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
853 {
854 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
855 uint32 f = MT_GET_FMT (uptr);
856 t_mtrlnt i, rbc, tbc;
857 t_stat st;
858
859 if (ctx == NULL)
860 return sim_messagef (SCPE_IERR, "Bad Attach\n");
861 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rdrecr(unit=%d, buf=%p, max=%lld)\n",
862 (int)(uptr-ctx->dptr->units), buf, (long long)max);
863
864 if (MTSE_OK != (st = sim_tape_rdlntr (uptr, &tbc)))
865 return st;
866 *bc = rbc = MTR_L (tbc);
867 if (rbc > max)
868 return MTSE_INVRL;
869 i = (t_mtrlnt)sim_fread (buf, sizeof (uint8), rbc, uptr->fileref);
870 if (ferror (uptr->fileref))
871 return sim_tape_ioerr (uptr);
872 for ( ; i < rbc; i++)
873 buf[i] = 0;
874 if (f == MTUF_F_P7B)
875 buf[0] = buf[0] & P7B_DPAR;
876 sim_tape_data_trace(uptr, buf, rbc, "Record Read Reverse", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
877 return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
878 }
879
880 t_stat sim_tape_rdrecr_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback)
881 {
882 t_stat r = SCPE_OK;
883 r = sim_tape_rdrecr (uptr, buf, bc, max);
884 return r;
885 }
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904 t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc)
905 {
906 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
907 uint32 f = MT_GET_FMT (uptr);
908 t_mtrlnt sbc;
909
910 if (ctx == NULL)
911 return sim_messagef (SCPE_IERR, "Bad Attach\n");
912 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrrecf(unit=%d, buf=%p, bc=%lld)\n",
913 (int)(uptr-ctx->dptr->units), buf, (long long)bc);
914
915 sim_tape_data_trace(uptr, buf, bc, "Record Write", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
916 MT_CLR_PNU (uptr);
917 sbc = MTR_L (bc);
918 if ((uptr->flags & UNIT_ATT) == 0)
919 return MTSE_UNATT;
920 if (sim_tape_wrp (uptr))
921 return MTSE_WRP;
922 if (sbc == 0)
923 return MTSE_OK;
924 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
925 switch (f) {
926
927 case MTUF_F_STD:
928 sbc = MTR_L ((bc + 1) & ~1);
929
930 case MTUF_F_E11:
931 (void)sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
932 (void)sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
933 (void)sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
934 if (ferror (uptr->fileref)) {
935 MT_SET_PNU (uptr);
936 return sim_tape_ioerr (uptr);
937 }
938 uptr->pos = uptr->pos + sbc + (2 * sizeof (t_mtrlnt));
939 break;
940
941 case MTUF_F_P7B:
942 buf[0] = buf[0] | P7B_SOR;
943 (void)sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
944 (void)sim_fwrite (buf, sizeof (uint8), 1, uptr->fileref);
945 if (ferror (uptr->fileref)) {
946 MT_SET_PNU (uptr);
947 return sim_tape_ioerr (uptr);
948 }
949 uptr->pos = uptr->pos + sbc;
950 break;
951 }
952 sim_tape_data_trace(uptr, buf, sbc, "Record Written", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
953 return MTSE_OK;
954 }
955
956 t_stat sim_tape_wrrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt bc, TAPE_PCALLBACK callback)
957 {
958 t_stat r = SCPE_OK;
959 r = sim_tape_wrrecf (uptr, buf, bc);
960 return r;
961 }
962
963
964
965 static t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat)
966 {
967 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
968
969 MT_CLR_PNU (uptr);
970 if ((uptr->flags & UNIT_ATT) == 0)
971 return MTSE_UNATT;
972 if (ctx == NULL)
973 return sim_messagef (SCPE_IERR, "Bad Attach\n");
974 if (sim_tape_wrp (uptr))
975 return MTSE_WRP;
976 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
977 (void)sim_fwrite (&dat, sizeof (uint32_t), 1, uptr->fileref);
978 if (ferror (uptr->fileref)) {
979 MT_SET_PNU (uptr);
980 return sim_tape_ioerr (uptr);
981 }
982 sim_debug (MTSE_DBG_STR, ctx->dptr, "wr_lnt: lnt: %lld, pos: %" T_ADDR_FMT "u\n",
983 (long long)dat, uptr->pos);
984 uptr->pos = uptr->pos + sizeof (uint32_t);
985 return MTSE_OK;
986 }
987
988
989
990 t_stat sim_tape_wrtmk (UNIT *uptr)
991 {
992 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
993
994 if (ctx == NULL)
995 return sim_messagef (SCPE_IERR, "Bad Attach\n");
996 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrtmk(unit=%d)\n", (int)(uptr-ctx->dptr->units));
997 if (MT_GET_FMT (uptr) == MTUF_F_P7B) {
998 uint8 buf = P7B_EOF;
999 return sim_tape_wrrecf (uptr, &buf, 1);
1000 }
1001 return sim_tape_wrdata (uptr, MTR_TMK);
1002 }
1003
1004 t_stat sim_tape_wrtmk_a (UNIT *uptr, TAPE_PCALLBACK callback)
1005 {
1006 t_stat r = MTSE_OK;
1007 r = sim_tape_wrtmk (uptr);
1008 return r;
1009 }
1010
1011
1012
1013 t_stat sim_tape_wreom (UNIT *uptr)
1014 {
1015 t_stat result;
1016 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1017
1018 if (ctx == NULL)
1019 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1020 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wreom(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1021 if (MT_GET_FMT (uptr) == MTUF_F_P7B)
1022 return MTSE_FMT;
1023
1024 result = sim_tape_wrdata (uptr, MTR_EOM);
1025
1026 uptr->pos = uptr->pos - sizeof (t_mtrlnt);
1027 MT_SET_PNU (uptr);
1028
1029 return result;
1030 }
1031
1032 t_stat sim_tape_wreom_a (UNIT *uptr, TAPE_PCALLBACK callback)
1033 {
1034 t_stat r = MTSE_OK;
1035 r = sim_tape_wreom (uptr);
1036 return r;
1037 }
1038
1039
1040
1041 t_stat sim_tape_wreomrw (UNIT *uptr)
1042 {
1043 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1044 t_stat r;
1045
1046 if (ctx == NULL)
1047 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1048 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wreomrw(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1049 if (MT_GET_FMT (uptr) == MTUF_F_P7B)
1050 return MTSE_FMT;
1051 r = sim_tape_wrdata (uptr, MTR_EOM);
1052 if (r == MTSE_OK)
1053 r = sim_tape_rewind (uptr);
1054 return r;
1055 }
1056
1057 t_stat sim_tape_wreomrw_a (UNIT *uptr, TAPE_PCALLBACK callback)
1058 {
1059 t_stat r = MTSE_OK;
1060 r = sim_tape_wreomrw (uptr);
1061 return r;
1062 }
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164 t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen)
1165 {
1166 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1167 t_stat st;
1168 t_mtrlnt meta, sbc, new_len, rec_size;
1169 t_addr gap_pos = uptr->pos;
1170 uint32 file_size, marker_count, tape_density;
1171 int32 gap_needed;
1172 uint32 gap_alloc = 0;
1173 const uint32 format = MT_GET_FMT (uptr);
1174 const uint32 meta_size = sizeof (t_mtrlnt);
1175 const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2;
1176
1177 if (ctx == NULL)
1178 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1179 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrgap(unit=%d, gaplen=%u)\n", (int)(uptr-ctx->dptr->units), gaplen);
1180
1181 MT_CLR_PNU (uptr);
1182
1183 if ((uptr->flags & UNIT_ATT) == 0)
1184 return MTSE_UNATT;
1185
1186 else if (sim_tape_wrp (uptr))
1187 return MTSE_WRP;
1188
1189 tape_density = bpi [MT_DENS (uptr->dynflags)];
1190
1191 if (format != MTUF_F_STD)
1192 return MTSE_OK;
1193 else if (tape_density == 0)
1194 return MTSE_IOERR;
1195 else
1196 gap_needed = (gaplen * tape_density) / 10;
1197
1198 file_size = sim_fsize (uptr->fileref);
1199 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212 do {
1213 (void)sim_fread (&meta, meta_size, 1, uptr->fileref);
1214
1215 if (ferror (uptr->fileref)) {
1216 uptr->pos = gap_pos;
1217 MT_SET_PNU (uptr);
1218 return sim_tape_ioerr (uptr);
1219 }
1220 else
1221 uptr->pos = uptr->pos + meta_size;
1222
1223 if (feof (uptr->fileref) || (meta == MTR_EOM)) {
1224 gap_alloc = gap_alloc + gap_needed;
1225 gap_needed = 0;
1226 }
1227
1228 else if ((meta == MTR_GAP) || (meta == MTR_TMK)) {
1229 gap_alloc = gap_alloc + meta_size;
1230 gap_needed = gap_needed - meta_size;
1231 }
1232
1233 else if (meta == MTR_FHGAP) {
1234 uptr->pos = uptr->pos - meta_size / 2;
1235 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
1236 gap_alloc = gap_alloc + meta_size / 2;
1237 gap_needed = gap_needed - meta_size / 2;
1238 }
1239
1240 else if (uptr->pos +
1241 MTR_L (meta) + meta_size > file_size) {
1242 gap_alloc = gap_alloc + gap_needed;
1243 gap_needed = 0;
1244 }
1245
1246
1247
1248
1249
1250
1251
1252 else {
1253 sbc = MTR_L (meta);
1254 rec_size = ((sbc + 1) & ~1) + meta_size * 2;
1255
1256 if (rec_size < gap_needed + min_rec_size) {
1257 uptr->pos = uptr->pos - meta_size + rec_size;
1258 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
1259 gap_alloc = gap_alloc + rec_size;
1260 gap_needed = gap_needed - rec_size;
1261 }
1262
1263 else {
1264 uptr->pos = uptr->pos - meta_size + gap_needed;
1265 new_len = MTR_F (meta) | (sbc - gap_needed);
1266 st = sim_tape_wrdata (uptr, new_len);
1267
1268 if (st != MTSE_OK) {
1269 uptr->pos = gap_pos;
1270 return st;
1271 }
1272
1273 uptr->pos = uptr->pos + sbc - gap_needed;
1274 st = sim_tape_wrdata (uptr, new_len);
1275
1276 if (st != MTSE_OK) {
1277 uptr->pos = gap_pos;
1278 return st;
1279 }
1280
1281 gap_alloc = gap_alloc + gap_needed;
1282 gap_needed = 0;
1283 }
1284 }
1285 }
1286 while (gap_needed > 0);
1287
1288 uptr->pos = gap_pos;
1289
1290 if (gap_alloc & (meta_size - 1)) {
1291 st = sim_tape_wrdata (uptr, MTR_FHGAP);
1292 if (st != MTSE_OK) {
1293 uptr->pos = gap_pos;
1294 return st;
1295 }
1296 uptr->pos = uptr->pos - meta_size / 2;
1297 gap_alloc = gap_alloc - 2;
1298 }
1299
1300 marker_count = gap_alloc / meta_size;
1301
1302 do {
1303 st = sim_tape_wrdata (uptr, MTR_GAP);
1304 if (st != MTSE_OK) {
1305 uptr->pos = gap_pos;
1306 return st;
1307 }
1308 }
1309 while (--marker_count > 0);
1310
1311 return MTSE_OK;
1312 }
1313
1314 t_stat sim_tape_wrgap_a (UNIT *uptr, uint32 gaplen, TAPE_PCALLBACK callback)
1315 {
1316 t_stat r = MTSE_OK;
1317 return r;
1318 }
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338 t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc)
1339 {
1340 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1341 t_stat st;
1342
1343 *bc = 0;
1344 if (ctx == NULL)
1345 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1346 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecf(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1347
1348 st = sim_tape_rdlntf (uptr, bc);
1349 *bc = MTR_L (*bc);
1350 return st;
1351 }
1352
1353 t_stat sim_tape_sprecf_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback)
1354 {
1355 t_stat r = MTSE_OK;
1356 r = sim_tape_sprecf (uptr, bc);
1357 return r;
1358 }
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379 t_stat sim_tape_sprecsf (UNIT *uptr, uint32 count, uint32 *skipped)
1380 {
1381 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1382 t_stat st;
1383 t_mtrlnt tbc;
1384
1385 if (ctx == NULL)
1386 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1387 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecsf(unit=%d, count=%lld)\n",
1388 (int)(uptr-ctx->dptr->units), (long long)count);
1389
1390 *skipped = 0;
1391 while (*skipped < count) {
1392 st = sim_tape_sprecf (uptr, &tbc);
1393 if (st != MTSE_OK)
1394 return st;
1395 *skipped = *skipped + 1;
1396 }
1397 return MTSE_OK;
1398 }
1399
1400 t_stat sim_tape_sprecsf_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
1401 {
1402 t_stat r = MTSE_OK;
1403 r = sim_tape_sprecsf (uptr, count, skipped);
1404 return r;
1405 }
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426 t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc)
1427 {
1428 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1429 t_stat st;
1430
1431 if (ctx == NULL)
1432 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1433 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecr(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1434
1435 if (MT_TST_PNU (uptr)) {
1436 MT_CLR_PNU (uptr);
1437 *bc = 0;
1438 return MTSE_OK;
1439 }
1440 st = sim_tape_rdlntr (uptr, bc);
1441 *bc = MTR_L (*bc);
1442 return st;
1443 }
1444
1445 t_stat sim_tape_sprecr_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback)
1446 {
1447 t_stat r = MTSE_OK;
1448 r = sim_tape_sprecr (uptr, bc);
1449 return r;
1450 }
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472 t_stat sim_tape_sprecsr (UNIT *uptr, uint32 count, uint32 *skipped)
1473 {
1474 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1475 t_stat st;
1476 t_mtrlnt tbc;
1477
1478 if (ctx == NULL)
1479 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1480 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecsr(unit=%d, count=%lld)\n",
1481 (int)(uptr-ctx->dptr->units), (long long)count);
1482
1483 *skipped = 0;
1484 while (*skipped < count) {
1485 st = sim_tape_sprecr (uptr, &tbc);
1486 if (st != MTSE_OK)
1487 return st;
1488 *skipped = *skipped + 1;
1489 }
1490 return MTSE_OK;
1491 }
1492
1493 t_stat sim_tape_sprecsr_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
1494 {
1495 t_stat r = MTSE_OK;
1496 r = sim_tape_sprecsr (uptr, count, skipped);
1497 return r;
1498 }
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521 t_stat sim_tape_spfilebyrecf (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, t_bool check_leot)
1522 {
1523 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1524 t_stat st;
1525 t_bool last_tapemark = FALSE;
1526 uint32 filerecsskipped = 0;
1527 *skipped = *recsskipped = 0;
1528 if (ctx == NULL)
1529 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1530 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilebyrecf(unit=%d, count=%lld, check_leot=%lld)\n",
1531 (int)(uptr-ctx->dptr->units), (long long)count, (long long)check_leot);
1532
1533 if (check_leot) {
1534 t_mtrlnt rbc;
1535
1536 st = sim_tape_rdlntr (uptr, &rbc);
1537 last_tapemark = (MTSE_TMK == st);
1538 if ((st == MTSE_OK) || (st == MTSE_TMK))
1539 sim_tape_rdlntf (uptr, &rbc);
1540 }
1541 *skipped = 0;
1542 *recsskipped = 0;
1543 while (*skipped < count) {
1544 while (1) {
1545 st = sim_tape_sprecsf (uptr, 0x1ffffff, &filerecsskipped);
1546 *recsskipped += filerecsskipped;
1547 if (st != MTSE_OK)
1548 break;
1549 }
1550 if (st == MTSE_TMK) {
1551 *skipped = *skipped + 1;
1552 if (check_leot && (filerecsskipped == 0) && last_tapemark) {
1553 uint32 filefileskipped;
1554 sim_tape_spfilebyrecr (uptr, 1, &filefileskipped, &filerecsskipped);
1555 *skipped = *skipped - 1;
1556 return MTSE_LEOT;
1557 }
1558 last_tapemark = TRUE;
1559 }
1560 else
1561 return st;
1562 }
1563 return MTSE_OK;
1564 }
1565
1566 t_stat sim_tape_spfilebyrecf_a \
1567 (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, t_bool check_leot, TAPE_PCALLBACK callback)
1568 {
1569 t_stat r = MTSE_OK;
1570 r = sim_tape_spfilebyrecf \
1571 (uptr, count, skipped, recsskipped, check_leot);
1572 return r;
1573 }
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594 t_stat sim_tape_spfilef (UNIT *uptr, uint32 count, uint32 *skipped)
1595 {
1596 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1597 uint32 totalrecsskipped;
1598
1599 if (ctx == NULL)
1600 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1601 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilef(unit=%d, count=%lld)\n",
1602 (int)(uptr-ctx->dptr->units), (long long)count);
1603
1604 return sim_tape_spfilebyrecf (uptr, count, skipped, &totalrecsskipped, FALSE);
1605 }
1606
1607 t_stat sim_tape_spfilef_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
1608 {
1609 t_stat r = MTSE_OK;
1610 r = sim_tape_spfilef (uptr, count, skipped);
1611 return r;
1612 }
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635 t_stat sim_tape_spfilebyrecr (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped)
1636 {
1637 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1638 t_stat st;
1639 uint32 filerecsskipped = 0;
1640
1641 *skipped = 0;
1642 *recsskipped = 0;
1643 if (ctx == NULL)
1644 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1645 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilebyrecr(unit=%d, count=%lld)\n",
1646 (int)(uptr-ctx->dptr->units), (long long)count);
1647
1648 while (*skipped < count) {
1649 while (1) {
1650 st = sim_tape_sprecsr (uptr, 0x1ffffff, &filerecsskipped);
1651 *recsskipped += filerecsskipped;
1652 if (st != MTSE_OK)
1653 break;
1654 }
1655 if (st == MTSE_TMK)
1656 *skipped = *skipped + 1;
1657 else
1658 return st;
1659 }
1660 return MTSE_OK;
1661 }
1662
1663 t_stat sim_tape_spfilebyrecr_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, TAPE_PCALLBACK callback)
1664 {
1665 t_stat r = MTSE_OK;
1666 r = sim_tape_spfilebyrecr (uptr, count, skipped, recsskipped);
1667 return r;
1668 }
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690 t_stat sim_tape_spfiler (UNIT *uptr, uint32 count, uint32 *skipped)
1691 {
1692 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1693 uint32 totalrecsskipped;
1694
1695 if (ctx == NULL)
1696 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1697 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfiler(unit=%d, count=%lld)\n",
1698 (int)(uptr-ctx->dptr->units), (long long)count);
1699
1700 return sim_tape_spfilebyrecr (uptr, count, skipped, &totalrecsskipped);
1701 }
1702
1703 t_stat sim_tape_spfiler_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
1704 {
1705 t_stat r = MTSE_OK;
1706 r = sim_tape_spfiler (uptr, count, skipped);
1707 return r;
1708 }
1709
1710
1711
1712 t_stat sim_tape_rewind (UNIT *uptr)
1713 {
1714 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1715
1716 if (uptr->flags & UNIT_ATT) {
1717 if (ctx == NULL)
1718 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1719 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rewind(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1720 }
1721 uptr->pos = 0;
1722 MT_CLR_PNU (uptr);
1723 return MTSE_OK;
1724 }
1725
1726 t_stat sim_tape_rewind_a (UNIT *uptr, TAPE_PCALLBACK callback)
1727 {
1728 t_stat r = MTSE_OK;
1729 r = sim_tape_rewind (uptr);
1730 return r;
1731 }
1732
1733
1734
1735 t_stat sim_tape_position \
1736 (UNIT *uptr, uint32 flags, uint32 recs, uint32 *recsskipped, uint32 files, uint32 *filesskipped, uint32 *objectsskipped)
1737 {
1738 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1739 t_stat r = MTSE_OK;
1740
1741 if (ctx == NULL)
1742 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1743 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_position(unit=%d, flags=0x%X, recs=%lld, files=%lld)\n",
1744 (int)(uptr-ctx->dptr->units), flags, (long long)recs, (long long)files);
1745
1746 *recsskipped = *filesskipped = *objectsskipped = 0;
1747 if (flags & MTPOS_M_REW)
1748 r = sim_tape_rewind (uptr);
1749 if (r != MTSE_OK)
1750 return r;
1751 if (flags & MTPOS_M_OBJ) {
1752 uint32 objs = recs;
1753 uint32 skipped;
1754 uint32 objsremaining = objs;
1755
1756 while (*objectsskipped < objs) {
1757 if (flags & MTPOS_M_REV)
1758 r = sim_tape_sprecsr (uptr, objsremaining, &skipped);
1759 else
1760 r = sim_tape_sprecsf (uptr, objsremaining, &skipped);
1761 objsremaining = objsremaining - (skipped + ((r == MTSE_TMK) ? 1 : 0));
1762 if ((r == MTSE_TMK) || (r == MTSE_OK))
1763 *objectsskipped = *objectsskipped + skipped + ((r == MTSE_TMK) ? 1 : 0);
1764 else
1765 return r;
1766 }
1767 r = MTSE_OK;
1768 }
1769 else {
1770 uint32 fileskiprecs;
1771
1772 if (flags & MTPOS_M_REV)
1773 r = sim_tape_spfilebyrecr (uptr, files, filesskipped, &fileskiprecs);
1774 else
1775 r = sim_tape_spfilebyrecf (uptr, files, filesskipped, &fileskiprecs, (flags & MTPOS_M_DLE));
1776 if (r != MTSE_OK)
1777 return r;
1778 if (flags & MTPOS_M_REV)
1779 r = sim_tape_sprecsr (uptr, recs, recsskipped);
1780 else
1781 r = sim_tape_sprecsf (uptr, recs, recsskipped);
1782 if (r == MTSE_TMK)
1783 *filesskipped = *filesskipped + 1;
1784 *objectsskipped = fileskiprecs + *filesskipped + *recsskipped;
1785 }
1786 return r;
1787 }
1788
1789 t_stat sim_tape_position_a \
1790 (UNIT *uptr, uint32 flags, uint32 recs, uint32 *recsskipped, uint32 files,
1791 uint32 *filesskipped, uint32 *objectsskipped, TAPE_PCALLBACK callback)
1792 {
1793 t_stat r = MTSE_OK;
1794 r = sim_tape_position (uptr, flags, recs, recsskipped, files, filesskipped, objectsskipped);
1795 return r;
1796 }
1797
1798
1799
1800 t_stat sim_tape_reset (UNIT *uptr)
1801 {
1802 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1803
1804 MT_CLR_PNU (uptr);
1805 if (!(uptr->flags & UNIT_ATT))
1806 return SCPE_OK;
1807
1808 if (ctx == NULL)
1809 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1810 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_reset(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1811
1812 _sim_tape_io_flush(uptr);
1813 return SCPE_OK;
1814 }
1815
1816
1817
1818 t_bool sim_tape_bot (UNIT *uptr)
1819 {
1820 uint32 f = MT_GET_FMT (uptr);
1821
1822 return (uptr->pos <= fmts[f].bot)? TRUE: FALSE;
1823 }
1824
1825
1826
1827 t_bool sim_tape_eot (UNIT *uptr)
1828 {
1829 return (uptr->capac && (uptr->pos >= uptr->capac))? TRUE: FALSE;
1830 }
1831
1832
1833
1834 t_bool sim_tape_wrp (UNIT *uptr)
1835 {
1836 return ((uptr->flags & MTUF_WRP) || (MT_GET_FMT (uptr) == MTUF_F_TPC))? TRUE: FALSE;
1837 }
1838
1839
1840
1841 static t_stat sim_tape_ioerr (UNIT *uptr)
1842 {
1843 sim_printf ("%s: Magtape library I/O error: %s (Error %d)\r\n", sim_uname (uptr), xstrerror_l(errno), errno);
1844 clearerr (uptr->fileref);
1845 return MTSE_IOERR;
1846 }
1847
1848
1849
1850 t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
1851 {
1852 uint32 f;
1853
1854 if (uptr == NULL)
1855 return SCPE_IERR;
1856 if (uptr->flags & UNIT_ATT)
1857 return SCPE_ALATT;
1858 if (cptr == NULL)
1859 return SCPE_ARG;
1860 for (f = 0; f < MTUF_N_FMT; f++) {
1861 if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) {
1862 uptr->flags = (uptr->flags & ~MTUF_FMT) |
1863 (f << MTUF_V_FMT) | fmts[f].uflags;
1864 return SCPE_OK;
1865 }
1866 }
1867 return SCPE_ARG;
1868 }
1869
1870
1871
1872 t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
1873 {
1874 int32 f = MT_GET_FMT (uptr);
1875
1876 if (fmts[f].name)
1877 fprintf (st, "%s format", fmts[f].name);
1878 else fprintf (st, "invalid format");
1879 return SCPE_OK;
1880 }
1881
1882
1883
1884 static uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map, uint32 mapsize)
1885 {
1886 t_addr tpos, leot = 0;
1887 t_addr tape_size;
1888 t_tpclnt bc, last_bc = 0xFFFF;
1889 uint32 had_double_tape_mark = 0;
1890 size_t i;
1891 uint32 objc, sizec;
1892 uint32 *countmap = NULL;
1893 uint8 *recbuf = NULL;
1894 DEVICE *dptr = find_dev_from_unit (uptr);
1895
1896 if ((uptr == NULL) || (uptr->fileref == NULL))
1897 return 0;
1898 countmap = (uint32 *)calloc (65536, sizeof(*countmap));
1899 if (!countmap)
1900 {
1901 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1902 __func__, __FILE__, __LINE__);
1903 #if defined(USE_BACKTRACE)
1904 # if defined(SIGUSR2)
1905 (void)raise(SIGUSR2);
1906
1907 # endif
1908 #endif
1909 abort();
1910 }
1911 recbuf = (uint8 *)malloc (65536);
1912 if (!recbuf)
1913 {
1914 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1915 __func__, __FILE__, __LINE__);
1916 #if defined(USE_BACKTRACE)
1917 # if defined(SIGUSR2)
1918 (void)raise(SIGUSR2);
1919
1920 # endif
1921 #endif
1922 abort();
1923 }
1924 tape_size = (t_addr)sim_fsize (uptr->fileref);
1925 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: tape_size: %" T_ADDR_FMT "u\n", tape_size);
1926 for (objc = 0, sizec = 0, tpos = 0;; ) {
1927 sim_fseek (uptr->fileref, tpos, SEEK_SET);
1928 i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref);
1929 if (i == 0)
1930 break;
1931 if (countmap[bc] == 0)
1932 sizec++;
1933 ++countmap[bc];
1934 if (map && (objc < mapsize))
1935 map[objc] = tpos;
1936 if (bc) {
1937 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: %lld byte count at pos: %" T_ADDR_FMT "u\n",
1938 (long long)bc, tpos);
1939 if (sim_deb && (dptr->dctrl & MTSE_DBG_STR)) {
1940 (void)sim_fread (recbuf, 1, bc, uptr->fileref);
1941 sim_data_trace(dptr, uptr, ((dptr->dctrl & MTSE_DBG_DAT) ? recbuf : NULL), "", bc, "Data Record", MTSE_DBG_STR);
1942 }
1943 }
1944 else
1945 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: tape mark at pos: %" T_ADDR_FMT "u\n", tpos);
1946 objc++;
1947 tpos = tpos + ((bc + 1) & ~1) + sizeof (t_tpclnt);
1948 if ((bc == 0) && (last_bc == 0)) {
1949 had_double_tape_mark = objc;
1950 leot = tpos;
1951 }
1952 last_bc = bc;
1953 }
1954 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: objc: %u, different record sizes: %u\n", objc, sizec);
1955 for (i=0; i<65535; i++) {
1956 if (countmap[i]) {
1957 if (i == 0)
1958 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: summary - %u tape marks\n",
1959 countmap[i]);
1960 else
1961 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: summary - %u %d byte record%s\n",
1962 countmap[i], (int)i, (countmap[i] > 1) ? "s" : "");
1963 }
1964 }
1965 if (((last_bc != 0xffff) &&
1966 (tpos > tape_size) &&
1967 (!had_double_tape_mark)) ||
1968 (!had_double_tape_mark) ||
1969 ((objc == countmap[0]) &&
1970 (countmap[0] != 2))) {
1971 if (last_bc != 0xffff)
1972 sim_debug (MTSE_DBG_STR, dptr,
1973 "tpc_map: ERROR unexpected EOT byte count: %lld\n",
1974 (long long)last_bc);
1975 if (tpos > tape_size)
1976 sim_debug (MTSE_DBG_STR, dptr,
1977 "tpc_map: ERROR next record position %" T_ADDR_FMT "u beyond EOT: %" T_ADDR_FMT "u\n",
1978 tpos, tape_size);
1979 if (objc == countmap[0])
1980 sim_debug (MTSE_DBG_STR, dptr,
1981 "tpc_map: ERROR tape cnly contains tape marks\n");
1982 FREE (countmap);
1983 FREE (recbuf);
1984 return 0;
1985 }
1986
1987 if ((last_bc != 0xffff) && (tpos > tape_size)) {
1988 sim_debug (MTSE_DBG_STR, dptr,
1989 "tpc_map: WARNING unexpected EOT byte count: %lld, double tape mark before %" T_ADDR_FMT "u provides logical EOT\n",
1990 (long long)last_bc, leot);
1991 objc = had_double_tape_mark;
1992 tpos = leot;
1993 }
1994 if (map)
1995 map[objc] = tpos;
1996 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: OK objc: %lld\n", (long long)objc);
1997 FREE (countmap);
1998 FREE (recbuf);
1999 return objc;
2000 }
2001
2002
2003
2004 static t_stat sim_tape_simh_check (UNIT *uptr)
2005 {
2006 return SCPE_OK;
2007 }
2008
2009
2010
2011 static t_stat sim_tape_e11_check (UNIT *uptr)
2012 {
2013 return SCPE_OK;
2014 }
2015
2016
2017
2018 static t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map)
2019 {
2020 uint32 lo, hi, p;
2021
2022 if (map == NULL)
2023 return 0;
2024 lo = 0;
2025 hi = uptr->hwmark - 1;
2026 do {
2027 p = (lo + hi) >> 1;
2028 if (uptr->pos == map[p])
2029 return ((p == 0)? map[p]: map[p - 1]);
2030 else if (uptr->pos < map[p])
2031 hi = p - 1;
2032 else lo = p + 1;
2033 }
2034 while (lo <= hi);
2035 return ((p == 0)? map[p]: map[p - 1]);
2036 }
2037
2038
2039
2040 t_stat sim_tape_set_capac (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
2041 {
2042 t_addr cap;
2043 t_stat r;
2044
2045 if ((cptr == NULL) || (*cptr == 0))
2046 return SCPE_ARG;
2047 if (uptr->flags & UNIT_ATT)
2048 return SCPE_ALATT;
2049 cap = (t_addr) get_uint (cptr, 10, 2000000, &r);
2050 if (r != SCPE_OK)
2051 return SCPE_ARG;
2052 uptr->capac = cap * ((t_addr) 1000000);
2053 return SCPE_OK;
2054 }
2055
2056
2057
2058 t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
2059 {
2060 if (uptr->capac) {
2061 if (uptr->capac >= (t_addr) 1000000)
2062 fprintf (st, "capacity : %luMB", (unsigned long)(uptr->capac / ((t_addr) 1000000)));
2063 else {
2064 if (uptr->capac >= (t_addr) 1000)
2065 fprintf (st, "capacity : %luKB", (unsigned long)(uptr->capac / ((t_addr) 1000)));
2066 else
2067 fprintf (st, "capacity : %luB", (unsigned long)uptr->capac);
2068 }
2069 }
2070 else
2071 fprintf (st, "capacity : unlimited");
2072 return SCPE_OK;
2073 }
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094 t_stat sim_tape_set_dens (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
2095 {
2096 uint32 density, new_bpi;
2097 t_stat result = SCPE_OK;
2098
2099 if (uptr == NULL)
2100 return SCPE_IERR;
2101
2102 else if (desc == NULL)
2103 if (val > 0 && val < (int32) BPI_COUNT)
2104 uptr->dynflags = (uptr->dynflags & ~MTVF_DENS_MASK)
2105 | (val << UNIT_V_DF_TAPE);
2106 else
2107 return SCPE_ARG;
2108
2109 else {
2110 if (cptr == NULL || *cptr == 0)
2111 return SCPE_MISVAL;
2112
2113 new_bpi = (uint32) get_uint (cptr, 10, UINT_MAX, &result);
2114
2115 if (result != SCPE_OK)
2116 return SCPE_ARG;
2117
2118 else for (density = 0; density < BPI_COUNT; density++)
2119 if (new_bpi == bpi [density]
2120 && ((1 << density) & *(const int32 *) desc)) {
2121 uptr->dynflags = (uptr->dynflags & ~MTVF_DENS_MASK)
2122 | density << UNIT_V_DF_TAPE;
2123 return SCPE_OK;
2124 }
2125
2126 result = SCPE_ARG;
2127 }
2128
2129 return result;
2130 }
2131
2132
2133
2134 t_stat sim_tape_show_dens (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
2135 {
2136 uint32 tape_density;
2137
2138 if (uptr == NULL)
2139 return SCPE_IERR;
2140
2141 else {
2142 tape_density = bpi [MT_DENS (uptr->dynflags)];
2143
2144 if (tape_density)
2145 fprintf (st, "density=%lu bpi",
2146 (unsigned long)tape_density);
2147 else
2148 fprintf (st, "density not set");
2149 }
2150
2151 return SCPE_OK;
2152 }