;******************************************************
;						      *
;	PROGRAM ID:     DOUBLE D BOOTSTRAP (DDBOOT)   *
;						      *
;******************************************************
;						      *
;	VERSION:	CP/M  2.2    RELEASE 2	      *
;						      *
;******************************************************
;						      *
;	DISTRIBUTOR:	JADE COMPUTER PRODUCTS	      *
;			4901 W. ROSECRANS BLVD.	      *
;			HAWTHORNE, CALIFORNIA	      *
;			90250,   U.S.A.		      *
;						      *
;************************************************SK****


;******************************************************
; THE DOUBLE D BOOTSTRAP PROGRAM  (DDBOOT) IS USED TO *
; INITIATE THE SYSTEM TRACKS LOAD SEQUENCE FROM DRIVE *
; A (OR 0) AND TO PROVIDE CONSOLE I/0 SUBROUTINES FOR *
; THE DISK OPERATING SYSTEM (CP/M).  THIS PROM SHOULD *
; BE LOCATED AT F000 HEX.  THE SOURCE CODE FOR DDBOOT *
; CAN BE  ASSEMBLED  WITH  DIGITAL RESEARCH ASSEMBLER *
; ASM.COM.  MACHINE CODE IS  8080/8085/Z80 COMPATABLE *
;******************************************************


;******************************************************
; DDBOOT INJECTION MODULE IS COMMAND  COMPATABLE WITH *
; THE FOLLOWING  WESTERN  DIGITAL  CONTROLLER  CHIPS. *
; DOUBLE D  USER SWITCH 0  (U0 OR R0)  MUST BE SET TO *
; INDICATE THE  CONTROLLER CHIP  DATA  BUS  POLARITY. *
;******************************************************
;	CONTROLLER IC    	USER SW0	      *
;	-------------    	--------	      *
;	FD1791-02 (01)    	 CLOSED		      *
;	FD1793-02 (01)    	 OPENED		      *
;	FD1795-02         	 CLOSED		      *
;	FD1797-02         	 OPENED		      *
;******************************************************
; THE FD1795-02 AND FD1797-02 PROVIDE ENHANCED SINGLE *
; DENSITY PERFORMANCE IN THAT  THESE  CHIPS ARE FULLY *
; COMPATABLE WITH FD1771-01 3740 FORMATS.	      *
;******************************************************


;******************************************************
; CBIOS SCRATCH   ******   SYSTEM MEMORY ALLOCATION   *
;******************************************************
;  ADDRESS	NAME	  FUNCTION		      *
;  -------	----	  --------		      *
;  0040-41	D$ADDR	  ADDRESS POINTER TO DOUBLE D *
;  0042		D$MASK	  STATUS PORT HALT BIT MASK   *
;  0043		D$TEMP	  TEMPORARY, INSERT DISK MSG  *
;******************************************************


