        EXT DRNBN,HDNSEC,VBUF,DBUFF,BUFSW
        EXT  ABORT
        ENTRY RDY0,PBLK0
        ENTRY ERRLM,PASLM
        ENTRY UNIT0,SRW,SEC,TK,DRV
        ENTRY HEAD,BUFF,PASCT
        ENTRY ERRCT,ERRLM
;
;
STIN:   EQU  160        "READY FOR COMMAND" STATUS CHANNEL
COML:   EQU  167        LOW ORDER COMMAND CHANNEL
COMH:   EQU  COML-4     HIGH ORDER COMMAND CHANNEL
RSTCOD: EQU  0140       OPCODE FOR "READ STATUS"
WBCOD:  EQU  0100       OPCODE FOR "WRITE BUFFER"
WSCOD:  EQU  040        OPCODE FOR "WRITE SECTOR"
RSCOD:  EQU  060        OPCODE FOR "READ SECTOR"
RBCOD:  EQU  0120       OPCODE FOR "READ BUFFER"
;
;
;
;************************************************************
;
;       ENTRY POINT FOR UNIT DEPENDENT PART OF TEST
;
;************************************************************
;
;
;
;
RDY0:   POP  H          GET PBLK POINTER
;
; UNIT IS READY - TEST SRW AND EXECUTE COMMAND
;
.U      LXI  H,SRW
        MOV  A,M        GET SRW CODE
        RLC             ...DOUBLED
        PUSH H          SAVE PARAM BLOCK POINTER
        LXI  H,JTAB     GET JUMP TABLE BASE ADDRESS
        MVI  D,0
        MOV  E,A        SET UP INDEX
        DAD  D          ADD INDEX TO BASE
        MOV  E,M        GET LOW BYTE
        INX  H
        MOV  D,M        GET HIGH BYTE
        XCHG            GET COMMAND ROUTINE ADDRESS IN [HL]
        PCHL            JUMP TO COMMAND ROUTINE
;
; COMMAND ROUTINE JUMP TABLE
; [HL] POINTS TO SRW ON ENTRY TO EACH COMMAND ROUTINE
; (MUST BE POPPED FROM THE STACK FIRST)
;
JTAB:   DW  SEEK        SEEK
        DW  WRBUF       WRITE BUFFER AND SECTOR
        DW  SEEK        SEEK AWAY FROM CURRENT TRACK
        DW  SEEK        SEEK BACK TO CORRECT TRACK
        DW  RDSEC       READ SECTOR
        DW  RDBUF       READ BUFFER
        DW  ABORT       SERIOUS ERROR IF INDEXED THIS FAR
