Google
 

Trailing-Edge - PDP-10 Archives - BB-H311C-RM - swskit-utilities/mtest.mac
There are 4 other files named mtest.mac in the archive. Click here to see a list.
;<SWSKIT>MTEST.MAC.2, 10-Jan-82 00:36:09, EDIT BY ZIMA
;[1] Require SYS:CMD so build works.

                        TITLE MTEST

                  SEARCH CMD,MONSYM,MACSYM
                  .REQUIRE SYS:CMD,SYS:MACREL

                 SUBTTL Richard A. Schmitt/RAS/JGZ
                            SALL

                           T1==1
                           T2==2
                           T3==3
                           T4==4
                           Q1==5
                           Q2==6
                           Q3==7
                           Q4==10
                           P1==11
                           P2==12
                           P3==13
                           P4==14
                           P5==15
                           CX==16
                           P==17

                         .ADDOP==0
                         .SUBOP==1

                         VMAJOR==1
                         VMINOR==0
                          VEDIT==1
                          VWHO==0

        VMON==<VWHO>B2+<VMAJOR>B11+<VMINOR>B17+VEDIT

ENTVEC: JRST MONTST		; Entry Vector, Start test
	JRST MNTST0		; Reenter address
	VMON			; version number
CMDSTG				; Macro to define all COMND JSYS storage

MONSTK:	BLOCK 200		; Stack for this program
SYMSTK:	BLOCK 20		; Stack for decode of radix 50 symbol

MODNAM:	BLOCK 1			; Holds SIXBIT Module name for symbol lookup
UTBASE:	BLOCK 1			; Holds base address for MTEST test
TSTLEN:	BLOCK 1			; Holds the current size of the test window

FLAGS:	BLOCK 1


; There are two MTEST argument block, one for each function (.UTSET, .UTCLR)
; This allows us to preserve the bit map specifying the locations being tested
; as well as creating the bit map specifying which instructions were executed.

	UBTLEN==^D30		; Length of the MTEST bit map
	UABLEN==UBTLEN+2	; Length of the MTEST argument block

XCTBLK:	BLOCK 2			; Argument block used with .UTCLR
XCTMAP:	BLOCK UBTLEN		; Bit map specifying which inst were executed

TSTBLK:	BLOCK 2			; Argument block used with .UTSET
TSTMAP:	BLOCK UBTLEN		; Bit map specifying which inst are tested

; COMND JSYS Keyword table - Main Level

KEYS:	XWD 16,16		; Keyword Table (Macro T defined in CMD)
	T(Clear)		; Clear Lookup Module Name
	T(Examine)		; Examine section of Monitor code
	T(Exit)			; Exit from MTEST
	T(Help)			; Help routine
	T(Insert)		; Insert test into UTEST Data base
	T(Push)			; Push to new EXEC
	T(Reset)		; Reset UTEST data base
	T(Results)		; List results of Test
	T(Run)			; Run a program
	T(SDDT)			; Push into SDDT
	T(Set)			; Set Lookup Module name
	T(Start)		; Start testing
	T(Stop)			; Stop testing
	T(Toggle)		; Toggle character changing
	T(Translate)		; Translate Monitor symbol to a value

YESNO:	XWD 2,2			; Yes, No Keyword table
	T(No,0)			; No has a value of zero
	T(Yes,1)		; While Yes has a value of one

TOGKEY:	XWD ^D15,^D15		; Toggle character keyword table
	T(,.TICCA)		; CTRL/A
	T(,.TICCB)		; CTRL/B
	T(,.TICCD)		; CTRL/D
	T(,.TICCE)		; CTRL/E
	T(
,.TICCL)		; CTRL/L
	T(,.TICCN)		; CTRL/N
	T(,.TICCO)		; CTRL/O
	T(,.TICCP)		; CTRL/P
	T(,.TICCQ)		; CTRL/Q
	T(,.TICCS)		; CTRL/S
	T(,.TICCT)		; CTRL/T
	T(,.TICCV)		; CTRL/V
	T(,.TICCX)		; CTRL/X
	T(,.TICCY)		; CTRL/Y
	T(,.TICCZ)		; CTRL/Z
	

; Break set for input of toggle control character

	BRINI. KEYB0.,KEYB1.,KEYB2.,KEYB3. ; Initialize to std keyword break
	UNBRK. (.CHCNA,.CHCNE)	; Don't break on CTRL/A - CTRL/E
	UNBRK. (.CHFFD)		; Don't break on CTRL/L
	UNBRK. (.CHCNN,.CHCNQ)	; Don't break on CTRL/N - CTRL/Q
	UNBRK. (.CHCNS,.CHCNT)	; Don't break on CTRL/S or CTRL/T
	UNBRK. (.CHCNV)		; Don't break on CTRL/V
	UNBRK. (.CHCNX,.CHCNZ)	; Don't break on CTRL/X - CTRL/Z

TOGBRK:	W0.
	W1.
	W2.
	W3.

	.ICTOG==1		; Toggle channel is Channel 1

; COMND JSYS parse fields...

TERM:	FLDDB. (.CMNUX,,^D8,,,SYMPRS) ; parse a number
SYMPRS:	FLDBK. (.CMFLD,,,<Monitor Symbol>,<0>,SYMBRK) ; symbol
ADDFLD: FLDDB. (.CMTOK,,<POINT 7,[ASCIZ/+/]>,,,SUBFLD) ; add token
SUBFLD: FLDDB. (.CMTOK,,<POINT 7,[ASCIZ/-/]>,,,CFMFLD) ; sub token
CFMFLD:	FLDDB. (.CMCFM)		; confirm

; Break Mask for parsing of a Monitor Symbol

SYMBRK:	777777,,777760
	740160,,001760
	400000,,000740
	400000,,000740

TOGCHR:	.TICCD			; Place which holds toggle character
				; Initialized to control D

; PSI Storage

LEVTAB:	0,,PCLEV1		; Address to save PC
	Z			; No level 2
	Z			; or level 3

CHNTAB:	Z			; No channel zero
	1,,PSITOG		; PSITOG is routine that toggles tests
	BLOCK ^D34

PCLEV1:	BLOCK 1			; Storage for address

	WDWLEN==2000		; Window length
EXMPAG:	BLOCK WDWLEN		; Storage For Block Of Monitor Code

MSKSTR (TSTVLD,FLAGS,400000000000) ; Specifies whether we have valid test data
MSKSTR (TSTPRG,FLAGS,200000000000) ; Specifies whether a test is in progress
MSKSTR (TSTDON,FLAGS,100000000000) ; Specifies whether a new INSERT should 
				   ; reset the UTEST data base

