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