*DISK JOCKEY/2D FIRMWARE REVISION 4
*
	AORG	0E000H
*
ORIGIN	EQU	0E000H
*
	SORG	0E000H
*
	ORG	ORIGIN
*
RAM	EQU	ORIGIN+00400H
IO	EQU	ORIGIN+003F8H
UDATA	EQU	IO
DREG	EQU	IO+1
USTAT	EQU	DREG
DCMD	EQU	IO+2
DSTAT	EQU	DCMD
CMDREG	EQU	IO+4
CSTAT	EQU	CMDREG
TRKREG	EQU	IO+5
SECREG	EQU	IO+6
DATREG	EQU	IO+7
*
*
RCMD	EQU	200Q
WCMD	EQU	240Q
HEAD	EQU	4
LOAD	EQU	20Q
DENSITY	EQU	1
ULOAD	EQU	30Q
RSTBIT	EQU	4
ACCESS	EQU	2
READY	EQU	40Q
INDEX	EQU	20Q
RACMD	EQU	304Q
CLRCMD	EQU	320Q
SVCMD	EQU	35Q
SKCMD	EQU	30Q
HCMD	EQU	11Q
ISTAT	EQU	4
OSTAT	EQU	10Q
DSIDE	EQU	10Q
TZERO	EQU	4
MDINT	EQU	3
LIGHT	EQU	36Q
NOLITE	EQU	76Q
*
*
DBOOT	JMP	BOOT
TERMIN	JMP	CIN
TRMOUT	JMP	COUT
TKZERO	JMP	HOME
TRKSET	JMP	SEEK
SETSEC	JMP	SECSET
SETDMA	JMP	DMA
DREAD	JMP	READ
DWRITE	JMP	WRITE
SELDRV	JMP	DRIVE
TPANIC	JMP	CPAN
TSTAT	JMP	TMSTAT
DMAST	JMP	DMSTAT
STATUS	JMP	DISKST
DSKERR	JMP	LERROR
SETDEN	JMP	DENFIX
SETSID	JMP	SIDEFX
*
*
	DS	56Q
*
*
BOOT
	LXI	SP,TRACK+1	;initialize the SP
	LXI	H,TIMER-4	;memory test data
	LXI	D,STABLE	;the ROM compare
	MVI	B,4		;-data and count
TESTL
	LDAX	D		;get the ROM data
	CMP	M		;compare w/memory
	JNZ	DRESET		;do timeout?
	INX	H		;move the
	INX	D		;-two pointers
	DCR	B		;dec the count
	JNZ	TESTL		;test more?
	JMP	DSETUP		;no.
DRESET
	CALL	TIMOUT		;reset time out
DSETUP
	LXI	H,1
	PUSH	H		;track 0, sector 1
	MVI	L,MDINT		;set up side
	PUSH	H		;-select .. also
	MVI	H,0FFH		;-parameter
	PUSH	H		;-and
	PUSH	H		;-track info
	PUSH	H		;-for the 4
	PUSH	H		;-drives
	LXI	H,0		;initialize
	PUSH	H		;-the track
	INX	SP		;-zero flag
	MVI	H,008H		;current disk
	PUSH	H		;-and new disk
	MVI	H,0FEH		;initialize DRVSEL
	PUSH	H		;-and HDFLAG
	MVI	H,(RAM+0300H)/256
	PUSH	H		;DMA address
	MVI	H,018H		;temporary TIMER
	PUSH	H		;-constant
	MVI	A,MDINT		;initialize 1791
	STA	DCMD		;-control bits
	MVI	A,CLRCMD	;1791 reset
	STA	CMDREG		;-command
LDHEAD
	XRA	A		;load the head
	CALL	HDCHK		;-and test for
	JNC	DOOROK		;-drive ready
	MVI	A,LIGHT		;turn on the
	STA	DRVSEL		;-error LED
	CALL	TIMOUT		;time out to
	JMP	LDHEAD		;-close drive door
