junyangliu

【转】如何在Qsys Subsystem使用Interrupt? (SOC) (Nios II) (Qsys)

0
阅读(4580)

Abstract
Qsys其中之一的卖点就是允许你建立hierarchical的subsystem。在SOC设计中,通常我们会将慢速的周边使用较慢的clock而自成一个系统,在Qsys中允许我们将这些较慢的周边包成一个peripheral subsystem,而不是像SOPC Builder一样只能有一个system。当我们使用subsystem的架构时,该如何让subsystem内IP使用interrupt的方式与Nios II沟通呢?

Introduction
使用环境:Windows XP SP3 + VirtualBox 4.1.2 + Quartus II 11.0

本文将讨论以下主题:

1.如何使用IRQ Bridge连接subsystem的IRQ export到Nios II Processor?

2.如何避开Nios II SBT目前无法自动产生IRQ number常数在system.h的bug?

3.如何在App project使用Interrupt?

1.如何使用IRQ Bridge连接subsystemIRQ exportNios II Processor?

根据[1] Qsys Interconnect p.7-27 IRQ Bridge章节的建议,若要在subsystem使用interrupt,必须在包含Nios II的CPU subsystem使用IRQ Bridge接收Peripheral subsystem所export出来的IRQ,然后才连到Nios II Processor。至于下图中的Merlin IRQ Mapper则并不是必需的,若你在CPU subsystem中也有IP要使用interrupt,这必须再包一层Merlin IRQ Mapper;若你在CPU subsystem没有IP要使用interrupt,只有Peripheral subsystem使用interrupt,可以直接只使用IRQ Bridge连接到Nios II Processor。

常见的错误(也是我第一次的错误)是直接将Peripheral subsystem所export的IRQ直接连到Nios II Processor,这样Qsys与Quartus II编译都没有任何错误,Nios II也没有错误,不过Nios II的C code将收不到来自Peripheral subsystem的interrupt。

clip_image001

2.如何避开Nios II SBT目前无法自动产生IRQ number常数在system.hbug?

除此之外,在[2] Quartus II 11.0 Release Notes的p.15已经承认在Quartus II 11.0有以下的bug。

clip_image002

简单的说,就是若你在subsystem中使用interrupt,当你使用Generate BSP时,Nios II SBT根据*.sopcinfo在system.h所产生相对应的IRQ number常数,永远都是-1,并无法反应出目前硬件架构中真正的IRQ number。且经过实测,这个问题在Quartus II 11.1也依然存在。

如图所示,我们对push button使用interrupt,但在system.h的PERIPHERAL_SYSTEM_BUTTON_PIO_IRQ常数却是-1,与在Qsys上的IRQ number不同。

clip_image003

这会造成什么影响呢?只要你的App project使用到有使用interrupt的IP,编译就会产生错误,如下图我们在system timer有使用interrupt,所以一编译就产生错误无法继续。

clip_image004

详细错误讯息如下:

Error: Interrupt not connected for peripheral_system_timer_0. The system clock driver requires an interrupt to be connected. Please select an IRQ for this device in SOPC builder.

root cause就是system.h的IRQ number都是-1,所以App project找不到该IP的IRQ number而无法编译。

Solution
既然在system.h的IRQ number都是-1,我们只好重新自己在system.h手动定义IRQ number。根据[3] Altera Wiki : New Qsys Issues for Interrupts的建议

clip_image005

当然你可以直接去修改system.h,但别忘了BSP project的所有档案最好不要手动修改,应该交由Nios II SBT或者command line script去修改才对,因为每当你执行Generate BSP或者BSP Editor时,Nios II SBT都会重新产生system.h,也就是你做的所有修改都会被覆盖掉。所以[3] Altera Wiki : New Qsys Issues for Interrupts 的解法虽然可行,但并不完美。

根据 [2] Quartus II 11.0 Release Notes的建议

clip_image002[1]

看起来是要我们自己另开一个my_system.h,然后将system.h所有内容复制到system.h,自己在my_system.h加上IRQ number常数,并且App project也使用my_system.h,这样Generate BSP与BSP Editor就不会改到我的my_system.h了。

这样看似理想,但却衍生另外一个问题:BSP project有大量的档案都include "system.h",你必须手动一一的改成include "my_system.h",这也是个大工程。所以[2] Quartus II 11.0 Release Notes 看似也不尽理想。

