  	.TITLE	MONHWA
	.IDENT	/V1.0/

; This program will dump information about all nodes sending a SYSID.  It
; listens to the Remote Console multicast to gather information about nodes.

; Author = David Gagne

	.LIBRARY	"SYS$LIBRARY:LIB.MLB"

	$IODEF				;Define I/O functions and modifiers
	$NMADEF				;Define Network Management parameters
	$LNMDEF				;Define logical name parameters


; Modification history
;
;	1.0	David Gagne
;		01 Initial creation


; QIO data structures for the MOP (SYSTEM ID) channel.

; P2 parameter buffer for starting the channel.

SIDPARM:
	.WORD	NMA$C_PCLI_PTY		; Protocol Type
		.LONG	^X0260
	.WORD	NMA$C_PCLI_MCA		; Multicast address
		.WORD	8
		.WORD	NMA$C_LINMC_SET
		.BYTE	^XAB,00,00,02,00,00

SIDPARMLEN = .-SIDPARM

SIDPARMDSC:
	.LONG		SIDPARMLEN
	.ADDRESS	SIDPARM

; Read buffer for receiving System IDs

RCVBUF:
	.BLKB	1504

RCVBUFLEN = .-RCVBUF

; Place to store incoming P5 buffer (the frame header)

RCVP5:
RCVDA:	.BLKB	6
RCVSA:	.BLKB	6
RCVPT:	.BLKB	2


; Message structures

; General message buffer

FAODESC:
FAOLEN:	.LONG		80
	.ADDRESS	FAOBUF
FAOBUF:
	.BLKB		80

HDRMSG1:
	.ASCID	"MONHWA - Ethernet HWA monitoring program. Version 1.0"
IOMSG:
	.ASCID	"!/The contents of the 2nd longword in the IOSB is !XL"
NDMSG:
	.ASCID	"No device found.  Please define ETH appropriately."
DNEMSG:
	.ASCID	"MONHWA complete.  Thank you for your continued support."
BLNKMSG:
	.ASCID	""

; Output strings for monitoring all periodic SYSID messages

M1HDR0:
	.ASCID	"  Monitor output from all periodic SYSID messages"
M1HDR1:
	.ASCID	"  -----------------------------------------------"
M1HDR2:
	.ASCID	"    Hardware Address   Device     Physical Address    Node #"
M1HDR3:
	.ASCID	"    ----------------   --------   -----------------   -------"
M1INFO:
	.ASCID	"                                                             "
M1HWA:
	.ASCID	"!XB!XB!XB!XB!XB!XB"
M1DTYP:
	.ASCID	"!2UB=!AS"
M1ADDR:
	.ASCID	"!XB-!XB-!XB-!XB-!XB-!XB"
M1NODE:
	.ASCID	"!2UB.!UW    "
M1NNOD:
	.ASCID	"       "
M1NONE:
	.ASCID	"    There were no SYSID messages found."
M2HDR:
	.ASCID	"  Address usage summary"
M2SUM1:
	.ASCID	"    Nodes using their hardware address: !4UW"
M2SUM2:
	.ASCID	"    Nodes using a DECnet address:       !4UW"
M2SUM3:
	.ASCID	"    Nodes using their another address:  !4UW"
M2SUM4:
	.ASCID	"    ----------------------------------------"
M2SUM5:
	.ASCID	"           Total number of nodes found: !4UW"
M3HDR1:
	.ASCID	"  Device usage summary"
M3HDR2:
	.ASCID	"    Device    Amount"
M3HDR3:
	.ASCID	"    ------    ------"
M3INFO:
	.ASCID	"    !5AS     !5UW"

; Running totals for address usage

SUMHWA:	.WORD	0
SUMDEC:	.WORD	0
SUMOTH:	.WORD	0

; Strings for various device names

DEV01:	.ASCID	"DEUNA"
DEV05:	.ASCID	"DEQNA"
DEV11:	.ASCID	"DELUA"
DEV17:	.ASCID	"DS100"
DEV21:	.ASCID	"DEBET"
DEV23:	.ASCID	"DEBNA"
DEV25:	.ASCID	"PCLAN"
DEV33:	.ASCID	"DS200"
DEV35:	.ASCID	"DS500"
DEV37:	.ASCID	"DELQA"
DEV39:	.ASCID	"DESVA"
DEV47:	.ASCID	"DESNC"
DEV65:	.ASCID	"DEBNI"
DEVNR:	.ASCID	"Noans"
DEVUK:	.ASCID	"Unkwn"
DEVMS:	.ASCID	"Misng"

