	.TITLE	S3V
	.IDENT	/V4.5/

;	This program is used to test the speed of instructions
;		on VAX family processors.
;
;	11-Apr-85	B. Z. Lederman
;	02-Jan-86		"	revisions, re-format output
;			Make program run in batch with LIB$PUT_OUTPUT

$NREP == 4000.			; number of instructions wanted at one pass
$NREAL = <$NREP - 3.>		; (minus loop instructions)
$NPAS == 250.			; number of passes

	.BLKW	2		; buffer
A:	.LONG	63		; some dummy data
	.LONG	63
B:	.LONG	<63 * 1024>	; some more dummy data
	.LONG	<63 * 1024>
C:	.BLKL	4		; just some buffer space

MNEADR:	.ADDRESS MNTAB		; starting point for mnemonics
TABADR:	.ADDRESS TABLE		; starting point for instructions

DTBUF:	.BLKW	4		; space for NUMTIM buffer
DTMIN:	.BLKW	1		; minutes		(not used anymore)
DTSEC:	.BLKW	1		; seconds
DTHUN:	.BLKW	1		; hundredths of second

FAODSC:	.LONG	80		; FAO descriptor
	.ADDRESS FAOBUF		; address of buffer
FAOBUF:	.BLKB	80		; FAO buffer
FAOLEN:	.WORD	0		; length of initial string
	.WORD	0		; need quad for descriptor
	.ADDRESS FAOBUF		; repeat for PUT_OUTPUT descriptor

STRTIM:	.BLKQ	1		; starting time
ENDTIM:	.BLKQ	1		; ending time

;	.NLIST	BEX

MSG2:	.ASCID	/          !UW.!UW/
MSG4:	.ASCID	/ !UL Instructions, !UL Passes through loop./

; The following table contains the mnemonics for the instructions
;	being tested.  It should match the next table after, which
;	contains the actual instructions.

MNTAB::
	.ASCII	/MOVB 5/
	.ASCII	/MOVB 6/
	.ASCII	/MOVB78/
	.ASCII	/MOVW 5/
	.ASCII	/MOVW 6/
	.ASCII	/MOVW78/
	.ASCII	/MOVL 5/
	.ASCII	/MOVL 6/
	.ASCII	/MOVL78/
	.ASCII	/MOVQ 5/
	.ASCII	/MOVQ 6/
	.ASCII	/MOVQ78/
	.ASCII	/MNEGW5/
	.ASCII	/MNEGW6/
	.ASCII	/MNEGL5/
	.ASCII	/MNEGL6/
	.ASCII	/MCOMW5/
	.ASCII	/CVTBW5/
	.ASCII	/MOVZBL/
	.ASCII	/CMPW 5/
	.ASCII	/CMPL 6/
	.ASCII	/ADDW2 /
	.ASCII	/BITW 5/
	.ASCII	/MULW2 /
	.ASCII	/DIVW2 /
	.ASCII	/Last  /

;	.LIST BEX

TABLE::
	MOVB	R6, R7		; MOVe Byte mode 5
	MOVB	(R6), (R7)	; MOVe Byte mode 6
	MOVB	-(SP), (SP)+	; MOVe Byte mode 7 and 8
	MOVW	R6, R7		; MOVe Word mode 5
	MOVW	(R6), (R7)	; MOVe Word mode 6
	MOVW	-(SP), (SP)+	; MOVe Word mode 7 and 8
	MOVL	R6, R7		; MOVe Long mode 5
	MOVL	(R6), (R7)	; MOVe Long mode 6
	MOVL	-(SP), (SP)+	; MOVe Long mode 7 and 8
	MOVQ	R6, R7		; MOVe Quad mode 5
	MOVQ	(R6), (R7)	; MOVe Quad mode 6
	MOVQ	-(SP), (SP)+	; MOVe Quad mode 7 and 8
	MNEGW	R6, R7		; Move NEGated Word
	MNEGW	(R6), (R7)	; Move NEGated Word
	MNEGL	R6, R7		; Move NEGated Word
	MNEGL	(R6), (R7)	; Move NEGated Word
	MCOMW	R6, R7		; Move COMplemented Word
	CVTBW	R6, R7		; ConVert Byte to Word
	MOVZBL	R6, R7		; MOVe Zero-extend Byte to Long word
	CMPW	R6, R7		; CoMPare Word
	CMPL	(R6), (R7)	; CoMPare Quad
	ADDW2	R6, R7		; Add Word
	BITW	R6, R7		; BIt Test Word
	MULW2	R6, R7		; MULtiply Word
	DIVW2	R6, R7		; DIVide Word
	HALT			; won't actually do this
	HALT
	HALT
	.PAGE

