;************ biosio.z8k **************************
;*
;*	Direct disk I/O for the Disk copy program
;*	for Olivetti M20 (Z8001) system.
;*
;* 830214 F. Zlotnick (Zilog) -- created, stolen from
;*	the M20 Bios routines written by Steve Savitzky.
;*
;****************************************************

;****************************************************
;*
;* Global declarations
;*
;****************************************************


	.global	_disk_io
	.global _bdos

;****************************************************

SUPV	.equ	62		; Supervisor state BDOS call
BDOS_SC	.equ	2		; System call number 2

;****************************************************
;
; 	Following macro stolen from Steve Savitzky
;
;****************************************************

scall	.MACRO

	.word	05f00h		; 5F00 = segmented call
	.long	?1		; segmented address

	.ENDM

__text:	.sect

;****************************************************
;*
;* NOTE	The Olivetti PROM routines are segmented.
;*	The C portion of the copy program is non-segmented.
;*
;*	This assembly-language module is assembled
;*	non-segmented, and serves as the interface.
;*
;*	Segmented operations are well-isolated, and
;*	are either the same as their non-segmented
;*	counterparts, or constructed using macros.
;*
;****************************************************



;****************************************************
;*
;* C Stack frame equates
;*
;*	A C stack frame consists of the PC on top,
;*	followed by the arguments, leftmost argument first.
;*
;*	The caller adjusts the stack on return.
;*	Returned value is in r7 (int) or rr6 (long)
;*
;****************************************************

PCSIZE	.equ	2		;PC size non-segmented
INTSIZE	.equ	2		;INT data type size
LONGSIZE .equ	4		;LONG data type size

ARG1	.equ	PCSIZE		;integer arguments
ARG2	.equ	ARG1+INTSIZE
ARG3	.equ	ARG2+INTSIZE
ARG4	.equ	ARG3+INTSIZE
ARG5	.equ	ARG4+INTSIZE

				

;****************************************************
;*
;* Prom Subroutine Access
;*
;****************************************************

_disk_io:	;err=disk_io(drv, cmd, count, blk, addr)

	dec	r15,#14		;save registers
	ldm	@r15,r8,#7

	ldb	rh7,14+ARG1+1(r15)	;get args
	ldb	rl7,14+ARG2+1(r15)
	ld	r8, 14+ARG3(r15)
	ld	r9, 14+ARG4(r15)
	ldl	rr10,14+ARG5(r15)

			;rh7 = drive #
			;rl7 = command
			;r8  = block count
			;r9  = block number
			;rr10 = segmented address

;
;	Now we must call the BDOS to get into segmented supervisor
;	mode.  Dangerous!
;
;	First save r7, which gets stepped on by the ldl instruction
;
	ld	r12, r7			; r12 is available
;
	ldl	rr6,#0			; Must be long
	ld	r5,#SUPV		; BDOS function
	sc	#BDOS_SC
;
;	Watch it!  Now in system mode, and the stack pointer isn't yours!
;
;	Now restore r7
;
	ld	r7, r12
;
	scall	84000068h
;
;	That's all in segmented mode;  Now lets get back to
;	user nonseg as fast as possible.
;
	ldctl	r1,FCW			; Get FCW in r1
	and	r1,#03FFFh		; Mask seg and sysmode
	ldctl	FCW,r1			; BOOM!
			;r8  = block count not transferred
			;rh7 = #retries
			;rl7 = final error code (RETURNED)
			;rh6 = error retried

	and	r7,#0FFh	;value returned in r7

	ldm	r8,@r15,#7	;restore regs
	inc	r15,#14
	ret