DEVTBL:	.BYTE	1
	.WORD	0
	.ADDRESS	DEV01
	.BYTE	5
	.WORD	0
	.ADDRESS	DEV05
	.BYTE	11
	.WORD	0
	.ADDRESS	DEV11
	.BYTE	17
	.WORD	0
	.ADDRESS	DEV17
	.BYTE	21
	.WORD	0
	.ADDRESS	DEV21
	.BYTE	23
	.WORD	0
	.ADDRESS	DEV23
	.BYTE	25
	.WORD	0
	.ADDRESS	DEV25
	.BYTE	33
	.WORD	0
	.ADDRESS	DEV33
	.BYTE	35
	.WORD	0
	.ADDRESS	DEV35
	.BYTE	37
	.WORD	0
	.ADDRESS	DEV37
	.BYTE	39
	.WORD	0
	.ADDRESS	DEV39
	.BYTE	47
	.WORD	0
	.ADDRESS	DEV47
	.BYTE	65
	.WORD	0
	.ADDRESS	DEV65
	.BYTE	0
	.WORD	0
DEVMSG:	.WORD	0			; Number of missing device IDs

DEVDSC:	.BLKQ	1			; General device name descriptor
DEVID:	.BLKB	1			; Device ID from SYSID response
HWA:	.BLKB	6			; Device HWA from SYSID response
CNTADR:	.BLKL	1			; Address of device counter

; Buffers, variables, and strings for the time control of the program

HOURS:	.BYTE	0			; Storage of requested input
MINUTES:.BYTE	0
SECONDS:.BYTE	0

; The following variable are for reading input from the user after prompting.

INPSTRDSC:				; Input buffer descriptor
	.LONG		0
	.ADDRESS	INPSTR

INPSTR:	.BLKB		18		; Input buffer

INPSIZ:	.BLKL	1			

; The prompts are defined next.

HPRMT:	.ASCID	"How many hours   would you like to monitor: "
MPRMT:	.ASCID	"How many minutes would you like to monitor: "
SPRMT:	.ASCID	"How many seconds would you like to monitor: "

ENDTIM:	.BLKQ	1			; Time to end test
TIME:	.BLKQ	1			; Temporary time buffer
DTIME:	.ASCID	/0 !2ZB:!2ZB:!2ZB.00/	; String for calculating delta time

; Miscellaneous variables

IOSB:	.BLKQ	1			; I/O status block

; Device names

DEVDSC1:.ASCID	'ETH'			; Units to use for test
DEVDSC2:.ASCID	'ESA0'
DEVDSC3:.ASCID	'XQA0'
DEVDSC4:.ASCID	'ETA0'
DEVDSC5:.ASCID	'XEA0'
DEVDSC6:.ASCID	'EXA0'
DEVDSC7:.ASCID	'EZA0'

; Table of pointers to device names

DEVADR:	.ADDRESS	DEVDSC1
	.ADDRESS	DEVDSC2
	.ADDRESS	DEVDSC3
	.ADDRESS	DEVDSC4
	.ADDRESS	DEVDSC5
	.ADDRESS	DEVDSC6
	.ADDRESS	DEVDSC7
	.LONG	0

; Channels - one for Remote Console

CHNRMC:	.BLKL	1

	.ENTRY	START,^M<>

; Assign the channel to the first device found which is available

	CLRL	R5			; Check each channel name to see if one
10$:	TSTL	DEVADR(R5)		; is available until one is found: the
	BEQL	20$			; first name checked is "ETH", a dummy
	MOVL	DEVADR(R5),R4		; name which can be defined to the
	$ASSIGN_S-			; device desired if either:
		DEVNAM=(R4),-		;      1) An unregistered device is used
		CHAN=CHNRMC		;  or  2) One device is prefered
	BLBS	R0,ASSIGN_OK		; If success, exit the loop
	ADDL	#4,R5			; Skip to next device name
	CMPW	R0,#SS$_NOSUCHDEV	; Was the error "no such device"?
	BEQL	10$			; If yes, try next device name
	BRW	ERROR			; Else, exit with error

; No device was found.

