Google
 

Trailing-Edge - PDP-10 Archives - tops10_703a_sys_atpch16_bb-fr67f-bb - cnforn.x16
There are 2 other files named cnforn.x16 in the archive. Click here to see a list.
	TITLE	CNFORN - CONFIG module for ORION
	SUBTTL	Nick Tamburri/JAD		23-Apr-86

;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1975,1976,1977,1978,1979,1980
;1981,1982,1983,1984,1986,1987.  ALL RIGHTS RESERVED.
;
;
;     THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;     AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE
;     AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS
;     SOFTWARE  OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR
;     OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON.  NO  TITLE  TO
;     AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED.
;     
;     THE INFORMATION  IN  THIS  SOFTWARE  IS  SUBJECT  TO  CHANGE
;     WITHOUT  NOTICE  AND SHOULD NOT BE CONSTRUED AS A COMMITMENT
;     BY DIGITAL EQUIPMENT CORPORATION.
;     
;     DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY
;     OF  ITS  SOFTWARE  ON  EQUIPMENT  WHICH  IS  NOT SUPPLIED BY
;     DIGITAL.


	SALL
	SEARCH	GLXMAC
	SEARCH	ORNMAC
	PROLOG	(CNFORN)

	.TEXT	"/LOCALS"

	EXTERN	WTORTN
	.REQUE	CNFHDW
	SUBTTL	Macros and other stuff

	F==.A13			;Dedicated flag AC

	FL.ADD==1B0		;Various bit flags
	FL.NO==1B1
	FL.DMN==1B2
	FL.HEA==1B3
	FL.NCD==1B4
	FL.WAC==1B5

;CPU STATUS FLAGS

	CS.DWN==1B0		;DOWN
	CS.NEX==1B1		;NON-EXISTANT
	CS.DET==1B2		;DETACHED
	CS.NOK==1B3		;OK WORD NOT COUNTING UP
	CS.BOT==1B4		;THIS IS THE BOOT CPU

DEFINE	GTTAB(AC,ENTRY,DEFAULT),<
	MOVE	AC,[ENTRY]
	XLIST
	GETTAB	AC,
	  IFB  <DEFAULT>,<JSP TF,GTBERR>
	  IFNB <DEFAULT>,<MOVE AC,[DEFAULT]>
	LIST
	SALL
>
;STORAGE

;*** KEEP THE NEXT TWO SYMBOLS CONTIGUOUS
RCNARG:	BLOCK	1		;RECON. .RCBTX FUNCTION WORD COUNT
RSNTXT:	BLOCK	<<.TXTSZ==16>/5>+1 ;BUFFER FOR SNAPSHOT/SHUTDOWN REASON
RSNEND==.-1

RSNADR:	BLOCK	1		;Address of reason text
CTYBLK:	BLOCK	3		;Arg block for CTY typeout TRMOP.
DCHARG:	BLOCK	.DCMAX		;DSKCHR UUO BLOCK
INIDON:	BLOCK	1		;Initialization done flag
ULDTXT:	BLOCK	10		;DEVICE STORAGE FOR MICROCODE ACKS AND ERRORS
SYSSIZ:	BLOCK	1		;SIZE OF THE MONITOR
NWCORE:	BLOCK	1		;NUMBER OF WORDS OF MEMORY ON THE SYSTEM
JOBPTR:	BLOCK	1		;AOBJN POINTER TO ALL JOBS
CPUN:	BLOCK	1		;NUMBER OF RUNNING CPU'S IN SYSTEM
CPUOK:	BLOCK	1		;NUMBER OF CPUS WITH OK WORDS RUNNING
CPURUN:	BLOCK	1		;MASK WHICH ARE RUNNING 
CPUSTS:	BLOCK	6		;ONE PER CPU (EVEN IF NOT THERE)
				;LH = CPU STATUS FLAGS (CS.XXX)
				;RH = CDB ADDRESS
ADDREM:	BLOCK	1		;ADDRESS OF "ADD" OR "REMOVE" TEXT
TXTPTR:	BLOCK	1		;BYTE POINTER TO DEPOSIT MESSAGE CHARACTERS
BTXBLK:	BLOCK	20		;BOOT TEXT BLOCK


; SET KLINIK
Z.KLIB:!			;Start of data to zero
KLICPU:	BLOCK	1		;CPU number or 7 for ALL
KLIDTD:	BLOCK	<26+3>/4	;Data for DTE. UUO
Z.KLIE:!			;End of data to zero
	SUBTTL	Dispatch Tables

;Main commands

CNFDSP::$STAB
	.CFADD##,,C$ADD			;Add command
	.CFAUT##,,C$AUTO		;Autoconfigure
	.CFREM##,,C$REMV		;Remove
	.CFLOD##,,C$LOAD		;Load microcode
	.CFSET##,,C$SET			;Set
	.CFSHO##,,C$SHOW		;Show
	.CFSHT##,,C$SHUT		;Shutdown
	.CFSNP##,,C$SNAP		;Snapshot
	.CFSUS##,,C$SUSP		;Suspend
	$ETAB
CNFDSX::BLOCK	1			;For stand-alone CONFIG
CNFDSL==:CNFDSX-CNFDSP			;Ditto

;ADD/REMOVE commands

ADDDSP:	$STAB
	.ARMEM##,,ADDMEM		;Memory
	.CMDEV,,ADDDEV			;Device
	$ETAB

ADDCPX:	$STAB
	.ARCPU##,,ADDCPU		;CPU
	.ARCI##,,ADDCI			;CI
	.ARNI##,,ADDNI			;NI
	$ETAB

;SET commands

SETDSP:	$STAB
	.STBOT##,,SETBOT		;Boot text
	.STULD##,,SETULD		;Set [no] microcode loading
	.STNOT##,,SETNOT		;Negator
	.STAUT##,,SETAUT		;Auto-reload
	.STKLI##,,KLINIK		;Set KLINIK
	.STDMP##,,SETDMP		;Set DUMP (on)
	.STRLD##,,SETRLD		;Set RELOAD (on)
	.STPLC##,,SETPLC		;SET POLICY-CPU
	$ETAB

;SET NO commands

STNDSP:	$STAB
	.STBOT##,,SETBOT		;Boot text
	.STULD##,,SETULD		;Set [no] microcode loading
	.STAUT##,,SETAUT		;Auto-reload
	.STDMP##,,SETDMP		;Set DUMP (on)
	.STRLD##,,SETRLD		;Set RELOAD (on)
	$ETAB
;SHOW commands

SHODSP:	$STAB
	.SHBTX##,,SHWBTX		;SHOW BOOT-TEXT
	.SHHDW##,,SHWHDW		;SHOW HARDWARE-CONFIGURATION
	.SHKLI##,,KLISHW		;SHOW KLINIK
	.SHSTP##,,SHWSTP		;SHOW STOPCODE-FLAGS
	$ETAB

;CPU names table

	DEFINE	CPUNMS(NUMBER)<IRP <NUMBER>,<SIXBIT |CPU'NUMBER|>>

CPUNAM:	CPUNMS<0,1,2,3,4,5>

;CPU bits

CPUBIT:	EXP 1,2,4,10,20,40		;BIT FOR CPUN
	SUBTTL	CNFORN - Main dispatch routine.

;	Here from ORION's application dispatch, to dispatch to the
; various CONFIG command routines.

;	INTERN	CNFORN			;MAKE AVAILABLE TO ORION

CNFORN::SKIPE	INIDON			;Have we initialized ourselves
	  JRST	CNF.1			;Yes, don't do it again
	GTTAB	S1,%CNNWC		;Get the number of words of memory
	MOVEM	S1,NWCORE		;Save it
	GTTAB	S1,%CNSIZ		;Get maximum core size
	MOVEM	S1,SYSSIZ		;Store it
	GTTAB	S1,%CNSJN		;Get -#segments,,#jobs
	MOVNI	S1,-1(S1)		;Make it negative and skip null job
	HRLI	S1,1			;Start at job 1
	MOVSM	S1,JOBPTR		;Save for DETJBS
	SETOM	INIDON			;Remember we've come through here

CNF.1:	$CALL	SETCPU			;Set up CPU database
	$CALL	SETDSK##		;Set up disk database
	MOVE	S2,COM.PB(MI)		;Was parser block filled in
	ADDI	S2,(MI)			;POINT PB AT THE BLOCK
	MOVE	S1,S2			;GET THE BLOCK POINTER
	$CALL	P$SETU##		;SETUP THE POINTER
	$CALL	P$KEYW##		;GET THE FIRST KEYWORD
	 $RETIF				;ERROR
	MOVEI	S2,CNFDSP		;Get the address of the table
	$CALL	TABSRC##		;Search the command table for dispatch
	 $RETIF				;Illegal command?
	$CALL	.SAVET			;Give workers room
	SETZB	F,TXTPTR		;Clear all flags, and message address
	PJRST	(S2)			;Go process the command
	SUBTTL	Command processors -- ADD/REMOVE commands

C$REMV:	TXZA	F,FL.ADD		;Clear the adding flag
C$ADD:	TXO	F,FL.ADD		;Set flag to add
	MOVEI	S1,[ASCIZ |ADD|]	;Assume ADD command
	TXNN	F,FL.ADD		;Good guess?
	MOVEI	S1,[ASCIZ |REMOVE|]	;No
	MOVEM	S1,ADDREM		;Save for $IACK
	$CALL	P$KEYW##		;Get the object of the verb
	CAXE	S1,.CMDEV		;This will fail P$KEYW
	$RETIF
	MOVEI	S2,ADDDSP		;Point at dispatch table
	$CALL	TABSRC##		;See if a canned command
	JUMPT	(S2)			;Dispatch if found a match
	MOVEI	S2,ADDCPX		;Point to per-CPU table
	PUSHJ	P,CPUSRC		;Search the table
	JUMPT	(S2)			;Dispatch if found a match
	HRLZ	S2,S1			;Copy the argument
	DEVTYP	S2,			;See what type of device
	  $RETF				;That's odd
	JUMPE	S2,.RETF		;No such device if zero returned
	LOAD	S2,S2,TY.DEV		;Get type code
	CAXN	S2,.TYDSK		;Disk?
	PJRST	ADDKON			;Yes, go do that
	CAXN	S2,.TYMTA		;Magtape?
	JRST	RATKON			;Yes, go do that
	$RETF				;Error

