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.
6 This module contains the following public functions:
8 * void __install_entry_handler(void);
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.
14 * void __remove_entry_handler(void);
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.
22 /* This file contains 32 bit assembly code. */
28 #define CAUSE_EXCMASK 0x3c /* mask for ExcCode in Cause Register */
29 #define EXC_RI 0x28 /* 101000 == 10 << 2 */
31 /* Set DEBUG to 1 to enable recording of the last 16 interrupt causes. */
39 .space 4 /* interrupt count modulo 16 */
41 .space 4*16 /* last 16 interrupt causes */
46 .set noreorder /* Do NOT reorder instructions */
49 /* __entry_exit_handler - the reserved instruction exception handler
50 that emulates the entry and exit instruction. */
53 .set noat /* Do NOT use at register */
55 /* Must avoid using 'la' pseudo-op because it uses gp register, which
56 may not have a good value in an exception handler. */
58 # la k0, int_count /* intcount = (intcount + 1) & 0xf */
59 lui k0 ,%hi(int_count)
60 addiu k0, k0 ,%lo(int_count)
65 # la k0, int_cause /* k1 = &int_cause[intcount] */
66 lui k0, %hi(int_cause)
67 addiu k0, k0, %lo(int_cause)
71 mfc0 k0, C0_CAUSE /* Fetch cause */
73 sw k0, -4(k1) /* Save exception cause in buffer */
75 mfc0 k1, C0_EPC /* Check for Reserved Inst. without */
76 and k0, CAUSE_EXCMASK /* destroying any register */
78 bne k0, zero, check_others /* Sorry, go do something else */
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 */
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. */
87 .set at /* Now it's ok to use at again */
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
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 */
105 jr t2 /* Jump into the instruction table */
106 rfe /* We run the rest in user-mode */
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 */
115 dera: and t1, t0, 0x0020 /* Isolate the save-ra bit */
116 move t7, sp /* Temporary SP */
118 subu sp, 32 /* Default SP adjustment */
122 desreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */
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 */
129 leave: jr t8 /* Exit to unmodified EPC */
130 nop /* Urgh - the only nop!! */
132 doexf0: mtc1 v0,$f0 /* Copy float value */
135 doexf1: mtc1 v1,$f0 /* Copy double value */
139 doexit: slt t2, t1, 21
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 */
150 dxsreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */
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 */
157 leavex: jr ra /* Exit to ra */
158 addu sp, 32 /* Clean up stack pointer */
160 /* Come here for exceptions we can't handle. */
164 check_others: /* call the previous handler */
171 la k0, __entry_exit_handler
172 # lui k0, %hi(exception)
173 # addiu k0, k0, %lo(exception)
177 __exception_code_end:
181 .space (__exception_code_end - __exception_code)
185 /* void __install_entry_handler(void)
187 Install our entry/exit reserved instruction exception handler.
189 .ent __install_entry_handler
190 .globl __install_entry_handler
191 __install_entry_handler:
198 lui a0,0x8000 /* delay slot */
202 addiu a0,a0,0x080 /* a0 = base vector table address */
203 li a1,(__exception_code_end - __exception_code)
204 la a2,__exception_code
206 /* there must be a better way of doing this???? */
221 .end __install_entry_handler
224 /* void __remove_entry_handler(void);
226 Remove our entry/exit reserved instruction exception handler.
229 .ent __remove_entry_handler
230 .globl __remove_entry_handler
231 __remove_entry_handler:
238 beq a1,$0,res_baseaddr
239 lui a0,0x8000 /* delay slot */
243 addiu a0,a0,0x0180 /* a0 = base vector table address */
244 li a1,(__exception_code_end - __exception_code)
247 /* there must be a better way of doing this???? */
254 bne a1,$0,res_copyloop
259 .end __remove_entry_handler
262 /* software_init_hook - install entry/exit handler and arrange to have it
263 removed at exit. This function is called by crt0.S. */
266 .globl software_init_hook
267 .ent software_init_hook
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 */
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 */
279 addu sp, sp, 8 /* deallocate stack */
281 .end software_init_hook