; DISK I/O ROUTINES FOR THE ICOM FD360 (OR FD3712) DISK DRIVE TO WORK
;    WITH THE MITS PROGRAMMING SYSTEM II.
;
; USING SSM-IO4 AS BUS INTERFACE REQUIRES INVERTING DATA BYTES AND
;    SWAPPING BITS 76543210 TO 10325476.

	ORG	0F800H

ICOM	equ	1
IO4	equ	0

 if IO4
; FD3712 COMMANDS (INVERTED AND BITS SWAPPED)

CSTATUS	EQU	0FFH	;00H
CREAD	EQU	03FH	;03H
CWRITE	EQU	0AFH	;05H
CRDCRC	EQU	02FH	;07H
CSEEK	EQU	09FH	;09H
CCLRERR	EQU	01FH	;0BH
CRESTOR	EQU	08FH	;0DH
CSETTRK	EQU	0BBH	;11H
CDRVSEC	EQU	0B7H	;21H
CWRTBUF	EQU	0B3H	;31H
CRDBUF	EQU	0FEH	;40H
CSHIFT	EQU	0BEH	;41H
CRESET	EQU	0BDH	;81H
CLDCFG	EQU	0ABH	;15H

; CONTROLLER STATUS BITS (BITS SWAPPED)

SBUSY	EQU	40H	;01H
SCRCERR	EQU	20H	;08H
SWRTPRT	EQU	04H	;10H
SNOTRDY	EQU	08H	;20H
SRDERRS	EQU	28H	;28H
SWRERRS	EQU	0CH	;30H
 endif

 if ICOM
; FD3712 controller commands

cSTATUS	equ	00h		;read status
cREAD	equ	03h		;read sector
cWRITE	equ	05h		;write sector
cRDCRC	equ	07h		;validate sector CRC
cSEEK	equ	09h		;seek to track
cCLRERR	equ	0Bh		;clear error flags
cRESTOR	equ	0Dh		;seek to track 0
cSETTRK	equ	11h		;set track to seek
cDRVSEC	equ	21h		;set unit and sector
cWRTBUF	equ	31h		;write buffer
cRDBUF	equ	40h		;read buffer
cSHIFT	equ	41h		;shift read buffer
cRESET	equ	81h		;reset the controller
cLDCFG	equ	15h		;load configuration

; Controller status bits

sBUSY	equ	01h		;1=busy
sCRCERR	equ	08h		;1=CRC error
sWRTPRT	equ	10h		;1=write protected
sNOTRDY	equ	20h		;1=drive not ready
sRDERRS	equ	28h		;not ready and CRC bits
SWRERRS	EQU	30H
 endif

; INTERFACE BOARD 

CMDOUT	EQU	0C0H
DATAIN	EQU	0C0H
DATAOUT	EQU	0C1H

; DRIVE EQUATES

SECTRK1	EQU	27		;SECTORS PER TRACK+1
SECLEN	EQU	128
WSTRKS	EQU	7		;NUM TRACKS IN WORKSPACE
NUMWS	EQU	11		;NUM WORKSPACES ON DISK

; CONSOLE I/O

SIOCSR	EQU	10H
SIODR	EQU	11H
RCVRDY	EQU	01H
XMTRDY	EQU	02H

; MISC EQUATES

JMPINST	EQU	0C3H		;JMP INSTRUCTION
CR	EQU	00DH
LF	EQU	00AH
LFMSB	EQU	08AH		;LF WITH MSB SET
SPMSB	EQU	0A0H		;SPACE WITH MSB SET

; JUMP TABLE

	JMP	BOOT		;LOAD WORKSPACE FOR COLD BOOT
	JMP	LOADWS		;LOAD WORKSPACE
	JMP	SAVEWS		;SAVE WORKSPACE

	JMP	DRVINI
	JMP	SETDRV
	JMP	SETTRK
	JMP	SETSEC
	JMP	SETDMA
	JMP	READ
	JMP	WRITE

	JMP	GETCHR
	JMP	DSPCHR
	JMP	DSPMSG