20$:	BSBW	BLANK			; No device was found, so say so and
	PUSHAB	NDMSG			; then exit.
	CALLS	#1,G^LIB$PUT_OUTPUT
	BRW	EXIT

ASSIGN_OK:

; Start up the channel for listening to SYSID messages.

	$QIOW_S	FUNC=#<IO$_SETMODE!IO$M_CTRL!IO$M_STARTUP>,-
		CHAN=CHNRMC,-
		IOSB=IOSB,-
		P2=#SIDPARMDSC

	BLBS	R0,START_REQ_OK
	BRW	ERROR

START_REQ_OK:

	MOVL	IOSB,R0
	BLBS	R0,START_IO_OK
	BRW	ERROR

START_IO_OK:

; Print program header

	BSBW	BLANK
	PUSHAB	HDRMSG1
	CALLS	#1,G^LIB$PUT_OUTPUT

; Find out how long they want to listen for SYSID messages and then start
; listening.

	BSBW	GET_TIME
	BSBW	BLANK
	BSBW	SET_TIME

;==========================================================================
; Print the header

	BSBW	BLANK
	PUSHAB	M1HDR0
	CALLS	#1,G^LIB$PUT_OUTPUT
	PUSHAB	M1HDR1
	CALLS	#1,G^LIB$PUT_OUTPUT
	BSBW	BLANK

; Collect SYSID information until we've either filled our data area or until
; we've listened for the requested amount of time.

	BSBW	COLLECT

; Now print the results and exit

	BSBW	PRTBL
	BSBW	PRADR
	BSBW	PRDEV
	BRW	EXIT


COLLECT:

; Collect SYSID information until we've either filled our data area or until
; we've listened for the requested amount of time.

; Check if we've been looping for the requested amount of time.

	$GETTIM_S-			; Get current time
		TIMADR=TIME
	CMPL	TIME+4,ENDTIM+4		; Did we look long enough?
	BEQL	10$			; If equal, need to check low longword
	BLSSU	20$			; If LSSU, continue
	RSB				; Else return
10$:	CMPL	TIME,ENDTIM		; Check low longword
	BLSSU	20$			; If LSSU, continue
	RSB				; Else return

; Try to read another SYSID message.

20$:	$QIOW_S	FUNC=#IO$_READVBLK!IO$M_NOW,-
		CHAN=CHNRMC,-
		IOSB=IOSB,-
		P1=RCVBUF,-
		P2=#RCVBUFLEN,-
		P5=#RCVP5

	BLBS	R0,RCV_REQ_OK
	BRW	ERROR

RCV_REQ_OK:
	MOVZWL	IOSB,R0
	BLBS	R0,RCV_IO_OK
	CMPW	R0,#SS$_ENDOFFILE
	BEQL	COLLECT
	BRW	ERROR

RCV_IO_OK:

; Check if this is a multicast message.  If not, throw it away and look for
; another message.  If this is not a SYSTEM ID message, then throw it away.

	BLBC	RCVDA,COLLECT		; Ignore packet if sent to physical

	CMPB	RCVBUF,#7		; Is this a SYSTEM ID message?
	BNEQ	COLLECT			; If NEQ, no, read another

; Get the information about this node.  If it's not in the table yet, add it.
; Both the HWA and the physical address must match for it to already be in
; the table.  This allows us to capture information about nodes that run
; with multiple physical addresses and physical addresses that run on
; multiple nodes.

	BSBW	GET_IDHWA		; Get the Device ID and HWA
	CMPB	HWA,#^XFF		; Was there a HWA?
	BNEQ	10$			; If yes, continue
	BRW	COLLECT			; If none, don't list this one

10$:	MOVAL	NODTBL,R4		; Get beginning of table
	MOVL	NODCNT,R5		; Get number of entries to compare
	BEQL	ADDNODE			; If none yet, just add this one

20$:	CMPL	HWA,(R4)		; HWA match?
	BNEQ	30$			; If NEQ, no match on this entry
	CMPW	HWA+4,4(R4)		; HWA match?
	BNEQ	30$			; If NEQ, no match on this entry
	CMPL	RCVSA,16(R4)		; PHA match?
	BNEQ	30$			; If NEQ, no match on this entry
	CMPW	RCVSA+4,20(R4)		; PHA match?
	BNEQ	30$			; If NEQ, no match on this entry
	BRW	COLLECT			; Identical entry, ignore this SYSID
