1071 lines
37 KiB
C
1071 lines
37 KiB
C
/* ka10_mt.c: TM10A/B Magnetic tape controller
|
||
|
||
Copyright (c) 2013-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 PURPOSE 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.
|
||
|
||
Magnetic tapes are represented as a series of variable records
|
||
of the form:
|
||
|
||
32b byte count
|
||
byte 0
|
||
byte 1
|
||
:
|
||
byte n-2
|
||
byte n-1
|
||
32b byte count
|
||
|
||
If the byte count is odd, the record is padded with an extra byte
|
||
of junk. File marks are represented by a byte count of 0.
|
||
*/
|
||
|
||
#include "kx10_defs.h"
|
||
#include "sim_tape.h"
|
||
|
||
#ifndef NUM_DEVS_MT
|
||
#define NUM_DEVS_MT 0
|
||
#endif
|
||
|
||
#if (NUM_DEVS_MT > 0)
|
||
|
||
#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF)
|
||
#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF
|
||
|
||
#define MTDF_TYPEB (1 << DEV_V_UF)
|
||
#define MTUF_7TRK (1 << MTUF_V_UF)
|
||
|
||
#define BUFFSIZE (32 * 1024)
|
||
#define UNIT_MT UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE
|
||
#define LT 66 /* Time per char low density */
|
||
#define HT 16 /* Time per char high density */
|
||
|
||
#define NOP_CLR 000 /* Nop clear, interrupt */
|
||
#define NOP_IDLE 010 /* Nop interrupt when idle */
|
||
#define REWIND 001 /* Rewind */
|
||
#define UNLOAD 011 /* Unload */
|
||
#define READ 002 /* Read */
|
||
#define READ_NOEOR 012 /* Read no end of record. */
|
||
#define CMP 003 /* Compare */
|
||
#define CMP_NOEOR 013 /* Compare no end of record. */
|
||
#define WRITE 004 /* Write */
|
||
#define WRITE_LONG 014 /* Write with long record gap. */
|
||
#define WTM 005 /* Write End of File */
|
||
#define ERG 015 /* Write blank tape */
|
||
#define SPC_FWD 006 /* Space forward */
|
||
#define SPC_EOF 016 /* Space to end of file */
|
||
#define SPC_REV 007 /* Space reverse */
|
||
#define SPC_REV_EOF 017 /* Space reverse to EOF. */
|
||
|
||
#define DATA_REQUEST 00000000001
|
||
#define NEXT_UNIT 00000000002
|
||
#define SEVEN_CHAN 00000000004
|
||
#define WRITE_LOCK 00000000010
|
||
#define CHAN_ERR 00000000020
|
||
#define IDLE_UNIT 00000000040
|
||
#define JOB_DONE 00000000100
|
||
#define BAD_TAPE 00000000200
|
||
#define DATA_LATE 00000000400
|
||
#define RLC_ERR 00000001000
|
||
#define READ_CMP 00000002000
|
||
#define EOT_FLAG 00000004000
|
||
#define EOF_FLAG 00000010000
|
||
#define PARITY_ERR 00000020000
|
||
#define ILL_OPR 00000040000
|
||
#define BOT_FLAG 00000100000
|
||
#define REW_FLAG 00000200000
|
||
#define TRAN_HUNG 00000400000
|
||
#define CHAR_COUNT 00007000000
|
||
#define WT_CW_DONE 00010000000
|
||
#define DATA_PARITY 00020000000
|
||
#define NXM_ERR 00040000000
|
||
#define CW_PAR_ERR 00100000000
|
||
#define B22_FLAG 00400000000
|
||
|
||
#define DATA_PIA 000000007 /* 0 */
|
||
#define FLAG_PIA 000000070 /* 3 */
|
||
#define DENS_200 000000000
|
||
#define DENS_556 000000100
|
||
#define DENS_800 000000200
|
||
#define DENS_MSK 000000300 /* 6 */
|
||
#define NEXT_UNIT_ENAB 000000400 /* 8 */
|
||
#define FUNCTION 000017000 /* 9 */
|
||
#define CORE_DUMP 000020000 /*13 */
|
||
#define ODD_PARITY 000040000 /*14 */
|
||
#define UNIT_NUM 000700000 /*15 */
|
||
#define NEXT_UNIT_NUM 007000000 /*18 */
|
||
|
||
#define MT_DEVNUM 0340
|
||
#define MT_MOTION 000000001 /* Mag tape unit in motion */
|
||
#define MT_BUSY 000000002 /* Mag tape unit is busy */
|
||
#define MT_BUFFUL 000000004 /* Buffer full of data */
|
||
#define MT_BRFUL 000000010 /* BR register full */
|
||
#define MT_STOP 000000020 /* DF10 End of Channel */
|
||
#define MT_LASTWD 000000040 /* Last data word of record */
|
||
|
||
#define CNTRL u3
|
||
#define CPOS u5 /* Character position */
|
||
#define BPOS u6 /* Position in buffer */
|
||
|
||
t_stat mt_devio(uint32 dev, uint64 *data);
|
||
t_stat mt_srv(UNIT *);
|
||
t_stat mt_boot(int32, DEVICE *);
|
||
t_stat mt_set_mta (UNIT *uptr, int32 val, CONST char *cptr, void *desc) ;
|
||
t_stat mt_show_mta (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||
#if MPX_DEV
|
||
t_stat mt_set_mpx (UNIT *uptr, int32 val, CONST char *cptr, void *desc) ;
|
||
t_stat mt_show_mpx (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||
#endif
|
||
t_stat mt_reset(DEVICE *);
|
||
t_stat mt_attach(UNIT *, CONST char *);
|
||
t_stat mt_detach(UNIT *);
|
||
t_stat mt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||
const char *cptr);
|
||
const char *mt_description (DEVICE *dptr);
|
||
|
||
struct df10 mt_df10;
|
||
uint16 mt_pia;
|
||
uint8 mt_sel_unit;
|
||
uint8 mt_next_unit;
|
||
uint8 wr_eor;
|
||
uint64 mt_status;
|
||
uint64 mt_hold_reg;
|
||
int mt_mpx_lvl = 0;
|
||
int hri_mode; /* Read in mode for TM10B */
|
||
|
||
static uint8 parity_table[64] = {
|
||
/* 0 1 2 3 4 5 6 7 */
|
||
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
|
||
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
|
||
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
|
||
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
|
||
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000
|
||
};
|
||
|
||
|
||
/* One buffer per channel */
|
||
uint8 mt_buffer[BUFFSIZE];
|
||
|
||
UNIT mt_unit[] = {
|
||
/* Controller 1 */
|
||
{UDATA(&mt_srv, UNIT_MT, 0)}, /* 0 */
|
||
{UDATA(&mt_srv, UNIT_MT, 0)}, /* 1 */
|
||
{UDATA(&mt_srv, UNIT_MT, 0)}, /* 2 */
|
||
{UDATA(&mt_srv, UNIT_MT, 0)}, /* 3 */
|
||
{UDATA(&mt_srv, UNIT_MT, 0)}, /* 4 */
|
||
{UDATA(&mt_srv, UNIT_MT, 0)}, /* 5 */
|
||
{UDATA(&mt_srv, UNIT_MT, 0)}, /* 6 */
|
||
{UDATA(&mt_srv, UNIT_MT, 0)}, /* 7 */
|
||
};
|
||
|
||
DIB mt_dib = {MT_DEVNUM, 2, &mt_devio, NULL};
|
||
|
||
MTAB mt_mod[] = {
|
||
{MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL},
|
||
{MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL},
|
||
{MTAB_XTD|MTAB_VDV|MTAB_VALR, MTDF_TYPEB, "TYPE", "TYPE", &mt_set_mta, &mt_show_mta},
|
||
{MTUF_7TRK, 0, "9T", "9T", NULL, NULL},
|
||
{MTUF_7TRK, MTUF_7TRK, "7T", "7T", NULL, 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},
|
||
#if MPX_DEV
|
||
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "MPX", "MPX",
|
||
&mt_set_mpx, &mt_show_mpx, NULL},
|
||
#endif
|
||
{0}
|
||
};
|
||
|
||
REG mt_reg[] = {
|
||
{BRDATA(BUFF, &mt_buffer[0], 16, 64, BUFFSIZE), REG_HRO},
|
||
{ORDATA(PIA, mt_pia, 3)},
|
||
{ORDATA(UNIT, mt_sel_unit, 3)},
|
||
{ORDATA(NUNIT, mt_next_unit, 3)},
|
||
{FLDATA(READIN, hri_mode, 0), REG_HRO},
|
||
{FLDATA(WREOR, wr_eor, 0), REG_HRO},
|
||
{ORDATA(STATUS, mt_status, 18), REG_HRO},
|
||
{ORDATA(HOLD, mt_hold_reg, 36), REG_HRO},
|
||
{ORDATA(MPX, mt_mpx_lvl, 3)},
|
||
{ORDATA(DSTATUS, mt_df10.status, 18), REG_RO},
|
||
{ORDATA(CIA, mt_df10.cia, 18)},
|
||
{ORDATA(CCW, mt_df10.ccw, 18)},
|
||
{ORDATA(WCR, mt_df10.wcr, 18)},
|
||
{ORDATA(CDA, mt_df10.cda, 18)},
|
||
{ORDATA(DEVNUM, mt_df10.devnum, 9), REG_HRO},
|
||
{ORDATA(BUF, mt_df10.buf, 36), REG_HRO},
|
||
{ORDATA(NXM, mt_df10.nxmerr, 8), REG_HRO},
|
||
{ORDATA(COMP, mt_df10.ccw_comp, 8), REG_HRO},
|
||
{0}
|
||
};
|
||
|
||
DEVICE mt_dev = {
|
||
"MTA", mt_unit, mt_reg, mt_mod,
|
||
8, 8, 15, 1, 8, 8,
|
||
NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach,
|
||
&mt_dib, DEV_DISABLE | DEV_DEBUG | DEV_TAPE, 0, dev_debug,
|
||
NULL, NULL, &mt_help, NULL, NULL, &mt_description
|
||
};
|
||
|
||
t_stat mt_devio(uint32 dev, uint64 *data) {
|
||
uint64 res;
|
||
DEVICE *dptr = &mt_dev;
|
||
UNIT *uptr = &mt_unit[mt_sel_unit];
|
||
|
||
switch(dev & 07) {
|
||
case CONI:
|
||
res = (uint64)(mt_pia & (NEXT_UNIT_ENAB|FLAG_PIA|DATA_PIA));
|
||
res |= (uint64)(uptr->CNTRL & 077300);
|
||
res |= ((uint64)mt_sel_unit) << 15;
|
||
res |= ((uint64)mt_next_unit) << 18;
|
||
res |= ((uint64)wr_eor) << 21;
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
res |= 7LL; /* Force DATA PIA to 7 on type B */
|
||
if (cpu_unit[0].flags & UNIT_ITSPAGE)
|
||
res |= SMASK;
|
||
*data = res;
|
||
sim_debug(DEBUG_CONI, dptr, "MT CONI %03o status %06o %o %o PC=%06o\n",
|
||
dev, (uint32)res, mt_sel_unit, mt_pia, PC);
|
||
break;
|
||
|
||
case CONO:
|
||
clr_interrupt(MT_DEVNUM);
|
||
clr_interrupt(MT_DEVNUM+4);
|
||
mt_next_unit = (*data >> 15) & 07;
|
||
mt_pia = (uint16)(*data) & (NEXT_UNIT_ENAB|FLAG_PIA|DATA_PIA);
|
||
mt_status &= ~(DATA_REQUEST|CHAN_ERR|JOB_DONE|DATA_LATE| \
|
||
BAD_TAPE|RLC_ERR|READ_CMP|EOF_FLAG|EOT_FLAG|BOT_FLAG| \
|
||
PARITY_ERR|ILL_OPR|REW_FLAG|TRAN_HUNG| \
|
||
WT_CW_DONE|DATA_PARITY|NXM_ERR|CW_PAR_ERR|IDLE_UNIT| \
|
||
SEVEN_CHAN|NEXT_UNIT);
|
||
/* Check if we can switch to new unit */
|
||
if (mt_next_unit != mt_sel_unit) {
|
||
sim_cancel(uptr);
|
||
mt_sel_unit = mt_next_unit;
|
||
uptr = &mt_unit[mt_sel_unit];
|
||
}
|
||
if (mt_pia & NEXT_UNIT_ENAB) {
|
||
set_interrupt(dev, mt_pia >> 3);
|
||
}
|
||
uptr->CNTRL = (int32)(*data & 077300);
|
||
mt_df10.buf = 0;
|
||
sim_debug(DEBUG_CONO, dptr,
|
||
"MT CONO %03o start %o %o %o %012llo %012llo PC=%06o\n",
|
||
dev, uptr->CNTRL, mt_sel_unit, mt_pia, *data, mt_status, PC);
|
||
if ((uptr->flags & UNIT_ATT) != 0) {
|
||
/* Check if Write */
|
||
int cmd = (uptr->CNTRL & FUNCTION) >> 9;
|
||
uptr->CNTRL &= ~(MT_BRFUL|MT_BUFFUL|MT_STOP);
|
||
switch(cmd & 07) {
|
||
case NOP_CLR:
|
||
uptr->CNTRL &= ~MT_BUSY;
|
||
wr_eor = 0;
|
||
mt_status |= NEXT_UNIT;
|
||
if ((cmd & 010) != 0 || (mt_pia & NEXT_UNIT_ENAB) != 0) {
|
||
mt_status |= JOB_DONE;
|
||
set_interrupt(MT_DEVNUM+4, mt_pia >> 3);
|
||
} else {
|
||
clr_interrupt(MT_DEVNUM+4);
|
||
}
|
||
clr_interrupt(MT_DEVNUM);
|
||
sim_debug(DEBUG_EXP, dptr, "Setting status %012llo\n", mt_status);
|
||
return SCPE_OK;
|
||
|
||
case REWIND:
|
||
mt_status |= REW_FLAG;
|
||
break;
|
||
|
||
case WRITE:
|
||
if ((uptr->flags & MTUF_WLK) != 0) {
|
||
mt_status |= IDLE_UNIT|ILL_OPR|EOF_FLAG;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
|
||
case WTM:
|
||
case READ:
|
||
case CMP:
|
||
CLR_BUF(uptr);
|
||
uptr->CPOS = 0;
|
||
break;
|
||
|
||
case SPC_REV:
|
||
if (sim_tape_bot(uptr)) {
|
||
mt_status |= JOB_DONE|ILL_OPR;
|
||
set_interrupt(MT_DEVNUM+4, mt_pia >> 3);
|
||
return SCPE_OK;
|
||
}
|
||
/* Fall through */
|
||
|
||
case SPC_FWD:
|
||
if ((dptr->flags & MTDF_TYPEB) == 0 && (cmd & 010) == 0) {
|
||
mt_status |= DATA_REQUEST;
|
||
set_interrupt_mpx(MT_DEVNUM, mt_pia, mt_mpx_lvl);
|
||
}
|
||
}
|
||
mt_status |= IDLE_UNIT;
|
||
uptr->CNTRL |= MT_BUSY;
|
||
sim_activate(uptr, 1000);
|
||
} else {
|
||
sim_activate(uptr, 9999999);
|
||
sim_debug(DEBUG_CONO, dptr, "MT CONO %03o hung PC=%06o\n", dev, PC);
|
||
}
|
||
break;
|
||
|
||
case DATAI:
|
||
/* Xfer data */
|
||
clr_interrupt(MT_DEVNUM);
|
||
*data = mt_hold_reg;
|
||
uptr->CNTRL &= ~MT_BUFFUL;
|
||
mt_status &= ~DATA_REQUEST;
|
||
if (uptr->CNTRL & MT_BRFUL) {
|
||
mt_hold_reg = mt_df10.buf;
|
||
mt_df10.buf = 0;
|
||
uptr->CNTRL &= ~MT_BRFUL;
|
||
uptr->CNTRL |= MT_BUFFUL;
|
||
if ((dptr->flags & MTDF_TYPEB) == 0) {
|
||
mt_status |= DATA_REQUEST;
|
||
set_interrupt_mpx(MT_DEVNUM, mt_pia, mt_mpx_lvl);
|
||
}
|
||
}
|
||
sim_debug(DEBUG_DATA, dptr, "MT %03o >%012llo\n", dev, *data);
|
||
break;
|
||
|
||
case DATAO:
|
||
/* Xfer data */
|
||
mt_hold_reg = *data;
|
||
mt_status &= ~DATA_REQUEST;
|
||
clr_interrupt(MT_DEVNUM);
|
||
uptr->CNTRL |= MT_BUFFUL;
|
||
sim_debug(DEBUG_DATA, dptr, "MT %03o <%012llo, %012llo\n",
|
||
dev, mt_hold_reg, mt_df10.buf);
|
||
break;
|
||
|
||
case CONI|04:
|
||
res = mt_status;
|
||
if ((uptr->CNTRL & MT_BUSY) == 0)
|
||
res |= NEXT_UNIT;
|
||
if ((uptr->CNTRL & (06000|MT_STOP)) == 02000 && (mt_status & JOB_DONE) != 0)
|
||
res |= RLC_ERR;
|
||
if ((uptr->flags & MTUF_7TRK) != 0)
|
||
res |= SEVEN_CHAN;
|
||
if ((uptr->flags & UNIT_ATT) != 0 && (uptr->CNTRL & MT_MOTION) == 0)
|
||
res |= IDLE_UNIT;
|
||
if ((uptr->flags & MTUF_WLK) != 0)
|
||
res |= WRITE_LOCK;
|
||
if (sim_tape_bot(uptr))
|
||
res |= BOT_FLAG;
|
||
if (sim_tape_eot(uptr))
|
||
res |= EOT_FLAG;
|
||
if ((dptr->flags & MTDF_TYPEB) == 0)
|
||
res |= WT_CW_DONE|DATA_PARITY|NXM_ERR|CW_PAR_ERR;
|
||
#if KI_22BIT
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
res |= B22_FLAG;
|
||
#endif
|
||
*data = res;
|
||
sim_debug(DEBUG_CONI, dptr, "MT CONI %03o status2 %012llo %o %012llo PC=%06o\n",
|
||
dev, res, mt_sel_unit, mt_status, PC);
|
||
break;
|
||
|
||
case CONO|04:
|
||
if (*data & 1) {
|
||
uptr->CNTRL |= MT_STOP;
|
||
hri_mode = 0;
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT stop %03o %012llo\n", dev, mt_status);
|
||
}
|
||
if (*data & 2) {
|
||
mt_hold_reg ^= mt_df10.buf;
|
||
}
|
||
if (dptr->flags & MTDF_TYPEB) {
|
||
if (*data & 04)
|
||
df10_writecw(&mt_df10);
|
||
if (*data & 010)
|
||
mt_status &= ~(WT_CW_DONE);
|
||
}
|
||
sim_debug(DEBUG_CONO, dptr, "MT CONO %03o control %o %o %012llo %012llo\n",
|
||
dev, uptr->CNTRL, mt_sel_unit, mt_hold_reg, mt_df10.buf);
|
||
break;
|
||
|
||
case DATAI|04:
|
||
*data = 0;
|
||
break;
|
||
|
||
case DATAO|04:
|
||
/* Set Initial CCW */
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
df10_setup(&mt_df10, (uint32) *data);
|
||
else
|
||
mt_df10.buf ^= mt_hold_reg;
|
||
sim_debug(DEBUG_DATAIO, dptr, "MT DATAO %03o %012llo\n", dev, *data);
|
||
break;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Wrapper to handle reading of hold register or via DF10 */
|
||
void mt_df10_read(DEVICE *dptr, UNIT *uptr) {
|
||
if (dptr->flags & MTDF_TYPEB) {
|
||
if (!df10_read(&mt_df10)) {
|
||
uptr->CNTRL |= MT_STOP;
|
||
}
|
||
sim_debug(DEBUG_DATA, dptr, "MT <%012llo %o\n", mt_df10.buf, uptr->CPOS);
|
||
} else {
|
||
if (uptr->CNTRL & MT_BUFFUL) {
|
||
mt_df10.buf = mt_hold_reg;
|
||
if ((uptr->CNTRL & MT_STOP) == 0) {
|
||
mt_status |= DATA_REQUEST;
|
||
set_interrupt_mpx(MT_DEVNUM, mt_pia, mt_mpx_lvl);
|
||
}
|
||
} else {
|
||
if ((uptr->CNTRL & MT_STOP) == 0) {
|
||
mt_status |= DATA_LATE;
|
||
uptr->CNTRL |= MT_STOP;
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
uptr->CNTRL &= ~MT_BUFFUL;
|
||
uptr->CNTRL |= MT_BRFUL;
|
||
uptr->CPOS = 0;
|
||
}
|
||
|
||
/* Wrapper to handle writing of hold register or via DF10 */
|
||
void mt_df10_write(DEVICE *dptr, UNIT *uptr) {
|
||
if (dptr->flags & MTDF_TYPEB) {
|
||
if (hri_mode) {
|
||
mt_hold_reg = mt_df10.buf;
|
||
mt_status |= DATA_REQUEST;
|
||
} else if (!df10_write(&mt_df10)) {
|
||
uptr->CNTRL |= MT_STOP;
|
||
return;
|
||
}
|
||
sim_debug(DEBUG_DATA, dptr, "MT >%012llo %o\n", mt_df10.buf, uptr->CPOS);
|
||
uptr->CNTRL &= ~(MT_BUFFUL|MT_BRFUL);
|
||
} else {
|
||
if ((uptr->CNTRL & MT_BUFFUL) == 0) {
|
||
mt_hold_reg = mt_df10.buf;
|
||
mt_status |= DATA_REQUEST;
|
||
uptr->CNTRL &= ~(MT_BRFUL);
|
||
uptr->CNTRL |= MT_BUFFUL;
|
||
set_interrupt_mpx(MT_DEVNUM, mt_pia, mt_mpx_lvl);
|
||
} else {
|
||
uptr->CNTRL |= MT_BRFUL;
|
||
}
|
||
}
|
||
mt_df10.buf = 0;
|
||
uptr->CPOS = 0;
|
||
}
|
||
|
||
|
||
/* Map simH errors into machine errors */
|
||
t_stat mt_error(UNIT * uptr, t_stat r, DEVICE * dptr)
|
||
{
|
||
switch (r) {
|
||
case MTSE_OK: /* no error */
|
||
break;
|
||
|
||
case MTSE_TMK: /* tape mark */
|
||
mt_status |= EOF_FLAG;
|
||
break;
|
||
|
||
case MTSE_WRP: /* write protected */
|
||
mt_status |= WRITE_LOCK;
|
||
break;
|
||
|
||
case MTSE_UNATT: /* unattached */
|
||
mt_status |= TRAN_HUNG;
|
||
break;
|
||
|
||
case MTSE_IOERR: /* IO error */
|
||
case MTSE_FMT: /* invalid format */
|
||
mt_status |= ILL_OPR;
|
||
break;
|
||
|
||
case MTSE_RECE: /* error in record */
|
||
mt_status |= BAD_TAPE;
|
||
break;
|
||
|
||
case MTSE_BOT: /* beginning of tape */
|
||
mt_status |= BOT_FLAG;
|
||
break;
|
||
|
||
case MTSE_INVRL: /* invalid rec lnt */
|
||
break;
|
||
|
||
case MTSE_EOM: /* end of medium */
|
||
mt_status |= EOT_FLAG;
|
||
break;
|
||
}
|
||
if (mt_next_unit != mt_sel_unit) {
|
||
mt_sel_unit = mt_next_unit;
|
||
mt_status |= NEXT_UNIT;
|
||
if (mt_pia & NEXT_UNIT_ENAB)
|
||
set_interrupt(MT_DEVNUM+4, mt_pia >> 3);
|
||
}
|
||
mt_status |= JOB_DONE;
|
||
uptr->CNTRL &= ~MT_BUSY;
|
||
sim_debug(DEBUG_EXP, dptr, "Setting status %d %012llo\n", r, mt_status);
|
||
set_interrupt(MT_DEVNUM+4, mt_pia >> 3);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Handle processing of tape requests. */
|
||
t_stat mt_srv(UNIT * uptr)
|
||
{
|
||
DEVICE *dptr = find_dev_from_unit(uptr);
|
||
int unit = (uptr - dptr->units) & 7;
|
||
int cmd = (uptr->CNTRL & FUNCTION) >> 9;
|
||
t_mtrlnt reclen;
|
||
t_stat r = SCPE_ARG; /* Force error if not set */
|
||
uint8 ch;
|
||
int cc;
|
||
int cc_max;
|
||
|
||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
return mt_error(uptr, MTSE_UNATT, dptr); /* attached? */
|
||
}
|
||
|
||
if ((cmd & 6) != 0 && (uptr->CNTRL & DENS_MSK) != DENS_800) {
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
return mt_error(uptr, MTSE_FMT, dptr); /* wrong density? */
|
||
}
|
||
|
||
if (uptr->flags & MTUF_7TRK) {
|
||
cc_max = 6;
|
||
} else {
|
||
cc_max = (4 + ((uptr->CNTRL & CORE_DUMP) != 0));
|
||
}
|
||
|
||
switch(cmd) {
|
||
case NOP_IDLE:
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o Idle\n", unit);
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
return mt_error(uptr, MTSE_OK, dptr);
|
||
|
||
case NOP_CLR:
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o nop\n", unit);
|
||
return mt_error(uptr, MTSE_OK, dptr); /* Nop */
|
||
|
||
case REWIND:
|
||
mt_status &= ~IDLE_UNIT;
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o rewind\n", unit);
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
mt_status |= BOT_FLAG;
|
||
return mt_error(uptr, sim_tape_rewind(uptr), dptr);
|
||
|
||
case UNLOAD:
|
||
mt_status &= ~IDLE_UNIT;
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o unload\n", unit);
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
return mt_error(uptr, sim_tape_detach(uptr), dptr);
|
||
|
||
case READ:
|
||
case READ_NOEOR:
|
||
if (uptr->CNTRL & MT_STOP) {
|
||
if ((uptr->CNTRL & MT_LASTWD) == 0)
|
||
mt_status |= RLC_ERR;
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
df10_writecw(&mt_df10);
|
||
return mt_error(uptr, MTSE_OK, dptr);
|
||
}
|
||
if (BUF_EMPTY(uptr)) {
|
||
uptr->CNTRL |= MT_MOTION;
|
||
mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOF_FLAG|EOT_FLAG|PARITY_ERR|CHAR_COUNT);
|
||
if ((r = sim_tape_rdrecf(uptr, &mt_buffer[0], &reclen,
|
||
BUFFSIZE)) != MTSE_OK) {
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o read error %d\n", unit, r);
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
if (dptr->flags & MTDF_TYPEB && r == MTSE_TMK) {
|
||
df10_write(&mt_df10);
|
||
df10_writecw(&mt_df10);
|
||
}
|
||
return mt_error(uptr, r, dptr);
|
||
}
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o read %d\n", unit, reclen);
|
||
uptr->hwmark = reclen;
|
||
uptr->BPOS = 0;
|
||
}
|
||
if (uptr->CNTRL & MT_BRFUL) {
|
||
mt_status |= DATA_LATE;
|
||
sim_debug(DEBUG_EXP, dptr, "data late\n");
|
||
break;
|
||
}
|
||
if ((uint32)uptr->BPOS < uptr->hwmark) {
|
||
if (uptr->flags & MTUF_7TRK) {
|
||
cc = 6 * (5 - uptr->CPOS);
|
||
ch = mt_buffer[uptr->BPOS];
|
||
if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^ (ch & 0x40) ^
|
||
parity_table[ch & 0x3f]) != 0) {
|
||
mt_status |= PARITY_ERR;
|
||
}
|
||
mt_df10.buf |= (uint64)(ch & 0x3f) << cc;
|
||
} else {
|
||
if ((uptr->CNTRL & ODD_PARITY) == 0)
|
||
mt_status |= PARITY_ERR;
|
||
cc = (8 * (3 - uptr->CPOS)) + 4;
|
||
ch = mt_buffer[uptr->BPOS];
|
||
if (cc < 0)
|
||
mt_df10.buf |= (uint64)(ch & 0x3f);
|
||
else
|
||
mt_df10.buf |= (uint64)(ch & 0xff) << cc;
|
||
}
|
||
uptr->BPOS++;
|
||
uptr->CPOS++;
|
||
if ((uint32)(uptr->BPOS + cc_max) >= uptr->hwmark)
|
||
uptr->CNTRL |= MT_LASTWD;
|
||
mt_status &= ~CHAR_COUNT;
|
||
mt_status |= (uint64)(uptr->CPOS) << 18;
|
||
if (uptr->CPOS == cc_max)
|
||
mt_df10_write(dptr, uptr);
|
||
} else {
|
||
if ((cmd & 010) == 0) {
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
df10_writecw(&mt_df10);
|
||
uptr->CNTRL &= ~(MT_MOTION|MT_BUSY);
|
||
return mt_error(uptr, MTSE_OK, dptr);
|
||
} else {
|
||
CLR_BUF(uptr);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case CMP:
|
||
case CMP_NOEOR:
|
||
if (uptr->CNTRL & MT_STOP) {
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
df10_writecw(&mt_df10);
|
||
return mt_error(uptr, MTSE_OK, dptr);
|
||
}
|
||
if (BUF_EMPTY(uptr)) {
|
||
uptr->CNTRL |= MT_MOTION;
|
||
mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOF_FLAG|EOT_FLAG|PARITY_ERR|CHAR_COUNT);
|
||
if ((r = sim_tape_rdrecf(uptr, &mt_buffer[0], &reclen,
|
||
BUFFSIZE)) != MTSE_OK) {
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o read error %d\n", unit, r);
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
if (dptr->flags & MTDF_TYPEB && r == MTSE_TMK)
|
||
mt_df10_read(dptr, uptr);
|
||
return mt_error(uptr, r, dptr);
|
||
}
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o compare %d\n", unit, reclen);
|
||
uptr->hwmark = reclen;
|
||
uptr->BPOS = 0;
|
||
if ((dptr->flags & MTDF_TYPEB) == 0) {
|
||
mt_status |= DATA_REQUEST;
|
||
set_interrupt_mpx(MT_DEVNUM, mt_pia, mt_mpx_lvl);
|
||
}
|
||
break;
|
||
}
|
||
if (uptr->BPOS >= (int32)uptr->hwmark) {
|
||
if (cmd == CMP_NOEOR) {
|
||
CLR_BUF(uptr);
|
||
uptr->CNTRL &= ~MT_LASTWD;
|
||
} else {
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
df10_writecw(&mt_df10);
|
||
uptr->CNTRL &= ~(MT_MOTION|MT_BUSY);
|
||
return mt_error(uptr, MTSE_INVRL, dptr);
|
||
}
|
||
} else if ((uptr->CNTRL & MT_BRFUL) == 0) {
|
||
/* Write out first character. */
|
||
mt_df10_read(dptr, uptr);
|
||
}
|
||
if ((uptr->CNTRL & MT_BRFUL) != 0) {
|
||
if (uptr->flags & MTUF_7TRK) {
|
||
ch = mt_buffer[uptr->BPOS];
|
||
if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^ (ch & 0x40) ^
|
||
parity_table[ch & 0x3f]) != 0) {
|
||
mt_status |= PARITY_ERR;
|
||
}
|
||
mt_buffer[uptr->BPOS] &= 0x3f;
|
||
cc = 6 * (5 - uptr->CPOS);
|
||
ch = (mt_df10.buf >> cc) & 0x3f;
|
||
} else {
|
||
if ((uptr->CNTRL & ODD_PARITY) == 0)
|
||
mt_status |= PARITY_ERR;
|
||
/* Write next char out */
|
||
cc = (8 * (3 - uptr->CPOS)) + 4;
|
||
if (cc < 0)
|
||
ch = mt_df10.buf & 0x3f;
|
||
else
|
||
ch = (mt_df10.buf >> cc) & 0xff;
|
||
}
|
||
if (mt_buffer[uptr->BPOS] != ch) {
|
||
mt_status |= READ_CMP;
|
||
if ((dptr->flags & MTDF_TYPEB) == 0) {
|
||
uptr->BPOS = uptr->hwmark;
|
||
mt_status &= ~CHAR_COUNT;
|
||
mt_status |= (uint64)(uptr->CPOS+1) << 18;
|
||
uptr->CNTRL &= ~(MT_MOTION|MT_BUSY);
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
df10_writecw(&mt_df10);
|
||
return mt_error(uptr, MTSE_OK, dptr);
|
||
}
|
||
}
|
||
uptr->BPOS++;
|
||
uptr->CPOS++;
|
||
if (uptr->BPOS == uptr->hwmark)
|
||
uptr->CNTRL |= MT_LASTWD;
|
||
if (uptr->CPOS == cc_max) {
|
||
uptr->CPOS = 0;
|
||
uptr->CNTRL &= ~MT_BRFUL;
|
||
}
|
||
mt_status &= ~CHAR_COUNT;
|
||
mt_status |= (uint64)(uptr->CPOS+1) << 18;
|
||
}
|
||
break;
|
||
|
||
case WRITE:
|
||
case WRITE_LONG:
|
||
/* Writing and Type A, request first data word */
|
||
if (BUF_EMPTY(uptr)) {
|
||
uptr->CNTRL |= MT_MOTION;
|
||
mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOF_FLAG|EOT_FLAG|PARITY_ERR|CHAR_COUNT);
|
||
sim_debug(DEBUG_EXP, dptr, "MT%o Init write\n", unit);
|
||
uptr->hwmark = 0;
|
||
uptr->CPOS = 0;
|
||
uptr->BPOS = 0;
|
||
mt_status |= (uint64)(1) << 18;
|
||
if ((dptr->flags & MTDF_TYPEB) == 0) {
|
||
mt_status |= DATA_REQUEST;
|
||
set_interrupt_mpx(MT_DEVNUM, mt_pia, mt_mpx_lvl);
|
||
}
|
||
break;
|
||
}
|
||
/* Force error if we exceed buffer size */
|
||
if (uptr->BPOS >= BUFFSIZE)
|
||
return mt_error(uptr, MTSE_RECE, dptr);
|
||
if ((uptr->CNTRL & MT_BRFUL) == 0)
|
||
mt_df10_read(dptr, uptr);
|
||
if ((uptr->CNTRL & MT_BRFUL) != 0) {
|
||
if (uptr->flags & MTUF_7TRK) {
|
||
cc = 6 * (5 - uptr->CPOS);
|
||
ch = (mt_df10.buf >> cc) & 0x3f;
|
||
ch |= ((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^
|
||
parity_table[ch & 0x3f];
|
||
} else {
|
||
/* Write next char out */
|
||
cc = (8 * (3 - uptr->CPOS)) + 4;
|
||
if (cc < 0)
|
||
ch = mt_df10.buf & 0x3f;
|
||
else
|
||
ch = (mt_df10.buf >> cc) & 0xff;
|
||
}
|
||
mt_buffer[uptr->BPOS] = ch;
|
||
uptr->BPOS++;
|
||
uptr->hwmark = uptr->BPOS;
|
||
uptr->CPOS++;
|
||
if (uptr->CPOS == cc_max) {
|
||
uptr->CPOS = 0;
|
||
uptr->CNTRL &= ~MT_BRFUL;
|
||
}
|
||
mt_status &= ~CHAR_COUNT;
|
||
mt_status |= (uint64)(uptr->CPOS+1) << 18;
|
||
}
|
||
if ((uptr->CNTRL & (MT_STOP|MT_BRFUL|MT_BUFFUL)) == MT_STOP) {
|
||
/* Write out the block */
|
||
wr_eor = 1;
|
||
reclen = uptr->hwmark;
|
||
mt_status &= ~(BOT_FLAG|EOF_FLAG|EOT_FLAG|CHAR_COUNT);
|
||
r = sim_tape_wrrecf(uptr, &mt_buffer[0], reclen);
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o Write %d\n", unit, reclen);
|
||
uptr->BPOS = 0;
|
||
uptr->hwmark = 0;
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
df10_writecw(&mt_df10);
|
||
return mt_error(uptr, r, dptr); /* Record errors */
|
||
}
|
||
break;
|
||
|
||
case WTM:
|
||
if ((uptr->flags & MTUF_WLK) != 0)
|
||
return mt_error(uptr, MTSE_WRP, dptr);
|
||
if (uptr->CPOS == 0) {
|
||
mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOT_FLAG);
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o WTM\n", unit);
|
||
r = sim_tape_wrtmk(uptr);
|
||
if (r != MTSE_OK)
|
||
return mt_error(uptr, r, dptr);
|
||
uptr->CPOS++;
|
||
wr_eor = 1;
|
||
} else {
|
||
wr_eor = 0;
|
||
mt_status |= EOF_FLAG;
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
return mt_error(uptr, MTSE_OK, dptr);
|
||
}
|
||
break;
|
||
|
||
case ERG:
|
||
if ((uptr->flags & MTUF_WLK) != 0)
|
||
return mt_error(uptr, MTSE_WRP, dptr);
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOT_FLAG);
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o ERG\n", unit);
|
||
return mt_error(uptr, sim_tape_wrgap(uptr, 35), dptr);
|
||
|
||
case SPC_REV_EOF:
|
||
case SPC_EOF:
|
||
case SPC_REV:
|
||
case SPC_FWD:
|
||
sim_debug(DEBUG_DETAIL, dptr, "MT%o space %o\n", unit, cmd);
|
||
uptr->CNTRL |= MT_MOTION;
|
||
mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOT_FLAG);
|
||
/* Always skip at least one record */
|
||
if ((cmd & 7) == SPC_FWD)
|
||
r = sim_tape_sprecf(uptr, &reclen);
|
||
else
|
||
r = sim_tape_sprecr(uptr, &reclen);
|
||
switch (r) {
|
||
case MTSE_OK: /* no error */
|
||
break;
|
||
case MTSE_TMK: /* tape mark */
|
||
case MTSE_BOT: /* beginning of tape */
|
||
case MTSE_EOM: /* end of medium */
|
||
/* Stop motion if we recieve any of these */
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
mt_status &= ~DATA_REQUEST;
|
||
clr_interrupt(MT_DEVNUM);
|
||
return mt_error(uptr, r, dptr);
|
||
}
|
||
/* Clear tape mark, command, idle since we will need to change dir */
|
||
if ((cmd & 010) == 0) {
|
||
mt_df10_read(dptr, uptr);
|
||
if ((uptr->CNTRL & MT_BRFUL) == 0) {
|
||
mt_status &= ~DATA_LATE;
|
||
uptr->CNTRL &= ~MT_MOTION;
|
||
if (dptr->flags & MTDF_TYPEB)
|
||
df10_writecw(&mt_df10);
|
||
return mt_error(uptr, MTSE_OK, dptr);
|
||
}
|
||
uptr->CNTRL &= ~MT_BRFUL;
|
||
}
|
||
uptr->hwmark = 0;
|
||
sim_activate(uptr, 5000);
|
||
return SCPE_OK;
|
||
}
|
||
sim_activate(uptr, 420);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
void mt_read_word(UNIT *uptr) {
|
||
int i, cc, ch, cc_max;
|
||
|
||
mt_df10.buf = 0;
|
||
cc_max = (uptr->flags & MTUF_7TRK) ? 5: 4;
|
||
for(i = 0; i <= cc_max; i++) {
|
||
ch = mt_buffer[uptr->BPOS];
|
||
if (uptr->flags & MTUF_7TRK) {
|
||
cc = 6 * (5 - i);
|
||
mt_df10.buf |= (uint64)(ch & 0x3f) << cc;
|
||
} else {
|
||
cc = (8 * (3 - i)) + 4;
|
||
if (cc < 0)
|
||
mt_df10.buf |= (uint64)(ch & 0x3f);
|
||
else
|
||
mt_df10.buf |= (uint64)(ch & 0xff) << cc;
|
||
}
|
||
uptr->BPOS++;
|
||
}
|
||
}
|
||
|
||
/* Boot from given device */
|
||
t_stat
|
||
mt_boot(int32 unit_num, DEVICE * dptr)
|
||
{
|
||
UNIT *uptr = &dptr->units[unit_num];
|
||
t_mtrlnt reclen;
|
||
t_stat r;
|
||
int wc, addr;
|
||
|
||
if ((uptr->flags & UNIT_ATT) == 0)
|
||
return SCPE_UNATT; /* attached? */
|
||
|
||
r = sim_tape_rewind(uptr);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
uptr->CNTRL = 022200; /* Read 800 BPI, Core */
|
||
r = sim_tape_rdrecf(uptr, &mt_buffer[0], &reclen, BUFFSIZE);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
uptr->BPOS = 0;
|
||
uptr->hwmark = reclen;
|
||
|
||
mt_read_word(uptr);
|
||
wc = (mt_df10.buf >> 18) & RMASK;
|
||
addr = mt_df10.buf & RMASK;
|
||
while (wc != 0) {
|
||
wc = (wc + 1) & RMASK;
|
||
addr = (addr + 1) & RMASK;
|
||
if ((uint32)uptr->BPOS >= uptr->hwmark) {
|
||
r = sim_tape_rdrecf(uptr, &mt_buffer[0], &reclen, BUFFSIZE);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
uptr->BPOS = 0;
|
||
uptr->hwmark = reclen;
|
||
}
|
||
mt_read_word(uptr);
|
||
if (addr < 020)
|
||
FM[addr] = mt_df10.buf;
|
||
else
|
||
M[addr] = mt_df10.buf;
|
||
}
|
||
if (addr < 020)
|
||
FM[addr] = mt_df10.buf;
|
||
else
|
||
M[addr] = mt_df10.buf;
|
||
|
||
PC = mt_df10.buf & RMASK;
|
||
/* If not at end of record and TMA continue record read */
|
||
if ((uint32)uptr->BPOS < uptr->hwmark) {
|
||
uptr->CNTRL |= MT_MOTION|MT_BUSY;
|
||
uptr->CNTRL &= ~(MT_BRFUL|MT_BUFFUL);
|
||
mt_hold_reg = mt_df10.buf = 0;
|
||
if ((dptr->flags & MTDF_TYPEB) != 0) {
|
||
mt_df10.cia = 020;
|
||
mt_df10.cda = addr;
|
||
}
|
||
hri_mode = 1;
|
||
sim_activate(uptr, 300);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat mt_set_mta (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
DEVICE *dptr;
|
||
dptr = find_dev_from_unit (uptr);
|
||
if (dptr == NULL)
|
||
return SCPE_IERR;
|
||
dptr->flags &= ~MTDF_TYPEB;
|
||
if (*cptr == 'B')
|
||
dptr->flags |= val;
|
||
else if (*cptr != 'A')
|
||
return SCPE_ARG;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat mt_show_mta (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
DEVICE *dptr;
|
||
|
||
if (uptr == NULL)
|
||
return SCPE_IERR;
|
||
|
||
dptr = find_dev_from_unit(uptr);
|
||
if (dptr == NULL)
|
||
return SCPE_IERR;
|
||
if (dptr->flags & val) {
|
||
fprintf (st, "TM10B");
|
||
} else {
|
||
fprintf (st, "TM10A");
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
#if MPX_DEV
|
||
/* set MPX level number */
|
||
t_stat mt_set_mpx (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
int32 mpx;
|
||
t_stat r;
|
||
|
||
if (cptr == NULL)
|
||
return SCPE_ARG;
|
||
mpx = (int32) get_uint (cptr, 8, 8, &r);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
mt_mpx_lvl = mpx;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat mt_show_mpx (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
if (uptr == NULL)
|
||
return SCPE_IERR;
|
||
|
||
fprintf (st, "MPX=%o", mt_mpx_lvl);
|
||
return SCPE_OK;
|
||
}
|
||
#endif
|
||
|
||
t_stat
|
||
mt_reset(DEVICE * dptr)
|
||
{
|
||
int i;
|
||
for (i = 0 ; i < 8; i++) {
|
||
UNIT *uptr = &mt_unit[i];
|
||
|
||
if (MT_DENS(uptr->dynflags) == MT_DENS_NONE)
|
||
uptr->dynflags = MT_200_VALID | MT_556_VALID;
|
||
uptr->CNTRL = 0;
|
||
sim_cancel(uptr);
|
||
}
|
||
mt_df10.devnum = mt_dib.dev_num;
|
||
mt_df10.nxmerr = 24;
|
||
mt_df10.ccw_comp = 25;
|
||
mt_pia = 0;
|
||
mt_status = 0;
|
||
mt_sel_unit = 0;
|
||
mt_next_unit = 0;
|
||
mt_hold_reg = 0;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
mt_attach(UNIT * uptr, CONST char *file)
|
||
{
|
||
return sim_tape_attach_ex(uptr, file, 0, 0);
|
||
}
|
||
|
||
t_stat
|
||
mt_detach(UNIT * uptr)
|
||
{
|
||
uptr->CPOS = 0;
|
||
return sim_tape_detach(uptr);
|
||
}
|
||
|
||
t_stat mt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "MT10 Magnetic Tape\n\n");
|
||
fprintf (st, "The MT10 tape controller can be set to either type A or B\n");
|
||
fprintf (st, "The A model lacks a DF10, so all I/O must be polled mode. To set the\n");
|
||
fprintf (st, "tape controller to a B model with DF10 do:\n\n");
|
||
fprintf (st, " sim> SET %s TYPE=B \n", dptr->name);
|
||
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. The\n");
|
||
fprintf (st, "bad block option can be used only when a unit is attached to a file.\n");
|
||
fprintf (st, "The MT10 does support the BOOT command.\n");
|
||
sim_tape_attach_help (st, dptr, uptr, flag, cptr);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *mt_description (DEVICE *dptr)
|
||
{
|
||
return "MT10 magnetic tape controller" ;
|
||
}
|
||
|
||
#endif
|