DEFSTR (INSTR,(P1),8,9)		; Defstrs For fields of instruction
DEFSTR (AC,(P1),12,4)		; AC instruction field
DEFSTR (INDRCT,(P1),13,1)	; Indirect Bit
DEFSTR (INDEX,(P1),17,4)	; Index Register
DEFSTR (OPRND,(P1),35,18)	; Operand field
DEFINE ERET (STRING)		; error return macro
	<IFNB <STRING>,<
	   JRST [ TMSG <?'STRING>	; Print out message
		  RET]>		; And return down the stack
	 IFB <STRING>,<
	   JRST [ MOVEI T1,"?"	; Get Question mark
		  PBOUT		; Print it out
		  MOVEI T1,.PRIOU ; Outputting to primary output
		  HRLOI T2,.FHSLF ; Our selves and last error
		  SETZ T3,	; Output all of the message
		  ERSTR
		   JFCL
		   JFCL
		  RET]>>	; And return

DEFINE OPC (STRING),		; macro for defining opcode table
	<POINT 7,[ASCIZ/STRING/]>

OPCTBL:	REPEAT 104,< Z >	; opcode table 
	OPC (JSYS)		; a zero means undefined opcode
	OPC (ADJSP)		; otherwise a pointer to the opcode
	Z			; symbol corresponding to the offset
	Z			; in the table is contained in the 
	OPC (DFAD)		; location
	OPC (DFSB)
	OPC (DFMP)
	OPC (DFDV)
	OPC (DADD)
	OPC (DSUB)
	OPC (DMUL)
	OPC (DDIV)
	OPC (DMOVE)
	OPC (DMOVN)
	OPC (FIX)
	OPC (EXTEND)
	OPC (DMOVEM)
	OPC (DMOVNM)
	OPC (FIXR)
	OPC (FLTR)
	OPC (UFA)
	OPC (DFN)
	OPC (FSC)
	OPC (IBP)
	OPC (ILDB)
	OPC (LDB)
	OPC (IDPB)
	OPC (DPB)
	OPC (FAD)
	OPC (FADL)
	OPC (FADM)
	OPC (FADB)
	OPC (FADR)
	OPC (FADRI)
	OPC (FADRM)
	OPC (FADRB)
	OPC (FSB)
	OPC (FSBL)
	OPC (FSBM)
	OPC (FSBB)
	OPC (FSBR)
	OPC (FSBRI)
	OPC (FSBRM)
	OPC (FSBRB)
	OPC (FMP)
	OPC (FMPL)
	OPC (FMPM)
	OPC (FMPB)
	OPC (FMPR)
	OPC (FMPRI)
	OPC (FMPRM)
	OPC (FMPRB)
	OPC (FDV)
	OPC (FDVL)
	OPC (FDVM)
	OPC (FDVB)
	OPC (FDVR)
	OPC (FDVRI)
	OPC (FDVRM)
	OPC (FDVRB)
	OPC (MOVE)
	OPC (MOVEI)
	OPC (MOVEM)
	OPC (MOVES)
	OPC (MOVS)
	OPC (MOVSI)
	OPC (MOVSM)
	OPC (MOVSS)
	OPC (MOVN)
	OPC (MOVNI)
	OPC (MOVNM)
	OPC (MOVNS)
	OPC (MOVM)
	OPC (MOVMI)
	OPC (MOVMM)
	OPC (MOVMS)
	OPC (IMUL)
	OPC (IMULI)
	OPC (IMULM)
	OPC (IMULB)
	OPC (MUL)
	OPC (MULI)
	OPC (MULM)
	OPC (MULB)
	OPC (IDIV)
	OPC (IDIVI)
	OPC (IDIVM)
	OPC (IDIVB)
	OPC (DIV)
	OPC (DIVI)
	OPC (DIVM)
	OPC (DIVB)
	OPC (ASH)
	OPC (ROT)
	OPC (LSH)
	OPC (JFFO)
	OPC (ASHC)
	OPC (ROTC)
	OPC (LSHC)
	Z
	OPC (EXCH)
	OPC (BLT)
	OPC (AOBJP)
	OPC (AOBJN)
	OPC (JRST)
	OPC (JFCL)
	OPC (XCT)
	OPC (MAP)
	OPC (PUSHJ)
	OPC (PUSH)
	OPC (POP)
	OPC (POPJ)
	OPC (JSR)
	OPC (JSP)
	OPC (JSA)
	OPC (JRA)
	OPC (ADD)
	OPC (ADDI)
	OPC (ADDM)
	OPC (ADDB)
	OPC (SUB)
	OPC (SUBI)
	OPC (SUBM)
	OPC (SUBB)
	OPC (CAI)
	OPC (CAIL)
	OPC (CAIE)
	OPC (CAILE)
	OPC (CAIA)
	OPC (CAIGE)
	OPC (CAIN)
	OPC (CAIG)
	OPC (CAM)
	OPC (CAML)
	OPC (CAME)
	OPC (CAMLE)
	OPC (CAMA)
	OPC (CAMGE)
	OPC (CAMN)
	OPC (CAMG)
	OPC (JUMP)
	OPC (JUMPL)
	OPC (JUMPE)
	OPC (JUMPLE)
	OPC (JUMPA)
	OPC (JUMPGE)
	OPC (JUMPN)
	OPC (JUMPG)
	OPC (SKIP)
	OPC (SKIPL)
	OPC (SKIPE)
	OPC (SKIPLE)
	OPC (SKIPA)
	OPC (SKIPGE)
	OPC (SKIPN)
	OPC (SKIPG)
	OPC (AOJ)
	OPC (AOJL)
	OPC (AOJE)
	OPC (AOJLE)
	OPC (AOJA)
	OPC (AOJGE)
	OPC (AOJN)
	OPC (AOJG)
	OPC (AOS)
	OPC (AOSL)
	OPC (AOSE)
	OPC (AOSLE)
	OPC (AOSA)
	OPC (AOSGE)
	OPC (AOSN)
	OPC (AOSG)
	OPC (SOJ)
	OPC (SOJL)
	OPC (SOJE)
	OPC (SOJLE)
	OPC (SOJA)
	OPC (SOJGE)
	OPC (SOJN)
	OPC (SOJG)
	OPC (SOS)
	OPC (SOSL)
	OPC (SOSE)
	OPC (SOSLE)
	OPC (SOSA)
	OPC (SOSGE)
	OPC (SOSN)
	OPC (SOSG)
	OPC (SETZ)
	OPC (SETZI)
	OPC (SETZM)
	OPC (SETZB)
	OPC (AND)
	OPC (ANDI)
	OPC (ANDM)
	OPC (ANDB)
	OPC (ANDCA)
	OPC (ANDCAI)
	OPC (ANDCAM)
	OPC (ANDCAB)
	OPC (SETM)
	OPC (XMOVEI)
	OPC (SETMM)
	OPC (SETMB)
	OPC (ANDCM)
	OPC (ANDCMI)
	OPC (ANDCMM)
	OPC (ANDCMB)
	OPC (SETA)
	OPC (SETAI)
	OPC (SETAM)
	OPC (SETAB)
	OPC (XOR)
	OPC (XORI)
	OPC (XORM)
	OPC (XORB)
	OPC (IOR)
	OPC (IORI)
	OPC (IORM)
	OPC (IORB)
	OPC (ANDCB)
	OPC (ANDCBI)
	OPC (ANDCBM)
	OPC (ANDCBB)
	OPC (EQV)
	OPC (EQVI)
	OPC (EQVM)
	OPC (EQVB)
	OPC (SETCA)
	OPC (SETCAI)
	OPC (SETCAM)
	OPC (SETCAB)
	OPC (ORCA)
	OPC (ORCAI)
	OPC (ORCAM)
	OPC (ORCAB)
	OPC (SETCM)
	OPC (SETCMI)
	OPC (SETCMM)
	OPC (SETCMB)
	OPC (ORCM)
	OPC (ORCMI)
	OPC (ORCMM)
	OPC (ORCMB)
	OPC (ORCB)
	OPC (ORCBI)
	OPC (ORCBM)
	OPC (ORCBB)
	OPC (SETO)
	OPC (SETOI)
	OPC (SETOM)
	OPC (SETOB)
	OPC (HLL)
	OPC (HLLI)
	OPC (HLLM)
	OPC (HLLS)
	OPC (HRL)
	OPC (HRLI)
	OPC (HRLM)
	OPC (HRLS)
	OPC (HLLZ)
	OPC (HLLZI)
	OPC (HLLZM)
	OPC (HLLZS)
	OPC (HRLZ)
	OPC (HRLZI)
	OPC (HRLZM)
	OPC (HRLZS)
	OPC (HLLO)
	OPC (HLLOI)
	OPC (HLLOM)
	OPC (HLLOS)
	OPC (HRLO)
	OPC (HRLOI)
	OPC (HRLOM)
	OPC (HRLOS)
	OPC (HLLE)
	OPC (HLLEI)
	OPC (HLLEM)
	OPC (HLLES)
	OPC (HRLE)
	OPC (HRLEI)
	OPC (HRLEM)
	OPC (HRLES)
	OPC (HRR)
	OPC (HRRI)
	OPC (HRRM)
	OPC (HRRS)
	OPC (HLR)
	OPC (HLRI)
	OPC (HLRM)
	OPC (HLRS)
	OPC (HRRZ)
	OPC (HRRZI)
	OPC (HRRZM)
	OPC (HRRZS)
	OPC (HLRZ)
	OPC (HLRZI)
	OPC (HLRZM)
	OPC (HLRZS)
	OPC (HRRO)
	OPC (HRROI)
	OPC (HRROM)
	OPC (HRROS)
	OPC (HLRO)
	OPC (HLROI)
	OPC (HLROM)
	OPC (HLROS)
	OPC (HRRE)
	OPC (HRREI)
	OPC (HRREM)
	OPC (HRRES)
	OPC (HLRE)
	OPC (HLREI)
	OPC (HLREM)
	OPC (HLRES)
	OPC (TRN)
	OPC (TLN)
	OPC (TRNE)
	OPC (TLNE)
	OPC (TRNA)
	OPC (TLNA)
	OPC (TRNN)
	OPC (TLNN)
	OPC (TDN)
	OPC (TSN)
	OPC (TDNE)
	OPC (TSNE)
	OPC (TDNA)
	OPC (TSNA)
	OPC (TDNN)
	OPC (TSNN)
	OPC (TRZ)
	OPC (TLZ)
	OPC (TRZE)
	OPC (TLZE)
	OPC (TRZA)
	OPC (TLZA)
	OPC (TRZN)
	OPC (TLZN)
	OPC (TDZ)
	OPC (TSZ)
	OPC (TDZE)
	OPC (TSZE)
	OPC (TDZA)
	OPC (TSZA)
	OPC (TDZN)
	OPC (TSZN)
	OPC (TRC)
	OPC (TLC)
	OPC (TRCE)
	OPC (TLCE)
	OPC (TRCA)
	OPC (TLCA)
	OPC (TRCN)
	OPC (TLCN)
	OPC (TDC)
	OPC (TSC)
	OPC (TDCE)
	OPC (TSCE)
	OPC (TDCA)
	OPC (TSCA)
	OPC (TDCN)
	OPC (TSCN)
	OPC (TRO)
	OPC (TLO)
	OPC (TROE)
	OPC (TLOE)
	OPC (TROA)
	OPC (TLOA)
	OPC (TRON)
	OPC (TLON)
	OPC (TDO)
	OPC (TSO)
	OPC (TDOE)
	OPC (TSOE)
	OPC (TDOA)
	OPC (TSOA)
	OPC (TDON)
	OPC (TSON)
	OPC (BLKI)
	OPC (DATAI)
	OPC (CONO)
