;Format - Data Technology Corporation CP/M 2.2 Format.
;
;       +-----------------------+
;       |                       |
;       |      F O R M A T      |
;       |                       |
;       +-----------------------+
;
;
;       Version number: 2.2B
;       Version date:   October 24, 1980
;
;       UPDATE  JANUARY 6,1981
;       ADD MRX101D DISK SIZE CONDITIONALS
;
;       Update March 31, 1981
;               Modified for assembly with ASM.
;               Parameterized for hard disk.
;
;       Update April 27, 1981
;               Modified for controller timeout.
;
;       Update date:    June 15, 1981
;               Modified for new configuration parameters.
;               Formats full hard disk only.

;       The following code is supplied to customers who
;       purchase a hard/floppy disk system from DTC.
;       The following code formats floppy disks and the
;       hard disk contained within the DTC hard disk unit.





VERS:   EQU     22

CR:     EQU     0Dh             ;ASCII carrriage return
LF:     EQU     0Ah             ;ASCII line feed
EOS:    EQU     '$'             ;BDOS End of string
TAB:    EQU     9               ;ASCII horizontal tab
ERRCD:  EQU     0FFh            ;BDOS error code





;       BDOS function equates.

PRTSTR: EQU     09      ;Print String    DE = buffer address.
RDCB:   EQU     10      ;Read console buffer   DE = buffer address.
OPEN:   EQU     15      ;Open file   DE = FCB address.
READS:  EQU     20      ;Read sequential file    DE = FCB.
SETDMA: EQU     26      ;Set DMA address    DE = DMA address.

;       Page zero locations.

BDOSV:  EQU     5       ;BDOS JUMP ADDRESS.
DFCB:   EQU     005Ch   ;Default FCB address.
DBUF:   EQU     0080h   ;Default DMA buffer.







       ORG     100h


FORMAT:
       PUSH    PSW
       PUSH    B
       PUSH    D
       PUSH    H
       LXI     H,0
       DAD     SP
       SHLD    SYSTK           ;save system stack


       LXI     SP,STACK
       LXI     D,SMESSG        ;Output sign-on message
       MVI     C,PRTSTR
       CALL    BDOSV

       CALL    INITBF          ;intialize data buffer
FORM1:  CALL    INITL           ;Intialize for formatting
       LDA     DTYPE
       MOV     B,A
       ANI     TYPEDRV
       JZ      FORM2           ;If floppy disk
       MOV     A,B
       ANI     TYPEN48+TYPEN96
       JNZ     FORM2
       CALL    FORMH           ;Format hard disk
       JNZ     FORM1           ;If new disk requested
       JMP     SYSRET

FORM2:  CALL    FORMF           ;Format floppy disk
       JNZ     FORM1           ;If new disk requested
       JMP     SYSRET


;       Return to system gracefully.

SYSRET: LHLD    SYSTK
       SPHL
       POP     H
       POP     D
       POP     B
       POP     PSW
       RET                     ;return to system

SMESSG: DB      CR,LF,LF,LF
       DB      'Data Technology Disk Format Program'
       DB      ' Version ',VERS/10+'0','.',VERS mod 10 + '0'
       DB      CR,LF,EOS




;       INITBF - Intialize data buffer with constant pettern.

INITBF:
       MVI     C,0E5h
       LHLD    BDOSV+1         ;Get buffer end address
       XCHG
       LXI     H,BUFFER
IBF1:   MOV     M,C             ;Set a byte
       INX     H
       MOV     A,D
       CMP     H
       JNZ     IBF1
       MOV     A,E
       CMP     L
       JNZ     IBF1            ;If entire buffer not set

       RET



;       INITL - Get parameters from operator.

INITL:
       XRA     A               ;Reset E5FLAG
       STA     E5FLAG
