Google
 

Trailing-Edge - PDP-10 Archives - tops20-v7-ft-dist1-clock - 7-sources/knildr.mac
There are 8 other files named knildr.mac in the archive. Click here to see a list.
; *** Edit 11 to KNILDR.MAC by RASPUZZI on 11-Feb-88, (TCO 7.1221)
; Define major version for NI ucode correctly.
; *** Edit 10 to KNILDR.MAC by RASPUZZI on 23-Apr-87, for SPR #21606
; Don't do a DOBE% when running in automagic mode because this can cause
; bad things like CHKRNR if the CTY is behind in output or some moron has
; the CTY ^Sed or maybe the CTY is just plain snailing at 300 baud.
; UPD ID= 117, SNARK:<6.1.UTILITIES>KNILDR.MAC.16,  23-Apr-85 17:52:29 by GROSSMAN
;More TCO 6.1.1338 - Update edit # to 9.
; UPD ID= 116, SNARK:<6.1.UTILITIES>KNILDR.MAC.15,  23-Apr-85 17:49:54 by GROSSMAN
;TCO 6.1.1338 - Make BADFIL check ATOFLG.
; UPD ID= 101, SNARK:<6.1.UTILITIES>KNILDR.MAC.14,  20-Mar-85 14:02:11 by GROSSMAN
;Even more TCO 6.1.1226 - Dump the PS block too!  Edit # 8
; UPD ID= 100, SNARK:<6.1.UTILITIES>KNILDR.MAC.13,  20-Mar-85 13:08:19 by GROSSMAN
;More TCO 6.1.1226 - Dump PCB and LAR also.  Edit # 7.
; UPD ID= 96, SNARK:<6.1.UTILITIES>KNILDR.MAC.12,  13-Mar-85 10:34:42 by GROSSMAN
;More TCO 6.1.1226 - Fix fencepost error in condition code dumper (CCPYLP).
; Edit # 6.
; UPD ID= 94, SNARK:<6.1.UTILITIES>KNILDR.MAC.11,  11-Mar-85 09:40:59 by GROSSMAN
;More TCO 6.1.1246 - Increment edit # to 5.
; UPD ID= 93, SNARK:<6.1.UTILITIES>KNILDR.MAC.10,  11-Mar-85 09:36:05 by GROSSMAN
;TCO 6.1.1246 - Add INFO VER and HELP command.
; UPD ID= 90, SNARK:<6.1.UTILITIES>KNILDR.MAC.9,   3-Mar-85 09:15:36 by GROSSMAN
;TCO 6.1.1226 - Enhance dumper to include 2910 stack, condition codes, and the
;used buffer list.  Edit # 4.
; UPD ID= 89, SNARK:<6.1.UTILITIES>KNILDR.MAC.8,  26-Feb-85 10:51:17 by GROSSMAN
;TCO 6.1.1221 - Edit # 3.  Make automatic mode dump to SYSTEM: instead of to
;connected directory.
; UPD ID= 65, SNARK:<6.1.UTILITIES>KNILDR.MAC.7,   1-Jan-85 17:04:16 by GROSSMAN
;TCO 6.1.1102 - Edit # 2.  Restart the KLNI after reloading or dumping it.
; UPD ID= 49, SNARK:<6.1.UTILITIES>KNILDR.MAC.6,  19-Nov-84 19:14:47 by GROSSMAN
;More TCO 6.1.1060 - Set edit number to 1.
; UPD ID= 48, SNARK:<6.1.UTILITIES>KNILDR.MAC.5,  19-Nov-84 17:03:24 by GROSSMAN
;TCO 6.1.1060 - Support new microcode version # format.  Use new NI% JSYS
; symbols.
; UPD ID= 42, SNARK:<6.1.UTILITIES>KNILDR.MAC.4,  13-Nov-84 03:09:51 by GROSSMAN
;Correct assembly errors by using new symbols.
; UPD ID= 41, SNARK:<6.1.UTILITIES>KNILDR.MAC.3,  13-Nov-84 01:32:27 by GROSSMAN
;TCO 6.1.1049 - Remove search of NISYM, as it is no more...
; UPD ID= 30, SNARK:<6.1.UTILITIES>KNILDR.MAC.2,   4-Sep-84 09:14:57 by GROSSMAN
; .REQUIRE MACREL to simplify build procedure.
; Program creation - Stu Grossman - August 1984
	TITLE	KNILDR - Loader/Dumper for KLNI's

	SEARCH MACSYM,MONSYM,JOBDAT

	SALL			; Suppress macro expansions

	.REQUIRE SYS:MACREL

; AC defs

	STDAC.

	CHN=P4			; Always holds the KLNI channel #

; Version numbers

	VERWHO==0		; Customer version number
	VERMAJ==1		; Major version number
	VERMIN==0		; Minor version number
	VEREDT==^D11		; Edit number

; Entry vector

ENTVEC:	JRST KNILDR		; Normal start address
	JRST KNIATO		; Automatic mode start address
	<BYTE (3)VERWHO (9)VERMAJ (6)VERMIN (18)VEREDT> + VI%DEC
	SUBTTL Macros

; DIE macro - Used when program encounters a fatal error
;
; DIE (nam,text)
;
;	nam - 3 letter suffix for stopcode name.  Must be unique.
;	text - Long form explanation.
;

	DEFINE DIE(nam,text)<JRST [HALTF%]>

; HLPTXT macro - Use this macro as the first instruction for a command.
; The text can then be automatically found by the help routine.

	DEFINE HLPTXT(text)<TRN [ASCIZ |text|]>
; Handy macro's for dealing with the COMND% JSYS

; Command line init
	DEFINE CMDINI <MOVEI T2,[FLDDB. (.CMINI)]
			CALL DOCMND>

; Keyword parser
	DEFINE GETKEY (table)<MOVEI T2,[FLDDB. (.CMKEY,,table)]
				CALL DOCMND>

; Switch parser
	DEFINE GETSWI (table,defalt)<MOVEI T2,[FLDDB. (.CMSWI,,table,,defalt)]
					CALL DOCMND>

; Noise
	DEFINE NOISE (phrase)<MOVEI T2,[FLDDB. (.CMNOI,,<-1,,[ASCIZ |phrase|]>)]
				CALL DOCMND>

; Input file
	DEFINE IFILE<MOVEI T2,[FLDDB.(.CMIFI)]
			CALL DOCMND>

; Output file
	DEFINE OFILE (defalt)<MOVEI T2,[FLDDB. (.CMOFI,,,,defalt)]
				CALL DOCMND>

; Number
	DEFINE GETNUM (radix)<MOVEI T2,[FLDDB. (.CMNUM,,radix)]
				CALL DOCMND>

; Confirm
	DEFINE CONFRM <CALL CNFIRM>

; Error message handler

	DEFINE ERROR (text) <JRST [HRROI T1,[ASCIZ |text|]
				   JRST ERRTRM]>
	SUBTTL Symbols

; These symbols describe the action that should be taken after dumping or
; reloading the KLNI.

	.KYHLT==0		; Halt the KLNI
	.KYPRE==1		; Preserve the state
	.KYSTA==2		; Start the KLNI
	SUBTTL Device control bits

KNI==564			; Device code for KLIPA

;CONI BITS - LEFT

CI.PPT==1B0			;PORT PRESENT
CI.DCC==1B2			;DIAG CSR CHANGE
CI.CPE==1B6			;CRAM PARITY ERROR
CI.MBE==1B7			;MBUS ERROR
CI.IDL==1B11			;IDLE
CI.DCP==1B12			;DISABLE COMPLETE
CI.ECP==1B13			;ENABLE COMPLETE

;CONI/CONO BITS - RIGHT

CO.CPT==1B18			;CLEAR PORT
CO.SEB==1B19			;SELECT EBUF
CO.LAR==1B21			;SELECT LAR
CO.SSC==1B22			;DIAG SINGLE CYCLE
CI.EPE==1B24			;EBUS PARITY ERROR
CI.FQE==1B25			;FREE QUEUE ERROR
CI.DME==1B26			;DATA MOVER ERROR
CO.CQA==1B27			;COMMAND QUEUE AVAILABLE
CI.RQA==1B28			;RESPONSE QUEUE AVAILABLE
CO.DIS==1B30			;DISABLE
CO.ENA==1B31			;ENABLE
CO.MRN==1B32			;MICRO-PROCESSOR RUN

DO.LAD==1B0			;BIT ON IN DATAO TO LOAD RAM ADDRESS REGISTER
DO.MSB==1B13			;BIT ON IN DATAO TO LOAD HIGH ORDER UWORD

CI.ERR==CI.CPE!CI.MBE!CI.EPE!CI.DME

LSLEN==^D1024			; Local storage length

CRMLEN==^D4096			; Length of ucode memory

DEFSTR	MICPC,,12,12		;UPROC PC FIELD WHEN READ VIA A DATAI

; Microword field definitions

; This set of definitions is based on the KLPDDT storage format for CRAM
; locations.  Each cram loc takes up two words right justified in bits
; 6-35 of each word.

	BEGSTR MW

	 FILLER 6		; First twelve bits are ignored
	 FIELD JMP,12		; MWJMPFLD Microword Jump Address
	 FIELD PAR,1		; MWPAR Microword Parity Bit
	 FIELD OEN,1		; MWOUTPUTENA ALU Data Output Enable Bit
	 FIELD MGC,10		; MWMGCFLD Magic Number Field
	 FIELD SRC,3		; MWSORCEFLD ALU Source Input Field
	 FIELD FUN,3		; MWFUNCTFLD ALU Function Field

	 NXTWRD			; Force us into the next word
	 FILLER 6		; Jump to next word
	 FIELD DST,3		; MWDESTFLD ALU Destination Output Field
	 FIELD CCE,1		; MWCCENA Condition Code Enable Bit
	 FIELD RAM,1		; MWRAMODE Local Storage RAM Mode Bit
	 FIELD PRA,4		; MWPORTAFLD ALU Port "A" Address Field 
	 FIELD PRB,4		; MWPORTBFLD ALU Port "B" Address Field 
	 FIELD SKP,5		; MWSKIPFLD Microword Skip Field
	 FIELD BUS,3		; MWBUSCTLFLD Microprocessor Bus Control Field
	 FIELD CRY,1		; MWCARRY Microword Carry Input Bit to ALU
	 FIELD CTL,4		; MWCTRLFLD Microseqr Control Input Field
	 FIELD TIM,1		; MWTIMEFLD Microword Time Field Bit
	 FIELD UNU,2		; MWSPARE0 & MWSPARE1  Unused
	 FIELD MRK,1		; MWMARKBIT Microword Mark Bit
	ENDSTR MW

