	.title	'hard disk controller ram firmware'
	.ident	hardfirm
	.pabs
	.phex
version	==	4
revision==	0	;changed 20-Jan-84

;
;		TABLE OF CONTENTS		PAGE
;
; 1. version change descriptions		2
; 2. equates					4
; 3. initalise firmware				12
; 4. idle code					17
;	clean least recently used buffer	18
;	write out dirty bad sector tables	19
; 5. get command from host			21
; 6. absolute read and write routines		23
; 7. cpm function decoding			25
;	flush and netwrite			26
;	select disk and partition		27
;	swap unit and set volume pointer	29
;	cpm128 byte read routine		30
;	cpm 128 byte write			33
;	netread (1k)				34
;	assign command				35
;	return volume info			37
;	find a sector in the buffer		38
;	get a free buffer			39
;	is any buffer clean			41
;	locbuf,cleana,cleanb and bufback	42
;	set buffer most recently used		43
;	doread and dowrite			44
;	calculate track,head and sector		47
;	shift and divide			48
;	oasis commands				50
; 8. Physical reads and writes			52
;	seek and head select routines		53
;	read or write sector routines		57
;	actual hardware read and write		59
; 8. error correction 				62
; 9. inited data area				67
;10. uninited buffers				70
;11. init code overwrite buffers		71
	.page
	.sbttl	'version change descriptions'
;	ver 4.0 20-Jan-84	les wilson
;	updated for release, uses rom 4.0

;	ver 3.1	19-Jan-84	les wilson
;	rom version must be 3.1 for zero settling

;	ver 3.0 6-Dec-83	les wilson
;	check version of rom to know whether
;	any settling is needed.  If new rom (3.0)
;	assume mods made for zero settling.  Otherwise
;	settle for 15 millisecs on reads

;
;	ver 2.9 28-Oct-83	les wilson
;	added read write routines from rom to firmware
;	to allow enhancements as follows:
;	1. The read settle time will be reduced to 0 and 
;	the write settle time will be reduced from 40 
;	millisecs to 30 the factory spec.  No error 
;	correction will be attempted on reads until
;	after the second unsuccessful read.  Without
;	settling too many falsely correctable errors
;	occur.
;	2. The alloc table search will be terminated 
;	correctly if the entry is not found.
;	3. Select will reject unit numbers greater than
;	63.
;	4. On writes the buffer will be flushed immediately
;	if it is entirely dirty.
;	5. return status to master in write after receiving
;	data and before finding a buffer for it.
;	6. Include getcommand in firmware so idle flush 
;	can be called after 30 milliseconds of idle.
;	7. provide flag on netread as to whether data
;	came from buffer or not.
;	8. flag in netread command to force preread of
;	next sector.
;	9. command to force a crc error to the last
;	sector of the disk to allow crc circuitry test.
;	10. when searching for a clean buffer search
;	all buffers instead of just least recently used

;	ver 2.6 13-Apr-83  les wilson
;	added past history of commands to debug mode
;	debuged 2.5 features
;
;	ver 2.5 24-Mar-83	
;	1.if errors occur in
;	doread pay attention.  in particular dont place
;	record into buffer or send to host
;	2.	write out buffers on same track.
;	previously one buffer was checked many times
;	for being dirty
;	3.	move initialisation code to where
;	it can be used for a buffer when init complete
;	4.	change write, so old record is only
;	read in when cleaning buffer, saving a seek
;	5.	when doing 1k read if clean buffer
;	is availible read next sector into buffer
;
;	ver 2.4 17-Feb-83	in errexit clean up
;	stack as errexit is jumped to from within
;	subroutines

;
;	ver 2.3 10-sept-82	change in hardcrc.asm
;	only.  does not do error correction if
;	old rom is present

;	ver 2.2 5-aug-82	select disk only returns
;	status if multidisk os indicated 

;	
;	ver 2.1 3-Aug-82	Select disk (CPM) always
;	returns status

;	ver 1.1 may-82	multiple hard disks supported

;
;	ADDED 1K BYTE READ 4/12/81
;	ADDED MULT BUFFERS 9/13/80
;	COMBINED OASIS CODE 2/16/81
;	CPMUSER PROGRAM 8/24/79 9AM
;
;
	
	.insert	hardequ
debug	=\	"for debug mode enter 0,production enter 1"
romversion == 4	;version of rom needed for no settling
romrevision == 0 ;revision of for no settling

	.page
	.sbttl	'initialise firmware'
	
	.LOC	usrprog	;ENTER HERE

	LXI	D,usrprog+2		;OVERLAY STARTING THERE
	LXI	H,LASTJMP+2
	LXI	B,LASTJMP+4-SMOV
	LDDR
	JMP	firminit		;LEAVE FOLLOWING AS IS
;
;
;	note: disk tracks, sec/trk, disksize and
;	volumne level all get altered by hardhelp
;	before loading for the specific disk
;
SMOV:
	.BYTE	0,0,0,0,0,0,0		;SYS VARIABLES
	.ifn .-usrprog-offtracks,[.prntx 'bad offtracks']
	.byte	memtracks	;disk tracks for fujitsu
	.BYTE	VERSION,REVISION
	.ifn .-usrprog-offtype,[.prntx 'bad offtype']
	.BYTE	memsectors	;SEC/TRK MX=11, SA=17
	.ifn .-usrprog-offsize,[.prntx 'bad offsize']
	.BYTE	mem11headmask	;DISKSIZE=3,7,B,F
	JMP	DUMMY0
	JMP	DUMMY1
	JMP	IDLE
	JMP	rderr
LASTJMP: JMP	funcdecode	;THIS ENDS UP AT 4100H

;
;	the volumne label is altered in hardhelp
;	when placing firmware on disk
;
	.ifn .-usrprog-offvollabel,[.prntx 'bad offvollabel']
vollabel:.ascii	/          / 
	.ifn .-vollabel-vlabsize,[.prntx 'bad label size']
;
;	initialize the firmware
;
firminit:
;
;	decide from rom version of settling must occur
;
	lda	lcromversion
	cpi	romversion
	jrnz	..mustsettle
	lda	lcromrevision
	cpi	romrevision
	jrnz	..mustsettle
	mvi	a,true
	sta	nosettleok
	jmpr	..saveuser
..mustsettle:
	mvi	a,false
	sta	nosettleok
..saveuser:
	LXI	H,commbuff	;SAVE USER COMD
	LXI	D,tbuff1	;TEMP STORAGE
	LXI	B,commsize
	LDIR
	LXI	H,0
	SHLD	PHYTRACK	;WANT 0,0,2=BLOCK 1
	MVI	A,2
	lxi	d,4500h		;place for nextsector
..frloop:
	push	psw
;
;read a sector of firmware
;
;	input reg a - sector to read
;	      red de - location to store
;	output reg de - de input + 400h
;
;	NOTE: PHYTRACK AND PHYHEAD MUST BE SET BEFORE CALLING
;	ROUTINE.  USES ROM READ ROUTINES
;
	sta	physec
	push	d	;save place to store sector
	mvi	a,8ah	;ecc + 10 retries
	sta 	con0
	call	goreadsec	;rom 1k read routine
	jrz	..frok
	mvi	a,hdeinit	;error in firmware read
	jmp	errexit		;will clean up stack
..frok:
	pop	d
	lxi	h,rddata
	lxi	b,400h		;sector length
	ldir

	pop	psw
	inr	a
	cpi	5	;firmware occupies sectors 1-4
	jrnz	..frloop

;	
;	fill in volumn information for each volumn
;
	xra	a	;start with unit 0
