Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_1_19910112 - 7/ft3/monitor/stanford/physai.mac
There are no other files named physai.mac in the archive.
;[SIERRA.STANFORD.EDU]SRC:<6.1.MONITOR.STANFORD.MARS>PHYSAI.MAC.8, 16-Mar-87 16:19:34, Edit by ALDERSON
; More GOTCHN cleanup
; Fix UDSINI code from previous edit
;[SIERRA.STANFORD.EDU]SRC:<6.1.MONITOR.STANFORD.MARS>PHYSAI.MAC.7, 13-Mar-87 12:22:06, Edit by ALDERSON
; Allow GOTCHN routine to start at channel table entry 0
; Make SSAINI say that subchannels not found by UDSINI are OFFLINE and
; UNAVAILABLE (US.OFS!US.UNA)
;[SIERRA.STANFORD.EDU]SRC:<6.1.MONITOR.STANFORD.MARS>PHYSAI.MAC.6, 14-Feb-87 20:03:15, Edit by ALDERSON
; More of same:  Make a constant KNIRH2 instead of hardcoding numeric 5 in
; GOTCHN routine
;[MACBETH.STANFORD.EDU]EPIC:<SU-MONITOR.MARS>PHYSAI.MAC.5, 29-Jan-87 15:48:25, Edit by A.ALDERSON
; Make GOTCHN routine start AFTER the CI slot
; Make KOO's change:
;; Increased IU1CWT timeout count
;[SIERRA.STANFORD.EDU]SRC:<6.1.MONITOR.STANFORD.MARS>PHYSAI.MAC.3, 27-Jan-87 17:53:46, Edit by ALDERSON
; Make SSAINI more civilized with respect to its treatment of CHNTAB and P4
;EPIC:<SU-MONITOR.MARS>PHYSAI.MAC.2, 11-Apr-86 17:13:23, Edit by A.ALDERSON
; Comment out references to FA disk symbols
;<5-1-MONITOR>PHYSAI.MAC.5033, 29-Oct-84 17:03:25, Edit by MRC
; Changes for IU10/MARS operation
;<5.ISI.MONITOR>PHYSA.MAC.5000	22-Oct-82 08:45:54	Edit by SMITH
;#500 CDSCCA dispatch added
;<4.ISI-MONITOR>PHYSA.MAC.260	31-Mar-81 13:08:50	Edit by SMITH
;#26 Support IBM-3420 compatable Tape drives on SA10 channel
;#25 Support IBM-3330 compatable disks on SA10 channel.
;#25 ;#26 Entire module included in these change #'S

	SEARCH PROLOG		; system parameter file
	TTITLE (PHYSA,,< - Channel dependent code for SA10 controller>)
	SUBTTL Dennis R. Smith 30-Nov-79/Mark Crispin 9/84 for IU10/FA10

	SEARCH PHYPAR		; PHYSIO parameters

Comment	~
	
	This module contains  the code  to handle one  or more  SA10
	controllers.  It interfaces with PHYSIO, which calls it, and
	individual  device  modules,   which  it  calls   (currently
	supported: IBM 3330 style disks and IBM 3420 style  magnetic
	tapes).  SSAINI is intitially called by PHYSIO during system
	initialization through the  dispatch vector SSADSP.   SSAINI
	sets up CDB's for each subchannel  on each SA10 it finds  of
	those it is assembled to handle, and call each of the device
	initialization routines it  knows about  for every  possible
	unit on each subchannel  (except that channels having  disks
	are not  checked for  other devices).   SSASV is  a  routine
	called by the PI service  routine for the channel  'SSACHN'.
	It dispatches PHYSIO as though it were the routine put  into
	the CDB  by massbus  controller routines  to handle  massbus
	interrupts.

	The base addresses for the SA10s  reside on a page which  is
	not cached, and SSAINI sets  that. The device lists used  by
	the devices are  assumed to reside  on a page  which is  not
	cached, and it is up to the device routines to see that this
	is so.  It is also up to the device routines to assure  that
	any pages involved in I/O  have been flushed from cache,  or
	are not cached.

	~
	SUBTTL Parameters

; Device dependent definitions in the CDB