;******************************************************
; MODIFICATION MAY BE NEEDED.  THIS PROM PROVIDES THE *
; CONSOLE STATUS, INPUT, AND OUTPUT SUBROUTINES. MANY *
; END USER SYSTEMS REQUIRE UART / USART AND BAUD RATE *
; GENERATOR INITIALIZATION. THESE  ROUTINES  MAY NEED *
; TO BE PATCHED TO PROVIDE FOR PROPER CONSOLE LINKAGE *
; PATCHING MAY ALSO BE DONE FOR SOME DISK DRIVES.     *
;******************************************************
;      PROM LOCATIONS THAT MAY NEED PATCHING	      *
;******************************************************
; SYSTEM INITIALIZATION - UART/USART, BAUD RATE, AND  *
; AND POWER ON JUMP CIRCUITRY MAY REQUIRE SOFTWARE    *
; INITIALIZATION. A PATCH AREA IS RESERVED AT "INIT"  *
;******************************************************
; CONSOLE STATUS CHECK - RETURNS KEYBOARD STATUS TO   *
; CP/M OPERATING SYSTEM.  THIS SUBROUTINE MUST USE    *
; THE CORRECT PORT ADDRESS AND TEST PROPER STATUS BIT.*
; ROUTINE IS LABELED "CNS$CK" AND CONTAINS PATCH AREA.*
;******************************************************
; CONSOLE INPUT - RETURNS KEYBOARD CHARACTER TO CP/M  *
; OPERATING SYSTEM.  THIS ROUTINE MUST ALSO USE THE   *
; CORRECT PORT ADDRESSING.   THIS ROUTINE IS LABELED  *
; "CNS$IN" AND CONTAINS A PATCH AREA.		      *
;******************************************************
; CONSOLE OUTPUT - DISPLAYS CHARACTER TO CONSOLE UNIT.*
; THIS ROUTINE MUST USE THE CORRECT PORT ADDRESS FOR  *
; BOTH THE OUTPUT STATUS AND OUTPUT DATA PORTS.  THIS *
; ROUTINE MUST TEST THE CONSOLE OUTPUT STATUS BIT.    *
; THIS ROUTINE IS LABELED  "CNS$OT"  AND CONTAINS A   *
; PATCH AREA.					      *
;******************************************************
; BOARD REVISION - NOTE SOURCE FILE HAS CONDITIONAL   *
; STATEMENTS FOR BOARD REVISION.  REVISION B BOARDS   *
; MAY BE MODIFIED TO ACT AS REV-C (CALL JADE) OR      *
; DDBOOT MAY BE PATCHED. PROM IS FOR REV-C.	      *
; --------------------------------------------------- *
; ADDRESS  NAME    FUNCTION       REV-C    REV-B      *
; -------  ----    --------       -----    -----      *
;  F040	   DS$ASW  ADDR SW MASK	   0E       0C	      *
;  F043    D$BASE  ADDR 8K RANGE   E0       E4 **     *
;  F04B    DS$HLT  DD HALT BIT     01       02        *
; --------------------------------------------------- *
;  ** SHOULD BE "E0" IF MA10 JUMPER IS INSTALLED.     *
;******************************************************
; DISK DRIVES - DDBOOT IS USING A 10 MILLISECOND STEP *
; WHICH WILL HOME THE R/W HEAD ON MOST DRIVES. IF THE *
; USER DRIVE IS MUCH FASTER (SHUGART SA850 OR SIEMENS *
; FD100-8D) THEN THE STEP RATE CONSTANT MAY BE PATCHED*
; NOTE: A DDBOOT PROM PATCHED FOR FAST DRIVES WILL    *
; NOT  FUNCTION  PROPERLY  IF LATER USED WITH  SLOWER *
; DRIVES.  SLOWER STEPS SHOULD ALWAYS WORK.  A DELAY  *
; BEFORE READING HAS BEEN PROVIDED FOR HEAD LOAD TIME *
; AND CAN BE USED FOR DRIVE-MOTOR START UP TIME WHEN  *
; THE DRIVE MOTORS ARE CONTROLLED BY THE DOUBLE-D.    *
; --------------------------------------------------- *
; ADDRESS     NAME        FUNCTION		      *
; -------     ----        --------		      *
; F1CE-F1CF   IM$TM$STP   STEP TIME		      *
; F1F7-F1F8   IM$TM$DBR   DELAY BEFORE READ	      *
;******************************************************


;******************************************************
; DOUBLE D BOOTSTRAP SYSTEM ADDRESS		      *
;******************************************************

PROM$ADDR	EQU	0F000H	;DDBOOT SYSTEM ADDRESS.

;******************************************************
; SET DOUBLE D SYSTEM PORT ADDRESS		      *
;******************************************************

D$PORT	EQU	043H	;DOUBLE D PORT ADDRESS.

;******************************************************
; SET USER DOUBLE D BOARD REVISION		      *
;******************************************************

TRUE	EQU	1	;SET TRUE TO LOGIC ONE.
FALSE	EQU	0	;SET FALSE TO LOGIC ZERO
REV$B	EQU	FALSE	;SET TRUE FOR REV B BOARDS.
REV$C	EQU	TRUE	;SET TRUE FOR REV C BOARDS.
MA10	EQU	FALSE	;TRUE IF MA10 JUMPED (REV-B).

;******************************************************
; DEFINE HALT MASK AND BASE ADDRESS OF DOUBLE D       *
;******************************************************

	IF	REV$B
DS$HLT	EQU	002H	;STATUS PORT HALT INDICATOR.
DS$ASW	EQU	00CH	;STATUS PORT ADDR SW MASK.
D$BASE	SET	0E400H	;SYSTEM WINDOW BASE ADDRESS
	ENDIF

	IF	MA10
