mirror of
https://github.com/rcornwell/sims.git
synced 2026-02-18 13:27:51 +00:00
SEL32: Fix ADFD, SUFD, MPFD, DVFD instructions display. SEL32: Change console output to handle 8 bit parity for UTX. SEL32: Correct RPSWT instruction for V9 processor. SEL32: Reverse scan order of channel complete and interrupts. SEL32: Move memory and map register r/w macros to sel32_defs.h.
1393 lines
66 KiB
C
1393 lines
66 KiB
C
/* sel32_hsdp.c: SEL-32 8064 High Speed Disk Processor
|
|
|
|
Copyright (c) 2018-2019, James C. Bevier
|
|
Portions provided by Richard Cornwell and other SIMH contributers
|
|
|
|
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
|
|
JAMES C. BEVIER 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.
|
|
*/
|
|
|
|
#include "sel32_defs.h"
|
|
|
|
extern t_stat set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
|
|
extern t_stat show_dev_addr(FILE * st, UNIT * uptr, int32 v, CONST void *desc);
|
|
extern void chan_end(uint16 chan, uint8 flags);
|
|
extern int chan_read_byte(uint16 chsa, uint8 *data);
|
|
extern int chan_write_byte(uint16 chsa, uint8 *data);
|
|
extern void set_devattn(uint16 addr, uint8 flags);
|
|
extern t_stat chan_boot(uint16 addr, DEVICE *dptr);
|
|
extern int test_write_byte_end(uint16 chsa);
|
|
|
|
extern uint32 M[]; /* our memory */
|
|
extern uint32 SPAD[]; /* cpu SPAD memory */
|
|
|
|
#ifdef NUM_DEVS_HSDP
|
|
#define UNIT_V_TYPE (UNIT_V_UF + 0)
|
|
#define UNIT_TYPE (0xf << UNIT_V_TYPE)
|
|
|
|
#define GET_TYPE(x) ((UNIT_TYPE & (x)) >> UNIT_V_TYPE)
|
|
#define SET_TYPE(x) (UNIT_TYPE & ((x) << UNIT_V_TYPE))
|
|
#define UNIT_HSDP UNIT_ATTABLE | UNIT_IDLE
|
|
|
|
/* INCH command information */
|
|
/*
|
|
WD 0 - Data address
|
|
WD 1 - Flags - 0 -36 byte count
|
|
|
|
Data - 224 word INCH buffer address (SST)
|
|
WD 1 Drive 0 Attribute register
|
|
WD 2 Drive 1 Attribute register
|
|
WD 3 Drive 2 Attribute register
|
|
WD 4 Drive 3 Attribute register
|
|
WD 5 Drive 4 Attribute register
|
|
WD 6 Drive 5 Attribute register
|
|
WD 7 Drive 6 Attribute register
|
|
WD 8 Drive 7 Attribute register
|
|
|
|
Drive attribute register bit assignments (DATR)
|
|
Byte 0 bits 0-7 - Flags
|
|
Drive type
|
|
bits 0&1 - 00=Undefined
|
|
- 01=MHD
|
|
- 10=Undefined
|
|
- 11=Undefined
|
|
Optimized seeks
|
|
bit 2&3 - 00=Optimize seeks and post IOCL status out of order
|
|
- 01=Optimize seeks and post IOCL status in order
|
|
- 10=Do not optimize seeks
|
|
- 11=Do not optimize seeks
|
|
bit 4 - 0=Drive is present
|
|
- 1=Drive not present
|
|
bit 5 - 0=Not Dual Port
|
|
- 1=Dual Port
|
|
Sector Size
|
|
bit 6&7 - 00=768 bytes
|
|
01=1024 bytes
|
|
10=2048 bytes
|
|
11=Unassigned
|
|
Byte 1 bits 8-15 - Sectors per track
|
|
Byte 2 bits 16-23 - Number of head
|
|
Byte 3 bits 24-31 - Reserved (zero)
|
|
*/
|
|
|
|
/*
|
|
Drive status bit assignments (DSR)
|
|
Byte 0 bits 0-7
|
|
bit 00 - Seek End
|
|
01 - Unit selected
|
|
02 - Sector pulse counter bit 0
|
|
03 - Sector pulse counter bit 1
|
|
04 - Sector pulse counter bit 2
|
|
05 - Sector pulse counter bit 3
|
|
06 - Sector pulse counter bit 4
|
|
07 - Sector pulse counter bit 5
|
|
Byte 1 bits 7-15
|
|
bit 08 - Disc drive fault
|
|
09 - Seek error
|
|
10 - On cylinder
|
|
11 - Unit Ready
|
|
12 - Write protected
|
|
13 - Drive busy
|
|
14 - Reserved (zero)
|
|
15 - Reserved (zero)
|
|
*/
|
|
|
|
/* Subchannel Target Register (STAR) */
|
|
/* byte 0 - Cylinder MS byte */
|
|
/* byte 1 - Cylinder LS byte */
|
|
/* byte 2 - Track count */
|
|
/* byte 3 - Sector count */
|
|
|
|
/* Mode Register (MODE) */
|
|
/* Bits 0-7 - bit assignments */
|
|
|
|
/* Bits 0-3 are for data recovery operations which can be */
|
|
/* tried by the software */
|
|
/* 0 - Servo offset 0/1=disable/enable */
|
|
/* 1 - Servo offset polarity 0/1=positive/negative */
|
|
/* 2 - Data strobe offset 0/1=disable/enable */
|
|
/* 3 - Data strobe offset polarity 0/1=positive/negative */
|
|
/* Bit 4 enables sector ECC data to be read or written for */
|
|
/* diagnostic commands */
|
|
/* 4 - Read/write ECC data 0/1=disable/enable */
|
|
/* Bit 5 controls the transfer of an ID during express bus */
|
|
/* read commands */
|
|
/* 5 - Express bus ID 0/1=enable/disable */
|
|
/* Bit 6 enables auto-retry in accordance with the firmware */
|
|
/* auto-retry algorithms */
|
|
/* 6 - Auto retry 0/1=enable/disable */
|
|
/* Bit 7 disables the subchannel from interacting with the */
|
|
/* disc drive and is for diagnostic testing only */
|
|
/* 7 - Diagnostic mode 0/1=disable/enable */
|
|
|
|
/* Sense Buffer Register (SBR) */
|
|
/* The SBR contains subchannel error status information */
|
|
/* Byte 0
|
|
* bit 00 Command rejected (CR)
|
|
* 01 Intervention requested (IR)
|
|
* 02 Unit select error (USEL)
|
|
* 03 Equipment check (EQCK)
|
|
* 04 Reserved (zero)
|
|
* 05 Reserved (zero)
|
|
* 06 Disc format error (DFER)
|
|
* 07 Defective track encountered (DETR)
|
|
* Byte 1
|
|
* bit 08 Reserved (zero)
|
|
* 09 At alternate track (AATT)
|
|
* 10 Write protect error (WPER)
|
|
* 11 Write lock error (WRL)
|
|
* 12 Mode check (MOCK)
|
|
* 13 Invalid address (INAD)
|
|
* 14 Release fault (RELF)
|
|
* 15 Chaining error (CHER)
|
|
* Byte 2
|
|
* bit 16 Revolution lost (REVL)
|
|
* 17 Disc addressing or seek error
|
|
* 18 Reserved (zero)
|
|
* 19 Reserved (zero)
|
|
* 20 ECC error in data (ECCD)
|
|
* 21 Reserved (zero)
|
|
* 22 Reserved (zero)
|
|
* 23 Uncorrectable ECC error (UECC)
|
|
* Byte 3
|
|
* Not used
|
|
* */
|
|
|
|
/* 224 word Subchannel Storage Buffer (SST) */
|
|
/* 128 words reserved */
|
|
/* 66 words (33 DW) of program status queue (PSQ) */
|
|
/* 8 words of retry counters (1/channel) */
|
|
/* 22 words reserved */
|
|
|
|
#define CMD u3
|
|
/* u3 */
|
|
/* in u3 is device command code and status */
|
|
#define DSK_CMDMSK 0x00ff /* Command being run */
|
|
#define DSK_STAR 0x0100 /* STAR value in u4 */
|
|
#define DSK_NU2 0x0200 /* */
|
|
#define DSK_READDONE 0x0400 /* Read finished, end channel */
|
|
#define DSK_ENDDSK 0x0800 /* Sensed end of disk */
|
|
#define DSK_SEEKING 0x1000 /* Disk is currently seeking */
|
|
#define DSK_READING 0x2000 /* Disk is reading data */
|
|
#define DSK_WRITING 0x4000 /* Disk is writing data */
|
|
#define DSK_BUSY 0x8000 /* Disk is busy */
|
|
/* commands */
|
|
#define DSK_INCH 0x00 /* Initialize channel */
|
|
#define DSK_WD 0x01 /* Write data */
|
|
#define DSK_RD 0x02 /* Read data */
|
|
#define DSK_NOP 0x03 /* No operation */
|
|
#define DSK_SNS 0x04 /* Sense */
|
|
#define DSK_SKC 0x07 /* Seek cylinder, track, sector */
|
|
#define DSK_TIC 0x08 /* Transfer in channel */
|
|
#define DSK_FMT 0x0B /* Format track */
|
|
#define DSK_RE 0x12 /* Read express bus with ECC */
|
|
//#define DSK_LPL 0x13 /* Lock protected label */
|
|
#define DSK_LMR 0x1F /* Load mode register */
|
|
#define DSK_RENO 0x22 /* Read express bus with no ECC */
|
|
#define DSK_RES 0x23 /* Reserve */
|
|
#define DSK_WSL 0x31 /* Write sector label */
|
|
#define DSK_RSL 0x32 /* Read sector label */
|
|
#define DSK_REL 0x33 /* Release */
|
|
#define DSK_XEZ 0x37 /* Rezero */
|
|
#define DSK_WTF 0x41 /* Write track format */
|
|
#define DSK_RVL 0x42 /* Read vendor label */
|
|
#define DSK_POR 0x43 /* Priority Override */
|
|
#define DSK_IHA 0x47 /* Increment head address */
|
|
//#define DSK_SRM 0x4F /* Set reserve track mode */
|
|
#define DSK_WTL 0x51 /* Write track label */
|
|
#define DSK_RTL 0x52 /* Read track label */
|
|
//#define DSK_XRM 0x5F /* Reset reserve track mode */
|
|
#define DSK_RAP 0xA2 /* Read angular position */
|
|
//#define DSK_TESS 0xAB /* Test STAR (subchannel target address register) */
|
|
#define DSK_REC 0xB2 /* Read ECC */
|
|
#define DSK_FINC 0xC0 /* Fake while in srv Initialize channel */
|
|
#define DSK_INC 0xFF /* Initialize Controller */
|
|
|
|
#define STAR u4
|
|
/* u4 - sector target address register (STAR) */
|
|
/* Holds the current cylinder, head(track), sector */
|
|
#define DISK_CYL 0xFFFF0000 /* cylinder mask */
|
|
#define DISK_TRACK 0x0000FF00 /* track mask */
|
|
#define DISK_SECTOR 0x000000ff /* sector mask */
|
|
|
|
#define SNS u5
|
|
/* u5 */
|
|
/* Sense byte 0 - mode register */
|
|
#define SNS_DROFF 0x80000000 /* Drive Carriage will be offset */
|
|
#define SNS_TRKOFF 0x40000000 /* Track offset: 0=positive, 1=negative */
|
|
#define SNS_RDTMOFF 0x20000000 /* Read timing offset = 1 */
|
|
#define SNS_RDSTRBT 0x10000000 /* Read strobe timing: 1=positive, 0=negative */
|
|
#define SNS_DIAGMOD 0x08000000 /* Diagnostic Mode ECC Code generation and checking */
|
|
#define SNS_RSVTRK 0x04000000 /* Reserve Track mode: 1=OK to write, 0=read only */
|
|
#define SNS_FHDOPT 0x02000000 /* FHD or FHD option = 1 */
|
|
#define SNS_RESERV 0x01000000 /* Reserved */
|
|
|
|
/* Sense byte 1 */
|
|
#define SNS_CMDREJ 0x800000 /* Command reject */
|
|
#define SNS_INTVENT 0x400000 /* Unit intervention required */
|
|
#define SNS_SPARE1 0x200000 /* Spare */
|
|
#define SNS_EQUCHK 0x100000 /* Equipment check */
|
|
#define SNS_DATCHK 0x080000 /* Data Check */
|
|
#define SNS_OVRRUN 0x040000 /* Data overrun/underrun */
|
|
#define SNS_DSKFERR 0x020000 /* Disk format error */
|
|
#define SNS_DEFTRK 0x010000 /* Defective track encountered */
|
|
|
|
/* Sense byte 2 */
|
|
#define SNS_LAST 0x8000 /* Last track flag encountered */
|
|
#define SNS_AATT 0x4000 /* At Alternate track */
|
|
#define SNS_WPER 0x2000 /* Write protection error */
|
|
#define SNS_WRL 0x1000 /* Write lock error */
|
|
#define SNS_MOCK 0x0800 /* Mode check */
|
|
#define SNS_INAD 0x0400 /* Invalid memory address */
|
|
#define SNS_RELF 0x0200 /* Release fault */
|
|
#define SNS_CHER 0x0100 /* Chaining error */
|
|
|
|
/* Sense byte 3 */
|
|
#define SNS_REVL 0x80 /* Revolution lost */
|
|
#define SNS_DADE 0x40 /* Disc addressing or seek error */
|
|
#define SNS_BUCK 0x20 /* Buffer check */
|
|
#define SNS_ECCS 0x10 /* ECC error in sector label */
|
|
#define SNS_ECCD 0x08 /* ECC error iin data */
|
|
#define SNS_ECCT 0x04 /* ECC error in track label */
|
|
#define SNS_RTAE 0x02 /* Reserve track access error */
|
|
#define SNS_UESS 0x01 /* Uncorrectable ECC error */
|
|
|
|
#define ATTR u6
|
|
/* u6 holds drive attribute entry */
|
|
/* provided by inch command for controller */
|
|
/*
|
|
bits 0-7 - Flags
|
|
bits 0&1 - 00=Reserved, 01=MHD, 10=FHD, 11=MHD with FHD option
|
|
bit 2 - 1=Cartridge module drive
|
|
bit 3 - 0=Reserved
|
|
bit 4 - 1=Drive not present
|
|
bit 5 - 1=Dual Port
|
|
bit 6 - 0=Reserved
|
|
bit 7 - 0=Reserved
|
|
bits 8-15 - sector count (sectors per track)(F16=16, F20=20)
|
|
bits 16-23 - MHD Head count (number of heads on MHD)
|
|
bits 24-31 - FHD head count (number of heads on FHD or number head on FHD option of
|
|
mini-module)
|
|
*/
|
|
|
|
#define DDATA up7
|
|
/* Pointer held in up7 */
|
|
/* sects/cylinder = sects/track * numhds */
|
|
/* allocated during attach command for each unit defined */
|
|
struct ddata_t
|
|
{
|
|
uint16 cyl; /* Cylinder head at */
|
|
uint16 tpos; /* Track position */
|
|
uint16 spos; /* Sector position */
|
|
};
|
|
|
|
/* disk definition structure */
|
|
struct hsdp_t
|
|
{
|
|
const char *name; /* Device ID Name */
|
|
uint32 taus; /* total allocation units */
|
|
uint16 bms; /* bit map size */
|
|
uint16 nhds; /* Number of heads */
|
|
uint16 ssiz; /* sector size in words */
|
|
uint16 spt; /* # sectors per track(cylinder) */
|
|
uint8 spau; /* # sectors per allocation unit */
|
|
uint8 spb; /* # sectors per block (256 WDS)*/
|
|
uint32 cyl; /* Number of cylinders */
|
|
uint32 geom; /* disk star geometry cyl(16) hsd(8) sec(8) */
|
|
uint8 type; /* Device type code */
|
|
}
|
|
|
|
hsdp_type[] =
|
|
{
|
|
/* Class F Disc Devices */ /*XX CYL SIZE */
|
|
{"MH040", 20000, 625, 5, 256, 16, 2, 1, 400, 0, 0x40}, /*0 411 40 M */
|
|
{"MH080", 40000, 1250, 5, 256, 16, 2, 1, 800, 0, 0x40}, /*1 823 80 M 9342 */
|
|
{"MH160", 80000, 1250, 10, 256, 16, 4, 1, 1600, 0, 0x40}, /*2 823 160 M 8148 */
|
|
// {"MH300", 76000, 2375, 19, 256, 16, 4, 1, 800, 0, 0x40}, /*3 823 300 M 9346 */
|
|
// {"MH300", 80000, 2500, 10, 256, 35, 4, 1, 800, 0, 0x40}, /*3 823 300 M 8887 */
|
|
// {"MH300", 80000, 2500, 10, 256, 34, 4, 1, 820, 0, 0x40}, /*3 823 300 M 8887 */
|
|
{"8887", 80000, 2500, 10, 256, 34, 4, 1, 844, 0, 0x40}, /*3 823 300 M 8887 */
|
|
{"MH300", 80000, 2500, 10, 256, 34, 4, 1, 844, 0, 0x40}, /*3 823 300 M 8887 */
|
|
{"MH340", 76000, 2375, 24, 256, 16, 4, 1, 800, 0, 0x40}, /*4 711 340 M 8858 */
|
|
{"FH005", 5120, 184, 4, 256, 16, 1, 1, 64, 0, 0x80}, /*5 64 5 M */
|
|
{"CD032", 8000, 250, 1, 256, 16, 2, 1, 800, 0, 0x60}, /*6 823 32 M */
|
|
{"CD032", 8000, 250, 1, 256, 16, 2, 1, 800, 0, 0x60}, /*7 823 32 M */
|
|
{"CD064", 8000, 250, 1, 256, 16, 2, 1, 800, 0, 0x60}, /*8 823 64 M */
|
|
{"CD064", 24000, 750, 3, 256, 16, 2, 1, 800, 0, 0x60}, /*9 823 64 M */
|
|
{"CD096", 8000, 250, 1, 256, 16, 2, 1, 800, 0, 0x60}, /*10 823 96 M */
|
|
{"CD096", 40000, 1250, 5, 256, 16, 2, 1, 800, 0, 0x60}, /*11 823 96 M */
|
|
{"MH600", 80000, 2500, 40, 256, 16, 8, 1, 800, 0, 0x40}, /*12 843 600 M */
|
|
{"FM600", 80000, 2500, 40, 256, 16, 8, 1, 800, 0, 0x40}, /*13 843 600 M */
|
|
{"FM600", 1600, 50, 40, 256, 16, 1, 1, 2, 0, 0x80}, /*14 10 600 M */
|
|
{NULL, 0}
|
|
};
|
|
|
|
#if 0
|
|
*****************************************************************
|
|
* DEVICE ID TABLE
|
|
*****************************************************************
|
|
SPACE
|
|
BOUND 1W
|
|
DID.TBL EQU $ MPX1.X
|
|
*
|
|
*DEVICE ID NAME..................................................
|
|
*TOTAL ALLOC. UNITS..................................... :
|
|
*BIT MAP SIZE .............................. : :
|
|
*NO. OF HEADS ........................ : : :
|
|
*SECTOR SIZE ................... : : : :
|
|
*SECTORS/TRACK .............. : : : : :
|
|
*SECTORS/ALOC. UNIT.......... : : : : : :
|
|
*SECTORS/BLOCK ....... : : : : : : :
|
|
*OLD DEVICE ID NAME.... : : : : : : : :
|
|
* : : : : : : : : :
|
|
* ......:..:..:...:....:....:.....:......:........:
|
|
DID FORM 32, 8, 8, 8, 8, 16, 16, 32, 64
|
|
SPACE
|
|
* CLASS 'F' EXTENDED I/O DISC DEVICES (MPX 1.X)
|
|
DID C'DF01', 3, 3, 26, 64, 2, , 1334, C'FL001'
|
|
DID C'DF02', 1, 2, 20, 192, 5, 625, 20000, C'MH040'
|
|
DID C'DF03', 1, 2, 20, 192, 5, 1250, 40000, C'MH080'
|
|
DID C'DF04', 1, 4, 20, 192, 19, 2375, 76000, C'MH300'
|
|
DID C'DF05', 1, 1, 20, 192, 4, 184, 5120, C'FH005'
|
|
DID C'DF06', 1, 2, 20, 192, 1, 250, 8000, C'CD032'
|
|
DID C'DF06', 1, 2, 20, 192, 1, 250, 8000, C'CD032'
|
|
DID C'DF07', 1, 2, 20, 192, 1, 250, 8000, C'CD064'
|
|
DID C'DF07', 1, 2, 20, 192, 3, 750, 24000, C'CD064'
|
|
DID C'DF08', 1, 2, 20, 192, 1, 250, 8000, C'CD096'
|
|
DID C'DF08', 1, 2, 20, 192, 5, 1250, 40000, C'CD096'
|
|
DID C'DF09', 1, 8, 20, 192, 40, 2500, 80000, C'MH600'
|
|
DID C'DF0A', 1, 8, 20, 192, 40, 2500, 80000, C'FM600'
|
|
DID C'DF0A', 1, 1, 20, 192, 40, 50, 1600, C'FM600'
|
|
*
|
|
BOUND 1W
|
|
DID.TBL EQU $ MPX3.X
|
|
*
|
|
*DEVICE ID NAME..................................................
|
|
*TOTAL SECTORS ......................................... :
|
|
*BIT MAP SIZE .............................. : :
|
|
*NO. OF HEADS ........................ : : :
|
|
*SECTOR SIZE ................... : : : :
|
|
*SECTORS/TRACK .............. : : : : :
|
|
*SECTORS/ALOC. UNIT.......... : : : : : :
|
|
*SECTORS/BLOCK ....... : : : : : : :
|
|
*OLD DEVICE ID NAME.... : : : : : : : :
|
|
* : : : : : : : : :
|
|
* ......:..:..:...:....:....:.....:......:........:
|
|
DID FORM 32, 8, 8, 8, 8, 16, 16, 32, 64
|
|
SPACE
|
|
* CLASS 'F' EXTENDED I/O DISC DEVICES MPX3.X
|
|
DID C'DF01', 3, 1, 26, 64, 2, , 4004, C'FL001 '
|
|
DID C'DF02', 1, 2, 20, 192, 5, 642, 41100, C'MH040 '
|
|
DID C'DF03', 1, 2, 20, 192, 5, 1286, 82300, C'MH080 '
|
|
DID C'DF04', 1, 4, 20, 192, 19, 2444,312740, C'MH300 '
|
|
DID C'DF05', 1, 1, 20, 192, 4, 160, 5120, C'FH005 '
|
|
DID C'DF06', 1, 2, 20, 192, 1, 258, 16460, C'CD032 '
|
|
DID C'DF06', 1, 2, 20, 192, 1, 258, 16460, C'CD032 '
|
|
DID C'DF07', 1, 2, 20, 192, 1, 258, 16460, C'CD064 '
|
|
DID C'DF07', 1, 2, 20, 192, 3, 772, 49380, C'CD064 '
|
|
DID C'DF08', 1, 2, 20, 192, 1, 258, 16460, C'CD096 '
|
|
DID C'DF08', 1, 2, 20, 192, 5, 1286, 82300, C'CD096 '
|
|
DID C'DF09', 1,10, 20, 192, 40, 2635,674400, C'MH600 '
|
|
DID C'DF0A', 1,10, 20, 192, 40, 2635,674400, C'FM600 '
|
|
DID C'DF0A', 1, 1, 20, 192, 96, 60, 1920, C'FM600 '
|
|
DID C'DF0B', 1, 4, 20, 192, 10, 1286,164600, C'MH160 '
|
|
DID C'DF0C', 1, 2, 20, 192, 5, 1286, 00, C'ANY '
|
|
DID C'DF0D', 1, 4, 20, 192, 24, 2670,341280, C'MH340 '
|
|
*
|
|
#endif
|
|
|
|
uint8 hsdp_preio(UNIT *uptr, uint16 chan) ;
|
|
uint8 hsdp_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) ;
|
|
uint8 hsdp_haltio(uint16 addr);
|
|
t_stat hsdp_srv(UNIT *);
|
|
t_stat hsdp_boot(int32, DEVICE *);
|
|
void hsdp_ini(UNIT *, t_bool);
|
|
t_stat hsdp_reset(DEVICE *);
|
|
t_stat hsdp_attach(UNIT *, CONST char *);
|
|
t_stat hsdp_detach(UNIT *);
|
|
t_stat hsdp_set_type(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat hsdp_get_type(FILE * st, UNIT * uptr, int32 v, CONST void *desc);
|
|
t_stat hsdp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
|
const char *hsdp_description (DEVICE *dptr);
|
|
|
|
/* channel program information */
|
|
CHANP dpa_chp[NUM_UNITS_HSDP] = {0};
|
|
|
|
MTAB hsdp_mod[] = {
|
|
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "TYPE", "TYPE",
|
|
&hsdp_set_type, &hsdp_get_type, NULL, "Type of disk"},
|
|
{MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
|
|
&show_dev_addr, NULL, "Device channel address"},
|
|
{0}
|
|
};
|
|
|
|
UNIT dpa_unit[] = {
|
|
/* SET_TYPE(3) DM300 */
|
|
/* SET_TYPE(4) 8887 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0x800)}, /* 0 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0x802)}, /* 1 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0x804)}, /* 2 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0x806)}, /* 3 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0x808)}, /* 4 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0x80A)}, /* 5 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0x80C)}, /* 6 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0x80E)}, /* 7 */
|
|
};
|
|
|
|
DIB dpa_dib = {
|
|
hsdp_preio, /* Pre start I/O */
|
|
hsdp_startcmd, /* Start a command */
|
|
NULL, /* Stop I/O */
|
|
NULL, /* Test I/O */
|
|
NULL, /* Post I/O */
|
|
hsdp_ini, /* init function */
|
|
dpa_unit, /* Pointer to units structure */
|
|
dpa_chp, /* Pointer to chan_prg structure */
|
|
NUM_UNITS_HSDP, /* number of units defined */
|
|
0x0E, /* 16 devices - device mask */
|
|
0x0800, /* parent channel address */
|
|
0, /* fifo input index */
|
|
0, /* fifo output index */
|
|
{0}, /* interrupt status fifo for channel */
|
|
};
|
|
|
|
DEVICE dpa_dev = {
|
|
"DPA", dpa_unit, NULL, hsdp_mod,
|
|
NUM_UNITS_HSDP, 16, 24, 4, 16, 32,
|
|
NULL, NULL, &hsdp_reset, &hsdp_boot, &hsdp_attach, &hsdp_detach,
|
|
&dpa_dib, DEV_DISABLE|DEV_DEBUG, 0, dev_debug,
|
|
NULL, NULL, &hsdp_help, NULL, NULL, &hsdp_description
|
|
};
|
|
|
|
#if NUM_DEVS_HSDP > 1
|
|
/* channel program information */
|
|
CHANP dpb_chp[NUM_UNITS_HSDP] = {0};
|
|
|
|
UNIT dpb_unit[] = {
|
|
/* SET_TYPE(3) DM300 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0xC00)}, /* 0 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0xC02)}, /* 1 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0xC04)}, /* 2 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0xC06)}, /* 3 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0xC08)}, /* 4 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0xC0A)}, /* 5 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0xC0C)}, /* 6 */
|
|
{UDATA(&hsdp_srv, UNIT_HSDP|SET_TYPE(3), 0), 0, UNIT_ADDR(0xC0E)}, /* 7 */
|
|
};
|
|
|
|
|
|
DIB dpb_dib = {
|
|
hsdp_preio, /* Pre Start I/O */
|
|
hsdp_startcmd, /* Start a command SIO */
|
|
NULL, /* Stop I/O HIO */
|
|
NULL, /* Test I/O TIO */
|
|
NULL, /* Post I/O */
|
|
hsdp_ini, /* init function */
|
|
dpb_unit, /* Pointer to units structure */
|
|
dpb_chp, /* Pointer to chan_prg structure */
|
|
NUM_UNITS_HSDP, /* number of units defined */
|
|
0x0E, /* 8 devices - device mask */
|
|
0x0C00, /* parent channel address */
|
|
0, /* fifo input index */
|
|
0, /* fifo output index */
|
|
{0}, /* interrupt status fifo for channel */
|
|
};
|
|
|
|
DEVICE dpb_dev = {
|
|
"DPB", dpb_unit, NULL, hsdp_mod,
|
|
NUM_UNITS_HSDP, 16, 24, 4, 16, 32,
|
|
NULL, NULL, &hsdp_reset, &hsdp_boot, &hsdp_attach, &hsdp_detach,
|
|
&dpb_dib, DEV_DISABLE|DEV_DEBUG, 0, dev_debug,
|
|
NULL, NULL, &hsdp_help, NULL, NULL, &hsdp_description
|
|
};
|
|
#endif
|
|
|
|
/* start a disk operation */
|
|
uint8 hsdp_preio(UNIT *uptr, uint16 chan)
|
|
{
|
|
DEVICE *dptr = find_dev_from_unit(uptr);
|
|
uint16 addr = GET_UADDR(uptr->CMD);
|
|
int unit = (uptr - dptr->units);
|
|
|
|
//TRY if ((uptr->CMD & 0xff00) != 0) { /* just return if busy */
|
|
if (uptr->CMD & DSK_BUSY) { /* just return if busy */
|
|
return SNS_BSY;
|
|
}
|
|
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_preio unit=%02x chsa=%04x OK\n", unit, addr);
|
|
return 0; /* good to go */
|
|
}
|
|
|
|
uint8 hsdp_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
|
|
{
|
|
uint16 addr = GET_UADDR(uptr->CMD);
|
|
DEVICE *dptr = find_dev_from_unit(uptr);
|
|
int unit = (uptr - dptr->units);
|
|
uint8 ch;
|
|
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd addr %04x unit %02x cmd %02x CMD %08x\n",
|
|
addr, unit, cmd, uptr->CMD);
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd unit %02x not attached\n", unit);
|
|
uptr->SNS |= SNS_INTVENT; /* unit intervention required */
|
|
if (cmd != DSK_SNS) /* we are completed with unit check status */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
|
}
|
|
|
|
if ((uptr->CMD & DSK_CMDMSK) != 0) {
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd unit %02x busy\n", unit);
|
|
uptr->CMD |= DSK_BUSY; /* Flag we we are busy */
|
|
return SNS_BSY;
|
|
}
|
|
if ((uptr->CMD & 0xff00) != 0) { /* if any status info, we are busy */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd unit %02x busy2\n", unit);
|
|
return SNS_BSY;
|
|
}
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd CMD continue unit=%02x cmd %02x\n", unit, cmd);
|
|
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* see if unit is attached */
|
|
if (cmd == DSK_SNS) { /* not attached, is cmd Sense 0x04 */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd CMD sense\n");
|
|
/* bytes 0,1 - Cyl entry from STAR reg in STAR */
|
|
ch = (uptr->STAR >> 24) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_startcmd sense STAR b0 unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(addr, &ch) ;
|
|
ch = (uptr->STAR >> 16) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_startcmd sense STAR b1 unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(addr, &ch) ;
|
|
/* byte 2 - Track entry from STAR reg in STAR */
|
|
ch = (uptr->STAR >> 8) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_startcmd sense STAR b2 unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(addr, &ch) ;
|
|
/* byte 3 - Sector entry from STAR reg in STAR */
|
|
ch = (uptr->STAR) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_startcmd sense STAR b3 unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(addr, &ch) ;
|
|
/* bytes 4 - mode reg, byte 0 of SNS */
|
|
ch = (uptr->SNS >> 24) & 0xff; /* return the sense data for device */
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_startcmd sense unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(addr, &ch) ;
|
|
/* bytes 5-7 - status bytes, bytes 1-3 of SNS */
|
|
ch = (uptr->SNS >> 16) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_startcmd sense unit=%02x %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(addr, &ch) ;
|
|
ch = (uptr->SNS >> 8) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_startcmd sense unit=%02x 3 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(addr, &ch) ;
|
|
ch = (uptr->SNS) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_startcmd sense unit=%02x 4 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(addr, &ch) ;
|
|
/* bytes 8-11 - drive attribute register (DATR) entries from uptr->ATTR via
|
|
* INCH cmd */
|
|
ch = (uptr->ATTR >> 24) & 0xff;
|
|
chan_write_byte(addr, &ch) ;
|
|
ch = (uptr->ATTR >> 16) & 0xff;
|
|
chan_write_byte(addr, &ch) ;
|
|
ch = (uptr->ATTR >> 8 ) & 0xff;
|
|
chan_write_byte(addr, &ch) ;
|
|
ch = (uptr->ATTR >> 0) & 0xff;
|
|
chan_write_byte(addr, &ch) ;
|
|
/* bytes 12 & 13 contain drive related status */
|
|
ch = 0; /* zero for now */
|
|
/* TODO set drive status bits here */
|
|
chan_write_byte(addr, &ch) ;
|
|
chan_write_byte(addr, &ch) ;
|
|
|
|
uptr->SNS &= 0xff000000; /* clear status bytes, but leave mode data */
|
|
return SNS_CHNEND|SNS_DEVEND;
|
|
}
|
|
if (cmd == 0x0) /* INCH cmd gives unit check here */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
|
|
|
uptr->SNS |= (SNS_INTVENT|SNS_CMDREJ); /* set new error status */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK; /* we done */
|
|
}
|
|
|
|
/* Unit is online, so process a command */
|
|
switch (cmd) {
|
|
|
|
case DSK_INCH: /* INCH 0x00 */
|
|
{
|
|
uint32 mema; /* memory address */
|
|
uint32 i;
|
|
UNIT *up = dptr->units; /* first unit for this device */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd starting inch cmd addr %04x STAR %08x\n",
|
|
addr, uptr->STAR);
|
|
/* STAR (u4) has IOCD word 1 contents. For the disk processor it contains */
|
|
/* a pointer to the INCH buffer followed by 8 drive attribute words that */
|
|
/* contains the flags, sector count, MHD head count, and FHD count */
|
|
/* us9 has the byte count from IOCD wd2 and should be 0x24 (36) */
|
|
/* the INCH buffer address must be returned in STAR and us9 left non-zero */
|
|
/* just return OK and channel software will use up8 as status buffer */
|
|
mema = (uint32)uptr->STAR; /* get memory address of buffer */
|
|
uptr->STAR = M[mema>>2]; /* get status buffer address for XIO return status */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"hsdp_startcmd starting inch cmd addr %04x stat buf addr %08x mema %08x units %02x\n",
|
|
addr, uptr->STAR, mema, dptr->numunits);
|
|
/* the next 8 words have drive data for each unit */
|
|
/* WARNING 8 drives must be defined for this controller */
|
|
/* so we will not have a map fault */
|
|
for (i=0; i<dptr->numunits && i<8; i++) { /* process all drives */
|
|
int type = GET_TYPE(up->flags); /* get disk type */
|
|
up->ATTR = M[(mema>>2)+i+1]; /* save each unit's drive data */
|
|
/* see if sec/trk and num hds are set, if not set them */
|
|
if ((up->ATTR & 0x00ff0000) == 0)
|
|
up->ATTR = (up->ATTR & 0xff00ffff) | ((hsdp_type[type].spt & 0xff) << 16);
|
|
if ((up->ATTR & 0x0000ff00) == 0)
|
|
up->ATTR = (up->ATTR & 0xffff00ff) | ((hsdp_type[type].nhds & 0xff) << 8);
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"hsdp_startcmd ATTR data %08x unit %02x flags %02x sec %02x MHD %02x FHD %02x\n",
|
|
up->ATTR, i, (up->ATTR >> 24)&0xff, (up->ATTR >> 16)&0xff, (up->ATTR >> 8)&0xff, (up->ATTR&0xff));
|
|
up++; /* next unit for this device */
|
|
}
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd done inch cmd addr %04x\n", addr);
|
|
// uptr->CMD |= DSK_CMDMSK; /* use 0xff for inch, just need int */
|
|
uptr->CMD |= DSK_FINC; /* use 0xc0 for inch, just need int */
|
|
sim_activate(uptr, 20); /* start things off */
|
|
return 0;
|
|
}
|
|
|
|
case DSK_SKC: /* Seek command 0x07 */
|
|
case DSK_XEZ: /* Rezero & Read IPL record 0x1f */
|
|
uptr->CMD &= ~(DSK_STAR); /* show we do not have seek STAR in STAR */
|
|
case DSK_WD: /* Write command 0x01 */
|
|
case DSK_RD: /* Read command 0x02 */
|
|
case DSK_LMR: /* read mode register */
|
|
|
|
uptr->CMD |= cmd; /* save cmd */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"hsdp_startcmd starting disk seek r/w cmd %02x addr %04x\n", cmd, addr);
|
|
sim_activate(uptr, 20); /* start things off */
|
|
return 0;
|
|
|
|
case DSK_NOP: /* NOP 0x03 */
|
|
uptr->CMD |= cmd; /* save cmd */
|
|
sim_activate(uptr, 20); /* start things off */
|
|
return 0;
|
|
|
|
case DSK_SNS: /* Sense 0x04 */
|
|
uptr->CMD |= cmd; /* save cmd */
|
|
sim_activate(uptr, 20); /* start things off */
|
|
break;
|
|
|
|
case DSK_RTL: /* RTL 0x52 */
|
|
uptr->CMD |= cmd; /* save cmd */
|
|
sim_activate(uptr, 20); /* start things off */
|
|
return 0;
|
|
}
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"hsdp_startcmd done with hsdp_startcmd %02x addr %04x SNS %08x\n",
|
|
cmd, addr, uptr->SNS);
|
|
if (uptr->SNS & 0xff) /* any other cmd is error */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
|
sim_activate(uptr, 20); /* start things off */
|
|
return SNS_CHNEND|SNS_DEVEND;
|
|
}
|
|
|
|
/* Handle processing of disk requests. */
|
|
t_stat hsdp_srv(UNIT * uptr)
|
|
{
|
|
uint16 chsa = GET_UADDR(uptr->CMD);
|
|
DEVICE *dptr = find_dev_from_unit(uptr);
|
|
DIB *dibp = (DIB *)dptr->ctxt;
|
|
/* get pointer to Dev Info Blk for this device */
|
|
CHANP *chp = (CHANP *)dibp->chan_prg; /* get pointer to channel program */
|
|
struct ddata_t *data = (struct ddata_t *)(uptr->DDATA);
|
|
int cmd = uptr->CMD & DSK_CMDMSK;
|
|
int type = GET_TYPE(uptr->flags);
|
|
uint32 trk, cyl;
|
|
int unit = (uptr - dptr->units);
|
|
int len;
|
|
int i;
|
|
uint8 ch;
|
|
int tsize = hsdp_type[type].spt * hsdp_type[type].ssiz * 4; /* get track size in bytes */
|
|
int ssize = hsdp_type[type].ssiz * 4; /* disk sector size in bytes */
|
|
int tstart;
|
|
uint8 buf2[1024];
|
|
uint8 buf[1024];
|
|
|
|
sim_debug(DEBUG_DETAIL, dptr,
|
|
"hsdp_srv entry unit %02x cmd %02x chsa %04x chan %04x count %04x\n",
|
|
unit, cmd, chsa, chsa>>8, chp->ccw_count);
|
|
|
|
if ((uptr->flags & UNIT_ATT) == 0) { /* unit attached status */
|
|
uptr->SNS |= SNS_INTVENT; /* unit intervention required */
|
|
if (cmd != DSK_SNS) /* we are completed with unit check status */
|
|
return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
|
|
}
|
|
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_srv cmd=%02x chsa %04x count %04x\n",
|
|
cmd, chsa, chp->ccw_count);
|
|
switch (cmd) {
|
|
case 0: /* No command, stop disk */
|
|
break;
|
|
|
|
// case DSK_CMDMSK: /* use 0xff for inch, just need int */
|
|
case DSK_FINC: /* use 0xc0 for inch, just need int */
|
|
uptr->CMD &= ~(0xffff); /* remove old cmd */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_srv cmd=%02x chsa %04x count %04x completed\n",
|
|
cmd, chsa, chp->ccw_count);
|
|
#ifdef FIX4MPX
|
|
chan_end(chsa, SNS_CHNEND); /* return just channel end OK */
|
|
#else
|
|
//TRY chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */
|
|
chan_end(chsa, SNS_CHNEND); /* return OK for UTX */
|
|
#endif
|
|
break;
|
|
|
|
case DSK_NOP: /* NOP 0x03 */
|
|
uptr->CMD &= ~(0xffff); /* remove old cmd */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_srv cmd NOP chsa %04x count %04x completed\n",
|
|
chsa, chp->ccw_count);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */
|
|
break;
|
|
|
|
case DSK_SNS: /* 0x4 */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd CMD sense\n");
|
|
|
|
/* bytes 0,1 - Cyl entry from STAR reg in STAR */
|
|
// ch = (uptr->STAR >> 24) & 0xff;
|
|
ch = (data->cyl >> 8) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv sense STAR b0 unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
// ch = (uptr->STAR >> 16) & 0xff;
|
|
ch = (data->cyl) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv sense STAR b1 unit=%02x 2 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
/* byte 2 - Track entry from STAR reg in STAR */
|
|
// ch = (uptr->STAR >> 8) & 0xff;
|
|
ch = (data->tpos) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv sense STAR b2 unit=%02x 3 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
/* byte 3 - Sector entry from STAR reg in STAR */
|
|
// ch = (uptr->STAR) & 0xff;
|
|
ch = (data->spos) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv sense STAR b3 unit=%02x 4 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
/* bytes 4 - mode reg, byte 0 of SNS */
|
|
ch = (uptr->SNS >> 24) & 0xff; /* return the sense data for device */
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv sense unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
/* bytes 5-7 - status bytes, bytes 1-3 of SNS */
|
|
ch = (uptr->SNS >> 16) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv sense unit=%02x 2 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
ch = (uptr->SNS >> 8) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv sense unit=%02x 3 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
ch = (uptr->SNS) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv sense unit=%02x 4 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
/* bytes 8-11 - drive attribute register (DATR) entries from uptr->ATTR via
|
|
* INCH cmd */
|
|
ch = (uptr->ATTR >> 24) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv datr unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
ch = (uptr->ATTR >> 16) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv datr unit=%02x 2 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
ch = (uptr->ATTR >> 8 ) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv datr unit=%02x 3 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
ch = (uptr->ATTR >> 0) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv datr unit=%02x 4 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
/* bytes 12 & 13 are optional, so check if read done */
|
|
/* TODO add drive status bits here */
|
|
if ((test_write_byte_end(chsa)) == 0) {
|
|
/* bytes 12 & 13 contain drive related status */
|
|
ch = 0; /* zero for now */
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv dsr unit=%02x 1 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv dsr unit=%02x 2 %02x\n",
|
|
unit, ch);
|
|
chan_write_byte(chsa, &ch);
|
|
}
|
|
uptr->SNS &= 0xff000000; /* clear status bytes, but leave mode data */
|
|
//TRY uptr->CMD &= ~(0xff00); /* clear busy status */
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
|
|
break;
|
|
|
|
case DSK_SKC: /* Seek cylinder, track, sector 0x07 */
|
|
|
|
/* If we are waiting on seek to finish, check if there yet. */
|
|
if (uptr->CMD & DSK_SEEKING) {
|
|
/* see if on cylinder yet */
|
|
if ((uptr->STAR >> 16) == data->cyl) {
|
|
/* we are on cylinder, seek is done */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_srv seek on cylinder unit=%02x %02x %04x\n",
|
|
unit, uptr->STAR >> 16, data->cyl);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
set_devattn(chsa, SNS_DEVEND); /* start the operation */
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv seek end unit=%02x %02x %04x\n",
|
|
unit, uptr->STAR >> 16, data->cyl);
|
|
sim_activate(uptr, 20);
|
|
break;
|
|
} else {
|
|
/* Compute delay based of difference. */
|
|
/* Set next state = index */
|
|
i = (uptr->STAR >> 16) - data->cyl;
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_srv seek unit=%02x %02x %04x\n", unit,
|
|
uptr->STAR >> 16, i);
|
|
if (i > 0 ) {
|
|
if (i > 50) {
|
|
data->cyl += 50; /* seek 50 cyl */
|
|
sim_activate(uptr, 800);
|
|
} else
|
|
if (i > 20) {
|
|
data->cyl += 20; /* seek 20 cyl */
|
|
sim_activate(uptr, 400);
|
|
} else {
|
|
data->cyl++; /* Seek 1 cyl */
|
|
sim_activate(uptr, 200);
|
|
}
|
|
if (data->cyl >= (int)hsdp_type[type].cyl) /* test for over max */
|
|
data->cyl = hsdp_type[type].cyl-1; /* make max */
|
|
} else {
|
|
if (i < -50) {
|
|
data->cyl -= 50; /* seek 50 cyl */
|
|
sim_activate(uptr, 800);
|
|
} else
|
|
if (i < -20) {
|
|
data->cyl -= 20; /* seek 20 cyl */
|
|
sim_activate(uptr, 400);
|
|
} else {
|
|
data->cyl--; /* seek 1 cyl */
|
|
sim_activate(uptr, 200);
|
|
}
|
|
if ((int32)data->cyl < 0) /* test for less than zero */
|
|
data->cyl = 0; /* make zero */
|
|
}
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv seek next unit=%02x %02x %04x\n",
|
|
unit, uptr->STAR >> 16, data->cyl);
|
|
sim_activate(uptr, 2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* not seeking, so start a new seek */
|
|
/* set buf data to current STAR values */
|
|
buf[0] = (data->cyl >> 8) & 0xff;
|
|
buf[1] = (data->cyl) & 0xff;
|
|
buf[2] = (data->tpos) & 0xff;
|
|
buf[3] = (data->spos) & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv STAR unit=%02x star %02x %02x %02x %02x\n",
|
|
unit, buf[0], buf[1], buf[2], buf[3]);
|
|
/* Read in up to 4 character seek code */
|
|
for (i = 0; i < 4; i++) {
|
|
if (chan_read_byte(chsa, &buf[i])) {
|
|
if (i == 0) {
|
|
/* we have error, bail out */
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
/* just read the next byte */
|
|
}
|
|
}
|
|
/* done reading, see how many we read */
|
|
if (i == 1) {
|
|
/* UTX wants to set seek STAR to zero */
|
|
buf[0] = buf[1] = buf[2] = buf[3] = 0;
|
|
}
|
|
/* else the cyl, trk, and sect are ready to update */
|
|
rezero:
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv seek unit=%02x star %02x %02x %02x %02x\n",
|
|
unit, buf[0], buf[1], buf[2], buf[3]);
|
|
/* save STAR (target sector) data in STAR */
|
|
uptr->STAR = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
|
|
cyl = (uptr->STAR >> 16) & 0xffff; /* get the cylinder */
|
|
trk = buf[2]; /* get the track */
|
|
sim_debug(DEBUG_DETAIL, dptr,
|
|
"hsdp_srv SEEK cyl %04x trk %02x sec %02x unit=%02x\n", cyl&0xffff, trk, buf[3], unit);
|
|
|
|
/* Check if seek valid */
|
|
if (cyl > hsdp_type[type].cyl ||
|
|
trk >= hsdp_type[type].nhds ||
|
|
buf[3] > hsdp_type[type].spt) {
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"hsdp_srv seek ERROR cyl %04x trk %02x sec %02x unit=%02x\n",
|
|
cyl, trk, buf[3], unit);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK; /* set error status */
|
|
|
|
/* we have an error, tell user */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); /* end command */
|
|
break;
|
|
}
|
|
|
|
uptr->CMD |= DSK_STAR; /* show we have seek STAR in STAR */
|
|
/* calc the sector address of data */
|
|
/* calculate file position in bytes of requested sector */
|
|
// FIXME for variable sector size
|
|
tstart = (cyl * hsdp_type[type].nhds * tsize) + (trk * tsize) + (buf[3] * 1024);
|
|
data->tpos = trk; /* save the track/head number */
|
|
data->spos = buf[3]; /* save the sector number */
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv seek start %04x cyl %04x trk %02x sec %02x\n",
|
|
tstart, cyl, trk, buf[3]);
|
|
if ((sim_fseek(uptr->fileref, tstart, SEEK_SET)) != 0) { /* seek home */
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv Error on seek to %08x\n", tstart);
|
|
}
|
|
|
|
/* Check if already on correct cylinder */
|
|
if (cyl != data->cyl) {
|
|
/* No, Do seek */
|
|
uptr->CMD |= DSK_SEEKING; /* show we are seeking */
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv seek unit=%02x cyl %04x trk %02x sec %02x\n",
|
|
unit, cyl, trk, buf[3]);
|
|
sim_activate(uptr, 20); /* start up off */
|
|
chan_end(chsa, SNS_CHNEND);
|
|
} else {
|
|
/* Yes, we done */
|
|
sim_debug(DEBUG_DETAIL, dptr,
|
|
"hsdp_srv calc sect addr seek start %04x cyl %04x trk %02x sec %02x\n",
|
|
tstart, cyl, trk, buf[3]);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
sim_activate(uptr, 20);
|
|
chan_end(chsa, SNS_DEVEND|SNS_CHNEND);
|
|
}
|
|
return SCPE_OK;
|
|
|
|
case DSK_XEZ: /* Rezero & Read IPL record */
|
|
|
|
sim_debug(DEBUG_CMD, dptr, "RD REZERO IPL unit=%02x seek 0\n", unit);
|
|
/* Do a seek to 0 */
|
|
uptr->STAR = 0; /* set STAR to 0, 0, 0 */
|
|
uptr->CMD &= ~(0xffff); /* remove old cmd */
|
|
uptr->CMD |= DSK_SKC; /* show as seek command */
|
|
tstart = 0; /* byte offset is 0 */
|
|
/* Read in 1 dummy character for length to inhibit SLI posting */
|
|
if (chan_read_byte(chsa, &buf[0])) {
|
|
/* we have error, bail out */
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
/* zero stuff */
|
|
buf[0] = buf[1] = buf[2] = buf[3] = 0;
|
|
goto rezero; /* murge with seek code */
|
|
break;
|
|
|
|
case DSK_LMR:
|
|
sim_debug(DEBUG_CMD, dptr, "Load Mode Reg unit=%02x\n", unit);
|
|
/* Read in 1 character of mode data */
|
|
if (chan_read_byte(chsa, &buf[0])) {
|
|
/* we have error, bail out */
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
uptr->CMD &= ~(0xffff); /* remove old cmd */
|
|
uptr->SNS &= 0x00ffffff; /* clear old mode data */
|
|
uptr->SNS |= (buf[0] << 24); /* save mode value */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
|
|
break;
|
|
|
|
case DSK_RD: /* Read Data */
|
|
if ((uptr->CMD & DSK_READING) == 0) { /* see if we are reading data */
|
|
uptr->CMD |= DSK_READING; /* read from disk starting */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"DISK READ starting unit=%02x CMD %02x\n", unit, uptr->CMD);
|
|
}
|
|
|
|
if (uptr->CMD & DSK_READING) { /* see if we are reading data */
|
|
/* read in a sector of data from disk */
|
|
if ((len=sim_fread(buf, 1, ssize, uptr->fileref)) != ssize) {
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"Error %08x on read %04x of diskfile cyl %04x hds %02x sec %02x\n",
|
|
len, ssize, data->cyl, data->tpos, data->spos);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"hsdp_srv after READ chsa %04x count %04x\n", chsa, chp->ccw_count);
|
|
/* process the next sector of data */
|
|
for (i=0; i<len; i++) {
|
|
ch = buf[i]; /* get a char from buffer */
|
|
if (chan_write_byte(chsa, &ch)) { /* put a byte to memory */
|
|
sim_debug(DEBUG_DATA, dptr,
|
|
"DISK Read %04x bytes from dskfile cyl %04x hds %02x sec %02x\n",
|
|
i, data->cyl, data->tpos, data->spos);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
|
|
goto rddone;
|
|
}
|
|
}
|
|
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"DISK READ at sector end, read %04x bytes from disk @ cyl %04x hds %02x sec %02x\n",
|
|
ssize, data->cyl, data->tpos, data->spos);
|
|
data->spos++;
|
|
/* set sector to read next one */
|
|
if (data->spos >= (hsdp_type[type].spt)) {
|
|
data->spos = 0; /* number of sectors per track */
|
|
data->tpos++; /* track position */
|
|
if (data->tpos >= (hsdp_type[type].nhds)) {
|
|
data->tpos = 0; /* number of tracks per cylinder */
|
|
data->cyl++; /* cylinder position */
|
|
if (data->cyl >= (int)(hsdp_type[type].cyl)) {
|
|
/* EOM reached, abort */
|
|
sim_debug(DEBUG_DATA, dptr,
|
|
"DISK Read reached EOM for read from disk @ cyl %04x hds %02x sec %02x\n",
|
|
data->cyl, data->tpos, data->spos);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
data->cyl = 0; /* reset cylinder position */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* see if we are done reading data */
|
|
if (test_write_byte_end(chsa)) {
|
|
sim_debug(DEBUG_DATA, dptr,
|
|
"DISK Read complete for read from disk @ cyl %04x hds %02x sec %02x\n",
|
|
data->cyl, data->tpos, data->spos);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
|
|
}
|
|
rddone:
|
|
sim_activate(uptr, 10); /* wait to read next sector */
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DSK_WD: /* Write Data */
|
|
if ((uptr->CMD & DSK_WRITING) == 0) { /* see if we are writing data */
|
|
uptr->CMD |= DSK_WRITING; /* write to disk starting */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"DISK WRITE starting unit=%02x CMD %02x\n", unit, uptr->CMD);
|
|
}
|
|
if (uptr->CMD & DSK_WRITING) { /* see if we are writing data */
|
|
/* process the next sector of data */
|
|
len = 0; /* used here as a flag for short read */
|
|
for (i=0; i<ssize; i++) {
|
|
if (chan_read_byte(chsa, &ch)) { /* get a byte from memory */
|
|
/* if error on reading 1st byte, we are done writing */
|
|
if (i == 0) {
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"DISK Wrote %04x bytes to diskfile cyl %04x hds %02x sec %02x\n",
|
|
ssize, data->cyl, data->tpos, data->spos);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
|
|
goto wrdone;
|
|
}
|
|
ch = 0; /* finish out the sector with zero */
|
|
len++; /* show we have no more data to write */
|
|
}
|
|
buf2[i] = ch; /* save the char */
|
|
}
|
|
/* write the sector to disk */
|
|
if ((i=sim_fwrite(buf2, 1, ssize, uptr->fileref)) != ssize) {
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"Error %08x on write %04x bytes to diskfile cyl %04x hds %02x sec %02x\n",
|
|
i, ssize, data->cyl, data->tpos, data->spos);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
if (len != 0) { /* see if done with write command */
|
|
sim_debug(DEBUG_DATA, dptr,
|
|
"DISK WroteB %04x bytes to diskfile cyl %04x hds %02x sec %02x\n",
|
|
ssize, data->cyl, data->tpos, data->spos);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* we done */
|
|
break;
|
|
}
|
|
sim_debug(DEBUG_CMD, dptr,
|
|
"DISK WR to sec end %0x4x bytes end %04x to diskfile cyl %04x hds %02x sec %02x\n",
|
|
len, ssize, data->cyl, data->tpos, data->spos);
|
|
data->spos++;
|
|
if (data->spos >= (hsdp_type[type].spt)) {
|
|
data->spos = 0; /* number of sectors per track */
|
|
data->tpos++; /* track position */
|
|
if (data->tpos >= (hsdp_type[type].nhds)) {
|
|
data->tpos = 0; /* number of tracks per cylinder */
|
|
data->cyl++; /* cylinder position */
|
|
if (data->cyl >= (int)(hsdp_type[type].cyl)) {
|
|
/* EOM reached, abort */
|
|
sim_debug(DEBUG_DETAIL, dptr,
|
|
"Error %08x on write %04x to diskfile cyl %04x hds %02x sec %02x\n",
|
|
i, ssize, data->cyl, data->tpos, data->spos);
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
wrdone:
|
|
sim_activate(uptr, 10);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DSK_RTL: /* RTL 0x52 */
|
|
/* Read track zero to get disk geometry */
|
|
/* write 30 bytes, b0-b1=cyl, b1=trk, b2=sec */
|
|
/* zero the Track Label Buffer */
|
|
for (i = 0; i < 30; i++)
|
|
buf[i] = 0;
|
|
i = 286895; /* umap sector address */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_startcmd RTL STAR %08x Umap pointer %08x\n",
|
|
hsdp_type[type].geom, i);
|
|
/* set buf data to current STAR values */
|
|
buf[0] = (hsdp_type[type].cyl >> 8) & 0xff;
|
|
buf[1] = (hsdp_type[type].cyl) & 0xff;
|
|
buf[2] = hsdp_type[type].nhds & 0xff;
|
|
buf[3] = hsdp_type[type].spt & 0xff;
|
|
sim_debug(DEBUG_DETAIL, dptr,
|
|
"hsdp_srv RTL unit=%02x star %02x %02x %02x %02x\n",
|
|
unit, buf[0], buf[1], buf[2], buf[3]);
|
|
|
|
/* the umap pointer is placed by prep program */
|
|
/* simulate pointer here */
|
|
i = 286895; /* umap sector address */
|
|
buf[16] = (i >> 24) & 0xff;
|
|
buf[17] = (i >> 16) & 0xff;
|
|
buf[18] = (i >> 8) & 0xff;
|
|
buf[19] = (i) & 0xff;
|
|
/* the tech doc shows the cyl/trk/sec data is in the first 4 bytes */
|
|
/* of the track label, BUT it is really in the configuration data */
|
|
/* area are too. That is where UTX looks. Byte 27 is sectors/track */
|
|
/* and byte 28 is number of heads. Byte 25 is copy of byte 27. */
|
|
buf[25] = hsdp_type[type].spt & 0xff;
|
|
buf[27] = hsdp_type[type].spt & 0xff;
|
|
buf[28] = hsdp_type[type].nhds & 0xff;
|
|
|
|
/* now write track label data */
|
|
for (i = 0; i < 30; i++) {
|
|
if (chan_write_byte(chsa, &buf[i])) {
|
|
/* we have write error, bail out */
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* command done */
|
|
uptr->CMD &= ~(0xffff); /* remove old cmd */
|
|
sim_debug(DEBUG_CMD, dptr, "hsdp_srv cmd RTL done chsa %04x count %04x completed\n",
|
|
chsa, chp->ccw_count);
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */
|
|
break;
|
|
|
|
default:
|
|
sim_debug(DEBUG_DETAIL, dptr, "invalid command %02x unit %02x\n", cmd, unit);
|
|
uptr->SNS |= SNS_CMDREJ;
|
|
uptr->CMD &= ~(0xffff); /* remove old status bits & cmd */
|
|
chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
|
|
break;
|
|
}
|
|
sim_debug(DEBUG_DETAIL, dptr, "hsdp_srv done cmd=%02x chsa %04x count %04x\n",
|
|
cmd, chsa, chp->ccw_count);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* initialize the disk */
|
|
void hsdp_ini(UNIT *uptr, t_bool f)
|
|
{
|
|
DEVICE *dptr = find_dev_from_unit(uptr);
|
|
int i = GET_TYPE(uptr->flags);
|
|
|
|
uptr->CMD &= ~0xffff; /* clear out the flags but leave ch/sa */
|
|
/* capacity is total allocation units time sectors per allocation unit */
|
|
/* total sectors on disk */
|
|
uptr->capac = hsdp_type[i].taus * hsdp_type[i].spau;
|
|
|
|
sim_debug(DEBUG_EXP, dptr, "DPA init device %s on unit DPA%.1x cap %x\n",
|
|
dptr->name, GET_UADDR(uptr->CMD), uptr->capac);
|
|
}
|
|
|
|
t_stat hsdp_reset(DEVICE * dptr)
|
|
{
|
|
/* add reset code here */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* attach the selected file to the disk */
|
|
t_stat hsdp_attach(UNIT *uptr, CONST char *file)
|
|
{
|
|
uint16 addr = GET_UADDR(uptr->CMD);
|
|
int type = GET_TYPE(uptr->flags);
|
|
DEVICE *dptr = find_dev_from_unit(uptr);
|
|
t_stat r;
|
|
// uint16 tsize; /* track size in bytes */
|
|
uint16 ssize; /* sector size in bytes */
|
|
struct ddata_t *data;
|
|
// uint8 buff[1024];
|
|
|
|
/* have simulator attach the file to the unit */
|
|
if ((r = attach_unit(uptr, file)) != SCPE_OK)
|
|
return r;
|
|
|
|
if (hsdp_type[type].name == 0) { /* does the assigned disk have a name */
|
|
detach_unit(uptr); /* no, reject */
|
|
return SCPE_FMT; /* error */
|
|
}
|
|
|
|
/* get a buffer to hold hsdp_t structure */
|
|
/* extended data structure per unit */
|
|
if ((data = (struct ddata_t *)calloc(1, sizeof(struct ddata_t))) == 0) {
|
|
detach_unit(uptr);
|
|
return SCPE_FMT;
|
|
}
|
|
|
|
uptr->DDATA = (void *)data; /* save pointer to structure in DDATA */
|
|
/* track size in bytes is sectors/track times words/sector time 4 bytse/word */
|
|
// tsize = hsdp_type[type].spt * hsdp_type[type].ssiz * 4; /* get track size in bytes */
|
|
uptr->capac = hsdp_type[type].taus * hsdp_type[type].spau;
|
|
/* disk capacity in sectors */
|
|
ssize = hsdp_type[type].ssiz * 4; /* disk sector size in bytes */
|
|
uptr->capac *= ssize; /* disk capacity in bytes */
|
|
|
|
sim_debug(DEBUG_CMD, dptr, "Disk taus %d spau %d ssiz %d cap %d\n",
|
|
hsdp_type[type].taus, hsdp_type[type].spau, hsdp_type[type].ssiz * 4,
|
|
uptr->capac); /* disk capacity */
|
|
|
|
if ((sim_fseek(uptr->fileref, 0, SEEK_SET)) != 0) { /* seek home */
|
|
detach_unit(uptr); /* if no space, error */
|
|
return SCPE_FMT; /* error */
|
|
}
|
|
|
|
/* set the max configuration geometry */
|
|
hsdp_type[type].geom = (hsdp_type[type].cyl << 16) |
|
|
(hsdp_type[type].nhds << 8) | (hsdp_type[type].spt);
|
|
data->cyl = 0; /* current cylinder position */
|
|
data->tpos = 0; /* current track position */
|
|
data->spos = 0; /* current sector position */
|
|
|
|
set_devattn(addr, SNS_DEVEND);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* detach a disk device */
|
|
t_stat hsdp_detach(UNIT * uptr) {
|
|
struct ddata_t *data = (struct ddata_t *)uptr->DDATA;
|
|
|
|
if (data != 0) {
|
|
free(data); /* free disk data structure */
|
|
}
|
|
uptr->DDATA = 0; /* no pointer to disk data */
|
|
uptr->CMD &= ~0xffff; /* no cmd and flags */
|
|
return detach_unit(uptr); /* tell simh we are done with disk */
|
|
}
|
|
|
|
/* boot from the specified disk unit */
|
|
t_stat hsdp_boot(int32 unit_num, DEVICE * dptr) {
|
|
UNIT *uptr = &dptr->units[unit_num]; /* find disk unit number */
|
|
|
|
sim_debug(DEBUG_CMD, dptr, "Disk Boot dev/unit %x\n", GET_UADDR(uptr->CMD));
|
|
SPAD[0xf4] = GET_UADDR(uptr->CMD); /* put boot device chan/sa into spad */
|
|
SPAD[0xf8] = 0xF000; /* show as F class device */
|
|
if ((uptr->flags & UNIT_ATT) == 0)
|
|
return SCPE_UNATT; /* attached? */
|
|
return chan_boot(GET_UADDR(uptr->CMD), dptr); /* boot the ch/sa */
|
|
}
|
|
|
|
/* Disk option setting commands */
|
|
t_stat hsdp_set_type(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
int i;
|
|
|
|
if (cptr == NULL)
|
|
return SCPE_ARG;
|
|
if (uptr == NULL)
|
|
return SCPE_IERR;
|
|
if (uptr->flags & UNIT_ATT)
|
|
return SCPE_ALATT;
|
|
for (i = 0; hsdp_type[i].name != 0; i++) {
|
|
if (strcmp(hsdp_type[i].name, cptr) == 0) {
|
|
uptr->flags &= ~UNIT_TYPE; /* clear old type */
|
|
uptr->flags |= SET_TYPE(i); /* set new type */
|
|
uptr->capac = hsdp_type[i].taus * hsdp_type[i].spau;
|
|
return SCPE_OK;
|
|
}
|
|
}
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
t_stat hsdp_get_type(FILE * st, UNIT * uptr, int32 v, CONST void *desc)
|
|
{
|
|
if (uptr == NULL)
|
|
return SCPE_IERR;
|
|
fputs("TYPE=", st);
|
|
fputs(hsdp_type[GET_TYPE(uptr->flags)].name, st);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* help information for disk */
|
|
t_stat hsdp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
|
const char *cptr)
|
|
{
|
|
int i;
|
|
fprintf (st, "SEL 8064 High Speed Disk Processor\r\n");
|
|
fprintf (st, "Use:\r\n");
|
|
fprintf (st, " sim> SET %sn TYPE=type\r\n", dptr->name);
|
|
fprintf (st, "Type can be: ");
|
|
for (i = 0; hsdp_type[i].name != 0; i++) {
|
|
fprintf(st, "%s", hsdp_type[i].name);
|
|
if (hsdp_type[i+1].name != 0)
|
|
fprintf(st, ", ");
|
|
}
|
|
fprintf (st, ".\nEach drive has the following storage capacity:\r\n");
|
|
for (i = 0; hsdp_type[i].name != 0; i++) {
|
|
/* disk capacity in sectors */
|
|
int32 capac = hsdp_type[i].taus * hsdp_type[i].spau;
|
|
int32 ssize = hsdp_type[i].ssiz * 4; /* disk sector size in bytes */
|
|
int32 size = capac * ssize; /* disk capacity in bytes */
|
|
size /= 1024; /* make KB */
|
|
size = (10 * size) / 1024; /* size in MB * 10 */
|
|
fprintf(st, " %-8s %4d.%1d MB\r\n", hsdp_type[i].name, size/10, size%10);
|
|
}
|
|
fprint_set_help(st, dptr);
|
|
fprint_show_help(st, dptr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
const char *hsdp_description (DEVICE *dptr)
|
|
{
|
|
return "SEL 8064 High Speed Disk Processor";
|
|
}
|
|
|
|
#endif
|