/
boot.S
274 lines (226 loc) · 10.3 KB
/
boot.S
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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// This boot code is derived from https://github.com/sergev/LiteBSD/blob/master/sys/mips/pic32/locore.s
#include <mips/regdef.h>
#include <mips/asm.h>
#include <mips/m32c0.h>
.set noreorder # Don't allow the assembler to reorder instructions.
.set noat
/*-----------------------------------
* Reset/NMI exception handler.
*/
.globl start
.type start, @function
.section .reset
start:
mtc0 zero, C0_COUNT # Clear cp0 Count (Used to measure boot time.)
//
// Set all GPRs of all register sets to predefined state.
//
init_gpr:
li $1, 0xdeadbeef # 0xdeadbeef stands out, kseg2 mapped, odd.
# Determine how many shadow sets are implemented (in addition to the base register set.)
# the first time thru the loop it will initialize using $1 set above.
# At the bottom og the loop, 1 is subtract from $30
# and loop back to next_shadow_set to start the next loop and the next lowest set number.
mfc0 $29, C0_SRSCTL # read SRSCtl
ext $30, $29, 26, 4 # extract HSS
next_shadow_set: # set PSS to shadow set to be initialized
ins $29, $30, 6, 4 # insert PSS
mtc0 $29, C0_SRSCTL # write SRSCtl
wrpgpr $1, $1
wrpgpr $2, $1
wrpgpr $3, $1
wrpgpr $4, $1
wrpgpr $5, $1
wrpgpr $6, $1
wrpgpr $7, $1
wrpgpr $8, $1
wrpgpr $9, $1
wrpgpr $10, $1
wrpgpr $11, $1
wrpgpr $12, $1
wrpgpr $13, $1
wrpgpr $14, $1
wrpgpr $15, $1
wrpgpr $16, $1
wrpgpr $17, $1
wrpgpr $18, $1
wrpgpr $19, $1
wrpgpr $20, $1
wrpgpr $21, $1
wrpgpr $22, $1
wrpgpr $23, $1
wrpgpr $24, $1
wrpgpr $25, $1
wrpgpr $26, $1
wrpgpr $27, $1
wrpgpr $28, $1
beqz $30, init_cp0
wrpgpr $29, $1
wrpgpr $30, $1
wrpgpr $31, $1
b next_shadow_set
add $30, -1 # Decrement to the next lower number
//
// Init CP0 Status, Count, Compare, Watch*, and Cause.
//
init_cp0:
# Initialize Status
li v1, 0x00400004 // (M_StatusERL | M_StatusBEV)
mtc0 v1, C0_STATUS # write Status
# Initialize Watch registers if implemented.
mfc0 v0, C0_CONFIG1 # read Config1
ext v1, v0, 3, 1 # extract bit 3 WR (Watch registers implemented)
beq v1, zero, done_wr
li v1, 0x7 # (M_WatchHiI | M_WatchHiR | M_WatchHiW)
# Clear Watch Status bits and disable watch exceptions
mtc0 v1, C0_WATCHHI # write WatchHi0
mfc0 v0, C0_WATCHHI # read WatchHi0
bgez v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 zero, C0_WATCHLO # clear WatchLo0
mtc0 v1, C0_WATCHHI, 1 # write WatchHi1
mfc0 v0, C0_WATCHHI, 1 # read WatchHi1
bgez v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 zero, C0_WATCHLO,1 # clear WatchLo1
mtc0 v1, C0_WATCHHI, 2 # write WatchHi2
mfc0 v0, C0_WATCHHI, 2 # read WatchHi2
bgez v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 zero, C0_WATCHLO, 2 # clear WatchLo2
mtc0 v1, C0_WATCHHI, 3 # write WatchHi3
mfc0 v0, C0_WATCHHI, 3 # read WatchHi3
bgez v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 zero, C0_WATCHLO, 3 # clear WatchLo3
mtc0 v1, C0_WATCHHI, 4 # write WatchHi4
mfc0 v0, C0_WATCHHI, 4 # read WatchHi4
bgez v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 zero, C0_WATCHLO, 4 # clear WatchLo4
mtc0 v1, C0_WATCHHI, 5 # write WatchHi5
mfc0 v0, C0_WATCHHI, 5 # read WatchHi5
bgez v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 zero, C0_WATCHLO, 5 # clear WatchLo5
mtc0 v1, C0_WATCHHI, 6 # write WatchHi6
mfc0 v0, C0_WATCHHI, 6 # read WatchHi6
bgez v0, done_wr # Check for bit 31 (sign bit) for more Watch registers
mtc0 zero, C0_WATCHLO, 6 # clear WatchLo6
mtc0 v1, C0_WATCHHI, 7 # write WatchHi7
mtc0 zero, C0_WATCHLO, 7 # clear WatchLo7
done_wr:
# Clear WP bit to avoid watch exception upon user code entry, IV, and software interrupts.
mtc0 zero, C0_CAUSE # clear Cause: init AFTER init of WatchHi/Lo registers.
# Clear timer interrupt. (Count was cleared at the reset vector to allow timing boot.)
mtc0 zero, C0_COMPARE # clear Compare
/*-----------------------------------
* Initialization.
*/
//
// Clear TLB: generate unique EntryHi contents per entry pair.
//
init_tlb:
# Determine if we have a TLB
mfc0 v1, C0_CONFIG # read Config
ext v1, v1, 7, 3 # extract MT field
li a3, 0x1 # load a 1 to check against
bne v1, a3, init_icache
# Config1MMUSize == Number of TLB entries - 1
mfc0 v0, C0_CONFIG1 # Config1
ext v1, v0, 25, 6 # extract MMU Size
mtc0 zero, C0_ENTRYLO0 # clear EntryLo0
mtc0 zero, C0_ENTRYLO1 # clear EntryLo1
mtc0 zero, C0_PAGEMASK # clear PageMask
mtc0 zero, C0_WIRED # clear Wired
li a0, 0x80000000
next_tlb_entry:
mtc0 v1, C0_INDEX # write Index
mtc0 a0, C0_ENTRYHI # write EntryHi
ehb
tlbwi
add a0, 2 << 13 # Add 8K to the address to avoid TLB conflict with previous entry
bne v1, zero, next_tlb_entry
add v1, -1
//
// Clear L1 instruction cache.
//
init_icache:
# Determine how big the I-cache is
mfc0 v0, C0_CONFIG1 # read Config1
ext v1, v0, 19, 3 # extract I-cache line size
beq v1, zero, done_icache # Skip ahead if no I-cache
nop
li a2, 2
sllv v1, a2, v1 # Now have true I-cache line size in bytes
ext a0, v0, 22, 3 # extract IS
li a2, 64
sllv a0, a2, a0 # I-cache sets per way
ext a1, v0, 16, 3 # extract I-cache Assoc - 1
add a1, 1
mul a0, a0, a1 # Total number of sets
lui a2, 0x8000 # Get a KSeg0 address for cacheops
mtc0 zero, C0_ITAGLO # Clear ITagLo register
move a3, a0
next_icache_tag:
# Index Store Tag Cache Op
# Will invalidate the tag entry, clear the lock bit, and clear the LRF bit
cache 0x8, 0 (a2) # ICIndexStTag
add a3, -1 # Decrement set counter
bne a3, zero, next_icache_tag
add a2, v1 # Get next line address
done_icache:
//
// Enable cacheability of kseg0 segment.
// Until this point the code is executed from segment bfc00000,
// (i.e. kseg1), so I-cache is not used.
// Here we jump to kseg0 and run with I-cache enabled.
//
enable_k0_cache:
# Set CCA for kseg0 to cacheable.
# NOTE! This code must be executed in KSEG1 (not KSEG0 uncached)
mfc0 v0, C0_CONFIG # read Config
li v1, 3 # CCA for single-core processors
ins v0, v1, 0, 3 # insert K0
mtc0 v0, C0_CONFIG # write Config
la a2, init_dcache
jr a2 # switch back to KSEG0
ehb
//
// Initialize the L1 data cache
//
init_dcache:
mfc0 v0, C0_CONFIG1 # read Config1
ext v1, v0, 10, 3 # extract D-cache line size
beq v1, zero, done_dcache # Skip ahead if no D-cache
nop
li a2, 2
sllv v1, a2, v1 # Now have true D-cache line size in bytes
ext a0, v0, 13, 3 # extract DS
li a2, 64
sllv a0, a2, a0 # D-cache sets per way
ext a1, v0, 7, 3 # extract D-cache Assoc - 1
add a1, 1
mul a0, a0, a1 # Get total number of sets
lui a2, 0x8000 # Get a KSeg0 address for cacheops
mtc0 zero, C0_ITAGLO # Clear ITagLo/DTagLo registers
mtc0 zero, C0_DTAGLO
move a3, a0
next_dcache_tag:
# Index Store Tag Cache Op
# Will invalidate the tag entry, clear the lock bit, and clear the LRF bit
cache 0x9, 0 (a2) # DCIndexStTag
add a3, -1 # Decrement set counter
bne a3, zero, next_dcache_tag
add a2, v1 # Get next line address
done_dcache:
# Prepare for eret to main.
la ra, all_done # If main returns then go to all_done:.
move a0, zero # Indicate that there are no arguments available.
la v0, main # load the address of the CRT entry point _start.
mtc0 v0, $30 # Write ErrorEPC with the address of main
ehb # clear hazards (makes sure write to ErrorPC has completed)
# Set stack and global data
la sp, __stack
la gp, _gp
# Return from exception will now execute code in main
eret # Exit reset exception handler and start execution of _start.
/**************************************************************************************/
all_done:
# If main returns it will return to this point. Just spin here.
b all_done
nop