D$BASE	SET	0E000H	;SYSTEM WINDOW BASE ADDRESS
	ENDIF

	IF	REV$C
DS$HLT	EQU	001H	;STATUS PORT HALT INDICATOR.
DS$ASW	EQU	00EH	;STATUS PORT ADDR SW MASK.
D$BASE	SET	0E000H	;SYSTEM WINDOW BASE ADDRESS
	ENDIF

;******************************************************
; BOOTSTRAP LINKAGE ADDRESS.			      *
;******************************************************

BSTACK	EQU	0080H	;BOOTSTRAP TOP OF STACK.
D$ADDR	EQU	0040H	;DOUBLE D ADDRESS POINTER.
D$MASK	EQU	0042H	;DOUBLE D HALT BIT ADDR.
D$TEMP	EQU	0043H	;DDBOOT TEMPORARY LOCATION.
BL$DCS	EQU	0377H	;DCM DISK CONTROLLER STATUS.
BL$ADR	EQU	0378H	;DCM LOAD AND JUMP ADDR PNTR.
BL$BSZ	EQU	037AH	;DCM BLOCK LOAD SIZE.
BL$DNR	EQU	0080H	;DRIVE NOT READY BIT.

;******************************************************
; DOUBLE D HARDWARE COMMANDS			      *
;******************************************************

DC$BGN	EQU	080H	;RESET Z80A AND EXECUTE.
DC$MRQ	EQU	001H	;REQUEST MEMORY WINDOW.
DC$MRT	EQU	000H	;RELEASE MEMORY WINDOW.
DC$MB0	EQU	001H	;SELECT MEMORY BANK 0.
DC$MB1	EQU	003H	;SELECT MEMORY BANK 1.
DC$EXC	EQU	002H	;ISSUE DOUBLE D INTERRUPT.

;******************************************************
; ASSEMBLER DIRECTIVES				      *
;******************************************************

	ORG	PROM$ADDR	;MODULE ADDRESS.

;******************************************************
; DDBOOT FUNCTIONS VECTOR TABLE			      *
;******************************************************

	JMP	INIT		;INITIALIZE AND BOOT.
	JMP	BOOT		;REBOOT DISK SYSTEM.
	JMP	CNS$CK		;CONSOLE STATUS.
	JMP	CNS$IN		;CONSOLE INPUT.
	JMP	CNS$OT		;CONSOLE OUTPUT.
	JMP	MSG$OT		;MESSAGE TO CONSOLE.

;******************************************************
; INITIALIZE SYSTEM HARDWARE - USER PATCH AREA	      *
;******************************************************

INIT:	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.
	NOP!NOP!NOP!NOP		;PATCH AREA.

;******************************************************
; SET STACK AND DETERMINE CONTROLLER ADDRESS	      *
;******************************************************

BOOT:	LXI	SP,BSTACK	;SET STACK POINTER.
	IN	D$PORT		;INPUT STATUS PORT.
	ANI	DS$ASW		;MASK FOR ADDR SWS.
	RLC			;POSITION BITS.
	ORI	D$BASE SHR 8	;OR IN BASE ADDR.
	MOV	H,A		;HIGH BYTE VALUE.
	MVI	L,0		;LOW BYTE VALUE.
	SHLD	D$ADDR		;STORE THE ADDRESS
	MVI	A,DS$HLT	;LOAD HALT BIT MASK.
	STA	D$MASK		;STORE FOR BIOS USE.
	STA	D$TEMP		;SET REPEAT FLAG NZ.

;******************************************************
; INJECT BOOT MODULE INTO CONTROLLER		      *
;******************************************************

INJECT:	MVI	A,DC$MB0	;REQUEST DD MEM BANK 0.
	OUT	D$PORT		;ISSUE COMMAND.
	LXI	B,IM$END-IM$BGN	;INJECTION MODULE SIZE.
	XCHG			;D$ADDR HL TO DE.	
	LXI	H,IM$BGN	;INJECTION MODULE ADDR.
	CALL 	BLOCK		;BLOCK MOVE.

;******************************************************
; RESET AND START THE DISK PROCESSOR		      *
;******************************************************

	MVI	A,DC$BGN	;BEGIN DD PROCESSOR.
	OUT	D$PORT		;ISSUE  COMMAND.
	XTHL			;ALLOW DOUBLE D TIME
	XTHL			;TO START UP.