DOOROK
	MVI	A,NOLITE	;turn off the
	STA	DRVSEL		;-error LED
	MVI	M,MDINT		;open data reg
	POP	H		;discard old TIMER
	CALL	MEASUR		;head load time
	POP	B		;recover boot
	PUSH	B		;address from DMAADDR
	PUSH	D		;-new TIMER value
	LHLD	STABLE+2	;set up
	PUSH	H		;-time out
	LHLD	STABLE		;-test
	PUSH	H		;-data
	NOP			;debug instruction
	PUSH	B		;boot address
	MVI	B,00AH		;number of retries
LDLOOP
	PUSH	B		;save the retry no
	CALL	READ		;read boot sector
	POP	B		;restore retry no
	RNC			;successful read?
	DCR	B		;no, count down
	JNZ	LDLOOP		;try again
LERROR
	MVI	C,03FH
	LXI	D,0A2C3H
LELOOP
	DCX	D
	MOV	A,D
	ORA	E
	JNZ	LELOOP
	MVI	A,020H		;blink
	XRA	C		;-the LED at
	STA	DREG		;-top of the
	MOV	C,A		;-circuit board
	JMP	LERROR+2
*
*
COUT
	LDA	USTAT		;get UART status
	ANI	OSTAT		;output ready bit
	JNZ	COUT		;test output ready
	MOV	A,C		;character data
	CMA
	STA	UDATA		;send to UART
	CMA
	RET
CIN
	LDA	USTAT		;get UART status
	ANI	ISTAT		;input ready bit
	JNZ	CIN		;test input ready
	LDA	UDATA		;get the character
	CMA			;true data
	ANI	07FH		;trim to 7 bits
	RET
CPAN
	LDA	DREG		;get UART status
	ANI	ISTAT		;input ready bit
	RNZ			;test for character
	CALL	CIN		;get character
	CMP	C		;test for panic
	RET
TMSTAT
	LDA	USTAT		;get UART status
	ANI	ISTAT		;input ready bit
	RET
DISKST
	LDA	SECREG		;get current
	MOV	B,A		;-sector no in B
	LDA	TRKREG		;get current
	MOV	C,A		;-track no in C
	LDA	DCREG		;get current
	CMA			;-density in
	ANI	001H		;-the msb
	RRC			;-position
	MOV	D,A		;save in D
	LDA	SIDE		;put the
	RLC			;-side
	RLC			;-select
	RLC			;-flag
	ADD	D		;-in bit
	MOV	D,A		;-position 6
	LDA	SECLEN		;put the
	RAL			;-sector length
	RAL			;-code in bits
	ADD	D		;-2 & 3
	MOV	D,A
	LDA	CDISK		;put the current
	ADD	D		;-disk no in bits
	RET			;-0 & 1
*
*
DMSTAT
	PUSH	H		;save the H-L pair
	LHLD	DMAADR		;DMA addr to H-L
	MOV	B,H		;move the DMA
	MOV	C,L		;-addr to B-C
	POP	H		;recover H-L
	RET
*
*
DRIVE
	MVI	A,0FCH		;test for the
	ADD	C		;-new drive number
	MVI	A,010H		;less than 4
	RC
	MOV	A,C		;store the new
	STA	DISK		;drive in DISK
	RET
*
*
DMA
	LXI	H,8-ORIGIN	;test the
	DAD	B		;-DMA address
	JNC	DMASET		;-for conflict
	LXI	H,-RAM		;-with the I/O
	DAD	B		;-on the DJ/2D
	JC	DMASET		;controller
	STC
	MVI	A,010H
	RET
DMASET
	MOV	H,B		;get the DMA addr
	MOV	L,C		;to the H-L pair
	SHLD	DMAADR		;store
	XRA	A		;clear the error
	RET			;-flag and return