..volloop:
	call	swapunit
	call	initvolinfo
	lda	unitno
	inr	a
	cpi	maxvol+1
	jrnz	..volloop
	xra	a		;restore unit as 0
	call	swapunit
	LXI	H,tbuff1	;RESTORE USER COMD
	LXI	D,commbuff
	LXI	B,commsize
	LDIR
	JMP	funcdecode	;NOW RUN CONT PROG

;
;	init volumne information
;
initvolinfo:
	lda	unitno
	call	setvolptr	;x reg points to data
;
;	read firmware sector to get disk size stuff
;
	lxi	h,0
	shld	hardsec		;sector to be read
	call	doread
	jrz	..firmok	;if bad read do not
				;init volumne info
	mov	vliopenerr(x),a	;save error
	ret
;
;	if firmware on disk not latest version
;	dont mark disk as present or read from
;	need firmware for disk size data for
;	later reads
;
..firmok:
	lda	rddata+offversion
	cpi	version
	jrz	..verok
..verbad:
	mvi	a,hdeversionbad
	mov	vliopenerr(x),a
	ret
..verok:
	lda	rddata+offrevision
	cpi	revision
	jrnz	..verbad

;
;	compare volume label with volume label for 
;	volume 0, if duplicate presume running with
;	single disk controller and mark volume as not
;	present
;
	lxi	h,rddata+offvollabel
	lxi	d,vli0+vlivollabel
	mvi	b,vlabsize
labloop:
	ldax	d
	cmp	m
	jrnz	..labok	;a character is different
	inx	d
	inx	h
	djnz	labloop
	mvi	a,hdeduplicatevollabel
	mov	vliopenerr(x),a
	ret
..labok:
	mvi	vlipresent(x),true ;mark volumne as present
	lda	rddata+offtracks
	mov	vlitracks(x),a
	lda	rddata+offtype
	mov	vlitype(x),a
	lda	rddata+offsize
	mov	vlisize(x),a
	lxi	h,vlivollabel
	push	x
	pop	d
	dad	d
	xchg			;de points to vol 
				;label area
	lxi	h,rddata+offvollabel
	lxi	b,vlabsize
	ldir			;copy volumne label
	lda	unitno
	call	swapunit	;get info avail to rom
;
;	read volumne bad sector table
;
	lxi	h,bstsec	;block number for bad
	shld	hardsec		;sector table
	call	doread
	jrz	..bsok
	mov	vliopenerr(x),a	;save error
	ret

..bsok:
	mov	e,vlibadtable(x)
	mov	d,vlibadtable+1(x) ; d points bad
				;table for volumne
	lxi	h,rddata
	lxi	b,1024
	ldir			;copy table to right area

	mov	l,vlidirty(x)
	mov	h,vlidirty+1(x)
	mov	m,false		;mark as not dirty
;
;	READ DISK ASSIGNMENT TABLE, BLOCK 15, AND
;	COMPUTE H0BIAS TABLE ENTRIES FROM SIZE BYTE
;
	LXI	H,dtable	;WANT DISK ASS TABLE
	SHLD	HARDSEC
	CALL	DOREAD
	JRZ	..dasok
	mov	vliopenerr(x),a	;save error
	ret
..dasok:
	mov	l,vlibiastable(x)
	mov	h,vlibiastable+1(x)
;
;	build a partition bias table when
;	passed location of table in hl and
;	partitions sector is in rddata
;
	MVI	B,63
	LXI	D,RDDATA+16
	XRA	A
	MOV	M,A		;FORCE UNIT 0 TO BLOCK0
	INX	H
	MOV	M,A
	INR	A
	STA	CUMBLK		;CUM BLOCK COUNT
..1:	LDAX	D
	ORA	A
	JRZ	..3		;IF NOT ASSIGNED
	MOV	C,A
	MVI	A,80H
..2:	RLC			;MAKE A=2**C-1
	DCR	C
	JRNZ	..2
	MOV	C,A
	LDA	CUMBLK
	ADD	C
	STA	CUMBLK
	SUB	C
	JMPR	..4
..3:	LDA	CUMBLK
..4:	INX	H
	MVI	M,0
	INX	H
	MOV	M,A		;1,2,4,8,10,20,40,FF
;
;POINT to NEXT ENTRY
;
	PUSH	H
	LXI	H,16
	DAD	D
	XCHG
	POP	H
	DJNZ	..1
	ret

	.page
	.sbttl	'idle code'
;
;	NOTE: EVERYTHING BEFORE THIS LABEL (DUMMY0) IS 
;	INITIALISATION CODE AND IS ELIGABLE FOR 
;	OVERWRITING WITH BUFFERS THEREAFTER
;

DUMMY0:	
;
DUMMY1:	RET
;
;	CALLED AFTER 1 SEC IDLE BY ROM. DIRTY
;	AND CLEAN ARE CALLED BY FLUSH COMMAND
;	
IDLE:
	.ife	debug,[
	ret		]
	
	lda	unitno	;save unit active at start
	push	psw	;of idle
	CALL	DIRTY			
..2:	CALL	CLEAN		;CHECK OTHER DRTY BUFS
	jrz	..ret		;RET IF NO MORE DRTY
	IN	PSTATUS		;READ HOST STAT
	RRC
	RRC			;CHECK LSB=HOST DA
	jrnc    ..2	;keep on if no new command
..ret:
	pop	psw
	jmp	swapunit ;restore unit active at
			;start of idle
			;return from there

	.page
	.sbttl	'clean least recently used buffer'
;
;	return zero flag clear if dirty buffer cleaned
;	zero set if no dirty buffers
;
CLEAN:			;CLEAN LRU DIRTY BUFFER
	MVI	B,NUMBUF	;LOOP CONTROL
	LXI	H,MRUTAB+NUMBUF-1
..2:	MOV	A,M		;GET LRU BUF NUM
	PUSH	H
	PUSH	B
	CALL	LOCBUF		;MOVE INFO TO CUR
	POP	B
	POP	H
	LDA	CURD		;IS IT DIRTY
	ORA	A
	JRNZ	..3
	DCX	H
	DJNZ	..2
	RET			;ZERO MEANS NONE DIRTY
;
..3:	call	cleana
	XRA	A
	INR	A
	RET			;WITH NON ZERO
	.page
	.sbttl	'write out dirty bad sector tables'
;
;	WRITE OUT DIRTY BADSECTOR TABLES
;	FOR EACH VOLUME
;
dirty:
	xra	a
	sta	dirtyvolume	;start with vol 0
..volloop:
	lda	dirtyvolume
	call	swapunit
	mov	a,vlipresent(x)
	cpi	true
	jrnz	..nextvol
	
	mov	l,vlidirty(x)		;IS BST DIRTY
	mov	h,vlidirty+1(x)
	mov	a,m
	ORA	A
	JRZ	..nextvol		;IF CLEAN=NO NEW CRC ERR
	XRA	A
	mov	m,a		;MARK CLEAN
	MVI	B,10		;10 RETRYS
..1:	PUSH	B
	LXI	H,BSTSEC
	CALL	RDHL		;SET UP TO WR BSTSEC
	mov	l,vlibadtable(x)
	mov	h,vlibadtable+1(x)
	LXI	D,BUFDATA	;WRITE OUT BST
	LXI	B,400H
	LDIR
	CALL	writesec
	POP	B		;RETRY COUNT
	ORA	A		;ERR ON WRITE
	JRZ	..nextvol
	DJNZ	..1		;TRY AGAIN
	mvi	a,flush		;mark command
	sta	commbuff
	call	markfatal
..nextvol:
	lda	dirtyvolume
	inr	a
	cpi	maxvol+1
	rnc			;no more volumes
	sta	dirtyvolume
	jmpr	..volloop