30$:	ADDL	#NODSIZ,R4		; Get next entry in the table
	SOBGTR	R5,20$			; Look at more entries

; This is a new SYSID, so add it to the table.

ADDNODE:

	MOVL	HWA,(R4)+		; Add HWA
	MOVW	HWA+4,(R4)+
	MOVB	DEVID,(R4)+		; Add device ID
	TSTB	(R4)+
	MOVQ	DEVDSC,(R4)+		; Add Device name descriptor
	MOVL	RCVSA,(R4)+		; Add Physical address
	MOVW	RCVSA+4,(R4)

	INCW	@CNTADR			; One more of this specific device
	INCL	NODCNT			; One more node in the table
	CMPL	NODCNT,#MAXNOD		; Table full?
	BGEQU	10$			; If EQL, yes, so return
	BRW	COLLECT			; Else read another SYSID
10$:	RSB


PRTBL:

; Print the results.  If no entries were found, just print that none were
; found.

	MOVL	NODCNT,R5		; Get the number of nodes
	BNEQ	10$			; If some exist, print table
					; else print none found message

;==========================================================================
; Print the "no nodes found" message

	PUSHAB	M1NONE
	CALLS	#1,G^LIB$PUT_OUTPUT
	RSB

;==========================================================================
; Print the table header

10$:	PUSHAB	M1HDR2
	CALLS	#1,G^LIB$PUT_OUTPUT
	PUSHAB	M1HDR3
	CALLS	#1,G^LIB$PUT_OUTPUT

20$:	BSBW	GET_NODE		; Get a node
	MOVL	R2,R4			; Any found?
	BNEQ	21$			; If NEQ, yes
	RSB

;==========================================================================
; Get the hardware address into the table string

21$:	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M1HWA,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=5(R4),-
		P2=4(R4),-
		P3=3(R4),-
		P4=2(R4),-
		P5=1(R4),-
		P6=0(R4)
	MOVQ	R4,-(SP)
	MOVC3	FAOLEN,FAOBUF,M1INFO+8+4
	MOVQ	(SP)+,R4

;==========================================================================
; Get the Ethernet controller ID and name into the table string

	MOVL	#80,FAOLEN
	MOVQ	8(R4),DEVDSC
	$FAO_S	CTRSTR=M1DTYP,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=6(R4),-
		P2=#DEVDSC
	MOVQ	R4,-(SP)
	MOVC3	FAOLEN,FAOBUF,M1INFO+8+4+19
	MOVQ	(SP)+,R4

; If the HWA is the same as the physical address, then the rest of the
; table string can be left blank.

	CMPL	(R4),16(R4)		; Addresses the same?
	BNEQ	25$			; If NEQ, no
	CMPW	4(R4),20(R4)		; Addresses the same?
	BNEQ	25$			; If NEQ, no
	MOVQ	R4,-(SP)
	MOVC5	#0,FAOBUF,#^A' ',#27,M1INFO+8+4+19+11
	MOVQ	(SP)+,R4
	INCW	SUMHWA			; Another node using its HWA
	BRW	29$

;==========================================================================
; Get the physical address into the table string

25$:	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M1ADDR,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=16(R4),-
		P2=17(R4),-
		P3=18(R4),-
		P4=19(R4),-
		P5=20(R4),-
		P6=21(R4)
	MOVQ	R4,-(SP)
	MOVC3	FAOLEN,FAOBUF,M1INFO+8+4+19+11
	MOVQ	(SP)+,R4

;==========================================================================
; Get the node number in the table string if the PHA is a DECnet address

	CMPL	#^X000400AA,16(R4)	; Is this a DECnet address?
	BEQL	27$			; If EQL, yes, so print it
	MOVQ	R4,-(SP)
	MOVC5	#0,FAOBUF,#^A' ',#7,M1INFO+8+4+19+11+20
	MOVQ	(SP)+,R4
	INCW	SUMOTH			; Another node using some other address
	BRW	29$

27$:	MOVZWL	20(R4),R0
	BICW	#^XFC00,R0
	MOVZBL	21(R4),R1
	ASHL	#-2,R1,R1
	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M1NODE,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=R1,-
		P2=R0
	MOVQ	R4,-(SP)
	MOVC3	#7,FAOBUF,M1INFO+8+4+19+11+20
	MOVQ	(SP)+,R4
	INCW	SUMDEC			; Another node using a DECnet address

