Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / mips-arch.c
CommitLineData
82a2bc67 1/*
2
82a2bc67 3 This code was written as part of the CMU Common Lisp project at
4 Carnegie Mellon University, and has been placed in the public domain.
5
6*/
7
62957726 8#include <stdio.h>
0dda2eec 9
10#ifdef mach
62957726 11#include <mips/cpu.h>
0dda2eec 12#else
13#ifdef irix
14#include <sys/sbd.h>
15#endif
16#endif
62957726 17
18#include "lisp.h"
19#include "globals.h"
20#include "validate.h"
21#include "os.h"
22#include "internals.h"
23#include "arch.h"
24#include "lispregs.h"
25#include "signal.h"
26#include "alloc.h"
27#include "interrupt.h"
28#include "interr.h"
29#include "breakpoint.h"
30
9a8c1c2f 31char *
32arch_init(void)
62957726 33{
34 return NULL;
35}
36
9a8c1c2f 37os_vm_address_t
38arch_get_bad_addr(int sig, int code, struct sigcontext * scp)
62957726 39{
40 /* Finding the bad address on the mips is easy. */
9a8c1c2f 41 return (os_vm_address_t) scp->sc_badvaddr;
62957726 42}
43
f2d8a32d 44#ifdef irix
45void
46emulate_branch(struct sigcontext *scp, unsigned long inst)
47{
9a8c1c2f 48 long opcode = inst >> 26;
49 long r1 = (inst >> 21) & 0x1f;
50 long r2 = (inst >> 16) & 0x1f;
51 long bdisp = (inst & (1 << 15)) ? inst | (-1 << 16) : inst & 0xffff;
52 long jdisp = (inst & (1 << 25)) ? inst | (-1 << 26) : inst & 0xffff;
53 long disp = 0;
54
55 switch (opcode) {
56 case 0x1: /* bltz, bgez, bltzal, bgezal */
57 switch ((inst >> 16) & 0x1f) {
58 case 0x00: /* bltz */
59 if (scp->sc_regs[r1] < 0)
60 disp = bdisp;
61 break;
62 case 0x01: /* bgez */
63 if (scp->sc_regs[r1] >= 0)
64 disp = bdisp;
65 break;
66 case 0x10: /* bltzal */
67 if (scp->sc_regs[r1] < 0)
68 disp = bdisp;
69 scp->sc_regs[31] = scp->sc_pc + 4;
70 break;
71 case 0x11: /* bgezal */
72 if (scp->sc_regs[r1] >= 0)
73 disp = bdisp;
74 scp->sc_regs[31] = scp->sc_pc + 4;
75 break;
76 }
77 break;
78 case 0x4: /* beq */
79 if (scp->sc_regs[r1] == scp->sc_regs[r2])
80 disp = bdisp;
81 break;
82 case 0x5: /* bne */
83 if (scp->sc_regs[r1] != scp->sc_regs[r2])
84 disp = bdisp;
85 break;
86 case 0x6: /* ble */
87 if (scp->sc_regs[r1] <= scp->sc_regs[r2])
88 disp = bdisp;
89 break;
90 case 0x7: /* bgtz */
91 if (scp->sc_regs[r1] >= scp->sc_regs[r2])
92 disp = bdisp;
93 break;
94 case 0x2: /* j */
95 disp = jdisp;
96 break;
97 case 0x3: /* jal */
98 disp = jdisp;
99 scp->sc_regs[31] = scp->sc_pc + 4;
100 break;
f2d8a32d 101 }
9a8c1c2f 102 scp->sc_pc += disp * 4;
f2d8a32d 103}
104#endif
105
9a8c1c2f 106void
107arch_skip_instruction(scp)
108 struct sigcontext *scp;
62957726 109{
110 /* Skip the offending instruction */
111 if (scp->sc_cause & CAUSE_BD)
9a8c1c2f 112 emulate_branch(scp, *(unsigned long *) scp->sc_pc);
62957726 113 else
9a8c1c2f 114 scp->sc_pc += 4;
62957726 115}
116
9a8c1c2f 117unsigned char *
118arch_internal_error_arguments(struct sigcontext *scp)
62957726 119{
120 if (scp->sc_cause & CAUSE_BD)
9a8c1c2f 121 return (unsigned char *) (scp->sc_pc + 8);
62957726 122 else
9a8c1c2f 123 return (unsigned char *) (scp->sc_pc + 4);
62957726 124}
125
9a8c1c2f 126boolean
127arch_pseudo_atomic_atomic(struct sigcontext *scp)
62957726 128{
129 return (scp->sc_regs[reg_ALLOC] & 1);
130}
131
85ee26dd 132#define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
62957726 133
9a8c1c2f 134void
135arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
62957726 136{
85ee26dd 137 scp->sc_regs[reg_NL4] += PSEUDO_ATOMIC_INTERRUPTED_BIAS;
62957726 138}
139
9a8c1c2f 140unsigned long
141arch_install_breakpoint(void *pc)
62957726 142{
9a8c1c2f 143 unsigned long *ptr = (unsigned long *) pc;
62957726 144 unsigned long result = *ptr;
9a8c1c2f 145
62957726 146 *ptr = (trap_Breakpoint << 16) | 0xd;
e8e8525a 147
9a8c1c2f 148 os_flush_icache((os_vm_address_t) ptr, sizeof(unsigned long));
e8e8525a 149
62957726 150 return result;
151}
152
9a8c1c2f 153void
154arch_remove_breakpoint(void *pc, unsigned long orig_inst)
62957726 155{
9a8c1c2f 156 *(unsigned long *) pc = orig_inst;
e8e8525a 157
9a8c1c2f 158 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
62957726 159}
160
161static unsigned long *skipped_break_addr, displaced_after_inst;
6b1d440f 162static int orig_sigmask;
62957726 163
9a8c1c2f 164void
165arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
62957726 166{
9a8c1c2f 167 unsigned long *pc = (unsigned long *) scp->sc_pc;
62957726 168 unsigned long *break_pc, *next_pc;
169 unsigned long next_inst;
170 int opcode;
171 struct sigcontext tmp;
172
6b1d440f 173 orig_sigmask = scp->sc_mask;
174 scp->sc_mask = BLOCKABLE;
175
62957726 176 /* Figure out where the breakpoint is, and what happens next. */
177 if (scp->sc_cause & CAUSE_BD) {
9a8c1c2f 178 break_pc = pc + 1;
62957726 179 next_inst = *pc;
9a8c1c2f 180 } else {
62957726 181 break_pc = pc;
182 next_inst = orig_inst;
183 }
184
185 /* Put the original instruction back. */
186 *break_pc = orig_inst;
9a8c1c2f 187 os_flush_icache((os_vm_address_t) break_pc, sizeof(unsigned long));
188
62957726 189 skipped_break_addr = break_pc;
190
191 /* Figure out where it goes. */
192 opcode = next_inst >> 26;
9a8c1c2f 193 if (opcode == 1 || ((opcode & 0x3c) == 0x4)
194 || ((next_inst & 0xf00e0000) == 0x80000000)) {
62957726 195 tmp = *scp;
9a8c1c2f 196 emulate_branch(&tmp, next_inst);
197 next_pc = (unsigned long *) tmp.sc_pc;
198 } else
199 next_pc = pc + 1;
62957726 200
201 displaced_after_inst = *next_pc;
202 *next_pc = (trap_AfterBreakpoint << 16) | 0xd;
9a8c1c2f 203 os_flush_icache((os_vm_address_t) next_pc, sizeof(unsigned long));
62957726 204
0dda2eec 205#ifdef mach
62957726 206 sigreturn(scp);
0dda2eec 207#endif
62957726 208}
209
9a8c1c2f 210static void
211sigtrap_handler(int signal, int code, struct sigcontext *scp)
62957726 212{
6b1d440f 213 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
214 /* use debugger breakpoints anywhere in here. */
215 sigsetmask(scp->sc_mask);
216
62957726 217 switch (code) {
218 case trap_PendingInterrupt:
9a8c1c2f 219 arch_skip_instruction(scp);
220 interrupt_handle_pending(scp);
221 break;
62957726 222
223 case trap_Halt:
9a8c1c2f 224 fake_foreign_function_call(scp);
225 lose("%%primitive halt called; the party is over.\n");
62957726 226
227 case trap_Error:
228 case trap_Cerror:
9a8c1c2f 229 interrupt_internal_error(signal, code, scp, code == trap_Cerror);
230 break;
62957726 231
232 case trap_Breakpoint:
9a8c1c2f 233 handle_breakpoint(signal, code, scp);
234 break;
62957726 235
236 case trap_FunctionEndBreakpoint:
9a8c1c2f 237 scp->sc_pc = (int) handle_function_end_breakpoint(signal, code, scp);
238 break;
62957726 239
240 case trap_AfterBreakpoint:
9a8c1c2f 241 *skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
242 os_flush_icache((os_vm_address_t) skipped_break_addr,
243
244 sizeof(unsigned long));
245 skipped_break_addr = NULL;
246 *(unsigned long *) scp->sc_pc = displaced_after_inst;
247 os_flush_icache((os_vm_address_t) scp->sc_pc, sizeof(unsigned long));
248
249 scp->sc_mask = orig_sigmask;
250 break;
62957726 251
252 default:
9a8c1c2f 253 interrupt_handle_now(signal, code, scp);
254 break;
62957726 255 }
256}
257
9a8c1c2f 258static void
259sigfpe_handler(int signal, int code, struct sigcontext *scp)
62957726 260{
261 unsigned long bad_inst;
262 unsigned int op, rs, rt, rd, funct, dest;
263 int immed;
264 long result;
265
266 if (scp->sc_cause & CAUSE_BD)
9a8c1c2f 267 bad_inst = *(unsigned long *) (scp->sc_pc + 4);
62957726 268 else
9a8c1c2f 269 bad_inst = *(unsigned long *) (scp->sc_pc);
62957726 270
271 op = (bad_inst >> 26) & 0x3f;
272 rs = (bad_inst >> 21) & 0x1f;
273 rt = (bad_inst >> 16) & 0x1f;
274 rd = (bad_inst >> 11) & 0x1f;
275 funct = bad_inst & 0x3f;
9a8c1c2f 276 immed = (((int) (bad_inst & 0xffff)) << 16) >> 16;
62957726 277
278 switch (op) {
9a8c1c2f 279 case 0x0: /* SPECIAL */
280 switch (funct) {
281 case 0x20: /* ADD */
282 /* Check to see if this is really a pa_interrupted hit */
283 if (rs == reg_ALLOC && rt == reg_NL4) {
284 scp->sc_regs[reg_ALLOC] +=
285 (scp->sc_regs[reg_NL4] -
286 PSEUDO_ATOMIC_INTERRUPTED_BIAS);
287 arch_skip_instruction(scp);
288 interrupt_handle_pending(scp);
289 return;
290 }
291 result =
7df234a8 292 fixnum_value(scp->sc_regs[rs]) +
293 fixnum_value(scp->sc_regs[rt]);
9a8c1c2f 294 dest = rd;
295 break;
296
297 case 0x22: /* SUB */
298 result =
7df234a8 299 fixnum_value(scp->sc_regs[rs]) -
300 fixnum_value(scp->sc_regs[rt]);
9a8c1c2f 301 dest = rd;
302 break;
303
304 default:
305 dest = 32;
306 break;
307 }
308 break;
309
310 case 0x8: /* ADDI */
7df234a8 311 result = fixnum_value(scp->sc_regs[rs]) + (immed >> 2);
9a8c1c2f 312 dest = rt;
313 break;
314
315 default:
316 dest = 32;
317 break;
62957726 318 }
319
320 if (dest < 32) {
9a8c1c2f 321 current_dynamic_space_free_pointer =
322 (lispobj *) scp->sc_regs[reg_ALLOC];
62957726 323
9a8c1c2f 324 scp->sc_regs[dest] = alloc_number(result);
62957726 325
326 scp->sc_regs[reg_ALLOC] =
327 (unsigned long) current_dynamic_space_free_pointer;
328
9a8c1c2f 329 arch_skip_instruction(scp);
62957726 330
9a8c1c2f 331 } else
332 interrupt_handle_now(signal, code, scp);
62957726 333}
334
9a8c1c2f 335void
b8d0dfaf 336arch_install_interrupt_handlers(void)
62957726 337{
9a8c1c2f 338 interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
339 interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
62957726 340}
341
9a8c1c2f 342extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
62957726 343
9a8c1c2f 344lispobj
345funcall0(lispobj function)
62957726 346{
347 lispobj *args = current_control_stack_pointer;
348
349 return call_into_lisp(function, args, 0);
350}
351
9a8c1c2f 352lispobj
353funcall1(lispobj function, lispobj arg0)
62957726 354{
355 lispobj *args = current_control_stack_pointer;
356
357 current_control_stack_pointer += 1;
358 args[0] = arg0;
359
360 return call_into_lisp(function, args, 1);
361}
362
9a8c1c2f 363lispobj
364funcall2(lispobj function, lispobj arg0, lispobj arg1)
62957726 365{
366 lispobj *args = current_control_stack_pointer;
367
368 current_control_stack_pointer += 2;
369 args[0] = arg0;
370 args[1] = arg1;
371
372 return call_into_lisp(function, args, 2);
373}
374
9a8c1c2f 375lispobj
376funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
62957726 377{
378 lispobj *args = current_control_stack_pointer;
379
380 current_control_stack_pointer += 3;
381 args[0] = arg0;
382 args[1] = arg1;
383 args[2] = arg2;
384
385 return call_into_lisp(function, args, 3);
386}
387
388
389/* This is apparently called by emulate_branch, but isn't defined. So */
390/* just do nothing and hope it works... */
391
9a8c1c2f 392void
393cacheflush(void)
62957726 394{
395}