;******************************************************
; WAIT FOR TASK COMPLETION			      *
;******************************************************

	LDA	D$MASK		;HALT BIT MASK.
	MOV	B,A		;MOVE INTO B REG.
WAIT:	IN	D$PORT		;INPUT DD STATUS.
	ANA	B		;TEST HALT* STATUS.
	JNZ	WAIT		;WAIT TILL HALTED.

;******************************************************
; SWITCH CONTROLLER MEMORY INTO SYSTEM BUS	      *
;******************************************************

	MVI	A,DC$MRQ	;REQUEST MEM (BANK 0).
	OUT	D$PORT		;ISSUE COMMAND.

;******************************************************
; CHECK FOR BOOTSTRAP MALFUNCTION		      *
;******************************************************

	LHLD	D$ADDR		;CONTROLLER ADDRESS.
	LXI	D,BL$DCS	;ERROR CODE IM$BGN.
	DAD	D		;SET HL POINTER.
	MOV	A,M		;GET ERROR CODE.
	ANI	BL$DNR		;TEST DRIVE NOT READY.
	JNZ	INSERT		;IF DRIVE NOT READY.
	MOV	A,M		;GET ERROR CODE.
	ANA	A		;TEST REGISTER.
	JNZ	BAD$LD		;BAD LOAD.

;******************************************************
; PERFORM BLOCK TRANSFER FROM DISK MEMORY	      *
;******************************************************

	LHLD	D$ADDR		;CONTROLLER ADDRESS.
	LXI	D,BL$ADR	;LOAD ADDRESS PNTR.
	DAD	D		;SET HL POINTER.
	MOV	E,M		;LOW ORDER ADDR.
	INX	H		;INCREMENT HL.
	MOV	D,M		;HIGH ORDER ADDR.
	INX	H		;REQUIRES BL.BSZ NEXT.
	MOV	C,M		;LOW ORDER LENGTH.
	INX	H		;INCREMENT HL.
	MOV	B,M		;HIGH ORDER LENGTH.
	PUSH	D		;USE AS JUMP ADDR.
	MVI	A,DC$MB1	;SWITCH TO MEM BANK 1.
	OUT	D$PORT		;ISSUE COMMAND.
	LHLD	D$ADDR		;DOUBLE D MEM ADDRESS.
	CALL	BLOCK		;MOVE BIOS MODULE.

;******************************************************
; TRANSFER CONTROL TO OPERATING SYSTEM		      *
;******************************************************

	MVI	A,DC$MB0	;SWITCH TO BANK.0
	OUT	D$PORT		;ISSUE COMMAND.
	RET			;GOTO BIOS COLD ENTRY.

;******************************************************
; BLOCK MOVE SUBROUTINE (Z80 BLOCK MOVE REGISTERS)    *
;******************************************************

BLOCK:	MOV	A,M		;GET BYTE.
	INX	H		;INC POINTER
	XCHG			;GET DESTINATION.
	MOV	M,A		;PUT BYTE.
	INX	H		;INC POINTER
	XCHG			;GET SOURCE.
	DCX	B		;ONE LESS TO DO.
	MOV	A,B		;GET HI COUNT.
	ORA	C		;GET LO COUNT.
	JNZ	BLOCK		;FINISH LOADING.
	RET

;******************************************************
; DISK DRIVE IS NOT READY			      *
;******************************************************

INSERT:	LDA	D$TEMP		;LOAD INIT FLAG.
	ANA	A		;TEST FOR INITIAL.
	JZ	INJECT		;TRY BOOTING AGAIN.
	XRA	A		;ZERO A REGISTER.
	STA	D$TEMP		;CLEAR INITIAL FLAG.
	LXI	H,MSG$IN	;INSERT MESSAGE ADDR.
	CALL	MSG$OT		;OUTPUT MESSAGE.
	JMP	INJECT		;TRY BOOTING AGAIN.

;******************************************************
; DOUBLE D BOOTSTRAP MALFUNCTION		      *
;******************************************************

BAD$LD:	STA	D$TEMP		;STORE ERROR CODE.
	LXI	H,MSG$ER	;ERROR MESSAGE ADDEESS.
	CALL	MSG$OT		;DISPLAY MESSAGE.
	LDA	D$TEMP		;LOAD ERROR CODE.
	CALL	HXB$OT		;DISPLAY HEX BYTE.
	HLT!NOP!NOP		;HALT OR JUMP MONITOR.