INIL1:  LXI     D,DMESSG        ;Output disk selection message
       CALL    INFCRT
       STA     LETTER
       SUI     '0'
       JM      INIL1           ;If invalid entry
       CPI     4
       JP      INIL1           ;If invalid entry
       RRC
       RRC
       RRC
       STA     DRVNO

       CALL    DDTYPE          ;Determine Disk type
       JNZ     INIL4
       LDA     DTYPE
       MOV     B,A
       ANI     TYPEDRV
       JZ      INILf           ;If floppy disk unit
       MOV     A,B             ; or mini floppy
       ANI     18h
       JNZ     INILf

       XRA     A
INIL2:  LXI     D,HDMESG
       CALL    INFCRT          ;Get hard disk response
       CPI     'Y'
       RNZ

INIL3:  LXI     D,INTMSG        ;Get interleave code
       CALL    INFCRT
       SUI     '1'
       JM      INIL3           ;If invalid interleave code
       CPI     16
       JP      INIL3           ;If invlaid interleave code
       INR     A
       STA     HDILC           ;Save interleave code

       RET

INIL4:
       LXI     D,ADTMSG
       MVI     C,PRTSTR
       CALL    BDOSV
       JMP     INITL


INILf:  LXI     D,DENMSG        ;Output density seclection
       CALL    INFCRT
       SUI     '1'
       JM      INILf           ;If invalid density
       CPI     2
       JP      INILf           ;If invalid density
       STA     FPDEN

INILg:  LXI     D,SIDMSG        ;Get number of sides
       CALL    INFCRT
       SUI     '1'
       JM      INILg           ;If invalid number of sides
       CPI     2
       JP      INILg           ;If invalid number of sides
       MOV     C,A
       LDA     FPDEN
       ADD     A
       ADD     C
       STA     FPSLV           ;Save format selection value
       RET

DMESSG: DB      CR,LF
       DB      'Select Drive (0, 1, 2, 3): ',EOS

DENMSG: DB      CR,LF
       DB      'Select a sector size:'
       DB      CR,LF
       DB      '     1) 128 Byte Single density.'
       DB      CR,LF
       DB      '     2) 256 Byte Double density.'
       DB      CR,LF
       DB      'Sector Size: ',EOS

HDMESG: DB      CR,LF
       DB      'This program will format the entire hard disk.',CR,LF
       DB      'Do you wish to continue (Y or N)? ',EOS

ADTMSG: DB      CR,LF,'Assign Drive Type error.',EOS

INTMSG: DB      CR,LF
       DB      'Enter interleave value (1--16): '
       DB      EOS

SIDMSG: DB      CR,LF
       DB      'Enter number of sides (1 or 2): '
       DB      EOS





;       FORMH - Format a hard disk unit.

FORMH:
       CALL    SCMND           ;Set command buffers
       LDA     HDILC           ;Set interleave code
       STA     CIOFDC+4
       LXI     H,CIOSTC
       CALL    EXEC            ;Output command buffer
       CZ      WAITF           ;Wait completion
       MOV     A,C
       ANI     FERR
       JZ      FRMH1           ;If unit is ready
       LXI     D,UNDMSG        ;Unit not available
       MVI     C,PRTSTR
       CALL    BDOSV
       ORI     0FFh
       RET

FRMH1:

       LXI     D,BFDMSG                ;Output message
       MVI     C,PRTSTR
       CALL    BDOSV

       LXI     H,CIOFDC
       CALL    EXEC            ;Output Command
       CZ      WAITF           ;Wait for completion
       MOV     A,C
       ANI     FERR
       JZ      FRMH2           ;If no errors
       LXI     H,CIOFDC
       CALL    ERROR           ;Print error message
       JMP     FORMH

FRMH2:
       CALL    FRME5           ;Fill disk with E5s
       JC      FORMH           ;Error
       RET


FRME5:
       LDA     E5FLAG          ;Is data E5?
       CPI     0E5h
       JZ      FRMH7
       ORA     A               ;No.  Has data been checked?
       JNZ     FRMH12
       LXI     H,0
       SHLD    CIORED+2
       LXI     H,CIORED        ;No.  Read a sector.
       LXI     D,BUFFER
       CALL    RDISK
       MOV     A,C
       ANI     FERR
       JZ      FRMH3
       LXI     H,CIORED
       CALL    ERROR
       STC
       RET