;
;	mark that a fatal error occured during buffer
;	flush, save command buffer that generated
;	error
;
markfatal:
	sta	con0	;save actual error
	lda	unitno
	sta	tag0		;save volume
	lxi	h,commbuff
	lxi	d,fatalsave
	lxi	b,commsize
	ldir
	xra	a
	sta	con1		;clear error flag
	cma			;now 0ffh
	STA	FATAL		;FATAL ERROR FLAG
	ret

.page
.sbttl	'get command from host'
;
;	GET COMMAND FROM HOST PROCESSOR
;
GETCOMMAND:

	LXI	B,2310	;ASSUME IDLE IF DCR TO 0
			;this constant chosen to
			;provide 30 millisec of idle
			;this should be enough time
			;for the master to have polled
			;everyone, and no one has 
			;anything to do
GC1:	IN	PSTATUS
	RRC
	RRC
	JRC	GC2
	DCX	B
	MOV	A,B
	ORA	C
	JRNZ	GC1
	CALL	idle		;WRITE ANY DIRTY SEC
	JMPR	GETCOMMAND
GC2:	IN	INPORT
	CPI	REQTOSEND
	JRZ	GETIT
ANSWAIT:
	IN	PSTATUS
	RRC
	JRC	ANSWAIT
	MVI	A,NOCLEAR
	OUT	OUTPORT
	JMPR	GETCOMMAND
GETIT:
	IN	PSTATUS
	RRC
	JRC	GETIT
	MVI	A,CLEAR
	OUT	OUTPORT
	LXI	H,COMMBUFF
	LXI	D,COMMSIZE
	CALL	goPREAD
	LDA	COMMBUFF
	ORA	A
	JZ	cmderror	;cannot init from firmware
	cpi	bootunit
	jz	cmderror	;go boot alternate unit
				;not supported from firmware
	DCR	A
	JrZ	ABSREAD
	DCR	A
	JRZ	ABSWRITE
	DCR	A
	JZ	cmderror	;cannot load user from
				;firmware
	DCR	A
	JRZ	ABSWRITE
	DCR	A
	JNZ	funcdecode	;see if firmware command
;
	LHLD	TAG0		;GET HDC ADDR
	XCHG
	LHLD	PHYHEAD		;BYTE COUNT
	JMPr	RDMEM
	.page
	.sbttl	'absolute read and write routines'
;
;
;
;		ABSOLUTE READ AND WRITE ROUTINES
;
STRIPR:			;GET MSB OF RETRYS
	LDA	CON0
	MOV	B,A
	ANI	80H
	STA	RDAFTW		;SAVE AS RAW OR ECC
	MOV	A,B
	ANI	07FH
	STA	CON0
	RET
;
;
ABSWRITE:
	LXI	H,BUFDATA
	LXI	D,1024
	CALL	goPREAD
	CALL	STRIPR
ABSW2:	CALL	WRITESEC
	MOV	B,A		;SAVE ERR RETURN
	JRZ	ABSW3		;IF NO ERR
ABSW2A:	LXI	H,CON0
	DCR	M		;DCR RETRYS
	JRNZ	ABSW2
	MOV	A,B		;GET ERR TYPE & RET
	JMPR	ABSW6
ABSW3:	LDA	RDAFTW		;CHECK FOR R AFTER W
	ORA	A
	JRZ	ABSW6		;RET IF NOT REQUIRED
ABSW4:	CALL	READSEC
	MOV	B,A
	JRNZ	ABSW2A
	LXI	H,BUFDATA	;COMPARE WRITE BUFFER
	LXI	D,RDDATA	;WITH READ BUFFER
	LXI	B,4		;FOR 1024 BYTES
ABSW5:	LDAX	D
	SUB	M		;LEAVE A=0 IF OK
	JRNZ	RWERR
	INX	H
	INX	D
	DJNZ	ABSW5		;LOOP
	DCR	C		;ABOVE LOOP 4 TIMES
	JRNZ	ABSW5
ABSW6:	STA	CON1		;RETURN STATUS
	jmp	sendst		;SEND BACK COMMAND BLOCK
RWERR:	LXI	H,CON0		;TEST FOR RETRY
	DCR	M
	JRNZ	ABSW2		;RETRY ENTIRE OPERATION
	MVI	A,hdereadafterwrite ;COMPARE ERROR CODE
	JMPR	ABSW6
;
ABSREAD:
	CALL	RDRTRY
	STA	CON1	;FOR NOW, JUST RETURN THE ERROR
			;STATUS INDICATION
	CALL	goPUTCOMD
	LXI	H,RDDATA
	LXI	D,1024
RDMEM:	jmp	writeandget
;
;
RDRTRY:				;READ AND RETRY TILL CON0=0
	CALL	STRIPR		;GET CORRECT WANTED BIT
	CALL	READSEC
	RZ
	MOV	B,A		;SAVE ERR TYPE
	LXI	H,CON0
	DCR	M
	JRNZ	RDRTRY
	MOV	A,B		;GET ERR TYPE
	ORA	A		;SET FLAG
	RET
	.page
	.sbttl	'cpm function decodeing'
funcdecode:
	.ife	debug,[
;
;	for debug purposes save in buffer past commands.
;	buffer has most recent command at top
;
pastcommands ==	6000h	;location of past history 
			;buffer
pastlen	== 2000h		;length of past history buffer
	lxi	d,pastcommands + pastlen - 1
	lxi h,pastcommands + pastlen - 1 - commsize
	lxi	b,pastlen - commsize
	lddr	;move old stuff down
	lxi	h,commbuff
	lxi	d,pastcommands
	lxi	b,commsize
	ldir	]

	LDA	COMMBUFF
	SUI	11H		;11H IS FIRST COMD
	JZ	HARDread
	DCR	A
	JZ	HARDW
	DCR	A
	JRZ	SELDSK
	DCR	A
	JRZ	DOFLUSH
	DCR	A
	JZ	DONETR
	DCR	A
	JRZ	DONETW
	DCR	A
	JZ	DOASGN
	dcr	a
	jz	dounitinfo
	dcr	a
	jz	generatecrcerror
;	JMP	TRYOASIS	;TRY OASIS COMMANDS
cmdERROR:
				;SET COMMAND ERROR BIT
	MVI	A,hdebadcommand
errexit:
	STA	CON1
SENDST:	CALL	goputcomd
	lxi	sp,stack	;clean up the stack
	JMP	getcommand
	.page
	.sbttl	'flush and netwrite'
;
DOFLUSH:
	lda	unitno
	push	psw		;save unit were on
	call	dirty		;clean up bad sector 
				;tables
..cleanloop:
	call	clean		;clean lru buffer
	jrnz	..cleanloop	;found one,may be more
	pop	psw
	call	swapunit	;restore unit we were
				;on
	JMPr	SENDST
;
;
DONETW:
	JMPr	cmderror	;invalid command

	.page
	.sbttl	'seleck disk and partition'

;
SELDSK:
	lda	unitno
	lxi	h,commbuff+2	;select physical drive
	cmp	m
	jrz	..sameunit
	lda	con0
	cpi	'M'		;check that multi disk
	jrnz	..sameunit	;select intended
	mov	a,m
	cpi	maxvol+1
	jrc	..doswap	;volume ok
	mvi	a,hdebdvolume
	jmpr	selexit
..doswap:
	call	swapunit	;go select new unit
..sameunit:
	lda	unitno
	call	setvolptr
	mov	a,vlipresent(x)
	cpi	true
	jrz	..ispresent
	lda	con0
	cpi	'M'
	jrnz	..trytoset	;try to set to a valid unit
..notpresent:
	mvi	a,hdeunitnotpresent
	jmpr	selexit
