source: rtems/bsps/mips/shared/irq/exception.S @ 8f8ccee

5
Last change on this file since 8f8ccee was 8f8ccee, checked in by Sebastian Huber <sebastian.huber@…>, on 04/23/18 at 07:50:39

bsps: Move interrupt controller support to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 15.2 KB
Line 
1/*
2 *  This file contains a customized MIPS exception handler.
3 *  It hooks into the exception handler present in the resident
4 *  PMON debug monitor.
5 */
6
7/*
8 *  Author: Bruce Robinson
9 *
10 *  This code was derived from cpu_asm.S with the following copyright:
11 *
12 *  COPYRIGHT (c) 1996 by Transition Networks Inc.
13 *
14 *  To anyone who acknowledges that this file is provided "AS IS"
15 *  without any express or implied warranty:
16 *      permission to use, copy, modify, and distribute this file
17 *      for any purpose is hereby granted without fee, provided that
18 *      the above copyright notice and this notice appears in all
19 *      copies, and that the name of Transition Networks not be used in
20 *      advertising or publicity pertaining to distribution of the
21 *      software without specific, written prior permission.
22 *      Transition Networks makes no representations about the suitability
23 *      of this software for any purpose.
24 *
25 *  Derived from c/src/exec/score/cpu/no_cpu/cpu_asm.s:
26 *
27 *  COPYRIGHT (c) 1989-2010.
28 *  On-Line Applications Research Corporation (OAR).
29 *
30 *  The license and distribution terms for this file may be
31 *  found in the file LICENSE in this distribution or at
32 *  http://www.rtems.org/license/LICENSE.
33 */
34
35#include <bspopts.h>
36#include <rtems/asm.h>
37#include <rtems/score/percpu.h>
38#include <rtems/mips/iregdef.h>
39#include <rtems/mips/idtcpu.h>
40#if BSP_HAS_USC320
41  #include <usc.h>
42#endif
43
44#if __mips == 3
45/* 64 bit register operations */
46#define NOP     nop
47#define ADD     dadd
48#define STREG   sd
49#define LDREG   ld
50#define ADDU    addu
51#define ADDIU   addiu
52#define STREGC1 sdc1
53#define LDREGC1 ldc1
54#define R_SZ    8
55#define F_SZ    8
56#define SZ_INT  8
57#define SZ_INT_POW2 3
58
59/* XXX if we don't always want 64 bit register ops, then another ifdef */
60
61#elif __mips == 1
62/* 32 bit register operations*/
63#define NOP     nop
64#define ADD     add
65#define STREG   sw
66#define LDREG   lw
67#define ADDU    add
68#define ADDIU   addi
69#define STREGC1 swc1
70#define LDREGC1 lwc1
71#define R_SZ    4
72#define F_SZ    4
73#define SZ_INT  4
74#define SZ_INT_POW2 2
75#else
76#error "mips assembly: what size registers do I deal with?"
77#endif
78
79
80#define ISR_VEC_SIZE    4
81#define EXCP_STACK_SIZE (NREGS*R_SZ)
82
83.extern _Thread_Dispatch
84
85/*  void __ISR_Handler()
86 *
87 *  This routine provides the RTEMS interrupt management.
88 *
89 */
90
91#if 0
92void _ISR_Handler()
93{
94   /*
95    *  This discussion ignores a lot of the ugly details in a real
96    *  implementation such as saving enough registers/state to be
97    *  able to do something real.  Keep in mind that the goal is
98    *  to invoke a user's ISR handler which is written in C and
99    *  uses a certain set of registers.
100    *
101    *  Also note that the exact order is to a large extent flexible.
102    *  Hardware will dictate a sequence for a certain subset of
103    *  _ISR_Handler while requirements for setting
104    */
105
106  /*
107   *  At entry to "common" _ISR_Handler, the vector number must be
108   *  available.  On some CPUs the hardware puts either the vector
109   *  number or the offset into the vector table for this ISR in a
110   *  known place.  If the hardware does not give us this information,
111   *  then the assembly portion of RTEMS for this port will contain
112   *  a set of distinct interrupt entry points which somehow place
113   *  the vector number in a known place (which is safe if another
114   *  interrupt nests this one) and branches to _ISR_Handler.
115   *
116   */
117#endif
118FRAME(bsp_ISR_Handler,sp,0,ra)
119        .set noreorder
120
121#if 0
122/* Activate TX49xx PIO19 signal for diagnostics */
123        lui     k0,0xff1f
124        ori     k0,k0,0xf500
125        lw      k0,(k0)
126        lui     k1,0x8
127        or      k1,k1,k0
128        lui     k0,0xff1f
129        ori     k0,k0,0xf500
130        sw      k1,(k0)
131#endif
132        mfc0 k0,C0_CAUSE        /* Determine if an interrupt generated this exception */
133        nop
134        and k1,k0,CAUSE_EXCMASK
135        beq k1,zero,_chk_int    /* If so, branch to service here */
136        nop
137        la  k0,_int_esr_link    /* Otherwise, jump to next exception handler in PMON exception chain */
138        lw  k0,(k0)
139        lw  k0,4(k0)
140        j   k0
141        nop
142_chk_int:
143        mfc0 k1,C0_SR
144        nop
145        and k0,k1
146#if HAS_RM52xx
147        and k0,CAUSE_IPMASK
148#elif HAS_TX49xx
149        and k0,(SR_IBIT1 | SR_IBIT2 | SR_IBIT3)
150#endif
151        /* external interrupt not enabled, ignore */
152        beq k0,zero,_ISR_Handler_quick_exit
153        nop
154
155/* For debugging interrupts, clear EXL to allow breakpoints */
156#if 0
157        MFC0    k0, C0_SR
158#if __mips == 3
159        li      k1,SR_EXL       /* Clear EXL and Set IE to enable interrupts */
160        not     k1
161        and     k0,k1
162        li      k1,SR_IE
163#elif __mips == 1
164        li      k1,SR_IEC
165#endif
166        or      k0, k1
167        mtc0    k0, C0_SR
168        NOP
169#endif
170
171
172  /*
173   *  save some or all context on stack
174   *  may need to save some special interrupt information for exit
175   */
176
177        /* Q: _ISR_Handler, not using IDT/SIM ...save extra regs? */
178
179        /* wastes a lot of stack space for context?? */
180        ADDIU    sp,sp,-EXCP_STACK_SIZE
181
182        STREG ra, R_RA*R_SZ(sp)  /* store ra on the stack */
183        STREG v0, R_V0*R_SZ(sp)
184        STREG v1, R_V1*R_SZ(sp)
185        STREG a0, R_A0*R_SZ(sp)
186        STREG a1, R_A1*R_SZ(sp)
187        STREG a2, R_A2*R_SZ(sp)
188        STREG a3, R_A3*R_SZ(sp)
189        STREG t0, R_T0*R_SZ(sp)
190        STREG t1, R_T1*R_SZ(sp)
191        STREG t2, R_T2*R_SZ(sp)
192        STREG t3, R_T3*R_SZ(sp)
193        STREG t4, R_T4*R_SZ(sp)
194        STREG t5, R_T5*R_SZ(sp)
195        STREG t6, R_T6*R_SZ(sp)
196        STREG t7, R_T7*R_SZ(sp)
197        mflo  t0
198        STREG t8, R_T8*R_SZ(sp)
199        STREG t0, R_MDLO*R_SZ(sp)
200        STREG t9, R_T9*R_SZ(sp)
201        mfhi  t0
202        STREG gp, R_GP*R_SZ(sp)
203        STREG t0, R_MDHI*R_SZ(sp)
204        STREG fp, R_FP*R_SZ(sp)
205
206        .set noat
207        STREG AT, R_AT*R_SZ(sp)
208        .set at
209
210        mfc0     t0,C0_SR
211        dmfc0    t1,C0_EPC
212        STREG    t0,R_SR*R_SZ(sp)
213        STREG    t1,R_EPC*R_SZ(sp)
214
215  /*
216   *
217   *  #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
218   *    if ( _ISR_Nest_level == 0 )
219   *      switch to software interrupt stack
220   *  #endif
221   */
222
223  /*
224   *  _ISR_Nest_level++;
225   */
226        lw      t0,ISR_NEST_LEVEL
227        NOP
228        add     t0,t0,1
229        sw      t0,ISR_NEST_LEVEL
230  /*
231   *  _Thread_Dispatch_disable_level++;
232   */
233        lw      t1,THREAD_DISPATCH_DISABLE_LEVEL
234        NOP
235        add     t1,t1,1
236        sw      t1,THREAD_DISPATCH_DISABLE_LEVEL
237
238        /* DEBUG - Add the following code to disable interrupts and clear
239         *         EXL in status register, this will allow memory
240         *         exceptions to occur while servicing the current interrupt
241         */
242#if 0
243        /* Disable interrupts from internal interrupt controller */
244        li t0,~CAUSE_IP2_MASK
245        mfc0 t1,C0_SR
246        nop
247        and t1,t0
248        mtc0 t1,C0_SR
249        nop
250        /* Clear EXL in status register to allow memory exceptions to occur */
251        li t0,~SR_EXL
252        mfc0 t1,C0_SR
253        nop
254        and t1,t0
255        mtc0 t1,C0_SR
256        nop
257#endif
258
259  /*
260   *  Call the CPU model or BSP specific routine to decode the
261   *  interrupt source and actually vector to device ISR handlers.
262   */
263        move     a0,sp
264        jal      mips_vector_isr_handlers
265        NOP
266
267        /* Add the following code to disable interrupts (see DEBUG above) */
268#if 0
269        li t0,SR_EXL            /* Set EXL to hold off interrupts */
270        mfc0 t1,C0_SR
271        nop
272        or t1,t0
273        mtc0 t1,C0_SR
274        nop
275        /* Enable interrupts from internal interrupt controller */
276        li t0,CAUSE_IP2_MASK
277        mfc0 t1,C0_SR
278        nop
279        or t1,t0
280        mtc0 t1,C0_SR
281        nop
282#endif
283
284_ISR_Handler_cleanup:
285
286  /*
287   *  --_ISR_Nest_level;
288   */
289        lw      t2,ISR_NEST_LEVEL
290        NOP
291        add     t2,t2,-1
292        sw      t2,ISR_NEST_LEVEL
293  /*
294   *  --_Thread_Dispatch_disable_level;
295   */
296        lw      t1,THREAD_DISPATCH_DISABLE_LEVEL
297        NOP
298        add     t1,t1,-1
299        sw      t1,THREAD_DISPATCH_DISABLE_LEVEL
300  /*
301   *  if ( _Thread_Dispatch_disable_level || _ISR_Nest_level )
302   *    goto the label "exit interrupt (simple case)"
303   */
304        or  t0,t2,t1
305        bne t0,zero,_ISR_Handler_exit
306        NOP
307
308
309  /*
310   *  #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
311   *    restore stack
312   *  #endif
313   *
314   *  if ( !_Thread_Dispatch_necessary )
315   *    goto the label "exit interrupt (simple case)"
316   */
317        lb      t0,DISPATCH_NEEDED
318        NOP
319        or      t0,t0,t0
320        beq     t0,zero,_ISR_Handler_exit
321        NOP
322
323/*
324** Turn on interrupts before entering Thread_Dispatch which
325** will run for a while, thus allowing new interrupts to
326** be serviced.  Observe the Thread_Dispatch_disable_level interlock
327** that prevents recursive entry into Thread_Dispatch.
328*/
329
330        mfc0    t0, C0_SR
331#if __mips == 3
332        li      t1,SR_EXL       /* Clear EXL and Set IE to enable interrupts */
333        not     t1
334        and     t0,t1
335        li      t1,SR_IE
336#elif __mips == 1
337        li      t1,SR_IEC
338#endif
339        or      t0, t1
340        mtc0    t0, C0_SR
341        NOP
342
343        /* save off our stack frame so the context switcher can get to it */
344        la      t0,__exceptionStackFrame
345        STREG   sp,(t0)
346
347        jal     _Thread_Dispatch
348        NOP
349
350        /* and make sure its clear in case we didn't dispatch.  if we did, its
351        ** already cleared */
352        la      t0,__exceptionStackFrame
353        STREG   zero,(t0)
354        NOP
355
356/*
357** turn interrupts back off while we restore context so
358** a badly timed interrupt won't accidentally mess things up
359*/
360        mfc0    t0, C0_SR
361#if __mips == 3
362        li      t1,SR_IE                /* Clear IE first (recommended) */
363        not     t1
364        and     t0,t1
365        mtc0    t0, C0_SR
366        li      t1,SR_EXL | SR_IE       /* Set EXL and IE, this puts status register bits back to interrupted state */
367        or      t0,t1
368#elif __mips == 1
369        /* ints off, current & prev kernel mode on (kernel mode enabled is bit clear..argh!) */
370        li      t1,SR_IEC | SR_KUP | SR_KUC
371        not     t1
372        and     t0, t1
373#endif
374        mtc0    t0, C0_SR
375        NOP
376
377  /*
378   *  prepare to get out of interrupt
379   *  return from interrupt  (maybe to _ISR_Dispatch)
380   *
381   *  LABEL "exit interrupt (simple case):"
382   *  prepare to get out of interrupt
383   *  return from interrupt
384   */
385
386_ISR_Handler_exit:
387
388/* restore interrupt context from stack */
389        LDREG t8, R_MDLO*R_SZ(sp)
390        LDREG t0, R_T0*R_SZ(sp)
391        mtlo  t8
392        LDREG t8, R_MDHI*R_SZ(sp)
393        LDREG t1, R_T1*R_SZ(sp)
394        mthi  t8
395        LDREG t2, R_T2*R_SZ(sp)
396        LDREG t3, R_T3*R_SZ(sp)
397        LDREG t4, R_T4*R_SZ(sp)
398        LDREG t5, R_T5*R_SZ(sp)
399        LDREG t6, R_T6*R_SZ(sp)
400        LDREG t7, R_T7*R_SZ(sp)
401        LDREG t8, R_T8*R_SZ(sp)
402        LDREG t9, R_T9*R_SZ(sp)
403        LDREG gp, R_GP*R_SZ(sp)
404        LDREG fp, R_FP*R_SZ(sp)
405        LDREG ra, R_RA*R_SZ(sp)
406        LDREG a0, R_A0*R_SZ(sp)
407        LDREG a1, R_A1*R_SZ(sp)
408        LDREG a2, R_A2*R_SZ(sp)
409        LDREG a3, R_A3*R_SZ(sp)
410        LDREG v1, R_V1*R_SZ(sp)
411        LDREG v0, R_V0*R_SZ(sp)
412
413        LDREG k1, R_EPC*R_SZ(sp)
414        mtc0  k1,C0_EPC
415
416        .set noat
417        LDREG     AT, R_AT*R_SZ(sp)
418        .set at
419
420        ADDIU     sp,sp,EXCP_STACK_SIZE
421
422_ISR_Handler_quick_exit:
423        eret
424        nop
425
426
427#if BSP_HAS_USC320
428        /* Interrupts from USC320 are serviced here */
429        .global USC_isr
430        .extern Clock_isr
431USC_isr:
432        /* check if it's a USC320 heartbeat interrupt */
433        la      k0,INT_STAT     /* read INT_STAT register */
434        lw      k0,(k0)
435        nop                     /* reading from external device */
436        sll     k0,(31-21)      /* test bit 21 (HBI) */
437
438        bgez    k0,USC_isr2     /* branch if not a heartbeat interrupt */
439        NOP
440
441        /* clear the heartbeat interrupt */
442        la      k0,INT_STAT
443        li      t0,HBI_MASK
444        sw      t0,(k0)
445        /* wait for interrupt to clear */
446USC_isr1:
447        la      k0,INT_STAT     /* read INT_STAT register */
448        lw      k0,(k0)
449        nop                     /* reading from external device */
450        sll     k0,(31-21)      /* test bit 21 (HBI) */
451        bltz    k0,USC_isr1     /* branch if bit set */
452        nop
453        j       Clock_isr       /* Jump to clock isr */
454        nop
455USC_isr2:
456        j       ra              /* no serviceable interrupt, return without doing anything */
457        nop
458#endif
459
460#if 0
461        .global int7_isr
462        .extern Interrupt_7_isr
463int7_isr:
464        /* Verify interrupt is from Timer */
465        la      k0,IRCS         /* read Interrupt Current Status register */
466        lw      k0,(k0)
467        nop                     /* reading from external device */
468        li      k1,IRCS_CAUSE_MASK
469        and     k0,k0,k1        /* isolate interrupt cause  */
470
471        li      k1,INT7INT      /* test for interrupt 7 */
472        subu    k1,k0,k1
473        beq     k1,zero,int7_isr1
474        nop
475        j       ra              /* interrupt 7 no longer valid, return without doing anything */
476        nop
477int7_isr1:
478        j       Interrupt_7_isr /* Jump to Interrupt 7 isr */
479        nop
480#endif
481
482       .set    reorder
483
484ENDFRAME(bsp_ISR_Handler)
485
486
487FRAME(_BRK_Handler,sp,0,ra)
488        .set noreorder
489
490#if BSP_HAS_USC320
491        la      k0,INT_CFG3     /* Disable heartbeat interrupt in USC320, it interferes with PMON exception handler */
492        lw      k1,(k0)
493        li      k0,~HBI_MASK
494        and     k1,k1,k0
495        la      k0,INT_CFG3
496        sw      k1,(k0)
497#endif
498
499        la  k0,_brk_esr_link    /* Jump to next exception handler in PMON exception chain */
500        lw  k0,(k0)
501        lw  k0,4(k0)
502        j   k0
503        nop
504
505        .set reorder
506ENDFRAME(_BRK_Handler)
507
508
509/**************************************************************************
510**
511**      init_exc_vecs() - moves the exception code into the addresses
512**                        reserved for exception vectors
513**
514**      UTLB Miss exception vector at address 0x80000000
515**
516**      General exception vector at address 0x80000080
517**
518**      RESET exception vector is at address 0xbfc00000
519**
520***************************************************************************/
521
522FRAME(init_exc_vecs,sp,0,ra)
523        .set noreorder
524
525        .extern mon_onintr
526
527/* Install interrupt handler in PMON exception handling chain */
528
529        addiu   sp,sp,-8
530        sw      ra,(sp)                 /* Save ra contents on stack */
531        move    a0,zero
532        la      a1,_int_esr_link
533        jal     mon_onintr              /* Make PMON system call to install interrupt exception handler */
534        nop
535        li      a0,9
536        la      a1,_brk_esr_link
537        jal     mon_onintr              /* Make PMON system call to install break exception handler */
538        nop
539        lw      ra,(sp)
540        addiu   sp,sp,8                 /* Restore ra contents from stack */
541        j       ra
542        nop
543
544        .set reorder
545ENDFRAME(init_exc_vecs)
546
547
548#if 0           /* Unused code below */
549
550/*************************************************************
551*  enable_int7(ints)
552*       Enable interrupt 7
553*/
554FRAME(enable_int7,sp,0,ra)
555        .set noreorder
556
557        la      t0,IRDM1        # Set interrupt controller detection mode (bits 2-3 = 0 for int 7 active low)
558        li      t1,0x0
559        sw      t1,(t0)
560
561        la      t0,IRLVL4       # Set interrupt controller level (bit 8-10 = 2 for int 7 at level 2)
562        li      t1,0x200
563        sw      t1,(t0)
564
565        la      t0,IRMSK        # Set interrupt controller mask
566        li      t1,0x0
567        sw      t1,(t0)
568
569        la      t0,IRDEN        # Enable interrupts from controller
570        li      t1,0x1
571        sw      t1,(t0)
572
573        j       ra
574        nop
575        .set reorder
576ENDFRAME(enable_int7)
577
578/*************************************************************
579*  disable_int7(ints)
580*       Disable interrupt 7
581*/
582FRAME(disable_int7,sp,0,ra)
583        .set noreorder
584
585        la      t0,IRLVL4       # Set interrupt controller level (bit 8-10 = 0 to diasble int 7)
586        li      t1,0x200
587        sw      t1,(t0)
588
589        j       ra
590        nop
591        .set reorder
592ENDFRAME(disable_int7)
593#endif
594
595/*************************************************************
596*  exception:
597*       Diagnostic code that can be hooked to PMON interrupt handler.
598*       Generates pulse on PIO22 pin.
599*       Called from _exception code in PMON (see mips.s of PMON).
600*       Return address is located in k1.
601*/
602FRAME(tx49xxexception,sp,0,ra)
603        .set noreorder
604        la      k0,k1tmp
605        sw      k1,(k0)
606
607/* Activate TX49xx PIO22 signal for diagnostics */
608        lui     k0,0xff1f
609        ori     k0,k0,0xf500
610        lw      k0,(k0)
611        lui     k1,0x40
612        or      k1,k1,k0
613        lui     k0,0xff1f
614        ori     k0,k0,0xf500
615        sw      k1,(k0)
616        nop
617
618/* De-activate TX49xx PIO22 signal for diagnostics */
619        lui     k0,0xff1f
620        ori     k0,k0,0xf500
621        lw      k0,(k0)
622        lui     k1,0x40
623        not     k1
624        and     k1,k1,k0
625        lui     k0,0xff1f
626        ori     k0,k0,0xf500
627        sw      k1,(k0)
628        nop
629
630        la      k0,k1tmp
631        lw      k1,(k0)
632        j       k1
633        .set reorder
634ENDFRAME(tx49xxexception)
635
636
637
638
639        .data
640
641k1tmp:  .word   0       /* Temporary strage for K1 during interrupt service */
642
643/*************************************************************
644*
645* Exception handler links, used in PMON exception handler chains
646*/
647        /* Interrupt exception service routine link */
648        .global _int_esr_link
649_int_esr_link:
650        .word   0
651        .word   bsp_ISR_Handler
652
653        /* Break exception service routine link */
654        .global _brk_esr_link
655_brk_esr_link:
656        .word   0
657        .word   _BRK_Handler
658
659
660
661
Note: See TracBrowser for help on using the repository browser.