;
;	DOS GENERAL SUBROUTINES
;
; 02.35 DEW ??/??/?? macros
; 02.37 KRS 03/??/82 2.37 FIXES
; 02.40 sbw 08/05/82 ZEROBY
;
	icl	pdef		;02.39
	icl	df		;02.39
	df.dos			;02.39
	df.cpu			;02.39
	df.sys			;02.39
;
	NAM	UTL240
;
	ENT	MOVE/ےےےےےے
	RN6
	ENT	MUL32,DIV32,DIV32X
	ENT	CMPHL
	ENT	ZMOVE		;02.01 Z80 STYLE MOVE
	ENT	ZEROBY		;02.01 ZERO BYTES
;
;	HEX & ERROR OUTPUT ROUTINES
;
	ENT	BINH2,BINH1,PHEX,ERMSG
	EXT	CWPIM	; CHAR OUT ROUT.
;
; ROUTINE: ZMOVE (Z80 STYLE MOVE)
;	@DE <- @HL UNTIL BC=0
;
	ifc	syscpu=c.z80		;02.37
zmove:	ldir				;02.37
	elsec				;02.37
ZMOVE:	XCHG
	CALL	MOVE
	XCHG
	endc				;02.37
	RET
;
;  ROUTINE:  MOVE
;
;	@DE -> @HL UNTIL BC=0
;
; EXIT:  A=0 , BC=0 , @DE=SOURCE+1
;			@HL=TARGET+1
;
	ifc	syscpu=c.z80		;02.37
move:	xchg				;02.37
	ldir				;02.37
	xchg				;02.37
	RET				;02.37
	elsec				;02.37
MOVE:	MOV	A,B
	ORA	C	; IF BC=0
	RZ		; THEN EXIT
	LDAX	D
	MOV	M,A
	INX	D
	INX	H
	DCX	B
	BR	MOVE			;02.35
	endc				;02.37
;
; ROUTINE: ZEROBY
;	     @HL PUT 0'S UNTIL B=0
;
ZEROBY:	MVI	M,0
	INX	H
	dbrnz	ZEROBY				;02.35		;02.40
	RET
;
;	STANDARD MATH ROUTINES
;	16-BIT MULTIPLY AND DIVIDE (UNSIGNED)
;
; ROUTINE: MUL16
; FUNCTION: 16-BIT BY 16-BIT MULTIPICATION OF 
;	UNSIGNED INTEGERS
;	DE:=DE*HL , HL,BC UNCHANGED
; TECHINQUE: SHIFT RESULT (BC) & FACTOR(DE) 16 TIMES
;    RIGHT AS A 32-BIT INTEGER/ USE LSB AS ADDING FLAG
;
MUL16:
	PUSH	B
	PUSH	H
	MVI	L,16
	LXI	B,0	; PRODUCT:=0
;
MUL1A:
	XTHL		; HL:=PROD,TOP=CNTR
	MVI	A,1
	ANA	E	; IF LSB
	BRZ	MIL1B					;02.35
	PUSH	H
	DAD	B	; THEN ADD FACTOR TO PRODUCT
	XTHL
	POP	B	; HL=FACTOR,BC=PRODUCT
MIL1B:	MOV	A,B
	RAR
	MOV	B,A
	MOV	A,C	; SHIFT RIGHT(B,C,D,E)
	RAR
	MOV	C,A
	MOV	A,D
	RAR
	MOV	D,A
	MOV	A,E
	RAR
	MOV	E,A
;
	XTHL
	DCR	L	; COUNT DOWN
	BRNZ	MUL1A					;02.35
;
	POP	H
	POP	B
	RET
;
; ROUTINE:   DIV16
;
;           HL=HL/DE   DE=REMAINDER
;
;   NO TEST IS MADE FOR OVERFLOW
;
DIV16:
	MOV	A,D
	ORA	E
	RZ		; DIVIDE BY ZERO
;
	MOV	A,D
	CMA
	MOV	D,A
	MOV	A,E
	CMA
	MOV	E,A
	INX	D	; DE:=-DIVISOR
	PUSH	B
	MOV	B,H
	MOV	C,L
	LXI	H,0
	MVI	A,17	; LOOP CNTR
;
DV0:	PUSH	H	; SAVE REMAINDER
	DAD	D	; SUBTRACT DIVISOR
	BRNC	DV1					;02.35
	XTHL		; IF TOO SMALL THEN RESTORE HL
DV1:	POP	H
	PUSH	PSW	; SAVE CNTR
;
	MOV	A,C	; SHIFT LEFT (CY,C,B,L,H)
	RAL
	MOV	C,A
	MOV	A,B
	RAL
	MOV	B,A
	MOV	A,L
	RAL
	MOV	L,A
	MOV	A,H
	RAL
	MOV	H,A
;
	POP	PSW	; GET CNTR
	DCR	A
	BRNZ	DV0					;02.35
;
	ORA	A	; FINAL SHIFT
	MOV	A,H
	RAR
	MOV	D,A
	MOV	A,L
	RAR
	MOV	E,A
	MOV	H,B
	MOV	L,C	; RESULT=HL
	POP	B	; RECOVER B
	RET
;
;  MUL32:   32 BIT MULTIPLY
;
;	DEHL := DE * BC
;
MUL32:	LXI	H,0
	MVI	A,16