; Version # fields in the ucode

;**;[11] Change MWMAJ bit mask		MDR	5-FEB-88
	DEFSTR MWMAJ,136*2+1,^D23,4	; [11] Major version #
	DEFSTR MWMIN,136*2+1,^D29,4	; Minor version #
	DEFSTR MWEDT,137*2+1,^D29,^D10	; Edit #

; Device code field of an I/O instruction

DEFSTR DVCOD,,9,7
	SUBTTL KNILDR - Manual program start address

KNILDR:	RESET%
	MOVE P,STKAC		; Setup the stack pointer
	SETZM ATOFLG		; Indicate we are in manual mode

; Initialize for command scanning

COMLOP:	CMDINI			; Initialize the scanner

; Basic command loop

COMRPR:	MOVE P,STKAC		; Reset the stack

	GETKEY (CMDTBL)		; Parse the initial command

	HRRZ T1,(T2)		; Get command routine address
	CALL (T1)		; Call the processor
	JRST COMLOP		; And jump back again

; Top level command table

DEFINE COMM(comand,flgs)<IFB <flgs>,<XWD [ASCIZ |comand|],.'comand>
		      IFNB <flgs>,<XWD [CM%FW+flgs
					ASCIZ |comand|],.'comand>>

DEFINE ABR(comand,loc)<XWD [CM%FW+CM%ABR+CM%INV
			ASCIZ |comand|],loc>

DEFINE NG(comand)<XWD [CM%FW+CM%NOR
			ASCIZ |comand|],0>

CMDTBL:	XWD CMDTLN,CMDTLN	; Length of command table
	COMM DUMP		; Dump KLNI into a file
	ABR E,.+4		; Abbreviation for exit
	NG ENABL		; Suppress abbreviations
	COMM ENABLE,CM%INV	; Enable magical commands
	ABR EX,.+1		;     "
	COMM EXIT		; Exit the program
	COMM EXTRACT,CM%INV	; Extract symbols from a .ULD file
	COMM GET,CM%INV		; Get microcode from a file
	COMM HALT		; Stop the KLNI
	COMM HELP		; Obtain help
	COMM INFORMATION	; Information about KLNI's
	COMM LOAD		; Load microcode into the KLNI
	COMM START		; Start the KLNI
	ABR T,.+1		; Abbreviation for TAKE
;	COMM TAKE		; Take a command file
	COMM TRANSLATE,CM%INV	; Translate a dump into human readable form
	CMDTLN==.-CMDTBL-1

REPAR:	JRST COMRPR

.TAKE:
.EXIT:	HLPTXT <
EXIT -	Exit the program.>

	CONFRM			; Wait for the CRLF
	HALTF%
	RET
	SUBTTL GET Command

; This command will read a .ULD file and put it's microcode into the buffer
; starting at location CRAM.
;
; Command format:
; KNILDR>GET (MICROCODE FROM FILE) FOO.ULD
;

.GET:	HLPTXT <
GET -	Reads the microassembler output and saves it in this core image.
	After doing a GET, you should EXIT and SAVE the program to make
	it permanent.>

	SAVEAC P1
	NOISE MICROCODE FROM FILE

	IFILE			; Parse an input file

	MOVE P1,T2		; Put JFN in a safe place

	CONFRM			; Eat the CRLF

	MOVE T1,P1		; Get JFN
	MOVE T2,[FLD(7,OF%BSZ)+OF%RD] ; Open file for read, 7 bit bytes
	OPENF%			; Open the file
	 ERJMP BADFIL
	SETZM BUFCNT		; Reset the input buffer count
	SETZM MICVAL		; Clear the valid micorcode flag
	SETZM LINNUM		; Start line numbers at 1
	SETZM NUMMIC		; Reset number of microwords read
	SETZM CRAM		; Clear first word of CRAM buffer
	MOVE T1,[CRAM,,CRAM+1]	; Prepare to BLT
	BLT T1,CRAM+CRMLEN-1	;  the CRAM buffer away
	MOVEM P1,JFN		; Put JFN in a safe place
	SUBTTL .ULD file parsing routines

	SAVEAC <P1,P2,P3>

NEWLIN:	AOS LINNUM		; Increment the line counter
	CALL REDCHR		; Read the first character of the line
	 JRST FILDON		;  End of file

	CAIN T1,";"		; Comment?
	 JRST COMENT		;  Yes, eat the comment
	CAIE T1,"["		; Location indicator?
	 JRST FILDON		;  Nope, we are done

	CALL REDNUM		; Read in the PC
	 JRST FILERR		;  Bad place to end the file
	CAIE T2,"]"		; Did the PC terminate correctly?
	 JRST FILERR		;  Nope, complain
	CAILE T1,CRMLEN-1	; Is the PC reasonable?
	 JRST FILERR		;  PC out of range
	MOVE P1,T1		; Save the PC for a moment
	LSH P1,1		; Multiply the PC by 2
	CALL REDCHR		; Get the next character
	 JRST FILERR		;  Bad place to end the file
	CAIE T1,"="		; Is it an "="???
	 JRST FILERR		;  Nope, bitch
	CALL REDHLF		; Read half of a microword
	 JRST FILERR		;  Bad place to end the file
	MOVEM T1,CRAM+1(P1)	; Save the MSB's of the microword
	CALL REDHLF		; Read half of a microword
	 JRST FILERR		;  Bad place to end the file
	MOVEM T1,CRAM(P1)	; Save the LSB's of the microword
	AOS NUMMIC		; Increment the number of uwords loaded
	CALL REDCHR		; Get a carriage return
	 JRST FILERR
	CAIE T1,15		; Carriage return?
	 JRST FILERR
EATLF:	CALL REDCHR		; Get line feed
	 JRST FILERR
	CAIE T1,12		; Line feed?
	 JRST FILERR
	JRST NEWLIN		; Back to the start of the line

; Here to eat comments

COMENT:	CALL REDCHR		; Get a character
	 JRST FILDON		;  End of file, quit
	CAIE T1,15		; Carriage return?
	 JRST COMENT		;  Nope, try again
	JRST EATLF		; Yes, go eat the line feed

FILDON:	SKIPN NUMMIC		; Did we load any microcode?
	 JRST FILDO2		;  No, file was probably bogus

	SETOM MICVAL		; Microcode is now valid
	CALL .TYMPR		; Type out standard prefix
	HRROI T1,[ASCIZ |Microcode version |]
	PSOUT%
	MOVX T1,CRAM		; Get address of ucode
	CALL .TYMVR		; Type out the ucode version
	HRROI T1,[ASCIZ | loaded]
|]
	PSOUT%

FILDO2:	CALL .TYMPR		; Type out standard prefix
	MOVE T1,NUMMIC		; Get the number of uwords we loaded
	CALL .TYDEC		; Type it out
	HRROI T1,[ASCIZ | words of microcode loaded]

|]
	PSOUT%

FILDO1:	MOVE T1,JFN		; Get the JFN
	CLOSF%			; Close the file
	 ERJMP .+1
	RET			; All done

FILERR:	CALL .TYEPR		; Type out standard prefix
	MOVE T1,LINNUM		; Get the errant line number
	CALL .TYDEC		; Type the number
	HRROI T1,[ASCIZ | in file |]
	PSOUT%
	MOVX T1,.PRIOU		; Use primary output
	MOVE T2,JFN		; Get the JFN
	SETZ T3,		; Use default format control
	JFNS%			; Print out the file name
	HRROI T1,[ASCIZ |

|]
	PSOUT%			; Finish off the line
	JRST FILDO1		; And close off the file

; Here when some file I/O error occurs

BADFIL:	MOVE T2,T1		; Get error code
	CALL .TYJSE		; Type it out
	SKIPN ATOFLG		; Are we in auto mode?
	 JRST COMLOP		;  Nope, abort the command
	RET			; Yes, just give error return
	SUBTTL DUMP Command

; This command will dump the contents of a KLNI to a file.  The local store,
; microcode stack, and ALU registers will be dumped.
;
; Command format:
;
; KNILDR>DUMP (CHANNEL) channel (TO FILE) filename

.DUMP:	HLPTXT <
DUMP -	This command will dump the variables of a KLNI into a file.  It may
	be used at any time, even when the KLNI is running.>

	SAVEAC <P1,P2>
	NOISE CHANNEL

	GETNUM ^D10		; Get the channel #

	MOVE CHN,T2		; Save the channel #

	DPB CHN,DEFCHN		; Put the channel number into the filename

	NOISE TO FILE

	MOVEI T2,[FLD(.CMOFI,CM%FNC)+CM%DPP ; Output filespec
		  0		; No data
		  0		; No help message
		  -1,,DEFFIL]	; Pointer to default filespec
	CALL DOCMND		; Do the COMND% jsys

	MOVEM T2,JFN		; Save the JFN

	GETSWI (STASWI,/PRESERVE-STATE)
	HRRZ P1,(T2)		; Get the new state indicator

	CONFRM			; Get the CRLF

	CALL GETCHS		; Get the KLNIs current state
	 DIE CGS,
	MOVE P2,T1		; Save the state in a safe place

	CALL DODUM1		; Go do the actual dump

	DMOVE T1,P1		; Get the state disp and old state
	CALLRET SETDSP		; Set the new state
	SUBTTL LOAD command