;******************************************************
;  CONSOLE INPUT AND OUTPUT			      *
;******************************************************
;						      *
;  XXX$SP:  STATUS PORT ADDRESS			      *
;  XXX$SB:  STATUS READY BIT			      *
;  XXX$SI:  IF READY TRUE IS "1" USE "00" ELSE "FF"   *
;  XXX$DP:  DATA PORT ADDRESS			      *
;						      *
;******************************************************
  
CNI$SP	EQU	000H		;INPUT STATUS PORT.
CNI$SB	EQU	002H		;INPUT STATUS BIT.
CNI$SI	EQU	000H		;INPUT STATUS INVERT.
CNI$DP	EQU	001H		;INPUT DATA PORT.

CNO$SP	EQU	000H		;OUTPUT STATUS PORT.
CNO$SB	EQU	004H		;OUTPUT STATUS BIT.
CNO$SI	EQU	000H		;OUTPUT STATUS INVERT.
CNO$DP	EQU	001H		;OUTPUT DATA PORT.

;******************************************************
; CONSOLE INPUT STATUS CHECK			      *
;******************************************************

CNS$CK:	IN	CNI$SP		;INPUT STATUS PORT.
	XRI	CNI$SI		;ADJUST POLARITY.
	ANI	CNI$SB		;TEST READY BIT.
	RZ			;ZERO IS NOT READY.
	MVI	A,0FFH		;SET CONSOLE READY.
	RET			;ONES INDICATE READY.

	DB	0,0,0,0,0,0	;PATCHING AREA.
	DB	0,0,0,0,0,0	;PATCHING AREA.
	DB	0,0,0,0,0,0	;PATCHING AREA.

;******************************************************
; CONSOLE DATA INPUT				      *
;******************************************************

CNS$IN:	CALL	CNS$CK		;TEST INPUT READY.
	JZ	CNS$IN		;REPEAT TEST FOR RDY.
	IN	CNI$DP		;INPUT CONSOLE DATA.
	ANI	07FH		;SEVEN BITS OF ASCII.
	RET			;RETURN WITH DATA.

	DB	0,0,0,0,0,0	;PATCHING AREA.
	DB	0,0,0,0,0,0	;PATCHING AREA.
	DB	0,0,0,0,0,0	;PATCHING AREA.

;******************************************************
; CONSOLE DATA OUTPUT				      *
;******************************************************

CNS$OT:	IN	CNO$SP		;OUTPUT STATUS PORT.
	XRI	CNO$SI		;ADJUST POLARITY.
	ANI	CNO$SB		;TEST READY BIT.
	JZ	CNS$OT		;TEST AGAIN FOR RDY.
	MOV	A,C		;OUTPUT SETUP.
	OUT	CNO$DP		;OUTPUT CONSOLE DATA.
	RET			;RETURN COMPLETE.

	DB	0,0,0,0,0,0	;PATCHING AREA.
	DB	0,0,0,0,0,0	;PATCHING AREA.
	DB	0,0,0,0,0,0	;PATCHING AREA.


;******************************************************
; MESSAGE DISPLAY ROUTINE - HL REG POINTS TO STRING   *
;******************************************************

MSG$OT:	MOV	A,M		;LOAD CHARACTER/BYTE.
	CPI	'$'		;CHECK FOR TERMINATOR.
	RZ			;EXIT IF TERMINATOR.
	MOV	C,A		;PASS BYTE IN C REG.
	CALL	CNS$OT		;DISPLAY CHARACTER.
	INX	H		;POINT TO NEXT BYTE.
	JMP	MSG$OT		;REPEAT SEQUENCE.

;******************************************************
; DISPLAY A REGISTER IS HEXIDECIMAL		      *
;******************************************************

HXB$OT:	PUSH	PSW		;SAVE A REGISTER.
	RRC!RRC!RRC!RRC		;SHIFT 4 PLACES.
	CALL	HXN$OT		;DISPLAY HEX NIBBLE.
	POP	PSW		;RESTORE A REGISTER.
HXN$OT:	ANI	00FH		;MASK LOWER NIBBLE.
	CPI	00AH		;TEST IF LETTER HEX.
	JC	HXN$NM		;DISPLAY NUMBER.
	ADI	'A'-'9'-1	;ADD LETTER OFFSET.