FRMH3:
       LDA     BUFFER          ;Set E5FLAG
       ORA     A
       JNZ     FRMH4
       INR     A
FRMH4:
       STA     E5FLAG
       CPI     0E5h            ;Is data E5?
       JZ      FRMH12
       CALL    INITBF          ;No.  Set buffer to E5s
       LHLD    BDOSV+1         ;Compute # sectors in buffer
       LXI     D,-BUFFER
       DAD     D
       LDA     DTYPE
       ANI     TYPESEC
       RRC
       MOV     B,A
       MVI     D,3
       CALL    DBLSHR
FRMH5:
       DCR     B
       JM      FRMH6
       MVI     D,1
       CALL    DBLSHR
       JMP     FRMH5
FRMH6:
       MOV     A,L
       STA     CIOWRT+4        ;# SECTORS
       XCHG
       LXI     H,0
       SHLD    CIOWRT+2
FRMH7:
       PUSH    D
       LXI     H,CIOWRT
       LXI     D,BUFFER
       CALL    WDISK           ;Output  buffer
       POP     D
       MOV     A,C
       ANI     FERR
       JZ      FRMH8           ;If no errors
       LXI     H,CIOWRT
       CALL    ERROR
       STC
       RET

FRMH8:
       PUSH    D               ;Increment logical address
       LXI     H,CIOWRT+2
       MOV     D,M             ;It's in reverse order
       INX     H
       MOV     E,M
       POP     H
       XCHG
       DAD     D
       PUSH    D
       XCHG
       LXI     H,CIOWRT+1
       JNC     FRMH9
       INR     M
FRMH9:
       INX     H
       MOV     M,D
       INX     H
       MOV     M,E
       LXI     D,ESECTOR       ;Done?
       LXI     H,CIOWRT+1
       MOV     A,M
       ANI     1Fh
       XCHG
FRMH10:
       CMP     M
       JZ      FRMH11
       POP     D
       JMP     FRMH8
FRMH11:
       INX     D
       INX     H
       DCR     B
       LDAX    D
       JNZ     FRMH10

FRMH12:
       LXI     D,FCMSG
       CALL    INFCRT
       CPI     CR
       RET

UNDMSG: DB      CR,LF,'Unit is not present.',CR,LF,EOS

BFDMSG: DB      CR,LF,'Begin formatting hard disk.'
       DB      CR,LF,EOS

FNAMSG: DB      CR,LF,'Function is not presently available.'
       DB      CR,LF,EOS




;       FORMF - Format a floppy disk unit.

FORMF:
       CALL    SCMND           ;Set command buffers
       MVI     A,1             ;Set interleave code
       STA     CIOFDC+4
       LXI     H,CIOSTC
       CALL    EXEC            ;Output command buffer
       CZ      WAITF           ;Wait completion
       MOV     A,C
       ANI     FERR
       JZ      FRMF1           ;If unit is ready
       LXI     D,NRYMSG        ;Output not ready message
       CALL    INFCRT
       JMP     FORMF           ;retry on any character

FRMF1:
       LDA     FPSLV           ;Get selection value
       MOV     E,A
       MVI     D,0
       LXI     H,FPYTFC
       LDA     DTYPE
       MOV     B,A
       ANI     TYPEDRV
       JZ      FRMF2
       LXI     H,M48TFC
       MOV     A,B
       ANI     TYPEN48
       JNZ     FRMF2
       LXI     H,M96TFC
FRMF2:
       DAD     D
       MOV     A,M
       STA     CIOFSC+5
       LXI     H,CIOFSC
       CALL    EXEC            ;Output Command
       CZ      WAITF           ;Wait function complete

       LXI     D,FDKMSG
       MVI     C,PRTSTR
       CALL    BDOSV           ;Output format disk
       LXI     H,CIOFDC
       CALL    EXEC            ;Output Command
       CZ      WAITF           ;Wait for completion
       MOV     A,C
       ANI     FERR
       JZ      FRMF3           ;If no errors
       LXI     H,CIOFDC
       CALL    ERROR           ;PRINT ERROR MESSAGE
       JMP     FORMF

