1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-04-25 19:51:57 +00:00
Files
rcornwell.sims/PDP10/ka10_mt.c
Mark Pizzolato 00247993d8 KA10, KI10: Compiler warning cleanup
- Removed unreferenced variables and labels
- Cast values to avoid size and/or signed/unsigned issues where needed
- Removed redundant DEVICE declarations
- Fixed load_rim to handle EOF cases correctly
2016-07-11 13:05:41 -07:00

825 lines
28 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ka10_mt.c: TM10A/B Magnetic tape controller
Copyright (c) 2016, 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 "ka10_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 MTDF_BUFFUL (2 << DEV_V_UF)
#define MTDF_STOP (4 << DEV_V_UF)
#define MTDF_MOTION (8 << DEV_V_UF)
#define MTDF_V_UNIT (DEV_V_UF + 4)
#define MTDF_UNIT_MSK (7 << MTDF_V_UNIT)
#define BUFFSIZE (32 * 1024)
#define UNIT_MT(x) UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | \
UNIT_S_CHAN(x)
#define MTUF_ONLINE (1 << UNIT_V_LOCAL)
#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 0000000001
#define NEXT_UNIT 0000000002
#define SEVEN_CHAN 0000000004
#define WRITE_LOCK 0000000010
#define CHAN_ERR 0000000020
#define IDLE_UNIT 0000000040
#define JOB_DONE 0000000100
#define BAD_TAPE 0000000200
#define DATA_LATE 0000000400
#define RLC_ERR 0000001000
#define READ_CMP 0000002000
#define EOT_FLAG 0000004000
#define EOF_FLAG 0000010000
#define PARITY_ERR 0000020000
#define ILL_OPR 0000040000
#define BOT_FLAG 0000100000
#define REW_FLAG 0000200000
#define TRAN_HUNG 0000400000
#define CHAR_COUNT 0017000000
#define WT_CW_DONE 0020000000
#define DATA_PARITY 0040000000
#define NXM_ERR 0100000000
#define CW_PAR_ERR 0200000000
#define B22_FLAG 01000000000
#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 NXT_UNIT_ENAB 000000400 /* 8 */
#define FUNCTION 000017000 /* 9 */
#define CORE_DUMP 000020000 /*13 */
#define ODD_PARITY 000040000 /*14 */
#define UNIT_NUM 000700000 /*15 */
#define NXT_UNIT 007000000 /*18 */
#define MT_DEVNUM 0340
/* in u3 is device address */
/* in u4 is current buffer position */
/* in u5 */
t_stat mt_devio(uint32 dev, uint64 *data);
t_stat mt_srv(UNIT *);
t_stat mt_boot(int32, DEVICE *);
void mt_ini(UNIT *, t_bool);
t_stat set_mta (UNIT *uptr, int32 val, CONST char *cptr, void *desc) ;
t_stat show_mta (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
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);
uint32 mt_cia;
uint32 mt_ccw;
uint32 mt_wcr;
uint32 mt_cda;
uint32 status;
uint64 hold_reg;
uint64 buf_reg;
int cc;
/* One buffer per channel */
uint8 mt_buffer[BUFFSIZE];
UNIT mt_unit[] = {
/* Controller 1 */
{UDATA(&mt_srv, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, 0)}, /* 0 */
{UDATA(&mt_srv, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, 0)}, /* 1 */
{UDATA(&mt_srv, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, 0)}, /* 2 */
{UDATA(&mt_srv, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, 0)}, /* 3 */
{UDATA(&mt_srv, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, 0)}, /* 4 */
{UDATA(&mt_srv, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, 0)}, /* 5 */
{UDATA(&mt_srv, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, 0)}, /* 6 */
{UDATA(&mt_srv, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, 0)}, /* 7 */
};
DIB mt_dib = {MT_DEVNUM, 2, &mt_devio};
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", &set_mta, &show_mta},
{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}
};
DEVICE mt_dev = {
"MTA", mt_unit, NULL, mt_mod,
8, 8, 15, 1, 8, 8,
NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach,
&mt_dib, DEV_DISABLE | DEV_DEBUG, 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;
int unit = (dptr->flags >> MTDF_V_UNIT) & 7;
UNIT *uptr = &mt_unit[unit];
switch(dev & 07) {
case CONI:
res = (uptr->u3 & 077777);
res |= unit << 15;
res |= unit << 18;
if (dptr->flags & MTDF_TYPEB)
res |= 7; /* Force DATA PIA to 7 on type B */
*data = res;
sim_debug(DEBUG_CONI, dptr, "MT CONI %03o status %06o %o\n",
dev, (uint32)res, unit);
break;
case CONO:
unit = (*data >> 15) & 07;
uptr = &mt_unit[unit];
uptr->u3 = (int32)*data;
CLR_BUF(uptr);
dptr->flags &= ~(MTDF_BUFFUL|MTDF_STOP|MTDF_UNIT_MSK);
dptr->flags |= (unit << MTDF_V_UNIT);
sim_debug(DEBUG_CONO, dptr, "MT CONO %03o start %o %o %o\n",
dev, uptr->u3, unit, (uptr->u3 & FUNCTION) >> 9);
if (uptr->u3 & 000007000)
dptr->flags |= MTDF_MOTION;
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|CHAR_COUNT|WT_CW_DONE| \
DATA_PARITY|NXM_ERR|CW_PAR_ERR);
clr_interrupt(MT_DEVNUM + 4);
sim_activate(uptr, 1000);
buf_reg = 0;
mt_ccw = mt_cia;
mt_wcr = 0;
break;
case DATAI:
/* Xfer data */
dptr->flags &= ~MTDF_BUFFUL;
status &= ~DATA_REQUEST;
if (status & JOB_DONE)
buf_reg = 0;
clr_interrupt(MT_DEVNUM);
*data = hold_reg;
sim_debug(DEBUG_DATA, dptr, "MT %03o >%012llo\n", dev, hold_reg);
break;
case DATAO:
/* Xfer data */
hold_reg = *data;
dptr->flags |= MTDF_BUFFUL;
status &= ~DATA_REQUEST;
clr_interrupt(MT_DEVNUM);
if (status & JOB_DONE)
buf_reg = 0;
sim_debug(DEBUG_DATA, dptr, "MT %03o <%012llo\n", dev, hold_reg);
break;
case CONI|04:
res = status;
if ((dptr->flags & MTDF_MOTION) == 0)
res |= IDLE_UNIT;
#if KI10_22BIT
res |= B22_FLAG;
#endif
*data = res;
sim_debug(DEBUG_CONI, dptr, "MT CONI %03o status2 %06o %o\n",
dev, (uint32)res, unit);
break;
case CONO|04:
if (*data & 1) {
dptr->flags |= MTDF_STOP;
if (status & DATA_REQUEST) {
status &= ~DATA_REQUEST;
clr_interrupt(MT_DEVNUM);
}
}
if (*data & 2) {
hold_reg = buf_reg;
buf_reg = 0;
}
sim_debug(DEBUG_CONO, dptr, "MT CONO %03o control %o %o %o\n",
dev, uptr->u3, unit, (uptr->u3 & FUNCTION) >> 9);
break;
case DATAI|04:
break;
case DATAO|04:
/* Set Initial CCW */
mt_cia = *data & 0776;
sim_debug(DEBUG_DATAIO, dptr, "MT DATAO %03o %012llo\n", dev, *data);
break;
}
return SCPE_OK;
}
void mt_finish_op(DEVICE *dptr, int flags) {
status |= flags|WT_CW_DONE;
M[mt_cia|1] = (((uint64)(mt_ccw)) << CSHIFT) | mt_cda;
dptr->flags |= MTDF_STOP;
}
int mt_df10_fetch(DEVICE *dptr, int addr) {
uint64 data;
data = M[mt_ccw];
while((data & (WMASK & CSHIFT)) == 0) {
if ((data & AMASK) == 0) {
mt_finish_op(dptr,0);
return 0;
}
mt_ccw = data & AMASK;
if (mt_ccw > MEMSIZE) {
mt_finish_op(dptr, NXM_ERR);
return 0;
}
data = M[mt_ccw];
}
mt_wcr = (data >> CSHIFT) &WMASK;
mt_cda = data &AMASK;
mt_ccw = (mt_ccw + 1) & AMASK;
return 1;
}
int mt_df10_read(DEVICE *dptr, UNIT *uptr) {
if (dptr->flags & MTDF_TYPEB) {
if (mt_wcr == 0) {
if(!mt_df10_fetch(dptr, 0))
return 0;
}
mt_wcr = (mt_wcr + 1) & WMASK;
if (mt_cda != 0) {
if (mt_cda > MEMSIZE) {
mt_finish_op(dptr, NXM_ERR);
return 0;
}
mt_cda = (mt_cda + 1) & AMASK;
buf_reg = M[mt_cda];
} else {
buf_reg = 0;
}
dptr->flags &= ~MTDF_BUFFUL;
if (mt_wcr == 0) {
mt_df10_fetch(dptr, mt_ccw);
}
} else {
if (dptr->flags & MTDF_BUFFUL) {
buf_reg = hold_reg;
dptr->flags &= ~MTDF_BUFFUL;
if ((dptr->flags & MTDF_STOP) == 0) {
status |= DATA_REQUEST;
set_interrupt(MT_DEVNUM, uptr->u3 & DATA_PIA);
}
} else {
if ((dptr->flags & MTDF_STOP) == 0) {
status |= DATA_LATE;
dptr->flags |= MTDF_STOP;
}
return 0;
}
}
return 1;
}
int mt_df10_write(DEVICE *dptr, UNIT *uptr) {
if (dptr->flags & MTDF_TYPEB) {
if (mt_wcr == 0) {
if(!mt_df10_fetch(dptr, 0))
return 0;
}
mt_wcr = (mt_wcr + 1) & WMASK;
if (mt_cda != 0) {
if (mt_cda > MEMSIZE) {
mt_finish_op(dptr, NXM_ERR);
return 0;
}
mt_cda = (mt_cda + 1) & AMASK;
M[mt_cda] = hold_reg;
} else {
buf_reg = 0;
}
dptr->flags &= ~MTDF_BUFFUL;
if (mt_wcr == 0) {
mt_df10_fetch(dptr, mt_ccw);
}
} else {
if (dptr->flags & MTDF_BUFFUL) {
status |= DATA_LATE;
dptr->flags |= MTDF_STOP;
return 0;
} else {
status |= DATA_REQUEST;
dptr->flags |= MTDF_BUFFUL;
set_interrupt(MT_DEVNUM, uptr->u3 & DATA_PIA);
}
}
return 1;
}
/* Map simH errors into machine errors */
t_stat mt_error(UNIT * uptr, t_stat r, DEVICE * dptr)
{
switch (r) {
case MTSE_OK: /* no error */
status |= JOB_DONE|IDLE_UNIT;
set_interrupt(MT_DEVNUM+4, (uptr->u3 & FLAG_PIA) >> 3);
return SCPE_OK;
case MTSE_TMK: /* tape mark */
status |= EOF_FLAG;
break;
case MTSE_WRP: /* write protected */
status |= WRITE_LOCK;
break;
case MTSE_UNATT: /* unattached */
status |= TRAN_HUNG;
break;
case MTSE_IOERR: /* IO error */
case MTSE_FMT: /* invalid format */
status |= ILL_OPR;
break;
case MTSE_RECE: /* error in record */
status |= BAD_TAPE;
break;
case MTSE_BOT: /* beginning of tape */
status |= BOT_FLAG;
break;
case MTSE_INVRL: /* invalid rec lnt */
status |= RLC_ERR;
break;
case MTSE_EOM: /* end of medium */
status |= EOT_FLAG;
break;
}
status |= JOB_DONE|IDLE_UNIT;
sim_debug(DEBUG_EXP, dptr, "Setting status %o\n", status);
set_interrupt(MT_DEVNUM+4, (uptr->u3 & FLAG_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->u3 & FUNCTION) >> 9;
t_mtrlnt reclen;
t_stat r = SCPE_ARG; /* Force error if not set */
switch(cmd) {
case NOP_IDLE:
sim_debug(DEBUG_DETAIL, dptr, "MT%o Idle\n", unit);
dptr->flags &= ~MTDF_MOTION;
if (status & NEXT_UNIT)
set_interrupt(MT_DEVNUM+4, (uptr->u3 & FLAG_PIA) >> 3);
return mt_error(uptr, MTSE_OK, dptr);
case NOP_CLR:
sim_debug(DEBUG_DETAIL, dptr, "MT%o nop\n", unit);
return SCPE_OK;
case REWIND:
sim_debug(DEBUG_DETAIL, dptr, "MT%o rewind\n", unit);
dptr->flags &= ~MTDF_MOTION;
status |= BOT_FLAG;
if (status & NEXT_UNIT)
set_interrupt(MT_DEVNUM+4, (uptr->u3 & FLAG_PIA) >> 3);
return mt_error(uptr, sim_tape_rewind(uptr), dptr);
case UNLOAD:
sim_debug(DEBUG_DETAIL, dptr, "MT%o unload\n", unit);
dptr->flags &= ~MTDF_MOTION;
if (status & NEXT_UNIT)
set_interrupt(MT_DEVNUM+4, (uptr->u3 & FLAG_PIA) >> 3);
return mt_error(uptr, sim_tape_detach(uptr), dptr);
case READ:
case READ_NOEOR:
case CMP:
case CMP_NOEOR:
if (BUF_EMPTY(uptr)) {
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr);
if ((uptr->flags & UNIT_ATT) == 0)
return mt_error(uptr, MTSE_UNATT, dptr); /* attached? */
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr); /* attached? */
}
if (BUF_EMPTY(uptr)) {
if (dptr->flags & MTDF_STOP) {
return mt_error(uptr, MTSE_OK, dptr);
}
status &= ~(BOT_FLAG|EOF_FLAG|EOT_FLAG);
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);
return mt_error(uptr, r, dptr);
}
sim_debug(DEBUG_DETAIL, dptr, "MT%o read %d\n", unit, reclen);
uptr->hwmark = reclen;
uptr->u6 = 0;
uptr->u5 = 0;
}
if ((uint32)uptr->u6 < uptr->hwmark) {
int cc = (8 * (3 - uptr->u5)) + 4;
uint8 ch;
if ((cmd & 07) == CMP && uptr->u5 == 0) {
buf_reg = 0;
if (!mt_df10_read(dptr, uptr)) {
dptr->flags |= MTDF_STOP;
return mt_error(uptr, MTSE_INVRL, dptr);
}
}
if ((cmd & 07) == CMP) {
if (cc < 0)
ch = buf_reg & 0x3f;
else
ch = (buf_reg >> cc) & 0xff;
if (ch != mt_buffer[uptr->u6]) {
status |= READ_CMP;
mt_error(uptr, MTSE_OK, dptr);
}
} else {
ch = mt_buffer[uptr->u6];
if (cc < 0)
buf_reg |= (uint64)(ch & 0x3f);
else
buf_reg |= (uint64)(ch & 0xff) << cc;
}
uptr->u6++;
uptr->u5++;
status &= ~CHAR_COUNT;
status |= (uint64)(uptr->u5) << 18;
if (uptr->u5 == (4 + ((uptr->u3 & CORE_DUMP) != 0))) {
uptr->u5 = 0;
if ((cmd & 7) != CMP) {
hold_reg = buf_reg;
buf_reg = 0;
mt_df10_write(dptr, uptr);
}
if (dptr->flags & MTDF_STOP) {
return mt_error(uptr, MTSE_INVRL, dptr);
}
}
} else {
if ((cmd & 010) == 0) {
dptr->flags &= ~MTDF_MOTION;
if (status & NEXT_UNIT)
set_interrupt(MT_DEVNUM+4, (uptr->u3 & FLAG_PIA) >> 3);
return mt_error(uptr, MTSE_OK, dptr);
} else {
CLR_BUF(uptr);
}
}
break;
case WRITE:
case WRITE_LONG:
if (BUF_EMPTY(uptr)) {
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr);
if ((uptr->flags & UNIT_ATT) == 0)
return mt_error(uptr, MTSE_UNATT, dptr); /* attached? */
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr); /* attached? */
}
if (BUF_EMPTY(uptr) && (dptr->flags & MTDF_TYPEB) == 0) {
sim_debug(DEBUG_EXP, dptr, "MT%o Init write\n", unit);
status |= DATA_REQUEST;
dptr->flags &= ~(MTDF_BUFFUL);
uptr->hwmark = 0;
uptr->u5 = 0;
uptr->u6 = 0;
set_interrupt(MT_DEVNUM, uptr->u3 & DATA_PIA);
break;
}
if (uptr->u5 != 0) {
/* Write next char out */
int cc = (8 * (3 - uptr->u5)) + 4;
uint8 ch;
if (cc < 0)
ch = buf_reg & 0x3f;
else
ch = (buf_reg >> cc) & 0xff;
mt_buffer[uptr->u6] = ch;
uptr->u6++;
uptr->hwmark = uptr->u6;
uptr->u5++;
if (uptr->u5 == (4 + ((uptr->u3 & CORE_DUMP) != 0)))
uptr->u5 = 0;
status &= ~CHAR_COUNT;
status |= (uint64)(uptr->u5) << 18;
} else if (dptr->flags & MTDF_STOP && (dptr->flags & MTDF_BUFFUL) == 0) {
/* Write out the block */
reclen = uptr->hwmark;
status &= ~(BOT_FLAG|EOF_FLAG|EOT_FLAG);
r = sim_tape_wrrecf(uptr, &mt_buffer[0], reclen);
sim_debug(DEBUG_DETAIL, dptr, "MT%o Write %d\n", unit, reclen);
uptr->u6 = 0;
uptr->hwmark = 0;
dptr->flags &= ~MTDF_MOTION;
return mt_error(uptr, r, dptr); /* Record errors */
} else {
/* Write out first character. */
if (mt_df10_read(dptr, uptr)) {
uint8 ch;
ch = (buf_reg >> 28) & 0xff;
mt_buffer[uptr->u6] = ch;
uptr->u6++;
uptr->hwmark = uptr->u6;
uptr->u5++;
status &= ~CHAR_COUNT;
status |= (uint64)(uptr->u5) << 18;
} else {
dptr->flags |= MTDF_STOP;
}
}
break;
case WTM:
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr);
if ((uptr->flags & UNIT_ATT) == 0)
return mt_error(uptr, MTSE_UNATT, dptr); /* attached? */
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr); /* attached? */
dptr->flags &= ~MTDF_MOTION;
status &= ~(BOT_FLAG|EOT_FLAG);
sim_debug(DEBUG_DETAIL, dptr, "MT%o WTM\n", unit);
return mt_error(uptr, sim_tape_wrtmk(uptr), dptr);
case ERG:
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr);
if ((uptr->flags & UNIT_ATT) == 0)
return mt_error(uptr, MTSE_UNATT, dptr); /* attached? */
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr); /* attached? */
dptr->flags &= ~MTDF_MOTION;
status &= ~(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:
if (BUF_EMPTY(uptr)) {
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr);
if ((uptr->flags & UNIT_ATT) == 0)
return mt_error(uptr, MTSE_UNATT, dptr); /* attached? */
if ((uptr->u3 & DENS_MSK) != DENS_800)
return mt_error(uptr, MTSE_FMT, dptr); /* attached? */
}
sim_debug(DEBUG_DETAIL, dptr, "MT%o space %o\n", unit, cmd);
/* Clear tape mark, command, idle since we will need to change dir */
if ((cmd & 010) == 0) {
if (BUF_EMPTY(uptr)) {
mt_df10_read(dptr, uptr);
status &= ~DATA_LATE;
uptr->hwmark = 0;
} else {
if (!mt_df10_read(dptr, uptr)) {
status &= ~DATA_LATE;
dptr->flags |= MTDF_MOTION;
return mt_error(uptr, MTSE_OK, dptr);
}
}
}
status &= ~(BOT_FLAG|EOT_FLAG);
if ((cmd & 7) == SPC_FWD)
r = sim_tape_sprecf(uptr, &reclen);
else
r = sim_tape_sprecr(uptr, &reclen);
/* Always skip if first record is mark */
if ((cmd & 010) != 0 && r == MTSE_TMK && BUF_EMPTY(uptr)) {
r = MTSE_OK;
}
if (cmd & 010) {
uptr->hwmark = 0;
}
if (r != MTSE_OK) {
dptr->flags &= ~MTDF_MOTION;
return mt_error(uptr, r, dptr);
}
sim_activate(uptr, 5000);
return SCPE_OK;
}
sim_activate(uptr, 50);
return SCPE_OK;
}
void mt_read_word(UNIT *uptr) {
int i, cc, ch;
buf_reg = 0;
for(i = 0; i <= 4; i++) {
cc = (8 * (3 - i)) + 4;
ch = mt_buffer[uptr->u6];
if (cc < 0)
buf_reg |= (uint64)(ch & 0x3f);
else
buf_reg |= (uint64)(ch & 0xff) << cc;
uptr->u6++;
}
}
/* 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;
r = sim_tape_rdrecf(uptr, &mt_buffer[0], &reclen, BUFFSIZE);
if (r != SCPE_OK)
return r;
uptr->u6 = 0;
uptr->hwmark = reclen;
mt_read_word(uptr);
wc = (buf_reg >> 18) & RMASK;
addr = buf_reg & RMASK;
while (wc != 0) {
wc = (wc + 1) & RMASK;
addr = (addr + 1) & RMASK;
if ((uint32)uptr->u6 >= reclen) {
r = sim_tape_rdrecf(uptr, &mt_buffer[0], &reclen, BUFFSIZE);
if (r != SCPE_OK)
return r;
uptr->u6 = 0;
}
mt_read_word(uptr);
M[addr] = buf_reg;
}
PC = addr;
return SCPE_OK;
}
t_stat 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 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, "MT10B");
} else {
fprintf (st, "MT10A");
}
return SCPE_OK;
}
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 |
MT_800_VALID | (MT_DENS_800 << UNIT_V_DF_TAPE);
}
return SCPE_OK;
}
t_stat
mt_attach(UNIT * uptr, CONST char *file)
{
return sim_tape_attach(uptr, file);
}
t_stat
mt_detach(UNIT * uptr)
{
uptr->u5 = 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