;==========================================================================
; Print the table string

29$:	PUSHAB	M1INFO
	CALLS	#1,G^LIB$PUT_OUTPUT

;==========================================================================
	CLRL	8(R4)			; This entry has been printed
	BRW	20$


PRADR:

; Print the address totals.

;==========================================================================
; Print the header

	PUSHAB	M2HDR
	CALLS	#1,G^LIB$PUT_OUTPUT
	BSBW	BLANK

;==========================================================================
; Print the SUMS

	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M2SUM1,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=SUMHWA
	PUSHAB	FAODESC
	CALLS	#1,G^LIB$PUT_OUTPUT
	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M2SUM2,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=SUMDEC
	PUSHAB	FAODESC
	CALLS	#1,G^LIB$PUT_OUTPUT
	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M2SUM3,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=SUMOTH
	PUSHAB	FAODESC
	CALLS	#1,G^LIB$PUT_OUTPUT
	PUSHAB	M2SUM4
	CALLS	#1,G^LIB$PUT_OUTPUT
	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M2SUM5,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=NODCNT
	PUSHAB	FAODESC
	CALLS	#1,G^LIB$PUT_OUTPUT
	RSB


PRDEV:

; Print the device totals.

;==========================================================================
; Print the header

	PUSHAB	M3HDR1
	CALLS	#1,G^LIB$PUT_OUTPUT
	BSBW	BLANK
	PUSHAB	M3HDR2
	CALLS	#1,G^LIB$PUT_OUTPUT
	PUSHAB	M3HDR3
	CALLS	#1,G^LIB$PUT_OUTPUT

;==========================================================================
; Print the device totals

	MOVAB	DEVTBL,R5		; Start at beginning of table

; Loop printing each device in the device table.

10$:	TSTB	(R5)			; End of table?
	BEQL	20$			; If EQL, yes

	MOVL	3(R5),R6		; Get the address of the descriptor
	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M3INFO,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=R6,-
		P2=1(R5)
	PUSHAB	FAODESC
	CALLS	#1,G^LIB$PUT_OUTPUT
	ADDL	#7,R5			; Skip this entry
	BRB	10$			; Loop for more devices

; Now print the number of unknown devices.

20$:	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M3INFO,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=#DEVUK,-
		P2=1(R5)
	PUSHAB	FAODESC
	CALLS	#1,G^LIB$PUT_OUTPUT

; Now print the number of missing devices.

	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=M3INFO,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=#DEVMS,-
		P2=DEVMSG
	PUSHAB	FAODESC
	CALLS	#1,G^LIB$PUT_OUTPUT
	RSB


GET_IDHWA:

; Get the node's device ID, device name, and HWA.  This is done by looking
; at the message received.  The message contains a device ID.  From the
; device ID, we will select the correct device name.  Upon completion of
; this routine, DEVID (a byte) will have the device ID and DEVDSC will point
; to the device name.  The message also contains the hardware address.  Upon
; completion of this routine, HWA will contain the hardware address or FF
; in the first byte if none was found.  Another field initialized is the
; CNTADR field which will contain the address of the counter which should
; be incremented if this SYSID is unique.

; Look for the Device ID entry in this SYSID message.

	MOVL	#4,R3			; Skip over SYSID header

; Loop through the entries in the SYSID looking for the Device ID entry.

10$:	CMPW	R3,IOSB+2		; Any buffer left to look at?
	BLSSU	20$			; If LSSU, yes, so look for more
	BRW	210$			; Else report Device ID missing
20$:	CMPW	RCVBUF(R3),#^D100	; Is this the device ID entry?
	BEQL	30$			; If EQL, yes
	MOVZBL	RCVBUF+2(R3),R1		; Get size of this entry
	ADDL	#3,R3			; Skip over entry type and size
	ADDL	R1,R3			; Skip over entry value
	BRW	10$			; Check next entry

; The Device ID was found.  Store the Device ID and select a device name.

30$:	ADDL	#3,R3			; Skip over Device ID header
	MOVB	RCVBUF(R3),DEVID	; Store the Device ID
	MOVAB	DEVTBL,R5		; Start at beginning of table

40$:	TSTB	(R5)			; End of table?
	BEQL	200$			; If EQL, yes
	CMPB	DEVID,(R5)+		; Device number match?
	BEQL	50$			; If EQL, yes
	ADDL	#6,R5			; Skip to next entry
	BRB	40$			; Check next entry