我在此提供一个小技巧对付Nios II SBT目前这个bug。

在system.h的尾部自己加上IP IRQ number的定义如下图,先执行#undef取消这个常数的定义,再用#define重新这个常数,因为若同一个常数在system.h重复#define,会产生warning,若使用#undef就完全没有warning。

clip_image006

然后将这些#undef与#define另存一个文本文件,每当你执行Generate BSP或者BSP Editor时,system.h就会被Nios II SBT重新产生盖掉你原先的设定,再将这些#undef#define贴到system.h的最下方。如此就只需修改system.h,其他BSP档案都不用做任何修改。

如此修改重新编译后,就可顺利Build Project,没有任何错误。

clip_image007

3.如何在App project使用Interrupt?

根据[4] Exception Handling p.8-16与p.8-17的建议,我们将App project写成如下的code使用interrupt。

nios2_onchip_leg_push_button.c / C

clip_image008

1 /*
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : nios2_onchip_led_push_button.c
5 Compiler : Nios II SBT 11.0
6 Description : test led, push_button & interrupt in subsystem
7 Release : Jan.06,2012 1.0
8 */
9
10 #include <stdio.h>
11 #include "system.h"
12 #include "alt_types.h"
13 #include "sys/alt_irq.h"
14 #include "altera_avalon_pio_regs.h"
15
16 volatile int edge_capture;
17
18 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
19 void handle_key_interrupts(void *context) {
20 #else
21 void handle_key_interrupts(void *context, alt_u32 id) {
22 #endif
23
24 volatile int *edge_capture_ptr = (volatile int*)context;
25 *edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(PERIPHERAL_SYSTEM_BUTTON_PIO_BASE);
26 IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PERIPHERAL_SYSTEM_BUTTON_PIO_BASE, 0);
27
28 if (edge_capture == 0x01) {
29 printf("key 1 pressed!\n");
30 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xFE);
31 edge_capture = 0x00;
32 }
33 else if (edge_capture == 0x02) {
34 printf("key 2 pressed\n");
35 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xFD);
36 edge_capture = 0x00;
37 }
38 else if (edge_capture == 0x04) {
39 printf("key 3 pressed\n");
40 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xFB);
41 edge_capture = 0x00;
42 }
43 else if (edge_capture == 0x08) {
44 printf("key 4 pressed\n");
45 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xF7);
46 edge_capture = 0x00;
47 }
48 else if (edge_capture == 0x10) {
49 printf("key 5 pressed\n");
50 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xEF);
51 edge_capture = 0x00;
52 }
53 else if (edge_capture == 0x20) {
54 printf("key 6 pressed\n");
55 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xDF);
56 edge_capture = 0x00;
57 }
58 else if (edge_capture == 0x40) {
59 printf("key 7 pressed\n");
60 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xBF);
61 edge_capture = 0x00;
62 }
63 else if (edge_capture == 0x80) {
64 printf("key 8 pressed\n");
65 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0x7F);
66 edge_capture = 0x00;
67 }
68 }
69
70
71 void init_key() {
72 void *edge_capture_ptr = (void *)&edge_capture;
73 IOWR_ALTERA_AVALON_PIO_IRQ_MASK(PERIPHERAL_SYSTEM_BUTTON_PIO_BASE, 0xFF);
74 IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PERIPHERAL_SYSTEM_BUTTON_PIO_BASE, 0x0);
75
76 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
77 alt_ic_isr_register(PERIPHERAL_SYSTEM_BUTTON_PIO_IRQ_INTERRUPT_CONTROLLER_ID,
78 PERIPHERAL_SYSTEM_BUTTON_PIO_IRQ,
79 handle_key_interrupts,
80 edge_capture_ptr,
81 0x0);
82 #else
83
84 alt_irq_register(PERIPHERAL_SYSTEM_BUTTON_PIO_IRQ,
85 edge_capture_ptr,
86 handle_key_interrupts);
87 #endif
88 }
89
90
91 int main() {
92 printf("Nios II + Onchip + LED + Push Button Test!\n");
93
94 init_key();
95
96 while(1);
97
98 return 0;
99 }

clip_image008[1]

