]> sourceware.org Git - newlib-cygwin.git/blob - libgloss/mips/entry.S
2013-04-19 Steve Ellcey <sellcey@imgtec.com>
[newlib-cygwin.git] / libgloss / mips / entry.S
1 /* entry.S - exception handler for emulating MIPS16 'entry' and 'exit'
2 pseudo-instructions. These instructions are generated by the compiler
3 when the -mentry switch is used. The instructions are not implemented
4 in the MIPS16 CPU; hence the exception handler that emulates them.
5
6 This module contains the following public functions:
7
8 * void __install_entry_handler(void);
9
10 This function installs the entry/exit exception handler. It should
11 be called before executing any MIPS16 functions that were compiled with
12 -mentry, typically before main() is called.
13
14 * void __remove_entry_handler(void);
15
16 This function removes the entry/exit exception handler. It should
17 be called when the program is exiting, or when it is known that no
18 more MIPS16 functions compiled with -mentry will be called.
19 */
20
21 #ifdef __mips16
22 /* This file contains 32 bit assembly code. */
23 .set nomips16
24 #endif
25
26 #include "regs.S"
27
28 #define CAUSE_EXCMASK 0x3c /* mask for ExcCode in Cause Register */
29 #define EXC_RI 0x28 /* 101000 == 10 << 2 */
30
31 /* Set DEBUG to 1 to enable recording of the last 16 interrupt causes. */
32
33 #define DEBUG 0
34
35 #if DEBUG
36
37 .sdata
38 int_count:
39 .space 4 /* interrupt count modulo 16 */
40 int_cause:
41 .space 4*16 /* last 16 interrupt causes */
42 #endif
43
44 .text
45
46 .set noreorder /* Do NOT reorder instructions */
47
48
49 /* __entry_exit_handler - the reserved instruction exception handler
50 that emulates the entry and exit instruction. */
51
52 __entry_exit_handler:
53 .set noat /* Do NOT use at register */
54 #if DEBUG
55 /* Must avoid using 'la' pseudo-op because it uses gp register, which
56 may not have a good value in an exception handler. */
57
58 # la k0, int_count /* intcount = (intcount + 1) & 0xf */
59 lui k0 ,%hi(int_count)
60 addiu k0, k0 ,%lo(int_count)
61 lw k1, (k0)
62 addiu k1, k1, 1
63 andi k1, k1, 0x0f
64 sw k1, (k0)
65 # la k0, int_cause /* k1 = &int_cause[intcount] */
66 lui k0, %hi(int_cause)
67 addiu k0, k0, %lo(int_cause)
68 sll k1, k1, 2
69 add k1, k1, k0
70 #endif
71 mfc0 k0, C0_CAUSE /* Fetch cause */
72 #if DEBUG
73 sw k0, -4(k1) /* Save exception cause in buffer */
74 #endif
75 mfc0 k1, C0_EPC /* Check for Reserved Inst. without */
76 and k0, CAUSE_EXCMASK /* destroying any register */
77 subu k0, EXC_RI
78 bne k0, zero, check_others /* Sorry, go do something else */
79
80 and k0, k1, 1 /* Check for TR mode (pc.0 = 1) */
81 beq k0, zero, ri_in_32 /* Sorry, RI in 32-bit mode */
82 xor k1, 1
83
84 /* Since we now are going to emulate or die, we can use all the T-registers */
85 /* that MIPS16 does not use (at, t0-t8), and we don't have to save them. */
86
87 .set at /* Now it's ok to use at again */
88
89 #if 0
90 j leave
91 rfe
92 #endif
93
94 lhu t0, 0(k1) /* Fetch the offending instruction */
95 xor t8, k1, 1 /* Prepare t8 for exit */
96 and t1, t0, 0xf81f /* Check for entry/exit opcode */
97 bne t1, 0xe809, other_ri
98
99 deareg: and t1, t0, 0x0700 /* Isolate the three a-bits */
100 srl t1, 6 /* Adjust them so x4 is applied */
101 slt t2, t1, 17 /* See if this is the exit instruction */
102 beqz t2, doexit
103 la t2, savea
104 subu t2, t1
105 jr t2 /* Jump into the instruction table */
106 rfe /* We run the rest in user-mode */
107
108 /* This is the entry instruction! */
109 sw a3, 12(sp) /* 4: a0-a3 saved */
110 sw a2, 8(sp) /* 3: a0-a2 saved */
111 sw a1, 4(sp) /* 2: a0-a1 saved */
112 sw a0, 0(sp) /* 1: a0 saved */
113 savea: /* 0: No arg regs saved */
114
115 dera: and t1, t0, 0x0020 /* Isolate the save-ra bit */
116 move t7, sp /* Temporary SP */
117 beq t1, zero, desreg
118 subu sp, 32 /* Default SP adjustment */
119 sw ra, -4(t7)
120 subu t7, 4
121
122 desreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */
123 beq t1, zero, leave
124 subu t1, 0x0040
125 beq t1, zero, leave /* Only one to save... */
126 sw s0, -4(t7) /* Do the first one */
127 sw s1, -8(t7) /* Do the last one */
128
129 leave: jr t8 /* Exit to unmodified EPC */
130 nop /* Urgh - the only nop!! */
131
132 doexf0: mtc1 v0,$f0 /* Copy float value */
133 b doex2
134
135 doexf1: mtc1 v1,$f0 /* Copy double value */
136 mtc1 v0,$f1
137 b doex2
138
139 doexit: slt t2, t1, 21
140 beq t2, zero, doexf0
141 slt t2, t1, 25
142 beq t2, zero, doexf1
143
144 doex2: and t1, t0, 0x0020 /* Isolate ra bit */
145 beq t1, zero, dxsreg /* t1 holds ra-bit */
146 addu t7, sp, 32 /* Temporary SP */
147 lw ra, -4(t7)
148 subu t7, 4
149
150 dxsreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */
151 beq t1, zero, leavex
152 subu t1, 0x0040
153 beq t1, zero, leavex /* Only one to save... */
154 lw s0, -4(t7) /* Do the first one */
155 lw s1, -8(t7) /* Do the last one */
156
157 leavex: jr ra /* Exit to ra */
158 addu sp, 32 /* Clean up stack pointer */
159
160 /* Come here for exceptions we can't handle. */
161
162 ri_in_32:
163 other_ri:
164 check_others: /* call the previous handler */
165 la k0,__previous
166 jr k0
167 nop
168
169 __exception_code:
170 .set noreorder
171 la k0, __entry_exit_handler
172 # lui k0, %hi(exception)
173 # addiu k0, k0, %lo(exception)
174 jr k0
175 nop
176 .set reorder
177 __exception_code_end:
178
179 .data
180 __previous:
181 .space (__exception_code_end - __exception_code)
182 .text
183
184
185 /* void __install_entry_handler(void)
186
187 Install our entry/exit reserved instruction exception handler.
188 */
189 .ent __install_entry_handler
190 .globl __install_entry_handler
191 __install_entry_handler:
192 .set noreorder
193 mfc0 a0,C0_SR
194 nop
195 li a1,SR_BEV
196 and a1,a1,a0
197 beq a1,$0,baseaddr
198 lui a0,0x8000 /* delay slot */
199 lui a0,0xbfc0
200 addiu a0,a0,0x0100
201 baseaddr:
202 addiu a0,a0,0x080 /* a0 = base vector table address */
203 li a1,(__exception_code_end - __exception_code)
204 la a2,__exception_code
205 la a3,__previous
206 /* there must be a better way of doing this???? */
207 copyloop:
208 lw v0,0(a0)
209 sw v0,0(a3)
210 lw v0,0(a2)
211 sw v0,0(a0)
212 addiu a0,a0,4
213 addiu a2,a2,4
214 addiu a3,a3,4
215 subu a1,a1,4
216 bne a1,$0,copyloop
217 nop
218 j ra
219 nop
220 .set reorder
221 .end __install_entry_handler
222
223
224 /* void __remove_entry_handler(void);
225
226 Remove our entry/exit reserved instruction exception handler.
227 */
228
229 .ent __remove_entry_handler
230 .globl __remove_entry_handler
231 __remove_entry_handler:
232 .set noreorder
233
234 mfc0 a0,C0_SR
235 nop
236 li a1,SR_BEV
237 and a1,a1,a0
238 beq a1,$0,res_baseaddr
239 lui a0,0x8000 /* delay slot */
240 lui a0,0xbfc0
241 addiu a0,a0,0x0200
242 res_baseaddr:
243 addiu a0,a0,0x0180 /* a0 = base vector table address */
244 li a1,(__exception_code_end - __exception_code)
245 la a3,__previous
246
247 /* there must be a better way of doing this???? */
248 res_copyloop:
249 lw v0,0(a3)
250 sw v0,0(a0)
251 addiu a0,a0,4
252 addiu a3,a3,4
253 subu a1,a1,4
254 bne a1,$0,res_copyloop
255 nop
256 j ra
257 nop
258 .set reorder
259 .end __remove_entry_handler
260
261
262 /* software_init_hook - install entry/exit handler and arrange to have it
263 removed at exit. This function is called by crt0.S. */
264
265 .text
266 .globl software_init_hook
267 .ent software_init_hook
268 software_init_hook:
269 .set noreorder
270 subu sp, sp, 8 /* allocate stack space */
271 sw ra, 4(sp) /* save return address */
272 jal __install_entry_handler /* install entry/exit handler */
273 nop
274 lui a0, %hi(__remove_entry_handler) /* arrange for exit to */
275 jal atexit /* de-install handler */
276 addiu a0, a0, %lo(__remove_entry_handler) /* delay slot */
277 lw ra, 4(sp) /* get return address */
278 j ra /* return */
279 addu sp, sp, 8 /* deallocate stack */
280 .set reorder
281 .end software_init_hook
This page took 0.045551 seconds and 5 git commands to generate.