..trytoset:			;try to set to unit 0 for
	xra	a		;old rom and hinet
	sta 	unitno
	call	setvolptr
	mov	a,vlipresent(x)
	cpi	true
	jrnz	..notpresent	;still bad
..ispresent:
	LDA	COMMBUFF+1
	STA	FIXFLAG		;HARD9=FIXED HEADS
	cpi	maxpartitions	;check partition
	jrc	..partok	;requested is valid
	mvi	a,hdebdpartion
	jmpr	selexit
..partok:
	MOV	L,A
	MVI	H,0
	mov	e,vlibiastable(x)
	mov	d,vlibiastable+1(x)
	DAD	H
	DAD	D		;HL NOW POINTS TO BIAS FOR SELECTED DRIVE
	MOV	E,M
	INX	H
	MOV	D,M
	SDED	VBIAS
	INX	H
	MOV	E,M		;GET MAX BLOCK NO
	INX	H
	MOV	D,M
	SDED	MAXBIAS
	xra	a		;no error
selexit:
	sta	selerr
	lda	con0
	cpi	'M'		;if not multi disk
	jnz	getcommand	;do not return status block
	call	checkfatal	;see if error
			;occured if buffer flush
	lda	selerr
	JMP	errexit		;return status

;
;	check that no fatal error occured in flushing
;	of buffers
;
checkfatal:
	LDA	FATAL		;ERROR ON CLEAN
	ORA	A
	rz			;no error
	xra	a
	sta	fatal		;clear fatal flag
	lxi	h,fatalsave	;REPORT ERR
	lxi	d,commbuff
	lxi	b,commsize	;copy offending
	ldir		;command to buffer to send
			;back
	mvi	a,hdeflusherror
	jmp	errexit
	.page
	.sbttl	'swap unit and set volumne pointer'
;
;	swap unit, new unit passed in a
;	all parameters for rom, saved for
;	old unit and changed for new
;
swapunit:
	push	psw	;save new unit
	lda	unitno	;old unit
	call	setvolptr
	lda	trkd0	;current track for old unit
	mov	vlicurtrack(x),a ;save old track

	pop	psw	;restore new unit
	sta	unitno	;store as unit number
	call	setvolptr
	lxi	h,trkd0
	mov	a,vlicurtrack(x) ;set current track
	mov	m,a
	lxi	h,disktracks
	mov	a,vlitracks(x)	;set tracks info
	mov	m,a
	lxi	h,disktype
	mov	a,vlitype(x)	;set type
	mov	m,a
	inx	h
	mov	a,vlisize(x)	;set size
	mov	m,a
	ret

;
;	set x to point to volumne info
;	for unit passed in a
;	regs a,d,h altered
;
setvolptr:
	slar	a	;* 2
	mov	e,a
	mvi	d,0
	lxi	h,vliindex
	dad	d	;hl points to vol info ptr
	mov	e,m
	inx	h
	mov	d,m	;de points to vol info
	push	d
	pop	x	;x points to vol info
	ret
	
	.page
	.sbttl	'cpm 128 byte read routine'
;
;
; HARD DISK READ RTN
;
HARDREAD:
	call	cpmcheck	;is unit setup
	CALL	MAPC		;MAP TO BLOCK
	CALL	FINDSEC		;IS SEC IN BUFFER
	jrnz	..setmru
	call	readbuf		;read in buffer
..setmru:
	CALL	SETMRU		;MAKE IT MRU
	call	checkdirty	;if dirty buffer
			;may require cleaning
			;before use
	CALL	goputcomd
	CALL	SETPOINT
writeandget:
	CALL	gopwrite
	JMP	getcommand

;
;	get a buffer and read into it
;
readbuf:
	call	GETBUF		;NO, GET IT
	lhld	hardsec		;hard sector used 
	shld	tag0		;for read or write
	CALL	DOREAD
	jnz	errexit
	LdeD	CURADR		;MOVE DATA TO BUF
	LXI	H,RDDATA
	LXI	B,1024
	LDIR
	jmp	bufback		;return from there

;
;	one may read a sector which is in the buffers
;	and only partially written to.  in this case
;	merge the partially writen sector with the
;	disk image and mark every sector as dirty
;	to insure no later merges are necessary.
;
checkdirty:
	lda	curd	;each bit marks a dirty 128
	ora	a	;byte cpm record within
	rz		;the 1024 byte sector
	cpi	0ffh
	rz
	call	merge	;merge dirty buffer with
	mvi	a,0ffh	;disk sector
	sta	curd	;mark all 128 byte records
	jmp	bufback	;as dirty
			;return from there

;
;
SETPOINT:
	LHLD	CURADR
	LDA	SECSEG
	INR	A
	MOV	C,A
	LXI	D,128	;**********USED ABOVE******
..SETPTLP:
	DCR	C
	RZ
	DAD	D
	JMPR	..SETPTLP
;

;
;	check that select disk was ok and current
;	volume is present
;
cpmcheck:
	lda	unitno
	call	setvolptr
	mov	a,vlipresent(x)
	ora	a	;false is zero
	jrnz	..present
	lda	unitno
	sta	con0		;return unit which isn't
				;present
	mvi	a,hdeunitnotpresent
..checkfailed:
	pop	h		;dont return,clean stack
	jmp	errexit
..present:
	lda	selerr
	ora	a
	rz
	jmpr	..checkfailed

;
; RTN TO MAP CP/M TRACK AND SECTORS TO THE HARDDISK
;
MAPC:	LHLD	COMMBUFF+1
	DCR	L		;CPM USES 1-128
	MOV	A,L
	ANI	7
	STA	SECSEG		;3BITS
	MOV	A,L
	RAL
	MOV	L,A
	MVI	C,4
	CALL	SHIFT		;12 BITS LEFT IN HL
	LDA	COMMBUFF+3	;GET MSBYTE TRACK
	RAL
	RAL
	RAL
	RAL
	ANI	0F0H		;JUST IN CASE
	ADD	H
	MOV	H,A
	XCHG
	LHLD	VBIAS
	DAD	D
	SHLD	HARDSEC
	XCHG
	LHLD	MAXBIAS
	DCX	H		;CHECK LESS THAN
	ORA	A
	DSBC	D
	RNC			;RET IF OK
;
;	return directly to error proceedure
;
	pop	h		;clean stack
	mvi	a,hdecpmmapping	;mapping error
	jmp	errexit

	.page
	.sbttl	'cpm 128 byte write'
hardw:
	lxi	h,cpmwbuf
	lxi	d,128
	call	gopread	 ;get info to write buffer 
	call	cpmcheck	;is unit setup
	CALL	MAPC		;MAP TO BLOCK
	call	goputcomd	;at this point we know
				;we got a valid command
				;so let master continue
	CALL	FINDSEC		;IS SEC IN BUFFER
	jrnz	..setmru
	call	getbuf	
	call	calcths		;calculate track,
	lxi	d,curt		;head and sector
	lxi	h,phytrack	;and save
	lxi	b,3
	ldir
	lda	unitno	;save current volume
	sta	curvol	;info with buffer
..setmru:
	CALL	SETMRU		;MAKE IT MRU
	lhld	hardsec		;hard sector used 
	shld	tag0		;for read or write
;
; HARD DISK WRITE RTN
;
	CALL	SETPOINT	;returns address to 
			;place info in in h and length
			;in d
	xchg
	push	h
	pop	b
	lxi	h,cpmwbuf
	ldir
;
;	mark 128 byte cpm within sector as dirty
;	0th cpm record marked by settin 2**0 bit,etc
;
	lda	secseg	;sector within segment
	inr	a
	mvi	b,1