; Initialization routine called at program start

MONINI:	CALL CMDINI		; Initialize the COMND JSYS
	SETZRO TSTPRG		; Say no test in progress
	SETZRO TSTVLD		; Say no valid test
	SETONE TSTDON		; Say Reset UTEST data base
	CALL PSIINI		; Initialize the PSI system
	RET			; and done

; Entry vectory start comes here

MONTST:	MOVE P,[XWD -200,MONSTK] ; Set up stack
	CALL MONINI		; And call the all purpose init routine
	CALL PRVINI		; Initialize Privileges
	 HALTF			; Can't get wheel. Die quietly.
				; If he CONTinues,  He'll get prompt
MNTST0:				; entry for restart
	PROMPT (MTEST>)		; give prompt
	MOVEI T1,[FLDDB. (.CMKEY,,KEYS)]
	CALL RFIELD		; read the keyword
	HRRZ T3,0(T2)		; get dispatch address
	CALL @T3		; dispatch to routine
	JRST MNTST0		; Loop for next command
	
; RESET - Command Dispatch Routine
;
; This routine will reset the UTEST Data Base.  This includes the
; flags which define the state of the data base, removing any tests
; in progress internally in the MONITOR and initializing the bit maps
; for the UTEST tests.

.RESET:	NOISE (Utest Data Base)	; Give Noise word
	CONFRM			; And Confirm Command
	SETZRO TSTVLD		; Say no valid test addresses
	SETZRO TSTPRG		; Say no test in progress
	SETONE TSTDON		; Say Time to Init Utest Data base
	HRLZI T1,.UTCLR		; Clear the monitor
	UTEST			; ...
	ERJMP .+1		; in case one wasn't set
	CALL RSTBTM		; Clear the bit tables
	RET			; And Return
