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

4.104.115
Last change on this file since efdfd48 was efdfd48, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/29/09 at 15:27:07

Whitespace removal.

  • 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.rtems.com/license/LICENSE.
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,1)
101EXTERN(_ISR_Signals_to_thread_executing,1)
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        lb      t0,_Context_Switch_necessary
285        lb      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        NOP
420
421        /* clear the heartbeat interrupt */
422        la      k0,INT_STAT
423        li      t0,HBI_MASK
424        sw      t0,(k0)
425        /* wait for interrupt to clear */
426USC_isr1:
427        la      k0,INT_STAT     /* read INT_STAT register */
428        lw      k0,(k0)
429        nop                     /* reading from external device */
430        sll     k0,(31-21)      /* test bit 21 (HBI) */
431        bltz    k0,USC_isr1     /* branch if bit set */
432        nop
433        j       Clock_isr       /* Jump to clock isr */
434        nop
435USC_isr2:
436        j       ra              /* no serviceable interrupt, return without doing anything */
437        nop
438
439       .set    reorder
440
441ENDFRAME(hurricane_ISR_Handler)
442
443
444FRAME(_BRK_Handler,sp,0,ra)
445        .set noreorder
446
447        la      k0,INT_CFG3     /* Disable heartbeat interrupt in USC320, it interferes with PMON exception handler */
448        lw      k1,(k0)
449        li      k0,~HBI_MASK
450        and     k1,k1,k0
451        la      k0,INT_CFG3
452        sw      k1,(k0)
453
454        la  k0,_brk_esr_link    /* Jump to next exception handler in PMON exception chain */
455        lw  k0,(k0)
456        lw  k0,4(k0)
457        j   k0
458        nop
459
460        .set reorder
461ENDFRAME(_BRK_Handler)
462
463
464/**************************************************************************
465**
466**      init_exc_vecs() - moves the exception code into the addresses
467**                        reserved for exception vectors
468**
469**      UTLB Miss exception vector at address 0x80000000
470**
471**      General exception vector at address 0x80000080
472**
473**      RESET exception vector is at address 0xbfc00000
474**
475***************************************************************************/
476
477FRAME(init_exc_vecs,sp,0,ra)
478        .set noreorder
479
480        .extern mon_onintr
481
482/* Install interrupt handler in PMON exception handling chain */
483
484        addiu   sp,sp,-8
485        sw      ra,(sp)                 /* Save ra contents on stack */
486        move    a0,zero
487        la      a1,_int_esr_link
488        jal     mon_onintr              /* Make PMON system call to install interrupt exception handler */
489        nop
490        li      a0,9
491        la      a1,_brk_esr_link
492        jal     mon_onintr              /* Make PMON system call to install break exception handler */
493        nop
494        lw      ra,(sp)
495        addiu   sp,sp,8                 /* Restore ra contents from stack */
496        j       ra
497        nop
498
499        .set reorder
500ENDFRAME(init_exc_vecs)
501
502
503
504/***************************************************************************
505**
506**   The following code was added to support boards using V3 USC320
507**     system controller chip.
508**
509****************************************************************************/
510
511/*************************************************************
512*  init_hbt()
513*       Initialize the heartbeat timer
514*/
515FRAME(init_hbt,sp,0,ra)
516        .set noreorder
517        la      t0,SYSTEM       # Unlock USC registers
518        li      t1,0xA5
519        sb      t1,(t0)
520
521        la      t0,WD_HBI       # Initialize heatbeat and watchdog timers
522
523                                # (1 / 64 MHz) * 4000 * (63 + 1) = 4000.0 microseconds
524                                # Watchdog period is heartbeat period times watchdog timer constant (bits 7 - 0)
525                                # Watchdog period = 4000 * 5 = 20000 microseconds
526        li      t1,(WD_EN | HBI_4000_PS | 0x00003F00 | 0x5)
527
528                                # (1 / 64 MHz) * 4000 * (15 + 1) = 1000.0 microseconds
529                                # Watchdog period is heartbeat period times watchdog timer constant (bits 7 - 0)
530                                # Watchdog period = 1000 * 20 = 20000 microseconds
531        li      t1,(WD_EN | HBI_4000_PS | 0x00000F00 | 0x14)
532
533                                # (1 / 64 MHz) * 40000 * (15 + 1) = 10000.0 microseconds
534                                # Watchdog period is heartbeat period times watchdog timer constant (bits 7 - 0)
535                                # Watchdog period = 10000 * 20 = 200000 microseconds
536        li      t1,(WD_EN | HBI_4000_PS | 0x00009600 | 0x14)
537
538        sw      t1,(t0)
539
540        la      t0,SYSTEM       # Lock USC registers
541        li      t1,0x60
542        sb      t1,(t0)
543
544        .set reorder
545        j       ra
546        nop
547        .set reorder
548ENDFRAME(init_hbt)
549
550/*************************************************************
551*  reset_wdt()
552*       Reset the watchdog timer
553*/
554FRAME(reset_wdt,sp,0,ra)
555        .set noreorder
556
557        la      t0,WD_HBI+2     # Load address watchdog timer reset byte
558        li      t1,WD_INIT
559        sb      t1,(t0)
560
561        .set reorder
562        j       ra
563        nop
564        .set reorder
565ENDFRAME(reset_wdt)
566
567/*************************************************************
568*  disable_wdt()
569*       Disable watchdog timer
570*/
571FRAME(disable_wdt,sp,0,ra)
572        .set noreorder
573        la      t0,WD_HBI       # Clear watchdog enable bit in control register
574        lw      t1,(t0)
575        li      t2,~WD_EN
576        and     t1,t1,t2
577        sw      t1,(t0)
578
579        .set reorder
580        j       ra
581        nop
582        .set reorder
583ENDFRAME(disable_wdt)
584
585/*************************************************************
586*  enable_hbi(ints)
587*       Enable the heartbeat interrupt
588*/
589FRAME(enable_hbi,sp,0,ra)
590        .set noreorder
591
592        la      t0,INT_CFG3     # Enable heartbeat interrupt in USC320
593        lw      t1,(t0)
594        li      t2,(HBI_MASK | MODE_TOTEM_POLE)
595        or      t1,t1,t2
596        sw      t1,(t0)
597
598        .set reorder
599        j       ra
600        nop
601        .set reorder
602ENDFRAME(enable_hbi)
603
604/*************************************************************
605*  disable_hbi(ints)
606*       Disable the heartbeat interrupt
607*/
608FRAME(disable_hbi,sp,0,ra)
609        .set noreorder
610        la      t0,INT_CFG3     # Disable heartbeat interrupt in USC320
611        lw      t1,(t0)
612        li      t2,~HBI_MASK
613        and     t1,t1,t2
614        sw      t1,(t0)
615
616        .set reorder
617        j       ra
618        nop
619        .set reorder
620ENDFRAME(disable_hbi)
621
622
623/*************************************************************
624*  enable_wdi()
625*       Enable the watchdog interrupt
626*/
627FRAME(enable_wdi,sp,0,ra)
628        .set noreorder
629
630        la      t0,INT_CFG1     # Enable watchdog interrupt in USC320
631        lw      t1,(t0)
632        li      t2,(WDI_MASK | MODE_TOTEM_POLE)
633        or      t1,t1,t2
634        sw      t1,(t0)
635
636        .set reorder
637        j       ra
638        nop
639        .set reorder
640ENDFRAME(enable_wdi)
641
642/*************************************************************
643*  disable_wdi(ints)
644*       Disable the watchdog interrupt
645*/
646FRAME(disable_wdi,sp,0,ra)
647        .set noreorder
648
649        la      t0,INT_CFG1     # Disable watchdog interrupt in USC320
650        lw      t1,(t0)
651        li      t2,~(WDI_MASK | MODE_TOTEM_POLE)
652        and     t1,t1,t2
653        sw      t1,(t0)
654
655        la      t0,INT_STAT     # Clear watchdog interrupt status bit
656        li      t1,WDI_MASK
657        sw      t1,(t0)
658
659        .set reorder
660        j       ra
661        nop
662        .set reorder
663ENDFRAME(disable_wdi)
664
665
666        .data
667
668k1tmp:  .word   0       /* Temporary strage for K1 during interrupt service */
669
670/*************************************************************
671*
672* Exception handler links, used in PMON exception handler chains
673*/
674        /* Interrupt exception service routine link */
675        .global _int_esr_link
676_int_esr_link:
677        .word   0
678        .word   hurricane_ISR_Handler
679
680        /* Break exception service routine link */
681        .global _brk_esr_link
682_brk_esr_link:
683        .word   0
684        .word   _BRK_Handler
685
686
687
688
Note: See TracBrowser for help on using the repository browser.