HOME
	CALL	HENTRY		;head to trk zero
	PUSH	PSW		;save the flags
	SBB	A		;update the
	STA	TRACK		;-track register
	POP	PSW		;recover the flags
	JMP	LEAVE		;unload the head
HENTRY
	CALL	HDLOAD		;load the head
	RC			;test for ready error
	XRA	A		;update
	STA	TZFLAG		;-the two
	STA	HDFLAG		;-flags
	LXI	H,0		;time out constant
	MVI	A,HCMD		;do the home
	CALL	CENTRY		;-command
	ANI	TZERO		;track zero bit
	RNZ
	STC			;error flag
	RET
*
*
SECSET
	XRA	A		;test for
	ORA	C		;-sector zero
	STC			;error flag
	RZ
	MOV	A,C		;test for
	CPI	27		;-sector
	CMC			;-too large
	RC
	STA	SECTOR		;save
	RET
*
*
SEEK
	MOV	A,C		;test for
	CPI	77		;-track
	CMC			;-too large
	RC
	STA	TRACK		;save
	RET
*
*
READ
	CALL	PREP		;prepare for read
	POP	H		;recover DMA addr
	MVI	A,040H		;test the
	CMP	E		;-read command for
	JZ	SINGLE		;-single density
	PUSH	H		;save DMA addr
	DAD	D		;ending
	DAD	D		;-address+1
	PUSH	H		;save also
	SPHL			;adjust SP
	DCX	D		;adjust byte cnt
	LXI	H,DATREG	;data register
	MVI	A,RCMD		;do the read
	STA	CMDREG		;-command
	MOV	B,M		;first byte of data
RLOOP
	MOV	C,M		;2nd byte of data pair
	PUSH	B		;save the data pair
	MOV	B,M		;1st byte of next pair
	DCR	E		;dec low byte of cnt
	JNZ	RLOOP
	DCR	D		;dec high byte of cnt
	JP	RLOOP
	MOV	C,M		;get last byte
	PUSH	B		;store last pair
	LXI	SP,STACK-6	;adjust SP
	POP	H		;get the end addr+1
	POP	D		;get the begin addr
ALOOP
	DCX	H		;early data pointer
	MOV	B,M		;get early data
	LDAX	D		;get late data
	MOV	M,A		;swap the
	MOV	A,B		;-two bytes
	STAX	D		;-of data
	INX	D		;advance late ptr
	MOV	A,L		;compare
	CMP	E		;-the two
	JNZ	ALOOP		;-data
	MOV	A,H		;-pointers
	CMP	D		;-for a
	JNZ	ALOOP		;-match
	JMP	CBUSY
*
*
SINGLE
	RLC			;initialize the data
	MOV	C,A		;-count to 128
	LXI	D,DATREG	;1791 data register
	MVI	A,RCMD		;issue the
	STA	CMDREG		;-read command
SHORTL
	LDAX	D		;get data from disk
	MOV	M,A		;move data to memory
	INX	H		;increment data pointer
	DCR	C		;decrement data count
	JNZ	SHORTL		;test for
	JMP	CBUSY		;-transfer done
*
*
WRITE
	CALL	PREP		;prepare for write
	POP	H		;recover DMA addr
	SPHL			;adjust SP
	DCX	D		;adjust byte cnt
	LXI	H,DATREG	;data reg
	MVI	A,WCMD		;do a write
	STA	CMDREG		;-command
	POP	B		;get the 1 data pair
	MOV	M,C		;write first byte
WLOOP
	MOV	M,B		;write high byte
	POP	B		;get next data pair
	MOV	M,C		;write low byte
	DCR	E		;dec low byte of cnt
	JNZ	WLOOP
	DCR	D		;dec high byte of cnt
	JP	WLOOP
	MOV	M,B		;write last byte
CBUSY
	LDA	CSTAT		;get 1791 status
	RAR			;busy bit to carry
	JC	CBUSY
	RAL			;restore the ACC
	ANI	0DFH		;error bit mask
	JZ	RETURN		;go to the exit
	STC			;set the error flag