; This command will reload a KLNI's microcode.
;
; Command format:
;
; KNILDR>LOAD (CHANNEL) channel

.LOAD:	HLPTXT <
LOAD -	Loads the KLNI's control store from the microcode contained in this
	file.>

	SAVEAC <P1,P2>
	NOISE CHANNEL

	GETNUM ^D10		; Read the channel number

	MOVE CHN,T2		; Save the channel #

	GETSWI (STASWI,/PRESERVE-STATE)

	CONFRM			; Read the end of a line

	HRRZ P1,(T2)		; Get the new state indicator
	CALL GETCHS		; Get the current state
	 DIE CGS
	MOVE P2,T1		; Save the current state

	CALL DORELD		; Do the actual reload

	DMOVE T1,P1		; Get the state disp and the old state
	CALLRET SETDSP		; Set the state according to the disposition

	DEFINE XX(cmdnum,comand)<XWD [ASCIZ |comand|],cmdnum>

STASWI:	XWD STATLN,STATLN	; Length of command table
	XX .KYHLT,HALT-ETHERNET-CHANNEL
	XX .KYPRE,PRESERVE-STATE
	XX .KYSTA,START-ETHERNET-CHANNEL
	STATLN==.-STASWI-1
	SUBTTL START command

; This command will start a KLNI.
;
; Command format:
;
; KNILDR>START (CHANNEL) channel