以上的code我不打算一行一行讲解,详细请参考[4] Exception Handling p.8-16与p.8-17,我要强调的是,一般在使用interrupt时,Altera都会建议你使用新的alt_ic_isr_register(),而不要使用旧的alt_irq_register(),并且说未来Nios II SBT版本将只支持alt_ic_isr_register(),若在只有一层Qsys的system下,可以使用alt_ic_isr_register()没有问题,但在具有Qsys subsystem下使用interrupt时,若使用alt_ic_isr_register()将会造成编译错误,会说找不到alt_ic_isr_register(),为什么会这样呢?

在一般只有一层Qsys system,在system.h可以看到#define ALT_ENHANCED_INTERRUPT_API_PRESENT,如下图所示:

clip_image009

但在使用Qsys subsystem的system.h下,看不到#define ALT_ENHANCED_INTERRUPT_API_PRESENT

clip_image010

在BSP的

sys/alt_irq.h / C

clip_image008[2]

1 #ifndef __ALT_IRQ_H__
2 #define __ALT_IRQ_H__
3
4 /******************************************************************************
5 * *
6 * License Agreement *
7 * *
8 * Copyright (c) 2009 Altera Corporation, San Jose, California, USA. *
9 * All rights reserved. *
10 * *
11 * Permission is hereby granted, free of charge, to any person obtaining a *
12 * copy of this software and associated documentation files (the "Software"), *
13 * to deal in the Software without restriction, including without limitation *
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
15 * and/or sell copies of the Software, and to permit persons to whom the *
16 * Software is furnished to do so, subject to the following conditions: *
17 * *
18 * The above copyright notice and this permission notice shall be included in *
19 * all copies or substantial portions of the Software. *
20 * *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
27 * DEALINGS IN THE SOFTWARE. *
28 * *
29 * This agreement shall be governed in all respects by the laws of the State *
30 * of California and by the laws of the United States of America. *
31 * *
32 ******************************************************************************/
33
34 /*
35 * alt_irq.h is the Nios II specific implementation of the interrupt controller
36 * interface.
37 *
38 * Nios II includes optional support for an external interrupt controller.
39 * When an external controller is present, the "Enhanced" interrupt API
40 * must be used to manage individual interrupts. The enhanced API also
41 * supports the processor's internal interrupt controller. Certain API
42 * members are accessible from either the "legacy" or "enhanced" interrpt
43 * API.
44 *
45 * Regardless of which API is in use, this file should be included by
46 * application code and device drivers that register ISRs or manage interrpts.
47 */
48 #include <errno.h>
49
50 #include "nios2.h"
51 #include "alt_types.h"
52 #include "system.h"
53
54 #ifdef __cplusplus
55 extern "C"
56 {
57 #endif /* __cplusplus */
58
59 /*
60 * Macros used by alt_irq_enabled
61 */
62 #define ALT_IRQ_ENABLED 1
63 #define ALT_IRQ_DISABLED 0
64
65 /*
66 * Number of available interrupts in internal interrupt controller.
67 */
68 #define ALT_NIRQ NIOS2_NIRQ
69
70 /*
71 * Used by alt_irq_disable_all() and alt_irq_enable_all().
72 */
73 typedef int alt_irq_context;
74
75 /* ISR Prototype */
76 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
77 typedef void (*alt_isr_func)(void* isr_context);
78 #else
79 typedef void (*alt_isr_func)(void* isr_context, alt_u32 id);
80 #endif
81
82 /*
83 * The following protypes and routines are supported by both
84 * the enhanced and legacy interrupt APIs
85 */
86
87 /*
88 * alt_irq_enabled can be called to determine if the processor's global
89 * interrupt enable is asserted. The return value is zero if interrupts
90 * are disabled, and non-zero otherwise.
91 *
92 * Whether the internal or external interrupt controller is present,
93 * individual interrupts may still be disabled. Use the other API to query
94 * a specific interrupt.
95 */
96 static ALT_INLINE int ALT_ALWAYS_INLINE alt_irq_enabled (void)
97 {
98 int status;
99
100 NIOS2_READ_STATUS (status);
101
102 return status & NIOS2_STATUS_PIE_MSK;
103 }
104
105 /*
106 * alt_irq_disable_all()
107 *
108 * This routine inhibits all interrupts by negating the status register PIE
109 * bit. It returns the previous contents of the CPU status register (IRQ
110 * context) which can be used to restore the status register PIE bit to its
111 * state before this routine was called.
112 */
113 static ALT_INLINE alt_irq_context ALT_ALWAYS_INLINE
114 alt_irq_disable_all (void)
115 {
116 alt_irq_context context;
117
118 NIOS2_READ_STATUS (context);
119
120 NIOS2_WRITE_STATUS (context & ~NIOS2_STATUS_PIE_MSK);
121
122 return context;
123 }
124
125 /*
126 * alt_irq_enable_all()
127 *
128 * Enable all interrupts that were previously disabled by alt_irq_disable_all()
129 *
130 * This routine accepts a context to restore the CPU status register PIE bit
131 * to the state prior to a call to alt_irq_disable_all().
132
133 * In the case of nested calls to alt_irq_disable_all()/alt_irq_enable_all(),
134 * this means that alt_irq_enable_all() does not necessarily re-enable
135 * interrupts.
136 *
137 * This routine will perform a read-modify-write sequence to restore only
138 * status.PIE if the processor is configured with options that add additional
139 * writeable status register bits. These include the MMU, MPU, the enhanced
140 * interrupt controller port, and shadow registers. Otherwise, as a performance
141 * enhancement, status is overwritten with the prior context.
142 */
143 static ALT_INLINE void ALT_ALWAYS_INLINE
144 alt_irq_enable_all (alt_irq_context context)
145 {
146 #if (NIOS2_NUM_OF_SHADOW_REG_SETS > 0) || (defined NIOS2_EIC_PRESENT) || \
147 (defined NIOS2_MMU_PRESENT) || (defined NIOS2_MPU_PRESENT)
148 alt_irq_context status;
149
150 NIOS2_READ_STATUS (status);
151
152 status &= ~NIOS2_STATUS_PIE_MSK;
153 status |= (context & NIOS2_STATUS_PIE_MSK);
154
155 NIOS2_WRITE_STATUS (status);
156 #else
157 NIOS2_WRITE_STATUS (context);
158 #endif
159 }
160
161 /*
162 * The function alt_irq_init() is defined within the auto-generated file
163 * alt_sys_init.c. This function calls the initilization macros for all
164 * interrupt controllers in the system at config time, before any other
165 * non-interrupt controller driver is initialized.
166 *
167 * The "base" parameter is ignored and only present for backwards-compatibility.
168 * It is recommended that NULL is passed in for the "base" parameter.
169 */
170 extern void alt_irq_init (const void* base);
171
172 /*
173 * alt_irq_cpu_enable_interrupts() enables the CPU to start taking interrupts.
174 */
175 static ALT_INLINE void ALT_ALWAYS_INLINE
176 alt_irq_cpu_enable_interrupts ()
177 {
178 NIOS2_WRITE_STATUS(NIOS2_STATUS_PIE_MSK
179 #if defined(NIOS2_EIC_PRESENT) && (NIOS2_NUM_OF_SHADOW_REG_SETS > 0)
180 | NIOS2_STATUS_RSIE_MSK
181 #endif
182 );
183 }
184
185
186 /*
187 * Prototypes for the enhanced interrupt API.
188 */
189 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
190 /*
191 * alt_ic_isr_register() can be used to register an interrupt handler. If the
192 * function is succesful, then the requested interrupt will be enabled upon
193 * return.
194 */
195 extern int alt_ic_isr_register(alt_u32 ic_id,
196 alt_u32 irq,
197 alt_isr_func isr,
198 void *isr_context,
199 void *flags);
200
201 /*
202 * alt_ic_irq_enable() and alt_ic_irq_disable() enable/disable a specific
203 * interrupt by using IRQ port and interrupt controller instance.
204 */
205 int alt_ic_irq_enable (alt_u32 ic_id, alt_u32 irq);
206 int alt_ic_irq_disable(alt_u32 ic_id, alt_u32 irq);
207
208 /*
209 * alt_ic_irq_enabled() indicates whether a specific interrupt, as
210 * specified by IRQ port and interrupt controller instance is enabled.
211 */
212 alt_u32 alt_ic_irq_enabled(alt_u32 ic_id, alt_u32 irq);
213
214 #else
215 /*
216 * Prototypes for the legacy interrupt API.
217 */
218 #include "priv/alt_legacy_irq.h"
219 #endif
220
221
222 /*
223 * alt_irq_pending() returns a bit list of the current pending interrupts.
224 * This is used by alt_irq_handler() to determine which registered interrupt
225 * handlers should be called.
226 *
227 * This routine is only available for the Nios II internal interrupt
228 * controller.
229 */
230 #ifndef NIOS2_EIC_PRESENT
231 static ALT_INLINE alt_u32 ALT_ALWAYS_INLINE alt_irq_pending (void)
232 {
233 alt_u32 active;
234
235 NIOS2_READ_IPENDING (active);
236
237 return active;
238 }
239 #endif
240
241 #ifdef __cplusplus
242 }
243 #endif /* __cplusplus */
244
245 #endif /* __ALT_IRQ_H__ */

