4451572eda2dd4fb934f8992fcf6cf81b85fa593
1 /* pdp8_ct.c: PDP-8 cassette tape simulator
3 Copyright (c) 2006-2007, Robert M Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
26 ct TA8E/TU60 cassette tape
28 13-Aug-07 RMS Fixed handling of BEOT
29 06-Aug-07 RMS Foward op at BOT skips initial file gap
30 30-May-2007 RMS Fixed typo (from Norm Lastovica)
32 Magnetic tapes are represented as a series of variable records
43 If the byte count is odd, the record is padded with an extra byte
44 of junk. File marks are represented by a byte count of 0.
46 Cassette format differs in one very significant way: it has file gaps
47 rather than file marks. If the controller spaces or reads into a file
48 gap and then reverses direction, the file gap is not seen again. This
49 is in contrast to magnetic tapes, where the file mark is a character
50 sequence and is seen again if direction is reversed. In addition,
51 cassettes have an initial file gap which is automatically skipped on
52 forward operations from beginning of tape.
54 Note that the read and write sequences for the cassette are asymmetric:
56 Read: KLSA /SELECT READ
57 KGOA /INIT READ, CLEAR DF
58 <data flag sets, char in buf>
59 KGOA /READ 1ST CHAR, CLEAR DF
62 <data flag sets, char in buf>
63 KGOA /READ LAST CHAR, CLEAR DF
65 <data flag sets, CRC1 in buf>
68 <data flag sets, CRC2 in buf>
70 <ready flag/CRC error flag sets>
72 Write: KLSA /SELECT WRITE
74 KGOA /INIT WRITE, CHAR TO BUF, CLEAR DF
75 <data flag sets, char to tape>
78 KGOA /CHAR TO BUF, CLEAR DF
79 <data flag sets, char to tape>
81 KGOA /WRITE CRC, CLEAR DF
82 <ready flag sets, CRC on tape>
85 #include "pdp8_defs.h"
88 #define CT_NUMDR 2 /* #drives */
89 #define FNC u3 /* unit function */
90 #define UST u4 /* unit status */
91 #define CT_MAXFR (CT_SIZE) /* max record lnt */
92 #define CT_SIZE 93000 /* chars/tape */
94 /* Status Register A */
96 #define SRA_ENAB 0200 /* enable */
97 #define SRA_V_UNIT 6 /* unit */
98 #define SRA_M_UNIT (CT_NUMDR - 1)
99 #define SRA_V_FNC 3 /* function */
110 #define SRA_IE 0001 /* int enable */
111 #define GET_UNIT(x) (((x) >> SRA_V_UNIT) & SRA_M_UNIT)
112 #define GET_FNC(x) (((x) >> SRA_V_FNC) & SRA_M_FNC)
114 /* Function code flags */
116 #define OP_WRI 01 /* op is a write */
117 #define OP_REV 02 /* op is rev motion */
118 #define OP_FWD 04 /* op is fwd motion */
120 /* Unit status flags */
122 #define UST_REV (OP_REV) /* last op was rev */
123 #define UST_GAP 01 /* last op hit gap */
125 /* Status Register B, ^ = computed on the fly */
127 #define SRB_WLE 0400 /* "write lock err" */
128 #define SRB_CRC 0200 /* CRC error */
129 #define SRB_TIM 0100 /* timing error */
130 #define SRB_BEOT 0040 /* ^BOT/EOT */
131 #define SRB_EOF 0020 /* end of file */
132 #define SRB_EMP 0010 /* ^drive empty */
133 #define SRB_REW 0004 /* rewinding */
134 #define SRB_WLK 0002 /* ^write locked */
135 #define SRB_RDY 0001 /* ^ready */
136 #define SRB_ALLERR (SRB_WLE|SRB_CRC|SRB_TIM|SRB_BEOT|SRB_EOF|SRB_EMP)
137 #define SRB_XFRERR (SRB_WLE|SRB_CRC|SRB_TIM|SRB_EOF)
139 extern int32 int_req
, stop_inst
;
140 extern UNIT cpu_unit
;
141 extern FILE *sim_deb
;
143 uint32 ct_sra
= 0; /* status reg A */
144 uint32 ct_srb
= 0; /* status reg B */
145 uint32 ct_db
= 0; /* data buffer */
146 uint32 ct_df
= 0; /* data flag */
147 uint32 ct_write
= 0; /* TU60 write flag */
148 uint32 ct_bptr
= 0; /* buf ptr */
149 uint32 ct_blnt
= 0; /* buf length */
150 int32 ct_stime
= 1000; /* start time */
151 int32 ct_ctime
= 100; /* char latency */
152 uint32 ct_stopioe
= 1; /* stop on error */
153 uint8
*ct_xb
= NULL
; /* transfer buffer */
154 static uint8 ct_fnc_tab
[SRA_M_FNC
+ 1] = {
155 OP_FWD
, 0 , OP_WRI
|OP_FWD
, OP_REV
,
156 OP_WRI
|OP_FWD
, OP_REV
, 0, OP_FWD
160 int32
ct70 (int32 IR
, int32 AC
);
161 t_stat
ct_svc (UNIT
*uptr
);
162 t_stat
ct_reset (DEVICE
*dptr
);
163 t_stat
ct_attach (UNIT
*uptr
, char *cptr
);
164 t_stat
ct_detach (UNIT
*uptr
);
165 t_stat
ct_boot (int32 unitno
, DEVICE
*dptr
);
166 uint32
ct_updsta (UNIT
*uptr
);
167 int32
ct_go_start (int32 AC
);
168 int32
ct_go_cont (UNIT
*uptr
, int32 AC
);
169 t_stat
ct_map_err (UNIT
*uptr
, t_stat st
);
170 UNIT
*ct_busy (void);
171 void ct_set_df (t_bool timchk
);
172 t_bool
ct_read_char (void);
173 uint32
ct_crc (uint8
*buf
, uint32 cnt
);
175 /* CT data structures
177 ct_dev CT device descriptor
179 ct_reg CT register list
180 ct_mod CT modifier list
183 DIB ct_dib
= { DEV_CT
, 1, { &ct70
} };
186 { UDATA (&ct_svc
, UNIT_ATTABLE
+UNIT_ROABLE
, CT_SIZE
) },
187 { UDATA (&ct_svc
, UNIT_ATTABLE
+UNIT_ROABLE
, CT_SIZE
) },
191 { ORDATA (CTSRA
, ct_sra
, 8) },
192 { ORDATA (CTSRB
, ct_srb
, 8) },
193 { ORDATA (CTDB
, ct_db
, 8) },
194 { FLDATA (CTDF
, ct_df
, 0) },
195 { FLDATA (RDY
, ct_srb
, 0) },
196 { FLDATA (WLE
, ct_srb
, 8) },
197 { FLDATA (WRITE
, ct_write
, 0) },
198 { FLDATA (INT
, int_req
, INT_V_CT
) },
199 { DRDATA (BPTR
, ct_bptr
, 17) },
200 { DRDATA (BLNT
, ct_blnt
, 17) },
201 { DRDATA (STIME
, ct_stime
, 24), PV_LEFT
+ REG_NZ
},
202 { DRDATA (CTIME
, ct_ctime
, 24), PV_LEFT
+ REG_NZ
},
203 { FLDATA (STOP_IOE
, ct_stopioe
, 0) },
204 { URDATA (UFNC
, ct_unit
[0].FNC
, 8, 4, 0, CT_NUMDR
, 0), REG_HRO
},
205 { URDATA (UST
, ct_unit
[0].UST
, 8, 2, 0, CT_NUMDR
, 0), REG_HRO
},
206 { URDATA (POS
, ct_unit
[0].pos
, 10, T_ADDR_W
, 0,
207 CT_NUMDR
, PV_LEFT
| REG_RO
) },
208 { FLDATA (DEVNUM
, ct_dib
.dev
, 6), REG_HRO
},
213 { MTUF_WLK
, 0, "write enabled", "WRITEENABLED", NULL
},
214 { MTUF_WLK
, MTUF_WLK
, "write locked", "LOCKED", NULL
},
215 // { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
216 // &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
217 { MTAB_XTD
|MTAB_VUN
, 0, "CAPACITY", NULL
,
218 NULL
, &sim_tape_show_capac
, NULL
},
219 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", "DEVNO",
220 &set_dev
, &show_dev
, NULL
},
225 "CT", ct_unit
, ct_reg
, ct_mod
,
226 CT_NUMDR
, 10, 31, 1, 8, 8,
227 NULL
, NULL
, &ct_reset
,
228 &ct_boot
, &ct_attach
, &ct_detach
,
229 &ct_dib
, DEV_DISABLE
| DEV_DIS
| DEV_DEBUG
234 int32
ct70 (int32 IR
, int32 AC
)
239 srb
= ct_updsta (NULL
); /* update status */
240 switch (IR
& 07) { /* decode IR<9:11> */
243 ct_reset (&ct_dev
); /* reset the world */
247 if (ct_df
) AC
|= IOT_SKP
;
251 if (srb
& SRB_ALLERR
) AC
|= IOT_SKP
;
255 if ((srb
& SRB_RDY
) && !(srb
& SRB_EMP
))
262 return ct_sra
^ 0377;
265 if (ct_df
|| (srb
& (SRB_ALLERR
|SRB_RDY
)))
270 ct_df
= 0; /* clear data flag */
271 if (uptr
= ct_busy ()) /* op in progress? */
272 AC
= ct_go_cont (uptr
, AC
); /* yes */
273 else AC
= ct_go_start (AC
); /* no, start */
284 /* Start a new operation - cassette is not busy */
286 int32
ct_go_start (int32 AC
)
288 UNIT
*uptr
= ct_dev
.units
+ GET_UNIT (ct_sra
);
289 uint32 fnc
= GET_FNC (ct_sra
);
290 uint32 flg
= ct_fnc_tab
[fnc
];
291 uint32 old_ust
= uptr
->UST
;
293 if (DEBUG_PRS (ct_dev
)) fprintf (sim_deb
,
294 ">>CT start: op=%o, old_sta = %o, pos=%d\n",
295 fnc
, uptr
->UST
, uptr
->pos
);
296 if ((ct_sra
& SRA_ENAB
) && (uptr
->flags
& UNIT_ATT
)) { /* enabled, att? */
297 ct_srb
&= ~(SRB_XFRERR
|SRB_REW
); /* clear err, rew */
298 if (flg
& OP_WRI
) { /* write-type op? */
299 if (sim_tape_wrp (uptr
)) { /* locked? */
300 ct_srb
|= SRB_WLE
; /* set flag, abort */
303 ct_write
= 1; /* set TU60 wr flag */
310 ct_srb
&= ~SRB_BEOT
; /* tape in motion */
311 if (fnc
== SRA_REW
) ct_srb
|= SRB_REW
; /* rew? set flag */
312 if ((fnc
!= SRA_REW
) && !(flg
& OP_WRI
)) { /* read cmd? */
315 uptr
->UST
= flg
& UST_REV
; /* save direction */
316 if (sim_tape_bot (uptr
) && (flg
& OP_FWD
)) { /* spc/read fwd bot? */
317 st
= sim_tape_rdrecf (uptr
, ct_xb
, &t
, CT_MAXFR
); /* skip file gap */
318 if (st
!= MTSE_TMK
) /* not there? */
319 sim_tape_rewind (uptr
); /* restore tap pos */
320 else old_ust
= 0; /* defang next */
322 if ((old_ust
^ uptr
->UST
) == (UST_REV
|UST_GAP
)) { /* rev in gap? */
323 if (DEBUG_PRS (ct_dev
)) fprintf (sim_deb
,
324 ">>CT skip gap: op=%o, old_sta = %o, pos=%d\n",
325 fnc
, uptr
->UST
, uptr
->pos
);
326 if (uptr
->UST
) /* skip file gap */
327 sim_tape_rdrecr (uptr
, ct_xb
, &t
, CT_MAXFR
);
328 else sim_tape_rdrecf (uptr
, ct_xb
, &t
, CT_MAXFR
);
332 ct_bptr
= 0; /* init buffer */
334 uptr
->FNC
= fnc
; /* save function */
335 sim_activate (uptr
, ct_stime
); /* schedule op */
337 if ((fnc
== SRA_READ
) || (fnc
== SRA_CRC
)) /* read or CRC? */
338 return 0; /* get "char" */
342 /* Continue an in-progress operation - cassette is in motion */
344 int32
ct_go_cont (UNIT
*uptr
, int32 AC
)
346 int32 fnc
= GET_FNC (ct_sra
);
348 switch (fnc
) { /* case on function */
350 case SRA_READ
: /* read */
351 return ct_db
; /* return data */
353 case SRA_WRITE
: /* write */
354 ct_db
= AC
& 0377; /* save data */
357 case SRA_CRC
: /* CRC */
358 if ((uptr
->FNC
& SRA_M_FNC
) != SRA_CRC
) /* if not CRC */
359 uptr
->FNC
= SRA_CRC
; /* start CRC seq */
360 if (!ct_write
) return ct_db
; /* read? AC <- buf */
372 t_stat
ct_svc (UNIT
*uptr
)
375 uint32 flgs
= ct_fnc_tab
[uptr
->FNC
& SRA_M_FNC
];
379 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* not attached? */
380 ct_updsta (uptr
); /* update status */
381 return (ct_stopioe
? SCPE_UNATT
: SCPE_OK
);
383 if (((flgs
& OP_REV
) && sim_tape_bot (uptr
)) || /* rev at BOT or */
384 ((flgs
& OP_FWD
) && sim_tape_eot (uptr
))) { /* fwd at EOT? */
385 ct_srb
|= SRB_BEOT
; /* error */
386 ct_updsta (uptr
); /* op done */
391 switch (uptr
->FNC
) { /* case on function */
393 case SRA_READ
: /* read start */
394 st
= sim_tape_rdrecf (uptr
, ct_xb
, &ct_blnt
, CT_MAXFR
); /* get rec */
395 if (st
== MTSE_RECE
) ct_srb
|= SRB_CRC
; /* rec in err? */
396 else if (st
!= MTSE_OK
) { /* other error? */
397 r
= ct_map_err (uptr
, st
); /* map error */
400 crc
= ct_crc (ct_xb
, ct_blnt
); /* calculate CRC */
401 ct_xb
[ct_blnt
++] = (crc
>> 8) & 0377; /* append to buffer */
402 ct_xb
[ct_blnt
++] = crc
& 0377;
403 uptr
->FNC
|= SRA_2ND
; /* next state */
404 sim_activate (uptr
, ct_ctime
); /* sched next char */
407 case SRA_READ
|SRA_2ND
: /* read char */
408 if (!ct_read_char ()) break; /* read, overrun? */
409 ct_set_df (TRUE
); /* set data flag */
410 sim_activate (uptr
, ct_ctime
); /* sched next char */
413 case SRA_WRITE
: /* write start */
414 for (i
= 0; i
< CT_MAXFR
; i
++) ct_xb
[i
] = 0; /* clear buffer */
415 uptr
->FNC
|= SRA_2ND
; /* next state */
416 sim_activate (uptr
, ct_ctime
); /* sched next char */
419 case SRA_WRITE
|SRA_2ND
: /* write char */
420 if ((ct_bptr
< CT_MAXFR
) && /* room in buf? */
421 ((uptr
->pos
+ ct_bptr
) < uptr
->capac
)) /* room on tape? */
422 ct_xb
[ct_bptr
++] = ct_db
; /* store char */
423 ct_set_df (TRUE
); /* set data flag */
424 sim_activate (uptr
, ct_ctime
); /* sched next char */
427 case SRA_CRC
: /* CRC */
428 if (ct_write
) { /* write? */
429 if (st
= sim_tape_wrrecf (uptr
, ct_xb
, ct_bptr
)) /* write, err? */
430 r
= ct_map_err (uptr
, st
); /* map error */
431 break; /* write done */
433 ct_read_char (); /* get second CRC */
434 ct_set_df (FALSE
); /* set df */
435 uptr
->FNC
|= SRA_2ND
; /* next state */
436 sim_activate (uptr
, ct_ctime
);
439 case SRA_CRC
|SRA_2ND
: /* second read CRC */
440 if (ct_bptr
!= ct_blnt
) { /* partial read? */
441 crc
= ct_crc (ct_xb
, ct_bptr
); /* actual CRC */
442 if (crc
!= 0) ct_srb
|= SRB_CRC
; /* must be zero */
444 break; /* read done */
446 case SRA_WFG
: /* write file gap */
447 if (st
= sim_tape_wrtmk (uptr
)) /* write tmk, err? */
448 r
= ct_map_err (uptr
, st
); /* map error */
451 case SRA_REW
: /* rewind */
452 sim_tape_rewind (uptr
);
453 ct_srb
|= SRB_BEOT
; /* set BOT */
456 case SRA_SRB
: /* space rev blk */
457 if (st
= sim_tape_sprecr (uptr
, &tbc
)) /* space rev, err? */
458 r
= ct_map_err (uptr
, st
); /* map error */
461 case SRA_SRF
: /* space rev file */
462 while ((st
= sim_tape_sprecr (uptr
, &tbc
)) == MTSE_OK
) ;
463 r
= ct_map_err (uptr
, st
); /* map error */
466 case SRA_SFF
: /* space fwd file */
467 while ((st
= sim_tape_sprecf (uptr
, &tbc
)) == MTSE_OK
) ;
468 r
= ct_map_err (uptr
, st
); /* map error */
471 default: /* never get here! */
475 ct_updsta (uptr
); /* update status */
476 if (DEBUG_PRS (ct_dev
)) fprintf (sim_deb
,
477 ">>CT done: op=%o, statusA = %o, statusB = %o, pos=%d\n",
478 uptr
->FNC
, ct_sra
, ct_srb
, uptr
->pos
);
482 /* Update controller status */
484 uint32
ct_updsta (UNIT
*uptr
)
488 if (uptr
== NULL
) { /* unit specified? */
489 uptr
= ct_busy (); /* use busy unit */
490 if ((uptr
== NULL
) && (ct_sra
& SRA_ENAB
)) /* none busy? */
491 uptr
= ct_dev
.units
+ GET_UNIT (ct_sra
); /* use sel unit */
493 else if (ct_srb
& SRB_EOF
) uptr
->UST
|= UST_GAP
; /* save gap */
494 if (uptr
) { /* any unit? */
495 ct_srb
&= ~(SRB_WLK
|SRB_EMP
|SRB_RDY
); /* clear dyn flags */
496 if ((uptr
->flags
& UNIT_ATT
) == 0) /* unattached? */
497 ct_srb
= (ct_srb
| SRB_EMP
|SRB_WLK
) & ~SRB_REW
; /* empty, locked */
498 if (!sim_is_active (uptr
)) { /* not busy? */
499 ct_srb
= (ct_srb
| SRB_RDY
) & ~SRB_REW
; /* ready, ~rew */
501 if (sim_tape_wrp (uptr
) || (ct_srb
& SRB_REW
)) /* locked or rew? */
502 ct_srb
|= SRB_WLK
; /* set locked */
504 if (ct_sra
& SRA_ENAB
) srb
= ct_srb
; /* can TA see TU60? */
505 else srb
= 0; /* no */
506 if ((ct_sra
& SRA_IE
) && /* int enabled? */
507 (ct_df
|| (srb
& (SRB_ALLERR
|SRB_RDY
)))) /* any flag? */
508 int_req
|= INT_CT
; /* set int req */
509 else int_req
&= ~INT_CT
; /* no, clr int req */
515 void ct_set_df (t_bool timchk
)
517 if (ct_df
&& timchk
) ct_srb
|= SRB_TIM
; /* flag still set? */
518 ct_df
= 1; /* set data flag */
519 if (ct_sra
& SRA_IE
) int_req
|= INT_CT
; /* if ie, int req */
525 t_bool
ct_read_char (void)
527 if (ct_bptr
< ct_blnt
) { /* more chars? */
528 ct_db
= ct_xb
[ct_bptr
++];
532 ct_srb
|= SRB_CRC
; /* overrun */
536 /* Test if controller busy */
543 for (u
= 0; u
< CT_NUMDR
; u
++) { /* loop thru units */
544 uptr
= ct_dev
.units
+ u
;
545 if (sim_is_active (uptr
)) return uptr
;
550 /* Calculate CRC on buffer */
552 uint32
ct_crc (uint8
*buf
, uint32 cnt
)
557 for (i
= 0; i
< cnt
; i
++) {
558 crc
= crc
^ (((uint32
) buf
[i
]) << 8);
559 for (j
= 0; j
< 8; j
++) {
560 if (crc
& 1) crc
= (crc
>> 1) ^ 0xA001;
567 /* Map error status */
569 t_stat
ct_map_err (UNIT
*uptr
, t_stat st
)
573 case MTSE_FMT
: /* illegal fmt */
574 case MTSE_UNATT
: /* unattached */
576 case MTSE_OK
: /* no error */
577 return SCPE_IERR
; /* never get here! */
579 case MTSE_TMK
: /* end of file */
583 case MTSE_IOERR
: /* IO error */
584 ct_srb
|= SRB_CRC
; /* set crc err */
585 if (ct_stopioe
) return SCPE_IOERR
;
588 case MTSE_INVRL
: /* invalid rec lnt */
589 ct_srb
|= SRB_CRC
; /* set crc err */
592 case MTSE_RECE
: /* record in error */
593 case MTSE_EOM
: /* end of medium */
594 ct_srb
|= SRB_CRC
; /* set crc err */
597 case MTSE_BOT
: /* reverse into BOT */
598 ct_srb
|= SRB_BEOT
; /* set BOT */
601 case MTSE_WRP
: /* write protect */
602 ct_srb
|= SRB_WLE
; /* set wlk err */
611 t_stat
ct_reset (DEVICE
*dptr
)
623 int_req
= int_req
& ~INT_CT
; /* clear interrupt */
624 for (u
= 0; u
< CT_NUMDR
; u
++) { /* loop thru units */
625 uptr
= ct_dev
.units
+ u
;
626 sim_cancel (uptr
); /* cancel activity */
627 sim_tape_reset (uptr
); /* reset tape */
629 if (ct_xb
== NULL
) ct_xb
= (uint8
*) calloc (CT_MAXFR
+ 2, sizeof (uint8
));
630 if (ct_xb
== NULL
) return SCPE_MEM
;
636 t_stat
ct_attach (UNIT
*uptr
, char *cptr
)
640 r
= sim_tape_attach (uptr
, cptr
);
641 if (r
!= SCPE_OK
) return r
;
649 t_stat
ct_detach (UNIT
* uptr
)
653 if (!(uptr
->flags
& UNIT_ATT
)) return SCPE_OK
; /* check attached */
654 r
= sim_tape_detach (uptr
);
660 /* Bootstrap routine */
662 #define BOOT_START 04000
663 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
665 static const uint16 boot_rom
[] = {
666 01237, /* BOOT, TAD M50 /change CRC to REW */
667 01206, /* CRCCHK, TAD L260 /crc op */
668 06704, /* KLSA /load op */
669 06706, /* KGOA /start */
670 06703, /* KSBF /ready? */
671 05204, /* RDCOD, JMP .-1 /loop */
672 07264, /* L260, CML STA RAL /L = 1, AC = halt */
673 06702, /* KSEN /error? */
674 07610, /* SKP CLA /halt on any error */
675 03211, /* DCA . /except REW or FFG */
676 03636, /* DCA I PTR /TAD I PTR mustn't change L */
677 01205, /* TAD RDCOD /read op */
678 06704, /* KLSA /load op */
679 06706, /* KGOA /start */
680 06701, /* LOOP, KSDF /data ready? */
681 05216, /* JMP .-1 /loop */
682 07002, /* BSW /to upper 6b */
683 07430, /* SZL /second byte? */
684 01636, /* TAD I PTR /yes */
685 07022, /* CML BSW /swap back */
686 03636, /* DCA I PTR /store in mem */
687 07420, /* SNL /done with both bytes? */
688 02236, /* ISZ PTR /yes, bump mem ptr */
689 02235, /* ISZ KNT /done with record? */
690 05215, /* JMP LOOP /next byte */
691 07346, /* STA CLL RTL */
692 07002, /* BSW /AC = 7757 */
693 03235, /* STA KNT /now read 200 byte record */
694 05201, /* JMP CRCCHK /go check CRC */
695 07737, /* KNT, 7737 /1's compl of byte count */
696 03557, /* PTR, 3557 /load point */
697 07730, /* M50, 7730 /CLA SPA SZL */
700 t_stat
ct_boot (int32 unitno
, DEVICE
*dptr
)
703 extern int32 saved_PC
;
706 if ((ct_dib
.dev
!= DEV_CT
) || unitno
) /* only std devno */
708 for (i
= 0; i
< BOOT_LEN
; i
++) M
[BOOT_START
+ i
] = boot_rom
[i
];
709 saved_PC
= BOOT_START
;