Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:51

0001 /*
0002  *  This file contains a customized MIPS exception handler.
0003  *  It hooks into the exception handler present in the resident
0004  *  PMON debug monitor.
0005  */
0006 
0007 /*
0008  *  Author: Bruce Robinson
0009  *
0010  *  This code was derived from cpu_asm.S with the following copyright:
0011  *
0012  *  COPYRIGHT (c) 1996 by Transition Networks Inc.
0013  *
0014  *  To anyone who acknowledges that this file is provided "AS IS"
0015  *  without any express or implied warranty:
0016  *      permission to use, copy, modify, and distribute this file
0017  *      for any purpose is hereby granted without fee, provided that
0018  *      the above copyright notice and this notice appears in all
0019  *      copies, and that the name of Transition Networks not be used in
0020  *      advertising or publicity pertaining to distribution of the
0021  *      software without specific, written prior permission.
0022  *      Transition Networks makes no representations about the suitability
0023  *      of this software for any purpose.
0024  *
0025  *  Derived from c/src/exec/score/cpu/no_cpu/cpu_asm.s:
0026  *
0027  *  COPYRIGHT (c) 1989-2010.
0028  *  On-Line Applications Research Corporation (OAR).
0029  *
0030  *  The license and distribution terms for this file may be
0031  *  found in the file LICENSE in this distribution or at
0032  *  http://www.rtems.org/license/LICENSE.
0033  */
0034 
0035 #include <bspopts.h>
0036 #include <rtems/asm.h>
0037 #include <rtems/score/percpu.h>
0038 #include <rtems/mips/iregdef.h>
0039 #include <rtems/mips/idtcpu.h>
0040 #if BSP_HAS_USC320
0041   #include <usc.h>
0042 #endif
0043 
0044 #if __mips == 3
0045 /* 64 bit register operations */
0046 #define NOP nop
0047 #define ADD dadd
0048 #define STREG   sd
0049 #define LDREG   ld
0050 #define ADDU    addu
0051 #define ADDIU   addiu
0052 #define STREGC1 sdc1
0053 #define LDREGC1 ldc1
0054 #define R_SZ    8
0055 #define F_SZ    8
0056 #define SZ_INT  8
0057 #define SZ_INT_POW2 3
0058 
0059 /* XXX if we don't always want 64 bit register ops, then another ifdef */
0060 
0061 #elif __mips == 1
0062 /* 32 bit register operations*/
0063 #define NOP nop
0064 #define ADD add
0065 #define STREG   sw
0066 #define LDREG   lw
0067 #define ADDU    add
0068 #define ADDIU   addi
0069 #define STREGC1 swc1
0070 #define LDREGC1 lwc1
0071 #define R_SZ    4
0072 #define F_SZ    4
0073 #define SZ_INT  4
0074 #define SZ_INT_POW2 2
0075 #else
0076 #error "mips assembly: what size registers do I deal with?"
0077 #endif
0078 
0079 
0080 #define ISR_VEC_SIZE    4
0081 #define EXCP_STACK_SIZE (NREGS*R_SZ)
0082 
0083 .extern _Thread_Dispatch
0084 
0085 /*  void __ISR_Handler()
0086  *
0087  *  This routine provides the RTEMS interrupt management.
0088  *
0089  */
0090 
0091 #if 0
0092 void _ISR_Handler()
0093 {
0094    /*
0095     *  This discussion ignores a lot of the ugly details in a real
0096     *  implementation such as saving enough registers/state to be
0097     *  able to do something real.  Keep in mind that the goal is
0098     *  to invoke a user's ISR handler which is written in C and
0099     *  uses a certain set of registers.
0100     *
0101     *  Also note that the exact order is to a large extent flexible.
0102     *  Hardware will dictate a sequence for a certain subset of
0103     *  _ISR_Handler while requirements for setting
0104     */
0105 
0106   /*
0107    *  At entry to "common" _ISR_Handler, the vector number must be
0108    *  available.  On some CPUs the hardware puts either the vector
0109    *  number or the offset into the vector table for this ISR in a
0110    *  known place.  If the hardware does not give us this information,
0111    *  then the assembly portion of RTEMS for this port will contain
0112    *  a set of distinct interrupt entry points which somehow place
0113    *  the vector number in a known place (which is safe if another
0114    *  interrupt nests this one) and branches to _ISR_Handler.
0115    *
0116    */
0117 #endif
0118 FRAME(bsp_ISR_Handler,sp,0,ra)
0119     .set noreorder
0120 
0121 #if 0
0122 /* Activate TX49xx PIO19 signal for diagnostics */
0123     lui k0,0xff1f
0124     ori k0,k0,0xf500
0125     lw  k0,(k0)
0126     lui k1,0x8
0127     or  k1,k1,k0
0128     lui k0,0xff1f
0129     ori k0,k0,0xf500
0130     sw  k1,(k0)
0131 #endif
0132     mfc0 k0,C0_CAUSE    /* Determine if an interrupt generated this exception */
0133     nop
0134     and k1,k0,CAUSE_EXCMASK
0135     beq k1,zero,_chk_int    /* If so, branch to service here */
0136     nop
0137     la  k0,_int_esr_link    /* Otherwise, jump to next exception handler in PMON exception chain */
0138     lw  k0,(k0)
0139     lw  k0,4(k0)
0140     j   k0
0141     nop
0142 _chk_int:
0143     mfc0 k1,C0_SR
0144     nop
0145     and k0,k1
0146 #if HAS_RM52xx
0147     and k0,CAUSE_IPMASK
0148 #elif HAS_TX49xx
0149     and k0,(SR_IBIT1 | SR_IBIT2 | SR_IBIT3)
0150 #endif
0151     /* external interrupt not enabled, ignore */
0152     beq k0,zero,_ISR_Handler_quick_exit
0153     nop
0154 
0155 /* For debugging interrupts, clear EXL to allow breakpoints */
0156 #if 0
0157         MFC0    k0, C0_SR
0158 #if __mips == 3
0159     li  k1,SR_EXL   /* Clear EXL and Set IE to enable interrupts */
0160     not k1
0161     and k0,k1
0162     li  k1,SR_IE
0163 #elif __mips == 1
0164     li  k1,SR_IEC
0165 #endif
0166     or  k0, k1
0167         mtc0    k0, C0_SR
0168     NOP
0169 #endif
0170 
0171 
0172   /*
0173    *  save some or all context on stack
0174    *  may need to save some special interrupt information for exit
0175    */
0176 
0177         /* Q: _ISR_Handler, not using IDT/SIM ...save extra regs? */
0178 
0179         /* wastes a lot of stack space for context?? */
0180     ADDIU    sp,sp,-EXCP_STACK_SIZE
0181 
0182         STREG ra, R_RA*R_SZ(sp)  /* store ra on the stack */
0183         STREG v0, R_V0*R_SZ(sp)
0184         STREG v1, R_V1*R_SZ(sp)
0185         STREG a0, R_A0*R_SZ(sp)
0186         STREG a1, R_A1*R_SZ(sp)
0187         STREG a2, R_A2*R_SZ(sp)
0188         STREG a3, R_A3*R_SZ(sp)
0189         STREG t0, R_T0*R_SZ(sp)
0190         STREG t1, R_T1*R_SZ(sp)
0191         STREG t2, R_T2*R_SZ(sp)
0192         STREG t3, R_T3*R_SZ(sp)
0193         STREG t4, R_T4*R_SZ(sp)
0194         STREG t5, R_T5*R_SZ(sp)
0195         STREG t6, R_T6*R_SZ(sp)
0196         STREG t7, R_T7*R_SZ(sp)
0197         mflo  t0
0198         STREG t8, R_T8*R_SZ(sp)
0199         STREG t0, R_MDLO*R_SZ(sp)
0200         STREG t9, R_T9*R_SZ(sp)
0201         mfhi  t0
0202         STREG gp, R_GP*R_SZ(sp)
0203         STREG t0, R_MDHI*R_SZ(sp)
0204         STREG fp, R_FP*R_SZ(sp)
0205 
0206         .set noat
0207         STREG AT, R_AT*R_SZ(sp)
0208         .set at
0209 
0210         mfc0     t0,C0_SR
0211     dmfc0    t1,C0_EPC
0212         STREG    t0,R_SR*R_SZ(sp)
0213         STREG    t1,R_EPC*R_SZ(sp)
0214 
0215   /*
0216    *
0217    *  if ( _ISR_Nest_level == 0 )
0218    *    switch to software interrupt stack
0219    */
0220 
0221   /*
0222    *  _ISR_Nest_level++;
0223    */
0224         lw  t0,ISR_NEST_LEVEL
0225     NOP
0226         add t0,t0,1
0227         sw  t0,ISR_NEST_LEVEL
0228   /*
0229    *  _Thread_Dispatch_disable_level++;
0230    */
0231         lw  t1,THREAD_DISPATCH_DISABLE_LEVEL
0232     NOP
0233         add t1,t1,1
0234         sw  t1,THREAD_DISPATCH_DISABLE_LEVEL
0235 
0236     /* DEBUG - Add the following code to disable interrupts and clear
0237      *     EXL in status register, this will allow memory
0238      *         exceptions to occur while servicing the current interrupt
0239      */
0240 #if 0
0241     /* Disable interrupts from internal interrupt controller */
0242     li t0,~CAUSE_IP2_MASK
0243     mfc0 t1,C0_SR
0244     nop
0245     and t1,t0
0246     mtc0 t1,C0_SR
0247     nop
0248     /* Clear EXL in status register to allow memory exceptions to occur */
0249     li t0,~SR_EXL
0250     mfc0 t1,C0_SR
0251     nop
0252     and t1,t0
0253     mtc0 t1,C0_SR
0254     nop
0255 #endif
0256 
0257   /*
0258    *  Call the CPU model or BSP specific routine to decode the
0259    *  interrupt source and actually vector to device ISR handlers.
0260    */
0261     move     a0,sp
0262         jal      mips_vector_isr_handlers
0263         NOP
0264 
0265     /* Add the following code to disable interrupts (see DEBUG above) */
0266 #if 0
0267     li t0,SR_EXL        /* Set EXL to hold off interrupts */
0268     mfc0 t1,C0_SR
0269     nop
0270     or t1,t0
0271     mtc0 t1,C0_SR
0272     nop
0273     /* Enable interrupts from internal interrupt controller */
0274     li t0,CAUSE_IP2_MASK
0275     mfc0 t1,C0_SR
0276     nop
0277     or t1,t0
0278     mtc0 t1,C0_SR
0279     nop
0280 #endif
0281 
0282 _ISR_Handler_cleanup:
0283 
0284   /*
0285    *  --_ISR_Nest_level;
0286    */
0287         lw  t2,ISR_NEST_LEVEL
0288     NOP
0289         add t2,t2,-1
0290         sw  t2,ISR_NEST_LEVEL
0291   /*
0292    *  --_Thread_Dispatch_disable_level;
0293    */
0294         lw  t1,THREAD_DISPATCH_DISABLE_LEVEL
0295     NOP
0296         add t1,t1,-1
0297         sw  t1,THREAD_DISPATCH_DISABLE_LEVEL
0298   /*
0299    *  if ( _Thread_Dispatch_disable_level || _ISR_Nest_level )
0300    *    goto the label "exit interrupt (simple case)"
0301    */
0302         or  t0,t2,t1
0303         bne t0,zero,_ISR_Handler_exit
0304         NOP
0305 
0306 
0307   /*
0308    *  restore stack
0309    *
0310    *  if ( !_Thread_Dispatch_necessary )
0311    *    goto the label "exit interrupt (simple case)"
0312    */
0313         lb  t0,DISPATCH_NEEDED
0314     NOP
0315         or  t0,t0,t0
0316         beq t0,zero,_ISR_Handler_exit
0317         NOP
0318 
0319 /*
0320 ** Turn on interrupts before entering Thread_Dispatch which
0321 ** will run for a while, thus allowing new interrupts to
0322 ** be serviced.  Observe the Thread_Dispatch_disable_level interlock
0323 ** that prevents recursive entry into Thread_Dispatch.
0324 */
0325 
0326         mfc0    t0, C0_SR
0327 #if __mips == 3
0328     li  t1,SR_EXL   /* Clear EXL and Set IE to enable interrupts */
0329     not t1
0330     and t0,t1
0331     li  t1,SR_IE
0332 #elif __mips == 1
0333     li  t1,SR_IEC
0334 #endif
0335     or  t0, t1
0336         mtc0    t0, C0_SR
0337     NOP
0338 
0339     /* save off our stack frame so the context switcher can get to it */
0340     la  t0,__exceptionStackFrame
0341     STREG   sp,(t0)
0342 
0343         jal     _Thread_Dispatch
0344         NOP
0345 
0346     /* and make sure its clear in case we didn't dispatch.  if we did, its
0347     ** already cleared */
0348     la  t0,__exceptionStackFrame
0349     STREG   zero,(t0)
0350     NOP
0351 
0352 /*
0353 ** turn interrupts back off while we restore context so
0354 ** a badly timed interrupt won't accidentally mess things up
0355 */
0356         mfc0    t0, C0_SR
0357 #if __mips == 3
0358     li  t1,SR_IE        /* Clear IE first (recommended) */
0359     not t1
0360     and t0,t1
0361         mtc0    t0, C0_SR
0362     li  t1,SR_EXL | SR_IE   /* Set EXL and IE, this puts status register bits back to interrupted state */
0363     or  t0,t1
0364 #elif __mips == 1
0365     /* ints off, current & prev kernel mode on (kernel mode enabled is bit clear..argh!) */
0366     li  t1,SR_IEC | SR_KUP | SR_KUC
0367     not t1
0368     and t0, t1
0369 #endif
0370     mtc0    t0, C0_SR
0371     NOP
0372 
0373   /*
0374    *  prepare to get out of interrupt
0375    *  return from interrupt
0376    *
0377    *  LABEL "exit interrupt (simple case):"
0378    *  prepare to get out of interrupt
0379    *  return from interrupt
0380    */
0381 
0382 _ISR_Handler_exit:
0383 
0384 /* restore interrupt context from stack */
0385         LDREG t8, R_MDLO*R_SZ(sp)
0386         LDREG t0, R_T0*R_SZ(sp)
0387         mtlo  t8
0388         LDREG t8, R_MDHI*R_SZ(sp)
0389         LDREG t1, R_T1*R_SZ(sp)
0390         mthi  t8
0391         LDREG t2, R_T2*R_SZ(sp)
0392         LDREG t3, R_T3*R_SZ(sp)
0393         LDREG t4, R_T4*R_SZ(sp)
0394         LDREG t5, R_T5*R_SZ(sp)
0395         LDREG t6, R_T6*R_SZ(sp)
0396         LDREG t7, R_T7*R_SZ(sp)
0397         LDREG t8, R_T8*R_SZ(sp)
0398         LDREG t9, R_T9*R_SZ(sp)
0399         LDREG gp, R_GP*R_SZ(sp)
0400         LDREG fp, R_FP*R_SZ(sp)
0401         LDREG ra, R_RA*R_SZ(sp)
0402         LDREG a0, R_A0*R_SZ(sp)
0403         LDREG a1, R_A1*R_SZ(sp)
0404         LDREG a2, R_A2*R_SZ(sp)
0405         LDREG a3, R_A3*R_SZ(sp)
0406         LDREG v1, R_V1*R_SZ(sp)
0407         LDREG v0, R_V0*R_SZ(sp)
0408 
0409         LDREG k1, R_EPC*R_SZ(sp)
0410     mtc0  k1,C0_EPC
0411 
0412     .set noat
0413         LDREG     AT, R_AT*R_SZ(sp)
0414         .set at
0415 
0416         ADDIU     sp,sp,EXCP_STACK_SIZE
0417 
0418 _ISR_Handler_quick_exit:
0419     eret
0420     nop
0421 
0422 
0423 #if BSP_HAS_USC320
0424     /* Interrupts from USC320 are serviced here */
0425     .global USC_isr
0426     .extern Clock_isr
0427 USC_isr:
0428     /* check if it's a USC320 heartbeat interrupt */
0429         la      k0,INT_STAT /* read INT_STAT register */
0430         lw      k0,(k0)
0431         nop         /* reading from external device */
0432         sll     k0,(31-21)  /* test bit 21 (HBI) */
0433 
0434         bgez    k0,USC_isr2 /* branch if not a heartbeat interrupt */
0435     NOP
0436 
0437     /* clear the heartbeat interrupt */
0438     la      k0,INT_STAT
0439     li      t0,HBI_MASK
0440     sw      t0,(k0)
0441     /* wait for interrupt to clear */
0442 USC_isr1:
0443     la      k0,INT_STAT /* read INT_STAT register */
0444     lw      k0,(k0)
0445     nop         /* reading from external device */
0446         sll     k0,(31-21)  /* test bit 21 (HBI) */
0447         bltz    k0,USC_isr1     /* branch if bit set */
0448         nop
0449     j   Clock_isr   /* Jump to clock isr */
0450     nop
0451 USC_isr2:
0452     j   ra      /* no serviceable interrupt, return without doing anything */
0453     nop
0454 #endif
0455 
0456 #if 0
0457     .global int7_isr
0458     .extern Interrupt_7_isr
0459 int7_isr:
0460     /* Verify interrupt is from Timer */
0461         la      k0,IRCS     /* read Interrupt Current Status register */
0462         lw      k0,(k0)
0463         nop         /* reading from external device */
0464     li  k1,IRCS_CAUSE_MASK
0465         and     k0,k0,k1    /* isolate interrupt cause  */
0466 
0467     li  k1,INT7INT  /* test for interrupt 7 */
0468         subu    k1,k0,k1
0469         beq k1,zero,int7_isr1
0470         nop
0471         j   ra      /* interrupt 7 no longer valid, return without doing anything */
0472         nop
0473 int7_isr1:
0474     j   Interrupt_7_isr /* Jump to Interrupt 7 isr */
0475     nop
0476 #endif
0477 
0478        .set    reorder
0479 
0480 ENDFRAME(bsp_ISR_Handler)
0481 
0482 
0483 FRAME(_BRK_Handler,sp,0,ra)
0484     .set noreorder
0485 
0486 #if BSP_HAS_USC320
0487     la  k0,INT_CFG3 /* Disable heartbeat interrupt in USC320, it interferes with PMON exception handler */
0488     lw  k1,(k0)
0489     li  k0,~HBI_MASK
0490     and k1,k1,k0
0491     la  k0,INT_CFG3
0492     sw  k1,(k0)
0493 #endif
0494 
0495     la  k0,_brk_esr_link    /* Jump to next exception handler in PMON exception chain */
0496     lw  k0,(k0)
0497     lw  k0,4(k0)
0498     j   k0
0499     nop
0500 
0501     .set reorder
0502 ENDFRAME(_BRK_Handler)
0503 
0504 
0505 /**************************************************************************
0506 **
0507 **  init_exc_vecs() - moves the exception code into the addresses
0508 **            reserved for exception vectors
0509 **
0510 **  UTLB Miss exception vector at address 0x80000000
0511 **
0512 **  General exception vector at address 0x80000080
0513 **
0514 **  RESET exception vector is at address 0xbfc00000
0515 **
0516 ***************************************************************************/
0517 
0518 FRAME(init_exc_vecs,sp,0,ra)
0519     .set noreorder
0520 
0521     .extern mon_onintr
0522 
0523 /* Install interrupt handler in PMON exception handling chain */
0524 
0525     addiu   sp,sp,-8
0526     sw  ra,(sp)         /* Save ra contents on stack */
0527     move    a0,zero
0528     la  a1,_int_esr_link
0529     jal mon_onintr      /* Make PMON system call to install interrupt exception handler */
0530     nop
0531     li  a0,9
0532     la  a1,_brk_esr_link
0533     jal mon_onintr      /* Make PMON system call to install break exception handler */
0534     nop
0535     lw  ra,(sp)
0536     addiu   sp,sp,8         /* Restore ra contents from stack */
0537     j   ra
0538     nop
0539 
0540     .set reorder
0541 ENDFRAME(init_exc_vecs)
0542 
0543 
0544 #if 0       /* Unused code below */
0545 
0546 /*************************************************************
0547 *  enable_int7(ints)
0548 *   Enable interrupt 7
0549 */
0550 FRAME(enable_int7,sp,0,ra)
0551     .set noreorder
0552 
0553     la  t0,IRDM1    # Set interrupt controller detection mode (bits 2-3 = 0 for int 7 active low)
0554     li  t1,0x0
0555     sw  t1,(t0)
0556 
0557     la  t0,IRLVL4   # Set interrupt controller level (bit 8-10 = 2 for int 7 at level 2)
0558     li  t1,0x200
0559     sw  t1,(t0)
0560 
0561     la  t0,IRMSK    # Set interrupt controller mask
0562     li  t1,0x0
0563     sw  t1,(t0)
0564 
0565     la  t0,IRDEN    # Enable interrupts from controller
0566     li  t1,0x1
0567     sw  t1,(t0)
0568 
0569     j   ra
0570     nop
0571     .set reorder
0572 ENDFRAME(enable_int7)
0573 
0574 /*************************************************************
0575 *  disable_int7(ints)
0576 *   Disable interrupt 7
0577 */
0578 FRAME(disable_int7,sp,0,ra)
0579     .set noreorder
0580 
0581     la  t0,IRLVL4   # Set interrupt controller level (bit 8-10 = 0 to diasble int 7)
0582     li  t1,0x200
0583     sw  t1,(t0)
0584 
0585     j   ra
0586     nop
0587     .set reorder
0588 ENDFRAME(disable_int7)
0589 #endif
0590 
0591 /*************************************************************
0592 *  exception:
0593 *       Diagnostic code that can be hooked to PMON interrupt handler.
0594 *       Generates pulse on PIO22 pin.
0595 *   Called from _exception code in PMON (see mips.s of PMON).
0596 *   Return address is located in k1.
0597 */
0598 FRAME(tx49xxexception,sp,0,ra)
0599     .set noreorder
0600     la  k0,k1tmp
0601     sw  k1,(k0)
0602 
0603 /* Activate TX49xx PIO22 signal for diagnostics */
0604     lui k0,0xff1f
0605     ori k0,k0,0xf500
0606     lw  k0,(k0)
0607     lui k1,0x40
0608     or  k1,k1,k0
0609     lui k0,0xff1f
0610     ori k0,k0,0xf500
0611     sw  k1,(k0)
0612     nop
0613 
0614 /* De-activate TX49xx PIO22 signal for diagnostics */
0615     lui k0,0xff1f
0616     ori k0,k0,0xf500
0617     lw  k0,(k0)
0618     lui k1,0x40
0619     not k1
0620     and k1,k1,k0
0621     lui k0,0xff1f
0622     ori k0,k0,0xf500
0623     sw  k1,(k0)
0624     nop
0625 
0626     la  k0,k1tmp
0627     lw  k1,(k0)
0628     j   k1
0629     .set reorder
0630 ENDFRAME(tx49xxexception)
0631 
0632 
0633 
0634 
0635     .data
0636 
0637 k1tmp:  .word   0   /* Temporary strage for K1 during interrupt service */
0638 
0639 /*************************************************************
0640 *
0641 * Exception handler links, used in PMON exception handler chains
0642 */
0643     /* Interrupt exception service routine link */
0644     .global _int_esr_link
0645 _int_esr_link:
0646     .word   0
0647     .word   bsp_ISR_Handler
0648 
0649     /* Break exception service routine link */
0650     .global _brk_esr_link
0651 _brk_esr_link:
0652     .word   0
0653     .word   _BRK_Handler
0654 
0655 
0656 
0657