; 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