1095 lines
44 KiB
C
1095 lines
44 KiB
C
/* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller
|
|
|
|
Copyright (c) 1993-2013, Robert M Supnik
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of Robert M Supnik shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Robert M Supnik.
|
|
|
|
tu TM02/TM03 magtape
|
|
|
|
23-Oct-13 RMS Revised for new boot setup routine
|
|
18-Apr-11 MP Fixed t_addr printouts for 64b big-endian systems
|
|
17-May-07 RMS CS1 DVA resides in device, not MBA
|
|
29-Apr-07 RMS Fixed bug in setting FCE on TMK Naoki Hamada)
|
|
16-Feb-06 RMS Added tape capacity checking
|
|
12-Nov-05 RMS Changed default formatter to TM03 (for VMS)
|
|
31-Oct-05 RMS Fixed address width for large files
|
|
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
|
31-Mar-05 RMS Fixed inaccuracies in error reporting
|
|
18-Mar-05 RMS Added attached test to detach routine
|
|
10-Sep-04 RMS Cloned from pdp10_tu.c
|
|
|
|
Magnetic tapes are represented as a series of variable 8b records
|
|
of the form:
|
|
|
|
32b record length in bytes - exact number, sign = error
|
|
byte 0
|
|
byte 1
|
|
:
|
|
byte n-2
|
|
byte n-1
|
|
32b record length in bytes - exact number, sign = error
|
|
|
|
If the byte count is odd, the record is padded with an extra byte
|
|
of junk. File marks are represented by a single record length of 0.
|
|
End of tape is two consecutive end of file marks.
|
|
*/
|
|
|
|
#if defined (VM_PDP10)
|
|
#error "PDP-10 uses pdp10_tu.c!"
|
|
|
|
#elif defined (VM_PDP11)
|
|
#include "pdp11_defs.h"
|
|
#define DEV_DIS_INIT DEV_DIS
|
|
|
|
#elif defined (VM_VAX)
|
|
#include "vax_defs.h"
|
|
#define DEV_DIS_INIT 0
|
|
#if (!UNIBUS)
|
|
#error "Qbus not supported!"
|
|
#endif
|
|
|
|
#endif
|
|
#include "sim_tape.h"
|
|
|
|
#define TU_NUMFM 1 /* #formatters */
|
|
#define TU_NUMDR 8 /* #drives */
|
|
#define USTAT u3 /* unit status */
|
|
#define UDENS u4 /* unit density */
|
|
#define UD_UNK 0 /* unknown */
|
|
#define MT_MAXFR (1 << 16) /* max data buf */
|
|
#define DEV_V_TM03 (DEV_V_FFUF + 0) /* TM02/TM03 */
|
|
#define DEV_TM03 (1 << DEV_V_TM03)
|
|
#define UNIT_V_TYPE (MTUF_V_UF + 0)
|
|
#define UNIT_M_TYPE 03
|
|
#define UNIT_TYPE (UNIT_M_TYPE << UNIT_V_TYPE)
|
|
#define UNIT_TE16 (0 << UNIT_V_TYPE)
|
|
#define UNIT_TU45 (1 << UNIT_V_TYPE)
|
|
#define UNIT_TU77 (2 << UNIT_V_TYPE)
|
|
#define GET_TYPE(x) (((x) >> UNIT_V_TYPE) & UNIT_M_TYPE)
|
|
|
|
/* CS1 - offset 0 */
|
|
|
|
#define CS1_OF 0
|
|
#define CS1_GO CSR_GO /* go */
|
|
#define CS1_V_FNC 1 /* function pos */
|
|
#define CS1_M_FNC 037 /* function mask */
|
|
#define CS1_N_FNC (CS1_M_FNC + 1)
|
|
#define FNC_NOP 000 /* no operation */
|
|
#define FNC_UNLOAD 001 /* unload */
|
|
#define FNC_REWIND 003 /* rewind */
|
|
#define FNC_FCLR 004 /* formatter clear */
|
|
#define FNC_RIP 010 /* read in preset */
|
|
#define FNC_ERASE 012 /* erase tape */
|
|
#define FNC_WREOF 013 /* write tape mark */
|
|
#define FNC_SPACEF 014 /* space forward */
|
|
#define FNC_SPACER 015 /* space reverse */
|
|
#define FNC_XFER 024 /* >=? data xfr */
|
|
#define FNC_WCHKF 024 /* write check */
|
|
#define FNC_WCHKR 027 /* write check rev */
|
|
#define FNC_WRITE 030 /* write */
|
|
#define FNC_READF 034 /* read forward */
|
|
#define FNC_READR 037 /* read reverse */
|
|
#define CS1_RW 077
|
|
#define CS1_DVA 04000 /* drive avail */
|
|
#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
|
|
|
|
/* TUFS - formatter status - offset 1
|
|
+ indicates kept in drive status
|
|
^ indicates calculated on the fly
|
|
*/
|
|
|
|
#define FS_OF 1
|
|
#define FS_SAT 0000001 /* slave attention */
|
|
#define FS_BOT 0000002 /* ^beginning of tape */
|
|
#define FS_TMK 0000004 /* end of file */
|
|
#define FS_ID 0000010 /* ID burst detected */
|
|
#define FS_SLOW 0000020 /* slowing down NI */
|
|
#define FS_PE 0000040 /* ^PE status */
|
|
#define FS_SSC 0000100 /* slave stat change */
|
|
#define FS_RDY 0000200 /* ^formatter ready */
|
|
#define FS_FPR 0000400 /* formatter present */
|
|
#define FS_EOT 0002000 /* +end of tape */
|
|
#define FS_WRL 0004000 /* ^write locked */
|
|
#define FS_MOL 0010000 /* ^medium online */
|
|
#define FS_PIP 0020000 /* +pos in progress */
|
|
#define FS_ERR 0040000 /* ^error */
|
|
#define FS_ATA 0100000 /* attention active */
|
|
#define FS_REW 0200000 /* +rewinding */
|
|
|
|
#define FS_DYN (FS_ERR | FS_PIP | FS_MOL | FS_WRL | FS_EOT | \
|
|
FS_RDY | FS_PE | FS_BOT)
|
|
|
|
/* TUER - error register - offset 2 */
|
|
|
|
#define ER_OF 2
|
|
#define ER_ILF 0000001 /* illegal func */
|
|
#define ER_ILR 0000002 /* illegal register */
|
|
#define ER_RMR 0000004 /* reg mod refused */
|
|
#define ER_MCP 0000010 /* Mbus cpar err NI */
|
|
#define ER_FER 0000020 /* format sel err */
|
|
#define ER_MDP 0000040 /* Mbus dpar err NI */
|
|
#define ER_VPE 0000100 /* vert parity err */
|
|
#define ER_CRC 0000200 /* CRC err NI */
|
|
#define ER_NSG 0000400 /* non std gap err NI */
|
|
#define ER_FCE 0001000 /* frame count err */
|
|
#define ER_ITM 0002000 /* inv tape mark NI */
|
|
#define ER_NXF 0004000 /* wlock or fnc err */
|
|
#define ER_DTE 0010000 /* time err NI */
|
|
#define ER_OPI 0020000 /* op incomplete */
|
|
#define ER_UNS 0040000 /* drive unsafe */
|
|
#define ER_DCK 0100000 /* data check NI */
|
|
|
|
/* TUMR - maintenance register - offset 03 */
|
|
|
|
#define MR_OF 3
|
|
#define MR_RW 0177637 /* read/write */
|
|
|
|
/* TUAS - attention summary - offset 4 */
|
|
|
|
#define AS_OF 4
|
|
#define AS_U0 0000001 /* unit 0 flag */
|
|
|
|
/* TUFC - offset 5 */
|
|
|
|
#define FC_OF 5
|
|
|
|
/* TUDT - drive type - offset 6 */
|
|
|
|
#define DT_OF 6
|
|
#define DT_NSA 0100000 /* not sect addr */
|
|
#define DT_TAPE 0040000 /* tape */
|
|
#define DT_PRES 0002000 /* slave present */
|
|
#define DT_TM03 0000040 /* TM03 formatter */
|
|
#define DT_OFF 0000010 /* drive off */
|
|
#define DT_TU16 0000011 /* TE16 */
|
|
#define DT_TU45 0000012 /* TU45 */
|
|
#define DT_TU77 0000014 /* TU77 */
|
|
|
|
/* TUCC - check character, read only - offset 7 */
|
|
|
|
#define CC_OF 7
|
|
#define CC_MBZ 0177000 /* must be zero */
|
|
|
|
/* TUSN - serial number - offset 8 */
|
|
|
|
#define SN_OF 8
|
|
|
|
/* TUTC - tape control register - offset 9 */
|
|
|
|
#define TC_OF 9
|
|
#define TC_V_UNIT 0 /* unit select */
|
|
#define TC_M_UNIT 07
|
|
#define TC_V_EVN 0000010 /* even parity */
|
|
#define TC_V_FMT 4 /* format select */
|
|
#define TC_M_FMT 017
|
|
#define TC_STD 014 /* standard */
|
|
#define TC_CDUMP 015 /* core dump */
|
|
#define TC_V_DEN 8 /* density select */
|
|
#define TC_M_DEN 07
|
|
#define TC_800 3 /* 800 bpi */
|
|
#define TC_1600 4 /* 1600 bpi */
|
|
#define TC_AER 0010000 /* abort on error */
|
|
#define TC_SAC 0020000 /* slave addr change */
|
|
#define TC_FCS 0040000 /* frame count status */
|
|
#define TC_ACC 0100000 /* accelerating NI */
|
|
#define TC_RW 0013777
|
|
#define TC_MBZ 0004000
|
|
#define TC_RIP ((TC_800 << TC_V_DEN) | (TC_STD << TC_V_FMT))
|
|
#define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN)
|
|
#define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT)
|
|
#define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT)
|
|
|
|
int32 tucs1 = 0; /* control/status 1 */
|
|
int32 tufc = 0; /* frame count */
|
|
int32 tufs = 0; /* formatter status */
|
|
int32 tuer = 0; /* error status */
|
|
int32 tucc = 0; /* check character */
|
|
int32 tumr = 0; /* maint register */
|
|
int32 tutc = 0; /* tape control */
|
|
int32 tu_time = 10; /* record latency */
|
|
int32 tu_stopioe = 1; /* stop on error */
|
|
static uint8 *xbuf = NULL; /* xfer buffer */
|
|
static uint16 *wbuf = NULL;
|
|
static int32 fmt_test[16] = { /* fmt valid */
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
|
|
};
|
|
static int32 dt_map[3] = { DT_TU16, DT_TU45, DT_TU77 };
|
|
static const char *tu_fname[CS1_N_FNC] = {
|
|
"NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7",
|
|
"RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17",
|
|
"20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR",
|
|
"WRITE", "31", "32", "33", "READF", "35", "36" "READR"
|
|
};
|
|
|
|
t_stat tu_mbrd (int32 *data, int32 PA, int32 fmtr);
|
|
t_stat tu_mbwr (int32 data, int32 PA, int32 fmtr);
|
|
t_stat tu_svc (UNIT *uptr);
|
|
t_stat tu_reset (DEVICE *dptr);
|
|
t_stat tu_attach (UNIT *uptr, char *cptr);
|
|
t_stat tu_detach (UNIT *uptr);
|
|
t_stat tu_boot (int32 unitno, DEVICE *dptr);
|
|
t_stat tu_set_fmtr (UNIT *uptr, int32 val, char *cptr, void *desc);
|
|
t_stat tu_show_fmtr (FILE *st, UNIT *uptr, int32 val, void *desc);
|
|
t_stat tu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
|
const char *tu_description (DEVICE *dptr);
|
|
t_stat tu_go (int32 drv);
|
|
int32 tu_abort (void);
|
|
void tu_set_er (int32 flg);
|
|
void tu_clr_as (int32 mask);
|
|
void tu_update_fs (int32 flg, int32 drv);
|
|
t_stat tu_map_err (int32 drv, t_stat st, t_bool qdt);
|
|
|
|
/* TU data structures
|
|
|
|
tu_dev TU device descriptor
|
|
tu_unit TU unit list
|
|
tu_reg TU register list
|
|
tu_mod TU modifier list
|
|
*/
|
|
|
|
DIB tu_dib = { MBA_TU, 0, &tu_mbrd, &tu_mbwr,0, 0, 0, { &tu_abort } };
|
|
|
|
UNIT tu_unit[] = {
|
|
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
|
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
|
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
|
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
|
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
|
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
|
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
|
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }
|
|
};
|
|
|
|
REG tu_reg[] = {
|
|
{ GRDATAD (CS1, tucs1, DEV_RDX, 6, 0, "current operation") },
|
|
{ GRDATAD (FC, tufc, DEV_RDX, 16, 0, "frame count") },
|
|
{ GRDATAD (FS, tufs, DEV_RDX, 16, 0, "formatter status") },
|
|
{ GRDATAD (ER, tuer, DEV_RDX, 16, 0, "formatter errors") },
|
|
{ GRDATAD (CC, tucc, DEV_RDX, 16, 0, "check character") },
|
|
{ GRDATAD (MR, tumr, DEV_RDX, 16, 0, "maintenance register") },
|
|
{ GRDATAD (TC, tutc, DEV_RDX, 16, 0, "tape control register") },
|
|
{ FLDATAD (STOP_IOE, tu_stopioe, 0, "stop on I/O error flag") },
|
|
{ DRDATAD (TIME, tu_time, 24, "operation execution time"), PV_LEFT },
|
|
{ URDATAD (UST, tu_unit[0].USTAT, DEV_RDX, 17, 0, TU_NUMDR, 0, "unit status") },
|
|
{ URDATAD (POS, tu_unit[0].pos, 10, T_ADDR_W, 0,
|
|
TU_NUMDR, PV_LEFT | REG_RO, "position") },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB tu_mod[] = {
|
|
{ MTAB_XTD|MTAB_VDV, 0, "MASSBUS", NULL,
|
|
NULL, &mba_show_num, NULL, "Display Massbus number" },
|
|
#if defined (VM_PDP11)
|
|
{ MTAB_XTD|MTAB_VDV, 0, "FORMATTER", "TM02",
|
|
&tu_set_fmtr, NULL , NULL, "Set formatter/controller type to TM02" },
|
|
{ MTAB_XTD|MTAB_VDV, 1, NULL, "TM03",
|
|
&tu_set_fmtr, NULL, NULL, "Set formatter/controller type to TM03" },
|
|
#endif
|
|
{ MTAB_XTD|MTAB_VDV, 0, "FORMATTER", NULL,
|
|
NULL, &tu_show_fmtr, NULL, "Display formatter/controller type" },
|
|
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED",
|
|
NULL, NULL, NULL, "Write enable tape drive" },
|
|
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED",
|
|
NULL, NULL, NULL, "Write lock tape drive" },
|
|
{ UNIT_TYPE, UNIT_TE16, "TE16", "TE16",
|
|
NULL, NULL, NULL, "Set drive type to TE16" },
|
|
{ UNIT_TYPE, UNIT_TU45, "TU45", "TU45",
|
|
NULL, NULL, NULL, "Set drive type to TU45" },
|
|
{ UNIT_TYPE, UNIT_TU77, "TU77", "TU77",
|
|
NULL, NULL, NULL, "Set drive type to TU77" },
|
|
{ MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "FORMAT", "FORMAT",
|
|
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL, "Set/Display tape format (SIMH, E11, TPC, P7B)" },
|
|
{ MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "CAPACITY", "CAPACITY",
|
|
&sim_tape_set_capac, &sim_tape_show_capac, NULL, "Set unit n capacity to arg MB (0 = unlimited)" },
|
|
{ MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "CAPACITY", NULL,
|
|
NULL, &sim_tape_show_capac, NULL, "Set/Display capacity" },
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE tu_dev = {
|
|
"TU", tu_unit, tu_reg, tu_mod,
|
|
TU_NUMDR, 10, T_ADDR_W, 1, DEV_RDX, 8,
|
|
NULL, NULL, &tu_reset,
|
|
&tu_boot, &tu_attach, &tu_detach,
|
|
&tu_dib, DEV_MBUS|DEV_UBUS|DEV_QBUS|DEV_DEBUG|DEV_DISABLE|DEV_DIS_INIT|DEV_TM03|DEV_TAPE,
|
|
0, NULL, NULL, NULL, &tu_help, NULL, NULL,
|
|
&tu_description
|
|
};
|
|
|
|
/* Massbus register read */
|
|
|
|
t_stat tu_mbrd (int32 *data, int32 ofs, int32 fmtr)
|
|
{
|
|
int32 drv;
|
|
|
|
if (fmtr != 0) { /* only one fmtr */
|
|
*data = 0;
|
|
return MBE_NXD;
|
|
}
|
|
drv = GET_DRV (tutc); /* get current unit */
|
|
tu_update_fs (0, drv); /* update status */
|
|
|
|
switch (ofs) { /* decode offset */
|
|
|
|
case CS1_OF: /* MTCS1 */
|
|
*data = (tucs1 & CS1_RW) | CS1_DVA; /* DVA always set */
|
|
break;
|
|
|
|
case FC_OF: /* MTFC */
|
|
*data = tufc;
|
|
break;
|
|
|
|
case FS_OF: /* MTFS */
|
|
*data = tufs & 0177777; /* mask off rewind */
|
|
break;
|
|
|
|
case ER_OF: /* MTER */
|
|
*data = tuer;
|
|
break;
|
|
|
|
case AS_OF: /* MTAS */
|
|
*data = (tufs & FS_ATA)? AS_U0: 0;
|
|
break;
|
|
|
|
case CC_OF: /* MTCC */
|
|
*data = tucc = tucc & ~CC_MBZ;
|
|
break;
|
|
|
|
case MR_OF: /* MTMR */
|
|
*data = tumr;
|
|
break;
|
|
|
|
case DT_OF: /* MTDT */
|
|
*data = DT_NSA | DT_TAPE | /* fmtr flags */
|
|
((tu_dev.flags & DEV_TM03)? DT_TM03: 0);
|
|
if (tu_unit[drv].flags & UNIT_DIS)
|
|
*data |= DT_OFF;
|
|
else *data |= DT_PRES | dt_map[GET_TYPE (tu_unit[drv].flags)];
|
|
break;
|
|
|
|
case SN_OF: /* MTSN */
|
|
*data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1);
|
|
break;
|
|
|
|
case TC_OF: /* MTTC */
|
|
*data = tutc = tutc & ~TC_MBZ;
|
|
break;
|
|
|
|
default: /* all others */
|
|
return MBE_NXR;
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Massbus register write */
|
|
|
|
t_stat tu_mbwr (int32 data, int32 ofs, int32 fmtr)
|
|
{
|
|
int32 drv;
|
|
|
|
if (fmtr != 0) /* only one fmtr */
|
|
return MBE_NXD;
|
|
drv = GET_DRV (tutc); /* get current unit */
|
|
|
|
switch (ofs) { /* decode PA<4:1> */
|
|
|
|
case CS1_OF: /* MTCS1 */
|
|
if (tucs1 & CS1_GO)
|
|
tu_set_er (ER_RMR);
|
|
else {
|
|
tucs1 = data & CS1_RW;
|
|
if (tucs1 & CS1_GO)
|
|
return tu_go (drv);
|
|
}
|
|
break;
|
|
|
|
case FC_OF: /* MTFC */
|
|
if (tucs1 & CS1_GO)
|
|
tu_set_er (ER_RMR);
|
|
else {
|
|
tufc = data;
|
|
tutc = tutc | TC_FCS; /* set fc flag */
|
|
}
|
|
break;
|
|
|
|
case AS_OF: /* MTAS */
|
|
tu_clr_as (data);
|
|
break;
|
|
|
|
case MR_OF: /* MTMR */
|
|
tumr = (tumr & ~MR_RW) | (data & MR_RW);
|
|
break;
|
|
|
|
case TC_OF: /* MTTC */
|
|
if (tucs1 & CS1_GO)
|
|
tu_set_er (ER_RMR);
|
|
else {
|
|
tutc = (tutc & ~TC_RW) | (data & TC_RW) | TC_SAC;
|
|
drv = GET_DRV (tutc);
|
|
}
|
|
break;
|
|
|
|
case FS_OF: /* MTFS */
|
|
case ER_OF: /* MTER */
|
|
case CC_OF: /* MTCC */
|
|
case DT_OF: /* MTDT */
|
|
case SN_OF: /* MTSN */
|
|
if (tucs1 & CS1_GO)
|
|
tu_set_er (ER_RMR);
|
|
break; /* read only */
|
|
|
|
default: /* all others */
|
|
return MBE_NXR;
|
|
} /* end switch */
|
|
|
|
tu_update_fs (0, drv);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* New magtape command */
|
|
|
|
t_stat tu_go (int32 drv)
|
|
{
|
|
int32 fnc, den;
|
|
UNIT *uptr;
|
|
|
|
fnc = GET_FNC (tucs1); /* get function */
|
|
den = GET_DEN (tutc); /* get density */
|
|
uptr = tu_dev.units + drv; /* get unit */
|
|
if (DEBUG_PRS (tu_dev)) {
|
|
fprintf (sim_deb, ">>TU%d STRT: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=",
|
|
drv, tu_fname[fnc], tufc, tufs, tuer);
|
|
fprint_val (sim_deb, uptr->pos, 10, T_ADDR_W, PV_LEFT);
|
|
fprintf (sim_deb, "\n");
|
|
}
|
|
if ((fnc != FNC_FCLR) && /* not clear & err */
|
|
((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */
|
|
tu_set_er (ER_ILF); /* set err */
|
|
tucs1 = tucs1 & ~CS1_GO; /* clear go */
|
|
tu_update_fs (FS_ATA, drv); /* set attn */
|
|
return MBE_GOE;
|
|
}
|
|
tu_clr_as (AS_U0); /* clear ATA */
|
|
tutc = tutc & ~TC_SAC; /* clear addr change */
|
|
|
|
switch (fnc) { /* case on function */
|
|
|
|
case FNC_FCLR: /* drive clear */
|
|
tuer = 0; /* clear errors */
|
|
tutc = tutc & ~TC_FCS; /* clear fc status */
|
|
tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR);
|
|
sim_cancel (uptr); /* reset drive */
|
|
uptr->USTAT = 0;
|
|
case FNC_NOP:
|
|
tucs1 = tucs1 & ~CS1_GO; /* no operation */
|
|
return SCPE_OK;
|
|
|
|
case FNC_RIP: /* read-in preset */
|
|
tutc = TC_RIP; /* set tutc */
|
|
sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */
|
|
tu_unit[0].USTAT = 0;
|
|
tucs1 = tucs1 & ~CS1_GO;
|
|
tufs = tufs & ~FS_TMK;
|
|
return SCPE_OK;
|
|
|
|
case FNC_UNLOAD: /* unload */
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
|
|
tu_set_er (ER_UNS);
|
|
break;
|
|
}
|
|
detach_unit (uptr);
|
|
uptr->USTAT = FS_REW;
|
|
sim_activate (uptr, tu_time);
|
|
tucs1 = tucs1 & ~CS1_GO;
|
|
tufs = tufs & ~FS_TMK;
|
|
return SCPE_OK;
|
|
|
|
case FNC_REWIND:
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
|
|
tu_set_er (ER_UNS);
|
|
break;
|
|
}
|
|
uptr->USTAT = FS_PIP | FS_REW;
|
|
sim_activate (uptr, tu_time);
|
|
tucs1 = tucs1 & ~CS1_GO;
|
|
tufs = tufs & ~FS_TMK;
|
|
return SCPE_OK;
|
|
|
|
case FNC_SPACEF:
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
|
|
tu_set_er (ER_UNS);
|
|
break;
|
|
}
|
|
if (sim_tape_eot (uptr) || ((tutc & TC_FCS) == 0)) {
|
|
tu_set_er (ER_NXF);
|
|
break;
|
|
}
|
|
uptr->USTAT = FS_PIP;
|
|
goto GO_XFER;
|
|
|
|
case FNC_SPACER:
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
|
|
tu_set_er (ER_UNS);
|
|
break;
|
|
}
|
|
if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) {
|
|
tu_set_er (ER_NXF);
|
|
break;
|
|
}
|
|
uptr->USTAT = FS_PIP;
|
|
goto GO_XFER;
|
|
|
|
case FNC_WCHKR: /* wchk = read */
|
|
case FNC_READR: /* read rev */
|
|
if (tufs & FS_BOT) { /* beginning of tape? */
|
|
tu_set_er (ER_NXF);
|
|
break;
|
|
}
|
|
goto DATA_XFER;
|
|
|
|
case FNC_WRITE: /* write */
|
|
if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */
|
|
((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */
|
|
tu_set_er (ER_NXF);
|
|
break;
|
|
}
|
|
case FNC_WREOF: /* write tape mark */
|
|
case FNC_ERASE: /* erase */
|
|
if (sim_tape_wrp (uptr)) { /* write locked? */
|
|
tu_set_er (ER_NXF);
|
|
break;
|
|
}
|
|
case FNC_WCHKF: /* wchk = read */
|
|
case FNC_READF: /* read */
|
|
DATA_XFER:
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
|
|
tu_set_er (ER_UNS);
|
|
break;
|
|
}
|
|
if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */
|
|
tu_set_er (ER_FER);
|
|
break;
|
|
}
|
|
if (uptr->UDENS == UD_UNK) /* set dens */
|
|
uptr->UDENS = den;
|
|
uptr->USTAT = 0;
|
|
GO_XFER:
|
|
tufs = tufs & ~(FS_TMK | FS_ID); /* clear eof, id */
|
|
sim_activate (uptr, tu_time);
|
|
return SCPE_OK;
|
|
|
|
default: /* all others */
|
|
tu_set_er (ER_ILF); /* not supported */
|
|
break;
|
|
} /* end case function */
|
|
|
|
tucs1 = tucs1 & ~CS1_GO; /* clear go */
|
|
tu_update_fs (FS_ATA, drv); /* set attn */
|
|
return MBE_GOE;
|
|
}
|
|
|
|
/* Abort transfer */
|
|
|
|
int32 tu_abort (void)
|
|
{
|
|
return tu_reset (&tu_dev);
|
|
}
|
|
|
|
/* Unit service
|
|
|
|
Complete movement or data transfer command
|
|
Unit must exist - can't remove an active unit
|
|
Unit must be attached - detach cancels in progress operations
|
|
*/
|
|
|
|
t_stat tu_svc (UNIT *uptr)
|
|
{
|
|
int32 fnc, fmt, j, xbc;
|
|
int32 fc, drv;
|
|
t_mtrlnt i, tbc;
|
|
t_stat st, r = SCPE_OK;
|
|
|
|
drv = (int32) (uptr - tu_dev.units); /* get drive # */
|
|
if (uptr->USTAT & FS_REW) { /* rewind or unload? */
|
|
sim_tape_rewind (uptr); /* rewind tape */
|
|
uptr->USTAT = 0; /* clear status */
|
|
tu_update_fs (FS_ATA | FS_SSC, drv);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
fnc = GET_FNC (tucs1); /* get command */
|
|
fmt = GET_FMT (tutc); /* get format */
|
|
fc = 0200000 - tufc; /* get frame count */
|
|
uptr->USTAT = 0; /* clear status */
|
|
|
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
|
tu_set_er (ER_UNS); /* set formatter error */
|
|
if (fnc >= FNC_XFER)
|
|
mba_set_don (tu_dib.ba);
|
|
tu_update_fs (FS_ATA, drv);
|
|
return (tu_stopioe? SCPE_UNATT: SCPE_OK);
|
|
}
|
|
switch (fnc) { /* case on function */
|
|
|
|
/* Non-data transfer commands - set ATA when done */
|
|
|
|
case FNC_SPACEF: /* space forward */
|
|
do {
|
|
tufc = (tufc + 1) & 0177777; /* incr fc */
|
|
if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */
|
|
r = tu_map_err (drv, st, 0); /* map error */
|
|
break;
|
|
}
|
|
} while ((tufc != 0) && !sim_tape_eot (uptr));
|
|
if (tufc)
|
|
tu_set_er (ER_FCE);
|
|
else tutc = tutc & ~TC_FCS;
|
|
break;
|
|
|
|
case FNC_SPACER: /* space reverse */
|
|
do {
|
|
tufc = (tufc + 1) & 0177777; /* incr wc */
|
|
if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */
|
|
r = tu_map_err (drv, st, 0); /* map error */
|
|
break;
|
|
}
|
|
} while (tufc != 0);
|
|
if (tufc)
|
|
tu_set_er (ER_FCE);
|
|
else tutc = tutc & ~TC_FCS;
|
|
break;
|
|
|
|
case FNC_WREOF: /* write end of file */
|
|
if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */
|
|
r = tu_map_err (drv, st, 0); /* map error */
|
|
break;
|
|
|
|
case FNC_ERASE:
|
|
if (sim_tape_wrp (uptr)) /* write protected? */
|
|
r = tu_map_err (drv, MTSE_WRP, 0); /* map error */
|
|
break;
|
|
|
|
/* Unit service - data transfer commands */
|
|
|
|
case FNC_READF: /* read */
|
|
case FNC_WCHKF: /* wcheck = read */
|
|
tufc = 0; /* clear frame count */
|
|
if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr))
|
|
tufs = tufs | FS_ID; /* PE BOT? ID burst */
|
|
if ((st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR))) {/* read fwd */
|
|
if (st == MTSE_TMK) /* tmk also sets FCE */
|
|
tu_set_er (ER_FCE);
|
|
r = tu_map_err (drv, st, 1); /* map error */
|
|
break; /* done */
|
|
}
|
|
for (i = tbc; i < tbc + 4; i++) /* pad with 0's */
|
|
xbuf[i] = 0;
|
|
if (fmt == TC_CDUMP) { /* core dump? */
|
|
for (i = j = 0; i < tbc; i = i + 4) {
|
|
wbuf[j++] = ((uint16) xbuf[i] & 0xF) |
|
|
(((uint16) (xbuf[i + 1] & 0xF)) << 4) |
|
|
(((uint16) (xbuf[i + 2] & 0xF)) << 8) |
|
|
(((uint16) (xbuf[i + 3] & 0xf)) << 12);
|
|
}
|
|
xbc = (tbc + 1) >> 1;
|
|
}
|
|
else { /* standard */
|
|
for (i = j = 0; i < tbc; i = i + 2) {
|
|
wbuf[j++] = ((uint16) xbuf[i]) |
|
|
(((uint16) xbuf[i + 1]) << 8);
|
|
}
|
|
xbc = tbc;
|
|
}
|
|
if (mba_get_bc (tu_dib.ba) > xbc) /* record short? */
|
|
tu_set_er (ER_FCE); /* set FCE, ATN */
|
|
if (fnc == FNC_WCHKF)
|
|
mba_chbufW (tu_dib.ba, xbc, wbuf);
|
|
else mba_wrbufW (tu_dib.ba, xbc, wbuf);
|
|
tufc = tbc & 0177777;
|
|
break;
|
|
|
|
case FNC_WRITE: /* write */
|
|
xbc = mba_rdbufW (tu_dib.ba, fc, wbuf); /* read buffer */
|
|
if (xbc == 0) /* anything?? */
|
|
break;
|
|
if (fmt == TC_CDUMP) { /* core dump? */
|
|
for (i = j = 0; j < xbc; j = j + 1) {
|
|
xbuf[i++] = wbuf[j] & 0xF;
|
|
xbuf[i++] = (wbuf[j] >> 4) & 0xF;
|
|
xbuf[i++] = (wbuf[j] >> 8) & 0xF;
|
|
xbuf[i++] = (wbuf[j] >> 12) & 0xF;
|
|
}
|
|
tbc = (xbc + 1) >> 1;
|
|
}
|
|
else { /* standard */
|
|
for (i = j = 0; j < xbc; j = j + 1) {
|
|
xbuf[i++] = wbuf[j] & 0377;
|
|
xbuf[i++] = (wbuf[j] >> 8) & 0377;
|
|
}
|
|
tbc = xbc;
|
|
}
|
|
if ((st = sim_tape_wrrecf (uptr, xbuf, tbc))) /* write rec, err? */
|
|
r = tu_map_err (drv, st, 1); /* map error */
|
|
else {
|
|
tufc = (tufc + tbc) & 0177777;
|
|
if (tufc == 0)
|
|
tutc = tutc & ~TC_FCS;
|
|
}
|
|
break;
|
|
|
|
case FNC_READR: /* read reverse */
|
|
case FNC_WCHKR: /* wcheck = read */
|
|
tufc = 0; /* clear frame count */
|
|
if ((st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR))) {/* read rev */
|
|
if (st == MTSE_TMK) /* tmk also sets FCE */
|
|
tu_set_er (ER_FCE);
|
|
r = tu_map_err (drv, st, 1); /* map error */
|
|
break; /* done */
|
|
}
|
|
for (i = 0; i < 4; i++) xbuf[i] = 0; /* pad with 0's */
|
|
if (fmt == TC_CDUMP) { /* core dump? */
|
|
for (i = tbc + 3, j = 0; i > 3; i = i - 4) {
|
|
wbuf[j++] = ((uint16) xbuf[i] & 0xF) |
|
|
(((uint16) (xbuf[i - 1] & 0xF)) << 4) |
|
|
(((uint16) (xbuf[i - 2] & 0xF)) << 8) |
|
|
(((uint16) (xbuf[i - 3] & 0xf)) << 12);
|
|
}
|
|
xbc = (tbc + 1) >> 1;
|
|
}
|
|
else { /* standard */
|
|
for (i = tbc + 3, j = 0; i > 3; i = i - 2) {
|
|
wbuf[j++] = ((uint16) xbuf[i]) |
|
|
(((uint16) xbuf[i - 1]) << 8);
|
|
}
|
|
xbc = tbc;
|
|
}
|
|
if (mba_get_bc (tu_dib.ba) > xbc) /* record short? */
|
|
tu_set_er (ER_FCE); /* set FCE, ATN */
|
|
if (fnc == FNC_WCHKR)
|
|
mba_chbufW (tu_dib.ba, xbc, wbuf);
|
|
else mba_wrbufW (tu_dib.ba, xbc, wbuf);
|
|
tufc = tbc & 0177777;
|
|
break;
|
|
} /* end case */
|
|
|
|
tucs1 = tucs1 & ~CS1_GO; /* clear go */
|
|
if (fnc >= FNC_XFER) { /* data xfer? */
|
|
mba_set_don (tu_dib.ba); /* set done */
|
|
tu_update_fs (0, drv); /* update fs */
|
|
}
|
|
else tu_update_fs (FS_ATA, drv); /* no, set attn */
|
|
if (DEBUG_PRS (tu_dev)) {
|
|
fprintf (sim_deb, ">>TU%d DONE: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=",
|
|
drv, tu_fname[fnc], tufc, tufs, tuer);
|
|
fprint_val (sim_deb, uptr->pos, 10, T_ADDR_W, PV_LEFT);
|
|
fprintf (sim_deb, ", r=%d\n", r);
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Set formatter error */
|
|
|
|
void tu_set_er (int32 flg)
|
|
{
|
|
tuer = tuer | flg;
|
|
tufs = tufs | FS_ATA;
|
|
mba_upd_ata (tu_dib.ba, 1);
|
|
return;
|
|
}
|
|
|
|
/* Clear attention */
|
|
|
|
void tu_clr_as (int32 mask)
|
|
{
|
|
if (mask & AS_U0)
|
|
tufs = tufs & ~FS_ATA;
|
|
mba_upd_ata (tu_dib.ba, tufs & FS_ATA);
|
|
return;
|
|
}
|
|
|
|
/* Formatter update status */
|
|
|
|
void tu_update_fs (int32 flg, int32 drv)
|
|
{
|
|
int32 act = sim_activate_time (&tu_unit[drv]);
|
|
|
|
tufs = (tufs & ~FS_DYN) | FS_FPR | flg;
|
|
if (tu_unit[drv].flags & UNIT_ATT) {
|
|
tufs = tufs | FS_MOL | tu_unit[drv].USTAT;
|
|
if (tu_unit[drv].UDENS == TC_1600)
|
|
tufs = tufs | FS_PE;
|
|
if (sim_tape_wrp (&tu_unit[drv]))
|
|
tufs = tufs | FS_WRL;
|
|
if (!act) {
|
|
if (sim_tape_bot (&tu_unit[drv]))
|
|
tufs = tufs | FS_BOT;
|
|
if (sim_tape_eot (&tu_unit[drv]))
|
|
tufs = tufs | FS_EOT;
|
|
}
|
|
}
|
|
if (tuer)
|
|
tufs = tufs | FS_ERR;
|
|
if (tufs && !act)
|
|
tufs = tufs | FS_RDY;
|
|
if (flg & FS_ATA)
|
|
mba_upd_ata (tu_dib.ba, 1);
|
|
return;
|
|
}
|
|
|
|
/* Map tape error status */
|
|
|
|
t_stat tu_map_err (int32 drv, t_stat st, t_bool qdt)
|
|
{
|
|
switch (st) {
|
|
|
|
case MTSE_FMT: /* illegal fmt */
|
|
case MTSE_UNATT: /* not attached */
|
|
tu_set_er (ER_NXF); /* can't execute */
|
|
if (qdt) /* set exception */
|
|
mba_set_exc (tu_dib.ba);
|
|
break;
|
|
|
|
case MTSE_TMK: /* end of file */
|
|
tufs = tufs | FS_TMK;
|
|
break;
|
|
|
|
case MTSE_IOERR: /* IO error */
|
|
tu_set_er (ER_VPE); /* flag error */
|
|
if (qdt) /* set exception */
|
|
mba_set_exc (tu_dib.ba);
|
|
return (tu_stopioe? SCPE_IOERR: SCPE_OK);
|
|
|
|
case MTSE_INVRL: /* invalid rec lnt */
|
|
tu_set_er (ER_VPE); /* flag error */
|
|
if (qdt) /* set exception */
|
|
mba_set_exc (tu_dib.ba);
|
|
return SCPE_MTRLNT;
|
|
|
|
case MTSE_RECE: /* record in error */
|
|
tu_set_er (ER_CRC); /* set crc err */
|
|
if (qdt) /* set exception */
|
|
mba_set_exc (tu_dib.ba);
|
|
break;
|
|
|
|
case MTSE_EOM: /* end of medium */
|
|
tu_set_er (ER_OPI); /* incomplete */
|
|
if (qdt) /* set exception */
|
|
mba_set_exc (tu_dib.ba);
|
|
break;
|
|
|
|
case MTSE_BOT: /* reverse into BOT */
|
|
return SCPE_OK;
|
|
|
|
case MTSE_WRP: /* write protect */
|
|
tu_set_er (ER_NXF); /* can't execute */
|
|
if (qdt) /* set exception */
|
|
mba_set_exc (tu_dib.ba);
|
|
break;
|
|
|
|
default: /* unknown error */
|
|
return SCPE_IERR;
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Reset routine */
|
|
|
|
t_stat tu_reset (DEVICE *dptr)
|
|
{
|
|
int32 u;
|
|
UNIT *uptr;
|
|
|
|
mba_set_enbdis (MBA_TU, tu_dev.flags & DEV_DIS);
|
|
tucs1 = 0;
|
|
tufc = 0;
|
|
tuer = 0;
|
|
tufs = FS_FPR | FS_RDY;
|
|
if (sim_switches & SWMASK ('P')) /* powerup? clr TC */
|
|
tutc = 0;
|
|
else tutc = tutc & ~TC_FCS; /* no, clr <fcs> */
|
|
for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */
|
|
uptr = tu_dev.units + u;
|
|
sim_tape_reset (uptr); /* clear pos flag */
|
|
sim_cancel (uptr); /* cancel activity */
|
|
uptr->USTAT = 0;
|
|
}
|
|
if (xbuf == NULL)
|
|
xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8));
|
|
if (xbuf == NULL)
|
|
return SCPE_MEM;
|
|
if (wbuf == NULL)
|
|
wbuf = (uint16 *) calloc ((MT_MAXFR + 4) >> 1, sizeof (uint16));
|
|
if (wbuf == NULL)
|
|
return SCPE_MEM;
|
|
return auto_config(0, 0);
|
|
}
|
|
|
|
/* Attach routine */
|
|
|
|
t_stat tu_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
int32 drv = uptr - tu_dev.units, flg;
|
|
t_stat r;
|
|
|
|
r = sim_tape_attach (uptr, cptr);
|
|
if (r != SCPE_OK)
|
|
return r;
|
|
uptr->USTAT = 0; /* clear unit status */
|
|
uptr->UDENS = UD_UNK; /* unknown density */
|
|
flg = FS_ATA | FS_SSC; /* set attention */
|
|
if (GET_DRV (tutc) == drv) /* sel drv? set SAT */
|
|
flg = flg | FS_SAT;
|
|
tu_update_fs (flg, drv); /* update status */
|
|
return r;
|
|
}
|
|
|
|
/* Detach routine */
|
|
|
|
t_stat tu_detach (UNIT* uptr)
|
|
{
|
|
int32 drv = uptr - tu_dev.units;
|
|
|
|
if (!(uptr->flags & UNIT_ATT)) /* attached? */
|
|
return SCPE_OK;
|
|
uptr->USTAT = 0; /* clear status flags */
|
|
tu_update_fs (FS_ATA | FS_SSC, drv); /* update status */
|
|
return sim_tape_detach (uptr);
|
|
}
|
|
|
|
/* Set/show formatter type */
|
|
|
|
t_stat tu_set_fmtr (UNIT *uptr, int32 val, char *cptr, void *desc)
|
|
{
|
|
DEVICE *dptr = find_dev_from_unit (uptr);
|
|
|
|
if (cptr != NULL)
|
|
return SCPE_ARG;
|
|
if (dptr == NULL)
|
|
return SCPE_IERR;
|
|
if (val)
|
|
dptr->flags = dptr->flags | DEV_TM03;
|
|
else dptr->flags = dptr->flags & ~DEV_TM03;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat tu_show_fmtr (FILE *st, UNIT *uptr, int32 val, void *desc)
|
|
{
|
|
DEVICE *dptr = find_dev_from_unit (uptr);
|
|
|
|
if (dptr == NULL)
|
|
return SCPE_IERR;
|
|
fprintf (st, "TM0%d", (dptr->flags & DEV_TM03? 3: 2));
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Device bootstrap */
|
|
|
|
#if defined (PDP11)
|
|
|
|
#elif defined (VM_PDP11)
|
|
|
|
#define BOOT_START 016000 /* start */
|
|
#define BOOT_ENTRY (BOOT_START + 002) /* entry */
|
|
#define BOOT_UNIT (BOOT_START + 010) /* unit number */
|
|
#define BOOT_CSR (BOOT_START + 014) /* CSR */
|
|
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16))
|
|
|
|
static const uint16 boot_rom[] = {
|
|
0046515, /* "MM" */
|
|
0012706, BOOT_START, /* mov #boot_start, sp */
|
|
0012700, 0000000, /* mov #unit, r0 */
|
|
0012701, 0172440, /* mov #TUCS1, r1 */
|
|
0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */
|
|
0012711, 0000021, /* mov #RIP+GO, (r1) ; rip */
|
|
0010004, /* mov r0, r4 */
|
|
0052704, 0002300, /* bis #2300, r4 ; set den */
|
|
0010461, 0000032, /* mov r4, 32(r1) ; set unit */
|
|
0012761, 0177777, 0000006, /* mov #-1, 6(r1) ; set fc */
|
|
0012711, 0000031, /* mov #SPCF+GO, (r1) ; skip rec */
|
|
0105761, 0000012, /* tstb 12 (r1) ; fmtr rdy? */
|
|
0100375, /* bpl .-4 */
|
|
0012761, 0177000, 0000002, /* mov #-1000, 2(r1) ; set wc */
|
|
0005061, 0000004, /* clr 4(r1) ; clr ba */
|
|
0005061, 0000006, /* clr 6(r1) ; clr fc */
|
|
0012711, 0000071, /* mov #READ+GO, (r1) ; read */
|
|
0105711, /* tstb (r1) ; wait */
|
|
0100376, /* bpl .-2 */
|
|
0005002, /* clr R2 */
|
|
0005003, /* clr R3 */
|
|
0012704, BOOT_START+020, /* mov #start+020, r4 */
|
|
0005005, /* clr R5 */
|
|
0105011, /* clrb (r1) */
|
|
0005007 /* clr PC */
|
|
};
|
|
|
|
t_stat tu_boot (int32 unitno, DEVICE *dptr)
|
|
{
|
|
size_t i;
|
|
extern uint16 *M;
|
|
|
|
for (i = 0; i < BOOT_LEN; i++)
|
|
M[(BOOT_START >> 1) + i] = boot_rom[i];
|
|
M[BOOT_UNIT >> 1] = unitno & (TU_NUMDR - 1);
|
|
M[BOOT_CSR >> 1] = mba_get_csr (tu_dib.ba) & DMASK;
|
|
cpu_set_boot (BOOT_ENTRY);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
#else
|
|
|
|
t_stat tu_boot (int32 unitno, DEVICE *dptr)
|
|
{
|
|
return SCPE_NOFNC;
|
|
}
|
|
|
|
#endif
|
|
|
|
t_stat tu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
|
{
|
|
fprintf (st, "TM02/TM03/TE16/TU45/TU77 Magnetic Tapes\n\n");
|
|
fprintf (st, "The TU controller implements the Massbus family of 800/1600bpi magnetic tape\n");
|
|
fprintf (st, "drives. TU options include the ability to set the drive type to one of three\n");
|
|
fprintf (st, "drives (TE16, TU45, or TU77), and to set the drives write enabled or write\n");
|
|
fprintf (st, "locked. When configured on a PDP11 simulator, the TU formatter type can be\n");
|
|
fprintf (st, "selected as either TM02 or TM03),\n\n");
|
|
fprint_set_help (st, dptr);
|
|
fprintf (st, "\nMagnetic tape units can be set to a specific reel capacity in MB, or to\n");
|
|
fprintf (st, "unlimited capacity:\n\n");
|
|
#if defined (VM_PDP11)
|
|
fprintf (st, "The TU controller supports the BOOT command.\n");
|
|
#endif
|
|
fprintf (st, "\nThe TU controller implements the following registers:\n\n");
|
|
fprint_reg_help (st, dptr);
|
|
fprintf (st, "\nError handling is as follows:\n\n");
|
|
fprintf (st, " error processed as\n");
|
|
fprintf (st, " not attached tape not ready; if STOP_IOE, stop\n");
|
|
fprintf (st, " end of file bad tape\n");
|
|
fprintf (st, " OS I/O error parity error; if STOP_IOE, stop\n");
|
|
return SCPE_OK;
|
|
}
|
|
|
|
const char *tu_description (DEVICE *dptr)
|
|
{
|
|
return "TM03 tape formatter";
|
|
}
|