blob: 69abf45d6e0af6f53bc0522acfe5e0bf652c7699 [file] [log] [blame] [raw]
/* hp_disclib.h: HP MAC/ICD disc controller simulator library declarations
Copyright (c) 2011-2017, 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.
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_disclib.c"
13-May-16 JDB Modified for revised SCP API function parameter types
24-Mar-16 JDB Added the DL_BUFFER type to define the disc buffer array
21-Mar-16 JDB Changed uint16 types to HP_WORD
27-Jul-15 JDB First revised release version
21-Feb-15 JDB Revised for new controller interface model
24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash
07-May-12 JDB Added end-of-track delay time as a controller variable
02-May-12 JDB First release
09-Nov-11 JDB Created disc controller common library from DS simulator
This file provides the declarations for interoperation between interface
simulators and the simulation library for the HP 13037 and 13365 disc
controllers. It must be included by the interface-specific modules.
*/
/* Architectural constants.
The type of the disc buffer element is defined. This must be a 16-bit array
for the file representation to be packed.
*/
typedef uint16 DL_BUFFER; /* a buffer containing 16-bit disc data words */
/* Program limits */
#define DL_MAXDRIVE 7 /* last valid drive number */
#define DL_AUXUNITS 1 /* number of MAC auxiliary units required */
#define DL_BUFSIZE 138 /* required buffer size in words (full sector) */
/* Program constants (cylinders * heads * sectors * words per sector) */
#define WORDS_7905 (411 * 3 * 48 * 128) /* 7905 capacity = 15 MB */
#define WORDS_7906 (411 * 4 * 48 * 128) /* 7906 capacity = 20 MB */
#define WORDS_7920 (823 * 5 * 48 * 128) /* 7920 capacity = 50 MB */
#define WORDS_7925 (823 * 9 * 64 * 128) /* 7925 capacity = 120 MB */
/* Debug flags */
#define DL_DEB_CMD (1u << 0) /* trace controller commands */
#define DL_DEB_INCO (1u << 1) /* trace command initiations and completions */
#define DL_DEB_STATE (1u << 2) /* trace command execution state changes */
#define DL_DEB_SERV (1u << 3) /* trace unit service scheduling calls */
#define DL_DEB_XFER (1u << 4) /* trace data reads and writes */
#define DL_DEB_IOB (1u << 5) /* trace I/O bus signals and data words */
#define DL_DEB_V_UF 6 /* first free debug flag bit */
/* Common per-unit disc drive state variables */
#define CYL u3 /* drive cylinder */
#define STATUS u4 /* drive status (Status 2) */
#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 (1u << DEV_REALTIME_SHIFT) /* realistic timing flag */
/* Unit flags and accessors */
#define UNIT_MODEL_SHIFT (UNIT_V_UF + 0) /* bits 0-1: drive model ID */
#define UNIT_PROT_SHIFT (UNIT_V_UF + 2) /* bits 2-3 write protection */
#define UNIT_UNLOAD_SHIFT (UNIT_V_UF + 4) /* bits 4-4: heads unloaded */
#define UNIT_FMT_SHIFT (UNIT_V_UF + 5) /* bits 5-5: format enabled */
#define DL_V_UF (UNIT_V_UF + 6) /* first free unit flag bit */
#define UNIT_MODEL_MASK 0000003u /* model ID mask */
#define UNIT_PROT_MASK 0000003u /* head protection mask */
#define UNIT_MODEL (UNIT_MODEL_MASK << UNIT_MODEL_SHIFT)
#define UNIT_PROT (UNIT_PROT_MASK << UNIT_PROT_SHIFT)
#define UNIT_PROT_L (1u << UNIT_PROT_SHIFT + 0)
#define UNIT_PROT_U (1u << UNIT_PROT_SHIFT + 1)
#define UNIT_UNLOAD (1u << UNIT_UNLOAD_SHIFT)
#define UNIT_FMT (1u << UNIT_FMT_SHIFT)
#define UNIT_7905 (HP_7905 << UNIT_MODEL_SHIFT)
#define UNIT_7906 (HP_7906 << UNIT_MODEL_SHIFT)
#define UNIT_7920 (HP_7920 << UNIT_MODEL_SHIFT)
#define UNIT_7925 (HP_7925 << UNIT_MODEL_SHIFT)
/* Controller flag and function accessors */
#define DLIFN(C) ((CNTLR_IFN_SET) ((C) & ~D16_MASK))
#define DLIBUS(C) ((CNTLR_IBUS) ((C) & D16_MASK))
#define DLNEXTIFN(S) ((CNTLR_IFN) IOPRIORITY (S))
/* Disc drive types */
typedef enum {
HP_All = -1,
HP_7906 = 0, /* these values */
HP_7920 = 1, /* are hard-coded */
HP_7905 = 2, /* in the 13037 */
HP_7925 = 3 /* controller microcode */
} DRIVE_TYPE;
/* Controller types */
typedef enum {
MAC = 0,
ICD,
CS80
} CNTLR_TYPE;
#define LAST_CNTLR CS80
#define CNTLR_COUNT (LAST_CNTLR + 1)
/* Interface flags and function bus orders.
The CNTLR_FLAG and CNTLR_IFN declarations mirror the hardware signals that
are received and asserted, respectively, by the 13037 disc controller. In
simulation, the interface to which the controller is connected sends a set of
one or more flags that indicate the state of the interface to the controller.
The controller then returns a set of one or more functions that request the
interface to perform certain actions.
In hardware, a series of functions are sent sequentially to the interface as
encoded values accompanied by IFVLD (interface function is valid) or IFCLK
(interface function clock) signals. In simulation, the functions are 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.
4. The hardware signal CLEAR is renamed CLEARF in simulation to avoid the
name clash with the flip-flop CLEAR enumeration value. (A sensible
language would allow a definition of CLEAR in each of the enumerations.
However, C has a single name space for all enumeration constants.)
5. In hardware, the BUSY command is used in combination with the LSB of the
data bus to set or clear the interface busy flip-flop. In simulation,
separate BUSY (set busy) and FREE (clear busy) commands are used to allow
the data bus to carry a full 16-bit value.
6. The DVEND function must come numerically after RQSRV, as DVEND will abort
the transfer if no retries are left.
*/
typedef enum { /* interface flags */
CLEARF = 0000001, /* Clear Controller */
CMRDY = 0000002, /* Command Ready */
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 */
BUSY = 000000200000, /* Set Interface Busy */
DSCIF = 000000400000, /* Disconnect Interface */
SELIF = 000001000000, /* Select Interface */
IFIN = 000002000000, /* Interface In */
IFOUT = 000004000000, /* Interface Out */
IFGTC = 000010000000, /* Interface Get Command */
IFPRF = 000020000000, /* Interface Prefetch Command */
RQSRV = 000040000000, /* Request Service */
DVEND = 000100000000, /* Device End */
SRTRY = 000200000000, /* Set Retry Counter */
STDFL = 000400000000, /* Set Data Flag */
STINT = 001000000000, /* Set Interrupt */
WRTIO = 002000000000, /* Write TIO Register */
FREE = 004000000000 /* Set Interface Free */
} 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 */
typedef enum {
Cold_Load_Read = 000,
Recalibrate = 001,
Seek = 002,
Request_Status = 003,
Request_Sector_Address = 004,
Read = 005,
Read_Full_Sector = 006,
Verify = 007,
Write = 010,
Write_Full_Sector = 011,
Clear = 012,
Initialize = 013,
Address_Record = 014,
Request_Syndrome = 015,
Read_With_Offset = 016,
Set_File_Mask = 017,
Invalid_Opcode = 020,
Read_Without_Verify = 022,
Load_TIO_Register = 023,
Request_Disc_Address = 024,
End = 025,
Wakeup = 026
} CNTLR_OPCODE;
#define LAST_OPCODE Wakeup
/* Controller command classifications */
typedef enum {
Class_Invalid, /* invalid classification */
Class_Read, /* read classification */
Class_Write, /* write classification */
Class_Control, /* control classification */
Class_Status /* status classification */
} CNTLR_CLASS;
/* Controller status.
Not all status values are returned by the library. The values not currently
returned are:
- Illegal_Drive_Type
- Cylinder_Miscompare
- Head_Sector_Miscompare
- Sync_Timeout
- Correctable_Data_Error
- Illegal_Spare_Access
- Defective_Track
In hardware, all of the above errors, except for Illegal_Drive_Type and
Correctable_Data_Error, potentially could occur during the address
verification that precedes normal reads and writes. In simulation, these
cannot occur, as sector address headers are not simulated. However, any
error may be returned if diagnostic overrides are used.
In simulation, Uncorrectable_Data_Error is returned by default by the Request
Syndrome command. Uncorrectable_Data_Error is also returned if a host I/O
error occurs on reading or writing.
*/
typedef enum {
Normal_Completion = 000,
Illegal_Opcode = 001,
Unit_Available = 002,
Illegal_Drive_Type = 003,
Cylinder_Miscompare = 007,
Uncorrectable_Data_Error = 010,
Head_Sector_Miscompare = 011,
IO_Program_Error = 012,
Sync_Timeout = 013,
End_of_Cylinder = 014,
Data_Overrun = 016,
Correctable_Data_Error = 017,
Illegal_Spare_Access = 020,
Defective_Track = 021,
Access_Not_Ready = 022,
Status_2_Error = 023,
Protected_Track = 026,
Unit_Unavailable = 027,
Drive_Attention = 037
} CNTLR_STATUS;
#define LAST_STATUS Drive_Attention
/* Controller execution states */
typedef enum {
Idle_State, /* idle */
Wait_State, /* command wait */
Busy_State /* busy */
} CNTLR_STATE;
/* Unit command phases */
typedef enum {
Idle_Phase = 0,
Parameter_Phase,
Seek_Phase,
Rotate_Phase,
Data_Phase,
Intersector_Phase,
End_Phase
} CNTLR_PHASE;
#define LAST_PHASE End_Phase
/* Diagnostic override entries.
Diagnostic overrides are used to return controller status values that
otherwise are not simulated to a diagnostic program. A table of override
entries may be set up by the interface simulator if this facility is desired.
*/
typedef struct {
uint32 cylinder; /* matching cylinder address */
uint32 head; /* matching head address */
uint32 sector; /* matching sector address */
CNTLR_OPCODE opcode; /* matching controller opcode */
uint32 spd; /* returned S/P/D flags */
CNTLR_STATUS status; /* returned controller status */
} DIAG_ENTRY;
#define DL_OVEND D32_UMAX /* marker for the end of the current override set */
/* Disc access delays */
typedef struct {
CNTLR_TYPE type; /* controller type */
DRIVE_TYPE drive; /* drive type */
int32 seek_one; /* track-to-track seek time */
int32 seek_full; /* full-stroke seek time */
int32 sector_full; /* full sector rotation time */
int32 data_xfer; /* per-word data transfer time */
int32 intersector_gap; /* intersector gap time */
int32 overhead; /* controller execution overhead */
} DELAY_PROPS;
#define DELAY_INIT(sk1,skf,scf,dxfr,isg,ovhd) \
(CNTLR_TYPE) 0, (DRIVE_TYPE) 0, \
(sk1), (skf), (scf), (dxfr), (isg), (ovhd)
/* Disc controller state */
typedef struct {
CNTLR_TYPE type; /* controller type */
DEVICE *device; /* controlling device pointer */
CNTLR_STATE state; /* controller state */
CNTLR_OPCODE opcode; /* controller opcode */
CNTLR_STATUS status; /* controller status */
FLIP_FLOP eoc; /* end-of-cylinder flag */
t_bool verify; /* address verification required */
uint32 spd_unit; /* S/P/D flags and unit number */
uint32 file_mask; /* file mask */
uint32 cylinder; /* cylinder address */
uint32 head; /* head address */
uint32 sector; /* sector address */
uint32 count; /* count of words transferred or to verify */
uint32 poll_unit; /* last unit polled for attention */
DL_BUFFER *buffer; /* data buffer pointer */
uint32 index; /* data buffer current index */
uint32 length; /* data buffer valid length */
DIAG_ENTRY *dop_base; /* pointer to the diagnostic override array */
int32 dop_index; /* current diagnostic override entry index */
DELAY_PROPS *fastptr; /* pointer to the FASTTIME delays */
const DELAY_PROPS *dlyptr; /* current delay property pointer */
} CNTLR_VARS;
typedef CNTLR_VARS *CVPTR; /* 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 DL_BUFFER)
doa - a pointer to the diagnostic override array (array of DIAG_ENTRY)
or NULL if this facility is not used
fast - a pointer to the fast timing values (DELAY_PROPS)
*/
#define CNTLR_INIT(ctype,dev,bufptr,doa,fast) \
(ctype), &(dev), Idle_State, End, Normal_Completion, \
CLEAR, FALSE, \
0, 0, 0, 0, 0, 0, 0, \
(bufptr), 0, 0, \
(doa), -1, \
&(fast), &(fast)
/* Disc 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 units in the unit array
buffer - the sector buffer (array of DL_BUFFER)
times - the fast timing values structure (DELAY_PROPS)
Implementation notes:
1. The CNTLR_VARS fields "type", "device", "buffer", "dop_base", "fastptr",
and "dlyptr" do not need to appear in the REG array, as "dlyptr" is reset
by the dl_attach routine during a RESTORE, and the others are static.
2. The fast timing structure does not use the controller and drive type
fields, so they do not appear in hidden registers, as they need not be
SAVEd or RESTOREd.
*/
#define DL_REGS(cntlr,units,numunits,buffer,times) \
/* Macro Name Location Radix Width Depth Flags */ \
/* ------ -------- ------------------ ----- ----- ----------------- ----------------- */ \
{ ORDATA (OPCODE, (cntlr).opcode, 5), REG_RO }, \
{ ORDATA (CSTATS, (cntlr).status, 5), REG_RO }, \
{ DRDATA (CSTATE, (cntlr).state, 2), PV_LEFT | REG_RO }, \
{ FLDATA (EOC, (cntlr).eoc, 0) }, \
{ FLDATA (VERIFY, (cntlr).verify, 0) }, \
{ ORDATA (SPDU, (cntlr).spd_unit, 16) }, \
{ ORDATA (FLMASK, (cntlr).file_mask, 4) }, \
{ DRDATA (CYL, (cntlr).cylinder, 16), PV_LEFT }, \
{ DRDATA (HEAD, (cntlr).head, 6), PV_LEFT }, \
{ DRDATA (SECTOR, (cntlr).sector, 8), PV_LEFT }, \
{ DRDATA (COUNT, (cntlr).count, 16), PV_LEFT }, \
{ BRDATA (SECBUF, (buffer), 8, 16, DL_BUFSIZE), REG_X }, \
{ DRDATA (INDEX, (cntlr).index, 8), PV_LEFT }, \
{ DRDATA (LENGTH, (cntlr).length, 8), PV_LEFT }, \
{ DRDATA (POLLU, (cntlr).poll_unit, 4), REG_HRO }, \
{ DRDATA (DOINDX, (cntlr).dop_index, 16), PV_LEFT | REG_HRO }, \
\
/* Macro Name Location Width Flags */ \
/* ------ ------ ------------------------ ----- ---------------- */ \
{ DRDATA (TTIME, (times).seek_one, 24), PV_LEFT | REG_NZ }, \
{ DRDATA (FTIME, (times).seek_full, 24), PV_LEFT | REG_NZ }, \
{ DRDATA (STIME, (times).sector_full, 24), PV_LEFT | REG_NZ }, \
{ DRDATA (XTIME, (times).data_xfer, 24), PV_LEFT | REG_NZ }, \
{ DRDATA (GTIME, (times).intersector_gap, 24), PV_LEFT | REG_NZ }, \
{ DRDATA (OTIME, (times).overhead, 24), PV_LEFT | REG_NZ }, \
\
/* Macro Name Location Radix Width Offset Depth Flags */ \
/* ------ ------- ------------------ ----- --------- ------ ----------- ----------------- */ \
{ URDATA (UCYL, (units)[0].CYL, 10, 10, 0, (numunits), PV_LEFT) }, \
{ URDATA (UOPCODE, (units)[0].OPCODE, 8, 6, 0, (numunits), PV_RZRO | REG_RO) }, \
{ URDATA (USTATUS, (units)[0].STATUS, 2, 32, 0, (numunits), PV_RZRO) }, \
{ URDATA (USTATE, (units)[0].PHASE, 10, 4, 0, (numunits), PV_RZRO | REG_RO) }, \
{ URDATA (UPOS, (units)[0].pos, 10, T_ADDR_W, 0, (numunits), PV_LEFT | REG_RO) }, \
{ URDATA (UWAIT, (units)[0].wait, 8, 32, 0, (numunits), PV_LEFT) }
/* Disc controller device modifier definitions.
These definitions should be included BEFORE any device-specific modifiers.
*/
#define DL_MODS(cntlr,loadvalid,ovcount) \
/* Mask Value Match Value Print String Match String Validation Display Descriptor */ \
/* ------------ ----------- ----------------- ------------ ------------- ------- ---------- */ \
{ UNIT_MODEL, UNIT_7905, "7905", "7905", &dl_set_model, NULL, NULL }, \
{ UNIT_MODEL, UNIT_7906, "7906", "7906", &dl_set_model, NULL, NULL }, \
{ UNIT_MODEL, UNIT_7920, "7920", "7920", &dl_set_model, NULL, NULL }, \
{ UNIT_MODEL, UNIT_7925, "7925", "7925", &dl_set_model, NULL, NULL }, \
\
{ UNIT_UNLOAD, 0, "heads loaded", "LOAD", &(loadvalid), NULL, NULL }, \
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOAD", &(loadvalid), NULL, NULL }, \
\
{ UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL }, \
{ UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL }, \
\
/* Entry Flags Value Print String Match String Validation Display Descriptor */ \
/* ------------------- ---------- ------------ -------------- ---------------- ----------------- ----------------- */ \
{ MTAB_XUN, 1, "", "PROTECT", &dl_set_protect, &dl_show_protect, NULL }, \
{ MTAB_XUN, 0, NULL, "UNPROTECT", &dl_set_protect, NULL, NULL }, \
\
{ MTAB_XDV, 0, NULL, "FASTTIME", &dl_set_timing, NULL, (void *) &(cntlr) }, \
{ MTAB_XDV, 1, NULL, "REALTIME", &dl_set_timing, NULL, (void *) &(cntlr) }, \
{ MTAB_XDV, 0, "TIMING", NULL, NULL, &dl_show_timing, (void *) &(cntlr) }, \
\
{ MTAB_XDV | MTAB_NMO, (ovcount), "DIAG", "DIAGNOSTIC", &dl_set_diag, &dl_show_diag, (void *) &(cntlr) }, \
{ MTAB_XDV, 0, "", "NODIAGNOSTIC", &dl_set_diag, &dl_show_diag, (void *) &(cntlr) }
/* Disc library global controller routines */
extern CNTLR_IFN_IBUS dl_controller (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data);
extern t_stat dl_load_unload (CVPTR cvptr, UNIT *uptr, t_bool load);
/* Disc library global utility routines */
extern const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode);
extern const char *dl_status_name (CNTLR_STATUS status);
/* Disc library global SCP support routines */
extern t_stat dl_attach (CVPTR cvptr, UNIT *uptr, CONST char *cptr);
extern t_stat dl_detach (CVPTR cvptr, UNIT *uptr);
extern t_stat dl_set_model (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
extern t_stat dl_set_protect (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
extern t_stat dl_set_diag (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
extern t_stat dl_set_timing (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
extern t_stat dl_show_protect (FILE *st, UNIT *uptr, int32 value, CONST void *desc);
extern t_stat dl_show_diag (FILE *st, UNIT *uptr, int32 value, CONST void *desc);
extern t_stat dl_show_timing (FILE *st, UNIT *uptr, int32 value, CONST void *desc);