RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially debugged. Do NOT enable these features for normal operations. 1. New Features in 3.1-0 1.1 SCP and libraries - Added simulated Ethernet support for VMS, FreeBSD, Mac OS/X. - Added status return to tmxr_putc_ln. - Added sim_putchar_s to handle possible output stalls. 1.2 All DECtapes - Added "DECtape off reel" error stop. 1.3 All Asynchronous Consoles - Added support for output congestion stall if using a Telnet connection. 1.4 PDP-1 - Added Type 23 parallel drum support. 1.5 PDP-8 - Added instruction history. - Added TSC8-75 option support for ETOS. - Added TD8E DECtape support. 1.6 PDP-18b - Added instruction history. - Changed PDP-9, PDP-15 API default to enabled. 1.7 PDP-11 - Added support for 18b only Qbus devices. - Formalized bus and addressing definitions. - Added control to enable/disable autoconfiguration. - Added stub support for second Unibus Ethernet controller. 1.7 Interdata 32b - Added instruction history. 1.8 Eclipse - Added floating point support. - Added programmable interval timer support. 1.9 H316 - Added DMA/DMC support. - Added fixed head disk support. - Added moving head disk support. - Added magtape support. 1.10 IBM 1130 (Brian Knittel) - Added support for physical card reader, using the Cardread interface (www.ibm1130.org/sim/downloads). - Added support for physical printer (flushes output buffer after each line). 2. Bugs Fixed in 3.1-0 2.1 SCP and libraries - Fixed numerous bugs in Ethernet library. 2.2 All DECtapes - Fixed reverse checksum value in 'read all' mode. - Simplified (and sped up) timing. 2.3 PDP-8 - Fixed bug in RX28 read status (found by Charles Dickman). - Fixed RX28 double density write. 2.4 PDP-18b - Fixed autoincrement bug in PDP-4, PDP-7, PDP-9. 2.5 PDP-11/VAX - Revised RQ MB->LBN conversion for greater accuracy. - Fixed bug in IO configuration (found by David Hittner). - Fixed bug with multiple RQ RAUSER drives. - Fixed bug in second Qbus Ethernet controller interrupts. 2.6 Nova/Eclipse - Fixed bugs in DKP flag clear, map setup, map usage (Charles Owen). - Fixed bug in MT, reset completes despite I/O reset (Charles Owen). - Fixed bug in MT, space operations return word count (Charles Owen). 2.7 IBM 1130 (Brian Knittel) - Fixed bug in setting carry bit in subtract and subtract double. - Fixed timing problem in console printer simulation. 2.8 1620 - Fixed bug in branch digit (found by Dave Babcock). 3. New Features in 3.0 vs prior releases 3.1 SCP and Libraries - Added ASSIGN/DEASSIGN (logical name) commands. - Changed RESTORE to unconditionally detach files. - Added E11 and TPC format support to magtape library. - Fixed bug in SHOW CONNECTIONS. - Added USE_ADDR64 support. 3.2 All magtapes - Magtapes support SIMH format, E11 format, and TPC format (read only). - SET <tape_unit> FORMAT=format sets the specified tape unit's format. - SHOW <tape_unit> FORMAT displays the specified tape unit's format. - Tape format can also be set as part of the ATTACH command, using the -F switch. 3.3 VAX - VAX can be compiled without USE_INT64. - If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support files > 2GB. - VAX ROM has speed control (SET ROM DELAY/NODELAY). 3.4 PDP-1 - Added block loader format support to LOAD. - Changed BOOT PTR to allow loading of all of the first bank of memory. - The LOAD command takes an optional argument specifying the memory field to be loaded. - The PTR BOOT command takes its starting memory field from the TA (address switch) register. 3.5 PDP-18b Family - Added PDP-4 EAE support. - Added PDP-15 FP15 support. - Added PDP-15 XVM support. - Added PDP-15 "re-entrancy ECO". - Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR. 4. Bugs Fixed in 3.0 vs prior releases 4.1 SCP and Libraries - Fixed end of file problem in dep, idep. - Fixed handling of trailing spaces in dep, idep. 4.2 VAX - Fixed CVTfi bug: integer overflow not set if exponent out of range - Fixed EMODx bugs: o First and second operands reversed o Separated fraction received wrong exponent o Overflow calculation on separated integer incorrect o Fraction not set to zero if exponent out of range - Fixed interval timer and ROM access to pass power-up self-test even on very fast host processors (fixes from Mark Pizzolato). - Fixed bug in user disk size (found by Chaskiel M Grundman). 4.3 1401 - Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS. - Fixed MCE bug, BS off by 1 if zero suppress. - Fixed chaining bug, D lost if return to SCP. - Fixed H branch, branch occurs after continue. - Added check for invalid 8 character MCW, LCA. - Fixed magtape load-mode end of record response. - Revised fetch to model hardware more closely. - Fixed tape read end-of-record handling based on real 1401. - Added diagnostic read (space forward). 4.4 Nova - Fixed DSK variable size interaction with restore. - Fixed bug in DSK set size routine. 4.5 PDP-1 - Fixed DT variable size interaction with restore. - Updated CPU, line printer, standard devices to detect indefinite I/O wait. - Fixed incorrect logical, missing activate, break in drum simulator. - Fixed bugs in instruction decoding, overprinting for line printer. - Fixed system hang if continue after PTR error. - Fixed PTR to start/stop on successive rpa instructions. 4.6 PDP-11 - Fixed DT variable size interaction with restore. - Fixed bug in MMR1 update (found by Tim Stark). - Added XQ features and fixed bugs: o Corrected XQ interrupts on IE state transition (code by Tom Evans). o Added XQ interrupt clear on soft reset. o Removed XQ interrupt when setting XL or RL (multiple people). o Added SET/SHOW XQ STATS. o Added SHOW XQ FILTERS. o Added ability to split received packet into multiple buffers. o Added explicit runt and giant packet processing. - Fixed bug in user disk size (found by Chaskiel M Grundman). 4.7 PDP-18B - Fixed DT, RF variable size interaction with restore. - Fixed MT bug in MTTR. - Fixed bug in PDP-4 line printer overprinting. - Fixed bug in PDP-15 memory protect/skip interaction. - Fixed bug in RF set size routine. - Increased PTP TIME for PDP-15 operating systems. - Fixed priorities in PDP-15 API (differs from PDP-9). - Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9). - Fixed bug in CAF, clears API subsystem. 4.8 PDP-8 - Fixed DT, DF, RF, RX variable size interaction with restore. - Fixed MT bug in SKTR. - Fixed bug in DF, RF set size routine. 4.9 HP2100 - Fixed bug in DP (13210A controller only), DQ read status. - Fixed bug in DP, DQ seek complete. - Fixed DR drum sizes. - Fixed DR variable capacity interaction with SAVE/RESTORE. 4.10 GRI - Fixed bug in SC queue pointer management. 4.11 PDP-10 - Fixed bug in RP read header. 4.12 Ibm1130 - Fixed bugs found by APL 1130. 4.13 Altairz80 - Fixed bug in real-time clock on Windows host. 4.14 1620 - Fixed bug in immediate index add (found by Michael Short).
520 lines
17 KiB
C
520 lines
17 KiB
C
/* h316_mt.c: H316/516 magnetic tape simulator
|
||
|
||
Copyright (c) 2003, 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.
|
||
|
||
mt 516-4100 seven track magnetic tape
|
||
|
||
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 "h316_defs.h"
|
||
#include "sim_tape.h"
|
||
|
||
#define MT_NUMDR 4 /* number of drives */
|
||
#define DB_N_SIZE 16 /* max data buf */
|
||
#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */
|
||
#define FNC u3 /* function */
|
||
#define UST u4 /* unit status */
|
||
#define UNIT_WPRT (MTUF_WLK | UNIT_RO) /* write prot */
|
||
|
||
/* Function codes */
|
||
|
||
#define FNC_RBCD2 000
|
||
#define FNC_RBIN2 001
|
||
#define FNC_RBIN3 002
|
||
#define FNC_DMANM 003
|
||
#define FNC_WBCD2 004
|
||
#define FNC_WBIN2 005
|
||
#define FNC_WEOF 006
|
||
#define FNC_IOBUS 007
|
||
#define FNC_WBIN3 010
|
||
#define FNC_FSR 011
|
||
#define FNC_FSF 012
|
||
#define FNC_DMAAU 013
|
||
#define FNC_REW 014
|
||
#define FNC_BSR 015
|
||
#define FNC_BSF 016
|
||
#define FNC_STOPW 017
|
||
#define FNC_2ND 020 /* second state */
|
||
#define FNC_NOP (FNC_STOPW|FNC_2ND)
|
||
#define FNC_EOM 040 /* end of motion */
|
||
|
||
/* Status - unit.UST */
|
||
|
||
#define STA_BOT 0000002 /* beg of tape */
|
||
#define STA_EOT 0000001 /* end of tape */
|
||
|
||
extern int32 dev_int, dev_enb, chan_req;
|
||
extern int32 stop_inst;
|
||
|
||
uint32 mt_buf = 0; /* data buffer */
|
||
uint32 mt_usel = 0; /* unit select */
|
||
uint32 mt_busy = 0; /* ctlr busy */
|
||
uint32 mt_mdirq = 0; /* motion done int req */
|
||
uint32 mt_rdy = 0; /* transfer ready (int) */
|
||
uint32 mt_err = 0; /* error */
|
||
uint32 mt_eof = 0; /* end of file */
|
||
uint32 mt_eor = 0; /* transfer done */
|
||
uint32 mt_dma = 0; /* DMA/DMC */
|
||
uint32 mt_xtime = 16; /* transfer time */
|
||
uint32 mt_ctime = 3000; /* start/stop time */
|
||
uint32 mt_stopioe = 1; /* stop on I/O error */
|
||
uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */
|
||
t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */
|
||
|
||
int32 mtio (int32 inst, int32 fnc, int32 dat, int32 dev);
|
||
void mt_updint (uint32 rdy, uint32 mdone);
|
||
t_stat mt_svc (UNIT *uptr);
|
||
t_stat mt_reset (DEVICE *dptr);
|
||
t_stat mt_attach (UNIT *uptr, char *cptr);
|
||
t_stat mt_detach (UNIT *uptr);
|
||
t_stat mt_map_err (UNIT *uptr, t_stat st);
|
||
void mt_wrwd (UNIT *uptr, uint32 dat);
|
||
|
||
/* MT data structures
|
||
|
||
mt_dev MT device descriptor
|
||
mt_unit MT unit list
|
||
mt_reg MT register list
|
||
mt_mod MT modifier list
|
||
*/
|
||
|
||
DIB mt_dib = { MT, IOBUS, MT_NUMDR, &mtio };
|
||
|
||
UNIT mt_unit[] = {
|
||
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
|
||
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
|
||
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
|
||
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) } };
|
||
|
||
REG mt_reg[] = {
|
||
{ ORDATA (BUF, mt_buf, 16) },
|
||
{ ORDATA (USEL, mt_usel, 2) },
|
||
{ FLDATA (BUSY, mt_busy, 0) },
|
||
{ FLDATA (RDY, mt_rdy, 0) },
|
||
{ FLDATA (ERR, mt_err, 0) },
|
||
{ FLDATA (EOF, mt_eof, 0) },
|
||
{ FLDATA (EOR, mt_eor, 0) },
|
||
{ FLDATA (MDIRQ, mt_mdirq, 0) },
|
||
{ FLDATA (DMA, mt_dma, 0) },
|
||
{ FLDATA (INTREQ, dev_int, INT_V_MT) },
|
||
{ FLDATA (ENABLE, dev_enb, INT_V_MT) },
|
||
{ BRDATA (DBUF, mtxb, 8, 8, DBSIZE) },
|
||
{ DRDATA (BPTR, mt_ptr, DB_N_SIZE + 1) },
|
||
{ DRDATA (BMAX, mt_max, DB_N_SIZE + 1) },
|
||
{ DRDATA (CTIME, mt_ctime, 24), REG_NZ + PV_LEFT },
|
||
{ DRDATA (XTIME, mt_xtime, 24), REG_NZ + PV_LEFT },
|
||
{ URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0, MT_NUMDR, PV_LEFT) },
|
||
{ URDATA (FNC, mt_unit[0].FNC, 8, 8, 0, MT_NUMDR, REG_HRO) },
|
||
{ URDATA (UST, mt_unit[0].UST, 8, 2, 0, MT_NUMDR, REG_HRO) },
|
||
{ ORDATA (CHAN, mt_dib.chan, 5), REG_HRO },
|
||
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
|
||
{ NULL } };
|
||
|
||
MTAB mt_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_VDV, 0, NULL, "IOBUS",
|
||
&io_set_iobus, NULL, NULL },
|
||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMC",
|
||
&io_set_dmc, NULL, NULL },
|
||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMA",
|
||
&io_set_dma, NULL, NULL },
|
||
{ MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL,
|
||
NULL, &io_show_chan, NULL },
|
||
{ 0 } };
|
||
|
||
DEVICE mt_dev = {
|
||
"MT", mt_unit, mt_reg, mt_mod,
|
||
MT_NUMDR, 10, 31, 1, 8, 8,
|
||
NULL, NULL, &mt_reset,
|
||
NULL, &mt_attach, &mt_detach,
|
||
&mt_dib, DEV_DISABLE };
|
||
|
||
/* IO routine */
|
||
|
||
int32 mtio (int32 inst, int32 fnc, int32 dat, int32 dev)
|
||
{
|
||
uint32 u = dev & 03;
|
||
UNIT *uptr = mt_dev.units + u;
|
||
static uint8 wrt_fnc[16] = { /* >0 = wr, 1 = chan op */
|
||
0, 0, 0, 0, 1, 1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0 };
|
||
|
||
switch (inst) { /* case on opcode */
|
||
case ioOCP:
|
||
mt_updint (mt_rdy, 0); /* clear motion intr */
|
||
mt_eof = 0; /* clear eof */
|
||
switch (fnc) { /* case on function */
|
||
case FNC_DMANM: /* set DMA/DMC */
|
||
case FNC_DMAAU:
|
||
mt_usel = u; /* save unit select */
|
||
if (mt_dib.chan) mt_dma = 1; /* if configured */
|
||
break;
|
||
case FNC_IOBUS: /* set IOBUS */
|
||
mt_usel = u; /* save unit select */
|
||
mt_dma = 0;
|
||
break;
|
||
case FNC_STOPW: /* stop write */
|
||
mt_usel = u; /* save unit select */
|
||
mt_updint (0, mt_mdirq); /* clear ready */
|
||
if (wrt_fnc[uptr->FNC & 017] == 1) /* writing? */
|
||
mt_eor = 1; /* set transfer done */
|
||
break;
|
||
default: /* motion command */
|
||
if (mt_busy) return dat; /* nop if ctlr busy */
|
||
mt_eor = 0; /* clr transfer done */
|
||
mt_err = 0; /* clr error */
|
||
mt_usel = u; /* save unit select */
|
||
if (((uptr->flags & UNIT_ATT) == 0) || /* nop if not att */
|
||
sim_is_active (uptr)) /* or busy */
|
||
(IORETURN (mt_stopioe, SCPE_UNATT) | dat);
|
||
if (wrt_fnc[fnc] && (uptr->flags & UNIT_WPRT))
|
||
return (STOP_MTWRP << IOT_V_REASON);
|
||
uptr->FNC = fnc;
|
||
uptr->UST = 0;
|
||
mt_busy = 1;
|
||
sim_activate (uptr, mt_ctime); /* schedule */
|
||
break; }
|
||
break;
|
||
case ioINA: /* INA */
|
||
if (fnc) return IOBADFNC (dat); /* fnc 0 only */
|
||
if (mt_rdy) { /* ready? */
|
||
mt_rdy = 0; /* clear ready */
|
||
return IOSKIP (dat | mt_buf); } /* ret buf, skip */
|
||
break;
|
||
case ioOTA: /* OTA */
|
||
if (fnc) return IOBADFNC (dat); /* fnc 0 only */
|
||
if (mt_rdy) { /* ready? */
|
||
mt_rdy = 0; /* clear ready */
|
||
mt_buf = dat; /* store buf */
|
||
return IOSKIP (dat); } /* skip */
|
||
break;
|
||
case ioSKS:
|
||
uptr = mt_dev.units + mt_usel; /* use saved unit sel */
|
||
switch (fnc) {
|
||
case 000: /* ready */
|
||
if (mt_rdy) return IOSKIP (dat);
|
||
break;
|
||
case 001: /* !busy */
|
||
if (!mt_busy) return IOSKIP (dat);
|
||
break;
|
||
case 002: /* !error */
|
||
if (!mt_err) return IOSKIP (dat);
|
||
break;
|
||
case 003: /* !BOT */
|
||
if (!(uptr->UST & STA_BOT)) return IOSKIP (dat);
|
||
break;
|
||
case 004: /* !interrupting */
|
||
if (!TST_INTREQ (INT_MT)) return IOSKIP (dat);
|
||
break;
|
||
case 005: /* !EOT */
|
||
if (!(uptr->UST & STA_EOT)) return IOSKIP (dat);
|
||
break;
|
||
case 006: /* !EOF */
|
||
if (!mt_eof) return IOSKIP (dat);
|
||
break;
|
||
case 007: /* !write prot */
|
||
if (!(uptr->flags & UNIT_WPRT)) return IOSKIP (dat);
|
||
break;
|
||
case 011: /* operational */
|
||
if ((uptr->flags & UNIT_ATT) &&
|
||
((uptr->FNC & 017) != FNC_REW)) return IOSKIP (dat);
|
||
break;
|
||
case 012: /* skip if !chan 2 */
|
||
return IOSKIP (dat);
|
||
case 013: /* skip if !auto */
|
||
return IOSKIP (dat);
|
||
case 014: /* !rewinding */
|
||
uptr = mt_dev.units + (dev & 03); /* use specified unit */
|
||
if ((uptr->FNC & 017) != FNC_REW) return IOSKIP (dat);
|
||
break; }
|
||
break;
|
||
case ioEND: /* end of range */
|
||
mt_eor = 1; /* transfer done */
|
||
break; }
|
||
return dat;
|
||
}
|
||
|
||
/* Unit service
|
||
|
||
If rewind done, reposition to start of tape, set status
|
||
else, do operation, set done, interrupt
|
||
|
||
Can't be write locked, can only write lock detached unit
|
||
*/
|
||
|
||
t_stat mt_svc (UNIT *uptr)
|
||
{
|
||
int32 ch = mt_dib.chan - 1; /* DMA/DMC ch */
|
||
uint32 i, c1, c2, c3;
|
||
t_mtrlnt tbc;
|
||
t_stat st, r = SCPE_OK;
|
||
|
||
if ((uptr->flags & UNIT_ATT) == 0) { /* offline? */
|
||
mt_err = 1;
|
||
mt_busy = 0;
|
||
mt_updint (0, 1); /* cmd done */
|
||
return IORETURN (mt_stopioe, SCPE_UNATT); }
|
||
|
||
switch (uptr->FNC) { /* case on function */
|
||
case FNC_REW: /* rewind (initial) */
|
||
mt_busy = 0; /* ctlr not busy */
|
||
uptr->FNC = uptr->FNC | FNC_2ND;
|
||
sim_activate (uptr, mt_ctime);
|
||
return SCPE_OK; /* continue */
|
||
|
||
case FNC_REW | FNC_2ND: /* rewind done */
|
||
uptr->pos = 0; /* reposition file */
|
||
uptr->UST = STA_BOT; /* set BOT */
|
||
uptr->FNC = FNC_NOP; /* nop function */
|
||
for (i = 0; i < MT_NUMDR; i++) { /* last rewind? */
|
||
if ((mt_unit[i].FNC & 017) == FNC_REW) return SCPE_OK; }
|
||
mt_updint (mt_rdy, 1); /* yes, motion done */
|
||
return SCPE_OK;
|
||
|
||
case FNC_WEOF: /* write file mark */
|
||
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
|
||
r = mt_map_err (uptr, st); /* map error */
|
||
break; /* sched end motion */
|
||
|
||
case FNC_FSR: /* space fwd rec */
|
||
if (st = sim_tape_sprecf (uptr, &tbc)) /* space fwd, err? */
|
||
r = mt_map_err (uptr, st); /* map error */
|
||
break; /* sched end motion */
|
||
|
||
case FNC_BSR: /* space rev rec */
|
||
if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */
|
||
r = mt_map_err (uptr, st); /* map error */
|
||
break; /* sched end motion */
|
||
|
||
case FNC_FSF: /* space fwd file */
|
||
while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;
|
||
r = mt_map_err (uptr, st); /* map error */
|
||
break; /* sched end motion */
|
||
|
||
case FNC_BSF: /* space rev file */
|
||
while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
|
||
r = mt_map_err (uptr, st); /* map error */
|
||
break; /* sched end motion */
|
||
|
||
case FNC_EOM: /* end of motion */
|
||
uptr->FNC = FNC_NOP; /* nop function */
|
||
mt_busy = 0; /* not busy */
|
||
mt_updint (mt_rdy, 1); /* end of motion */
|
||
return SCPE_OK; /* done! */
|
||
|
||
/* Unit service, continued */
|
||
|
||
case FNC_RBCD2: case FNC_RBIN2: case FNC_RBIN3: /* read first */
|
||
mt_ptr = 0; /* clr buf ptr */
|
||
st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */
|
||
if (st != MTSE_OK) { /* error? */
|
||
r = mt_map_err (uptr, st); /* map error */
|
||
break; } /* sched end motion */
|
||
uptr->FNC = uptr->FNC | FNC_2ND; /* next state */
|
||
sim_activate (uptr, mt_xtime); /* sched xfer */
|
||
return SCPE_OK;
|
||
|
||
case FNC_RBCD2 | FNC_2ND: /* read, word */
|
||
case FNC_RBIN2 | FNC_2ND:
|
||
case FNC_RBIN3 | FNC_2ND:
|
||
if (mt_ptr >= mt_max) break; /* record done? */
|
||
c1 = mtxb[mt_ptr++] & 077; /* get 2 chars */
|
||
c2 = mtxb[mt_ptr++] & 077;
|
||
if (uptr->FNC == (FNC_RBCD2 | FNC_2ND)) { /* BCD? */
|
||
if (c1 == 012) c1 = 0; /* change 12 to 0 */
|
||
if (c2 == 012) c2 = 0; }
|
||
if (uptr->FNC == (FNC_RBIN3 | FNC_2ND)) { /* read 3? */
|
||
if (mt_ptr >= mt_max) break; /* lose wd if not enuf */
|
||
c3 = mtxb[mt_ptr++] & 017; } /* get 3rd char */
|
||
else c3 = 0;
|
||
sim_activate (uptr, mt_xtime); /* no, sched word */
|
||
if (mt_eor) return SCPE_OK; /* xfer done? */
|
||
mt_buf = (c1 << 10) | (c2 << 4) | c3; /* pack chars */
|
||
if (mt_rdy) mt_err = 1; /* buf full? err */
|
||
mt_updint (1, mt_mdirq); /* set ready */
|
||
if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */
|
||
return SCPE_OK; /* continue */
|
||
|
||
case FNC_WBCD2: case FNC_WBIN2: case FNC_WBIN3: /* write first */
|
||
mt_ptr = 0; /* clear buf ptr */
|
||
mt_updint (1, mt_mdirq); /* set ready */
|
||
if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */
|
||
uptr->FNC = uptr->FNC | FNC_2ND; /* next state */
|
||
sim_activate (uptr, mt_xtime); /* sched xfer */
|
||
return SCPE_OK; /* continue */
|
||
|
||
case FNC_WBCD2 | FNC_2ND: /* write, word */
|
||
case FNC_WBIN2 | FNC_2ND:
|
||
case FNC_WBIN3 | FNC_2ND:
|
||
if (mt_eor || mt_rdy) { /* done or no data? */
|
||
if (!mt_rdy) mt_wrwd (uptr, mt_buf); /* write last word */
|
||
if (mt_ptr) { /* any data? */
|
||
if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) /* write, err? */
|
||
r = mt_map_err (uptr, st); } /* map error */
|
||
break; } /* sched end motion */
|
||
mt_wrwd (uptr, mt_buf); /* write word */
|
||
sim_activate (uptr, mt_xtime); /* no, sched word */
|
||
mt_updint (1, mt_mdirq); /* set ready */
|
||
if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */
|
||
return SCPE_OK; /* continue */
|
||
|
||
default: /* unknown */
|
||
break; }
|
||
|
||
/* End of command, process error or schedule end of motion */
|
||
|
||
if (r != SCPE_OK) {
|
||
uptr->FNC = FNC_NOP; /* nop function */
|
||
mt_busy = 0; /* not busy */
|
||
mt_updint (mt_rdy, 1); /* end of motion */
|
||
return r; }
|
||
uptr->FNC = FNC_EOM; /* sched end motion */
|
||
sim_activate (uptr, mt_ctime);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Write word to buffer */
|
||
|
||
void mt_wrwd (UNIT *uptr, uint32 dat)
|
||
{
|
||
uint32 c1, c2;
|
||
|
||
c1 = (dat >> 10) & 077; /* get 2 chars */
|
||
c2 = (dat >> 4) & 077;
|
||
if (uptr->FNC == (FNC_WBCD2 | FNC_2ND)) { /* BCD? */
|
||
if (c1 == 0) c1 = 012; /* change 0 to 12 */
|
||
if (c2 == 0) c2 = 012; }
|
||
if (mt_ptr < DBSIZE) mtxb[mt_ptr++] = c1; /* store 2 char */
|
||
if (mt_ptr < DBSIZE) mtxb[mt_ptr++] = c2;
|
||
if ((uptr->FNC == (FNC_WBIN3 | FNC_2ND)) && /* write 3? */
|
||
(mt_ptr < DBSIZE)) mtxb[mt_ptr++] = mt_buf & 017;
|
||
return;
|
||
}
|
||
|
||
/* Map tape error status */
|
||
|
||
t_stat mt_map_err (UNIT *uptr, t_stat st)
|
||
{
|
||
switch (st) {
|
||
case MTSE_FMT: /* illegal fmt */
|
||
case MTSE_UNATT: /* unattached */
|
||
mt_err = 1; /* reject */
|
||
case MTSE_OK: /* no error */
|
||
return SCPE_IERR; /* never get here! */
|
||
case MTSE_TMK: /* end of file */
|
||
mt_eof = 1; /* eof */
|
||
break;
|
||
case MTSE_INVRL: /* invalid rec lnt */
|
||
mt_err = 1;
|
||
return SCPE_MTRLNT;
|
||
case MTSE_IOERR: /* IO error */
|
||
mt_err = 1; /* error */
|
||
if (mt_stopioe) return SCPE_IOERR;
|
||
break;
|
||
case MTSE_RECE: /* record in error */
|
||
case MTSE_EOM: /* end of medium */
|
||
mt_err = 1; /* error */
|
||
break;
|
||
case MTSE_BOT: /* reverse into BOT */
|
||
uptr->UST = STA_BOT; /* set status */
|
||
break;
|
||
case MTSE_WRP: /* write protect */
|
||
mt_err = 1; /* error */
|
||
return STOP_MTWRP; }
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Update interrupts */
|
||
|
||
void mt_updint (uint32 rdy, uint32 mdirq)
|
||
{
|
||
mt_rdy = rdy; /* store new ready */
|
||
mt_mdirq = mdirq; /* store new motion irq */
|
||
if ((mt_rdy && !mt_dma) || mt_mdirq) SET_INT (INT_MT); /* update int request */
|
||
else CLR_INT (INT_MT);
|
||
return;
|
||
}
|
||
|
||
/* Reset routine */
|
||
|
||
t_stat mt_reset (DEVICE *dptr)
|
||
{
|
||
int32 i;
|
||
UNIT *uptr;
|
||
|
||
mt_buf = 0; /* clear state */
|
||
mt_usel = 0;
|
||
mt_mdirq = 0;
|
||
mt_eor = 0;
|
||
mt_busy = 0;
|
||
mt_rdy = 0;
|
||
mt_eof = 0;
|
||
mt_err = 0;
|
||
mt_dma = 0;
|
||
CLR_INT (INT_MT); /* clear int, enb */
|
||
CLR_ENB (INT_MT);
|
||
for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */
|
||
uptr = mt_dev.units + i;
|
||
sim_tape_reset (uptr); /* reset tape */
|
||
sim_cancel (uptr); /* cancel op */
|
||
uptr->UST = uptr->pos? 0: STA_BOT; /* update status */
|
||
uptr->FNC = FNC_NOP; }
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Attach routine */
|
||
|
||
t_stat mt_attach (UNIT *uptr, char *cptr)
|
||
{
|
||
t_stat r;
|
||
|
||
r = sim_tape_attach (uptr, cptr); /* attach unit */
|
||
if (r != SCPE_OK) return r; /* update status */
|
||
uptr->UST = STA_BOT;
|
||
return r;
|
||
}
|
||
|
||
/* Detach routine */
|
||
|
||
t_stat mt_detach (UNIT* uptr)
|
||
{
|
||
uptr->UST = 0; /* update status */
|
||
uptr->FNC = FNC_NOP; /* nop function */
|
||
return sim_tape_detach (uptr); /* detach unit */
|
||
}
|