..markloop:
	dcr	a
	jrz	..set
	slar	b
	jmpr	..markloop
..set:	lda	curd
	ora	b
	sta	curd
	cpi	0ffh	;all sectors dirty
	cz	cleana	;write it out if so
	CALL	BUFBACK
	JMP	getcommand

	.page
	.sbttl	'netread (1k)'
DONETR:
	call	cpmcheck	;see that proper unit
				;selected
	CALL	MAPC		;MAP TO PHYSICAL
	CALL	FINDSEC		;IN BUFFER
	JRNZ	..getfrombuffer	;IF YES
	CALL	DOREAD
	jnz	errexit		;bad read
	mvi	a,false
	sta	tag1		;sector came from read
	LXI	H,RDDATA
	call	send1k		;send sector to host
	call	isanyclean	;see if clean
	jrz	..getanother	;buffer availible
	lda	tag0
	cpi	true
	jnz	getcommand  ;not forced to read another
..getanother:
	lhld	hardsec		;if so read in 
	inx	h		;next sector
	shld	hardsec
	call	findsec		;if next sector already
	jnz	getcommand	;in buffers dont read
	call	readbuf		
	call	setmru		;mark as most recent
	jmp	getcommand
..getfrombuffer:
	call	checkdirty	;make sure all 128
				;byte cpm records 
			;are latest
	mvi	a,true
	sta	tag1	;the data came from buffer
	LHLD	CURADR
	call	send1k
	lda	tag0
	cpi	true
	jrz	..getanother
	JMP	getcommand
;
;	send command buffer and 1k block to host
;	as fast as possible
;
send1k:
	PUSH	H
	CALL	goputcomd
	POP	H
	.ife	debug,[
	lxi	d,1024
	call	gopwrite	][
	LXI	D,2
	PUSH	H
	CALL	gopwrite		;SEND BLOCK TO HOST
	POP	H
	INX	H
	INX	H
	LXI	B,254*256+0FBH
	OUTIR
	OUTIR
	OUTIR
	OUTIR	]
	ret

	.page
	.sbttl	'assign command'
;
DOASGN:		;DO ASSIGN COMMAND
	LXI	D,14		;GET NAME, PASSWORD
	LXI	H,NAMPAS	;SAVE HERE
	CALL	gopread
	lda	unitno
	sta	saveunit	;save the present unit
				;to restore when done
	xra	a		;start with unit 0
..unitloop:
	call	swapunit
	lda	unitno
	call	setvolptr	;x reg points to vol
				;data
	mov	a,vlipresent(x)
	cpi	true
	jrnz	..notfound
	LXI	H,dtable	;TABLE IS BLOCK 15
	SHLD	HARDSEC
	CALL	DOREAD
	STA	CON1		;0 IF NO DISK ERR
	jrnz	..notfound
	LXI	H,RDDATA+1
	mvi	b,maxpartitions	;partion names to search
..nameloop:
	lxi	d,nampas
	ldax	d
	cmp	m
	jrz	..maybe
..more:			;see if more names to check
	lxi	d,16
	dad	d	;point hl to next entry
	djnz	..nameloop
	jmpr	..notfound
..maybe:		;maybe have a name match
	PUSH	B
	PUSH	H
	inx	h
	MVI	B,13		;CHECK OTHER 13 CHAR
..5:	INX	D
	LDAX	D
	CPI	00
	JRZ	..5A
	CMP	M
	JRNZ	..4		;NOT THIS ONE
..5A:	INX	H
	DJNZ	..5
	MOV	A,M
	STA	COMMBUFF+2	;FOUND, GET CTRL BYTE
	LXI	D,-15
	DAD	D		;GET TO SIZE BYTE
	MOV	A,M
	STA	COMMBUFF
	LXI	D,-(RDDATA)
	DAD	D	;RSLT SHOUULD = UNIT*16
	MVI	A,0FH
	ANA	L		;ARE WE OK
	JRNZ	..4
	POP	D		;PUSHED AS H,B
	POP	D
	MVI	C,4
	CALL	SHIFT
	MOV	A,L
..6:	STA	COMMBUFF+1	;partition
	lda	unitno		;drive unit found on
	sta	commbuff+3
	lda	saveunit
	call	swapunit	;restore active
				;unit called with
	JMP	SENDST		;SEND STATUS BACK
..4:	POP	H
	POP	B
	JMPR	..more	;go see if more names to try

..notfound:
	lda	unitno
	inr	a
	cpi	maxvol+1
	jrnz	..unitloop
	MVI	A,0FFH		;SET DENIED FLAG
	STA	COMMBUFF
	JMPR	..6
	.page
	.sbttl	'return volumne info'
dounitinfo:
	lda	lcromversion	;return rom version 
	sta	commbuff+1	;and revision
	lda	lcromrevision
	sta	commbuff+2
	lda	usrprog+offversion	;return firmware 
	sta	commbuff+3		;version and
	lda	usrprog+offrevision	;revision
	sta	commbuff+4
	xra	a
	sta	con1	;no error
	call	goputcommand
	lxi	d,vlibufsize*4	;bytes to send
	lxi	h,vli0
	jmp	writeandget

	.page
	.sbttl	'generate crc error on last sector'
;
;	generate a crc error on the last sector of
;	the disk to allow crc circuitry test from
;	hardhelp
;
generatecrcerror:
	lda	disksize
	sta	phyhead		;last valid head
	lda	disktracks
	dcr	a
	sta	phytrack	;last valid track
	call	selunit		;talk to desired unit
	call	setup		;get to track and
				;get head selected
	lda	disktype
	sta	physec		;last valid sector
	call	finds1		;find sector minus 1
;
;	write and abort after 32 bytes
;
	call	hwrt		;issue write command
	mvi	b,0		;write and abort counter
..waloop:
	in	cstatus
	ani	10h
	jrnz	..wdelay	;wait for byte 32
	djnz	..waloop
..wdelay:mvi	a,128
..delloop:dcr	a		;delay .5 msec for 
	jrnz	..delloop	;refresh
	out	command		;get ram back
	jmp	getcommand	;go get another 
				;request

	.page
	.sbttl	'find a sector in the buffer'
;
;	now check that volume number in buffer info agrees
;	with current volume number
;
;	on return zero flag clear if sector found
;
FINDSEC:		;COMP (HARDSEC) WITH SEC NO
			;FIELD FOR EACH BUFFER
	LHLD	HARDSEC
	MOV	A,H		;COMP FROM A,C
	MOV	C,L
	MVI	B,NUMBUF	;LOOP CONTROL
	LXI	H,BUFINFO+3	;SEC NO FIELD
	LXI	D,BLEN		;BUFINFO LENGTH
..4:	CMP	M		;COMP MS BYTE
	JRNZ	..2		;NOT EQUAL
	PUSH	PSW		;SAVE
	DCX	H		;CHECK LS BYTE
	MOV	A,M
	CMP	C
	JRZ	..3		;IF BOTH COMP
..notfound:
	POP	PSW
	INX	H		;RESTORE
..2:	DAD	D		;GET NEXT BUF
	DJNZ	..4
	XRA	A
	RET			;ZERO SET=NOT FOUND
;
..3:	
	push	h
	pop	y
	lda	unitno
	cmp	6(y)		;volume byte in info
	jrnz	..notfound
	POP	PSW		;CLEAN STACK
	MVI	A,NUMBUF+1	;COMPUTE NUM OF BUF
	SUB	B
	STA	CURBNO
	DCX	H
	DCX	H
MVBUFI:	LXI	D,CURADR	;MOVE BUF TO CURBUF
	LXI	B,BLEN
	SHLD	BIADR		;SAVE WHERE CAME FROM
	LDIR
	INR	B		;CLEAR ZERO
	RET			;NOT ZERO = FOUND