SSACNI==CDBDDP+0		; CONI SSA,T1
SSACNO==CDBDDP+1		; CONO SSA,SA%CHn(T1)
SSACN1==CDBDDP+2		; what to do before SSACNO
SSABAS==:CDBDDP+3		; address of base register for subchannel
SSASCI==:CDBDDP+4		; subchannel index (4*<SA10 #> + subchan)
SSASBA==:CDBDDP+5		; address of sense buffer for channel
SSADVL==:CDBDDP+6		; address of device list for channel (disk)
SSACUB==:CDBDDP+6		; current UDB that is active on this channel (tape)
SSAFAF==:CDBDDP+7 		; non-zero if FA10
L.SSA==CDBDDP+10-CDBINT		; length of SA10 CDB
	SUBTTL Channel Dispatch Table for SA10

SSADSP::JRST SSAINI		;  0 - Initiation
	JRST SSASTK		;  1 - Stack second channel command
	JRST SSASIO		;  2 - Start I/O
	JRST SSAPOS		;  3 - Position request
	JRST SSALTM		;  4 - Return best xfer
	JRST SSAINT		;  5 - Interrupt processing
	JRST SSACCW		;  6 - Make channel xfer word
	JRST SSAHNG		;  7 - Transfer hung
	JRST SSARST		; 10 - Reset channel
	JRST SSACHK		; 11 - Periodic check
	JRST EXTKDB		; 12 - check legality of unit - use PHYSIO rtn.
	JRST SSACCA		; 13 - Extract address from CCW 

; Dummy routines

SSALTM:	RET
	SUBTTL Initialization

; SSAINI - initialize SA10 devices on system
; Called from PHYSIO via CDSINI entry in SSADSP.
; P4/ first free system channel #
;	CALL SSAINI	or	 CALL CDSINI(ac) ; Where ac/ SSADSP
; RETURN +1: Always
;  P4/ next free system channel #
;   Other AC's not preserved.

SSAINI:	MOVEI T1,SA0BAS/PGSIZ	; page uncacheable data is on
	CALL NOCASH		; turn off caching on it
	ADDI T1,1		; turn off caching for next page as well
	CALL NOCASH
	MOVE T1,[SAXCDB,,SAXCDB+1]
	MOVE T2,SAXMSC		; get maximum subchannel number
	SETZM SAXSEL		; zero selector
	ADDI T2,SAXCDB		; Point to last entry in table
	SETZM SAXCDB		; clear table of CDB for each subchannel
	BLT T1,0(T2)		; clear rest of table
	SETZ P2,		; Start with CH0 on SA0
	DO.
	  MOVX T1,SA%INI!SA%CME	; clear the channel
	  XCT SAXCNO(P2)
	  MOVX T1,SSACHN	; assign PI but do not enable
	  XCT SAXCNO(P2)
	  XCT SAXCNI(P2)	; Read it back
	  IFXN. T1,SA%PIA	; Have a PI assignment?
	    HRLI P2,-SSANSC	; Yes, counter for doing each subchannel
	    DO.
	      CALL GOTCHN	; Check whether there is a free channel slot
	      IFSKP.
		SKIPN SAXFAF(P2) ; is this an FA?
		IFSKP.
		  MOVX T1,FACPSZ ; yes, get a base block big enough for an FA
		  CALL SSAALC
		   BUG.(HLT,SSAFSE,PHYSA,HARD,<PHYSA - Not enough uncached free space for FA10 base block>)
		  MOVEM T1,SAXBAS(P2) ; Set up new base address
		ENDIF.
	        MOVX T1,SA%SET!FLD(.SARSC,SA%FCN)!SA%CME!SSACHN ; Reset subchan
		HRRZ T2,P2	; Get subchannel index
		ANDX T2,<SSANSC-1> ; subchannel only
		STOR T2,SA%CHN,T1 ; Set in reset command
		XCT SAXCNO(P2)	; do the reset
		XCT SAXCNI(P2)	; Read status back
	      ANDXN. T1,SA%PIA	; Make sure it really exists!
		MOVX T1,L.SSA	; Length of CDB
		CALL PHYALC	; allocate CDB
		 RET		; failure, quit
		HRRZ T3,P2	; Get subchannel index
		ANDX T3,<SSANSC-1> ; Isolate subchannel
		MOVEI P1,-CDBINT(T1) ; CDB base address to P1
		MOVEM P1,CHNTAB(P4) ; Save CDB in channel table
		MOVEM P1,SAXCDB(P2) ; Save CDB in SA10 subchannel table
		HRRZM P4,CDBADR(P1) ; Store logical channel number
		HRRZM P2,SSASCI(P1) ; Store subchannel index
		EXCH P1,P3	; Get CDB in P3
		MOVX T1,.BTCDB	; Mark as CDB
		DPB T1,USYBKT
		EXCH P1,P3	; Restore
		MOVX T1,.CTSSA	; Set type
		DPB T1,CSYTYP
		MOVX T1,SSACHN	; SA10 PI channel
		DPB T1,CSYPIA	; Set PIA in configuration information
		STOR T3,SA%CHN,T1 ; Store subchannel number in it
		HRLI T1,(<IORI T1,>) ; Make IOR instruction
		MOVEM T1,SSACN1(P1) ; Store as setup
		MOVE T1,SAXCNO(P2) ; Get CONO SAn,SSACHN
		MOVEM T1,SSACNO(P1) ; Store CONO in CDB
		MOVE T1,SAXCNI(P2) ; Get CONI appropriate for this channel
		MOVEM T1,SSACNI(P1) ; Keep a copy handy in CDB
		SKIPE SAXFAF(P2) ; is this an FA10?
		 SETOM SSAFAF(P1) ; yes, note that this is an FA
		MOVE T1,SAXBAS(P2) ; Get base address for this subchannel
		MOVEM T1,SSABAS(P1) ; Save base address in CDB
		DMOVE T1,[BLT 17,17 ; Get instruction to restore AC's
			  SETOM SAXICH]	; and one to show no int in progress
		DMOVEM T1,CDBJEN(P1) ; Put them in CDB for PHYSIO exit sequence
		MOVE T1,[UNBRK SSA] ; Instruction to return to PI5 routine
		MOVEM T1,CDBJEN+2(P1) ; Put in exit sequence
		MOVEI T1,SSADSP	 ; Insert address of dispatch vector
		MOVEM T1,CDBDSP(P1) ; into DCB
		MOVE Q3,[-MAXSAU,,CDBUDB] ; AOBJN pointer to UDB table
		ADDI Q3,(P1)	; Relocate pointer
		MOVEM Q3,CDBCUN(P1) ; Store in UDB as current pointer
		MOVEM Q3,CDBIUN(P1) ; Store also as initial pointer
		SETOM CDBXFR(P1) ; Indicate channel free   ???
		MOVEI Q2,0	; first unit #
		DO.
		  SETZ P3,	; In case not wanted
		  SKIPN SSAFAF(P1) ; Is this an FA10?
		  IFSKP.
;		    SKIPE T1,[FADDSP] ; FA10 disk service exists?
;		     CALL UDSINI(T1) ; Yes, initialize
		    jfcl
		  ELSE.
		    SKIPE T1,[CC1DSP] ; SA10 disks exist?
		     CALL UDSINI(T1) ; Yes, initialize
		  ANDE. P3
		    SKIPE T1,[SATDSP] ; SA10 tapes exist?
		     CALL UDSINI(T1) ; Yes, initialize
		  ENDIF.
		  LOAD T2,USTYP,UDBSTS(P3)	; Any device there?
		  SKIPE T2
		  IFSKP.	; Say "Not there and you can't have it anyway"
		    MOVX T2,US.UNA!US.OFS
		    IORM T2,UDBSTS(P3)
		  ENDIF.
		  MOVEM P3,0(Q3) ; Store in CDB if any (0 if none)
		  ADDI Q2,1	; Next device
		  AOBJN Q3,TOP.	; Keep going
		ENDDO.
		ADDI P4,1	; Next system channel #
	      ENDIF.
	      AOBJN P2,TOP.	; do each subchannel
	    ENDDO.
	    MOVX T1,SA%SET!FLD(.SAPIE,SA%FCN)!SSACHN ; enable PI interrupts
	    DO.
	      XCT SAXCNO-4(P2)	; enable PI interrupts on SA10 just processed
	      ADDI T1,FLD(.SACH1,SA%CHN) ; Next subchannel on that SA10
	      JXN T1,SA%CHN,TOP. ; do next subchannel if any left
	    ENDDO.
	  ELSE.
	    ADDI P2,SSANSC	; No PIA, on to next SA10
	  ENDIF.
	  CAMGE P2,SAXMSC	; done them all?
	   LOOP.		; No, do next
	ENDDO.
	MOVE T1,[JRST SSASV2]	; Interrupt entry for 2 SA10's
	SKIPE SAXCDB		; SA0 found?
	 SKIPN SAXCDB+SSANSC	; and SA1 too?
	  HRRI T1,SSASV1	; Only 1 SA10, use simpler routine
	MOVEM T1,SSASV		; establish entry routine
	RET			; Return to PHYSIO

KNIRH2==5

GOTCHN:	SETZ P4,		; Initiate search for unused channel slot
	DO.
	  CAIL P4,CHNN		; Less than maximum number of channels?
	   RET			; No, fail
	  CAIE P4,KNIRH2	; Is this a KLNI channel?
	   CAIN P4,KLPRH2	;  or a KLIPA channel?
	  IFSKP.		; No
	    SKIPN CHNTAB(P4)	; Is this channel already assigned?
	     JRST RSKP		; No, use it
	  ENDIF.
	  AOJA P4,TOP.		; Next possible channel number
	ENDDO.
	SUBTTL Start I/O and Positioning

; SSAPOS - start positioning
; P1/ CDB
; P3/ UDB
; P4/ IORB
;	CALL CDSPOS(ac)		; Where ac/ SSADSP
; RETURNS +1: failure
; RETURNS +2: success, positioning started

SSAPOS:	HRRZ T1,UDBDSP(P3)	; address of device routine vector
	CALLRET UDSPOS(T1)	; Start positioning

; SSASIO - Start an I/O operation
; P1/ CDB
; P3/ UDB
; P4/ IORB
;	CALL CDSSIO(ac)		; Where ac/ SSADSP
; RETURNS +1: failure
; RETURNS +2: success, I/O started

SSASIO:	HRRZ T1,UDBDSP(P3)	; Get device routine vector
	CALL UDSSIO(T1)		; Try to start I/O
	 RETBAD			; Lost, do not skip
	RETSKP			; Won

; SSASTK - stack a second command
; P1/ CDB
; P3/ UDB
; P4/ IORB
;	CALL CDSSTK(ac)		; Where ac/ SSADSP
; RETURNS +1: failure
; RETURNS +2: success, command stacked

SSASTK:	HRRZ T1,UDBDSP(P3)	; Get device dispatch
	CALLRET UDSSTK(T1)	; Let him stack it if he can
	SUBTTL Hung, Reset, and Check entries

; SSAHNG - handle a hung transfer
; called with PI off
; P1/ CDB
; P3/ UDB
; P4/ IORB
;	CALL CDSHNG(ac)		; Where ac/ SSADSP
; RETURNS +1: Always

SSAHNG:	RET			; do nothing

; SSARST - Reset the channel and all units
; T1/ 0 for reset just the channel (subchannel)
; T1/ 1 for full reset
; ( both resets currently the same for the SA10 )
; P1/ CDB
;	CALL CDSRST(ac)		; Where ac/ SSADSP
; RETURNS +1: Always

SSARST:	MOVX T1,SA%SET!FLD(.SARSC,SA%FCN)!SA%CME ; Reset subchannel
	XCT SSACN1(P1)		; do any setup
	XCT SSACNO(P1)
	RET

; SSACHK - check PIA for SA10 (call about once a second)
; P1/ CDB
;	CALL CDSCHK(ac)		; Where ac/ SSADSP
; RETURNS +1: Always

SSACHK:	XCT SSACNI(P1)		; do CONI
	LOAD T1,SA%PIA,T1	; Isolate PIA
	LDB T2,CSYPIA		; Get what PIA should be
	CAMN T1,T2		; are they the same?
	 RET			; Yes
	HRRZ T3,SSASCI(P1)	; No, get SubChannel Index
	BUG.(CHK,SSAPIM,PHYSA,HARD,<PHYSA - SA10 lost PI assignment>,<<T3,CONI>>)
	LDB T1,CSYPIA		; Get correct PIA
	IORX T1,SA%SET!FLD(.SAPIE,SA%FCN) ; enable PI interrupts 
	XCT SAXCNO(T3)		; Set the PIA
	RET
	SUBTTL CCW Generation entry

; SSACCW - generate a channel xfer word.
; This routine generates the second word of an SA10 CCW (IOW).
; T1/ mode,,+count (1B0 if backwards)
; T2/ Physical address
; P1/ CDB
; P3/ UDB
; P4/ IORB
;	CALL CDSCCW(ac)		; Where ac/ SSADSP
; RETURNS +1: Always
;  T1/ CCW for this transfer
;[note: Transfer cannot cross page boundary ... that is caller's problem.]

SSACCW:	HRRZ T3,T1		; Get count
	TXZ T1,1B0		; clear backwards bit from mode
	HLRZS T1		; Get mode in correct place
	CAIN T1,IRMWRD		; Is it the common case (word mode)?
	IFSKP.
	  IFG. T1		; make sure legal mode
	    CAILE T1,IRMMAX
	  ANSKP.
	    IDIV T3,MODTAB(T1)	; convert to words
	    SKIPE T4		; Leftovers?
	     ADDI T3,1		; Yes, need another word
	  ELSE.
	    BUG.(CHK,SSAIHM,PHYSA,HARD,<PHYSA - Illegal HDW Mode - Word Mode Assumed>,<<T1,MODE>,<SSASCI(P1),SUBCHN>>)
	    MOVX T1,IRMWRD	; assume word mode
	  ENDIF.
	ENDIF.
	MOVX T1,SC%LST		; build CCW - indicate no chaining
	MOVNI T3,0(T3)		; Get negative count
	STOR T3,SC%CNT,T1	; Store count in CCW
	STOR T2,SC%ADR,T1	; Store address in CCW
	MOVEM T1,CDBCCL(P1)	; Store CCW
	RET			; Return
;#500 SSACCA - EXTRACT THE PHYSICAL MEMORY ADDRESS FROM A CCW TRANSFER WORD.
;#500 ARGUMENT:
;#500   T1/	CCW WORD
;#500 RETURNS:
;#500   T1/	ADDRESS, OR ZERO IF NONE

SSACCA:	LOAD T1,SC%ADR,T1	;#500  Get Address from CCW
	RET			;#500 .
	SUBTTL Interrupt routine

; SSAINT - service interrupt on SA10 for subchannel
; P1/ CDB
;	CALL CDSINT(ac)		; Where ac/ SSADSP
; RETURNS +1: Error detected
;  P4/ 0 : request PHYSIO to dismiss interrupt
;      negative : Request Schedule cycle
;      IORB : I/O completed on this IORB
;  P2-P3 not preserved
;  Q1-Q4 not preserved
; RETURNS +2: no error detected
;  P4/ 0 : request PHYSIO to dismiss interrupt
;      negative : Request Schedule cycle
;      IORB : I/O completed on this IORB
;  P2-P3 not preserved
;  Q1-Q4 not preserved

SSAINT:	SETZ P4,		; assume exit with no IORB
	XCT SSACNI(P1)		; get conditions on channel
	MOVEM T1,CDBCNI(P1)	; save them
REPEAT 0,<	;only for "real" SA10
	IFXN. T1,SA%MPE!SA%NXM	; any fatal memory errors?
	  SETOM SAXICH		; Yes, show no subchannel being serviced
	  MOVX T2,<-6,,0>	; Read 6 SA10 registers (0-5)
	  HRRZ T3,SSASCI(P1)	; Get subchannel index
	  DO.
	    MOVEI T1,0(T2)	; Register to read
	    LSH T1,3		; Shift register number to select position
	    XCT SAXCNO(T3)	; Select word desired
	    MOVEI T1,SAXERD(T2)	; Where to store this word
	    XCT SAXDTI(T3)	; Input word to buffer
	    AOBJN T2,TOP.	; Loop to get all registers
	  ENDDO.
	  MOVX T1,SA%CME!SSACHN	; clear memory errors
	  XCT SAXCNO(T3)	; clear memory errors
	  MOVE T4,CDBCNI(P1)	; Get conditions back
	  IFXN. T4,SA%NXM	; Was it a NXM?
	    BUG.(CHK,SSANXM,PHYSA,HARD,<PHYSA - NXM detected by SA10>,<<SAXERD,CHN/CBUS/uPC>,<SAXERD+1,MEMADR>,<SAXERD+2,MB.LH>,<SAXERD+3,MB.RH>>)
	    AOS CDBNXM(P1)	; count errors
	  ELSE.
	    HLRZ T1,SAXERD+2	; Get channel pariter error happened on
	    ANDI T1,3		; Isolate subchannel number
	    ADDI T3,(T1)	; create subchannel index
	    MOVSI T1,(SIXBIT 'SSA') ; Record who saw error
	    MOVEM T1,DEVMPE	; Save for JOB0
	    AOS CDBPAR(P1)	; count errors
	  ENDIF.
	  RETBAD
	ENDIF.
>;REPEAT 0
	MOVE Q3,SSABAS(P1)	; Get base register address
	SKIPN SSAFAF(P1)	; Is this really an FA10?
	IFSKP.
	  LOAD T1,FASTW,(Q3)	; Get FA10 status word
	  MOVEM T1,CDBCS0(P1)	; Save it in the CDB
	ELSE.
	  DMOVE T1,1(Q3)	; Get SA10 status words from base block
	  DMOVEM T1,CDBCS1(P1)	; Save them in the CDB
	ENDIF.
	AOS T2,SAXTTP		; Get Trace Table Pointer
	ANDI T2,SAXTTL-1	; Wrap around
	MOVEM T1,SAXTT(T2)	; Store status word 1 in table
	SKIPN SSAFAF(P1)	; Is this an FA10?
	IFSKP.
	  LOAD T1,FAUNT,.FAUSB(Q3) ; get number of device causing interrupt
	ELSE.			; SA10 case
	  LOAD T1,S1%DEV,1(Q3)	; Get number of device causing interrupt
	  MOVE Q2,T1		; copy address
	ENDIF.
	ANDX T1,<MAXSAU-1>	; convert to unit number
	CALL SETUDB		; Set P3 := UDB, T2 := xxxDSP
	IFN. P3			; Unit known?
	  CALL UDSINT(T2)	; Yes, call interrupt service
	   NOP			; ERROR: special action necessary?
	ELSE.			; Interrupt from unknown unit
	  SKIPN SSAFAF(P1)	; If FA10, this is easy
	  IFSKP.
;	    MOVEI T2,FADDSP	; Get address of FA disk service
;	    CALL FADDSP+UDSINT	; call interrupt routine
	     BUG.(CHK,SSAFIF,PHYSA,HARD,<PHYSA - FA unit initialization failed>,<<Q2,DEVADR>,<SSASCI(P1),SUBCHN>>)
	  ELSE.			; SA10 case
	    MOVE T1,Q2		; Get device address
 	    TRZ T1,<MAXSAU-1>	; Remove unit code
	    SETZ T2,		; don't know what type of unit
	    CAIN T1,.IDDSK	; disk?
	     MOVEI T2,CC1DSP	; Yes
	    CAIN T1,.IDMTA	; Mag tape?
	     MOVEI T2,SATDSP	; Yes
	    IFE. T2		; bugchk if no unit found
	      BUG.(CHK,SSAUKU,PHYSA,HARD,<PHYSA - Unknown unit interrupted>,<<Q2,DEVADR>,<CDBCS1(P1),SW1>,<SSASCI(P1),SUBCHN>>)
	    ELSE.
	      CALL UDSINT(T2)	; call interrupt routine
	       BUG.(CHK,SSAIIS,PHYSA,HARD,<PHYSA - Unit initialization failed>,<<Q2,DEVADR>,<SSASCI(P1),SUBCHN>>)
	    ENDIF.
	  ENDIF.
	ANDN. P3		; Have a UDB?
	  MOVEI Q3,CDBUDB(P1)	; Yes, get address of UDB list
	  ADDI Q3,0(Q2)		; Where to store UDB for this unit
	  MOVEM P3,0(Q3)	; Store UDB for unit
	ENDIF.
	MOVX T1,FLD(.SASTS,SA%FCN) ; clear status of interrupting channel
	XCT SSACN1(P1)		; do any setup
	XCT SSACNO(P1)		; clear status
	SETOM SAXICH
	RETSKP			; Good return
	SUBTTL Interrupt Service - called from PI service routine

; This routine is called by the PI service routine for "SSACHN".
; It has T1-T4 & CX available for scratch, and must save any
; other AC's it uses.  P is set to a ^O20 word stack, and a RET
; will return to process the next device on that channel.  The
; RET is used if the interrupt was not for the SA10.  Otherwise,
; return is via "UNBRK SSA".

; This routine will set up for a call to PHYSIO as though an
; interrupt came from an RH20 channel thru the interrupt code in
; a CDB.  PHYSIO will save all the AC's except for P1, which it
; expects in CDBSVQ, and the AC's will be restored in CDBJEN,
; thru which PHYSIO exits.

;; SSASV::	; SA10 PI interrupt service routine, JRST SSASV1 or SSASV2

SSASV2::			; interrupt routine if 2 SA10s
	MOVE T3,SAXSEL		; get last channel serviced
	TRC T3,SSANSC		; switch to other SA10
	XCT SAXCNI(T3)		; do a CONI
	JXN T1,SA%PIR,SSASV9	; service interrupt if it wants it
SSASV1::			; interrupt routine if only one SA10 
	xct saxcni+0
	jxn t1,sa%pir,ssasv9
	xct saxcni+1
	jxn t1,sa%pir,ssasv9
	xct saxcni+2
	jxn t1,sa%pir,ssasv9
	xct saxcni+3
	jxn t1,sa%pir,ssasv9
	ret

;	MOVE T3,SAXSEL		; get subchannel number
;	XCT SAXCNI(T3)		; do a CONI
;	JXE T1,SA%PIR,R		; return to PI routine if no interrupt request
SSASV9:				; merging point of SSASV1,SSASV2
	setz t3,
;	MOVEM T3,SAXSEL		; remember channel serviced
	MOVE T4,T1		; save the status
	ANDX T1,SA%SFN		; only want status flags
	JFFO T1,.+2		; find the first flag
	IFSKP.
	  ADDI T3,-^L<SA%SFN>(T2)  ; compute subchannel index
	  MOVEM T3,SAXICH	; remember where interrupt came from
	  SKIPE T2,SAXCDB(T3)	; get address of CDB for this channel
	  IFSKP.
	    BUG.(CHK,SSAUKC,PHYSA,HARD,<PHYSA - Interrupt from unknown channel>,<<T3,SUBCHN>,<T4,CONI>>)
	    RET			; dismiss interrupt
	  ENDIF.
	  MOVEM P1,CDBSVQ(T2)	; save P1 where PHYSIO expects it
	  MOVE P1,T2		; put CDB address in P1 for PHYSIO
	  JRST PHYINT		; go to interrupt handler in PHYSIO
	ENDIF.
	LOAD T1,SA%PIA,T4	; Z80 interrupt, get current PIA
	IORX T1,<FLD .IUCLR,IU.FCN> ; merge in clear Z80 interrupt function
	XCT SAXCNO(T3)		; do the CONO
	RETSKP			; done, dismiss interrupt
	SUBTTL SAINGO - Initialization routine to start I/O

; SAINGO - Routine to start I/O during initialization
; [Note: Caller must worry about caching of channel program and I/O area.]
; T1/ address of channel program 
; T2/ 0 = do reset (else don't)
; P1/ CDB
;	CALL SAINGO
; RETURNS +1: I/O unsuccessful
;  T1-T4 destroyed
; RETURNS +2: I/O successful
;  T1-T4 destroyed

SAINGO::SAVEQ			; Save some AC's
	MOVE Q1,T1		; copy CP address
	TXO Q1,TCH		; create transfer program
	MOVE Q2,SSASCI(P1)	; Get subchannel index
	MOVE Q3,SSABAS(P1)	; Get base address
	IFE. T2			; Reset desired?
	  CALL SSARST		; Reset subchannel, clear errors
	  MOVX T1,4000		; some delay for the SA10 and channel
	  SOJG T1,.		; Stall
	ENDIF.
	MOVX T3,4		; Try up to 4 times
	DO.
	  SETOM 1(Q3)		; Store phony SA10 status
	  SETOM CDBCS1(P1)	; Store phony status for caller
	  MOVE T1,Q1		; Get CP address
	  CALL SSAGO		; Start the I/O
	  MOVX T4,100000	; Lots of time to find the device
	  DO.
	    XCT SSACNI(P1)	; Get current conditions
	    IFXN. T1,SA%MPE!SA%NXM ; Parity error or NXM?
	      BUG.(CHK,SAIERR,PHYSA,HARD,<SAINGO - parity error or NXM>,<<T1,CONI>,<Q2,SUBCHN>>)
	      SETZ T4,		; blow it away
	    ENDIF.
	    TDNN T1,BITS+^L<SA%SFN>(Q2) ; Status flag present?
	     SOJG T4,TOP.	; No, go look again
	  ENDDO.
	  IFG. T4		; continue if not timed out yet
	    DMOVE T1,1(Q3)	; Get SA10 status words
	    DMOVEM T1,CDBCS1(P1) ; Save in CDB
	    IFXE. T1,FLD(.S1SER!.S1BIP!.S1CSE,S1%CHS) ; Stop if "not found"
	      JXE T1,FLD(.S1BSY!.S1CUE,S1%DVS),ENDLP. ; done if no transients
	    ENDIF.
	    MOVX T1,SA%CME!FLD(.SASTS,SA%FCN) ; clear status and errors
	    XCT SSACN1(P1)	; do any setup
	    XCT SSACNO(P1)	; Now clear them so we can try again
	    SOJG T3,TOP.	; Try again if haven't tried too much
	  ENDIF.
	  SETZ T4,		; Indicate failure
	ENDDO.
	SETZM 0(Q3)		; clear channel dispatch
	MOVX T1,SA%CME!FLD(.SASTS,SA%FCN) ; clear status and errors
	XCT SSACN1(P1)		; do any setup
	XCT SSACNO(P1)		; do clears
	JUMPE T4,R		;"not found" return
	RETSKP			; Win big
	SUBTTL SSAGO - Start I/O

; SSAGO - Start I/O on SA10 subchannel
; P1/ CDB
; T1/ TCH to Channel program, or Mux pointer (SA10 only)
;	CALL SSAGO
; RETURNS +1: Always
;  T1 destroyed

SSAGO::	SKIPE SSAFAF(P1)	; Is this an SA10?
	IFSKP.
	  MOVEM T1,@SSABAS(P1)	; Yes, store pointer
	ENDIF.
	MOVX T1,SA%SET!FLD(.SAGOF,SA%FCN) ; Request channel to execute cmd
	XCT SSACN1(P1)		; do any setup
	XCT SSACNO(P1)		; Go
	RET			; Return
	SUBTTL SSAALC - Allocate space in uncached page

; SSAALC - Allocate uncached space
; T1/ number of words needed
; Returns +1: Failure - not enough space
; Returns +2: Success
;  T1/ Address of 1st word allocated

SSAALC::SAVEAC <T2,T3>
	MOVE T3,T1		; copy size to T3
	HRLI T1,(T1)		; copy amount wanted to LH
	ADD T1,SAXFRE		; calculate <-amt left>,,<new free>
	JUMPGE T1,R		; fail if negative count goes positive
	EXCH T1,SAXFRE		; set up new header, get address from old
	HRRZS T2,T1		; address only, copy to T2
	HRLI T2,1(T1)		; destination,,source
	MOVSS T2		; source,,destination
	ADDI T3,-1(T1)		; last address to clear in T3
	SETZM (T1)		; clear block
	BLT T2,(T3)
	RETSKP			; Skip return for success
	SUBTTL IU10 Parameters

IU0==:440			; device code of first IU10
IU1==:444

; CONI/CONO bits

IU.DFL==:MASKB(24,27)		; (CONI) channel done flags
IU.INT==:1B28			; (CONI) interrupt
IU.AOK==:1B29			; (CONI) OK (running, no reset pending)
IU.DRQ==:1B30			; (CONI) data request
IU.STA==:MASKB(31,32)		; (CONI) protocol state
IU.FCN==:MASKB(28,32)		; (CONO) function code
IU.CHN==:MASKB(31,32)		; (CONO) channel number in function code
IU.PIA==:MASKB(33,35)		; PIA channel

; DATAI/DATAO bits

IU.GFL==:MASKB(24,27)		; (DATAI) channel go flags
IU.DAT==:MASKB(28,35)		; data to/from IU10
IU.DCH==:MASKB(29,30)		; channel number in commands which take it

; Protocol state in CONI 

.IUCWT==:0			; waiting for command
.IUDWT==:1			; waiting for data
.IUBZY==:2			; busy
.IUDAT==:3			; data available for CPU

; Function code in CONO

.IUNOP==:1			; no-op
.IUCLR==:4			; clear interrupt
.IUSDR==:5			; set data request
.IURST==:6			; reset all channels
.IUERS==:7			; emergency reset
.IUSGF==:10			; (+chnl#) set go
.IUCDF==:14			; (+chnl#) clear done

; Data (status code) in DATAI

.IZOKB==:001			; good status
.IZBPE==:020			; buffer parity error
.IZCPE==:040			; control memory parity error

; Data (command code) in DATAO

.IZNOP==:000			; no-op
.IZGO==:203			; initialize channel
.IZRST==:204			; read status
.IZRNN==:214			; read node number
.IZSLR==:215			; selective reset
	SUBTTL IU10 Support routines

;  SAnCNI - Simulation for CONI SAn,T1.  This routine isn't as straightforward
; as it could have been because it can be called from channel 5 unvectored
; interrupt level where the stack is disgustingly short.  Consequently this
; routine must be *very* conservative with its stack usage.  No SAVEAC is done,
; so T1 (which is known to be the CONI address) and CX (saved by PISC5) are the
; only two AC's available to us.

SA1CNI::SKIPA T1,[IU1IOT]
SA0CNI:: MOVEI T1,IU0IOT
SANCNI:	STKVAR <SACONI,IUDATI,IUCONI>
	SETZM SACONI		; initially no status
	MOVX CX,^D2000
	DO.
	  XCT $IUSOK(T1)	; see if OK
	   SOJG CX,TOP.		; no, wait some more
	ENDDO.
	IFG. CX			; got an okay?
	  XCT $IUCNI(T1)	; do CONI IUn,IUCONI
	  XCT $IUDTI(T1)	; do DATAI IUn,IUDATI
	  IFQN. IU.INT,IUCONI	; is IU10 interrupt set?
	    SETONE SA%PIR,SACONI ; yes, just set PIR
	  ENDIF.
	  LOAD T1,IU.PIA,IUCONI	; get PIA
	  STOR T1,SA%PIA,SACONI	; save IU PIA as SA PIA
	  LOAD T1,IU.DFL,IUCONI	; get channel done flags
	  STOR T1,SA%SFN,SACONI	; set as status flags
	  IFN. T1		; if any channels done
	    SETONE SA%PIR,SACONI ; indicate interrupt requested
	  ENDIF.
	  LOAD T1,IU.GFL,IUDATI	; get go flags
	  STOR T1,SA%GON,SACONI	; save them
	  SETONE SA%IEN,SACONI	; interrupt enable is always set
	ENDIF.
	MOVE T1,SACONI		; get resulting status
	RET			; and return to caller
; Here to define the CONI instruction vectors

	DEFINE IUXIOT (N) <
IU'N'IOT:
	PHASE 0
$IUSOK:!CONSO IU'N',IU.AOK
$IUCNI:!CONI IU'N',IUCONI
$IUDTI:!DATAI IU'N',IUDATI
	DEPHASE
>; DEFINE IUXIOT

	IUXIOT 0		; define vector for IU0
	IUXIOT 1		; define vector for IU1

	ENDSV.
; SA0CNO - Simulation for CONO SA0,(T1)

SA0CNO::TRVAR <SACONO,IUCONO,IUDATO>
	SAVEAC <T1,T2>
	HRLI T1,<(CONO IU0,)>	; set up CONO
SANCNO:	CALL DOCONO		; interpret code
	 XCT IUCONO		; success, hit it
	RET			; return to caller

; SA1CNO - Simulation for CONO SA1,(T1)

SA1CNO::TRVAR <SACONO,IUCONO,IUDATO> ; ** must match SA0CNO **
	SAVEAC <T1,T2>
	HRLI T1,<(CONO IU1,)>	; set up CONO
	JRST SANCNO
; ... still under CONO TRVAR context
;
;  Common code to build a CONO via the IU10.  Warning: it is NOT "alright" to
; do a SA%INI CONO except at system initialization or unless you are prepared
; to do a .SARSC CONO right afterwards.  This is because unlike a real SA the
; IU SA is stopped and the base address cleared by this function.
;  Also, neither SA%INI nor .SARSC should be done with PI's on.
; Returns +2 if no CONO should be done

DOCONO:	HLLZM T1,IUCONO		; initially no conditions set
	HRRZM T1,SACONO		; save CONO argument
	IFXN. T1,SA%INI		; push the button?
	  MOVX T1,.IURST	; yes, get reset all function
	  STOR T1,IU.FCN,IUCONO	; set in command
	  XCT IUCONO
	  MOVX T1,^D2000	; timeout period
	  MOVE T2,IUCONO	; get CONO word
	  ANDX T2,774B9		; only want device code
	  IOR T2,[CONSO .-.,IU.AOK] ; make CONSO out of it
	  DO.
	    XCT T2		; do CONSO
	     SOJG T1,TOP.	; wait until okay
	  ENDDO.
	  IFG. T1		; make sure didn't time out
	    MOVX T1,.IUCLR	; get clear interrupt code
	    STOR T1,IU.FCN,IUCONO ; set in command
	    XCT IUCONO
	    MOVX T1,.IZNOP	; send a (bogus) no-op
	    MOVE T2,IUCONO	; get CONO word
	    ANDX T2,774B9	; only want device code
	    IOR T2,[DATAO .-.,T1] ; make DATAO out of it
	    XCT T2		; do DATAO
	    LOAD T1,SA%PIA,SACONO ; get PIA
	    STOR T1,IU.PIA,IUCONO ; okay to let it get set now
	    CALL IU1DRW		; wait for DREQ to fall
	  ANSKP.
	    RETSKP		; and don't try to do anything more!
	  ENDIF.
	  SETZRO IU.PIA,IUCONO	; loser, don't let this IU have a PIA!
	  MOVX T1,.IUNOP	; set up a NOP
	  STOR T1,IU.FCN,IUCONO
	  RET			; make sure this last CONO gets done
	ENDIF.
	LOAD T1,SA%PIA,SACONO	; get PIA
	STOR T1,IU.PIA,IUCONO	; set it

; . . .
; . . .

	LOAD T1,SA%FCN,SACONO	; get function code
	CAIE T1,.SARSC		; reset subchannel?
	IFSKP.
	  STKVAR <BASADR>
	  LOAD T2,SA%CHN,SACONO	; get subchannel
	  LDB T1,[POINT 7,IUCONO,9] ; get IU10 device code
	  LSH T1,2		; offset it properly
	  SUBI T1,IU0
	  ADDI T1,(T2)		; make SA10 channel number
	  MOVE T1,SAXBAS(T1)	; and base address from that
	  MOVEM T1,BASADR
	  MOVX T1,.IZGO		; get a GO command
	  STOR T2,IU.DCH,T1	; set channel number in GO
	  CALL IU1SNC		; send it down
	  IFSKP.
	    LDB T1,[POINT 8,BASADR,35] ; send three bytes of channel base addr
	    CALL IU1SND
	  ANSKP.
	    LDB T1,[POINT 8,BASADR,27] ; second byte
	    CALL IU1SND
	  ANSKP.
	    LDB T1,[POINT 8,BASADR,19] ; third byte
	    CALL IU1SND
	  ANSKP.
	    CALL IU1CWT		; wait for protocol to return done
	  ANSKP.
	    MOVX T1,.IUCLR	; get clear interrupt code
	    STOR T1,IU.FCN,IUCONO ; set in command
	    XCT IUCONO		; now do it
	    MOVX T1,.IZRST	; read status
	    LOAD T2,SA%CHN,SACONO ; get subchannel
	    STOR T2,IU.DCH,T1	; set it
	    CALL IU1SNC		; do it!
	  ANSKP.
	    CALL IU1DWT		; wait for it to complete
	  ANSKP.
	    MOVE T2,IUCONO	; get IOT
	    ANDX T2,774B9	; only want device code
	    IOR T2,[DATAI .-.,T1] ; make DATAI
	    XCT T2		; get status
	    LOAD T1,IU.DAT,T1	; get status back
	    MOVEM T1,BASADR	; Save status for a moment
	    CALL IU1DRW		; Wait for DREQ to fall
	  ANSKP.
	    MOVE T1,BASADR	; Get the status back
	    CAIE T1,.IZOKB	; got good status?
	  ANSKP.

; . . .
; . . .

	  ELSE.			; here the channel is sick sick sick
	    LOAD T2,SA%CHN,SACONO ; failed, get subchannel number
	    LDB T1,[POINT 7,IUCONO,9] ; get IU10 device code
	    LSH T1,2		; offset it properly
	    SUBI T1,IU0
	    ADDI T1,(T2)	; make SA10 channel number
	    MOVX T2,<SETZ T1,>	; CONI T1 now just zeros T1
	    MOVEM T2,SAXCNI(T1)
	    MOVX T2,<NOP>	; CONO now does nothing
	    MOVEM T2,SAXCNO(T1)
	  ENDIF.
	  RETSKP		; return, doing nothing more

	  ENDSV.		; exit STKVAR BASADR context
	ENDIF.
	CAIE T1,.SAGOF		; frob GO flag?
	IFSKP.
	ANDQN. SA%SET,SACONO	; yes, better be setting it!
	  LOAD T1,SA%CHN,SACONO	; we are, get subchannel to set
	  ADDI T1,.IUSGF	; make into appropriate set GO command
	  STOR T1,IU.FCN,IUCONO	; store resulting function
	  RET
	ENDIF.
	CAIE T1,.SASTS
	IFSKP.
	ANDQE. SA%SET,SACONO	; yes, better not be setting it!
	  LOAD T1,SA%CHN,SACONO	; we aren't, get subchannel to set
	  ADDI T1,.IUCDF	; make into appropriate clear DONE command
	  STOR T1,IU.FCN,IUCONO	; store resulting function
	  RET
	ENDIF.
	CAIE T1,.SAPIE		; set interrupt enables?
	 CAIN T1,.SANOP		; or no-op?
	IFNSK.
	  MOVX T1,.IUNOP	; yes, get no-op code
	  STOR T1,IU.FCN,IUCONO	; set in command
	  RET
	ENDIF.
	BUG.(HLT,SSABGC,PHYSA,HARD,<PHYSA - bogus CONO>,<<SACONO,CONOFN>>)
	RET
	SUBTTL IU10 protocol transmit/receive

; ... still under CONO TRVAR context

; Routine to send IU10 protocol command
; Accepts: T1/ protocol byte to send
;	CALL IU1SNC for command, CALL IU1SND for data
; Returns: +1 Failure
;	   +2 Success

IU1SNC:	TDZA T2,T2		; .IUCWT=0 so eqv to SKIPA T2,[.IUCWT]
IU1SND:	 MOVX T2,.IUDWT		; waiting for data
	STKVAR <STATE>
	MOVEM T2,STATE		; save desired protocol state
	MOVE T2,IUCONO		; get CONO word
	ANDX T2,774B9		; only want device code
	IOR T2,[CONI .-.,T2]	; make CONI out of it
	XCT T2			; do CONI
	TXNE T2,IU.AOK		; protocol ok?
	 TXNE T2,IU.DRQ		; yes, data request?
	  RET			; protocol lost or data request
	LOAD T2,IU.STA,T2	; get protocol state
	CAME T2,STATE		; waiting for command?
	 RET			; no, complain
	MOVE T2,IUCONO		; get CONO word
	ANDX T2,774B9		; only want device code
	IOR T2,[DATAO .-.,T1]	; make DATAO out of it
	XCT T2			; do DATAO
	CALLRET IU1DRW

	ENDSV.
; ... still under CONO TRVAR context

; Routine to wait for IU10 DREQ to fall
;	CALL IU1DRW
; Returns: +1 Failure
;	   +2 Success

IU1DRW:	MOVX T1,.IUSDR		; get set DREQ
	STOR T1,IU.FCN,IUCONO	; set in command
	XCT IUCONO
	MOVX T1,^D2000		; this long to wait
	MOVE T2,IUCONO		; get CONO word
	ANDX T2,774B9		; only want device code
	IOR T2,[CONSZ .-.,IU.DRQ] ; make CONSZ out of it
	DO.
	  XCT T2		; do CONSZ
	   SOJG T1,TOP.
	ENDDO.
	XORX T2,IU.DRQ!IU.AOK	; now check for OK status
	XCT T2
	 JUMPG T1,RSKP		; and that it said it was done
	RET			; no to either, indicate lossage
; ... still under CONO TRVAR context

; Routine to wait for IU10 protocol command to complete
;	CALL IU1CWT or CALL IU1DWT
; Returns: +1 Failure
;	   +2 Success

IU1DWT:	SKIPA T1,[IU.AOK!<FLD .IUDAT,IU.STA>] ; data wait
IU1CWT:	 MOVX T1,IU.AOK!<FLD .IUCWT,IU.STA> ; command wait
	STKVAR <WAITCN>
	MOVEM T1,WAITCN
;	MOVEI T2,^D25000	; wait at last 50 ms
	MOVSI T2,1		; KOO's change
	DO.
	  MOVE T1,IUCONO	; get CONO word
	  ANDX T1,774B9		; only want device code
	  IOR T1,[CONI .-.,T1]	; make CONI out of it
	  XCT T1		; do CONI
	  ANDX T1,IU.AOK!IU.DRQ!IU.STA ; only look at OK, DREQ, state
	  CAMN T1,WAITCN	; wait condition satisfied?
	  IFSKP.
	    SKIPLE T2		; give up if already timed out
	     CAIE T1,IU.AOK!<FLD .IUBZY,IU.STA> ; busy?
	      SOJA T2,R		; error if not
	    MOVE T1,IUCONO	; get CONO word
	    ANDX T1,774B9	; only want device code
	    IOR T1,[CONSO .-.,IU.INT] ; make CONSZ out of it
	    DO.
	      XCT T1		; do the CONSZ
	       SOJG T2,TOP.	; not yet
	    ENDDO.
	    LOOP.		; interrupt or timeout, take another look
	  ENDIF.
	ENDDO.
	RETSKP

	ENDSV.

	ENDTV.			; leave CONO TRVAR context
	TNXEND
	END