[comp.sys.m88k] Request help with interrupt/exception handling

fsset@bach.lerc.nasa.gov (Scott E. Townsend) (11/22/90)

[ I'm not expecting miracles, but I'll take 'em if I get 'em]

I've been having problems off and on with exceptions/interrupt handling.
I've got some code (included below) which works in many situations but is
not fully correct, and I would appreciate any pointers anyone could provide.
I've read the 88100 manual a couple of times, but things still aren't quite
sinking in.

The system is a hypercube-style machine with multiple CPUs sahring VME bus
memory in each node.  We don't do virtual memory (yet), but we do use the
CMMUs for mapping memory as cached/non-cached.

My current problem is an error exception.  I suspect that I'm getting a
floating imprecise exception while trying to drain the FPU to handle an
interrupt, here's the home-grown register dump I get:


Cube Client> arc2d
Cube Client> load 0 0 arc2d
             copying 'arc2d-0.bin' to remote host
             copying 'arc2d.sym' to remote host
             loading cube node 0, processor 0 from 'arc2d'...
Cube Client> 
Cube Client> assign 0 0 stdin  small.in
Cube Client> assign 0 0 stdout small.out
Cube Client> 
Cube Client> start 0 0

Halt advisory from 0.0, Error exception (9)

      R00 = 00000000   R01 = 800003F3   R02 = 72800000   R03 = 08800000 
      R04 = 1E800000   R05 = 7D800000   R06 = 347FFFFE   R07 = BE2AAAAB 
      R08 = 3E124925   R09 = 13800000   R10 = 67800000   R11 = 00000001 
      R12 = 00000000   R13 = 3E4CCCCD   R14 = 3F36DB6F   R15 = 40200001 
      R16 = 001066E8   R17 = 41800002   R18 = 0000000B   R19 = 80000000 
      R20 = 3F800000   R21 = 00000019   R22 = 00000000   R23 = 3F4CCCCC 
      R24 = 00106684   R25 = 40200001   R26 = 00000000   R27 = 00000000 
      R28 = 00000000   R29 = 00000000   R30 = 00000000   R31 = 007D3AF0 

      PID = 00000011   PSR = 800003FB  EPSR = 800003F0  SSBR = 00000404 
     SXIP = 000AB5AE  SNIP = 000AB5B2  SFIP = 000AB5B6   VBR = 00000000 
     DMT0 = 00000000  DMD0 = 0008087C  DMA0 = 007D3B1C  DMT1 = 00000000 
     DMD1 = 0008087C  DMA1 = 007D3B1C  DMT2 = 00000000  DMD2 = 7D800000 
     DMA2 = 007D3B1C   SR0 = 00000000   SR1 = 800003F3   SR2 = 00000000 
      SR3 = 00003008 FPECR = 00000004 FPHS1 = 00000000 FPLS1 = 00000000 
    FPHS2 = 000FA75E FPLS2 = 00000000  FPPT = 0000D9E0  FPRH = 00100000 
     FPRL = 00000000  FPIT = F4F0000A  FPSR = 00000001  FPCR = 00000000 

At '_logf' + 6C (000AB5AC)

000AB5AC: 85490009              fmul.sss    r10,r9,r9


             elapsed time:  0 00:00:04


(This example is running on a single node and processor)

Now here's my interrupt handler:

;
;  Interrupt exception.
;
	global	_interrupt
_interrupt:
	subu	sp,sp,72

	st	r1,sp,16

	ldcr	r1,SFIP		; save exception regs
	st	r1,sp,8
	ldcr	r1,SNIP
	st	r1,sp,4
	ldcr	r1,EPSR
	st	r1,sp,0

	ldcr	r1,PSR		; prepare to re-enable exceptions
	and	r1,r1,0XFFF7	; but leave interrupts disabled
	stcr	r1,EPSR

	or.u	r1,r0,hi16(fpu_snip+2)
	or	r1,r1,lo16(fpu_snip+2)
	stcr	r1,SNIP

	or.u	r1,r0,hi16(fpu_sfip+2)
	or	r1,r1,lo16(fpu_sfip+2)
	stcr	r1,SFIP

	ld	r1,sp,16
	rte			; flush pending FPU operations
fpu_snip:
	tb1	0,r0,511
fpu_sfip:
	st	r1,sp,16

	ldcr	r1,PSR
	and	r1,r1,0XFFFE
	tb1	0,r0,511
	stcr	r0,SSBR
	tb1	0,r0,511
	stcr	r1,PSR		; re-enable shadowing

	st.d	r12,sp,64	; save compiler scratch regs
	st.d	r10,sp,56
	st.d	r8,sp,48
	st.d	r6,sp,40
	st.d	r4,sp,32
	st.d	r2,sp,24

	or.u	r1,r0,hi16(MVME181_SSR) ; fetch interrupt status
	ld	r1,r1,lo16(MVME181_SSR)

	bb1	VMEINT7,r1,abort ; unsupported interrupts
	bb1	VMEINT6,r1,abort
	bb1	VMEINT5,r1,abort
	bb1	VMEINT4,r1,abort
	bb1	VMEINT3,r1,abort
	bb1	PARINT,r1,abort
	bb1	ACFAIL,r1,abort
	bb1	SYSFAIL,r1,abort