; TRANSLATE - Command Dispatch Routine
;
; This routine will transalate a monitor symbol which is parsed from
; The Primary I/O and print it out to the Primary output.

.TRANS:	NOISE (Monitor Symbol)	; Output noise word
	CALL EVAL		; Evaluate the symbol
	 RET			; error
	MOVE T2,T1		; get address in t2
	MOVEI T1,.PRIOU		; primary i/o in t1
	MOVEI T3,^D8		; and output in octal
	NOUT			; Output the number to the primary I/O
	 JSERR			; error
	CALL PCRLF		; print a crlf
	RET			; and return

; CLEAR - Command Dispatch Routine
;
; This Routine will Clear the Lookup Module Name which is stored
; in MODNAM.  This value is used in the SNOOP JSYS to specify which
; MONITOR module symbol table to search for the symbol.  It is set using
; the SET command.

.CLEAR:	NOISE (Lookup Module)	; Output noise word
	CONFRM			; Confirm the command
	SETZM MODNAM		; clear the module name
	RET			; And return
; EXAMINE - Command Dispatch Routine
;
; This routine will map a section of MONITOR code, deassemble
; it and print it out to the Primary output.  The subroutine
; RANGE inputs the first and last address of the section
; and the subroutine DASSEM will deassemble the section of code.

.EXAMI:	NOISE (Monitor Code)	; Give noise word
	CONFRM			; confirm the command
	CALL RANGE		; First Adr in T1, length in T2
	 RET			; some error
	CAILE T2,WDWLEN		; Less than window length?
	 ERET (Examine Area Greater Than two Pages)
	HRL T1,T2		; Get length of the area in LH of T1
	MOVEI T2,EXMPAG		; Get address of our page
	PEEK			; Get the code
	 ERET ()		; Failed
	CALL DASSEM		; Interprete code and print it out
	RET			; And done

; RANGE -
; 
; This Routine will parse from the Primary input, a range of monitor
; code.  It will prompt for starting address and last address.
;
; CALL RANGE
;
; RETURNS +1	Error, Message has already been typed
;	  +2	Success, T1 holds the first address of the range
;		         T2 Holds the length of the section

RANGE:	STKVAR <ADDR1,ADDR2>	; Temporary storage
	PROMPT (Starting At: )	; another noise word
	CALL EVAL		; Evaluate expression
	 RET			; some error
	MOVEM T1,ADDR1		; Save First Address
	PROMPT (Ending At: )	; another noise word
	CALL EVAL		; Evaluate to
	 RET			; some error
	MOVEM T1,ADDR2		; Save second address
	SUB T1,ADDR1		; Get word count in T1
	AOS T2,T1		; incr so we get last word
	MOVE T1,ADDR1		; get starting address in t1
	RETSKP			; And return to Calling routine
; EVAL -
;
; This routine will eventually be a general evaluation routine.
; At present, all I will have it do is evaluate an expression
; such as.. 
;
;    <expression>	::= <term>
;			::= <term> <add-operator> <expression>
;    <term>		::= <monitor symbol>
;			::= <constant>
;    <add-operator>	::= +
;			::= -
;
; This routine expects to parse the expression from the primary
; I/O using the COMND JSYS.
; 
; CALL EVAL
;
; RETURNS  +1	Always, with T1 holding integer result.

EVAL:	SAVEAC <T2,T3,T4>
	STKVAR <SUM,LASTOP>
	SETZM SUM		; initialize the sum
	MOVEI T1,.ADDOP		; get the add symbol
	MOVEM T1,LASTOP		; and initialize last op

; Loop to read expressions until CRLF

EVAL1:	MOVEI T1,TERM		; parse symbol or constant
	CALL RFIELD		; ...
	HRRZS T3		; get address of FDB parsed
	CAIN T3,SYMPRS		; Did we parse a symbol?
	JRST [	CALL EVLSYM	; Yes, evaluate the symbol
		 RET		;  Error, pass it down
		JRST .+1]	; continue - T2 holds symbol value
	MOVE T1,LASTOP		; get last op
	EXCH T2,SUM		; exchange these values for ease
	XCT [	ADDM T2,SUM	; either add or sub the term
		SUBM T2,SUM](T1) ; depend on last op
	MOVEI T1,ADDFLD		; parse "+","-", or <CRLF>
	CALL RFIELD		; ...
	HRRZS T3		; get field actually parsed
	CAIN T3,CFMFLD		; was it a confirm
	JRST [	MOVE T1,SUM	; yes, get sum in AC1
		RETSKP]		; and return
	MOVEI T1,.ADDOP		; get addop code in T1
	CAIE T3,ADDFLD		; did we parse a "+"?
	MOVEI T1,.SUBOP		; no, get subop code
	MOVEM T1,LASTOP		; and save as last op
	JRST EVAL1		; and loop till see confirm
; EVLSYM -
;
; This routine will evaluate the ASCIZ monitor symbol located
; in the COMND JSYS atom buffer and return the value to the
; calling routine
;
; CALL EVLSYM
;
; RETURNS  +1	Error
;	   +2	Success, Symbol value returned in T1

EVLSYM: MOVEI T1,ATMBUF		; get address of atom buffer
	HRLI T1,440700		; make standard byte pointer
	CALL ASCR50		; convert to radix 50
	MOVEI T1,.SNPSY		; obtain address of mon sym
	MOVE T3,MODNAM		; get module name if any
	SNOOP			; get the address
	JRST [	MOVEI T1,.SNPSY	; Error, try again
		SETZ T3,	; seaching entire symbol table
		SNOOP		; ...
		 ERET ()	; Still error, Give up
		JRST .+1]	; this time successful
	RETSKP			; success, ADR in T2
; DASSEM -
; Routine to deassemble a section of monitor code in user address
; space and type out code on the primary output designator.
;
; CALL DASSEM
;
; ACCEPTS  T1 	Number of words,,user address of start of block
;	   T2   Monitor address of start of section
;
; RETURNS  +1   Always,  Line has been typed out

DASSEM:	SAVEAC <P1,P2>		; save pointer acs
	HLRZ P1,T1		; Get AOBJN pointer into P1
	MOVNS P1		; make negative
	HRLZS P1		; move in left half
	HRR P1,T2		; and move first address in 
	HRRZ P2,T1		; Get Index for addresses
DASSM1:	CALL TRNLIN		; Translate line
	CALL PCRLF		; Print a CR & LF
	AOS P2			; Increment address
	AOBJN P1,DASSM1		; Loop till done
	RET			; Finished

; TRNLIN -
; Deassembles one line of code pointed to by the RH of P1
; uses monitor address supplied in P2
;
; CALL TRNLIN
;
; ACCEPTS  P1   RH - address of code to deassemble
;	   P2   Monitor address of code
;
; RETURNS  +1   always