; for very long loops, two error routines are needed, one at each
; end of the program as word displacement isn't enough to reach
; across very long instruction sequences.

ERRORH::
	BLBC	R0, 100$		; if error, branch
	RSB				; otherwise, continue

100$:	RET				; let the system output the message

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

	.ENTRY	SPEED, ^M<R4, R5, R6, R7, R8, R9, R10, R11>

	$FAO_S	CTRSTR = MSG4, -	; format first message
		OUTLEN = FAOLEN, OUTBUF = FAODSC, P1 = #$NREP, P2 = #$NPAS

	BSBW	ERRORH

	PUSHAQ	FAOLEN

	CALLS	#1, G^LIB$PUT_OUTPUT	; output first message

	BSBW	ERRORH

BEGIN::
;	MOVAL	MNTAB, R12		; get address of mnemonic
	MOVL	MNEADR, R12		; get address of mnemonic
	MOVAL	MSG2, R7		; get address of descriptor
	ADDL	#9, R7			; adjust past start of message space
	MOVB	(R12)+, (R7)+		; move mnemonic into message
	MOVB	(R12)+, (R7)+
	MOVB	(R12)+, (R7)+		; could probably replace all this
	MOVB	(R12)+, (R7)+		; with a move character inst.
	MOVB	(R12)+, (R7)+
	MOVB	(R12)+, (R7)+
	MOVL	R12, MNEADR		; save address of next mnemonic

	MOVL	TABADR, R12		; Get address of instruction
	MOVB	(R12)+, R6		; get first byte of instruction
	BNEQ	15$			; branch if O.K. instruction
	JMP	EXIT			; quit here if HALT instruction

15$:	MOVB	(R12)+, R7		; second byte of instruction
	MOVB	(R12)+, R8		; third byte of instruction
	MOVL	R12, TABADR		; save address of next instruction
	MOVL	#$NREAL, R4		; number of repetitions
	MOVAL	ISTRT, R5		; address of instruction space

20$:	MOVB	R6, (R5)+		; move in instruction
	MOVB	R7, (R5)+		; second byte of instruction
	MOVB	R8, (R5)+		; third byte of instruction
	SOBGTR	R4, 20$			; continue until all loaded

	MOVL	#$NPAS, R4		; number of times through the loop
	MOVAL	A, R6			; need this for some modes
	MOVAL	B, R7			; this also

	$GETTIM_S TIMADR = STRTIM	; get NOW from system

	BSBW	ERRORH			; check for directive error

ISTRT::
	.REPT	$NREAL			; this number of instructions
	NOP				; filled with real instructions above
	NOP
	NOP
	.ENDR

	DECL	R4			; count number of passes
	BLEQ	TIMES			; quit if enough passes
	JMP	ISTRT			; otherwise continue

TIMES::	$GETTIM_S TIMADR = ENDTIM	; get NOW from system

	BSBW	ERROR			; check for error

	SUBL	ENDTIM, STRTIM		; get difference (in reverse order
	SBWC	ENDTIM+4, STRTIM+4	; as negative indicates delta time)

	$NUMTIM_S -			; convert to binary values
		TIMBUF = DTBUF, TIMADR = STRTIM

	BSBW	ERROR

				; format instruction & time message
	$FAO_S	CTRSTR = MSG2, -
		OUTLEN = FAOLEN, OUTBUF = FAODSC, -
		P1 = DTSEC, P2 = DTHUN

	BSBW	ERROR
				; output instruction & time message
	PUSHAQ	FAOLEN

	CALLS	#1, G^LIB$PUT_OUTPUT

	BSBW	ERROR

	JMP	BEGIN			; repeat until last instruction

EXIT::	$EXIT_S				; byebye

;	Error Checking Routine

ERROR::
	BLBC	R0, 200$		; if error, branch
	RSB				; otherwise, continue

200$:	RET				; system outputs error message

	.END	SPEED