vmeint2:
	bb0	VMEINT2,r1,vmeint1

	or.u	r1,r0,hi16(MVME181_VMEACK2) ; fetch interrupt vector
	or	r1,r1,lo16(MVME181_VMEACK2)
	ld.h	r2,r1,0		; halfword to get lower byte
	mask	r2,r2,0X00FF	; only lower byte is significant
	bsr	_pr_int_handler

	or.u	r1,r0,hi16(MVME181_SSR) ; re-fetch interrupt status
	ld	r1,r1,lo16(MVME181_SSR)

vmeint1:
	bb0	VMEINT1,r1,asio

	or.u	r1,r0,hi16(MVME181_VMEACK1) ; fetch interrupt vector
	or	r1,r1,lo16(MVME181_VMEACK1)
	ld.h	r2,r1,0		; halfword to get lower byte
	mask	r2,r2,0X00FF	; only lower byte is significant
	bsr	_pt_int_handler

	or.u	r1,r0,hi16(MVME181_SSR) ; re-fetch interrupt status
	ld	r1,r1,lo16(MVME181_SSR)

asio:
	bb0	ASIOINT,r1,abort

	bsr	_timer_handler

	or.u	r1,r0,hi16(MVME181_SSR) ; re-fetch interrupt status
	ld	r1,r1,lo16(MVME181_SSR)

abort:
	bb0	ABORTINT,r1,exit

	ldcr	r10,SXIP	; for determining where we were
	ld	r11,sp,16	; (saved r1)
	or	r12,r1,r0	; (interrupt condition)
	addu	sp,sp,72	; restore & jump to debugger
	xcr	sp,sp,SR3	; (taken from debugger vector)
	or.u	r1,r0,hi16(DBUG_INT)
	or	r1,r1,lo16(DBUG_INT)
	jmp	r1

exit:
	tb0	0,r0,204	; disable exceptions

	or.u	r1,r0,hi16(_sched_event) ; test for scheduler event
	ld.b	r10,r1,lo16(_sched_event)
	bcnd	ne0,r10,goto_sched

resume:
	ld.d	r2,sp,24	; restore scratch regs
	ld.d	r4,sp,32
	ld.d	r6,sp,40
	ld.d	r8,sp,48
	ld.d	r10,sp,56
	ld.d	r12,sp,64

	ld	r1,sp,0		; restore exception regs
	stcr	r1,EPSR
	ld	r1,sp,4
	stcr	r1,SNIP
	ld	r1,sp,8
	stcr	r1,SFIP

	ld	r1,sp,16
	addu	sp,sp,72

	tb1	0,r0,511	; clear scoreboard
	stcr	r0,SSBR
	rte
;
;  A scheduler event has occured, so we return to it rather than where we
;  were at the time of the interrupt.
;
goto_sched:
	ld.d	r2,sp,24	; restore scratch regs
	ld.d	r4,sp,32
	ld.d	r6,sp,40
	ld.d	r8,sp,48
	ld.d	r10,sp,56
	ld.d	r12,sp,64

	ld	r1,sp,0		; restore exception regs
	stcr	r1,EPSR
	ld	r1,sp,4
	stcr	r1,SNIP
	ld	r1,sp,8
	stcr	r1,SFIP

	stcr	r0,SSBR
	or.u	r1,r0,hi16(_branch_to_loop+2)
	or	r1,r1,lo16(_branch_to_loop+2)
	stcr	r1,SNIP

	or.u	r1,r0,hi16(_branch_to_loop+6)
	or	r1,r1,lo16(_branch_to_loop+6)
	stcr	r1,SFIP

	ld	r1,sp,16
	addu	sp,sp,72

	tb1	0,r0,511	; clear scoreboard
	stcr	r0,SSBR
	rte
;
;  Freeze shadowing.
;	
	global	_trap_204
_trap_204:
	ldcr	r10,EPSR
	or	r10,r10,1
	stcr	r10,EPSR
	rte


So if anyone out there would be kind enough to look at this, I'd really
appreciate it.  If you could send example code, that would be even better!

Thanks for any help you can provide.

--
------------------------------------------------------------------------
Scott Townsend               |   Phone: 216-433-8101
NASA Lewis Research Center   |   Mail Stop: 5-11
Cleveland, Ohio  44135       |   Email: fsset@bach.lerc.nasa.gov
------------------------------------------------------------------------

andrew@frip.WV.TEK.COM (Andrew Klossner) (11/26/90)

|	ldcr	r1,PSR		; prepare to re-enable exceptions
|	and	r1,r1,0XFFF7	; but leave interrupts disabled
|	stcr	r1,EPSR
|
|	or.u	r1,r0,hi16(fpu_snip+2)
|	or	r1,r1,lo16(fpu_snip+2)
|	stcr	r1,SNIP
|
|	or.u	r1,r0,hi16(fpu_sfip+2)
|	or	r1,r1,lo16(fpu_sfip+2)
|	stcr	r1,SFIP
|
|	ld	r1,sp,16
|	rte			; flush pending FPU operations

The RTE instruction will enable the FPU but shadows will still be
frozen, so any FPU exceptions will take the ERROR exception vector.

You could put a fast bypass around this code by checking to see if SSBR
is zero.  If so, no scoreboard registers were set, and so there can't
be any pending FPU exceptions.  (This assumes up-to-date silicon.)

By the way, there's no code here to clean up the data pipeline.  You
have to do that on every interrupt exception.

  -=- Andrew Klossner   (uunet!tektronix!frip.WV.TEK!andrew)    [UUCP]
                        (andrew%frip.wv.tek.com@relay.cs.net)   [ARPA]