.title DUAL_ISR10A Two Port Master Interrupt Subroutine ; ; This contains the code for the master two port interrupt service routine ; ; It process all interrupts that come from both ports. ; Some of these interrupts are from Q-Bus and VME devices, so they are rerouted ; to their respective ISRs ; ; For each interrupt, the procedure is as follows ; ; 1) Read the pQBA INT1 register and check for any errors. ; If there are any errors, return them, clear INT1 to disable pQBA ; interrupts and clearr the errors, signal the pQBA error device, ; and exit. ; ; 2) If there were no INT1 errors above, read the pQBA INT0 register. ; Read the INT1 register to make sure that no error ocurred in reading ; INT0. If an INT1 error occurs, disable INT0 and INT1 interrupts, ; return the errors, and signal the pQBA error device. If a Q-Bus ; device vector was read from INT0, mask off the unused bits and ; range check it. If it is from 0x100 to 0x3fc, then use it as an ; index into the ISR dispatch table. Check the address associated ; with the vector to make sure that an ISR exists for the vector. ; If the ISR exists, call the dispatch code. If the vector is out ; of range, or if no ISR exists, set the error, signal the pQBA error ; device, disable pQBA interrupts and return. ; ; 3) After the sub ISR code returns to the main ISR, decrement the ISR loop ; count. If the count is > 0, go to step 5. Otherwise, ; return a count overflow error on the pVBA error device, disable ; pVBA INT0 interrupts, signal the device and exit. ; 4) If the ISR has not been exited due to previous errors, read the pVBA INT1 ; register and check for any errors. If there are any errors, return ; them, disable pQBA interrupts, signal the pVBA error device, and exit. ; ; 5) If there were no INT1 errors above, read the pVBA INT0 register. ; Read the INT1 register to make sure that no error ocurred in ; reading INT0. If an INT1 error occurs, disable INT0 and INT1 ; interrupts, return the errors, and signal the device. ; If a VME device vector was read from INT0, mask off the unused ; bits and range check it. If it is from 0x40 to 0xff, ; then use it as an index into the ISR dispatch table. Check the ; address associated with the vector to make sure that an ISR ; exists for the vector. If the ISR exists, call the dispatch code. ; If the vector is out of range, or if no ISR exists, set the error, ; signal the pVBA error device, disable interrupts and return. ; ; 6) After the sub ISR code returns to the main ISR, decrement the ISR loop ; count. If the count is > 0, go back to step 1. Otherwise, ; return a count overflow error on the pVBA error device, disable ; pVBA INT0 interrupts, signal the device and exit. ; ; ; Stack on entry: ; 4(ap) Address of base pQBA registers ; 8(ap) Address of interrupt region ; ; ; Register Usage: ; ; R0 - Value read from pQBA or pVBA INT0/INT1, scratch ; R1 - Value read from pQBA or pVBA INT1 register ; R2 - Pointer to base of pQBA or pVBA registers ; R3 - Pointer to base of interrupt region ; R4 - Interrupt counter to detect stuck interrupt requests ; ; pQBA offsets INT0 = ^x10 ;Offset for INT0 register INT1 = ^x14 ;Offset for INT1 register QEAR = ^xc ;Offset for Q-Bus error address reg DMAEAR = ^x8 ;Offset for DMA error address reg RSTREG = ^x18 ;Offset for Reset Register QINT1_MSK = ^xD800FFFF ;Mask of valid bits in pQBA INT1 VINT1_MSK = ^x800000FF ;Mask of valid bits in pVBA INT1 ; Interrupt region offsets INT0_ERROR = 0 ; INT0 Error bits INT1_ERROR = 4 ; INT1 Error bits BOGUS_CNT = 8 ; Count of bogus interrupts INT0_VAL = 12 ; Last value read from INT0 INT1_VAL = 16 ; Last value read from INT1 QEAR_VAL = 20 ; Value read from QB Error Addr Reg DMAEAR_VAL = 24 ; Value read from DMA Error Addr Reg OVERFLOW_CNT = 28 ; Maximum number of times to loop in ISR. PVBA = 32 ; Pointer to base of pVBA DEVCNT = ^xfc ; Number of remapped devices DISPATCH = ^x100 ; Base of jump table ; Interrupt 0 Error codes PQBA_UNEXP_VECTOR = 1 ; Interrupt from unmapped device PQBA_BAD_VECTOR = 2 ; Vector out of range PQBA_INT_OVERFLOW = 4 ; Interrupt not getting cleared PQBA_VEC_ERR = 8 ; INT1 error after reading the vector ; Interrupt 0 Error codes PVBA_UNEXP_VECTOR = 1 ; Interrupt from unmapped device PVBA_BAD_VECTOR = 2 ; Vector out of range PVBA_INT_OVERFLOW = 4 ; Interrupt not getting cleared PVBA_VEC_ERR = 8 ; INT1 error after reading the vector .entry dual_isr,^m ;Note: R0/R1 saved by IDB code movl 8(ap),r3 ;Get interrupt region pointer movl OVERFLOW_CNT(r3),r4 ;Init interrupt loop counter main_isr_loop: movl 4(ap),r2 ;Get pQBA pointer movl INT1(r2),r0 ;Read INT1 pQBA register movl r0,INT1_VAL(r3) ;Save value in interrupt region movl QEAR(r2),QEAR_VAL(r3) ;Get QB error address reg value movl DMAEAR(r2),DMAEAR_VAL(r3) ;Get DMA error address reg value cmpl r0,#^xffffffff ;Check for reset error bneq 1$ movl #1,RSTREG(r2) ;Clear the reset interrupt ;and reset the pQBA movl #^xffffffff,INT1_ERROR(r3) clrq -(sp) ;Put two 0s on the stack calls #2, @#KER$SIGNAL_DEVICE ;Signal the pQBA device ret 1$: bicl3 #^cQINT1_MSK,r0,r0 ;Mask non interrupt bits beql qint0_loop ;if 0 then no INT1 ints clrl INT1(r2) ;Disable INT1 interrupts movl r0,INT1_ERROR(r3) clrq -(sp) ;Put two 0s on the stack calls #2, @#KER$SIGNAL_DEVICE ;Signal the pQBA device ret ; Process Q-Bus interrupts qint0_loop: tstb INT0+2(r2) ;See if INT0 interrupt are enabled blss l1 brw do_pvba ;Skip pQBA INT0 processing if ints not enabled l1: movl INT0(r2),r0 ;Get value from Q-Bus interrupt register movl r0,INT0_VAL(r3) ;Save value in interrupt region movl INT1(r2),r1 ;See if error on interrupt read movl r1,INT1_VAL(r3) ;Save value in interrupt region bicl3 #^cQINT1_MSK,r1,r1 ;Mask non interrupt bits beql 0$ ;if 0 then no INT1 ints movl QEAR(r2),QEAR_VAL(r3) ;Get error address reg value movl r1,INT1_ERROR(r3) movl #PQBA_VEC_ERR,INT0_ERROR(r3) ;Set error code clrl INT0(r2) ;Disable INT0 interrupts clrl INT1(r2) ;Disable INT1 interrupts clrq -(sp) ;Put two 0s on the stack calls #2, @#KER$SIGNAL_DEVICE ;Signal the pQBA device ret 0$: tstl r0 ;See if interrupt valid bit set blss 1$ brw do_pvba 1$: bicl #^c^x1FF,r0 ;Maks off unused bits cmpl r0,#^x100 ;Check the range ... blss 2$ cmpl r0,#^x3fc bleq 3$ ; ; This code is executed if there is a vector which is out of range ; 2$: movl #PQBA_BAD_VECTOR,INT0_ERROR(r3) ;Set error code clrl INT0(r2) ;Disable INT0 interrupts clrq -(sp) ;Put two 0s on the stack calls #2, @#KER$SIGNAL_DEVICE ;Signal the pQBA device ret ; ;Vector has been range checked, so check the call table to make sure that ; it is non zero before using it. ; ; R0 contains the vector 3$: tstb (r3)[r0] ;See if the address is null beql 5$ addl r3,r0 jsb @(r0) ;Call the interrupt dispatcher decl r4 ;Decrement ISR loop count bleq 4$ brw do_pvba ; ; Here if the ISR has looped more than OVERFLOW_CNT times. Likely that there ; is a problem, so interrupts are disabled an an error signalled ; 4$: clrl INT0(r2) ;Disable INT0 interrupts movl #PQBA_INT_OVERFLOW,INT0_ERROR(r3) clrq -(sp) ;Put two 0's on stack calls #2, @#KER$SIGNAL_DEVICE ;Signal the pQBA device ret ; ; This code is executed if there is a vector which is not attached to a device ; 5$: movl #PQBA_UNEXP_VECTOR,INT0_ERROR(r3) ;Set error code clrl INT0(r2) ;Disable INT0 interrupts clrq -(sp) ;Put two 0s on the stack calls #2, @#KER$SIGNAL_DEVICE ;Signal the pQBA device ret ; ; Process the pVBA interrupts ; do_pvba: movl PVBA(r3),r2 ;Get pVBA pointer movl INT1(r2),r0 ;Read INT1 pVBA register movl r0,INT1_VAL(r3) ;Save value in interrupt region cmpl r0,#^xffffffff ;Check for reset error bneq 1$ movl #1,RSTREG(r2) ;Clear the reset interrupt ;and reset the pVBA movl #^xffffffff,INT1_ERROR(r3) movl #1,-(sp) ;Device number 1 for pVBA error clrl -(sp) ;NULL calls #2, @#KER$SIGNAL_DEVICE ;Signal the pVBA device ret 1$: bicl3 #^cVINT1_MSK,r0,r0 ;Mask non interrupt bits blss vdo_int0 ;if D31 set then no INT1 ints bisb #^X80,INT1+2(r2) ;Disable INT1 interrupts movl r0,INT1_ERROR(r3) movl #1,-(sp) ;Device number 1 for pVBA error clrl -(sp) ;NULL calls #2, @#KER$SIGNAL_DEVICE ;Signal the pVBA device ret ; Process VME Bus interrupts vdo_int0: movl #4,r5 ;Load retry count for error on vector read vint0_loop: tstb INT0+2(r2) ;See if INT0 interrupt are enabled bgeq 0$ brw main_isr_loop ;Skip pVBA INT0 processing if ints not enabled 0$: movl INT0(r2),r0 ;Get value from VME interrupt register movl r0,INT0_VAL(r3) ;Save value in interrupt region movl INT1(r2),r1 ;See if error on interrupt read cmpb r1,#^xa bneq 1$ ;branch if not a bus error decl r5 bgeq vint0_loop ;Retry on bus error 1$: movl r1,INT1_VAL(r3) ;Save INT1 value in interrupt region bicl3 #^cVINT1_MSK,r1,r1 ;Mask non interrupt bits blss 2$ ;if D31 set then no INT1 err on vec rd movl r1,INT1_ERROR(r3) movl #PVBA_VEC_ERR,INT0_ERROR(r3) ;Set error code bisb #^x80,INT0+2(r2) ;Disable INT0 interrupts bisb #^x80,INT1+2(r2) ;Disable INT1 interrupts movl #1,-(sp) ;Device number 1 for pVBA error clrl -(sp) ;NULL calls #2, @#KER$SIGNAL_DEVICE ;Signal the pVBA device ret 2$: tstl r0 ;See if VME interrupt valid bit ; is low (active) bgeq 3$ incl BOGUS_CNT(r3) ;No INT0 interrupts ret 3$: bicl #^c^xFF,r0 ;Only 8 bit VME vectors supported bneq 4$ ;branch if nonzero vector decl r5 bgeq vint0_loop ;Retry on Zero Vector 4$: cmpl r0,#^x40 ;Check the range ... blss 5$ cmpl r0,#^xff bleq 6$ ; ; This code is executed if there is a vector which is out of range ; 5$: movl #PVBA_BAD_VECTOR,INT0_ERROR(r3) ;Set error code bisb #^X80,INT0+2(r2) ;Disable INT0 interrupts movl #1,-(sp) ;Device number 1 for pVBA error clrl -(sp) ;NULL calls #2, @#KER$SIGNAL_DEVICE ;Signal the pVBA device ret ; ;Vector has been range checked, so check the call table to make sure that ; it is non zero before using it. ; ; R0 contains the vector 6$: ashl #2,r0,r0 ;Convert vector into longword address tstb (r3)[r0] ;See if the ISR address is null beql 8$ addl r3,r0 ;calc pointer to dispatch code jsb @(r0) ;Call the interrupt dispatcher decl r4 ;Decrement ISR loop count bleq 7$ brw main_isr_loop ; ; Here if the ISR has looped more than OVERFLOW_CNT times. Likely that there ; is a problem, so interrupts are disabled an an error signalled ; 7$: bisb #^X80,INT0+2(r2) ;Disable INT0 interrupts movl #PVBA_INT_OVERFLOW,INT0_ERROR(r3) movl #1,-(sp) ;Device number 1 for pVBA error clrl -(sp) ;NULL calls #2, @#KER$SIGNAL_DEVICE ;Signal the pVBA device ret ; ; This code is executed if there is a vector which is not attatched to a device ; 8$: movl #PVBA_UNEXP_VECTOR,INT0_ERROR(r3) ;Set error code bisb #^X80,INT0+2(r2) ;Disable INT0 interrupts movl #1,-(sp) ;Device number 1 for pVBA error clrl -(sp) ;NULL calls #2, @#KER$SIGNAL_DEVICE ;Signal the pVBA device ret .end