;************ biosmem2.z8k **************************
;*
;*	Memory Management for P-CP/M (tm) BIOS
;*	for Olivetti M20 (Z8001) system.
;*
;* 821013 S. Savitzky (Zilog) -- split modules
;* 820913 S. Savitzky (Zilog) -- created.
;*

;  01/12/83	Adapted for Z8002 (DMH, FMZ)

__text:	.sect

;****************************************************
;*
;*	This module copies data from one memory space
;*	to another.  The machine-dependent parts of
;*	the mapping are well isolated.
;*
;*	Segmented operations are well-isolated, and
;*	are either the same as their non-segmented
;*	counterparts, or constructed using macros.
;*
;****************************************************

	.input	"biosdefs2.z8k"

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

	.global _sysseg, _usrseg, _sysstk, _psap
	.global _mem_mov, _map_wdw
	.global memsc

	.global _blkmov


;****************************************************
;*
;* Externals
;*
;****************************************************

	.global xfersc
	.global _mem_bcp


;****************************************************
;*
;* System/User Memory Access 
;*
;* _mem_cpy( source, dest, length)
;*	long source, dest, length;
;* _map_adr( addr,  space)	  -> paddr
;*	long addr; int space;
;*
;* _map_adr( addr,  -1)		  -> addr
;*	sets user seg# from addr
;*
;* _map_adr( addr,  -2)
;*	control transfer to context at addr.
;*
;* system call:  mem_cpy
;*	rr6:	source
;*	rr4:	dest
;*	rr2:	length (0 < length <= 64K)
;*	 returns
;*	registers unchanged
;*
;* system call:  map_adr
;*	rr6:	logical addr
;*	r5:	space code
;*	r4:	ignored
;*	rr2:	0
;*	 returns
;*	rr6:	physical addr
;*
;* space codes:
;*	0:	caller data
;*	1:	caller program
;*	2:	system data
;*	3:	system program
;*	4:	TPA data
;*	5:	TPA program
;*
;*	The following does not apply in Z8002 case
;*
;*	x+256	x=1, 3, 5 : segmented I-space addr.
;*			    instead of data access
;*
;*	FFFF:	set user segment
;*
;****************************************************


memsc:		;memory manager system call
				; CALLED FROM SC
				; IN SEGMENTED MODE
				; rr6: source
				; rr4: dest   / space
				; rr2: length / 0
	testl	rr2
	jr z	mem_map


mem_copy:			; copy data.
				; rr6: source
				; rr4: dest
				; rr2: length
	push	@r15,r3		; push length as a short!
	pushl	@r15,rr4	; push dest
	pushl	@r15, rr6	; push source
	call	_mem_bcp	; call C copy routine
	ldl	rr6,4(r15)	; get dest into rr6
	add	r7,8(r15)	; return dest plus length
	inc	r15,#10		; restore stack
	ret

mem_map:		; map address
				; rr6: source
				; r4:  caller's seg.
				; r5:  space
				; r2:  caller's FCW

	cp	r5,#-2		; space=-2: xfer
	jp  eq	xfersc

;*	ld	r4,scseg+co(r15)   Not done in Z8002 implementation
	ld	r2,scfcw+co(r15)
	calr	map_1
	ldl	cr6+co(r15),rr6	; return rr6
	ret

map_1:				; dispatch

	cp	r5,#0FFFFh
	jr eq	set_usr		; space=-1: user seg

	cpb	rl5,#0
	jr eq	call_data
	cpb	rl5,#1
	jr eq	call_prog
	cpb	rl5,#2
	jr eq	sys_data
	cpb	rl5,#3
	jr eq	sys_prog
	cpb	rl5,#4
	jr eq	usr_data
	cpb	rl5,#5
	jr eq	usr_prog

	ret			;default: no mapping

set_usr:			;-1: set user seg.
	ld	_usrseg,r6
	ret

;*
;*** THE FOLLOWING CODE IS SYSTEM-DEPENDENT ***
;*
;*	rr6= logical address
;*	r4 = caller's PC segment - but NOT in the Z8002 implementation!
;*	r2 = caller's FCW
;*	 returns
;*	rr6= mapped address
;*
;* This code is much simpler than the corresponding
;* Z8001 code.  If the caller's FCW indicates that he
;* was in Normal mode, then _usrseg is returned.
;* Otherwise, pseudo-segment 0 is returned.
;*

call_data:
	bit	r2,#14		; System caller?
	jr nz	sys_data	; yes-- use system seg
	ld	r6,_usrseg	; no -- use pc segment
	ret

call_prog:
	 bit	r2,#14		; System caller?
	jr nz	sys_prog	; yes-- use system seg
	ld	r6,_usrseg	; no 00 use pc segment
	jr	map_prog	; map prog as data

sys_data:
sys_prog:
	ld	r6, _sysseg
	ret			; assume sys does not
				; separate code, data

usr_data:
	ld	r6, _usrseg
	ret

usr_prog:
	ld	r6, _usrseg
	jr	map_prog


map_prog:			; map program addr into data
				; rr6 = address

	and	r6,#7F00h	; extract seg bits

	; kontron:   pseudo-segment 2 is the only one with
	;	     separate I and D spaces, and
	;	     the program space is accessed
	;	     as pseudo-segment 1, data space as pseudo-segment 2

	cpb	rh6,#2
	ret ne
	ldb	rh6,#1
	ret

;*
;* The following routine copies a block of data from one part
;* of the system address space to another.  In practice, part
;* of the address space may be windowed, but that is transparent
;* here.
;*
;* The interface is:
;*	blkmov(source,dest,length)
;*	short source,dest,length;
;*

_blkmov:
	ld	r5,ARG1(r15)	; r5: source
	ld	r4,ARG2(r15)	; r4: dest
	ld	r2,ARG3(r15)	; r2: length (just a word!)
	ld	r7,r2		; return value = bytes copied
	ldirb	@r4,@r5,r2	;  copy!
	ret


;****************************************************
;*	mem_mov -- C callable block move routine
;*	input stack:
;*		ret. addr	(word)
;*		source		(word)
;*		destination	(word)
;*		length, bytes	(word)

_mem_mov:
	ld r5,2(r15)		; pull off source
	ld r7,4(r15)		; pull off destination
	ld r0,6(r15)		; pull off length
	ldirb @r7,@r5,r0	; block move
	ret

;****************************************************
;*	map_wdw -- C callable map window routine,
;		  system dependent.
;*	input stack:
;*		ret. addr	(word)
;*		window code	(word)
;*				2 means physical block 2
;*				3 means physical block 3
;*				x means physical block 1
;*
;*  Note:	the manual is unclear, but implies that 
;*		history must be kept concerning the window
;*		mapping, if the window was last block 3.
;*		That is why I map block one before others.
;*		See ECB/C16 Hardware description for details.

_map_wdw:
	ld	r0,2(r15)		; pull off window code
	out	0c000h,r0		; map physical block 1
	cp	r0,#2			; map physical block 2?
	jr	nz,map_wdw_3		; No, go for physical block 3.
	out	8001h,r0		; Funny port address, huh?
	ret

map_wdw_3:
	cp r0,#3			; map pysical block 3?
	ret nz				; no, already mapped to 1.

	out	0c001h,r0		; yes.
	ret

;****************************************************
;*
;* Data
;*
;****************************************************

__bss:	.sect

_sysseg: .block 2	;system segment
_usrseg: .block 2	;user segment
_sysstk: .block 2	;system stack pointer
_psap:	 .block 2	;program status area ptr


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