clip_image008[3]

186行

clip_image008[4]

1 /*
2 * Prototypes for the enhanced interrupt API.
3 */
4 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
5 /*
6 * alt_ic_isr_register() can be used to register an interrupt handler. If the
7 * function is succesful, then the requested interrupt will be enabled upon
8 * return.
9 */
10 extern int alt_ic_isr_register(alt_u32 ic_id,
11 alt_u32 irq,
12 alt_isr_func isr,
13 void *isr_context,
14 void *flags);
15
16 /*
17 * alt_ic_irq_enable() and alt_ic_irq_disable() enable/disable a specific
18 * interrupt by using IRQ port and interrupt controller instance.
19 */
20 int alt_ic_irq_enable (alt_u32 ic_id, alt_u32 irq);
21 int alt_ic_irq_disable(alt_u32 ic_id, alt_u32 irq);
22
23 /*
24 * alt_ic_irq_enabled() indicates whether a specific interrupt, as
25 * specified by IRQ port and interrupt controller instance is enabled.
26 */
27 alt_u32 alt_ic_irq_enabled(alt_u32 ic_id, alt_u32 irq);
28
29 #else
30 /*
31 * Prototypes for the legacy interrupt API.
32 */
33 #include "priv/alt_legacy_irq.h"
34 #endif

