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
275
276
277
278
279
280
281
|
/* entry.S - exception handler for emulating MIPS16 'entry' and 'exit'
pseudo-instructions. These instructions are generated by the compiler
when the -mentry switch is used. The instructions are not implemented
in the MIPS16 CPU; hence the exception handler that emulates them.
This module contains the following public functions:
* void __install_entry_handler(void);
This function installs the entry/exit exception handler. It should
be called before executing any MIPS16 functions that were compiled with
-mentry, typically before main() is called.
* void __remove_entry_handler(void);
This function removes the entry/exit exception handler. It should
be called when the program is exiting, or when it is known that no
more MIPS16 functions compiled with -mentry will be called.
*/
#ifdef __mips16
/* This file contains 32 bit assembly code. */
.set nomips16
#endif
#include "regs.S"
#define CAUSE_EXCMASK 0x3c /* mask for ExcCode in Cause Register */
#define EXC_RI 0x28 /* 101000 == 10 << 2 */
/* Set DEBUG to 1 to enable recording of the last 16 interrupt causes. */
#define DEBUG 0
#if DEBUG
.sdata
int_count:
.space 4 /* interrupt count modulo 16 */
int_cause:
.space 4*16 /* last 16 interrupt causes */
#endif
.text
.set noreorder /* Do NOT reorder instructions */
/* __entry_exit_handler - the reserved instruction exception handler
that emulates the entry and exit instruction. */
__entry_exit_handler:
.set noat /* Do NOT use at register */
#if DEBUG
/* Must avoid using 'la' pseudo-op because it uses gp register, which
may not have a good value in an exception handler. */
# la k0, int_count /* intcount = (intcount + 1) & 0xf */
lui k0 ,%hi(int_count)
addiu k0, k0 ,%lo(int_count)
lw k1, (k0)
addiu k1, k1, 1
andi k1, k1, 0x0f
sw k1, (k0)
# la k0, int_cause /* k1 = &int_cause[intcount] */
lui k0, %hi(int_cause)
addiu k0, k0, %lo(int_cause)
sll k1, k1, 2
add k1, k1, k0
#endif
mfc0 k0, C0_CAUSE /* Fetch cause */
#if DEBUG
sw k0, -4(k1) /* Save exception cause in buffer */
#endif
mfc0 k1, C0_EPC /* Check for Reserved Inst. without */
and k0, CAUSE_EXCMASK /* destroying any register */
subu k0, EXC_RI
bne k0, zero, check_others /* Sorry, go do something else */
and k0, k1, 1 /* Check for TR mode (pc.0 = 1) */
beq k0, zero, ri_in_32 /* Sorry, RI in 32-bit mode */
xor k1, 1
/* Since we now are going to emulate or die, we can use all the T-registers */
/* that MIPS16 does not use (at, t0-t8), and we don't have to save them. */
.set at /* Now it's ok to use at again */
#if 0
j leave
rfe
#endif
lhu t0, 0(k1) /* Fetch the offending instruction */
xor t8, k1, 1 /* Prepare t8 for exit */
and t1, t0, 0xf81f /* Check for entry/exit opcode */
bne t1, 0xe809, other_ri
deareg: and t1, t0, 0x0700 /* Isolate the three a-bits */
srl t1, 6 /* Adjust them so x4 is applied */
slt t2, t1, 17 /* See if this is the exit instruction */
beqz t2, doexit
la t2, savea
subu t2, t1
jr t2 /* Jump into the instruction table */
rfe /* We run the rest in user-mode */
/* This is the entry instruction! */
sw a3, 12(sp) /* 4: a0-a3 saved */
sw a2, 8(sp) /* 3: a0-a2 saved */
sw a1, 4(sp) /* 2: a0-a1 saved */
sw a0, 0(sp) /* 1: a0 saved */
savea: /* 0: No arg regs saved */
dera: and t1, t0, 0x0020 /* Isolate the save-ra bit */
move t7, sp /* Temporary SP */
beq t1, zero, desreg
subu sp, 32 /* Default SP adjustment */
sw ra, -4(t7)
subu t7, 4
desreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */
beq t1, zero, leave
subu t1, 0x0040
beq t1, zero, leave /* Only one to save... */
sw s0, -4(t7) /* Do the first one */
sw s1, -8(t7) /* Do the last one */
leave: jr t8 /* Exit to unmodified EPC */
nop /* Urgh - the only nop!! */
doexf0: mtc1 v0,$f0 /* Copy float value */
b doex2
doexf1: mtc1 v1,$f0 /* Copy double value */
mtc1 v0,$f1
b doex2
doexit: slt t2, t1, 21
beq t2, zero, doexf0
slt t2, t1, 25
beq t2, zero, doexf1
doex2: and t1, t0, 0x0020 /* Isolate ra bit */
beq t1, zero, dxsreg /* t1 holds ra-bit */
addu t7, sp, 32 /* Temporary SP */
lw ra, -4(t7)
subu t7, 4
dxsreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */
beq t1, zero, leavex
subu t1, 0x0040
beq t1, zero, leavex /* Only one to save... */
lw s0, -4(t7) /* Do the first one */
lw s1, -8(t7) /* Do the last one */
leavex: jr ra /* Exit to ra */
addu sp, 32 /* Clean up stack pointer */
/* Come here for exceptions we can't handle. */
ri_in_32:
other_ri:
check_others: /* call the previous handler */
la k0,__previous
jr k0
nop
__exception_code:
.set noreorder
la k0, __entry_exit_handler
# lui k0, %hi(exception)
# addiu k0, k0, %lo(exception)
jr k0
nop
.set reorder
__exception_code_end:
.data
__previous:
.space (__exception_code_end - __exception_code)
.text
/* void __install_entry_handler(void)
Install our entry/exit reserved instruction exception handler.
*/
.ent __install_entry_handler
.globl __install_entry_handler
__install_entry_handler:
.set noreorder
mfc0 a0,C0_SR
nop
li a1,SR_BEV
and a1,a1,a0
beq a1,$0,baseaddr
lui a0,0x8000 /* delay slot */
lui a0,0xbfc0
addiu a0,a0,0x0100
baseaddr:
addiu a0,a0,0x080 /* a0 = base vector table address */
li a1,(__exception_code_end - __exception_code)
la a2,__exception_code
la a3,__previous
/* there must be a better way of doing this???? */
copyloop:
lw v0,0(a0)
sw v0,0(a3)
lw v0,0(a2)
sw v0,0(a0)
addiu a0,a0,4
addiu a2,a2,4
addiu a3,a3,4
subu a1,a1,4
bne a1,$0,copyloop
nop
j ra
nop
.set reorder
.end __install_entry_handler
/* void __remove_entry_handler(void);
Remove our entry/exit reserved instruction exception handler.
*/
.ent __remove_entry_handler
.globl __remove_entry_handler
__remove_entry_handler:
.set noreorder
mfc0 a0,C0_SR
nop
li a1,SR_BEV
and a1,a1,a0
beq a1,$0,res_baseaddr
lui a0,0x8000 /* delay slot */
lui a0,0xbfc0
addiu a0,a0,0x0200
res_baseaddr:
addiu a0,a0,0x0180 /* a0 = base vector table address */
li a1,(__exception_code_end - __exception_code)
la a3,__previous
/* there must be a better way of doing this???? */
res_copyloop:
lw v0,0(a3)
sw v0,0(a0)
addiu a0,a0,4
addiu a3,a3,4
subu a1,a1,4
bne a1,$0,res_copyloop
nop
j ra
nop
.set reorder
.end __remove_entry_handler
/* software_init_hook - install entry/exit handler and arrange to have it
removed at exit. This function is called by crt0.S. */
.text
.globl software_init_hook
.ent software_init_hook
software_init_hook:
.set noreorder
subu sp, sp, 8 /* allocate stack space */
sw ra, 4(sp) /* save return address */
jal __install_entry_handler /* install entry/exit handler */
nop
lui a0, %hi(__remove_entry_handler) /* arrange for exit to */
jal atexit /* de-install handler */
addiu a0, a0, %lo(__remove_entry_handler) /* delay slot */
lw ra, 4(sp) /* get return address */
j ra /* return */
addu sp, sp, 8 /* deallocate stack */
.set reorder
.end software_init_hook
|