1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
/* interrupts-asm.S -- interrupt handling for OpenRISC 1000.
*
* Copyright (c) 2011, 2012, 2014 Authors
*
* Contributor Julius Baxter <juliusbaxter@gmail.com>
* Contributor Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
* Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de>
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*/
/* -------------------------------------------------------------------------- */
/*!Generic interrupt handler function for or1k
*/
/* -------------------------------------------------------------------------- */
#include "include/or1k-asm.h"
#include "include/or1k-sprs.h"
.extern _or1k_interrupt_handler_table
.extern _or1k_interrupt_handler_data_ptr_table
/* -------------------------------------------------------------------------- */
/*!Function to call appropriate interrupt handler
*/
/* -------------------------------------------------------------------------- */
.section .text
.global _or1k_interrupt_handler
.type _or1k_interrupt_handler,@function
_or1k_interrupt_handler:
/* Make room on stack, save link register */
l.addi r1,r1,-12
l.sw 0(r1),r9
/* Read PICSR */
l.mfspr r3,r0,OR1K_SPR_PIC_PICSR_ADDR
/* Load handler table base address */
l.movhi r7,hi(_or1k_interrupt_handler_table)
l.ori r7,r7,lo(_or1k_interrupt_handler_table)
/* Load data pointer table base address */
l.movhi r12,hi(_or1k_interrupt_handler_data_ptr_table)
l.ori r12,r12,lo(_or1k_interrupt_handler_data_ptr_table)
#ifdef __OR1K_MULTICORE__
/* Read the addresses of the arrays of cores */
/* r7 = (*or1k_interrupt_handler_table) */
l.lwz r7,0(r7)
/* r12 = (*or1k_interrupt_handler_data_ptr_table) */
l.lwz r12,0(r12)
/* Generate offset in arrays */
/* r14 = coreid */
l.mfspr r14,r0,OR1K_SPR_SYS_COREID_ADDR
/* r14 = coreid*32*4 = off */
l.slli r14,r14,7
/* r7 = (*or1k_exception_handler_table)[coreid] */
l.add r7,r7,r14
/* r12 = (*or1k_exception_handler_table)[coreid] */
l.add r12,r12,r14
#endif
.L0:
/* Find first set bit in PICSR */
l.ff1 r4,r3
/* Any bits set? */
l.sfne r4,r0
/* If none, finish */
OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L2))
/* What is IRQ function table offset? */
l.addi r5,r4,-1
l.slli r6,r5,2
/* Add this to table bases */
l.add r14,r6,r7
l.add r13,r6,r12
/* Fetch handler function address */
l.lwz r14,0(r14)
/* Double check it's valid, compare against INTERRUPT_HANDLER_NOT_SET */
l.sfne r14,r0
/* Skip if no handler: TODO: Indicate interrupt fired but no handler*/
OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L1))
/* Pull out data pointer from table, save r3, we'll write over it */
l.sw 4(r1),r3
l.lwz r3,0(r13)
/* Call handler, save r5 in delay slot */
OR1K_DELAYED(
OR1K_INST(l.sw 8(r1),r5),
OR1K_INST(l.jalr r14)
)
/* Reload r3,r5 */
l.lwz r3,4(r1)
l.lwz r5,8(r1)
.L1:
/* Clear bit from PICSR, return to start of checking loop */
l.ori r6,r0,1
l.sll r6,r6,r5
OR1K_DELAYED(
OR1K_INST(l.xor r3,r3,r6),
OR1K_INST(l.j .L0)
)
.L2:
/* Finish up - write PICSR back, restore r9*/
l.lwz r9,0(r1)
l.mtspr r0,r3,OR1K_SPR_PIC_PICSR_ADDR
OR1K_DELAYED(
OR1K_INST(l.addi r1,r1,12),
OR1K_INST(l.jr r9)
)
/* -------------------------------------------------------------------------- */
/*!Function to enable an interrupt handler in the PICMR
*/
/* -------------------------------------------------------------------------- */
.global or1k_interrupt_enable
.type or1k_interrupt_enable,@function
/* r3 should have IRQ line for peripheral */
or1k_interrupt_enable:
l.addi r1,r1,-4
l.sw 0(r1),r4
l.ori r4,r0,0x1
l.sll r4,r4,r3
l.mfspr r3,r0,OR1K_SPR_PIC_PICMR_ADDR
l.or r3,r3,r4
l.mtspr r0,r3,OR1K_SPR_PIC_PICMR_ADDR
l.lwz r4,0(r1)
OR1K_DELAYED(
OR1K_INST(l.addi r1,r1,4),
OR1K_INST(l.jr r9)
)
/* -------------------------------------------------------------------------- */
/*!Function to disable an interrupt handler in the PICMR
*/
/* -------------------------------------------------------------------------- */
.global or1k_interrupt_disable
.type or1k_interrupt_disable,@function
/* r3 should have IRQ line for peripheral */
or1k_interrupt_disable:
l.addi r1,r1,-4
l.sw 0(r1),r4
l.ori r4,r0,0x1
l.sll r4,r4,r3
l.xori r4,r4,0xffff
l.mfspr r3,r0,OR1K_SPR_PIC_PICMR_ADDR
l.and r3,r3,r4
l.mtspr r0,r3,OR1K_SPR_PIC_PICMR_ADDR
l.lwz r4,0(r1)
OR1K_DELAYED(
OR1K_INST(l.addi r1,r1,4),
OR1K_INST(l.jr r9)
)
|