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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
#include "mips.h"
#include "system.h"
.extern main
.global start
.set mips32r2
.set noreorder
.set noat
.section .init.text,"ax",%progbits
start:
di # disable interrupts
bltzal zero, load_addr # ra = PC + 8, branch not taken
nop
load_addr:
addiu v0, ra, -12 # calc real load address
# account for branch delay slot
# and very first 'di' instruction
core_clk_setup:
la t0, 0xb0010000 # CMU base
li t1, 0x440 # HOSC enable, bypass
sw t1, 0(t0) # CMU_COREPLL
li t1, 0x350 # CORECLKS 24M, CCLKDIV = 1, SCLKDIV = 2,
# PCLKDIV = 4
sw t1, 0x0c(t0) # CMU_BUSCLK
li t1, 0xc6 # HOSC enable, PLL enable, 6*6M = 36M
sw t1, 0(t0) # CMU_COREPLL
nop
nop
nop
nop
nop
nop
nop
nop # arbitrary 300ns delay as there is no
# PLL lock feedback
li t1, 0x390 # CORECLKS COREPLL, CCLKDIV = 1, SCLKDIV = 2,
# PCLKDIV = 4
sw t1, 0x0c(t0) # CMU_BUSCLK
cache_setup:
la t0, 0x80000000 # an idx op should use an unmappable address
ori t1, t0, 0x4000 # 16kB cache
mtc0 zero, C0_TAGLO
mtc0 zero, C0_TAGHI
cache_init_loop:
cache ICIndexStTag, 0(t0) # index store icache tag
cache DCIndexStTag, 0(t0) # index store dcache tag
bne t0, t1, cache_init_loop
addiu t0, t0, 0x10
li t0, 3 # enable cache for kseg0 accesses
mtc0 t0, C0_CONFIG
ehb
la t0, relocstart
la t1, relocend
beq t0, v0, entry_point # no relocation needed
nop
reloc_loop:
lw s0, 0(v0) # src
lw s1, 4(v0)
lw s2, 8(v0)
lw s3, 12(v0)
sw s0, 0(t0) # dst
sw s1, 4(t0)
sw s2, 8(t0)
sw s3, 12(t0)
synci 0(t0) # dcache writeback invalidate
# icache invalidate
addiu t0, t0, 16 # inc dst addr
slt t2, t0, t1
bnez t2, reloc_loop
addiu v0, v0, 16 # inc src addr
entry_point_jump:
la t0, entry_point
sync
jr.hb t0
nop
entry_point:
intc_setup:
li t0, 0xb0020000 # INTC base
lw zero, 4(t0) # INTC_MSK mask all interrupt sources
core_irq_setup:
li t0, 0x00404000 # BEV=1 for C0_EBASE setup, IM6=1, IE=0
mtc0 t0, C0_STATUS
la t0, _irqbase # vectors base address must be 4k aligned
mtc0 t0, C0_EBASE
li t0, 0x00004000
mtc0 t0, C0_STATUS # BEV=0, IM6=1, IE=0
li t1, 0x08800000
mtc0 t1, C0_CAUSE # DC=1, IV=1
mtc0 zero,C0_INTCTL # VS = 0
clear_bss:
la t0, bssbegin
la t1, bssend
beq t0, t1, stack_setup
nop
clear_bss_loop:
sw zero, 0(t0)
bne t0, t1, clear_bss_loop
addiu t0, 4
stack_setup:
la k0, irqstackend
la sp, stackend
la t0, stackbegin
li t1, 0xdeadbeef
stack_munge_loop:
sw t1, 0(t0)
bne t0, sp, stack_munge_loop
addiu t0, 4
# jump to C code with enabled interrupts
la t0, main
jr.hb t0
ei
.extern exception_jmp_ctx_ptr
.global tlb_refill_handler
.section .exception.tlb_refill,"ax",%progbits
tlb_refill_handler:
li a0, EXCEPTION_ADDR
la k0, restore_exception_jmp
jr k0
nop
.global cache_error_handler
.section .exception.cache_error,"ax",%progbits
cache_error_handler:
li a0, EXCEPTION_ADDR
la k0, restore_exception_jmp
jr k0
nop
.global general_exception_handler
.section .exception.general_exception,"ax",%progbits
general_exception_handler:
li a0, EXCEPTION_UNSP
la k0, restore_exception_jmp
jr k0
nop
/* s0-s7 not saved as this are callee saved registers
* CO_STATUS is not saved as nested interrupts are not supported
*
* Separate irqstack is used for context save and irq processing
* k0 holds the address of the top of this stack and k1 is used
* to hold original sp value. Since we do not support nesting
* there is nothing to worry about
*/
.extern INT_UDC
.global irq_handler
.section .exception.irq,"ax",%progbits
irq_handler:
move k1, sp
move sp, k0
addiu sp, sp, -84
/* context save */
sw AT, 0(sp)
sw v0, 4(sp)
sw v1, 8(sp)
sw a0, 12(sp)
sw a1, 16(sp)
sw a2, 20(sp)
sw a3, 24(sp)
sw t0, 28(sp)
sw t1, 32(sp)
sw t2, 36(sp)
sw t3, 40(sp)
sw t4, 44(sp)
sw t5, 48(sp)
sw t6, 52(sp)
sw t7, 56(sp)
sw t8, 60(sp)
sw t9, 64(sp)
sw fp, 68(sp)
sw ra, 72(sp)
mfhi t0
mflo t1
sw t0, 76(sp)
sw t1, 80(sp)
/* handle interrupt */
lui t0, 0xb002 /* INTC base */
lw a0, 0(t0) /* INTC_PD */
lw a1, 4(t0) /* INTC_MSK */
and a0, a0, a1 /* mask */
andi a0, a0, 0x10 /* UDC flag */
beq a0, zero, restore
nop
/* irq dispatch */
la a0, INT_UDC
jalr a0
nop
restore:
/* context restore */
lw t0, 76(sp)
lw t1, 80(sp)
mthi t0
mtlo t1
lw AT, 0(sp)
lw v0, 4(sp)
lw v1, 8(sp)
lw a0, 12(sp)
lw a1, 16(sp)
lw a2, 20(sp)
lw a3, 24(sp)
lw t0, 28(sp)
lw t1, 32(sp)
lw t2, 36(sp)
lw t3, 40(sp)
lw t4, 44(sp)
lw t5, 48(sp)
lw t6, 52(sp)
lw t7, 56(sp)
lw t8, 60(sp)
lw t9, 64(sp)
lw fp, 68(sp)
lw ra, 72(sp)
addiu sp, sp, 84
move sp, k1
eret
nop
.set reorder
.set at
|