;
	.page
	.sbttl	'get a free buffer'
;
GETBUF:			;GET OR MAKE A FREE BUFFER
			;CLEAN IF LRU IS DIRTY
		;do not READ HARDSEC INTO BUFFER
	call	isanyclean
	JZ	..somethingclean
	lda	unitno
	push	psw		;save current unit
;
;	find the nearest dirty buffer (distance away
;	in tracks) and flush it.  look for nearest 
;	on any volume if more than on present
;
	lxi	h,distance
	mvi	m,0ffh		;largest distance
				;possible
	mvi	b,numbuf	;number of buffers
				;to check
	lxi	h,mrutab
..nearestloop:
	mov	a,m
	push	b
	push	h
	call	bufy	;get info about buffer
	mov	a,bfivolume(y)
	call	setvolptr ;get track info about
				;that volume
	mov	a,bfitrack(y) ;track for buffer
	sub	vlitracks(x)
	jrnc	..knowdistance
	mov	a,vlitracks(x)
	sub	bfitrack(y)
..knowdistance:
	lxi	h,distance
	cmp	m
	jrnc	..keepon
	sta	distance
	pop	h
	push	h
	mov	a,m
	sta	nearest
..keepon:
	pop	h
	pop	b
	inx	h	;point to next buffer number
	djnz	..nearestloop
	lda	nearest	;now know nearest so clean it
	call	locbuf
	CALL	CLEANA		;MARK CLEAN
	lda	unitno
	sta	volclean	;save volume that
				;on track for
.page
;
;	write out any buffers on same track while 
;	there
;
	LXI	H,MRUTAB+NUMBUF-1
	LDA	CURT		;LOOK FOR ANY OTHER
	MOV	C,A		;DIRTY BUF ON SAME TRK
	MVI	B,NUMBUF
..3:	PUSH	b
	PUSH	h

	MOV	A,M		;FROM MRU TABLE
	CALL	bufy		;GET PARAMETERS
	mov	a,bfidirty(y)
	ORA	A
	JRZ	..4		;IF NOT DIRTY
	mov	a,bfitrack(y)	;GET TRK WE ARE ON
	CMP	C
	JRNZ	..4		;IF DIFF TRACK
	mov	a,bfivolume(y)
	lxi	h,volclean	;check that on same
	cmp	m		;volume
	jrnz	..4
	pop	h
	push	h
	mov	a,m
	call	locbuf
	CALL	CLEANA
..4:	POP	h
	POP	b
	dcx	h		;look at previous
				;buffer
	DJNZ	..3
	pop	psw
	call	swapunit	;restore current unit
	lda	nearest		;is now clean
	call	locbuf		;get buffer info ready
..somethingclean:	
	LHLD	HARDSEC
	SHLD	CURSEC		;SAVE SEC NUM
	CALL	BUFBACK
	RET
.page
.sbttl	'is any buffer clean'
;
;	return zero if any buffer is clean,
;	non zero if dirty.  set up current
;	buffer if clean.  searches from least
;	recently used.
isanyclean:
	mvi	b,numbuf	;number of buffers
				;to search
	lxi	h,mrutab+numbuf-1 ;end of most
			;recently used is least r.u.
..cleanloop:
	mov	a,m	;buffer number
	call	bufy	;get y reg to point to buffer
	mov	a,bfidirty(y)
	ora	a
	jrz	..found
	dcx	h
	djnz	..cleanloop
	ora	a
	ret		;return non zero for failure
..found:
	mov	a,m
	call	locbuf	;get buffer info
	xra	a	;set zero flag success
	ret
	
;
;	get y register to point to buffer info
;	specified in a register. d register molested
;	in process
;
bufy:
	rlc
	rlc
	rlc		;*8
	add	m	;*9
	lxi	d,bufinfo-blen
	add	e
	jrnc	..nocarry
	inr	d
..nocarry: mov	e,a
	push	d
	pop	y
	ret
.page
.sbttl	'locbuf,cleana,cleanb and bufback'

;
;
;  FOLLOWING ROUTINE IS CALLED WITH BUFNO IN A, MOVES
;  CORRECT BUFINFO TO CURBUF
;
LOCBUF:	STA	CURBNO
	LXI	H,BUFINFO-BLEN	;WILL DAD>0
	LXI	D,BLEN
..2:	DAD	D
	DCR	A		;RANGE 1 TO NUMBUF
	JRNZ	..2
	JMP	MVBUFI		;DO MOVE
;
;  BUFBACK RESTORES BUFINFO FROM CURBUF
;
CLEANA:	CALL	DOWRITE
CLEANB:	XRA	A		;MARK CLEAN
	STA	CURD		;AND PUT BACK
BUFBACK:
	LHLD	BIADR
	XCHG
	LXI	H,CURADR
	LXI	B,BLEN
	LDIR
	RET
	.page
	.sbttl	'set buffer most recently used'
SETMRU:	LDA	CURBNO		;SET CUR TO MRU
	LXI	B,NUMBUF	;LOOP CONTROL
	MOV	E,C
	LXI	H,MRUTAB
	CCIR			;FIND POS IN TABLE
	MOV	D,A		;SAVE MRU
	MOV	A,E
	SUB	C		;NUMBUF-POSITION
	DCR	A		;ALREADY MRU
	RZ			;IF YES
	MOV	C,A		;NUM TO MOVE DOWN
	MOV	A,D
	DCX	H		;ADJUST FROM CCIR
	MOV	D,H
	MOV	E,L		;MAKE DEST
	DCX	H
	LDDR			;MOV DOWN ONE
	INX	H		;POINT TO MRU
	MOV	M,A
	RET
	
	.page
	.sbttl	'doread and dowrite'
DOREAD:			;READ HARDSEC INTO RDDATA
	lda	unitno
	sta	curvol	;set up current bol to store
			;with buffer info
	CALL	CALCTHS		;CONVERT SECNO TO THS
	MVI	A,10		;10 ReTRYS,no error
	CALL	DSETUP		;correction
	LDIR			;PUT THS TO CURINFO
DORD2:
..tryagain:	
	CALL	readsec
	STA	CON1		;SAVE ERR RESULT
	RZ			;IF NO ERR
	LXI	H,CON0
	DCR	M
	JRZ	..bad		;no retries left
	mov	a,m
	cpi	8
	jrnz	..tryagain	;after second try 
				;allow error 
				;correction
	lxi	h,rdaftw
	mvi	m,80h		;flag to use error
	jmpr	..tryagain	;correction
..bad:
	ora	A		;FORCE NON ZERO
	RET
;
DOWRITE:		;WRITE HARDSEC TO DISK
;
;	we have in the buffer all dirty
;	cpm sectors within the hard disk sector.
;	if all are dirty just send it out, otherwise
;	read sector from disk and copy clean sectors
;	to buffer, then send it out.  it is marked as
;	clean and is stil availible in buffer for
;	subsequent reads
;
	lda	curd
	cpi	0ffh
	jrz	..setup	;all dirty no need to read
	call	merge	;merge buffer with disk sector
..setup:
	LHLD	CURADR		;MOVE TO WRITE AREA
	LXI	D,BUFDATA
	LXI	B,1024
	LDIR
	MVI	A,10		;RETRYS
	CALL	DSETUP
	XCHG
	LDIR		;MOVE CUR TO THS
	MOV	M,B		;PUT 0 IN DIRTY
..2:	CALL	writesec
	RZ
	LXI	H,CON0
	DCR	M		;CHECK RETRYS
	JRNZ	..2
	call	markfatal
	RET			;NON ZERO = ERROR