TRNLIN:	SAVEAC <T1>		; save ac for space index
	CALL TRNADR		; Translate and print the address
	MOVEI T1,4		; print four spaces
TRNLN1:	CALL PSPACE		; before instruction
	SOJG T1,TRNLN1		; Loop till four spaces
	CALL TRNINS		; Translate and print the instruction
	RET			; And return
; TRNADR -
;
; Obtains a monitor symbol and offset for monitor address in P2
; and prints it out
;
; CALL TRNADR
;
; ACCEPTS  P2   Monitor address to interpret
;
; RETURNS  +1   always

TRNADR:	SAVEAC <T1>
	MOVE T1,P2		; Get address in T1
	CALL TRNSYM		; Translate the symbol
	RET			; and return

; TRNINS -
;
; Will deassemble the instruction pointed to by RH of P1 with
; monitor symbols.
;
; CALL TRNINS
;
; ACCEPTS  P1   RH address of instruction to deassemble
;
; RETURNS  +1   always

TRNINS:	SAVEAC <T1>
	LOAD T1,INSTR		; Get 9 bit instruction code
	MOVE T1,OPCTBL(T1)	; Get Pointer to instruction
	SKIPN T1		; Is it valid?
	 JRST NOINST
	PSOUT			; Output the instruction
	CALL PSPACE		; Print out a space
	LOAD T1,AC		; Get the AC field
	JUMPE T1,TRNIN1		; If zero, skip the AC field
	CALL NUMOUT		; output the number
	CALL PCOMMA		; Print a comma
TRNIN1:	LOAD T1,INDRCT		; get indirect bit
	SKIPE T1		; is it indirect?
	JRST [	MOVEI T1,"@"	; yes, print out at sign
		PBOUT
		JRST .+1]
	LOAD T1,OPRND		; Get the operand
	CALL TRNSYM		; Translate the Symbol and Print it
	LOAD T1,INDEX		; Get Index field
	SKIPN T1		; Is there a field
	RET			; No, Just return
	CALL LPAREN		; Print Left Paren
	CALL NUMOUT		; output the number
	CALL RPAREN		; Print Right Paren
	RET			; And Return
; TRNSYM -
;
; Obtains the monitor symbol for an address supplied in T1 and
; prints it out
;
; CALL TRNSYM
;
; ACCEPTS  T1   Value of the symbol
;
; RETURNS  +1   always

TRNSYM:	SAVEAC <T2,T3>
	MOVE T2,T1		; Get Symbol value in T2
	MOVEI T1,.SNPAD		; Obtain Monitor Symbol
	MOVE T3,MODNAM		; Module name to give preference
	SNOOP			; Find the symbol
	 JRST [	MOVEI T1,.SNPAD	; Try again
		SETZ T3,	; With general Symbol Table
		SNOOP		; ...
		 ERET ()	;  give up
		JRST TRNSY1]
TRNSY1:	MOVE T1,T2		; Get Radix 50 symbol in T1
	CALL R50ASC		; Convert to ascii
	SKIPN T2,T3		; Is there an offset
	RET			; No
	CALL PPLUS		; Print a Plus sign
	MOVEI T1,.PRIOU		; Output offset to Primary output
	MOVEI T3,^D8		; And in octal
	NOUT			; Perform the output
	 ERET ()
	RET			; And return

; NOINST -
;
; This routine will treat a word as a full word constant and
; type it out

NOINST:	MOVE T1,EXMPAG(P1)	; Get whole word
	CALL TRNSYM		; translate as a symbol
	RET			; And return
; The PRINT Routines -
;
; Each routine prints out on the terminal a small string of ascii char
;
; PCRLF	   :   Prints <CRLF>
; PPLUS    :   Prints a plus sign
; PTAB	   :   Prints a tab
; PSPACE   :   Prints out a space
; LPAREN   :   Prints out a left parentheses
; RPAREN   :   Prints out a right parentheses
; PCOMMA   :   Prints a comma

; PCRLF -

PCRLF:	SAVEAC <T1>		; Save T1
	HRROI T1,[ASCIZ/
/]				; CRLF
	PSOUT			; type it out
	RET			; And return

; PPLUS -

PPLUS:	SAVEAC <T1>		; Save T1
	MOVEI T1,"+"		; Get plus sign
	PBOUT			; Output it
	RET			; And return

; PTAB - 

PTAB:	SAVEAC <T1>		; Save T1
	MOVEI T1,"	"	; get a TAB
	PBOUT			; Print it out
	RET			; And return

; PSPACE -

PSPACE:	SAVEAC <T1>		; Save T1
	MOVEI T1," "		; Get space
	PBOUT			; Output it
	RET			; And Return
; LPAREN -

LPAREN:	SAVEAC <T1>		; Save T1
	MOVEI T1,"("		; Get left paren
	PBOUT			; Output it
	RET			; And Return

; RPAREN -

RPAREN:	SAVEAC <T1>		; Save T1
	MOVEI T1,")"		; Get a Right Paren
	PBOUT			; Print it out
	RET			; and return

; PCOMMA -

PCOMMA:	SAVEAC <T1>		; Save T1
	MOVEI T1,","		; get a comma
	PBOUT			; Print it out
	RET			; and return
; R50ASC -
;
; Routine to convert the radix 50 value in T1 to ASCII and print
; it out.  This routine was borrowed from DDT's symbol evaluation
; routine
;
; CALL R50ASC
;
; ACCEPTS  T1   Radix 50 symbol
;
; RETURNS  +1   always

R50ASC:	SAVEAC <T2,T3,p3>	; Radix 50 symbol print
	MOVE P3,[XWD -20,SYMSTK] ; set up symbol stack
	LDB T1,[POINT 32,T1,35] ; Get symbol

SPT1:	IDIVI T1,50		; get remainder = character
	PUSH P3,T2		; save symbol value
	JUMPE T1,SPT2		; if null, we're done
	PUSHJ P,SPT1		; continue recursively
SPT2:	POP P3,T2		; get back symbol value
	SKIPN T2		; Null?
	 RET			; flush nulls
	ADDI T2,260-1		; Krptic algorithm copied
        CAILE T2,271		; from ddt
	ADDI T2,301-272		; ...
	CAILE T2,332		; ...
	SUBI T2,334-244		; ...
	CAIN T2,243		; ...
	MOVEI T2,256		; ...
	MOVE T1,T2		; Get ascii character
	PBOUT			; Print it out
	RET			; and return recursively
; R50CNV - 
; Routine to convert input to radix50 value.  This routine was copied
; from JGZ's WS program.  Terminates on first out of range character.
;
; CALL R50CNV
;
; ACCEPTS  T1	Bytepointer to string to be translated
;
; RETURNS  +1	Always, with value in T2.

