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\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\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\n\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\n\n", dptr->name, (unsigned long)i);
290 }
291 else
292 fprintf (st, " sim> ATTACH {switches} %s tapefile\n\n", dptr->name);
293 }
294 else
295 fprintf (st, " sim> ATTACH {switches} %s tapefile\n\n", dptr->name);
296 fprintf (st, "Attach command switches\n");
297 fprintf (st, " -R Attach Read Only.\n");
298 fprintf (st, " -E Must Exist (if not specified an attempt to create the indicated\n");
299 fprintf (st, " virtual tape will be attempted).\n");
300 fprintf (st, " -F Open the indicated tape container in a specific format (default\n");
301 fprintf (st, " is SIMH, alternatives are E11, TPC and P7B)\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\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\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\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 *bc = buffer [--bufcntr];
686
687 uptr->pos = uptr->pos - sizeof (t_mtrlnt);
688
689 if (*bc == MTR_TMK) {
690 r = MTSE_TMK;
691 break;
692 }
693
694 else if (*bc == MTR_GAP)
695 runaway_counter -= sizeof_gap;
696
697 else if ((*bc & MTR_M_RHGAP) == MTR_RHGAP
698 || *bc == MTR_RRGAP) {
699 uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2;
700 bufcntr = 0;
701
702 *bc = MTR_GAP;
703 runaway_counter -= sizeof_gap / 2;
704 }
705
706 else {
707 sbc = MTR_L (*bc);
708 uptr->pos = uptr->pos - sizeof (t_mtrlnt)
709 - (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc);
710 (void)sim_fseek (uptr->fileref,
711 uptr->pos + sizeof (t_mtrlnt), SEEK_SET);
712 }
713 }
714 while (*bc == MTR_GAP && runaway_counter > 0);
715
716 if (r == MTSE_OK && runaway_counter <= 0)
717 r = MTSE_RUNAWAY;
718
719 break;
720
721 case MTUF_F_TPC:
722 ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf);
723 (void)sim_fseek (uptr->fileref, ppos, SEEK_SET);
724 (void)sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
725 *bc = tpcbc;
726 if (ferror (uptr->fileref))
727 return sim_tape_ioerr (uptr);
728 if (feof (uptr->fileref)) {
729 r = MTSE_EOM;
730 break;
731 }
732 uptr->pos = ppos;
733 if (*bc == MTR_TMK) {
734 r = MTSE_TMK;
735 break;
736 }
737 (void)sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET);
738 break;
739
740 case MTUF_F_P7B:
741 for (sbc = 1, all_eof = 1; (t_addr) sbc <= uptr->pos ; sbc++) {
742 (void)sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET);
743 (void)sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
744 if (ferror (uptr->fileref))
745 return sim_tape_ioerr (uptr);
746 if (feof (uptr->fileref)) {
747 r = MTSE_EOM;
748 break;
749 }
750 if ((c & P7B_DPAR) != P7B_EOF)
751 all_eof = 0;
752 if (c & P7B_SOR)
753 break;
754 }
755 uptr->pos = uptr->pos - sbc;
756 *bc = sbc;
757 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
758 if (all_eof)
759 r = MTSE_TMK;
760 break;
761
762 default:
763 return MTSE_FMT;
764 }
765 sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %lld, lnt: %lld, pos: %" T_ADDR_FMT "u\n",
766 (long long)r, (long long)*bc, uptr->pos);
767 return r;
768 }
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791 t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
792 {
793 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
794 uint32 f = MT_GET_FMT (uptr);
795 t_mtrlnt i, tbc, rbc;
796 t_addr opos;
797 t_stat st;
798
799 if (ctx == NULL)
800 return sim_messagef (SCPE_IERR, "Bad Attach\n");
801 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rdrecf(unit=%d, buf=%p, max=%lld)\n",
802 (int)(uptr-ctx->dptr->units), buf, (long long)max);
803
804 opos = uptr->pos;
805 if (MTSE_OK != (st = sim_tape_rdlntf (uptr, &tbc)))
806 return st;
807 *bc = rbc = MTR_L (tbc);
808 if (rbc > max) {
809 MT_SET_PNU (uptr);
810 uptr->pos = opos;
811 return MTSE_INVRL;
812 }
813 i = (t_mtrlnt)sim_fread (buf, sizeof (uint8), rbc, uptr->fileref);
814 if (ferror (uptr->fileref)) {
815 MT_SET_PNU (uptr);
816 uptr->pos = opos;
817 return sim_tape_ioerr (uptr);
818 }
819 for ( ; i < rbc; i++)
820 buf[i] = 0;
821 if (f == MTUF_F_P7B)
822 buf[0] = buf[0] & P7B_DPAR;
823 sim_tape_data_trace(uptr, buf, rbc, "Record Read", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
824 return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
825 }
826
827 t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback)
828 {
829 t_stat r = SCPE_OK;
830 r = sim_tape_rdrecf (uptr, buf, bc, max);
831 return r;
832 }
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856 t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
857 {
858 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
859 uint32 f = MT_GET_FMT (uptr);
860 t_mtrlnt i, rbc, tbc;
861 t_stat st;
862
863 if (ctx == NULL)
864 return sim_messagef (SCPE_IERR, "Bad Attach\n");
865 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rdrecr(unit=%d, buf=%p, max=%lld)\n",
866 (int)(uptr-ctx->dptr->units), buf, (long long)max);
867
868 if (MTSE_OK != (st = sim_tape_rdlntr (uptr, &tbc)))
869 return st;
870 *bc = rbc = MTR_L (tbc);
871 if (rbc > max)
872 return MTSE_INVRL;
873 i = (t_mtrlnt)sim_fread (buf, sizeof (uint8), rbc, uptr->fileref);
874 if (ferror (uptr->fileref))
875 return sim_tape_ioerr (uptr);
876 for ( ; i < rbc; i++)
877 buf[i] = 0;
878 if (f == MTUF_F_P7B)
879 buf[0] = buf[0] & P7B_DPAR;
880 sim_tape_data_trace(uptr, buf, rbc, "Record Read Reverse", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
881 return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
882 }
883
884 t_stat sim_tape_rdrecr_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback)
885 {
886 t_stat r = SCPE_OK;
887 r = sim_tape_rdrecr (uptr, buf, bc, max);
888 return r;
889 }
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908 t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc)
909 {
910 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
911 uint32 f = MT_GET_FMT (uptr);
912 t_mtrlnt sbc;
913
914 if (ctx == NULL)
915 return sim_messagef (SCPE_IERR, "Bad Attach\n");
916 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrrecf(unit=%d, buf=%p, bc=%lld)\n",
917 (int)(uptr-ctx->dptr->units), buf, (long long)bc);
918
919 sim_tape_data_trace(uptr, buf, bc, "Record Write", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
920 MT_CLR_PNU (uptr);
921 sbc = MTR_L (bc);
922 if ((uptr->flags & UNIT_ATT) == 0)
923 return MTSE_UNATT;
924 if (sim_tape_wrp (uptr))
925 return MTSE_WRP;
926 if (sbc == 0)
927 return MTSE_OK;
928 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
929 switch (f) {
930
931 case MTUF_F_STD:
932 sbc = MTR_L ((bc + 1) & ~1);
933
934 case MTUF_F_E11:
935 (void)sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
936 (void)sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
937 (void)sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
938 if (ferror (uptr->fileref)) {
939 MT_SET_PNU (uptr);
940 return sim_tape_ioerr (uptr);
941 }
942 uptr->pos = uptr->pos + sbc + (2 * sizeof (t_mtrlnt));
943 break;
944
945 case MTUF_F_P7B:
946 buf[0] = buf[0] | P7B_SOR;
947 (void)sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
948 (void)sim_fwrite (buf, sizeof (uint8), 1, uptr->fileref);
949 if (ferror (uptr->fileref)) {
950 MT_SET_PNU (uptr);
951 return sim_tape_ioerr (uptr);
952 }
953 uptr->pos = uptr->pos + sbc;
954 break;
955 }
956 sim_tape_data_trace(uptr, buf, sbc, "Record Written", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
957 return MTSE_OK;
958 }
959
960 t_stat sim_tape_wrrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt bc, TAPE_PCALLBACK callback)
961 {
962 t_stat r = SCPE_OK;
963 r = sim_tape_wrrecf (uptr, buf, bc);
964 return r;
965 }
966
967
968
969 static t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat)
970 {
971 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
972
973 MT_CLR_PNU (uptr);
974 if ((uptr->flags & UNIT_ATT) == 0)
975 return MTSE_UNATT;
976 if (ctx == NULL)
977 return sim_messagef (SCPE_IERR, "Bad Attach\n");
978 if (sim_tape_wrp (uptr))
979 return MTSE_WRP;
980 (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
981 (void)sim_fwrite (&dat, sizeof (uint32_t), 1, uptr->fileref);
982 if (ferror (uptr->fileref)) {
983 MT_SET_PNU (uptr);
984 return sim_tape_ioerr (uptr);
985 }
986 sim_debug (MTSE_DBG_STR, ctx->dptr, "wr_lnt: lnt: %lld, pos: %" T_ADDR_FMT "u\n",
987 (long long)dat, uptr->pos);
988 uptr->pos = uptr->pos + sizeof (uint32_t);
989 return MTSE_OK;
990 }
991
992
993
994 t_stat sim_tape_wrtmk (UNIT *uptr)
995 {
996 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
997
998 if (ctx == NULL)
999 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1000 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrtmk(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1001 if (MT_GET_FMT (uptr) == MTUF_F_P7B) {
1002 uint8 buf = P7B_EOF;
1003 return sim_tape_wrrecf (uptr, &buf, 1);
1004 }
1005 return sim_tape_wrdata (uptr, MTR_TMK);
1006 }
1007
1008 t_stat sim_tape_wrtmk_a (UNIT *uptr, TAPE_PCALLBACK callback)
1009 {
1010 t_stat r = MTSE_OK;
1011 r = sim_tape_wrtmk (uptr);
1012 return r;
1013 }
1014
1015
1016
1017 t_stat sim_tape_wreom (UNIT *uptr)
1018 {
1019 t_stat result;
1020 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1021
1022 if (ctx == NULL)
1023 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1024 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wreom(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1025 if (MT_GET_FMT (uptr) == MTUF_F_P7B)
1026 return MTSE_FMT;
1027
1028 result = sim_tape_wrdata (uptr, MTR_EOM);
1029
1030 uptr->pos = uptr->pos - sizeof (t_mtrlnt);
1031 MT_SET_PNU (uptr);
1032
1033 return result;
1034 }
1035
1036 t_stat sim_tape_wreom_a (UNIT *uptr, TAPE_PCALLBACK callback)
1037 {
1038 t_stat r = MTSE_OK;
1039 r = sim_tape_wreom (uptr);
1040 return r;
1041 }
1042
1043
1044
1045 t_stat sim_tape_wreomrw (UNIT *uptr)
1046 {
1047 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1048 t_stat r;
1049
1050 if (ctx == NULL)
1051 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1052 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wreomrw(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1053 if (MT_GET_FMT (uptr) == MTUF_F_P7B)
1054 return MTSE_FMT;
1055 r = sim_tape_wrdata (uptr, MTR_EOM);
1056 if (r == MTSE_OK)
1057 r = sim_tape_rewind (uptr);
1058 return r;
1059 }
1060
1061 t_stat sim_tape_wreomrw_a (UNIT *uptr, TAPE_PCALLBACK callback)
1062 {
1063 t_stat r = MTSE_OK;
1064 r = sim_tape_wreomrw (uptr);
1065 return r;
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
1165
1166
1167
1168 t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen)
1169 {
1170 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1171 t_stat st;
1172 t_mtrlnt meta, sbc, new_len, rec_size;
1173 t_addr gap_pos = uptr->pos;
1174 uint32 file_size, marker_count, tape_density;
1175 int32 gap_needed;
1176 uint32 gap_alloc = 0;
1177 const uint32 format = MT_GET_FMT (uptr);
1178 const uint32 meta_size = sizeof (t_mtrlnt);
1179 const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2;
1180
1181 if (ctx == NULL)
1182 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1183 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrgap(unit=%d, gaplen=%u)\n", (int)(uptr-ctx->dptr->units), gaplen);
1184
1185 MT_CLR_PNU (uptr);
1186
1187 if ((uptr->flags & UNIT_ATT) == 0)
1188 return MTSE_UNATT;
1189
1190 else if (sim_tape_wrp (uptr))
1191 return MTSE_WRP;
1192
1193 tape_density = bpi [MT_DENS (uptr->dynflags)];
1194
1195 if (format != MTUF_F_STD)
1196 return MTSE_OK;
1197 else if (tape_density == 0)
1198 return MTSE_IOERR;
1199 else
1200 gap_needed = (gaplen * tape_density) / 10;
1201
1202 file_size = sim_fsize (uptr->fileref);
1203 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216 do {
1217 (void)sim_fread (&meta, meta_size, 1, uptr->fileref);
1218
1219 if (ferror (uptr->fileref)) {
1220 uptr->pos = gap_pos;
1221 MT_SET_PNU (uptr);
1222 return sim_tape_ioerr (uptr);
1223 }
1224 else
1225 uptr->pos = uptr->pos + meta_size;
1226
1227 if (feof (uptr->fileref) || (meta == MTR_EOM)) {
1228 gap_alloc = gap_alloc + gap_needed;
1229 gap_needed = 0;
1230 }
1231
1232 else if ((meta == MTR_GAP) || (meta == MTR_TMK)) {
1233 gap_alloc = gap_alloc + meta_size;
1234 gap_needed = gap_needed - meta_size;
1235 }
1236
1237 else if (meta == MTR_FHGAP) {
1238 uptr->pos = uptr->pos - meta_size / 2;
1239 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
1240 gap_alloc = gap_alloc + meta_size / 2;
1241 gap_needed = gap_needed - meta_size / 2;
1242 }
1243
1244 else if (uptr->pos +
1245 MTR_L (meta) + meta_size > file_size) {
1246 gap_alloc = gap_alloc + gap_needed;
1247 gap_needed = 0;
1248 }
1249
1250
1251
1252
1253
1254
1255
1256 else {
1257 sbc = MTR_L (meta);
1258 rec_size = ((sbc + 1) & ~1) + meta_size * 2;
1259
1260 if (rec_size < gap_needed + min_rec_size) {
1261 uptr->pos = uptr->pos - meta_size + rec_size;
1262 sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);
1263 gap_alloc = gap_alloc + rec_size;
1264 gap_needed = gap_needed - rec_size;
1265 }
1266
1267 else {
1268 uptr->pos = uptr->pos - meta_size + gap_needed;
1269 new_len = MTR_F (meta) | (sbc - gap_needed);
1270 st = sim_tape_wrdata (uptr, new_len);
1271
1272 if (st != MTSE_OK) {
1273 uptr->pos = gap_pos;
1274 return st;
1275 }
1276
1277 uptr->pos = uptr->pos + sbc - gap_needed;
1278 st = sim_tape_wrdata (uptr, new_len);
1279
1280 if (st != MTSE_OK) {
1281 uptr->pos = gap_pos;
1282 return st;
1283 }
1284
1285 gap_alloc = gap_alloc + gap_needed;
1286 gap_needed = 0;
1287 }
1288 }
1289 }
1290 while (gap_needed > 0);
1291
1292 uptr->pos = gap_pos;
1293
1294 if (gap_alloc & (meta_size - 1)) {
1295 st = sim_tape_wrdata (uptr, MTR_FHGAP);
1296 if (st != MTSE_OK) {
1297 uptr->pos = gap_pos;
1298 return st;
1299 }
1300 uptr->pos = uptr->pos - meta_size / 2;
1301 gap_alloc = gap_alloc - 2;
1302 }
1303
1304 marker_count = gap_alloc / meta_size;
1305
1306 do {
1307 st = sim_tape_wrdata (uptr, MTR_GAP);
1308 if (st != MTSE_OK) {
1309 uptr->pos = gap_pos;
1310 return st;
1311 }
1312 }
1313 while (--marker_count > 0);
1314
1315 return MTSE_OK;
1316 }
1317
1318 t_stat sim_tape_wrgap_a (UNIT *uptr, uint32 gaplen, TAPE_PCALLBACK callback)
1319 {
1320 t_stat r = MTSE_OK;
1321 return r;
1322 }
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342 t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc)
1343 {
1344 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1345 t_stat st;
1346
1347 *bc = 0;
1348 if (ctx == NULL)
1349 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1350 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecf(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1351
1352 st = sim_tape_rdlntf (uptr, bc);
1353 *bc = MTR_L (*bc);
1354 return st;
1355 }
1356
1357 t_stat sim_tape_sprecf_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback)
1358 {
1359 t_stat r = MTSE_OK;
1360 r = sim_tape_sprecf (uptr, bc);
1361 return r;
1362 }
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383 t_stat sim_tape_sprecsf (UNIT *uptr, uint32 count, uint32 *skipped)
1384 {
1385 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1386 t_stat st;
1387 t_mtrlnt tbc;
1388
1389 if (ctx == NULL)
1390 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1391 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecsf(unit=%d, count=%lld)\n",
1392 (int)(uptr-ctx->dptr->units), (long long)count);
1393
1394 *skipped = 0;
1395 while (*skipped < count) {
1396 st = sim_tape_sprecf (uptr, &tbc);
1397 if (st != MTSE_OK)
1398 return st;
1399 *skipped = *skipped + 1;
1400 }
1401 return MTSE_OK;
1402 }
1403
1404 t_stat sim_tape_sprecsf_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
1405 {
1406 t_stat r = MTSE_OK;
1407 r = sim_tape_sprecsf (uptr, count, skipped);
1408 return r;
1409 }
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430 t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc)
1431 {
1432 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1433 t_stat st;
1434
1435 if (ctx == NULL)
1436 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1437 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecr(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1438
1439 if (MT_TST_PNU (uptr)) {
1440 MT_CLR_PNU (uptr);
1441 *bc = 0;
1442 return MTSE_OK;
1443 }
1444 st = sim_tape_rdlntr (uptr, bc);
1445 *bc = MTR_L (*bc);
1446 return st;
1447 }
1448
1449 t_stat sim_tape_sprecr_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback)
1450 {
1451 t_stat r = MTSE_OK;
1452 r = sim_tape_sprecr (uptr, bc);
1453 return r;
1454 }
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476 t_stat sim_tape_sprecsr (UNIT *uptr, uint32 count, uint32 *skipped)
1477 {
1478 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1479 t_stat st;
1480 t_mtrlnt tbc;
1481
1482 if (ctx == NULL)
1483 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1484 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecsr(unit=%d, count=%lld)\n",
1485 (int)(uptr-ctx->dptr->units), (long long)count);
1486
1487 *skipped = 0;
1488 while (*skipped < count) {
1489 st = sim_tape_sprecr (uptr, &tbc);
1490 if (st != MTSE_OK)
1491 return st;
1492 *skipped = *skipped + 1;
1493 }
1494 return MTSE_OK;
1495 }
1496
1497 t_stat sim_tape_sprecsr_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
1498 {
1499 t_stat r = MTSE_OK;
1500 r = sim_tape_sprecsr (uptr, count, skipped);
1501 return r;
1502 }
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525 t_stat sim_tape_spfilebyrecf (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, t_bool check_leot)
1526 {
1527 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1528 t_stat st;
1529 t_bool last_tapemark = FALSE;
1530 uint32 filerecsskipped = 0;
1531 *skipped = *recsskipped = 0;
1532 if (ctx == NULL)
1533 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1534 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilebyrecf(unit=%d, count=%lld, check_leot=%lld)\n",
1535 (int)(uptr-ctx->dptr->units), (long long)count, (long long)check_leot);
1536
1537 if (check_leot) {
1538 t_mtrlnt rbc;
1539
1540 st = sim_tape_rdlntr (uptr, &rbc);
1541 last_tapemark = (MTSE_TMK == st);
1542 if ((st == MTSE_OK) || (st == MTSE_TMK))
1543 sim_tape_rdlntf (uptr, &rbc);
1544 }
1545 *skipped = 0;
1546 *recsskipped = 0;
1547 while (*skipped < count) {
1548 while (1) {
1549 st = sim_tape_sprecsf (uptr, 0x1ffffff, &filerecsskipped);
1550 *recsskipped += filerecsskipped;
1551 if (st != MTSE_OK)
1552 break;
1553 }
1554 if (st == MTSE_TMK) {
1555 *skipped = *skipped + 1;
1556 if (check_leot && (filerecsskipped == 0) && last_tapemark) {
1557 uint32 filefileskipped;
1558 sim_tape_spfilebyrecr (uptr, 1, &filefileskipped, &filerecsskipped);
1559 *skipped = *skipped - 1;
1560 return MTSE_LEOT;
1561 }
1562 last_tapemark = TRUE;
1563 }
1564 else
1565 return st;
1566 }
1567 return MTSE_OK;
1568 }
1569
1570 t_stat sim_tape_spfilebyrecf_a \
1571 (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, t_bool check_leot, TAPE_PCALLBACK callback)
1572 {
1573 t_stat r = MTSE_OK;
1574 r = sim_tape_spfilebyrecf \
1575 (uptr, count, skipped, recsskipped, check_leot);
1576 return r;
1577 }
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598 t_stat sim_tape_spfilef (UNIT *uptr, uint32 count, uint32 *skipped)
1599 {
1600 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1601 uint32 totalrecsskipped;
1602
1603 if (ctx == NULL)
1604 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1605 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilef(unit=%d, count=%lld)\n",
1606 (int)(uptr-ctx->dptr->units), (long long)count);
1607
1608 return sim_tape_spfilebyrecf (uptr, count, skipped, &totalrecsskipped, FALSE);
1609 }
1610
1611 t_stat sim_tape_spfilef_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
1612 {
1613 t_stat r = MTSE_OK;
1614 r = sim_tape_spfilef (uptr, count, skipped);
1615 return r;
1616 }
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639 t_stat sim_tape_spfilebyrecr (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped)
1640 {
1641 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1642 t_stat st;
1643 uint32 filerecsskipped = 0;
1644
1645 *skipped = 0;
1646 *recsskipped = 0;
1647 if (ctx == NULL)
1648 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1649 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilebyrecr(unit=%d, count=%lld)\n",
1650 (int)(uptr-ctx->dptr->units), (long long)count);
1651
1652 while (*skipped < count) {
1653 while (1) {
1654 st = sim_tape_sprecsr (uptr, 0x1ffffff, &filerecsskipped);
1655 *recsskipped += filerecsskipped;
1656 if (st != MTSE_OK)
1657 break;
1658 }
1659 if (st == MTSE_TMK)
1660 *skipped = *skipped + 1;
1661 else
1662 return st;
1663 }
1664 return MTSE_OK;
1665 }
1666
1667 t_stat sim_tape_spfilebyrecr_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, TAPE_PCALLBACK callback)
1668 {
1669 t_stat r = MTSE_OK;
1670 r = sim_tape_spfilebyrecr (uptr, count, skipped, recsskipped);
1671 return r;
1672 }
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694 t_stat sim_tape_spfiler (UNIT *uptr, uint32 count, uint32 *skipped)
1695 {
1696 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1697 uint32 totalrecsskipped;
1698
1699 if (ctx == NULL)
1700 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1701 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfiler(unit=%d, count=%lld)\n",
1702 (int)(uptr-ctx->dptr->units), (long long)count);
1703
1704 return sim_tape_spfilebyrecr (uptr, count, skipped, &totalrecsskipped);
1705 }
1706
1707 t_stat sim_tape_spfiler_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
1708 {
1709 t_stat r = MTSE_OK;
1710 r = sim_tape_spfiler (uptr, count, skipped);
1711 return r;
1712 }
1713
1714
1715
1716 t_stat sim_tape_rewind (UNIT *uptr)
1717 {
1718 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1719
1720 if (uptr->flags & UNIT_ATT) {
1721 if (ctx == NULL)
1722 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1723 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rewind(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1724 }
1725 uptr->pos = 0;
1726 MT_CLR_PNU (uptr);
1727 return MTSE_OK;
1728 }
1729
1730 t_stat sim_tape_rewind_a (UNIT *uptr, TAPE_PCALLBACK callback)
1731 {
1732 t_stat r = MTSE_OK;
1733 r = sim_tape_rewind (uptr);
1734 return r;
1735 }
1736
1737
1738
1739 t_stat sim_tape_position \
1740 (UNIT *uptr, uint32 flags, uint32 recs, uint32 *recsskipped, uint32 files, uint32 *filesskipped, uint32 *objectsskipped)
1741 {
1742 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1743 t_stat r = MTSE_OK;
1744
1745 if (ctx == NULL)
1746 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1747 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_position(unit=%d, flags=0x%X, recs=%lld, files=%lld)\n",
1748 (int)(uptr-ctx->dptr->units), flags, (long long)recs, (long long)files);
1749
1750 *recsskipped = *filesskipped = *objectsskipped = 0;
1751 if (flags & MTPOS_M_REW)
1752 r = sim_tape_rewind (uptr);
1753 if (r != MTSE_OK)
1754 return r;
1755 if (flags & MTPOS_M_OBJ) {
1756 uint32 objs = recs;
1757 uint32 skipped;
1758 uint32 objsremaining = objs;
1759
1760 while (*objectsskipped < objs) {
1761 if (flags & MTPOS_M_REV)
1762 r = sim_tape_sprecsr (uptr, objsremaining, &skipped);
1763 else
1764 r = sim_tape_sprecsf (uptr, objsremaining, &skipped);
1765 objsremaining = objsremaining - (skipped + ((r == MTSE_TMK) ? 1 : 0));
1766 if ((r == MTSE_TMK) || (r == MTSE_OK))
1767 *objectsskipped = *objectsskipped + skipped + ((r == MTSE_TMK) ? 1 : 0);
1768 else
1769 return r;
1770 }
1771 r = MTSE_OK;
1772 }
1773 else {
1774 uint32 fileskiprecs;
1775
1776 if (flags & MTPOS_M_REV)
1777 r = sim_tape_spfilebyrecr (uptr, files, filesskipped, &fileskiprecs);
1778 else
1779 r = sim_tape_spfilebyrecf (uptr, files, filesskipped, &fileskiprecs, (flags & MTPOS_M_DLE));
1780 if (r != MTSE_OK)
1781 return r;
1782 if (flags & MTPOS_M_REV)
1783 r = sim_tape_sprecsr (uptr, recs, recsskipped);
1784 else
1785 r = sim_tape_sprecsf (uptr, recs, recsskipped);
1786 if (r == MTSE_TMK)
1787 *filesskipped = *filesskipped + 1;
1788 *objectsskipped = fileskiprecs + *filesskipped + *recsskipped;
1789 }
1790 return r;
1791 }
1792
1793 t_stat sim_tape_position_a \
1794 (UNIT *uptr, uint32 flags, uint32 recs, uint32 *recsskipped, uint32 files,
1795 uint32 *filesskipped, uint32 *objectsskipped, TAPE_PCALLBACK callback)
1796 {
1797 t_stat r = MTSE_OK;
1798 r = sim_tape_position (uptr, flags, recs, recsskipped, files, filesskipped, objectsskipped);
1799 return r;
1800 }
1801
1802
1803
1804 t_stat sim_tape_reset (UNIT *uptr)
1805 {
1806 struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
1807
1808 MT_CLR_PNU (uptr);
1809 if (!(uptr->flags & UNIT_ATT))
1810 return SCPE_OK;
1811
1812 if (ctx == NULL)
1813 return sim_messagef (SCPE_IERR, "Bad Attach\n");
1814 sim_debug (ctx->dbit, ctx->dptr, "sim_tape_reset(unit=%d)\n", (int)(uptr-ctx->dptr->units));
1815
1816 _sim_tape_io_flush(uptr);
1817 return SCPE_OK;
1818 }
1819
1820
1821
1822 t_bool sim_tape_bot (UNIT *uptr)
1823 {
1824 uint32 f = MT_GET_FMT (uptr);
1825
1826 return (uptr->pos <= fmts[f].bot)? TRUE: FALSE;
1827 }
1828
1829
1830
1831 t_bool sim_tape_eot (UNIT *uptr)
1832 {
1833 return (uptr->capac && (uptr->pos >= uptr->capac))? TRUE: FALSE;
1834 }
1835
1836
1837
1838 t_bool sim_tape_wrp (UNIT *uptr)
1839 {
1840 return ((uptr->flags & MTUF_WRP) || (MT_GET_FMT (uptr) == MTUF_F_TPC))? TRUE: FALSE;
1841 }
1842
1843
1844
1845 static t_stat sim_tape_ioerr (UNIT *uptr)
1846 {
1847 sim_printf ("%s: Magtape library I/O error: %s (Error %d)\r\n", sim_uname (uptr), xstrerror_l(errno), errno);
1848 clearerr (uptr->fileref);
1849 return MTSE_IOERR;
1850 }
1851
1852
1853
1854 t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
1855 {
1856 uint32 f;
1857
1858 if (uptr == NULL)
1859 return SCPE_IERR;
1860 if (uptr->flags & UNIT_ATT)
1861 return SCPE_ALATT;
1862 if (cptr == NULL)
1863 return SCPE_ARG;
1864 for (f = 0; f < MTUF_N_FMT; f++) {
1865 if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) {
1866 uptr->flags = (uptr->flags & ~MTUF_FMT) |
1867 (f << MTUF_V_FMT) | fmts[f].uflags;
1868 return SCPE_OK;
1869 }
1870 }
1871 return SCPE_ARG;
1872 }
1873
1874
1875
1876 t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
1877 {
1878 int32 f = MT_GET_FMT (uptr);
1879
1880 if (fmts[f].name)
1881 fprintf (st, "%s format", fmts[f].name);
1882 else fprintf (st, "invalid format");
1883 return SCPE_OK;
1884 }
1885
1886
1887
1888 static uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map, uint32 mapsize)
1889 {
1890 t_addr tpos, leot = 0;
1891 t_addr tape_size;
1892 t_tpclnt bc, last_bc = 0xFFFF;
1893 uint32 had_double_tape_mark = 0;
1894 size_t i;
1895 uint32 objc, sizec;
1896 uint32 *countmap = NULL;
1897 uint8 *recbuf = NULL;
1898 DEVICE *dptr = find_dev_from_unit (uptr);
1899
1900 if ((uptr == NULL) || (uptr->fileref == NULL))
1901 return 0;
1902 countmap = (uint32 *)calloc (65536, sizeof(*countmap));
1903 if (!countmap)
1904 {
1905 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1906 __func__, __FILE__, __LINE__);
1907 #if defined(USE_BACKTRACE)
1908 # if defined(SIGUSR2)
1909 (void)raise(SIGUSR2);
1910
1911 # endif
1912 #endif
1913 abort();
1914 }
1915 recbuf = (uint8 *)malloc (65536);
1916 if (!recbuf)
1917 {
1918 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1919 __func__, __FILE__, __LINE__);
1920 #if defined(USE_BACKTRACE)
1921 # if defined(SIGUSR2)
1922 (void)raise(SIGUSR2);
1923
1924 # endif
1925 #endif
1926 abort();
1927 }
1928 tape_size = (t_addr)sim_fsize (uptr->fileref);
1929 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: tape_size: %" T_ADDR_FMT "u\n", tape_size);
1930 for (objc = 0, sizec = 0, tpos = 0;; ) {
1931 sim_fseek (uptr->fileref, tpos, SEEK_SET);
1932 i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref);
1933 if (i == 0)
1934 break;
1935 if (countmap[bc] == 0)
1936 sizec++;
1937 ++countmap[bc];
1938 if (map && (objc < mapsize))
1939 map[objc] = tpos;
1940 if (bc) {
1941 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: %lld byte count at pos: %" T_ADDR_FMT "u\n",
1942 (long long)bc, tpos);
1943 if (sim_deb && (dptr->dctrl & MTSE_DBG_STR)) {
1944 (void)sim_fread (recbuf, 1, bc, uptr->fileref);
1945 sim_data_trace(dptr, uptr, ((dptr->dctrl & MTSE_DBG_DAT) ? recbuf : NULL), "", bc, "Data Record", MTSE_DBG_STR);
1946 }
1947 }
1948 else
1949 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: tape mark at pos: %" T_ADDR_FMT "u\n", tpos);
1950 objc++;
1951 tpos = tpos + ((bc + 1) & ~1) + sizeof (t_tpclnt);
1952 if ((bc == 0) && (last_bc == 0)) {
1953 had_double_tape_mark = objc;
1954 leot = tpos;
1955 }
1956 last_bc = bc;
1957 }
1958 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: objc: %u, different record sizes: %u\n", objc, sizec);
1959 for (i=0; i<65535; i++) {
1960 if (countmap[i]) {
1961 if (i == 0)
1962 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: summary - %u tape marks\n",
1963 countmap[i]);
1964 else
1965 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: summary - %u %d byte record%s\n",
1966 countmap[i], (int)i, (countmap[i] > 1) ? "s" : "");
1967 }
1968 }
1969 if (((last_bc != 0xffff) &&
1970 (tpos > tape_size) &&
1971 (!had_double_tape_mark)) ||
1972 (!had_double_tape_mark) ||
1973 ((objc == countmap[0]) &&
1974 (countmap[0] != 2))) {
1975 if (last_bc != 0xffff)
1976 sim_debug (MTSE_DBG_STR, dptr,
1977 "tpc_map: ERROR unexpected EOT byte count: %lld\n",
1978 (long long)last_bc);
1979 if (tpos > tape_size)
1980 sim_debug (MTSE_DBG_STR, dptr,
1981 "tpc_map: ERROR next record position %" T_ADDR_FMT "u beyond EOT: %" T_ADDR_FMT "u\n",
1982 tpos, tape_size);
1983 if (objc == countmap[0])
1984 sim_debug (MTSE_DBG_STR, dptr,
1985 "tpc_map: ERROR tape cnly contains tape marks\n");
1986 FREE (countmap);
1987 FREE (recbuf);
1988 return 0;
1989 }
1990
1991 if ((last_bc != 0xffff) && (tpos > tape_size)) {
1992 sim_debug (MTSE_DBG_STR, dptr,
1993 "tpc_map: WARNING unexpected EOT byte count: %lld, double tape mark before %" T_ADDR_FMT "u provides logical EOT\n",
1994 (long long)last_bc, leot);
1995 objc = had_double_tape_mark;
1996 tpos = leot;
1997 }
1998 if (map)
1999 map[objc] = tpos;
2000 sim_debug (MTSE_DBG_STR, dptr, "tpc_map: OK objc: %lld\n", (long long)objc);
2001 FREE (countmap);
2002 FREE (recbuf);
2003 return objc;
2004 }
2005
2006
2007
2008 static t_stat sim_tape_simh_check (UNIT *uptr)
2009 {
2010 return SCPE_OK;
2011 }
2012
2013
2014
2015 static t_stat sim_tape_e11_check (UNIT *uptr)
2016 {
2017 return SCPE_OK;
2018 }
2019
2020
2021
2022 static t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map)
2023 {
2024 uint32 lo, hi, p;
2025
2026 if (map == NULL)
2027 return 0;
2028 lo = 0;
2029 hi = uptr->hwmark - 1;
2030 do {
2031 p = (lo + hi) >> 1;
2032 if (uptr->pos == map[p])
2033 return ((p == 0)? map[p]: map[p - 1]);
2034 else if (uptr->pos < map[p])
2035 hi = p - 1;
2036 else lo = p + 1;
2037 }
2038 while (lo <= hi);
2039 return ((p == 0)? map[p]: map[p - 1]);
2040 }
2041
2042
2043
2044 t_stat sim_tape_set_capac (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
2045 {
2046 t_addr cap;
2047 t_stat r;
2048
2049 if ((cptr == NULL) || (*cptr == 0))
2050 return SCPE_ARG;
2051 if (uptr->flags & UNIT_ATT)
2052 return SCPE_ALATT;
2053 cap = (t_addr) get_uint (cptr, 10, 2000000, &r);
2054 if (r != SCPE_OK)
2055 return SCPE_ARG;
2056 uptr->capac = cap * ((t_addr) 1000000);
2057 return SCPE_OK;
2058 }
2059
2060
2061
2062 t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
2063 {
2064 if (uptr->capac) {
2065 if (uptr->capac >= (t_addr) 1000000)
2066 fprintf (st, "capacity : %luMB", (unsigned long)(uptr->capac / ((t_addr) 1000000)));
2067 else {
2068 if (uptr->capac >= (t_addr) 1000)
2069 fprintf (st, "capacity : %luKB", (unsigned long)(uptr->capac / ((t_addr) 1000)));
2070 else
2071 fprintf (st, "capacity : %luB", (unsigned long)uptr->capac);
2072 }
2073 }
2074 else
2075 fprintf (st, "capacity : unlimited");
2076 return SCPE_OK;
2077 }
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098 t_stat sim_tape_set_dens (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
2099 {
2100 uint32 density, new_bpi;
2101 t_stat result = SCPE_OK;
2102
2103 if (uptr == NULL)
2104 return SCPE_IERR;
2105
2106 else if (desc == NULL)
2107 if (val > 0 && val < (int32) BPI_COUNT)
2108 uptr->dynflags = (uptr->dynflags & ~MTVF_DENS_MASK)
2109 | (val << UNIT_V_DF_TAPE);
2110 else
2111 return SCPE_ARG;
2112
2113 else {
2114 if (cptr == NULL || *cptr == 0)
2115 return SCPE_MISVAL;
2116
2117 new_bpi = (uint32) get_uint (cptr, 10, UINT_MAX, &result);
2118
2119 if (result != SCPE_OK)
2120 return SCPE_ARG;
2121
2122 else for (density = 0; density < BPI_COUNT; density++)
2123 if (new_bpi == bpi [density]
2124 && ((1 << density) & *(const int32 *) desc)) {
2125 uptr->dynflags = (uptr->dynflags & ~MTVF_DENS_MASK)
2126 | density << UNIT_V_DF_TAPE;
2127 return SCPE_OK;
2128 }
2129
2130 result = SCPE_ARG;
2131 }
2132
2133 return result;
2134 }
2135
2136
2137
2138 t_stat sim_tape_show_dens (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
2139 {
2140 uint32 tape_density;
2141
2142 if (uptr == NULL)
2143 return SCPE_IERR;
2144
2145 else {
2146 tape_density = bpi [MT_DENS (uptr->dynflags)];
2147
2148 if (tape_density)
2149 fprintf (st, "density=%lu bpi",
2150 (unsigned long)tape_density);
2151 else
2152 fprintf (st, "density not set");
2153 }
2154
2155 return SCPE_OK;
2156 }