clip_image008[5]

我们可以发现,当system.h有定义ALT_ENHANCED_INTERRUPT_API_PRESENT常数时,就有alt_ic_isr_register()可用,若没定义,则#inlclude priv/alt_legacy_irq.h

alt_legacy_irq.h / C

clip_image008[6]

1 #ifndef __ALT_LEGACY_IRQ_H__
2 #define __ALT_LEGACY_IRQ_H__
3
4 /******************************************************************************
5 * *
6 * License Agreement *
7 * *
8 * Copyright (c) 2009 Altera Corporation, San Jose, California, USA. *
9 * All rights reserved. *
10 * *
11 * Permission is hereby granted, free of charge, to any person obtaining a *
12 * copy of this software and associated documentation files (the "Software"), *
13 * to deal in the Software without restriction, including without limitation *
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
15 * and/or sell copies of the Software, and to permit persons to whom the *
16 * Software is furnished to do so, subject to the following conditions: *
17 * *
18 * The above copyright notice and this permission notice shall be included in *
19 * all copies or substantial portions of the Software. *
20 * *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
27 * DEALINGS IN THE SOFTWARE. *
28 * *
29 * This agreement shall be governed in all respects by the laws of the State *
30 * of California and by the laws of the United States of America. *
31 * *
32 ******************************************************************************/
33
34 /*
35 * This file provides prototypes and inline implementations of certain routines
36 * used by the legacy interrupt API. Do not include this in your driver or
37 * application source files, use "sys/alt_irq.h" instead to access the proper
38 * public API.
39 */
40
41 #include <errno.h>
42 #include "system.h"
43
44 #ifndef NIOS2_EIC_PRESENT
45
46 #include "nios2.h"
47 #include "alt_types.h"
48
49 #include "sys/alt_irq.h"
50
51 #ifdef __cplusplus
52 extern "C"
53 {
54 #endif /* __cplusplus */
55
56 /*
57 * alt_irq_register() can be used to register an interrupt handler. If the
58 * function is succesful, then the requested interrupt will be enabled upon
59 * return.
60 */
61 extern int alt_irq_register (alt_u32 id,
62 void* context,
63 alt_isr_func handler);
64
65 /*
66 * alt_irq_disable() disables the individual interrupt indicated by "id".
67 */
68 static ALT_INLINE int ALT_ALWAYS_INLINE alt_irq_disable (alt_u32 id)
69 {
70 alt_irq_context status;
71 extern volatile alt_u32 alt_irq_active;
72
73 status = alt_irq_disable_all ();
74
75 alt_irq_active &= ~(1 << id);
76 NIOS2_WRITE_IENABLE (alt_irq_active);
77
78 alt_irq_enable_all(status);
79
80 return 0;
81 }
82
83 /*
84 * alt_irq_enable() enables the individual interrupt indicated by "id".
85 */
86 static ALT_INLINE int ALT_ALWAYS_INLINE alt_irq_enable (alt_u32 id)
87 {
88 alt_irq_context status;
89 extern volatile alt_u32 alt_irq_active;
90
91 status = alt_irq_disable_all ();
92
93 alt_irq_active |= (1 << id);
94 NIOS2_WRITE_IENABLE (alt_irq_active);
95
96 alt_irq_enable_all(status);
97
98 return 0;
99 }
100
101 #ifndef ALT_EXCEPTION_STACK
102 /*
103 * alt_irq_initerruptable() should only be called from within an ISR. It is used
104 * to allow higer priority interrupts to interrupt the current ISR. The input
105 * argument, "priority", is the priority, i.e. interrupt number of the current
106 * interrupt.
107 *
108 * If this function is called, then the ISR is required to make a call to
109 * alt_irq_non_interruptible() before returning. The input argument to
110 * alt_irq_non_interruptible() is the return value from alt_irq_interruptible().
111 *
112 * Care should be taken when using this pair of functions, since they increasing
113 * the system overhead associated with interrupt handling.
114 *
115 * If you are using an exception stack then nested interrupts won't work, so
116 * these functions are not available in that case.
117 */
118 static ALT_INLINE alt_u32 ALT_ALWAYS_INLINE alt_irq_interruptible (alt_u32 priority)
119 {
120 extern volatile alt_u32 alt_priority_mask;
121 extern volatile alt_u32 alt_irq_active;
122
123 alt_u32 old_priority;
124
125 old_priority = alt_priority_mask;
126 alt_priority_mask = (1 << priority) - 1;
127
128 NIOS2_WRITE_IENABLE (alt_irq_active & alt_priority_mask);
129
130 NIOS2_WRITE_STATUS (1);
131
132 return old_priority;
133 }
134
135 /*
136 * See Comments above for alt_irq_interruptible() for an explanation of the use of this
137 * function.
138 */
139 static ALT_INLINE void ALT_ALWAYS_INLINE alt_irq_non_interruptible (alt_u32 mask)
140 {
141 extern volatile alt_u32 alt_priority_mask;
142 extern volatile alt_u32 alt_irq_active;
143
144 NIOS2_WRITE_STATUS (0);
145
146 alt_priority_mask = mask;
147
148 NIOS2_WRITE_IENABLE (mask & alt_irq_active);
149 }
150 #endif /* ALT_EXCEPTION_STACK */
151
152 #ifdef __cplusplus
153 }
154 #endif /* __cplusplus */
155
156 #endif /* NIOS2_EIC_PRESENT */
157
158 #endif /* __ALT_LEGACY_IRQ_H__ */

clip_image008[7]

61行

extern int alt_irq_register (alt_u32 id,
void* context,
alt_isr_func handler);

则是我们所用旧的alt_irq_register()。

至于ISR的prototype新旧不一样,trace的方式也一样,就不再赘述。

至于为什么目前在subsystem的interrupt只能使用旧的ISR register方式,我并不清楚,或许Quartus II未来版本会有所改变。

使用以上方法后,就可正确的在App project收到subsystem的interrupt了。

clip_image011

Conclusion
我们在本文看到了Qsys与SOPC Builder在subsystem与interrupt的处理有很大的差异,也看到了目前Qsys与Nios II SBT尚有些bug待修正。目前Quartus II 11.0与Quartus II 11.1都还有system.h的bug,相信未来的版本一定会修正这个问题。假如你现在要在subsystem使用interrupt,可暂时使用本文的方式当作short term solution。

Reference
[1] Qsys Interconnect
[2] Quartus II 11.0 Release Notes
[3] Altera Wiki : New Qsys Issues for Interrupts
[4] Exception Handling

全文完。