	TITLE	INTELLIGENT SASI HOST ADAPTOR INTERFACE
	LIST	NOCOND
;**************************************************************************
;
;	THIS MODULE CONTAINS THE INTELLIGENT HOST ADAPTER FIRMWARE.
;
;**************************************************************************
;
;	IOPB CONFIGURATION:
;
; DRIVE #	TRANSLATES TO
;   0		SASI physical drive 0
;   1		SASI physical drive 1
;   2		SASI physical drive 2
;   3		SASI physical drive 3
;   4		JADE floppy disk controller physical drive 0
;   5		JADE floppy disk controller physical drive 1
;   6		JADE floppy disk controller physical drive 2
;   7		JADE floppy disk controller physical drive 3
;
;**************************************************************************
;
;	REVISIONS:
; 1.0 -	28 DEC 83   GRH
;	DIAGNOSTIC VERSION FOR TESTING THE BOARD.
; 1.1 -	2 JAN 84   GRH
;	ADD HARD DISK CONTROLLER FIRMWARE.
; 1.2 -	1 APR 84   GRH
;	Fix Bug in host xfer subr. that caused problems on 32k boundary
;	crossings. Enable parity checking for received data. Enable
;	controller retrys.
; 1.3 -	2 APR 84   GRH
;	Fix Bug in read buffer routine which caused 1st 4 bytes of sector
;	to be 0 and read not retryed but sense status to be issued instead.
;	The CDB had to be re-initialized with the read command after getting
;	results command issued.
;
; 1.4 -	28 APR 84   GRH
;	Add Jade FDC routines. Change host block move subrs into general
;	 purpose subrs.
;
; 1.5 -	30 APR 84   GRH
;	Change hardware to reflect the state of the interrupt flip-flop
;	as the busy bit (D0). Hardware will now allow software setting of
;	the interrupt flip-flop to allow passing a busy state if required.
;	Normally this change will allow transparent operation of the soft-
;	ware, without concern to the busy status. All other status bits
;	reflect the software status register contents (D1..7).
;
; 1.6 - 3 MAY 84   GRH
;	Change block move subroutine to allow for 1..65,536 byte moves.
;	Fix bugs in Jade driver. Add printer output diagnostic.
;
; 1.7 -	2 JUN 84   GRH
;	Fix bug in HSTIN & HSTOUT macros outputting bit 7 data to XADDR
;	  register instead of to HXAD15 register.
;	Add JADE FDC dump to dump diagnostic command.
;
; 1.8 -	2 JUN 84   GRH
;	Change floppy disk read/write sector to logical sector for uniformity
;	   in IOPB parameters. (0..N-1 now changed to 1..N)
;
; 1.9 -	3 OCT 84   GRH
;	Fix bug in Jade driver which allowed errors to go undetected.
;
; 1.A -	18 APR 85   GRH
;	Fix logon problem. Code is only now showing bugs with 2nd hard
;	  disk installed.
;
; 1.B -	21 FEB 87   GRH
;	Add error return to IOPB.PBSTAT thus allowing user to only check
;	  this byte for errors rather than checking HSTATUS and then HDATA.
;
; 1.12 - 25 MAY 87   GRH
;	Change JADE code to allow interim communication with new JADE
;	 firmware.
;	Change version # to decimal number.
;
; 1.13 - 11 MAY 88   GRH
;	Remove hard disk format clearing of PBSECO. This effectively
;	 prevented formatting other than side 0.
;
; 2.00 - 24 MAY 88   GRH
;	Remove SASI floppy option. Fix bug in GETRES which failed to return
;	 error properly.
;	IOPB xfer only returns status bytes now. Return logon flag for
;	 CBIOS 3.xx.
;	Remove option to swap Jade & SASI drive #s.
;	Change LOGON & delete disk tables (hard disk only) & only return
;	 descriptor sector type.
;	Change version number return to IOPB function.
;
; 2.01	4 JUN 88   GRH
;	Add error recovery attempt by resetting controller & retrying.
;	Add additional timeouts to lessen the 'hang' conditions.
;	Correct Logon problems with sector & data xfer.
;	Make retrys more reasonable & change flags to disable retrys only.
;	Add IOPB track & sector limits checks.
;
; 2.02	7 JUN 88   GRH
;	Add conditional print for diagnostics, floppy & hard disk listing.
;	Recode the SASI protocol. Add ACK* sensing to hardware.
;
; 2.03	24 JUL 88   GRH
;	Lengthen controller reset wait time in CLRCONT. The old time proved
;	  inadequate for a different DTC 140x controller.
;	Change global definitions to add standard prefixes.
;
VERSN	EQU	203
;**************************************************************************
FALSE	EQU	0
TRUE	EQU	NOT FALSE
;
DEBUG	EQU	FALSE
;
LDIAG	EQU	FALSE		;TRUE TURNS ON DIAGNOSTICS CODE LISTING
LFLOPY	EQU	FALSE		;TRUE TURNS ON JADE FLOPPY CODE LISTING
LSASI	EQU	TRUE		;TRUE TURNS ON SASI CODE LISTING


;
;*INCLUDE JDDCONT.DEF
;*INCLUDE COMIOPB.DEF
;
	LIST	OFF
*INCLUDE JDDCONT.DEF
*INCLUDE COMIOPB.DEF
	LIST	ON

	SUBTTL	DEFINITIONS
;===========================================================================
;
;	I/O PORTS
;
;===========================================================================
S100D	EQU	0D8H		;DATA PORT VISIBLE TO S100 BUS
S100S	EQU	S100D + 1	;STATUS PORT VISIBLE TO S100 BUS
S100C	EQU	S100S		;COMMAND PORT VISIBLE TO S100 BUS
;
LOCPRTS	EQU	0		;BASE ADDRESS OF LOCAL PORTS
LOCMEM	EQU	0		;BASE ADDRESS OF LOCAL RAM
;
S1PRTS	EQU	80H		;BASE ADDRESS OF S100 PORTS


;===========================================================================
;
;	MEMORY AREAS
;
;===========================================================================
S1MEM	EQU	8000H		;BASE ADDRESS OF S100 MEMORY WINDOW
;
LOCROM	EQU	LOCMEM		;BASE ADDRESS OF LOCAL ROM
LOCRAM	EQU	LOCMEM + 4000H	;BASE ADDRESS OF LOCAL RAM
;
RAMSIZE	EQU	2048		;SIZE OF LOCAL RAM
ROMSIZE	EQU	2048		;SIZE OF LOCAL ROM