.START:	HLPTXT <
START -	Start the specified Ethernet channel.>

	NOISE CHANNEL
	GETNUM ^D10			; Read the channel number
	MOVE CHN,T2			; Put it in a safe place
	CONFRM

	MOVX T1,.EISRN			; New state is RUN
	CALL SETCHS			; Set the state
	 ERROR (Can't set channel state)
	RET
	SUBTTL HALT command

; This command will stop a KLNI.
;
; Command format:
;
; KNILDR>HALT (CHANNEL) channel

.HALT:	HLPTXT <
HALT -	Halt the specified Ethernet channel.>

	NOISE CHANNEL
	GETNUM ^D10			; Read the channel number
	MOVE CHN,T2			; Put it in a safe place
	CONFRM

	MOVX T1,.EISOF			; New state is off
	CALL SETCHS			; Set the state
	 ERROR (Can't set channel state)
	RET
	SUBTTL HELP Command

.HELP:	HLPTXT <
HELP -	Print this text.>

	NOISE WITH KNILDR

	CONFRM

	SAVEAC P1

	HRROI T1,[ASCIZ |
KNILDR is a utility used to perform various maintenance functions for the
NIA20 Ethernet controller.  KNILDR can start and stop the NIA20 microcode,
it also can reload the NIA20's microstore.  It can also dump the NIA20's
variables for later analysis.  KNILDR is also run automatically by TOPS-20
whenever the NIA20 needs to be reloaded or dumped.

|]
	PSOUT%

	MOVE P1,[-CMDTLN,,CMDTBL+1]	; Get AOBJN pointer to command table
HLPLOP:	HLRZ T1,(P1)			; Get the text address
	MOVE T1,(T1)			; Get the first word of text
	TLNE T1,774000			; First byte 0?
	 JRST HLPOK			;  Nope, help is on the way
	TXNN T1,CM%FW			; Is this a flags word?
	 JRST HLPOK			;  Nope, try helping him
	TXNE T1,CM%INV			; Invisible?
	 JRST HLPNXT			;  Yes, then don't help him

HLPOK:	HRRZ T1,(P1)			; Get start address of routine
	MOVE T1,(T1)			; Get first instruction of routine
	HLRZ T2,T1			; Get the opcode
	CAIE T2,(TRN)			; Is it the magic value?
	 JRST HLPNXT			;  Nope, keep trying
	TLO T1,-1			; Make it into a standard BP
	PSOUT%				; Output the text
	HRROI T1,[ASCIZ |
|]
	PSOUT%				; Finish it off with a return
HLPNXT:	AOBJN P1,HLPLOP			; Loop through the whole mess
	HRROI T1,[ASCIZ |
|]
	PSOUT%
	RET				; All done!
	SUBTTL ENABLE Command

.ENABLE:
	NOISE MAGIC MODE

	CONFRM

	SAVEAC P1

	MOVE P1,[-CMDTLN,,CMDTBL+1]	; Get AOBJN pointer to commands
ENABLP:	HLRZ T1,(P1)			; Get addr of flags word
	MOVE T2,(T1)			; Get the flags word
	TLNE T2,774000			; Possible flags word?
	 JRST ENBNXT			;  Nope, try next command
	TXNN T2,CM%FW			; Flags word?
	 JRST ENBNXT			;  Nope, try next command
	TXNN T2,CM%INV			; Invisible?
	 JRST ENBNXT			;  Nope, don't bother
	TXNE T2,CM%ABR			; Abbreviation?
	 JRST ENBNXT			;  Yes, leave it alone
	TXZ T2,CM%INV			; Make it visible
	MOVEM T2,(T1)			; Put it back into the table
ENBNXT:	AOBJN P1,ENABLP			; Loop through the whole mess

	RET
	SUBTTL INFORMATION Command

.INFORMATION:
	HLPTXT <
INFORMATION -
	Get information about various things.>

	NOISE ABOUT

	GETKEY (INFKEY)		; Get the subcommand

	HRRZ T1,(T2)		; Get the routine address
	CALLRET (T1)		; Call the sub-command processor

INFKEY:	INFTLN,,INFTLN		; Length of command table
	COMM VERSION		; Return the microcode version
	INFTLN==.-INFKEY-1

.VERSION:
	NOISE OF MICROCODE
	CONFRM

	SKIPN MICVAL		; Is the microcode valid?
	 ERROR This file does not contain valid microcode.

	HRROI T1,[ASCIZ |
This file contains NIA20 microcode version |]
	PSOUT%
	MOVX T1,CRAM		; Get the address of the ucode
	CALL .TYMVR		; Type out the version #
	MOVX T1,[ASCIZ |.
|]
	PSOUT%
	RET			; All done!
	SUBTTL EXTRACT Command - Extract symbols from a .ULD file

; This command will read the symbols from a .ULD file, and put them into an
; internal symbol table.
;
; Command format:
; KNILDR>EXTRACT (SYMBOLS FROM FILE) FOO.ULD
;

.EXTRACT:
	SAVEAC P1
	NOISE SYMBOLS FROM FILE

	IFILE			; Parse an input file

	MOVE P1,T2		; Put JFN in a safe place

	CONFRM			; Eat the CRLF

	MOVE T1,P1		; Get JFN
	MOVE T2,[FLD(7,OF%BSZ)+OF%RD] ; Open file for read, 7 bit bytes
	OPENF%			; Open the file
	 ERJMP BADFIL
	SETZM BUFCNT		; Reset the buffer character count
	MOVEM P1,JFN		; Put JFN in a safe place

	MOVE T1,[POINT 7,[ASCIZ |
FIELD M=<14:23>
|]]
	CALL SRCSTR		; Look for the field indicator
	 HALT .			;  Couldn't find the field indicator
	TRVAR <<SYMBUF,8>>

EXTRA1:	CALL REDCHR		; Read the next character
	 JRST EXTRA2		;  All done, return
	CAIE T1," "		; Did we get a space?
	 JRST EXTRA2		;  Nope, we're done
	MOVE T1,[POINT 7,SYMBUF] ; Get pointer to symbol buffer
	CALL REDSYM		; Read in the symbol
	 HALT .
	MOVE P1,T1		; Save length for a moment
	CALL REDNUM		; Read the value
	 HALT .
	CAIE T2,15		; Did number terminate correctly?
	 HALT .
	XMOVEI T2,SYMBUF	; Get pointer to symbol
	MOVE T3,P1		; Get length of symbol
	CALL INSSYM		; Insert the symbol

	CALL REDCHR		; Read the line feed
	 HALT .
	CAIE T1,12		; Is it a line feed?
	 HALT .
	JRST EXTRA1		; Loop over whole table

	HALT .

; Here when done with file

EXTRA2:	CALL FILDO1		; Close the file
	RET
	SUBTTL TRANSLATE Command

; This command will convert a KLNI binary dump file into a human readable
; text file.  Symbols will be used where possible.
;
; Command format:
; KNILDR>TRANSLATE (DUMP FILE) KLNI-0.DUMP (TO) KLNI-0.TXT
;

.TRANSLATE:
	SAVEAC <P1,P2,P3>

	NOISE DUMP FILE

	IFILE			; Parse an input file

	MOVE P1,T2		; Put input JFN in a safe place

	NOISE TO FILE

	OFILE			; Parse an output file

	MOVE P2,T2		; Save output JFN

	CONFRM			; Terminate the line

	MOVE T1,P1		; Get input JFN
	MOVE T2,[FLD(^D36,OF%BSZ)+OF%RD] ; Open the file for read
	OPENF%			; Open the file
	 ERJMP BADFIL

	MOVE T1,P2		; Get output JFN
	MOVE T2,[FLD(7,OF%BSZ)+OF%WR] ; Open the file for write
	OPENF%			; Open the file
	 ERJMP BADFIL

; First dump the local store, printing out the location symbolically

	SETZ P3,		; Reset the location counter
	DO.
	  MOVE T1,P3		; Get current location
	  CALL LOKSYM		; Look it up
	  IFSKP.		; If we found it, print it symbolically
	    MOVE T4,T1		; Put pointer in a safe place
	    DO.
	      MOVE T1,P2	; Get output JFN
	      HRROI T2,1(T4)	; Get address of ASCIZ symbol name
	      SETZ T3,		; Terminate on 0
	      SOUT%		; Output the symbol name
	      MOVE T4,(T4)	; Get next symbol name
	      JUMPE T4,ENDLP.	; Jump if at end of chain
	      MOVX T2,","	; Get a comma
	      BOUT%		; Output that
	      JRST TOP.		; And loop over all symbols
	    ENDDO.
	  ELSE.			; No symbol for this location
	    MOVE T1,P2		; Get output JFN
	    MOVE T2,P3		; Get location #
	    MOVX T3,8		; Print it in octal
	    NOUT%		; Output it numerically
	     HALT .
	  ENDIF.
	  HRROI T2,[ASCIZ |/ |]	; Get seperator
	  SETZ T3,		; Terminate on null
	  SOUT%			; Output the seperator

	  MOVE T1,P1		; Get input JFN
	  BIN%			; Input the location

	  MOVE T1,P2		; Get the output JFN
	  MOVX T3,<NO%MAG!8>	; Output it in octal
	  NOUT%			; Output the contents
	   HALT .

	  HRROI T2,[ASCIZ |
|]
	  SETZ T3,		; Terminate on null
	  SOUT%			; Finish off the line

	  CAIGE P3,LSLEN-1	; Did we do it all?
	   AOJA P3,TOP.		;  Nope, loop over the entire mess
	ENDDO.

	MOVE T1,P2		; Get the output JFN
	CLOSF%			; Close the file
	 ERJMP BADFIL
	MOVE T1,P1		; Get the input JFN
	CLOSF%			; Close input file
	 ERJMP BADFIL
	RET
	SUBTTL INSSYM - Insert a symbol into the symbol table

INSSYM:	SAVEAC <P1,P2>
	DMOVE P1,T1		; Save value and pointer

	SKIPL T1		; Less than 0?
	CAXLE T1,LSLEN		; Or larger than largest?
	 HALT .

	ADDI T3,4+5		; Round up to full word plus room for fwd ptr
	IDIVI T3,5		; Divide by chars/word
	MOVE T1,T3		; Setup length for GETMEM
	CALL GETMEM		; Get some memory
	 HALT .
	MOVE P2,T1		; Save address
	SETZM (P2)		; Clear forward ptr
	MOVEI T1,-1(T3)		; Get length
	MOVEI T3,1(P2)		; Point to space for symbol name
	EXTEND T1,[XBLT]	; Copy the data
	
	SKIPE SYMTAB(P1)	; Is there a symbol there already?
	 JRST INSSY1		;  Yes, loop down the chain
	MOVEM P2,SYMTAB(P1)	; Nope, install the new symbol
	RET

INSSY1:	HRROI T1,[ASCIZ |
? Symbol conflict |]
	PSOUT%
	HRROI T1,1(P2)
	PSOUT%
	MOVX T1,"="
	PBOUT%
	MOVX T1,.PRIOU
	MOVE T2,P1
	MOVX T3,8
	NOUT%
	 HALT .
	HRROI T1,[ASCIZ |
|]
	PSOUT%

; Now find the end of the symbol chain for this value and add this symbol
; to the list.

	XMOVEI T1,SYMTAB(P1)	; Get the first entry
CNFLOP:	MOVE T1,(T1)		; Get next entry
	SKIPE (T1)		; Did we find the end?
	 JRST CNFLOP		;  No, try again
	MOVEM P2,(T1)		; Install this item
	RET

SYMTAB:	BLOCK	LSLEN		; Symbol table
	SUBTTL LOKSYM - Lookup a value in the symbol table

LOKSYM:	MOVE T1,SYMTAB(T1)	; Fetch the symbol name
	JUMPE T1,RTN		; Non-skip if no name
	RETSKP			; Skip if name exists
	SUBTTL REDSYM - Read a symbol

; Call:	MOVX T1,BP to place to hold symbol
;	CALL REDSYM
;	 <+1 Symbol terminated prematurely>
;	<+2 Symbol read in, length (including 0 terminator) in T1>
;

REDSYM:	MOVE T2,T1			; Get symbol pointer in a safe place
	SETZ T3,			; Initial length is 0
REDSY1:	CALL REDCHR			; Read a character
	 RET				;  EOF?
	CAIE T1,177			; Delete?
	TRNN T1,140			; Printable character?
	 RET				;  Nope, fail
	CAIN T1,"="			; Did we get the proper terminator?
	 SETZ T1,			;  Yes, turn it into a null
	IDPB T1,T2			; Stuff the character
	ADDI T3,1			; Increment the length
	JUMPN T1,REDSY1			; And loop over the whole mess

	MOVE T1,T3			; Get the length
	RETSKP				; All done!
	SUBTTL SRCSTR - Search for a string

; Call:	MOVX T1,byte pointer to ASCIZ string
;	CALL SRCSTR
;	 <+1 String not found>
;	<+2 String found>

SRCSTR:	MOVE T2,T1		; Put BP into a safe place
SRCST1:	MOVE T4,T2		; Get fresh copy of the BP
SRCST2:	ILDB T3,T4		; Get a char from the string
	JUMPE T3,RSKP		; If we ran out, we succeeded
	CALL REDCHR		; Read a character from the file
	 RET			;  Ran out of file, fail
	CAIE T1,(T3)		; Character match?
	 JRST SRCST1		;  Nope, reset string and try again
	JRST SRCST2		; Yes, keep on going
	SUBTTL KNIATO - Automatic program start address

KNIATO:	RESET%			; Reset the universe (just in case)
	MOVE P,STKAC		; Setup stack pointer

	SETOM ATOFLG		; Indicate we are in automatic mode
	CALL SRVALL		; Call the main service loop
	 NOP
	SETZM ATOFLG		; No longer in automagic mode
	HALTF%			; All done
	JRST KNIATO		; Just in case
	SUBTTL SRVALL - Main service loop

; Loop through all known KLNI's dumping or reloading them according to their
; channel state.

; Execute the following code once for each channel

SRVALL:	SAVEAC P1
	CALL ALLCHN

	CALL GETCHS		; Get the channel's state
	 DIE CGS,<Can't get KLNI status>
	MOVE P1,STATAB-.EISVG(T1) ; Fetch the bits for this state

	TXNE P1,IGN		; Ignore?
	 RET			;  Yes, just return

	TXNE P1,DMP		; Do a dump?
	 CALL DODUMP		;  Yes, go do a dump

	TXNE P1,RLD		; Reload?
	 CALL DORELD		;  Yes, go do a reload

	MOVX T1,.EISRN		; Get the new state
	CALL SETCHS		; Start the KLNI
	 DIE CSS,<Can't set KLNI status>

	RET

; This table determines the actions KNILDR will take when the KLNI is in
; various states.

	IGN==1B0	; Ignore this state and do nothing to the KLNI
	RLD==1B1	; Reload the KLNI
	DMP==1B2	; Dump the KLNI

STATAB:	IGN		; .EISVG - Virgin - has never run before
	RLD		; .EISRE - Reload - reload requested
	IGN		; .EISCR - Can't Reload - reload request timed out
	IGN		; .EISIN - Init - waiting for response to first command
	IGN		; .EISRN - Run - channel is running and can accept commands
	DMP		; .EISDP - Dump - a dump has been requested
	DMP!RLD		; .EISDR - Dump & Reload - dump followed by a reload request
	IGN		; .EISBK - Broken - channel cannot be initialized
	IGN		; .EISOF - Off - channel is off
	SUBTTL DODUMP - Take a dump of a KLNI

; This routine will dump the contents of a KLNI into a file.  The file
; will have the name KLNI-<channel #>.DUMP.
;
; Call:	MOVX T1,new-channel-state-indicator
;	MOVX CHN,channel #
;	CALL DODUMP
;	<Return +1 Always>
;

DODUMP:	DPB CHN,ADFCHN		; Put the channel # into the filename
	MOVX T1,GJ%SHT+GJ%FOU	; Open the file for output
	HRROI T2,ADFFIL		; Get pointer to default filespec
	GTJFN%			; Get the JFN
	 DIE (GFD,GTJFN failure during a dump)
	MOVEM T1,JFN		; Put the JFN in a safe place

;Here from the DUMP command

DODUM1:	CALL .TYMPR		; Type message prefix
	HRROI T1,[ASCIZ |Dumping Ethernet channel |]
	PSOUT%
	MOVE T1,CHN		; Get the channel #
	CALL .TYOCT
	HRROI T1,[ASCIZ |]

|]
	PSOUT%
;**;[10] Remove 2 lines at DODUM1:+9L	MDR	23-APR-87

	MOVE T1,JFN		; Get the JFN
	MOVE T2,[FLD(^D36,OF%BSZ)+OF%WR] ; Open the file for write, PMAPS
	OPENF%			; Open the file
	 ERJMP BADFIL

	MOVX T1,WRDBLN		; Get the length of the buffer
	MOVEM T1,BUFCNT		; Save it
	MOVE T1,[POINT 36,CHRBUF] ; Get pointer to buffer
	MOVEM T1,BUFPTR		; Save it

	MOVX T1,.EISDP		; Set state to DUMP
	CALL SETCHS		; Tell the monitor about it
	 ERROR <Can't put channel into DUMP state>

	CALL SETDEV		; Setup the I/O instructions

	USRIO%			; Try to get User I/O
	 ERROR Can't get user I/O

	XCT DEVCNI		; Read the status bits
	TXNE T1,CO.MRN		; Is the KLNI still running?
	 ERROR <Can't dump KLNI, microcode is still running>

	CALL RDLAR		; Read the current PC
	 HALT .
	MOVEM T1,SAVUPC		; Save the micro PC

	MOVX T1,CI.EPE		; Don't blow up the word, just clear the
				;  nasty conditions.
	XCT DEVCNO		; Tell the hardware about it

	SAVEAC <P1>

	CALL INICRM		; Initialize the CRAM for dumping
	SUBTTL Dump the Condition Codes

	SETZ P1,		; Reset the condition code number
CCLOP:	MOVE T1,P1		; Get the condition #
	CALL RDCCOD		; Read the code
	MOVEM T1,CCSAVE(P1)	; Save the condition code
	CAIGE P1,17		; Did we do them all?
	 AOJA P1,CCLOP		;  Loop over all condition codes
	SUBTTL	Dump the 2901 registers

	HRLZI P1,-21		; Get AOBJN pointer for 2901 registers
L2901:	HRRZ T1,P1		; Get current register #
	CALL RDAC		; Read the 2901 reg
	MOVEM T1,ACS(P1)	; Save the register

	AOBJN P1,L2901		; And do all registers
	SUBTTL	Dump the Local Store

; Note that these routines destroy the contents of 2901 register 0.

	HRLZI P1,-LSLEN		; Set up AOBJN pointer for local store
DMPLOP:	SETZ T1,		; Clear DIAG SEL EBUF...
	XCT DEVCNO		; Tell the hardware about it
	MOVX T1,DO.LAD!DO.MSB+FLD(LSUCOD,MICPC)	; Point to MSB's
	XCT DEVDTO		; Set the RAR
	SETZ T3,		; Clear number of ones

	HRRZ T1,P1		; Get the local store address
	CALL PARITY		; Setup MWPAR to generate correct parity
	XOR T1,DMPCRM+LSUCOD*2	; Get MSB's possibly complimenting MWPAR

	STOR P1,MWMGC,+T1	; Setup the magic number field
	XCT DEVDTO		; Write loc 0 MSB's

	MOVX T1,LSUCOD		; Get the starting PC
	CALL STUCOD		; Start the microcode
	 DIE(EBS,Error bits set during dump)
	CALL RDEBUF		; Read the EBUF into T1
	 HALT .

	CALL PUTWRD		; Save the word
	AOBJN P1,DMPLOP		; And try again
	SUBTTL	Copy the AC's from the 2901 into the file

	HRLZI P1,-21		; Get AOBJN ptr to ACs
CPYLOP:	MOVE T1,ACS(P1)		; Get an AC
	CALL PUTWRD		; Write it to the file
	AOBJN P1,CPYLOP		; Loop over all AC's
	SUBTTL	Dump Used Buffer List

DMPUBL:	MOVX T1,11		; Disable link control reg
	MOVX T2,377		; Disable all bits
	CALL WRPLI		; Disable link control
	MOVX T1,1		; Enable link control reg
	MOVX T2,64		; 512*32 memory + Enable Link + Int. loopback
	CALL WRPLI		; Setup memory config + internal loopback

	MOVX T1,6		; Transmit action reg
	MOVX T2,1		; Reset transmit buffer address
	CALL WRPLI		; Point to start of xmit buffer

	MOVX T1,3		; Write transmit buffer reg
	MOVX T2,1		; Use a multicast address
	CALL WRPLI		; Send to multicast so that we receive our
				;  own transmissions

	MOVX P1,200		; Write 200 bytes
BLDXMB:	MOVX T1,3		; Write xmit buffer reg
	MOVE T2,P1		; Use the current count
	CALL WRPLI		; Put in into the xmit buffer
	SOJG P1,BLDXMB		; Write 200 bytes into xmit buffer
	MOVX T1,6		; Transmit action reg
	MOVX T2,3		; Write transmit end of frame
	CALL WRPLI		; Terminate the buffer

	MOVX P1,^D33		; Transmit 32 times + 1 for good luck
SNDXMB:	MOVX T1,6		; Transmit action reg
	MOVX T2,0		; Transmit frame
	CALL WRPLI		; Transmit the frame
	MOVX T1,13		; Read xmit status
	CALL RDPLI		; Read the status
	 HALT .
	SKIPE T1		; Any problems?
	 JRST [TRC T1,3
		TRNN T1,374	; Any bad bits?
		TRNN T1,3
		TRNA
		 JRST FUX
		AOS FOO#
		JRST SNDXMB]
FUX:	SOJG P1,SNDXMB		; Use up the free buffer list

	MOVX P1,^D32		; Read the entire used buffer list
REDUBL:	MOVX T1,15		; Read used buffer list
	CALL RDPLI		; Read a used buffer
	 HALT .
	CALL PUTWRD		; Write the entry into the file
	SOJG P1,REDUBL		; Loop over all buffers

	MOVX T1,11		; Disable link control reg
	MOVX T2,377		; Disable everything
	CALL WRPLI		; Tell the hardware about it
	SUBTTL Dump 2910 Stack

	MOVEI P1,5		; Number of time to pop the stack
STKLOP:	CALL RDSTAK		; Read the stack
	CALL PUTWRD		; Write it out to the file
	SOJG P1,STKLOP		; Loop over the whole stack
	SUBTTL Copy the dumped condition codes into the file

	HRLZI P1,-20		; Get AOBJN pointer to cond codes
CCPYLP:	MOVE T1,CCSAVE(P1)	; Get a cond code
	CALL PUTWRD		; Write it out
	AOBJN P1,CCPYLP		; Loop over the whole mess
	SUBTTL Put the micro PC into the file

	MOVE T1,SAVUPC		; Get the saved PC
	CALL PUTWRD		; Write it out
	SUBTTL Copy the PCB and the PS block into the dump file

	MOVE T1,[SQUOZE 0,PCBSTG] ; Start address of PCB
	MOVE T2,[SQUOZE 0,PB.LEN] ; Length of PCB
	CALL CPYMON		; Copy the PCB into the dump file
	 JRST DMPEND		;  Quit gracefully

	MOVE T1,[SQUOZE 0,PRTSTG] ; Start address of port variables
	MOVE T2,[SQUOZE 0,PS.LEN] ; Length of block
	CALL CPYMON		; Copy the variables into the dump file
	 JRST DMPEND		;  Quit gracefully
; All done with dumping, restore the CRAM locs we used

DMPEND:	CALL RESCRM

; All done with the file, flush the output buffer and close the file.

	SOS BUFCNT		; Correct for FLUSHO fencepost
	CALL FLUSHO		; Flush the output buffer
	MOVE T1,JFN		; Get the JFN
	CLOSF%			; Close the file
	 ERJMP .+1

	RET
	SUBTTL DORELD - Reload a KLNI's microcode

; This routine will reload a KLNI's microcode.  The microcode comes from
; a table built into the program.  The contents of the table may be altered
; by a command given by a user.
;
; Call:	MOVX T1,new-channel-state-indicator
;	MOVX CHN,channel #
;	CALL DORELD
;	<Return +1 Always>
;

DORELD:	SKIPN MICVAL		; Is the microcode valid?
	 ERROR Microcode is not valid

	CALL .TYMPR		; Type message prefix
	HRROI T1,[ASCIZ |Loading microcode version |]
	PSOUT%
	MOVX T1,CRAM		; Get address of ucode
	CALL .TYMVR		; Type out it's version #
	HRROI T1,[ASCIZ | into Ethernet channel |]
	PSOUT%
	MOVE T1,CHN		; Get the channel #
	CALL .TYOCT
	HRROI T1,[ASCIZ |]

|]
	PSOUT%
