	TITLE	INTELLIGENT SASI HOST ADAPTOR INTERFACE
	LIST	NOCOND
;**************************************************************************
;
;	THIS MODULE CONTAINS THE INTELLIGENT HOST ADAPTER FIRMWARE.
;
;**************************************************************************
;
;	IOPB CONFIGURATION:
;
; DRIVE		USAGE
;   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.
;
VERSN	EQU	1AH
;**************************************************************************
FALSE	EQU	0
TRUE	EQU	NOT FALSE
DEBUG	EQU	FALSE

*INCLUDE	JDDCONT.DEF

	SUBTTL	DEFINITIONS

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
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
;
;======================================
SASIDATA EQU	LOCPRTS		;SASI BUS DATA PORT

SASICMD	EQU	LOCPRTS + 1	;SASI BUS CONTROL PORT
;
;	7 6 5 4 3 2 1 0		BIT DEFINITIONS
;	      ^ ^ ^ ^ ^__ 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)
;
SINTE	EQU	0		;SASI INTERRUPT BIT #
SRESET	EQU	1		;SASI RESET BIT #
SSELECT	EQU	2		;SASI DEVICE SELECT STROBE BIT #
SERRCLR	EQU	3		;SASI PARITY ERROR CLEAR* BIT #
HINT	EQU	4		;HOST VECTORED INTERRUPT BIT #

SASIST	EQU	LOCPRTS + 1	;SASI BUS STATUS PORT
;
;	7 6 5 4 3 2 1 0		BIT DEFINITIONS
;	^     ^ ^ ^ ^ ^__ SASI BUSY (1)
;	|     | | | |____ SASI MESSAGE (1)
;	|     | | |______ SASI COMMAND (1) / DATA (0)
;	|     | |________ SASI REQUEST (1)
;	|     |__________ SASI INPUT (1) / OUTPUT (0)
;	|________________ SASI PARITY ERROR (1)
;
SBUSY	EQU	0		;SASI BUSY BIT
SMSG	EQU	1		;SASI MESSAGE BIT
SCD	EQU	2		;SASI C/D BIT
SREQ	EQU	3		;SASI REQUEST* BIT
SIO	EQU	4		;SASI I/O* BIT
SPERR	EQU	7		;SASI PARITY ERROR DETECTED BIT
SSTMSK	EQU	10011111B	;STATUS BIT MASK
SSTINV	EQU	00011000B	;STATUS BIT INVERSION MASK
SSXMSK	EQU	00010110B	;XFER CONTROL MASK
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

HINTC	EQU	LOCPRTS + 2	;HOST INTERRUPT CLEAR PORT (OUT, DATA= X)

HINTS	EQU	LOCPRTS + 3	;HOST INTERRUPT SET PORT   (OUT, DATA= X)

HSTAT	EQU	LOCPRTS + 4	;HOST STATUS PORT
;
;	7 6 5 4 3 2 1 0		BIT DEFINITION
;	^           ^ ^__ ISASI BUSY (1)
;	|           |____ FIRMWARE ERROR (1)
;	|________________ ERROR (1)
;
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

HCMD	EQU	LOCPRTS + 4	;HOST COMMAND PORT
;
;	7 6 5 4 3 2 1 0		BIT DEFINITIONS
;	^ ^   \_____/ ^__ HOST INTERRUPTED (1)
;	| |      |_______ NON-IOPB COMMAND CODE (0..F)
;	| |______________ HOST EXECUTE IOPB (1)
;	|________________ LOCAL RESET (1)
;
HINTRB	EQU	0		;HOST INTERRUPT REQUEST BIT
HIOPBB	EQU	6		;HOST EXECUTE IOPB BIT
HRESB	EQU	7		;HOST RESET LOCAL PROCESSOR BIT

HDATA	EQU	LOCPRTS + 5	;HOST DATA TRANSFER PORT

HXAD15	EQU	LOCPRTS + 6	;HOST A15 SET PORT
;
;	7 6 5 4 3 2 1 0		BIT DEFINITION
;	^________________ BIT APPLIED TO HOST BUS A15 WHEN ACCESSING ITS
;			    MEMORY
A15B	EQU	7		;HOST A15 BIT

HXADDR	EQU	LOCPRTS + 7	;EXTENDED ADDRESS PORT (A16..A23)
;
;	7 6 5 4 3 2 1 0		BIT DEFINITION
;	^ ^ ^ ^ ^ ^ ^ ^__ A16
;	| | | | | | |____ A17
;	| | | | | |______ A18
;	| | | | |________ A19
;	| | | |__________ A20
;	| | |____________ A21
;	| |______________ A22
;	|________________ A23


;======================================
;
;	FIRMWARE ERROR CODES
; IN HOST DATA REGISTER IF HOST STATUS
; BIT 1 SET
;
;======================================
FERR00	EQU	0	;UNKNOWN ERROR
FERR01	EQU	1	;RAM TEST FAILURE
FERR02	EQU	2	;ROM TEST FAILURE
FERR03	EQU	3	;ILLEGAL COMMAND
FERR04	EQU	4	;ILLEGAL INTERRUPT
FERR05	EQU	5	;ILLEGAL IOPB DRIVE SPEC
FERR06	EQU	6	;ILLEGAL IOPB COMMAND
FERR07	EQU	7	;CONTROLLER HANDSHAKE TIMOUT
FERR08	EQU	8	;CONTROLLER SYNC ERROR ???
FERR09	EQU	9	;CONTROLLER SENSE STATUS ERROR
FERR10	EQU	10	;ILLEGAL IOPB PARAMETER
FERR11	EQU	11	;PARITY ERROR
FERR12	EQU	12


;======================================
;
;	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 DEFINITIONS
;
;============================
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

	SUBTTL	MACROS
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	GET DATA MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@
GETDATA	MACRO
AA#SYM:	CALL	GETSTAT		;IF REQUEST FALSE THEN WAIT
	BIT	SREQ,A
	JR	Z,AA#SYM

	INI			;GET DATA

	ENDM


;@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	PUTDATA MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@
PUTDATA	MACRO
AC#SYM:	CALL	GETSTAT		;IF REQUEST NOT TRUE THEN WAIT
	BIT	SREQ,A
	JR	Z,AC#SYM

	OUTI			;ASSUME CALLER SET UP
				;DON'T WAIT
	ENDM

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;
;	BUFFER HALF SELECT MACRO
;
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
SELCTBUF MACRO
	LD	HL,HDSECB	;ASSUME 1ST HALF

	BIT	DFHARD,(IX + DTFLG)	;IF HARD DISK THEN DO SELECTION
	JR	NZ,BA#SYM

	LD	A,(PBTRK)	;ELSE IF TRK 00 THEN USE 1ST HALF ONLY
	OR	A
	JR	Z,BB#SYM

	BIT	DFDBL,(IX + DTFLG)	;IF NOT 256 BYTE SECTORS THEN DO
	JR	Z,BB#SYM		;  1ST HALF ONLY

BA#SYM:	LD	A,(PBSEC)	;IF SECTOR IS ODD THEN SELECT UPPER HALF
	AND	1
	JR	Z,BB#SYM

	LD	HL,HDSECB + 128