HXN$NM:	ADI	'0'		;START WITH ASCII 0.
	MOV	C,A		;OUTPUT BYTE TO C REG.
	JMP	CNS$OT		;CONSOLE OUTPUT.

;******************************************************
; SYSTEM BOOTSTRAP MESSAGE AREA    		      *
;******************************************************

MSG$IN:	DB	CR,LF,LF,'INSERT SYSTEM DISKETTE ','$'
MSG$ER:	DB	CR,LF,LF,'DDBOOT LOAD ERROR - ','$'

CR	EQU	00DH		;CARRAIGE RETURN.
LF	EQU	00AH		;LINE FEED COMMAND.

;******************************************************
;******************************************************
; INJECTION MODULE *** THE FOLLOWING EXECECUTES IN DD *
;******************************************************
; THIS SECTION OF CODE IS HAS BEEN WRITTEN WITH	AN    *
; ADDRESS OFFSET SO AS TO ASSEMBLE WITH IM$BGN AT     *
; LOCATION ZERO.				      *
;******************************************************
;******************************************************


;******************************************************
; DOUBLE D INTERNAL PORT ASSIGNMENTS		      *
;******************************************************

IM$BL$STS	EQU	000H	;BOARD STATUS
IM$BL$CTL	EQU	000H	;BOARD CONTROLS
IM$WD$CMD	EQU	004H	;179X COMMAND REGISTER
IM$WD$STS	EQU	004H	;179X STATUS REGISTER
IM$WD$TRK	EQU	005H	;179X TRACK REGISTER
IM$WD$SEC	EQU	006H	;179X SECTOR REGISTOR
IM$WD$DTA	EQU	007H	;179X DATA REGISTER
IM$XP$STP	EQU	008H	;STEPPER PULSE
IM$XP$MTO	EQU	010H	;MOTOR TIME OUT
IM$XP$MTX	EQU	040H	;MOTOR TIME EXTEND
IM$XP$DSH	EQU	080H	;DATA SYNC HOLD

;******************************************************
; 179X-02 COMMAND CODES				      *
;******************************************************

IM$DC$HDL	EQU	00011000B  ;LOAD R/W HEAD.
IM$DC$RMS	EQU	10011000B  ;READ MULTI-SECTOR.
IM$DC$STS	EQU	11010000B  ;SET TYPE 1 STATUS.

;******************************************************
; Z80 INSTRUCTION HEX CODES - NOTE HI/LOW ORDER SWAP  *
;******************************************************

IM$LXIY		EQU	021FDH	;LOAD Y REG IMED.
IM$RETN		EQU	045EDH	;RETN (NMI RETURN).
IM$XTIY		EQU	0E3FDH	;EXCHANGE (SP) <> IY.

;******************************************************
; BOARD STATUS AND CONTROL PORTS		      *
;******************************************************

IM$BS$US0	EQU	001H	;179X-02 POLARITY TEST.
IM$BC$DR0	EQU	004H	;DRIVE 0 SELECT/ENABLE.

;******************************************************
; DISK STATUS MASKS				      *
;******************************************************

IM$DM$RER  EQU	10011100B 	;READ ERROR TEST MASK.
IM$DM$TK0  EQU	00000100B 	;TRACK 0 TEST.
IM$DM$DNR  EQU	10000000B	;DRIVE NOT READY.

;******************************************************
; DISK DRIVE PARAMETERS				      *
;******************************************************

IM$TM$STP	EQU	10	;STEPPER INTERVAL - MS.
IM$TM$DBR	EQU	40	;DELAY BEFORE READ- MS.
IM$NB$TRK	EQU	76	;MAXIMUM NMBR OF STEPS.

;******************************************************
; INTERNAL MEMORY ASSIGNMENTS			      *
;******************************************************

IM$BK0	   EQU	0000H		;LOWER BANK ADDRESS.
IM$BKL     EQU	0400H		;1K BANK LENGTH.
IM$BK1     EQU	IM$BK0+IM$BKL	;UPPER BANK ADDRESS.
IM$NMI     EQU	IM$BK0+0066H	;NON-MASKABLE INT ADDR.
IM$BL$ERC  EQU	IM$BK0+0376H	;ERROR CODE LOCATION.
IM$BL$DCS  EQU	IM$BK0+BL$DCS	;DISK CONTROLLER STAT.

