;
; Hyperdriver
;
; 00.01 08/02/82 SBW Created
; 00.02 08/10/82 sbw Disable interrupts around moves
;
	nam	hyper
;
	org	0
hypnum:	ds	1	; Number of table entries
hyptab:	ds	2	; Addr of first table entry
hyplab:	ds	2	; Addr of hyperdrive label
hyprd:	ds	3	; Jump to read from hyperdrive
hypwr:	ds	3	; Jump to write to hyperdrive
hypsdt	equ	$	; Begin SDT patch area
	org	0
hyplen:	ds	2	; Size of the bank
hypadr:	ds	2	; Start addr+size
hypbnk:	ds	1	; Bank byte
hypsiz	equ	$	; Size of table entry
	rog
;
	icl	dskparm
;
	ent	hypset,hypio,hypspc
	ext	csdte,cducb
	ext	move		; @de->@hl until bc==0
	ext	eiinst
;
; Special call
;
hypspc:
	shld	chype		; Save current hyperdrive control block
	pop	psw		; Throw away buffer address
	mov	a,c		; Special command
	cpi	10		; Set disk characteristics?
	jnz	..1
;
	mov	a,m
	ani	80h		; Hyperdrive needs initialization?
	jz	..1
;
	mov	a,m		; Yes: clear init flag
	ani	7fh
	mov	m,a
;
	lxi	b,hyplab	; Labelled from previous incarnation?
	dad	b
	mov	e,m
	inx	h
	mov	d,m
	push	d		; Save pointer to canned label
;
	mvi	e,2		; Sector 2 (Directory start)
	call	dumzset		; Unit, track, surface all zero
	xra	a
	call	dumio		; Read first block of directory
;
	lxi	h,buff
	pop	d		; Compare canned label to directory
	mvi	b,32
	mvi	c,1		; Flag no directory init necessary
  .do
	ldax	d
	cmp	m
	jz	..2
	mvi	c,0		; If a difference found, flag init needed
	mov	m,a		; Move in label in any case
..2:
	inx	h
	inx	d
	dcr	b
	jnz	.do
  .until
	dcr	c		; Init needed?
	jz	..3		; Jump if no dir init needed, to patch SDT
;
	mvi	b,128		; else fill rest of first dir block w/e5s
	call	e5s
;
	call	dumwr		; Write first directory block back out
;
	lxi	h,buff		; Get a buffer of E5s
	mvi	b,128
	call	e5s
;
	lhld	chype
	lxi	b,(hypsdt-hypnum)+(sdtmln-sdtcsz)
	dad	b		; Point to # of dir entries
	mov	a,m
	ora	a
	rar			; Four entries per block
	rar
	mov	d,a
	dcr	d		; Minus one for first block already written
	mvi	e,3		; Sector 3 (Second directory block)
;
  .do
	push	d
	call	dumzset		; e=sector (1..)
	call	dumwr		; Call HYPIO to write
	pop	d
	inr	e		; Do until directory cleared
	dcr	d
	jnz	.do
  .until
;
..3:
	lhld	chype		; Restore control block
	lxi	b,hypsdt	; Point to hyperdrive size table
	dad	b
	xchg
	lhld	csdte		; Point to SDT
	lxi	b,sdtcsz	;     cluster size field
	dad	b
	lxi	b,sdtdty-sdtcsz	; Patch SDT for size of hyperdrive
	call	move
..1:
	xra	a
	ret			; Return no error
;
e5s:				; 0e5h to @hl++ until b==0
  .do
	mvi	m,0e5h
	inx	h
	dcr	b
	jnz	.do
  .until
	ret
;
dumzset:
	xra	a		; Surface zero
	mov	b,a		; Unit zero
	mov	c,a		; Track zero
	mov	d,a
dumset:
	push	h
	lhld	chype
