3 $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/mips-arch.c,v 1.12 2008/03/19 09:17:13 cshapiro Rel $
5 This code was written as part of the CMU Common Lisp project at
6 Carnegie Mellon University, and has been placed in the public domain.
24 #include "internals.h"
29 #include "interrupt.h"
31 #include "breakpoint.h"
40 arch_get_bad_addr(int sig, int code, struct sigcontext * scp)
42 /* Finding the bad address on the mips is easy. */
43 return (os_vm_address_t) scp->sc_badvaddr;
48 emulate_branch(struct sigcontext *scp, unsigned long inst)
50 long opcode = inst >> 26;
51 long r1 = (inst >> 21) & 0x1f;
52 long r2 = (inst >> 16) & 0x1f;
53 long bdisp = (inst & (1 << 15)) ? inst | (-1 << 16) : inst & 0xffff;
54 long jdisp = (inst & (1 << 25)) ? inst | (-1 << 26) : inst & 0xffff;
58 case 0x1: /* bltz, bgez, bltzal, bgezal */
59 switch ((inst >> 16) & 0x1f) {
61 if (scp->sc_regs[r1] < 0)
65 if (scp->sc_regs[r1] >= 0)
68 case 0x10: /* bltzal */
69 if (scp->sc_regs[r1] < 0)
71 scp->sc_regs[31] = scp->sc_pc + 4;
73 case 0x11: /* bgezal */
74 if (scp->sc_regs[r1] >= 0)
76 scp->sc_regs[31] = scp->sc_pc + 4;
81 if (scp->sc_regs[r1] == scp->sc_regs[r2])
85 if (scp->sc_regs[r1] != scp->sc_regs[r2])
89 if (scp->sc_regs[r1] <= scp->sc_regs[r2])
93 if (scp->sc_regs[r1] >= scp->sc_regs[r2])
101 scp->sc_regs[31] = scp->sc_pc + 4;
104 scp->sc_pc += disp * 4;
109 arch_skip_instruction(scp)
110 struct sigcontext *scp;
112 /* Skip the offending instruction */
113 if (scp->sc_cause & CAUSE_BD)
114 emulate_branch(scp, *(unsigned long *) scp->sc_pc);
120 arch_internal_error_arguments(struct sigcontext *scp)
122 if (scp->sc_cause & CAUSE_BD)
123 return (unsigned char *) (scp->sc_pc + 8);
125 return (unsigned char *) (scp->sc_pc + 4);
129 arch_pseudo_atomic_atomic(struct sigcontext *scp)
131 return (scp->sc_regs[reg_ALLOC] & 1);
134 #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
137 arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
139 scp->sc_regs[reg_NL4] += PSEUDO_ATOMIC_INTERRUPTED_BIAS;
143 arch_install_breakpoint(void *pc)
145 unsigned long *ptr = (unsigned long *) pc;
146 unsigned long result = *ptr;
148 *ptr = (trap_Breakpoint << 16) | 0xd;
150 os_flush_icache((os_vm_address_t) ptr, sizeof(unsigned long));
156 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
158 *(unsigned long *) pc = orig_inst;
160 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
163 static unsigned long *skipped_break_addr, displaced_after_inst;
164 static int orig_sigmask;
167 arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
169 unsigned long *pc = (unsigned long *) scp->sc_pc;
170 unsigned long *break_pc, *next_pc;
171 unsigned long next_inst;
173 struct sigcontext tmp;
175 orig_sigmask = scp->sc_mask;
176 scp->sc_mask = BLOCKABLE;
178 /* Figure out where the breakpoint is, and what happens next. */
179 if (scp->sc_cause & CAUSE_BD) {
184 next_inst = orig_inst;
187 /* Put the original instruction back. */
188 *break_pc = orig_inst;
189 os_flush_icache((os_vm_address_t) break_pc, sizeof(unsigned long));
191 skipped_break_addr = break_pc;
193 /* Figure out where it goes. */
194 opcode = next_inst >> 26;
195 if (opcode == 1 || ((opcode & 0x3c) == 0x4)
196 || ((next_inst & 0xf00e0000) == 0x80000000)) {
198 emulate_branch(&tmp, next_inst);
199 next_pc = (unsigned long *) tmp.sc_pc;
203 displaced_after_inst = *next_pc;
204 *next_pc = (trap_AfterBreakpoint << 16) | 0xd;
205 os_flush_icache((os_vm_address_t) next_pc, sizeof(unsigned long));
213 sigtrap_handler(int signal, int code, struct sigcontext *scp)
215 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
216 /* use debugger breakpoints anywhere in here. */
217 sigsetmask(scp->sc_mask);
220 case trap_PendingInterrupt:
221 arch_skip_instruction(scp);
222 interrupt_handle_pending(scp);
226 fake_foreign_function_call(scp);
227 lose("%%primitive halt called; the party is over.\n");
231 interrupt_internal_error(signal, code, scp, code == trap_Cerror);
234 case trap_Breakpoint:
235 handle_breakpoint(signal, code, scp);
238 case trap_FunctionEndBreakpoint:
239 scp->sc_pc = (int) handle_function_end_breakpoint(signal, code, scp);
242 case trap_AfterBreakpoint:
243 *skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
244 os_flush_icache((os_vm_address_t) skipped_break_addr,
246 sizeof(unsigned long));
247 skipped_break_addr = NULL;
248 *(unsigned long *) scp->sc_pc = displaced_after_inst;
249 os_flush_icache((os_vm_address_t) scp->sc_pc, sizeof(unsigned long));
251 scp->sc_mask = orig_sigmask;
255 interrupt_handle_now(signal, code, scp);
261 sigfpe_handler(int signal, int code, struct sigcontext *scp)
263 unsigned long bad_inst;
264 unsigned int op, rs, rt, rd, funct, dest;
268 if (scp->sc_cause & CAUSE_BD)
269 bad_inst = *(unsigned long *) (scp->sc_pc + 4);
271 bad_inst = *(unsigned long *) (scp->sc_pc);
273 op = (bad_inst >> 26) & 0x3f;
274 rs = (bad_inst >> 21) & 0x1f;
275 rt = (bad_inst >> 16) & 0x1f;
276 rd = (bad_inst >> 11) & 0x1f;
277 funct = bad_inst & 0x3f;
278 immed = (((int) (bad_inst & 0xffff)) << 16) >> 16;
281 case 0x0: /* SPECIAL */
284 /* Check to see if this is really a pa_interrupted hit */
285 if (rs == reg_ALLOC && rt == reg_NL4) {
286 scp->sc_regs[reg_ALLOC] +=
287 (scp->sc_regs[reg_NL4] -
288 PSEUDO_ATOMIC_INTERRUPTED_BIAS);
289 arch_skip_instruction(scp);
290 interrupt_handle_pending(scp);
294 fixnum_value(scp->sc_regs[rs]) +
295 fixnum_value(scp->sc_regs[rt]);
301 fixnum_value(scp->sc_regs[rs]) -
302 fixnum_value(scp->sc_regs[rt]);
313 result = fixnum_value(scp->sc_regs[rs]) + (immed >> 2);
323 current_dynamic_space_free_pointer =
324 (lispobj *) scp->sc_regs[reg_ALLOC];
326 scp->sc_regs[dest] = alloc_number(result);
328 scp->sc_regs[reg_ALLOC] =
329 (unsigned long) current_dynamic_space_free_pointer;
331 arch_skip_instruction(scp);
334 interrupt_handle_now(signal, code, scp);
338 arch_install_interrupt_handlers(void)
340 interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
341 interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
344 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
347 funcall0(lispobj function)
349 lispobj *args = current_control_stack_pointer;
351 return call_into_lisp(function, args, 0);
355 funcall1(lispobj function, lispobj arg0)
357 lispobj *args = current_control_stack_pointer;
359 current_control_stack_pointer += 1;
362 return call_into_lisp(function, args, 1);
366 funcall2(lispobj function, lispobj arg0, lispobj arg1)
368 lispobj *args = current_control_stack_pointer;
370 current_control_stack_pointer += 2;
374 return call_into_lisp(function, args, 2);
378 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
380 lispobj *args = current_control_stack_pointer;
382 current_control_stack_pointer += 3;
387 return call_into_lisp(function, args, 3);
391 /* This is apparently called by emulate_branch, but isn't defined. So */
392 /* just do nothing and hope it works... */