; WORKSPACE LOAD AND SAVE ROUTINES
;   READ OR WRITE 7 TRACKS FROM/TO RAM AT 0000H. STORED ON DISK IN
;   ASCENDING RAM ORDER WITH SKEW OF 2.
;	1,3,5...23,25,2,4,6...24,26.

; BOOT - SPECIALIZED CASE OF LOAD WORKSPACE THAT INITIALIZES THE STACK,
;    THE CONTROLLER, SERIAL I/O, AND DOESN'T EXIT TO MONITOR.

BOOT:	LXI	SP,STACK
	LXI	H,READ
	SHLD	DVADDR
	CALL	DRVINI
	CALL	SIOINI

BOOTLP:	CALL	GETWSP		;GET WORKSPACE, PROMPT FORCED
	JNC	BOOTLP		;INVALID
	JMP	XFRWS	

; LOADWS, SAVEWS - LOAD OR SAVE WORKSPACE

LOADWS:	LXI	H,READ
	JMP	XFRINI

SAVEWS:	LXI	H,WRITE

XFRINI:	SHLD	DVADDR
	LXI	SP,STACK
	CALL	GETWS
	JNC	BADWS

; XFRWS - TRANSFER THE WORKSPACE (LOAD OR SAVE)

XFRWS:	MVI	A,JMPINST	;INIT THE DISK VECTOR JUMP
	STA	DSKVEC
	LXI	H,0		;STARTING AT ADDRESS ZERO
	MVI	D,WSTRKS	;D=COUNT OF TRACKS 

TRKLP:	CALL	XFRTRK
	JNZ	DSKERR
	LDA	TRKNUM	
	INR	A
	STA	TRKNUM
	DCR	D
	JNZ	TRKLP	

	JMP	0 		;JUMP TO LOADED WORKSPACE

BADWS:	CALL	DSPMSG
	DB	'WE',CR,LFMSB
	JMP	0		;EXIT TO MONITOR

DSKERR:	CALL	DSPMSG
	DB	'DE',CR,LFMSB
	JMP	BOOTLP		;TRY AGAIN 

; XFRTRK - TRANSFER A TRACK OF SECTORS
	
XFRTRK:	MVI	A,1		;START AT SECTOR 1

XTLOOP:	STA	SECNUM
	SHLD	DMAADR
	CALL	DSKVEC		;READ OR WRITE
	RNZ		
	LDA	SECNUM		;INCREMENT SECTOR BY 2
	ADI	2
	CPI	SECTRK1
	JC	XTLOOP

	JNZ	XTEXIT		;EVEN SECTOR DONE, TRACK COMPLETE
	MVI	A,2		;READ EVEN SECTORS
	JMP	XTLOOP

XTEXIT:	XRA	A		;FORCE ZERO STATUS
	RET

; GETWS - PROMPT FOR AND INPUT WORKSPACE NUMBER TO LOAD/SAVE. RETURNS
;    CARRY SET IF VALID, CARRY CLEAR IF INVALID.

GETWS:	LDAX	B		;GET COMMAND LINE LENGTH
	CPI	6		;NOT 6, PROMPT FOR WORKSPACE
	JNZ	GETWSP

	INX	D		;MOVE TO WS #
	INX	D
	LDAX	D		;A=WS #
	JMP	GWCONV

GETWSP:	CALL	DSPMSG
	DB	'Workspace #:',SPMSB
	CALL	GETCHR
	CALL	DSPCHR		;ECHO

	PUSH	PSW		;SAVE VALUE TYPED
	CALL	DSPMSG
	DB	CR,LFMSB
	POP	PSW

GWCONV:	SUI	30H		;SUBTRACT ASCII OFFSET
	CPI	9
	JC	HAVEWS	
	SUI	7		;DUST 'A'-'F' TO 9-E
	
