.Z80
include	280MACRO.MAC


;********************************************************
;							*
;	Q/C Runtime Library Version 3.2 (Z80)		*
;   Copyright (c) 1984 by Quality Computer Systems	*
;							*
;	Includes improved routines by Kirk Bailey:	*
;	  ?e,?ne,?gt,?ugt,lt,?ult,?le,?ule,		*
;	  ?ge,?uge,?s,?neg,?mult,?div			*
;							*
;			01/03/84			*
;********************************************************
;
	.Z80
;Inclusive OR HL and DE into HL
	PUBLIC	?o
?o:	LD	A,L
	OR	E
	LD	L,A
	LD	A,H
	OR	D
	LD	H,A
	RET
;Exclusive OR HL and DE into HL
	PUBLIC	?x
?x:	LD	A,L
	XOR	E
	LD	L,A
	LD	A,H
	XOR	D
	LD	H,A
	RET
;AND HL and DE into HL
	PUBLIC	?a
?a:	LD	A,L
	AND	E
	LD	L,A
	LD	A,H
	AND	D
	LD	H,A
	RET
;All of the following compare routines return with:
;	if condition = TRUE	HL = 1 and Z flag is reset
;	if condition = FALSE	HL = 0 and Z flag is set
;
;For a signed compare the positive and negative numbers
;are first mapped into unsigned numbers by doing an
;exclusive or of the sign bit with one. This allows us
;to do an unsigned compare and still get the correct result.
;The mapping looks like this:
;
;	-32768 (0x8000) --> 0	  (0x0000)
;	-32767 (0x8001) --> 1	  (0x0001)
;	 .....
;	    -1 (0xFFFF) --> 32767 (0x7FFF)
;	     0 (0x0000) --> 32768 (0x8000)
;	     1 (0x0001) --> 32769 (0x8001)
;	 .....
;	 32766 (0x7FFE) --> 65534 (0xFFFE)
;	 32767 (0x7FFF) --> 65535 (0xFFFF)

;Test DE == HL
	PUBLIC	?e
?e:	XOR	A	;clear carry
	SBC	HL,DE
	JR	Z,?true
	LD	H,A	;preset false code (hl=0)
	LD	L,A
	XOR	A	;set zero flag
	RET
;Test DE != HL
	PUBLIC	?ne
?ne:	XOR	A	;clear carry
	SBC	HL,DE
	RET	Z
	LD	H,A
	LD	L,A
?true:	INC	L	;indicate true (hl=1), and clear zero flag
	RET
;Test DE >  HL (signed and unsigned)
	PUBLIC	?gt
	PUBLIC	?ugt
?gt:	LD	A,D	;map signed numbers into unsigned
	XOR	80H
	LD	D,A
	LD	A,H
	XOR	80H
	LD	H,A
?ugt:	XOR	A	;clear carry
	SBC	HL,DE
	LD	H,A
	LD	L,A
	JR	C,?true
	XOR	A
	RET
;Test DE < HL (signed and unsigned)
	PUBLIC	?lt
	PUBLIC	?ult
?lt:	LD	A,D	;map signed numbers into unsigned
	XOR	80H
	LD	D,A
	LD	A,H
	XOR	80H
	LD	H,A
?ult:	EX	DE,HL
	XOR	A	;clear carry
	SBC	HL,DE
	LD	H,A
	LD	L,A
	JR	C,?true
	XOR	A
	RET
;Test DE <= HL (signed and unsigned)
	PUBLIC	?le
	PUBLIC	?ule
?le:	LD	A,D	;map signed numbers into unsigned
	XOR	80H
	LD	D,A
	LD	A,H
	XOR	80H
	LD	H,A
?ule:	XOR	A	;clear carry
	SBC	HL,DE
	LD	H,A
	LD	L,A
	JR	NC,?true
	XOR	A
	RET
;Test DE >= HL (signed and unsigned)
	PUBLIC	?ge
	PUBLIC	?uge
?ge:	LD	A,D	;map signed numbers into unsigned
	XOR	80H
	LD	D,A
	LD	A,H
	XOR	80H
	LD	H,A
?uge:	EX	DE,HL
	XOR	A	;clear carry
	SBC	HL,DE
	LD	H,A
	LD	L,A
	JR	NC,?true
	XOR	A
	RET
;Shift DE arithmetically right by HL and return in HL
	PUBLIC	?asr
	PUBLIC	?asr1
?asr:	EX	DE,HL
?asr1:	DEC	E
	RET	M
	SRA	H
	RR	L
	JR	?asr1
;Shift DE arithmetically and logically left by HL and return in HL
	PUBLIC	?asl
	PUBLIC	?asl1