RETURN
	LHLD	STACK-2		;get the user SP
	SPHL			;restore the user SP
LEAVE
	PUSH	PSW
	LDA	DCREG		;1791 control bits
	XRI	LOAD		;toggle the
	STA	DCMD		;-load bit
	POP	PSW		;-the 1791 data reg
	RET
*
*
PREP
	POP	D		;get return addr
	LXI	H,0		;get the user's
	DAD	SP		;-stack pointer
	LXI	SP,STACK	;local stack
	PUSH	H		;save user's SP
	LHLD	DMAADR		;DMA address
	PUSH	H		;save DMA addr
	PUSH	D		;save return addr
	LXI	H,RETURN	;error
	PUSH	H		;-exit
	CALL	HDLOAD		;load the head
	RC			;dis not ready?
	LDA	TRKREG		;get the old trk
	INR	A		;test for head
	CZ	HENTRY		;-not calibrated
	JC	SERROR		;seek error?
	LXI	H,TRKREG	;present trk
	LDA	TRACK		;the new track
	CMP	M		;test for head motion
	INX	H		;advance to the
	INX	H		;-data register
	MOV	M,A		;save the new trk
	MOV	A,C		;turn off data
	STA	DCMD		;-access control bit
	JZ	TVERFY		;test for seek
	XRA	A		;force a read
	STA	HDFLAG		;-header operation
	LDA	DSTAT		;get the
	ANI	DSIDE		;-double
	MOV	A,A		;-sided
	RAR			;-flag
	RAR			;-to do 3 ms
	ADI	SKCMD		;-step operation
	LXI	H,0		;do a seek
	CALL	CENTRY		;-command
	JC	SERROR		;seek error?
TVERFY
	LDA	HDFLAG		;get the force
	ORA	A		;-verify track flag
	JNZ	CHKSEC		;no seek & head OK
	MVI	B,2		;verify retry no
SLOOP
	MVI	A,SVCMD		;do a verify
	CALL	COMAND		;-command
	ANI	099H		;error bit mask
	JZ	RDHDR		;no error
	LDA	DCREG		;1791 control reg
	XRI	DENSITY		;flip the density bit
	STA	DCREG		;update and
	STA	DCMD		;-change density
	DCR	B		;dec retry count
	JNZ	SLOOP		;-and try again
SERROR
	CALL	HOME		;there is a
	JMP	BERROR		;-hard seek error
RDHDR
	MVI	B,00AH		;number of retries
RHLOOP
	LXI	D,DATREG	;data register
	LXI	H,TRACK+1	;storage area
	MVI	A,RACMD		;do the read
	STA	CSTAT		;-header command
RHL1
	LDAX	D		;get a data byte
	MOV	M,A		;store in memory
	INR	L		;inc mem pointer
	JNZ	RHL1		;test for more data
	LXI	H,CSTAT		;wait for 1791
	CALL	BUSY		;to finish cmd
	ORA	A		;test for errors
	JZ	CHKSEC		;transfer OK?
	DCR	B		;dec retry count
	JNZ	RHLOOP		;test for
	JMP	SERROR		;-hard error
CHKSEC
	LDA	SECLEN		;get the sector
	MOV	C,A		;-size and setup
	MVI	B,0		;-the offset
	LXI	H,STABLE	;sec size tbl
	DAD	B		;add the offset
	LDA	SECTOR		;get the sector
	MOV	B,A		;save in B
	ADD	M		;compare w/table entry
	MVI	A,010H		;error flag
	RC			;error return
	POP	H		;return addr to TOS
	MOV	A,B		;save the sector
	STA	SECREG		;-in sector reg
	LXI	H,00040H	;half page count
SZLOOP
	DCR	C		;sec size count
	MOV	D,H		;half size count
	MOV	E,L		;-to the D-E pair
	RM			;return if done
	DAD	H		;double the xfer
	JMP	SZLOOP		;-size count