HAVEWS:	CPI	NUMWS		;VALID?
	RNC			;NO, ABORT
	
	MOV	C,A		;MULTIPLY BY 7 TRACKS PER WS
	ADD	A		;*2
	ADD	A		;*4
	ADD	A		;*8
	SUB	C		;*7
	STA	TRKNUM
	STC			;CARRY=VALID
	RET

; SETTRK, SETDRV, SETSEC, SETDMA - SIMILAR TO CP/M BIOS ENTRY POINTS
;    TO ALLOW EXTERNAL USE OF THE READ AND WRITE ROUTINES

SETDRV:	STA	DRVNUM
	MVI	A,0FFH		;TRACK NUM NOT KNOWN
	STA	DRVTRK
	RET

SETTRK:	STA	TRKNUM
	RET        

SETSEC:	STA	SECNUM
	RET
	
SETDMA:	SHLD	DMAADR
	RET

; READ - READ SECTOR. ZERO TRUE FOR SUCCESS, FALSE FOR FAILURE.

READ:	CALL	SEEK
	RNZ
	MVI	C,10		;C=RETRY COUNTER

RDRTRY:	MVI	A,CREAD
	CALL	DOCMD
	ANI	SRDERRS
	JZ	RDXFER		;GOOD READ, GO TRANSFER DATA

	CALL	CLRERR
	DCR	C
	JNZ	RDRTRY

	INR	C		;FORCE ERROR STATUS
	RET

RDXFER:	LHLD	DMAADR
	MVI	C,SECLEN
	
RDLOOP:	MVI	A,CRDBUF	;READ BYTE
	OUT	CMDOUT
	IN	DATAIN
	MOV	M,A

	MVI	A,CSHIFT	;SHIFT FIFO TO NEXT BYTE
	OUT	CMDOUT
	INX	H 
	DCR	C
	JNZ	RDLOOP

	MVI	A,CSTATUS	;LEAVE CONTROLLER IN STATUS STATE
	OUT	CMDOUT
	RET

; WRITE - WRITE SECTOR. ZERO TRUE FOR SUCCESS, FALSE FOR FAILURE.

WRITE:	CALL	SEEK
	RNZ
	LHLD	DMAADR
	MVI	C,SECLEN 

WRLOOP:	MOV	A,M		;WRITE BYTE TO CONTROLLER
	OUT	DATAOUT
	MVI	A,CWRTBUF
	OUT	CMDOUT
	MVI	A,CSTATUS	;LSBIT BACK TO ZERO
	OUT	CMDOUT
	
	INX	H 
	DCR	C
	JNZ	WRLOOP

	MVI	A,CWRITE 	;ISSUE WRITE CMD
	CALL	DOCMD
	ANI	SWRERRS
	RZ			;GOOD WRITE

	PUSH	PSW		;SAVE ERROR
	CALL	CLRERR
	POP	PSW
	RET		

; SEEK - SEEK TO TRACK AND SPECIFY SECTOR. ZERO TRUE FOR SUCCESS,
;    FALSE FOR FAILURE.

SEEK:	CALL	SELSEC		;SELECT DRIVE, SET SECTOR
	MVI	E,2		;E=RETRY COUNTER

SKRTRY:	LDA	TRKNUM
	LXI	H,DRVTRK	;HL->CURRENT TRACK
	CMP	M
	RZ			;ALREADY ON TRACK

	MOV	M,A		;DRVTRK=NEW TRACK	
	CALL	CTLTRK		;SET TRACK IN CONTROLLER
	MVI	A,CSEEK
	CALL	DOCMD
	ANI	SRDERRS	
	RZ

	CALL	CLRERR		 
	MVI	M,0FFH		;TRACK NOT VALID	
	DCR	E
	JNZ	SKRTRY
	
	INR	E		;FORCE ERROR STATUS
	RET


; SELSEC - SELECT DRIVE, SET SECTOR IN CONTROLLER