;
;	merge buffer with sector from disk into buffer,
;	copying 128 byte cpm records from disk image
;	into buffer
;
merge:
;
;	read in the sector
;
	MVI	A,10		;10 ReTRYS,no error
	CALL	DSETUP		;correction
	xchg
	LDIR			;PUT THS TO CURINFO
	call	dord2
	jrz	..rdcomplete	;IF NO ERR
	call	markfatal	;error, flag but
				;go on
..rdcomplete:
	mvi	a,1	;bit which will be rotated
	sta	whichbit ;around to test dirty sectors
	lded	curadr	;where to copy to
	lxi	h,rddata
..copyloop:
	lxi	b,128
	push	h
	lxi	h,curd
	ana	m
	pop	h
	jrnz	..dontmove	;sector is dirty
	ldir
..next:
	lda	whichbit
	slar	a
	sta	whichbit
	jrnz	..copyloop
	ret			;done
..dontmove:			;advance pointers
	dad	b
	push	h
	xchg
	dad	b
	xchg
	pop	h
	jmpr	..next

;
DSETUP:			;SETUP RETRY CNT
	mov	b,a
	ani	7fh	;strip error correction bit
	sta	con0
			;set error correction
	mov	a,b
	ani	080h
	sta	rdaftw
	lda	curvol
	call	swapunit	;ready to act from
				;right vol
	LXI	D,CURT		;XCHG CURTHS,THS
	LXI	H,PHYTRACK	;SOURCE FOR READ
	LXI	B,3
	RET

	.page
	.sbttl	'calculate track head and sector'

CALCTHS:
	LHLD	HARDSEC
;
; HL NOW HAS A NUMBER THAT IS ONE OF THE 28,000 SECTORS
;ON THE HARD DISK. WE NOW NEED TO BREAK THIS DOWN INTO
;TRACK AND HEAD.
;
; FIRST DIVIDE BY NUM OF SEC PER TRK
;
RDHL:
	CALL	DIVSPT
	INR	A
	STA	PHYSEC
;
; HL NOW HAS REMAINING NUMBER TO CALC TRACK AND HEAD
;
	LDA	FIXFLAG		;CHECK FOR FIXED HEADS
	CPI	63
	JRNZ	CHT
	MVI	A,8
	ADD	L		;GET TO HEAD 8-F
	STA	PHYHEAD
	MVI	A,0FFH		;FIXED HDS ARE TRK FF
	STA	PHYTRACK
	RET
CHT:	LDA	DISKSIZE
	ANI	4		;THIS BIT=28MBYTE
	MOV	C,A		;SAVE IT
	ORI	3
	ANA	L
	STA	PHYHEAD		;PHY HEAD (0-7)
;
; SHIFT REMAINING BITS 2 OR 3 PLACES TO GET THE TRACK
;
	MOV	A,C		;GET 28MB BIT
	RAR
	RAR
	ADI	2		;NOW = 2 OR 3
	MOV	C,A
	CALL	SHIFT
	MOV	A,H
	ORA	A		;SHOULD BE 0
	JRZ	..2
	MVI	A,0FEH		;FORCE ILLEGAL TRK
	JMPR	..3
..2:	MOV	A,L
..3:	STA	PHYTRACK
	RET

	.page
	.sbttl	'shift and divide'
;
;SHIFTS HL TO THE RIGHT BY THE AMOUNT IN C.
;
SHIFT:
	SRLR	H
	RARR	L
	DCR	C
	JRNZ	SHIFT
	RET
;
;
; DIVIDE BY NUMBER OF SECTORS PER TRACK
;
DIVSPT:	LDA	DISKTYPE	;DIV BY SEC/TRK
DIVIDE:			;DIVIDE (HL) BY (A)
	MVI	B,0FFH
DV1:	RLC
	INR	B		;NORMALIZE AND COUNT
	JrNC	DV1
	RRC			;FIX ONE TOO MANY
	RRC
;
	PUSH	B
	MOV	C,A		;WILL SUB FROM C
	MVI	D,0FFH		;CATCH CASE HL>8800
	MOV	A,H
..2:	MOV	H,A
	SUB	C
	INR	D
	JrNC	..2
	MOV	A,D
	CALL	DV3B
	MOV	D,A		;SAVE FIRST RESULT
	MVI	B,8		;DO 8 MORE
	CALL	DV3
	MOV	E,A
	MOV	A,H
	XCHG			;RESULT TO HL
	POP	B		;NORM COUNT
DV2:	RAR
	DJNZ	DV2
	RET
;
DV3:	XRA	A
DV3A:	RLC
DV3B:	MOV	E,A		;BUILD RESULT
	MOV	A,H
	SUB	C		;TEST THIS BIT
	JrNC	DV4		;IF C TOO BIG
	XRA	A
	JMPR	DV5
DV4:	MOV	H,A		;RESTORE H
	MVI	A,1		;THIS RESULT
DV5:	ADD	E		;ADD PREV RSLT
	DAD	H		;SHIFT HL
	DJNZ	DV3A		;LOOP
	RET
;
	.page
	.sbttl	'oasis commands'
dooasis	==	0	;0 to include oasis
			;1 to exclude code
		
;
;	oasis conditionally supported
;	NOTE: OASIS CODE STILL USES ROM READ AND
;	WRITE CODE WITH SLOW SETTLE TIMES
;
TRYOASIS:			;CHECK FOR OASIS COMD
.ife	dooasis,[
	LDA	COMMBUFF
	CPI	021H
	JRZ	OAREAD
	CPI	022H
	JRZ	OAWRITE
	jmp	cmderror
	]
;
;
;******************************************************
;OASIS READ
;OASIS RENDS TRACK, HEAD, SECTOR, AND WHICH 256 BYTE
;LOGICAL SECTOR (0-3) TO SEND
;SEE IF THE SECTOR IS ALREADY IN
.ife	dooasis,[
OAREAD:
	CALL	goreadsec		;READ IT IN
				;ACC HAS STATUS
	STA	CON1
	CALL	goputcomd	;ECHO IT BACK
			;GET CORRECT 256 BYTE SECTOR
	CALL	OASTPT
			;H,L HAVE START OF BUFFFER
RD10:
				;D,E HAVE 256 * TAG1
	LDA	TAG1
	MOV	D,A
	XRA	A
	MOV	E,A
	jmp	 writeandget

;
;******************************************************
;OASIS WRITE
;OASIS SENDS TRACK, HEAD, SECTOR, AND WHICH 256 BYTE
;LOGICAL SECTOR TO CHANGE
OAWRITE:
	LXI	H,TBUFF1	;GET THE DATA FROM THE
			;HOST AND PUT INTO TEMP BUFFER
	MVI	E,0
	LDA	TAG1
	MOV	D,A
	CALL 	gopread
;NOW SEE IF THE PHYSICAL SECTOR IS ALREADY IN MEMORY
	CALL	goreadsec
	;1K PHYSICAL SECTOR IS NOW IN THE READ BUFFER.  
			;FIND THE CORRECT 256 BYTE AREA
	CALL	OASTPT
			;H,L HAVE START OF 256 BYTE AREA
			;PUT INTO D,E AS DESTINATION
	XCHG
				;SOURCE
	LXI	H,TBUFF1
				;LENGTH=256*TAG1
	LDA	TAG1
	MOV	B,A
	MVI	C,0
	LDIR
				;WRITE THE BUFFER
	LXI	H,RDDATA
	LXI	D,BUFDATA
	LXI	B,1024
	LDIR
	CALL	gowritesec
				;ACC HAS STATUS
	STA	CON1
	jmp	sendst

;
;
OASTPT:
	LXI	H,RDDATA
	LDA	TAG0
	INR	A
	LXI	D,256
SET10:
	DCR	A
	RZ
	DAD	D
	JMPR	SET10
	]
	.insert hardrw
	.insert	hardcrc
	.page
	.sbttl	'inited data area'