;**;[10] Remove 2 lines at DORELD:+16L	MDR	23-APR-87

	CALL SETDEV		; Setup the I/O instructions

	USRIO%			; Try to get User I/O
	 ERROR Can't get user I/O

	MOVX T1,.EISRE		; Set state to reload
	CALL SETCHS		; Set the channel's state
	 ERROR <Can't stop the channel>

	XCT DEVCNI		; Read the status bits
	TXNE T1,CO.MRN		; Is the KLNI still running?
	 ERROR <Can't reload KLNI, microcode still running>

	MOVX T1,CO.CPT		; Clear the port
	XCT DEVCNO		; Tell the hardware about it

	MOVX T1,DO.LAD		; Setup current CRAM address reg
	MOVE T2,DEVBKO		; Get the BLKO
	IORI T2,T3		; Setup addr of IOWD
	MOVE T3,[IOWD CRMBLN,CRAM] ; Setup IOWD pointer to ucode

RELLOP:	XCT DEVDTO		; Set the CRAM address in the KLIPA
	ADDX T1,1B13		; Point to the next micro 1/2 word
	XCT T2			; Load in 1/2 a micro word
	 JRSTF @[RTN]		;  All done, return & clear user I/O
	JRST RELLOP		; Loop till done with load
	SUBTTL GETCHS - Get the status of a channel

; Read the "substate" of a channel.
;
; Call:	MOVX CHN,channel #
;	CALL GETCHS
;	 <Error return>
;	<Good return, T1/ channel state>
;

GETCHS:	MOVX T1,.EIBMX			; Get length of arg block
	STOR T1,EILEN,+NIBLOK		; Save it
	MOVX T1,.EIRCI			; Function is Read Channel Info
	STOR T1,EIFCN,+NIBLOK		; Save it
	STOR CHN,EICHN,+NIBLOK		; Install the channel #
	XMOVEI T1,NIBLOK		; Get arg block address
	NI%				; Get the status from the monitor
	 ERJMP [RET]			;  Non-ex channel??
	LOAD T1,EISST,+NIBLOK		; Get the substate
	RETSKP				; And return success

SETCHS:	STOR T1,EISST,+NIBLOK		; Save the new state
	MOVX T1,.EIBMX			; Get length of arg block
	STOR T1,EILEN,+NIBLOK		; Save it
	MOVX T1,.EISCS			; Function is Set Channel State
	STOR T1,EIFCN,+NIBLOK		; Save it
	STOR CHN,EICHN,+NIBLOK		; Install the channel #
	XMOVEI T1,NIBLOK		; Get arg block address
	NI%				; Get the status from the monitor
	 ERJMP [RET]			;  Non-ex channel??
	RETSKP				; And return success
	SUBTTL SETDSP - Set KLNI state according to state disposition

; This routine will set the KLNI's state according to the state disposition
; contained in T1.
;
; Call:	MOVX T1,state_disposition
;	MOVX T2,old_state
;	CALL SETDSP
;	<Return +1 always>