; We found a match in the table.

50$:	MOVL	R5,CNTADR		; Save address of counter
	TSTW	(R5)+			; Skip the device count
	MOVQ	@(R5),DEVDSC		; Save descriptor
	BRB	300$

200$:	MOVAL	1(R5),CNTADR		; Save address of counter
	MOVQ	DEVUK,DEVDSC		; This is an unknown device
	BRB	300$

210$:	MOVAL	DEVMSG,CNTADR		; Save address of counter
	CLRB	DEVID			; No Device ID was found
	MOVQ	DEVMS,DEVDSC		; Device ID is missing

; Now look for the Hardware address in the SYSID response.

300$:	MOVL	#4,R3			; Skip over SYSID header

; Loop through the entries in the SYSID looking for the HWA entry.

310$:	CMPW	R3,IOSB+2		; Any buffer left to look at?
	BLSSU	320$			; If LSSU, yes, so look for more
	BRW	340$			; Else report HWA missing
320$:	CMPW	RCVBUF(R3),#^D7		; Is this the HWA entry?
	BEQL	330$			; If EQL, yes
	MOVZBL	RCVBUF+2(R3),R1		; Get size of this entry
	ADDL	#3,R3			; Skip over entry type and size
	ADDL	R1,R3			; Skip over entry value
	BRW	310$			; Check next entry

; The HWA was found.  Store the HWA.

330$:	ADDL	#3,R3			; Skip over HWA header
	MOVL	RCVBUF(R3),HWA		; Store first longword
	MOVW	RCVBUF+4(R3),HWA+4	; Store last word
	RSB
340$:	MOVB	#^XFF,HWA		; Set "no HWA found"
	RSB


GET_TIME:

; Get number of hours to run test for

GET_HOUR:
	BSBW	BLANK
	MOVL	#6,INPSTRDSC
	PUSHAB	INPSIZ
	PUSHAB	HPRMT
	PUSHAB	INPSTRDSC
	CALLS	#3,G^LIB$GET_INPUT

; Convert number of hours

	CLRL	R1
	CLRW	R2
NUM_LOOP2:
	MOVZBL	INPSTR(R2),R0
	SUBL2	#^A/0/,R0
	MULL2	#^D10,R1
	ADDL2	R0,R1
	INCW	R2
	CMPW	R2,INPSIZ
	BLSS	NUM_LOOP2
	CMPL	R1,#^D23
	BGTR	GET_HOUR
	MOVL	R1,HOURS

; Get number of minutes to run test for

GET_MINUTE:
	MOVL	#6,INPSTRDSC
	PUSHAB	INPSIZ
	PUSHAB	MPRMT
	PUSHAB	INPSTRDSC
	CALLS	#3,G^LIB$GET_INPUT

; Convert number of minutes

	CLRL	R1
	CLRW	R2
NUM_LOOP3:
	MOVZBL	INPSTR(R2),R0
	SUBL2	#^A/0/,R0
	MULL2	#^D10,R1
	ADDL2	R0,R1
	INCW	R2
	CMPW	R2,INPSIZ
	BLSS	NUM_LOOP3
	CMPL	R1,#^D59
	BGTR	GET_MINUTE
	MOVL	R1,MINUTES

; Get number of seconds to run test for

GET_SECOND:
	MOVL	#6,INPSTRDSC
	PUSHAB	INPSIZ
	PUSHAB	SPRMT
	PUSHAB	INPSTRDSC
	CALLS	#3,G^LIB$GET_INPUT

; Convert number of seconds

	CLRL	R1
	CLRW	R2
NUM_LOOP4:
	MOVZBL	INPSTR(R2),R0
	SUBL2	#^A/0/,R0
	MULL2	#^D10,R1
	ADDL2	R0,R1
	INCW	R2
	CMPW	R2,INPSIZ
	BLSS	NUM_LOOP4
	CMPL	R1,#^D59
	BGTR	GET_SECOND
	MOVL	R1,SECONDS
	RSB

SET_TIME:

; Determine the time to stop the test

; Now put the total time into one string

	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=DTIME,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=HOURS,-
		P2=MINUTES,-
		P3=SECONDS

; Change the ASCII string for the time to a quadword value.

	$BINTIM_S-
		TIMBUF=FAODESC,-
		TIMADR=TIME
	MNEGL	TIME+4,TIME+4
	MNEGL	TIME,TIME
	SBWC	#0,TIME+4