ASCR50:	SAVEAC <T1,T3,T4>	; Save some ACs
	SETZ T2,		; start with zero
	MOVEI T4,6		; max chars to read
R50CNL:	ILDB T3,T1		; get next byte
	CAIL T3,"A"+40		; make the usual
	CAILE T3,"Z"+40		; lower to upper case
	 SKIPA			; conversion
	SUBI T3,40		; for alphapbetics
	CAIL T3,"A"		; check for a letter
	CAILE T3,"Z"		; ... 
	 JRST R50CN1		; try digits
	SOJL T4,R50CNL		; just loop if more than six
	IMULI T2,50		; make room and
	ADDI T2,-<"A"-^D11>(T3) ; include this character in RADIX50
	JRST R50CNL		; and loop

R50CN1:	CAIL T3,"0"		; check for a digit
	CAILE T3,"9"		; ...  
	 JRST R50CN2		; try the special chars
	SOJL T4,R50CNL		; just loop if more than six
	IMULI T2,50		; make room and
	ADDI T2,-<"0"-1>(T3)	; add in RADIX50 value for this digit
	JRST R50CNL		; and loop

R50CN2:	CAIN T3,"."		; period perhaps?
	HRROI T3,45		; yes
	CAIN T3,"$"		; dollar sign?
	HRROI T3,46		; yes
	CAIN T3,"%"		; or finally percent?
	HRROI T3,47		; yes
	JUMPGE T3,[ret]		; if not a RADIX50 char, LH is still pos, so go
	SOJL T4,R50CNL		; but check for more than six
	IMULI T2,50		; make room
	ADDI T2,0(T3)		; and include the RADIX50 character
	JRST R50CNL		; and loop
; RSTBTM -
;
; This routine will reset the Bit Maps (both the Test Bit map and the
; Execute Bit map).
;
; CALL RSTBTM
;
; RETURNS  +1	Always

RSTBTM:	SAVEAC <T1,T2>
	SETZM TSTMAP		; clear first word of table
	HRLI T1,TSTMAP		; get first address
	HRRI T1,TSTMAP+1	; plus one
	BLT T1,TSTMAP+UBTLEN-1	; clear the table

	SETOM XCTMAP		; init xct map say not xcted
	HRLI T1,XCTMAP		; get first address
	HRRI T1,XCTMAP+1	; plus one
	BLT T1,XCTMAP+UBTLEN-1	; init table
	SETZM UTBASE		; and clear the base
	RET

; INSERT - Command Dispatch Routine
;
; This routine will insert a section of Monitor code to test using
; the UTEST JSYS.  This routine does not actually insert the test
; into the MONITOR, rather it sets up our data base so we know which
; instructions are to be tested.  It enforces the fact that all the tests
; which are in the UTEST data base fit in a two page window.

.INSER:	NOISE (Code Test)
	CONFRM			; confirm command string
	LOAD T3,TSTPRG		; is test in progress
	SKIPE T3		; ...
	 ERET (Test already in progress)
	CALL RANGE		; returns from in t1, len in t2
	 RET			; error
	LOAD T3,TSTDON		; is this first time since test done?
	SKIPE T3		; ...
	JRST [	CALL RSTBTM	; reset the bit map
		HRRM T1,UTBASE	; save new base address
		SETONE TSTVLD	; say addresses are valid
		SETZRO TSTDON	; and than we're working on a new one
		JRST .+1]	; and contnue in line
	MOVE T3,UTBASE		; get current base
	SUBM T1,T3		; subtract new address
	SKIPGE T3		; Is new address less than current base
	JRST [	MOVMS T3	; get absolute value of t3
		ADD T3,TSTLEN	; add current length
		CAILE T3,WDWLEN	; will it fit?
		JRST INSERE	; insert error
		CALL ADJBTB	; Adjust the bit map
		JRST INSER2]
	ADD T3,T2		; add current length to get total
	CAILE T3,WDWLEN		; 
	JRST INSERE		; insert error
INSER2:	MOVEM T3,TSTLEN		; Save new test length
	SUB T1,UTBASE		; get offset into bit map
	MOVE T3,[POINT 1,TSTMAP] ; get pointer to bit map
	ADJBP T1,T3		; adjust it by t1 bits
	MOVEI T3,1		; get a one
INSER1:	IDPB T3,T1		; and set bit in map
	SOJG T2,INSER1		; loop till entire test is entered
	RET			; and return

INSERE:	ERET (Inserts must not exceed two page window)

; ADJBTB -
;
; This routine will adjust the bit maps so that the two
; page window will start at the lowest Monitor address to test.
;
; CALL ADJBTB
;
; ACCEPTS  T1	New Base address
;
; RETURNS  +1	Always

ADJBTB:	SAVEAC <T1,T2,T3,T4>
	STKVAR <OLDLEN>
	MOVE T3,TSTLEN		; get old test length
	MOVEM T3,OLDLEN		; and save the old length
	EXCH T1,UTBASE		; make new base
	SUB T1,UTBASE		; get offset
	MOVE T2,[POINT 1,TSTMAP] ; get pointer to bit map
	SETZ T4,		; initialize a zero bit
	ADD T1,T3		; get new length
	ADJBP T3,T2		; incr bp to point to old last bit
	ADJBP T1,T2		; and this to point to new last bit
ADJBT1:	LDB T2,T3		; get old bit
	DPB T2,T1		; and make new bit
	DPB T4,T3		; clear old bit
	MOVE Q1,[-1]		; back pointer up one
	ADJBP Q1,T3		; ...
	MOVEM Q1,T3		; and save it
	MOVE Q1,[-1]		; back pointer up onq
	ADJBP Q1,T1		; ...
	MOVEM Q1,T1		; and save this one
	SOSLE OLDLEN		; decrement index
	JRST ADJBT1		; keep looping till we've moved all
	RET			; done
; PUSH -
;
; Routine will push to another EXEC and clean up when done.
; It uses the same routine as SDDT

.PUSH:	NOISE (To New EXEC)
	CONFRM
	HRROI T2,[ASCIZ/SYSTEM:EXEC.EXE/] ; Get pointer to EXEC
	CALL DOFORK		; Create fork, start, and kill when done
	RET			; and then return

; RUN -
;
; This routine will run a program which will be parsed from COMND

.RUN:	NOISE (Program)		; Give noise word
	HRROI T1,[ASCIZ/EXE/]	; Get default extenstion
	MOVEM T1,CJFNBK+.GJEXT	; Save as default extension
	MOVX T1,GJ%OLD		; We want an existing generation
	MOVEM T1,CJFNBK+.GJGEN	; Save flag in GTJFN block
	MOVEI T1,[FLDDB. (.CMFIL)] ; get file
	CALL CFIELD		; and end with CRLF
	CALL DOFORK		; Now execute the program
	RET			; Then return