SETDSP:	XCT SETDS1-.KYHLT(T1)		; Get the new state
	CALL SETCHS			; Get the new state
	 TRN
	RET

SETDS1:	MOVX T1,.EISOF			; New state is off
	MOVE T1,T2			; Preserve the state
	MOVX T1,.EISRN			; New state is run
	SUBTTL ALLCHN - Co-routine to loop through all channels

ALLCHN:	PUSH P,CHN
	MOVX CHN,0			; Fudge up channel 0 for now
	CALL @-1(P)			; Call back the caller
	NOP
	POP P,CHN			; Restore CHN
	POP P,(P)			; Pop the caller off the stack
	RET				; All done
	SUBTTL SETDEV - Setup I/O instructions

; This routine will setup the locations DEVxyz to contain an I/O instruction
; for the correct device.
;
; Call:	MOVX CHN,channel #
;	CALL SETDEV
;	<Return +1 Always>
;

SETDEV:	CALL GETION			; Get the device code
	 DIE CGF,<Call to GETION failed>

	STOR T1,DVCOD,DEVCNI		; CONI dev,T1
	STOR T1,DVCOD,DEVCNO		; CONO dev,(T1)
	STOR T1,DVCOD,DEVDTI		; DATAI dev,T1
	STOR T1,DVCOD,DEVDTO		; DATAO dev,T1
	STOR T1,DVCOD,DEVBKO		; BLKO dev,0
	RET
	SUBTTL GETION - Get I/O device # for a given channel #

GETION:	MOVX T1,564_-2			; Fudge this up for now
	RETSKP
	SUBTTL REDHLF - Read half of a microword

REDHLF:	MOVEI T3,^D10			; Just read 10 digits
	SETZ T2,			; Clear receiving buffer
REDHL2:	CALL REDCHR			; Read the next character
	 RET				;  EOF??
	CAIL T1,"0"			; Is it
	 CAILE T1,"7"			;  numeric?
	  RET				;   Nope, quit now
	SUBI T1,"0"			; Turn character into a number
	LSH T2,3			; Make room for the new digit
	IOR T2,T1			; Install the new digit
	SOJG T3,REDHL2			; Loop for rest of digits
	MOVE T1,T2			; Get number into the right place
	RETSKP				; All done
	SUBTTL REDNUM - Read an octal number from the file

REDNUM:	SETZ T2,			; Clear receiving buffer
REDNU2:	CALL REDCHR			; Read the next character
	 RET				;  EOF???
	CAIL T1,"0"			; Is it
	 CAILE T1,"7"			;  numeric?
	  JRST REDNU1			;   Nope, terminate
	SUBI T1,"0"			; Turn character into a number
	LSH T2,3			; Make room for the new digit
	IOR T2,T1			; Install the new digit
	JRST REDNU2			; And do it all over again

REDNU1:	EXCH T1,T2			; T1 gets number, T2 gets terminator
	RETSKP				; Return success
	SUBTTL REDCHR - Low level file I/O

REDCHR:	SOSGE BUFCNT			; Anything left in the buffer?
	 JRST REDCH1			;  Nope, try to get another buffer
	ILDB T1,BUFPTR			; Get a character from the buffer
	RETSKP				; And return

REDCH1:	PUSH P,T2			; Preserve T's
	PUSH P,T3
	MOVE T1,JFN			; Get JFN
	MOVE T2,[POINT 7,CHRBUF]	; Get pointer to character buffer
	MOVEM T2,BUFPTR			; Save it
	MOVX T3,CHRBLN			; Get length of character buffer
	SIN%				; Read the data
	SUBI T3,CHRBLN			; Compute negative length of data
	MOVNM T3,BUFCNT			; Save the buffer length
	POP P,T3
	POP P,T2
	SKIPN BUFCNT			; Did we read anything this time?
	 RET				;  Nope, give non-skip return
	JRST REDCHR			; And fetch the next character

PUTWD1:	CALL FLUSHO			; Flush the output buffer
PUTWRD:	SOSGE BUFCNT			; Any room left in the buffer?
	 JRST PUTWD1			;  Nope, write it out
	IDPB T1,BUFPTR			; Yes, deposit the byte
	RET				; All done

FLUSHO:	SAVEAC <T1,T2,T3>		; Preserve all AC's
	MOVE T1,JFN			; Get JFN
	MOVE T2,[POINT 36,CHRBUF]	; Get pointer to buffer
	MOVEM T2,BUFPTR			; Save it
	AOS T3,BUFCNT			; Get # of words left in buffer
	SUBI T3,WRDBLN			; Compute # of words written
	SOUT%				; Write the data
	MOVX T1,WRDBLN			; Get the length of the buffer
	MOVEM T1,BUFCNT			; Save the buffer length
	RET
	SUBTTL DOCMND - Do a COMND% JSYS

DOCMND:	MOVEI T1,CSB			; Get address of command state block
	COMND%				; Do the command
	 ERJMP [DIE CMF,<COMND% JSYS FAILED>] ;  Error, complain
	TXNN T1,CM%NOP			; No parse?
	 RET				;  Nope, return to the user

DOCMN1:	CALL .TYJSE			; Type out a JSYS error
	JRST COMLOP			; Abort the command
	SUBTTL Error recovery

; Here to print an error message and terminate a command

ERRTRM:	CALL .TYERR			; Type out the error message
	SKIPN ATOFLG			; Are we in auto mode?
	 JRST COMLOP			;  No, just abort the command
	RET				; Yes, return failure

; Here to type out a JSYS error

.TYJSE:	HRROI T1,ERRBUF			; Point to error buffer
	HRLI T2,.FHSLF			; Use our process handle
	MOVX T3,ERRBLN
	ERSTR%				; Print out the error
	 JFCL
	 JFCL
	HRROI T1,ERRBUF			; Restore pointer to error buffer

; Here to type out a standard error message

.TYERR:	PUSH P,T1			; Preserve error message
	CALL .TYEPR			; Type error prpefix
	POP P,T1			; Restore the error message
	PSOUT%				; Type out the message
	HRROI T1,[ASCIZ |

|]
	PSOUT%
	RET

.TYEPR:	HRROI T1,[ASCIZ | KNILDR: |]
	ESOUT%				; Type out the error prefix
	RET