MUL32A:	PUSH	PSW
	DAD	H
	MOV	A,E
	RAL
	MOV	E,A
	MOV	A,D
	RAL
	MOV	D,A
	BRNC	MUL32B					;02.35
	DAD	B
	BRNC	MUL32B					;02.35
	INX	D
MUL32B:	POP	PSW
	DCR	A
	BRNZ	MUL32A					;02.35
	RET
;
;  DIV32:   32 BIT DIVIDE
;
;	DE := DEHL / BC
;	HL := REMAINDER
;
DIV32:	XCHG		;HLDE := DEHL
DIV32X:	PUSH	B	;DON'T CHANGE BC
	MOV	A,C	;BC:=-BC
	CMA
	MOV	C,A
	MOV	A,B
	CMA
	MOV	B,A
	INX	B
	MVI	A,16
DIV32A:	PUSH	PSW	;SAVE COUNT
	DAD	H	;LEFT SHIFT HLDE
	RAR		;SAVE CARRY OUT
	XCHG
	DAD	H
	XCHG
	BRNC	DIV32B					;02.35
	INX	H	;HALF CARRY
DIV32B:	RAL		;REAL CARRY
	BRC	DIV32C	;RESULT GETS A 1.		;02.35
	MOV	A,L	;TEST IF 1.
	ADD	C
	MOV	A,H
	ADC	B
	BRNC	DIV32D					;02.35
DIV32C:	DAD	B	;SUBTRACT
	INX	D	;INSERT BIT
DIV32D:	POP	PSW	;GET COUNT
	DCR	A
	BRNZ	DIV32A					;02.35
	POP	B
	RET
;
;  CMPHL  COMPARE DE TO HL
;		AS...  CMP B
;
CMPHL:	MOV	A,D
	CMP	H
	RNZ
	MOV	A,E
	CMP	L
	RET
;
;  INTERNAL BINARY TO ASCII HEX ROUTINES
;
; BINARY TO 2 DIGIT HEX
;
;	A=VALUE , DE=ASCII
;
BINH2:	MOV	D,A	; DISTROYS A
	RAR
	RAR
	RAR
	RAR
	CALL	BINH1
	MOV	A,D
	MOV	D,E	; MSD
;
; SINGLE DIGIT BINARY TO ASCII HEX
;
;	A=VALUE , E=ASCII
;
BINH1:	ANI	15
	ADI	'0'
	CPI	'9'+1
	MOV	E,A
	RC		; 0..9
	ADI	7	;  ALPHA CORRECTION
	MOV	E,A
	RET		; A..F
;
;  PRINT A BYTE FROM MEMORY
;
PHEXM:	MOV	A,M	; GET THE BYTE
;
; PRINT A DIGIT HEX (FROM A)
;	DISTROYS BC,DE,AF
;
PHEX:	CALL	BINH2
	MOV	A,D
	CALL	CWPIM
	MOV	A,E
	JMP	CWPIM
;
;  GENERAL ERROR MESSAGE PRINTER
;
;	@HL:    TEXT TERMINATED BY 0
;		IN TEXT:  80H-PRECEDES 1 BYTE HEX
;			  81H-PRECEEDS 2 BYTE HEX
;	(BINARY VALUE IS 2 BYTES (DW) IN-LINE AFTER FLAG)
;
ERMSG:	MOV	A,M
	ORA	A
	RZ	; NUL=EOL
	JM	ERMGX
;		IF MSB LOW
	CALL	CWPIM	; THEN PRINT @HL
	INX	H
	BR	ERMSG					;02.35
;			ELSE PHEX
ERMGX:	INX	H
	INX	H	; SKIP FLAG,LOW BYTE
	ANI	1
	CNZ	PHEXM	;  IF LSB SET THEN PHEX(HI BYTE)
	DCX	H
	CALL	PHEXM	; ALWAYS PHEX(LOW BYTE)
	INX	H
	INX	H
	BR	ERMSG					;02.35
;
	ENT	SAVBC				;02.37
SAVBC:						;02.37
	IFC	SYSUCB=MULTI			;02.37
	PUSH	B				;02.37
	MVI	C,URBC				;02.37
	CALL	SHLRG				;02.37
	PO	ANA	E	; IF LSB
	BRZ	MIL1B					;02.35
	PUSH	H
	DAD	B	; THEN ADD FACTOR TO PRODUCT
	XTHL
	POP	B	; HL=FACTOR,BC=PRODUCT
MIL1b=MULTI				;02.35
;
;	UCB ACCESS
;
	ENT	RDUCB,ADUCB,SVCRG,SHLRG
	EXT	URREG
;
;	SAVE REG @ C
;	@(C+URREG):=DE
;
SHLRG:	XCHG	; SAVE FROM HL ENTRY
SVCRG:	CALL	ADUCB
	MOV	M,E
	INX	H
	MOV	M,D
	RET
;
;	READ USER CONTROL BLOCK -> HL
;	   C IS OFFSET (B IS SAVED)
;  NOTE: IF LEN(VALUE)=2 , VAL=HL 
; 		       1 , VAL=L
;	AF IS SAVED 
;
RDUCB:	PUSH	PSW
	CALL	ADUCB	; HL:=(UCB+OFF)@
	MOV	A,M
	INX	H
	MOV	H,M
	MOV	L,A
	POP	PSW
	RET
;
; RETURN ADDRESS IN UCB
;	FROM 'C'
;
ADUCB:	PUSH	B
	MVI	B,0
	LHLD	URREG
	DAD	B
	POP	B	; SAVE B
	RET
    endc				;02.35
;
	END
