Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99p-bb - autcon.x22
There are 2 other files named autcon.x22 in the archive. Click here to see a list.
TITLE	AUTCON	AUTOCONFIGURATION AND COMMON DEVICE I/O ROUTINES - V151
SUBTTL	D. MASTROVITO/DPM	14-FEBRUARY-89

	SEARCH F,S,DEVPRM

	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1986,1988>

	XP VAUTCN,151

AUTCON::ENTRY	AUTCON
SUBTTL	AUTOCONFIGURATION -- AUTADN/AUTDDN - ALLOCATE/DEALLOCATE DEVICE NUMBER


;ALLOCATE THE NEXT AVAILABLE KONTROLLER OR DEVICE NUMBER FROM THE
;MONGEN'ED DEVICE TABLE
;CALL:	PUSHJ	P,AUTADN/AUTDDN
;
;ON RETURN, T1 HAS THE NEW NUMBER AND THE DATA BASE HAS BEEN UPDATED
;IF ALLOCATING.  T1 INDETERMINATE IF DEALLOCATING.

AUTDDN::TDZA	T1,T1		;DEALLOCATE
AUTADN::MOVEI	T1,1		;ALLOCATE
	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	MOVEI	P3,(T1)		;SAVE FLAG
	MOVE	P1,.CPCPN##	;START WITH OUR CPU NUMBER
	PUSHJ	P,ADNBPT	;FORM A BYTE POINTER
	LDB	T1,P1		;GET NUMBER RESERVED PER-CPU
IFE FTXMON,<AOS P1>		;ADVANCE POINTER
IFN FTXMON,<AOS P2>		;ADVANCE POINTER
	LDB	T2,P1		;GET ALLOCATED PER-CPU SO FAR
	XCT	ADNCNT(P3)	;COUNT UP OR DOWN
	DPB	T2,P1		;UPDATE COUNTER
	CAIL	T2,0		;KEEP IT A
	CAILE	T2,(T1)		; SMALL INTEGER
	SKIPA			;MUST ADJUST
	JRST	AUTAD2		;GO FINISH UP

;HERE WHEN A PER-CPU COUNTER OVERFLOWS
AUTAD1:	SYSPIF			;INTERLOCK
IFE FTXMON,<MOVE T2,(P1)>	;GET SYSTEM-WIDE COUNT
IFN FTXMON,<MOVE T2,(P2)>	;GET SYSTEM-WIDE COUNT
	LSH	T2,-1		;POSITION
	XCT	ADNCNT(P3)	;COUNT UP OR DOWN
	CAIL	T2,0		;KEEP IT A
	CAILE	T2,(T1)		; SMALL INTEGER
	ANDI	T2,37		;AVOID OVERFLOW OR UNDERFLOW
	DPB	T2,P1		;UPDATE PER-CPU COUNT
	SYSPIN			;RELEASE INTERLOCK
;HERE TO UPDATE THE HIGHEST NUMBER IN SYSTEM
AUTAD2:	JUMPE	P3,CPOPJ##	;RETURN IF DEALLOCATING
	MOVEI	P1,6		;SPECIAL BYTE
	PUSHJ	P,ADNBPT	;GENERATE A BYTE POINTER
IFE FTXMON,<AOS P1>		;ONLY CARE ABOUT SECOND ENTRY
IFN FTXMON,<AOS P2>		;ONLY CARE ABOUT SECOND ENTRY
	LDB	T1,P1		;GET HIGH VALUE SO FAR
	CAILE	T2,(T1)		;INCREMENTING
	DPB	T2,P1		;UPDATE
	AOS	NUMKON		;COUNT A CONTROLLER
	PUSH	P,T2		;SAVE COUNTER
	PUSHJ	P,ADNFIX	;FIXUP GLOBAL COUNTERS IF NECESSARY
	POP	P,T1		;GET RESULT
	SOJA	T1,CPOPJ##	;START COUNTING FROM ZERO, AND RETURN


;INSTRUCTIONS TO COUNT
ADNCNT:	SOS	T2		;COUNT DOWN
	AOS	T2		;COUNT UP
SUBTTL	AUTOCONFIGURATION -- AUTADP - GENERATE ALLOCATED DEVICE POINTER


;ROUTINE TO GENERATE THE ALLOCATED DEVICE BYTE POINTER TO THE
;PER-CPU COUNTERS
;CALL:	MOVE	T1, CPU NUMBER OR 6 FOR SYSTEM-WIDE COUNTER
;	PUSHJ	P,AUTADP
;
;ON RETURN, T1 & T2 CONTAIN A TWO-WORD BYTE POINTER FOR EXTENDED MONITORS,
;OR T1 CONTAINS A ONE-WORD BYTE POINTER FOR NON-EXTENDED MONITORS

AUTADP::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVEI	P1,(T1)		;COPY CPU NUMBER
	PUSHJ	P,ADNBPT	;GENERATE BYTE POINTER
	DMOVE	T1,P1		;COPY RESULTS
	POPJ	P,		;AND RETURN


;ROUTINE TO COMPUTE A BYTE POINTER GIVEN A CPU NUMBER IN P1
ADNBPT:	AOS	P1		;PRE-INCREMENT
	MOVSI	P2,(POINT 5,)	;5-BIT BYTES
	ADJBP	P1,P2		;POINT TO THE BYTE FOR THIS CPU
	MOVE	P2,.CPDRV##	;DRIVER DISPATCH
IFE FTXMON,<
	HRR	P1,DRVMDT(P2)	;POINT TO TABLE
>; END IFE FTXMON
IFN FTXMON,<
	MOVE	P2,DRVMDT(P2)	;POINT TO TABLE
	TLO	P1,(1B12)	;TWO-WORD BYTE POINTER
	TRZ	P1,-1		;CLEAR RH JUNK FOR AESTHETIC REASONS ONLY
>; END IFN FTXMON
	POPJ	P,		;RETURN
SUBTTL	AUTOCONFIGURATION -- AUTAMR - ALLOCATE UNIBUS MAPPING REGISTERS


;ROUTINE TO ALLOCATE UNIBUS MAPPING REGISTERS
;CALL:	MOVE	T1, UNIBUS ADAPTER NUMBER
;	MOVE	T2, NUMBER OF REGISTERS DESIRED
;	PUSHJ	P,AUTAMR
;	  <NON-SKIP>		;INSUFFICIENT FREE REGISTERS
;	<SKIP>			;T1 = UNIBUS ADDRESS OF FIRST REGISTER ALLOCATED
				;T2 = NUMBER OF REGISTERS ALLOCATED
				;T3 = INITIAL ELEVEN ADDRESS

IFN FTKS10,<
AUTAMR::SKIPE	T1		;MUST BE A VALID UBA NUMBER
	CAILE	T1,MAXUBA	;...
	POPJ	P,		;SORRY
	MOVE	T3,.CPUMR##-1(T1) ;GET HIGHEST MAPPING REGISTER ALLOCATED
	ADD	T3,T2		;NUMBER THEY WANT
	CAILE	T3,UBAPGS	;EXCEEDED THE NUMBER OF MAPPING REGISTERS?
	POPJ	P,		;YES, RETURN
	EXCH	T3,.CPUMR##-1(T1) ;GET FIRST REGISTER FOR CALLER, RESET HIGHEST
	MOVSS	T1		;PUT UBA NUMBER IN LEFT HALF
	HRRI	T1,UBAEXP(T3)	;GET UNIBUS ADDRESS OF FIRST MAPPING REGISTER
	IMULI	T3,UBAMUL	;COMPUTE INITIAL ELEVEN ADDRESS
	JRST	CPOPJ1##	;SKIP RETURN
>; END IFN FTKS10
SUBTTL	AUTOCONFIGURATION -- AUTCHN - BUILD A CHANNEL DATA BLOCK


;BUILD A CHANNEL DATA BLOCK
;CALL:	MOVE	T1, CHANNEL BITS
;	PUSHJ	P,AUTCHN
;	  <NON-SKIP>		;NO CORE
;	<SKIP>			;.CPCHA = CHANNEL ADDRESS

AUTCHN::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	XMOVEI	P1,SYSCHN##-CHNSYS ;SET PREDECESSOR
	MOVE	P2,T1		;COPY CHANNEL BITS
IFN FTCIDSK,<
	TRNE	P2,400000	;SPECIAL CI DISK HACKERY?
	JRST	AUTCH2		;YES, DON'T CHECK FOR DUPLICATES
>; END IFN FTCIDSK

AUTCH1:	MOVE	P1,CHNSYS(P1)	;GET CHANNEL ADDRESS
	HLRZS	P1		;ADDRESS IN LH QUANTITY
	JUMPE	P1,AUTCH2	;MUST CREATE ONE
	MOVE	T1,.CPDVC##	;GET <CPU>B2 + (<DEVICE CODE>/4 OR UBA ADDR)
	CAME	T1,CHNDVC(P1)	;KNOWN CHANNEL?
	JRST	AUTCH1		;KEEP SEARCHING
	MOVEM	P1,.CPCHA##	;SAVE FOR DRIVERS THAT MIGHT CARE
	JRST	CPOPJ1##	;AND RETURN

AUTCH2:	MOVEI	T1,CHNLEN	;LENGTH OF A CHANNEL DATA BLOCK
	PUSHJ	P,GETCOR	;ALLOCATE CORE
	  POPJ	P,		;NOT AVAILABLE
	MOVE	P1,T2		;COPY ADDRESS
	MOVEI	T1,SYSCHN##-CHNSYS ;SET PREDECESSOR
	SYSPIF			;INTERLOCK CHAIN SCANNING

AUTCH3:	SKIPN	T2,CHNSYS(T1)	;LINK TO NEXT CHANNEL
	JRST	AUTCH4		;END OF CHAIN
	HLRZ	T1,T2		;COPY
	JRST	AUTCH3		;SEARCH FOR END OF CHAIN

AUTCH4:	HRLM	P1,CHNSYS(T1)	;SAVE CHANNEL DATA BLOCK ADDRESS
	SYSPIN			;RELEASE INTERLOCK
	MOVEM	P1,.CPCHA##	;SAVE FOR DRIVERS THAT MIGHT CARE
	SETOM	CHNBSY(P1)	;INDICATE IDLE
	MOVE	T1,.CPDVC##	;GET <CPU>B2 + (<DEVICE CODE>/4 OR UBA ADDR)
	MOVEM	T1,CHNDVC(P1)	;SAVE FOR AUTOCONFIGURE LATER ON
	HLLZM	P2,CHNTYP(P1)	;SAVE CHANNEL BITS
	MOVEI	T1,CHVIFP##
	HRRM	T1,CHNIFP(P1)
	MOVEI	T1,CHVIFT##
	MOVEM	T1,CHNIFT(P1)
	MOVEI	T1,3		;INITIAL FAIRNESS FOR SWAPPING
	MOVEM	T1,CHNIFS(P1)
