1161 lines
42 KiB
C
1161 lines
42 KiB
C
/* ka10_tu.c: Dec RH10 TM03/TU10 tape controller
|
||
|
||
Copyright (c) 2017, Richard Cornwell
|
||
|
||
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 PUTUOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
RICHARD CORNWELL 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.
|
||
|
||
*/
|
||
|
||
#include "kx10_defs.h"
|
||
#include "sim_tape.h"
|
||
|
||
#ifndef NUM_DEVS_TU
|
||
#define NUM_DEVS_TU 0
|
||
#endif
|
||
|
||
#if (NUM_DEVS_TU > 0)
|
||
|
||
#define NUM_UNITS_TU 8
|
||
#define TU_NUMFR (64*1024)
|
||
|
||
#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF)
|
||
#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF
|
||
|
||
/* Flags in the unit flags word */
|
||
|
||
#define TU_UNIT UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE
|
||
#define CNTRL_V_CTYPE (MTUF_V_UF)
|
||
#define CNTRL_M_CTYPE 7
|
||
#define GET_CNTRL(x) (((x) >> CNTRL_V_CTYPE) & CNTRL_M_CTYPE)
|
||
#define CNTRL(x) (((x) & CNTRL_M_CTYPE) << CNTRL_V_CTYPE)
|
||
|
||
/* CONI Flags */
|
||
#define IADR_ATTN 0000000000040LL /* Interrupt on attention */
|
||
#define IARD_RAE 0000000000100LL /* Interrupt on register access error */
|
||
#define DIB_CBOV 0000000000200LL /* Control bus overrun */
|
||
#define CXR_PS_FAIL 0000000002000LL /* Power supply fail (not implemented) */
|
||
#define CXR_ILC 0000000004000LL /* Illegal function code */
|
||
#define CR_DRE 0000000010000LL /* Or Data and Control Timeout */
|
||
#define DTC_OVER 0000000020000LL /* DF10 did not supply word on time (not implemented) */
|
||
#define CCW_COMP_1 0000000040000LL /* Control word written. */
|
||
#define CXR_CHAN_ER 0000000100000LL /* Channel Error */
|
||
#define CXR_EXC 0000000200000LL /* Error in drive transfer */
|
||
#define CXR_DBPE 0000000400000LL /* Device Parity error (not implemented) */
|
||
#define CXR_NXM 0000001000000LL /* Channel non-existent memory (not implemented) */
|
||
#define CXR_CWPE 0000002000000LL /* Channel Control word parity error (not implemented) */
|
||
#define CXR_CDPE 0000004000000LL /* Channel Data Parity Error (not implemented) */
|
||
#define CXR_SD_RAE 0000200000000LL /* Register access error */
|
||
#define CXR_ILFC 0000400000000LL /* Illegal CXR function code */
|
||
#define B22_FLAG 0004000000000LL /* 22 bit channel */
|
||
#define CC_CHAN_PLS 0010000000000LL /* Channel transfer pulse (not implemented) */
|
||
#define CC_CHAN_ACT 0020000000000LL /* Channel in use */
|
||
#define CC_INH 0040000000000LL /* Disconnect channel */
|
||
#define CB_FULL 0200000000000LL /* Set when channel buffer is full (not implemented) */
|
||
#define AR_FULL 0400000000000LL /* Set when AR is full (not implemented) */
|
||
|
||
/* CONO Flags */
|
||
#define ATTN_EN 0000000000040LL /* enable attention interrupt. */
|
||
#define REA_EN 0000000000100LL /* enable register error interrupt */
|
||
#define CBOV_CLR 0000000000200LL /* Clear CBOV */
|
||
#define CONT_RESET 0000000002000LL /* Clear All error bits */
|
||
#define ILC_CLR 0000000004000LL /* Clear ILC and SD RAE */
|
||
#define DRE_CLR 0000000010000LL /* Clear CR_CBTO and CR_DBTO */
|
||
#define OVER_CLR 0000000020000LL /* Clear DTC overrun */
|
||
#define WRT_CW 0000000040000LL /* Write control word */
|
||
#define CHN_CLR 0000000100000LL /* Clear Channel Error */
|
||
#define DR_EXC_CLR 0000000200000LL /* Clear DR_EXC */
|
||
#define DBPE_CLR 0000000400000LL /* Clear CXR_DBPE */
|
||
|
||
/* DATAO/DATAI */
|
||
#define CR_REG 0770000000000LL /* Register number */
|
||
#define LOAD_REG 0004000000000LL /* Load register */
|
||
#define CR_MAINT_MODE 0000100000000LL /* Maint mode... not implemented */
|
||
#define CR_DRIVE 0000007000000LL
|
||
#define CR_GEN_EVD 0000000400000LL /* Enable Parity */
|
||
#define CR_DXES 0000000200000LL /* Disable DXES errors */
|
||
#define CR_INAD 0000000077600LL
|
||
#define CR_WTEVM 0000000000100LL /* Verify Parity */
|
||
#define CR_FUNC 0000000000076LL
|
||
#define CR_GO 0000000000001LL
|
||
|
||
#define IRQ_VECT 0000000000177LL /* Interupt vector */
|
||
#define IRQ_KI10 0000002000000LL
|
||
#define IRQ_KA10 0000001000000LL
|
||
|
||
#define CMD u3
|
||
/* u3 low */
|
||
/* TUC - 00 - control */
|
||
|
||
#define CS1_GO CR_GO /* go */
|
||
#define CS1_V_FNC 1 /* function pos */
|
||
#define CS1_M_FNC 037 /* function mask */
|
||
#define CS1_FNC (CS1_M_FNC << CS1_V_FNC)
|
||
#define FNC_NOP 000 /* no operation */
|
||
#define FNC_UNLOAD 001 /* unload */
|
||
#define FNC_REWIND 003 /* rewind */
|
||
#define FNC_DCLR 004 /* drive clear */
|
||
#define FNC_PRESET 010 /* read-in preset */
|
||
#define FNC_ERASE 012 /* Erase */
|
||
#define FNC_WTM 013 /* Write Tape Mark */
|
||
#define FNC_SPACEF 014 /* Space record forward */
|
||
#define FNC_SPACEB 015 /* Space record backward */
|
||
#define FNC_XFER 024 /* >=? data xfr */
|
||
#define FNC_WCHK 024 /* write check */
|
||
#define FNC_WCHKREV 027 /* write check reverse */
|
||
#define FNC_WRITE 030 /* write */
|
||
#define FNC_READ 034 /* read */
|
||
#define FNC_READREV 037 /* read reverse */
|
||
#define CS1_DVA 0004000 /* drive avail NI */
|
||
#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
|
||
#define CS_TM 001000 /* Tape mark sensed */
|
||
#define CS_MOTION 002000 /* Tape moving */
|
||
#define CS_PIP 004000 /* Tape Position command */
|
||
#define CS_ATA 010000 /* Tape signals attention */
|
||
#define CS_CHANGE 020000 /* Status changed */
|
||
|
||
#define STATUS u5
|
||
/* u5 low */
|
||
/* TUDS - 01 - drive status */
|
||
|
||
#define DS_SLA 0000001 /* Drive has become ready */
|
||
#define DS_BOT 0000002 /* Beginning of tape */
|
||
#define DS_TM 0000004 /* Tape mark */
|
||
#define DS_IDB 0000010 /* Identification burst */
|
||
#define DS_SDWN 0000020 /* Tape stoped */
|
||
#define DS_PES 0000040 /* Phase Encoding */
|
||
#define DS_SSC 0000100 /* Status change */
|
||
#define DS_DRY 0000200 /* drive ready */
|
||
#define DS_DPR 0000400 /* drive present */
|
||
#define DS_PGM 0001000 /* programable NI */
|
||
#define DS_EOT 0002000 /* end of tape */
|
||
#define DS_WRL 0004000 /* write locked */
|
||
#define DS_MOL 0010000 /* medium online */
|
||
#define DS_PIP 0020000 /* pos in progress */
|
||
#define DS_ERR 0040000 /* error */
|
||
#define DS_ATA 0100000 /* attention active */
|
||
|
||
/* u5 high */
|
||
/* TUER1 - 02 - error status 1 */
|
||
|
||
#define ER1_ILF 0000001 /* illegal func */
|
||
#define ER1_ILR 0000002 /* illegal register */
|
||
#define ER1_RMR 0000004 /* reg mod refused */
|
||
#define ER1_CPAR 0000010 /* control parity err NI */
|
||
#define ER1_FMT 0000020 /* format err */
|
||
#define ER1_DPAR 0000040 /* data parity error */
|
||
#define ER1_INC 0000100 /* Incorrectable data */
|
||
#define ER1_PEF 0000200 /* format error */
|
||
#define ER1_NSG 0000400 /* Nonstandard gap NI */
|
||
#define ER1_FCE 0001000 /* Frame count error */
|
||
#define ER1_ITM 0002000 /* Illegal tape mark */
|
||
#define ER1_NEF 0004000 /* Non executable function */
|
||
#define ER1_DTE 0010000 /* drive time err NI */
|
||
#define ER1_OPI 0020000 /* op incomplete */
|
||
#define ER1_UNS 0040000 /* drive unsafe */
|
||
#define ER1_DCK 0100000 /* data check NI */
|
||
|
||
/* TUMR - 03 - maintenace register */
|
||
|
||
/* TUAS - 04 - attention summary */
|
||
|
||
#define AS_U0 0000001 /* unit 0 flag */
|
||
|
||
/* TUDC - 05 - frame count */
|
||
|
||
/* TUDT - 06 - drive type */
|
||
|
||
/* TULA - 07 - look ahead register */
|
||
|
||
/* TUSN - 10 - serial number */
|
||
|
||
/* TUTC - 11 - Tape control register */
|
||
#define TC_SS 0000007 /* Slave select mask */
|
||
#define TC_EVPAR 0000010 /* Even parity */
|
||
#define TC_FMTSEL 0000360 /* Format select */
|
||
#define TC_10CORE 000 /* PDP 10 Core */
|
||
/* 4 8 bit chars + 1 4 bit char */
|
||
#define TC_15CORE 001 /* PDP 15 core */
|
||
/* 3 6 bit chars per word */
|
||
#define TC_10NORM 003 /* PDP 10 Compatible */
|
||
/* 4 8 bit chars per word */
|
||
#define TC_11NORM 014 /* PDP 11 Normal */
|
||
/* 2 8 bit chars per word */
|
||
#define TC_11CORE 015 /* PDP 11 Core */
|
||
/* 4 4 bit chars per word */
|
||
#define TC_15NORM 016 /* PDP 15 Normal */
|
||
/* 2 8 bit chars per word */
|
||
#define TC_DENS 0003400 /* Density (ignored) */
|
||
#define TC_800 0001400 /* 800 BPI */
|
||
#define TC_1600 0002000 /* 1600 BPI */
|
||
#define TC_EAODTE 0010000 /* Enable abort */
|
||
#define TC_SAC 0020000 /* Slave address change */
|
||
#define TC_FCS 0040000 /* Frame count status */
|
||
#define TC_ACCL 0100000 /* Acceleration */
|
||
|
||
|
||
/* TUER3 - 15 - error status 3 - more unsafe conditions - unimplemented */
|
||
|
||
#define CPOS u4
|
||
#define DATAPTR u6
|
||
|
||
struct df10 tu_df10[NUM_DEVS_TU];
|
||
int tu_xfer_drive[NUM_DEVS_TU];
|
||
uint8 tu_buf[NUM_DEVS_TU][TU_NUMFR];
|
||
int tu_reg[NUM_DEVS_TU];
|
||
int tu_ivect[NUM_DEVS_TU];
|
||
int tu_imode[NUM_DEVS_TU];
|
||
int tu_drive[NUM_DEVS_TU];
|
||
int tu_rae[NUM_DEVS_TU];
|
||
int tu_attn[NUM_DEVS_TU];
|
||
uint16 tu_frame[NUM_DEVS_TU];
|
||
uint16 tu_tcr[NUM_DEVS_TU];
|
||
extern int readin_flag;
|
||
static uint64 tu_boot_buffer;
|
||
|
||
t_stat tu_devio(uint32 dev, uint64 *data);
|
||
int tu_devirq(uint32 dev, int addr);
|
||
void tu_write(int ctlr, int unit, int reg, uint32 data);
|
||
uint32 tu_read(int ctlr, int unit, int reg);
|
||
t_stat tu_srv(UNIT *);
|
||
t_stat tu_boot(int32, DEVICE *);
|
||
void tu_ini(UNIT *, t_bool);
|
||
t_stat tu_reset(DEVICE *);
|
||
t_stat tu_attach(UNIT *, CONST char *);
|
||
t_stat tu_detach(UNIT *);
|
||
t_stat tu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||
const char *cptr);
|
||
const char *tu_description (DEVICE *dptr);
|
||
|
||
|
||
UNIT tu_unit[] = {
|
||
/* Controller 1 */
|
||
{ UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) },
|
||
{ UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) },
|
||
{ UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) },
|
||
{ UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) },
|
||
{ UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) },
|
||
{ UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) },
|
||
{ UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) },
|
||
{ UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) },
|
||
};
|
||
|
||
DIB tu_dib[] = {
|
||
{RH10_DEV, 1, &tu_devio, &tu_devirq}
|
||
};
|
||
|
||
MTAB tu_mod[] = {
|
||
{MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||
{MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL},
|
||
{MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL},
|
||
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LENGTH", "LENGTH",
|
||
&sim_tape_set_capac, &sim_tape_show_capac, NULL},
|
||
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DENSITY", "DENSITY",
|
||
&sim_tape_set_dens, &sim_tape_show_dens, NULL},
|
||
{0}
|
||
};
|
||
|
||
REG tua_reg[] = {
|
||
{ORDATA(IVECT, tu_ivect[0], 18)},
|
||
{FLDATA(IMODE, tu_imode[0], 0)},
|
||
{ORDATA(FRAME, tu_frame[0], 16)},
|
||
{ORDATA(TCR, tu_tcr[0], 16)},
|
||
{ORDATA(XFER, tu_xfer_drive[0], 3), REG_HRO},
|
||
{ORDATA(DRIVE, tu_drive[0], 3), REG_HRO},
|
||
{ORDATA(REG, tu_reg[0], 6), REG_RO},
|
||
{ORDATA(RAE, tu_rae[0], 8), REG_RO},
|
||
{ORDATA(ATTN, tu_attn[0], 8), REG_RO},
|
||
{FLDATA(READIN, readin_flag, 0), REG_HRO},
|
||
{ORDATA(STATUS, tu_df10[0].status, 18), REG_RO},
|
||
{ORDATA(CIA, tu_df10[0].cia, 18)},
|
||
{ORDATA(CCW, tu_df10[0].ccw, 18)},
|
||
{ORDATA(WCR, tu_df10[0].wcr, 18)},
|
||
{ORDATA(CDA, tu_df10[0].cda, 18)},
|
||
{ORDATA(DEVNUM, tu_df10[0].devnum, 9), REG_HRO},
|
||
{ORDATA(BUF, tu_df10[0].buf, 36), REG_HRO},
|
||
{ORDATA(NXM, tu_df10[0].nxmerr, 8), REG_HRO},
|
||
{ORDATA(COMP, tu_df10[0].ccw_comp, 8), REG_HRO},
|
||
{BRDATA(BUFF, &tu_buf[0][0], 16, 8, TU_NUMFR), REG_HRO},
|
||
{0}
|
||
};
|
||
|
||
DEVICE tua_dev = {
|
||
"TUA", tu_unit, NULL, tu_mod,
|
||
NUM_UNITS_TU, 8, 18, 1, 8, 36,
|
||
NULL, NULL, &tu_reset, &tu_boot, &tu_attach, &tu_detach,
|
||
&tu_dib[0], DEV_DISABLE | DEV_DEBUG | DEV_TAPE, 0, dev_debug,
|
||
NULL, NULL, &tu_help, NULL, NULL, &tu_description
|
||
};
|
||
|
||
|
||
DEVICE *tu_devs[] = {
|
||
&tua_dev,
|
||
};
|
||
|
||
|
||
t_stat tu_devio(uint32 dev, uint64 *data) {
|
||
int ctlr = -1;
|
||
DEVICE *dptr = NULL;
|
||
struct df10 *df10;
|
||
int drive;
|
||
|
||
for (drive = 0; rh[drive].dev_num != 0; drive++) {
|
||
if (rh[drive].dev_num == (dev & 0774)) {
|
||
dptr = rh[drive].dev;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (dptr == NULL)
|
||
return SCPE_OK;
|
||
ctlr = GET_CNTRL(dptr->units[0].flags);
|
||
df10 = &tu_df10[ctlr];
|
||
df10->devnum = dev;
|
||
switch(dev & 3) {
|
||
case CONI:
|
||
*data = df10->status & ~(IADR_ATTN|IARD_RAE);
|
||
if (tu_attn[ctlr] != 0 && (df10->status & IADR_ATTN))
|
||
*data |= IADR_ATTN;
|
||
if (tu_rae[ctlr] != 0 && (df10->status & IARD_RAE))
|
||
*data |= IARD_RAE;
|
||
#if KI_22BIT
|
||
*data |= B22_FLAG;
|
||
#endif
|
||
sim_debug(DEBUG_CONI, dptr, "TU %03o CONI %06o PC=%o %o\n",
|
||
dev, (uint32)*data, PC, tu_attn[ctlr]);
|
||
return SCPE_OK;
|
||
|
||
case CONO:
|
||
clr_interrupt(dev);
|
||
df10->status &= ~07LL;
|
||
df10->status |= *data & (07LL|IADR_ATTN|IARD_RAE);
|
||
/* Clear flags */
|
||
if (*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR))
|
||
df10->status &= ~(*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR));
|
||
if (*data & OVER_CLR)
|
||
df10->status &= ~(DTC_OVER);
|
||
if (*data & CBOV_CLR)
|
||
df10->status &= ~(DIB_CBOV);
|
||
if (*data & CXR_ILC)
|
||
df10->status &= ~(CXR_ILFC|CXR_SD_RAE);
|
||
if (*data & WRT_CW)
|
||
df10_writecw(df10);
|
||
if (*data & PI_ENABLE)
|
||
df10->status &= ~PI_ENABLE;
|
||
if (df10->status & PI_ENABLE)
|
||
set_interrupt(dev, df10->status);
|
||
if ((df10->status & IADR_ATTN) != 0 && tu_attn[ctlr] != 0)
|
||
set_interrupt(dev, df10->status);
|
||
sim_debug(DEBUG_CONO, dptr, "TU %03o CONO %06o %d PC=%06o %06o\n",
|
||
dev, (uint32)*data, ctlr, PC, df10->status);
|
||
return SCPE_OK;
|
||
|
||
case DATAI:
|
||
*data = 0;
|
||
if (df10->status & BUSY && tu_reg[ctlr] != 04) {
|
||
df10->status |= CC_CHAN_ACT;
|
||
return SCPE_OK;
|
||
}
|
||
if (tu_reg[ctlr] == 040) {
|
||
*data = (uint64)(tu_read(ctlr, tu_drive[ctlr], 0) & 077);
|
||
*data |= ((uint64)(df10->cia)) << 6;
|
||
*data |= ((uint64)(tu_xfer_drive[ctlr])) << 18;
|
||
} else if (tu_reg[ctlr] == 044) {
|
||
*data = (uint64)tu_ivect[ctlr];
|
||
if (tu_imode[ctlr])
|
||
*data |= IRQ_KI10;
|
||
else
|
||
*data |= IRQ_KA10;
|
||
} else if (tu_reg[ctlr] == 054) {
|
||
*data = (uint64)(tu_rae[ctlr]);
|
||
} else if ((tu_reg[ctlr] & 040) == 0) {
|
||
*data = (uint64)(tu_read(ctlr, tu_drive[ctlr], tu_reg[ctlr]) & 0177777);
|
||
*data |= ((uint64)(tu_drive[ctlr])) << 18;
|
||
}
|
||
*data |= ((uint64)(tu_reg[ctlr])) << 30;
|
||
sim_debug(DEBUG_DATAIO, dptr, "TU %03o DATI %012llo, %d %d PC=%06o\n",
|
||
dev, *data, ctlr, tu_drive[ctlr], PC);
|
||
return SCPE_OK;
|
||
|
||
case DATAO:
|
||
sim_debug(DEBUG_DATAIO, dptr, "TU %03o DATO %012llo, %d PC=%06o %06o\n",
|
||
dev, *data, ctlr, PC, df10->status);
|
||
tu_reg[ctlr] = ((int)(*data >> 30)) & 077;
|
||
if (tu_reg[ctlr] < 040 && tu_reg[ctlr] != 04) {
|
||
tu_drive[ctlr] = (int)(*data >> 18) & 07;
|
||
}
|
||
if (*data & LOAD_REG) {
|
||
if (tu_reg[ctlr] == 040) {
|
||
if ((*data & 1) == 0) {
|
||
return SCPE_OK;
|
||
}
|
||
if (df10->status & BUSY) {
|
||
df10->status |= CC_CHAN_ACT;
|
||
sim_debug(DEBUG_DATAIO, dptr,
|
||
"TU %03o command busy %012llo, %d[%d] PC=%06o %06o\n",
|
||
dev, *data, ctlr, tu_drive[ctlr], PC, df10->status);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
df10->status &= ~(1 << df10->ccw_comp);
|
||
df10->status &= ~PI_ENABLE;
|
||
if (((*data >> 1) & 077) < FNC_XFER) {
|
||
df10->status |= CXR_ILC;
|
||
df10_setirq(df10);
|
||
sim_debug(DEBUG_DATAIO, dptr,
|
||
"TU %03o command abort %012llo, %d[%d] PC=%06o %06o\n",
|
||
dev, *data, ctlr, tu_drive[ctlr], PC, df10->status);
|
||
return SCPE_OK;
|
||
}
|
||
/* Check if access error */
|
||
if (tu_rae[ctlr] & (1 << tu_drive[ctlr])) {
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Start command */
|
||
df10_setup(df10, (uint32)(*data >> 6));
|
||
tu_xfer_drive[ctlr] = (int)(*data >> 18) & 07;
|
||
tu_write(ctlr, tu_drive[ctlr], 0, (uint32)(*data & 077));
|
||
sim_debug(DEBUG_DATAIO, dptr,
|
||
"TU %03o command %012llo, %d[%d] PC=%06o %06o\n",
|
||
dev, *data, ctlr, tu_drive[ctlr], PC, df10->status);
|
||
} else if (tu_reg[ctlr] == 044) {
|
||
/* Set KI10 Irq vector */
|
||
tu_ivect[ctlr] = (int)(*data & IRQ_VECT);
|
||
tu_imode[ctlr] = (*data & IRQ_KI10) != 0;
|
||
} else if (tu_reg[ctlr] == 050) {
|
||
; /* Diagnostic access to mass bus. */
|
||
} else if (tu_reg[ctlr] == 054) {
|
||
/* clear flags */
|
||
tu_rae[ctlr] &= ~(*data & 0377);
|
||
if (tu_rae[ctlr] == 0)
|
||
clr_interrupt(dev);
|
||
} else if ((tu_reg[ctlr] & 040) == 0) {
|
||
tu_drive[ctlr] = (int)(*data >> 18) & 07;
|
||
/* Check if access error */
|
||
if (tu_rae[ctlr] & (1 << tu_drive[ctlr])) {
|
||
return SCPE_OK;
|
||
}
|
||
tu_drive[ctlr] = (int)(*data >> 18) & 07;
|
||
tu_write(ctlr, tu_drive[ctlr], tu_reg[ctlr] & 037,
|
||
(int)(*data & 0777777));
|
||
}
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
return SCPE_OK; /* Unreached */
|
||
}
|
||
|
||
/* Handle KI and KL style interrupt vectors */
|
||
int
|
||
tu_devirq(uint32 dev, int addr) {
|
||
DEVICE *dptr = NULL;
|
||
int drive;
|
||
|
||
for (drive = 0; rh[drive].dev_num != 0; drive++) {
|
||
if (rh[drive].dev_num == (dev & 0774)) {
|
||
dptr = rh[drive].dev;
|
||
break;
|
||
}
|
||
}
|
||
if (dptr != NULL) {
|
||
drive = GET_CNTRL(dptr->units[0].flags);
|
||
return (tu_imode[drive] ? tu_ivect[drive] : addr);
|
||
}
|
||
return addr;
|
||
}
|
||
|
||
void
|
||
tu_write(int ctlr, int unit, int reg, uint32 data) {
|
||
UNIT *uptr = &tu_unit[(ctlr * 8) + (tu_tcr[ctlr] & 07)];
|
||
DEVICE *dptr = tu_devs[ctlr];
|
||
struct df10 *df10 = &tu_df10[ctlr];
|
||
int i;
|
||
|
||
if (uptr->CMD & CR_GO) {
|
||
uptr->STATUS |= (ER1_RMR);
|
||
return;
|
||
}
|
||
|
||
switch(reg) {
|
||
case 000: /* control */
|
||
sim_debug(DEBUG_DETAIL, dptr, "TUA%o %d Status=%06o\n",
|
||
unit, ctlr, uptr->STATUS);
|
||
df10->status &= ~(1 << df10->ccw_comp);
|
||
if ((data & 01) != 0 && (uptr->flags & UNIT_ATT) != 0) {
|
||
uptr->CMD = data & 076;
|
||
switch (GET_FNC(data)) {
|
||
case FNC_NOP:
|
||
break;
|
||
|
||
case FNC_PRESET: /* read-in preset */
|
||
case FNC_READ: /* read */
|
||
case FNC_READREV: /* read w/ headers */
|
||
tu_frame[ctlr] = 0;
|
||
/* Fall through */
|
||
|
||
case FNC_ERASE: /* Erase gap */
|
||
case FNC_WRITE: /* write */
|
||
case FNC_WTM: /* Write tape mark */
|
||
case FNC_SPACEF: /* Space forward */
|
||
case FNC_SPACEB: /* Space backward */
|
||
case FNC_WCHK: /* write check */
|
||
case FNC_REWIND: /* rewind */
|
||
case FNC_UNLOAD: /* unload */
|
||
case FNC_WCHKREV: /* write w/ headers */
|
||
uptr->CMD |= CS_PIP|CR_GO;
|
||
uptr->CMD &= ~CS_TM;
|
||
CLR_BUF(uptr);
|
||
uptr->DATAPTR = 0;
|
||
df10->status &= ~PI_ENABLE;
|
||
sim_activate(uptr, 100);
|
||
break;
|
||
|
||
case FNC_DCLR: /* drive clear */
|
||
uptr->CMD &= ~(CS_ATA|CR_GO|CS_TM);
|
||
uptr->STATUS = 0;
|
||
tu_attn[ctlr] = 0;
|
||
clr_interrupt(df10->devnum);
|
||
for (i = 0; i < 8; i++) {
|
||
if (tu_unit[(ctlr * 8) + i].CMD & CS_ATA)
|
||
tu_attn[ctlr] = 1;
|
||
}
|
||
if ((df10->status & IADR_ATTN) != 0 && tu_attn[ctlr] != 0)
|
||
df10_setirq(df10);
|
||
break;
|
||
default:
|
||
uptr->STATUS |= (ER1_ILF);
|
||
uptr->CMD |= CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
if ((df10->status & IADR_ATTN) != 0)
|
||
df10_setirq(df10);
|
||
}
|
||
sim_debug(DEBUG_DETAIL, dptr, "TUA%o AStatus=%06o\n", unit,
|
||
uptr->CMD);
|
||
}
|
||
return;
|
||
case 001: /* status */
|
||
break;
|
||
case 002: /* error register 1 */
|
||
uptr->STATUS &= ~0177777;
|
||
uptr->STATUS |= data;
|
||
break;
|
||
case 003: /* maintenance */
|
||
break;
|
||
case 004: /* atten summary */
|
||
tu_attn[ctlr] = 0;
|
||
for (i = 0; i < 8; i++) {
|
||
if (data & (1<<i))
|
||
tu_unit[(ctlr * 8) + i].CMD &= ~CS_ATA;
|
||
if (tu_unit[(ctlr * 8) + i].CMD & CS_ATA)
|
||
tu_attn[ctlr] = 1;
|
||
}
|
||
clr_interrupt(df10->devnum);
|
||
if (((df10->status & IADR_ATTN) != 0 && tu_attn[ctlr] != 0) ||
|
||
(df10->status & PI_ENABLE))
|
||
df10_setirq(df10);
|
||
break;
|
||
case 005: /* frame count */
|
||
tu_frame[ctlr] = data & 0177777;
|
||
break;
|
||
case 006: /* drive type */
|
||
case 007: /* look ahead */
|
||
case 011: /* tape control register */
|
||
tu_tcr[ctlr] = data & 0177777 ;
|
||
break;
|
||
default:
|
||
uptr->STATUS |= ER1_ILR;
|
||
uptr->CMD |= CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
tu_rae[ctlr] |= (1<<unit);
|
||
if ((df10->status & IADR_ATTN) != 0)
|
||
df10_setirq(df10);
|
||
}
|
||
}
|
||
|
||
uint32
|
||
tu_read(int ctlr, int unit, int reg) {
|
||
UNIT *uptr = &tu_unit[(ctlr * 8) + (tu_tcr[ctlr] & 07)];
|
||
struct df10 *df10 = &tu_df10[ctlr];
|
||
uint32 temp = 0;
|
||
int i;
|
||
|
||
switch(reg) {
|
||
case 000: /* control */
|
||
temp = uptr->CMD & 076;
|
||
if (uptr->flags & UNIT_ATT)
|
||
temp |= CS1_DVA;
|
||
if (df10->status & BUSY || uptr->CMD & CR_GO)
|
||
temp |= CS1_GO;
|
||
break;
|
||
case 001: /* status */
|
||
temp = DS_DPR;
|
||
if (tu_attn[ctlr] != 0)
|
||
temp |= DS_ATA;
|
||
if (uptr->CMD & CS_CHANGE)
|
||
temp |= DS_SSC;
|
||
if ((uptr->STATUS & 0177777) != 0)
|
||
temp |= DS_ERR|DS_ATA;
|
||
if ((uptr->flags & UNIT_ATT) != 0) {
|
||
temp |= DS_MOL;
|
||
if (uptr->CMD & CS_TM)
|
||
temp |= DS_TM;
|
||
if (uptr->flags & MTUF_WLK)
|
||
temp |= DS_WRL;
|
||
if ((uptr->CMD & (CS_MOTION|CS_PIP|CR_GO)) == 0)
|
||
temp |= DS_DRY;
|
||
if (sim_tape_bot(uptr))
|
||
temp |= DS_BOT;
|
||
if (sim_tape_eot(uptr))
|
||
temp |= DS_EOT;
|
||
if ((uptr->CMD & CS_MOTION) == 0)
|
||
temp |= DS_SDWN;
|
||
if (uptr->CMD & CS_PIP)
|
||
temp |= DS_PIP;
|
||
}
|
||
break;
|
||
case 002: /* error register 1 */
|
||
temp = uptr->STATUS & 0177777;
|
||
break;
|
||
case 004: /* atten summary */
|
||
for (i = 0; i < 8; i++) {
|
||
if (tu_unit[(ctlr * 8) + i].CMD & CS_ATA) {
|
||
temp |= 1 << i;
|
||
}
|
||
}
|
||
break;
|
||
case 005: /* frame count */
|
||
temp = tu_frame[ctlr];
|
||
break;
|
||
case 006: /* drive type */
|
||
temp = 040054;
|
||
break;
|
||
case 011: /* tape control register */
|
||
temp = tu_tcr[ctlr];
|
||
break;
|
||
case 010: /* serial no */
|
||
temp = 020 + (unit + 1);
|
||
break;
|
||
case 003: /* maintenance */
|
||
case 007: /* look ahead */
|
||
break;
|
||
default:
|
||
uptr->STATUS |= (ER1_ILR);
|
||
uptr->CMD |= CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
tu_rae[ctlr] |= (1<<unit);
|
||
if ((df10->status & IADR_ATTN) != 0)
|
||
df10_setirq(df10);
|
||
}
|
||
return temp;
|
||
}
|
||
|
||
|
||
/* Map simH errors into machine errors */
|
||
void tu_error(UNIT * uptr, t_stat r)
|
||
{
|
||
int ctlr = GET_CNTRL(uptr->flags);
|
||
DEVICE *dptr = tu_devs[ctlr];
|
||
|
||
switch (r) {
|
||
case MTSE_OK: /* no error */
|
||
break;
|
||
|
||
case MTSE_TMK: /* tape mark */
|
||
uptr->CMD |= CS_TM;
|
||
break;
|
||
|
||
case MTSE_WRP: /* write protected */
|
||
uptr->STATUS |= (ER1_NEF);
|
||
uptr->CMD |= CS_ATA;
|
||
break;
|
||
|
||
case MTSE_UNATT: /* unattached */
|
||
case MTSE_BOT: /* beginning of tape */
|
||
case MTSE_EOM: /* end of medium */
|
||
break;
|
||
|
||
case MTSE_IOERR: /* IO error */
|
||
case MTSE_FMT: /* invalid format */
|
||
uptr->STATUS |= (ER1_PEF);
|
||
uptr->CMD |= CS_ATA;
|
||
break;
|
||
|
||
case MTSE_RECE: /* error in record */
|
||
uptr->STATUS |= (ER1_DPAR);
|
||
uptr->CMD |= CS_ATA;
|
||
break;
|
||
|
||
case MTSE_INVRL: /* invalid rec lnt */
|
||
uptr->STATUS |= (ER1_FCE);
|
||
uptr->CMD |= CS_ATA;
|
||
break;
|
||
|
||
}
|
||
if (uptr->CMD & CS_ATA) {
|
||
tu_attn[ctlr] = 1;
|
||
}
|
||
uptr->CMD &= ~(CS_MOTION|CS_PIP|CR_GO);
|
||
sim_debug(DEBUG_EXP, dptr, "Setting status %d\n", r);
|
||
}
|
||
|
||
/* Handle processing of tape requests. */
|
||
t_stat tu_srv(UNIT * uptr)
|
||
{
|
||
int ctlr = GET_CNTRL(uptr->flags);
|
||
int unit;
|
||
DEVICE *dptr;
|
||
struct df10 *df;
|
||
t_stat r;
|
||
t_mtrlnt reclen;
|
||
uint8 ch;
|
||
int cc;
|
||
int cc_max;
|
||
|
||
/* Find dptr, and df10 */
|
||
dptr = tu_devs[ctlr];
|
||
unit = uptr - dptr->units;
|
||
df = &tu_df10[ctlr];
|
||
cc_max = (4 + ((tu_tcr[ctlr] & TC_FMTSEL) == 0));
|
||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||
tu_error(uptr, MTSE_UNATT); /* attached? */
|
||
df10_setirq(df);
|
||
return SCPE_OK;
|
||
}
|
||
switch (GET_FNC(uptr->CMD)) {
|
||
case FNC_NOP:
|
||
case FNC_DCLR:
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o nop\n", unit);
|
||
tu_error(uptr, MTSE_OK); /* Nop */
|
||
df10_setirq(df);
|
||
return SCPE_OK;
|
||
|
||
case FNC_REWIND:
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o rewind\n", unit);
|
||
if (uptr->CMD & CR_GO) {
|
||
sim_activate(uptr,40000);
|
||
uptr->CMD |= CS_MOTION;
|
||
uptr->CMD &= ~(CR_GO);
|
||
} else {
|
||
uptr->CMD &= ~(CS_MOTION|CS_PIP);
|
||
uptr->CMD |= CS_CHANGE|CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
tu_error(uptr, sim_tape_rewind(uptr));
|
||
}
|
||
return SCPE_OK;
|
||
|
||
case FNC_UNLOAD:
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o unload\n", unit);
|
||
uptr->CMD &= ~(CR_GO);
|
||
uptr->CMD |= CS_CHANGE|CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
tu_error(uptr, sim_tape_detach(uptr));
|
||
return SCPE_OK;
|
||
|
||
case FNC_WCHKREV:
|
||
case FNC_READREV:
|
||
if (BUF_EMPTY(uptr)) {
|
||
uptr->CMD &= ~CS_PIP;
|
||
if ((r = sim_tape_rdrecr(uptr, &tu_buf[ctlr][0], &reclen,
|
||
TU_NUMFR)) != MTSE_OK) {
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o read error %d\n", unit, r);
|
||
if (r == MTSE_BOT)
|
||
uptr->STATUS |= ER1_NEF;
|
||
tu_error(uptr, r);
|
||
df10_finish_op(df, 0);
|
||
} else {
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o read %d\n", unit, reclen);
|
||
uptr->CMD |= CS_MOTION;
|
||
uptr->hwmark = reclen;
|
||
uptr->DATAPTR = uptr->hwmark-1;
|
||
uptr->CPOS = cc_max;
|
||
df->buf = 0;
|
||
sim_activate(uptr, 100);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
if (uptr->DATAPTR >= 0) {
|
||
tu_frame[ctlr]++;
|
||
cc = (8 * (3 - uptr->CPOS)) + 4;
|
||
ch = tu_buf[ctlr][uptr->DATAPTR];
|
||
if (cc < 0)
|
||
df->buf |= (uint64)(ch & 0x0f);
|
||
else
|
||
df->buf |= (uint64)(ch & 0xff) << cc;
|
||
uptr->DATAPTR--;
|
||
uptr->CPOS--;
|
||
if (uptr->CPOS == 0) {
|
||
uptr->CPOS = cc_max;
|
||
if (GET_FNC(uptr->CMD) == FNC_READREV &&
|
||
df10_write(df) == 0) {
|
||
tu_error(uptr, MTSE_OK);
|
||
return SCPE_OK;
|
||
}
|
||
sim_debug(DEBUG_DATA, dptr, "TU%o readrev %012llo\n",
|
||
unit, df->buf);
|
||
df->buf = 0;
|
||
}
|
||
} else {
|
||
if (uptr->CPOS != cc_max)
|
||
df10_write(df);
|
||
tu_error(uptr, MTSE_OK);
|
||
return SCPE_OK;
|
||
}
|
||
break;
|
||
|
||
case FNC_WCHK:
|
||
case FNC_READ:
|
||
if (BUF_EMPTY(uptr)) {
|
||
uptr->CMD &= ~CS_PIP;
|
||
uptr->CMD |= CS_MOTION;
|
||
if ((r = sim_tape_rdrecf(uptr, &tu_buf[ctlr][0], &reclen,
|
||
TU_NUMFR)) != MTSE_OK) {
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o read error %d\n", unit, r);
|
||
tu_error(uptr, r);
|
||
df10_finish_op(df, 0);
|
||
} else {
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o read %d\n", unit, reclen);
|
||
uptr->hwmark = reclen;
|
||
uptr->DATAPTR = 0;
|
||
uptr->CPOS = 0;
|
||
df->buf = 0;
|
||
sim_activate(uptr, 100);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
if ((uint32)uptr->DATAPTR < uptr->hwmark) {
|
||
tu_frame[ctlr]++;
|
||
cc = (8 * (3 - uptr->CPOS)) + 4;
|
||
ch = tu_buf[ctlr][uptr->DATAPTR];
|
||
if (cc < 0)
|
||
df->buf |= (uint64)(ch & 0x0f);
|
||
else
|
||
df->buf |= (uint64)(ch & 0xff) << cc;
|
||
uptr->DATAPTR++;
|
||
uptr->CPOS++;
|
||
if (uptr->CPOS == cc_max) {
|
||
uptr->CPOS = 0;
|
||
if (GET_FNC(uptr->CMD) == FNC_READ &&
|
||
df10_write(df) == 0) {
|
||
tu_error(uptr, MTSE_OK);
|
||
return SCPE_OK;
|
||
}
|
||
sim_debug(DEBUG_DATA, dptr, "TU%o read %012llo\n",
|
||
unit, df->buf);
|
||
df->buf = 0;
|
||
}
|
||
} else {
|
||
if (uptr->CPOS != 0) {
|
||
sim_debug(DEBUG_DATA, dptr, "TU%o read %012llo\n",
|
||
unit, df->buf);
|
||
df10_write(df);
|
||
}
|
||
tu_error(uptr, MTSE_OK);
|
||
df10_finish_op(df, 0);
|
||
return SCPE_OK;
|
||
}
|
||
break;
|
||
|
||
case FNC_WRITE:
|
||
if (BUF_EMPTY(uptr)) {
|
||
uptr->CMD &= ~CS_PIP;
|
||
if (tu_frame[ctlr] == 0) {
|
||
uptr->STATUS |= ER1_NEF;
|
||
uptr->CMD &= ~(CR_GO);
|
||
uptr->CMD |= CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
tu_error(uptr, MTSE_OK);
|
||
df10_finish_op(df, 0);
|
||
return SCPE_OK;
|
||
}
|
||
if ((uptr->flags & MTUF_WLK) != 0) {
|
||
tu_error(uptr, MTSE_WRP);
|
||
df10_finish_op(df, 0);
|
||
return SCPE_OK;
|
||
}
|
||
uptr->CMD |= CS_MOTION;
|
||
sim_debug(DEBUG_EXP, dptr, "TU%o Init write\n", unit);
|
||
uptr->hwmark = 0;
|
||
uptr->CPOS = 0;
|
||
uptr->DATAPTR = 0;
|
||
df->buf = 0;
|
||
}
|
||
if (tu_frame[ctlr] != 0 && uptr->CPOS == 0 && df10_read(df) == 0)
|
||
uptr->CPOS |= 010;
|
||
|
||
if ((uptr->CMD & CS_MOTION) != 0) {
|
||
if (uptr->CPOS == 0)
|
||
sim_debug(DEBUG_DATA, dptr, "TU%o write %012llo\n",
|
||
unit, df->buf);
|
||
/* Write next char out */
|
||
cc = (8 * (3 - (uptr->CPOS & 07))) + 4;
|
||
if (cc < 0)
|
||
ch = df->buf & 0x0f;
|
||
else
|
||
ch = (df->buf >> cc) & 0xff;
|
||
tu_buf[ctlr][uptr->DATAPTR] = ch;
|
||
uptr->DATAPTR++;
|
||
uptr->hwmark = uptr->DATAPTR;
|
||
uptr->CPOS = (uptr->CPOS & 010) | ((uptr->CPOS & 07) + 1);
|
||
if ((uptr->CPOS & 7) == cc_max) {
|
||
uptr->CPOS &= 010;
|
||
}
|
||
tu_frame[ctlr] = 0177777 & (tu_frame[ctlr] + 1);
|
||
if (tu_frame[ctlr] == 0)
|
||
uptr->CPOS = 010;
|
||
}
|
||
if (uptr->CPOS == 010) {
|
||
/* Write out the block */
|
||
reclen = uptr->hwmark;
|
||
r = sim_tape_wrrecf(uptr, &tu_buf[ctlr][0], reclen);
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o Write %d %d\n",
|
||
unit, reclen, uptr->CPOS);
|
||
uptr->DATAPTR = 0;
|
||
uptr->hwmark = 0;
|
||
df10_finish_op(df,0 );
|
||
tu_error(uptr, r); /* Record errors */
|
||
return SCPE_OK;
|
||
}
|
||
break;
|
||
|
||
case FNC_WTM:
|
||
if ((uptr->flags & MTUF_WLK) != 0) {
|
||
tu_error(uptr, MTSE_WRP);
|
||
} else {
|
||
tu_error(uptr, sim_tape_wrtmk(uptr));
|
||
}
|
||
uptr->CMD |= CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o WTM\n", unit);
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
return SCPE_OK;
|
||
|
||
case FNC_ERASE:
|
||
if ((uptr->flags & MTUF_WLK) != 0) {
|
||
tu_error(uptr, MTSE_WRP);
|
||
} else {
|
||
tu_error(uptr, sim_tape_wrgap(uptr, 35));
|
||
}
|
||
uptr->CMD |= CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o ERG\n", unit);
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
return SCPE_OK;
|
||
|
||
case FNC_SPACEF:
|
||
case FNC_SPACEB:
|
||
sim_debug(DEBUG_DETAIL, dptr, "TU%o space %o\n", unit, GET_FNC(uptr->CMD));
|
||
if (tu_frame[ctlr] == 0) {
|
||
uptr->STATUS |= ER1_NEF;
|
||
uptr->CMD |= CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
tu_error(uptr, MTSE_OK);
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
return SCPE_OK;
|
||
}
|
||
uptr->CMD |= CS_MOTION;
|
||
/* Always skip at least one record */
|
||
if (GET_FNC(uptr->CMD) == FNC_SPACEF)
|
||
r = sim_tape_sprecf(uptr, &reclen);
|
||
else
|
||
r = sim_tape_sprecr(uptr, &reclen);
|
||
switch (r) {
|
||
case MTSE_OK: /* no error */
|
||
break;
|
||
|
||
case MTSE_BOT: /* beginning of tape */
|
||
uptr->STATUS |= ER1_NEF;
|
||
/* Fall Through */
|
||
|
||
case MTSE_TMK: /* tape mark */
|
||
case MTSE_EOM: /* end of medium */
|
||
if (tu_frame[ctlr] != 0)
|
||
uptr->STATUS |= ER1_FCE;
|
||
uptr->CMD &= ~(CR_GO);
|
||
uptr->CMD |= CS_ATA;
|
||
tu_attn[ctlr] = 1;
|
||
/* Stop motion if we recieve any of these */
|
||
tu_error(uptr, r);
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
return SCPE_OK;
|
||
}
|
||
tu_frame[ctlr] = 0177777 & (tu_frame[ctlr] + 1);
|
||
if (tu_frame[ctlr] == 0) {
|
||
tu_error(uptr, MTSE_OK);
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
return SCPE_OK;
|
||
} else
|
||
sim_activate(uptr, 5000);
|
||
return SCPE_OK;
|
||
}
|
||
sim_activate(uptr, 200);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
|
||
|
||
t_stat
|
||
tu_reset(DEVICE * dptr)
|
||
{
|
||
int ctlr;
|
||
for (ctlr = 0; ctlr < NUM_DEVS_TU; ctlr++) {
|
||
tu_df10[ctlr].devnum = tu_dib[ctlr].dev_num;
|
||
tu_df10[ctlr].nxmerr = 19;
|
||
tu_df10[ctlr].ccw_comp = 14;
|
||
tu_attn[ctlr] = 0;
|
||
tu_rae[ctlr] = 0;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
void tu_read_word(UNIT *uptr) {
|
||
int i, cc, ch;
|
||
|
||
tu_boot_buffer = 0;
|
||
for(i = 0; i <= 4; i++) {
|
||
cc = (8 * (3 - i)) + 4;
|
||
ch = tu_buf[0][uptr->DATAPTR];
|
||
if (cc < 0)
|
||
tu_boot_buffer |= (uint64)(ch & 0x0f);
|
||
else
|
||
tu_boot_buffer |= (uint64)(ch & 0xff) << cc;
|
||
uptr->DATAPTR++;
|
||
}
|
||
}
|
||
|
||
/* Boot from given device */
|
||
t_stat
|
||
tu_boot(int32 unit_num, DEVICE * dptr)
|
||
{
|
||
UNIT *uptr = &dptr->units[unit_num];
|
||
t_mtrlnt reclen;
|
||
t_stat r;
|
||
uint32 addr;
|
||
int wc;
|
||
|
||
if ((uptr->flags & UNIT_ATT) == 0)
|
||
return SCPE_UNATT; /* attached? */
|
||
|
||
r = sim_tape_rewind(uptr);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
r = sim_tape_rdrecf(uptr, &tu_buf[0][0], &reclen, TU_NUMFR);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
uptr->DATAPTR = 0;
|
||
uptr->hwmark = reclen;
|
||
|
||
tu_read_word(uptr);
|
||
wc = (tu_boot_buffer >> 18) & RMASK;
|
||
addr = tu_boot_buffer & RMASK;
|
||
while (wc != 0) {
|
||
wc = (wc + 1) & RMASK;
|
||
addr = (addr + 1) & RMASK;
|
||
if ((uint32)uptr->DATAPTR >= uptr->hwmark) {
|
||
r = sim_tape_rdrecf(uptr, &tu_buf[0][0], &reclen, TU_NUMFR);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
uptr->DATAPTR = 0;
|
||
uptr->hwmark = reclen;
|
||
}
|
||
tu_read_word(uptr);
|
||
if (addr < 020)
|
||
FM[addr] = tu_boot_buffer;
|
||
else
|
||
M[addr] = tu_boot_buffer;
|
||
}
|
||
if (addr < 020)
|
||
FM[addr] = tu_boot_buffer;
|
||
else
|
||
M[addr] = tu_boot_buffer;
|
||
|
||
PC = tu_boot_buffer & RMASK;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
t_stat
|
||
tu_attach(UNIT * uptr, CONST char *file)
|
||
{ t_stat r;
|
||
int ctlr = GET_CNTRL(uptr->flags);
|
||
struct df10 *df;
|
||
|
||
/* Find df10 */
|
||
df = &tu_df10[ctlr];
|
||
|
||
uptr->CMD = 0;
|
||
uptr->STATUS = 0;
|
||
r = sim_tape_attach_ex(uptr, file, 0, 0);
|
||
if (r == SCPE_OK) {
|
||
uptr->CMD = CS_ATA|CS_CHANGE;
|
||
tu_attn[ctlr] = 1;
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
}
|
||
return r;
|
||
}
|
||
|
||
t_stat
|
||
tu_detach(UNIT * uptr)
|
||
{
|
||
int ctlr = GET_CNTRL(uptr->flags);
|
||
struct df10 *df;
|
||
|
||
/* Find df10 */
|
||
df = &tu_df10[ctlr];
|
||
uptr->STATUS = 0;
|
||
uptr->CMD = CS_ATA|CS_CHANGE;
|
||
tu_attn[ctlr] = 1;
|
||
if ((df->status & IADR_ATTN) != 0)
|
||
df10_setirq(df);
|
||
return sim_tape_detach(uptr);
|
||
}
|
||
|
||
|
||
|
||
t_stat tu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "TU Tape Drives with TM03 formatter. (TU)\n\n");
|
||
fprintf (st, "The TU controller implements the Massbus tape formatter the TM03. TU\n");
|
||
fprintf (st, "options include the ability to set units write enabled or write locked\n\n");
|
||
fprint_set_help (st, dptr);
|
||
fprint_show_help (st, dptr);
|
||
fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n");
|
||
fprintf (st, "The TU device supports the BOOT command.\n");
|
||
sim_tape_attach_help (st, dptr, uptr, flag, cptr);
|
||
fprint_reg_help (st, dptr);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *tu_description (DEVICE *dptr)
|
||
{
|
||
return "TU04/05/06/07 Massbus disk controller";
|
||
}
|
||
|
||
|
||
#endif
|