;===========================================================================
;
;	LOCAL PORT DEFINITIONS
;
;===========================================================================
;
;   SASI BUS DATA TRANSFER
;
SASIDATA EQU	LOCPRTS
;
;   SASI BUS CONTROL
;
SASICMD	EQU	LOCPRTS + 1
;
; 7 6 5 4 3 2 1 0
;       ^ ^ ^ ^ ^__ SASI INTERRUPT ON REQUEST ENABLE (1), HOST (0)
;       | | | |____ SASI RESET BIT (1)
;       | | |______ SASI DEVICE SELECT STROBE (1)
;       | |________ SASI PARITY ERROR CLEAR (0)
;       |__________ HOST VECTORED INTERRUPT (1)
;
;   BIT DEFINITIONS:
SINTE	EQU	0		;SASI INTERRUPT
SRESET	EQU	1		;SASI RESET
SSELECT	EQU	2		;SASI DEVICE SELECT STROBE
SERRCLR	EQU	3		;SASI PARITY ERROR CLEAR*
HINT	EQU	4		;HOST VECTORED INTERRUPT
;
;   SASI BUS STATUS
;
SASIST	EQU	LOCPRTS + 1
;
; 7 6 5 4 3 2 1 0
; ^   ^ ^ ^ ^ ^ ^__ BUSY (1)
; |   | | | | |____ MESSAGE (1)
; |   | | | |______ COMMAND (1) / DATA (0)
; |   | | |________ REQUEST* (0)
; |   | |__________ INPUT (0) / OUTPUT (1)
; |   |____________ ACKNOWLEGE (1)
; |________________ PARITY ERROR (1)
;
;   BIT DEFINITIONS:
SBUSY	EQU	0	;BUSY
SMSG	EQU	1	;MESSAGE
SCD	EQU	2	;C/D
SREQ	EQU	3	;REQUEST*
SIO	EQU	4	;I/O*
SACK	EQU	5	;ACK
SPERR	EQU	7	;PARITY ERROR DETECTED
;
;   MASKS:
SSTMSK	EQU	10111111B	;STATUS BIT MASK
SSTINV	EQU	(1 SHL SIO) + (1 SHL SREQ)	;STATUS BIT INVERSION MASK
SSXMSK	EQU	(1 SHL SIO) + (1 SHL SCD) + (1 SHL SMSG) ;XFER CONTROL MASK
;
;   CONTROL DATA:
SGTCMD	EQU	1 SHL SCD	;GET COMMAND FROM H/A
SGTDAT	EQU	0		;GET DATA FROM H/A
SSNDDAT	EQU	1 SHL SIO	;SEND DATA TO H/A
SSNDST	EQU	(1 SHL SIO) + (1 SHL SCD)	;SEND STATUS TO H/A
SCMDDN	EQU	(1 SHL SIO) + (1 SHL SCD) + (1 SHL SMSG)	;COMMAND DONE
;
;   HOST INTERRUPT CLEAR (W/O, DATA= DON'T CARE)
;
HINTC	EQU	LOCPRTS + 2
;
;   HOST INTERRUPT SET (W/O, DATA= DON'T CARE)
;
HINTS	EQU	LOCPRTS + 3
;
;   HOST STATUS
;
HSTAT	EQU	LOCPRTS + 4	;HOST STATUS PORT
;
; 7 6 5 4 3 2 1 0
; ^           ^ ^__ BOARD BUSY (1)
; |           |____ FIRMWARE ERROR (1)
; |________________ ERROR (1)
;
;   BIT DEFINITIONS:
HBUSY	EQU	0		;HOST BUSY STATUS BIT
HFERRB	EQU	1		;HOST FIRMWARE ERROR BIT
HSERRB	EQU	7		;HOST ERROR STATUS BIT
HFERR	EQU	(1 SHL HSERRB) + (1 SHL HFERRB)	;FIRMWARE ERROR BYTE
;
;   HOST COMMAND REGISTER
;
HCMD	EQU	LOCPRTS + 4
;
; 7 6 5 4 3 2 1 0
; ^ ^   \_____/ ^__ HOST INTERRUPT (1)
; | |      |_______ NON-IOPB COMMAND CODE (0..F)
; | |______________ EXECUTE IOPB (1)
; |________________ BOARD RESET (1)
;
;   BIT DEFINITIONS:
HINTRB	EQU	0		;HOST INTERRUPT REQUEST BIT
HIOPBB	EQU	6		;HOST EXECUTE IOPB BIT
HRESB	EQU	7		;HOST RESET LOCAL PROCESSOR BIT
;
;   HOST DATA XFER REGISTER
;
HDATA	EQU	LOCPRTS + 5
;
;   HOST BUS A15 CONTROL REGISTER FOR DMA
;
HXAD15	EQU	LOCPRTS + 6
;
; 7 6 5 4 3 2 1 0
; ^________________ BIT APPLIED TO HOST BUS A15 WHEN ACCESSING ITS MEMORY
;
;   BIT DEFINITIONS:
A15B	EQU	7		;HOST A15 BIT
;
;   HOST BUS EXTENDED ADDRESS REGISTER FOR DMA
;
HXADDR	EQU	LOCPRTS + 7
;
; 7 6 5 4 3 2 1 0
; ^ ^ ^ ^ ^ ^ ^ ^__ A16
; | | | | | | |____ A17
; | | | | | |______ A18
; | | | | |________ A19
; | | | |__________ A20
; | | |____________ A21
; | |______________ A22
; |________________ A23


;===========================================================================
;
;	FIRMWARE ERROR CODES
; RETURNED IN HOST DATA REGISTER IF HOST STATUS BIT 1 SET AND IN IOPB.PBSTATO
;  IF APPLICABLE.
;
;===========================================================================
TMOERR	EQU	?HNDSERR	;CONTROLLER HANDSHAKE TIMOUT


;===========================================================================
;
;	SASI HARD DISK DEFINITIONS
;
;===========================================================================
HDCONT	EQU	0		;THIS CONTROLLER'S ADDRESS BIT
HDBASD	EQU	0		;BASE DRIVE # OF HD CONTROLLER
HDNDRV	EQU	4		;NUMBER OF PHYSICAL DRIVES SUPPORTED
HDNLUN	EQU	HDNDRV
INLEV	EQU	6		;INTERLEAVE FACTOR FOR FORMAT


;===========================================================================
;
;			SASI COMMANDS
;
;===========================================================================
SCRDY	EQU	0	;TEST DRIVE READY COMMAND
SCREC	EQU	1	;RECALIBRATE
SCSNSE	EQU	3	;REQUEST SENSE
SCFMTD	EQU	4	;FORMAT ENTIRE DRIVE
SCFMTT	EQU	6	;FORMAT TRACK
SCFMTBT	EQU	7	;FORMAT BAD TRACK
SCREAD	EQU	8	;READ SECTOR(S)
SCWRIT	EQU	10	;WRITE SECTOR(S)
SCSEEK	EQU	11	;SEEK TRACK
;
SCCOPY	EQU	20H	;COPY BLOCK(S)
;
SCDEF	EQU	0C0H	;DEFINE FLOPPY DISK PARAMETERS


;===========================================================================
;
;			JADE DEFINITIONS
;
;===========================================================================
JADBASD	EQU	4		;BASE DRIVE # OF JADE CONTROLLER
JADNDRV	EQU	4		;NUMBER OF LOGICAL JADE CONTROLLER DRIVES

;DDPORT	EQU	?DDPORT8

DDBUF	EQU	0380H		;BUFFER OFFSET
IDFLGO	EQU	0031H		;ID SECTOR DISK FLAGS OFFSET
DFHARD	EQU	5		;HARD DISK FLAG BIT
DFDBL	EQU	6		;
DFT0D	EQU	0		;TRACK 0 DENSITY FLAG BIT

	SUBTTL	MACROS
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	BUFFER HALF SELECT MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
SELCTBUF MACRO
;
;   ASSUME 1ST HALF
;
	LD	HL,HDSECB
;
;   SELECT BUFFER HALF BASED ON SECTOR BIT 0
;
	LD	A,(PBSEC)	;IF SECTOR IS ODD THEN SELECT UPPER HALF
	AND	A,1
	JR	Z,BB#SYM
;
	LD	HL,HDSECB + 128
BB#SYM:
	ENDM


;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;;
;;	HOST OUTPUT MACRO
;;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
HSTOUT:	MACRO	#PORT, #DATA
;;
;;   SELECT INSTRUCTION BASED ON EFFICIENCY
;;
;
;   SET BIT 7 OF PORT
;
	IF	#PORT < 80H
	XOR	A,A
	ELSE
	LD	A,#PORT
	ENDIF
	OUT	(HXAD15),A
;
;   OUTPUT DATA
;
	IF	(#DATA = 0) AND (#PORT <> 0)
	XOR	A,A
	ENDIF
	IF	#DATA <> 0
	LD	A,#DATA		;OUTPUT DATA
	ENDIF
	OUT	(#PORT OR 80H),A
	ENDM


;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;;
;;	HOST INPUT MACRO
;;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
HSTIN:	MACRO	#PORT
;;
;;   SELECT PROPER INSTRUCTION BASED ON PORT BIT 7
;;
;
;  SELECT BIT 7 OF PORT
;
	IF	#PORT < 80H
	XOR	A,A
	ELSE
	LD	A,#PORT		;SET UP BIT 7
	ENDIF
	OUT	(HXAD15),A
;
;   INPUT DATA
;
	IN	A,(#PORT OR 80H)	;FETCH DATA
	ENDM

	SUBTTL	MAIN CODE
	ORG	LOCROM
;---------------------------------------------------------------------------
;
;	PROCESSOR REGISTER USAGE:
;	IY= PTR TO CURRENT COMMAND DESCRIPTOR BLOCK
;
;---------------------------------------------------------------------------
;
;   MAIN CODE FROM RESET
;
RESETV:
;
;   SET BUSY FLAG UNTIL WE'RE DONE
;
	OUT	(HINTS),A
;
;   PASS 0 TO HOST IN STATUS
;
	XOR	A,A
	OUT	(HSTAT),A
;
;   SET UP INTERRUPT
;
	IM	1
;
;   SET UP STACK
;
	LD	SP,STACK	;INIT STACK
;
;   DO RAM TEST 1ST
;
	LD	HL,LOCRAM
	LD	BC,RAMSIZE
;
MTLP:	LD	A,(HL)		;COMPLEMENT & TEST
	CPL
	LD	(HL),A
	CP	A,(HL)
	JR	NZ,MEMERR
;
	CPL			;RESTORE
	LD	(HL),A
;
	INC	HL		;NEXT LOCATION
	DEC	BC
	LD	A,B
	OR	A,C
	JR	NZ,MTLP
;
;   RAM OK. DO ANY OTHER INITIALIZATION
;
	CALL	INIT		;ANY OTHER INITIALIZATION
;
;   GO WAIT FOR HOST COMMAND
;
	JP	HWAITC
;
;
;	RAM ERROR ENCOUNTERED
;
MEMERR:
;
;   PASS ERROR TO HOST
;
	LD	A,?RAMERR	;PASS ERROR TO HOST & HALT
	OUT	(HDATA),A
;
;   SET ERROR FLAG TO HOST
;
	LD	A,HFERR
	OUT	(HSTAT),A
;
;   CLEAR PENDING INTERRUPT & GO TO SLEEP
;
	OUT	(HINTC),A
	HALT


	IF	$ > 38H
	CONMSG	**** ERROR! RESET CODE OVERLAPS INTERRUPT CODE! ****
	ENDIF
;---------------------------------------------------------------------------
;
;	INTERRUPT ENTRY VECTOR OCCURRS WHEN HOST INTERRUPTS OR IF SASI IS
;  IMPLEMENTED WITH INTERRUPT THEN MEANS SASI IS REQUESTING SOMETHING.
;
;---------------------------------------------------------------------------
	ORG	LOCROM + 38H
;
;   GET HOST COMMAND
;
	IN	A,(HCMD)
;
;   IF NOT HOST INTERRUPT THEN ASSUME SASI
;
	BIT	HINTRB,A
	JP	Z,SASINT
;
;   IF IOPB COMMAND THEN GO EXECUTE IT
;
	BIT	HIOPBB,A
	JP	NZ,EXIOPB
;
;   MUST BE DIRECT COMMAND FOR EXECUTION
;
	AND	A,00011110B	;MASK OFF UNUSED COMMANDS
;
	CP	A,NUMCMDS * 2	;IF COMMAND ERROR THEN RETURN FIRMWARE ERR
	JR	C,CMDOK
;
;   ILLEGAL DIRECT COMMAND. RETURN ERROR TO HOST
;
	LD	A,?CMDERR
	JR	CMDRET
;
;
;   COMMAND OK. PERFORM COMPUTED GOSUB TO EXECUTE IT
;
CMDOK:	LD	HL,CMDTBL	;POINT TO TABLE
	ADD	A,L		;COMPUTE ENTRY ADDRESS
	LD	L,A
	LD	A,0
	ADC	A,H
	LD	H,A
	LD	E,(HL)		;FETCH EXECUTION ADDRESS
	INC	HL
	LD	D,(HL)
	EX	DE,HL
	IN	A,(HDATA)	;PREFETCH ARGUMENT
;
	LD	DE,CMDRET	;PUT RETURN ADDRESS ON STACK
	PUSH	DE
	JP	(HL)
;
;
;
;	ALL COMMANDS RETURN HERE
;	ENTRY-	A= 0: NO ERROR
;		  /0: ERROR CODE
;
CMDRET:
;
;   IF ERROR THEN PASS IT TO HOST
;
	OR	A,A		;IF A= 0 THEN NO ERROR
	JR	Z,CMDR1
;
;   ELSE PASS ERROR CODE TO HOST
;
	OUT	(HDATA),A	;PUT ERROR IN DATA REG
;
	LD	A,HFERR		;SET ERROR FLAGS
;
CMDR1:	OUT	(HSTAT),A	;PASS ERROR TO HOST
;
;   SET UP FOR TERMINATION
;
	POP	HL		;WASTE RETURN ADDRESS TO WAIT RTN
;
HWAITC:
;
;   TELL HOST WE'RE DONE
;
	OUT	(HINTC),A
;
;   FALL INTO MAIN LOOP
;


;---------------------------------------------------------------------------
;
;	MAIN INTERRUPTED LOOP
;
;---------------------------------------------------------------------------
HWAIT:
;
;   SET UP TO DESELECT SASI IN ORDER TO DESELECT DRIVE ON SOME CONTROLLERS
;
	XOR	A,A
	OUT	(SASIDATA),A
	LD	A,[1 SHL SSELECT] OR [1 SHL SERRCLR]
;
;   DISALLOW INTERRUPTS WHILE THIS SEQUENCE IS IN PROCESS
;
	DI
;
	OUT	(SASICMD),A
	LD	A,[1 SHL SERRCLR]
	OUT	(SASICMD),A
;
;   ENABLE NEXT HOST INTERRUPT & WAIT FOR IT
;
	EI
	JR	$


;###########################################################################
;
;	COMMAND TABLE FOR NON-IOPB COMMANDS
;
;###########################################################################
CMDTBL:
	DW	IOPBLO		;(1) SET IOPB LO COMMAND
	DW	IOPBHI		;(3) SET IOPB HI COMMAND
	DW	IOPBX		;(5) SET IOPB XADDR COMMAND
	DW	DIAG0		;(7) DUMP LOCAL MEMORY DIAGNOSTIC CMD
	DW	DIAG1		;(9) SET OUTPUT PORTS DIAG. COMMAND
	DW	DIAG2		;(B) TEST S100 MEMORY ACCESS COMMAND
	DW	DIAG3		;(D) BLOCK MOVE 01000H TO 02000H COMMAND
	DW	PRINT		;(F) PRINT ASCII STRING TO PORT COMMAND
	DW	RETVERS		;(11) RETURN FIRMWARE VERSION
;
NUMCMDS	EQU	($ - CMDTBL) / 2	;NUMBER OF COMMANDS

	SUBTTL	COMMANDS
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	SET IOPB ADDRESS FUNCTION
; MUST BE INITIALIZED BEFORE DISK ACCESS
;	ENTRY-	A= DATA
;	EXIT -	A= 0
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;   SET LOW BYTE
;
IOPBLO:
	LD	HL,IOPBL	;POINT TO BYTE TO ALTER
	JR	IOPBST
;
;   SET HIGH BYTE
;
IOPBHI:
	LD	HL,IOPBH
	JR	IOPBST
;
;   SET EXTENDED ADDRESS BYTE
;
IOPBX:
	LD	HL,IOPBXA
;
;   COMMON SET CODE
;
IOPBST:	LD	C,(HL)		;SAVE OLD DATA
	LD	(HL),A		;SET NEW DATA
	LD	A,C		;PASS OLD DATA TO HOST
	OUT	(HDATA),A
;
;   RETURN NO ERRORS
;
	XOR	A		;RETURN NO ERRORS (PREVENTS DATA OVERWRITE)
	RET


   IF	LDIAG = FALSE
	LIST	OFF
   ENDIF
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	DIAGNOSTIC DUMP LOADS HOST MEMORY WITH RAM IMAGE
;	ENTRY-	A= BANK ADDRESS
;	EXIT -	XX4000H..XX47FFH= RAM IMAGE
;		XX4800H..XX4FFFH= ROM IMAGE
;		XX5000H..XX57FFH= JADE FDC IMAGE
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DIAG0:
;
;*** COMMENTED OUT FOR NOW ***
;
;	OUT	(HXADDR),A		;USE DATA FOR EXTENDED ADDRESS
;
;   SET UP FOR LOWER 32K
;
	XOR	A,A
	OUT	(HXADDR),A
	OUT	(HXAD15),A
;
;   DUMP LOCAL RAM TO S100 RAM AT 4000H
;
	LD	HL,LOCRAM
	LD	DE,S1MEM + 4000H
	LD	BC,RAMSIZE
	LDIR
;
;   DUMP LOCAL ROM TO S100 RAM AT 4800H
;
	LD	HL,LOCROM
	LD	BC,ROMSIZE
	LDIR
;
;   JUST FOR GRINS.. DUMP JADE CONTROLLER BANK 0 TO HOST RAM AT 5000H
;
	HSTOUT	?DDPORT8,?DDMB0		;FOLLOW WITH FDC BANK 0
	LD	HL,(FDADDR)
	LD	BC,1024
	PUSH	HL
	LD	A,H			;SET BUS BIT 15
	OUT	(HXAD15),A
	LDIR
;
;   NOW JADE BANK 1 AT 5400H
;
	HSTOUT	?DDPORT8,?DDMB1		;FOLLOW WITH FDC BANK 1
	POP	HL
	LD	A,H		;SET BUS BIT 15
	OUT	(HXAD15),A
	LD	BC,1024
	LDIR
;
	HSTOUT	?DDPORT8,?DDFREE	;REMOVE DD WINDOW SO HOST WON'T CRASH
;
;   PASS NO ERRORS TO HOST
;
	XOR	A,A		;NO ERRORS
	OUT	(HSTAT),A
;
;   DIRECT RETURN TO WAIT LOOP
;
DIAGR:	LD	SP,STACK	;FLUSH RETURN ADDR FROM STACK
	JP	HWAITC


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	DIAGNOSTIC 1 LOADS DATA INTO DATA OUT & STATUS REGS
;	ENTRY-	A= DATA
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DIAG1:
;
;   SET DATA & STATUS REGISTERS WITH HOST ARGUMENT
;
	OUT	(HDATA),A
	OUT	(HSTAT),A
;
;   DIRECT RETURN TO WAIT LOOP
;
	JP	DIAGR


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	DIAG2 TESTS S100 MEMORY READS & WRITES FROM XX1000H TO XX1FFFH
;	EXIT-	XX0FF2H= LAST LOCATION CHECKED
;		XX0FF4H= 0: OK
;			 READ DATA IF ERROR
;		XX0FF5H= CONTENTS OF LAST LOCATION
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DIAG2:
;
;   SET UP TO TEST HOST MEMORY
;
	LD	HL,S1MEM + 1000H
	LD	BC,ROMSIZE + RAMSIZE
;
;   DO TEST
;
D2LP:	LD	A,(HL)
	CPL
	LD	(HL),A
	CP	A,(HL)
	CPL			;RESTORE
	LD	(HL),A
	JR	NZ,D2ERR
;
;   TEST OK. DO NEXT
;
	INC	HL
;
;   CHECK FOR DONE
;
	DEC	BC
	LD	A,B
	OR	A,C
	JR	NZ,D2LP
;
;   PASS ERROR DATA TO HOST MEMORY
;
D2ERR:	LD	(S1MEM + 0FF2H),HL
	LD	(S1MEM + 0FF4H),A
	LD	A,(HL)
	LD	(S1MEM + 0FF5H),A
;
;   RETURN NO ERRORS
;
	XOR	A,A
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	DIAG3 DOES S100 MEMORY ACCESSES DEPENDING ON DATA
; NOTE:	SCOPING TESTS CONTINUE UNTIL ANOTHER DATA WORD IS
;	WRITTEN TO THE DATA REGISTER BY THE HOST.
;	ENTRY-	A= 0: BLOCK MOVE FROM 1000H TO 2000H
;		   1: READ FROM 1000H (SCOPING TEST)
;		   2: WRITE TO 1000H  (SCOPING TEST)
;		   3: BLOCK MOVE FROM E000H TO E800H
;		   ALL OTHERS: NOP
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DIAG3:
;
;   DO TESTS BASED ON HOST ARGUMENT
;
	OR	A,A
	JR	Z,DOMOVE
;
D3LP:	IN	A,(HDATA)		;IF DATA CHANGED THEN CHECK
	CP	A,2
	JR	C,DOREAD
	JR	Z,DOWRITE
	CP	A,3
	JR	Z,DOBLKH
;
;   IF UNKNOWN COMMAND THEN QUIT WITHOUT ERROR
;
	XOR	A,A
	RET
;
;
;   CONTINUOUS WRITES COMMAND
;
DOWRITE:
	LD	(S1MEM + 1000H),A	;USE ARGUMENT AS DATA
	JR	D3LP
;
;
;   CONTINUOUS READS COMMAND
;
DOREAD:
	LD	A,(S1MEM + 1000H)
	JR	D3LP
;
;
;   BLOCK MOVE COMMAND TO LOW MEMORY
;
DOMOVE:
	LD	HL,S1MEM + 1000H
	LD	DE,S1MEM + 2000H
	LD	BC,1000H
	LDIR
;
;   ONLY DO THIS ONE ONCE
;
	XOR	A,A
	RET
;
;
;   BLOCK MOVE TO HIGH MEMORY COMMAND
;
DOBLKH:	LD	A,1 SHL A15B		;SET HIGH PAGE
	OUT	(HXAD15),A
	LD	HL,0E000H
	LD	DE,0E800H
	LD	BC,800H
	LDIR
;
;   ONLY DO THIS ONE ONCE ALSO
;
	XOR	A,A
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	PRINT TEXT ON THE PRINTER COMMAND EXERCISES THE I/O CAPABILITY
;	ENTRY-	A= PORT #
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PRINT:
;
;   USE HOST ARGUMENT AS PORT #
;
	OUT	(HXAD15),A	;SET PORT TO DATA
	SET	7,A		;MAP TO HOST
	LD	C,A
;
	CALL	CRLF
;
	LD	E,'0'	;START WITH '0'
	LD	B,80	;DO 1 LINE
PRINT1:	CALL	PRT
;
;   NEXT CHAR
;
	INC	E
	DJNZ	PRINT1
;
;   END WITH A NEWLINE
;
CRLF:	LD	E,0DH
	CALL	PRT
	LD	E,0AH
	CALL	PRT
;
;   RETURN NO ERRORS
;
	XOR	A,A
	RET


;***************************************************************************
;
;	PRINT THE CHAR SUBROUTINE
;	ENTRY-	E= CHAR TO OUTPUT
;		C= PORT #
;
;***************************************************************************
PRT:	IN	A,(C)	;IF BUSY THEN WAIT
	AND	A,1
	JR	NZ,PRT
;
	LD	A,E	;OUTPUT THE CHAR
	SET	7,A
	OUT	(C),A
;
	RES	7,A
	OUT	(C),A
;
	SET	7,A
	OUT	(C),A
;
	RET
   IF	LDIAG = FALSE
	LIST	ON
   ENDIF


	SUBTTL	IOPB EXECUTION
;---------------------------------------------------------------------------
;
;			EXECUTE IOPB
;
;---------------------------------------------------------------------------
EXIOPB:
;
;   MOVE HOST'S IOPB TO LOCAL ARRAY
;
	LD	DE,PBCMD		;DESTINATION
	LD	HL,(IOPBL)		;GET HOST'S ADDRESS OF IOPB
	EX	DE,HL
;
	LD	A,(IOPBXA)		;  SET BANK #
;
	LD	BC,IOPBSIZE
	CALL	MOVFHST
;
;   SELECT SASI OR JADE BASED ON IOPB.PBDRV
;
	LD	A,(PBDRV)		;IF HARD DISK CONTROLLER THEN DO IT
	LD	HL,HDCMDS
;
	CP	A,HDBASD + HDNDRV
	JR	C,XTABL
;
;   CHECK IF JADE CONTROLLER
;
	LD	HL,JADCMDS
	SUB	A,JADBASD			;BIAS DOWN TOO
	JR	C,XILDRV		;IF NOT JADE THEN DOESN'T EXIST
;
	CP	A,JADNDRV
	JR	NC,XILDRV
;
	LD	(PBDRV),A		;IS JADE, OFFSET DRIVE #
;
;   COMMAND EXECUTION ADDRESS TABLE SELECTED
;
XTABL:
;
;   IF ILLEGAL COMMAND THEN RETURN ERROR TO HOST
;
	LD	A,(PBCMD)
	CP	A,(HL)		;COUNT IS 1ST TABLE BYTE
	JR	NC,XILCMD
;
;   VALID COMMAND. DO COMPUTED GOSUB TO COMMAND
;
	INC	HL		;SKIP COUNT
;
	ADD	A,A		;MULTIPLY CMD BY 2 FOR OFFSET
	LD	E,A
	LD	D,0
	ADD	HL,DE
;
	LD	E,(HL)		;GET COMMAND FROM TABLE
	INC	HL
	LD	D,(HL)
	EX	DE,HL
;
	LD	DE,XRET		;PUT RETURN ADDRESS ON STACK
	PUSH	DE
	JP	(HL)			;EXECUTE COMMAND
;
;
;	IOPB COMMANDS RETURN HERE.
; THIS RETURN MUST RETURN IOPB TO HOST FOR STATUS UPDATE
;	AF= ERROR STATUS
;
XRET:
	PUSH	AF		;SAVE POSSIBLE ERROR CODE
;
;   RETURN ERROR IN IOPB ALSO  (REV 1.B)
;
	LD	(PBSTAT),A
;
;   XFER LOCAL IOPB STATUS BYTES TO HOST'S IOPB
;
	LD	DE,PBSTAT - PBCMD	;CALCULATE USER OFFSET TO STATUS
	LD	HL,(IOPBL)		;ADD TO USER IOPB BASE
	ADD	HL,DE
	EX	DE,HL			;PUT IN DE

	LD	HL,PBSTAT		;SOURCE := LOCAL IOPB IMAGE
;
	LD	A,(IOPBXA)		;GET BANK #
	ADC	A,0			;ADD IN CARRY FROM CALCULATION ABOVE
;
	LD	BC,IOPBSIZE - (PBSTAT - PBCMD)	;ONLY RETURN STATUS BYTES
	CALL	MOV2HST
;
;   RETURN ERROR STATUS TO HOST
;
	POP	AF
	JP	CMDRET
;
;
;   ILLEGAL DRIVE REQUESTED
;
XILDRV:
	LD	A,?SELERR
	JP	XRET
;
;
;   ILLEGAL COMMAND REQUESTED
;
XILCMD:	LD	A,?CMDERR
	JP	XRET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RETURN FIRMWARE VERSION COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RETVERS:
	LD	HL,VERSN
	LD	(PBSTAT + 2),HL
;
;   RETURN NO ERRORS
;
	XOR	A
	RET


;###########################################################################
;
;		IOPB COMMAND EXECUTION TABLES
;
;###########################################################################
;
;   JADE FLOPPY CONTROLLER COMMANDS
;
JADCMDS:
	DB	MXJCMDS
	DW	JADLOG		;LOG ON DISK
	DW	JADREAD		;READ SECTOR
	DW	JADWRT		;WRITE SECTOR
	DW	JADFORM		;FORMAT TRACK
	DW	JADRDAD		;READ ADDRESS
	DW	JADEXEC		;EIA OUTPUT
	DW	JADEXEC		;EIA STATUS
	DW	JADEXEC		;IDLE
	DW	JADEXEC		;RET VERS
	DW	JADWRT		;SET FLAGS
	DW	JADEXEC		;LOAD HEAD
	DW	JADEXEC		;SEEK
	DW	JADWRT		;SET DRV PARAMS
	DW	JADEXEC		;RET DRV STATUS
	DW	JADEXEC		;SET BAUD
	DW	JADEXEC		;CLEAR
;
MXJCMDS	EQU	($ - JADCMDS-1) / 2

HDCMDS:
	DB	MXHCMDS
	DW	HDLOG		;LOG ON DISK (SELECT DISK)
	DW	HDREAD		;READ DEBLOCKED SECTOR
	DW	HDWRT		;WRITE DEBLOCKED SECTOR
	DW	HDFORM		;FORMAT TRACK
	DW	HDRECAL		;RECAL
	DW	HDCERR
	DW	HDCERR
	DW	HDCERR
	DW	RETVERS		;RETURN VERSION
	DW	HDCERR
	DW	HDCERR
	DW	HDSEEK		;SEEK TRACK (NORMALLY IMPLIED)
	DW	HDCERR
	DW	HDCERR
	DW	HDCERR
	DW	HDCERR
;
MXHCMDS	EQU	($ - HDCMDS -1) / 2

   IF	LFLOPY = FALSE
	LIST	OFF
   ENDIF
	SUBTTL	JADE IOPB COMMANDS
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;		LOGON COMMAND IS SAME AS READ
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
JADLOG:
;
;   FALL INTO READ COMMAND
;


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			READ SECTOR COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
JADREAD:
;
;   SWITCH JADE FDC INTO HOST MEMORY
;
	HSTOUT	?DDPORT8,?DDMB0
;
;   EXECUTE COMMAND
;
	CALL	FDSKEX
;
;   XFER DATA TO LOCAL BUFFER
;
	PUSH	AF		;SAVE ERROR STATUS
;
	HSTOUT	?DDPORT8,?DDMB1	;GET BANK 1 FOR SECTOR BUFFER
	LD	HL,(FDADDR)	;GET FDC ADDRESS
	LD	DE,JADSECB
	EX	DE,HL
	LD	BC,128		;FETCH SECTOR DATA
	XOR	A,A
	CALL	MOVFHST
;
;   REMOVE JADE FDC WINDOW
;
	HSTOUT	?DDPORT8,?DDFREE
;
;   XFER LOCAL BUFFER DATA TO HOST
;
	LD	HL,JADSECB
	CALL	HDHSTW
;
;   RETURN JADE ERROR STATUS TO HOST
;
	POP	AF
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			WRITE SECTOR COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
JADWRT:
;
;   XFER HOST DATA TO LOCAL BUFFER
;
	LD	HL,JADSECB
	CALL	HDHSTR
;
;   OPEN JADE FDC WINDOW
;
	HSTOUT	?DDPORT8,?DDMB1
;
;   XFER LOCAL BUFFER DATA TO JADE FDC BUFFER
;
	LD	HL,(FDADDR)
	EX	DE,HL
	LD	HL,JADSECB
	LD	BC,128
	XOR	A,A
	CALL	MOV2HST
;
;   EXECUTE THE WRITE COMMAND
;
	CALL	FDSKEX
;
;   REMOVE JADE FDC WINDOW
;
	PUSH	AF		;SAVE ERROR STATUS
	HSTOUT	?DDPORT8,?DDFREE	;REMOVE WINDOW
;
;   RETURN ERROR STATUS
;
	POP	AF
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			FORMAT COMMAND
;	(NOT IMPLEMENTED)
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
JADFORM:


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			READ ADDRESS COMMAND
;	(NOT IMPLEMENTED)
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
JADRDAD:


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			IDLE COMMAND
;	(NOT IMPLEMENTED)
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
JADEXEC:
;
;   RETURN ILLEGAL COMMAND ERROR
;
	LD	A,?CMDERR
	RET

	SUBTTL	JADE FDC SUBR
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;		EXECUTE THE COMMAND BLOCK FUNC.
;	EXIT -	NZ= ERROR, A= ERROR CODE
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
FDSKEX:
;
;   FORMAT DATA
;
	LD	A,(PBSEC)
	INC	A		;CHANGE FROM LOGICAL ADDR TO SECTOR #
	LD	(PBSEC),A
;
;   OUTPUT IOPB TO THE CONTROLLER
;
	HSTOUT	?DDPORT8,?DDMB0		;GET BANK 0
;
	LD	DE,?DDCBO		;CALCULATE FDC ADDRESS
	LD	HL,(FDADDR)
	ADD	HL,DE
	EX	DE,HL
	LD	HL,PBCMD
	LD	BC,PBSTAT - PBCMD
	XOR	A,A
	CALL	MOV2HST
;
;   HAVE JADE FDC EXECUTE THE COMMAND
;
	HSTOUT	?DDPORT8,?DDEXC		;ISSUE COMMAND
;
FDSKWT:	HSTIN	?DDPORT8		;WAIT UNTIL DONE
	AND	A,?DDSHLT
	JR	NZ,FDSKWT
;
;   MOVE STATUS BYTES TO LOCAL IOPB
;
	HSTOUT	?DDPORT8,?DDMB0		;GET WINDOW
	LD	BC,[PBCMD + IOPBSIZE] - PBSTAT
;
	XOR	A,A
	CALL	MOVFHST
;
;   PASS ERROR STATUS TO HOST
;
	LD	A,(PBSTAT)		;IF NO ERROR THEN RETURN 0, NC
	OR	A,A
	RET
   IF	LFLOPY = FALSE
	LIST	ON
   ENDIF

   IF	LSASI = FALSE
	LIST	OFF
   ENDIF
	SUBTTL	HARD DISK IOPB COMMANDS
;---------------------------------------------------------------------------
;
;	INTERRUPT WITHOUT HOST BIT SET
;
;---------------------------------------------------------------------------
SASINT:
;
;   THIS INTERRUPT NOT IMPLEMENTED. RETURN ERROR TO HOST
;
	LD	A,?INTERR
	JP	CMDRET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			UNSUPPORTED COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDCERR:
;
;   RETURN ILLEGAL COMMAND ERROR
;
	LD	A,?CMDERR
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;		DRIVE SELECT/LOG-ON COMMAND
; CHECK DRIVE READY
;	EXIT -	A= 0: OK, /0: ERROR CODE
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDLOG:
;
;   SELECT DRIVE
;
	CALL	HDSELCT
	RET	NZ
;
;   READ THE DISK DESCRIPTOR SECTOR
;
	LD	IY,IDRCDB
;
	LD	A,(LUNSV)	;LUN STILL THERE FROM SELECT
	LD	(IY + LUN),A
;
	CALL	GETLAD		;GET WHERE THE ID SECTOR IS LOCATED
	RET	NZ
;
	CALL	HDRDBUF
	RET	NZ
;
;   VERIFY THE SECTOR AS A LEGAL DESCRIPTOR SECTOR
;
	SELCTBUF		;SELECT BUFFER HALF
	PUSH	HL		;SAVE BUFFER PTR FOR RETRY OR XFER
;
	LD	DE,16		;ADD OFFSET TO DESCRIPTOR TEXT
	ADD	HL,DE
;
	LD	DE,IDTXT	;POINT TO TEXT CONSTANT
	LD	B,IDSZE		;SIZE OF COMPARE
;
HDCKID:	LD	A,(DE)		;IF NO MATCH THEN EXIT
	CP	A,(HL)
	JR	NZ,HDNTID
;
	INC	HL		;ELSE NEXT CHAR
	INC	DE
	DJNZ	HDCKID
;
;   ID CHECKS, SET FLAG
;
	LD	A,-2		;NEW DESCRIPTOR SECTOR FLAG
XFRID:	LD	(PBSTAT + 2),A
;
;   XFER ID SECTOR TO HOST BUFFER
;
	POP	HL		;RESTORE PTR TO BUFFER HALF
	CALL	HDHSTW
;
	CALL	CLRBUFR		;FLUSH BUFFER OF IOPB SECTOR (DON'T CARE)
;
;   DONE, RETURN NO ERRORS TO HOST
;
	XOR	A,A
	RET
;
;
;   NOT ID SECTOR, CHECK FOR OLD FORMAT ID SECTOR
;
HDNTID:
	POP	HL		;RESTORE BUFFER PTR
	PUSH	HL
;
	LD	DE,JIDTXT	;USE JADE ID CONSTANT
	LD	B,JIDSZE	;JADE ID SIZE
;
HDCKJID:
	LD	A,(DE)		;IF NO MATCH THEN RETURN
	CP	A,(HL)
	JR	NZ,HDLOG1
;
	INC	HL
	INC	DE
	DJNZ	HDCKJID
;
;   IS JADE FORMAT, RETURN ITS FLAG
;
	LD	A,-1
	JR	XFRID
;
;
;   NO ID SECTOR, RETURN SO
;
HDLOG1:	XOR	A,A		;PASS NOT ID SECTOR FLAG
	JR	XFRID		;XFER DATA ANYWAY


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;		READ DEBLOCKED SECTOR COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDREAD:
;
;   SELECT DRIVE
;
	CALL	HDSELCT
	RET	NZ
;
;   SET UP FOR READ
;
	LD	IY,LAXCDB	;USE XFER CDB
;
	LD	A,(LUNSV)	;STILL HAS SELECTED LUN
	LD	(IY + LUN),A
;
	CALL	GETLAD
	RET	NZ
;
;   READ SECTOR INTO LOCAL BUFFER
;
	CALL	HDRDBUF
	RET	NZ
;
;   DEBLOCK DATA BUFFER
;
	SELCTBUF
;
;   XFER DATA TO HOST
;
	CALL	HDHSTW		;WRITE TO HOST
;
;   SUCCESSFUL READ. RETURN NO ERRORS
;
	XOR	A,A		;NO ERRORS
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			WRITE SECTOR COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDWRT:
;
;   SELECT DRIVE
;
	CALL	HDSELCT		;IMPLIED SELECT
	RET	NZ
;
;   SET UP DATA TO PRE-READ SECTOR
;
	LD	IY,LAXCDB	;USE XFER CDB
;
	LD	A,(LUNSV)	;STILL HAS SELECTED LUN
	LD	(IY + LUN),A
;
	CALL	GETLAD
	RET	NZ
;
;   PRE-READ SECTOR
;
	CALL	HDRDBUF		;REFRESH BUFFER WITH SECTOR DATA
	RET	NZ
;
;   BLOCK SECTOR
;
	SELCTBUF
;
;   XFER HOST DATA TO LOCAL BUFFER
;
	CALL	HDHSTR		;READ HOST BUFFER
;
;   WRITE SECTOR & RETURN STATUS TO HOST
;
	JP	HDWRBUF		;WRITE TO DISK


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			FORMAT TRACK COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDFORM:
;
;   SELECT DRIVE
;
	CALL	HDSELCT
	RET	NZ
;
;   SET UP FOR FORMAT
;
	LD	IY,LAXCDB
	LD	(IY + CMD),SCFMTT
;
;   FETCH INTERLEAVE FACTOR FROM SECTOR DATA
;
	LD	A,(PBSEC)	;SECTOR BYTE HAS INTERLEAVE FACTOR
	LD	C,A
	AND	A,00001111B	;MASK OFF HEAD BITS
	LD	(IY + ILV),A
;
;   MASK OFF INTERLEAVE BUT LEAVE HEAD DATA IN SECTOR
;
	LD	A,C
	AND	A,11000000B
	LD	(PBSEC),A
;
;   SET UP CDB
;
	LD	A,(LUNSV)	;STILL HAS SELECTED LUN
	LD	(IY + LUN),A
;
	CALL	GETLAD		;GET LOGICAL ADDRESS
	JR	NZ,FRILV
;
;   IF NO ERROR THEN SEND THE FORMAT COMMAND TO THE SASI CONTROLLER
;
	CALL	SNDCDB
;
;   RETURN RESULT STATUS TO HOST
;
	CALL	Z,GETRES		;FINISH UP

;
;   RESTORE CDB INTERLEAVE BYTE
;
FRILV:	LD	(IY+ILV),0	;RESTORE ILV BYTE TO 0
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			RECAL COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDRECAL:
;
;   SELECT DRIVE
;
	CALL	HDSELCT
	RET	NZ
;
;   CONTINUE WITH RECAL FUNCTION
;
	JP	RECALC


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;			SEEK COMMAND
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDSEEK:
;
;   SELECT DRIVE
;
	CALL	HDSELCT
	RET	NZ
;
;   SET UP CDB DATA
;
	LD	IY,LAXCDB	;USE XFER CDB
	LD	(IY + CMD),SCSEEK	;SEEK COMMAND
;
	LD	A,(LUNSV)	;STILL HAS SELECTED LUN
	LD	(IY + LUN),A
;
	CALL	GETLAD		;GET USER'S BLOCK
	RET	NZ
;
;   SEND THE COMMAND TO THE SASI CONTROLLER
;
	CALL	SNDCDB
	RET	NZ
;
;   RETURN THE COMMAND STATUS TO HOST
;
	JP	GETRES
	LIST	ON


	SUBTTL	HARD DISK SUBROUTINES
;***************************************************************************
;
;	ADDITIONAL INITIALIZATION CODE
;
;***************************************************************************
INIT:
;
;   SET CURRENT DRIVE TO NONE
;
	LD	HL,CURDRV
	LD	(HL),-1
;
;   INIT CDB DATA
;
	LD	HL,NULCDB	;ZERO CDBS
	LD	B,CDBINIT
INITRAM:
	LD	(HL),0
	INC	HL
	DJNZ	INITRAM
;
;   RESET SASI CONTROLLER
;
	CALL	CLRCONT
;
;   FLUSH SECTOR BUFFER
;
	CALL	CLRBUFR		;START WITH FRESH BUFFER READ
;
;   INITIALIZE JADE FDC ADDRESS PTR
;
	HSTIN	?DDPORT8		;FETCH FDC ADDRESS
	AND	A,?DDSASW
	RLCA
	OR	A,HIGH ?DDBASE
	LD	H,A
	LD	L,0
	LD	(FDADDR),HL
;
;   DONE. RETURN TO MAIN CODE
;
	RET


;***************************************************************************
;
;	RESET SASI CONTROLLER PROCEDURE
;	EXIT -	A= 0
;
;****************************************************************************
CLRCONT:
;
;   ASSERT RESET
;
	LD	A,1 SHL SRESET
	OUT	(SASICMD),A
;
;   DELAY A WHILE FOR CONTROLLER TO SENSE IT
;
	EX	(SP),HL
	EX	(SP),HL
;
;   RELEASE RESET
;
	LD	A,1 SHL SERRCLR	;RELEASE RESET
	OUT	(SASICMD),A
;
;   WAIT FOR CONTROLLER TO DO IT'S THING
;
	PUSH	HL		;SAVE REGS
	PUSH	BC
;
	LD	HL,0		;SET DELAY TIME
	LD	B,3		;STRETCH TIME DELAY FOR SLOW TARGETS
;
CLRCON1:
	DEC	HL		;DECRIMENT COUNT UNTIL EXHAUSTED
	LD	A,L
	OR	A,H
	JR	NZ,CLRCON1
;
	DJNZ	CLRCON1		;IF EXTENDED DELAY NOT EXHAUSTED THEN REPEAT
;
;   DONE, RESTORE REGS & RETURN
;
	POP	BC
	POP	HL
;
;   DONE
;
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	SELECT DRIVE FUNCTION
;	EXIT -	NZ= ERROR, A= CODE
;		BC,HL= ?
;		IY= NULCDB
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDSELCT:
;
;   IF SAME DRIVE AS LAST OPERATION THEN JUST RETURN NO ERRORS
;
	LD	A,(PBDRV)
	AND	A,00000011B
	LD	C,A		;SAVE DRIVE
	LD	HL,CURDRV
	SUB	A,(HL)
	RET	Z
;
;   FIRST SAVE DRIVE FOR GETLUN
;
	LD	(HL),C
;
;   SEE IF REQUESTED DRIVE IS READY
;
	LD	IY,NULCDB	;USE NUL CDB
	LD	(IY+CMD),SCRDY	;TEST READY COMMAND
;
	CALL	GETLUN		;REQUEST LUN FROM USER
	CALL	SNDCDB		;EXECUTE CDB
	JR	NZ,HDSERR
;
	CALL	GETRES		;GET RESULT BYTE
	RET	Z
;
;   SELECT ERROR, RESET CONTROLLER & TRY AGAIN
;
HDSERR:	CALL	CLRCONT
	CALL	SNDCDB
;
	CALL	Z,GETRES
	RET	Z
;
;   SELECT ERROR EXIT
;
	LD	HL,CURDRV	;CURRENT DRIVE = NONEXISTENT
	LD	(HL),-1
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	READ HD SECTOR INTO BUFFER FUCTION
;	ENTRY-	IY= CDB PTR
;		CDB= SET UP
;	EXIT -	NZ= ERROR, A= CODE
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDRDBUF:
;
;   IF BUFFER DATA VALID THEN RETURN
;
	CALL	QBUFR
	RET	Z
;
;   SET UP RETRY COUNT
;
	LD	A,4		;ASSUME 12 RETRYS (THIS # X 3 IN CONTROLLER)
	LD	(RETRYS),A
;
	LD	(IY + RTY),0	;TURN ON CONTROLLER RETRYS
;
;   IF RETRYS DISABLED THEN RETRY COUNT = 0
; 
	LD	A,(PBFLG)
	BIT	PBRTRY,A
	JP	Z,HDRBRTY
;
	XOR	A,A		;COUNT = 0
	LD	(RETRYS),A
;
	LD	(IY + RTY),80H	;DISABLE CONTROLLER RETRYS
;
;   TOP OF READ SECTOR DATA LOOP
;
HDRBRTY:
;
;   ISSUE COMMAND BLOCK TO CONTROLLER
;
	LD	(IY+CMD),SCREAD	;READ COMMAND
	LD	(IY+NBK),1	;ALLWAYS USE 1 BLOCK (SECTOR)
;
	CALL	SNDCDB
	JR	NZ,HDRBERR
;
;   SET UP FOR DATA XFER FROM CONTROLLER
;
	LD	BC,[HDBUFSZ * 256] + SASIDATA	;SET PORT
	LD	HL,HDSECB
;
;   TOP OF READ DATA LOOP
;
HDRBLP:
;
;   WAIT FOR REQUEST
;
	CALL	WAITRQ		;IF NOT READY THEN WAIT
	JR	C,HDRBERR	;IF TIMEOUT THEN PROCESS
;
;   IF C/D ASSERTED THEN XFER DONE
;
	BIT	SCD,A
	JR	NZ,HDRBGET
;
;   XFER DATA
;
	INI
;
;   IF BUFFER NOT FULL THEN REPEAT FOR NEXT BYTE
;
	JP	NZ,HDRBLP
;
;   ELSE WASTE BYTES UNTIL COMMAND REQUESTED
;
HDRBWST:
	CALL	WAITRQ
	JR	C,HDRBERR
;
;   IF C/D ASSERTED THEN EXIT WITH ERROR
;
	BIT	SCD,A
	JR	NZ,HDRBGER
;
;   ELSE WASTE DATA
;
	IN	A,(C)
	INC	HL		;BUMP PTR TO FORCE OVERFLOW ERROR
	JP	HDRBWST
;
;
;   NORMAL FINISH
;
HDRBGET:
	CALL	GETRES
	CALL	Z,MAKSAME
	RET	Z
;
;   ERROR, IF TIMEOUT THEN RESET CONTROLLER & RETRY
;
HDRBERR:
	CP	A,TMOERR
	JP	NZ,HDRBCKR
;
	CALL	CLRCONT
	PUSH	IY
	CALL	RECALC
	POP	IY
;
;   CHECK RETRY COUNT
;
HDRBCKR:
	PUSH	AF
	LD	A,(RETRYS)
	SUB	A,1
	LD	(RETRYS),A
	JR	C,HDRBRE
;
;   RETRY
;
	POP	AF
	JP	HDRBRTY
;
;
;   HARD ERROR, CLEAR CONTAMINATED BUFFER
;
HDRBRE:
	CALL	CLRBUFR
;
	POP	AF
	RET
;
;
;   POSSIBLE OVERFLOW ERROR
;
HDRBGER:
;
;   IF NO OVERFLOW THEN USE NORMAL RETURN
;
	LD	DE,-[HDSECB + HDBUFSZ]	;TEST PTR FOR 1 PAST BUFFER END
	ADC	HL,DE		;MUST USE ADC FOR ZF! WAITRQ CLEARS CF.
	JP	Z,HDRBGET
;
;   ELSE PROCESS AS ERROR
;
	CALL	GETRES
	JR	NZ,HDRBERR
;
;   IF NO CONTROLLER ERROR THEN RETURN SYNC ERROR
;
	LD	A,1		;SUB-ERROR 1, READ OVERFLOW
	LD	C,-1		;NO STATUS
	CALL	SYNERR		;SET THE IOPB & RETURN
	JR	HDRBERR		;CHECK RETRYS



;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	WRITE HD SECTOR FROM BUFFER FUNCTION
;	ENTRY-	IY= CDB PTR
;		CDB= SET UP
;	EXIT -	NZ= ERROR, A= CODE
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HDWRBUF:
;
;   SET UP RETRY COUNT
;
	LD	A,4		;ASSUME 12 RETRYS (THIS # X 3 IN CONTROLLER)
	LD	(RETRYS),A
;
	LD	(IY + RTY),0	;TURN ON CONTROLLER RETRYS
;
;   IF RETRYS DISABLED THEN RETRY COUNT = 0
; 
	LD	A,(PBFLG)
	BIT	PBRTRY,A
	JP	Z,HDWBRTY
;
	XOR	A,A		;COUNT = 0
	LD	(RETRYS),A
;
	LD	(IY + RTY),80H	;DISABLE CONTROLLER RETRYS
;
;   TOP OF WRITE SECTOR DATA LOOP
;
HDWBRTY:
;
;   ISSUE COMMAND BLOCK TO CONTROLLER
;
	LD	(IY+CMD),SCWRIT	;WRITE COMMAND
	LD	(IY+NBK),1	;ALLWAYS USE 1 BLOCK (SECTOR)
;
	CALL	SNDCDB
	JR	NZ,HDWBERR
;
;   SET UP FOR DATA XFER FROM CONTROLLER
;
	LD	BC,[HDBUFSZ * 256] + SASIDATA	;SET PORT
	LD	HL,HDSECB
;
;   TOP OF WRITE DATA LOOP
;
HDWBLP:
;
;   WAIT FOR REQUEST
;
	CALL	WAITRQ		;IF NOT READY THEN WAIT
	JR	C,HDWBERR	;IF TIMEOUT THEN PROCESS
;
;   IF C/D ASSERTED THEN XFER DONE
;
	BIT	SCD,A
	JR	NZ,HDWBGET
;
;   XFER DATA
;
	OUTI
;
;   IF BUFFER NOT FULL THEN REPEAT FOR NEXT BYTE
;
	JP	NZ,HDWBLP
;
;   ELSE WASTE BYTES UNTIL COMMAND REQUESTED
;
HDWBWST:
	CALL	WAITRQ
	JR	C,HDWBERR
;
;   IF C/D ASSERTED THEN EXIT WITH ERROR
;
	BIT	SCD,A
	JR	NZ,HDWBGER
;
;   ELSE WASTE DATA
;
	LD	A,0E5H
	OUT	(C),A
	INC	HL		;FORCE OVERFLOW ERROR
	JP	HDWBWST
;
;
;   NORMAL FINISH
;
HDWBGET:
	CALL	GETRES
	RET	Z
;
;   ERROR, IF TIMEOUT THEN RESET CONTROLLER & RETRY
;
HDWBERR:
	CP	A,TMOERR
	JP	NZ,HDWBCKR
;
	CALL	CLRCONT
	PUSH	IY
	CALL	RECALC
	POP	IY
;
;   CHECK RETRY COUNT
;
HDWBCKR:
	PUSH	AF
	LD	A,(RETRYS)
	SUB	A,1
	LD	(RETRYS),A
	JR	C,HDWBRE
;
;   RETRY
;
	POP	AF
	JP	HDWBRTY
;
;
;   HARD ERROR
;
HDWBRE:
	POP	AF
	RET
;
;
;   POSSIBLE OVERFLOW ERROR
;
HDWBGER:
;
;   IF NO OVERFLOW THEN USE NORMAL RETURN
;
	LD	DE,-[HDSECB + HDBUFSZ]	;TEST PTR FOR 1 PAST BUFFER END
	ADC	HL,DE
	JP	Z,HDWBGET
;
;   ELSE PROCESS AS ERROR
;
	CALL	GETRES
	JR	NZ,HDWBERR
;
;   IF NO CONTROLLER ERROR THEN RETURN SYNC ERROR
;
	LD	A,2		;SUB-ERROR 2, WRITE OVERFLOW
	LD	C,-1		;NO STATUS
	CALL	SYNERR
	JR	HDWBERR


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	QUERY BUFFER THE SAME FUNCTION
;	EXIT -	ZF= SAME
;		NZ= NOT SAME
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
QBUFR:
;
;   IF DRIVE NOT SAME THEN RETURN NZ
;
	LD	A,(PBDRV)
	LD	HL,BUFDRV
	CP	A,(HL)
	RET	NZ
;
;   IF SECTOR NOT SAME THEN RETURN NZ
;
	LD	DE,(PBSEC)	;NOW CHECK SECTOR
	RES	0,E		;CLEAR BLOCKING BIT
;
	LD	HL,(BUFSEC)
	SBC	HL,DE
	RET	NZ
;
;   IF TRACK NOT SAME THEN RETURN NZ
;
	LD	DE,(PBTRK)	;LAST, CHECK TRACK
	LD	HL,(BUFTRK)
	SBC	HL,DE
	RET


;***************************************************************************
;
;	CLEAR BUFFER SUBR
;	EXIT -	AF= NZ
;
;***************************************************************************
CLRBUFR:
;
;   JUST SET DRIVE TO NON-EXISTENT # SO FAILS COMPARE
;
	LD	A,-2
	LD	(BUFDRV),A
	OR	A,A
	RET


;***************************************************************************
;
;	MAKE BUFFER PTRS = PB PTRS
;	EXIT -	AF= UNCHANGED
;		HL= ?
;
;***************************************************************************
MAKSAME:
	LD	A,(PBDRV)	;BUFFER_DRIVE = CURRENT_DRIVE
	LD	(BUFDRV),A
;
	LD	HL,(PBTRK)	;BUFFER_TRACK = CURRENT_TRACK
	LD	(BUFTRK),HL
;
	LD	HL,(PBSEC)	;BUFFER_SECTOR = CURRENT_SECTOR & FEH
	RES	0,L
	LD	(BUFSEC),HL
;
;   DONE
;
	RET


;***************************************************************************
;
;	READ DATA FROM HOST IOPB SUBR
;	ENTRY-	HL= DESTINATION PTR
;
;***************************************************************************
HDHSTR:
;
;   SET UP FOR XFER
;
	LD	DE,(PBDMA)	;GET DESTINATION PTR
	LD	A,(PBDMAX)	;SET BANK REGISTER
	LD	BC,128		;MOVE 128 BYTES
;
;   FALL INTO MOVE ROUTINE
;


;***************************************************************************
;
;	BLOCK MOVE FROM HOST SUBR
;	ENTRY-	HL= LOCAL PTR (DST)
;		DE= HOST PTR (SRC)
;		BC= BYTE COUNT
;		A= BANK ADDRESS (SRC)
;
;***************************************************************************
MOVFHST:
;
;   SET UP EXTENDED ADDRESS REGISTER
;
	LD	(MOVX),A	;SAVE EXTENDED ADDRESS FOR BUMPING
	OUT	(HXADDR),A
;
;   FALL INTO MOVER
;


;***************************************************************************
;
;	MOVE SUBR CHECKS FOR A MOVE CROSSING ANY 32K BOUNDARY AND SELECTING
; A FAST BLOCK MOVE IF NOT, AND A SLOWER BLOCK MOVE WHICH CHECKS AFTER EACH
; BYTE FOR AN OVERFLOW CONDITION IF TRUE.
;	ENTRY-	HL= LOCAL MEMORY (DESTINATION) PTR
;		DE= S100 MEMORY (SOURCE) PTR
;		BC= BYTE COUNT TO TRANSFER
;
;	EXIT -	AF= ?
;		BC= 0
;		HL= HL + BC
;		DE= DE + BC
;
;***************************************************************************
;
;   SET BIT 15 REGISTER TO S100 PTR BIT 15
;
	LD	A,D		;SET BIT 15
	OUT	(HXAD15),A
;
;   IF > 32K MOVE THEN DO LONG WAY
;
	DEC	BC
	LD	A,B
	CP	A,32768 / 256
	JR	NC,DOLONGF
;
;   IF GOING TO CROSS 64K BOUNDARY THEN DO LONG WAY
;
	LD	A,E		;ADD COUNT TO PTR
	ADD	A,C
	LD	A,D
	ADC	A,B
	JR	C,DOLONGF	;IF OVERFLOW THEN WILL WRAP-AROUND
;
;   IF GOING TO CROSS 32K BOUNDARY THEN DO LONG WAY
;
	XOR	A,D		;IF 32K CROSS THEN DO LONG WAY
	JP	M,DOLONGF
;
;   NO BOUNDARY CROSSING. USE BLOCK MOVE INSTRUCTION
;
	INC	BC		;RESTORE COUNT
	SET	7,D		;INSURE S100 MAP
	EX	DE,HL		;  SWAP
	LDIR
	EX	DE,HL		;  SWAP BACK
;
;   MOVE DONE
;
	RET
;
;
;   LONG TRANSFER TESTS EACH BYTE FOR THRESHOLDS
;
DOLONGF:
	INC	BC		;RESTORE COUNT
	LD	A,D		;SET UP CURRENT BIT 15
	LD	I,A		;SAVE IN I SINCE NOT USING MODE 2 INTERRUPTS
;
;   INSURE S100 ACCESS FOR SOURCE
;
NO64KXF:
	SET	7,D
;
;   MOVE 1 BYTE
;
MOV4F:
	EX	DE,HL		;   SWAP PTRS
	LDI			;SINGLE BYTE MOVE
	EX	DE,HL		;SWAP BACK
;
;   IF COUNT EXHAUSTED THEN DONE
;
	RET	PO
;
;   IF NO ROLLOVER THEN REPEAT
;
	BIT	7,D
	JP	NZ,MOV4F
;
;   S100 PTR ROLLED OVER 32K BOUNDARY, TOGGLE BIT 15
;
	LD	A,I
	XOR	A,80H
	LD	I,A
	OUT	(HXAD15),A
;
;   IF BIT 15 TOGGLED TO 0 THEN 64K ROLLOVER, NEXT BANK
;
	BIT	7,A
	JP	NZ,NO64KXF
;
	LD	A,(MOVX)
	INC	A
	LD	(MOVX),A
	OUT	(HXADDR),A
;
;   XFER ANOTHER BYTE
;
	JP	NO64KXF


;***************************************************************************
;
;	WRITE DATA TO HOST IOPB SUBR
;	ENTRY-	HL= SOURCE PTR
;
;***************************************************************************
HDHSTW:
;
;   SET UP DATA
;
	LD	DE,(PBDMA)	;GET DESTINATION PTR
	LD	A,(PBDMAX)	;SET BANK REGISTER
	LD	BC,128		;MOVE 128 BYTES
;
;   FALL INTO MOVE ROUTINE
;


;***************************************************************************
;
;	BLOCK MOVE TO HOST SUBR
;	ENTRY-	HL= LOCAL PTR (SRC)
;		DE= HOST PTR (DST)
;		BC= BYTE COUNT
;		A= BANK ADDRESS (DST)
;
;***************************************************************************
MOV2HST:
;
;   SET UP EXTENDED ADDRESS REGISTER
;
	LD	(MOVX),A	;SAVE EXTENDED ADDRESS VALUE FOR BUMPING
	LD	(HXADDR),A
;
;   FALL INTO MOVE PRIMITIVE
;


;***************************************************************************
;
;	MOVE SUBR CHECKS FOR A MOVE CROSSING ANY 32K BOUNDARY AND SELECTING
; A FAST BLOCK MOVE IF NOT, AND A SLOWER BLOCK MOVE WHICH CHECKS AFTER EACH
; BYTE FOR AN OVERFLOW CONDITION IF TRUE.
;	ENTRY-	HL= LOCAL MEMORY (SOURCE) PTR
;		DE= S100 MEMORY (DESTINATION) PTR
;		BC= BYTE COUNT TO TRANSFER
;
;	EXIT -	AF= ?
;		BC= 0
;		HL= HL + BC
;		DE= DE + BC
;
;***************************************************************************
;
;   SET BIT 15 REGISTER TO PTR BIT 15
;
	LD	A,D		;SET BIT 15
	OUT	(HXAD15),A
;
;   IF > 32K MOVE THEN DO LONG WAY
;
	DEC	BC
	LD	A,B
	CP	A,32768 / 256
	JR	NC,DOLONG
;
;   IF GOING TO CROSS 64K BOUNDARY THEN DO LONG WAY
;
	LD	A,E
	ADD	A,C
	LD	A,D
	ADC	A,B
	JR	C,DOLONG
;
;   IF GOING TO CROSS 32K BOUNDARY THEN DO LONG WAY
;
	XOR	A,D
	JP	M,DOLONG
;
;   NO BOUNDARY CROSSING. USE BLOCK MOVE INSTRUCTION
;
	INC	BC		;RESTORE COUNT
	SET	7,D		;INSURE S100 MAP
;
	LDIR
;
;   MOVE DONE. RETURN
;
	RET
;
;
;	LONG TRANSFER TESTS EACH BYTE FOR THRESHOLDS
;
DOLONG:	INC	BC		;RESTORE COUNT
	LD	A,D		;SET UP CURRENT BIT 15
	LD	I,A		;SAVE IN I SINCE NOT USING MODE 2 INTERRUPTS
;
NO64KX:	SET	7,D		;INSURE S100
;
;   XFER 1 BYTE
;
MOV4:	LDI
;
;   IF COUNT EXHAUSTED THEN RETURN
;
	RET	PO
;
;   IF NO ROLLOVER THEN REPEAT
;
	BIT	7,D
	JP	NZ,MOV4
;
;   S100 PTR ROLLED OVER 32K BOUNDARY, TOGGLE BIT 15
;
	LD	A,I
	XOR	A,80H
	LD	I,A
	OUT	(HXAD15),A
;
;   IF BIT 15 TOGGLED TO 0 THEN NEXT BANK
;
	BIT	7,A
	JP	NZ,NO64KX
;
	LD	A,(MOVX)
	INC	A
	LD	(MOVX),A
	OUT	(HXADDR),A
;
;   NEXT BYTE
;
	JP	NO64KX


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	RECALIBRATE FUNCTION
;	EXIT -	NZ= ERROR (A= CODE #)
;		IY= NULCDB
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RECALC:
;
;   SEND RECAL COMMAND TO SASI CONTROLLER
;
	LD	IY,NULCDB
	LD	(IY+CMD),SCREC		;RECAL COMMAND
;
	LD	A,(LUNSV)	;STILL HAS SELECTED LUN
	LD	(IY + LUN),A
;
	CALL	SNDCDB
	RET	NZ
;
;   RETURN COMMAND RESULTS STATUS
;
	JP	GETRES		;FINISH UP


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	TRANSMIT CDB FUNCTION
;	ENTRY-	IY= CDB TO XMIT
;	EXIT -	NZ= ERROR, A= CODE
;		DE= ?
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SNDCDB:
;
;   CONTROLLER SELECT PHASE
;
	LD	A,[1 SHL HDCONT]	;ASSERT TARGET ADDRESS BIT
	OUT	(SASIDATA),A
;
	LD	A,[1 SHL SSELECT] OR [1 SHL SERRCLR]	;ASSERT SEL
	OUT	(SASICMD),A
;
;   WAIT FOR BUSY ACKNOWLEDGE OF SELECT
;
	LD	DE,0		;SET ALARM
;
SNDCBW:	IN	A,(SASIST)
	BIT	SBUSY,A
	JR	Z,SNDC2
;
;   SELECT ACKNOWLEDGED, FINISH SELECT PHASE
;
	LD	A,1 SHL SERRCLR		;DEASSERT SEL
	OUT	(SASICMD),A
;
;   SELECT PHASE DONE, ENTER COMMAND PHASE
;
	LD	C,SASIDATA	;SET PORT #
;
	PUSH	IY		;PUT PTR TO CDB IN HL
	POP	HL
;
;   WAIT FOR COMMAND REQUEST
;
SNDCDB3:
	CALL	WAITRQ		;WAIT FOR REQUEST
	RET	C		;RETURN ERROR IF TIMEOUT
;
;   IF NOT COMMAND PHASE THEN DONE
;
	AND	A,[1 SHL SCD] OR [1 SHL SIO]	;C/D & /I/O
	CP	A,[1 SHL SCD] OR [1 SHL SIO]	;SIO IS INVERTED!
	JR	NZ,SNDCDN
;
;   ELSE CONTINUE OUTPUTING BYTES UNTIL CONTROLLER SATISFIED
;
	OUTI
	JP	SNDCDB3
;
;
;   BUSY STILL FALSE, CHECK ALARM
;
SNDC2:	DEC	DE
	LD	A,E
	OR	A,D
	JR	NZ,SNDCBW
;
;   ALARM WENT OFF! RETURN TIMEOUT ERR
;
	LD	A,1		;TELL USER WHERE OCCURRED
;
SNDCTO:	LD	(PBSTAT + 1),A
	LD	A,TMOERR
	OR	A,A
	RET
;
;
;   DONE WITH COMMAND PHASE, RETURN NO ERRORS
;
SNDCDN:	XOR	A,A
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	GET CONTROLLER RESULTS FUNCTION
;	EXIT -	NZ= ERROR, A & (PBSTAT)= CODE
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
GETRES:
;
;   START STATUS PHASE
;
	CALL	WAITRQ		;WAIT FOR CONTROLLER
	RET	C		;IF TIMEOUT THEN RETURN ERROR
;
;   IF NOT STATUS PHASE THEN SYNC ERROR
;
	LD	C,A		;SAVE STATUS FOR LATER
	AND	A,[1 SHL SCD] OR [1 SHL SIO]	;C/D & I/O
	CP	A,[1 SHL SCD]			;SIO IS INVERTED!
;
	LD	A,3		;SUB-ERROR 3, STATUS PHASE EXPECTED
	JP	NZ,SYNERR
;
;   FETCH STATUS BYTE TO COMPLETE STATUS PHASE
;
	IN	A,(SASIDATA)
	LD	(RSTAT),A
;
;   ENTER MESSAGE PHASE
;
	CALL	WAITRQ
	RET	C
;
;   IF NOT MESSAGE PHASE THEN RETURN SYNC ERROR
;
	LD	B,C
	LD	C,A
	AND	A,[1 SHL SCD] OR [1 SHL SIO] OR [1 SHL SMSG] ;C/D & I/O & MSG
	CP	A,[1 SHL SCD] OR [1 SHL SMSG]		;SIO IS INVERTED!
	LD	A,4		;SUB-ERROR 4, MESSAGE PHASE EXPECTED
	JP	NZ,SYNERR
;
;   ACKNOWLEDGE MESSAGE PHASE BY SENDING ACK
;
	IN	A,(SASIDATA)
;
;   CHECK FOR HARDWARE PARITY ERROR DURING WHOLE OPERATION
;
	BIT	SPERR,B		;B STILL HAS STATUS RESULT STATUS
	JR	NZ,HDPERR
;
;   ALL PHASES DONE, IF NO ERROR THEN RETURN NO ERROR
;
	LD	A,(RSTAT)
	AND	A,00000011B
	RET	Z
;
;   ELSE IF CONTROLLER PARITY ERROR THEN RETURN THE ERROR
;
	BIT	1,A
	JR	Z,GRESPE
;
;   ERROR ENCOUNTERED. REQUEST SENSE
;
	LD	(IY+CMD),SCSNSE
	CALL	SNDCDB
	RET	NZ
;
;   ENTER DATA PHASE & GET STATUS BYTES
;
	LD	HL,PBSTAT
	LD	BC,[6 SHL 8] + SASIDATA	;MAX BYTES + PORT
;
GETR2:	CALL	WAITRQ
	RET	C		;IF TIMEOUT THEN RETURN ERROR
;
;   IF NOT DATA PHASE THEN DONE
;
	BIT	SCD,A
	JR	NZ,GETR3
;
;   GET STATUS BYTE
;
	INI
;
;   IF IOPB STATUS NOT FULL THEN REPEAT
;
	JP	NZ,GETR2
;
;   STATUS OVERFLOW! KEEP GOING
;
GETR2A:	CALL	WAITRQ
	RET	C
;
;   IF NOT DATA PHASE THEN STOP
;
	BIT	SCD,A
	JR	NZ,GETR3A
;
;   XFER BYTE INTO BIT BUCKET
;
	IN	A,(SASIDATA)
	JP	GETR2A
;
;
;   STATUS OVERFLOW, TELL SO
;
GETR3A:	LD	A,?FDCERR
	LD	(PBSTAT),A
	LD	A,-2
	LD	(PBSTAT + 1),A
;
;   DATA PHASE DONE, ENTER STATUS PHASE
;
GETR3:	CALL	WAITRQ
	RET	C
;
;   IF NOT STATUS PHASE THEN SYNC ERROR
;
	LD	C,A		;SAVE STATUS FOR LATER
	AND	A,[1 SHL SCD] OR [1 SHL SIO]
	CP	A,[1 SHL SCD]
	LD	A,5		;SUB-ERROR 5, EXPECTED STATUS PHASE
	CALL	NZ,SYNERR
;
;   FETCH STATUS BYTE TO COMPLETE STATUS PHASE
;
	IN	A,(SASIDATA)
	LD	(RSTAT),A
;
;   ENTER MESSAGE PHASE
;
	CALL	WAITRQ
	RET	C
;
;   IF NOT MESSAGE PHASE THEN RETURN SYNC ERROR
;
	LD	B,C
	LD	C,A
	AND	A,[1 SHL SCD] OR [1 SHL SIO] OR [1 SHL SMSG]
	CP	A,[1 SHL SCD] OR [1 SHL SMSG]
	LD	A,6		;SUB-ERROR 6, EXPECTED MESSAGE PHASE
	CALL	NZ,SYNERR
;
;   ACKNOWLEDGE MESSAGE PHASE BY SENDING ACK
;
	IN	A,(SASIDATA)
;
;   CHECK FOR HARDWARE PARITY ERROR DURING WHOLE OPERATION
;
	BIT	SPERR,B
	JR	NZ,HDPERR
;
;   ALL PHASES DONE, IF NO ERROR THEN RETURN CONTROLLER ERROR
;
	LD	A,(RSTAT)
	AND	A,00000011B
	JR	NZ,GETR4
;
;   ELSE RETURN CONTROLLER'S ERROR CODE
;
	LD	A,(PBSTAT)
	OR	A,A
	RET
;
;
;   IF CONTROLLER PARITY ERROR THEN RETURN THE ERROR
;
GETR4:	BIT	1,A
	JR	Z,HDPERR
;
;   ELSE HARD ERROR
;
	LD	A,-1		;CONTROLLER ERROR MUST HAVE BYTE 2 SET
	LD	(PBSTAT + 1),A
;
	LD	A,?FDCERR
	OR	A,A
	RET
;
;
;   DATA XFER PARITY ERROR
;
HDPERR:	XOR	A,A		;CLEAR ERROR
	OUT	(SASICMD),A
	LD	A,1 SHL SERRCLR
	OUT	(SASICMD),A
;
;   RETURN THE ERROR
;
GRESPE:	LD	A,?PARERR	;RETURN PARITY ERROR
	OR	A,A
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	SASI CONTROLLER SYNC ERROR FUNCTION
;	ENTRY-	A= SUB-ERROR TO GO INTO PBSTAT + 1
;		C= SASI BUS STATUS WORD CAUSING ERROR TO GO INTO PBSTAT + 2
;	EXIT -	AF= SYNCER, NZ
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SYNERR:
;
;   STORE SUB-ERROR FOR HOST
;
	LD	(PBSTAT + 1),A
;
;   STORE STATUS FOR HOST
;
	LD	A,C
	LD	(PBSTAT + 2),A
;
;   RETURN ERROR
;
	LD	A,?SYNCER
	OR	A,A
	RET


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	GET LUN FROM USER FUNCTION
;	ENTRY-	IY= CDB PTR
;		(CURDRV)= FORMATTED DRIVE # {0..3}
;	EXIT -	AF= ?
;
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
GETLUN:
;
;   COMPUTE DRIVE #
;
	LD	A,(CURDRV)	;FETCH DRIVE #
;
	RRCA			;PUT IN PROPER FIELD
	RRCA
	RRCA
;
;   SAVE LUN # FOR LATER USE
;
	LD	(LUNSV), A
	LD	(IY + LUN), A
;
	RET


;***************************************************************************
;
;	GET LOGICAL ADDR FROM IOPB SUBR
;	ENTRY-	IY= CDB PTR
;	EXIT -	A= 0: OK, /0: ERROR CODE
;		DE= ?
;
;***************************************************************************
GETLAD:
;
;   IF SECTOR DATA OUT OF RANGE THEN RETURN ERROR
;
	LD	DE,(PBSEC)	;{0..255}
	LD	A,D
	OR	A,A
	JR	NZ,GETLADE
;
;   IF TRACK DATA OUT OF RANGE THEN RETRUN ERROR
;
	LD	A,(PBTRK + 1)	;{0..255}
	OR	A,A
	JR	NZ,GETLADE
;
;   COMPUTE LOGICAL ADDRESS FROM SECTOR, TRACK
;
	LD	A,(PBTRK)	;PICK UP TRACK LSB & PUT INTO LA0 BIT 7
	SRL	A		;  SECTOR BIT 0 IS WASTED
	RR	E
	LD	(IY + LA0),E	;PHEW! LA0 DONE
;
	LD	(IY + LA1),A	;LA1 HAPPENS TO BE IN A
;
;   RETURN NO ERRORS
;
	XOR	A,A
	RET
;
;
;   DATA OUT OF RANGE
;
GETLADE:
	LD	A,?ADDRERR
	OR	A,A
	RET


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	WAIT FOR REQUEST FROM CONTROLLER FUNCTION
;	EXIT -	CF= TIMEOUT: NZ, A= TMOERR
;		NC= A: STATUS
;		DE= ?
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
WAITRQ:
;
;   INSURE NC RETURNED IF ALL TESTS PASS
;
	OR	A,A
;
;   FIRST INSURE ACK IS FALSE (PREVIOUS BYTE HAS BEEN READ)
;
	LD	DE,0		;SET ALARM
;
WTRQ3:	IN	A,(SASIST)
	BIT	SACK,A
	JR	NZ,WTRQ2
;
;   ACK FALSE, WAIT FOR REQUEST
;
	LD	DE,0		;SET ALARM
;
;   IF REQUEST == TRUE (0) THEN RETURN
;
WTRQ1:	IN	A,(SASIST)
	BIT	SREQ,A
	RET	Z
;
;   CHECK ALARM
;
	DEC	DE
	LD	A,E
	OR	A,D
	JP	NZ,WTRQ1
;
;   ALARM WENT OFF! RETURN REQUEST TIMEOUT ERROR
;
	LD	A,3
;
WTRQ9:	LD	(PBSTAT + 1),A
;
	LD	A,TMOERR
	OR	A,A
	SCF
	RET
;
;
;   ACK FALSE ALARM CHECK
;
WTRQ2:	DEC	DE
	LD	A,E
	OR	A,D
	JP	NZ,WTRQ3
;
;   ALARM WENT OFF, RETURN ACK TIMEOUT ERROR
;
	LD	A,2
	JR	WTRQ9


	SUBTTL	CONSTANTS
;###########################################################################
;
;			ID SECTOR TEXT
;
;###########################################################################
IDTXT	DB	'Disk Descriptor '
IDSZE	EQU	$ - IDTXT
;
JIDTXT	DB	'Jade DD '
JIDSZE	EQU	$ - JIDTXT

	IF	$ >= (LOCROM + ROMSIZE)
	CONMSG	**** ERROR! CODE TOO LARGE FOR DECLARED PROM SIZE! ****
	ENDIF

	SUBTTL	RAM AREA
	ORG	LOCRAM
;###########################################################################
;
;			VARIABLES
;
;###########################################################################
;
;   IOPB PTRS
;
IOPBL	DS	1	;LOW ADDRESS OF IOPB TO EXECUTE
IOPBH	DS	1	;HIGH ADDRESS OF IOPB
IOPBXA	DS	1	;BANK ADDRESS OF IOPB
;
;   STATUS PHASE RESULT BYTE
;
RSTAT	DS	1	;COMMAND STATUS RETURNED
			;BIT 1: ERROR (ISSUE SENSE COMMAND)
			;BIT 5..7: LUN
;
;   SECTOR BUFFER DEBLOCKING PTRS
;
BUFDRV	DS	1	;BUFFER CONTENTS DRIVE BYTE
BUFSEC	DS	2	;BUFFER CONTENTS SECTOR WORD
BUFTRK	DS	2	;BUFFER CONTENTS TRACK WORD
;
;  DISCRETE VARIABLES
;
LUNSV	DS	1	;LUN # {0..3}
RETRYS	DS	1	;RETRY COUNT
MOVX	DS	1	;HOST BANK ADDRESS SAVE FOR BLOCK MOVE SUBRS
FDADDR	DS	2	;FDC ADDRESS PTR
TIMOUT	DS	2	;UNSELECT SASI DELAY
CURDRV	DS	1	;CURRENT PHYSICAL DRIVE {0..3}


;###########################################################################
;
;	SASI CONTROLLER COMMAND DESCRIPTOR BLOCKS (CDB)
;
;###########################################################################
;
NULCDB:	DS	6	;NO TRANSFER CDB
LAXCDB:	DS	6	;MAIN XFER CDB
IDRCDB	DS	6	;ID SECTOR READ CDB
CDBINIT	EQU	$ - NULCDB
;
;	CDB OFFSETS
;
CMD	EQU	0	;COMMAND
LUN	EQU	1	;LOGICAL UNIT NUMBER IN BITS 5..7
LA2	EQU	LUN	;LOGICAL ADDRESS 2 IN BITS 0..4
LA1	EQU	2	;LOGICAL ADDRESS 1
LA0	EQU	3	;LOGICAL ADDRESS 0
NBK	EQU	4	;XFER COMMANDS BLOCK (SECTOR) COUNT
ILV	EQU	NBK	;FORMAT COMMAND INTERLEAVE FACTOR
RTY	EQU	5	;RETRY FLAG 0: RETRY 3 TIMES, 80H: NO RETRYS


;###########################################################################
;
;		I/O PARAMETER BLOCK SAVE AREA
;
;###########################################################################
PBCMD	DS	1		;COMMAND BYTE
PBDRV	DS	1		;DRIVE BYTE
PBTRK	DS	2		;TRACK #
PBSEC	DS	2		;SECTOR #, FORMAT INTERLEAVE, FLOPPY PARAMS
PBFLG	DS	1		;INPUT FLAG BYTE (LOG-ON, BLOCKING FLAGS)
				; SELECT DISK - 0: NOT SELECTED BEFORE
				; BLOCKING - 0: NORMAL WRITE (READ-WRITE)
				;	     1: DIRECTORY WRITE (READ-WRITE)
				;	     2: UNALLOCATED WRITE (NO READ)
PBLOG	EQU	0		;LOGON REQUEST BIT
PBRTRY5	EQU	6		;RETRY 5 TIMES BIT (ALONG WITH BIT 7 SET)
PBRTRY	EQU	7		;DISABLE RETRYS BIT

PBDMA	DS	2		;TRANSFER ADDRESS
PBDMAX	DS	1		;TRANSFER BANK ADDRESS
PBSTAT	DS	4		;SENSE STATUS BYTES (IF ERROR)
	DS	2		;SPARES
IOPBSIZE EQU	$ - PBCMD


;###########################################################################
;
;		HARD DISK SECTOR BUFFER
;
;###########################################################################
HDBUFSZ	EQU	256
HDSECB	DS	HDBUFSZ
;


;###########################################################################
;
;	JADE SECTOR BUFFER
;
;###########################################################################
JADSECB	DS	256


;###########################################################################
;
;			STACK AREA
;
;###########################################################################
	IF	$ > (LOCRAM + RAMSIZE - 32)
	CONMSG	**** ERROR! DATA TOO LARGE FOR DECLARED RAM SIZE! ****
	ENDIF
	DS	32
STACK	EQU	LOCRAM + RAMSIZE

	END