?asl:	EX	DE,HL
?asl1:	DEC	E
	RET	M
	ADD	HL,HL
	JR	?asl1
;Shift DE logically right by HL and return in HL
	PUBLIC	?lsr
	PUBLIC	?lsr1
?lsr:	EX	DE,HL
?lsr1:	DEC	E
	RET	M
	SRL	H
	RR	L
	JR	?lsr1
;Subtract (signed and unsigned) HL from DE and return in HL
	PUBLIC	?s
?s:	EX	DE,HL
	XOR	A	;clear carry
	SBC	HL,DE
	RET
;Form the two's complement of HL
	PUBLIC	?neg
?neg:	LD	A,H
	CPL
	LD	H,A
	LD	A,L
	CPL
	LD	L,A
	INC	HL
	RET
;Form the one's complement of HL
	PUBLIC	?com
?com:	LD	A,H
	CPL
	LD	H,A
	LD	A,L
	CPL
	LD	L,A
	RET
;Form logical not of HL
	PUBLIC	?n
?n:	LD	A,H
	OR	L
	JR	Z,?not1
	XOR	A	;set Z to indicate FALSE
	LD	H,A	;set HL=0 to indicate FALSE
	LD	L,A
	RET
?not1:	INC	L	;set HL=1 and reset Z to indicate TRUE
	RET

;Divide (signed) DE by HL and return quotient in HL remainder in DE
	PUBLIC	?div
?div:	
	LD	A,H
	OR	L
	RET	Z
	PUSH	BC
	LD	B,H
	LD	C,L
	EX	DE,HL
	LD	DE,0
	DIVBC
	POP	BC
	RET
;
;Divide (unsigned) DE by HL and return quotient in HL remainder in DE
	PUBLIC	?udiv
?udiv:	
	LD	A,H
	OR	L
	RET	Z
	PUSH	BC
	LD	B,H
	LD	C,L
	EX	DE,HL
	LD	DE,0
	DIVUBC
	POP	BC
	RET



;
;Select the appropriate case for a switch statement
	PUBLIC	?sw
?sw:	EX	DE,HL	;save val of expression in DE
	POP	HL	;get address of arg list
	PUSH	BC	;save calling routine's stack frame pointer
	LD	C,(HL)	;load no. of cases in C
	INC	HL	;ignore high order byte of count
?sw1:	DEC	C	;count down cases
	JP	M,?sw3	;no more cases -- goto default
	INC	HL	;val of expr == case val?
	LD	A,(HL)
	CP	E
	INC	HL
	JR	NZ,?sw2 ;no, goto next case
	LD	A,(HL)
	CP	D
	JR	Z,?sw3	;yes, goto matching label
?sw2:	INC	HL	;skip label for this case
	INC	HL
	JR	?sw1	;go try next case
?sw3:	INC	HL	;get address of this case label
	LD	A,(HL)
	INC	HL
	LD	H,(HL)
	LD	L,A
	POP	BC	;restore calling routine's stack frame pointer
	JP	(HL)	;go to case label
;


;
;Exit which restores stack frame pointer and deallocates local space
	PUBLIC	?nexs
?nexs:	EX	DE,HL	;save function's return value (if any)
	POP	HL	;address of local space to deallocate
	LD	A,(HL)	;get amount of local space
	INC	HL
	LD	H,(HL)
	LD	L,A
	ADD	HL,SP
	LD	SP,HL	;deallocate local space
	EX	DE,HL	;restore return value
	POP	IX	;  and stack frame pointer
	RET



;Entry which sets stack frame pointer,
; and does not allocate local space
	PUBLIC	?nen
?nen:	POP	HL	;ret return address
	PUSH	IX	;save stack frame pointer
	LD	IX,-2	;set new frame ptr to point one word below
	ADD	IX,SP
	JP	(HL)	;return



;Entry which sets stack frame pointer and allocates local space,

	PUBLIC	?nens
?nens:	POP	HL	;get RET addr
	PUSH	IX	;save stack frame pointer
	LD	IX,-2	;set new stack frame pointer
	ADD	IX,SP
	LD	E,(HL)	;get local space needed
	INC	HL
	LD	D,(HL)
	INC	HL	;skip over argument to this routine
	EX	DE,HL	;RET address <--> local space needed
	ADD	HL,SP
	LD	SP,HL	;reserve local space
	EX	DE,HL	;retrieve return address
	JP	(HL)

;
;Define end-of-memory symbols for M80 and RMAC linkers and
;	Q/C memory allocation functions
	PUBLIC	$MEMRY,?MEMRY,@free?
$MEMRY:
?MEMRY:
@free?: DEFS	2

	END