;******************************************************
; BOOTSTRAP COMMUNICATION			      *
;******************************************************

BE$HOM	EQU	001H		;HOME ERROR.
BE$RDA	EQU	002H		;READ ERROR A.
BE$RDB	EQU	004H		;READ ERROR B.

;******************************************************
; DISK CONTROLLER MODULE (DCM) LINKAGE		      *
;******************************************************

DCM$SS	EQU	13		;FIRST DCM SECTOR = 13.
DCM$BG	EQU	IM$BK1+3	;DCM COLD START ENTRY.
DCM$LN	EQU	0400H		;DCM LENGTH

;******************************************************
; SET STACK, START DRIVE MOTOR, AND SET INVERT SW (C) *
;******************************************************

IM$BGN:	LXI	SP,IM$BK1	;SET UP STACK.
	IN	IM$XP$MTX	;TURN ON MOTOR.
	MVI	C,0		;ASSUME 1793.
	IN	IM$BL$STS	;INPUT STATUS.
	ANI	IM$BS$US0	;TEST USER SW 0.
	JNZ	IM$DRV-IM$BGN	;GOTO SELECT DRV.
	MVI	C,0FFH		;1791-01 INVERTS.

;******************************************************
; CLEAR 179X-01 INTERRUPT AND SELECT DRIVE 0          *
;******************************************************

IM$DRV:	CALL	IM$STS-IM$BGN	;179X-01 FORCED CLEAR. 
	MVI	A,IM$BC$DR0	;DRIVE 0, ENABLED.
	OUT	IM$BL$CTL	;OUTPUT CONTROLS.

;******************************************************
; CHECK FOR DRIVE READY SIGNAL			      *
;******************************************************

	CALL	IM$STS-IM$BGN	;GET DRIVE STATUS.
	STA	IM$BL$DCS	;STORE DRIVE STATUS.
	ANI	IM$DM$DNR	;CHECK DRIVE NOT RDY.
	JZ	IM$HDL-IM$BGN	;IF READY, BOOT SYSTEM.
	XRA	A		;ZERO A REGISTER.
	JMP	IM$HLT-IM$BGN	;DOUBLE D SHUTDOWN.

;******************************************************
; LOAD R/W HEAD ON SELECTED DRIVE		      *
;******************************************************

IM$HDL:	MOV	A,C		;GET TRACK 0 VALUE.
	OUT	IM$WD$TRK	;SET TRACK REGISTER.
	OUT	IM$WD$DTA	;SEEK SAME TRACK.
	DW	IM$LXIY		;Z80 LXIY HEX CODE.
	DW	IM$HME-IM$BGN	;SET NMI RETURN ADDR.
	MVI	A,IM$DC$HDL	;HEAD LOAD COMMAND.
	XRA	C		;INVERT (1791-01).
	OUT	IM$WD$CMD	;ISSUE COMMAND.
IM$WFI:	JMP	IM$WFI-IM$BGN	;WAIT FOR INTERRUPT.

;******************************************************
; POSITION R/W HEAD AT TRACK ZERO		      *
;******************************************************

IM$HME:	MVI	L,IM$NB$TRK	;SET MAX TRACKS.
IM$STP:	CALL	IM$STS-IM$BGN	;GET 179X STATUS.
	ANI	IM$DM$TK0	;TEST TRACK 0 BIT.
	JNZ	IM$RSU-IM$BGN	;TRACK 0 EXIT.
	DCR	L		;DEC ATTEMPTS.
	JZ	IM$EHM-IM$BGN	;CANT FIND TRK 0?
	IN	IM$XP$STP	;ISSUE STEP PULSE.
	LXI	D,IM$TM$STP	;STEP INTERVAL TIME.
	CALL	IM$TMR-IM$BGN	;PAUSE FOR PERIOD.
	JMP	IM$STP-IM$BGN	;TRY ANOTHER TIME.

;******************************************************
; GET UPDATED 179X-01 STATUS			      *
;******************************************************

IM$STS:	MVI	A,IM$DC$STS	;TYPE 4 - STATUS.
	XRA	C		;INVERT (1791-01).
	OUT	IM$WD$CMD	;ISSUE COMMAND.
	XTHL			;DELAY
	XTHL			;DELAY
	XTHL			;DELAY
	XTHL			;DELAY
	IN	IM$WD$STS	;GET STATUS
	XRA	C		;INVERT (1791-01).
	RET			;RETURN TO CALLER.

