/* hp_tapelib.h: HP magnetic tape controller simulator library declarations Copyright (c) 2013-2019, J. David Bryan Copyright (c) 2004-2011, 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 THE AUTHORS 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 the authors shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. 01-Feb-19 JDB Remap sim_tape_attach to avoid unwanted debug output 05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X 10-Oct-16 JDB Moved "hp3000_defs.h" inclusion to "hp_tapelib.c" 13-May-16 JDB Modified for revised SCP API function parameter types 24-Mar-16 JDB Added the TL_BUFFER type to define the tape buffer array 21-Mar-16 JDB Changed uint16 types to HP_WORD 11-Nov-15 JDB First release version 24-Mar-13 JDB Created tape controller common library from MS simulator This file defines the interface between machine-specific tape drive simulators and the common HP tape controller simulation library. It must be included by the controller-specific modules. */ #include "sim_rev.h" /* For SIM_MAJOR */ #include "sim_tape.h" /* Remap tape attach in 4.x to avoid unwanted debug output */ #if (SIM_MAJOR >= 4) #define sim_tape_attach(a,b) sim_tape_attach_ex (a, b, 0, 0) #endif /* Architectural constants. The type of the tape buffer element is defined. This must be an 8-bit array for compatibility with the simulator tape support library (sim_tape). */ typedef uint8 TL_BUFFER; /* a buffer containing 8-bit tape data words */ /* Program limits */ #define TL_MAXDRIVE 3 /* last valid drive number */ #define TL_AUXUNITS 1 /* number of auxiliary units required */ #define TL_CNTLR_UNIT (TL_MAXDRIVE + 1) /* controller unit number */ #define TL_MAXREC (DV_UMAX + 1) /* maximum supported tape record size in bytes */ #define TL_BUFSIZE (TL_MAXREC + 2) /* buffer size in bytes (including space for CRCC/LRCC) */ /* Debug flags */ #define TL_DEB_CMD (1u << 0) /* trace controller commands */ #define TL_DEB_INCO (1u << 1) /* trace command initiations and completions */ #define TL_DEB_STATE (1u << 2) /* trace command execution state changes */ #define TL_DEB_SERV (1u << 3) /* trace unit service scheduling calls */ #define TL_DEB_XFER (1u << 4) /* trace data reads and writes */ #define TL_DEB_IOB (1u << 5) /* trace I/O bus signals and data words */ #define TL_DEB_V_UF 6 /* first free debug flag bit */ /* Common per-unit tape drive state variables */ #define PROP u3 /* drive properties */ #define STATUS u4 /* drive status */ #define OPCODE u5 /* drive current operation */ #define PHASE u6 /* drive current operation phase */ /* Device flags and accessors */ #define DEV_REALTIME_SHIFT (DEV_V_UF + 0) /* bits 0-0: timing mode is realistic */ #define DEV_REALTIME (1 << DEV_REALTIME_SHIFT) /* realistic timing flag */ /* Unit flags and accessors. The user-defined unit flags are used to store tape unit status that may be modified by the user, as follows: +---+---+---+---+---+---+---+---+ [...] - - - | R | O | model | +---+---+---+---+---+---+---+---+ Where: R = the unit is rewinding O = the unit is offline model = the DRIVE_TYPE enumeration constant for the simulated drive Implementation notes: 1. The hardware REWIND STATUS (SRW) signal is implemented as a unit flag, although it may be inferred from unit.OPCODE = Rewind or Rewind_Offline and unit.PHASE = Traverse_Phase. This is for the convenience of testing the "unit busy" condition, which exists when a unit is offline or rewinding. */ #define UNIT_MODEL_SHIFT (MTUF_V_UF + 0) /* bits 0-2: drive model ID */ #define UNIT_OFFLINE_SHIFT (MTUF_V_UF + 3) /* bits 3-3: unit is offline */ #define UNIT_REW_SHIFT (MTUF_V_UF + 4) /* bits 4-4: unit is rewinding */ #define TL_UNIT_V_UF (MTUF_V_UF + 5) /* first free unit flag bit */ #define UNIT_MODEL_MASK 0000007u /* model ID mask */ #define UNIT_MODEL (UNIT_MODEL_MASK << UNIT_MODEL_SHIFT) #define UNIT_OFFLINE (1u << UNIT_OFFLINE_SHIFT) #define UNIT_REWINDING (1u << UNIT_REW_SHIFT) #define UNIT_7970B (HP_7970B << UNIT_MODEL_SHIFT) #define UNIT_7970E (HP_7970E << UNIT_MODEL_SHIFT) #define UNIT_7974 (HP_7974 << UNIT_MODEL_SHIFT) #define UNIT_7978 (HP_7978 << UNIT_MODEL_SHIFT) /* Controller flag and function accessors */ #define TLIFN(C) ((CNTLR_IFN_SET) ((C) & ~D16_MASK)) #define TLIBUS(C) ((CNTLR_IBUS) ((C) & D16_MASK)) #define TLNEXTIFN(S) ((CNTLR_IFN) IOPRIORITY (S)) /* Tape drive types */ typedef enum { HP_7970B, /* HP 7970B 800 bpi NRZI */ HP_7970E, /* HP 7970E 1600 bpi PE */ HP_7974, /* HP 7974A 800/1600 bpi NRZI/PE */ HP_7978 /* HP 7978A 1600/6250 bpi PE/GCR */ } DRIVE_TYPE; /* Controller types */ typedef enum { HP_13181, /* HP 1000 NRZI controller */ HP_13183, /* HP 1000 PE controller */ HP_30215, /* HP 3000 NRZI/PE controller */ HP_IB /* HP-IB controller */ } CNTLR_TYPE; #define LAST_CNTLR HP_IB #define CNTLR_COUNT (LAST_CNTLR + 1) /* Interface flags and function bus orders. The CNTLR_FLAG and CNTLR_IFN declarations simulate hardware signals that are received and asserted, respectively, by the abstract tape controller. In simulation, the interface sends a set of one or more flags that indicates the state of the interface to the controller. The controller then returns a set of one or more functions that requests the interface to perform certain actions. The function set is decoded into a set of function identifiers that are returned to, and then processed sequentially by, the interface in order of ascending numerical value. Implementation notes: 1. The enumerations describe signals. A set of signals normally would be modeled as an unsigned integer, as a set may contain more than one signal. However, we define a set as the enumeration, as the "gdb" debugger has special provisions for an enumeration of discrete bit values and will display the set in "ORed" form. 2. The null sets -- NO_FLAGS and NO_FUNCTIONS -- cannot be defined as enumeration constants, as including them would require handlers for them in "switch" statements, which is undesirable. Therefore, we define them as an explicit integer zero values compatible with the enumerations. 3. Function bus values are restricted to the upper 16 bits to allow the combined function and data value to fit in 32 bits. */ typedef enum { /* interface flags */ CMRDY = 0000001, /* Command Ready */ CMXEQ = 0000002, /* Command Execute */ DTRDY = 0000004, /* Data Ready */ EOD = 0000010, /* End of Data */ INTOK = 0000020, /* Interrupt OK */ OVRUN = 0000040, /* Data Overrun */ XFRNG = 0000100 /* Data Transfer No Good */ } CNTLR_FLAG; #define NO_FLAGS (CNTLR_FLAG) 0 /* no flags are asserted */ typedef CNTLR_FLAG CNTLR_FLAG_SET; /* a set of CNTLR_FLAGs */ typedef enum { /* interface function bus orders */ IFIN = 000000200000, /* Interface In */ IFOUT = 000000400000, /* Interface Out */ IFGTC = 000001000000, /* Interface Get Command */ SCPE = 000002000000, /* SCP Error Status */ RQSRV = 000004000000, /* Request Service */ DVEND = 000010000000, /* Device End */ STCFL = 000020000000, /* Set Control Flag */ STDFL = 000040000000, /* Set Data Flag */ STINT = 000100000000, /* Set Interrupt */ DATTN = 000200000000 /* Drive Attention */ } CNTLR_IFN; #define NO_FUNCTIONS (CNTLR_IFN) 0 /* no functions are asserted */ typedef CNTLR_IFN CNTLR_IFN_SET; /* a set of CNTLR_IFNs */ typedef HP_WORD CNTLR_IBUS; /* the interface data bus */ #undef NO_DATA /* remove winsock definition */ #define NO_DATA (CNTLR_IBUS) 0 /* no data asserted */ typedef uint32 CNTLR_IFN_IBUS; /* a combined interface function set and data bus value */ /* Controller opcodes. Each tape interface uses its own encoding for tape commands that must be translated to the appropriate CNTLR_OPCODEs of the common set, typically via a lookup table. Implementation notes: 1. The Select Unit 0-3 opcodes must have contiguous values, so that the value of the selected unit may be added to the Select_Unit_0 value to obtain the correct opcode. 2. The Invalid Opcode must be the last enumeration value. */ typedef enum { Select_Unit_0, Select_Unit_1, Select_Unit_2, Select_Unit_3, Clear_Controller, Read_Record, Read_Record_with_CRCC, Read_Record_Backward, Read_File_Forward, Write_Record, Write_Record_without_Parity, Write_File_Mark, Write_Gap, Write_Gap_and_File_Mark, Forward_Space_Record, Forward_Space_File, Backspace_Record, Backspace_File, Rewind, Rewind_Offline, Invalid_Opcode } CNTLR_OPCODE; /* Controller opcode classifications */ typedef enum { Class_Invalid, /* invalid classification */ Class_Read, /* read classification */ Class_Write, /* write classification */ Class_Rewind, /* rewind classification */ Class_Control /* control classification */ } CNTLR_CLASS; /* Controller execution states. The controller is in the idle state while it is awaiting a command. It is in the busy state while it is executing a command. The end and error states are busy states in which a device end or a device error, respectively, has occurred while executing the command. A device end occurs when a record shorter than the requested length is read. A device error occurs when a simulator tape support library routine returns an error (e.g., a read of a tape mark or of a record that is marked bad), or a data overrun is detected by the interface. In these cases, command execution completes normally, but notification is given that the channel order or program should be aborted. Implementation notes: 1. The error states (End_State and Error_State) must be numerically greater than the non-error states (Idle_State and Busy_State). */ typedef enum { Idle_State, /* idle */ Busy_State, /* busy */ End_State, /* device end */ Error_State /* device error */ } CNTLR_STATE; /* Tape activation delays structure. The simulation models the mechanical delays of the tape drive as timed events that are scheduled by unit command phase transitions. For example, a tape record read is modeled as a start phase, a data transfer phase, and a stop phase. These correspond to the motion of the physical tape as it starts and ramps up to speed while crossing the interrecord gap, passes the data record over the read head, and then slows the tape to a stop in the next interrecord gap. Separate structures contain the delays for realistic and optimized timing for the various tape drive types. The structure contains these fields: rewind_start -- the time from rewind initiation to controller idle rewind_rate -- the travel time per inch during rewinding rewind_stop -- the time from BOT detection to load point search completion bot_start -- the time starting from the BOT marker to the data block ir_start -- the time starting from the IR gap to the data block data_xfer -- the travel time from one data byte to the next overhead -- the controller execution time from command to first motion The bot_start and ir_start values include the drive start/stop time and the traverse time across the initial gap and one-half of the interrecord gap, respectively. The ir_start value doubles as the stop time. */ typedef struct { int32 rewind_start; /* rewind initiation time */ int32 rewind_rate; /* rewind time per inch */ int32 rewind_stop; /* rewind completion time */ int32 bot_start; /* beginning of tape gap traverse time */ int32 ir_start; /* interrecord traverse time */ int32 data_xfer; /* per-byte data transfer time */ int32 overhead; /* controller execution overhead */ } DELAY_PROPS; #define DELAY_INIT(rstart,rrate,rstop,bot,ir,dxfr,ovhd) \ (rstart), (rrate), (rstop), (bot), (ir), (dxfr), (ovhd) /* Tape controller state */ typedef struct { CNTLR_TYPE type; /* controller type */ DEVICE *device; /* controlling device pointer */ CNTLR_STATE state; /* controller state */ uint32 status; /* controller status */ uint32 unit_selected; /* unit number currently selected */ uint32 unit_attention; /* bitmap of units needing attention */ TL_BUFFER *buffer; /* data buffer pointer */ t_stat call_status; /* simulator tape support library call status */ t_mtrlnt length; /* data buffer valid length */ t_mtrlnt index; /* data buffer current index */ t_mtrlnt gaplen; /* current record erase gap length */ t_addr initial_position; /* tape motion initial position */ DELAY_PROPS *fastptr; /* pointer to the FASTTIME delays */ const DELAY_PROPS *dlyptr; /* current delay property pointer */ } CNTLR_VARS; typedef CNTLR_VARS *CVPTR; /* a pointer to a controller state variable structure */ /* Controller state variable structure initialization. The supplied parameters are: ctype - the type of the controller (CNTLR_TYPE) dev - the device on which the controller operates (DEVICE) bufptr - a pointer to the data buffer (array of TL_BUFFER) fast - a pointer to the fast timing values (DELAY_PROPS) */ #define CNTLR_INIT(ctype,dev,bufptr,fast) \ (ctype), &(dev), Idle_State, 0, 0, 0, \ (bufptr), MTSE_OK, 0, 0, 0, 0, \ &(fast), &(fast) /* Tape controller device register definitions. These definitions should be included AFTER any interface-specific registers. The supplied parameters are: cntlr -- the controller state variable structure (CNTLR_VARS) units -- the unit array (array of UNIT) numunits -- the number of tape drive units buffer -- the buffer array (array of TL_BUFFER) times -- the structure containing the fast delay time values (DELAY_PROPS) Implementation notes: 1. The CNTLR_VARS fields "type", "device", "buffer", "fastptr", and "dlyptr" do not need to appear in the REG array, as "dlyptr" is reset by the tl_attach routine during a RESTORE, and the others are static. */ #define TL_REGS(cntlr,units,numunits,buffer,times) \ /* Macro Name Location Radix Width Depth Flags */ \ /* ------ ------ ------------------------ ----- -------- --------------- ----------------- */ \ { DRDATA (CSTATE, (cntlr).state, 4), PV_LEFT | REG_RO }, \ { ORDATA (STATUS, (cntlr).status, 16), REG_RO }, \ { DRDATA (USEL, (cntlr).unit_selected, 4), PV_LEFT | REG_RO }, \ { YRDATA (UATTN, (cntlr).unit_attention, 4, PV_RZRO) }, \ { BRDATA (RECBUF, (buffer), 8, 8, TL_BUFSIZE), REG_X }, \ { DRDATA (LIBSTA, (cntlr).call_status, 16), PV_LEFT }, \ { DRDATA (LENGTH, (cntlr).length, 24), PV_LEFT }, \ { DRDATA (INDEX, (cntlr).index, 24), PV_LEFT }, \ { DRDATA (GAPLEN, (cntlr).gaplen, 32), PV_LEFT }, \ { DRDATA (INPOS, (cntlr).initial_position, T_ADDR_W), PV_LEFT }, \ \ /* Macro Name Location Width Flags */ \ /* ------ ------- -------------------- ----- ---------------- */ \ { DRDATA (RSTART, (times).rewind_start, 24), PV_LEFT | REG_NZ }, \ { DRDATA (RRATE, (times).rewind_rate, 24), PV_LEFT | REG_NZ }, \ { DRDATA (RSTOP, (times).rewind_stop, 24), PV_LEFT | REG_NZ }, \ { DRDATA (BTIME, (times).bot_start, 24), PV_LEFT | REG_NZ }, \ { DRDATA (ITIME, (times).ir_start, 24), PV_LEFT | REG_NZ }, \ { DRDATA (DTIME, (times).data_xfer, 24), PV_LEFT | REG_NZ }, \ { DRDATA (OTIME, (times).overhead, 24), PV_LEFT | REG_NZ }, \ \ /* Macro Name Location Radix Width Offset Depth Flags */ \ /* ------ ------- ----------------- ----- -------- ------ ---------- ------------------ */ \ { URDATA (UPROP, (units)[0].PROP, 8, 16, 0, (numunits), PV_RZRO) }, \ { URDATA (USTATUS, (units)[0].STATUS, 2, 16, 0, (numunits), PV_RZRO) }, \ { URDATA (UOPCODE, (units)[0].OPCODE, 10, 6, 0, (numunits), PV_LEFT | REG_RO) }, \ { URDATA (USTATE, (units)[0].PHASE, 10, 4, 0, (numunits), PV_LEFT | REG_RO) }, \ { URDATA (UPOS, (units)[0].pos, 10, T_ADDR_W, 0, (numunits), PV_LEFT | REG_RO) }, \ { URDATA (UWAIT, (units)[0].wait, 10, 32, 0, (numunits), PV_LEFT | REG_HRO) } /* Tape controller device modifier structure initialization. This initialization should be included BEFORE any device-specific modifiers. The supplied parameters are: cntlr -- the controller state variable structure (CNTLR_VARS) typeset -- the set of drive type flags supported by the interface densset -- the set of drive density flags supported by the interface offvalid -- the interface SET ONLINE/OFFLINE validation function Implementation notes: 1. The IFTYPE and IFDENSITY macros test their respective flag sets and enable or disable the associated modifier entries as indicated. An entry is disabled by setting the print and match strings to NULL; this ensures that the modifier is neither printed nor matched against any user input. 2. The UNIT_RO modifier displays "write ring" if the flag is not set. There is no corresponding entry for the opposite condition because "read only" is automatically printed after the attached filename. */ /* Selectable drive type flags */ #define TL_7970B (1u << HP_7970B) #define TL_7970E (1u << HP_7970E) #define TL_7974 (1u << HP_7974) #define TL_7978 (1u << HP_7978) /* Selectable drive density flags */ #define TL_FIXED 0 #define TL_800 (1u << MT_DENS_800) #define TL_1600 (1u << MT_DENS_1600) #define TL_6250 (1u << MT_DENS_6250) #define IFTYPE(t,s) (TL_##t & (s) ? #t : NULL), \ (TL_##t & (s) ? #t : NULL) #define IFDENSITY(s) ((s) ? "DENSITY" : NULL), \ ((s) ? "DENSITY" : NULL) #define TL_MODS(cntlr,typeset,densset,offvalid) \ /* Mask Value Match Value Print String Match String Validation Display Descriptor */ \ /* ----------- ----------- ------------ ------------ ------------- ------- ----------------- */ \ { UNIT_MODEL, UNIT_7970B, IFTYPE (7970B, typeset), &tl_set_model, NULL, (void *) &(cntlr) }, \ { UNIT_MODEL, UNIT_7970E, IFTYPE (7970E, typeset), &tl_set_model, NULL, (void *) &(cntlr) }, \ { UNIT_MODEL, UNIT_7974, IFTYPE (7974, typeset), &tl_set_model, NULL, (void *) &(cntlr) }, \ { UNIT_MODEL, UNIT_7978, IFTYPE (7978, typeset), &tl_set_model, NULL, (void *) &(cntlr) }, \ \ /* Entry Flags Value Print String Match String Validation Display Descriptor */ \ /* ------------------- ----- ------------ ------------ ---------------- ----------------- ----------------- */ \ { MTAB_XUN, 0, IFDENSITY (densset), &tl_set_density, &tl_show_density, (void *) &(cntlr) }, \ { MTAB_XUN, 0, "CAPACITY", "CAPACITY", &tl_set_reelsize, &tl_show_reelsize, NULL }, \ { MTAB_XUN | MTAB_NMO, 1, "REEL", "REEL", &tl_set_reelsize, &tl_show_reelsize, NULL }, \ \ /* Mask Value Match Value Print String Match String Validation Display Descriptor */ \ /* ------------ ------------ ------------ ------------ ----------- ------- ----------------- */ \ { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", &(offvalid), NULL, NULL }, \ { UNIT_OFFLINE, 0, "online", "ONLINE", &(offvalid), NULL, (void *) &(cntlr) }, \ \ { UNIT_RO, 0, "write ring", NULL, NULL, NULL, NULL }, \ \ /* Entry Flags Value Print String Match String Validation Display Descriptor */ \ /* ------------ ----- ------------ ------------ ----------------- ------------------ ----------------- */ \ { MTAB_XDV, 0, "TIMING", "FASTTIME", &tl_set_timing, &tl_show_timing, (void *) &(cntlr) }, \ { MTAB_XDV, 1, NULL, "REALTIME", &tl_set_timing, NULL, (void *) &(cntlr) }, \ \ { MTAB_XUN, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL } /* Tape library global controller routines */ extern CNTLR_IFN_IBUS tl_controller (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data); extern t_stat tl_onoffline (CVPTR cvptr, UNIT *uptr, t_bool online); extern HP_WORD tl_status (CVPTR cvptr); extern t_stat tl_reset (CVPTR cvptr); extern void tl_clear (CVPTR cvptr); /* Tape library global utility routines */ extern const char *tl_opcode_name (CNTLR_OPCODE opcode); extern const char *tl_unit_name (int32 unit); /* Tape library global SCP support routines */ extern t_stat tl_attach (CVPTR cvptr, UNIT *uptr, CONST char *cptr); extern t_stat tl_detach (UNIT *uptr); extern t_stat tl_set_timing (UNIT *uptr, int32 value, CONST char *cptr, void *desc); extern t_stat tl_set_model (UNIT *uptr, int32 value, CONST char *cptr, void *desc); extern t_stat tl_set_density (UNIT *uptr, int32 value, CONST char *cptr, void *desc); extern t_stat tl_set_reelsize (UNIT *uptr, int32 value, CONST char *cptr, void *desc); extern t_stat tl_show_timing (FILE *st, UNIT *uptr, int32 value, CONST void *desc); extern t_stat tl_show_density (FILE *st, UNIT *uptr, int32 value, CONST void *desc); extern t_stat tl_show_reelsize (FILE *st, UNIT *uptr, int32 value, CONST void *desc);