RATKON:	$IACK	(^T/@ADDREM/ magtape controller doesn't work yet)
	$RETF				;Not yet
	SUBTTL	ADD/REMOVE MEMORY

ADDMEM:	$IACK	(^T/@ADDREM/ MEMORY)
	$CALL	GETADR			;Get the beginning address
	  $RETIF
	MOVE	T2,S1			;Save it
	$CALL	GETADR			;Get the end address
	  $RETIF
	MOVE	T3,S1			;Save it
	MOVEI	T1,3			;Get the lenght of the arg block
	MOVE	S1,[XWD .RCMON,T1]	;Assume adding
	TXNN	F,FL.ADD		;Are we adding?
	MOVE	S1,[XWD .RCMOF,T1]	; Not, so we're removing
	RECON.	S1,			;Tell the monitor what we want
	  JRST	RCNERR			;Go type the code and reason
	MOVEI	S1,[ASCIZ |online|]	;Assume he removed memory
	TXNN	F,FL.ADD		;Did he really add
	MOVEI	S1,[ASCIZ |offline|]	;Yes, get real message
	LSH	T2,-1			;Convert to kilos
	LSH	T3,-1			;Both addresses
	$TEXT	(WTORTN,<Memory from address ^D/T2/K to ^D/T3/K is now ^T/(S1)/>)
	LSH	T2,^D10			;Convert to words now
	LSH	T3,^D10			; .  .  .
	$TEXT	(WTORTN,<(Words from ^O/T2/ to ^O/T3/)>)
	$RETT				;Return true
	SUBTTL	ADD/REMOVE DEVICE

ADDDEV:	PUSHJ	P,P$DEV##		;Parse a device
	$RETIF				;If error
	HRROI	S1,ARG.DA(S1)		;Point at the device string
	PUSHJ	P,S%SIXB		;Convert to SIXBIT
	MOVEI	S1,2			;Number of arguments
	DMOVEM	S1,RCNARG		;Save for ATTDET
	$IACK	(^T/@ADDREM/ ^W/RCNARG+1/) ;ACK them
	PUSHJ	P,ATTDET		;Do the RECON. UUO
	$RETIF				;If error
	MOVEI	S1,[ITEXT (added)]
	TXNN	F,FL.ADD		;Removing?
	MOVEI	S1,[ITEXT (removed)]
	$TEXT	(WTORTN,<Device ^W/RCNARG+1/ ^I/(S1)/>)
	$RETT				;Done
	SUBTTL	ADD/REMOVE KONTROLLER

ADDKON:	$IACK	(^T/@ADDREM/ CONTROLLER)
	$SAVE	<P1>			;Make room
	HRLZS	P1,S1			;Save controller name, move to LH
	MOVEM	S1,DCHARG+.DCNAM	;Set up for DSKCHR
	MOVE	S1,[.DCMAX,,DCHARG]	;Point at DSKCHR argument list
	DSKCHR	S1,			;Get info
	  JRST	AKON.2			;Gulp?
	LOAD	S1,DCHARG+.DCXCH,DC.XCA	;Get CPU mask
	TDNE	S1,CPURUN		;Any of the CPUs up?
	JRST	AKON.1			;Yes, remove kontroller and return
	$TEXT	(WTORTN,<CPU owning controller ^W/P1/ is down>)
	$RETF				;END MESSAGE AND RETURN

AKON.1:	MOVE	S1,P1			;Copy controller name
	TXNN	F,FL.ADD		;Removing a controller?
	PUSHJ	P,CRDKON		;Yes, must check first
	TXNE	F,FL.NCD		;Can we do it?
	JRST	AKON.2			;Nope
	MOVE	S1,P1			;Copy controller name
	PUSHJ	P,RADKON		;Remove the controller
	MOVEI	S1,[ITEXT (added)]
	TXNN	F,FL.ADD		;Removing?
	MOVEI	S1,[ITEXT (removed)]
	$TEXT	(WTORTN,<Controller ^W/P1/ ^I/(S1)/>)
	$RETT				;Done

AKON.2:	MOVEI	S1,[ITEXT (added)]
	TXNN	F,FL.ADD		;Removing?
	MOVEI	S1,[ITEXT (removed)]
	$TEXT	(WTORTN,<Controller ^W/P1/ can't be ^I/(S1)/>)
	$RETF				;Croak 'em
	SUBTTL	ADD/REMOVE CPU

ADDCPU:	SUBI	S1,.ARCPU##		;Translate to CPU number
	CAIL	S1,0			;Range check
	CAILE	S1,5			; (ALL is illegal)
	$RETF				;Give up if not valid
	$SAVE	<P1>			;Make room for the CPU number
	MOVE	P1,S1			;Save it
	$IACK	(^T/@ADDREM/ CPU)
	MOVSI	S1,(CS.NEX)		;NON-EXISTANT BIT
	TDNN	S1,CPUSTS(P1)		;IN RANGE, IS IT REAL
	JRST	ADDCP1			;Yep try to do it
	$TEXT	(WTORTN,<Illegal CPU specified - CPU^O/P1/ does not exist>)
	$RETF

ADDCP1:	TXNE	F,FL.ADD		;Adding?
	JRST	A%CPU			;Go to that routine
;	JRST	R%CPU			;Remove CPU
;HERE TO REMOVE A CPU

	.CREF	CS.DWN			;BIT WE'RE TESTING
R%CPU:	SKIPL	CPUSTS(P1)		;CPU ALREADY DOWN
	JRST	RCPU.1			;NO
	$TEXT	(WTORTN,<CPU^D/P1/ is already removed>)
	$RETT				;YES, JUST RETURN NOW

RCPU.1:	MOVE	S1,CPUN			;GET NUMBER OF RUNNING CPUS
	CAIE	S1,1			;TRYING TO REMOVE THE LAST REMAINING CPU
	JRST	RCPU.2			;NO, ONWARD
	$TEXT	(WTORTN,<Use SHUTDOWN to remove last CPU>)
	$RETF				;END OUTPUT AND RETURN

RCPU.2:	MOVE	S1,CPUOK		;NUMBER OF ACTUALLY RUNNING CPUS
	CAIE	S1,1			;ONLY ONE OF THOSE LEFT
	JRST	RCPU.3			;NO
	MOVSI	S1,(CS.NOK)		;YES, CHECK IF CPU NOT RUNNING ANYWAY
	TDNE	S1,CPUSTS(P1)	 	;WELL?
	JRST	RCPU.3			;CPU IS DEAD, OK TO REMOVE IT
	$TEXT	(WTORTN,<No running CPUs would be left>)
	$RETF				;IF OPERATOR REALLY WANTS THIS, USE "SHUT"

RCPU.3:	$CALL	P$SWITCH##		;See if he typed the force switch
	JUMPF	RCPU.4			;No, check before doing
	HLRZ	S1,0(S1)		;Get switch keyword
	CAIN	S1,.ARFRC##		;Force switch?
	JRST	RCPU.5			;Yes, so bypass
	$RETF				;COMMAND ERROR

RCPU.4:	TXO	F,FL.WAC	 	;SET "WORRY ABOUT CPU"
	SETZ	S1,			;CHECK ALL CONTROLLERS
	MOVE	S2,CPUBIT(P1)		;GET BIT FOR THE CPU
	PUSHJ	P,CRDKON		;CHECK DISK CONTROLLERS
	TXNE	F,FL.NCD		;DID SOME CHECK FAIL
	JRST	RCPU.E			;GENERIC ERROR MESSAGE
	MOVE	S1,P1			;Get the CPU number
	PUSHJ	P,LSTDEV		;LOOK FOR LOST DEVICES, GIVE WARNING
	MOVE	S1,P1			;Get the CPU we're removing
	PUSHJ	P,DETJBS		;DETACH JOBS AS APPROPRIATE
	TRNA				;WE HAVE DONE CHECKS
RCPU.5:	$TEXT	(WTORTN,<%Bypassing lots of checking>)
	MOVSI	S1,(CS.DWN)		;GET CPU IS DOWN BIT
	IORB	S1,CPUSTS(P1)		;LIGHT IN STATUS BLOCK
	SOS	CPUN			;ONE LESS CPU IN SYSTEM
	TLON	S1,(CS.NOK)		;WAS CPU'S OK WORD COUNTING BEFORE
	SOS	CPUOK			;YES, BUT IT WILL STOP SOON
	MOVEM	S1,CPUSTS(P1)		;LIGHT THE BIT NOW
	MOVE	S1,CPUBIT(P1)		;GET BIT FOR CPU BEING REMOVED
	ANDCAB	S1,CPURUN		;CLEAR/GET NEW RUNNING CPU MASK
	HRLI	S1,.STCRN		;SET RUN CPUN
	SETUUO	S1,			;SET NEW SPECIFICATION
	  $TEXT	(WTORTN,<%SETUUO to set CPU^D/P1/ runnability failed>)
	MOVSI	T1,(CS.NOK)		;IS CPU'S OK WORD COUNTING?
	TDNE	T1,CPUSTS(P1)
	JRST	RCPU.7			;NO, AVOID LOOP, SHUT DOWN IF ALREADY DEAD
RCPU.6:	MOVEI	S1,(P1)			;GET CPU NUMBER
	LSH	S1,1			;*2 FOR SUBTABLE GETTABS
	ADD	S1,[%CVJOB]		;JOB CURRENTLY RUNNING ON CPU
	GETTAB	S1,			;GET IT
	  $TEXT	(WTORTN,<%Unable to determine job running on CPU^D/P1/ - continuing>)
	JUMPN	S1,RCPU.6		;WAIT FOR CPU TO ONLY RUN NULL JOB

	SETZ	S1,			;REMOVE ALL CONTROLLERS
	MOVE	S2,CPUBIT(P1)		;BIT FOR THE CPU BEING REMOVED
	TXNN	F,FL.DMN		;DON'T DETACH IF FORCED REMOVAL
	PUSHJ	P,RADKON		;GO AND DETACH ALL THE UNITS NOW
RCPU.7:	MOVEI	S1,ST.URE(P1)		;GET CPU NUMBER, FLAG AS REMOVE
	HRLI	S1,.STCDN		;SET "DOWN" CPUN
	SETUUO	S1,			;SHUT IT DOWN
	  $TEXT	(WTORTN,<%Can't shut down CPU^D/P1/>)
RCPU.8:	MOVEI	S1,(P1)			;GET CPU NUMBER
	LSH	S1,1			;*2 FOR SUBTABLE GETTABS
	ADD	S1,[%CCOKP]		;GET THE OK WORD FOR CPUN
	GETTAB	S1,			;GET IT
	  SKIPA				;ASSUME DOWN
	JUMPLE	S1,RCPU.8		;WAIT FOR IT TO STICK ITS HEAD IN THE SAND

	MOVE	S1,CPUN			;HOW MANY CPU'S ARE LEFT
	CAIE	S1,1			;ONLY 1 REMAINING
	JRST	RCPU.9			;NO, JUST MAKE THE CPU GO AWAY
	MOVSI	S1,.STCSB		;OK TO CACHE MONITOR DATA BASE NOW
	HRRI	S1,1B35			;LIGHT BIT TO TURN ON CACHE
	SETUUO	S1,			;SINCE ONLY 1 PROCESSOR LEFT
	  JFCL				;OK, MUST BE A KI
RCPU.9:	MOVSI	S1,(CS.DET)		;"CPU DETACHED" BIT
	TDNE	S1,CPUSTS(P1)		;IS THE CPU ALREADY DETACHED
	JRST	RCPU.0			;YES, ACK 'EM AND RETURN
	IORM	S1,CPUSTS(P1)		;SAY DETACHED NOW
	MOVEI	S1,2			;Get the lenght of the arge block
	MOVE	S2,CPUNAM(P1)		;And get the SIXBIT CPU name
	DMOVEM	S1,RCNARG		;SAVE ARGUMENTS
	PUSHJ	P,ATTDET		;Do the UUO
	JUMPF	RCPU.E			;If error
RCPU.0:	$TEXT	(WTORTN,<CPU^D/P1/ removed>)
	$RETT

RCPU.E:	$TEXT	(WTORTN,<CPU^D/P1/ can't be removed>)
	$RETF				;ERROR
;HERE TO ADD A CPU

	.CREF	CS.DWN			;BIT WE'RE TESTING
A%CPU:	SKIPL	CPUSTS(P1)		;IS IT ALREADY UP
	JRST	ACPU.2			;YES, GO LET IT IN
	MOVSI	S1,(CS.DWN!CS.NOK)	;CPU IS DOWN BIT
	ANDCAM	S1,CPUSTS(P1)		;NOT ANY MORE
	AOS	CPUN			;ONE MORE CPU RUNNING
	AOS	CPUOK			;ONE MORE COUNTING
	MOVSI	S1,.STCSB		;MUST UNCACHE MONITOR DATA BASE
	SETUUO	S1,			;DO IT (1B35 = 0)
	  JFCL				;OK, MUST BE A KI
	MOVSI	S1,(CS.DET)		;CPU DETACHED BIT
	TDNN	S1,CPUSTS(P1)		;IS IT
	JRST	ACPU.1			;NO, LET IT IN
	ANDCAM	S1,CPUSTS(P1)		;CLEAR DETACHED CPU BIT
	MOVEI	S1,2			;TWO WORD ARGUMENT
	MOVE	S2,CPUNAM(P1)		;GET CPU NAME
	DMOVEM	S1,RCNARG		;SAVE
	PUSHJ	P,ATTDET		;DO THE UUO
	$RETIF				;QUIT WHILE WE'RE AHEAD?
ACPU.1:	MOVE	S1,P1			;GET CPU NUMBER (ST.URE OFF = ADD THIS ONE)
	HRLI	S1,.STCDN		;SET CPU UP ( OR ALLOWED TO BE UP )
	SETUUO	S1,			;i.e. LET THIS CPU IN
	  $TEXT	(WTORTN,<%Can't set CPU^D/P1/ to up status>)
ACPU.2:	MOVE	S1,CPUBIT(P1)		;GET A BIT FOR CPU BEING ADDED
	IORB	S1,CPURUN		;ADD/GET NEW RUNNING CPU MASK
	HRLI	S1,.STCRN		;NOW ALLOW IT TO RUN JOBS
	SETUUO	S1,			;OTHERWISE WHY BOTHER ADDING IT
	  $TEXT	(WTORTN,<%Can't set CPU^D/P1/ to run jobs>)
	$TEXT	(WTORTN,<CPU^D/P1/ added>) ;ACK 'EM
	$RETT				;ADDING IS A LOT EASIER THAN REMOVING
	SUBTTL	ADD/REMOVE CI

ADDCI:	SUBI	S1,.ARCI##		;TRANSLATE TO CI NUMBER
	CAIL	S1,0			;RANGE
	CAILE	S1,6			; CHECK
	$RETF				;GIVE UP IF NOT VALID
	$SAVE	<P1>			;SAVE AN AC
	MOVSI	P1,-6			;ASSUME ALL CPUS
	CAIE	S1,6			;WAS IS?
	HRRO	P1,S1			;NO
	PUSHJ	P,P$CFM##		;NEED A CRLF
	$RETIF				;ERROR
	$IACK	(^T/@ADDREM/ CI)

ADCI.1:	HRLZ	T1,P1			;GET CPU NUMBER
	HRRI	T1,.DIISM		;DIAG. FUNCTION TO SET MAINT MODE
	TXNE	F,FL.ADD		;"ADD CI"?
	HRRI	T1,.DIICM		;YES, THAT MEANS CLEAR MAINT MODE
	MOVX	T2,<574B8>		;LOAD DEVICE CODE
	MOVEI	S1,[ASCIZ |dis|]	;ASSUME REMOVING
	TXNE	F,FL.ADD		;GOOD GUESS?
	MOVEI	S1,[ASCIZ |en|]		;NOPE
	MOVE	S2,[XWD -2,T1]		;POINT AT THE ARGUMENTS
	DIAG.	S2,			;DO THE UUO
	  JRST	ADCI.2			;ERROR
	$TEXT	(WTORTN,<CI port on CPU^O/T1,LHMASK/ ^T/0(S1)/abled>)
	JRST	ADCI.3			;ONWARD

ADCI.2:	CAIN	S2,DIANR%		;CPU DOWN?
	JRST	ADCI.3			;YES
	CAIL	S2,DIAETL		;KNOWN ERROR CODE?
	MOVEI	S2,DIAETL		;NO, USE CATCH-ALL
	$TEXT	(WTORTN,<DIAG. UUO error attempting to ^T/0(S1)/able CI port on CPU^O/T1,LHMASK/^M^J(Error (^O/S2/) ^T/@DIAETX(S2)/)>)

ADCI.3:	AOBJN	P1,ADCI.1		;LOOP FOR ANOTHER CPU
	$RETT				;RETURN
	SUBTTL	ADD/REMOVE NI

ADDNI:	SUBI	S1,.ARNI##		;TRANSLATE TO CI NUMBER
	CAIL	S1,0			;RANGE
	CAILE	S1,6			; CHECK
	$RETF				;GIVE UP IF NOT VALID
	$SAVE	<P1>			;SAVE AN AC
	MOVSI	P1,-6			;ASSUME ALL CPUS
	CAIE	S1,6			;WAS IS?
	HRRO	P1,S1			;NO
	PUSHJ	P,P$CFM##		;NEED A CRLF
	$RETIF				;ERROR
	$IACK	(^T/@ADDREM/ NI)

ADNI.1:	HRLZ	T1,P1			;GET CPU NUMBER
	HRRI	T1,.DIISM		;DIAG. FUNCTION TO SET MAINT MODE
	TXNE	F,FL.ADD		;"ADD NI"?
	HRRI	T1,.DIICM		;YES, THAT MEANS CLEAR MAINT MODE
	MOVX	T2,<564B8>		;LOAD DEVICE CODE
	MOVEI	S1,[ASCIZ |dis|]	;ASSUME REMOVING
	TXNE	F,FL.ADD		;GOOD GUESS?
	MOVEI	S1,[ASCIZ |en|]		;NOPE
	MOVE	S2,[XWD -2,T1]		;POINT AT THE ARGUMENTS
	DIAG.	S2,			;DO THE UUO
	  JRST	ADNI.2			;ERROR
	$TEXT	(WTORTN,<NI port on CPU^O/T1,LHMASK/ ^T/0(S1)/abled>)
	JRST	ADNI.3			;ONWARD

ADNI.2:	CAIN	S2,DIANR%		;CPU DOWN?
	JRST	ADNI.3			;YES
	CAIL	S2,DIAETL		;KNOWN ERROR CODE?
	MOVEI	S2,DIAETL		;NO, USE CATCH-ALL
	$TEXT	(WTORTN,<DIAG. UUO error attempting to ^T/0(S1)/able NI port on CPU^O/T1,LHMASK/^M^J(Error (^O/S2/) ^T/@DIAETX(S2)/)>)

ADNI.3:	AOBJN	P1,ADNI.1		;LOOP
	$RETT				;RETURN
	SUBTTL	"LOAD microcode"


C$LOAD:	$IACK	(LOAD microcode)
	PUSHJ	P,ULDARG		;GET DIAG ARGUMENTS
	$RETIF				;CHECK FOR ERRORS
	HRRI	T1,.DILOD		;FUNCTION CODE
	MOVE	S1,[-2,,T1]		;SET UP UUO AC
	DIAG.	S1,			;LOAD MICROCODE
	  JRST	LOAD.E			;FAILED
	$TEXT	(WTORTN,<Microcode loaded on ^T/ULDTXT/>)
	$RETT				;RETURN
LOAD.E:	$TEXT	(WTORTN,<Microcode load failed; ^A>)
	PJRST	DIAERR			;REPORT DIAG ERROR AND RETURN
; RETURN DIAG. UUO ARGUMENTS FOR LOAD AND SET [NO] MICROCODE COMMANDS
ULDARG:	SETZ	T1,			;ASSUME CPU0
	PUSHJ	P,P$KEYW##		;GET A KEYWORD
	JUMPF	ULDDEV			;TRY FOR A DEVICE CODE

; CPU NUMBER
ULDCPU:	MOVEI	S2,-.ARCPU##(S1)	;GET POSSIBLE CPU INDEX
	CAIL	S2,0			;RANGE
	CAILE	S2,5			; CHECK
	JRST	ULDKON			;PERHAPS A KONTROLLER
	MOVE	T1,S2			;SAVE

; DEVICE CODE
ULDDEV:	PUSHJ	P,P$NUM##		;GET A DEVICE CODE
	JUMPF	ULDOPE			;OPR CMD ERROR
	CAIL	S1,000			;RANGE
	CAILE	S1,776			; CHECK
	JRST	ULDDCE			;ILLEGAL DEVICE CODE
	TRNE	S1,3			;ONE MORE
	JRST	ULDDCE			;ILLEGAL DEVICE CODE
	HRLZ	T2,S1			;SAVE
	PUSHJ	P,P$NUM##		;ELSE GET A UNIT NUMBER
	JUMPF	ULDOPE			;OPR CMD ERROR
	CAIL	S1,0			;RANGE
	CAILE	S1,7			; CHECK
	JRST	ULDUNE			;ILLEGAL UNIT NUMBER
	LSH	S1,3			;POSITION
	HRR	T2,S1			;SAVE
	JRST	ULDXIT			;DONE
; KONTROLLER NAME
ULDKON:	HRLZ	S2,S1			;COPY KEYWORD INDEX
	MOVEM	S2,DCHARG		;INCASE IT'S A DISK KONT
	MOVE	S2,[.DCMAX,,DCHARG]	;SET UP UUO AC
	DSKCHR	S2,			;A DISK?
	  JRST	ULDKO1			;NO--TRY FOR A NON-DISK KONT
	MOVE	S2,DCHARG+.DCUPN	;GET UNIT NAME
	LOAD	TF,DCHARG+.DCXCH,DC.XCA	;GET CPU MASK
	JRST	ULDKO2			;ONWARD
ULDKO1:	HRLZ	S2,S1			;COPY KEYWORD INDEX
	DEVNAM	S2,			;A NON-DISK KONTROLLER?
	  JRST	ULDCIP			;CHECK CI PORT
	MOVE	TF,[.RCCPU,,S1]		;SET UP UUO AC
	MOVEI	S1,2			;TWO WORD ARG BLOCK
	RECON.	TF,			;GET CPU MASK
	  JRST	ULDNCP			;CAN'T GET CPU NUMBER
ULDKO2:	JFFO	TF,.+1			;FIND FIRST BIT
	MOVEI	T1,43			;OFFSET FROM CPU0
	SUB	T1,S1			;GET CPU NUMBER
	MOVE	T2,[-2,,S1]		;SET UP UUO AC
	MOVEI	S1,.DIAKU		;FUNCTION CODE
	DIAG.	T2,			;TRANSLATE KONT NAME INTO DIAG ARGS
	  JRST	ULDNDC			;CAN'T GET DEVICE CODE
	JRST	ULDXIT			;DONE

; CI20 PORT
ULDCIP:	MOVEI	S2,-.ARCI##(S1)		;GET POSSIBLE CI PORT INDEX
	CAIL	S2,0			;RANGE
	CAILE	S2,5			; CHECK
	JRST	ULDNIP			;CHECK NI PORT
	MOVE	T1,S2			;PUT CPU NUMBER IN LH
	MOVSI	T2,574			;DEVICE CODE
	JRST	ULDXIT			;DONE

; NIA20 PORT
ULDNIP:	MOVEI	S2,-.ARNI##(S1)		;GET POSSIBLE NI PORT INDEX
	CAIL	S2,0			;RANGE
	CAILE	S2,5			; CHECK
	JRST	ULDDCE			;SAY CAN'T DETERMINE DEVICE CODE
	MOVE	T1,S2			;PUT CPU NUMBER IN LH
	MOVSI	T2,564			;DEVICE CODE
;	JRST	ULDXIT			;DONE
; EXIT
ULDXIT:	HLRZ	S1,T2			;GET DEVICE CODE
	LDB	S2,[POINT 3,T2,32]	;GET UNIT NUMBER
	$TEXT	(<-1,,ULDTXT>,<^I/ULDITX/^0>) ;GENERATE ACK TEXT
	HRLZS	T1			;POSITION CPU NUMBER
	MOVE	S1,T2			;COPY DEVICE,,UNIT
	TRZ	S1,7			;CLEAR SLAVE NUMBER
	TRZ	T2,70			;CLEAR UNIT NUMBER
	LSH	S1,3			;POSITION UNIT FIELD
	IOR	T2,S1			;MERGE CORRECT UNIT/SLAVE
	LSH	S1,6			;POSITION DEVICE CODE
	HLL	T2,S1			;REPLACE
	$RETT				;RETURN

ULDITX:	ITEXT	(<CPU^O/T1/, device ^O3/S1/, unit ^O/S2/>)
ULDOPE:	MOVEI	S2,[ASCIZ /Operator command parsing error/]
	JRST	ULDERR
ULDDCE:	MOVEI	S2,[ASCIZ /Illegal device code/]
	JRST	ULDERR
ULDUNE:	MOVEI	S2,[ASCIZ /Illegal unit number/]
	JRST	ULDERR
ULDNDC:	MOVEI	S2,[ASCIZ /Cannot determine device code for controller/]
	JRST	ULDERR
ULDNCP:	MOVEI	S2,[ASCIZ /Cannot determine CPU number for controller/]
;	JRST	ULDERR
ULDERR:	$TEXT	(WTORTN,<^T/(S2)/>)
	$RETF
	SUBTTL	The "SUSPEND" Command

C$SUSP:	$IACK	(SUSPEND)
	$CALL	P$TEXT			;Get the text string
	SKIPF				;Failed?
	 SKIPN	1(S1)			;String null?
	  JRST	REAS.1			;No reason given is an error
	MOVEM	S1,RSNADR		;Store its address
	MOVEI	S1,[ASCIZ /SEND ALL Expect an interruption of service/]
	PUSHJ	P,SNDALL		;OUTPUT THE MESSAGE
	MOVEI	S1,^D5			;GIVE IT TIME TO TYPE OUT
	SLEEP	S1,			;WAIT

	MOVE	S1,[.RCROM,,T1]		;SET TO RUN ONLY ME NOW
	MOVEI	T1,2			;2 WORD ARGUMENT BLOCK
	MOVE	T2,G$MJOB##		;ONLY ME
	RECON.	S1,			;DO IT
	  JRST	RCNERR
	MOVSI	S1,.RCIOW		;Get wait for I/O to finish function
	RECON.	S1,			;Wait
	  PUSHJ	P,RCNERR		;REPORT RECON. UUO ERROR
	MOVSI	T1,-6			;NUMBER OF CPUS
	.CREF	CS.DWN			;BIT WE'RE TESTING
SUSP.1:	SKIPL	T2,CPUSTS(T1)		;IS THE CPU DOWN
	TLNE	T2,(CS.BOT)		;OR THE BOOT CPU
	JRST	SUSP.2			;IGNORE THIS ONE
	MOVEI	T2,ST.USU(T1)		;GET CPU NUMBER AND FLAG = SUSPEND THYSELF
	HRLI	T2,.STCDN		;SET "DOWN" CPU FUNCTION
	SETUUO	T2,			;MAKE IT GO AWAY
	  $TEXT	(WTORTN,<%Can't suspend CPU^D/T1,RHMASK/>)
SUSP.2:	AOBJN	T1,SUSP.1		;DO ALL CPUS THAT WILL REMAIN AFTER SUSPEND
	MOVSI	S1,.RCIOW		;Get wait for I/O to finish function
	RECON.	S1,			;Wait
	  PUSHJ	P,RCNERR		;REPORT RECON. UUO ERROR
	MOVSI	S1,.RCSPN		;FUNCTION SUSPEND
	MOVE	0,RSNADR		;Get the address of the reason
	ADDI	0,1			; so it can be found in the dump
	RECON.	S1,			;Do the suspend
	  TRNA				;Failed? Get everything back
	JRST	SUSP.4			;Monitor already welcomed users
	PUSHJ	P,RCNERR		;REPORT RECON. UUO ERROR
	MOVEI	S1,[ASCIZ /SEND ALL System resumed/]
	PUSHJ	P,SNDALL		;TELL WORLD THE SYSTEM IS BACK
SUSP.4:	MOVE	S1,[.RCROM,,T1]		;SET TO RUN ONLY 1 JOB
	MOVEI	T1,2			;2 WORD ARGUMENT BLOCK
	SETZ	T2,			;JOB NUMBER 0 = ALLOW ALL USERS
	RECON.	S1,			;DO THE UUO
	  JRST	AUTO.E			;Something really wrong here
	$RETT
	SUBTTL	The "SNAPSHOT" and "SHUTDOWN" commands


C$SNAP:	$IACK	(SNAPSHOT)
	MOVSI	T1,.RCCI7		;WANT A CI7 CONTINUABLE STOPCD
	JRST	REASON			;ASK FOR REASON, DO COMMAND


C$SHUT:	$IACK	(SHUTDOWN)
	MOVSI	T1,.RCRLD		;WANT TO RELOAD THE MONITOR
	JRST	REASON			;ASK FOR REASON, DO COMMAND


REASON:	$CALL	P$TEXT##		;Get the reason
	 JUMPF	REAS.1			;Need a reason
	MOVEI	0,1(S1)			;POINT TO IT WITH AC 0 FOR THE DUMP
	SKIPN	@0			;Null reason illegal also
	 JRST	REAS.1
	MOVE	S1,T1			;Get function to perform (for RCNERR)
	RECON.	S1,			;DO THE FUNCTION
	 JRST	RCNERR			;GIVE ERROR
	$RETT				;RETURN

REAS.1:	$TEXT	(WTORTN,<A reason must be specified>)
	$RET
	SUBTTL	The "AUTOCONFIGURE" command


C$AUTO:	$SAVE	<P1>			;SAVE P1
	PUSHJ	P,P$KEYW##		;TRY FOR A KEYWORD
	JUMPF	AUTO.A			;NO GOOD
	SUBI	S1,.ARCPU##		;OFFSET
	CAIL	S1,0			;RANGE
	CAILE	S1,6			; CHECK
	$RETF				;BAD CPU NUMBER
	CAIN	S1,6			;ALL CPUS?
AUTO.A:	MOVNI	S1,1			;YES--SET TO -1
	MOVE	P1,S1			;PRESERVE CPU ARGUMENT
	PUSHJ	P,P$CFM##		;TIME FOR A CRLF
	$RETIF				;JUNK INPUT
	$IACK	(AUTOCONFIGURE)
	TXZ	F,FL.ADD		;SET TO SEIZE MAGTAPE CONTROLLERS
	PUSHJ	P,SEZMTK		;DO IT
	 JUMPF	RCNERR			;Not supported
	MOVE	S1,[.RCROM,,T1]		;SET TO RUN ONLY ME NOW
	MOVEI	T1,2			;2 WORD ARGUMENT BLOCK
	MOVE	T2,G$MJOB##		;ONLY ME
	RECON.	S1,			;DO IT
	  JRST AUTO.M			;PROBABLY NOT PRIVLEGED
	MOVSI	S1,.RCIOW		;Get wait for I/O to finish function
	RECON.	S1,			;Wait
	  PUSHJ	P,RCNERR		;REPORT RECON. UUO ERROR
	MOVE	S1,[.RCRAC,,T1]		;AUTOCONFIGURE
	MOVEI	T1,2			;ARGUMENT LIST IS 2 WORDS LONG
	MOVE	T2,P1			;GET CPU ARGUMENT
	RECON.	S1,			;DO IT
	  TRNA
	JRST	AUTO.1			;Done, continue onward
	PUSHJ	P,RCNERR		;PRINT RECON. UUO ERROR MESSAGE
	MOVE	S1,[.RCROM,,T1]		;SET TO TURN TIMESHARING BACK ON
	MOVEI	T1,2			;2 WORD ARGUMENT LIST
	SETZ	T2,			;ALLOW USERS AGAIN
	RECON.	S1,			;DO IT
	  JRST	AUTO.E			;System very sick
AUTO.M:	TXO	F,FL.ADD		;ALSO FREE UP MAGTAPES
	PUSHJ	P,SEZMTK		;RELEASE MTA KONTROLLERS
	$RETT				;FINISH THE LINE AND EXIT
AUTO.1:	MOVE	S1,[.RCROM,,T1]		;SET TO RUN ALL JOBS
	MOVEI	T1,2			;2 WORD ARGUMENT BLOCK
	SETZ	T2,			;JOB NUMBER 0 = ALLOW ALL USERS
	RECON.	S1,			;DO THE UUO
	  JRST	AUTO.E			;Nasty trouble
	TXO	F,FL.ADD!FL.WAC		;WANT TO ADD CONTROLLERS
	PUSHJ	P,SEZMTK		;FREE UP MAGTAPE KONTROLLERS
	MOVSI	P1,-6			;NUMBER OF CPUS
	.CREF	CS.DWN			;BIT WE'RE TESTING
AUTO.2:	SKIPGE	CPUSTS(P1)		;CPU UP?
	JRST	AUTO.3			;NO, DON'T WORRY ABOUT IT
	SETZ	S1,			;ALL CONTROLLERS
	MOVE	S2,CPUBIT(P1)		;BIT FOR CPU BEING ADDED
	PUSHJ	P,RADKON		;ADD ALL DISK CONTROLLERS
AUTO.3:	AOBJN	P1,AUTO.2		;DO IT FOR ALL CPUS
	$RETT				;ALL DONE, SO JUST EXIT

;Here when we try to set system to run all and fail. The system is
;totally useless, and we might as well just reload.

AUTO.E:	$TEXT	(CTYTYP,<^G^G?Error trying to set all users to run>)
	$TEXT	(CTYTYP,<Error code from RECON. UUO is ^O/S1/>)
	$TEXT	(CTYTYP,<System shutting down with RLD stopcode>)
	MOVEI	0,[ASCIZ |ORION CONFIG error trying to set all users to run|]
	MOVSI	S1,.RCRLD		;Get the reload function
	RECON.	S1,			;Reload the system please
	  TRNA				;Now we really can't do much more
	$RETT				;Just for consistency's sake
	$TEXT	(CTYTYP,<^G^G?Error attempting reload function>)
	$TEXT	(CTYTYP,<Error code from RECON. UUO is ^O/S1/>)
	$TEXT	(CTYTYP,<Please reload system manually - ORION halting>)
	STOPCD	(ESS,HALT,,<Error shutting down system>)
;SUBROUTINE TO SEIZE OR RELEASE MAGTAPE CONTROLLERS
; RETURNS TRUE NORMALLY, FALSE IF NOT-IMPLEMENTED OR ALREADY SEIZED

SEZMTK:	$SAVE	<P1,P2>			;Get some save acs
	MOVE	S1,[-2,,P1]		;DIAG. ARGUMENT LIST
	MOVEI	P1,.DIARM		;ASSUME RELEASING MAGTAPE KONTROLLERS
	TXNN	F,FL.ADD		;ACTUALLY SEIZING KONTROLLERS?
	MOVEI	P1,.DIASM		;YES, SET TO SEIZE KONTROLLER
	MOVEI	P2,0			;ALL KONTROLLERS
	DIAG.	S1,			;DO IT
	  JRST	DIAERR			;REPORT ERROR
	$RETT
	SUBTTL	The "SET" command

C$SET:	$CALL	P$KEYW##		;Get the set keyword
	 $RETIF
	MOVEI	S2,SETDSP		;Get the address of the table
	$CALL	TABSRC##		;FIND ARGUMENT
	 $RETIF
	JRST	(S2)			;DISPATCH TO PROCESS ARGUMENT

;"NO"

SETNOT:	TXO	F,FL.NO			;Set no flag
	$CALL	P$KEYW##		;Get the next keyword
	 $RETIF
	MOVEI	S2,STNDSP		;GEt the address of the table to search
	$CALL	TABSRC##		;Fidn it
	 $RETIF
	JRST	(S2)			;Call the routine

;"MICROCODE (loading)"

SETULD:	$IACK	(SET MICROCODE)
	PUSHJ	P,ULDARG		;GET DIAG ARGUMENTS
	$RETIF				;CHECK FOR ERRORS
	MOVEI	S2,[ASCIZ /enabled/]	;ASSUME ENABLE
	TXNE	F,FL.NO			;NO?
	MOVEI	S2,[ASCIZ /disabled/]	;DISABLE
	HRRI	T1,.DIELD		;ASSUME ENABLE
	TXNE	F,FL.NO			;NO?
	HRRI	T1,.DIDLD		;DISABLE
	MOVE	S1,[-2,,T1]		;SET UP UUO AC
	DIAG.	S1,			;LOAD MICROCODE
	  JRST	ULDX.E			;FAILED
	$TEXT	(WTORTN,<Microcode loading is ^T/(S2)/ on ^T/ULDTXT/>)
	$RETT
ULDX.E:	$TEXT	(WTORTN,<Set microcode loading ^T/(S2)/ failed; ^A>)
	PJRST	DIAERR			;REPORT DIAG ERROR AND RETURN

;"RELOAD"

SETAUT:	$IACK	(SET AUTO-RELOAD)
	MOVE	S1,[.RCNAR,,T1]		;GET FUNCTION CODE,,ADDRESS
	MOVEI	T1,2			;LENGTH OF BLOCK IS 2
	MOVE	T2,F			;GET FLAG WORD
	ANDX	T2,<FL.NO>		;Set no if no bit on
	RECON.	S1,			;DO FUNCTION
	  JRST	RCNERR			;FAILED, TELL WHY
	MOVEI	S1,[ASCIZ |enabled|]	;Assume he's enabling
	TXNE	F,FL.NO			;Is he really disabling
	 MOVEI	S1,[ASCIZ |disabled|]	;Yes, get the real message
	$TEXT	(WTORTN,<Automatic system reload is ^T/(S1)/>)
	$RETT
;"BOOTXT"

SETBOT:	$CALL	P$TEXT##		;Get the boot text
	 $RETIF
	DMOVE	T1,S1			;Save the temporary ACs
	$IACK	(SET BOOTXT)
	DMOVE	S1,T1			;Restore the temporaries
	CAIG	S2,.TXTSZ		;Less than eighty characters?
	 JRST	SBOT.1			;Yes, onward
	$TEXT	(WTORTN,<Maximum of ^D/[.TXTSZ]/ characters allowed for boot message>)
	$RETF
SBOT.1:	MOVEI	T3,1(S1)		;Get the address of the text
	HRLI	T3,(POINT 7,)		;Build a byte pointer
	MOVE	T4,[POINT 7,RSNTXT]	;And get the destination pointer
	SETZ	T2,			;Zero character counter
SBOT.2:	ILDB	T1,T3			;Get a character
	JUMPE	T1,SBOT.3		;If the end, go finish things up
	IDPB	T1,T4			;Store into the arg block
	AOJA	T2,SBOT.2		;Count the character and loop
SBOT.3:	SETZ	T1,
	IDPB	T1,T4
	MOVEI	S1,1(T2)		;INCLUDE NULL IN COUNT, MOVE TO P1
	IDIVI	S1,5			;COMPUTE WORD COUNT
	SKIPE	S2			;Any chars left over?
	 ADDI	S1,1			;Yes, account for them also
	ADDI	S1,1			;INCLUDE THE WORD COUNT WORD
	MOVEM	S1,RCNARG		;STORE WORD COUNT
	MOVE	S1,[.RCBTX,,RCNARG]	;POINT TO BLOCK
	RECON.	S1,			;REPLACE THE BOOTXT STRING
	  JRST	RCNERR			;FAILED, TELL WHY
	MOVEI	S1,RSNTXT		;Get address of string
	SKIPN	T2			;Null string?
	 MOVEI	S1,[ASCIZ |[Null]|]	;Otherwise get null indicator
	$TEXT	(WTORTN,<Boot-text setting accepted.  New boot string is:>)
	$TEXT	(WTORTN,<	^T/(S1)/>)
	$RETT
;"DUMP" OR "RELOAD"

SETDMP:	TDZA	S1,S1			;NOTE "DUMP" ENTRY AND SKIP
SETRLD:	MOVEI	S1,1			;NOTE "RELOAD" ENTRY
	$SAVE	<P1,P2>			;SAVE AN AC OR TWO
	MOVE	P1,S1			;SAVE ENTRY FLAG IN P1
	SETZ	P2,			;START WITH NOTHING
SDMP.1:	$CALL	P$KEYW##		;GET NEXT KEYWORD
	 $RETIF
	MOVEI	S2,DMPTAB		;ASSUME DUMP
	SKIPE	P1			;GOOD GUESS?
	MOVEI	S2,RLDTAB		;NO
	$CALL	TABSRC##		;TRANSLATE THE KEYWORD
	 $RETIF				;SHOULDN'T HAPPEN
	IOR	P2,(S2)			;ADD IN THE BIT
	$CALL	P$COMMA##		;SEE IF COMMA
	JUMPT	SDMP.1			;IF SO, KEEP LOOKING
	$CALL	P$CFM##			;SEE IF CONFIRM
	 $RETIF

	$IACK	(SET ^T/@DMPRLD(P1)/)
	JUMPN	P1,SRLD.1		;JUMP IF SET [NO] RELOAD
	MOVSI	S1,.RCSDF		;ASSUME SET
	TXNN	F,FL.NO			;DID THEY SAY NO?
	MOVSI	S1,.RCCDF		;NO, THAT MEANS CLEAR THE BITS
	JRST	SDMP.2			;JOIN COMMON CODE

SRLD.1:	MOVSI	S1,.RCSDF		;ASSUME SET
	TXNE	F,FL.NO			;DID THEY SAY NO?
	MOVSI	S1,.RCCDF		;YES, THAT MEANS CLEAR THE BITS
SDMP.2:	HRRI	S1,T1			;ADDRESS OF ARGUMENT LIST
	MOVEI	T1,2			;NUMBER OF WORDS
	MOVE	T2,P2			;COPY FLAGS HERE
	RECON.	S1,			;DO IT
	  JRST	RCNERR			;ERROR
	PJRST	SHST.1			;FINISH UP VIA SHOW STOPCODE-FLAGS

DMPRLD:	[ASCIZ	/DUMP/]
	[ASCIZ	/RELOAD/]

DMPTAB:	$STAB
	.STCPN##,,[ST%DCP]
	.STDBG##,,[ST%DDC]
	.STJOB##,,[ST%DJE]
	$ETAB

RLDTAB:	$STAB
	.STCPN##,,[ST%CP1]
	.STDBG##,,[ST%RDC]
	.STJOB##,,[ST%RJE]
	$ETAB
;"POLICY-CPU"

SETPLC:	$CALL	P$KEYW##		;Get next keyword (CPU name)
	 $RETIF				;If error
	SUBI	S1,.ARCPU##		;Translate to CPU number
	CAIL	S1,0			;Range
	CAILE	S1,5			; Check
	$RETF				;Loser
	$SAVE	<P1>			;Make room for the CPU number
	MOVE	P1,S1			;Save it
	$IACK	(SET POLICY-CPU)
	MOVE	S1,CPUSTS(P1)		;Get status
	TXNE	S1,CS.NEX		;Non-existant?
	JRST	SETPE1			;Yep
	TXNE	S1,CS.DWN!CS.DET!CS.NOK	;Down or detached?
	JRST	SETPE2			;Yep
	MOVE	S1,P1			;Get CPU number again
	HRLI	S1,.STPCP		;SETUUO function code
	SETUUO	S1,			;Swap policy CPU
	  JRST	SETPE3			;Error
	$TEXT	(WTORTN,<^W/CPUNAM(P1)/ is the new policy CPU>)
	$RETT				;Return happy

SETPE1:	SKIPA	S1,[[ITEXT (<^W/CPUNAM(P1)/ does not exist>)]] ;(SNH)
SETPE2:	MOVEI	S1,[ITEXT (<^W/CPUNAM(P1)/ is not running>)]
	JRST	SETPEC			;Error
SETPE3:	CAXN	S1,STNAR%		;Not running?
	MOVEI	S2,[ITEXT (<^W/CPUNAM(P1)/ is not running>)]
	CAXN	S1,STDHP%		;Not privileged?
	MOVEI	S2,[ITEXT (not privileged)]
	TLNE	S1,-1			;AC unchanged?
	MOVEI	S2,[ITEXT (function not implemented)]
	MOVEI	S1,[ITEXT (<SETUUO failure (^I/0(S2)/)>)]
SETPEC:	$TEXT	(WTORTN,<Can't set policy CPU - ^I/0(S1)/>)
	$RETF				;We tried
	SUBTTL	The "SHOW STOPCODE-FLAGS" command

SHWSTP:	$SAVE	<P1>			;SAVE AN AC
	$IACK	(SHOW STOPCODE-FLAGS)
	MOVX	S1,%CNDBG		;DEBUG FLAGS WORD
	GETTAB	S1,			;ASK THE MONITOR
	  SETZ	S1,			;DUH?
SHST.1:	MOVE	P1,S1			;COPY FLAGS WORD TO A SAFE AC
	$TEXT	(WTORTN,<System will ^A>) ;START TEXT
	TXC	P1,ST%DCP!ST%DDC!ST%DJE	;FLIP THE BITS
	TXNN	P1,ST%DCP!ST%DDC!ST%DJE	;ALL BITS ON? (LEAVE FLIPPED)
	JRST	[$TEXT	(WTORTN,<not do continuable stopcode dumps>)
		 JRST	SHST.R]		;SEE ABOUT RELOADS
	$TEXT	(WTORTN,<do continuable dumps on ^A>) ;MORE NOISE
	MOVEI	S1,DMPBTS		;POINT AT TABLE
	PUSHJ	P,PRTBIT		;PRINT PRETTY BITS
	$TEXT	(WTORTN,< stopcodes>)	;ADD CRLF
SHST.R:	$TEXT	(WTORTN,<System will reload on ^A>) ;START TEXT
	TXO	P1,ST%NAR		;SET THE "STOP" BIT FOR PRTBIT
	MOVEI	S1,RLDBTS		;POINT AT TABLE
	PUSHJ	P,PRTBIT		;PRINT PRETTY BITS
	$TEXT	(WTORTN,< stopcodes>)	;ADD CRLF
	$RETT

DMPBTS:	$STAB
	[ST%DCP],,[ASCIZ /CPU/]
	[ST%DDC],,[ASCIZ /DEBUG/]
	[ST%DJE],,[ASCIZ /JOB/]
	$ETAB

RLDBTS:	$STAB
	[ST%CP1],,[ASCIZ /CPU/]
	[ST%RDC],,[ASCIZ /DEBUG/]
	[ST%RJE],,[ASCIZ /JOB/]
	[ST%NAR],,[ASCIZ /STOP/]	;FAKE TO INCLUDE THIS
	$ETAB
;ROUTINE TO HELP SHOW STOPCODE-FLAGS COMMAND PRINT PRETTY TEXT.
;COULD BE MADE MORE GENERAL IF THE NEED ARISES.  CALL WITH THE
;CONTROL TABLE ADDRESS IN S1, AND THE BITS TO TEST IN P1.  THIS
;ROUTINE WILL ADD COMMAS AND/OR "and" AS APPROPRIATE.

PRTBIT:	$SAVE	<P2,P3>			;SAVE AN AC OR TWO
	MOVE	P2,S1			;COPY TABLE ADDRESS
	HLLZ	S1,(P2)			;GET LENGTH OF TABLE
	MOVNS	S1			;MAKE IT -VE
	HRRI	S1,1(P2)		;POINT AT REAL ENTRIES
	MOVE	P2,S1			;BACK WHERE ITS SAFE

;FIRST COUNT HOW MANY BITS ARE SET

	SETZ	P3,			;INIT COUNT OF BITS TO ZERO
	MOVE	T1,P2			;COPY THE AOBJN POINTER
PBIT.1:	HLRZ	S1,(T1)			;GET A BIT ADDRESS
	TDNE	P1,(S1)			;BIT SET?
	AOS	P3			;YES, COUNT IT
	AOBJN	T1,PBIT.1		;LOOP

;NOW PRINT THE TEXT FOR EACH BIT WITH PROPER PUNCTUATION.

	PUSH	P,[0]			;INIT A FLAG
	CAIL	P3,3			;3 OR MORE ITEMS?
	SETOM	(P)			;YES, REMEMBER THAT
PBIT.2:	HLRZ	S1,(P2)			;GET A BIT ADDRESS
	TDNN	P1,(S1)			;BIT SET?
	JRST	PBIT.4			;NO
	HRRZ	S1,(P2)			;GET TEXT ADDRESS
	$TEXT	(WTORTN,<^T/0(S1)/^A>)	;ADD NAME
	SUBI	P3,1			;ONE LESS ITEM LEFT
	SKIPN	(P)			;NEED ANY COMMAS?
	JRST	PBIT.3			;NO
	SKIPE	P3			;ANY MORE ITEMS?
	$TEXT	(WTORTN,<,^A>)		;YES, PRINT ","
	CAILE	P3,1			;MORE THAN ONE ITEM LEFT?
	$TEXT	(WTORTN,< ^A>)		;YES, PRINT " "
PBIT.3:	CAIN	P3,1			;ONE MORE ITEM LEFT?
	$TEXT	(WTORTN,< and ^A>)	;YES, NEED THE "and" NOW
PBIT.4:	AOBJN	P2,PBIT.2		;DO ALL BITS
	POP	P,(P)			;TOSS JUNK
	$RETT				;RETURN
	SUBTTL	The "SHOW BOOT-TEXT" command

SHWBTX:	$SAVE	<P1>			;SAVE AN AC
	$IACK	(SHOW BOOT-TEXT)
	MOVE	S1,[.GTBTX,,.GTSLF]	;ASK FOR GETTAB INFO
	GETTAB	S1,
	  SETZ	S1,
	LOAD	S1,S1,SL.MAX		;GET MAXIMUM TABLE ITEM
	JUMPN	S1,SHWB.1		;GO IF TABLE IN MONITOR
	$TEXT	(WTORTN,<? GETTAB for BOOT-TEXT doesn't exist in this monitor>)
	$RETF				;SORRY

SHWB.1:	MOVNI	P1,1(S1)		;CORRECT FOR NUMBER OF ITEMS
	HRLZS	P1			;MAKE AN AOBJN POINTER
SHWB.2:	MOVS	S1,P1			;GET TABLE INDEX
	HRRI	S1,.GTBTX		;TABLE NUMBER
	GETTAB	S1,			;ASK
	  SETZ	S1,
	MOVEM	S1,BTXBLK(P1)		;SAVE IT
	AOBJN	P1,SHWB.2		;LOOP FOR ALL
	MOVEI	S1,BTXBLK		;POINT AT BLOCK
	SKIPN	BTXBLK			;UNLESS NULL,
	MOVEI	S1,[ASCIZ /[Null]/]	; IN WHICH CASE, SAY SO
	$TEXT	(WTORTN,<Boot string is:>)
	$TEXT	(WTORTN,<	^T/(S1)/>)
	$RETT				;ALL DONE
	SUBTTL	The "SHOW HARDWARE-CONFIGURATION" command

SHWHDW:	SETZ	F,			;CLEAR FLAGS AC
	$CALL	P$CFM			;SEE WHAT'S COMING
	JUMPT	SHWH.9			;JUST <CR> IMPLIES ALL
SHWH.1:	$CALL	P$SWIT			;GRAB A SWITCH
	$RETIF				;ERROR
	MOVEI	S2,HDWSWI		;POINT AT TABLE
	PUSHJ	P,TABSRC##		;FIND A MATCH
	$RETIF				;ERROR
	TDO	F,S2			;SET THE BIT
	$CALL	P$CFM			;SEE IF DONE
	JUMPF	SHWH.1			;IF NOT, KEEP LOOKING
	SKIPA	S1,F			;COPY FLAGS AND SKIP
SHWH.9:	SETO	S1,			;SHOW ALL IF JUST <CR>
	$IACK	(SHOW HARDWARE-CONFIGURATION)
	PUSHJ	P,CNFHDW##		;CALL THE ROUTINE
	$RETT				;ALL DONE

HDWSWI:	$STAB
	.SWHCF,,HW.CFE
	.SWHCI,,HW.CI
	.SWHCP,,HW.CPU
	.SWHDI,,HW.DSK
	.SWHMM,,HW.MME
	.SWHTA,,HW.TAP
	.SWHUR,,HW.URC
	$ETAB
	SUBTTL	KLINIK routines


	;The SHOW KLINIK command

	BYTMSK==377

KLISHW:	$SAVE	<P1,P2>			;Preserve AC
	MOVE	S1,[Z.KLIB,,Z.KLIB+1]	;Set up BLT
	SETZM	Z.KLIB			;Clear first word
	BLT	S1,Z.KLIE-1		;Clear KLINIK data storage
	PUSHJ	P,P$CFM##		;Confirm this
	$RETIF
	$IACK	(KLINIK Status)
	MOVSI	P1,-6			;For all CPUs
	SETO	P2,			;Flag for first time
KLIS.1:	MOVSI	S1,(CS.DWN!CS.NEX!CS.DET) ;Down, non-ex, or DET?
	TDNE	S1,CPUSTS(P1)		;??
	 JRST	KLIS.X			;Yes, don't even try
	AOSE	P2			;First time?
	$TEXT	(WTORTN,<>)		;No, add a blank line
	HRLOM	P1,T1			;CPU,,Master DTE
	MOVE	T2,[XWD ^D16,KLIDTD]	;Point to string block
	MOVE	S1,[XWD .DTKPR,T1]	;Read parameters
	MOVE	S2,S1			;Save original C(AC)
	DTE.	S1,			;Read current setting
	 JRST	[PUSHJ	P,KLIDTE	;Report error
		  HALT	.		;Always skips
		 JRST	KLIS.X]		;Go try next CPU
	$TEXT	(WTORTN,<	-- CPU^O1/T1,LHMASK/ KLINIK Status -->)
	MOVEI	T4,KLIDTD		;Point to returned data
	HRLI	T4,(POINT 16,,)		;Thus
	ILDB	T1,T4			;Get byte count
	LDB	T3,[POINT 16,KLIDTD+3,32];Console,,KLINIK
	TRNE	T3,BYTMSK		;Open?
	 JRST	KLS.OW			;Yes
	$TEXT	(WTORTN,<Access window closed>)
	JRST	KLIS.X			;Output string
KLS.OW:	$TEXT	(WTORTN,<Access window open
Window opened on ^A>)
	PUSHJ	P,KLS.DT		;Type date
	$TEXT	(WTORTN,<^M^JWindow closes on ^A>)
	PUSHJ	P,KLS.DT		;Type date
	$TEXT	(WTORTN,<^M^JKLINIK mode: ^A>)
	ILDB	T1,T4			;Fetch CSL,,KLINIK
	MOVE	T3,T1			;Save CSL
	ANDI	T1,BYTMSK		;Get KLINIK
	CAIN	T1,BYTMSK		;USER mode?
	 JRST	[$TEXT	(WTORTN,<USER>)
		 JRST	KLIS.X]		;Yes, done
	MOVE	T1,T3			;Get CSL mode
	LSH	T1,-8			;only CSL mode
	IDIVI	T1,3			;Xlate (1,3,7) to (0,1,2)
	$TEXT	(WTORTN,<REMOTE	Console mode: ^T/@MODTAB(T1)/>)
KLIS.X:	AOBJN	P1,KLIS.1		;Next
	$RETT

MODTAB:	[ASCIZ .OPERATOR.]
	[ASCIZ .PROGRAMMER.]
	[ASCIZ .MAINTENANCE.]
KLS.DT:	ILDB	T1,T4			;Fetch the time(sec/2)
	PUSH	P,T1			;Save time
	ILDB	T1,T4			;Get mon,,yr
	ILDB	T2,T4			;Get 0,,day
	MOVE	T3,T1			;Month,,yr
	LSH	T3,-8			;Month
	CAILE	T3,^D12			;Better be legal
	 SETZ	T3,			;Glad we checked
	$TEXT	(WTORTN,<^D2R0/T2,BYTMSK/^T/MONTAB(T3)/-^D2R0/T1,BYTMSK/ at ^A>)
	POP	P,T1			;Restore time
	LSH	T1,1			;Make seconds
	IDIVI	T1,^D60			;Min:sec
	MOVE	T3,T2			;Sec
	IDIVI	T1,^D60			;Hr:min
	$TEXT	(WTORTN,<^D2R0/T1/:^D2R0/T2/:^D2R0/T3/^A>)
	POPJ	P,

MONTAB:	0
	ASCIZ .-Jan.
	ASCIZ .-Feb.
	ASCIZ .-Mar.
	ASCIZ .-Apr.
	ASCIZ .-May.
	ASCIZ .-Jun.
	ASCIZ .-Jul.
	ASCIZ .-Aug.
	ASCIZ .-Sep.
	ASCIZ .-Oct.
	ASCIZ .-Nov.
	ASCIZ .-Dec.
;The SET KLINIK Command

KLINIK:	$SAVE	<P1>			;Save P1
	MOVE	S1,[Z.KLIB,,Z.KLIB+1]	;Set up BLT
	SETZM	Z.KLIB			;Clear first word
	BLT	S1,Z.KLIE-1		;Clear KLINIK data storage
	PUSHJ	P,P$CFM##		;Try for a CRLF
	JUMPT	KLIN.1			;Go default to "ALL-CPUS"
	PUSHJ	P,P$KEYW##		;Get a keyword instead
	$RETIF				;Give up
	SUBI	S1,.ARCPU##		;Translate to CPU number
	CAIL	S1,0			;Range
	CAILE	S1,6			; Check
	$RETF				;Loser
	CAIN	S1,6			;"ALL-CPUS"?
	MOVEI	S1,7			;Yes
	HRLOM	S1,KLICPU		;Save CPU number (DTE=MASTER)
	PUSHJ	P,P$CFM##		;Must have a CRLF now
	$RETIF				;We don't
	JRST	KLIN.2			;Onward
KLIN.1:	MOVEI	S1,7			;All CPUs
	HRLOM	S1,KLICPU		;Save CPU number (DTE=MASTER)
KLIN.2:	PUSHJ	P,P$KEYW##		;Pick up a keyword
	$RETIF				;Need one of these too
	MOVNI	P1,1			;Init temp storage
	CAIN	S1,.KLOFF##		;Off?
	MOVEI	P1,0			;Yes
	CAIN	S1,.KLREM##		;Remote?
	MOVEI	P1,1			;Yes
	CAIN	S1,.KLUSR##		;User?
	MOVEI	P1,377			;Yes
	JUMPL	P1,.RETF		;Give up if we're fed junk
	DPB	P1,[POINT 8,KLIDTD+3,31];Save KLINIK mode
	PUSHJ	P,P$CFM##		;Want a CRLF
	$RETIF				;Didn't get one
	JUMPE	P1,KLIN.4		;If SET KLINIK OFF, go do it now
	CAIE	P1,1			;Remote?
	JRST	KLIN.3			;No
	PUSHJ	P,P$SIXF##		;Get a sixbit quantity
	$RETIF				;No such animal
	SETZ	T1,			;Keep track of where we are
	MOVE	S2,S1			;Grab password
KLI.2A:	JUMPE	S2,KLI.2B		;If end, quit
	SETZ	S1,			;Clear junk
	LSHC	S1,6			;Get next char
	ADDI	S1," "-' '		;Make UC ASCII
	DPB	S1,[POINT 8,KLIDTD+4,15
		    POINT 8,KLIDTD+4,7
		    POINT 8,KLIDTD+4,31
		    POINT 8,KLIDTD+4,23
		    POINT 8,KLIDTD+5,15
		    POINT 8,KLIDTD+5,7](T1)
	AOJA	T1,KLI.2A		;Loop for all 6 chars of password

KLI.2B:	PUSHJ	P,P$CFM##		;Time for a CRLF
	$RETIF				;OPR gave us garbage
KLIN.3:	PUSHJ	P,P$TIME##		;Get date-time
	$RETIF				;Must have one of these
	MOVE	P2,S1			;Save OPEN UDT
	MOVE	T4,[POINT 8,KLIDTD+0,15];Point to OPEN time
	PUSHJ	P,KLIN.T		;Convert and store
	PUSHJ	P,P$CFM##		;CRLF again
	$RETIF				;Trashed.
	PUSHJ	P,P$TIME##		;Get date-time
	$RETIF				;Not there
	CAMG	S1,P2			;Closing beyond opening date-time?
	$RETF				;Nope
	MOVE	T4,[POINT 8,KLIDTD+2]	;Point to CLOSE time
	PUSHJ	P,KLIN.T		;Convert and store
	PUSHJ	P,P$CFM##		;Get a CRLF
	$RETIF				;Can't
	CAIE	P1,1			;Remote?
	JRST	KLIN.4			;No
	PUSHJ	P,P$KEYW##		;Get a keyword
	$RETIF				;Must have one
	MOVNI	P1,1			;Init temp storage
	CAIN	S1,.KLMNT##		;Console mode MAINTENANCE?
	MOVEI	P1,7			;Yes
	CAIN	S1,.KLOPR##		;Console mode OPERATOR?
	MOVEI	P1,1			;Yes
	CAIN	S1,.KLPRG##		;Console mode PROGRAMMER?
	MOVEI	P1,3			;Yes
	JUMPL	P1,.RETF		;Have a known quantity?
	DPB	P1,[POINT 8,KLIDTD+3,23];Store for -20F
	PUSHJ	P,P$CFM##		;Parse a CRLF
	$RETIF
KLIN.4:	$IACK	(SET KLINIK)
	MOVE	T1,KLICPU		;CPU#,,DTE#
	MOVE	T2,[XWD 26,KLIDTD]	;String len,,addr
	MOVEI	S1,24			;Data length
	DPB	S1,[POINT 16,KLIDTD,15]	;Goes in arg block
	HLRZ	S1,T1			;CPU#
	CAIN	S1,7			;ALL?
	 JRST	KLIN.A			;YES
	MOVE	S1,[XWD	.DTKPS,T1]	;Set KLINIK
	MOVE	S2,S1			;Keep a copy in case of error
	DTE.	S1,			;AHoooom
	 PUSHJ	P,KLIDTE		;Report error
	$TEXT	(WTORTN,<CPU^O/T1,LHMASK/ SET KLINIK succeeded>)
	$RETT				;Exit

KLIN.A:	MOVSI	P1,-6			;TRY EACH CPU
KLIA.1:	MOVSI	S1,(CS.DWN!CS.NEX!CS.DET) ;Down, non-ex, or DET?
	TDNE	S1,CPUSTS(P1)		;??
	 JRST	KLIA.2			;Yes, don't even try
	HRLM	P1,T1			;Try this CPU
	MOVE	S1,[XWD .DTKPS,T1]	;UUO pointer
	MOVE	S2,S1			;Save in case of error
	DTE.	S1,			;AHoooom
	 PUSHJ	P,KLIDTE		;Report error
	$TEXT	(WTORTN,<CPU^O/T1,LHMASK/ SET KLINIK succeeded>)
KLIA.2:	AOBJN	P1,KLIA.1		;Next
	$RETT				;Done
	;DTE. UUO error handler

KLIDTE:	PUSH	P,T4			;Save AC
	HLRZ	T4,S2			;Get function that failed
	CAIN	T4,.DTKPR		;Read?
	 SKIPA	T4,[SIXBIT /SHOW/]	;Yes
	MOVE	T4,[SIXBIT /SET/]	;No, must be a SET command
	PUSH	P,T4			;Save command name for later
	MOVSI	T4,-ERRTBL		;Length of error table
	CAMN	S1,S2			;No UUO?
	 JRST	DTEERE			;If no UUO, no KLINIK
DTEERL:	MOVS	S2,ERRTAB(T4)		;Get error
	CAIE	S1,(S2)			;Match?
	AOBJN	T4,DTEERL		;No
DTEERE:	HRRZ	T4,ERRTAB(T4)		;Get ITEXT address
	POP	P,S2			;Restore command that failed
	$TEXT	(WTORTN,<CPU^O/T1,LHMASK/ ^W/S2/ KLINIK failed>)
	$TEXT	(WTORTN,<DTE. UUO  error - ^I/@T4,RHMASK/>)
	POP	P,T4
	AOS	(P)
	POPJ	P,

ERRTAB:	XWD	DTEUF%,[ITEXT <KLINIK functions not present>]
	XWD	DTEDC%,[ITEXT <CPU illegal or down>]
	XWD	DTEAP%,[ITEXT <Primary protocol not running>]
	XWD	DTENC%,[ITEXT <Inusfficient monitor free core>]
	XWD	DTEIB%,[ITEXT <CONFIG/Monitor version skew>]
ERRTBL==.-ERRTAB
	XWD	0,[ITEXT <Unexpected DTE. error (^O/S1/)>]

KLIN.T:	$CALL	S%U2DT			;Get time and date
	PUSH	P,S2			;Save date
	ADDI	S1,^D1K			;Round to nearest 2-sec clunk
	IDIVI	S1,^D2K			;And convert
	ROT	S1,-^D8			;Get high byte first
	IDPB	S1,T4			;Store
	ROT	S1,^D8			;Now low byte
	IDPB	S1,T4			;Finish time
	MOVE	S1,(P)			;Get date
	IDIVI	S1,^D31			;Get days
	AOJ	S2,			;1-31
	MOVEM	S2,(P)			;Save daze
	IDIVI	S1,^D12			;Get months
	AOJ	S2,			;1-12
	IDPB	S2,T4			;Month comes next
	ADDI	S1,^D64			;Year
	IDPB	S1,T4			;Store year
	SETZ	S1,			;Required zero
	IDPB	S1,T4			;Store that
	POP	P,S1			;Day of month
	IDPB	S1,T4			;Store that
	POPJ	P,			;Done
	SUBTTL	SHOW Command

C$SHOW:	$CALL	P$KEYW##		;Get the show keyword
	 $RETIF
	MOVEI	S2,SHODSP		;Get the address of the table
	$CALL	TABSRC##		;Find argument
	 $RETIF
	JRST	(S2)			;Dispatch to process argument
	SUBTTL	Some Random Subroutines -- DETJBS - Detach jobs lost from CPU

;SUBROUTINE TO DETACH JOBS WHOSE TERMINAL WILL BE LOST BY REMOVING A CPU
;CALL:	S1 = CPU BEING REMOVED

DETJBS:	$CALL	.SAVE4			;Get some save ACs
	TXZ	F,FL.HEA		;New heading required
	MOVE	P4,CPUBIT(S1)		;Get bit for CPU being checked
	MOVE	P1,JOBPTR		;Get AOBJN for jobs
	MOVEI	P2,2			;Get the argblock lenght for RECON.
DETJ.1:	HRRZ	P3,P1			;Get the job number to check
	TRMNO.	P3,			;Get its terminal number
	  JRST	DETJ.3			;ISN'T ANY, TRY NEXT
	MOVE	S2,P3			;Save possible line number
	DEVNAM	P3,			;Get the SIXBIT terminal name
	  JRST	DETJ.3			;Shouldn't happen
	MOVE	S1,[XWD .RCCPU,P2]	;Get the argument pointer
	RECON.	S1,			;Get the CPU accessibility for terminal
	  JRST	DETJ.3			;Shouldn't happen
	TDZN	S1,P4			;Accesible from us?
	JRST	DETJ.3			;No, continue
	JUMPN	S1,DETJ.3		;If others can access it, continue
	ANDI	S2,777			;Isolate line number for job
	HRLZS	S2			;In left half for detach
	HRR	S2,P1			;Get the job number
	ATTACH	S2,			;DETACH THE JOB
	  JRST	DETJ.3			;Shouldn't happen
DETJ.2:	TXON	F,FL.HEA		;HEADING GIVEN
	$TEXT	(WTORTN,<%Detaching jobs:>)
	$TEXT	(WTORTN,< ^D/P1/^A>)
DETJ.3:	AOBJN	P1,DETJ.1		;CONTINUE FOR ALL JOBS IN THE SYSTEM
	TXNE	F,FL.HEA		;HAVE TO CLEAN UP
	$TEXT	(WTORTN,<>)		;Carriage return
	$RETT
	SUBTTL	LSTDEV - Report any devices that will be lost

;CALL:	S1 = CPU BEING REMOVED

LSTDEV:	$SAVE	<P1>			;Make room
	MOVE	P1,CPUBIT(S1)		;Get a bit for CPU being checked
	TXZ	F,FL.HEA		;New heading for this loop
LSTD.0:	SETO	T1,			;Init DVPHY. arg block for all devices
	SETZ	T2,			;Start at first device
	MOVEI	T3,2			;Init a place for RECON.
LSTD.1:	MOVE	S1,[XWD 2,T1]		;Get pointer to DVPHY. arg block
	DVPHY.	S1,			;Get a device name
	  JRST	LSTD.0			;Perhaps a network device disconnected
	JUMPE	T2,.RETT		;All done, return
	MOVE	T4,T2			;Move to find CPU that owns it
	MOVE	S1,[XWD .RCCPU,T3]	;Get the pointer for a RECON.
	RECON.	S1,			;Get the mask of CPUs that own this
	  JRST	RCNERR			;Strange
	TDZN	S1,P1			;One of them the one we're looking for?
	JRST	LSTD.1			;No, loop
	JUMPN	S1,LSTD.1		;Continue if others can access it
	MOVE	S1,T4			;Get the device name
	DEVCHR	S1,			;Get status bits
	TXNN	S1,<DV.ASC!DV.ASP>	;Is it inited or assigned?
	JRST	LSTD.1			;No, loop
	TXON	F,FL.HEA		;Did we already print the header?
	$TEXT	(WTORTN,<%The following active devices will be lost:>)
	$TEXT	(WTORTN,<	^W/T4/>)
	JRST	LSTD.1			;AND LOOK AT ANOTHER DEVICE
	SUBTTL	Check if Disk Controller May be Removed


;Routine to check if a disk controller may be removed.
;Call:
;	S1/ Controller name (zero if ALL controllers)
;	S2/ Bit for CPU being removed if FL.WAC set
;	PUSHJ	P,CRDKON
;Returns:
;	FL.NCD set if can't remove (warnings printed)
;	FL.NCD clear if OK to remove
;Note:  S2 only needs to be set up when removing a CPU, i.e., when
;FL.WAC is set.  In this case, S1 should contains zero.

CRDKON:	$SAVE	<P1,P2>		;SAVE AN AC OR TWO
	SKIPN	S1		;CONTROLLER NAME ZERO?
	TXNE	F,FL.WAC	;YES, THIS IS THE ONLY LEGAL CASE
	SKIPA			;OK
	STOPCD	(BAR,HALT,,<Bad arguments to CRDKON>)
	DMOVE	P1,S1		;COPY ARGUMENTS
	TXZ	F,FL.NCD!FL.HEA	;ASSUME IT WILL WORK
	MOVE	S1,DSKLST##	;GET LIST HANDLE FOR DISK DATABASE
	$CALL	L%FIRST		;POSITION TO FIRST ENTRY
CRDK.1:	JUMPF	.RETT		;RETURN WHEN HIT END OF LIST
	JUMPE	P1,CRDK.2	;SKIP NAME CHECK IF ALL CONTROLLERS ACCEPTABLE
	HLLZ	S1,.DDNAM(S2)	;GET CONTROLLER NAME
	CAME	S1,P1		;MATCH?
	JRST	CRDK.4		;NO
CRDK.2:	SKIPE	.DDSNM(S2)	;A STRUCTURE MOUNTED?
	SKIPE	.DDALT(S2)	;YES, NO ALTERNATE PORT?
	JRST	CRDK.4		;NO, NO BIG DEAL
	TXNN	F,FL.WAC	;REMOVING A CPU?
	JRST	CRDK.3		;NO
	LOAD	S1,.DDXCH(S2),DC.XCA ;GET MASK OF ACCESSIBLE CPUS
	TDZN	S1,P2		;CLEAR BITS FOR THIS CPU
	JRST	CRDK.4		;CONTROLLER ISN'T ON CPU BEING REMOVED
	JUMPN	S1,CRDK.4	;OK IF STILL ACCESSIBLE VIA OTHER CPUS
CRDK.3:	TXON	F,FL.NCD!FL.HEA	;SET THE BITS, IS IT THE FIRST TIME?
	$TEXT	(WTORTN,<The following structures must be dismounted:>)
	$TEXT	(WTORTN,<	^W/.DDSNM(S2)/ on unit ^W/.DDNAM(S2)/>)
CRDK.4:	MOVE	S1,DSKLST##	;GET LIST HANDLE
	$CALL	L%NEXT		;POSITION TO NEXT ENTRY
	JRST	CRDK.1		;SEE IF OTHERS
	SUBTTL	Add/Remove Disk Controller


;Routine to add or remove a disk controller.
;Call:
;	F/ FL.ADD set if add, FL.ADD clear if remove
;	S1/ Controller name (zero if ALL controllers)
;	S2/ Bit for CPU being removed if FL.WAC set
;	PUSHJ	P,RADKON
;Return:
;	TRUE always

RADKON:	$SAVE	<P1,P2>		;SAVE AN AC OR TWO
	DMOVE	P1,S1		;COPY ARGUMENTS
	TXZ	F,FL.HEA	;CLEAR HEADER PRINTED FLAG
	MOVE	S1,DSKLST##	;GET LIST HANDLE FOR DISK DATABASE
	$CALL	L%FIRST		;POSITION TO FIRST ENTRY
RADK.1:	JUMPF	.RETT		;RETURN WHEN HIT END OF LIST
	JUMPE	P1,RADK.2	;SKIP NAME CHECK IF ALL CONTROLLERS ACCEPTABLE
	HLLZ	S1,.DDNAM(S2)	;GET CONTROLLER NAME
	CAME	S1,P1		;MATCH?
	JRST	RADK.6		;NO
RADK.2:	TXNN	F,FL.WAC	;ADDING A CPU?
	JRST	RADK.3		;NO
	TDNN	P2,.DDXCH(S2)	;IS CONTROLLER ON CPU BEING ADDED/REMOVED?
	JRST	RADK.6		;NO, SKIP IT
RADK.3:	LOAD	S1,.DDSTS(S2),DC.STS ;GET UNIT STATUS
	TXNN	F,FL.ADD	;ADD OR REMOVE?
	JRST	RADK.4		;REMOVE

;Add

	CAIE	S1,.DCSTD	;ADD IS EASIER, IS UNIT STATE = DOWN?
	JRST	RADK.6		;NO, IT'S ALREADY THERE, NOTHING TO DO
	MOVEI	T1,2		;LENGTH OF ARGUMENT BLOCK
	MOVE	T2,.DDNAM(S2)	;UNIT NAME
	DMOVEM	T1,RCNARG	;SAVE ARGUMENTS
	PUSHJ	P,ATTDET	;DO THE UUO
	JRST	RADK.6		;THAT WAS EASY!
;Remove

RADK.4:	CAIN	S1,.DCSTD	;IS UNIT STATE = DOWN?
	JRST	RADK.6		;YES, IT'S ALREADY REMOVED, NOTHING TO DO
	SKIPN	.DDALT(S2)	;IS THE UNIT DUAL PORTED?
	JRST	RADK.5		;NO
	TXNE	F,FL.WAC	;DOING THIS FOR A CPU?
	SKIPA	T1,[[ASCIZ /CPU/]]
	MOVEI	T1,[ASCIZ /controller/]
	TXON	F,FL.HEA	;FIRST TIME?
	$TEXT	(WTORTN,<The following drives are dual ported with the ^T/0(T1)/ being removed:>)
	$TEXT	(WTORTN,<	^W/.DDALT(S2)/>) ;GIVE THEM A CLUE
RADK.5:	MOVEI	T1,2		;LENGTH OF ARGUMENT BLOCK
	MOVE	T2,.DDNAM(S2)	;UNIT NAME
	DMOVEM	T1,RCNARG	;SAVE ARGUMENTS
	PUSHJ	P,ATTDET	;DO THE UUO
RADK.6:	MOVE	S1,DSKLST##	;GET LIST HANDLE
	$CALL	L%NEXT		;POSITION TO NEXT ENTRY
	JRST	RADK.1		;SEE IF OTHERS
	SUBTTL	Subroutine to set up CPU status table

SETCPU:	$SAVE	<P1>			;Get a safe AC
	MOVE	S1,[.STCPU,,SP.CR0!SP.CR1!SP.CR2!SP.CR3!SP.CR4!SP.CR5]
	SETUUO	S1,			;Set this job to run anywhere
	  JFCL				;Ok, must be a single processor
	SETZM	CPUN			;Clear count of running cpus
	SETZM	CPUOK			;Clear count of cpus with ok words counting
	SETZM	CPURUN			;And mask for running ones
	MOVSI	S1,-6			;Max cpus
SETC.1:	MOVSI	S2,(S1)			;Cpun to lh
	LSH	S2,1			;*2 for gettab
	ADD	S2,[.GTC0C,,.GTSLF]
	GETTAB	S2,			;Get base of cdb constants = cdb address
	STOPCD	(CDB,HALT,,<Can't determine CDB base address for CPU (in S1)>)
	TLNN	S2,(SL.MAX)		;Is max for gettab = 0
	JRST	[MOVSI S2,(CS.DWN!CS.NEX) ;Yes, mark it non-existant
		JRST SETC.2]		;And store data
	MOVEI	P1,(S1)			;Copy cpu number
	LSH	P1,1			;*2 for gettab
	ADD	P1,[%CVRUN]		;Get .CPRUN
	GETTAB	P1,			;Get it
	STOPCD	(CDS,HALT,,<Can't determine run status for CPU (in S1)>)
	TLNE	P1,(CV%DET)		;Is it detached
	JRST	[HRLI S2,(CS.DWN!CS.DET) ;Yes, mark it
		JRST SETC.2]		;Store data
	TLNE	P1,(CV%RMV)		;Is cpu already stopped
	JRST	[HRLI S2,(CS.DWN)	;Yes, mark it down
		JRST SETC.2]		;Store data
	TLZ	S2,-1			;CPU is up, clear status bits
	AOS	CPUN			;Count a running CPU
	GTTAB	P1,%CNBCP		;Find the boot cpu
	CAIN	P1,(S1)			;This it
	TLO	S2,(CS.BOT)		;Yes, remember that
	MOVE	P1,CPUBIT(S1)		;Get a bit for this CPU
	IORM	P1,CPURUN		;Light a running cpu bit
	MOVEI	P1,(S1)			;Copy cpu number
	LSH	P1,1			;*2 for gettab
	ADD	P1,[%CCOKP]		;Get the ok word
	GETTAB	P1,			;Get it
	STOPCD	(CDU,HALT,,<Can't determine up status for CPU (in S1)>)
	SKIPG	P1			;Is the cpu really running
	AOSA	CPUOK			;Yes, count the cpu
	TLO	S2,(CS.NOK)		;No, remember this one isn't
SETC.2:	MOVEM	S2,CPUSTS(S1)		;Update status
	AOBJN	S1,SETC.1		;And try another cpu
	$RETT				;Return
	SUBTTL	CPUSRC - CPU-driven table searching


CPUSRC:	HLLZ	T1,(S2)			;GET THE NUMBER OF ENTRIES
	MOVN	T1,T1			;MAKE IT NEGATIVE
	HRRI	T1,1(S2)		;ADDRESS OF THE TABLE
CPUS.1:	HLRZ	T2,(T1)			;MINIMUM OFFSET IS CPU0
	MOVEI	T3,6(T2)		;MAXIMUM OFFSET IS CPU5 + 1 (ALL CPUS)
	CAIL	S1,(T2)			;RANGE
	CAILE	S1,(T3)			; CHECK
	SKIPA				;NO MATCH
	JRST	CPUS.2			;YES..
	AOBJN	T1,CPUS.1		;TRY NEXT ONE
	$RETF				;ERROR..RETURN
CPUS.2:	HRRZ	S2,(T1)			;GET THE DATA
	$RETT				;RETURN TRUE
	SUBTTL	GETADR - Input an address from a token

; This routine will return a number based on the string a user types.
;If the string begins with a # character, the number will be assumed
;octal else it will be decimal, if the number is followed by a "P"
;then it will be assumed to mean page number, else it will be in units
;if 1024 words.

GETADR:	$SAVE	<P1,P2,P3>		;Make some room
	MOVEI	P3,^D10			;Assume decimal radix
	$CALL	P$TOK##			;See if he specified octal
	 SKIPF				;Didn't see if number
	MOVEI	P3,^O10			;He did, get real radix
	PUSHJ	P,P$FLD##		;Get the next token
	 JUMPF	GETA.6			; ??
	MOVEI	P1,1(S1)		;Save the string address
	MOVE	S2,P1			;Make a working copy
	HRLI	S2,(POINT 7,)		;Make it a byte pointer
	SETO	P2,			;Clear the place for the number
GETA.1:	ILDB	S1,S2			;Get the next character
	CAIL	S1,"0"			;Numeric?
	 CAILE	S1,"9"			; .  .  .
	  JRST	GETA.3			;No, go see if done
	SKIPGE	P2			;First time through?
	 SETZ	P2,			;Yes, start with a null
	IMUL	P2,P3			;Shift current total by radix
	ADDI	P2,-"0"(S1)		;Add this character into it
	JRST	GETA.1			;Loop for all

;When we get here, we have a number in P2 which will default to
;representing pages. We'll see if we have to convert it to kilo-words.

GETA.3:	JUMPE	S1,GETA.8		;All done?
	CAIE	S1,"K"			;No, did he specify kilo?
	 CAIN	S1,"k"			;Both ways
	  TRNA				;Yes
	JRST	GETA30			;No, try for pages
	LSH	P2,1			;Convert to right number of pages
	JRST	GETA.9			;Go return the value
GETA30:	CAIE	S1,"P"			;Did he specify pages
	 CAIN	S1,"p"			; .  .  .
	  JRST	GETA.9			;All set, go return the number
	JRST	GETA40			;Illegal format
	ILDB	S1,S2			;Make sure he didn't type more
	JUMPE	S1,GETA.5		;If he didn't, go finish up
GETA40:	$TEXT	(WTORTN,<Illegally formatted address>)
	$RETF				;Return bad
GETA.5:	JUMPGE	P2,.RETT		;Did he type any digits?
	$TEXT	(WTORTN,<Illegal address specified - at least one digit must be specified>)
	$RETF
GETA.6:	$TEXT	(WTORTN,<Error parsing address field>)
	$RETF
;Here with a number of words.

GETA.8:	ADR2PG	P2			;Convert to pages
GETA.9:	MOVE	S1,P2			;Get the number to be returned
	$RETT				;Return it
	SUBTTL	SNDALL - Routine to send a message to all terminals

SNDALL:	$SAVE	<S2+1>			;Save possible data reg
	PUSHJ	P,SEND.1		;Send the message
	MOVEI	S1,[BYTE (7).CHCRT,.CHLFD] ;Append a CRLF to it
SEND.1:	MOVE	S2+1,S1			;Point to text
	MOVX	S1,.TOTYP		;TRMOP. to stuff text down TTY's throat
	MOVE	S2,FRCLIN##		;Send text to FRCLIN
	MOVX	TF,<3,,S1>		;Set up for CALLI
	TRMOP.	TF,			;Do SEND ALL command
	  $RETF				;Can't
	$RETT				;Return sucessful
	SUBTTL	CTYTYP - Type messages on the CTY

CTYTYP:	SKIPN	CTYBLK+1		;Did we already set-up TRMOP. block
	 PUSHJ	P,SETCTY		;No, do so now
	MOVEM	S1,CTYBLK+2		;Store the character
	MOVE	S1,[3,,CTYBLK]		;Point to the argument block
	TRMOP.	S1,			;Type the character
	STOPCD	(CTC,HALT,,<Can't type to CTY>)
	$RETT

SETCTY:	MOVSI	S2,'CTY'		;Get the name of the CTY
	IONDX.	S2,			;And get it's UDX
	STOPCD	(CGU,HALT,,<Can't get universal device index of CTY>)
	MOVEM	S2,CTYBLK+1		;Store it
	MOVEI	S2,.TOOUC		;Get the output a character functionn
	MOVEM	S2,CTYBLK		;Store it
	$RET
	SUBTTL	Useful subroutines

;Do the RECON. UUO to attach or detach a piece of hardware, and
;report any errors which occur.
;Call:
;	RCNARG/ Arguments (word count, device name)

ATTDET:	MOVE	S1,[.RCDET,,RCNARG]	;Assume DETACH
	TXNE	F,FL.ADD		;ADD command?
	HRLI	S1,.RCATT		;Yes, that means ATTACH
	RECON.	S1,			;Do the UUO
	  PJRST	RCNERR			;Report error and FALSE return
	$RETT				;TRUE return
	SUBTTL	Error subroutines

RCNERR:	$TEXT	(WTORTN,<RECON. UUO error (^O/S1/)^A >)
	CAIL	S1,RCNETL		;Error number in range?
	MOVEI	S1,RCNETL		;No, something really wrong
	$TEXT	(WTORTN,< ^I/@RCNETX(S1)/>)
	JRST	ERRXIT			;Join common error exit

DIAERR:	$TEXT	(WTORTN,<DIAG. UUO error (^O/S1/)^A >)
	CAIL	S1,DIAETL		;Error number in range?
	MOVEI	S1,DIAETL		;No, something really wrong
	$TEXT	(WTORTN,< ^T/@DIAETX(S1)/>)
ERRXIT:	MOVE	S1,[EXP MF.FAT!<INSVL.(<'CNF'>,MF.SUF)>] ;Get error flags
	MOVEM	S1,G$APFG##		;Set them for typeout
	$RETF


GTBERR:	STOPCD	(GTE,HALT,,<GETTAB error>)
RCNETX:	[ITEXT	(<No such error code>)]
	[ITEXT	(<Illegal argument list>)]
	[ITEXT	(<Not privileged>)]
	[ITEXT	(<Timesharing has already stopped on some CPU>)]
	[ITEXT	(<Illegal job number>)]
	[ITEXT	(<System cannot be snapshotted>)]
	[ITEXT	(<Address check>)]
	[ITEXT	(<Illegal string>)]
	[ITEXT	(<Illegal CPU number>)]
	[ITEXT	(<CPU still running>)]
	[ITEXT	(<Can't attach disk unit ^W/RCNARG+1/>)]
	[ITEXT	(<Device ^W/RCNARG+1/ is spooled>)]
	[ITEXT	(<Device ^W/RCNARG+1/ is already attached>)]
	[ITEXT	(<Illegal device ^W/RCNARG+1/>)]
	[ITEXT	(<Device ^W/RCNARG+1/ is in use>)]
	[ITEXT	(<Can't detach disk unit ^W/RCNARG+1/>)]
	[ITEXT	(<LOKCON not loaded (can't set memory off-line)>)]
	[ITEXT	(<Removing monitor memory>)]
	[ITEXT	(<Job(s) too big>)]
	[ITEXT	(<Moving locked job(s)>)]
RCNETL==.-RCNETX
	[ITEXT	(<Unknown error code>)]

DIAETX:	[ASCIZ	/No such error code/]
	[ASCIZ	/Not privileged/]
	[ASCIZ	/Illegal number of arguments/]
	[ASCIZ	/Illegal controller/]
	[ASCIZ	/Illegal unit/]
	[ASCIZ	/Some units already assigned/]
	[ASCIZ	/Unit not in diagnostic mode/]
	[ASCIZ	/Unit assigned to another job/]
	[ASCIZ	/No free core/]
	[ASCIZ	/No assigned units/]
	[ASCIZ	\I/O word crosses a page boundary\]
	[ASCIZ	/Illegal function/]
	[ASCIZ	/Job can't be virtual/]
	[ASCIZ	/No such CPU/]
	[ASCIZ	/CPU not running/]
	[ASCIZ	/Bad argument list/]
	[ASCIZ	/No CI port on CPU/]
	[ASCIZ	/Read CI port counters timed out/]
	[ASCIZ	/No NI port on CPU/]
	[ASCIZ	/Microcode reload failed/]
	[ASCIZ	/Microcode not available/]
	[ASCIZ	/Port not running/]
DIAETL==.-DIAETX
	[ASCIZ	/Unknown error code/]
	SUBTTL	End of CNFORN

	END