;
TBUFF1	=	0D000H
;
;
HARDSEC:	.WORD	0
SECSEG:		.BYTE	0
VBIAS:		.WORD	0
MAXBIAS:	.WORD	0
BOOTERR:	.BYTE	0
FIXFLAG:	.BYTE	0
FATAL:		.BYTE	0		;FATAL ERR FLAG
;
BUFINFO:		;ONE BLOCK FOR EACH 1K BUFFER
BUF1:	.WORD	5400H,0FFFFH
	.BYTE	0,0,0,0,0
BUF2:	.WORD	5800H,0FFFFH
	.BYTE	0,0,0,0,0
BUF3:	.WORD	5C00H,0FFFFH
	.BYTE	0,0,0,0,0
BUF4:	.WORD	6000H,0FFFFH
	.BYTE	0,0,0,0,0
BUF5:	.WORD	6400H,0FFFFH
	.BYTE	0,0,0,0,0
BUF6:	.WORD	6800H,0FFFFH
	.BYTE	0,0,0,0,0
BUF7:	.WORD	6C00H,0FFFFH
	.BYTE	0,0,0,0,0
BUF8:	.WORD	7000H,0FFFFH
	.BYTE	0,0,0,0,0
BUF9:	.WORD	7400H,0FFFFH
	.BYTE	0,0,0,0,0
BUFa:	.WORD	7800H,0FFFFH
	.BYTE	0,0,0,0,0
BUFb:	.WORD	7C00H,0FFFFH
	.BYTE	0,0,0,0,0
BUFc:	.WORD	0C000H,0FFFFH
	.BYTE	0,0,0,0,0
BUFd:	.WORD	0C400H,0FFFFH
	.BYTE	0,0,0,0,0
BUFe:	.WORD	0C800H,0FFFFH
	.BYTE	0,0,0,0,0
BUFf:	.WORD	0CC00H,0FFFFH
	.BYTE	0,0,0,0,0
BUF10:	.WORD	0D000H,0FFFFH
	.BYTE	0,0,0,0,0
;
MRUTAB:	.BYTE	1,2,3
	.ifn	debug,[
	.byte	4,5,6,7,8,9,10,11,12,13,14,15,16
	]
NUMBUF	=	.-MRUTAB

CUMBLK:	.BYTE	0	;cumulative block count in init

vliindex:		;index by unit into volumne info
	.word	vli0
	.word	vli1
	.word	vli2
	.word   vli3

vli0:
	.byte	false	;volumne present
	.byte	0ffh	;current track
	.byte	shutracks	;tracks on disk
	.byte	memsectors	;sectors / track
	.byte	mem11headmask	;head mask
	.word	h0bias	;partition bias table
	.word	badtable ;bad table location
	.word	bstdrty ;location of bad sector dirty
			;flag
	.byte	0	;failure if any in init disk reads
	.ascii	/no volabel/ ;label
	.blkb	vlibufsize+vli0-.

vli1:
	.byte	false	;volumne present
	.byte	0ffh	;current track
	.byte	shutracks	;tracks on disk
	.byte	memsectors	;sectors / track
	.byte	mem11headmask	;head mask
	.word	h1bias	;partition bias table
	.word	bad1table ;bad table location
	.word	bad1dirty ;location of bad sector dirty
			;flag
	.byte	0	;failure if any in init disk reads
	.ascii	/no volabel/ ;label
	.blkb	vlibufsize+vli1-.

vli2:
	.byte	false	;volumne present
	.byte	0ffh	;current track
	.byte	shutracks	;tracks on disk
	.byte	memsectors	;sectors / track
	.byte	mem11headmask	;head mask
	.word	h2bias	;partition bias table
	.word	bad2table ;bad table location
	.word	bad2dirty ;location of bad sector dirty
			;flag
	.byte	0	;failure if any in init disk reads
	.ascii	/no volabel/ ;label
	.blkb	vlibufsize+vli2-.

vli3:
	.byte	false	;volumne present
	.byte	0ffh	;current track
	.byte	shutracks	;tracks on disk
	.byte	memsectors	;sectors / track
	.byte	mem11headmask	;head mask
	.word	h3bias	;partition bias table
	.word	bad3table ;bad table location
	.word	bad3dirty ;location of bad sector dirty
			;flag
	.byte	0	;failure if any in init disk reads
	.ascii	/no volabel/ ;label
;	.blkb	vlibufsize+vli3-.
	.ifg	.-4f00h,[
	.prntx	'too much code'][
	.prntx	'code length ok']
	.page
	.sbttl	'uninited buffers'
;
;	after this point only uninited buffers
;	allowed
;
H0BIAS:	.BLKW	64	;partion offset table
H1BIAS:	.BLKW	64	;partion offset table
H2BIAS:	.BLKW	64	;partion offset table
H3BIAS:	.BLKW	64	;partion offset table

readflag:.blkb	1	;true if present operation is
			;a read, false if a write.
			;used for generating different
			;settle times
fullsettleoccurred:.blkb 1	;flag set when a full
			;settle has occured so writes
			;can be done with no further
			;settling
nosettleok:.blkb 1	;flag set if rom version
			;indicates hardware mods for
			;no settling have occured
BIADR:	.blkw	1		;ADR OF BUF FOR CURINFO
CURBNO:	.blkb	1		;BUF NUM OF CUR
CURADR:	.blkw	1		;CURRENT BUF ADR
CURSEC:	.blkw	1		;CUR SECTOR NUMBER
CURT:	.blkb	1		;CUR TRACK
CURH:	.blkb	1		;CUR HEAD
CURS:	.blkb	1		;CUR SECTOR
CURD:	.blkb	1		;=FF IF CUR BUF DIRTY
curvol:	.blkb	1		;current volume
BLEN	=	.-CURADR	;LENGTH OF INFO BLOCK
;
;
;**********************WARNING
;
;	LAST ADR MUST BE LESS THAN 5400 (BUF11)
;
	.ifg	5400h-.,[
	.prntx	'ram used ok'][
	.prntx	'too much ram used']

	.page
	.sbttl	'init code overwrite buffers'

;
;	the following uninited buffers overwrite the
;	firmware init code
;	NOTE: NO VARIABLES DEFINEED HERE MAY BE USED IN
;	IN INIT CODE
;
	.loc	usrprog + 3	;jump to function decode
				;at beginning of firmware

NAMPAS:	.BLKB	14	;name and password tested
			;for assign

saveunit:.blkb	1	;save unit during assign
selerr:	.blkb	1	;error from seldsk,passed
			;back in subsequent read
			;or write
dirtyvolume:.blkb 1	;used to keep track of volume
			;whose dirty bad sector
			;tables are being written
			;to disk in routine dirty
volclean:.blkb	1	;used to keep volume that
			;lru buffer written to to
			;check if any other sector
			;on same track
cpmwbuf:.blkb 128	;read stuff from host to here
fatalsave:.blkb commsize	;buffer to save error
			;that occurs during flush
			;of buffers
whichbit:.blkb	1	;which of curd(current dirty)
			;byte looking at during 
			;merging of partially dirty
			;write buffer and clean
			;sector from disk
nearest: .blkb	1	;buffer number of dirty 
			;buffer nearest the current
			;track
distance:.blkb	1	;the distance in tracks to
			;the nearest dirty buffer
			;from a current track postion

	.ifg	dummy0-.,[
	.prntx 'buffers overwriting init code ok'][
	.prntx 'buffers overwriting init code too big']

	.end