SELSEC:	LDA	DRVNUM
	ANI	03H
	RRC			;PUT DRIVE NUMBER IN UPPER TWO BITS
	RRC
	MOV	C,A		;C=DRIVE IN UPPER TWO BITS

	LDA	SECNUM		;COMBINE DRIVE WITH SECTOR NUMBER
	ORA	C
	MVI	C,CDRVSEC	;SET SECTOR IN CONTROLLER
	JMP	CMDDAT

; CTLTRK - SET TRACK IN CONTROLLER

CTLTRK:	MVI	C,CSETTRK

; CMDDAT - SEND CMD FROM C AFTER SETTING DATA FROM A

CMDDAT:	equ	$

 if IO4
	PUSH	PSW		;MAP BITS 76543210 TO 10325476
	RLC
	RLC
	ANI	33H		;--32--76
	MOV	B,A		;B=half result

	POP	PSW		
	RRC
	RRC
	ANI	0CCH		;10--54--
	
	ADD	B		;A=ALL BITS SWAPPED
	CMA			;INVERT BYTE
 endif
	OUT	DATAOUT		;SET DATA
	MOV	A,C		;A=COMMAND TO WRITE

; DOCMD - ISSUE COMMAND FROM A, WAIT FOR COMPLETION

DOCMD:	OUT	CMDOUT 
	MVI	A,CSTATUS	;EXIT IN EXAMINE STATUS
	OUT	CMDOUT

WTCMD:	IN	DATAIN		;WAIT FOR NOT BUSY
	ANI	SBUSY
	JNZ	WTCMD
;	JZ	WTCMD		;DATA COMES IN INVERTED

	IN	DATAIN		;GET STATUS
;	CMA			;DATA COMES IN INVERTED
	RET

; DRVINI - INIT DRIVE AND CONTROLLER

DRVINI:	XRA	A		;DEF DRIVE 0
	STA	DRVNUM
	DCR	A		;INVALID CURRENT TRACK	
	STA	DRVTRK
	MVI	A,CRESET
	JMP	DOCMD		;RESET AND EXIT

; CLRERR - CLEAR CONTROLLER ERRORS

CLRERR:	MVI	A,CCLRERR
	JMP	DOCMD

; SIOINI - INITIALIZE SERIAL PORT

SIOINI:	LXI	B,800		;DELAY 10MS, LET OUTPUT FINISH
 	
SIODLY:	DCX	B
 	MOV	A,B
 	ORA	C
 	JNZ	SIODLY
 	
	MVI	A,3		;RESET 6850 UART
	OUT	SIOCSR
	MVI	A,15H		;8N1
	OUT	SIOCSR
	RET

; DSPCHR - DISPLAY CHAR FROM A, CLOBBERS B

DSPCHR:	MOV	B,A

DCLOOP:	IN	SIOCSR
	ANI	XMTRDY
	JZ	DCLOOP

	MOV	A,B
	ANI	7FH
	OUT	SIODR
	RET

; GETCHR - WAIT FOR AND RETURN NEXT CHARACTER TYPED

GETCHR:	IN	SIOCSR
	ANI	RCVRDY
	JZ	GETCHR

	IN	SIODR
	ANI	7FH
	RET

; DISPLAY MSBIT TERMINATED MESSAGE, CLOBBERS B

DSPMSG:	POP	H		;HL->MSG

DMLOOP:	MOV	A,M
	INX	H
	CALL	DSPCHR
	CMP	B
	JZ	DMLOOP		;LOOP UNTIL MSB SET

	PCHL			;RETURN PAST MESSAGE

; RAM ALLOCATION

	ORG	7F00H		;OUTSIDE LOADED WORKSPACE
DRVNUM:	DS	1
TRKNUM:	DS	1
DRVTRK:	DS	1		;TRACK DRIVE IS ON
SECNUM:	DS	1
DMAADR:	DS	2

DSKVEC:	DS	1		;JUMP TO DISK READ OR WRITE
DVADDR:	DS	2		;  ADDRESS IN JUMP INSTRUCTION

	DS	32		;STACK SPACE
STACK:	DS	1		;EQU $ FAILS HERE

	END
	EOA