*
*
STABLE
	DB	345Q
	DB	345Q
	DB	360Q
	DB	367Q
*
*
HDLOAD
	LXI	H,DISK
	MOV	C,M		;new disk no to C
	INX	H
	MOV	E,M		;current disk to E
	MOV	M,C		;updaate current disk
	INX	H		;head load constant
	MOV	A,E		;test for
	CMP	C		;-disk change
	MOV	A,M		;head load flag
	MVI	M,HEAD		;update head load
	INX	H		;addr of disk table
	JZ	HDCHK		;no disk change?
	PUSH	H		;save table address
	MVI	D,0		;set up the
	MOV	B,D		;-offset address
	DAD	D		;get the current
	DAD	D		;disk parameters
	LDA	DCREG		;save the
	MOV	M,A		;density info
	INX	H		;current track
	LXI	D,TRKREG
	LDAX	D		;get current trk
	MOV	M,A		;save
	POP	H		;recover tbl addr
	DAD	B		;add the
	DAD	B		;-offset
	MOV	A,M		;get control bits
	STA	DCREG		;update DCREG
	INX	H		;get the old
	MOV	A,M		;track number
	STAX	D		;and update 1791
	MVI	A,07FH		;disk select bits
DSROT
	RLC			;rotate to
	DCR	C		;-select the
	JP	DSROT		;-proper drive
	STA	DRVSEL		;save
	XRA	A		;force head load
HDCHK
	LXI	H,DCMD		;test for
	ANA	M		;-head loaded
	STA	HDFLAG		;save the head
	PUSH	PSW		;-loaded status
	LDA	DRVSEL		;get current drive
	MOV	C,A		;save
	LDA	SIDE		;get current side
	CMA			;and merge
	ANA	C		;-with drive select
	STA	DREG		;select drive & side
	LDA	DCREG		;1791 control bits
	MOV	C,A		;save
	LDA	TRACK		;get the new trk
	SUI	1		;force single
	SBB	A		;-density
	DCR	A		;if track = 0
	CMA			;compliment
	ORA	C		;merge w/control bits
	MOV	M,A		;set 1791 control
	XRI	ACCESS		;toggel access bit
	MOV	C,A		;save PREP routine
	POP	PSW		;head load status
	JNZ	RDYCHK		;conditionally
	PUSH	H		;-wait for head
	LHLD	TIMER		;-load timeout
TLOOP
	DCX	H		;count down
	MOV	A,H		;-40 ms for
	ORA	L		;-head load
	JNZ	TLOOP		;-time out
	POP	H		;disk status addr
RDYCHK
	MOV	A,M		;test for
	ANI	READY		;-disk ready
	RZ
UNLOAD
	LDA	DCREG		;for a
	ORI	ULOAD		;-head
	MOV	M,A		;-unload
	MVI	A,080H		;set disk
	STC			;-not ready
	RET			;-error flag
COMAND
	LHLD	TIMER		;get index count
	DAD	H		;-and multiply
	DAD	H		;-by four
CENTRY
	XCHG			;save in D-E pair
	LXI	H,CSTAT		;issue command
	JMP	PATCH+3		;jump around patch
PATCH
	JMP	HDLOAD		;patch for old ATE
	NOP			;fill instruction
	NOP			;fill instruction
	MOV	M,A		;to the 1791
NBUSY
	MOV	A,M		;wait
	RAR			;-for the
	JNC	NBUSY		;-busy flag
