-
Notifications
You must be signed in to change notification settings - Fork 1
/
interrupt.h
231 lines (187 loc) · 6.36 KB
/
interrupt.h
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
//
// Created by junha on 4/3/2019.
//
#ifndef REFURBSOUP_INTERRUPT_H
#define REFURBSOUP_INTERRUPT_H
#include "interrupt_ID.h"
#include "defines.h"
#include "address_map_arm.h"
extern volatile int key_dir;
extern volatile int pattern;
extern volatile int *LEDR_ptr;
extern volatile int *SW_ptr;
extern volatile int *KEY_EDGE_ptr;
extern volatile char *character_buffer;
extern volatile int *pixel_ctrl_ptr;
extern bool KEYBOARD_UP;
extern bool KEYBOARD_DOWN;
extern bool KEYBOARD_LEFT;
extern bool KEYBOARD_RIGHT;
extern bool KEYBOARD_RESTART;
unsigned char byte1 = 0;
unsigned char byte2 = 0;
unsigned char byte3 = 0;
void config_interrupt (int, int);
void hw_write_bits(volatile int *, volatile int, volatile int);
void set_A9_IRQ_stack(void);
void enable_A9_interrupts(void);
void config_GIC(void);
void config_KEYs();
void config_PS2();
void pushbutton_ISR(void);
void PS2_ISR();
// Define the IRQ exception handler
void __attribute__ ((interrupt)) __cs3_isr_irq (void)
{
// Read the ICCIAR from the processor interface
int address = MPCORE_GIC_CPUIF + ICCIAR;
int int_ID = *((int *) address);
if (int_ID == PS2_IRQ) // check if interrupt is from the PS/2
PS2_ISR ();
else
while (1); // if unexpected, then halt
// Write to the End of Interrupt Register (ICCEOIR)
address = MPCORE_GIC_CPUIF + ICCEOIR;
*((int *) address) = int_ID;
return;
}
// Define the remaining exception handlers
void __attribute__((interrupt)) __cs3_reset(void) {
while (1);
}
void __attribute__((interrupt)) __cs3_isr_undef(void) {
while (1);
}
void __attribute__((interrupt)) __cs3_isr_swi(void) {
while (1);
}
void __attribute__((interrupt)) __cs3_isr_pabort(void) {
while (1);
}
void __attribute__((interrupt)) __cs3_isr_dabort(void) {
while (1);
}
void __attribute__((interrupt)) __cs3_isr_fiq(void) {
while (1);
}
/*
* Initialize the banked stack pointer register for IRQ mode
*/
void set_A9_IRQ_stack(void)
{
int stack, mode;
stack = A9_ONCHIP_END - 7; // top of A9 onchip memory, aligned to 8 bytes
/* change processor to IRQ mode with interrupts disabled */
mode = INT_DISABLE | IRQ_MODE;
asm("msr cpsr, %[ps]" : : [ps] "r" (mode));
/* set banked stack pointer */
asm("mov sp, %[ps]" : : [ps] "r" (stack));
/* go back to SVC mode before executing subroutine return! */
mode = INT_DISABLE | SVC_MODE;
asm("msr cpsr, %[ps]" : : [ps] "r" (mode));
}
/*
* Turn on interrupts in the ARM processor
*/
void enable_A9_interrupts(void)
{
int status = SVC_MODE | INT_ENABLE;
asm("msr cpsr,%[ps]" : : [ps]"r"(status));
}
/*
* Configure the Generic Interrupt Controller (GIC)
*/
void config_GIC(void)
{
int address; // used to calculate register addresses
/* enable some examples of interrupts */
config_interrupt (PS2_IRQ, CPU0);
// Set Interrupt Priority Mask Register (ICCPMR). Enable interrupts for lowest priority
address = MPCORE_GIC_CPUIF + ICCPMR;
*((int *) address) = 0xFFFF;
// Set CPU Interface Control Register (ICCICR). Enable signaling of interrupts
address = MPCORE_GIC_CPUIF + ICCICR;
*((int *) address) = ENABLE;
// Configure the Distributor Control Register (ICDDCR) to send pending interrupts to CPUs
address = MPCORE_GIC_DIST + ICDDCR;
*((int *) address) = ENABLE;
}
/* setup the KEY interrupts in the FPGA */
void config_KEYs() {
volatile int *KEY_ptr = (int *) KEY_BASE; // pushbutton KEY address
*(KEY_ptr + 2) = 0x3; // enable interrupts for KEY[1]
}
/* setup the PS/2 interrupts */
void config_PS2() {
volatile int * PS2_ptr = (int *)PS2_BASE; // PS/2 port address
*(PS2_ptr) = 0xFF; /* reset */
*(PS2_ptr + 1) =
0x1; /* write to the PS/2 Control register to enable interrupts */
}
void pushbutton_ISR(void) {
volatile int *KEY_ptr = (int *) KEY_BASE;
int press;
press = *(KEY_ptr + 3); // read the pushbutton interrupt register
*(KEY_ptr + 3) = press; // Clear the interrupt
key_dir ^= 1; // Toggle key_dir value
return;
}
void PS2_ISR(void) {
volatile int * PS2_ptr = (int *) 0xFF200100; // PS/2 port address
int PS2_data, RAVAIL;
PS2_data = *(PS2_ptr); // read the Data register in the PS/2 port
RAVAIL = (PS2_data & 0xFFFF0000) >> 16; // extract the RAVAIL field
if (RAVAIL > 0)
{
/* always save the last three bytes received */
byte1 = byte2;
byte2 = byte3;
byte3 = PS2_data & 0xFF;
if ((byte2 == (char) 0xE0) && (byte3 == (char) 0x75)) {
KEYBOARD_UP = true;
} else if((byte2 == (char) 0xE0) && (byte3 == (char) 0x72)){
KEYBOARD_DOWN = true;
} else if((byte2 == (char) 0xE0) && (byte3 == (char) 0x6B)){
KEYBOARD_LEFT = true;
} else if((byte2 == (char) 0xE0) && (byte3 == (char) 0x74)){
KEYBOARD_RIGHT = true;
} else if((byte2 == (char) 0xE0) && (byte3 == (char) 0x69)){
KEYBOARD_RESTART = true;
}
}
}
/*
* Configure registers in the GIC for individual interrupt IDs.
*/
void config_interrupt (int int_ID, int CPU_target)
{
int n, addr_offset, value, address;
/* Set Interrupt Processor Targets Register (ICDIPTRn) to cpu0.
* n = integer_div(int_ID / 4) * 4
* addr_offet = #ICDIPTR + n
* value = CPU_target << ((int_ID & 0x3) * 8)
*/
n = (int_ID >> 2) << 2;
addr_offset = ICDIPTR + n;
value = CPU_target << ((int_ID & 0x3) << 3);
/* Now that we know the register address and value, we need to set the correct bits in
* the GIC register, without changing the other bits */
address = MPCORE_GIC_DIST + addr_offset;
hw_write_bits((int *) address, 0xff << ((int_ID & 0x3) << 3), value);
/* Set Interrupt Set-Enable Registers (ICDISERn).
* n = (integer_div(in_ID / 32) * 4
* addr_offset = 0x100 + n
* value = enable << (int_ID & 0x1F) */
n = (int_ID >> 5) << 2;
addr_offset = ICDISER + n;
value = 0x1 << (int_ID & 0x1f);
/* Now that we know the register address and value, we need to set the correct bits in
* the GIC register, without changing the other bits */
address = MPCORE_GIC_DIST + addr_offset;
hw_write_bits((int *) address, 0x1 << (int_ID & 0x1f), value);
}
void hw_write_bits(volatile int * addr, volatile int unmask, volatile int value)
{
*addr = ((~unmask) & *addr) | value;
}
#endif //REFURBSOUP_INTERRUPT_H