; RESULTS - Command Dispatch Routine
;
; This routine will type out the results of the Test.  If an instruction
; has been executed, it will be preceeded by an 'X'.

.RESUL:	NOISE (Of Previous Test)
	CONFRM			; Confirm command string
	LOAD T1,TSTVLD		; is there a valid test
	SKIPN T1		; ...
	 ERET (No valid test, Use INSERT first)
	LOAD T1,TSTPRG		; is a test in progress?
	SKIPE T1		; ...
	 ERET (Test still in progress)
	MOVE P3,[POINT 1,TSTMAP] ; pointer to bits in map
	MOVE P4,[POINT 1,XCTMAP] ; pointer to words xcted
	HRL T1,TSTLEN		; get length of section
	HRR T1,UTBASE		; and start in t1
	MOVEI T2,EXMPAG		; where it should go
	PEEK			; get the code
	 ERET ()		; an error
	HRRZ T1,TSTLEN		; get length of section
	MOVNS T1		; make negative
	HRLZ P1,T1		; get in lh of p1
	HRRI P1,EXMPAG		; and start of user page
	HRRZ P2,UTBASE		; monitor address here

; loop to type out all instructions in test

RESUL1:	ILDB T1,P3		; get bit which says we've tested
	ILDB T2,P4		; get bit which says xcted
	SKIPN T1		; have we tested this instr
	JRST RESUL2		; no, skip line
	HRROI T1,[ASCIZ/     /]	; default is not tested
	SKIPN T2		; has this word been executed?
	HRROI T1,[ASCIZ/  X  /]	; it has been executed
	PSOUT			; print out this little info
	CALL TRNLIN		; translate the line
	CALL PCRLF		; type out a crlf
RESUL2:	AOS P2			; increment monitor symbol
	AOBJN P1,RESUL1		; and loop for all of them
	RET			; and return
; SDDT - Command Dispatch Routine
;
; This routine will push to SDDT.  Uses the same routine as
; PUSH

.SDDT:	CONFRM			; make user confimr string
	HRROI T2,[ASCIZ/SYS:SDDT.EXE/]
	CALL DOFORK		; Do the fork
	RET			; And ret when done

; DOFORK -
;
; This routine will create a fork and load the program specified
; in the call into it, start the program, wait for it to complete
; and kill it when it is done.
;
; CALL DOFORK
;
; ACCEPTS  T2	Pointer to file name string to map into process
;		or JFN of file to map in.
;
; RETURNS  +1	Always, when fork halts

DOFORK:	STKVAR (FHNDL)
	MOVX T1,CR%CAP		; same privs
	CFORK			; create a fork
	 ERET ()
	MOVEM T1,FHNDL		; save fork handle
	TLNN T2,777777		; Do we have a pointer or a JFN
	JRST [	MOVE T1,T2	; A JFN - Get JFN in T1
		JRST DOFRK1]	; And skip GTJFN
	MOVX T1,GJ%OLD+GJ%SHT
	GTJFN			; get a jfn for sddt
	 ERET ()
DOFRK1:	HRL T1,FHNDL		; get process handle in lh
	GET			; get the file
	MOVE T1,FHNDL		; get process handle again
	SETZ T2,		; start at primary start address
	SFRKV			; ...
	WFORK			; wait for it to stop
	KFORK			; and kill it when it does
	RET			; Then return
; SET - Command Dispatch Routine
;
; This routine will set the lookup module name to some module
; name parsed from the terminal.  This is used during all lookups
; of Monitor Symbols using the SNOOP JSYS.

.SET:	NOISE (Lookup Module Name to) ; noise
	MOVEI T1,SYMPRS		; parse a symbol
	CALL RFIELD		; ...
	MOVEI T1,ATMBUF		; get address of atom buffer
	HRLI T1,440700		; make standard byte pointer
	CALL ASCR50		; convert to radix 50
	PUSH P,T2		; save it for a little
	CONFRM			; confirm the command
	POP P,T2		; get back the symbol
	MOVEM T2,MODNAM		; and save it
	RET			; and return

; START - Command Dispatch Routine
;
; This routine will start the test using the data in our
; Utest Data Base

.START:	NOISE (Testing)
	CONFRM			; confirm command line
	LOAD T1,TSTPRG		; is test in progress
	SKIPE T1		; ...
	 ERET (Test already in progress)
	LOAD T1,TSTVLD		; do we have a valid test?
	SKIPN T1		; ...
	 ERET (No valid Addresses.  Use INSERT first)
	CALL TOGSTR		; Toggle start the test
	RET			; And return

TOGSTR:	MOVEI T2,TSTBLK		; get addr of arg blk in t2
	MOVE T1,UTBASE		; get test from
	MOVEM T1,.UTADR(T2)	; save start of test
	MOVE T1,TSTLEN		; and length
	MOVEM T1,.UTLEN(T2)	; and save this in arg blk
	MOVE T1,[XWD .UTSET,UABLEN] ; start test function
	SETONE TSTPRG		; lock the test facility
	UTEST			; start the test
	RET			; and return
; STOP - Command Dispatch Routine
;
; This routine will stop the MTEST test and update the EXECTUTE
; bit table to reflect the instructions actually executed

.STOP:	NOISE (Testing)
	CONFRM			; confirm the command
	LOAD T1,TSTPRG		; is a test in progress?
	SKIPN T1		; ...
	 ERET (No test in progress)
	CALL TOGSTP		; Toggle stop the test
	RET			; And return

TOGSTP:	MOVE T1,[XWD .UTCLR,UABLEN] ; stop testing
	MOVEI T2,XCTBLK		; get address of argument block
	MOVE T3,UTBASE		; get base address
	MOVEM T3,.UTADR(T2)	; save the base address
	MOVE T3,TSTLEN		; get length of test
	MOVEM T3,.UTLEN(T2)	; save the length
	UTEST			; ...
	SETZRO TSTPRG		; say no test in progress
	SETONE TSTDON		; say test is done
	RET			; and return

; EXIT - Command Dispatch Routine
;
; This routine will Exit MONTST.  It will not let one
; exit unless they have removed all tests

.EXIT:	NOISE (Program)		; output noise word
	CONFRM			; confirm the command
	LOAD T1,TSTPRG		; is a test in progress
	SKIPE T1		; ...
	 ERET (Test still in progress, Stop test first)
	HALTF			; and halt the program
	RET			; if continued
; NUMOUT -
; 
; This routine will type out a number to the primary output in octal
;
; CALL NUMOUT
;
; ACCEPTS  T1 	Number to be output
;
; RETURNS  +1	Always