BUSY
	MOV	A,M		;test for
	RAR			;-device busy
	MOV	A,M		;restore status
	RNC			;return if not busy
	DCX	D		;test for
	MOV	A,D		;-two disk
	ORA	E		;-revolutions
	JNZ	BUSY		;47 machine cycles
	PUSH	H		;save cmd address
	INX	H		;track register
	MOV	D,M		;save present track
	LDA	DCREG		;1791 control bits
	XRI	RSTBIT		;reset the 1791
	STA	DCMD		;-controller to
	XRI	RSTBIT		;-clear the
	XTHL			;-command busy
	STA	DCMD		;-fault
	MVI	M,CLRCMD	;force an interrupt
	XTHL			;restore the
	MOV	M,D		;-the track no
	POP	H		;restore the stack
BERROR
	MVI	A,011H		;lost record
	STC			;-error flag
	RET
*
*
MEASUR
	LXI	D,0		;initialize count
	LXI	H,DCMD		;status port
	MVI	C,INDEX		;index bit flag
INDXHI
	MOV	A,M		;wait for
	ANA	C		;-index
	JNZ	INDXHI		;-pulse low
INDXLO
	MOV	A,M		;wait for
	ANA	C		;-index
	JZ	INDXLO		;-pulse high
INDXCT
	INX	D		;advance count
	XTHL			;four
	XTHL			;-dummy
	XTHL			;-instructions
	XTHL			;-for delay
	MOV	A,M		;wait
	ANA	C		;-for next
	JNZ	INDXCT		;-low index
	RET			;98 machine cycles
*
*
DENFIX
	MOV	A,C		;trim excess
	ANI	1		;-bits
	CMA			;compliment
	MOV	B,A		;-B and save
	LXI	H,DISK		;new disk
	MOV	E,M		;get disk no
	MVI	D,0		;offset addr
	INX	H		;current disk
	MOV	A,M		;move to ACC
	XRA	E		;compare w/new
	PUSH	PSW		;save status
	INX	H		;disk table
	INX	H		;-address
	DAD	D		;add the
	DAD	D		;offset
	MOV	A,M		;get parameters
	ORI	001H		;make off density
	ANA	B		;set new density
	MOV	M,A		;update
	POP	PSW		;check for nd=cd
	RNZ			;new disk not old
	MOV	A,M		;update CDISK
	STA	DCREG		;-also
	RET
*
*
SIDEFX
	MOV	A,C		;set the site bit
	ANI	1		;trim excess bits
	RAL			;move the bit
	RAL			;-to the side
	RAL			;-select bit
	RAL			;-position
	STA	SIDE		;save
	RET
*
*
TIMOUT
	LXI	H,0		;time out delay
TILOOP
	DCX	H		;decrement
	MOV	A,H		;test for
	ORA	L		;-count zero
	XTHL			;long
	XTHL			;-NOP
	JNZ	TILOOP
	RET

	DB	DBOOT/256	;backward
	DB	0		;-jump
DVREND	DB	0C3H		;-instruction
;
;
	ORG	RAM+02CCH
STACK	DS	31Q
;
TIMER	DW	01800H		;head load time
DMAADR	DW	0E700H		;dma address
HDFLAG	DB	0		;read header flag
DRVSEL	DB	0FEH		;drive select constant
DISK	DB	0		;new drive
CDISK	DB	008H		;current drive
TZFLAG	DB	0		;track zero indicator
D0PRAM	DB	3		;drive 0 parameters
D0TRK	DB	0FFH		;drive 0 track no
D1PRAM	DB	3		;drive 1 parameters
D1TRK	DB	0FFH		;drive 1 track no
D2PRAM	DB	3		;drive 2 parameters
D2TRK	DB	0FFH		;drive 2 track no
D3PRAM	DB	3		;drive 3 parameters
D3TRK	DB	0FFH		;drive 3 track no
DCREG	DB	3		;current parameters
SIDE	DB	0		;new side select
SECTOR	DB	0		;new sector
TRACK	DB	0		;new track
TRKNO	DB	0		;disk
SIDENO	DB	0		;-sector
SECTNO	DB	0		;-header
SECLEN	DB	0		;-data
CRCLO	DB	0		;-buffer
CRCHI	DB	0		;

	END
