*Size 20
*Include CSMDEF
*Include ZEXTDEF

; RTMCODE.GEN : Root segment miscellaneous machine code functions.

;			ZEM  Z80 Emulator and Monitor
;			 Version 1.03   22 June 1986
;
;			(C) 1986 by P. G. Kenny
;				    27 Colwyn Road
;			 	    Northampton
;
;	Permission is hereby granted for all non-commercial
;	reproduction and distribution of this material provided
;	this notice is included.

; This file contains some simple machine code utilities required by the
; root segment. The following global functions are included :
;
;	msb(a)		- returns most significant byte of 16 bit word
;	word(h, l)	- makes 16 bit word from high and low bytes
;	sext(b)		- extends sign of single byte quantity
;     $ vget()		- returns character from vdu drivers
;     $ vput(ch)	- outputs character to vdu drivers
;	test_cpu()	- tests that cpu is Z80
;
; A '$' character next to the name indicates that the function is machine
; dependent.


;  ***	Directory

	dirent	msb MS B
	dirent	word WOR D
	dirent	sext SEX T
	dirent	vget VGE T
	dirent	vput VPU T
	dirent	tcpu TEST_CP U
	enddir

;  ***	Modules follow

; msb(a) - Returns ms byte of address

	module	msb
	body	msb

	ld	hl, 3		; offset to msb of first arg
	add	hl, sp		; make pointer
	ld	l, (hl)		; load indirect
	ld	h, 0		; high byte zero
	ret			; return with value in hl

	rparam	msb
	endmod	msb		; end of module

; word(h,l) - Makes word out of high and low bytes

	module	word
	body	word

	ld	hl, 2		; offset to lsb of first arg
	add	hl, sp		; make pointer
	ld	d, (hl)		; load indirect and put in d
	inc	hl
	inc	hl		; pointer to next arg
	ld	e, (hl)		; load indirect and put in e
	ex	de, hl		; result in hl
	ret

	rparam	word
	endmod	word

; sext(b) - sign extend byte to make integer

	module	sext
	body	sext

	ld	hl, 2		; offset to first arg
	add	hl, sp		; make pointer
	ld	l, (hl)		; put low byte in l
	xor	a		; clear a and h
	ld	h, a
	or	l		; test for sign of arg
	ret	p		; exit leaving 0 in h if was positive
	dec	h		; else leave 0ffh in h
	ret

	rparam	sext
	endmod	sext

; vget() - get byte from SVC

; This machine dependent function is specific to Gemini IVC/SVC vdu drivers
; and is only used by certain other machine dependent functions.
; It is probably not needed for other implementations.

	module	vget
	body	vget

vstat	equ	0b2h		; svc status port
vdata	equ	0b1h		; svc data port
vgloop:	in	a, (vstat)	; read status
	rlca			; test ms bit
	jr	c, vgloop	; wait until buffer not empty
	in	a, (vdata)	; get byte
	ld	l, a		; transfer to hl
	ld	h, 0
	ret			; exit

	rparam	vget
	endmod	vget

; vput(b) - put byte to svc

; This machine dependent function outputs a character to the screen drivers
; without trapping control codes or checking the keyboard. It is equivalent
; to the bios CONOUT call but has been written in machine code for speed.

	module	vput
	body	vput

	ld	hl, 2		; offset to first arg
	add	hl, sp		; make pointer
vpwait:	in	a, (vstat)	; wait until svc ready
	rrca
	jr	c, vpwait
	ld	a, (hl)		; get arg in a
	out	(vdata), a	; and output to data port
	ret			; exit

	rparam	vput
	endmod	vput

; test_cpu() - returns ERROR if CPU in use is not Z80

	module	tcpu
	body	tcpu

	ld	hl, 0		; value to return if CPU is Z80
	ld	a, 2
	inc	a
	ret	po		; return if Z80
	dec	hl		; else hl = -1 = ERROR
	ret			; exit

	rparam	tcpu
	endmod	tcpu

	endcode
	end

;  ***	END OF RTMCODE.GEN

	dec	hl		; else hl = -1 = ERROR
	ret			; exit

	rparam	tcpu
	endmod	tcpu

	e