Welcome to mirror list, hosted at ThFree Co, Russian Federation.

interrupts-asm.S « or1k « libgloss - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 560035285d86233a6e0e8932db0947ce591fa02e (plain)
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)
	)