; Now get the present time and add the test time to get the end time.

	$GETTIM_S-
		TIMADR=ENDTIM
	ADDL	TIME,ENDTIM
	ADWC	TIME+4,ENDTIM+4
	RSB


GET_NODE:

; Locate the next node in the table to be printed.  We will locate the node
; with the lowest hardware address.  We will skip over nodes that have a
; zero in their device descriptor field.

	MOVQ	R0,-(SP)		; Save R0 and R1
	CLRL	R1			; Start our counter at zero
	CLRL	R0			; Start with no node found
	MOVAL	NODTBL,R2		; Start at beginning of table

10$:	TSTL	8(R2)			; Is this a valid entry?
	BEQL	30$			; If EQL, no

; If this is the first entry found, just store it.  Else compare it with the
; smallest found so far.

	TSTL	R0			; Did we find a node yet?
	BEQL	20$			; If EQL, no, so save this one
	CMPL	2(R2),2(R0)		; Is the new one smaller?
	BGTRU	30$			; If GTRU, no, so skip this node
	BLSSU	20$			; If LSSU, yes, so save it
	CMPW	(R2),(R0)		; Is the new one smaller?
	BGEQU	30$			; If GEQU, no, so skip this node
20$:	MOVL	R2,R0			; Save this as the smallest node

; Skip to next node and continue if there are more nodes to look at.

30$:	ADDL	#NODSIZ,R2		; Skip to next entry in table
	INCL	R1			; Bump node counter
	CMPL	R1,NODCNT		; Are we done?
	BLSSU	10$			; If LSSU, no, so loop
	MOVL	R0,R2			; Return pointer to smallest node
	MOVQ	(SP)+,R0		; Restore R0 and R1
	RSB


EXIT:
	BSBW	BLANK
	PUSHAB	DNEMSG
	CALLS	#1,G^LIB$PUT_OUTPUT
	BSBW	BLANK

	$DASSGN_S-
		CHAN=CHNRMC

	$EXIT_S


BLANK:

; Print blank line

	PUSHAB	BLNKMSG
	CALLS	#1,G^LIB$PUT_OUTPUT
	RSB


; An error has occured, so print R0 value and 2nd longword of IOSB.

ERROR:	PUSHL	R0			; Pass R0 error code
	CALLS	#1,RBL$ERCODE		; Print error code

; Print IOSB 2nd longword value in hex

	MOVL	#80,FAOLEN
	$FAO_S	CTRSTR=IOMSG,-
		OUTLEN=FAOLEN,-
		OUTBUF=FAODESC,-
		P1=IOSB+4

	PUSHAB	FAODESC
	CALLS	#1,G^LIB$PUT_OUTPUT

	BRW	EXIT			; Now exit normally

	.PAGE

; RBL$ERCODE
;
; This subroutine accepts a VMS error code in binary
; and print the message on the terminal.
;
; INPUT:	4(AP) = Error Code
;
; OUTPUT:	all registers saved except R0 and R1
;
; CALLING SEQ:	PUSHx	error code
;		CALL_S	#1,RBL$ERCODE
;

	.ENTRY	RBL$ERCODE,^M<R3,R4>

	MOVL	4(AP),R3		; Get error code

	$GETMSG_S-			; Convert error code to message
		MSGID=R3,-
		MSGLEN=ERRMSG_LEN,-
		BUFADR=ERRMSG_BUF_DESC

	PUSHAB	ERRMSG_BUF_DESC
	CALLS	#1,G^LIB$PUT_OUTPUT

	RET				; Return to caller

; Structures used to build error message from error code

ERRMSG_BUF_DESC:
ERRMSG_LEN:
	.LONG	256
	.ADDRESS-
		ERRMSG_BUF
ERRMSG_BUF:
	.BLKB	256


; Table for information on nodes already found.

; Each entry consists of:
;
;	6 bytes of hardware address
;	1 byte  of DEVICE ID
;	1 byte  of spare info
;	8 bytes of DEVICE NAME descriptor
;	6 bytes of physical address
;	4 bytes of address of device counter

NODSIZ = 26
MAXNOD = 1000

NODCNT:	.LONG	0
NODTBL:	.BLKB	MAXNOD*NODSIZ

	.END	START
