source: rtems/c/src/lib/libbsp/mips/shared/irq/exception.S @ c499856

4.11
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on Mar 20, 2014 at 9:10:47 PM

Change all references of rtems.com to rtems.org.

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