source: rtems/c/src/lib/libbsp/mips/hurricane/startup/exception.S @ 7283768

4.104.114.84.95
Last change on this file since 7283768 was 7283768, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/16/06 at 17:18:20

New (Submission by Bruce Robinson <brucer@…>).

  • Property mode set to 100644
File size: 16.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-1999.
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.OARcorp.com/rtems/license.html.
32 *
33 *  $Id$
34 */
35/* @(#)exception.S       10/11/04     1.00 */
36
37#include <rtems/mips/iregdef.h>
38#include <rtems/mips/idtcpu.h>
39#include <usc.h>
40
41
42#define FRAME(name,frm_reg,offset,ret_reg)      \
43        .globl  name;                           \
44        .ent    name;                           \
45name:;                                          \
46        .frame  frm_reg,offset,ret_reg
47#define ENDFRAME(name)                          \
48        .end name
49
50
51#if __mips == 3
52/* 64 bit register operations */
53#define NOP     nop
54#define ADD     dadd
55#define STREG   sd
56#define LDREG   ld
57#define ADDU    addu
58#define ADDIU   addiu
59#define STREGC1 sdc1
60#define LDREGC1 ldc1
61#define R_SZ    8
62#define F_SZ    8
63#define SZ_INT  8
64#define SZ_INT_POW2 3
65
66/* XXX if we don't always want 64 bit register ops, then another ifdef */
67
68#elif __mips == 1
69/* 32 bit register operations*/
70#define NOP     nop
71#define ADD     add
72#define STREG   sw
73#define LDREG   lw
74#define ADDU    add
75#define ADDIU   addi
76#define STREGC1 swc1
77#define LDREGC1 lwc1
78#define R_SZ    4
79#define F_SZ    4
80#define SZ_INT  4
81#define SZ_INT_POW2 2
82#else
83#error "mips assembly: what size registers do I deal with?"
84#endif
85
86
87#define ISR_VEC_SIZE    4
88#define EXCP_STACK_SIZE (NREGS*R_SZ)
89
90
91#ifdef __GNUC__
92#define EXTERN(x,size) .extern x,size
93#else
94#define EXTERN(x,size)
95#endif
96
97
98EXTERN(_ISR_Nest_level, 4)
99EXTERN(_Thread_Dispatch_disable_level,4)
100EXTERN(_Context_Switch_necessary,4)
101EXTERN(_ISR_Signals_to_thread_executing,4)
102.extern _Thread_Dispatch
103.extern _ISR_Vector_table
104
105/*  void __ISR_Handler()
106 *
107 *  This routine provides the RTEMS interrupt management.
108 *
109 */
110
111#if 0
112void _ISR_Handler()
113{
114   /*
115    *  This discussion ignores a lot of the ugly details in a real
116    *  implementation such as saving enough registers/state to be
117    *  able to do something real.  Keep in mind that the goal is
118    *  to invoke a user's ISR handler which is written in C and
119    *  uses a certain set of registers.
120    *
121    *  Also note that the exact order is to a large extent flexible.
122    *  Hardware will dictate a sequence for a certain subset of
123    *  _ISR_Handler while requirements for setting
124    */
125
126  /*
127   *  At entry to "common" _ISR_Handler, the vector number must be
128   *  available.  On some CPUs the hardware puts either the vector
129   *  number or the offset into the vector table for this ISR in a
130   *  known place.  If the hardware does not give us this information,
131   *  then the assembly portion of RTEMS for this port will contain
132   *  a set of distinct interrupt entry points which somehow place
133   *  the vector number in a known place (which is safe if another
134   *  interrupt nests this one) and branches to _ISR_Handler.
135   *
136   */
137#endif
138FRAME(hurricane_ISR_Handler,sp,0,ra)
139        .set noreorder
140
141        mfc0 k0,C0_CAUSE        /* Determine if an interrupt generated this exception */
142        nop
143        and k1,k0,CAUSE_EXCMASK
144        beq k1,zero,_chk_int    /* If so, branch to service here */
145        nop
1461:      la  k0,_int_esr_link    /* Otherwise, jump to next exception handler in PMON exception chain */
147        lw  k0,(k0)
148        lw  k0,4(k0)
149        j   k0
150        nop
151_chk_int:
152        mfc0 k1,C0_SR
153        nop
154        and k0,k1
155        and k0,CAUSE_IPMASK
156        beq k0,zero,_ISR_Handler_quick_exit     /* external interrupt not enabled, ignore */
157
158        nop
159
160/* For debugging interrupts, clear EXL to allow breakpoints */
161#if 0
162        MFC0    k0, C0_SR
163#if __mips == 3
164        li      k1,SR_EXL       /* Clear EXL and Set IE to enable interrupts */
165        not     k1
166        and     k0,k1
167        li      k1,SR_IE
168#elif __mips == 1
169        li      k1,SR_IEC
170#endif
171        or      k0, k1
172        mtc0    k0, C0_SR
173        NOP
174#endif
175
176
177  /*
178   *  save some or all context on stack
179   *  may need to save some special interrupt information for exit
180   */
181
182        /* Q: _ISR_Handler, not using IDT/SIM ...save extra regs? */
183
184        /* wastes a lot of stack space for context?? */
185        ADDIU    sp,sp,-EXCP_STACK_SIZE
186
187        STREG ra, R_RA*R_SZ(sp)  /* store ra on the stack */
188        STREG v0, R_V0*R_SZ(sp)
189        STREG v1, R_V1*R_SZ(sp)
190        STREG a0, R_A0*R_SZ(sp)
191        STREG a1, R_A1*R_SZ(sp)
192        STREG a2, R_A2*R_SZ(sp)
193        STREG a3, R_A3*R_SZ(sp)
194        STREG t0, R_T0*R_SZ(sp)
195        STREG t1, R_T1*R_SZ(sp)
196        STREG t2, R_T2*R_SZ(sp)
197        STREG t3, R_T3*R_SZ(sp)
198        STREG t4, R_T4*R_SZ(sp)
199        STREG t5, R_T5*R_SZ(sp)
200        STREG t6, R_T6*R_SZ(sp)
201        STREG t7, R_T7*R_SZ(sp)
202        mflo  t0
203        STREG t8, R_T8*R_SZ(sp)
204        STREG t0, R_MDLO*R_SZ(sp)
205        STREG t9, R_T9*R_SZ(sp)
206        mfhi  t0
207        STREG gp, R_GP*R_SZ(sp)
208        STREG t0, R_MDHI*R_SZ(sp)
209        STREG fp, R_FP*R_SZ(sp)
210       
211        .set noat
212        STREG AT, R_AT*R_SZ(sp)
213        .set at
214
215        mfc0     t0,C0_SR
216        dmfc0    t1,C0_EPC
217        STREG    t0,R_SR*R_SZ(sp)
218        STREG    t1,R_EPC*R_SZ(sp)
219
220  /*
221   *
222   *  #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
223   *    if ( _ISR_Nest_level == 0 )
224   *      switch to software interrupt stack
225   *  #endif
226   */
227
228  /*
229   *  _ISR_Nest_level++;
230   */
231        lw      t0,_ISR_Nest_level
232        NOP
233        add     t0,t0,1
234        sw      t0,_ISR_Nest_level
235  /*
236   *  _Thread_Dispatch_disable_level++;
237   */
238        lw      t1,_Thread_Dispatch_disable_level
239        NOP
240        add     t1,t1,1
241        sw      t1,_Thread_Dispatch_disable_level
242
243  /*
244   *  Call the CPU model or BSP specific routine to decode the
245   *  interrupt source and actually vector to device ISR handlers.
246   */
247        move     a0,sp
248        jal      mips_vector_isr_handlers
249        NOP
250
251_ISR_Handler_cleanup:
252
253  /*
254   *  --_ISR_Nest_level;
255   */
256        lw      t2,_ISR_Nest_level
257        NOP
258        add     t2,t2,-1
259        sw      t2,_ISR_Nest_level
260  /*
261   *  --_Thread_Dispatch_disable_level;
262   */
263        lw      t1,_Thread_Dispatch_disable_level
264        NOP
265        add     t1,t1,-1
266        sw      t1,_Thread_Dispatch_disable_level
267  /*
268   *  if ( _Thread_Dispatch_disable_level || _ISR_Nest_level )
269   *    goto the label "exit interrupt (simple case)"
270   */
271        or  t0,t2,t1
272        bne t0,zero,_ISR_Handler_exit
273        NOP
274
275
276  /*
277   *  #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
278   *    restore stack
279   *  #endif
280   * 
281   *  if ( !_Context_Switch_necessary && !_ISR_Signals_to_thread_executing )
282   *    goto the label "exit interrupt (simple case)"
283   */
284        lw      t0,_Context_Switch_necessary
285        lw      t1,_ISR_Signals_to_thread_executing
286        NOP
287        or      t0,t0,t1
288        beq     t0,zero,_ISR_Handler_exit
289        NOP
290
291/*
292** Turn on interrupts before entering Thread_Dispatch which
293** will run for a while, thus allowing new interrupts to
294** be serviced.  Observe the Thread_Dispatch_disable_level interlock
295** that prevents recursive entry into Thread_Dispatch.
296*/
297
298        mfc0    t0, C0_SR
299#if __mips == 3
300        li      t1,SR_EXL       /* Clear EXL and Set IE to enable interrupts */
301        not     t1
302        and     t0,t1
303        li      t1,SR_IE
304#elif __mips == 1
305        li      t1,SR_IEC
306#endif
307        or      t0, t1
308        mtc0    t0, C0_SR
309        NOP
310
311        /* save off our stack frame so the context switcher can get to it */
312        la      t0,__exceptionStackFrame
313        STREG   sp,(t0)
314                                       
315        jal     _Thread_Dispatch
316        NOP
317
318        /* and make sure its clear in case we didn't dispatch.  if we did, its
319        ** already cleared */
320        la      t0,__exceptionStackFrame
321        STREG   zero,(t0)
322        NOP
323
324/*
325** turn interrupts back off while we restore context so
326** a badly timed interrupt won't accidentally mess things up
327*/
328        mfc0    t0, C0_SR
329#if __mips == 3
330        li      t1,SR_IE                /* Clear IE first (recommended) */
331        not     t1
332        and     t0,t1
333        mtc0    t0, C0_SR
334        li      t1,SR_EXL | SR_IE       /* Set EXL and IE, this puts status register bits back to interrupted state */
335        or      t0,t1
336#elif __mips == 1
337        /* ints off, current & prev kernel mode on (kernel mode enabled is bit clear..argh!) */
338        li      t1,SR_IEC | SR_KUP | SR_KUC     
339        not     t1
340        and     t0, t1
341#endif
342
343#if __mips == 1
344        /* disabled 7/29, gregm, this tasks context was saved previously in an interrupt,
345        ** so we'll just restore the task's previous interrupt enables.
346
347        **
348        ** make sure previous int enable is on  because we're returning from an interrupt
349        ** which means interrupts have to be enabled
350       
351        li      t1,SR_IEP
352        or      t0,t1
353        */
354#endif
355        mtc0    t0, C0_SR
356        NOP
357       
358  /*
359   *  prepare to get out of interrupt
360   *  return from interrupt  (maybe to _ISR_Dispatch)
361   *
362   *  LABEL "exit interrupt (simple case):"
363   *  prepare to get out of interrupt
364   *  return from interrupt
365   */
366
367_ISR_Handler_exit:
368
369/* restore interrupt context from stack */
370        LDREG t8, R_MDLO*R_SZ(sp)
371        LDREG t0, R_T0*R_SZ(sp)
372        mtlo  t8
373        LDREG t8, R_MDHI*R_SZ(sp)           
374        LDREG t1, R_T1*R_SZ(sp)
375        mthi  t8
376        LDREG t2, R_T2*R_SZ(sp)
377        LDREG t3, R_T3*R_SZ(sp)
378        LDREG t4, R_T4*R_SZ(sp)
379        LDREG t5, R_T5*R_SZ(sp)
380        LDREG t6, R_T6*R_SZ(sp)
381        LDREG t7, R_T7*R_SZ(sp)
382        LDREG t8, R_T8*R_SZ(sp)
383        LDREG t9, R_T9*R_SZ(sp)
384        LDREG gp, R_GP*R_SZ(sp)
385        LDREG fp, R_FP*R_SZ(sp)
386        LDREG ra, R_RA*R_SZ(sp)
387        LDREG a0, R_A0*R_SZ(sp)
388        LDREG a1, R_A1*R_SZ(sp)
389        LDREG a2, R_A2*R_SZ(sp)
390        LDREG a3, R_A3*R_SZ(sp)
391        LDREG v1, R_V1*R_SZ(sp)
392        LDREG v0, R_V0*R_SZ(sp)
393       
394        LDREG k1, R_EPC*R_SZ(sp)
395        mtc0  k1,C0_EPC
396       
397        .set noat
398        LDREG     AT, R_AT*R_SZ(sp)
399        .set at
400
401        ADDIU     sp,sp,EXCP_STACK_SIZE
402
403_ISR_Handler_quick_exit:
404        eret
405        nop
406
407
408        /* Interrupts from USC320 are serviced here */
409        .global USC_isr
410        .extern Clock_isr       
411USC_isr:
412        /* check if it's a USC320 heartbeat interrupt */
413        la      k0,INT_STAT     /* read INT_STAT register */
414        lw      k0,(k0)
415        nop                     /* reading from external device */
416        sll     k0,(31-21)      /* test bit 21 (HBI) */
417       
418        bgez    k0,USC_isr2     /* branch if not a heartbeat interrupt */
419
420        /* clear the heartbeat interrupt */
421        la      k0,INT_STAT
422        li      t0,HBI_MASK
423        sw      t0,(k0)
424        /* wait for interrupt to clear */
425USC_isr1:
426        la      k0,INT_STAT     /* read INT_STAT register */
427        lw      k0,(k0)
428        nop                     /* reading from external device */
429        sll     k0,(31-21)      /* test bit 21 (HBI) */
430        bltz    k0,USC_isr1     /* branch if bit set */
431        nop
432        j       Clock_isr       /* Jump to clock isr */
433        nop
434USC_isr2:
435        j       ra              /* no serviceable interrupt, return without doing anything */
436        nop             
437
438       .set    reorder
439
440ENDFRAME(hurricane_ISR_Handler)
441
442
443FRAME(_BRK_Handler,sp,0,ra)
444        .set noreorder
445
446        la      k0,INT_CFG3     /* Disable heartbeat interrupt in USC320, it interferes with PMON exception handler */
447        lw      k1,(k0)
448        li      k0,~HBI_MASK
449        and     k1,k1,k0
450        la      k0,INT_CFG3
451        sw      k1,(k0)
452       
453        la  k0,_brk_esr_link    /* Jump to next exception handler in PMON exception chain */
454        lw  k0,(k0)
455        lw  k0,4(k0)
456        j   k0
457        nop
458
459        .set reorder
460ENDFRAME(_BRK_Handler)
461
462
463/**************************************************************************
464**
465**      init_exc_vecs() - moves the exception code into the addresses
466**                        reserved for exception vectors
467**
468**      UTLB Miss exception vector at address 0x80000000
469**
470**      General exception vector at address 0x80000080
471**
472**      RESET exception vector is at address 0xbfc00000
473**
474***************************************************************************/
475
476FRAME(init_exc_vecs,sp,0,ra)
477        .set noreorder
478
479        .extern mon_onintr
480       
481/* Install interrupt handler in PMON exception handling chain */
482
483        addiu   sp,sp,-8
484        sw      ra,(sp)                 /* Save ra contents on stack */
485        move    a0,zero
486        la      a1,_int_esr_link
487        jal     mon_onintr              /* Make PMON system call to install interrupt exception handler */
488        nop
489        li      a0,9
490        la      a1,_brk_esr_link
491        jal     mon_onintr              /* Make PMON system call to install break exception handler */
492        nop
493        lw      ra,(sp)
494        addiu   sp,sp,8                 /* Restore ra contents from stack */
495        j       ra
496        nop
497
498        .set reorder
499ENDFRAME(init_exc_vecs)
500
501
502
503/***************************************************************************
504**
505**   The following code was added to support boards using V3 USC320
506**     system controller chip.
507**
508****************************************************************************/
509
510/*************************************************************
511*  init_hbt()
512*       Initialize the heartbeat timer
513*/
514FRAME(init_hbt,sp,0,ra)
515        .set noreorder
516        la      t0,SYSTEM       # Unlock USC registers
517        li      t1,0xA5
518        sb      t1,(t0)
519       
520        la      t0,WD_HBI       # Initialize heatbeat and watchdog timers
521
522                                # (1 / 64 MHz) * 4000 * (63 + 1) = 4000.0 microseconds
523                                # Watchdog period is heartbeat period times watchdog timer constant (bits 7 - 0)
524                                # Watchdog period = 4000 * 5 = 20000 microseconds
525        li      t1,(WD_EN | HBI_4000_PS | 0x00003F00 | 0x5)
526
527                                # (1 / 64 MHz) * 4000 * (15 + 1) = 1000.0 microseconds
528                                # Watchdog period is heartbeat period times watchdog timer constant (bits 7 - 0)
529                                # Watchdog period = 1000 * 20 = 20000 microseconds
530        li      t1,(WD_EN | HBI_4000_PS | 0x00000F00 | 0x14)
531
532                                # (1 / 64 MHz) * 40000 * (15 + 1) = 10000.0 microseconds
533                                # Watchdog period is heartbeat period times watchdog timer constant (bits 7 - 0)
534                                # Watchdog period = 10000 * 20 = 200000 microseconds
535        li      t1,(WD_EN | HBI_4000_PS | 0x00009600 | 0x14)
536
537        sw      t1,(t0)
538       
539        la      t0,SYSTEM       # Lock USC registers
540        li      t1,0x60
541        sb      t1,(t0)
542       
543        .set reorder
544        j       ra
545        nop
546        .set reorder
547ENDFRAME(init_hbt)
548
549/*************************************************************
550*  reset_wdt()
551*       Reset the watchdog timer
552*/
553FRAME(reset_wdt,sp,0,ra)
554        .set noreorder
555
556        la      t0,WD_HBI+2     # Load address watchdog timer reset byte
557        li      t1,WD_INIT     
558        sb      t1,(t0)
559       
560        .set reorder
561        j       ra
562        nop
563        .set reorder
564ENDFRAME(reset_wdt)
565
566/*************************************************************
567*  disable_wdt()
568*       Disable watchdog timer
569*/
570FRAME(disable_wdt,sp,0,ra)
571        .set noreorder
572        la      t0,WD_HBI       # Clear watchdog enable bit in control register
573        lw      t1,(t0)
574        li      t2,~WD_EN
575        and     t1,t1,t2
576        sw      t1,(t0)
577       
578        .set reorder
579        j       ra
580        nop
581        .set reorder
582ENDFRAME(disable_wdt)
583
584/*************************************************************
585*  enable_hbi(ints)
586*       Enable the heartbeat interrupt
587*/
588FRAME(enable_hbi,sp,0,ra)
589        .set noreorder
590       
591        la      t0,INT_CFG3     # Enable heartbeat interrupt in USC320
592        lw      t1,(t0)
593        li      t2,(HBI_MASK | MODE_TOTEM_POLE)
594        or      t1,t1,t2
595        sw      t1,(t0)
596       
597        .set reorder
598        j       ra
599        nop
600        .set reorder
601ENDFRAME(enable_hbi)
602
603/*************************************************************
604*  disable_hbi(ints)
605*       Disable the heartbeat interrupt
606*/
607FRAME(disable_hbi,sp,0,ra)
608        .set noreorder
609        la      t0,INT_CFG3     # Disable heartbeat interrupt in USC320
610        lw      t1,(t0)
611        li      t2,~HBI_MASK
612        and     t1,t1,t2
613        sw      t1,(t0)
614       
615        .set reorder
616        j       ra
617        nop
618        .set reorder
619ENDFRAME(disable_hbi)
620
621
622/*************************************************************
623*  enable_wdi()
624*       Enable the watchdog interrupt
625*/
626FRAME(enable_wdi,sp,0,ra)
627        .set noreorder
628       
629        la      t0,INT_CFG1     # Enable watchdog interrupt in USC320
630        lw      t1,(t0)
631        li      t2,(WDI_MASK | MODE_TOTEM_POLE)
632        or      t1,t1,t2
633        sw      t1,(t0)
634       
635        .set reorder
636        j       ra
637        nop
638        .set reorder
639ENDFRAME(enable_wdi)
640
641/*************************************************************
642*  disable_wdi(ints)
643*       Disable the watchdog interrupt
644*/
645FRAME(disable_wdi,sp,0,ra)
646        .set noreorder
647       
648        la      t0,INT_CFG1     # Disable watchdog interrupt in USC320
649        lw      t1,(t0)
650        li      t2,~(WDI_MASK | MODE_TOTEM_POLE)
651        and     t1,t1,t2
652        sw      t1,(t0)
653       
654        la      t0,INT_STAT     # Clear watchdog interrupt status bit
655        li      t1,WDI_MASK
656        sw      t1,(t0)
657       
658        .set reorder
659        j       ra
660        nop
661        .set reorder
662ENDFRAME(disable_wdi)
663
664
665        .data
666
667k1tmp:  .word   0       /* Temporary strage for K1 during interrupt service */
668       
669/*************************************************************
670*
671* Exception handler links, used in PMON exception handler chains
672*/
673        /* Interrupt exception service routine link */
674        .global _int_esr_link
675_int_esr_link:
676        .word   0
677        .word   hurricane_ISR_Handler
678       
679        /* Break exception service routine link */
680        .global _brk_esr_link
681_brk_esr_link:
682        .word   0
683        .word   _BRK_Handler
684
685
686       
687
Note: See TracBrowser for help on using the repository browser.