NUMOUT:	SAVEAC <T1,T2,T3>
	MOVE T2,T1		; Get number in T2
	MOVEI T1,.PRIOU		; And output to primary output
	MOVEI T3,^D8		; In octal
	NOUT			; ...
	 ERET ()		; problem
	RET			; Return

; PRVINI -
;
; Routine initializes WHEEL privileges.  If the user does not have
; Wheel privs, this routine will give the +1 Return.  If the user
; has Wheel but is not enabled, then this routine will prompt the user
; as to whether wheel should be enabled.
;
; CALL PRVINI
;
; RETURNS  +1  Privs not enabled
;          +2  WHEEL enabled

PRVINI:	SAVEAC <T1,T2>
	STKVAR <PRIVS>
	MOVEI T1,.FHSLF		; Get our Process Handle
	RPCAP			; Read the Capabilities
	TXNN T2,SC%WHL		; Is user a Wheel
	 ERET <Need to be WHEEL>
	TXNE T3,SC%WHL		; Is user enabled
	RETSKP			; Yes
	MOVEM T2,PRIVS		; Save Privs possible
	TMSG <You need to be an enabled WHEEL to run this program>
	PROMPT (Do You Want to be enabled?)
	MOVEI T1,[FLDDB. (.CMKEY,,YESNO)]
	CALL CFIELD		; Read field and require confirm
	HRRZ T1,0(T2)		; Get RH of keyword parsed
	SKIPN T1		; He said yes
	RET			; He doesn't want to enable. Loose
	MOVEI T1,.FHSLF		; Get our process handle
	MOVE T2,PRIVS		; Get the privs
	SETZ T3,		; Clear T3
	TXO T3,SC%WHL		; And set WHEEL
	EPCAP			; And enable it
	RETSKP			; And return success

; PSIINI -
;
; Initialize the PSI system for this process to recieve CONTROL/D
; Interrupts from the terminal which will toggle Start Test, Stop
; Test.
;
; CALL PSIINI
;
; RETURNS  +1  Always

PSIINI:	
	MOVEI T1,.FHSLF		; Get our process Handle
	MOVE T2,[LEVTAB,,CHNTAB] ; Get the tables
	SIR			; Specify them
	EIR			; Enable the interrupt system
	MOVE T2,[1B<.ICTOG>]	; Get toggle channel
	AIC			; And enable toggle channel
	MOVE T1,.TICCD		; Get control d code
	MOVEM T1,TOGCHR		; And initialize Toggle character
	MOVE T1,[.TICCD,,.ICTOG] ; Assign control D to toggle channel
	ATI			; ...
	RET			; And return

; TOGGLE - Command dispatch routine
;
; This routine will change the toggle interrupt character

.TOGGL:	NOISE (Character is)	; Output noise
	MOVEI T1,[FLDBK. (.CMKEY,,TOGKEY,,<>,TOGBRK)]
	CALL CFIELD		; Parse the toggle character
	MOVE T1,TOGCHR		; Get old toggle character
	DTI			; Deassign the interrupt character
	HRL T1,0(T2)		; Get New toggle code
	HRRI T1,.ICTOG		; And put on .ICTOG channel
	ATI			; Assign it
	RET			; And finished

; PSITOG -
;
; This routine toggles the tests, if the test is currently on, the test
; is turned off, if the test is currently off, the test is turned on.
; If no valid test, the interrupt quietly goes away.

PSITOG:	CALL PSITG0		; Do the work lower so we have stack ACs
	DEBRK			; Debreak when done

PSITG0:	SAVEAC <T1,T2,T3,T4>	; Save some ACs
	LOAD T1,TSTVLD		; Get test valid flag
	SKIPN T1		; is a test valid
	 RET			; No valid test
	LOAD T1,TSTPRG		; Get test in progress flag
	SKIPN T1		; Is one in progress?
	JRST [	CALL TOGSTR	; No, Toggle start it
		TMSG <[MTEST Test Started]
> ; output message
		RET]		; And return
	CALL TOGSTP		; Toggle stop it
	TMSG <[MTEST Test Stopped]
> ; output message
	RET			; and return

; HELP - 
;
; This routine will print out the file MTEST.HLP from device HLP:
; It maps a page at a time to HLPBUF then types it out.

.HELP:	STKVAR <HLPBUF,HLPJFN>
	CONFRM
	MOVX T1,GJ%OLD+GJ%SHT	; GTJFN flags
	HRROI T2,[ASCIZ/HLP:MTEST.HLP/]	;Help file
	GTJFN			;Get a JFN for it
	 ERET ()		;Some problem
	HRRZM T1,HLPJFN		;Save Help JFN
	MOVX T2,OF%RD		;Want to read the file
	OPENF			;Open it.
	 ERJMP [MOVE T1,HLPJFN	;Get back jfn
		RLJFN		;Release it
		 JFCL		;Maybe not there
		ERET ()]	;And return the error
	SIZEF			;Find number of pages in file
	 ERET ()		;some error
	MOVN P1,T3		;Get negative number of pages in P1
	HRLZS P1		;And put in left half (AOBJN Pointer)
	CALL FFFPAG		;find first free page in process
	 RET			;No free pages
	MOVEM T1,HLPBUF		;Save page # of help buffer

HLPLOP:	HRLZ T1,HLPJFN		;Get source JFN in LH
	HRR T1,P1		;And page in RH
	HRLZI T2,.FHSLF		;Get our process handle as destination
	HRR T2,HLPBUF		;And get page for help buffer
	MOVX T3,PM%RD		;Read only
	PMAP			;Map the page
	MOVE T2,HLPBUF		;get help buffer page
	IMULI T2,1000		;Find word address
	HRROS T2		;And make pointer to help string
	MOVEI T1,.PRIOU		;Output to primary output
	MOVEI T3,5000		;Write out this many bytes
	SETZ T4,		;or terminate on NULL byte
	SOUT			;output it
	SKIPN T3		;have we encountered a NULL byte
	AOBJN P1,HLPLOP		;no, loop till no more pages
	SETOM T1		;unmap the help buffer
	HRLZI T2,.FHSLF		;In our process
	HRR T2,HLPBUF		;At this address
	PMAP
	MOVE T1,HLPJFN		;Get back JFN
	CLOSF			;And close it
	 ERET ()
	RET

FFFPAG:	HRLZI T1,.FHSLF		;Get pointer to page
FFFPG0:	RPACS			;Find access
	 ERJMP [ERET ()]	;Pass down error
	TXNE T2,PA%PEX		;Does page exist
	AOJA T1,FFFPG0		;Yes, loop for more
	HRRZS T1		;Clear left half of T1
	RETSKP

	END <3,,ENTVEC>