BB#SYM:
	ENDM

;;
;;	HOST OUTPUT MACRO
;;
HSTOUT:	MACRO	#PORT, #DATA
	IF	#PORT < 80H
	XOR	A
	ELSE
	LD	A,#PORT		;SET UP BIT 7
	ENDIF
	OUT	(HXAD15),A

	IF	(#DATA = 0) AND (#PORT <> 0)
	XOR	A
	ENDIF
	IF	#DATA <> 0
	LD	A,#DATA		;OUTPUT DATA
	ENDIF
	OUT	(#PORT OR 80H),A
	ENDM

;;
;;	HOST INPUT MACRO
;;
HSTIN:	MACRO	#PORT
	IF	#PORT < 80H
	XOR	A
	ELSE
	LD	A,#PORT		;SET UP BIT 7
	ENDIF
	OUT	(HXAD15),A

	IN	A,(#PORT OR 80H)	;FETCH DATA
	ENDM

	SUBTTL	CODE
	ORG	LOCROM
;************************************************
;
;	PROCESSOR REGISTER USAGE:
;	IX= PTR TO CURRENT DISK DRIVE TABLE
;	IY= PTR TO CURRENT COMMAND DESCRIPTOR BLOCK
;
;************************************************
RESETV:
	OUT	(HINTS),A	;SET BUSY FLAG
	XOR	A		;PASS NOT -1 TO BOOT
	OUT	(HSTAT),A

	IM	1		;ONLY 1 INTERRUPT
	LD	SP,STACK	;INIT STACK

	LD	HL,LOCRAM	;DO RAM TEST
	LD	BC,RAMSIZE

MTLP:	LD	A,(HL)		;COMPLEMENT & TEST
	CPL
	LD	(HL),A
	CP	(HL)
	JR	NZ,MEMERR

	CPL			;RESTORE
	LD	(HL),A

	INC	HL		;NEXT LOCATION
	DEC	BC
	LD	A,B
	OR	C
	JR	NZ,MTLP

	CALL	INIT		;ANY OTHER INITIALIZATION

	LD	HL,0		;FORCE NO TIMEOUT
	JP	HWAITC

;--------------------------------------
;
;	RAM ERROR ENCOUNTERED
;
;--------------------------------------
MEMERR:	LD	A,FERR01	;PASS ERROR TO HOST & HALT
	OUT	(HDATA),A
	LD	A,HFERR
	OUT	(HSTAT),A
	OUT	(HINTC),A	;CLEAR PENDING INTERRUPT
	HALT

	IF	$ > 38H
	CONMSG	**** ERROR! RESET CODE OVERLAPS INTERRUPT CODE! ****
	ENDIF
;----------------------------
;
;	INTERRUPT ENTRY VECTOR
;
;----------------------------
	ORG	LOCROM + 38H

	IN	A,(HCMD)	;GET COMMAND
	BIT	HINTRB,A	;IF NOT HOST INTERRUPT THEN MUST BE SASI
	JP	Z,SASINT

	BIT	HIOPBB,A	;IF IOPB BIT SET THEN EXECUTE IOPB
	JP	NZ,EXIOPB

	AND	00011110B	;MASK OFF UNUSED COMMANDS

	CP	NUMCMDS * 2	;IF COMMAND ERROR THEN RETURN FIRMWARE ERR
	JR	C,CMDOK

	LD	A,FERR03
	SCF
	JR	CMDRET

CMDOK:	LD	HL,CMDTBL
	ADD	L
	LD	L,A
	LD	A,0
	ADC	A,H
	LD	H,A
	LD	E,(HL)
	INC	HL
	LD	D,(HL)
	EX	DE,HL
	IN	A,(HDATA)

	LD	DE,CMDRET	;PUT RETURN ADDRESS ON STACK
	PUSH	DE
	JP	(HL)

;--------------------------------------
;
;	ALL COMMANDS RETURN HERE
;	ENTRY-	CF= ERROR
;		A= 0: NOT FIRMWARE ERROR
;		  /0: ERROR CODE
;
;--------------------------------------
CMDRET:
	JR	NC,CNOERR	;IF NOT ERROR THEN SAY SO

	OR	A		;IF A= 0 THEN NO ERROR
	JR	Z,CNOTF

	OUT	(HDATA),A	;PUT ERROR IN DATA REG
	LD	A,HFERR		;SET FIRMWARE ERROR

CMDR1:	OUT	(HSTAT),A	;PASS ERROR TO HOST

	POP	HL		;WASTE RETURN ADDRESS TO WAIT RTN

	LD	HL,-1		;SET TIMOUT TIME
HWAITC:	LD	(TIMOUT),HL

	OUT	(HINTC),A	;CLEAR HOST INTERRUPT & BUSY FLAG


;----------------------------
;
;	MAIN INTERRUPTED LOOP
;
;----------------------------
HWAIT:
	EI			;ALLOW INTERRUPTS

	LD	HL,(TIMOUT)	;IF TIMED OUT THEN JUST WAIT
	LD	A,H
	OR	L
	JR	Z,HWAIT

	DEC	HL
	LD	(TIMOUT),HL
	LD	A,H		;IF TIME OUT JUST WENT TO 0 THEN
	OR	L
	JR	NZ,HWAIT

	XOR	A		;   DESELECT SASI BUS
	OUT	(SASIDATA),A
	LD	A,[1 SHL SSELECT] OR [1 SHL SERRCLR]
	DI
	OUT	(SASICMD),A
	LD	A,[1 SHL SERRCLR]
	OUT	(SASICMD),A
	EI
	JR	HWAIT


CNOTF:	LD	A,1 SHL HSERRB	;PLAIN ERROR
	JR	CMDR1

CNOERR:	XOR	A		;CLEAR BUSY & ERROR FLAGS
	JR	CMDR1

;
;	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	9		;NUMBER OF COMMANDS

	SUBTTL	COMMANDS
;--------------------------------------
;
;	SET IOPB ADDRESS COMMANDS
; MUST BE INITIALIZED BEFORE DISK ACCESS
;	ENTRY-	A= DATA
;	EXIT -	HDATA= OLD DATA
;
;--------------------------------------
IOPBLO:
	LD	HL,IOPBL	;POINT TO BYTE TO ALTER
	JR	IOPBST

IOPBHI:
	LD	HL,IOPBH
	JR	IOPBST

IOPBX:
	LD	HL,IOPBXA

IOPBST:	LD	C,(HL)		;SAVE OLD DATA
	LD	(HL),A		;SET NEW DATA
	LD	A,C		;PASS OLD DATA TO HOST
	OUT	(HDATA),A

	XOR	A		;RETURN NO ERRORS (PREVENTS DATA OVERWRITE)
	RET


;----------------------------------------------------------
;
;	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
	XOR	A			;BOTTOM 32K
	OUT	(HXADDR),A
	OUT	(HXAD15),A
	LD	HL,LOCRAM		;DUMP LOCAL RAM TO S100 RAM
	LD	DE,S1MEM + 4000H	;DUMP TO HOST AT 4000H
	LD	BC,RAMSIZE		;USE ALL RAM
	LDIR

	LD	HL,LOCROM		;FOLLOW WITH ROM IMAGE
	LD	BC,ROMSIZE
	LDIR

	HSTOUT	DDPORT,DDMB0		;FOLLOW WITH FDC BANK 0
	LD	HL,(FDADDR)
	LD	BC,1024
	PUSH	HL
	LDIR

	HSTOUT	DDPORT,DDMB1		;FOLLOW WITH FDC BANK 1
	POP	HL
	LD	BC,1024
	LDIR

	HSTOUT	DDPORT,DDOUT	;REMOVE DD WINDOW SO HOST WON'T CRASH

	XOR	A		;NO ERRORS
	OUT	(HSTAT),A

DIAGR:	LD	SP,STACK	;DIRECT RETURN, FLUSH RETURN ADDR FROM STACK
	LD	HL,(TIMOUT)	;PASS TIMEOUT
	JP	HWAITC


;---------------------------------------------------------------
;
;	DIAGNOSTIC 1 LOADS DATA INTO DATA OUT & STATUS REGS
;	ENTRY-	A= DATA
;
;---------------------------------------------------------------
DIAG1:	OUT	(HDATA),A
	OUT	(HSTAT),A
	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:
	LD	HL,S1MEM + 1000H
	LD	BC,ROMSIZE + RAMSIZE

D2LP:	LD	A,(HL)
	CPL
	LD	(HL),A
	CP	(HL)
	CPL			;RESTORE
	LD	(HL),A
	JR	NZ,D2ERR

	INC	HL
	DEC	BC
	LD	A,B
	OR	C
	JR	NZ,D2LP

D2ERR:	LD	(S1MEM + 0FF2H),HL
	LD	(S1MEM + 0FF4H),A
	LD	A,(HL)
	LD	(S1MEM + 0FF5H),A

	XOR	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:
	OR	A
	JR	Z,DOMOVE

D3LP:	IN	A,(HDATA)		;IF DATA CHANGED THEN CHECK
	CP	2
	JR	C,DOREAD
	JR	Z,DOWRITE
	CP	3
	JR	Z,DOBLKH

	XOR	A
	RET

DOWRITE:
	LD	(S1MEM + 1000H),A
	JR	D3LP

DOREAD:
	LD	A,(S1MEM + 1000H)
	JR	D3LP

DOMOVE:
	LD	HL,S1MEM + 1000H
	LD	DE,S1MEM + 2000H
	LD	BC,1000H
	LDIR
	XOR	A
	RET

DOBLKH:	LD	A,1 SHL A15B		;SET HIGH PAGE
	OUT	(HXAD15),A
	LD	HL,0E000H
	LD	DE,0E800H
	LD	BC,800H
	LDIR
	XOR	A
	RET


;------------------------------------------------
;
;	PRINT TEXT ON THE PRINTER COMMAND
; EXERCISES THE I/O CAPABILITY
;	ENTRY-	A= PORT #
;
;------------------------------------------------
PRINT:	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
	INC	E
	DJNZ	PRINT1
CRLF:	LD	E,0DH
	CALL	PRT
	LD	E,0AH
	CALL	PRT
	XOR	A
	RET


PRT:	IN	A,(C)	;IF BUSY THEN WAIT
	AND	1
	JR	NZ,PRT

	LD	A,E
	SET	7,A
	OUT	(C),A

	RES	7,A
	OUT	(C),A

	SET	7,A
	OUT	(C),A
	RET


	SUBTTL	SASI INTERRUPT
;------------------------------------------------
;
;	INTERRUPT WITHOUT HOST BIT SET
;
;-----------------------------------------------
SASINT:
	LD	A,FERR04		;OUTPUT ERROR FOR NOW
	SCF
	JP	CMDRET

	SUBTTL	IOPB EXECUTION
;----------------------------
;
;	EXECUTE IOPB
;
;----------------------------
EXIOPB:
	LD	DE,PBCMD		;DESTINATION := LOCAL IOPB IMAGE
	LD	HL,(IOPBL)		;GET ADDRESS OF IOPB IN USER RAM
	LD	A,H			;  SET A15
	OUT	(HXAD15),A

	SET	7,H			;INSURE HOST MEMORY AREA

	LD	A,(IOPBXA)		;  SET BANK #
	OUT	(HXADDR),A
	LD	BC,IOPBSIZE
	IF	FALSE
	CALL	MOVFHST
	ELSE
	LDIR
	ENDIF

	LD	A,(PBDRV)		;IF HARD DISK CONTROLLER THEN DO IT
	LD	HL,HDCMDS
	CP	HDBASD			;IF WITHIN HARD DISK DRIVES THEN EXIT
	JR	C,CHKJAD
	CP	HDBASD + HDNDRV
	JR	C,XTABL
CHKJAD:
	LD	HL,JADCMDS
	SUB	JADBASD			;BIAS DOWN TOO
	JR	C,XILDRV		;IF NOT JADE THEN DOESN'T EXIST
	CP	JADNDRV
	JR	NC,XILDRV
	LD	(BTDRV),A		;PRESTORE DRIVE IN COMMAND BLOCK

XTABL:
	LD	A,(PBCMD)		;CHECK IF LEGAL
	CP	MAXCMDS
	JR	NC,XILCMD

	ADD	A,A			;MULTIPLY CMD BY 2 FOR OFFSET
	ADD	L
	LD	L,A
	LD	A,0
	ADC	A,H
	LD	H,A
	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
;
;	THIS RETURN MUST RETURN IOPB TO HOST FOR STATUS UPDATE
;
XRET:
	PUSH	AF		;SAVE POSSIBLE ERROR CODE

	LD	HL,PBCMD	;SOURCE := LOCAL IOPB IMAGE
	LD	DE,(IOPBL)	;GET ADDRESS OF IOPB IN USER RAM
	LD	A,D		;  SET A15
	OUT	(HXAD15),A

	SET	7,D		;INSURE HOST MEMORY

	LD	A,(IOPBXA)	;  SET BANK #
	OUT	(HXADDR),A
	LD	BC,IOPBSIZE
	IF	FALSE
	CALL	MOV2HST
	ELSE
	LDIR
	ENDIF

	POP	AF
	JP	CMDRET


;----------------------------
;
;	ERROR EXITS
;
;----------------------------
XILDRV:
	LD	A,FERR05
	SCF
	JP	CMDRET

XILCMD:	LD	A,FERR06
	SCF
	JP	CMDRET

;-------------------------------------------
;
;	RETURN FIRMWARE VERSION COMMAND
;
;-------------------------------------------
RETVERS:
	LD	A,VERSN		;LOAD DATA REGISTER WITH VERSION
	OUT	(HDATA),A
	XOR	A
	RET


;----------------------------
;
;	IOPB COMMANDS
;
;----------------------------
MAXCMDS	EQU	8
JADCMDS:
	DW	JADLOG		;LOG ON DISK
	DW	JADREAD		;READ SECTOR
	DW	JADWRT		;WRITE SECTOR
	DW	JADFORM		;FORMAT TRACK
	DW	JADRDAD		;READ ADDRESS
	DW	JADEXEC
	DW	JADEXEC
	DW	JADEXEC		;IDLE

HDCMDS:
	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	HDSEEK		;SEEK TRACK (NORMALLY IMPLIED)
	DW	HDCERR
	DW	HDDEFF		;DEFINE FLOPPY CHARACTERISTICS

	SUBTTL	JADE IOPB COMMANDS
;--------------------------------------
;
;	LOGON COMMAND IS SAME AS READ
;
;--------------------------------------
JADLOG:


;----------------------------
;
;	READ SECTOR COMMAND
;
;----------------------------
JADREAD:
	HSTOUT	DDPORT,DDMRQ	;SWITCH DD INTO MEMORY
	CALL	FDSKEX
	PUSH	AF		;SAVE ERROR STATUS

	LD	HL,(FDADDR)	;GET FDC ADDRESS
	LD	DE,DDBUF
	ADD	HL,DE
	LD	DE,JADSECB
	EX	DE,HL
	LD	BC,128		;FETCH SECTOR DATA
	XOR	A
	CALL	MOVFHST

	HSTOUT	DDPORT,DDOUT	;REMOVE FDC WINDOW

	LD	HL,JADSECB	;NOW WRITE TO HOST
	CALL	HDHSTW

	POP	AF		;ERROR STATUS
	RET


;----------------------------
;
;	WRITE SECTOR COMMAND
;
;----------------------------
JADWRT:
	LD	HL,JADSECB	;GET DATA TO BUFFER
	CALL	HDHSTR

	HSTOUT	DDPORT,DDMRQ	;GET FDC WINDOW
	LD	DE,DDBUF	;PUT DATA FROM BUFFER INTO FDC
	LD	HL,(FDADDR)
	ADD	HL,DE
	EX	DE,HL
	LD	HL,JADSECB
	LD	BC,128
	XOR	A
	CALL	MOV2HST

	CALL	FDSKEX		;EXECUTE WRITE SECTOR CMD
	PUSH	AF		;SAVE ERROR STATUS

	HSTOUT	DDPORT,DDOUT	;REMOVE WINDOW

	POP	AF		;ERROR STATUS
	RET

;----------------------------
;
;	FORMAT COMMAND
;	(NOT IMPLEMENTED)
;
;----------------------------
JADFORM:


;----------------------------
;
;	READ ADDRESS COMMAND
;	(NOT IMPLEMENTED)
;
;----------------------------
JADRDAD:

;----------------------------
;
;	IDLE COMMAND
;	(NOT IMPLEMENTED)
;
;----------------------------
JADEXEC:
	LD	A,FERR05	;UNSUPPORTED FOR NOW!
	SCF
	RET

	SUBTTL	JADE FDC SUBR
;++++++++++++++++++++++++++++++++++++++
;
;	EXECUTE THE COMMAND BLOCK FUNC.
;	EXIT -	NZ, CF= ERROR
;		A= 0 (NOT FIRMWARE)
;
;++++++++++++++++++++++++++++++++++++++
FDSKEX:
	LD	A,(PBCMD)	;BUILD THE COMMAND BLOCK
	LD	(BTCMD),A
	LD	A,(PBTRK)
	LD	(BTTRK),A
	LD	A,(PBSEC)
	INC	A		;CHANGE FROM LOGICAL ADDR TO SECTOR #
	LD	(BTSEC),A
	LD	A,(PBFLG)
	LD	(BTMOD),A

	LD	DE,DDCMD		;MOVE COMMAND BLOCK INTO FDC
	LD	HL,(FDADDR)
	ADD	HL,DE
	EX	DE,HL
	LD	HL,BTCMD
	LD	BC,7
	XOR	A
	CALL	MOV2HST

	HSTOUT	DDPORT,DDEXC		;ISSUE COMMAND

	LD	BC,5			;SET UP TO MOVE STATUS DOWN

FDSKWT:	HSTIN	DDPORT			;WAIT UNTIL DONE
	AND	DDSHLT
	JR	NZ,FDSKWT

	HSTOUT	DDPORT,DDMRQ		;GET WINDOW

	XOR	A
	CALL	MOVFHST

	LD	A,(BTSTS)		;IF NO ERROR THEN RETURN 0, NC
	LD	(PBSTAT),A
	OR	A
	RET	Z

	LD	A,0			;NOT FIRMWARE ERROR
	SCF				; BUT ERROR JUST THE SAME
	RET


	SUBTTL	HARD DISK IOPB COMMANDS
;--------------------------------------
;
;	UNSUPPORTED COMMAND
;
;--------------------------------------
HDCERR:	LD	A,FERR06
	SCF
	RET


;--------------------------------------
;
;	DRIVE SELECT/LOG-ON COMMAND
; CHECK DRIVE READY
;	ENTRY-	(PBFLG)= 0: FULL LOG
;
;--------------------------------------
HDLOG:	CALL	HDSELCT
	RET	C

	LD	A,(PBFLG)		;IF FLAG <> 0 THEN SKIP LOG-ON
	OR	A
	JR	NZ,HDLOG1

	LD	A,(LUNSV)		;INIT THE DRIVE TABLE
	LD	(IX+DTDRV),A
	LD	(IX+DTVEC),0
	LD	(IX+ [DTVEC + 1]),0
	LD	(IX+DTFLG),0		;ASSUME SINGLE DENSITY

	LD	IY,IDRCDB		;READ THE ID SECTOR
	CALL	GETLUN
	CALL	HDRDBUF
	RET	C

	LD	DE,IDTXT		;CHECK FOR LEGAL ID
	LD	HL,HDSECB
	LD	B,IDSZE

HDCKID:	LD	A,(DE)
	CP	(HL)
	JR	NZ,HDNTID

	INC	HL
	INC	DE
	DJNZ	HDCKID
;
;	ID CHECKS, SET UP
;
	LD	A,(HDSECB + IDFLGO)	;FETCH FLAGS
	LD	(IX+DTFLG),A

HDNTID:	LD	HL,HDSECB		;WRITE ID SECTOR TO HOST
	CALL	HDHSTW
	CALL	CLRBUFR		;FLUSH BUFFER OF IOPB SECTOR (DON'T CARE)

HDLOG1:	XOR	A
	RET


;--------------------------------------
;
;	READ DEBLOCKED SECTOR COMMAND
;
;--------------------------------------
HDREAD:	CALL	HDSELCT		;IMPLIED SELECT
	RET	C

	LD	IY,LAXCDB	;USE XFER CDB
	CALL	GETLUN
	CALL	GETLAD
	CALL	HDRDBUF
	RET	C

	SELCTBUF

	CALL	HDHSTW		;WRITE TO HOST
	XOR	A		;NO ERRORS
	RET


;--------------------------------------
;
;	WRITE SECTOR COMMAND
;
;--------------------------------------
HDWRT:	CALL	HDSELCT		;IMPLIED SELECT
	RET	C

	LD	IY,LAXCDB	;USE XFER CDB
	CALL	GETLUN
	CALL	GETLAD

	CALL	HDRDBUF		;REFRESH BUFFER WITH SECTOR DATA
	RET	C

	SELCTBUF

	CALL	HDHSTR		;READ HOST BUFFER
	JP	HDWRBUF		;WRITE TO DISK


;--------------------------------------
;
;	FORMAT TRACK COMMAND
;
;--------------------------------------
HDFORM:	CALL	HDSELCT		;IMPLIED SELECT
	RET	C

	LD	IY,LAXCDB	;ELSE USE XFER CDB
	LD	(IY + CMD),SCFMTT

	LD	A,(PBSEC)	;SECTOR BYTE HAS INTERLEAVE FACTOR
	AND	00011111B	;MASK OFF HEAD BITS
	LD	(IY+ILV),A

	XOR	A		;FORCE SECTOR TO 0 FOR CLEANLINESS
	LD	(PBSEC),A

	CALL	GETLUN		;GET DRIVE
	CALL	GETLAD		;GET LOGICAL ADDRESS


	CALL	XCDB6
	RET	C		;ERR?

	LD	(IY+ILV),0	;RESTORE ILV BYTE TO 0

	JP	GETRES		;FINISH UP


;--------------------------------------
;
;	RECAL COMMAND
;
;--------------------------------------
HDRECAL:
	CALL	HDSELCT
	RET	C

	JP	RECALC


;--------------------------------------
;
;	SEEK COMMAND
;
;--------------------------------------
HDSEEK:	CALL	HDSELCT		;IMPLIED SELECT
	RET	C

	LD	IY,LAXCDB	;USE XFER CDB
	LD	(IY+CMD),SCSEEK	;SEEK COMMAND
	CALL	GETLUN
	CALL	GETLAD		;GET USER'S BLOCK
	CALL	XCDB6		;SEND CDB
	RET	C

	JP	GETRES		;GET ANY ERRORS


;------------------------------------------------
;
;	DEFINE FLOPPY DISK PARAMS COMMAND
;
;------------------------------------------------
HDDEFF:	LD	IY,NULCDB	;USE NUL CDB
	LD	(IY+CMD),SCDEF	;DEFINE CMD
	CALL	GETLUN

	LD	A,(PBSEC)	;USE SECTOR BYTE TO PASS FLOPPY DEFINITION
	LD	(IY + FDD),A	;SET DEFINE BYTE TO SIDES & DENSITY

	CALL	XCDB6		;EXECUTE
	RET	C

	JP	GETRES		;IF ERR THEN OUTPUT IT

	SUBTTL	HARD DISK SUBROUTINES
;**************************************
;
;	CLEAR CONTROLLER SUBR
;
;**************************************
INIT:	LD	IX,HDDMY	;INIT DUMMY DISK DRIVE TABLE ENTRY PTR

	LD	HL,DTIMG	;MOVE DEFAULT DRIVE TABLES TO RAM
	LD	DE,HDDTBL
	LD	BC,DTICNT
	LDIR

	LD	HL,NULCDB	;ZERO CDBS
	LD	B,CDBINIT
INITRAM:
	LD	(HL),0
	INC	HL
	DJNZ	INITRAM

	LD	A,1 SHL SRESET	;RESET CONTROLLER
	OUT	SASICMD,A

	EX	(SP),HL		;GIVE A LITTLE EXTRA TIME
	EX	(SP),HL

	LD	A,1 SHL SERRCLR	;RELEASE RESET
	OUT	SASICMD,A

	CALL	CLRBUFR		;START WITH FRESH BUFFER READ

	HSTIN	DDPORT		;FETCH FDC ADDRESS
	AND	DDSASW
	RLCA
	OR	HIGH DDBASE
	LD	H,A
	LD	L,0
	LD	(FDADDR),HL
	RET


;++++++++++++++++++++++++++++++++++++++
;
;	SELECT DRIVE FUNCTION
;	EXIT -	CY= NC: NORMAL
;		    CF: ERROR, A= CODE
;
;++++++++++++++++++++++++++++++++++++++
HDSELCT:
	LD	A,(PBDRV)	;IF REQUESTED DRIVE = CURRENT DRIVE THEN
	SUB	A,HDBASD
	AND	00000011B
	SUB	A,(IX+DTDRV)
	RET	Z		;   RETURN

	LD	IY,NULCDB	;USE NUL CDB
	LD	(IY+CMD),SCRDY	;TEST READY COMMAND

	CALL	GETLUN		;REQUEST LUN FROM USER
	CALL	XCDB6		;EXECUTE CDB
	JR	C,SELERR

	CALL	GETRES		;GET RESULT BYTE
	JR	C,SELERR

	LD	A,(LUNSV)	;SELECT DRIVE TABLE
	ADD	A,A
	ADD	A,A
	LD	IX,HDDTBL
	LD	E,A
	LD	D,0
	ADD	IX,DE

	XOR	A		;NO ERRORS
	RET

SELERR:
	LD	IX,HDDMY	;IF DRIVE SELECT ERR THEN POINT TO DUMMY
	RET			;   RETURN SELECT ERROR


;**************************************
;
;	READ HD SECTOR INTO BUFFER SUBR
;	ENTRY-	IY= CDB PTR
;		CDB= SET UP
;	EXIT -	CF= ERROR
;
;**************************************
HDRDBUF:
	CALL	QBUFR		;IF BUFFER DATA VALID THEN SKIP READ
	RET	Z

	LD	C,10		;ASSUME RETRIES
	LD	HL,PBFLG

	LD	A,(HL)		;FETCH FLAGS
	BIT	PBRTRY,A
	JR	Z,HDRTRY1

	LD	C,0
HDRTRY1:
	LD	A,C
	LD	(RETRYS),A

	LD	A,(HL)		;CHECK FOR CONTROLLER RETRY DISABLE
	RLA
	OR	(HL)
	AND	80H
	LD	(IY + RTY),A

HDRDRTY:
	LD	(IY+CMD),SCREAD	;READ COMMAND
	LD	(IY+NBK),1	;ALLWAYS USE 1 BLOCK (SECTOR)

	CALL	XCDB6		;SEND CDB
	RET	C

	LD	BC,[HDBUFSZ * 256] + SASIDATA	;SET COUNT, PORT
	LD	HL,HDSECB

HDRDLP:
	CALL	GETSTAT		;IF NOT READY THEN WAIT
	BIT	SREQ,A
	JR	Z,HDRDLP

	AND	SSXMSK		;   IF DATA READY THEN GET IT
	CP	SSNDDAT
	JP	Z,HDRD2

	CP	SSNDST		;   ELSE IF NOT READY FOR STATUS THEN ERR
	JR	NZ,HDRWFER

HDRDDN:	CALL	GETRES
	PUSH	AF
	CALL	NC,MAKSAME	;MAKE BUFFER PTRS REFLECT DISK DATA
	POP	AF
	RET	NC

	PUSH	AF		;SAVE ERROR CODE
	LD	A,(RETRYS)
	SUB	A,1
	LD	(RETRYS),A
	JR	C,HDRDNOT

	POP	AF
	JP	HDRDRTY

HDRDNOT:
	CALL	CLRBUFR		;BUFFER CONTAMINATED
	POP	AF
	RET


HDRD2:	INI			;*PTR++ = SASI DATA; CNT--
	JP	NZ,HDRDLP

HDRDOV:	CALL	GETSTAT		;IF READY THEN INPUT DATA
	BIT	SREQ,A
	JR	Z,HDRDOV

	AND	SSXMSK
	CP	SSNDST		;IF READY FOR STATUS THEN GET IT
	JP	Z,HDRDDN
HDWASTE:
	CALL	HDXWST		;OVERFLOW, WASTE DATA
	CALL	GETRES		;FINISH UP
HDRWFER:
	CALL	CLRBUFR		;BUFFER CONTAMINATED
	LD	A,FERR08	;   UNKNOWN CONDITION, USE HANDSHAKE
	SCF
	RET


;**************************************
;
;	WRITE HD SECTOR FROM BUFFER SUBR
;	ENTRY-	IY= CDB PTR
;		CDB= SET UP
;
;**************************************
HDWRBUF:
	LD	(IY+CMD),SCWRIT	;WRITE COMMAND

	LD	(IY+NBK),1	;ALLWAYS USE 1 BLOCK (SECTOR)
	CALL	XCDB6		;SEND CDB
	RET	C

	LD	BC,[HDBUFSZ * 256] + SASIDATA	;SET COUNT, PORT
	LD	HL,HDSECB

HDWRLP:	CALL	GETSTAT		;IF READY THEN
	BIT	SREQ,A
	JR	Z,HDWRLP

	AND	SSXMSK		;   IF DATA READY THEN PUT IT
	CP	SGTDAT
	JP	Z,HDWR2

	CP	SSNDST		;   ELSE IF READY FOR STATUS THEN GET IT
	JP	NZ,HDRWFER	;   ELSE UNKNOWN CONDITION!

	JP	GETRES


HDWR2:	OUTI			;SASI DATA = *PTR++; CNT--
	JP	NZ,HDWRLP

HDWROV:	CALL	GETSTAT		;OVERFLOW, WASTE DATA
	BIT	SREQ,A
	JR	Z,HDWROV

	AND	SSXMSK
	CP	SSNDST
	JP	NZ,HDWASTE	;IF NOT STATUS THEN WASTE DATA

	JP	GETRES


;++++++++++++++++++++++++++++++++++++++
;
;	QUERY BUFFER THE SAME FUNCTION
;	EXIT -	ZF= SAME
;		NZ= NOT SAME
;
;++++++++++++++++++++++++++++++++++++++
QBUFR:	LD	A,(PBDRV)	;CHECK DRIVE 1ST
	LD	HL,BUFDRV
	CP	(HL)
	RET	NZ

	LD	DE,(PBSEC)	;NOW CHECK SECTOR
	OR	A		;IF DRIVE 0 THEN SKIP TRACK TEST
	JR	Z,QBBLK

	LD	A,(PBTRK)	;IF TRACK 0 OF FLOPPY THEN NO BLOCKING
	OR	A
	JR	Z,QBNBLK

QBBLK:	RES	0,E		;CLEAR BLOCKING BIT

QBNBLK:	LD	HL,(BUFSEC)
	SBC	HL,DE
	RET	NZ

	LD	DE,(PBTRK)	;LAST, CHECK TRACK
	LD	HL,(BUFTRK)
	SBC	HL,DE
	RET


;**************************************
;
;	CLEAR BUFFER SUBR
;
;**************************************
CLRBUFR:
	LD	A,-1
	LD	(BUFDRV),A
	RET


;**************************************
;
;	MAKE BUFFER PTRS = PB PTRS
;
;**************************************
MAKSAME:
	LD	A,(PBDRV)
	LD	(BUFDRV),A
	LD	HL,(PBTRK)
	LD	(BUFTRK),HL
	LD	HL,(PBSEC)
	RES	0,L
	LD	(BUFSEC),HL
	RET


;**************************************
;
;	READ DATA FROM HOST IOPB SUBR
;	ENTRY-	HL= DESTINATION PTR
;
;**************************************
HDHSTR:	LD	DE,(PBDMA)	;GET DESTINATION PTR
	LD	A,(PBDMAX)	;SET BANK REGISTER
	LD	BC,128		;MOVE 128 BYTES


;**************************************
;
;	BLOCK MOVE FROM HOST SUBR
;	ENTRY-	HL= LOCAL PTR (DST)
;		DE= HOST PTR (SRC)
;		BC= BYTE COUNT
;		A= BANK ADDRESS (SRC)
;
;**************************************
MOVFHST:
	LD	(MOVX),A	;SAVE EXTENDED ADDRESS FOR BUMPING
	OUT	(HXADDR),A

	XOR	A		;TRANSFER FROM S100
	EX	AF,AF'
	JP	MOVIT


;**************************************
;
;	WRITE DATA TO HOST IOPB SUBR
;	ENTRY-	HL= SOURCE PTR
;
;**************************************
HDHSTW:	LD	DE,(PBDMA)	;GET DESTINATION PTR
	LD	A,(PBDMAX)	;SET BANK REGISTER
	LD	BC,128		;MOVE 128 BYTES
	

;**************************************
;
;	BLOCK MOVE TO HOST SUBR
;	ENTRY-	HL= LOCAL PTR (SRC)
;		DE= HOST PTR (DST)
;		BC= BYTE COUNT
;		A= BANK ADDRESS (DST)
;
;**************************************
MOV2HST:
	LD	(MOVX),A	;SAVE EXTENDED ADDRESS VALUE FOR BUMPING
	LD	(HXADDR),A

	LD	A,1		;TRANSFER TO S100
	OR	A
	EX	AF,AF'


;********************************************************************
;
;	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 PTR
;		DE= S100 MEMORY PTR
;		BC= BYTE COUNT TO TRANSFER
;		AF'= 0: XFER FROM S100 MEMORY TO LOCAL MEMORY
;		     1: XFER FROM LOCAL MEMORY TO S100 MEMORY
;
;	EXIT -	AF, AF'= ?
;		BC= 0
;		HL= HL + BC
;		DE= DE + BC
;
;********************************************************************
MOVIT:	EX	AF,AF'		;SET FLAGS
	OR	A
	EX	AF,AF'

	LD	A,D		;SET BIT 15
	OUT	(HXAD15),A

	DEC	BC		;IF > 32K MOVE THEN DO LONG WAY
	LD	A,B
	CP	32768 / 256
	JR	NC,DOLONG

	LD	A,E		;IF 64K CROSS THEN DO LONG WAY
	ADD	C
	LD	A,D
	ADC	B
	JR	C,DOLONG

	XOR	D		;IF 32K CROSS THEN DO LONG WAY
	JP	M,DOLONG

	INC	BC		;RESTORE COUNT

	SET	7,D		;INSURE S100 MAP

	EX	AF,AF'		;IF FROM S100 THEN
	JP	NZ,MOV1
	EX	DE,HL		;  SWAP

MOV1:	LDIR

	JP	NZ,MOV6
	EX	DE,HL		;  SWAP BACK

MOV6:	EX	AF,AF'
	XOR	A
	RET

;
;	LONG TRANSFER PART TESTS EACH BYTE FOR THRESHOLDS
;
DOLONG:	INC	BC		;RESTORE COUNT
	LD	A,D		;SET UP CURRENT BIT 15
	LD	I,A

NO64KX:	SET	7,D		;INSURE S100

MOV4:	EX	AF,AF'		;IF HL= S100 THEN
	JP	NZ,MOV2
	EX	DE,HL
MOV2:	LDI
	JP	NZ,MOV3
	EX	DE,HL
MOV3:	JP	PO,MOV5		;IF DONE THEN RETURN

	EX	AF,AF'
	BIT	7,D		;IF NOT ROLLOVER THEN REPEAT
	JP	NZ,MOV4

	LD	A,I		;TOGGLE BIT 15
	XOR	80H
	LD	I,A
	OUT	(HXAD15),A

	BIT	7,A		;IF TOGGLED TO 0 THEN BUMP BANK
	JP	NZ,NO64KX

	LD	A,(MOVX)
	INC	A
	LD	(MOVX),A
	OUT	(HXADDR),A
	JP	NO64KX

MOV5:	EX	AF,AF'		;BALANCE UP
	XOR	A
	RET


;**************************************
;
;	WASTE OVERFLOW DATA SUBR
;
;**************************************
HDXWST:	CALL	GETSTAT		;IF READY THEN INPUT DATA
	BIT	SREQ,A
	JR	Z,HDXWST

	AND	SSXMSK
	CP	SSNDST		;IF READY FOR STATUS THEN GET IT
	RET	Z

	LD	A,0E5H		;OUTPUT WILL ALSO DO FOR INPUT
	OUT	SASIDATA,A
	JR	HDXWST


;**************************************
;
;	RECALIBRATE SUBR
;
;**************************************
RECALC:	LD	IY,NULCDB
	LD	(IY+CMD),SCREC		;RECAL COMMAND
	CALL	GETLUN

	CALL	XCDB6
	JP	GETRES		;FINISH UP


;+++++++++++++++++++++++++++++++++++++
;
;	GET STATUS FUNCTION
;	EXIT-	A= STATUS WORD
;
;+++++++++++++++++++++++++++++++++++++
GETSTAT:
	IN	A,SASIST	;GET STATUS WORD
	AND	SSTMSK		;REMOVE UNUSED BITS
	XOR	SSTINV		;INVERT SOME
	RET


;++++++++++++++++++++++++++++++++++++++
;
;	TRANSMIT CDB FUNCTION
;	ENTRY-	(CDBPTR)= CDB TO XMIT
;	EXIT -	CF= ERROR
;		BC= ?
;
;++++++++++++++++++++++++++++++++++++++
XCDB6:
;
;	ISSUE CONTROLLER SELECT PER SHUGART MANUAL
;
	LD	A,[1 SHL HDCONT]	;SELECT DB0
	OUT	SASIDATA,A

	LD	A,[1 SHL SSELECT] OR [1 SHL SERRCLR]	;OUTPUT STROBE
	OUT	SASICMD,A

	LD	BC,0		;TIMEOUT

BSYWT2:	CALL	GETSTAT		;WAIT FOR BUSY
	BIT	SBUSY,A
	JR	NZ,BSYOK2

	DEC	BC
	LD	A,C
	OR	B
	JR	NZ,BSYWT2

	LD	A,FERR07	;HANDSHAKE TIMEOUT ERR
	SCF
	RET

BSYOK2:	LD	A,1 SHL SERRCLR		;REMOVE SELECT STROBE
	OUT	SASICMD,A

XCDB2:	CALL	GETSTAT		;CHECK FOR COMMAND ACCEPT
	BIT	SREQ,A		; WAIT FOR REQUEST
	JR	Z,XCDB2

	BIT	SCD,A		;IF NOT COMMAND THEN ???
	JR	NZ,XOK

XCDBER:	LD	A,FERR08	;CONTROLLER SYNC ERROR
	SCF
	RET

XOK:	LD	BC,[6 * 256] + SASIDATA		;BYTE COUNT IN B

	BIT	SIO,A		;IF DIRECTION NOT OUT THEN ERR
	JR	NZ,XCDBER

	PUSH	IY
	POP	HL

XCDB3:	PUTDATA			;GET CDB DATA
	JR	NZ,XCDB3

	XOR	A		;RETURN NO ERRORS
	RET


;++++++++++++++++++++++++++++++++++++++
;
;	GET CONTROLLER RESULTS FUNCTION
;	EXIT -	CF= HARD ERROR
;
;++++++++++++++++++++++++++++++++++++++
GETRES:	LD	HL,RSTAT	;INSURE DESTINATION CORRECT
	LD	C,SASIDATA
	GETDATA			;GET RESULT STATUS BYTE

				;CHECK FOR HARDWARE PARITY ERROR
	BIT	SPERR,A
	JR	NZ,HDPERR

	LD	A,(RSTAT)	;IF ERROR THEN GO REQUEST STATUS
	AND	00000011B
	RET	Z

	BIT	1,A		;IF CONTROLLER PARITY ERROR THEN EXIT
	JR	Z,HDPERR

	LD	(IY+CMD),SCSNSE	;REQUEST SENSE COMMAND
	CALL	XCDB6
	RET	C

GETR1:	LD	HL,PBSTAT	;READ SENSE STATUS BYTES
	LD	BC,[4 * 256] + SASIDATA		;4 BYTES

GETR2:	GETDATA
	JR	NZ,GETR2

GETR3:	CALL	GETSTAT		;FINISH OUT COMMAND
	BIT	SREQ,A
	JR	Z,GETR3

	IN	A,(C)		;GET RESULT BYTE OF COMMAND
	AND	00000011B	;IF ERROR THEN HARD ERROR
	SCF			;ERROR ANYWAY
	RET	Z

	LD	A,FERR09	;SENSE STATUS ERROR
	RET

HDPERR:	XOR	A		;CLEAR ERROR
	OUT	(SASICMD),A
	LD	A,1 SHL SERRCLR
	OUT	(SASICMD),A

	LD	A,FERR11	;RETURN PARITY ERROR
	SCF
	RET


;++++++++++++++++++++++++++++++++++++++
;
;	GET LUN FROM USER FUNCTION
;	ENTRY-	IY= CDB PTR
;	EXIT -	IY, HL= CDB PTR
;		BC, DE, AF= ?
;
;++++++++++++++++++++++++++++++++++++++
GETLUN:	LD	(CDBPTR),IY	;SAVE CDB PTR

	LD	A,(PBDRV)	;FETCH DRIVE #
	SUB	A,HDBASD
	AND	00000011B
	LD	(LUNSV),A	;SAVE IT FOR OTHERS

	RRCA			;PUT IN PROPER FIELD
	RRCA
	RRCA
	LD	(NULCDB + LUN), A
	LD	(LAXCDB + LUN), A
	LD	(IDRCDB + LUN), A

	LD	HL,(CDBPTR)	;RETURN CDB PTR
	RET


;*******************************************
;
;	GET LOGICAL ADDR FROM IOPB SUBR
;	ENTRY-	IY= CDB PTR
;		IX= DRIVE TABLE PTR
;
;*******************************************
GETLAD:	BIT	DFHARD,(IX + DTFLG)	;IF HARD DISK THEN SPLIT
	JR	NZ,HDLAX

;--------------------------------------
;
;	FLOPPY DISK LAD CALCULATION
;
;--------------------------------------
	LD	HL,128		;ASSUME SECTOR SIZE OF 128 BYTES

	LD	A,(PBTRK)	;IF TRACK 00 THEN USE 128
	JR	Z,GETLAD1

	BIT	DFDBL,(IX + DTFLG)	;IF SINGLE DENSITY THEN USE 128
	JR	Z,GETLAD1

	ADD	HL,HL		;ELSE USE 256
GETLAD1:
	LD	(BYTCNT),HL

	LD	DE,(PBTRK)	;GET TRACK
	LD	A,76		;CHECK LIMITS
	SUB	A,D
	JR	C,PARERR
	
	PUSH	DE		;LA = TRACK * 26 + SECTOR
	POP	HL
	ADD	HL,HL		;X * 26 = 8X + 5X * 2
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,DE		;	+5X
	ADD	HL,DE
	ADD	HL,DE
	ADD	HL,DE
	ADD	HL,DE
	ADD	HL,HL		;	* 2

	LD	A,(PBSEC)	;FETCH SECTOR
	LD	E,A
	LD	A,26		;CHECK FOR LIMIT
	SUB	A,E
	JR	NC,SECOK

PARERR:	LD	A,FERR10	;ILLEGAL PARAMETER
	SCF
	RET

SECOK:	ADD	HL,DE		;ADD IN SECTOR

	BIT	DFT0D,(IX + DTFLG)	;IF DOUBLE DENSITY THEN LESS 26
	JR	Z,HDFDOK

	LD	DE,26
	SBC	HL,DE

HDFDOK:	LD	(IY+LA0),L
	LD	(IY+LA1),H

	XOR	A		;RETURN NO ERRORS
	RET

;----------------------------
;
;	SET UP HARD DISK CDB
;
;----------------------------
HDLAX:	LD	HL,256		;SECTOR SIZE
	LD	(BYTCNT),HL

	LD	A,(PBSEC)	;FETCH SECTOR
	LD	E,A

	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

	XOR	A		;RETURN NO ERRORS
	RET

	SUBTTL	CONSTANTS
;##########################################################
;
;	INITIAL DISK DRIVE TABLES ARE MOVED TO RAM BY INIT
;
;##########################################################
DTIMG:	DB	0,0,0,01100000B	;LUN0
	DB	1,0,0,0		;LUN1
	DB	2,0,0,0		;LUN2
	DB	3,0,0,0		;LUN3
	DB	-1,0,0,0	;DUMMY DRIVE TABLE USED ON ERROR
DTICNT	EQU	$ - DTIMG

;#######################
;
;	ID SECTOR TEXT
;
;#######################
IDTXT	DB	'Jade DD '
IDSZE	EQU	$ - IDTXT

	IF	$ >= (LOCROM + ROMSIZE)
;############################
;
;	PROTECTION MESSAGE
;
;############################
	CONMSG	**** ERROR! CODE TOO LARGE FOR DECLARED PROM SIZE! ****
	ENDIF

	SUBTTL	RAM AREA
	ORG	LOCRAM
;############################
;
;	VARIABLES
;
;############################
IOPBL	DS	1		;LOW ADDRESS OF IOPB TO EXECUTE
IOPBH	DS	1		;HIGH ADDRESS OF IOPB
IOPBXA	DS	1		;BANK ADDRESS OF IOPB

;######################################
;
;	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

RSTAT	DS	1	;COMMAND STATUS RETURNED
			;BIT 1: ERROR (ISSUE SENSE COMMAND)
			;BIT 5..7: LUN
BUFDRV	DS	1	;BUFFER CONTENTS DRIVE BYTE
BUFSEC	DS	2	;BUFFER CONTENTS SECTOR WORD
BUFTRK	DS	2	;BUFFER CONTENTS TRACK WORD

;######################################
;
;	JADE SECTOR BUFFER
;
;######################################
JADSECB	DS	256


;######################################
;
;	JADE COMMAND BLOCK
;
;######################################
BTCMD	DS	1	;COMMAND
BTDRV	DS	1	;DRIVE
BTTRK	DS	1	;TRACK
BTSEC	DS	1	;SECTOR
	DS	2	;SPARES
BTMOD	DS	1	;MODE (FLAGS)
BTSTS	DS	1	;STATUS
BTLAD	DS	2	;BIOS LOAD ADDR
BTLNG	DS	2	;BIOS LENGTH


;##########################################################
;
;	DISK CONTROLLER COMMAND DESCRIPTOR BLOCKS (CDB)
;
;##########################################################
CDBPTR	DS	2		;PTR TO CURRENT COMMAND 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	1	;LOGICAL ADDRESS 2 IN BITS 0..4
LA1	EQU	2	;LOGICAL ADDRESS 1
LA0	EQU	3	;LOGICAL ADDRESS 0
ILV	EQU	4	;FORMAT COMMAND INTERLEAVE FACTOR
NBK	EQU	4	;XFER COMMANDS BLOCK (SECTOR) COUNT
RTY	EQU	5	;RETRY FLAG 0: RETRY 3 TIMES, 80H: NO RETRYS
LUND	EQU	5	;COPY COMMAND DEST. LUN IN BITS 5..7
LA2D	EQU	5	;COPY COMMAND DEST. LOGICAL ADDR 2 IN BITS 0..4
FDD	EQU	5	;DEFINE FLOPPY PARAMS COMMAND
			;BIT 0: 0= SINGLE SIDE, 1= DOUBLE SIDED
			;BIT 1: 0= SINGLE DENSITY, 1= DOUBLE DENSITY
			;BITS 2..3: 00= 128 BYTES, 01= 256 BYTES
LA1D	EQU	6	;COPY COMMAND DEST. LOGICAL ADDR 1
LA0D	EQU	7	;COPY COMMAND DEST. LOGICAL ADDR 0
RTYD	EQU	9	;COPY COMMAND RETRY FLAG

ERRCOD	DS	1


;#######################
;
;	DRIVE TABLES
;
;#######################
HDDTBL:
	DS	4	;HD PHYSICAL DRIVE 0
	DS	4	;		   1
	DS	4	;		   2
	DS	4	;		   3
HDDMY	DS	4	;DUMMY
;
DTDRV	EQU	0	;DRIVE BYTE OFFSET
;
DTVEC	EQU	1	;DRIVE VECTOR OFFSET
DTFLG	EQU	3	;DRIVE FLAGS OFFSET

;#######################
;
;  DISCRETE VARIABLES
;
;#######################
LUNSV	DS	1	;LUN #
BYTCNT	DS	2	;SECTOR SIZE
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


;------------------
;
;	STACK AREA
;
;------------------
	IF	$ > (LOCRAM + RAMSIZE - 32)
	CONMSG	**** ERROR! DATA TOO LARGE FOR DECLARED RAM SIZE! ****
	ENDIF
	DS	32
STACK	EQU	LOCRAM + RAMSIZE

	END