;
; SEEK TO TRACK (CYLINDER) TK
;
SEEK:   POP  H          GET PARAM BLOCK POINTER BACK
        INR  M          SET UP NEXT SRW
        MVI  A,3
        CMP  M          WILL THIS BE A MODIFIED SEEK ? (NEW SRW

        INX  H
        MOV  A,M        GET LOW ORDER CYLINDER BITS
        JNZ  +S         NO MODIFY - GO SEND
        CMA
        ANI  127        NEW CYLINDER = NOT(CYL(LOW)) AND 127
.S      PUSH PSW        SAVE LOW CYLINDER ADDRESS
        CALL STWT       WAIT FOR READY
        POP  PSW        GET LOW CYLINDER ADDRESS BACK
        OUT  COML       SEND LOW CYLINDER ADDRESS
        INX  H
        MOV  E,M        GET HIGH CYLINDER ADDRESS BITS
        INX  H
        MOV  A,M        GET DRIVE NUMBER
        RLC             SHIFT LEFT
        RLC             ...TWICE
        ORA  E          PUT IN HIGH CYLINDER BITS
        ANI  X'F1'      MAKE SURE SEEKS ARE ALWAYS ON PHYSICAL U

        OUT  COMH       SEND HIGH PART OF COMMAND
        RET
;
;
; WRITE PATTERN TO BUFFER
; PATTERN IS TRACK NUMBER (LOW/HIGH), SECTOR NUMBER,
; AND DATA PATTERNS 0 - 252.
;
WRBUF:  POP  H          GET PARAM BLOCK POINTER
        INX  H          SKIP TK(LOW)
        INX  H          ...AND TK(HIGH)
        INX  H          POINT TO DRIVE NUMBER
        CALL STWT       WAIT FOR READY STATUS
        XRA  A          SET UP BYTE COUNT (256 MOD 256)
        OUT  COML       SAY WE'LL SEND ALL 256 BYTES
        IN   COML               DUMMY READ TO CLEAR SOMETHING
        CALL DRNBN      COMBINE DRIVE/BUFFER NUMBERS
        PUSH PSW        SAVE RESULT FOR WRITE ROUTINES
        ORI  WBCOD      OR-IN "WRITE BUFFER" OPCODE
        OUT  COMH       SEND HIGH COMMAND BYTE
.W      IN   COML-1
        RLC             CAN WE SEND DATA ?
        JNC  -W          NO - WAIT
        INX  H          POINT TO SECTOR NUMBER
        PUSH H          SAVE POINTER FOR "WRITE SECTOR" ROUTINE
        MOV  A,M        GET SECTOR NUMBER
        PUSH PSW        ...AND SAVE IT
        DCX  H
        DCX  H
        DCX  H
        DCX  H          POINT TO TK(LOW)
        MOV  A,M
        OUT  COML       SEND IT
        INX  H
        MOV  A,M        GET TK(HIGH)
        OUT  COML       SEND IT
        POP  PSW        GET SECTOR NUMBER BACK
        OUT  COML       ...AND SEND IT
        XRA  A          SET UP FIRST PATTERN BYTE
.X      OUT  COML       SEND IT
        INR  A          SET UP NEXT PATTERN BYTE
        CPI  253        SEE IF ALL 256 BYTES WRITTEN
        JC   -X         KEEP GOING IF NOT
;
; BUFFER IS FULL - WRITE SECTOR
;
        POP  H          POINT TO SECTOR NUMBER
        CALL HDNSEC     COMBINE HEAD/SECTOR NUMBERS
        PUSH PSW        SAVE LOW COMMAND BYTE
        CALL STWT       WAIT FOR READY
        POP  PSW        GET LOW COMMAND BYTE BACK
        OUT  COML       SEND IT
        POP  PSW        GET DRIVE/BUFFER NUMBERS BACK
        ORI  WSCOD      OR-IN "WRITE SECTOR" OPCODE
        ANI  X'F3'      STAY ON PHYSICAL UNIT ZERO
        OUT  COMH       SEND HIGH COMMAND BYTE
        JMP  BUFSW      GO SWITCH BUFFERS
;
;
; READ SECTOR
;
RDSEC:  POP  H          GET BACK PARAM BLOCK POINTER
        INX  H          SKIP TK(LOW)
        INX  H          ...AND TK(HIGH)
        INX  H          POINT TO DRIVE NUMBER
        CALL DRNBN      COMBINE DRIVE/BUFFER NUMBERS
        PUSH PSW        SAVE RESULT
        INX  H          POINT TO SECTOR NUMBER
        CALL HDNSEC     COMBINE HEAD/SECTOR NUMBERS
        PUSH PSW        SAVE RESULT
        CALL STWT       WAIT FOR READY
        POP  PSW        GET SECTOR/HEAD NUMBERS BACK
        OUT  COML       SEND AS LOW COMMAND BYTE
        POP  PSW        GET DRIVE/BUFFER NUMBERS BACK
        ORI  RSCOD      OR-IN "READ SECTOR" OPCODE
        ANI  X'F3'      STAY ON PHYSICAL UNIT ZERO
        OUT  COMH       SEND HIGH COMMAND BYTE
;
; SET SRW SO NEXT OP IS "READ BUFFER"
;
        LXI  H,SRW      POINT TO SRW
        INR  M          INCREMENT IT
        RET
;
;
; READ BUFFER
;
RDBUF:  POP  H          GET PBLK POINTER BACK
        INX  H          SKIP TK(LOW)
        INX  H          ...AND TK(HIGH)
        INX  H          POINT TO DRIVE NUMBER
        CALL DRNBN      COMBINE DRIVE/BUFFER NUMBERS
        ORI  RBCOD      OR-IN "READ BUFFER" OPCODE
        PUSH PSW        SAVE HIGH COMMAND BYTE
        CALL STWT       WAIT FOR READY
        XRA  A          BYTE COUNT (256 MOD 256)
        OUT  COML       SAY WE'LL READ ALL 256 BYTES
        POP  PSW        GET HIGH COMMAND BYTE BACK
        OUT  COMH       SEND IT
        LXI  B,DBUFF    POINT TO VERIFY BUFFER
        PUSH B          SAVE POINTER FOR VERIFY ROUTINE
.R      IN   COMH+1
        RLC
        JNC  -R         WAIT FOR DATA READY
        MVI  E,0        SET UP TRANSFER COUNTER
.D      IN   COMH+2     READ A DATA BYTE
        STAX B          SAVE IT
        INX  B
        INR  E          ONE LESS TO GO
        JNZ  -D         READ ALL 256
        JMP  VBUF       GO VERIFY DATA
;
;
; UNIT PARAMETER BLOCK
;
PBLK0:  DS   0
UNIT0:  DB   0          UNIT NUMBER
SCHK:   DB   0          NUMBER OF TIMES WE'VE CHECKED FOR "READY

ERRLM:  DB   0          ERROR LIMIT
ERRCT:  DB   0          ERROR COUNTER
PASCT:  DB   0          PASS COUNT
PASLM:  DB   0          PASS LIMIT
SRW:    DB   0          NEXT OP INDICATOR
TK:     DW   0          TRACK (CYLINDER)  LOW/HIGH
DRV:    DB   0          LOGICAL DRIVE NUMBER
BUFF:   DB   0          CONTROLLER BUFFER NUMBER
SEC:    DB   0          SECTOR NUMBER
HEAD:   DB   0          HEAD NUMBER
RETRY:  DB   0          CRC ERROR RETRY COUNT
;
;
; WAIT FOR "READY FOR COMMAND" STATUS
;
STWT:   IN   STIN       GET STATUS
        RLC             CAN WE CONTINUE ?
        JNC  STWT        NO - WAIT
        IN   STIN+1        DUMMY
        IN   COMH          READS
        IN   COMH+2        TO CLEAR SOME STUFF
        RET
;
;
        END
