1 |
517 |
julius |
/* or1k-support - OR1K CPU support functions
|
2 |
|
|
|
3 |
|
|
Copyright (C) 2011, ORSoC AB
|
4 |
|
|
|
5 |
|
|
Contributor Julius Baxter
|
6 |
|
|
|
7 |
|
|
This file is part of Newlib.
|
8 |
|
|
|
9 |
|
|
This program is free software; you can redistribute it and/or modify it
|
10 |
|
|
under the terms of the GNU General Public License as published by the Free
|
11 |
|
|
Software Foundation; either version 3 of the License, or (at your option)
|
12 |
|
|
any later version.
|
13 |
|
|
|
14 |
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
15 |
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
16 |
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
17 |
|
|
more details.
|
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU General Public License along
|
20 |
|
|
with this program. If not, see . */
|
21 |
|
|
|
22 |
|
|
#include "spr-defs.h"
|
23 |
|
|
|
24 |
|
|
/* -------------------------------------------------------------------------- */
|
25 |
|
|
/*!Function to control MMU
|
26 |
|
|
*/
|
27 |
|
|
/* -------------------------------------------------------------------------- */
|
28 |
|
|
|
29 |
|
|
/* MMU control functions always switch MMU control with a l.rfe to return
|
30 |
|
|
from function */
|
31 |
|
|
.section .text
|
32 |
|
|
|
33 |
|
|
.global or1k_dmmu_enable
|
34 |
|
|
or1k_dmmu_enable:
|
35 |
|
|
l.mfspr r3,r0,SPR_SR
|
36 |
|
|
l.ori r3,r3,SPR_SR_DME
|
37 |
|
|
l.mtspr r0,r3,SPR_ESR_BASE
|
38 |
|
|
l.mtspr r0,r9,SPR_EPCR_BASE
|
39 |
|
|
l.rfe
|
40 |
|
|
l.nop
|
41 |
|
|
|
42 |
|
|
|
43 |
|
|
.global or1k_dmmu_disable
|
44 |
|
|
or1k_dmmu_disable:
|
45 |
|
|
l.ori r3,r0,SPR_SR_DME
|
46 |
|
|
l.xori r4,r3,0xffff
|
47 |
|
|
l.mfspr r3,r0,SPR_SR
|
48 |
|
|
l.and r3,r4,r3
|
49 |
|
|
l.mtspr r0,r3,SPR_ESR_BASE
|
50 |
|
|
l.mtspr r0,r9,SPR_EPCR_BASE
|
51 |
|
|
l.rfe
|
52 |
|
|
l.nop
|
53 |
|
|
|
54 |
|
|
|
55 |
|
|
.global or1k_immu_enable
|
56 |
|
|
or1k_immu_enable:
|
57 |
|
|
l.mfspr r3,r0,SPR_SR
|
58 |
|
|
l.ori r3,r3,SPR_SR_IME
|
59 |
|
|
l.mtspr r0,r3,SPR_ESR_BASE
|
60 |
|
|
l.mtspr r0,r9,SPR_EPCR_BASE
|
61 |
|
|
l.rfe
|
62 |
|
|
l.nop
|
63 |
|
|
|
64 |
|
|
.global or1k_immu_disable
|
65 |
|
|
or1k_immu_disable:
|
66 |
|
|
l.ori r3,r0,SPR_SR_IME
|
67 |
|
|
l.xori r4,r3,0xffff
|
68 |
|
|
l.mfspr r3,r0,SPR_SR
|
69 |
|
|
l.and r3,r4,r3
|
70 |
|
|
l.mtspr r0,r3,SPR_ESR_BASE
|
71 |
|
|
l.mtspr r0,r9,SPR_EPCR_BASE
|
72 |
|
|
l.rfe
|
73 |
|
|
l.nop
|
74 |
|
|
|
75 |
|
|
|
76 |
|
|
|
77 |
|
|
|
78 |
|
|
/* -------------------------------------------------------------------------- */
|
79 |
|
|
/*!Function used at reset to clear and enable all caches
|
80 |
|
|
*/
|
81 |
|
|
/* -------------------------------------------------------------------------- */
|
82 |
|
|
.global or1k_cache_init
|
83 |
|
|
.type or1k_cache_init,@function
|
84 |
|
|
|
85 |
|
|
or1k_cache_init:
|
86 |
|
|
/* Instruction cache enable */
|
87 |
|
|
/* Check if IC present and skip enabling otherwise */
|
88 |
|
|
.L6: l.mfspr r3,r0,SPR_UPR
|
89 |
|
|
l.andi r4,r3,SPR_UPR_ICP
|
90 |
|
|
l.sfeq r4,r0
|
91 |
|
|
l.bf .L8
|
92 |
|
|
l.nop
|
93 |
|
|
|
94 |
|
|
/* Disable IC */
|
95 |
|
|
l.mfspr r6,r0,SPR_SR
|
96 |
|
|
l.addi r5,r0,-1
|
97 |
|
|
l.xori r5,r5,SPR_SR_ICE
|
98 |
|
|
l.and r5,r6,r5
|
99 |
|
|
l.mtspr r0,r5,SPR_SR
|
100 |
|
|
|
101 |
|
|
/* Establish cache block size
|
102 |
|
|
If BS=0, 16;
|
103 |
|
|
If BS=1, 32;
|
104 |
|
|
r14 contain block size
|
105 |
|
|
*/
|
106 |
|
|
l.mfspr r3,r0,SPR_ICCFGR
|
107 |
|
|
l.andi r4,r3,SPR_ICCFGR_CBS
|
108 |
|
|
l.srli r7,r4,7
|
109 |
|
|
l.ori r8,r0,16
|
110 |
|
|
l.sll r14,r8,r7
|
111 |
|
|
|
112 |
|
|
/* Establish number of cache sets
|
113 |
|
|
r13 contains number of cache sets
|
114 |
|
|
r7 contains log(# of cache sets)
|
115 |
|
|
*/
|
116 |
|
|
l.andi r4,r3,SPR_ICCFGR_NCS
|
117 |
|
|
l.srli r7,r4,3
|
118 |
|
|
l.ori r8,r0,1
|
119 |
|
|
l.sll r13,r8,r7
|
120 |
|
|
|
121 |
|
|
/* Invalidate IC */
|
122 |
|
|
l.addi r6,r0,0
|
123 |
|
|
l.sll r5,r14,r7
|
124 |
|
|
|
125 |
|
|
.L7: l.mtspr r0,r6,SPR_ICBIR
|
126 |
|
|
l.sfne r6,r5
|
127 |
|
|
l.bf .L7
|
128 |
|
|
l.add r6,r6,r14
|
129 |
|
|
|
130 |
|
|
/* Enable IC */
|
131 |
|
|
l.mfspr r6,r0,SPR_SR
|
132 |
|
|
l.ori r6,r6,SPR_SR_ICE
|
133 |
|
|
l.mtspr r0,r6,SPR_SR
|
134 |
|
|
l.nop
|
135 |
|
|
l.nop
|
136 |
|
|
l.nop
|
137 |
|
|
l.nop
|
138 |
|
|
l.nop
|
139 |
|
|
l.nop
|
140 |
|
|
l.nop
|
141 |
|
|
l.nop
|
142 |
|
|
|
143 |
|
|
/* Data cache enable */
|
144 |
|
|
/* Check if DC present and skip enabling otherwise */
|
145 |
|
|
.L8: l.mfspr r3,r0,SPR_UPR
|
146 |
|
|
l.andi r4,r3,SPR_UPR_DCP
|
147 |
|
|
l.sfeq r4,r0
|
148 |
|
|
l.bf .L10
|
149 |
|
|
l.nop
|
150 |
|
|
/* Disable DC */
|
151 |
|
|
l.mfspr r6,r0,SPR_SR
|
152 |
|
|
l.addi r5,r0,-1
|
153 |
|
|
l.xori r5,r5,SPR_SR_DCE
|
154 |
|
|
l.and r5,r6,r5
|
155 |
|
|
l.mtspr r0,r5,SPR_SR
|
156 |
|
|
/* Establish cache block size
|
157 |
|
|
If BS=0, 16;
|
158 |
|
|
If BS=1, 32;
|
159 |
|
|
r14 contain block size
|
160 |
|
|
*/
|
161 |
|
|
l.mfspr r3,r0,SPR_DCCFGR
|
162 |
|
|
l.andi r4,r3,SPR_DCCFGR_CBS
|
163 |
|
|
l.srli r7,r4,7
|
164 |
|
|
l.ori r8,r0,16
|
165 |
|
|
l.sll r14,r8,r7
|
166 |
|
|
/* Establish number of cache sets
|
167 |
|
|
r13 contains number of cache sets
|
168 |
|
|
r7 contains log(# of cache sets)
|
169 |
|
|
*/
|
170 |
|
|
l.andi r4,r3,SPR_DCCFGR_NCS
|
171 |
|
|
l.srli r7,r4,3
|
172 |
|
|
l.ori r8,r0,1
|
173 |
|
|
l.sll r13,r8,r7
|
174 |
|
|
/* Invalidate DC */
|
175 |
|
|
l.addi r6,r0,0
|
176 |
|
|
l.sll r5,r14,r7
|
177 |
|
|
|
178 |
|
|
.L9: l.mtspr r0,r6,SPR_DCBIR
|
179 |
|
|
l.sfne r6,r5
|
180 |
|
|
l.bf .L9
|
181 |
|
|
l.add r6,r6,r14
|
182 |
|
|
/* Enable DC */
|
183 |
|
|
l.mfspr r6,r0,SPR_SR
|
184 |
|
|
l.ori r6,r6,SPR_SR_DCE
|
185 |
|
|
l.mtspr r0,r6,SPR_SR
|
186 |
|
|
|
187 |
|
|
.L10:
|
188 |
|
|
/* Return */
|
189 |
|
|
l.jr r9
|
190 |
|
|
l.nop
|
191 |
|
|
|
192 |
|
|
/* -------------------------------------------------------------------------- */
|
193 |
|
|
/*!Function to enable instruction cache
|
194 |
|
|
*/
|
195 |
|
|
/* -------------------------------------------------------------------------- */
|
196 |
|
|
|
197 |
|
|
.global or1k_icache_enable
|
198 |
|
|
.type or1k_icache_enable,@function
|
199 |
|
|
|
200 |
|
|
or1k_icache_enable:
|
201 |
|
|
/* Enable IC */
|
202 |
|
|
l.mfspr r13,r0,SPR_SR
|
203 |
|
|
l.ori r13,r13,SPR_SR_ICE
|
204 |
|
|
l.mtspr r0,r13,SPR_SR
|
205 |
|
|
l.nop
|
206 |
|
|
l.nop
|
207 |
|
|
l.nop
|
208 |
|
|
l.nop
|
209 |
|
|
l.nop
|
210 |
|
|
l.jr r9
|
211 |
|
|
l.nop
|
212 |
|
|
|
213 |
|
|
/* -------------------------------------------------------------------------- */
|
214 |
|
|
/*!Function to disable instruction cache
|
215 |
|
|
*/
|
216 |
|
|
/* -------------------------------------------------------------------------- */
|
217 |
|
|
.global or1k_icache_disable
|
218 |
|
|
.type or1k_icache_disable,@function
|
219 |
|
|
|
220 |
551 |
yannv |
or1k_icache_disable:
|
221 |
517 |
julius |
/* Disable IC */
|
222 |
|
|
l.mfspr r13,r0,SPR_SR
|
223 |
|
|
l.addi r12,r0,-1
|
224 |
|
|
l.xori r12,r12,SPR_SR_ICE
|
225 |
|
|
l.and r12,r13,r12
|
226 |
|
|
l.mtspr r0,r12,SPR_SR
|
227 |
|
|
l.jr r9
|
228 |
|
|
l.nop
|
229 |
|
|
|
230 |
|
|
/* -------------------------------------------------------------------------- */
|
231 |
|
|
/*!Function to flush address of instruction cache
|
232 |
|
|
*/
|
233 |
|
|
/* -------------------------------------------------------------------------- */
|
234 |
|
|
.global or1k_icache_flush
|
235 |
|
|
.type or1k_icache_flush,@function
|
236 |
|
|
|
237 |
|
|
or1k_icache_flush:
|
238 |
|
|
/* Push r3 into IC invalidate reg */
|
239 |
|
|
l.jr r9
|
240 |
|
|
l.mtspr r0,r3,SPR_ICBIR
|
241 |
|
|
|
242 |
|
|
|
243 |
|
|
/* -------------------------------------------------------------------------- */
|
244 |
|
|
/*!Function to enable data cache
|
245 |
|
|
*/
|
246 |
|
|
/* -------------------------------------------------------------------------- */
|
247 |
|
|
.global or1k_dcache_enable
|
248 |
|
|
.type or1k_dcache_enable,@function
|
249 |
|
|
|
250 |
|
|
or1k_dcache_enable:
|
251 |
|
|
/* Enable DC */
|
252 |
|
|
l.mfspr r13,r0,SPR_SR
|
253 |
|
|
l.ori r13,r13,SPR_SR_DCE
|
254 |
|
|
l.mtspr r0,r13,SPR_SR
|
255 |
|
|
l.nop
|
256 |
|
|
l.nop
|
257 |
|
|
l.nop
|
258 |
|
|
l.nop
|
259 |
|
|
l.nop
|
260 |
|
|
l.jr r9
|
261 |
|
|
l.nop
|
262 |
|
|
|
263 |
|
|
/* -------------------------------------------------------------------------- */
|
264 |
|
|
/*!Function to disable data cache
|
265 |
|
|
*/
|
266 |
|
|
/* -------------------------------------------------------------------------- */
|
267 |
|
|
.global or1k_dcache_disable
|
268 |
|
|
.type or1k_dcache_disable,@function
|
269 |
|
|
|
270 |
551 |
yannv |
or1k_dcache_disable:
|
271 |
517 |
julius |
/* Disable DC */
|
272 |
|
|
l.mfspr r13,r0,SPR_SR
|
273 |
|
|
l.addi r12,r0,-1
|
274 |
|
|
l.xori r12,r12,SPR_SR_DCE
|
275 |
|
|
l.and r12,r13,r12
|
276 |
|
|
l.mtspr r0,r12,SPR_SR
|
277 |
|
|
l.jr r9
|
278 |
|
|
l.nop
|
279 |
|
|
|
280 |
|
|
/* -------------------------------------------------------------------------- */
|
281 |
|
|
/*!Function to flush address of data cache
|
282 |
|
|
*/
|
283 |
|
|
/* -------------------------------------------------------------------------- */
|
284 |
|
|
.global or1k_dcache_flush
|
285 |
|
|
.type or1k_dcache_flush,@function
|
286 |
|
|
|
287 |
|
|
or1k_dcache_flush:
|
288 |
|
|
/* Push r3 into DC invalidate reg */
|
289 |
|
|
l.jr r9
|
290 |
|
|
l.mtspr r0,r3,SPR_DCBIR
|
291 |
|
|
|
292 |
|
|
|
293 |
|
|
|
294 |
|
|
|
295 |
|
|
/* -------------------------------------------------------------------------- */
|
296 |
|
|
/*!Generic interrupt handler function for or1k
|
297 |
|
|
*/
|
298 |
|
|
/* -------------------------------------------------------------------------- */
|
299 |
|
|
|
300 |
|
|
#define INTERRUPT_HANDLER_NOT_SET -1
|
301 |
|
|
|
302 |
|
|
.data
|
303 |
|
|
.align 4
|
304 |
|
|
.global or1k_interrupt_handler_table
|
305 |
|
|
or1k_interrupt_handler_table:
|
306 |
|
|
or1k_interrupt_handler0: .long INTERRUPT_HANDLER_NOT_SET
|
307 |
|
|
or1k_interrupt_handler1: .long INTERRUPT_HANDLER_NOT_SET
|
308 |
|
|
or1k_interrupt_handler2: .long INTERRUPT_HANDLER_NOT_SET
|
309 |
|
|
or1k_interrupt_handler3: .long INTERRUPT_HANDLER_NOT_SET
|
310 |
|
|
or1k_interrupt_handler4: .long INTERRUPT_HANDLER_NOT_SET
|
311 |
|
|
or1k_interrupt_handler5: .long INTERRUPT_HANDLER_NOT_SET
|
312 |
|
|
or1k_interrupt_handler6: .long INTERRUPT_HANDLER_NOT_SET
|
313 |
|
|
or1k_interrupt_handler7: .long INTERRUPT_HANDLER_NOT_SET
|
314 |
|
|
or1k_interrupt_handler8: .long INTERRUPT_HANDLER_NOT_SET
|
315 |
|
|
or1k_interrupt_handler9: .long INTERRUPT_HANDLER_NOT_SET
|
316 |
|
|
or1k_interrupt_handler10: .long INTERRUPT_HANDLER_NOT_SET
|
317 |
|
|
or1k_interrupt_handler11: .long INTERRUPT_HANDLER_NOT_SET
|
318 |
|
|
or1k_interrupt_handler12: .long INTERRUPT_HANDLER_NOT_SET
|
319 |
|
|
or1k_interrupt_handler13: .long INTERRUPT_HANDLER_NOT_SET
|
320 |
|
|
or1k_interrupt_handler14: .long INTERRUPT_HANDLER_NOT_SET
|
321 |
|
|
or1k_interrupt_handler15: .long INTERRUPT_HANDLER_NOT_SET
|
322 |
|
|
or1k_interrupt_handler16: .long INTERRUPT_HANDLER_NOT_SET
|
323 |
|
|
or1k_interrupt_handler17: .long INTERRUPT_HANDLER_NOT_SET
|
324 |
|
|
or1k_interrupt_handler18: .long INTERRUPT_HANDLER_NOT_SET
|
325 |
|
|
or1k_interrupt_handler19: .long INTERRUPT_HANDLER_NOT_SET
|
326 |
|
|
or1k_interrupt_handler20: .long INTERRUPT_HANDLER_NOT_SET
|
327 |
|
|
or1k_interrupt_handler21: .long INTERRUPT_HANDLER_NOT_SET
|
328 |
|
|
or1k_interrupt_handler22: .long INTERRUPT_HANDLER_NOT_SET
|
329 |
|
|
or1k_interrupt_handler23: .long INTERRUPT_HANDLER_NOT_SET
|
330 |
|
|
or1k_interrupt_handler24: .long INTERRUPT_HANDLER_NOT_SET
|
331 |
|
|
or1k_interrupt_handler25: .long INTERRUPT_HANDLER_NOT_SET
|
332 |
|
|
or1k_interrupt_handler26: .long INTERRUPT_HANDLER_NOT_SET
|
333 |
|
|
or1k_interrupt_handler27: .long INTERRUPT_HANDLER_NOT_SET
|
334 |
|
|
or1k_interrupt_handler28: .long INTERRUPT_HANDLER_NOT_SET
|
335 |
|
|
or1k_interrupt_handler29: .long INTERRUPT_HANDLER_NOT_SET
|
336 |
|
|
or1k_interrupt_handler30: .long INTERRUPT_HANDLER_NOT_SET
|
337 |
|
|
or1k_interrupt_handler31: .long INTERRUPT_HANDLER_NOT_SET
|
338 |
|
|
|
339 |
|
|
.global or1k_interrupt_handler_data_ptr_table
|
340 |
|
|
or1k_interrupt_handler_data_ptr_table:
|
341 |
|
|
or1k_interrupt_handler_data_ptr0: .long INTERRUPT_HANDLER_NOT_SET
|
342 |
|
|
or1k_interrupt_handler_data_ptr1: .long INTERRUPT_HANDLER_NOT_SET
|
343 |
|
|
or1k_interrupt_handler_data_ptr2: .long INTERRUPT_HANDLER_NOT_SET
|
344 |
|
|
or1k_interrupt_handler_data_ptr3: .long INTERRUPT_HANDLER_NOT_SET
|
345 |
|
|
or1k_interrupt_handler_data_ptr4: .long INTERRUPT_HANDLER_NOT_SET
|
346 |
|
|
or1k_interrupt_handler_data_ptr5: .long INTERRUPT_HANDLER_NOT_SET
|
347 |
|
|
or1k_interrupt_handler_data_ptr6: .long INTERRUPT_HANDLER_NOT_SET
|
348 |
|
|
or1k_interrupt_handler_data_ptr7: .long INTERRUPT_HANDLER_NOT_SET
|
349 |
|
|
or1k_interrupt_handler_data_ptr8: .long INTERRUPT_HANDLER_NOT_SET
|
350 |
|
|
or1k_interrupt_handler_data_ptr9: .long INTERRUPT_HANDLER_NOT_SET
|
351 |
|
|
or1k_interrupt_handler_data_ptr10: .long INTERRUPT_HANDLER_NOT_SET
|
352 |
|
|
or1k_interrupt_handler_data_ptr11: .long INTERRUPT_HANDLER_NOT_SET
|
353 |
|
|
or1k_interrupt_handler_data_ptr12: .long INTERRUPT_HANDLER_NOT_SET
|
354 |
|
|
or1k_interrupt_handler_data_ptr13: .long INTERRUPT_HANDLER_NOT_SET
|
355 |
|
|
or1k_interrupt_handler_data_ptr14: .long INTERRUPT_HANDLER_NOT_SET
|
356 |
|
|
or1k_interrupt_handler_data_ptr15: .long INTERRUPT_HANDLER_NOT_SET
|
357 |
|
|
or1k_interrupt_handler_data_ptr16: .long INTERRUPT_HANDLER_NOT_SET
|
358 |
|
|
or1k_interrupt_handler_data_ptr17: .long INTERRUPT_HANDLER_NOT_SET
|
359 |
|
|
or1k_interrupt_handler_data_ptr18: .long INTERRUPT_HANDLER_NOT_SET
|
360 |
|
|
or1k_interrupt_handler_data_ptr19: .long INTERRUPT_HANDLER_NOT_SET
|
361 |
|
|
or1k_interrupt_handler_data_ptr20: .long INTERRUPT_HANDLER_NOT_SET
|
362 |
|
|
or1k_interrupt_handler_data_ptr21: .long INTERRUPT_HANDLER_NOT_SET
|
363 |
|
|
or1k_interrupt_handler_data_ptr22: .long INTERRUPT_HANDLER_NOT_SET
|
364 |
|
|
or1k_interrupt_handler_data_ptr23: .long INTERRUPT_HANDLER_NOT_SET
|
365 |
|
|
or1k_interrupt_handler_data_ptr24: .long INTERRUPT_HANDLER_NOT_SET
|
366 |
|
|
or1k_interrupt_handler_data_ptr25: .long INTERRUPT_HANDLER_NOT_SET
|
367 |
|
|
or1k_interrupt_handler_data_ptr26: .long INTERRUPT_HANDLER_NOT_SET
|
368 |
|
|
or1k_interrupt_handler_data_ptr27: .long INTERRUPT_HANDLER_NOT_SET
|
369 |
|
|
or1k_interrupt_handler_data_ptr28: .long INTERRUPT_HANDLER_NOT_SET
|
370 |
|
|
or1k_interrupt_handler_data_ptr29: .long INTERRUPT_HANDLER_NOT_SET
|
371 |
|
|
or1k_interrupt_handler_data_ptr30: .long INTERRUPT_HANDLER_NOT_SET
|
372 |
|
|
or1k_interrupt_handler_data_ptr31: .long INTERRUPT_HANDLER_NOT_SET
|
373 |
|
|
|
374 |
|
|
|
375 |
|
|
/* -------------------------------------------------------------------------- */
|
376 |
|
|
/*!Function to call appropriate interrupt handler
|
377 |
|
|
*/
|
378 |
|
|
/* -------------------------------------------------------------------------- */
|
379 |
|
|
|
380 |
|
|
.section .text
|
381 |
|
|
.global or1k_interrupt_handler
|
382 |
|
|
.type or1k_interrupt_handler,@function
|
383 |
|
|
|
384 |
|
|
or1k_interrupt_handler:
|
385 |
|
|
/* Make room on stack, save link register */
|
386 |
|
|
l.addi r1,r1,-12
|
387 |
|
|
l.sw 0(r1),r9
|
388 |
|
|
|
389 |
|
|
/* Read PICSR */
|
390 |
|
|
l.mfspr r3,r0,SPR_PICSR
|
391 |
|
|
|
392 |
|
|
/* Load handler table base address */
|
393 |
|
|
l.movhi r7,hi(or1k_interrupt_handler_table)
|
394 |
|
|
l.ori r7,r7,lo(or1k_interrupt_handler_table)
|
395 |
|
|
/* Check to see if this handler has been set yet */
|
396 |
|
|
l.movhi r8,hi(INTERRUPT_HANDLER_NOT_SET)
|
397 |
|
|
l.ori r8,r8,lo(INTERRUPT_HANDLER_NOT_SET)
|
398 |
|
|
/* Load data pointer table base address */
|
399 |
|
|
l.movhi r12,hi(or1k_interrupt_handler_data_ptr_table)
|
400 |
|
|
l.ori r12,r12,lo(or1k_interrupt_handler_data_ptr_table)
|
401 |
|
|
|
402 |
|
|
.L0:
|
403 |
|
|
/* Find first set bit in PICSR */
|
404 |
|
|
l.ff1 r4,r3
|
405 |
|
|
/* Any bits set? */
|
406 |
|
|
l.sfne r4,r0
|
407 |
|
|
/* If none, finish */
|
408 |
|
|
l.bnf .L2
|
409 |
|
|
l.nop
|
410 |
|
|
/* What is IRQ function table offset? */
|
411 |
|
|
l.addi r5,r4,-1
|
412 |
|
|
l.slli r6,r5,2
|
413 |
|
|
/* Add this to table bases */
|
414 |
812 |
stekern |
l.add r14,r6,r7
|
415 |
517 |
julius |
l.add r13,r6,r12
|
416 |
|
|
|
417 |
|
|
/* Fetch handler function address */
|
418 |
812 |
stekern |
l.lwz r14,0(r14)
|
419 |
517 |
julius |
|
420 |
|
|
/* Double check it's valid, compare against INTERRUPT_HANDLER_NOT_SET */
|
421 |
812 |
stekern |
l.sfne r14,r8
|
422 |
517 |
julius |
/* Skip if no handler: TODO: Indicate interrupt fired but no handler*/
|
423 |
|
|
l.bnf .L1
|
424 |
|
|
l.nop
|
425 |
|
|
|
426 |
|
|
/* Pull out data pointer from table, save r3, we'll write over it */
|
427 |
|
|
l.sw 4(r1),r3
|
428 |
|
|
l.lwz r3,0(r13)
|
429 |
|
|
/* Call handler, save r5 in delay slot */
|
430 |
812 |
stekern |
l.jalr r14
|
431 |
517 |
julius |
l.sw 8(r1),r5
|
432 |
|
|
|
433 |
|
|
/* Reload r3,r5 */
|
434 |
|
|
l.lwz r3,4(r1)
|
435 |
|
|
l.lwz r5,8(r1)
|
436 |
|
|
.L1:
|
437 |
|
|
/* Clear bit from PICSR, return to start of checking loop */
|
438 |
|
|
l.ori r6,r0,1
|
439 |
|
|
l.sll r6,r6,r5
|
440 |
|
|
l.j .L0
|
441 |
|
|
l.xor r3,r3,r6
|
442 |
|
|
|
443 |
|
|
.L2:
|
444 |
|
|
/* Finish up - write PICSR back, restore r9*/
|
445 |
|
|
l.lwz r9,0(r1)
|
446 |
|
|
l.mtspr r0,r3,SPR_PICSR
|
447 |
|
|
l.jr r9
|
448 |
|
|
l.addi r1,r1,12
|
449 |
|
|
|
450 |
|
|
|
451 |
|
|
|
452 |
|
|
/* -------------------------------------------------------------------------- */
|
453 |
|
|
/*!Function to add handler to table
|
454 |
|
|
*/
|
455 |
|
|
/* -------------------------------------------------------------------------- */
|
456 |
|
|
.global or1k_interrupt_handler_add
|
457 |
|
|
.type or1k_interrupt_handler_add,@function
|
458 |
|
|
|
459 |
|
|
/* r3 should have IRQ line for peripheral */
|
460 |
|
|
/* r4 should have handler function address */
|
461 |
|
|
or1k_interrupt_handler_add:
|
462 |
|
|
l.addi r1,r1,-4
|
463 |
|
|
l.sw 0(r1),r6
|
464 |
|
|
/* Convert interrupt number into word address */
|
465 |
|
|
l.slli r3,r3,2
|
466 |
|
|
/* Get address of interrupt handler table */
|
467 |
|
|
l.movhi r6,hi(or1k_interrupt_handler_table)
|
468 |
|
|
l.ori r6,r6,lo(or1k_interrupt_handler_table)
|
469 |
|
|
/* Add handler offset to table base */
|
470 |
|
|
l.add r6,r6,r3
|
471 |
|
|
/* Store handler function address */
|
472 |
|
|
l.sw 0(r6),r4
|
473 |
|
|
/* Get address of interrupt handler data ptr table */
|
474 |
|
|
l.movhi r6,hi(or1k_interrupt_handler_data_ptr_table)
|
475 |
|
|
l.ori r6,r6,lo(or1k_interrupt_handler_data_ptr_table)
|
476 |
|
|
/* Add handler offset to table base */
|
477 |
|
|
l.add r6,r6,r3
|
478 |
|
|
/* Store handler data pointer address */
|
479 |
|
|
l.sw 0(r6),r5
|
480 |
|
|
/* Restore r6 */
|
481 |
|
|
l.lwz r6,0(r1)
|
482 |
|
|
/* Return via link register */
|
483 |
|
|
l.jr r9
|
484 |
|
|
/* Restore stack value */
|
485 |
|
|
l.addi r1,r1,4
|
486 |
|
|
|
487 |
|
|
|
488 |
|
|
/* -------------------------------------------------------------------------- */
|
489 |
|
|
/*!Function to enable an interrupt handler in the PICMR
|
490 |
|
|
*/
|
491 |
|
|
/* -------------------------------------------------------------------------- */
|
492 |
|
|
.global or1k_interrupt_enable
|
493 |
|
|
.type or1k_interrupt_enable,@function
|
494 |
|
|
|
495 |
|
|
/* r3 should have IRQ line for peripheral */
|
496 |
|
|
or1k_interrupt_enable:
|
497 |
|
|
l.addi r1,r1,-4
|
498 |
|
|
l.sw 0(r1),r4
|
499 |
|
|
l.ori r4,r0,0x1
|
500 |
|
|
l.sll r4,r4,r3
|
501 |
|
|
l.mfspr r3,r0,SPR_PICMR
|
502 |
|
|
l.or r3,r3,r4
|
503 |
|
|
l.mtspr r0,r3,SPR_PICMR
|
504 |
|
|
l.lwz r4,0(r1)
|
505 |
|
|
l.jr r9
|
506 |
|
|
l.addi r1,r1,4
|
507 |
|
|
|
508 |
|
|
/* -------------------------------------------------------------------------- */
|
509 |
|
|
/*!Function to disable an interrupt handler in the PICMR
|
510 |
|
|
*/
|
511 |
|
|
/* -------------------------------------------------------------------------- */
|
512 |
|
|
.global or1k_interrupt_disable
|
513 |
|
|
.type or1k_interrupt_disable,@function
|
514 |
|
|
|
515 |
|
|
/* r3 should have IRQ line for peripheral */
|
516 |
|
|
or1k_interrupt_disable:
|
517 |
|
|
l.addi r1,r1,-4
|
518 |
|
|
l.sw 0(r1),r4
|
519 |
|
|
l.ori r4,r0,0x1
|
520 |
|
|
l.sll r4,r4,r3
|
521 |
|
|
l.xori r4,r4,0xffff
|
522 |
|
|
l.mfspr r3,r0,SPR_PICMR
|
523 |
|
|
l.and r3,r3,r4
|
524 |
|
|
l.mtspr r0,r3,SPR_PICMR
|
525 |
|
|
l.lwz r4,0(r1)
|
526 |
|
|
l.jr r9
|
527 |
|
|
l.addi r1,r1,4
|
528 |
|
|
|
529 |
|
|
|
530 |
|
|
/* -------------------------------------------------------------------------- */
|
531 |
|
|
/*!Generic exception handler function
|
532 |
|
|
*/
|
533 |
|
|
/* -------------------------------------------------------------------------- */
|
534 |
|
|
// Warning - this must be the same as specified in crt0.S
|
535 |
|
|
#define EXCEPTION_STACK_SIZE 128+128
|
536 |
|
|
|
537 |
|
|
// Value handler addresses are initialised to
|
538 |
|
|
#define EXCEPTION_HANDLER_NOT_SET -1
|
539 |
|
|
|
540 |
|
|
|
541 |
|
|
.data
|
542 |
|
|
.align 4
|
543 |
|
|
.global or1k_exception_handler_table
|
544 |
|
|
.extern _interrupt_handler
|
545 |
|
|
or1k_exception_handler_table:
|
546 |
|
|
or1k_exception_handler_buserr: .long EXCEPTION_HANDLER_NOT_SET
|
547 |
|
|
or1k_exception_handler_dpfault: .long EXCEPTION_HANDLER_NOT_SET
|
548 |
|
|
or1k_exception_handler_ipfault: .long EXCEPTION_HANDLER_NOT_SET
|
549 |
|
|
or1k_exception_handler_tick: .long EXCEPTION_HANDLER_NOT_SET
|
550 |
|
|
or1k_exception_handler_align: .long EXCEPTION_HANDLER_NOT_SET
|
551 |
|
|
or1k_exception_handler_illegal: .long EXCEPTION_HANDLER_NOT_SET
|
552 |
|
|
or1k_exception_handler_interrupt: .long EXCEPTION_HANDLER_NOT_SET
|
553 |
|
|
or1k_exception_handler_dtlbmiss: .long EXCEPTION_HANDLER_NOT_SET
|
554 |
|
|
or1k_exception_handler_itlbmiss: .long EXCEPTION_HANDLER_NOT_SET
|
555 |
|
|
or1k_exception_handler_range: .long EXCEPTION_HANDLER_NOT_SET
|
556 |
|
|
or1k_exception_handler_systemcall: .long EXCEPTION_HANDLER_NOT_SET
|
557 |
|
|
or1k_exception_handler_float: .long EXCEPTION_HANDLER_NOT_SET
|
558 |
|
|
or1k_exception_handler_trap: .long EXCEPTION_HANDLER_NOT_SET
|
559 |
|
|
or1k_exception_handler_reserved0: .long EXCEPTION_HANDLER_NOT_SET
|
560 |
|
|
or1k_exception_handler_reserved1: .long EXCEPTION_HANDLER_NOT_SET
|
561 |
|
|
or1k_exception_handler_reserved2: .long EXCEPTION_HANDLER_NOT_SET
|
562 |
|
|
or1k_exception_handler_reserved3: .long EXCEPTION_HANDLER_NOT_SET
|
563 |
|
|
or1k_exception_handler_reserved4: .long EXCEPTION_HANDLER_NOT_SET
|
564 |
|
|
or1k_exception_handler_reserved5: .long EXCEPTION_HANDLER_NOT_SET
|
565 |
|
|
or1k_exception_handler_reserved6: .long EXCEPTION_HANDLER_NOT_SET
|
566 |
|
|
or1k_exception_handler_reserved7: .long EXCEPTION_HANDLER_NOT_SET
|
567 |
|
|
or1k_exception_handler_reserved8: .long EXCEPTION_HANDLER_NOT_SET
|
568 |
|
|
or1k_exception_handler_reserved9: .long EXCEPTION_HANDLER_NOT_SET
|
569 |
|
|
or1k_exception_handler_reserved10: .long EXCEPTION_HANDLER_NOT_SET
|
570 |
|
|
or1k_exception_handler_reserved11: .long EXCEPTION_HANDLER_NOT_SET
|
571 |
|
|
or1k_exception_handler_reserved12: .long EXCEPTION_HANDLER_NOT_SET
|
572 |
|
|
or1k_exception_handler_reserved13: .long EXCEPTION_HANDLER_NOT_SET
|
573 |
|
|
or1k_exception_handler_reserved14: .long EXCEPTION_HANDLER_NOT_SET
|
574 |
|
|
or1k_exception_handler_reserved15: .long EXCEPTION_HANDLER_NOT_SET
|
575 |
|
|
|
576 |
|
|
/* -------------------------------------------------------------------------- */
|
577 |
|
|
/*!Function to call appropriate exception handler
|
578 |
|
|
*/
|
579 |
|
|
/* -------------------------------------------------------------------------- */
|
580 |
|
|
.section .text
|
581 |
|
|
.global or1k_exception_handler
|
582 |
|
|
.type or1k_exception_handler,@function
|
583 |
|
|
|
584 |
|
|
/*
|
585 |
|
|
r3 = address of exception vector
|
586 |
|
|
r4 = address where exception occurred
|
587 |
|
|
*/
|
588 |
|
|
|
589 |
|
|
or1k_exception_handler:
|
590 |
|
|
/* Store remainder of state (r3,r4 stored in vector entry)*/
|
591 |
|
|
l.sw 0x00(r1), r2
|
592 |
|
|
l.sw 0x0c(r1), r5
|
593 |
|
|
l.sw 0x10(r1), r6
|
594 |
|
|
l.sw 0x14(r1), r7
|
595 |
|
|
l.sw 0x18(r1), r8
|
596 |
|
|
l.sw 0x1c(r1), r9
|
597 |
|
|
l.sw 0x20(r1), r10
|
598 |
|
|
l.sw 0x24(r1), r11
|
599 |
|
|
l.sw 0x28(r1), r12
|
600 |
|
|
l.sw 0x2c(r1), r13
|
601 |
|
|
l.sw 0x30(r1), r14
|
602 |
|
|
l.sw 0x34(r1), r15
|
603 |
|
|
l.sw 0x38(r1), r16
|
604 |
|
|
l.sw 0x3c(r1), r17
|
605 |
|
|
l.sw 0x40(r1), r18
|
606 |
|
|
l.sw 0x44(r1), r19
|
607 |
|
|
l.sw 0x48(r1), r20
|
608 |
|
|
l.sw 0x4c(r1), r21
|
609 |
|
|
l.sw 0x50(r1), r22
|
610 |
|
|
l.sw 0x54(r1), r23
|
611 |
|
|
l.sw 0x58(r1), r24
|
612 |
|
|
l.sw 0x5c(r1), r25
|
613 |
|
|
l.sw 0x60(r1), r26
|
614 |
|
|
l.sw 0x64(r1), r27
|
615 |
|
|
l.sw 0x68(r1), r28
|
616 |
|
|
l.sw 0x6c(r1), r29
|
617 |
|
|
l.sw 0x70(r1), r30
|
618 |
|
|
l.sw 0x74(r1), r31
|
619 |
|
|
|
620 |
|
|
/* Determine offset in table of exception handler using r3*/
|
621 |
|
|
l.andi r13,r3,0xffff
|
622 |
|
|
l.srli r13,r13,6
|
623 |
|
|
/* Substract 2 words, as we have no vector at 0 and no reset handler */
|
624 |
|
|
l.addi r13,r13,-8
|
625 |
|
|
/* r13 now contains offset in or1k_exception_handler_table for
|
626 |
|
|
function
|
627 |
|
|
*/
|
628 |
|
|
/* Get or1k_exception_handler_table address */
|
629 |
|
|
l.movhi r14,hi(or1k_exception_handler_table)
|
630 |
|
|
l.ori r14,r14,lo(or1k_exception_handler_table)
|
631 |
|
|
/* r14 now contains base of exception handler table */
|
632 |
|
|
l.add r14,r14,r13
|
633 |
|
|
l.lwz r13, 0(r14)
|
634 |
|
|
|
635 |
|
|
/* Check to see if this handler has been set yet */
|
636 |
|
|
l.movhi r15,hi(EXCEPTION_HANDLER_NOT_SET)
|
637 |
|
|
l.ori r15,r15,lo(EXCEPTION_HANDLER_NOT_SET)
|
638 |
|
|
l.sfne r13,r15
|
639 |
|
|
l.bnf exception_exit
|
640 |
|
|
l.nop
|
641 |
|
|
|
642 |
|
|
/* Call exception handler, copy EPCR to r3 */
|
643 |
|
|
l.jalr r13
|
644 |
|
|
l.or r3,r4,r4
|
645 |
|
|
|
646 |
|
|
/* Restore state */
|
647 |
|
|
l.lwz r2, 0x00(r1)
|
648 |
|
|
l.lwz r3, 0x04(r1)
|
649 |
|
|
l.lwz r4, 0x08(r1)
|
650 |
|
|
l.lwz r5, 0x0c(r1)
|
651 |
|
|
l.lwz r6, 0x10(r1)
|
652 |
|
|
l.lwz r7, 0x14(r1)
|
653 |
|
|
l.lwz r8, 0x18(r1)
|
654 |
|
|
l.lwz r9, 0x1c(r1)
|
655 |
|
|
l.lwz r10, 0x20(r1)
|
656 |
|
|
l.lwz r11, 0x24(r1)
|
657 |
|
|
l.lwz r12, 0x28(r1)
|
658 |
|
|
l.lwz r13, 0x2c(r1)
|
659 |
|
|
l.lwz r14, 0x30(r1)
|
660 |
|
|
l.lwz r15, 0x34(r1)
|
661 |
|
|
l.lwz r16, 0x38(r1)
|
662 |
|
|
l.lwz r17, 0x3c(r1)
|
663 |
|
|
l.lwz r18, 0x40(r1)
|
664 |
|
|
l.lwz r19, 0x44(r1)
|
665 |
|
|
l.lwz r20, 0x48(r1)
|
666 |
|
|
l.lwz r21, 0x4c(r1)
|
667 |
|
|
l.lwz r22, 0x50(r1)
|
668 |
|
|
l.lwz r23, 0x54(r1)
|
669 |
|
|
l.lwz r24, 0x58(r1)
|
670 |
|
|
l.lwz r25, 0x5c(r1)
|
671 |
|
|
l.lwz r26, 0x60(r1)
|
672 |
|
|
l.lwz r27, 0x64(r1)
|
673 |
|
|
l.lwz r28, 0x68(r1)
|
674 |
|
|
l.lwz r29, 0x6c(r1)
|
675 |
|
|
l.lwz r30, 0x70(r1)
|
676 |
|
|
l.lwz r31, 0x74(r1)
|
677 |
|
|
|
678 |
|
|
l.addi r1, r1, EXCEPTION_STACK_SIZE
|
679 |
|
|
|
680 |
|
|
l.rfe
|
681 |
|
|
l.nop
|
682 |
|
|
|
683 |
|
|
exception_exit:
|
684 |
|
|
/* Exception handler not set, exit */
|
685 |
|
|
l.jal exit
|
686 |
|
|
l.or r3,r4,r4
|
687 |
|
|
|
688 |
|
|
|
689 |
|
|
|
690 |
|
|
/* -------------------------------------------------------------------------- */
|
691 |
|
|
/*!Function to add handler to table
|
692 |
|
|
*/
|
693 |
|
|
/* -------------------------------------------------------------------------- */
|
694 |
|
|
.global or1k_exception_handler_add
|
695 |
|
|
.type or1k_exception_handler_add,@function
|
696 |
|
|
|
697 |
|
|
.extern or1k_exception_handler_table
|
698 |
|
|
|
699 |
|
|
/* r3 should have exception number (2 for buserr, 5 for tick, etc.) */
|
700 |
|
|
/* r4 should have handler function address */
|
701 |
|
|
or1k_exception_handler_add:
|
702 |
|
|
l.addi r1,r1,-4
|
703 |
|
|
l.sw 0(r1),r5
|
704 |
|
|
/* Convert exception number into word address */
|
705 |
|
|
l.slli r3,r3,2
|
706 |
|
|
l.addi r3,r3,-8
|
707 |
|
|
/* Get address of exception handler table */
|
708 |
|
|
l.movhi r5,hi(or1k_exception_handler_table)
|
709 |
|
|
l.ori r5,r5,lo(or1k_exception_handler_table)
|
710 |
|
|
/* Add handler offset to table base */
|
711 |
|
|
l.add r5,r5,r3
|
712 |
|
|
/* Store handler function address */
|
713 |
|
|
l.sw 0(r5),r4
|
714 |
|
|
/* Restore r5 */
|
715 |
|
|
l.lwz r5,0(r1)
|
716 |
|
|
/* Return via link register */
|
717 |
|
|
l.jr r9
|
718 |
|
|
/* Restore stack value */
|
719 |
|
|
l.addi r1,r1,4
|
720 |
812 |
stekern |
|