/* 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 names 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. | |
17-Jan-17 JDB Moved "hp2100_defs.h" inclusion to "hp2100_disclib.c" | |
13-May-16 JDB Modified for revised SCP API function parameter types | |
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 defines the interface between interface simulators and the | |
simulation library for the HP 13037 and 13365 disc controllers. It must be | |
included by the interface-specific modules (DA, DS, etc.). | |
*/ | |
/* Program limits */ | |
#define DL_MAXDRIVE 7 /* last valid drive number */ | |
#define DL_MAXUNIT 10 /* last legal unit number */ | |
#define DL_AUXUNITS 2 /* number of MAC auxiliary units required */ | |
#define DL_WPSEC 128 /* words per normal sector */ | |
#define DL_WPFSEC 138 /* words per full sector */ | |
#define DL_BUFSIZE DL_WPFSEC /* required buffer size in words */ | |
/* Default controller times */ | |
#define DL_EOT_TIME 160 /* end-of-track delay time */ | |
#define DL_SEEK_TIME 100 /* seek delay time (per cylinder) */ | |
#define DL_SECTOR_TIME 27 /* intersector delay time */ | |
#define DL_CMD_TIME 3 /* command start delay time */ | |
#define DL_DATA_TIME 1 /* data transfer delay time */ | |
#define DL_WAIT_TIME 2749200 /* command wait timeout (1.74 seconds) */ | |
/* Common per-unit disc drive state variables */ | |
#define CYL u3 /* current drive cylinder */ | |
#define STAT u4 /* current drive status (Status 2) */ | |
#define OP u5 /* current drive operation in process */ | |
#define PHASE u6 /* current drive operation phase */ | |
/* Unit flags and accessors */ | |
#define UNIT_V_MODEL (UNIT_V_UF + 0) /* bits 1-0: model ID */ | |
#define UNIT_V_WLK (UNIT_V_UF + 2) /* bits 2-2: write locked (protect switch) */ | |
#define UNIT_V_UNLOAD (UNIT_V_UF + 3) /* bits 3-3: heads unloaded */ | |
#define UNIT_V_FMT (UNIT_V_UF + 4) /* bits 4-4: format enabled */ | |
#define UNIT_V_AUTO (UNIT_V_UF + 5) /* bits 5-5: autosize */ | |
#define DL_V_UF (UNIT_V_UF + 6) /* first free unit flag bit */ | |
#define UNIT_M_MODEL 03 /* model ID mask */ | |
#define UNIT_MODEL (UNIT_M_MODEL << UNIT_V_MODEL) | |
#define UNIT_WLK (1 << UNIT_V_WLK) | |
#define UNIT_UNLOAD (1 << UNIT_V_UNLOAD) | |
#define UNIT_FMT (1 << UNIT_V_FMT) | |
#define UNIT_AUTO (1 << UNIT_V_AUTO) | |
#define UNIT_WPROT (UNIT_WLK | UNIT_RO) /* write protected if locked or read-only */ | |
#define GET_MODEL(t) (((t) >> UNIT_V_MODEL) & UNIT_M_MODEL) | |
#define SET_MODEL(t) (((t) & UNIT_M_MODEL) << UNIT_V_MODEL) | |
/* Status-1 accessors */ | |
#define DL_V_S1SPD 13 /* bits 15-13: S/P/D flags */ | |
#define DL_V_S1STAT 8 /* bits 12- 8: controller status */ | |
#define DL_V_S1UNIT 0 /* bits 3- 0: last unit number */ | |
#define DL_M_S1UNIT 017 /* unit number mask */ | |
#define GET_S1UNIT(v) (((v) >> DL_V_S1UNIT) & DL_M_S1UNIT) | |
#define SET_S1SPD(v) ((v) << DL_V_S1SPD) | |
#define SET_S1STAT(v) ((v) << DL_V_S1STAT) | |
#define SET_S1UNIT(v) ((v) << DL_V_S1UNIT) | |
/* Status-2 accessors (+ = kept in unit status, - = determined dynamically) */ | |
#define DL_V_S2ERR 15 /* bits 15-15: (-) any error flag */ | |
#define DL_V_S2DTYP 9 /* bits 12- 9: (-) drive type */ | |
#define DL_V_S2ATN 7 /* bits 7- 7: (+) attention flag */ | |
#define DL_V_S2RO 6 /* bits 6- 6: (-) read only flag */ | |
#define DL_V_S2FMT 5 /* bits 5- 5: (-) format enabled flag */ | |
#define DL_V_S2FAULT 4 /* bits 4- 4: (+) drive fault flag */ | |
#define DL_V_S2FS 3 /* bits 3- 3: (+) first status flag */ | |
#define DL_V_S2SC 2 /* bits 2- 2: (+) seek check flag */ | |
#define DL_V_S2NR 1 /* bits 1- 1: (-) not ready flag */ | |
#define DL_V_S2BUSY 0 /* bits 0- 1: (-) drive busy flag */ | |
#define DL_S2ERR (1 << DL_V_S2ERR) | |
#define DL_S2DTYP (1 << DL_V_S2DTYP) | |
#define DL_S2ATN (1 << DL_V_S2ATN) | |
#define DL_S2RO (1 << DL_V_S2RO) | |
#define DL_S2FMT (1 << DL_V_S2FMT) | |
#define DL_S2FAULT (1 << DL_V_S2FAULT) | |
#define DL_S2FS (1 << DL_V_S2FS) | |
#define DL_S2SC (1 << DL_V_S2SC) | |
#define DL_S2NR (1 << DL_V_S2NR) | |
#define DL_S2BUSY (1 << DL_V_S2BUSY) | |
#define DL_S2STOPS (DL_S2FAULT | DL_S2SC | DL_S2NR) /* bits that stop drive access */ | |
#define DL_S2ERRORS (DL_S2FAULT | DL_S2SC | DL_S2NR | DL_S2BUSY) /* bits that set S2ERR */ | |
#define DL_S2CPS (DL_S2ATN | DL_S2FAULT | DL_S2FS | DL_S2SC) /* bits cleared by Controller Preset */ | |
/* Drive properties. | |
The controller library supports four different disc drive models with these | |
properties: | |
Drive Model Drive Sectors Heads per Cylinders Megabytes | |
Model ID Type per Head Cylinder per Drive per Drive | |
----- ----- ----- -------- --------- --------- --------- | |
7905 0 2 48 3 411 15 | |
7906 1 0 48 4 411 20 | |
7920 2 1 48 5 823 50 | |
7925 3 3 64 9 823 120 | |
The Drive Type is reported by the controller in the second status word | |
(Status-2) returned by the Request Status command. | |
Model IDs are used in the unit flags to identify the unit's model. For the | |
autosizing feature to work, models must be assigned ascending IDs in order of | |
ascending drive sizes. | |
*/ | |
#define D7905_MODEL 0 | |
#define D7905_SECTS 48 | |
#define D7905_HEADS 3 | |
#define D7905_CYLS 411 | |
#define D7905_TYPE (2 << DL_V_S2DTYP) | |
#define D7905_WORDS (D7905_SECTS * D7905_HEADS * D7905_CYLS * DL_WPSEC) | |
#define D7906_MODEL 1 | |
#define D7906_SECTS 48 | |
#define D7906_HEADS 4 | |
#define D7906_CYLS 411 | |
#define D7906_TYPE (0 << DL_V_S2DTYP) | |
#define D7906_WORDS (D7906_SECTS * D7906_HEADS * D7906_CYLS * DL_WPSEC) | |
#define D7920_MODEL 2 | |
#define D7920_SECTS 48 | |
#define D7920_HEADS 5 | |
#define D7920_CYLS 823 | |
#define D7920_TYPE (1 << DL_V_S2DTYP) | |
#define D7920_WORDS (D7920_SECTS * D7920_HEADS * D7920_CYLS * DL_WPSEC) | |
#define D7925_MODEL 3 | |
#define D7925_SECTS 64 | |
#define D7925_HEADS 9 | |
#define D7925_CYLS 823 | |
#define D7925_TYPE (3 << DL_V_S2DTYP) | |
#define D7925_WORDS (D7925_SECTS * D7925_HEADS * D7925_CYLS * DL_WPSEC) | |
#define MODEL_7905 SET_MODEL (D7905_MODEL) | |
#define MODEL_7906 SET_MODEL (D7906_MODEL) | |
#define MODEL_7920 SET_MODEL (D7920_MODEL) | |
#define MODEL_7925 SET_MODEL (D7925_MODEL) | |
/* Controller types */ | |
typedef enum { | |
MAC = 0, | |
ICD, | |
last_type = ICD, /* last valid type */ | |
type_count /* count of controller types */ | |
} CNTLR_TYPE; | |
/* 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, | |
Last_Opcode = Wakeup /* last valid opcode */ | |
} CNTLR_OPCODE; | |
#define DL_OPCODE_MASK 037 | |
/* Controller command phases */ | |
typedef enum { | |
start_phase = 0, | |
data_phase, | |
end_phase, | |
last_phase = end_phase /* last valid phase */ | |
} CNTLR_PHASE; | |
/* 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 | |
- io_program_error | |
- sync_timeout | |
- correctable_data_error | |
- illegal_spare_access | |
- defective_track | |
- protected_track | |
*/ | |
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; | |
/* Controller execution states */ | |
typedef enum { | |
cntlr_idle, /* idle */ | |
cntlr_wait, /* command wait */ | |
cntlr_busy /* busy */ | |
} CNTLR_STATE; | |
/* 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 clear types */ | |
typedef enum { | |
hard_clear, /* power-on/preset hard clear */ | |
soft_clear /* programmed soft clear */ | |
} CNTLR_CLEAR; | |
/* Controller state variables */ | |
typedef struct { | |
CNTLR_TYPE type; /* controller type */ | |
CNTLR_STATE state; /* controller state */ | |
CNTLR_OPCODE opcode; /* controller opcode */ | |
CNTLR_STATUS status; /* controller status */ | |
FLIP_FLOP eoc; /* end-of-cylinder flag */ | |
FLIP_FLOP eod; /* end-of-data flag */ | |
uint32 spd_unit; /* S/P/D flags and unit number */ | |
uint32 file_mask; /* file mask */ | |
uint32 retry; /* retry counter */ | |
uint32 cylinder; /* cylinder address */ | |
uint32 head; /* head address */ | |
uint32 sector; /* sector address */ | |
uint32 verify_count; /* count of sectors to verify */ | |
uint32 poll_unit; /* last unit polled for attention */ | |
uint16 *buffer; /* data buffer pointer */ | |
uint32 index; /* data buffer current index */ | |
uint32 length; /* data buffer valid length */ | |
UNIT *aux; /* MAC auxiliary units (controller and timer) */ | |
int32 eot_time; /* end-of-track read delay time */ | |
int32 seek_time; /* per-cylinder seek delay time */ | |
int32 sector_time; /* intersector delay time */ | |
int32 cmd_time; /* command response time */ | |
int32 data_time; /* data transfer response time */ | |
int32 wait_time; /* command wait time */ | |
} CNTLR_VARS; | |
typedef CNTLR_VARS *CVPTR; /* pointer to controller state variables */ | |
/* Controller state variables initialization. | |
The parameters are: | |
ctype - type of the controller (CNTLR_TYPE) | |
bufptr - pointer to the data buffer | |
auxptr - pointer to the auxiliary units (MAC only; NULL for ICD) | |
*/ | |
#define CNTLR_INIT(ctype,bufptr,auxptr) \ | |
(ctype), cntlr_idle, End, normal_completion, \ | |
CLEAR, CLEAR, \ | |
0, 0, 0, 0, 0, 0, 0, 0, \ | |
(bufptr), 0, 0, (auxptr), \ | |
DL_EOT_TIME, DL_SEEK_TIME, DL_SECTOR_TIME, \ | |
DL_CMD_TIME, DL_DATA_TIME, DL_WAIT_TIME | |
/* Disc library global controller routines */ | |
extern t_bool dl_prepare_command (CVPTR cvptr, UNIT *units, uint32 unit_limit); | |
extern UNIT *dl_start_command (CVPTR cvptr, UNIT *units, uint32 unit_limit); | |
extern void dl_end_command (CVPTR cvptr, CNTLR_STATUS status); | |
extern t_bool dl_poll_drives (CVPTR cvptr, UNIT *units, uint32 unit_limit); | |
extern t_stat dl_service_drive (CVPTR cvptr, UNIT *uptr); | |
extern t_stat dl_service_controller (CVPTR cvptr, UNIT *uptr); | |
extern t_stat dl_service_timer (CVPTR cvptr, UNIT *uptr); | |
extern void dl_idle_controller (CVPTR cvptr); | |
extern t_stat dl_clear_controller (CVPTR cvptr, UNIT *uptr, CNTLR_CLEAR clear_type); | |
extern t_stat dl_load_unload (CVPTR cvptr, UNIT *uptr, t_bool load); | |
/* Disc library global utility routines */ | |
extern CNTLR_CLASS dl_classify (CNTLR_VARS cntlr); | |
extern const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode); | |
extern const char *dl_phase_name (CNTLR_PHASE phase); | |
/* Disc library global VM 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); |