;******************************************************
; DISK INTERRUPT "NMI" ROUTINE			      *
;******************************************************

	ORG	IM$BGN+IM$NMI

	IN	IM$WD$STS	;GET 179X STATUS.
	XRA	C		;INVERT (1791-01).
	STA	IM$BL$DCS	;MAKE STATUS VISIBLE.
	DW	IM$XTIY		;EXCHANGE (SP) <> IY.
	DW	IM$RETN		;NMI RETURN (RETN).

;******************************************************
; SET-UP FOR DCM READ OPERATION			      *
;******************************************************

IM$RSU:	LXI	D,IM$TM$DBR	;DELAY BEFORE READ.
	CALL	IM$TMR-IM$BGN	;CALL MS. TIMER.
	LXI	D,IM$BKL	;SET BANK LENGTH
	LXI	H,IM$BK1	;DCM LOAD ADDRESS
	DW	IM$LXIY		;Z80 LXI Y HEX CODE.
	DW	IM$REA-IM$BGN	;READ ERROR TRAP.
	MVI	A,DCM$SS	;FIRST SEC OF DCM.
	XRA	C		;INVERT (1791-01)
	OUT	IM$WD$SEC	;SET 179X SEC REG.
	MVI	A,IM$DC$RMS	;READ MULTI-SECTOR.
	XRA	C		;INVERT (1791-01).
	OUT	IM$WD$CMD	;ISSUE 179X COMMAND.

;******************************************************
; ACCEPT EACH BYTE AND STORE IN MEMORY		      *
;******************************************************

IM$RBT:	IN	IM$XP$DSH	;WAIT FOR DATA.
	IN	IM$WD$DTA	;INPUT INV DATA.
	XRA	C		;INVERT (1791-01).
	MOV	M,A		;STORE DCM BYTE.
	INX	H		;INCREMENT POINTER.
	DCX	D		;DECREMENT LENGTH.
	MOV	A,D		;GET HIGH REG.
	ORA	E		;THEN OR-IN LOW REG.
	JNZ	IM$RBT-IM$BGN	;READ ANOTHER BYTE.

;******************************************************
; TEST READ STATUS, TERMINATE OPERATION, GO DCM	      *
;******************************************************

IM$TRS:	IN	IM$WD$STS	;INPUT READ STATUS.
	XRA	C		;INVERT (1791-01).
	ANI	IM$DM$RER	;TEST FOR ERRORS.
	JNZ	IM$REB-IM$BGN	;READ ERROR TRAP.
	CALL	IM$STS-IM$BGN	;TERMINATE READ.
	JMP	DCM$BG		;TRANSFER TO DCM.

;******************************************************
; READ ERROR HAS BEEN DETECTED			      *
;******************************************************

IM$REA:	MVI	A,BE$RDA	;LOAD READ ERROR CODE.
	JMP	IM$HLT-IM$BGN	;GO TO ERROR HALT.
IM$REB:	MVI	A,BE$RDB	;LOAD READ ERROR CODE.
	JMP	IM$HLT-IM$BGN	;GO TO ERROR HALT.
IM$EHM:	MVI	A,BE$HOM	;HOME ERROR CODE.
IM$HLT:	STA	IM$BL$ERC	;DISPLAY ERROR CODE.
	XRA	A		;ZERO A REG.
	OUT	IM$BL$STS	;DESELECT DRIVE.
	IN	IM$XP$MTO	;MOTOR OFF!
	HLT			;TERMINATE.

;******************************************************
; TIMER - WAIT FOR (BC * 1.0) MILLISECONDS	      *
;******************************************************

IM$TMR:	MVI	A,220		;LOAD INT MS VALUE.
IM$TMX:	DCR	A		;DEC FOR 1 MS.
	NOP			;EXTRA TIMING DELAY.
	JNZ	IM$TMX-IM$BGN	;REPEAT FOR 1 MS.
	DCX	D		;TEST FOR ANOTHER MS.
	MOV	A,D		;CHECK REG D.
	ORA	E		;AND REGISTER E.
	JNZ	IM$TMR-IM$BGN	;DO ANOTHER 1 MS.
	RET			;TIME PERIOD EXPIRED!

;******************************************************

IM$END:	END	BEGIN		;END OF ASSEMBLY.
 