hypset:				; Set head:
	shld	chype
	mov	b,a
	pop	psw		; Throw away saved HL
	mov	a,b
	ora	a		; Must always be surface zero
	mvi	a,de$ilbk	; else illegal block #
	jnz	hyperr
;
	push	d
	mov	b,m		; Get count of table entries
	inx	h
	mov	e,m		; Get addr of first table entry
	inx	h
	mov	d,m
	xchg
	pop	d
;
; b=# table entries, *hl=table, cd=Track (0..), e=Sector(1..128)
;
	mov	a,e
	dcr	a		; Make sector (0..)
	ral			; Combine with track
	mov	e,a
	mov	a,c
	ora	a
	rar
	mov	c,a
	mov	a,d
	rar
	mov	d,a
	mov	a,e
	rar
	sui	1		; Subtract one to make block zero
	mov	e,a		; non-existant (will give illegal
	mov	a,d		; block error below) because directory
	sbi	0		; start may not be zero, and we do not
	mov	d,a		; Need any boot area on the hyperdrive.
	mov	a,c
	sbi	0
	mov	c,a
;
; cde=Block
;
  .do
	mov	a,e		; cde -= Length of bank
	sub	m
	mov	e,a
	inx	h
	mov	a,d
	sbb	m
	inx	h
	mov	d,a
	mov	a,c
	sbi	0
	mov	c,a
	jc	found		; cde<0 means found the bank
;
	inx	h		; else point past 
	inx	h		;      start addr
	inx	h		; Point past bank byte
	dcr	b		; More table entries?
	jnz	.do
  .until
	mvi	a,de$ilbk	; No: illegal block
hyperr:
	mov	b,a
	mvi	a,de$xerr
	ora	a
	ret			; Return the error
;
found:				; Found: add the length + bank start addr
	mov	a,e
	add	m
	mov	e,a
	inx	h
	mov	a,d
	adc	m
	mov	d,a		; hl=block addr of requested data within bank
	xchg
;
	dad	h
	dad	h
	dad	h		; Make memory addr out of block addr
	dad	h
	dad	h
	dad	h
	dad	h
;
	inx	d
	ldax	d		; Get the bank byte
	sta	bank		; Save for I/O routines
	shld	addr
	xra	a		; Return no error
	ret
;
dumwr:
	mvi	a,1		; Flag a write
dumio:
	lxi	h,buff		; Hyperdriver uses its own buffer for I/O
	push	h
	lhld	chype
hypio:
	shld	chype
	lhld	addr		; hl := data addr
	lxi	d,buff		; de := buffer addr
	ora	a
	jz	read		; a=0 read
;
write:
	xthl			; Get I/O addr
	xchg			; hl := buffer addr
	lxi	b,128
	call	move		; buffer := data
	lda	bank		; Get bank byte
	pop	h		; Get data addr
	lxi	d,buff		; Get buffer address
	call	hywrite		; Write to hyperdrive
	jmp	iodone
;
read:
	lda	bank		; Get bank byte
	xchg			; hl:=buffer address, de:=hyper address
	call	hyread		; buffer := hyper data
	pop	h		; get I/O addr
	lxi	d,buff
	lxi	b,128
	call	move		; I/O addr := buffer
iodone:
	xra	a
	ret			; Return no error
;
hyread:
	lxi	b,hyprd
	jmp	rdwr
;
hywrite:
	lxi	b,hypwr
rdwr:
	push	h
	lxi	h,eiinst	; Make a return address which reenables
	xthl			; the interrupts after the move.
;
	push	h
	lhld	chype
	dad	b		; Point to read or write routine
	xthl
	lxi	b,128		; Always 128 bytes in this version
	di			; Disable interrupts
	ret			; Jump to read or write routine
;
	ram
bank:	ds	1		; Bank containing requested data
addr:	ds	2		; Physical address within bank
chype:	ds	2		; Current hyperdirve control table entry
buff:	ds	128		; Transfer buffer
;
	end

