1 /* pdp11_tm.c: PDP-11 magnetic tape simulator
3 Copyright (c) 1993-2006, 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.
28 16-Feb-06 RMS Added tape capacity checking
29 31-Oct-05 RMS Fixed address width for large files
30 16-Aug-05 RMS Fixed C++ declaration and cast problems
31 07-Jul-05 RMS Removed extraneous externs
32 18-Mar-05 RMS Added attached test to detach routine
33 07-Dec-04 RMS Added read-only file support
34 30-Sep-04 RMS Revised Unibus interface
35 25-Jan-04 RMS Revised for device debug support
36 29-Dec-03 RMS Added 18b Qbus support
37 25-Apr-03 RMS Revised for extended file support
38 28-Mar-03 RMS Added multiformat support
39 28-Feb-03 RMS Revised for magtape library, added logging
40 30-Oct-02 RMS Revised BOT handling, added error record handling
41 30-Sep-02 RMS Added variable address support to bootstrap
42 Added vector change/display support
43 Changed mapping mnemonics
45 Updated error handling
46 28-Aug-02 RMS Added end of medium support
47 30-May-02 RMS Widened POS to 32b
48 22-Apr-02 RMS Fixed max record length, first block bootstrap
49 (found by Jonathan Engdahl)
50 26-Jan-02 RMS Revised bootstrap to conform to M9312
51 06-Jan-02 RMS Revised enable/disable support
52 30-Nov-01 RMS Added read only unit, extended SET/SHOW support
53 24-Nov-01 RMS Converted UST, POS, FLG to arrays
54 09-Nov-01 RMS Added bus map support
55 18-Oct-01 RMS Added stub diagnostic register (found by Thord Nilson)
56 07-Sep-01 RMS Revised device disable and interrupt mechanisms
57 26-Apr-01 RMS Added device enable/disable support
58 18-Apr-01 RMS Changed to rewind tape before boot
59 14-Apr-99 RMS Changed t_addr to unsigned
60 04-Oct-98 RMS V2.4 magtape format
61 10-May-98 RMS Fixed bug with non-zero unit operation (from Steven Schultz)
62 09-May-98 RMS Fixed problems in bootstrap (from Steven Schultz)
63 10-Apr-98 RMS Added 2nd block bootstrap (from John Holden,
65 31-Jul-97 RMS Added bootstrap (from Ethan Dicks, Ohio State)
66 22-Jan-97 RMS V2.3 magtape format
67 18-Jan-97 RMS Fixed double interrupt, error flag bugs
68 29-Jun-96 RMS Added unit disable support
70 Magnetic tapes are represented as a series of variable 8b records
73 32b record length in bytes - exact number
79 32b record length in bytes - exact number
81 If the byte count is odd, the record is padded with an extra byte
82 of junk. File marks are represented by a single record length of 0.
83 End of tape is two consecutive end of file marks.
86 #include "pdp11_defs.h"
89 #define TM_NUMDR 8 /* #drives */
90 #define USTAT u3 /* unit status */
92 /* Command - tm_cmd */
94 #define MTC_ERR (1 << CSR_V_ERR) /* error */
95 #define MTC_V_DEN 13 /* density */
97 #define MTC_DEN (MTC_M_DEN << MTC_V_DEN)
98 #define MTC_INIT 0010000 /* init */
99 #define MTC_LPAR 0004000 /* parity select */
100 #define MTC_V_UNIT 8 /* unit */
101 #define MTC_M_UNIT 07
102 #define MTC_UNIT (MTC_M_UNIT << MTC_V_UNIT)
103 #define MTC_DONE (1 << CSR_V_DONE) /* done */
104 #define MTC_IE (1 << CSR_V_IE) /* interrupt enable */
105 #define MTC_V_EMA 4 /* ext mem address */
107 #define MTC_EMA (MTC_M_EMA << MTC_V_EMA)
108 #define MTC_V_FNC 1 /* function */
110 #define MTC_UNLOAD 00
114 #define MTC_SPACEF 04
115 #define MTC_SPACER 05
117 #define MTC_REWIND 07
118 #define MTC_FNC (MTC_M_FNC << MTC_V_FNC)
119 #define MTC_GO (1 << CSR_V_GO) /* go */
120 #define MTC_RW (MTC_DEN | MTC_LPAR | MTC_UNIT | MTC_IE | \
122 #define GET_EMA(x) (((x) & MTC_EMA) << (16 - MTC_V_EMA))
123 #define GET_UNIT(x) (((x) >> MTC_V_UNIT) & MTC_M_UNIT)
124 #define GET_FNC(x) (((x) >> MTC_V_FNC) & MTC_M_FNC)
126 /* Status - stored in tm_sta or (*) uptr->USTAT or (+) calculated */
128 #define STA_ILL 0100000 /* illegal */
129 #define STA_EOF 0040000 /* *end of file */
130 #define STA_CRC 0020000 /* CRC error */
131 #define STA_PAR 0010000 /* parity error */
132 #define STA_DLT 0004000 /* data late */
133 #define STA_EOT 0002000 /* +end of tape */
134 #define STA_RLE 0001000 /* rec lnt error */
135 #define STA_BAD 0000400 /* bad tape error */
136 #define STA_NXM 0000200 /* non-existent mem */
137 #define STA_ONL 0000100 /* *online */
138 #define STA_BOT 0000040 /* *start of tape */
139 #define STA_7TK 0000020 /* 7 track */
140 #define STA_SDN 0000010 /* settle down */
141 #define STA_WLK 0000004 /* *write locked */
142 #define STA_REW 0000002 /* *rewinding */
143 #define STA_TUR 0000001 /* +unit ready */
145 #define STA_CLR (STA_7TK | STA_SDN) /* always clear */
146 #define STA_DYN (STA_EOF | STA_EOT | STA_ONL | STA_BOT | \
147 STA_WLK | STA_REW | STA_TUR) /* dynamic */
148 #define STA_EFLGS (STA_ILL | STA_EOF | STA_CRC | STA_PAR | \
149 STA_DLT | STA_EOT | STA_RLE | STA_BAD | STA_NXM)
152 /* Read lines - tm_rdl */
154 #define RDL_CLK 0100000 /* 10 Khz clock */
156 extern uint16
*M
; /* memory */
157 extern int32 int_req
[IPL_HLVL
];
158 extern FILE *sim_deb
;
160 uint8
*tmxb
= NULL
; /* xfer buffer */
161 int32 tm_sta
= 0; /* status register */
162 int32 tm_cmd
= 0; /* command register */
163 int32 tm_ca
= 0; /* current address */
164 int32 tm_bc
= 0; /* byte count */
165 int32 tm_db
= 0; /* data buffer */
166 int32 tm_rdl
= 0; /* read lines */
167 int32 tm_time
= 10; /* record latency */
168 int32 tm_stopioe
= 1; /* stop on error */
171 t_stat
tm_rd (int32
*data
, int32 PA
, int32 access
);
172 t_stat
tm_wr (int32 data
, int32 PA
, int32 access
);
173 t_stat
tm_svc (UNIT
*uptr
);
174 t_stat
tm_reset (DEVICE
*dptr
);
175 t_stat
tm_attach (UNIT
*uptr
, char *cptr
);
176 t_stat
tm_detach (UNIT
*uptr
);
177 t_stat
tm_boot (int32 unitno
, DEVICE
*dptr
);
178 void tm_go (UNIT
*uptr
);
179 int32
tm_updcsta (UNIT
*uptr
);
180 void tm_set_done (void);
181 t_stat
tm_map_err (UNIT
*uptr
, t_stat st
);
182 t_stat
tm_vlock (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
184 /* MT data structures
186 tm_dev MT device descriptor
188 tm_reg MT register list
189 tm_mod MT modifier list
193 IOBA_TM
, IOLN_TM
, &tm_rd
, &tm_wr
,
194 1, IVCL (TM
), VEC_TM
, { NULL
}
198 { UDATA (&tm_svc
, UNIT_ATTABLE
+ UNIT_ROABLE
+UNIT_DISABLE
, 0) },
199 { UDATA (&tm_svc
, UNIT_ATTABLE
+ UNIT_ROABLE
+UNIT_DISABLE
, 0) },
200 { UDATA (&tm_svc
, UNIT_ATTABLE
+ UNIT_ROABLE
+UNIT_DISABLE
, 0) },
201 { UDATA (&tm_svc
, UNIT_ATTABLE
+ UNIT_ROABLE
+UNIT_DISABLE
, 0) },
202 { UDATA (&tm_svc
, UNIT_ATTABLE
+ UNIT_ROABLE
+UNIT_DISABLE
, 0) },
203 { UDATA (&tm_svc
, UNIT_ATTABLE
+ UNIT_ROABLE
+UNIT_DISABLE
, 0) },
204 { UDATA (&tm_svc
, UNIT_ATTABLE
+ UNIT_ROABLE
+UNIT_DISABLE
, 0) },
205 { UDATA (&tm_svc
, UNIT_ATTABLE
+ UNIT_ROABLE
+UNIT_DISABLE
, 0) }
209 { ORDATA (MTS
, tm_sta
, 16) },
210 { ORDATA (MTC
, tm_cmd
, 16) },
211 { ORDATA (MTBRC
, tm_bc
, 16) },
212 { ORDATA (MTCMA
, tm_ca
, 16) },
213 { ORDATA (MTD
, tm_db
, 8) },
214 { ORDATA (MTRD
, tm_rdl
, 16) },
215 { FLDATA (INT
, IREQ (TM
), INT_V_TM
) },
216 { FLDATA (ERR
, tm_cmd
, CSR_V_ERR
) },
217 { FLDATA (DONE
, tm_cmd
, CSR_V_DONE
) },
218 { FLDATA (IE
, tm_cmd
, CSR_V_IE
) },
219 { FLDATA (STOP_IOE
, tm_stopioe
, 0) },
220 { DRDATA (TIME
, tm_time
, 24), PV_LEFT
},
221 { URDATA (UST
, tm_unit
[0].USTAT
, 8, 16, 0, TM_NUMDR
, 0) },
222 { URDATA (POS
, tm_unit
[0].pos
, 10, T_ADDR_W
, 0,
223 TM_NUMDR
, PV_LEFT
| REG_RO
) },
224 { ORDATA (DEVADDR
, tm_dib
.ba
, 32), REG_HRO
},
225 { ORDATA (DEVVEC
, tm_dib
.vec
, 16), REG_HRO
},
230 { MTUF_WLK
, 0, "write enabled", "WRITEENABLED", &tm_vlock
},
231 { MTUF_WLK
, MTUF_WLK
, "write locked", "LOCKED", &tm_vlock
},
232 { MTAB_XTD
|MTAB_VUN
, 0, "FORMAT", "FORMAT",
233 &sim_tape_set_fmt
, &sim_tape_show_fmt
, NULL
},
234 { MTAB_XTD
|MTAB_VUN
, 0, "CAPACITY", "CAPACITY",
235 &sim_tape_set_capac
, &sim_tape_show_capac
, NULL
},
236 { MTAB_XTD
|MTAB_VDV
, 020, "ADDRESS", "ADDRESS",
237 &set_addr
, &show_addr
, NULL
},
238 { MTAB_XTD
|MTAB_VDV
, 0, "VECTOR", "VECTOR",
239 &set_vec
, &show_vec
, NULL
},
244 "TM", tm_unit
, tm_reg
, tm_mod
,
245 TM_NUMDR
, 10, T_ADDR_W
, 1, 8, 8,
246 NULL
, NULL
, &tm_reset
,
247 &tm_boot
, &tm_attach
, &tm_detach
,
248 &tm_dib
, DEV_DISABLE
| DEV_UBUS
| DEV_Q18
| DEV_DEBUG
251 /* I/O dispatch routines, I/O addresses 17772520 - 17772532
253 17772520 MTS read only, constructed from tm_sta
254 plus current drive status flags
255 17772522 MTC read/write
256 17772524 MTBRC read/write
257 17772526 MTCMA read/write
258 17772530 MTD read/write
259 17772532 MTRD read only
262 t_stat
tm_rd (int32
*data
, int32 PA
, int32 access
)
266 uptr
= tm_dev
.units
+ GET_UNIT (tm_cmd
); /* get unit */
267 switch ((PA
>> 1) & 07) { /* decode PA<3:1> */
270 *data
= tm_updcsta (uptr
); /* update status */
274 tm_updcsta (uptr
); /* update status */
275 *data
= tm_cmd
; /* return command */
279 *data
= tm_bc
; /* return byte count */
283 *data
= tm_ca
; /* return mem addr */
287 *data
= tm_db
; /* return data buffer */
291 tm_rdl
= tm_rdl
^ RDL_CLK
; /* "clock" ticks */
295 default: /* unimplemented */
303 t_stat
tm_wr (int32 data
, int32 PA
, int32 access
)
307 switch ((PA
>> 1) & 07) { /* decode PA<3:1> */
309 case 0: /* MTS: read only */
313 uptr
= tm_dev
.units
+ GET_UNIT (tm_cmd
); /* select unit */
314 if ((tm_cmd
& MTC_DONE
) == 0) tm_sta
= tm_sta
| STA_ILL
;
316 if (access
== WRITEB
) data
= (PA
& 1)?
317 (tm_cmd
& 0377) | (data
<< 8):
318 (tm_cmd
& ~0377) | data
;
319 if (data
& MTC_INIT
) { /* init? */
320 tm_reset (&tm_dev
); /* reset device */
323 if ((data
& MTC_IE
) == 0) /* int disable? */
324 CLR_INT (TM
); /* clr int request */
325 else if ((tm_cmd
& (MTC_ERR
+ MTC_DONE
)) && !(tm_cmd
& MTC_IE
))
326 SET_INT (TM
); /* set int request */
327 tm_cmd
= (tm_cmd
& ~MTC_RW
) | (data
& MTC_RW
);
328 uptr
= tm_dev
.units
+ GET_UNIT (tm_cmd
); /* new unit */
329 if (data
& MTC_GO
) tm_go (uptr
); /* new function? */
331 tm_updcsta (uptr
); /* update status */
335 if (access
== WRITEB
) data
= (PA
& 1)?
336 (tm_bc
& 0377) | (data
<< 8): (tm_bc
& ~0377) | data
;
341 if (access
== WRITEB
) data
= (PA
& 1)?
342 (tm_ca
& 0377) | (data
<< 8): (tm_ca
& ~0377) | data
;
347 if ((access
== WRITEB
) && (PA
& 1)) return SCPE_OK
;
355 /* New magtape command */
357 void tm_go (UNIT
*uptr
)
361 f
= GET_FNC (tm_cmd
); /* get function */
362 if (((uptr
->flags
& UNIT_ATT
) == 0) || /* not attached? */
363 sim_is_active (uptr
) || /* busy? */
364 (((f
== MTC_WRITE
) || (f
== MTC_WREOF
) || (f
== MTC_WREXT
)) &&
365 sim_tape_wrp (uptr
))) { /* write locked? */
366 tm_sta
= tm_sta
| STA_ILL
; /* illegal */
367 tm_set_done (); /* set done */
370 uptr
->USTAT
= uptr
->USTAT
& (STA_WLK
| STA_ONL
); /* clear status */
371 tm_sta
= 0; /* clear errors */
372 if (f
== MTC_UNLOAD
) { /* unload? */
373 uptr
->USTAT
= (uptr
->USTAT
| STA_REW
) & ~STA_ONL
;
374 detach_unit (uptr
); /* set offline */
376 else if (f
== MTC_REWIND
) /* rewind */
377 uptr
->USTAT
= uptr
->USTAT
| STA_REW
; /* rewinding */
378 /* else /* uncomment this else if rewind/unload don't set done */
379 tm_cmd
= tm_cmd
& ~MTC_DONE
; /* clear done */
380 CLR_INT (TM
); /* clear int */
381 sim_activate (uptr
, tm_time
); /* start io */
387 If rewind done, reposition to start of tape, set status
388 else, do operation, set done, interrupt
391 t_stat
tm_svc (UNIT
*uptr
)
396 t_stat st
, r
= SCPE_OK
;
398 u
= (int32
) (uptr
- tm_dev
.units
); /* get unit number */
399 f
= GET_FNC (tm_cmd
); /* get command */
400 xma
= GET_EMA (tm_cmd
) | tm_ca
; /* get mem addr */
401 cbc
= 0200000 - tm_bc
; /* get bc */
403 if (uptr
->USTAT
& STA_REW
) { /* rewind? */
404 sim_tape_rewind (uptr
); /* update position */
405 if (uptr
->flags
& UNIT_ATT
) /* still on line? */
406 uptr
->USTAT
= STA_ONL
| STA_BOT
|
407 (sim_tape_wrp (uptr
)? STA_WLK
: 0);
408 else uptr
->USTAT
= 0;
409 if (u
== GET_UNIT (tm_cmd
)) { /* selected? */
410 tm_set_done (); /* set done */
411 tm_updcsta (uptr
); /* update status */
416 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* if not attached */
417 uptr
->USTAT
= 0; /* unit off line */
418 tm_sta
= tm_sta
| STA_ILL
; /* illegal operation */
419 tm_set_done (); /* set done */
420 tm_updcsta (uptr
); /* update status */
421 return IORETURN (tm_stopioe
, SCPE_UNATT
);
424 if (DEBUG_PRS (tm_dev
)) fprintf (sim_deb
,
425 ">>TM: op=%o, ma=%o, bc=%o, pos=%d\n", f
, xma
, tm_bc
, uptr
->pos
);
426 switch (f
) { /* case on function */
428 case MTC_READ
: /* read */
429 st
= sim_tape_rdrecf (uptr
, tmxb
, &tbc
, MT_MAXFR
); /* read rec */
430 if (st
== MTSE_RECE
) tm_sta
= tm_sta
| STA_PAR
; /* rec in error? */
431 else if (st
!= MTSE_OK
) { /* other error? */
432 r
= tm_map_err (uptr
, st
); /* map error */
435 if (tbc
> cbc
) tm_sta
= tm_sta
| STA_RLE
; /* wrong size? */
436 if (tbc
< cbc
) cbc
= tbc
; /* use smaller */
437 if (t
= Map_WriteB (xma
, cbc
, tmxb
)) { /* copy buf to mem */
438 tm_sta
= tm_sta
| STA_NXM
; /* NXM, set err */
439 cbc
= cbc
- t
; /* adj byte cnt */
441 xma
= (xma
+ cbc
) & 0777777; /* inc bus addr */
442 tm_bc
= (tm_bc
+ cbc
) & 0177777; /* inc byte cnt */
445 case MTC_WRITE
: /* write */
446 case MTC_WREXT
: /* write ext gap */
447 if (t
= Map_ReadB (xma
, cbc
, tmxb
)) { /* copy mem to buf */
448 tm_sta
= tm_sta
| STA_NXM
; /* NXM, set err */
449 cbc
= cbc
- t
; /* adj byte cnt */
450 if (cbc
== 0) break; /* no xfr? done */
452 if (st
= sim_tape_wrrecf (uptr
, tmxb
, cbc
)) /* write rec, err? */
453 r
= tm_map_err (uptr
, st
); /* map error */
455 xma
= (xma
+ cbc
) & 0777777; /* inc bus addr */
456 tm_bc
= (tm_bc
+ cbc
) & 0177777; /* inc byte cnt */
460 case MTC_WREOF
: /* write eof */
461 if (st
= sim_tape_wrtmk (uptr
)) /* write tmk, err? */
462 r
= tm_map_err (uptr
, st
); /* map error */
465 case MTC_SPACEF
: /* space forward */
467 tm_bc
= (tm_bc
+ 1) & 0177777; /* incr wc */
468 if (st
= sim_tape_sprecf (uptr
, &tbc
)) { /* spc rec fwd, err? */
469 r
= tm_map_err (uptr
, st
); /* map error */
472 } while (tm_bc
!= 0);
475 case MTC_SPACER
: /* space reverse */
477 tm_bc
= (tm_bc
+ 1) & 0177777; /* incr wc */
478 if (st
= sim_tape_sprecr (uptr
, &tbc
)) { /* spc rec rev, err? */
479 r
= tm_map_err (uptr
, st
); /* map error */
482 } while (tm_bc
!= 0);
486 tm_cmd
= (tm_cmd
& ~MTC_EMA
) | ((xma
>> (16 - MTC_V_EMA
)) & MTC_EMA
);
487 tm_ca
= xma
& 0177777; /* update mem addr */
488 tm_set_done (); /* set done */
489 tm_updcsta (uptr
); /* update status */
490 if (DEBUG_PRS (tm_dev
)) fprintf (sim_deb
,
491 ">>TM: sta=%o, ma=%o, bc=%o, pos=%d\n",
492 tm_sta
, tm_ca
, tm_bc
, uptr
->pos
);
496 /* Update controller status */
498 int32
tm_updcsta (UNIT
*uptr
)
500 tm_sta
= (tm_sta
& ~(STA_DYN
| STA_CLR
)) | (uptr
->USTAT
& STA_DYN
);
501 if (sim_tape_eot (uptr
)) tm_sta
= tm_sta
| STA_EOT
;
502 if (sim_is_active (uptr
)) tm_sta
= tm_sta
& ~STA_TUR
;
503 else tm_sta
= tm_sta
| STA_TUR
;
504 if (tm_sta
& STA_EFLGS
) tm_cmd
= tm_cmd
| MTC_ERR
;
505 else tm_cmd
= tm_cmd
& ~MTC_ERR
;
506 if ((tm_cmd
& MTC_IE
) == 0) CLR_INT (TM
);
512 void tm_set_done (void)
514 tm_cmd
= tm_cmd
| MTC_DONE
;
515 if (tm_cmd
& MTC_IE
) SET_INT (TM
);
519 /* Map tape error status */
521 t_stat
tm_map_err (UNIT
*uptr
, t_stat st
)
525 case MTSE_FMT
: /* illegal fmt */
526 case MTSE_UNATT
: /* not attached */
527 tm_sta
= tm_sta
| STA_ILL
;
528 case MTSE_OK
: /* no error */
531 case MTSE_TMK
: /* tape mark */
532 uptr
->USTAT
= uptr
->USTAT
| STA_EOF
; /* end of file */
535 case MTSE_IOERR
: /* IO error */
536 tm_sta
= tm_sta
| STA_PAR
; /* parity error */
537 if (tm_stopioe
) return SCPE_IOERR
;
540 case MTSE_INVRL
: /* invalid rec lnt */
541 tm_sta
= tm_sta
| STA_PAR
; /* parity error */
544 case MTSE_RECE
: /* record in error */
545 tm_sta
= tm_sta
| STA_PAR
; /* parity error */
548 case MTSE_EOM
: /* end of medium */
549 tm_sta
= tm_sta
| STA_BAD
; /* bad tape */
552 case MTSE_BOT
: /* reverse into BOT */
553 uptr
->USTAT
= uptr
->USTAT
| STA_BOT
; /* set status */
556 case MTSE_WRP
: /* write protect */
557 tm_sta
= tm_sta
| STA_ILL
; /* illegal operation */
566 t_stat
tm_reset (DEVICE
*dptr
)
571 tm_cmd
= MTC_DONE
; /* set done */
572 tm_bc
= tm_ca
= tm_db
= tm_sta
= tm_rdl
= 0;
573 CLR_INT (TM
); /* clear interrupt */
574 for (u
= 0; u
< TM_NUMDR
; u
++) { /* loop thru units */
575 uptr
= tm_dev
.units
+ u
;
576 sim_tape_reset (uptr
); /* reset tape */
577 sim_cancel (uptr
); /* cancel activity */
578 if (uptr
->flags
& UNIT_ATT
) uptr
->USTAT
= STA_ONL
|
579 (sim_tape_bot (uptr
)? STA_BOT
: 0) |
580 (sim_tape_wrp (uptr
)? STA_WLK
: 0);
581 else uptr
->USTAT
= 0;
583 if (tmxb
== NULL
) tmxb
= (uint8
*) calloc (MT_MAXFR
, sizeof (uint8
));
584 if (tmxb
== NULL
) return SCPE_MEM
;
590 t_stat
tm_attach (UNIT
*uptr
, char *cptr
)
593 int32 u
= uptr
- tm_dev
.units
;
595 r
= sim_tape_attach (uptr
, cptr
);
596 if (r
!= SCPE_OK
) return r
;
597 uptr
->USTAT
= STA_ONL
| STA_BOT
| (sim_tape_wrp (uptr
)? STA_WLK
: 0);
598 if (u
== GET_UNIT (tm_cmd
)) tm_updcsta (uptr
);
604 t_stat
tm_detach (UNIT
* uptr
)
606 int32 u
= uptr
- tm_dev
.units
;
608 if (!(uptr
->flags
& UNIT_ATT
)) return SCPE_OK
;
609 if (!sim_is_active (uptr
)) uptr
->USTAT
= 0;
610 if (u
== GET_UNIT (tm_cmd
)) tm_updcsta (uptr
);
611 return sim_tape_detach (uptr
);
614 /* Write lock/enable routine */
616 t_stat
tm_vlock (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
618 int32 u
= uptr
- tm_dev
.units
;
620 if ((uptr
->flags
& UNIT_ATT
) &&
621 (val
|| sim_tape_wrp (uptr
)))
622 uptr
->USTAT
= uptr
->USTAT
| STA_WLK
;
623 else uptr
->USTAT
= uptr
->USTAT
& ~STA_WLK
;
624 if (u
== GET_UNIT (tm_cmd
)) tm_updcsta (uptr
);
630 Magtape boot format changed over time. Originally, a boot tape
631 contained a boot loader in the first block. Eventually, the first
632 block was reserved for a tape label, and the second block was
633 expected to contain a boot loader. BSD and DEC operating systems
634 use the second block scheme, so it is the default.
636 To boot from the first block, use boot -o (old).
639 #define BOOT_START 016000
640 #define BOOT_ENTRY (BOOT_START + 2)
641 #define BOOT_UNIT (BOOT_START + 010)
642 #define BOOT_CSR (BOOT_START + 014)
643 #define BOOT1_LEN (sizeof (boot1_rom) / sizeof (int16))
644 #define BOOT2_LEN (sizeof (boot2_rom) / sizeof (int16))
646 static const uint16 boot1_rom
[] = {
647 0046524, /* boot_start: "TM" */
648 0012706, BOOT_START
, /* mov #boot_start, sp */
649 0012700, 0000000, /* mov #unit_num, r0 */
650 0012701, 0172526, /* mov #172526, r1 ; mtcma */
651 0005011, /* clr (r1) */
652 0010141, /* mov r1, -(r1) ; mtbrc */
653 0010002, /* mov r0,r2 */
654 0000302, /* swab r2 */
655 0062702, 0060003, /* add #60003, r2 */
656 0010241, /* mov r2, -(r1) ; read + go */
657 0105711, /* tstb (r1) ; mtc */
658 0100376, /* bpl .-2 */
659 0005002, /* clr r2 */
660 0005003, /* clr r3 */
661 0012704, BOOT_START
+020, /* mov #boot_start+20, r4 */
662 0005005, /* clr r5 */
666 static const uint16 boot2_rom
[] = {
667 0046524, /* boot_start: "TM" */
668 0012706, BOOT_START
, /* mov #boot_start, sp */
669 0012700, 0000000, /* mov #unit_num, r0 */
670 0012701, 0172526, /* mov #172526, r1 ; mtcma */
671 0005011, /* clr (r1) */
672 0012741, 0177777, /* mov #-1, -(r1) ; mtbrc */
673 0010002, /* mov r0,r2 */
674 0000302, /* swab r2 */
675 0062702, 0060011, /* add #60011, r2 */
676 0010241, /* mov r2, -(r1) ; space + go */
677 0105711, /* tstb (r1) ; mtc */
678 0100376, /* bpl .-2 */
679 0010002, /* mov r0,r2 */
680 0000302, /* swab r2 */
681 0062702, 0060003, /* add #60003, r2 */
682 0010211, /* mov r2, (r1) ; read + go */
683 0105711, /* tstb (r1) ; mtc */
684 0100376, /* bpl .-2 */
685 0005002, /* clr r2 */
686 0005003, /* clr r3 */
687 0012704, BOOT_START
+020, /* mov #boot_start+20, r4 */
688 0005005, /* clr r5 */
692 t_stat
tm_boot (int32 unitno
, DEVICE
*dptr
)
695 extern int32 saved_PC
;
696 extern int32 sim_switches
;
698 sim_tape_rewind (&tm_unit
[unitno
]);
699 if (sim_switches
& SWMASK ('O')) {
700 for (i
= 0; i
< BOOT1_LEN
; i
++)
701 M
[(BOOT_START
>> 1) + i
] = boot1_rom
[i
];
704 for (i
= 0; i
< BOOT2_LEN
; i
++)
705 M
[(BOOT_START
>> 1) + i
] = boot2_rom
[i
];
707 M
[BOOT_UNIT
>> 1] = unitno
;
708 M
[BOOT_CSR
>> 1] = (tm_dib
.ba
& DMASK
) + 06;
709 saved_PC
= BOOT_ENTRY
;