IFN FTKS10,<
	LDB	T1,[POINT 3,.CPDVC##,17] ;GET UNIBUS ADAPTER NUMBER
	HRLI	T1,UNBSTW	;INSERT ADDRESS OF UNIBUS STATUS REGISTER
	MOVSM	T1,CHNUBA(P1)	;STORE IN CHN
>; END IFN FTKS10
	MOVEI	T1,CHNKTB(P1)	;GET ADDRESS OF TABLE OF KONTROLLERS
	MOVEM	T1,CHNTBP(P1)	;STORE IN CHN
	AOS	CNFCHN##	;ONE MORE CHANNEL IN THE SYSTEM
	AOS	T1,.CPASC##	;ONE MORE CHANNEL ON THIS CPU
	DPB	T1,CHYSCN	;STORE IN CHN
	MOVN	T2,T1		;GET -CHANNEL NUMBER
	MOVSI	T1,(CP.CS0)	;BIT FOR CHANNEL 0
	LSH	T1,(T2)		;POSITION BIT
	TLO	T1,(CP.PXX)	;INCLUDE MEMORY SCAN BIT
	MOVEM	T1,CHNCSR(P1)	;SAVE FOR ERROR REPORTING
	JRST	CPOPJ1##	;SKIP RETURN
SUBTTL	AUTOCONFIGURATION -- AUTCLK - QUEUE UP A CLOCK REQUEST


;QUEUE UP A CPU-SPECIFIC CLOCK REQUEST FOR AUTOCONFIGURE PROCESSING
;AT A LATER TIME.  THE INTENT IS TO ALLOW DEVICE CONFIGURING TO OCCUR
;WHEN THE SYSTEM IS CONSIDERED UP AND TIMESHARING.  IT IS HERE PRIMARILY
;TO ACCOMODATE RSX-20F DEVICES, BUT CAN BE USED ANY TIME A DRIVER CHOOSES
;TO DELAY CONFIGURING UNTIL A LATER TIME.
;CALL:	MOVE	T1, CALL-BACK ROUTINE
;	MOVE	T2, TICKS TO WAIT
;	PUSHJ	P,AUTCLK
;	<RETURN>
;
;WHEN THE DRIVER ROUTINE IS CALLED, THE AUTCON DATA BASE WILL BE INTERLOCKED.
;IT IS THE RESPONSIBILITY OF THE DRIVER TO CALL AUTSET, AS THE NECESSARY
;INFORMATION TO DO THAT IS KNOWN ONLY TO THE DRIVER.

AUTCLK::PUSH	P,T3		;SAVE T3
	MOVE	T3,.CPCPN##	;CPU NUMBER
	TLO	T1,400000	;WILL BE A CPU-SPECIFIC REQUEST
	DPB	T3,[POINT 3,T1,3] ;STORE CPU NUMBER
	HRLI	T2,CLOCKR	;INCLUDE OUR CLOCK PROCESSING ENTRY POINT
	SYSPIF			;INTERLOCK QUEUE
	SETZM	CLKMIN##(T3)	;INDICATE NEW REQUEST IN QUEUE
	IDPB	T2,CLOCK##	;STORE ROUTINE,,#TICKS
	IDPB	T1,CLOCK##	;STORE CPU + DATA (DRIVER ROUTINE)
	SYSPIN			;RELEASE INTERLOCK
	POP	P,T3		;RESTORE T3
	POPJ	P,		;AND RETURN


;HERE WHEN CLOCK REQUEST TIMES OUT
CLOCKR:	SE1ENT			;RUN IN SECTION ONE
	MOVE	T2,TICSEC##	;TIME TO WASTE INCASE CANNOT INTERLOCK
	PUSHJ	P,AUTLOK	;INTERLOCK THE DATA BASE
	  JRST	AUTCLK		;AT INTERRUPT LEVEL, SO TRY AGAIN LATER
	PUSHJ	P,(T1)		;CALL DRIVER
	  JFCL			;IGNORE ERRORS
	PJRST	AUTULK		;RELEASE INTERLOCK AND RETURN
SUBTTL	AUTOCONFIGURATION -- AUTCPU - CONFIGURE ALL DEVICES ON A CPU


AUTCPU::SE1ENT			;RUN IN SECTION ONE
	PUSHJ	P,SAVE4##	;SAVE SOME ACS
	CONI	PI,.CPATP##	;SAVE STATE OF PI SYSTEM
	CONO	PI,PI.TFP+177	;TURN OFF ALL CHANNELS
	MOVEI	T1,^D30		;NUMBER OF SECONDS PROTOCOL PAUSE WILL LAST
	IMUL	T1,TICSEC##	;COMPUTE TICKS AND STUFF IN OK
	MOVNM	T1,.CPOK##	; WORD SO CLOCK1 WON'T CALL BRKLOK
	PUSHJ	P,AUTLOK	;GET DATA BASE INTERLOCK
	  JRST	.-1		;REALLY WANT THE INTERLOCK
IFN FTKL10,<PUSHJ P,DTESPP##>	;ENTER PROTOCOL PAUSE
	PUSHJ	P,CTYERM##	;SET UP CTY TYPEOUT ROUTINE

IFN FTKL10,<MOVEI T1,<M.FDVC##/4>-1> ;INITIAL DEVICE CODE
IFN FTKS10,<MOVSI T1,1>		;START AT FIRST UNIBUS ADAPTER
	MOVE	T2,.CPCPN##	;INCLUDE CPU NUMBER
	DPB	T2,[POINT 3,T1,2] ; IN BITS 0-2
	MOVEM	T1,.CPDVC##	;SAVE
IFN FTKS10,<
AUTCP0:	LDB	T1,[POINT 3,.CPDVC##,17] ;GET UNIBUS ADAPTER NUMBER
	HRLI	T1,UNBSTW	;ADDRESS OF THE STATUS REGISTER
	MOVSS	T1		;SWAP HALVES
	PUSHJ	P,UBGOOD##	;THIS UNIBUS ADAPTER EXIST?
	  JRST	[MOVSI T1,1	;NON-EXISTANT ADAPTER, BUMP ADAPTER NUMBER
		 ADDM  T1,.CPDVC##
		 JRST  AUTCP5]	;CONTINUE
	HRRI	T1,M.FDVC##-4	; SYMBOLIZE - GET STARTING UNIBUS ADDRESS
	HRRM	T1,.CPDVC##	;RESET FOR THIS ADAPTER
>; END IFN FTKS10

;LOOP CALLING EACH DRIVER FOR EACH DEVICE THAT EXISTS
AUTCP1:	MOVE	T1,DRVLST	;INITIAL DRIVER DISPATCH
	MOVEM	T1,.CPDRV##	;SAVE

;SEARCH FOR AN EXISTANT DEVICE
AUTCP2:
IFN FTKL10,<
	AOS	T1,.CPDVC##	;GET PREVIOUS DEVICE CODE
	HRRZS	T1		;ISOLATE <DEVICE CODE>/4
	CAILE	T1,M.LDVC##/4	;CHECKED ALL DEVICE CODES?
>; END IFN FTKL10
IFN FTKS10,<
	MOVEI	T1,4		;AMOUNT TO BUMP UNIBUS ADDRESS
	ADDB	T1,.CPDVC##	;ADVANCE TO NEXT UNIBUS ADDRESS
	HRRZ	T2,T1		;ISOLATE UNIBUS ADDRESS
	TRNE	T2,-1		;QUIT IF WE'VE GONE PAST THE END
	CAILE	T2,M.LDVC##	;CHECKED ALL ADDRESSES?
>; END IFN FTKS10
	JRST	AUTCP5		;FINISH UP
	MOVE	T2,.CPDRV##	;REDUNDANT, BUT THAT'S OK
	SETZ	T3,		;NO CHANNEL DATA BLOCK YET
	PUSHJ	P,AUTSET	;SET UP CPU VARIABLES
	PUSHJ	P,CHKDEV	;SEE IF DEVICE REALLY EXISTS (SAVE PIA TOO)
	  JRST	AUTCP2		;IT DOESN'T
;LOOP OVER EACH DRIVER WHEN A DEVICE IS DETECTED
AUTCP3:
IFN FTKL10,<
	XCT	.CPCNI##	;CONI DEV,T1
	MOVE	T2,T1		;COPY TO THE PROPER PLACE
	HRRZ	T1,.CPDVC##	;GET <DEVICE CODE>/4 AGAIN
>; END IFN FTKL10
IFN FTKS10,<LDB T1,[POINT 21,.CPDVC##,35]> ;GET UNIBUS ADDRESS
	MOVE	T3,.CPDRV##	;GET DRIVER DISPATCH
	MOVEI	T4,DR.SFT	;BIT TO TEST
	TDNE	T4,DRVCNF(T3)	;SOFTWARE DEVICE?
	JRST	AUTCP4		;ON THIS PASS
	PUSHJ	P,@DRVCFG(T3)	;ELSE CALL DRIVER
	  JRST	AUTCP1		;CONFIGURED--NO MORE FOR THIS DEVICE

AUTCP4:	MOVE	T1,.CPDRV##	;GET DRIVER DISPATCH
	SKIPN	T1,DRVLNK(T1)	;AND LINK TO NEXT
	JRST	AUTCP1		;NO MORE, SO ON TO THE NEXT DEVICE
	MOVEM	T1,.CPDRV##	;SAVE FOR NEXT TIME
	JRST	AUTCP3		;TRY ANOTHER DRIVER
AUTCP5:
IFN FTKS10,<
	LDB	T1,[POINT 3,.CPDVC##,17] ;GET UNIBUS ADAPTER NUMBER
	CAIG	T1,MAXUBA	;DONE ALL 4 ADAPTERS?
	JRST	AUTCP0		;NO, START OVER WITH THAT UNIBUS ADAPTER
>; END IFN FTKS10
	MOVE	T2,DRVLST	;HEAD OF CHAIN

AUTCP6:	MOVEM	T2,.CPDRV##	;SAVE DRIVER DISPATCH
	MOVEI	T1,DR.SFT	;BIT TO TEST
	TDNE	T1,DRVCNF(T2)	;SOFTWARE DEVICE?
	PUSHJ	P,@DRVCFG(T2)	;YES
	  JFCL			;IGNORE FOOLISHNESS
	MOVE	T2,.CPDRV##	;GET DRIVER DISPATCH
	SKIPE	T2,DRVLNK(T2)	;AND LINK TO NEXT
	JRST	AUTCP6		;CHECK OUT NEXT DRIVER

IFN FTNET,<PUSHJ P,NETDEV##>	;UPDATE DEVICE COUNTS IN HOST NDB
IFN FTKL10,<PUSHJ P,DTERPP##>	;CLEAR PROTOCOL PAUSE
	PUSHJ	P,AUTULK	;GIVE UP DATA BASE INTERLOCK
	MOVSI	T1,(CR.ATO)	;GET OUR BIT
	ANDCAM	T1,.CPRUN##	;LET THE DRIVERS DO THEIR THING
	MOVE	T1,.CPATP##	;GET SAVED PI SYSTEM STATE
	ANDI	T1,177		;ISOLATE CHANNELS
	CONO	PI,PI.TNP(T1)	;TURN THEM BACK ON AGAIN
	POPJ	P,		;RETURN
SUBTTL	AUTOCONFIGURATION -- AUTCSO - LINK UP CONSO SKIP CHAIN


;ROUTINE TO LINK INTERRUPT CODE INTO THE CONSO SKIP CHAIN
;CALL:	MOVE	T1, INTERRUPT CODE ADDRESS
;	MOVE	T2, PI CHANNEL
;	PUSHJ	P,AUTCSO

IFN FTKL10,<
AUTCSO::PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,T1		;COPY ARGUMENT
	MOVE	T1,T2		;COPY PIA
	LSH	T1,1		;TIMES TWO
	ADDI	T1,40-1		;COMPUTE INTERRUPT LOCATION
	ADD	T1,.CPEPT##	;INDEX INTO THE EPT
	HRRZ	T1,1(T1)	;XPCW ADDRESS
	MOVE	T2,4(T1)	;START OF CONSO SKIP CHAIN
	MOVEI	T3,(P1)		;COPY START OF INTERRUPT CODE
	HRLI	T3,(JRST)	;FORM INSTRUCTION
	MOVEM	T3,4(T1)	;LINK AT FRONT OF CHAIN
	MOVEM	T2,1(P1)	;LINK EXISTING CHAIN FOLLOWING THIS CODE
	POPJ	P,		;RETURN
> ;END IFN FTKL10
SUBTTL	AUTOCONFIGURATION -- AUTDDB - BUILD A DDB


;ROUTINE TO CREATE A DDB
;CALL:	MOVE	T1, SIXBIT GENERIC DEVICE NAME,,PHYSICAL DRIVE NUMBER
;	MOVE	T2, STATION OR ZERO (IF LOCAL)
;	PUSHJ	P,AUTDDB
;	  <NON-SKIP>		;NO CORE AVAILABLE
;	<SKIP>			;AC F = NEW KDB ADDRESS

AUTDDB::PUSHJ	P,SAVE4##	;SAVE SOME ACS
	MOVE	T4,.CPDRV##	;DRIVER DISPATCH
	MOVE	P1,DRVDDB(T4)	;COPY PROTOTYPE DDB ADDRESS
	MOVE	P2,DRVDDL(T4)	;COPY PROTOTYPE DDB LENGTH
	DMOVE	P3,T1		;COPY NAME & DRIVE, STATION
	TRNN	P4,-1		;STATION NUMBER SUPPLIED?
	HRR	P4,JBTLOC##	;DEFAULT TO LOCAL
	MOVE	F,P1		;SETUP F
	LDB	T1,PDVTYP##	;GET DEVICE TYPE INDEX
	SKIPE	DDBTAB(T1)	;TABLE ALREADY SETUP?
	JRST	AUTDD1		;YES
	MOVEM	P1,DDBTAB(T1)	;REMEMBER PROTOTYPE DDB ADDRESS
	MOVEM	P2,DDBSIZ(T1)	;REMEMBER PROTOTYPE DDB LENGTH

AUTDD1:	MOVE	T1,P2		;GET NUMBER OF WORDS
	PUSHJ	P,GETCOR	;ALLOCATE CORE
	  POPJ	P,		;CAN'T DO IT
	MOVE	F,T2		;COPY ADDRESS
IFE FTXMON,<
	MOVSI	T1,(P1)		;PROTOTYPE ADDRESS
	HRRI	T1,(F)		;DESTINATION
	ADDI	P2,(F)		;COMPUTE END OF BLT
	BLT	T1,-1(P2)	;COPY
> ;END IFE FTXMON
IFN FTXMON,<
	MOVEI	T1,(P2)		;LENGTH
	MOVE	T2,P1		;PROTOTYPE ADDRESS
	MOVE	T3,F		;DESTINATION
	EXTEND	T1,[XBLT]	;COPY
> ;END IFN FTXMON
	HRRZ	T1,P3		;PHYSICAL DRIVE NUMBER
	MOVEI	T2,DR.NET	;BIT TO TEST
	TDNN	T2,DRVCNF(T4)	;WANT ANF-10 STATION NUMBERS IN NAME?
	JRST	AUTDD2		;NO
	DPB	P4,[POINT 6,T1,32] ;INCLUDE IT
	JRST	AUTDD3		;FORCE OCTAL NUMBER

AUTDD2:	MOVEI	T3,DR.DDN	;BIT TO TEST
	TDNE	T3,DRVCNF(T4)	;WANT DECIMAL DEVICE NAME?
	SKIPA	T2,[EXP DECNAM]	;YES
AUTDD3:	MOVEI	T2,OCTNAM	;MAKE IT OCTAL
	PUSHJ	P,(T2)		;GENERATE SIXBIT NUMBER
	MOVEI	T2,DR.NET	;BIT TO TEST
	TDNN	T2,DRVCNF(T4)	;WANT ANF-10 STATION NUMBERS IN NAME?
	JRST	AUTDD4		;NO
	TRNE	T1,7700		;IF ONLY ONE CHARACTER,
	TRNE	T1,77		;OR THREE,
	JRST	AUTDD4		;THERE'S NOTHING TO FIX UP
	LSH	T1,-6		;WRONG--RIGHT-ADJUST
	TRO	T1,'0  '	;INSERT THE LEADING ZERO IN THE STATION NUMBER

AUTDD4:	HLL	T1,P3		;INCLUDE GENERIC PORTION
	MOVEM	T1,DEVNAM(F)	;STORE
	DPB	P3,PUNIT##	;STORE PHYSICAL DRIVE NUMBER AS UNIT
	DPB	P4,PDVSTA##	;STORE STATION NUMBER FOR NETSER
IFN FTMP,<
	LDB	T1,DEYCPF##	;GET PROTOTYPE'S OWNING CPU
	CAIGE	T1,CPFBIT##	;LEAVE CPFBIT & CPFBOO ALONE
	MOVE	T1,.CPCPN##	;NO, GET OUR CPU NUMBER
	DPB	T1,DEYCPF##	;SAVE IN DDB
	CAIL	T1,CPFBIT##	;IN RANGE OF REAL CPU NUMBERS?
	SETZ	T1,		;NO, USE CPU0'S INTERLOCKS
	LSH	T1,3		;OFFSET TO RIGHT BLOCK OF PI CHANNELS
	HRRZ	T2,DEVCPU(F)	;GET PI CHANNEL NUMBER
	CAIL	T2,100		;IS IT STILL A CHANNEL?
	SUBI	T2,INTL0##	;NO, CONVERT TO AN OFFSET
	ANDI	T2,7		;MAKE SURE JUST A PI CHANNEL
	ADDI	T1,INTL0##(T2)	;INDEX INTO TABLE
	HRRM	T1,DEVCPU(F)	;STORE
> ;END IFN FTMP

	MOVE	T4,.CPDRV##	;DISPATCH
	MOVEM	T4,DEVDRV(F)	;SAVE FOR DIAG. UUO, ETC.
	MOVE	T1,F		;DDB ADDRESS
	MOVE	T2,DRVDDL(T4)	;DDB LENGTH
	MOVEI	T3,DR.UCD	;BIT TO TEST
	TDNE	T3,DRVCNF(T4)	;WANT TO UNCACHE THE DDB?
	PUSHJ	P,UNCACH	;UNCACHE THE ADDRESS RANGE
	AOS	(P)		;WE'RE SUCCEEDING
	PJRST	LNKDDB		;LINK UP THE DDB & RETURN
SUBTTL	AUTOCONFIGURATION -- AUTLNK - LINK A DDB

;SUBROUTINE TO LINK A DDB INTO ITS CANONICAL PLACE IN DEVLST
;CALL:	MOVEI	F,DDB-ADDRESS
;	PUSHJ	P,AUTLNK
;	<RETURN>

AUTLNK::PUSHJ	P,SAVE4##	;PRESERVE SOME REGISTERS
LNKDDB:	LDB	P1,PDVTYP##	;DEVICE TYPE
	LDB	P2,PUNIT##	;UNIT NUMBER
	LDB	T1,PDVSTA##	;STATION NUMBER
	HRL	P2,T1		;MERGE WITH UNIT
	MOVE	P3,F		;SAVE NEW DDB ADDRESS
	SETZ	P4,		;NO KNOWN PREDECESSOR YET
	DDBSRL			;INTERLOCK DDB SCANNING
	SKIPE	F,DDBTAB(P1)	;IF NO FIRST DDB OF THIS KIND,
	SKIPE	DEVNAM(F)	;OR IF IT'S NOT A PROTOTYPE,
	TRNA			;WE HAVE TO LOOK FOR A PREDECESSOR
	JRST	LNKDD5		;GO WITH THE PROTOTYPE
	HLRZ	T2,DEVNAM(P3)	;GET THE GENERIC NAME FOR THIS DDB
	SKIPN	T2		;IF NONE,
	SKIPN	T2,DEVDRV(P3)	;CHECK THE DRIVER DISPATCH TABLE
	TRNA			;SIGH
	HLRZ	T2,DRVNAM(T2)	;GET GENERIC NAME FROM DRIVER IF NONE IN DDB
	SETZ	F,		;NO STARTING POINT YET
	SKIPL	T1,GENPTR##	;AOBJN INDEXER FOR GENTAB
	JRST	LNKDD3		;NOTHING YET--JUST LINK IN WHERE WE FIT
LNKDD1:	CAMG	T2,GENTAB##(T1)	;IS THIS STILL SOME SORT OF PREDECESSOR ENTRY?
	JRST	LNKDD2		;NO--GO DO OUR THING
	SKIPE	GENTAB##+1(T1)	;IF THERE IS A POINTER,
	MOVE	F,GENTAB##+1(T1) ;UPDATE OUR G.L.B.
	AOBJP	T1,LNKDD2	;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	T1,LNKDD1	;AND TRY AGAIN
				;FALL THROUGH
LNKDD2:	JUMPE	F,LNKDD3	;IF NO STARTING POINT, USE BEG OF CHAIN
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIN	T1,(P1)		;IF ALREADY MATCHING,
	JRST	LNKDD5		;JUST USE THIS AS THE PREDECESSOR

LNKDD3:	SKIPN	F		;FOUND STARTING POINT YET?
	XMOVEI	F,DEVLST##-DEVSER ;NO, USE START OF CHAIN
	HLRZ	P4,DEVSER(F)	;GET NEXT POSSIBLE CANDIDATE
	JUMPE	P4,LNKDD5	;OFF THE END--GO INSERT HERE
	EXCH	P4,F		;GET PREDECESSOR & CURRENT
	HLRZ	T1,DEVNAM(F)	;GET GENERIC NAME FROM DDB
	SKIPN	T1		;IF NOT THERE,
	SKIPN	T1,DEVDRV(F)	;TRY FOR A DRIVER DISPATCH TABLE
	TRNA			;IN DDB OR NO DEVDRV
	HLRZ	T1,DRVNAM(T1)	;FETCH FROM DRIVER
	CAMLE	T2,T1		;HAVE WE FOUND OUR NICHE?
	JRST	LNKDD3		;NO--KEEP LOOKING
				;YES--FALL INTO LNKDD4

LNKDD4:	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIE	T1,(P1)		;MATCHING DEVICE TYPES?
	JRST	LNKDD6		;NO--INSERT HERE
	HLRZ	T1,DEVNAM(F)	;GET GENERIC NAME
	HLRZ	T2,DEVNAM(P3)	;...
	CAIE	T1,(T2)		;MATCHING GENERIC NAMES?
	JRST	LNKDD5		;NO--TRY THE NEXT DDB
	LDB	T1,PUNIT##	;GET UNIT NUMBER
	LDB	T2,PDVSTA##	;GET STATION NUMBER
	HRL	T1,T2		;MERGE
	CAMG	P2,T1		;MAINTAIN ASCENDING STATION AND UNIT ORDER
	JRST	LNKDD6		;INSERT HERE

LNKDD5:	SKIPE	P4,F		;SAVE THIS ADDR AS PREVIOUS
	HLRZ	F,DEVSER(F)	;ADDR OF NEXT DDB
	JUMPN	F,LNKDD4	;LOOP BACK

LNKDD6:	JUMPN	P4,LNKDD8	;JUST GO LINK UP IF WE KNOW THE PREDECESSOR
	XMOVEI	P4,DEVLST##-DEVSER ;NO--GET PRE-CHAIN POINTER

LNKDD7:	HLRZ	P2,DEVSER(P4)	;GET NEXT DDB ADDRESS
	CAIN	P2,(F)		;IS THIS A MATCH?
	JRST	LNKDD8		;YES--WE CAN LINK IT UP NOW
	MOVE	P4,P2		;NO--ADVANCE PREDECESSOR POINTER
	JRST	LNKDD7		;AND TRY AGAIN

LNKDD8:	MOVEI	T1,(P3)		;*** UNTIL REAL EXTENDED DDBS
	CAIE	T1,(P4)		;IF WE MATCH OUR PREDECESSOR
	CAIN	T1,(F)		;OR OUR SUCCESSOR
	JRST	[DDBSRU		;UNLOCK DEVICE CHAIN SCANNING AND
		 MOVE	F,P3	;RESTORE INCOMING DDB
		 POPJ	P,]	;GET OUT NOW (REDUNDANT PROTOTYPE)
	HRLM	P3,DEVSER(P4)	;LINK NEW TO PREVIOUS
	HRLM	F,DEVSER(P3)	;LINK NEXT TO NEW
	HRRZ	T1,DDBTAB(P1)	;*** UNTIL REAL EXTENDED DDBS
	CAIE	T1,(F)		;IF SUCCESSOR WAS FIRST,
	SKIPN	DDBTAB(P1)	;OR IF THERE'S NOTHING BETTER,
	MOVEM	P3,DDBTAB(P1)	;THEN MAKE THIS THE FIRST OF ITS KIND
	MOVE	T1,DEVLST##	;GET START OF CHAIN
	MOVEM	T1,HNGLST##	;AND UPDATE SHADOW COPY
	DDBSRU			;RELEASE INTERLOCK
	MOVE	F,P3		;RESTORE F FOR CALLER
IFN FTNET,<
	SKIPE	T1,DEVDRV(F)	;SEE IF THERE'S A DRVDSP HERE
	HRRZ	T1,DRVDDB(T1)	;GET PROTOTYPE DDB IF SO *** NON-EXTENDED
	CAIN	T1,(F)		;IF A PROTOTYPE,
	JRST	LNKDD9		;DON'T COUNT IT
	LDB	T1,PDVSTA##	;GET STATION NUMBER
	CAME	T1,ANFNUM##	;IF NOT LOCAL,
	JRST	LNKDD9		;DON'T COUNT IT
	AOS	DDBCNT(P1)	;COUNT IT FOR NETSER
	PUSHJ	P,NETDEV##	;UPDATE COUNTS IN NETNDB
> ;END IFN FTNET
LNKDD9:	PJRST	GENADD		;UPDATE GENTAB IF NECESSARY, THEN RETURN
SUBTTL	AUTOCONFIGURATION -- AUTDPU - CHECK FOR DUAL PORTED UNITS


;THIS ROUTINE WILL CHECK FOR AND OPTIONALLY LINK UP UDBS FOR DUAL
;PORTED UNITS.
;CALL:	MOVE	W,  CURRENT KDB ADDRESS
;	MOVE	T1, DRIVE S/N (WORD 1)
;	MOVE	T2, DRIVE S/N (WORD 2)
;	MOVE	T3, PHYSICAL DRIVE NUMBER
;	PUSHJ	P,AUTDPU
;	  <NON-SKIP>		;DUAL PORTED UNIT
;	<SKIP>			;SINGLE PORTED UNIT
;
;IF THE NON-SKIP RETURN IS TAKEN, THE KDB/UDB LINKS WILL BE FIXED
;UP AS PER DR.LDP IN DRVCNF OF THE DRIVER DISPATCH TABLE.  WHEN THIS
;BIT IS SET, NO ADDITIONAL AUTOCONFIGURATION WORK IS NECESSARY AND
;THE CALLER MAY STEP TO THE NEXT POSSIBLE UNIT.  THE SKIP RETURN
;MEANS ADDITIONAL PROCESSING IS NEEDED.

AUTDPU::MOVE	T4,.CPDRV##	;DRIVER DISPATCH
	SKIPN	DRVCKT(T4)	;HAVE A COMPATIBLE KONTROLLER TYPE TABLE?
	JRST	CPOPJ1##	;NO
	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	PUSH	P,W		;SAVE W
	DMOVE	P1,T1		;COPY DRIVE S/N
	MOVE	P3,.CPDRV##	;DRIVER DISPATCH
	LDB	T1,[POINTR (DRVCNF(P3),DR.DVT)] ;DEVICE TYPE
	SKIPN	W,KDBTAB(T1)	;GET FIRST KDB ADDRESS
	JRST	AUTDP3		;NONE THERE

AUTDP1:	MOVE	T1,KDBDSP(W)	;DRIVER DISPATCH
	CAME	W,(P)		;FOUND OUR OWN KONTROLLER?
	SKIPN	T1,DRVCKT(T1)	;NO--GET ITS COMPATIBLE KONTROLLER TABLE
	JRST	AUTDP2		;SKIP THIS KDB
	LDB	T2,[POINTR (DRVCF2(P3),DR.KTY)] ;GET OUR KONTROLLER TYPE
	PUSHJ	P,MATCKT	;FIND A COMPATIBLE KONTROLLER
	  JRST	AUTDP2		;NOT HERE
	PUSHJ	P,MATDSN	;FIND A MATCHING DRIVE S/N
	  JRST	AUTDP2		;THERE ISN'T ONE
	POP	P,W		;RESTORE CURRENT KDB
	MOVE	U,T1		;COPY ALTERNATE UDB ADDRESS
	ADD	T2,KDBIUN(W)	;COMPUTE UDB SLOT FOR CURRENT KDB
	MOVEM	U,(T2)		;POINT KDB AT UDB
	MOVEI	T3,DR.DPU	;BIT TO TEST
	TDNN	T3,DRVCNF(P3)	;WANT DUAL PORTED KDB/UDB LINK FIXUP?
	POPJ	P,		;NO--ALL DONE
	PJRST	LNKUDB		;GO DO IT

AUTDP2:	SKIPE	W,KDBNXT(W)	;LINK TO NEXT
	JRST	AUTDP1		;LOOP BACK

AUTDP3:	POP	P,W		;RESTORE W
	JRST	CPOPJ1##	;CAN'T DUAL PORT THIS UNIT
;SCAN A COMPATIBLE KONTROLLER TABLE FOR A MATCH
;CALL:	MOVE	T1, TABLE ADDRESS
;	MOVE	T2, TYPE TO MATCH ON
;	PUSHJ	P,MATCKT

MATCKT:	SKIPN	T3,(T1)		;GET A KONTROLLER TYPE
	POPJ	P,		;END OF TABLE
	CAIE	T2,(T3)		;A MATCH?
	AOJA	T1,MATCKT	;TRY ANOTHER
	JRST	CPOPJ1##	;RETURN


;SCAN UDBS ON A KONTROLLER FOR A MATCHING DRIVE SERIAL NUMBER
;CALL:	MOVE	W,  KDB ADDRESS
;	MOVE	P1, DRIVE S/N (WORD 1)
;	MOVE	P2, DRIVE S/N (WORD 2)
;	PUSHJ	P,MATDSN

MATDSN:	MOVE	T2,KDBIUN(W)	;POINTER TO UDB TABLE

MATDS1:	SKIPN	T1,(T2)		;GET A UDB
	JRST	MATDS2		;NONE THERE
	DMOVE	T3,UDBDSN(T1)	;COPY S/N
	CAMN	P1,T3		;MATCH?
	CAME	P2,T4		;...
	JRST	MATDS2		;TRY ANOTHER
	SUB	T2,KDBIUN(W)	;GET UDB TABLE OFFSET
	JRST	CPOPJ1##	;RETURN WITH T1 & T2 SETUP

MATDS2:	CAMGE	T2,KDBFUN(W)	;FINAL UDB?
	AOJA	T2,MATDS1	;LOOP FOR MORE
	POPJ	P,		;GIVE UP
SUBTTL	AUTOCONFIGURATION -- AUTDSN - CHECK DRIVE S/N FOR ZEROS


;FOR OLD-STYLE UNITS INCAPABLE OF RETURNING A DRIVE SERIAL NUMBER, BUT
;WHICH CAN BE DUAL PORTED, A SCHEME HAS BEEN DEVELOPED IN WHICH A SERIAL
;NUMBER MAY BE FAKED UP.  THE S/N DOUBLE WORD IS CONJURED UP BY PUTTING
;THE DEVICE CODE IN THE HIGH WORD, THE MASSBUS UNIT & THE PHYSICAL DRIVE
;NUMBER IN THE LOW WORD.  THIS IS AKIN TO THE IBM STANDARD OF SETTING THE
;SERIAL NUMBER TO THE CU+DRIVE NUMBER.  THE RESTRICTIONS TO MAKE THIS WORK
;ARE QUITE SIMPLE.  THESE DRIVES MUST EXIST ON KONTROLLERS WITH THE SAME
;DEVICE CODE AND MASSBUS UNIT NUMBERS.  AGAIN, IN IBM TERMS, THE OTHER
;PORTS MUST BE ADDRESSED THE SAME (I.E. THE SAME CU).
;
;USING THIS SCHEME, THE MONITOR WILL TOLLERATE AT MOST, TWO UNITS WITH THE
;SAVE PHYSICAL DRIVE NUMBER PER COMPATIBLE KONTROLLER WHICH HAVE SERIAL
;NUMBERS OF ZERO.  ATTEMPTS TO HAVE MORE THAN TWO UNITS WITH A SERIAL NUMBER
;OF ZERO WILL MOST LIKELY CAUSE THE MONITOR TO DIE A RAPID AND RABID DEATH.
;
;THIS ROUTINE WILL CHECK THE SPECIFIED DRIVE SERIAL NUMBER FOR ZEROS
;AND IF THE KONTROLLER HAS A COMPATIBLE KONTROLLER TABLE, WILL CREATE
;A UNIQUE SERIAL NUMBER.
;CALL:	MOVE	W,  KDB ADDRESS
;	MOVE	T1, S/N WORD 1
;	MOVE	T2, S/N WORD 2
;	MOVE	T3, PHYSICAL DRIVE NUMBER
;	PUSHJ	P,AUTDSN
;
;ON RETURN, T1/T2 AND .CPTSN WILL ALWAYS BE SET WITH THE POSSIBLY
;NEW DRIVE SERIAL NUMBER

AUTDSN::MOVE	T4,T1		;HIGH PART
	IOR	T4,T2		;LOW PART
	JUMPN	T4,AUTDS1	;GO STORE IF NON-ZERO
	MOVE	T4,.CPDRV##	;DRIVER DISPATCH
	SKIPN	DRVCKT(T4)	;NO--COMPATIBLE KONTROLLER TABLE EXIST?
	JRST	AUTDS1		;DON'T ALTER ANYTHING
	HRRZ	T1,.CPDRV##	;USE DEVICE CODE AS HIGH WORD
	HLLZ	T2,KDBUNI(W)	;GET MASSBUS UNIT (IF ANY)
	HRR	T2,T3		;PLUS PHYSICAL DRIVE NUMBER FOR LOW WORD

AUTDS1:	DMOVEM	T1,.CPTSN##	;SAVE TEMPORARILY
	POPJ	P,		;RETURN
SUBTTL	AUTOCONFIGURATION -- AUTDVC - FILL IN DEVICE CODES


;ROUTINE TO SET DEVICE CODES
;THIS DEPENDS ON I/O INSTRUCTIONS HAVING THE FORM
;		INST 000,???
;
;WHERE	INST	ANY I/O INSTRUCTION
;	000	MUST BE ZERO AND WILL BE FILLED IN WITH
;		THE DEVICE CODE
;
;CALL:	MOVE	T1, -LENGTH,,0
;	XMOVEI	T2, STARTING ADDRESS
;	MOVE	T3, DEVICE CODE
;	PUSHJ	P,AUTDVC

IFN FTKL10,<
AUTDVC::MOVE	T4,(T2)		;GET POSSIBLE INSTRUCTION
	TLNE	T4,077400	;DEVICE CODE ZERO?
	JRST	AUTDV1		;NO--ASSUME NOT AN I/O INSTRUCTION
	TLC	T4,700000	;REALLY AN I/O
	TLCN	T4,700000	; INSTRUCTION?
	DPB	T3,[POINT 7,(T2),9] ;SET DEVICE CODE

AUTDV1:	AOS	T2		;ADVANCE TO NEXT STORAGE
	AOBJN	T1,AUTDVC	;AND LOOP
	POPJ	P,		;RETURN
>; END IFN FTKL10
SUBTTL	AUTOCONFIGURATION -- AUTEBD - HANDLE 18-BIT DF10/DF10C


;ROUTINE CALLED FROM DRIVERS WHICH DETECT AN 18-BIT DF10/DF10C TO PRINT
;AN ERROR MESSAGE AND IGNORE THE DEVICE.  ALWAYS RETURNS CPOPJ (BACK TO
;AUTCON FROM CALL TO DRIVER'S CFG ROUTINE).

IFN FTKL10,<
AUTEBD::STOPCD	CPOPJ##,INFORM,AUT18B,DIE18B, ;++18-BIT DF10/DF10C

;HERE FROM ERRCON ON AN AUT18B STOPCD

DIE18B:	PUSHJ	P,INLMES##	;PRINT SOME TEXT
	ASCIZ	.DF10/DF10C in 18-bit mode (device code .
	HRRZ	T1,.CPDVC##	;GET DEVICE CODE
	LSH	T1,2		;POSITION IT
	PUSHJ	P,PRTDI8##	;PRINT IT
	PJSP	T1,CONMES##	;FINISH MESSAGE AND RETURN
	ASCIZ	.) - controller ignored.
>; END IFN FTKL10
SUBTTL	AUTOCONFIGURATION -- AUTFND - FIND A DDB


;ROUTINE TO FIND A DDB GIVEN A DEVICE CODE.  THIS WAS WRITTEN SPECIFICALLY
;FOR THOSE DEVICES (SUCH AS LPTS) WHICH HAVE NO WAY TO DETERMINE OF A GIVEN
;DATA STRUCTURE ALREADY EXISTS FOR THE DEVICE IN QUESTION.
;CALL:	MOVE	T1, DDB OFFSET CONTAINING I/O INSTRUCTION
;	PUSHJ	P,AUTFND
;	  <NON-SKIP>		;F = DDB
;	<SKIP>			;NO DDB EXISTS

AUTFND::PUSHJ	P,SAVT##	;SAVE SOME ACS
	HRRZ	T2,.CPDVC##	;DEVICE CODE
	MOVE	T3,.CPDRV##	;DRIVER DISPATCH
	LDB	T3,[POINTR (DRVCNF(T3),DR.DVT)] ;GET DEVICE TYPE
	DDBSRL			;INTERLOCK
	SKIPE	F,DDBTAB(T3)	;GET HEAD OF CHAIN (PROTOTYPE DDB)

AUTFN1:	HLRZ	F,DEVSER(F)	;LINK TO FIRST REAL DDB
	JUMPE	F,AUTFN2	;SOMEONE IS CONFUSED
	LDB	T4,PDVTYP##	;GET DEVICE TYPE
	CAIE	T4,(T3)		;MATCH?
	JRST	AUTFN2		;NO DDBS OF THIS TYPE
	MOVE	T4,F		;COPY DDB ADDRESS
	ADDI	T4,(T1)		;OFFSET TO WORD CONTAINING I/O INSTRUCTION
IFN FTKL10,<LDB	T4,[POINT 7,(T4),9]> ;GET DEVICE CODE
IFN FTKS10,<MOVE T4,(T4)>	;GET UNIBUS ADDRESS
	CAME	T4,T2		;MATCH?
	JRST	AUTFN1		;NO--TRY ANOTHER DDB
	SKIPA			;NON-SKIP RETURN IF DDB EXISTS

AUTFN2:	AOS	(P)		;SKIP IF NO SUCH DDB
	DDBSRU			;RELEASE INTERLOCK
	POPJ	P,		;RETURN
SUBTTL	AUTOCONFIGURATION -- AUTICD - BUILD INTERRUPT CODE


;ROUTINE TO BUILD INTERRUPT CODE GIVEN A PROTOTYPE BLOCK
;CALL:	MOVE	T1, DATA BLOCK ADDRESS
;	MOVE	T2, INTERRUPT HANDLER ADDRESS
;	PUSHJ	P,AUTICD
;	  <NON-SKIP>		;NO CORE
;	<SKIP>			;T1 = SKIP-CHAIN ADDRESS, T2 = VECTOR ADDRESS

AUTICD::PUSHJ	P,SAVE4##	;SAVE SOME ACS
	DMOVE	P3,T1		;SAVE ARGUMENTS
	MOVE	T1,.CPDRV##	;DRIVER DISPATCH
	SKIPN	T1,DRVICL(T1)	;GET LENGTH OF PROTOTYPE
	JRST	CPOPJ1##	;NO PROTOTYPE, NO INTERRUPT CODE
	HRRZS	T1		;ISOLATE LENGTH
	PUSHJ	P,GETCOR	;ALLOCATE CORE
	  POPJ	P,		;GIVE UP
	MOVE	P1,T2		;COPY ADDRESS
	MOVE	T4,.CPDRV##	;DRIVER DISPATCH

IFE FTXMON,<
	HRR	T1,T2		;COPY ADDRESS
	HRL	T1,DRVICD(T4)	;MAKE A BLT POINTER
	MOVE	T2,DRVICL(T4)	;NUMBER OF WORDS
	ADDI	T2,(P1)		;COMPUTE END OF BLT
	BLT	T1,-1(T2)	;COPY PROTOTYPE
> ;END IFE FTXMON
IFN FTXMON,<
	MOVE	T1,DRVICL(T4)	;NUMBER OF WORDS
	MOVE	T2,DRVICD(T4)	;PROTOTYPE
	MOVE	T3,P1		;WHERE TO PUT IT
	EXTEND	T1,[XBLT]	;COPY
	MOVEI	T1,DR.XAD	;BIT TO TEST
	TDNN	T1,DRVCNF(T4)	;EXTENDED ADDRESSING DRIVER?
> ;END IFN FTXMON
	HRRZS	P4		;STRIP OFF SECTION NUMBER (IF ANY)
	MOVN	P2,DRVICL(T4)	;-NUMBER OF WORDS
	HRLZS	P2		;MAKE AN AOBJN POINTER
	SETZ	T4,		;WILL EVENTUALLY HAVE VECTOR ADDRESS
	PUSHJ	P,FIXINT	;FIX UP A WORD
	AOBJN	P2,.-1		;LOOP FOR ALL WORDS
	MOVE	T1,P1		;CONSO INTERRUPT ADDRESS
	MOVE	T2,T4		;VECTOR INTERRUPT ADDRESS
	JRST	CPOPJ1##	;AND RETURN
;ROUTINE TO FILL IN A WORD OF EITHER A CONSO SKIP CHAIN CODE OR
;VECTORED INTERRUPT CODE.
;CALL:	MOVE	P1, INTERRUPT ROUTINE BASE ADDRESS
;	MOVE	P2, AOBJN POINTER TO INTERRUPT ROUTINE
;	MOVE	P3, DATA BLOCK ADDRESS
;	MOVE	P4, INTERRUPT HANDLER ADDRESS
;	PUSHJ	P,FIXINT
;
;THE RULES FOR ADJUSTING INSTRUCTIONS OR DATA WORDS WITHIN THE
;INTERRUPT CODE ARE:
;	1. ANY CONSECUTIVE PAIRS OF ZERO WORDS WILL BE INTERPRETED AS
;	   AN XPCW ENTRY POINT.
;	2. ANY INSTRUCTION WHOSE RIGHT HALF CONTAINS AN INTEGER WITH
;	   A VALUE LESS THAN THE LENGTH OF THE INTERRUPT ROUTINE WILL
;	   CAUSE THAT INSTRUCTION TO BE RELOCATED BY THE ADDRESS OF
;	   THE INTERRUPT ROUTINE.
;	3. A "JSR PIERR" INSTRUCTION WILL BE REPLACED BY A CALL TO THE
;	   PI CHANNEL SAVE ROUTINE FOR THE DEVICE BEING CONFIGURED.
;	4. A "DMOVEM AC,-1" OR AN "XJEN -1" INSTRUCTION WILL BE REPLACED
;	   BY A DMOVEM/XJEN TO THE APPROPRIATE PI CHANNEL INTERRUPT ADDRESS.
;	5. ALL I/O INSTRUCTIONS WILL HAVE THE APPROPRIATE DEVICE CODE
;	   STORED INTO THEM.
;	6. ANY SKIPA INSTRUCTION IS INTERPRETED AS MEANING THE ADDRESS
;	   OF THE DATA BLOCK WILL BE LOADED INTO THE SPECIFIED AC.
;	7. AN "XJRST .+1" (KL10) OR A "JRST @.+1" (KS10) WILL BE INTERPRETED
;	   AS A JUMP TO THE INTERRUPT HANDLER.
;
;NOTE:	ON A KL10, THE START OF THE CONSO SKIP CHAIN MUST BE THE FIRST
;	WORD IN THE INTERRUPT ROUTINE.

FIXINT:	HRRZ	T1,P2		;OFFSET
	ADD	T1,P1		;INDEX INTO BLOCK
;CHECK FOR XPCW ENTRY POINT
FIXIN1:	MOVE	T2,0(T1)	;GET WORD 1
	IOR	T2,1(T1)	;AND WORD 2
	JUMPN	T2,FIXIN2	;MUST BE ZERO FOR XPCW ENTRY
	MOVE	T4,T1		;SAVE VECTOR INTERRUPT ADDRESS
	AOBJN	P2,.+1		;ADVANCE ONE
	AOBJN	P2,.+1		;ONE MORE BEYOND THE NEW PC FLAGS
	POPJ	P,		;AND RETURN

;CHECK FOR AN I/O INSTRUCTION
FIXIN2:	MOVE	T2,(T1)		;FETCH A WORD
	TLNE	T2,077400	;DEVICE CODE ZERO?
	JRST	FIXIN3		;ASSUME NOT AN I/O INSTRUCTION
	TLC	T2,700000	;REALLY AN I/O
	TLCN	T2,700000	; INSTRUCTION?
	SKIPA	T2,.CPDVC##	;GET DEVICE CODE
	JRST	FIXIN3		;TRY SOMETHING ELSE
IFN FTKL10,<DPB	T2,[POINT  7,(T1),9]> ;COMPLETE INSTRUCTION
IFN FTKS10,<DPB	T2,[POINT 21,(T1),35]> ;COMPLETE INSTRUCTION
	POPJ	P,		;DONE

;CHECK FOR RELOCATION
FIXIN3:	HRRZ	T2,(T1)		;GET RH OF POSSIBLE INSTRUCTION
	HLRE	T3,P2		;GET RH
	MOVNS	T3		;MAKE POSITIVE
	ADDI	T3,(P2)		;LENGTH OF ROUTINE
	CAIL	T2,0		;AVOID NEGATIVE OFFSETS
	CAILE	T2,-1(T3)	;WANT TO RELOCATE?
	SKIPA			;LEAVE IT ALONE
	ADDM	P1,(T1)		;RELOCATE ADDRESS

;CHECK FOR JSR TO SAVE ROUTINE
FIXIN4:	MOVE	T2,(T1)		;FETCH A WORD
	CAME	T2,[JSR PIERR##] ;NEED TO REPLACE?
	JRST	FIXIN5		;NO
	MOVE	T2,.CPDRV##	;DRIVER DISPATCH
IFN FTMP,< MOVE T3,DRVCNF(T2) >	;GET CONFIG BITS
	MOVE	T2,DRVPIC(T2)	;GET PI CHANNEL
IFN FTMP,<
	TRNN	T3,DR.MCD	;IF A NORMAL DEVICE,
	SKIPA	T2,.CPSAV##-1(T2) ;GET ASSOCIATED SAVE ROUTINE
	MOVS	T2,.CPSAV##-1(T2) ;GET SPECIAL SAVE ROUTINE FOR MULTI-CPU DEVS
> ;END OF IFN FTMP
IFE FTMP,< MOVE T2,.CPSAV##-1(T2) > ;GET ASSOCIATED SAVE ROUTINE
	HRRM	T2,(T1)		;MAKE INSTRUCTION USEFUL
	POPJ	P,		;DONE

;CHECK FOR DMOVEM/XJEN TO PI CHANNEL INTERRUPT LOCATION
FIXIN5:	MOVE	T2,(T1)		;GET WORD
	CAME	T2,[XJEN -1]	;AC FIELD IS JRST CLASS OPCODE
	TLZ	T2,(Z 17,0)	;CLEAR OUT AC FIELD
	CAME	T2,[DMOVEM -1]	;MAGIC OPCODE?
	CAMN	T2,[XJEN -1]	;...
	SKIPA	T2,.CPDRV##	;YES--DRIVER DISPATCH
	JRST	FIXIN6		;TEST SOMETHING ELSE
	MOVE	T2,DRVPIC(T2)	;GET PI CHANNEL
	LSH	T2,1		;TIMES 2
	ADDI	T2,40-1		;COMPUTE INTERRUPT LOCATION
	ADD	T2,.CPEPT##	;INDEX INTO EPT
	HRRZ	T2,1(T2)	;GET RH (XPCW CHXX)
	HRRM	T2,(T1)		;COMPLETE THE INSTRUCTION
	POPJ	P,		;DONE

;CHECK FOR SKIPA TO LOAD DATA BLOCK ADDRESS
FIXIN6:	SKIPE	T2,1(T1)	;FETCH POTENTIAL DATA BLOCK STORAGE
	JRST	FIXIN7		;MUST BE ZERO
	HLRZ	T2,0(T1)	;GET POSSIBLE SKIPA
	TRZ	T2,(<Z 17,0>)	;CLEAR OUT AC FIELD
	CAIE	T2,<SKIPA>_-22	;MAGIC OPCODE?
	JRST	FIXIN7		;NO
	MOVEM	P3,1(T1)	;STORE DATA BLOCK ADDRESS
	AOBJN	P2,.+1		;ADVANCE
	POPJ	P,		;DONE

;CHECK FOR XJRST/JRST FOR JUMP TO INTERRUPT HANDLER
FIXIN7:	SKIPE	T2,1(T1)	;FETCH POTENTIAL DATA BLOCK STORAGE
	JRST	FIXINX		;MUST BE ZERO
	HLRZ	T2,0(T1)	;GET POSSIBLE SKIA
IFE FTXMON,<CAIE T2,(JRST @)>	;MAGIC OPCODE?
IFN FTXMON,<CAIE T2,(XJRST)>	;MAGIC OPCODE?
	JRST	FIXINX		;NO
	MOVEM	P4,1(T1)	;STORE INTERRUPT HANDLER ADDRESS
	AOBJN	P2,.+1		;ADVANCE

FIXINX:	POPJ	P,		;DONE
SUBTTL	AUTOCONFIGURATION -- AUTINI - INITIALIZE AUTOCONFIGURATION


	$INIT

;INITIALIZE AUTO-CONFIGURATION
;CALL:	PUSHJ	P,AUTINI
;	<RETURN>

AUTINI::SE1ENT			;RUN IN NZS
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVSI	P1,INTNUM##	;AOBJN POINTER TO INTTAB

AUTIN1:	LDB	F,PINTDB##	;GET DDB ADDRESS
	SKIPE	F		;MUST HAVE A DDB
	SKIPE	DEVNAM(F)	;AND MUST HAVE NO NAME
	JRST	AUTIN2		;ELSE NOT A TRUE AUTOCONFIGURABLE DDB
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAILE	T1,TYPMAX	;REASONABLE CODE?
	JRST	AUTIN2		;NO
	LDB	T2,PINTSZ##	;GET SIZE
	MOVEM	T2,DDBSIZ(T1)	;STORE IT AWAY
	PUSHJ	P,AUTLNK	;PUT THE DDB WHERE IT BELONGS

AUTIN2:	AOBJP	P1,.+1		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	P1,AUTIN1	;ONTO THE NEXT INTTAB ENTRY
	SKIPN	T1,DRVLST	;INITIAL DRIVER DISPATCH
	JRST	AUTIN4		;THERE ARE NONE
	XMOVEI	T2,DRVLST	;"PREVIOUS" DRVLST ENTRY
	MOVEM	T2,PRVLST	;SAVE

AUTIN3:	PUSHJ	P,INIDSP	;DO DISPATCH ADDRESS FIXUPS
	MOVEM	T1,.CPDRV##	;SAVE FOR THOSE ROUTINES WHICH MIGHT NEED IT
	PUSHJ	P,INIADN	;TALLY UP PER-CPU DEVICE COUNTERS
	MOVE	T1,.CPDRV##	;RELOAD DISPATCH
	MOVE	T2,DRVDDL(T1)	;PROTOTYPE DDB LENGTH
	SKIPN	F,DRVDDB(T1)	;PROTOTYPE DDB ADDRESS
	JRST	AUTIN4		;NOTHING TO DO IF NO DDB
	SKIPN	DEVDRV(F)	;IF NO DISPATCH TABLE ADDRESS AS YET,
	MOVEM	T1,DEVDRV(F)	;GIVE IT ONE (SO LNKDDB WORKS)
	LDB	T3,PDVTYP##	;GET TYPE
	MOVEM	T2,DDBSIZ(T3)	;SAVE LENGTH
	PUSHJ	P,AUTLNK	;PUT THE DDB WHERE IT BELONGS
IFN FTMP,<
	MOVE	T1,.CPDRV##	;FROM DISPATCH TABLE,
	MOVE	T1,DRVPIC(T1)	;GET PI CHANNEL
	PUSHJ	P,DDBPIC	;FIXUP IN DEVCPU(F)
> ;END IFN FTMP
	MOVE	T1,.CPDRV##	;RESTORE DISPATCH TABLE ADDRESS

AUTIN4:	MOVEM	T1,PRVLST	;SAVE "PREVIOUS" DISPATCH ADDRESS
	SKIPE	T1,DRVLNK(T1)	;LINK TO NEXT DISPATCH
	JRST	AUTIN3		;LOOP IF MORE
	PUSHJ	P,INIGCC	;FIX UP GLOBAL CPU COUNTERS
	PUSHJ	P,INICKT	;FIX UP COMPATIBLE KONTROLLERS FOR EACH OTHER
	PUSHJ	P,GENSRT	;SORT GENTAB AND SET GENPTR
	POPJ	P,		;RETURN
;MONGEN'ED DEVICE TABLE FIXUP
;ROUTINE TO TALLY UP THE HIGHEST RESERVED DEVICE COUNTERS PER-CPU
;AND STORE THE RESULT AS THE STARTING COUNTER FOR OVERFLOW ALLOCATION

INIADN:	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	SKIPE	T4,@DRVMDT(T1)	;COPY RESERVED COUNTERS
	AOJA	T4,INIAD1	;REMEMBER MONGEN-SPECIFIED

;SETUP DEFAULT MAXIMUM PER-CPU COUNTERS
	LDB	T2,[POINTR (DRVCF2(T1),DR.LIM)] ;GET SYSTEM-WIDE DEVICE LIMIT
	SKIPN	T2		;LIMIT SPECIFIED?
	MOVEI	T2,^D26		;NO--DEFAULT MAXIMUM (I.E. MTA TO MTZ)
	IDIVI	T2,M.CPU##	;COMPUTE HOW MANY PER CPU ALLOWED
	SKIPE	T3		;REMAINDER?
	SUBI	T2,1		;ADJUST
	LSH	T2,37		;LEFT JUSTIFY
	MOVEI	T3,M.CPU##	;COUNTER
	IOR	T4,T2		;SET A BYTE
	LSH	T2,-5		;POSITION
	SOJG	T3,.-2		;LOOP FOR ALL CPUS
	MOVEM	T4,@DRVMDT(T1)	;UPATE

;TALLY UP PER-CPU MAXIMUM COUNTS AND SYSTEM-WIDE COUNT
INIAD1:	MOVE	P1,[POINT 5,T4]	;BYTE POINTER TO MAXIMUM COUNTS
	MOVSI	P2,-6		;AOBJN POINTER
	SETZB	P3,T3		;ZERO SYSTEM-WIDE TOTAL, INITIAL COUNTERS

INIAD2:	ILDB	T2,P1		;GET PER-CPU LIMIT
	ADDI	P3,(T2)		;ACCUMULATE
	SKIPE	T2		;NON-ZERO?
	DPB	P3,P1		;STORE MAXIMUM PER-CPU COUNT
	AOBJN	P2,INIAD2	;LOOP FOR ALL COUNTS
	DPB	P3,[POINT 5,T3,34] ;STORE SYSTEM-WIDE COUNT

;SETUP INITIAL PER-CPU COUNTERS
	MOVE	P1,[POINT 5,T4]	;BYTE POINTER TO MAXIMUM COUNTS
	MOVE	P2,[POINT 5,T3]	;BYTE POINTER TO INITIAL COUNTS
	MOVSI	P3,-6		;AOBJN POINTER
	SETZB	P4,T2		;CLEAR TEMPORARY COUNTERS

INIAD3:	ILDB	T2,P1		;GET A MAXIMUM COUNT FOR THIS CPU
	IBP	P2		;POSITION FOR INITIAL COUNT STORAGE
	JUMPE	T2,INIAD4	;ANY RESERVED ON THIS CPU?
	DPB	P4,P2		;YES
	MOVEI	P4,(T2)		;GET NEXT VALUE TO STORE

INIAD4:	AOBJN	P3,INIAD3	;LOOP
	EXCH	T3,T4		;T3 = MAXIMUM COUNTS, T4 = INITIAL COUNTS
	DMOVEM	T3,@DRVMDT(T1)	;UPDATE
	POPJ	P,		;RETURN
;DISPATCH TABLE FIXUP
;THIS ROUTINE IS CALLED BY AUTINI TO DO SPECIAL DISPATCH TABLE FIXUPS
;SUCH AS ADJUSTING THE COMMON DISPATCH ENTERIES FOR THE SUBROUTINES
;WHEN THE DRIVER RUNS IN SECTION ONE, AND RESOLVING ADDRESSES OF DATA
;STRUCTURES THAT DO NOT EXIST ARE POINTED TO BY DUMMY IFIWS.  NOTE
;THAT ALTHOUGH THE DRIVER DISPATCH TABLES RESIDE IN THE HIGH SEGMENT,
;CHANGES CAN STILL BE MADE BECAUSE THE HIGH SEGMENT IS WRITE ENABLED
;DURING SYSINI.

INIDSP:
IFN FTXMON,<
	HRLI	T1,(MCSEC1)	;.LINK PSEUDO OP ONLY DEALS WITH
	MOVSI	T2,(MCSEC1)	; 18-BIT ADDRESSES
	HLLM	T2,@PRVLST	; SO MUST FIXUP ALL
	MOVE	T2,T1		;COPY DISPATCH ADDRESS
	HRLI	T2,-<DRVLEN-DRVADF> ;AOBJN POINTER
	MOVSI	T3,(MCSEC1)	;MONITOR CODE SECTION ONE
	HLLM	T3,@PRVLST	;ADJUST PREVIOUS LINK

INIDS1:	MOVE	T4,DRVADF(T2)	;GET AN ADDRESS
	TLNN	T4,-1		;SECTION NUMBER ALREADY THERE?
	HLLM	T3,DRVADF(T2)	;MAKE GLOBAL ADDRESS
	AOBJN	T2,INIDS1	;LOOP BACK

	SKIPN	T2,DRVKDB(T1)	;KDB
	JRST	INIDS2		;NONE THERE
	TLNN	T2,-1
	HRLI	T2,(MCSEC1)
	MOVEM	T2,DRVKDB(T1)

INIDS2:	SKIPE	T2,DRVUDB(T1)	;UDB
	TLNE	T2,-1
	SKIPA
	HRLI	T2,(MCSEC1)
	MOVEM	T2,DRVUDB(T1)

	SKIPE	T2,DRVDDB(T1)	;DDB
	TLNE	T2,-1
	SKIPA
	HRLI	T2,(MCSEC1)
	MOVEM	T2,DRVDDB(T1)

	SKIPE	T2,DRVULP(T1)	;ULP
	TLNE	T2,-1
	SKIPA
	HRLI	T2,(MCSEC1)
	MOVEM	T2,DRVULP(T1)

	SKIPE	T2,DRVMDT(T1)	;MDT
	TLNE	T2,-1
	SKIPA
	HRLI	T2,(MCSEC1)
	MOVEM	T2,DRVMDT(T1)

	SKIPE	T2,DRVICD(T1)	;ICD
	TLNE	T2,-1
	SKIPA
	HRLI	T2,(MCSEC1)
	MOVEM	T2,DRVICD(T1)

	SKIPE	T2,DRVDIA(T1)	;DIAG
	SKIPN	T3,(T2)		;PREPROCESSOR ROUTINE
	JRST	INIDS3		;NO SUPPORT
	TLNE	T3,-1
	SKIPA
	HRLI	T3,(MCSEC1)
	MOVEM	T3,(T2)

INIDS3:	MOVEI	T2,DR.XAD	;BIT TO TEST
	TDNN	T2,DRVCNF(T1)	;EXTENDED ADDRESSING DRIVER?
	POPJ	P,		;NO
	SKIPE	T2,DRVINT(T1)	;INTERRUPT SERVICE
	TLNE	T2,-1		;NZS?
	SKIPA			;NO FIXUP
	HRLI	T2,(MCSEC1)	;FORCE SECTION ONE DISPATCH
	MOVEM	T2,DRVINT(T1)	;UPDATE
	SKIPE	T2,DRVDIA(T1)	;DIAG. UUO DISPATCH TABLE
	TLNE	T2,-1		;NZS?
	SKIPA			;NO FIXUP
	HRLI	T2,(MCSEC1)	;FORCE SECTION ONE DISPATCH
	MOVEM	T2,DRVDIA(T1)	;UPDATE
> ;END IFN FTXMON
	POPJ	P,		;RETURN
;DRIVER DISPATCH TABLE FIXUP
;THIS ROUTINE IS CALLED BY AUTINI TO FIX UP VARIOUS UDB AND DDB PARAMETERS
;FOR COMPATIBLE KONTROLLER TYPES.  IT MAXIMIZES THE LENGTHS OF THE UDB AND
;DDB, AND THE RESTRICTIONS ON WHETHER THE DDB NEEDS TO BE UNCACHED.

INICKT:	PUSHJ	P,SAVE4##	;NEED SOME ACS
	XMOVEI	P1,DRVLST	;WHERE TO START LOOKING

INICK1:	SKIPN	P1,DRVLNK(P1)	;GET NEXT DRIVER IN SYSTEM
	POPJ	P,		;DONE
	SKIPE	P2,DRVCKT(P1)	;DO WE HAVE COMPATIBLE KONTROLLERS?
	SKIPN	1(P2)		;I MEAN REALLY?
	JRST	INICK1		;NO, SKIP THIS ONE
	XMOVEI	P3,DRVLST	;YES, SET PREDECESSOR DRIVER TABLE
	LDB	P4,[POINTR (DRVCNF(P1),DR.DVT)] ;GET OUR DEVICE TYPE

INICK2:	SKIPN	P3,DRVLNK(P3)	;GET NEXT DRIVER TO EXAMINE
	JRST	INICK1		;NONE, TRY OUTER LOOP SOME MORE
	CAMN	P3,P1		;LOOKING AT MY OWN TABLE?
	JRST	INICK2		;YES, AVOID EXPENSIVE NO-OPS
	LDB	T1,[POINTR (DRVCNF(P3),DR.DVT)] ;GET INNER DEVICE TYPE
	CAIE	T1,(P4)		;ARE WE LOOKING AT THE RIGHT TYPE OF DEVICE?
	JRST	INICK2		;NO, LOOK FOR ANOTHER
	MOVE	T1,P2		;YES, POINT TO MY COMPATIBLE KON TABLE
	LDB	T2,[POINTR (DRVCF2(P3),DR.KTY)] ;GET INNER KON TYPE
	PUSHJ	P,MATCKT	;SEE IF HE'S IN MY TABLE
	  JRST	INICK2		;NO, LOOK FOR ANOTHER VICTIM
	MOVEI	T1,DR.UCD	;UNCACHE DDB BIT
	AND	T1,DRVCNF(P3)	;ISOLATE FROM INNER'S TABLE
	IORM	T1,DRVCNF(P1)	;RESTRICT OUTER DRIVER IF NEEDED
	MOVE	T1,DRVDDL(P3)	;GET INNER'S DDB LENGTH NEEDS
	CAMLE	T1,DRVDDL(P1)	;IF LARGER THAN OUR OWN,
	MOVEM	T1,DRVDDL(P1)	;UPDATE OURS
	MOVE	T1,DRVULN(P3)	;GET INNER'S UDB LENGTH NEEDS
	CAMLE	T1,DRVULN(P1)	;IF LARGER THAN OUR OWN,
	MOVEM	T1,DRVULN(P1)	;UPDATE OURS
	JRST	INICK2		;LOOP OVER ALL POTENTIAL MATCHES
;GLOBAL CPU COUNTER FIXUP
;THIS ROUTINE WILL SYNCHRONIZE ALL MDTS FOR DRIVERS WITH DR.GCC SET

INIGCC:	PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,DRVLST	;POINT TO START OF DRIVER CHAIN

INIGC1:	MOVEI	T1,DR.GCC	;BIT TO TEST
	MOVEI	T2,1		;AND ANOTHER
	TDNE	T1,DRVCNF(P1)	;USING GLOBAL CPU COUNTERS?
	TDNN	T2,@DRVMDT(P1)	;MONGEN-SPECIFIED?
	JRST	INIGC2		;NO
	ANDCAM	T2,@DRVMDT(P1)	;CLEAR SO WE DON'T FIND LATER
	MOVEM	P1,.CPDRV##	;SET DISPATCH FOR SUBROUTINE
	PUSHJ	P,ADNFIX	;FIXUP OTHER MDTS

INIGC2:	SKIPE	P1,DRVLNK(P1)	;LINK TO NEXT
	JRST	INIGC1		;LOOP BACK
	POPJ	P,		;RETURN

	$HIGH
SUBTTL	AUTOCONFIGURATION -- AUTKDB - BUILD A KDB


;BUILD A KDB
;CALL:	T1/ MASSBUS UNIT NUMBER (OR -1 IF MEANINGLESS)
;	PUSHJ	P,AUTKDB
;	  <NON-SKIP>		;NO CORE AVAILABLE
;	<SKIP>			;AC W = NEW KDB ADDRESS

AUTKDB::PUSHJ	P,SAVE3##	;SAVE SOME ACS
	MOVE	T4,.CPDRV##	;DRIVER DISPATCH
	MOVE	P1,DRVKDB(T4)	;COPY PROTOTYPE KDB ADDDRESS
	MOVE	P2,DRVKLN(T4)	;COPY PROTOTYPE KDB LENGTH
	HRRZ	P3,.CPDVC##	;<DEVICE CODE>/4
	HRL	P3,T1		;MASSBUS UNIT NUMBER
	PUSHJ	P,FNDKDB	;KDB ALREADY EXIST?
	  JRST	CPOPJ1##	;YES--NOTHING TO DO (KDB ADDRESS IN W)
IFN FTKL10,<
	PUSHJ	P,GETIOW	;GET ICCW
	  POPJ	P,		;NO LOW CORE BLOCKS AVAILABLE
	PUSH	P,T1		;SAVE ADDRESS OF ICCW
>; END IFN FTKL10
	MOVE	T1,P2		;GET PROTOTYPE KDB LENGTH
	PUSHJ	P,GETCOR	;ALLOCATE CORE
	  SKIPA			;CAN'T DO IT
	JRST	AUTKD1		;ONWARD
IFN FTKL10,<
	POP	P,T1		;GET ICCW ADDRESS BACK
	CAIL	T1,PAGSIZ	;LOW CORE BLOCK?
	POPJ	P,		;YES, NOTHING TO RETURN
	PJRST	RTNIOW##	;RETURN LOW CORE BLOCK AND QUIT
>; END IFN FTKL10
IFN FTKS10,<POPJ P,>		;RETURN
AUTKD1:	MOVE	W,T2		;COPY KDB ADDRESS
IFE FTXMON,<
	HRR	T1,T2		;COPY KDB ADDRESS
	HRLI	T1,(P1)		;PROTOTYPE ADDRESS
	ADD	T2,P2		;ADD IN LENGTH OF PROTOTYPE
	BLT	T1,-1(T2)	;COPY INTO WORKING STORAGE
> ;END IFE FTXMON
IFN FTXMON,<
	MOVE	T1,P2		;PROTOTYPE LENGTH
	MOVE	T2,P1		;PROTOTYPE ADDRESS
	MOVE	T3,W		;DESTINATION
	EXTEND	T1,[XBLT]	;COPY INTO WORKING STORAGE
> ;END IFN FTXMON
IFN FTKL10,<POP P,KDBICP(W)>	;STORE ICCW
	MOVE	T1,W		;DATA BLOCK ADDRESS
	MOVE	T2,.CPDRV##	;DRIVER DISPATCH
	MOVE	T2,DRVINT(T2)	;INTERRUPT SERVICE
	PUSHJ	P,AUTICD	;GENERATE INTERRUPT ROUTINES
	  SKIPA	T1,P2		;FAILED--GET KDB LENGTH
	JRST	AUTKD2		;ONWARD
	MOVE	T2,W		;GET KDB ADDRESS
	PJRST	GIVWDS##	;RETURN CORE

AUTKD2:	MOVEM	T2,KDBVIN(W)	;SAVE VECTOR ADDRESS FOR CURIOUS EYES
IFN FTKL10,<
	MOVEM	T1,KDBCSO(W)	;DITTO FOR SKIP CHAIN ADDRESS
	MOVE	T2,.CPDRV##	;DRIVER DISPATCH
	MOVE	T2,DRVPIC(T2)	;PI CHANNEL
	SKIPE	T1		;MAY NOT HAVE A SKIP CHAIN
	PUSHJ	P,AUTCSO	;LINK INTO CONSO SKIP CHAIN
	MOVE	T1,KDBICP(W)	;GET ICCW
	ADDI	T1,3		;POINT TO VECTORED INTERRUPT WORD
	HRLI	T1,744002	;ASSUME RH20 FLAVOR OF VECTOR
	HRRZ	T2,.CPDVC##	;GET DEVICE CODE
	CAIL	T2,FSTICD/4	;AN RH20?
	CAILE	T2,LSTICD/4	;...
	HRLI	T1,444002	;RH10-STYLE VECTOR
	MOVEM	T1,KDBIVI(W)	;SAVE
>; END IFN FTKL10
IFN FTKL10,<HRRZ T1,.CPDVC##>	;GET DEVICE CODE
IFN FTKS10,<LDB T1,[POINT 21,.CPDVC##,35]> ;GET UNIBUS ADDRESS OF DEVICE
	MOVEM	T1,KDBDVC(W)	;SAVE
IFN FTKS10,<
	PUSHJ	P,AUTVII	;COMPUTE ADDRESS OF INTERRUPT INSTRUCTION
	MOVEM	T1,KDBIVI(W)	;SAVE IVAR
	MOVE	T2,KDBVIN(W)	;GET ADDRESS OF VECTOR ROUTINE
	HRLI	T2,(XPCW)	;INTERRUPT INSTRUCTION IS AN XPCW
	MOVEM	T2,0(T1)	;SAVE IN VECTOR INTERRUPT TABLE
>; END IFN FTKS10

	MOVE	T1,.CPDRV##	;DRIVER DISPATCH
	MOVEM	T1,KDBDSP(W)	;STORE
	PUSHJ	P,AUTADN	;ALLOCATE A PER-CPU DEVICE NUMBER
	MOVE	T2,KDBNAM(W)	;GET NAME SO FAR
	PUSHJ	P,AUTNAM	;GENERATE DEVICE NAME
	MOVEM	T1,KDBNAM(W)	;UPDATE
	HLRE	T1,P3		;GET MASSBUS UNIT NUMBER
	HRLM	T1,KDBUNI(W)	;SET UNIT NUMBER OR -1
	MOVE	T2,T1		;MAKE A COPY
	MOVEI	T3,1		;GET A BIT
	LSH	T3,(T2)		;POSITION FOR PARTICULAR MASSBUS UNIT
	SKIPL	T1		;NEGATIVE IF NON-MULTI UNIT KONTROLLER
	HRRM	T3,KDBUNI(W)	;STORE ATTENTION BIT
	PUSHJ	P,SETULB	;SET UP MICROCODE LOADER BLOCK
	MOVE	T1,.CPDRV##	;DRIVER DISPATCH
	LDB	T1,[POINTR (DRVCF2(T1),DR.DMX)] ;GET MAX NUMBER OF DRIVES
	JUMPE	T1,AUTKD3	;JUMP IF DON'T SUPPORT ANY
	ADDM	W,KDBIUN(W)	;FIX UP INITIAL UDB POINTER
	ADDM	W,KDBCUN(W)	;FIX UP CURRENT UDB POINTER
	SUBI	T1,1		;CUZ WE COUNT FROM 0 TO N-1
	ADD	T1,KDBIUN(W)	;COMPUTE FINAL UDB POINTER
	MOVEM	T1,KDBFUN(W)	;STORE ADDRESS
AUTKD3:	MOVE	T1,.CPBIT##	;GET BIT FOR THIS CPU
	IORM	T1,KDBCAM(W)	;SET ACCESSIBILITY MASK IN KDB
IFN FTKL10,<
	MOVSI	T1,-<KDBIOE-KDBIOB> ;NUMBER OF WORDS TO CHECK
	XMOVEI	T2,KDBIOB(W)	;STARTING WORD
	HRRZ	T3,.CPDVC##	;<DEVICE CODE>/4
	PUSHJ	P,AUTDVC	;SET DEVICE CODES
>; END IFN FTKL10

	MOVE	T1,W		;KDB ADDRESS
	MOVE	T4,.CPDRV##	;DISPATCH
	MOVE	T2,DRVKLN(T4)	;KDB LENGTH
	MOVEI	T3,DR.UCK	;BIT TO TEST
	TDNE	T3,DRVCNF(T4)	;WANT TO UNCACHE THE KDB?
	PUSHJ	P,UNCACH	;UNCACHE THE ADDRESS RANGE
	PUSHJ	P,LNKKDB	;LINK KDB TO CHN AND OTHER KDBS
	JRST	CPOPJ1##	;RETURN
;ROUTINE TO SEE IF A KDB ALREADY EXISTS
FNDKDB:	MOVE	T1,.CPDRV##	;DRIVER DISPATCH
	LDB	T1,[POINTR (DRVCNF(T1),DR.DVT)] ;DEVICE TYPE
	XMOVEI	W,KDBTAB-KDBNXT(T1) ;SET PREDECESSOR
	MOVE	T1,.CPBIT##	;CPU BIT

FNDKD1:	SKIPN	W,KDBNXT(W)	;KDB THERE?
	JRST	CPOPJ1##	;NO
IFN FTKL10,<
	MOVE	T3,KDBDVC(W)	;GET <DEVICE CODE>/4 FROM KDB
	HLL	T3,KDBUNI(W)	;AND UNIT NUMBER TOO
	TDNE	T1,KDBCAM(W)	;ON THE RIGHT CPU?
	CAME	P3,T3		;AND DEVICE CODE & UNIT NUMBER MATCH?
>; END IFN FTKL10
IFN FTKS10,<
;*** KS10 CODE HERE
>; END IFN FTKS10
	JRST	FNDKD1		;NO
	POPJ	P,		;RETURN WITH KDB ADDRESS IN W
;ROUTINE TO LINK UP KDBS
LNKKDB:	MOVE	T1,.CPCHA##	;CHANNEL DATA BLOCK ADDRESS
	MOVEM	T1,KDBCHN(W)	;LINK TO KDB
	MOVSI	T2,-1		;MAKE CHANNEL'S LIST
	ADDB	T2,CHNTBP(T1)	; OF KDBS ONE LONGER
	AOBJN	T2,.		;MOVE TO END OF EXISTING KDBS
	MOVEI	T2,-1(T2)	;GET ADDRESS OF WHERE TO STORE KDB
	CAIL	T2,CHNLEN(T1)	;BETTER BE WITHIN THE CHANNEL DATA BLOCK!
	STOPCD	.,STOP,AUTTMK,	;++TOO MANY KDBS ON CHANNEL
	MOVEM	W,(T2)		;STORE KDB ADDRESS IN CHN

	MOVE	T1,.CPDRV##	;DRIVER DISPATCH
	LDB	T1,[POINTR (DRVCNF(T1),DR.DVT)] ;GET DEVICE TYPE
	XMOVEI	T1,KDBTAB(T1)	;POINT TO HEAD OF KDB CHAIN
	SUBI	T1,KDBNXT	;FAKE UP PREDECESSOR
	SYSPIF			;INTERLOCK

LNKKD1:	SKIPN	T2,KDBNXT(T1)	;LINK THIS KDB INTO CHAIN
	JRST	LNKKD2		;END OF CHAIN
	MOVE	T3,KDBNAM(T2)	;GET KDB NAME
	CAML	T3,KDBNAM(W)	;IN PROPER ASCENDING ORDER?
	JRST	LNKKD2		;SPLICE NEW KDB HERE
	MOVE	T1,T2		;COPY PREVIOUS
	JRST	LNKKD1		;LOOP BACK

LNKKD2:	MOVEM	T2,KDBNXT(W)	;LINK NEXT TO NEW
	MOVEM	W,KDBNXT(T1)	;LINK THIS TO PREVIOUS
	SYSPIN			;RELEASE INTERLOCK
	POPJ	P,		;RETURN
SUBTTL	ENTRY POINT -- AUTKIL - KILL (DELETE) A DDB


;THIS ROUTINE WILL UNLINK A DDB FROM THE DEVLST CHAIN, DELETE THE DDB,
;AND CLEAN UP ANY GENTAB ENTRIES THAT MAY EXIST.
;CALL:	MOVE	T1, DDB LENGTH
;	MOVE	T2, DDB ADDRESS
;	PUSHJ	P,AUTKIL
;	<RETURN>

AUTKIL::SE1ENT			;ENTER SECTION ONE
	PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	PUSH	P,F		;SAVE F
	DMOVE	P1,T1		;COPY ARGUMENTS
	MOVE	F,P2		;GET DDB ADDRESS
	PUSHJ	P,GENDEL	;DELETE GENTAB ENTRY IF NECESSARY
	MOVE	F,P2		;...
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	DDBSRL			;INTERLOCK DDB SCANNING
	SKIPE	F,DDBTAB(T1)	;PICK UP PROTOTYPE DDB
	SKIPE	T1,DEVNAM(F)	;MAKE SURE IT IS A PROTOTYPE
	TRNA			;NO PROTOTYPE--MUST SEARCH
	JRST	AUTKI2		;GOT IT--GO DELETE OUR ARGUMENT
	XMOVEI	F,DEVLST##-DEVSER ;GET META-PROTOTYPE
	HLRZ	T2,DEVNAM(F)	;GET GENERIC PORTION OF NAME
	SKIPE	T2		;IF ANY
	SKIPL	T1,GENPTR##	;GET AOBJN INDEX TO GENTAB
	JRST	AUTKI2		;NONE THERE--JUST TAKE IT FROM THE TOP

AUTKI1:	CAML	T2,GENTAB##(T1)	;HAVE WE FOUND OUR NICHE?
	JRST	AUTKI2		;YES--NOW SCAN THE CHAIN
	SKIPE	GENTAB##+1(T1)	;IF THERE IS A POINTER,
	MOVE	F,GENTAB##+1(T1) ;UPDATE OUR G.L.B.
	AOBJP	T1,AUTKI2	;ACCOUNT FOR TWO-WORD ENTRIES
	AOBJN	T1,AUTKI1	;LOOP OVER ALL LESSER NAMES IN GENTAB
				;FALL THROUGH TO AUTKI2

AUTKI2:	CAMN	P2,F		;MATCH?
	JRST	AUTKI3		;YES
	MOVE	T1,F		;COPY CURRENT TO PREVIOUS
	HLRZ	F,DEVSER(F)	;LINK TO NEXT DDB
	JUMPN	F,AUTKI2	;KEEP SEARCHING
	DDBSRU			;RELEASE INTERLOCK
	JRST	FPOPJ##		;GIVE UP

AUTKI3:	HLRZ	T2,DEVSER(F)	;GET POINTER TO NEXT DDB
	SKIPE	T1		;HAVE A PREVIOUS?
	HRLM	T2,DEVSER(T1)	;YES--POINT PREVIOUS AT IT
	LDB	T1,PDVTYP##	;GET INCOMING DEVTYP
	CAME	F,DDBTAB(T1)	;SKIP OVERHEAD IF NOT FIRST OF ITS KIND
	JRST	AUTKI4		;RIGHT
	SKIPE	F,T2		;NO PROTOTYPE--MOVE SUCCESSOR
	LDB	T2,PDVTYP##	;GET ITS DEVTYP
	CAIE	T1,(T2)		;DO THEY MATCH?
	SETZ	F,		;NO--PUNT THIS HEADER
	MOVEM	F,DDBTAB(T1)	;UPDATE FOR DEVCHK
AUTKI4:	MOVE	T1,DEVLST##	;GET START OF CHAIN
	MOVEM	T1,HNGLST##	;UPDATE SHADOW COPY
IFN FTNET,<
	MOVE	F,P2		;RESTORE INCOMING DDB ADDRESS
	SKIPE	T1,DEVDRV(F)	;IF A DRIVER,
	HRRZ	T1,DRVDDB(T1)	;POINT AT ITS PROTOTYPE *** NON-EXTENDED
	CAIN	T1,(F)		;IF A PROTOTYPE,
	JRST	AUTKI5		;DON'T COUNT IT
	LDB	T1,PDVSTA##	;GET ITS NODE NUMBER
	CAME	T1,ANFNUM##	;IF NOT LOCAL,
	JRST	AUTKI5		;DON'T COUNT IT
	LDB	T1,PDVTYP##	;GET DEVICE TYPE AGAIN
	SOSGE	DDBCNT(T1)	;COUNT A DEVICE LOST
	SETZM	DDBCNT(T1)	;SANITY CHECK
	PUSHJ	P,NETDEV##	;UPDATE COUNTS IN NETNDB
> ;END IFN FTNET
AUTKI5:	DDBSRU			;RELEASE INTERLOCK
	DMOVE	T1,P1		;GET ARGUMENTS BACK
	SKIPE	T1		;IF SIZE WAS GIVEN,
	PUSHJ	P,GIVWDS##	;RELEASE CORE
	JRST	FPOPJ##		;RESTORE F AND RETURN
SUBTTL	ENTRY POINT -- AUTKSN - PROCESS KONTROLLER SERIAL NUMBERS


;THIS ROUTINE WILL STORE KONTROLLER SERIAL NUMBERS
;CALL:	MOVE	W,  KDB ADDRESS
;	DMOVE	T1, SERIAL NUMBER WORDS
;	PUSHJ	P,AUTKSN

AUTKSN::PUSHJ	P,SAVT##	;SAVE SOME ACS
	SETZ	T3,		;NO DRIVE NUMBER STUFF
	PUSHJ	P,AUTDSN	;FIXUP S/N IF ZERO
	DMOVEM	T1,KDBSER(W)	;STORE SERIAL NUMBER WORDS
	POPJ	P,		;RETURN
SUBTTL	ENTRY POINT -- AUTMDT - SCAN THE MONGEN'ED DEVICE TABLES


;SCAN MONGEN'ED DEVICE TABLE
;THIS ROUTINE WILL SCAN FIRST THE MONGEN'ED DEVICE TABLE AND THEN
;THE DEFAULT TABLE (FROM THE DRIVER) FOR A MATCH ON THE FOLLOWING
;FIELDS:
;	1. CPU (COMPARED WITH .CPDVC)
;	2. DEVICE CODE OR UNIBUS ADDRESS (COMPARED WITH .CPDVC)
;	3. MASSBUS UNIT NUMBER
;	4. PHYSICAL DRIVE NUMBER
;
;ON A SUCCESSFUL MATCH, T1 WILL CONTAIN THE CORRESPONDING DATA WORD
;FROM ONE OF THE TABLES.  THIS DATA WORD IS VERY DEVICE-SPECIFIC.
;DEFINITIONS FOR THIS WORD SHOULD BE DEFINED AS GLOBALS IN THE DRIVER
;OR THE SERVICE ROUTINES.
;
;CALL:	MOVE	T1, ADDRESS OF MONGEN'ED DEVICE TABLE
;	MOVE	T2, ADDRESS OF DEFAULT TABLE
;	MOVE	T3, UNIT,,DRIVE
;	MOVE	T4, FLAGS
;	PUSHJ	P,AUTMDT
;	  <NON-SKIP>
;	<SKIP>
;
;UNIT MAY BE:
;	1. AN MASSBUS UNIT NUMBER
;	2. -1 TO MATCH ON ANY MASSBUS UNIT
;
;DRIVE MAY BE:
;	1. A PHYSICAL DRIVE NUMBER
;	2. -1 TO MATCH ON ANY PHYSICAL DRIVE
;
;FLAGS MAY BE:
;	ANY VALID MD.XXX BITS
;
;NOTE THAT SPECIFYING -1,,-1 WILL CAUSE A MATCH ON ONLY THE CPU AND
;KONTROLLER FIELDS.

IFN FTKL10,<
AUTMDT::PUSHJ	P,SAVE4##	;SAVE SOME ACS
	DMOVE	P1,T1		;COPY TABLE ADDRESSES
	DMOVE	P3,T3		;COPY MASSBUS UNIT,,DEVICE AND FLAGS
	HLRZS	T1		;GET POSSIBLE SECTION NUMBER
	CAIN	T1,(MCSEC1)	;SECTION ONE?
	HRRZS	P1		;YES
	SKIPE	P1		;ZERO (MAYBE EXCLUDING MONGEN'ED TABLE)?
	CAML	P1,SYSSIZ##	;TABLE FROM MONGEN?
	SKIPA			;DON'T ADJUST
	ADDI	P1,2		;SKIP OVER PER-CPU COUNTERS
	HRL	P1,T1		;RESTORE POSSIBLE SECTION NUMBER
	HLRZS	T2		;GET POSSIBLE SECTION NUMBER
	CAIN	T2,(MCSEC1)	;SECTION ONE?
	HRRZS	P2		;YES
	SKIPE	P2		;ZERO (MAYBE NOT USING INTERNAL TABLE)?
	CAML	P2,SYSSIZ##	;INCASE ARGUMENTS PASSED BACKWARDS
	SKIPA			;DON'T ADJUST
	ADDI	P2,2		;...
	HRL	P2,T2		;RESTORE POSSIBLE SECTION NUMBER

AUTMD1:	PUSHJ	P,MDTSCN	;TRY THE MONGEN'ED TABLE
	  JRST	AUTMD2		;NO MATCH
	JRST	AUTMD3		;MAKE SURE IT'S OK

AUTMD2:	SKIPE	P1,P2		;GET DEFAULT TABLE
	PUSHJ	P,MDTSCN	;AND GIVE IT A WHIRL
	  POPJ	P,		;GIVE UP
	SETZ	P2,		;AVOID RECURSION

AUTMD3:	MOVE	T1,1(P1)	;GET DATA FOR THIS ENTRY
	LDB	T2,PMDDVC	;AND DEVICE CODE
	JUMPN	T2,CPOPJ1##	;RETURN IF HAVE ONE
	PUSHJ	P,MDTDVC	;LOOK FOR A DEVICE CODE
	  POPJ	P,		;NONE FOUND
	JRST	CPOPJ1##	;RETURN GOODNESS


PMDCPU:	POINTR	((P1),MD.CPU)	;BYTE POINTER TO CPU
PMDDVC:	POINTR	((P1),MD.DVC)	;BYTE POINTER TO DEVICE CODE
PMDUNI:	POINTR	((P1),MD.UNI)	;BYTE POINTER TO MASSBUS UNIT
PMDDRV:	POINTR	((P1),MD.DRV)	;BYTE POINTER TO PHYSICAL DRIVE
MDTSCN:	SKIPN	T1,(P1)		;END OF TABLE?
	POPJ	P,		;YES--NO MATCH
	CAMN	T1,[EXP -1]	;ENTRY TO BE PATCHED BY RUNNING MONITOR?
	AOJA	P1,MDTSC1	;IGNORE IT

;CHECK CPU AND DEVICE CODE
	LDB	T1,PMDCPU	;GET CPU NUMBER
	CAIN	T1,7		;ALL CPUS?
	MOVE	T1,.CPCPN##	;MAKE IT OURS
	ROT	T1,-3		;PUT IN BITS 0-2
	LDB	T2,PMDDVC	;GET DEVICE CODE
	CAIN	T2,0		;ANY DEVICE CODE?
	HRRZ	T2,.CPDVC##	;...
	HRR	T1,T2		;MERGE THE TWO
	CAME	T1,.CPDVC##	;MATCH SO FAR?
	AOJA	P1,MDTSC1	;NO

;CHECK KONTROLLER DEFINITION
	MOVEI	T1,MD.KON	;BIT TO TEST
	TRNE	P4,MD.KON	;WANT KONTROLLER DEFINITION?
	TDNN	T1,(P1)		;AND IS THIS ONE?
	SKIPA			;NO
	JRST	CPOPJ1##	;FOUND A MATCH

;CHECK MASSBUS UNIT NUMBER
	LDB	T1,PMDUNI	;GET MASSBUS UNIT NUMBER
	HLRZ	T2,P3		;GET POSSIBLE UNIT NUMBER
	TLC	P3,-1		;MATCH ON
	TLCN	P3,-1		; ALL UNITS?
	MOVEI	T2,(T1)		;YES
	CAIE	T1,(T2)		;COMPARE
	AOJA	P1,MDTSC1	;TRY ANOTHER

;CHECK PHYSICAL DRIVE
	LDB	T1,PMDDRV	;GET DRIVE NUMBER
	HRRZ	T2,P3		;GET POSSIBLE DRIVE NUMBER
	TRC	P3,-1		;MATCH ON
	TRCN	P3,-1		; ALL DRIVES?
	MOVEI	T2,(T1)		;YES
	CAIE	T1,(T2)		;COMPARE
	AOJA	P1,MDTSC1	;TRY ANOTHER

;FINALLY HAVE A MATCH
	JRST	CPOPJ1##	;RETURN

MDTSC1:	AOS	P1		;ADVANCE TO NEXT ENTRY
	JRST	MDTSCN		;LOOP BACK AND TRY AGAIN
MDTDVC:	PUSH	P,P1		;SAVE ENTRY ADDRESS FOR A MOMENT

MDTDV1:	MOVEI	P4,MD.KON	;WANT A KONTROLLER DEFINITION
	PUSHJ	P,MDTSCN	;CONTINUE CHECKING THE TABLE
	  JRST	MDTDV2		;GO LOOK AT DEFAULT TABLE
	LDB	T2,PMDDVC	;GET DEVICE CODE
	JUMPN	T2,MDTDV3	;RETURN IF ONE EXISTS
	JRST	MDTDV1		;ELSE KEEP CHECKING THIS TABLE

MDTDV2:	SKIPN	P1,P2		;POINT TO THE DEFAULT TABLE
	JRST	MDTDV4		;ALREADY DID IT
	SETZ	P2,		;ONLY DO THIS ONCE
	JRST	MDTDV1		;LOOP BACK AND TRY AGAIN

MDTDV3:	AOS	-1(P)		;SKIP
MDTDV4:	POP	P,P1		;GET ORIGINAL ENTRY ADDRESS BACK
	POPJ	P,		;AND RETURN
>; END IFN FTKL10
;THE CROCKY KS EQUIVALENT

IFN FTKS10,<
AUTMDT::LDB	T1,[POINT 21,.CPDVC##,35] ;*** GET CURRENT UNIBUS ADAPTER & ADDRESS
	CAMN	T1,1(T2)	;*** MATCH WHAT DRIVER IS LOOKING FOR?
	PUSHJ	P,UBGOOD##	;*** DOES DEVICE EXIST?
	  POPJ	P,		;*** NO
	LDB	T1,[POINTR (0(T2),MD.IVI)] ;*** GET IVI FROM DRIVER
	DPB	T1,[POINT 7,.CPDVC##,9] ;*** STORE IN .CPDVC
	JRST	CPOPJ1##	;*** GIVE GOOD RETURN
>; END IFN FTKS10
SUBTTL	AUTOCONFIGURATION -- AUTMSK - SET/CLEAR DRIVE BITS IN A KDB MAP


;ROUTINE TO TOGGLE THE STATE OF A DRIVE BIT IN A KDB BIT MAP
;CALL:	MOVE	W,  KDB ADDRESS
;	MOVE	T1, PHYSICAL DRIVE NUMBER
;	MOVE	T2, STATE,,MASK OFFSET WORD
;	PUSHJ	P,AUTMSK
;	  <NON-SKIP>		;ILLEGAL DRIVE NUMBER
;	<SKIP>			;STATE SET AS REQUESTED
;

AUTMSK::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	HLRZ	P1,T2		;SAVE ON/OFF STATE
	HRRZ	P2,T2		;GET MASK OFFSET WORD
	ADD	P2,W		;INDEX INTO KDB
	MOVE	T2,KDBDSP(W)	;DRIVER DISPATCH
	LDB	T2,[POINTR (DRVCF2(T2),DR.HDN)] ;HIGHEST DRIVE ON KONT
	CAILE	T1,(T2)		;WITHIN RANGE?
	POPJ	P,		;NO
	IDIVI	T1,44		;DRIVES MAPPED PER WORD
	MOVE	T2,BITTBL##(T2)	;TRANSLATE DRIVE NUMBER TO BIT
	HRRZ	T3,(P2)		;GET OFFSET TO MASK IN KDB
	ADD	T3,W		;INDEX TO START OF MAP
	ADDI	T3,(T1)		;INDEX INTO MAP
	JUMPE	P1,AUTMS1	;GO IF CLEARING BIT
	SYSPIF			;INTERLOCK
	IORM	T2,(T3)		;SET BIT FOR SPECIFIED DRIVE
	HRROS	(P2)		;SET FLAG TOO
	SYSPIN			;RELEASE INTERLOCK
	JRST	CPOPJ1##	;RETURN

AUTMS1:	DMOVE	T3,T2		;COPY BIT AND ADDRESS TO A SAFER PLACE
	MOVE	T1,KDBDSP(W)	;DRIVER DISPATCH
	LDB	T1,[POINTR (DRVCF2(T1),DR.HDN)] ;HIGHEST DRIVE ON KONT
	ADDI	T1,44		;ROUND UP
	IDIVI	T1,44		;COMPUTE WORDS IN MAP
	HRRZ	T2,(P2)		;OFFSET TO START OF MAP
	ADD	T2,W		;INDEX INTO KDB
	SYSPIF			;INTERLOCK
	ANDCAM	T3,(T4)		;CLEAR BIT FOR SPECIFIED DRIVE
	HRRZS	KDBIUM(W)	;ASSUME NO OTHER IGNORED DRIVES

AUTMS2:	SKIPE	(T2)		;ANY BITS SET?
	JRST	AUTMS3		;YES
	AOS	T2		;ADVANCE TO NEXT WORD
	SOJG	T1,AUTMS2	;LOOP THROUGH MAP
	SKIPA			;NO OTHER DRIVES IGNORED

AUTMS3:	HRROS	(P2)		;FLAG OTHER DRIVES STILL MARKED IN MAP
	SYSPIN			;RELEASE INTERLOCK
	JRST	CPOPJ1##	;RETURN
SUBTTL	AUTOCONFIGURATION -- AUTNAM - SET UP A DEVICE NAME


;ROUTINE TO BUILD A DEVICE NAME
;CALL:	MOVE	T1, SIXBIT /NAME/
;	MOVE	T2, NUMBER
;	PUSHJ	P,AUTNAM
;
;ON RETURN, T1 HAS THE UPDATED NAME

AUTNAM::MOVE	T4,.CPDRV##	;DRIVER DISPATCH
	MOVE	T4,DRVCNF(T4)	;GET CONFIG WORD
	TRNE	T4,DR.NMC	;NAME INCLUDE CPU NUMBER?
	TROA	T1,'0'		;YES
	ADDI	T1,'A'		;ELSE TRANSLATE NUMBER TO NAME
	ROT	T1,-6		;LEFT JUSTIFY
	MOVSI	T3,770000	;CHARACTER MASK
	MOVSI	T4,-6		;AOBJN POINTER

AUTNA1:	TDNN	T3,T2		;CHARACTER IN USE
	JRST	AUTNA2		;NO
	LSH	T1,-6		;SLIDE CHARACTER OVER
	LSH	T3,-6		;AND MASK TOO
	AOBJN	T4,AUTNA1	;LOOP BACK
	POPJ	P,		;FULL WORD NAME?

AUTNA2:	IOR	T1,T2		;MERGE WITH CHARACTER
	POPJ	P,		;AND RETURN
SUBTTL	AUTOCONFIGURATION -- AUTSET - SET UP CPU VARIABLES


;CALL:	MOVE	T1, <DEVICE CODE>/4 (OR <IVI>B9 + <UNIBUS ADDR>B35)
;	MOVE	T2, DISPATCH
;	MOVE	T3, CHANNEL DATA BLOCK
;	PUSHJ	P,AUTSET
;	<RETURN>

AUTSET::MOVE	T4,.CPCPN##	;GET CPU NUMBER
	DPB	T4,[POINT 3,T1,2] ;STORE IN BITS 0-2
	MOVEM	T1,.CPDVC##	;STORE <CPU>B2 + (<DEVICE CODE>/4 OR UBA ADDR)
	MOVEM	T2,.CPDRV##	;STORE DRIVER DISPATCH
	MOVEM	T3,.CPCHA##	;STORE CHANNEL DATA BLOCK ADDRESS
IFN FTKL10,<
	DPB	T1,[POINT 7,.CPCNI##,9] ;MAKE CONI
	DPB	T1,[POINT 7,.CPCNO##,9] ;MAKE CONO
	DPB	T1,[POINT 7,.CPDTI##,9] ;MAKE DATAI
	DPB	T1,[POINT 7,.CPDTO##,9] ;MAKE DATAO
	DPB	T1,[POINT 7,.CPBKI##,9] ;MAKE BLKI
	DPB	T1,[POINT 7,.CPBKO##,9] ;MAKE BLKO
>; END IFN FTKL10
	POPJ	P,		;RETURN
SUBTTL	AUTOCONFIGURATION -- AUTSYS - SYSINI/ONCE ONLY DDB LINKAGE


	$INIT

AUTSYS::PUSHJ	P,SAVE4##	;SAVE SOME ACS
	XMOVEI	F,DEVLST##-DEVSER ;PRESET LINKAGE
	MOVSI	P1,INTNUM##	;AOBJN POINTER TO INTTAB

AUTSY1:	LDB	F,PINTDB##	;PROTOTYPE DDB ADDRESS
	JUMPE	F,AUTSY3	;NOTHING TO DO IF NO DDB
	LDB	P3,PINTSZ##	;PROTOTYPE DDB LENGTH
	LDB	P4,PINTNO##	;NUMBER OF DDBS TO CREATE
	MOVNS	P4		;NEGATE
	HRLZS	P4		;MAKE AN AOBJN POINTER

AUTSY2:	PUSHJ	P,DDBCOP	;COPY PROTOTYPE DDB
	  JRST	AUTSY3		;NO CORE FOR DDB
	PUSHJ	P,DDBNAM	;FIX UP NAME
	LDB	T1,PINTCH##	;GET PI CHANNEL NUMBER
	PUSHJ	P,DDBPIC	;FIX UP INTERLOCK
	MOVE	T1,JBTLOC##	;LOCAL STATION NUMBER
	DPB	T1,PDVSTA##	;STORE FOR NETSER
	PUSHJ	P,AUTLNK	;LINK IT INTO DEVLST
	AOBJN	P4,AUTSY2	;LOOP CREATING ALL NECESSARY DDBS

AUTSY3:	AOBJN	P1,.+1		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	P1,AUTSY1	;ONTO THE NEXT INTTAB ENTRY
IFN FTNET,<PUSHJ P,NETDEV##>	;UPDATE DEVICE COUNTS IN HOST NDB
;LINK DEVICE SERVICE ROUTINES TOGETHER

	MOVSI	P1,INTNUM##	;NEGATIVE NUMBER OF SERVICE ROUTINES*2
AUTSY7:	LDB	T1,PINTCH##	;GET NEXT PI NUMBER
	JUMPE	T1,AUTSY9	;DOES THIS DEVICE HAVE A PI CHANNEL (PTY)?
	LSH	T1,1		;SHIFT LEFT ONE SO MATCH PI LOCATIONS
	LDB	T2,PINTCP##	;GET CPU NUMBER
	IMULI	T2,.CPLEN##	;OFFSET TO CDB
	MOVE	T2,.C0EPT##(T2)	;GET EPT ADDRESS
	ADDI	T2,(T1)		;OFFSET INTO INTERRUPT LOCS
	MOVE	T2,.EPIL(T2)	;GET INTERRUPT INSTRUCTION
	ADDI	T2,3		;SKIP XPCW BLOCK

AUTSY8:	HRRZ	T1,T2		;SAVE IT (EITHER JRST DEV'INT OR XJEN CH'N)
	MOVE	T2,1(T1)	;PICK UP INSTR. FOLLOWING INTERRUPT CONSO
	TLNN	T2,000740	;IS IT AN XJEN?
	JRST	AUTSY8		;NO, KEEP LOOKING
	LDB	T3,PINTIN##	;YES, LAST DEVICE SO FAR, GET DEV'INT
	SKIPN	(T3)		;DEV'INT=0?
	JRST	AUTSY9		;YES, MUST BE VECTORED INTERRUPT DEVICE
	HRLI	T3,(JRST)	;MAKE JRST INSTR.
	MOVEM	T3,1(T1)	;CHANGE XJEN CH'N TO JRST DEV'NT
	MOVEM	T2,1(T3)	;MAKE DEV'NT+1 BE XJEN CH'N
AUTSY9:	AOBJN	P1,.+1		;PICKUP EVERY OTHER WORD
	AOBJN	P1,AUTSY7	;ANY MORE INTERRUPT SERVICE ROUTINES?
	POPJ	P,		;NO, RETURN
;COPY PROTOTYPE DDB
DDBCOP:	SKIPE	P4		;ONLY WANT ONE DDB?
	TRNN	P4,-1		;OR IS THIS UNIT ZERO?
	JRST	CPOPJ1##	;JUST RETURN GOODNESS
	MOVEI	T1,(P3)		;LENGTH OF DDB
	PUSHJ	P,GETCOR	;ALLOCATE CORE
	  POPJ	P,		;NONE AVAILABLE
	MOVE	T4,T2		;SAVE ADDRESS
IFE FTXMON,<
	MOVSI	T3,(F)		;PROTOTYPE DDB ADDRESS
	HRR	T3,T2		;DESTINATION
	ADDI	T2,(T1)		;COMPUTE END OF BLT
	BLT	T3,-1(T2)	;COPY
> ;END IFE FTXMON
IFN FTXMON,<
	MOVE	T3,T2		;DESTINATION
	MOVE	T2,F		;PROTOTYPE DDB ADDRESS
	EXTEND	T1,[XBLT]	;COPY
> ;END IFN FTXMON
	MOVE	F,T4		;POSITION NEW DDB ADDRESS
	JRST	CPOPJ1##	;RETURN GOODNESS
;FIX UP DDB NAME
DDBNAM:	HLLZ	T1,DEVNAM(F)	;GENERIC NAME EXIST?
	JUMPE	T1,CPOPJ##	;CAN DO NOTHING WITHOUT IT
	HRRZ	T1,P4		;GET UNIT NUMBER
	DPB	T1,PUNIT##	;STORE IN DDB
	LDB	T2,PDVTYP##	;***GET DEVICE TYPE
	CAIN	T2,.TYDTA	;***DTA?
	JRST	DDBNA2		;***YES
	SKIPN	T4,DEVDRV(F)	;GET DRIVER DISPATCH
	JRST	DDBNA0		;NO DRIVER DISPATCH, ASSUME STATION NUMBERS
				; INCLUDED IN OCTAL DEVICE NAME
	MOVEI	T3,DR.NET	;BIT TO TEST
	TDNN	T3,DRVCNF(T4)	;WANT TO INCLUDE ANF-10 STATION NAMES?
	JRST	DDBNA1		;NO
DDBNA0:	MOVE	T3,JBTLOC##	;LOCAL STATION NUMBER
	DPB	T3,[POINT 6,T1,32] ;SET FOR GENERATING NAME
	TRO	T1,1000		;MAKE SURE OF LEADING ZERO
	JRST	DDBNA2		;FORCE OCTAL

DDBNA1:	MOVEI	T3,DR.DDN	;BIT TO TEST
	TDNE	T3,DRVCNF(T4)	;WANT DECIMAL DEVICE NAME?
	SKIPA	T2,[EXP DECNAM]	;YES
DDBNA2:	MOVEI	T2,OCTNAM	;MAKE IT OCTAL
	PUSHJ	P,(T2)		;GENERATE SIXBIT NUMBER
	HRRM	T1,DEVNAM(F)	;STORE INTO NAME
	POPJ	P,		;RETURN


;FIX UP PI CHANNEL INTERRUPT INTERLOCK
DDBPIC:
IFN FTMP,<
	LDB	T2,DEYCPF##	;GET CPU NUMBER
	CAIE	T2,CPFBOO##	;GENERIC?
	CAIN	T2,CPFBIT##	;BIT MASKED DEVICE?
	TDZA	T2,T2		;YES--USE CPU0 INTERLOCKS
	LSH	T2,3		;(CPU * 10) + CHANNEL
	ADDI	T2,INTL0##(T1)	;OFFSET INTO TABLE
	HRRM	T2,DEVCPU(F)	;SAVE LOCATION OF INTERLOCK
>
	POPJ	P,		;RETURN

	$HIGH
SUBTTL	AUTOCONFIGURATION -- AUTUDB - BUILD A UDB


;BUILD A UDB
;CALL:	MOVE	W,  KDB ADDRESS
;	MOVE	T1, PHYSICAL DRIVE NUMBER,,UDB TABLE OFFSET
;	PUSHJ	P,AUTUDB
;	  <NON-SKIP>		;NO CORE AVAILABLE
;	<SKIP>			;AC U = NEW UDB ADDRESS

AUTUDB::PUSHJ	P,SAVE3##	;SAVE SOME ACS
	MOVE	T4,.CPDRV##	;DRIVER DISPATCH
	MOVE	P1,DRVUDB(T4)	;COPY PROTOTYPE UDB ADDRESS
	MOVE	P2,DRVULN(T4)	;COPY PROTOTYPE UDB LENGTH
	MOVE	P3,T1		;SAVE DRIVE NUMBER AND OFFSET
	HRRZS	T1		;KEEP ONLY UDB TABLE OFFSET
	ADD	T1,KDBIUN(W)	;INDEX INTO TABLE
	SKIPE	U,(T1)		;SEE IF UDB ALREADY EXISTS
	JRST	AUTUD1		;IT DOES SO NO CORE TO ALLOCATE

	MOVE	T1,P2		;GET PROTOTYPE UDB LENGTH
	PUSHJ	P,GETCOR	;ALLOCATE CORE
	  POPJ	P,		;CAN'T DO IT
	MOVE	U,T2		;COPY UDB ADDRESS
	JUMPE	P1,AUTUD1	;ONWARD IF NO PROTOTYPE
IFE FTXMON,<
	HRLI	T2,(P1)		;PROTOTYPE ADDRESS
	BLT	T2,-1(P2)	;COPY INTO WORKING STORAGE
> ;END IFE FTXMON
IFN FTXMON,<
	MOVE	T1,P2		;PROTOTYPE LENGTH
	MOVE	T2,P1		;PROTOTYPE ADDRESS
	MOVE	T3,U		;DESTINATION
	EXTEND	T1,[XBLT]	;COPY INTO WORKING STORAGE
> ;END IFN FTXMON

AUTUD1:	HRRZ	T1,P3		;GET TABLE OFFSET
	ADD	T1,KDBIUN(W)	;INDEX INTO UDB TABLE
	MOVEM	U,(T1)		;SAVE UDB ADDRESS
	HLRZ	T1,P3		;GET PHYSICAL DRIVE NUMBER
	PUSHJ	P,DECNAM	;CONVERT
	IOR	T1,KDBNAM(W)	;INCLUDE KONTROLLER DESIGNATION
	SKIPN	UDBKDB(U)	;DON'T OVERWRITE NAME IF HAVE A PRIMARY KDB
	MOVEM	T1,UDBNAM(U)	;SAVE
	HLRZM	P3,UDBPDN(U)	;STORE PHYSICAL DRIVE NUMBER
	MOVE	T1,.CPBIT##	;GET BIT FOR THIS CPU
	IORM	T1,UDBCAM(U)	;SET ACCESSIBILITY MASK IN UDB
	PUSHJ	P,LNKUDB	;LINK UP UDB TO KDB AND UNCACHE IF NEEDED
	JRST	CPOPJ1##	;RETURN
;ROUTINE TO LINK UP UDB TO KDB AND UNCACHE UDB IF NECESSARY
;CALL:	MOVE	U, UDB ADDRESS
;	MOVE	W, KDB ADDRESS
;	PUSHJ	P,LNKUDB

LNKUDB:	XMOVEI	T1,UDBKDB(U)	;POINT TO UDB'S TABLE
	MOVSI	T2,-MXPORT	;AOBJN POINTER
	SETZ	T3,		;CLEAR FREE SLOT ADDRESS

LNKUD1:	CAMN	W,(T1)		;FOUND EXISTING ENTRY?
	JRST	LNKUD3		;NO NEED TO UPDATE TABLE
	SKIPE	(T1)		;FREE SLOT?
	JRST	LNKUD2		;NO
	SKIPN	T3		;ALREADY FOUND FIRST FREE ENTRY?
	MOVE	T3,T1		;NO--REMEMBER ADDRESS
LNKUD2:	AOS	T1		;ADVANCE POINTER
	AOBJN	T2,LNKUD1	;KEEP SEARCHING
	SKIPE	T3		;TABLE FULL??
	MOVEM	W,(T3)		;POINT UDB BACK TO KDB

LNKUD3:	MOVE	T3,KDBCAM(W)	;CURRENT KDB'S ACCESSIBILITY MASK
	IORM	T3,UDBCAM(U)	;UPDATE FOR UDB
	MOVE	T1,U		;UDB ADDRESS
	MOVE	T4,.CPDRV##	;DISPATCH
	MOVE	T2,DRVULN(T4)	;UDB LENGTH
	MOVEI	T3,DR.UCU	;BIT TO TEST
	TDNE	T3,DRVCNF(T4)	;WANT TO UNCACHE THE UDB?
	PJRST	UNCACH		;UNCACHE THE ADDRESS RANGE AND RETURN
	POPJ	P,		;RETURN
SUBTTL	AUTOCONFIGURATION -- AUTVIA - COMPUTE VECTOR TABLE OFFSET


;COMPUTE VECTOR TABLE OFFSET FOR INTERRUPT INSTRUCTION(S)
;CALL:	MOVE	T1, UBA NUMBER
;	MOVE	T2, INTERRUPT VECTOR INDEX (BYTE INDEX)
;	PUSHJ	P,AUTVIA
;	<RETURN>		;T1 = ADDRESS OF PRIMARY INTERRUPT INSTRUCTION
;CALL AUTVII TO USE DATA DIRECTLY FROM .CPDVC.

IFN FTKS10,<
AUTVIA::LSH	T2,-2		;CONVERT BYTE OFFSET TO WORD OFFSET
	JRST	AUTVI1		;CONTINUE
AUTVII::LDB	T1,[POINT 3,.CPDVC##,17] ;GET UBA NUMBER
	LDB	T2,[POINT 7,.CPDVC##,9] ;GET <INTERRUPT VECTOR INDEX>/4
AUTVI1:	MOVE	T3,.CPEPT##	;GET ADDRESS OF EXEC PROCESS TABLE
	ADD	T3,T1		;OFFSET EPT ADDRESS BY UNIBUS ADAPTER NUMBER
	MOVE	T1,.EPVIT-1(T3)	;GET ADDRESS OF VECTOR TABLE
	ADD	T1,T2		;COMPUTE INTERRUPT INSTRUCTION ADDRESS IN TABLE
	POPJ	P,		;RETURN
>; END IFN FTKS10
SUBTTL	DATA BASE INTERLOCK CONTROL -- AUTOWN - CHECK INTERLOCK OWNERSHIP


;CHECK INTERLOCK TO SEE IF IT IS OWNED BY THE CALLER
;CALL:	PUSHJ	P,AUTOWN
;	  <NON-SKIP>		;NOT OWNED
;	<SKIP>			;OWNED

	$CSUB

AUTOWN::PUSH	P,T1		;SAVE T1
	PUSHJ	P,UUOLVL##	;AT UUO LEVEL?
	  TDZA	T1,T1		;NO
	MOVE	T1,.CPJOB##	;GET JOB ON THIS CPU
	CAMN	T1,.CPATO##	;COMPARE WITH INTERLOCK OWNER ID
	AOS	-1(P)		;WE ALREADY OWN IT
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

	$HIGH
SUBTTL	DATA BASE INTERLOCK CONTROL -- AUTLOK - GET INTERLOCK


;GET PER-CPU INTERLOCK
;THIS ROUTINE CHECKS TO SEE IF THE DDB INTERLOCK IS AVAILABLE, BUT
;NEVER GETS THE INTERLOCK.  THE REASON FOR THIS IS SIMPLE; QUITE OFTEN,
;THE CALLER WILL NEED THE DDB INTERLOCK (AUTDDB FOR EXAMPLE).  IF THIS
;OCCURS AT CLOCK LEVEL, AND THE DDB INTERLOCK WASN'T AVAILABLE, DDBLOK
;WOULD SPIN AND MOST LIKELY CAUSE A KAF.  IF THE CALLER IS AT UUO LEVEL,
;THIS ADDITIONAL OVERHEAD  OF CHECKING IS NEGLIGIBLE AND THE POSSIBILITY
;OF BEING RESCHEDULED BECAUSE THE INTERLOCK IS NOT AVAILABLE IS NORMALLY
;EXPECTED.
;CALL:	PUSHJ	P,AUTLOK
;	  <NON-SKIP>		;INTERLOCK NOT AVAILABLE
;	<SKIP>			;DATA BASE INTERLOCKED

AUTLOK::PUSH	P,T1		;SAVE T1
	PUSHJ	P,UUOLVL##	;AT UUO LEVEL?
	  TDZA	T1,T1		;NO
	MOVE	T1,.CPJOB##	;GET JOB ON THIS CPU
	CAMN	T1,.CPATO##	;DO WE ALREADY OWN THE INTERLOCK?
	JRST	TPOPJ1##	;YES--NOTHING TO DO HERE

AUTLO1:
IFN FTMP,<
	SKIPL	INTRDD##	;IS THE DDB INTERLOCK AVAILABLE?
	JRST	AUTLO2		;NO
> ;END IFN FTMP
	AOSE	.CPATR##	;TRY TO GET AUTCON INTERLOCK
	JRST	AUTLO2		;SPIN
	MOVEM	T1,.CPATO##	;STORE INTERLOCK OWNER
	JRST	TPOPJ1##	;RETURN

AUTLO2:	JUMPE	T1,TPOPJ##	;CAN'T SLEEP IF INTERRUPT LEVEL
	PUSH	P,T1		;SAVE OWNER ID
	MOVEI	T1,1		;ONE SECOND
	PUSHJ	P,SLEEPF##	;ZZZZZZ
	POP	P,T1		;GET OWNER ID BACK
	JRST	AUTLO1		;TRY AGAIN
SUBTTL	DATA BASE INTERLOCK CONTROL -- AUTULK - GIVE UP INTERLOCK


;GIVE UP PER-CPU INTERLOCK
;CALL:	PUSHJ	P,AUTULK

AUTULK::SETOM	.CPATO##	;RESET INTERLOCK OWNER ID
	SETOM	.CPATR##	;CLEAR INTERLOCK
	POPJ	P,		;RETURN
SUBTTL	GENTAB MANAGEMENT -- GENADD - ADD A DDB


GENADD:	MOVE	T1,GENPTR##	;GET POINTER TO GENTAB
	HLRZ	T2,DEVNAM(F)	;GENERIC NAME
	JUMPE	T2,CPOPJ##	;CHECK FOR STRANGE DEVICES

GENAD1:	CAMN	T2,GENTAB##(T1)	;MATCH?
	JRST	GENAD2		;YES--SEE IF THE ORDER IS CORRECT
	AOBJN	T1,.+1		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	T1,GENAD1	;LOOP THROUGH TABLE
	CAILE	T1,GENLEN##-2	;ROOM FOR MORE?
	POPJ	P,		;GIVE UP IF TABLE IS FULL
	MOVEM	T2,GENTAB##(T1)	;STORE NEW GENERIC NAME
	MOVEM	F,GENTAB##+1(T1) ;AND FIRST DDB OF ITS KIND
	PJRST	GENSRT		;GO SORT GENTAB, SET GENPTR, AND RETURN

GENAD2:	SKIPN	GENTAB##+1(T1)	;ABOUT TO ADD THE FIRST ENTRY?
	JRST	GENAD3		;JUST STUFF DDB AT HEAD OF CHAIN
	LDB	T2,PUNIT##	;GET NEW UNIT
	LDB	T3,PDVSTA##	;AND NEW STATION
	HRL	T2,T3		;MERGE
	PUSH	P,F		;SAVE F
	MOVE	F,GENTAB##+1(T1) ;POINT TO OLD DDB
	LDB	T3,PUNIT##	;GET NEW UNIT
	LDB	T4,PDVSTA##	;AND NEW STATION
	HRL	T3,T4		;MERGE
	POP	P,F		;RESTORE F
	CAMG	T2,T3		;SHOULD NEW DDB PRECEED OLD ONE?

GENAD3:	MOVEM	F,GENTAB##+1(T1) ;YES--UPDATE FIRST DDB OF ITS KIND
	POPJ	P,		;AND RETURN
SUBTTL	GENTAB MANAGEMENT -- GENDEL - DELETE A DDB


GENDEL:	MOVE	T1,GENPTR##	;GET POINTER TO GENTAB
	HLRZ	T2,DEVNAM(F)	;GENERIC NAME

GENDE1:	CAMN	T2,GENTAB##(T1)	;MATCH?
	JRST	GENDE2		;YES
	AOBJN	T1,.+1		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	T1,GENDE1	;LOOP THROUGH TABLE
	POPJ	P,		;NOT IN THE TABLE??

GENDE2:	CAME	F,GENTAB##+1(T1) ;FIRST DDB OF ITS KIND?
	POPJ	P,		;NO--NOTHING TO DO
	DDBSRL			;INTERLOCK DDB SCANNING
	HLRZ	T2,DEVSER(F)	;GET NEXT DDB
	JUMPE	T2,GENDE3	;END OF CHAIN?
	HLRZ	T3,DEVNAM(T2)	;AND IT'S GENERIC NAME
	CAME	T3,GENTAB##(T1)	;SAME KIND?
	TDZA	T2,T2		;NO--MUST DELETE ENTRY
	MOVEM	T2,GENTAB##+1(T1) ;MAKE DDB THE FIRST OF ITS KIND

GENDE3:	DDBSRU			;RELEASE INTERLOCK
	JUMPN	T2,CPOPJ##	;RETURN IF JUST SWITCHED POINTERS
	MOVEI	T2,-1		;ELSE FLAG ENTRY
	SETZ	T3,		; ABOUT TO BE FREED
	DMOVEM	T2,GENTAB##(T1)	;UPDATE
	PJRST	GENSRT		;GO SORT GENTAB, SET GENPTR, AND RETURN
SUBTTL	GENTAB MANAGEMENT -- GENSRT - SORT GENTAB


GENSRT:	PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	DDBSRL			;INTERLOCK DDB SCANNING

GENSR1:	MOVSI	P1,-GENLEN##+2	;AOBJN POINTER (TWO WORD ENTRIES)
	SETZ	P2,		;INIT CHANGE FLAG

GENSR2:	DMOVE	T1,GENTAB##(P1)	;GET NAME, FIRST DDB
	DMOVE	T3,GENTAB##+2(P1)
	CAIG	T1,(T3)		;IN THE PROPER ORDER?
	JRST	GENSR3		;YES
	EXCH	T1,T3		;SWAP
	EXCH	T2,T4		;...
	DMOVEM	T1,GENTAB##(P1)	;REPLACE
	DMOVEM	T3,GENTAB##+2(P1)
	AOS	P2		;FLAG THE CHANGE

GENSR3:	AOBJN	P1,.+1		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	P1,GENSR2	;LOOP THROUGH TABLE
	JUMPN	P2,GENSR1	;DO IT AGAIN IF SOMETHING CHANGED
	MOVSI	P1,-GENLEN##+2	;AOBJN POINTER (TWO WORD ENTRIES)

GENSR4:	HRRE	T1,GENTAB##(P1)	;GET NAME
	AOJE	T1,GENSR5	;FOUND LOGICAL END YET (0,,-1) ?
	AOBJN	P1,.+1		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	P1,GENSR4	;LOOP THROUGH TABLE

GENSR5:	MOVNI	T1,(P1)		;-LENGTH
	HRLZM	T1,GENPTR##	;SAVE FOR DDB SCANNING
	DDBSRU			;RELEASE INTERLOCK
	POPJ	P,		;RETURN
SUBTTL	MASSBUS REGISTER I/O -- RDDTR/RDDTN - READ DRIVE TYPE REGISTER


;READ A DRIVE TYPE REGISTER OR NAME
;CALL:	SKIPA	P1, MASSBUS UNIT,,0	;IF AUTOCONFIGURING
;	MOVE	W,  KDB ADDRESS		;IF NORMAL TIMESHARING
;	PUSHJ	P,RDDTR/RDDTN
;	<RETURN>
;
;ON RETURN, T2 HAS THE DATAI RESULTS
;ALL ACS ARE PRESERVED

RDDTR::	TDZA	T2,T2		;SIMPLE DATAI ENTRY POINT
RDDTN::	MOVEI	T2,1		;TRANSLATE DTR TO NAME
	PUSH	P,T2		;SAVE FLAG
IFN FTKL10,<
	PUSHJ	P,AUTOWN	;DO WE OWN THE DATA BASE INTERLOCK?
	JRST	RDDTR1		;NO
	MOVE	T2,T1		;SAVE T1
	MOVEI	T1,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
	XCT	.CPCNO##	;CONO DEV,(T1)
	MOVE	T1,T2		;RESTORE T1
RDDTR1:
>; END IFN FTKL10

IFN FTKL10,<MOVSI T2,(.DIDTR)>	;DRIVE TYPE REGISTER
IFN FTKS10,<MOVSI T2,.DODT>	;DRIVE TYPE REGISTER
	PUSHJ	P,RDMBR		;READ IT
	ANDI	T2,TR.TYP	;MASK OUT JUNK
	SKIPN	(P)		;WANT TO RETURN NAME INSTEAD?
	JRST	[POP	P,(P)	;NO--PHASE STACK
		 POPJ	P,]	;AND RETURN
	MOVEM	P1,(P)		;SAVE P1
	PUSH	P,P2		;SAVE P2
	MOVSI	P1,-DTRLEN	;AOBJN POINTER

RDDTR2:	HLRZ	P2,DTRTBL(P1)	;GET A DRIVE TYPE CODE
	CAIN	P2,(T2)		;A MATCH?
	JRST	RDDTR3		;YES
	AOBJN	P1,RDDTR2	;KEEP SEARCHING
	SKIPA	P2,[[EXP 0]]	;NO MATCH

RDDTR3:	HRRZ	P2,DTRTBL(P1)	;GET ADDRESS OF NAME
	MOVE	T2,(P2)		;AND GET NAME
	POP	P,P2		;RESTORE P2
	POP	P,P1		;RESTORE P1
	POPJ	P,		;AND RETURN
;TABLE OF DRIVE TYPE REGISTER CODES AND ASSOCIATED NAMES
DTRTBL:	XWD	000,['RS03  ']	;RH10 (4 US/WD XFER RATE)
	XWD	001,['RS03  ']	;RH10 (8 US/WD XFER RATE)
	XWD	002,['RS04  ']	;RH10 (4 US/WD XFER RATE)
	XWD	003,['RS04  ']	;RH10 (8 US/WD XFER RATE)
	XWD	010,['TM02  ']	;TM02
	XWD	011,['TU16  ']	;TM02
	XWD	012,['TU45  ']	;TM02
	XWD	013,['TE16  ']	;TM02
	XWD	014,['TU77  ']	;TM02
	XWD	020,['RP04  ']	;RH10/RH11/RH20 (88 MB)
	XWD	021,['RP05  ']	;RH10/RH11/RH20 (100 MB)
	XWD	022,['RP06  ']	;RH10/RH11/RH20
;	XWD	024,['RM02  ']	;RH10/RH11/RH20
;	XWD	025,['RM03  ']	;RH10/RH11/RH20
	XWD	024,['RM03  ']	;RH10/RH11/RH20
	XWD	026,['XRM02X']	;RH10/RH11/RH20
	XWD	027,['XRM03X']	;RH10/RH11/RH20
	XWD	040,['RP07  ']	;RH10/RH20 (RP07-XX 300MB)
	XWD	041,['RP07  ']	;RH10/RH20 (RP07-XX 300MB)
	XWD	042,['RP07  ']	;RH10/RH20 (RP07+ 600MB)
	XWD	043,['RP07  ']	;RH10/RH20 (RP07+ 600MB)
	XWD	050,['TM03  ']	;TM03
	XWD	051,['TU16  ']	;TM03
	XWD	052,['TU45  ']	;TM03
	XWD	053,['TE16  ']	;TM03
	XWD	054,['TU77  ']	;TM03
	XWD	060,['DX20-A']	;DX20 V100 ADAPTER FOR TAPE SUBSYSTEM
	XWD	061,['DX20-D']	;DX20 V200 ADAPTER FOR DISK SUBSYSTEM
	XWD	062,['DX20-M']	;DX20 V400 ADAPTER FOR MASSBUS TO MASSBUS
	XWD	063,['DX20-?']	;DX20 (FUTURE)
	XWD	063,['DX20-?']	;DX20 (FUTURE)
	XWD	064,['DX20-?']	;DX20 (FUTURE)
	XWD	065,['DX20-?']	;DX20 (FUTURE)
	XWD	066,['DX20-?']	;DX20 (FUTURE)
	XWD	067,['DX20-?']	;DX20 (FUTURE)
	XWD	070,['DX20-?']	;DX20 (FUTURE)
	XWD	071,['DX20-?']	;DX20 (FUTURE)
	XWD	072,['DX20-?']	;DX20 (FUTURE)
	XWD	073,['DX20-?']	;DX20 (FUTURE)
	XWD	074,['DX20-?']	;DX20 (FUTURE)
	XWD	075,['DX20-?']	;DX20 (FUTURE)
	XWD	076,['DX20-?']	;DX20 (FUTURE)
	XWD	077,['DX20-?']	;DX20 (FUTURE)
	XWD	100,['TM78  ']	;TM78
	XWD	101,['TU78/9']	;TM78
DTRLEN==.-DTRTBL		;LENGTH OF TABLE
SUBTTL	MASSBUS REGISTER I/O -- RDMBR - READ REGISTER


;READ A DRIVE OR CONTROLLER REGISTER
;CALL:	SKIPA	P1, MASSBUS UNIT,,0	;IF AUTOCONFIGURING
;	MOVE	W,  KDB ADDRESS		;IF NORMAL TIMESHARING
;	MOVE	T2, REGISTER
;	PUSHJ	P,RDMBR
;	<RETURN>
;
;ON RETURN, T2 HAS THE DATAI RESULTS
;ALL ACS ARE PRESERVED

IFN FTKL10,<
RDMBR::	PUSHJ	P,SAVW##	;SAVE W
	PUSH	P,T1		;SAVE T1
	PUSH	P,T3		;SAVE T3
	PUSHJ	P,AUTOWN	;DO WE OWN THE DATA BASE INTERLOCK?
	  JRST	RDMBR1		;NO--DO NORMAL STUFF
	XMOVEI	W,.CPCNI##-KDBCNI ;FAKE KDB I/O INSTRUCTIONS
	HLRZ	T3,P1		;MASSBUS UNIT NUMBER
	SKIPA			;ENTER COMMON CODE

RDMBR1:	HLRZ	T3,KDBUNI(W)	;MASSBUS UNIT NUMBER
	TLO	T2,<(DO.DRE)>(T3) ;SET UNIT, NO RAE
	MOVE	T3,KDBDVC(W)	;GET DEVICE CODE
	CAIL	T3,FSTICD/4	;INTERNAL
	CAILE	T3,LSTICD/4	; CHANNEL?
	TLZ	T2,<(DO.DRE)>	;NO
	PUSH	P,T2		;SAVE THE ARGUMENT
	XCT	KDBDTO(W)	;TELL MBC WHICH REGISTER WE WANT TO READ
	IMULI	P,1		;WAIT FOR THINGS
	IMULI	P,1		; TO SETTLE DOWN
	XCT	KDBDTI(W)	;READ THE VALUE
	XCT	KDBCNI(W)	;AND THE STATUS
	TRNN	T1,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	RDMBR3		;NO
	MOVEI	T3,^D10		;RETRY OPERATION 10 TIMES

RDMBR2:	MOVEI	T1,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
	XCT	KDBCNO(W)	;CLEAR THE ERROR
	MOVE	T2,(P)		;GET DATAO ARGUMENT BACK
	XCT	KDBDTO(W)	;SETUP THE PREPARATION REGISTER AGAIN
	IMULI	P,1		;WAIT FOR THINGS
	IMULI	P,1		; TO SETTLE DOWN
	XCT	KDBDTI(W)	;READ THE VALUE
	XCT	KDBCNI(W)	;AND THE STATUS
	TRNE	T1,CI.RAE	;REGISTER ACCESS ERROR?
	SOJG	T3,RDMBR2	;MUST TRY AGAIN
	MOVEI	T1,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
	XCT	KDBCNO(W)	;MAKE SURE RAE IS CLEARED

RDMBR3:	POP	P,(P)		;BRING STACK INTO PHASE
	POP	P,T3		;RESTORE T3
	POP	P,T1		;RESTORE T1
	ANDI	T2,DO.BAD	;RETURN ONLY DATA BITS
	POPJ	P,		;RETURN
> ;END IFN FTKL10
IFN FTKS10,<
RDMBR::	PUSH	P,T1		;SAVE AN AC
	PUSH	P,T3		;SAVE ANOTHER
	PUSHJ	P,AUTOWN	;DO WE OWN THE DATA BASE INTERLOCK?
	  SKIPA	T1,KDBDVC(W)	;NO, GET CSR ADDRESS FROM KDB
	LDB	T1,[POINT 21,.CPDVC##,35] ;YES, GET CSR ADDRESS FROM .CPDVC
	PUSH	P,T2		;SAVE ARGUMENT
	HLRZ	T2,P1		;ASSUME AUTCON IS RUNNING
	PUSHJ	P,AUTOWN	;DO WE OWN THE DATA BASE INTERLOCK?
	  HLRZ	T2,KDBUNI(W)	;GET MASSBUS UNIT FROM KDB
	MOVEI	T3,CS.BAI	;BUS ADDRESS INHIBIT
	TIOE	T3,.DOCS2(T1)	;IS IT SET?
	TRO	T2,CS.BAI	;YES--THEN PRESERVE IT
	WRIOB	T2,.DOCS2(T1)	;SELECT UNIT
	HLRZS	(P)		;MOVE REGISTER OFFSET TO RH
	ADD	T1,(P)		;OFFSET FROM UNIBUS BASE ADDRESS
	RDIO	T2,(T1)		;READ REGISTER
	POP	P,(P)		;PHASE STACK
	POP	P,T3		;RESTORE T3
	JRST	TPOPJ##		;POP OFF T1 AND RETURN
> ;END IFN FTKS10
SUBTTL	MASSBUS REGISTER I/O -- SVMBR - SAVE REGISTER


;SAVE A DRIVE OR CONTROLLER REGISTER
;THIS CO-ROUTINE IS USED BY INTERRUPT LEVEL TO SAVE AND RESTORE THE
;CURRENT DRIVE/CONTROLLER REGISTER THAT MAY BE IN USE BY UUO LEVEL.
;CALL:	MOVE	W,  KDB ADDRESS
;	PUSHJ	P,SVMBR
;	<RETURN>
;
;ALL ACS ARE PRESERVED

IFN FTKL10,<
SVMBR::	PUSH	P,W		;SAVE KDB ADDRESS
	PUSH	P,T2		;SAVE T2
	XCT	KDBDTI(W)	;READ MBR THE CHANNEL WAS CONNECTED TO
	EXCH	T2,(P)		;SAVE MBR, GET T2 BACK
	PUSHJ	P,@-2(P)	;CALL THE CALLER
	  CAIA			;NON-SKIP RETURN
	AOS	-3(P)		;ADJUST RETURN PC
	EXCH	W,-1(P)		;SAVE W, GET KDB ADDRESS BACK
	EXCH	T2,(P)		;SAVE T2, GET OLD MBR BACK
	AND	T2,[DO.REG!DO.DRV] ;ISOLATE MASSBUS UNIT AND REGISTER
	TLNN	T2,(DO.REG)	;CAN'T WRITE REGISTER 0 SINCE THAT
	TLO	T2,(INSVL.(1,DO.REG)) ; MIGHT SIEZE SOME MASSBUS UNITS
	XCT	KDBDTO(W)	;SET THE CHANNEL BACK TO ORIGINAL MBR
	POP	P,T2		;RESTORE T2
	POP	P,W		;RESTORE W
	POP	P,(P)		;PHASE STACK
	POPJ	P,		;RETURN
> ;END IFN FTKL10
SUBTTL	MASSBUS REGISTER I/O -- WTMBR - WRITE REGISTER


;WRITE A DRIVE OR CONTROLLER REGISTER
;CALL:	SKIPA	P1, MASSBUS UNIT,,0	;IF AUTOCONFIGURING
;	MOVE	W,  KDB ADDRESS		;IF NORMAL TIMESHARING
;	MOVE	T2, REGISTER
;	PUSHJ	P,WTMBR
;	<RETURN>
;
;ALL ACS ARE PRESERVED

IFN FTKL10,<
WTMBR::	PUSHJ	P,SAVW##	;SAVE W
	PUSH	P,T1		;SAVE T1
	PUSH	P,T2		;SAVE T2
	PUSH	P,T3		;SAVE T3
	PUSHJ	P,AUTOWN	;DO WE OWN THE DATA BASE INTERLOCK?
	  JRST	WTMBR1		;NO--DO NORMAL STUFF
	XMOVEI	W,.CPCNI##-KDBCNI ;FAKE KDB I/O INSTRUCTIONS
	HLRZ	T3,P1		;MASSBUS UNIT NUMBER
	SKIPA			;ENTER COMMON CODE

WTMBR1:	HLRZ	T3,KDBUNI(W)	;MASSBUS UNIT NUMBER
	TLO	T2,<(DO.LDR!DO.DRE)>(T3) ;SET UNIT, NO RAE, LOAD REGISTER
	MOVE	T3,KDBDVC(W)	;GET DEVICE CODE
	CAIL	T3,FSTICD/4	;INTERNAL
	CAILE	T3,LSTICD/4	; CHANNEL?
	TLZ	T2,<(DO.DRE)>	;NO
	MOVE	T3,T2		;COPY ARGUMENTS
	XCT	KDBDTO(W)	;DATAO
	XCT	KDBCNI(W)	;CONI
	TRNN	T1,CI.RAE	;REGISTER ACCESS ERROR?
	JRST	WTMBR3		;NO
	PUSH	P,T3		;SAVE DATAO ARGUMENTS
	MOVEI	T3,^D10		;RETRY OPERATION 10 TIMES

WTMBR2:	MOVEI	T1,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
	XCT	KDBCNO(W)	;CLEAR THE ERROR
	MOVE	T2,(P)		;GET ARGUMENTS BACK
	XCT	KDBDTO(W)	;RETRY THE OPERATION
	XCT	KDBCNI(W)	;CONI
	TRNE	T1,CI.RAE	;STILL HAVE AN ERROR
	SOJG	T3,WTMBR2	;YES, LOOP BUT NOT TOO MANY TIMES
	MOVEI	T1,CO.MBE!CO.RAE ;MASSBUS ENABLE PLUS CLEAR RAE
	XCT	KDBCNO(W)	;INSURE THAT RAE IS CLEARED
	POP	P,(P)		;PHASE STACK

WTMBR3:	POP	P,T3		;RESTORE T3
	POP	P,T2		;RESTORE T2
	POP	P,T1		;RESTORE T1
	POPJ	P,		;RETURN
> ;END IFN FTKL10
IFN FTKS10,<
WTMBR::	PUSH	P,T1		;SAVE AN AC
	PUSH	P,T3		;SAVE ANOTHER
	PUSHJ	P,AUTOWN	;DO WE OWN THE DATA BASE INTERLOCK?
	  SKIPA	T1,KDBDVC(W)	;NO, GET CSR ADDRESS FROM KDB
	LDB	T1,[POINT 21,.CPDVC##,35] ;YES, GET CSR ADDRESS FROM .CPDVC
	PUSH	P,T2		;SAVE ARGUMENT
	HLRZ	T2,P1		;ASSUME AUTCON IS RUNNING
	PUSHJ	P,AUTOWN	;DO WE OWN THE DATA BASE INTERLOCK?
	  HLRZ	T2,KDBUNI(W)	;GET MASSBUS UNIT FROM KDB
	MOVEI	T3,CS.BAI	;BUS ADDRESS INHIBIT
	TIOE	T3,.DOCS2(T1)	;IS IT SET?
	TRO	T2,CS.BAI	;YES--THEN PRESERVE IT
	WRIOB	T2,.DOCS2(T1)	;SELECT UNIT
	HRRZ	T2,(P)		;GET DATA TO WRITE
	HLRZS	(P)		;MOVE REGISTER OFFSET TO RH
	ADD	T1,(P)		;OFFSET FROM UNIBUS BASE ADDRESS
	WRIO	T2,(T1)		;WRITE REGISTER
	POP	P,(P)		;PHASE STACK
	POP	P,T3		;RESTORE T3
	JRST	TPOPJ##		;POP OFF T1 AND RETURN
> ;END IFN FTKS10
;ROUTINE TO FIXUP THE COUNTS FOR DEVICES WHOSE COUNTS ARE GLOBAL
;AMONG DIFFERENT KONTROLLERS (SUCH AS MAGTAPES)

ADNFIX:	MOVE	T1,.CPDRV##	;DRIVER DISPATCH
	MOVEI	T2,DR.GCC	;BIT TO TEST
	TDNN	T2,DRVCNF(T1)	;THIS DRIVER USE GLOBAL COUNTERS?
	POPJ	P,		;NO
	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	DMOVE	P1,@DRVMDT(T1)	;COPY THIS DRIVER'S ENTRY
	MOVE	P3,DRVCNF(T1)	;COPY INTERESTING BITS
	AND	P3,[DR.DVT!DR.GCC] ;KEEP ONLY THOSE OF INTEREST
	MOVE	T1,DRVLST	;POINT TO START OF DRIVER CHAIN
	SYSPIF			;INTERLOCK

ADNFI1:	MOVE	T2,DRVCNF(T1)	;GET CONFIGURATION WORD
	AND	T2,[DR.DVT!DR.GCC] ;ISOLATE IMPORTANT STUFF
	CAMN	T2,P3		;SAME?
	DMOVEM	P1,@DRVMDT(T1)	;YES--UPDATE
	SKIPE	T1,DRVLNK(T1)	;LINK TO NEXT
	JRST	ADNFI1		;LOOP BACK
	SYSPIN			;RELEASE INTERLOCK
	POPJ	P,		;RETURN
CHKDEV:
IFN FTKL10,<
	XCT	.CPCNI##	;READ DEVICE STATUS
	TLNE	T1,(CI.PPT)	;LIVE IPA DEVICE?
	JRST	CPOPJ1##	;YES
	PUSH	P,T1		;SAVE TEMPORARILY
	MOVEI	T1,7		;DUMMY PI CHANNEL
	XCT	.CPCNO##	;SET PI ASSIGNMENT
	XCT	.CPCNI##	;READ IT BACK
	EXCH	T1,(P)		;GET OLD CONI BACK, SAVE NEW
	XCT	.CPCNO##	;RESET DEVICE STATUS
	POP	P,T1		;PHASE STACK
	TRNE	T1,7		;IS DEVICE REALLY THERE?
	AOS	(P)		;YES
	POPJ	P,		;RETURN
>; END IFN FTKL10
IFN FTKS10,<
	LDB	T1,[POINT 21,.CPDVC##,35] ;GET UNIBUS ADDRESS
	PUSHJ	P,UBGOOD##	;DEVICE EXIST?
	  POPJ	P,		;NO
	PJRST	CPOPJ1##	;YES
>; END IFN FTKS10
;CREATE A NAME
;CALL:	MOVE	T1, DRIVE NUMBER
;	PUSHJ	P,OCTNAM/DECNAM
;	<RETURN>		;RH(T1) = SIXBIT NAME

DECNAM:	SKIPA	T2,[EXP 12]	;DECIMAL NAME
OCTNAM:	MOVEI	T2,10		;OCTAL NAME
	PUSH	P,T3		;SAVE T3
	PUSH	P,T4		;SAVE T4
	MOVEI	T4,(T2)		;GET RADIX
	SETZ	T3,		;CLEAR OUT RESULT

CRENAM:	IDIVI	T1,(T4)		;DIVIDE BY RADIX
	ADDI	T2,'0'		;CONVERT TO SIXBIT
	LSHC	T2,-6		;SHIFT IT OUT
	JUMPN	T1,CRENAM	;LOOP FOR ALL DIGITS
	TRNE	T3,770000	;IF SPECIAL CASE FOR NODE NUMBERS,
	LSH	T3,6		;DROP THE LEADING '1'
	HLRZ	T1,T3		;COPY RESULTS
	POP	P,T4		;RESTORE T4
	POP	P,T3		;RESTORE T3
	POPJ	P,		;RETURN
;ROUTINE TO GET THE ICCW BLOCK
IFN FTKL10,<
GETIOW:	HRRZ	T1,.CPDVC##	;GET <DEVICE CODE>/4
	CAIL	T1,FSTICD/4	;INTERNAL CHANNEL?
	CAILE	T1,LSTICD/4	;...
	JRST	GETIO1		;NO
	SUBI	T1,FSTICD/4	;REDUCE TO RH20 NUMBER
	LSH	T1,2		;POSITION
	ADD	T1,.CPEPT##	;INDEX INTO EPT
	JRST	CPOPJ1##	;RETURN

GETIO1:	PUSHJ	P,GCH4WD##	;GET LOW CORE BLOCK
	  POPJ	P,		;NOT AVAILABLE
	SKIPE	.UONCE##	;USER MODE (TWICE)?
	JRST	CPOPJ1##	;THIS IS MEANINGLESS
	MAP	T2,(T1)		;GET PHYSICAL ADDRESS
	TLZ	T2,-1-MXSECN	;KEEP ONLY THE ADDRESS
	CAIGE	T2,PAGSIZ	;MUST RESIDE IN PAGE ZERO
	JRST	CPOPJ1##	;IT DOES
	PJRST	RTNIOW##	;IT DOESN'T, RETURN BLOCK AND RETURN
>; END IFN FTKL10
;SETUP MICROCODE LOADER BLOCK IN A KDB
SETULB:	MOVE	T1,.CPDRV##	;DRIVER DISPATCH
	SKIPN	T2,DRVULP(T1)	;PROTOTYPE UCODE LOADER BLOCK?
	POPJ	P,		;NO
	MOVE	T3,DRVULO(T1)	;GET STORAGE OFFSET
IFE FTXMON,<
	HRLZS	T2		;PUT IN LH
	ADDI	T3,(W)		;DESTINATION
	PUSH	P,T3		;SAVE FOR A MOMENT
	HRR	T2,T3		;MAKE BLT POINTER
	BLT	T2,.ULLEN-1(T3)	;COPY INTO KDB
> ;END IFE FTXMON
IFN FTXMON,<
	MOVEI	T1,.ULLEN	;LENGTH OF BLOCK
	ADD	T3,W		;DESTINATION
	PUSH	P,T3		;SAVE FOR A MOMENT
	EXTEND	T1,[XBLT]	;COPY INTO KDB
> ;END IFN FTXMON
IFN FTKL10,<
	POP	P,T2		;GET ULB ADDRESS BACK AGAIN
	HRLZ	T3,.CPDVC##	;<DEVICE CODE>/4
	LSH	T3,2		;POSITION DEVICE CODE
	HLR	T3,KDBUNI(W)	;GET MASSBUS UNIT NUMBER TOO
	MOVEM	T3,.ULDEV(T2)	;STUFF IN BLOCK
	HLRZ	T3,KDBUNI(W)	;GET MASSBUS UNIT NUMBER
	HRRM	T3,.ULDEV(T2)	;SAVE IT
	POPJ	P,		;RETURN
>; END IFN FTKL10
IFN FTKS10,<JRST T2POPJ##>	;RETURN
;ROUTINE TO UNCACHE PAGES
;CALL:	MOVE	T1, STARTING ADDRESS
;	MOVE	T2, LENGTH OF BLOCK
;	PUSHJ	P,UNCACH
;	<RETURN>		;ADDRESS RANGE UNCACHED

UNCACH:	ADD	T2,T1		;COMPUTE ENDING ADDRESS
	LSH	T1,W2PLSH	;STARTING PAGE NUMBER
	LSH	T2,W2PLSH	;ENDING PAGE NUMBER
	MOVE	T3,T1		;COPY STARTING PAGE NUMBER

;SET UP TEMPORARY MAPPING
UNCAC1:	MOVE	T4,.CPMAP##	;SECTION ZERO MAP ADDRESS
	PUSH	P,.ECKSM/PAGSIZ(T4) ;SAVE TEMP SLOT INCASE ALREADY IN USE
	MOVE	T3,T1		;COPY STARTING PAGE NUMBER
	LSH	T3,P2SLSH	;GET ITS SECTION NUMBER
	MOVE	T4,.CPEPT##	;EPT ADDRESS
	ADDI	T4,SECTAB(T3)	;INDEX TO SECTION MAP SLOT
	MOVE	T4,(T4)		;FETCH SECTION POINTER
	ANDI	T4,PM.PAG	;REDUCE TO ONLY A PAGE NUMBER
	HRLI	T4,(<PM.DCD>B2+PM.WRT+PM.PUB) ;DIRECT POINTER + WRITE + PUBLIC
	PUSH	P,T4		;SAVE MAP ENTRY
	MOVE	T4,.CPMAP##	;SECTION ZERO MAP ADDRESS
	POP	P,.ECKSM/PAGSIZ(T4) ;STUFF POINTER INTO TEMP SLOT
	CLRPT	.ECKSM		;MAKE NEW MAPPING AVAILABLE TO HARDWARE
	MOVE	T3,T1		;COPY STARTING PAGE NUMBER AGAIN
	ANDI	T3,PAGSIZ-1	;KEEP ONLY THE INDEX WITHIN THE SECTION
	XMOVEI	T4,.ECKSM(T3)	;GET THE STARTING ADDRESS WITHIN MAP

;UNCACHE PAGES
UNCAC2:	SKIPN	T1,(T4)		;GET CONTENTS OF MAP SLOT
	STOPCD	.,STOP,DNM,	;++DATA NOT MAPPED
	TLZ	T1,(PM.CSH)	;CLEAR CACHE BIT
	MOVEM	T1,(T4)		;UPDATE
	AOS	T4		;ADVANCE POINTER FOR NEXT TIME
	ANDI	T1,PM.PAG	;GET PHYSICAL PAGE NUMBER
	SSX	T1,MS.MEM	;SECTION NUMBER
	EXCH	T2,PAGTAB(T1)	;GET ENTRY, SAVE T2
	TLZ	T2,TNCSHB	;CAN NEVER CACHED (EVEN IF SPLIT)
	EXCH	T2,PAGTAB(T1)	;STORE NEW SETTING, RESTORE T2
	CAIE	T3,(T2)		;DID WE JUST DO LAST PAGE?
	AOJA	T3,UNCAC2	;LOOP, WE HAVE MORE TO DO
	MOVE	T4,.CPMAP##	;SECTION ZERO MAP ADDRESS
	POP	P,.ECKSM/PAGSIZ(T4) ;RESTORE TEMP MAP SLOT FOR CALLER
	CLRPGT			;MAKE HARDWARE NOTICE NEW MAPPING
	POPJ	P,		;RETURN
GETCOR:	PUSH	P,T1		;SAVE WORDS TO GET
	PUSH	P,[EXP 0]	;PLACE HOLDER
	PUSH	P,T3		;SAVE T3
	PUSH	P,T4		;SAVE T4
	MOVE	T2,-3(P)	;GET REQUESTED NUMBER OF WORDS
	PUSHJ	P,GETWDS##	;ASK FOR THE CORE
	  JRST	[POP	P,T4
		 POP	P,T3
		 JRST	TTPOPJ##]
	MOVEM	T1,-2(P)	;SAVE ADDRESS OF ALLOCATED CORE
	SETZM	(T1)		;CLEAR FIRST WORD
IFE FTXMON,<
	MOVSI	T2,0(T1)	;START ADDRESS
	HRRI	T2,1(T1)	;MAKE A BLT POINTRE
	ADD	T1,-3(P)	;COMPUTE END OF BLT
	BLT	T2,-1(T1)	;CLEAR CORE
> ;END IFE FTXMON
IFN FTXMON,<
	DMOVE	T1,-3(P)	;WORD COUNT & START ADDRESS
	SOS	T1		;WE ALREADY DID THE FIRST
	MOVE	T3,T2		;DESTINATION
	AOS	T3		;MAKE A BLT POINTER
	EXTEND	T1,[XBLT]	;CLEAR CORE
> ;END IFN FTXMON
	POP	P,T4		;RESTORE T4
	POP	P,T3		;RESTORE T3
	POP	P,T2		;RESTORE ADDRESS
	POP	P,T1		;RESTORE WORD COUNT
	JRST	CPOPJ1##	;RETURN
SUBTTL	STATIC DATA OF INTEREST TO DRIVERS

	$CSUB

;BYTE POINTERS INTO THE CHANNEL DATA BLOCK
CHYSCN::POINT	CHSSCN,CHBSCN(P1),CHNSCN ;SOFTWARE CHANNEL NUMBER
CHYCPU::POINT	CHSCPU,CHBCPU(P1),CHNCPU ;CPU NUMBER OWNING CHANNEL

	$HIGH
	$LOW

	.LNKEN	.LKDRV,DRVLST
DRVLST::XWD	0,0		;DEVICE DRIVER DISPATCH LIST

PRVLST:	BLOCK	1		;PREVIOUS DISPATCH POINTER
KDBTAB::BLOCK	TYPMAX+1	;KDB CHAIN HEADERS
DDBTAB::BLOCK	TYPMAX+1	;PROTOTYPE DDB ADDRESSES
DDBSIZ:	BLOCK	TYPMAX+1	;PROTOTYPE DDB LENGTHS
DDBCNT::BLOCK	TYPMAX+1	;NUMBER OF DDBS
NUMKON::BLOCK	1		;TOTAL KONTROLLERS IN SYSTEM

	$HIGH

AUTEND:!END