; INTEL MDS FDC CARD EMULATOR
;
; SOURCED NOV 79 BY TREVOR MARSHALL
; Dept E & E Eng
; University of West Australia
; NEDLANDS, W.A. 6009
;
; This version of the source produces, after linking,
; object code in memory from 600H to A000H to enable
; a Prom Programmer resident in the host system
; to directly program the object file
;
; A version ORGed at F800H is compiled seperately
; and is provided on the master disk as MDSABS.Z80
;
;
; REGISTER USAGE DURING READ AND WRITE:
; D contains the (auto wait) drive control byte
; IX points to the IOPB base
; HL points to the current memory DMA address
; B contains the input byte counter for INI & OUTI
; C contains DDATA for INI & OUTI
; B' (alternate) contains the number of records required
; D' (alternate) contains the current sector address
; E' (alternate) contains the retry count
; H' (alternate) contains the previously logged track
; AF' (alternate) contains the previous drive mask
; to skip read trk# if it is already logged
; and allow for fast response without interleaving
;
; FDC CONTROLLER DEFINITIONS:
DCONTROL:EQU 63H ;Control Port
DFLAGS: EQU 63H ;FDC Status Port
DDATA: EQU 67H ;1793 Data Port
DSTATUS: EQU 64H ;1793 Status Port
DCOMMAND:EQU 64H ;1793 Command Port
DTRACK: EQU 65H ;1793 Track Port
DSECTOR: EQU 66H ;1793 Sector Port
DSIDE: EQU 4 ;Bit 1=0 selects side 1
; of D/S drives
;
; DISK CONTROL PORT HARDWARE ENVIRONMENT
; Bits 0-3 select drives 1-4
; Bit 7 enables auto wait on accesses to DDATA
; Bit 5 enables dsk drive motors
; Bit 4 selects single density (S/D)
;
; DISK STATUS PORT HARDWARE REQUIREMENTS
; Bit 0 is 1793 INTREQ status output
; Bit 5 indicates head is loaded
;
; DISK DENSITY DEFINITIONS
MAXSECTORS: EQU 1AH ;Single Density
MAXTRACKS: EQU 4CH ; 8" Disks
;
; PIO DEFINITIONS:
ACOMMAND:EQU 7AH
ADATA: EQU 78H
BCOMMAND:EQU 7BH
BDATA: EQU 79H
;
; BUS CONTROL:
RELEASE: EQU 7FH ;I/O To this addr releases bus
HOLD: EQU 7CH ;I/O to this addr requests bus
;
; MDS PORT DEFINITIONS:
STATUS: EQU 7EH ;S100 Bus reads 78H
;Note that port 78H is referenced directly in ASERVICE
;TYPE: Not Implemented
RESULT: EQU 7DH ;S100 Bus reads 7BH
;RESET: Not Implemented
IOPBLOW: EQU 79H
IOPBHIGH:EQU 7AH
;
; DISKETTE INSTRUCTION CODES:
NOP: EQU 0
SEEK: EQU 1
FORMAT: EQU 2
RECALIB: EQU 3
READ: EQU 4
VERIFY: EQU 5
WRITE: EQU 6
WRITEDEL:EQU 7 ;Write deleted data mark;
;
; AS THERE IS NO STACK RAM AVAILABLE ALL CODE
; MUST BE SEQUENTIAL
;
; THE PROM PROGRAMMER REQUIRES AN ADDRESS OFFSET
; OF 0F200H FOR THIS ORG 0F800H CODE
;
; THE FOLLOWING MACROS FORM COMMONLY USED ROUTINES
;
STOP: MACRO
LD SP,STACK; Point at ROM stack
IN A,RELEASE
RETI
MEND
DONE: MACRO ;Set up status port & stop
LD A,0FH
OUT STATUS,A
STOP
MEND
;
INTREQ: MACRO ;Wait for intreq
LL#SYM: IN A,DFLAGS ;Loop until 1793 INTREQ active
RRA
JR NC,LL#SYM
MEND
;
ERRORS: MACRO #LOOP,#MASK ;Check 1793 for errors
INTREQ
IN A,DSTATUS
EXX ;Save working registers
LD C,A ;Save error byte
AND 80H ;Not ready mask
EXX
JR NZ,#LOOP ;Loop until drive ready
EXX
LD A,C
AND #MASK ;General error mask
JP NZ,SELECT+OFFSET ;Retry if any errors
EXX
MEND
;
SETUP: MACRO ;Set up read and write common parameters
LP: DL AA#SYM
AA#SYM: INC D ;Sector #
LD A,D
OUT DSECTOR,A
EXX
LD A,D
OUT DCONTROL,A
LD B,80H ;Input byte count
IN A,DFLAGS ;Is head loaded?
AND 20H
JR Z,J2#SYM ;No
LD A,0
JR J3#SYM
J2#SYM: LD A,04H ;Head load mask for 1793
J3#SYM DL $
MEND
;
CHECK: MACRO ;See if read or write is complete
EXX
DJNZ LP
EXX
LD B,0 ;Done
JP FINISH+OFFSET
MEND
;
; NOTE THAT THE 1793 NEEDS TIME TO CALCULATE CRC
; BEFORE THE ERROR STATUS IS AVAILABLE
; IF THE DRQ IS NOT SERVICED
; The following delay loop is sufficient (4MHz Z-80)
DELAY: MACRO
LD B,30H ;12 to 15 give CRC errors
; 0 to 12 give BUSY flag
DJNZ $
MEND
;
; Check for 1793 errors during read and write
DERROR: MACRO #MASK
INTREQ
IN A,DSTATUS
EXX
LD C,A ;Save error byte
EXX
; Note that we will not check for deleted data marks
AND #MASK
JP NZ,S2+OFFSET ; Retry errors
MEND
; LINKER AND PROM PROGRAMMER CODE REQUIREMENTS
ORG 100H
JP 0
OFFSET: EQU 0F800H-600H
; Setup vectors at top of ROM
ORG 9F4H ;Effectively FBF4
VEC1: DW ASERVICE+OFFSET
VEC2: DW BSERVICE+OFFSET
WAIT: EI
HALT ;wait for interrupt
; STACK: To enable interrupt structure we need a 'stack'
DW WAIT+OFFSET
STACK: EQU $+OFFSET
DW WAIT+OFFSET
DW WAIT+OFFSET
;
; Hardware Reset Code
ORG 600H
START: JP 0F804H
NOP
; The ORG address is now effectively F804H
; Now setup PIO & Interupts
;
IM2
LD A,0FBH
LD I,A ;Int vector table near FBF2
LD A,0F4H ;IVEC(A) = FBF4
OUT ACOMMAND,A
LD A,0F6H ;IVEC(B) = FBF6
OUT BCOMMAND,A
LD A,4FH ;MODE 1
OUT ACOMMAND,A
OUT BCOMMAND,A
IN A,ADATA ;Set READY handshake
IN A,BDATA
LD A,87H ;Enable PIO interrupt mode
OUT ACOMMAND,A
OUT BCOMMAND,A
; Now setup output latches
LD A,00
OUT RESULT,A
LD A,0BH ;:F0:,:F1: ready, not D/D
OUT STATUS,A
EX AF,AF'
LD A,0 ;Clear drive select mask
EX AF,AF'
EXX
LD H,0FFH ;Clear logged trk
EXX
LD SP,STACK
EI
HALT
; Routine to service PIO inputs
; (79) go to IX lower, (7A) to IX upper
;
ASERVICE: DI
OUT HOLD,A ; Lock out bus until done
NOP ;Allow time for bus control
NOP
IN A,78H ; S100 Status port read (& reset)
; ; must be done during bus access
IN A,ADATA
LD IX,0
LD C,A
LD B,0
ADD IX,BC ;Now have A in IX
STOP
BSERVICE: DI
OUT HOLD,A ; Lock out bus until done
IN A,BDATA
LD B,A
LD C,0
ADD IX,BC ; IX now points to IOPB
; Now select side 0 of disks
LD A,2 ;Set bit 1
OUT DSIDE,A
;
EXX
LD E,0AH ;10 retries
JR SELECT
;
; NOW BEGIN DECODING COMMAND WORD
;
; FIRST SELECT THE DRIVE (:F0:=A:, :F1:=C:)
;
S2: EXX
LD H,0FFH ;Log off track if error occurs
; ;This will cause a RESTORE cmd
; ;To be executed for SEEK errors
SELECT: LD A,E
CP 0 ;Have we retried 10 times?
LD A,C ;Error byte
JP Z,EXIT+OFFSET
DEC E
EXX
LD A,(IX+0)
AND 3FH ;Check for acceptable channel word
JP NZ,CHERROR+OFFSET ; Channel error
;
;If the op is NOP,FORMAT or RECALIBRATE
;Dont check address field
LD A,(IX+1)
AND 07H ;Now have opcode field
CP 1 ;Seek
JR Z,DONTSKIP
SUB 4
JR C,SKIP ; <=3
DONTSKIP:
; Now check for valid IOPB addresses
N12: LD A,(IX+3) ;Track address
SUB MAXTRACKS+1 ;max track # + 1
JP NC,ADDERROR+OFFSET
LD A,(IX+4)
;
; Must reset bits 4 & 5 of sector byte (a drive select bit)
; to retain compatibility with S/D MDS systems
AND A,09FH
JP Z,ADDERROR+OFFSET ;Zero sector #
SUB MAXSECTORS+1 ;Max sector # + 1
JP NC,ADDERROR+OFFSET
LD A,(IX+4) ;Sector addr
;
; Must reset bit 5 of sector byte (a drive select bit)
; to retain compatibility with S/D MDS systems
AND A,09FH
LD C,(IX+2) ;Number of records requested
ADD A,C
SUB A,MAXSECTORS+2
JP NC,ADDERROR+OFFSET ;Final sector >1AH
; Address errors trapped, now seek to required track
;
SKIP: LD A,(IX+1) ;Instruction word
AND 30H ;Get drive mask
RRC A
RRC A
RRC A
RRC A
CP 3 ; S/D MDS drive #1 mask
JR Z,BSELECT ;Select drive B
; Dont allow for more than 2 drives
LD D,0B1H ;Auto wait,motor on,S/D,A:
JR J3
BSELECT: LD D,0B2H ;Auto wait,motor on,S/D,B:
; D contains the drive control byte with auto wait set
;
; Now check for recalibrate, nop & format instructions
;
J3: LD A,(IX+1)
AND 07H
CP RECALIB
JR Z,RESTORE
CP NOP
JR Z,DONOP
CP FORMAT
JR Z,DONOP
JR DOSEEK;Not one of these ops
DONOP: LD B,0
JP FINISH+OFFSET
RESTORE: LD A,D ;Drive control byte
AND 7FH ;Reset auto wait
OUT DCONTROL,A
LD A,0DH ;1793 Restore command
OUT DCOMMAND,A
ERRORS RESTORE,99H
LD B,0
JP FINISH+OFFSET
;
DOSEEK: ;Read, write, verify & seek
;all require a seek op first
; Now check if drive is logged
; trk # will then be available without the read addr op
;
EX AF,AF'
CP A,D ;Is it the same as the last?
LD A,D
JR NZ,LOG ;No, log it
EX AF,AF'
EXX
LD A,H ; fetch last trk #
EXX
LD B,A ;Save it
CP (IX+3) ;Is the desired trk the same?
JR NZ,LOG2 ;No, read address
JP LOGGED+OFFSET
; Check current track # by reading address from disk
;NOTE THAT THE 1793 DOES NOT HEAD LOAD ON 'READ ADDRESS'
; IF THE READY INPUT IS NOT ACTIVE
; so we must issue a dummy SEEK command first
;
LOG: EX AF,AF'
; Will first execute a RESTORE command on the new drive
REST1: LD A,D
AND 7FH ;Reset auto wait
OUT DCONTROL,A
LD A,0DH ;1793 Restore command
OUT DCOMMAND,A
ERRORS REST1,99H
;
; Now seek to desired track
LOG2: LD A,D
AND 7FH ;Reset auto wait
OUT DCONTROL,A
IN A,DTRACK
OUT DDATA,A ;desired trk=current one
L3: LD A,1AH ;Seek, no verify
OUT DCOMMAND,A
ERRORS LOG2,99H
;
L2: LD A,0C4H ;1793 Read address cmd
OUT DCOMMAND,A
;Discard the data bytes
INTREQ
DELAY
IN A,DSTATUS
AND 19H ; status would not be valid
JR NZ,L2
IN A,DSECTOR ;where the 1793 puts the trk
LD B,A ;Save it
EXX
LD H,A ; log it
EXX
;
; Now must clear the data request by reading DDATA
IN A,DDATA
;
LOGGED: LD A,B ;Fetch current track addr
CP (IX+3) ;Is it the same?
OUT DTRACK,A
JR Z,J11 ;Yes, skip read addr
LD A,(IX+3)
OUT DDATA,A
S1: LD A,D
AND 7FH
OUT DCONTROL,A ;Disable auto wait
LD A,1DH ;Seek with verify
OUT DCOMMAND,A
ERRORS S1,99H
; Now have desired track, check to see if op was seek
;
J11: LD A,(IX+1)
AND 07H
CP SEEK
JP Z,FINISH+OFFSET ; was seek only
;
; Now calculate the number of records
; and setup dedicated register values
;
EXX
LD B,(IX+2) ;Number of records
LD A,(IX+4)
;
; Must reset bit 5 of sector byte (a drive select bit)
; to retain compatibility with S/D MDS systems
LD D,09FH
AND A,D
LD D,A
DEC D ;Initial sector (-1 for SETUP)
EXX
;
LD H,(IX+6)
LD L,(IX+5)
LD C,DDATA
;
; Was it a read, write or writedel operation?
LD A,(IX+1)
AND 07H
CP READ
JR Z,DOREAD
CP WRITE
JP Z,DOWRT+OFFSET
CP WRITEDEL
JP Z,DOWRTDEL+OFFSET
CP VERIFY
JP DOVERIFY+OFFSET
;
DOREAD: EXX
SETUP
ADD A,88H ;1797 Read command
OUT DCOMMAND,A
J13: IN A,DFLAGS
RRA
JR C,J12 ;INTREQ = error or read complete
INI
JP NZ,J13+OFFSET ;Fetch next data byte
; Z set when B=0, ie 128 bytes have been read
J12: DERROR 9DH
CHECK
;
DOVERIFY: EXX ;Similar to DOREAD
SETUP
ADD 88H ;1797 compatible
OUT DCOMMAND,A
J14: IN A,DFLAGS
RRA
JR C,J15
IN A,(C) ;Discard input data
JP J14+OFFSET
J15: DERROR 9DH
CHECK
;
DOWRT: EXX ;Similar to read in structure
SETUP
ADD A,0A8H ;1797 compatible
OUT DCOMMAND,A
J16: IN A,DFLAGS
RRA
JR C,J17
OUTI
JP NZ,J16+OFFSET
J17: DERROR 0FDH
CHECK
;
DOWRTDEL: EXX
SETUP
ADD A,0A9H ;1797 compatible
OUT DCOMMAND,A
J20: IN A,DFLAGS
RRA
JR C,J19
OUTI
JP NZ,J20+OFFSET
J19: DERROR 0FDH
CHECK
;
; Address and Channel error routines
;
;THIS ENTRY IS VALID DURING ERROR TRAPS
A1: LD A,08H
OUT RESULT,A
JP STAT+OFFSET
;
; 1793 Error exit routines
;
; Will print out error messages for ease of debugging
; Will use the RST7,RST6 area of RAM for stack
;
EXIT: EXX
LD SP,0038H ; Out of ISIS area
PUSH AF
CALL PMSGFOLLOWING+OFFSET
DB 0DH,'1793',0A0H
POP AF
PUSH AF
CALL P2HEX+OFFSET
CALL PRINTIOPB+OFFSET
POP AF
LD B,0 ;Use B to hold result byte
BIT 0,A
JR Z,J5
SET 0,B
SET 7,B
J5 BIT 1,A ;DRQ error
JR Z,J6
SET 4,B
J6: BIT 2,A ;Lost data
JR Z,J7
SET 4,B
J7: BIT 3,A ;CRC
JR Z,J8
SET 1,B
J8: BIT 4,A ;Seek error
JR Z,J9
SET 2,B
J9: BIT 6,A
JR Z,FINISH
SET 5,B
FINISH: LD A,B
OUT RESULT,A
; The following code has been nulled as it
; causes the motors to 'cycle' in speed too much.
; A delayed turnoff is needed
; Switch off the drive motors
; LD A,D
; AND 5FH ;motors + wait off
; OUT DCONTROL,A
STAT: DONE
;
; OUTPUT MESSAGE ROUTINES
PRINTIOPB: CALL PMSGFOLLOWING+OFFSET
DB ' ERROR, IOPB A',0D4H
PUSH IX
POP HL
CALL SPACE+OFFSET
CALL PMSGFOLLOWING+OFFSET
DB ', CONTENTS:',0A0H
LD A,(IX+0)
CALL P2HEX+OFFSET
LD A,(IX+1)
CALL P2HEX+OFFSET
LD A,(IX+2)
CALL P2HEX+OFFSET
LD A,(IX+3)
CALL P2HEX+OFFSET
LD A,(IX+4)
CALL P2HEX+OFFSET
LD L,(IX+6) ;Print in reverse order
LD H,(IX+5)
CALL SPACE+OFFSET
CALL PMSGFOLLOWING+OFFSET
DB 0DH,8AH
RET
ADDERROR: LD SP,0038H ;Not in ISIS area
CALL PMSGFOLLOWING+OFFSET
DB 0DH,'ADDRESS',0A0H
CALL PRINTIOPB+OFFSET
JP A1+OFFSET
CHERROR: LD SP,0038H
CALL PMSGFOLLOWING+OFFSET
DB 0DH,'CHANNEL',0A0H
CALL PRINTIOPB+OFFSET
JP A1+OFFSET
PMSG: PUSH AF
PS1: LD A,(HL)
INC HL
CALL PCHR+OFFSET
RLA
JR NC,PS1
POP AF
RET
PMSGFOLLOWING:
EX (SP),HL
CALL PMSG+OFFSET
EX (SP),HL
RET
PCHR: PUSH AF
;SJ2: IN A,0F7H ;CRT STATUS
; AND 1
; JR Z,SJ2
; POP AF
; PUSH AF
; OUT 0F6H,A ;CRT DATA
SJ1: IN A,0FBH ;PRINTER STATUS
AND 1
JR Z,SJ1
POP AF
OUT 0FBH,A ;PRINT DATA
RET
SPACE: LD A,20H
CALL PCHR+OFFSET
LD A,H
CALL P2HEX+OFFSET
LD A,L
P2HEX: PUSH AF
LD A,20H
CALL PCHR+OFFSET
POP AF
CALL P1HEX+OFFSET
RRA
P1HEX: RRA
RRA
RRA
RRA
PUSH AF
AND 0FH
CP 10
JR C,PH1
ADD 7
PH1: ADD 30H
CALL PCHR+OFFSET
POP AF
RET
END START