1 #ifndef CYGONCE_HAL_VAR_INTR_H
2 #define CYGONCE_HAL_VAR_INTR_H
3 //==========================================================================
7 // VR4300 Interrupt and clock support
9 //==========================================================================
10 //####ECOSGPLCOPYRIGHTBEGIN####
11 // -------------------------------------------
12 // This file is part of eCos, the Embedded Configurable Operating System.
13 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
38 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
39 // at http://sources.redhat.com/ecos/ecos-license/
40 // -------------------------------------------
41 //####ECOSGPLCOPYRIGHTEND####
42 //==========================================================================
43 //#####DESCRIPTIONBEGIN####
45 // Author(s): hmt, nickg
46 // Contributors: nickg, jskov,
49 // Purpose: uPD985xx Interrupt support
50 // Description: The macros defined here provide the HAL APIs for handling
51 // interrupts and the clock for variants of the NEC uPD985xx
55 // #include <cyg/hal/var_intr.h>
59 //####DESCRIPTIONEND####
61 //==========================================================================
63 #include <cyg/hal/var_arch.h>
64 #include <cyg/hal/plf_intr.h>
66 //--------------------------------------------------------------------------
67 // Interrupt controller stuff.
69 #ifndef CYGHWR_HAL_INTERRUPT_VECTORS_DEFINED
70 // Interrupts dealt with via the status and cause registers
71 // must be numbered in bit order:
72 #define CYGNUM_HAL_INTERRUPT_STATUS_CAUSE_LOW (0)
73 // The first two are the "software interrupts" - you just set a bit.
74 #define CYGNUM_HAL_INTERRUPT_SOFT_ZERO (0)
75 #define CYGNUM_HAL_INTERRUPT_SOFT_ONE (1)
76 #define CYGNUM_HAL_INTERRUPT_FREE_TWO (2)
77 #define CYGNUM_HAL_INTERRUPT_USB (3)
78 #define CYGNUM_HAL_INTERRUPT_ETHER (4)
79 #define CYGNUM_HAL_INTERRUPT_FREE_FIVE (5)
80 #define CYGNUM_HAL_INTERRUPT_SYSCTL (6)
81 #define CYGNUM_HAL_INTERRUPT_COMPARE (7)
83 // Number 6 "SYSCTL" is all external sources in the system controller and
84 // will normally be decoded into one of 8-12 instead. If you use number 6
85 // directly, then this will disable *all* system controller sources.
86 // Startup code will ensure number 6 is unmasked by default, and it will
87 // have an arbitration routine installed to call all of the subsequent
88 // interrupts from the S_ISR register. This has to be an external routine
89 // because the S_ISR register is read-clear, and the interrupt sources are
90 // edge-triggered so they do not re-assert themselves - so we must address
91 // multiple sources per actual interrupt, in a loop.
93 #define CYGNUM_HAL_INTERRUPT_SYSCTL_LOW (8)
94 #define CYGNUM_HAL_INTERRUPT_SYSCTL_HI (12)
96 #define CYGNUM_HAL_INTERRUPT_TM0 (8) // TIMER CH0 interrupt.
97 #define CYGNUM_HAL_INTERRUPT_TM1 (9) // TIMER CH1 interrupt.
98 #define CYGNUM_HAL_INTERRUPT_UART (10) // UART interrupt.
99 #define CYGNUM_HAL_INTERRUPT_EXT (11) // External Interrupt.
100 #define CYGNUM_HAL_INTERRUPT_WU (12) // Wakeup Interrupt.
102 #define CYGHWR_HAL_GDB_PORT_VECTOR CYGNUM_HAL_INTERRUPT_UART
104 // Min/Max ISR numbers and how many there are
105 #define CYGNUM_HAL_ISR_MIN 0
106 #define CYGNUM_HAL_ISR_MAX 12
107 #define CYGNUM_HAL_ISR_COUNT 13
109 // The vector used by the Real time clock. The default here is to use
110 // interrupt 5, which is connected to the counter/comparator registers
111 // in many MIPS variants.
113 #ifndef CYGNUM_HAL_INTERRUPT_RTC
114 #define CYGNUM_HAL_INTERRUPT_RTC CYGNUM_HAL_INTERRUPT_COMPARE
117 #define CYGHWR_HAL_INTERRUPT_VECTORS_DEFINED
119 #endif // CYGHWR_HAL_INTERRUPT_VECTORS_DEFINED
121 #ifndef __ASSEMBLER__
123 // ------------------------------------------------------------------------
125 // This is placed in memory at a fixed location because we must share it
126 // with RedBoot, along with the VSR table and Virtual Vector table.
127 // It has to be an array to get the correct code generation to access it
128 // over all that distance.
129 externC volatile cyg_uint32 hal_interrupt_sr_mask_shadow_base[];
130 #define hal_interrupt_sr_mask_shadow (hal_interrupt_sr_mask_shadow_base[0])
132 // We have to have local versions of these to preserve the mask bits in the
133 // SR correctly when an interrupt occurs within one of these code sequences
134 // which are doing a read-modify-write to the main interrupt bit of the SR.
136 // Disable, it doesn't matter what the SR IM bits are - but it is possible
137 // for control to return with interrupts enabled if a context switch occurs
138 // away from the thread that disabled interrupts. Therefore we also make
139 // sure the contents of the SR match the shadow variable at the end.
141 #define HAL_DISABLE_INTERRUPTS(_old_) \
145 "mfc0 $8,$12; nop;" \
147 "and $8,$8,0xfffffffe;" \
154 /* interrupts disabled so can now inject the correct IM bits */ \
155 (_old_) = _tmp & 1; \
156 _tmp &= 0xffff00fe; \
157 _tmp |= (hal_interrupt_sr_mask_shadow & 0xff00); \
166 // Enable and restore, we must pick up hal_interrupt_sr_mask_shadow because
167 // it contains the truth. This is also for the convenience of the
168 // mask/unmask macros below.
169 #define HAL_ENABLE_INTERRUPTS() HAL_RESTORE_INTERRUPTS(1)
171 #define HAL_RESTORE_INTERRUPTS(_old_) \
174 "mfc0 $8,$12; nop;" \
175 "or $8,$8,%0;" /* inject IE bit */ \
176 "and $8,$8,0xffff00ff;" /* clear IM bits */ \
177 "or $8,$8,%1;" /* insert true IM */ \
181 : "r"((_old_) & 1),"r"(hal_interrupt_sr_mask_shadow & 0xff00) \
186 #define HAL_QUERY_INTERRUPTS( _state_ ) \
189 "mfc0 %0,$12; nop;" \
195 #define CYGHWR_HAL_INTERRUPT_ENABLE_DISABLE_RESTORE_DEFINED
197 // ------------------------------------------------------------------------
199 // For the bits which are in the SR, we only need to diddle the shadow
200 // variable; restore interrupts will pick that up at the end of the macro.
203 #ifndef CYGOPT_HAL_MIPS_UPD985XX_HARDWARE_BUGS_S2
204 // Vanilla versions here: trick versions with the workaround follow:
206 #define HAL_INTERRUPT_MASK( _vector_ ) \
208 register int _intstate; \
209 register int _shift; \
210 HAL_DISABLE_INTERRUPTS( _intstate ); \
211 if ( CYGNUM_HAL_INTERRUPT_SYSCTL_LOW > (_vector_) ) { \
212 /* mask starts at bit 8 */ \
213 _shift = 8 + (_vector_) - CYGNUM_HAL_INTERRUPT_STATUS_CAUSE_LOW; \
214 hal_interrupt_sr_mask_shadow &=~(1 << _shift); \
217 _shift = (_vector_) - CYGNUM_HAL_INTERRUPT_SYSCTL_LOW; \
218 *S_IMR &=~(1 << _shift); \
220 HAL_RESTORE_INTERRUPTS( _intstate ); \
224 #define HAL_INTERRUPT_UNMASK( _vector_ ) \
226 register int _intstate; \
227 register int _shift; \
228 HAL_DISABLE_INTERRUPTS( _intstate ); \
229 if ( CYGNUM_HAL_INTERRUPT_SYSCTL_LOW > (_vector_) ) { \
230 /* mask starts at bit 8 */ \
231 _shift = 8 + (_vector_) - CYGNUM_HAL_INTERRUPT_STATUS_CAUSE_LOW; \
232 hal_interrupt_sr_mask_shadow |= (1 << _shift); \
235 _shift = (_vector_) - CYGNUM_HAL_INTERRUPT_SYSCTL_LOW; \
236 *S_IMR |= (1 << _shift); \
238 HAL_RESTORE_INTERRUPTS( _intstate ); \
242 #define HAL_INTERRUPT_ACKNOWLEDGE( _vector_ ) \
244 register int _intstate; \
245 HAL_DISABLE_INTERRUPTS( _intstate ); \
246 /* Default clears the bit in the cause register. But VR4120 doc */ \
247 /* says this is a NOP so we ignore low numbered sources except the */ \
248 /* software interrupt bits. */ \
249 if ( CYGNUM_HAL_INTERRUPT_SYSCTL_LOW <= (_vector_) || \
250 CYGNUM_HAL_INTERRUPT_SYSCTL == (_vector_) ) { \
252 i = *S_ISR; /* This is read-clear! */ \
254 else if ( CYGNUM_HAL_INTERRUPT_SOFT_ZERO == (_vector_) || \
255 CYGNUM_HAL_INTERRUPT_SOFT_ONE == (_vector_) ) { \
256 /* These two are acknowledged by writing the bit to zero in */ \
257 /* the cause register. NB not the status register! */ \
260 "la $2,0x00000100\n" \
262 "andi $2,$2,0x0300\n" \
268 : "r"((_vector_)-CYGNUM_HAL_INTERRUPT_STATUS_CAUSE_LOW) \
272 HAL_RESTORE_INTERRUPTS( _intstate ); \
275 #else // DEFINED: CYGOPT_HAL_MIPS_UPD985XX_HARDWARE_BUGS_S2
280 extern void cyg_hal_interrupt_unmask( int vec );
281 extern void cyg_hal_interrupt_mask( int vec );
282 extern void cyg_hal_interrupt_acknowledge( int vec );
287 #define HAL_INTERRUPT_MASK( _vector_ ) \
289 register int _intstate; \
290 register int _shift; \
291 HAL_DISABLE_INTERRUPTS( _intstate ); \
292 if ( CYGNUM_HAL_INTERRUPT_SYSCTL_LOW > (_vector_) ) { \
293 /* mask starts at bit 8 */ \
294 _shift = 8 + (_vector_) - CYGNUM_HAL_INTERRUPT_STATUS_CAUSE_LOW; \
295 hal_interrupt_sr_mask_shadow &=~(1 << _shift); \
298 cyg_hal_interrupt_mask( (_vector_) ); \
300 HAL_RESTORE_INTERRUPTS( _intstate ); \
304 #define HAL_INTERRUPT_UNMASK( _vector_ ) \
306 register int _intstate; \
307 register int _shift; \
308 HAL_DISABLE_INTERRUPTS( _intstate ); \
309 if ( CYGNUM_HAL_INTERRUPT_SYSCTL_LOW > (_vector_) ) { \
310 /* mask starts at bit 8 */ \
311 _shift = 8 + (_vector_) - CYGNUM_HAL_INTERRUPT_STATUS_CAUSE_LOW; \
312 hal_interrupt_sr_mask_shadow |= (1 << _shift); \
315 cyg_hal_interrupt_unmask( (_vector_) ); \
317 HAL_RESTORE_INTERRUPTS( _intstate ); \
321 #define HAL_INTERRUPT_ACKNOWLEDGE( _vector_ ) \
323 register int _intstate; \
324 HAL_DISABLE_INTERRUPTS( _intstate ); \
325 /* Default clears the bit in the cause register. But VR4120 doc */ \
326 /* says this is a NOP so we ignore low numbered sources except the */ \
327 /* software interrupt bits. */ \
328 if ( CYGNUM_HAL_INTERRUPT_SYSCTL_LOW <= (_vector_) || \
329 CYGNUM_HAL_INTERRUPT_SYSCTL == (_vector_) ) { \
330 cyg_hal_interrupt_acknowledge( (_vector_) ); \
332 else if ( CYGNUM_HAL_INTERRUPT_SOFT_ZERO == (_vector_) || \
333 CYGNUM_HAL_INTERRUPT_SOFT_ONE == (_vector_) ) { \
334 /* These two are acknowledged by writing the bit to zero in */ \
335 /* the cause register. NB not the status register! */ \
338 "la $2,0x00000100\n" \
340 "andi $2,$2,0x0300\n" \
346 : "r"((_vector_)-CYGNUM_HAL_INTERRUPT_STATUS_CAUSE_LOW) \
350 HAL_RESTORE_INTERRUPTS( _intstate ); \
353 #endif // CYGOPT_HAL_MIPS_UPD985XX_HARDWARE_BUGS_S2
355 #define HAL_INTERRUPT_CONFIGURE( _vector_, _level_, _up_ )
357 #define HAL_INTERRUPT_SET_LEVEL( _vector_, _level_ )
359 #define CYGHWR_HAL_INTERRUPT_CONTROLLER_ACCESS_DEFINED
361 //--------------------------------------------------------------------------
362 // Useful for debugging...
364 #define HAL_READ_INTR_REGS( _status, _cause ) \
367 "mfc0 %0,$12; nop;" \
371 "mfc0 %0,$13; nop;" \
376 //--------------------------------------------------------------------------
377 #endif // ! __ASSEMBLER__
379 #endif // ifndef CYGONCE_HAL_VAR_INTR_H