FRMF3:
       LHLD    ESECTOR         ;Fill 1/4th of disk with E5s
       MVI     D,2
       CALL    DBLSHR
       SHLD    ESECTOR
       CALL    FRME5
       JC      FORMF
       RZ                      ;If request to return to CP/M
       CPI     'F'
       JZ      FORMF           ;If request for another
       RET
;       Track format code tables (indexed by density*2+# sides)
;
FPYTFC: DB      0,1,6,7
M48TFC: DB      0,1,4,5
M96TFC: DB      2,3,6,7
;

FCMSG:
       DB      CR,LF,'Function Complete.'
       DB      CR,LF,LF
       DB      'Type RETURN to return to CP/M, '
       DB      'or F to Format another: '
       DB      EOS

NRYMSG: DB      CR,LF
       DB      'Disk unit is not ready. ',CR,LF
       DB      'Please ready unit and hit RETURN. '
       DB      EOS

FDKMSG: DB      CR,LF,'Formatting the entire disk.'
       DB      CR,LF,EOS




;       INFCRT - Output message and input from console.
;
;       ENTRY   DE = message address.
;
;       EXIT    A = First character entered (upper case).

INFCRT:
       MVI     C,PRTSTR
       CALL    BDOSV           ;Output message
       LXI     D,INBUFX
       MVI     C,RDCB
       CALL    BDOSV
       LDA     INBUFX+1
       ANA     A
       MVI     A,CR
       RZ
       LDA     INBUF
       CPI     'A'+20h
       RC                      ;If upper case
       CPI     'Z'+20h+1
       RNC                     ;If upper case
       SUI     20h             ;Fold to uppercase
       RET

INBUFX  DB      10,0
INBUF   DB      0,0,0,0,0,0,0,0,0,0




;       DDTYPE - determine disk type (hard or floppy).

DDTYPE:
       XRA     A
       STA     CIOFSC+5
       LDA     DRVNO
       STA     CIOFSC+1
       STA     CIOADT+1
       LXI     H,DT
       LXI     D,6
       MVI     B,NLUN
DDTYP1:
       CMP     M
       JZ      DDTYP2
       DAD     D
       DCR     B
       JNZ     DDTYP1
       ORI     0FFH            ;Configuration error.
       RET
DDTYP2:
       INX     H
       MOV     A,M
       STA     DTYPE
       INX     H
       MOV     A,M
       STA     CIOADT+4        ;ASSIGN DRIVE TYPE
       INX     H               ;Compute end sector
       MOV     C,M
       INX     H
       MOV     E,M
       INX     H
       MOV     D,M
       CALL    MUL
       XCHG
       LXI     H,ESECTOR
       MOV     M,B
       INX     H
       MOV     M,D
       INX     H
       MOV     M,E
       LDA     CIOADT+4        ;Does controller have Class 6,
       CPI     0FFh            ;  op code 1?
       RZ
       LXI     H,CIOADT
       CALL    EXEC            ;Output Command
       CZ      WAITF           ;Wait function complete
       MOV     A,C
       ANI     FERR            ;Mask for errors
       RET
;
;       Drive Type table (indexed by LUN)
;
DT:
       IF      LUN0
       DB      0 SHL 5
       DB      LUN0TYPE+TYPEN48*N48M0+TYPEN96*N96M0
       DB      LUN0DAT,LUN0NLD
       DW      LUN0SEC
       ENDIF
       IF      LUN1
       DB      1 SHL 5
       DB      LUN1TYPE+TYPEN48*N48M1+TYPEN96*N96M1
       DB      LUN1DAT,LUN1NLD
       DW      LUN1SEC
       ENDIF
       IF      LUN2
       DB      2 SHL 5
       DB      LUN2TYPE+TYPEN48*N48M2+TYPEN96*N96M2
       DB      LUN2DAT,LUN2NLD
       DW      LUN2SEC
       ENDIF
       IF      LUN3
       DB      3 SHL 5
       DB      LUN3TYPE+TYPEN48*N48M3+TYPEN96*N96M3
       DB      LUN3DAT,LUN3NLD
       DW      LUN3SEC
       ENDIF
;




;       SCMND - Set drive into command buffers.

SCMND:
       LDA     DRVNO
       LXI     H,CIOFSC+1
       LXI     D,6
       MVI     B,CIONUM
SCMD1:  MOV     M,A
       DAD     D
       DCR     B
       JNZ     SCMD1           ;If not all buffer set
       RET





;       MOVDTA - Move data utility program.
;
;       ENTRY   H = Source field.
;               DE = Destination field.
;               BC = number of bytes.

MOVDTA:
       MOV     A,M
       STAX    D
       INX     H
       INX     D
       DCX     B
       MOV     A,B
       ANA     C
       CPI     0FFh            ;-1
       JNZ     MOVDTA
       RET



;MULTIPLY SINGLE X DOUBLE
;
;       ENTRY:  DE = MULTIPLICAND
;                C = MULTIPLIER
;       EXIT:   HL = PRODUCT (LEAST SIGNIFICANT)
;                B = PRODUCT (MOST SIGNIFICANT)
;
MUL:    LXI     H,0
       MOV     A,C
       ORA     A
       RZ
       MVI     B,0
MUL1:   DAD     D
       JNC     MUL2
       INR     B
MUL2:
       DCR     A
       JNZ     MUL1
       RET
;
;
;Shift HL right by (D)
;
DBLSHR:
       XRA     A
       MOV     A,H
       RAR
       MOV     H,A
       MOV     A,L
       RAR
       MOV     L,A
       DCR     D
       JNZ     DBLSHR
       RET
;
;
;
CIOBGN:
CIOFSC: DB      FSCMD,0,0,0,0,0
CIOWRT: DB      WTCMD,0,0,0,1,0C0h
CIORED: DB      RDCMD,0,0,0,1,0
CIOESC: DB      ESCMD,0,0,0,0,0
CIOSTC: DB      STCMD,0,0,0,0,0
CIOFDC: DB      FDCMD,0,0,0,0,0
CIOADT: DB      ADCMD,0,0,0,0,0
CIONUM: EQU     ($-CIOBGN)/6    ;Number of entries above




SYSTK:  DW      0               ;Hold stack



       DS      50
STACK:  DS      1





LETTER: DB      0,EOS

STRACK: DW      0               ;Starting track number
CTRACK: DW      0               ;Current track number
ETRACK: DW      0               ;Ending track number
ESECTOR: DS     3               ;Ending sector



DRVNO:  DB      0
DTYPE:  DB      0
HDFTP:  DB      0               ;Hard disk format type
HDILC:  DB      0               ;Hard disk interleave code
FPDEN:  DB      0               ;floppy Density selection
FPSLV:  DB      0               ;floppy format selection value

E5FLAG: DB      0               ;Format data value



;       Disk I/O Routines
;
;
       IF      I696
;       E X E C

EXEC:   MVI     B,BUSY          ;Wait for not busy.
       MVI     C,BUSY and (not BUSY)
       CALL    WAITM
       RNZ


       MVI     A,SLCT          ;Alert controller
       OUT     DIO+1
EXEC1:
       MOV     C,B             ;Wait for controller busy
       CALL    WAITM
       RNZ

       MVI     A,DODTA         ;Enable data in
       OUT     DIO+1

EXEC2:  IN      DIO+2           ;Get status
       XRI     0FFh
       JM      EXEC2           ;If not requesting next byte
       ANI     CMND+DIROUT
       JNZ     EXEC3           ;If CMND or DIROUT false
       MOV     A,M
       INX     H
       OUT     DIO             ;Send byte from command buffer
       JMP     EXEC2

EXEC3:  CMP     A               ;Z:=1
       RET
;
;
;
;
;       WDISK - Output from memory buffer.
;       ENTRY:  HL = COMMAND BUFFER ADDRESS
;               DE = DATA BUFFER ADDRESS
;

WDISK:  CALL    EXEC            ;Output command
       RNZ                     ;Return if timeout
WDISK1: IN      DIO+2           ;Read status
       ORA     A
       JP      WDISK1          ;If request is present
       ANI     CMND
       JNZ     GCMPS           ;If done with transfer
       LDAX    D               ;Get the data byte
       OUT     DIO
       INX     D               ;Advance buffer address
       JMP     WDISK1
;
;
;
;
;       RDISK - Input to memory buffer.
;
;       Entry:  HL = command buffer address
;               DE = data buffer address

RDISK:  CALL    EXEC
       RNZ                     ;Return if timeout
RDISK1: IN      DIO+2           ;Read status
       ORA     A
       JP      RDISK1          ;If request is present
       ANI     CMND
       JNZ     GCMPS
       IN      DIO
       STAX    D
       INX     D
       JMP     RDISK1
;
;
;
;
;       WAITF - Wait for function to complete.

WAITF:  MVI     B,REQ+CMND      ;Wait for both REQ and CMND
       MOV     C,B
       CALL    WAITM
       RNZ
;
;       Get completion status.

GCMPS:  IN      DIO             ;Get completion status
       MOV     C,A

GCMP1:  IN      DIO+2
       ORA     A
       JP      GCMP1           ;If REQ not set

       MOV     B,A
       IN      DIO             ;Get message byte
       RET
       ENDIF
;

;
;
;
       IF      I796
;       EXEC - Output the command
;
;       Enter:  HL is the command buffer address
;               DE - data transfer address.

EXEC:
       MOV     A,E             ;Output DMA address
       OUT     DIO+2
       MOV     A,D
       OUT     DIO+3
       MOV     A,L
       OUT     DIO+4
       MOV     A,H
       OUT     DIO+5
       MVI     A,0
       OUT     DIO+6
       OUT     DIO+7
       OUT     DIO
       CMP     A               ;Z:=1
       RET


;       Disk read/write
;
;       Entry:  same as EXEC
;
RDISK:
WDISK:  CALL    EXEC
       RNZ                     ;Return if timeout

;       WAITF - Wait until transfer done
;
;       Enter:  none
;       Exit:   when transfer completed

WAITF:  MVI     B,CMDDON        ;Wait for CMDDON
       MOV     C,B
       CALL    WAITM
       RNZ                     ;Return if timeout
;

;       GCMPS - Get completion status
;
;       Enter:  none
;       Exit:   Status in C
GCMPS:  IN      DIO+1
       MOV     C,A
       RET
       ENDIF

;       WAITM - Wait for controller with timeout
;
;       Entry:  B=Status mask
;               C=Status value
;       Exit:   Z=1 if OK, else timeout with A=C=TERR
;
WAITM:
       PUSH    D               ;Save D
       PUSH    H
       LXI     H,138           ;Two minute timeout
       LXI     D,0             ;Max wait @4MHZ is 868 ms
WAITML:
       IF      I696
       IN      DIO+2
       ENDIF
       IF      I796
       IN      DIO
       ENDIF
       ANA     B               ;Mask wait bits
       CMP     C               ;Check value
       JZ      WAITM1
       DCX     D               ;Not ready.  Decrement time
       MOV     A,D
       ORA     E
       JNZ     WAITML
       DCX     H
       MOV     A,H
       ORA     L
       JNZ     WAITML
       MVI     B,0             ;Timeout
       MVI     A,TERR
       ORA     A
WAITM1:
       POP     H
       POP     D               ;Restore D
       MOV     C,A             ;Return status in C
       RET
;       DTC Error Print Routine
;
;Called at completion of disk command when error status is returned.
;
;       Entry:  HL = Address of Command Descriptor Block
;               C = Status byte
;
ERROR:
       PUSH    B               ;Save status
       PUSH    H               ;SAVE ADDRESS OF CDB
       MOV     A,M             ;GET CLASS CODE
       ANI     0E0H
       RAL                     ;MAKE CDB LENGTH INDEX
       RAL
       RAL
       MOV     E,A             ;GET CDB LENGTH
       MVI     D,0
       LXI     H,CDBLEN
       DAD     D
       MOV     C,M
       POP     H               ;RESTORE CDB ADDRESS
       PUSH    H
       LXI     D,ERRCDB
       CALL    PUTHEX          ;BUILD CDB FOR PRINT
       LXI     D,EHEAD         ;Print header
       MVI     C,PRTSTR
       CALL    BDOSV
       POP     H               ;Get status
       POP     B
       PUSH    H
       MOV     A,C             ;Timeout?
       ANI     TERR
       LXI     D,TOMSG
       JNZ     ERROR1
       LXI     H,CIOESC        ;No. READ ERROR SENSE
       LXI     D,SENSE
       CALL    RDISK
       LXI     D,ESENSE
       MVI     C,PRTSTR
       CALL    BDOSV
       LXI     D,ESENS1
       LXI     H,SENSE
       MOV     A,M
       MVI     C,PRTSTR
       ORA     A
       CM      BDOSV
       LXI     D,ETYPE
       LXI     H,SENSE         ;BUILD ERROR SENSE MESSAGE
       MOV     A,M
       RAR
       RAR
       RAR
       RAR
       ANI     3
       CALL    HEXASC
       LXI     D,ECODE
       MOV     A,M
       CALL    HEXASC
       LXI     D,ELUN
       INX     H
       MOV     A,M
       RLC
       RLC
       RLC
       ANI     7
       CALL    HEXASC
       MOV     A,M
       ANI     01FH
       MOV     M,A
       LXI     D,ELAD
       MVI     C,3
       CALL    PUTHEX
       LXI     D,ESENS2        ;PRINT MESSAGE
ERROR1:
       MVI     C,PRTSTR
       CALL    BDOSV
       POP     H               ;RESTORE CDB ADDRESS
       RET
;
;

;       PUT HEXADECIMAL STRING
;
;       ENTRY:  HL = ADDRESS OF HEX NUMBER STRING
;               DE = ADDRESS OF HEX ASCII STRING
;                C = NUMBER OF BYTES TO CONVERT
;
PUTHEX: CALL    HEXBYT
       MVI     A,' '
       STAX    D
       INX     D
       DCR     C
       JNZ     PUTHEX
       MVI     A,EOS
       STAX    D
       RET
;
;
HEXBYT: MOV     A,M
       RAR
       RAR
       RAR
       RAR
       CALL    HEXASC
       MOV     A,M
       INX     H
HEXASC: ANI     0FH
       ADI     090H
       DAA
       ACI     040H
       DAA
       STAX    D
       INX     D
       RET
;
;
;       CDB length table (indexed by class)
CDBLEN: DB      6,10,0,0,0,0,6,6
;
EHEAD:  DB      CR,LF,LF,'Disk error:'
       DB      CR,LF,'Command Descriptor:',TAB,TAB
ERRCDB: DS      31
;
TOMSG:  DB      CR,LF,TAB,TAB,TAB,TAB,'Timeout',EOS
ESENSE: DB      CR,LF,'Error Sense:',EOS
ESENS1: DB      CR,LF,TAB,TAB,TAB,TAB,'Block address valid.',EOS
ESENS2: DB      CR,LF,TAB,'Error type:',TAB,TAB
ETYPE:  DS      1
       DB      CR,LF,TAB,'Error code:',TAB,TAB
ECODE:  DS      1
       DB      CR,LF,TAB,'Logical unit:',TAB,TAB
ELUN:   DS      1
       DB      CR,LF,TAB,'Logical address:',TAB
ELAD:   DS      4
SENSE:  DS      4
;
BUFFER: EQU     $
;
       END