Newer
Older
/*
$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/mips-arch.c,v 1.9 1994/10/27 17:13:54 ram Exp $
This code was written as part of the CMU Common Lisp project at
Carnegie Mellon University, and has been placed in the public domain.
*/
#else
#ifdef irix
#include <sys/sbd.h>
#endif
#endif
#include "lisp.h"
#include "globals.h"
#include "validate.h"
#include "os.h"
#include "internals.h"
#include "arch.h"
#include "lispregs.h"
#include "signal.h"
#include "alloc.h"
#include "interrupt.h"
#include "interr.h"
#include "breakpoint.h"
char *arch_init(void)
{
return NULL;
}
os_vm_address_t arch_get_bad_addr(int sig, int code, struct sigcontext *scp)
{
/* Finding the bad address on the mips is easy. */
return (os_vm_address_t)scp->sc_badvaddr;
}
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
#ifdef irix
void
emulate_branch(struct sigcontext *scp, unsigned long inst)
{
long opcode = inst >> 26;
long r1 = (inst >> 21) & 0x1f;
long r2 = (inst >> 16) & 0x1f;
long bdisp = (inst&(1<<15)) ? inst | (-1 << 16) : inst&0xffff;
long jdisp = (inst&(1<<25)) ? inst | (-1 << 26) : inst&0xffff;
long disp = 0;
switch(opcode) {
case 0x1: /* bltz, bgez, bltzal, bgezal */
switch((inst >> 16) & 0x1f) {
case 0x00: /* bltz */
if(scp->sc_regs[r1] < 0)
disp = bdisp;
break;
case 0x01: /* bgez */
if(scp->sc_regs[r1] >= 0)
disp = bdisp;
break;
case 0x10: /* bltzal */
if(scp->sc_regs[r1] < 0)
disp = bdisp;
scp->sc_regs[31] = scp->sc_pc + 4;
break;
case 0x11: /* bgezal */
if(scp->sc_regs[r1] >= 0)
disp = bdisp;
scp->sc_regs[31] = scp->sc_pc + 4;
break;
}
break;
case 0x4: /* beq */
if(scp->sc_regs[r1] == scp->sc_regs[r2])
disp = bdisp;
break;
case 0x5: /* bne */
if(scp->sc_regs[r1] != scp->sc_regs[r2])
disp = bdisp;
break;
case 0x6: /* ble */
if(scp->sc_regs[r1] <= scp->sc_regs[r2])
disp = bdisp;
break;
case 0x7: /* bgtz */
if(scp->sc_regs[r1] >= scp->sc_regs[r2])
disp = bdisp;
break;
case 0x2: /* j */
disp = jdisp;
break;
case 0x3: /* jal */
disp = jdisp;
scp->sc_regs[31] = scp->sc_pc + 4;
break;
}
scp->sc_pc += disp*4;
}
#endif
void arch_skip_instruction(scp)
struct sigcontext *scp;
{
/* Skip the offending instruction */
if (scp->sc_cause & CAUSE_BD)
emulate_branch(scp, *(unsigned long *)scp->sc_pc);
else
scp->sc_pc += 4;
}
unsigned char *arch_internal_error_arguments(struct sigcontext *scp)
{
if (scp->sc_cause & CAUSE_BD)
return (unsigned char *)(scp->sc_pc+8);
else
return (unsigned char *)(scp->sc_pc+4);
}
boolean arch_pseudo_atomic_atomic(struct sigcontext *scp)
{
return (scp->sc_regs[reg_ALLOC] & 1);
}
#define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
void arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
scp->sc_regs[reg_NL4] += PSEUDO_ATOMIC_INTERRUPTED_BIAS;
}
unsigned long arch_install_breakpoint(void *pc)
{
unsigned long *ptr = (unsigned long *)pc;
unsigned long result = *ptr;
*ptr = (trap_Breakpoint << 16) | 0xd;
os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned long));
return result;
}
void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
{
*(unsigned long *)pc = orig_inst;
os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
}
static unsigned long *skipped_break_addr, displaced_after_inst;
void arch_do_displaced_inst(struct sigcontext *scp,
unsigned long orig_inst)
{
unsigned long *pc = (unsigned long *)scp->sc_pc;
unsigned long *break_pc, *next_pc;
unsigned long next_inst;
int opcode;
struct sigcontext tmp;
orig_sigmask = scp->sc_mask;
scp->sc_mask = BLOCKABLE;
/* Figure out where the breakpoint is, and what happens next. */
if (scp->sc_cause & CAUSE_BD) {
break_pc = pc+1;
next_inst = *pc;
}
else {
break_pc = pc;
next_inst = orig_inst;
}
/* Put the original instruction back. */
*break_pc = orig_inst;
os_flush_icache((os_vm_address_t)break_pc, sizeof(unsigned long));
skipped_break_addr = break_pc;
/* Figure out where it goes. */
opcode = next_inst >> 26;
if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000)) {
tmp = *scp;
next_pc = (unsigned long *)tmp.sc_pc;
}
else
next_pc = pc+1;
displaced_after_inst = *next_pc;
*next_pc = (trap_AfterBreakpoint << 16) | 0xd;
os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned long));
}
static void sigtrap_handler(int signal, int code, struct sigcontext *scp)
{
/* Don't disallow recursive breakpoint traps. Otherwise, we can't */
/* use debugger breakpoints anywhere in here. */
sigsetmask(scp->sc_mask);
arch_skip_instruction(scp);
interrupt_handle_pending(scp);
break;
case trap_Halt:
fake_foreign_function_call(scp);
lose("%%primitive halt called; the party is over.\n");
case trap_Error:
case trap_Cerror:
interrupt_internal_error(signal, code, scp, code==trap_Cerror);
break;
case trap_Breakpoint:
handle_breakpoint(signal, code, scp);
break;
case trap_FunctionEndBreakpoint:
scp->sc_pc = (int)handle_function_end_breakpoint(signal, code, scp);
break;
case trap_AfterBreakpoint:
*skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
os_flush_icache((os_vm_address_t)skipped_break_addr,
sizeof(unsigned long));
skipped_break_addr = NULL;
*(unsigned long *)scp->sc_pc = displaced_after_inst;
os_flush_icache((os_vm_address_t)scp->sc_pc, sizeof(unsigned long));
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
break;
default:
interrupt_handle_now(signal, code, scp);
break;
}
}
#define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
static void sigfpe_handler(int signal, int code, struct sigcontext *scp)
{
unsigned long bad_inst;
unsigned int op, rs, rt, rd, funct, dest;
int immed;
long result;
if (scp->sc_cause & CAUSE_BD)
bad_inst = *(unsigned long *)(scp->sc_pc + 4);
else
bad_inst = *(unsigned long *)(scp->sc_pc);
op = (bad_inst >> 26) & 0x3f;
rs = (bad_inst >> 21) & 0x1f;
rt = (bad_inst >> 16) & 0x1f;
rd = (bad_inst >> 11) & 0x1f;
funct = bad_inst & 0x3f;
immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
switch (op) {
case 0x0: /* SPECIAL */
switch (funct) {
case 0x20: /* ADD */
/* Check to see if this is really a pa_interrupted hit */
if (rs == reg_ALLOC && rt == reg_NL4) {
scp->sc_regs[reg_ALLOC] +=
(scp->sc_regs[reg_NL4] -
PSEUDO_ATOMIC_INTERRUPTED_BIAS);
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
arch_skip_instruction(scp);
interrupt_handle_pending(scp);
return;
}
result = FIXNUM_VALUE(scp->sc_regs[rs]) + FIXNUM_VALUE(scp->sc_regs[rt]);
dest = rd;
break;
case 0x22: /* SUB */
result = FIXNUM_VALUE(scp->sc_regs[rs]) - FIXNUM_VALUE(scp->sc_regs[rt]);
dest = rd;
break;
default:
dest = 32;
break;
}
break;
case 0x8: /* ADDI */
result = FIXNUM_VALUE(scp->sc_regs[rs]) + (immed>>2);
dest = rt;
break;
default:
dest = 32;
break;
}
if (dest < 32) {
current_dynamic_space_free_pointer =
(lispobj *) scp->sc_regs[reg_ALLOC];
scp->sc_regs[dest] = alloc_number(result);
scp->sc_regs[reg_ALLOC] =
(unsigned long) current_dynamic_space_free_pointer;
arch_skip_instruction(scp);
}
else
interrupt_handle_now(signal, code, scp);
}
void arch_install_interrupt_handlers()
{
interrupt_install_low_level_handler(SIGTRAP,sigtrap_handler);
interrupt_install_low_level_handler(SIGFPE,sigfpe_handler);
}
extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
lispobj funcall0(lispobj function)
{
lispobj *args = current_control_stack_pointer;
return call_into_lisp(function, args, 0);
}
lispobj funcall1(lispobj function, lispobj arg0)
{
lispobj *args = current_control_stack_pointer;
current_control_stack_pointer += 1;
args[0] = arg0;
return call_into_lisp(function, args, 1);
}
lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
{
lispobj *args = current_control_stack_pointer;
current_control_stack_pointer += 2;
args[0] = arg0;
args[1] = arg1;
return call_into_lisp(function, args, 2);
}
lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
{
lispobj *args = current_control_stack_pointer;
current_control_stack_pointer += 3;
args[0] = arg0;
args[1] = arg1;
args[2] = arg2;
return call_into_lisp(function, args, 3);
}
/* This is apparently called by emulate_branch, but isn't defined. So */
/* just do nothing and hope it works... */
void cacheflush(void)
{
}