.TYMPR:	HRROI T1,[ASCIZ |[KNILDR: |]	; Type message prefix
	PSOUT%
	RET

; Type ucode version

.TYMVR:	SAVEAC P1
	MOVE P1,T1		; Save CRAM address
	LOAD T1,MWMAJ,(P1)	; Get the major version number
	CALL .TYOCT		; Type it out
	LOAD T2,MWMIN,(P1)	; Get the minor version number
	JUMPE T2,TYMVR1		; Skip this if its 0
	MOVX T1,"."		; Get a .
	PBOUT%			; Type out a .
	MOVE T1,T2		; Get the minor version #
	CALL .TYOCT		; Type out the minor version #

TYMVR1:	LOAD T2,MWEDT,(P1)	; Get the edit #
	JUMPE T2,RTN		; Skip this if 0
	MOVX T1,"("		; Get a paren
	PBOUT%			; Type it out
	MOVE T1,T2		; Get edit #
	CALL .TYOCT		; Type it out
	MOVX T1,")"		; Get the other paren
	PBOUT%			; Type out the paren
RTN:	RET

; Here to do a .CMCFM function

CNFIRM:	SAVEAC <T1,T2,T3,T4>		; Preserve all AC's
	MOVEI T2,[FLDDB. (.CMCFM)]	; Parse a <CRLF>
	CALLRET DOCMND			; Do the COMND% JSYS
	SUBTTL .TYxxx

.TYOCT:	SKIPA T3,[8]		; Type out an octal number
.TYDEC:	MOVX T3,^D10		; Use radix 10
	MOVE T2,T1		; Get number into the right AC
	MOVX T1,.PRIOU		; Get primary output designator
	NOUT%			; Type out the number
	 ERJMP [DIE NOF,<NOUT FAILURE>]
	RET
	SUBTTL RDCRAM and WRCRAM

;ROUTINE TO READ A CRAM LOCATION
;CALL:	MOVx T1,cram-address
;	CALL RDCRAM
;	 <+1 COULDN'T READ CRAM BECAUSE UCODE WAS RUNNING>
;	<+2 T1 6-35 CONTAINS CRAM MSB'S, T2 6-35 CONTAINS CRAM LSB'S>

RDCRAM:	MOVE T4,T1		; Save the PC in a safe place
	XCT DEVCNI		; Read the port's status
	TXNE T1,CO.MRN		; Is the port running?
	 RET			;  Yes, quit now
	SETZ T1,		; Get new status bits
	XCT DEVCNO		; Make sure CO.LAR is clear
	STOR T4,MICPC,T1	; Put the PC in the right place
	TXO T1,DO.LAD!DO.MSB	; Set up to read the MSB's
	XCT DEVDTO		; Tell the hardware about it
	XCT DEVDTI		; Get contents of high order part of CRAM
	TXZ T1,77B5		; Clear out 0-5 since they are meaningless
	MOVE T2,T1		; Put MSB's in a safe place
	SETZ T1,		; Clear PC
	STOR T4,MICPC,T1	; Put the PC into the right place
	TXO T1,DO.LAD		; Setup to load a new address
	XCT DEVDTO		; Set the new address
	XCT DEVDTI		; Get contents of low order part of CRAM
	TXZ T1,77B5		; Clear out 0-5 since they are meaningless
	EXCH T1,T2		; T1 gets MSB's, T2 gets LSB's
	RETSKP

;ROUTINE TO WRITE A CRAM LOCATION
;CALL:	MOVx	T1,cram-address
;	MOVx	T2,cram-msbs
;	MOVx	T3,cram-lsbs
;	CALL	WRCRAM
;	 <+1 COULDN'T WRITE CRAM BECAUSE UCODE WAS RUNNING>
;	<+2 Successful>

WRCRAM:	MOVE T4,T1		; Put PC into the right place
	XCT DEVCNI		; Get the status bits
	TXNE T1,CO.MRN		; Is the port running?
	 RET			;  Yes, quit now
	SETZ T1,		; Get new status
	XCT DEVCNO		; Clear CO.LAR
	STOR T4,MICPC,T1	; Put the PC in the right place
	TXO T1,DO.LAD!DO.MSB	; Set up to write the MSB's
	XCT DEVDTO		; Tell the hardware about it
	TXZ T2,77B5		; Clear out 0-5 since they are meaningless
	MOVE T1,T2		; Get MSB's into T1
	XCT DEVDTO		; Write contents of high order part of CRAM
	SETZ T1,		; Clear PC
	STOR T4,MICPC,T1	; Get PC again
	TXO T1,DO.LAD		; Set up to write the LSB's
	XCT DEVDTO		; Tell the hardware about it
	TXZ T3,77B5		; Clear out 0-5 since they are meaningless
	MOVE T1,T3		; Get LSB's into T1
	XCT DEVDTO		; Write contents of low order part of CRAM
	RETSKP
	SUBTTL INICRM - Load up microprograms for dumping things

INICRM:	SAVEAC P1

	SETZ P1,		; Reset location counter
INILOP:	MOVE T1,P1		; Get current location
	CALL RDCRAM		; Read the CRAM
	 HALT .
	MOVE T3,P1		; Get the loc
	LSH T3,1		; *2
	DMOVEM T1,SAVCRM(T3)	; Save the current CRAM contents

	DMOVE T2,DMPCRM(T3)	; Get the ucode for this loc
	MOVE T1,P1		; Get the loc into T1
	CALL WRCRAM		; Write it into the KLNI
	 HALT .
	CAIGE P1,DMPCLN-1	; Did we do 'em all?
	 AOJA P1,INILOP		;  Nope, keep going
	RET

; Here to restore the CRAM to it's original beauty

RESCRM:	SETZ P1,		; Reset location counter
RESLOP:	MOVE T2,P1		; Get the current location
	LSH T2,1		; Create a SAVCRM offset
	DMOVE T2,SAVCRM(T2)	; Get the saved CRAM
	MOVE T1,P1		; Get the location again
	CALL WRCRAM		; Restore the CRAM
	 HALT .
	CAIGE P1,DMPCLN-1	; Did we restore everything?
	 AOJA P1,RESLOP		;  Nope, keep going
	RET			; All done

DMPCRM:

; Program for dumping local store

LSUCOD==<.-DMPCRM>/2		; Starting PC

	XWD	1,400073	; 0
	XWD	2000,220040
	XWD	1,600443	; 1
	XWD	1000,5040

; Program for dumping 2901 AC's 0-17

ACUCOD==<.-DMPCRM>/2		; Starting PC

	XWD	2,600443	; 2
	XWD	1000,5040

; Program for dumping 2901 AC Q

QUCOD==<.-DMPCRM>/2		; Starting PC

	XWD	3,200420	; 3
	XWD	1000,5040

; Program for writing data into the PLI

WPUCOD==<.-DMPCRM>/2		; Starting PC

	XWD	5,73		; 4
	XWD	2000,240040
	XWD	0,604043	; 5
	XWD	1000,2340
	XWD	0,1400		; 6
	XWD	1000,1340
	XWD	7,0		; 7
	XWD	1000,40

; Routine for reading data from the PLI

RPUCOD==<.-DMPCRM>/2		; Starting PC

	XWD	11,402000	; 10
	XWD	1000,2040
	XWD	0,1200		; 11
	XWD	1000,1340
	XWD	0,430073	; 12
	XWD	2000,2340
	XWD	0,200443	; 13
	XWD	1000,5340
	XWD	16,400000	; 14
	XWD	1400,150060
	XWD	15,0		; 15
	XWD	1000,40
	XWD	16,0		; 16
	XWD	1000,40

; Program for reading and popping the top location off the 2910 stack

SKUCOD==<.-DMPCRM>/2		; Starting PC

	XWD	17,0		; 17
	XWD	1000,240

CCUCOD==<.-DMPCRM>/2		; Starting PC

	XWD	21,400000	; 20
	XWD	1000,40
	XWD	23,0		; 21
	XWD	1400,60
	XWD	22,400000	; 22
	XWD	1000,40
	XWD	23,0		; 23
	XWD	1000,40

RDFCOD==<.-DMPCRM>/2		; Start address

	XWD	24,74		; 24
	XWD	1400,120320

	DMPCLN==<.-DMPCRM>/2	; # of uwords of CRAM for dumping

SAVCRM:	BLOCK	DMPCLN*2	; Reserve space for holding old CRAM
	SUBTTL PARITY - Compute Parity

; Compute the parity of the number in T1.  Return with T1 containing MWPAR=1
; if parity would be even.  Otherwise, it will be 0.
;
; Call:	MOVX T1,number
;	CALL PARITY
;	<Return +1 always, T1/MWPAR or 0>

PARITY:	SETZ T4,		; Clear the counter
PARIT1:	MOVN T2,T1		; Negate the number
	TDZE T1,T2		; Did we find a 1?
	 AOJA T4,PARIT1		;  Yes, keep on truckin

	SETZ T1,		; Assume proper parity
	TRNE T4,1		; Even parity?
	 MOVX T1,MWPAR		;  Nope, odd must have parity bit
	RET
	SUBTTL STUCOD - Start Microcode at the specified address

; Call:	MOVX T1,micro_PC
;	CALL STUCOD
;	 <Return +1, error>
;	<Return +2 success>

SINCYC:	SKIPA T3,[CO.MRN!CO.SSC] ; Here for single cycle operation
STUCOD:	 MOVX T3,CO.MRN		;  Here for normal start
	MOVX T2,DO.LAD		; Get ready to load the RAR
	STOR T1,MICPC,+T2	; Insert the PC into the DATAO word
	MOVX T1,CI.EPE		; Clear all the nasty bits
	XCT DEVCNO		; Tell the hardware about it

	MOVE T1,T2		; Get the PC
	XCT DEVDTO		; Set the RAR

	MOVE T1,T3		; Get the run bit
	XCT DEVCNO		; Start the port

	SETZ T1,		; Get a 0
	XCT DEVCNO		; Stop the port

	XCT DEVCNI		; Read the status
	TXNE T1,CI.ERR		; Any errors?
	 RET			;  Yes, pass it upwards
	RETSKP			; Nope, return success
	SUBTTL RDLAR - Read the Latched Address Register

; Call:	CALL RDLAR
;	 <Return +1, error>
;	<Return +2 success, T1/ micro PC>

RDLAR:	XCT DEVCNI		; Read the CSR
	TXNE T1,CO.MRN		; Is it running?
	 RET			;  Yes, that's a no-no

	MOVX T1,CO.LAR		; Prepare to
	XCT DEVCNO		;  read the LAR

	XCT DEVDTI		; Read the LAR
	LOAD T1,MICPC,+T1	; Fetch the micro PC
	RETSKP			; And return success
	SUBTTL RDEBUF - Read the EBUS Buffer

; Call:	CALL RDEBUF
;	 <Return +1, error>
;	<Return +2 success, T1/ data from EBUF>

RDEBUF:	XCT DEVCNI		; Read the CSR
	TXNE T1,CO.MRN		; Is it running?
	 RET			;  Yes, that's a no-no

	MOVX T1,CO.SEB		; Prepare to
	XCT DEVCNO		;  read the EBUF

	XCT DEVDTI		; Read the EBUF into T1
	RETSKP			; And return success
	SUBTTL WRPLI - Write PLI

; This routine will write the data in T2 into the PLI register indicated by T1.
;
; Call:	MOVX T1,pli_reg
;	MOVX T2,data
;	CALL WRPLI
;	<+1 Return Always>
;

WRPLI:	SAVEAC <P1,P2>
	DMOVE P1,T1		; Save PLI # and data

	MOVE T1,P1		; Get the pli # again
	CALL PARITY		; Get proper value for MWPAR

	DMOVE T2,DMPCRM+<WPUCOD+2>*2 ; Get word we have to modify
	DPB P1,[POINT 6,T2,25]	; Insert PLI # into ucode
	TDC T2,T1		; Fix the parity
	MOVX T1,WPUCOD+2	; Get address to modify
	CALL WRCRAM		; Write the CRAM
	 HALT .

	MOVE T1,P2		; Get the data byte
	CALL PARITY		; Get parity bit

	DMOVE T2,DMPCRM+WPUCOD*2 ; Get word to stuff data into
	STOR P2,MWMGC,+T2	; Insert the data byte
	TDC T2,T1		; Complement the parity bit

	MOVX T1,WPUCOD		; Get address
	CALL WRCRAM		; Write the CRAM
	 HALT .

	MOVX T1,WPUCOD		; Get start address
	CALL STUCOD		; Start the microcode
	 HALT .

	RET			; All done
	SUBTTL RDPLI - Read PLI

; This routine will read the contents of the PLI register addressed by T1 into
; T2.
;
; Call:	MOVX T1,pli_reg
;	CALL RDPLI
;	 <+1 Return failure>
;	<+2 Return success>

RDPLI:	SAVEAC <P1,P2>
	MOVE P1,T1		; Remember the PLI register number

	MOVE T1,P1		; Get the PLI #
	CALL PARITY		; Setup T1 with MWPAR

	DMOVE T2,DMPCRM+<RPUCOD+1>*2 ; Get the uword
	DPB P1,[POINT 6,T2,25]	; Insert PLI # into ucode
	TDC T2,T1		; Complement the parity bit

	MOVX T1,RPUCOD+1	; Address 1
	CALL WRCRAM		; Write the CRAM
	 HALT .

	MOVX T1,RPUCOD		; Get the starting PC
	CALL STUCOD		; Start the microcode
	 HALT .

	CALL RDEBUF		; Read in the PLI data
	 HALT .
	ANDI T1,377		; Mask it down to 8 bits

	MOVE P1,T1		; Save the data for a moment
	CALL RDLAR		; Read the PC
	 HALT .
	CAIN T1,RPUCOD+6	; Did a parity error occur?
	 TXO P1,1B0		;  Yes, say so

	MOVE T1,P1		; Get the data
	RETSKP			; And return happily
	SUBTTL RDAC - Read a 2901 AC

; Read an AC from the 2901.  Specify AC # in T1 (Q=20).  Contents
; returned in T1.
;
; Call:	MOVX T1,ac#
;	CALL RDAC
;	<+1 Return Always, T1/ contents of AC>
;

RDAC:	SAVEAC P1
	MOVE P1,T1		; Save register # in a safer place

	CAIN T1,20		; Doing the Q register?
	IFSKP.			; Nope
	  CALL PARITY		; Get proper value for MWPAR

	  DMOVE T2,DMPCRM+ACUCOD*2 ; Get the little microroutine we need
	  TDC T2,T1		; Set the parity bit
	  STOR P1,MWPRA,+T2	; Install the register number

	  MOVX T1,ACUCOD	; Get PC of our little routine
	  CALL WRCRAM		; Install the microroutine
	   DIE(CD2,Can't load CRAM to dump 2901)
	  MOVX T1,ACUCOD	; Get the starting PC of the ucode
	ELSE.			; Dump the Q register
	  MOVX T1,QUCOD		; Get the starting PC
	ENDIF.

	CALL SINCYC		; Startup the port for a single cycle
	  DIE(R2E,Error reading 2901 register)

	CALL RDEBUF		; Read the result into T1
	 HALT .
	RET
	SUBTTL	RDSTAK - Read (and pop off) the top item on the 2910 stack

; Call:	CALL RDSTAK
;	<Return +1, Always with T1/ stack item>

RDSTAK:	MOVX T1,SKUCOD		; Get the start address
	CALL SINCYC		; Single cycle the port
	 HALT .
	CALL RDLAR		; Read the LAR
	 HALT .
	RET

REDTOP:	MOVX T1,RDFCOD		; Get the start address
	CALL SINCYC		; Step the port
	 HALT .
	CALL RDLAR		; Read the PC
	 HALT .
	RET
	SUBTTL	RDCCOD - Read Condition Codes

; Read the condition code specified by T1.  Return a sixbit code if the
; condition is set, 0 otherwise.
;
; Call:	MOVX T1,code#
;	CALL RDCCOD
;	<Return +1 Always, T1 indicates state of condition>
;

RDCCOD:	SAVEAC P1
	MOVE P1,T1			; Put condition # in a safe place
	CALL PARITY			; Generate MWPAR
	DMOVE T2,DMPCRM+<CCUCOD+1>*2	; Get the CRAM loc we have to modify
	TDC T2,T1			; Fix the parity bit
	STOR P1,MWSKP,+T2		; Install the condition code
	MOVX T1,CCUCOD+1		; Get the location for this uword
	CALL WRCRAM			; Install the word
	 HALT .
	MOVX T1,CCUCOD			; Get the starting address
	CALL STUCOD			; Start the microcode
	 HALT .
	CALL RDLAR			; Read the PC
	 HALT .
	MOVE T2,T1			; Put the PC in a safe place
	SETZ T1,			; Assume condition was not set
	CAIN T2,CCUCOD+3		; Is the condition enabled?
	 MOVE T1,CCTAB(P1)		;  Yes, say so
	RET				; All done

; Table of short abbreviations for condition codes.  Indexed by cond code.

	DEFINE X (name)<SIXBIT |name|>

CCTAB:	X CBAV		; 0 - CBus AVailable
	X GCSR		; 1 - Grant CSR
	X FEQ0		; 2 - last alu Function EQuals 0
	X CSRC		; 3 - CSR Changed
	X EBPE		; 4 - EBus Parity Error
	X RATN		; 5 - Receive ATteNtion
	X EOFF		; 6 - End of Frame Found
	X XATN		; 7 - Xmit ATteNtion
	X ERQS		; 10 - Ebus ReQueSt
	X IACT		; 11 - Interrupt ACTive
	X MSGN		; 12 - Msb/SiGN bit set
	X MVRP		; 13 - MoVeR Parity check
	X CBPE		; 14 - CBus Parity Error
	X PLPE		; 15 - PLi Parity Error
	X CHER		; 16 - CHannel ERror
	X CBLW		; 17 - CBus Last Word
	SUBTTL GETMEM - Allocate free space

; Call:	MOVX T1,# of words desired
;	CALL GETMEM
;	 <+1 No room>
;	<+2 Memory pointed at T1>
;

GETMEM:	ADD T1,.JBFF		; Compute new .JBFF
	EXCH T1,.JBFF		; Get old .JBFF, update .JBFF
	RETSKP			; Return success
	SUBTTL CPYMON - Copy a chunk of the monitor into the dump file

; Call this routine with the symbol representing the start address of a
; block in T1, and a symbol representing the length of the block in T2.
;
; Call:	MOVX T1,symbol1
;	MOVX T2,symbol2
;	CALL CPYMON
;	 Error return
;	Success return


CPYMON:	MOVE P1,T2		; Save length symbol for a moment
	CALL MONSYM		; Lookup the address
	 RET
	EXCH P1,T1		; Save location
	CALL MONSYM		; Lookup the length
	 RET

	MOVN T1,T1		; Negate the length
	HRL P1,T1		; Form an AOBJN pointer

PCBLOP:	HRRZ T1,P1		; Get address to read
	HRLI T1,1		; Just 1 word at a time
	MOVX T2,T1		; Read it into T1
	PEEK%			; Read the monitor
	 ERJMP RTN		;  Quit gracefully
	CALL PUTWRD		; Write out the word from the PCB
	AOBJN P1,PCBLOP		; Loop over the whole PCB
	RETSKP			; Return success
	SUBTTL MONSYM - Lookup a symbol in the monitor address space

MONSYM:	MOVE T2,T1		; Get symbol into the correct AC
	MOVX T1,.SNPSY		; Convert a symbol to a value
	MOVE T3,[SQUOZE 0,NISRV] ; In the module NISRV
	SNOOP%			; Snoop it out of the monitor
	 RET			;  Just quit if it fails
	MOVE T1,T2		; Get symbol into correct AC
	RETSKP			; Return success
	SUBTTL Storage

STKAC:	IOWD STKLEN,STACK		; AC for stack
STACK:	BLOCK 100
	STKLEN==.-STACK
ATOFLG:	BLOCK 1				; Non-zero means we are in auto mode

NIBLOK:	BLOCK .EIBMX			; Arg block for NI% jsys

; Command State Block for COMND% JSYS

CSB:	XWD 0,REPAR			; No flags,, reparse address
	XWD .PRIIN,.PRIOU		; Use primary I/O JFNs
	XWD -1,[ASCIZ |KNILDR>|]	; Setup prompt
	XWD -1,CMDBUF			; Pointer to command buffer
	XWD -1,CMDBUF			; Pointer to next field
	EXP CMDLEN			; Length of command buffer
	EXP 0				; No characters to parse yet
	XWD -1,ATMBUF			; Pointer to atom buffer
	EXP ATMLEN			; Length of atom buffer
	EXP GJBLK			; Address of GTJFN block

	CMDLEN==^D132			; Be generous with command length
CMDBUF:	BLOCK <CMDLEN+3>/4		; Command buffer

	ATMLEN==^D132			; Be generous with the atom buffer
ATMBUF:	BLOCK <ATMLEN+3>/4		; Atom buffer

GJBLK:	BLOCK 16			; GTJFN% block for COMND%

DEVCNI:	CONI 0,T1			; Prototype I/O instructions
DEVCNO:	CONO 0,(T1)
DEVDTI:	DATAI 0,T1
DEVDTO:	DATAO 0,T1
DEVBKO:	BLKO 0,0

MICVAL:	EXP 0				; Non-zero means microcode is valid
CRAM:	BLOCK CRMLEN*2			; Microcode goes here
	CRMBLN==.-CRAM			; Length of CRAM buffer

DEFINE XX (file)<
	..CNT==0
	IRPC file,<..CNT==..CNT+1
		   IFIDN <file><->,<STOPI>>
DEFCHN:	POINT 3,DEFFIL+..CNT/5,6+7*<..CNT-<<..CNT/5>*5>>
DEFFIL:	ASCIZ |file|
>

XX (KLNI-0.DUMP)			; Generate default filename

DEFINE XX (file)<
	..CNT==0
	IRPC file,<..CNT==..CNT+1
		   IFIDN <file><->,<STOPI>>
ADFCHN:	POINT 3,ADFFIL+..CNT/5,6+7*<..CNT-<<..CNT/5>*5>>
ADFFIL:	ASCIZ |file|
>

XX (SYSTEM:KLNI-0.DUMP)			; Generate automatic mode filename

ACS:	BLOCK 21			; Temp holding area for 2901 AC's
CCSAVE:	BLOCK 20			; Temp holding area for cond codes
SAVUPC:	BLOCK 1				; Temp holding area for the LAR
JFN:	BLOCK 1				; JFN goes here
LINNUM:	BLOCK 1				; Current line number of .ULD file
NUMMIC:	BLOCK 1				; Number of microwords loaded
BUFPTR:	BLOCK 1				; Byte pointer to file buffer goes here
BUFCNT:	EXP 0				; # of bytes remaining in buffer
CHRBUF:	BLOCK 1000			; File buffer
	WRDBLN==<.-CHRBUF>		; Length of the file buffer in words
	CHRBLN==WRDBLN*5		; Length of the file buffer in bytes

	ERRBLN==^D100			; Make error buffer 100 characters
ERRBUF:	BLOCK <ERRBLN+4>/5		; Buffer for holding JSYS error string

	END <3,,ENTVEC>