0.9.1.55: trivial cleanup, new documentation directory
[sbcl.git] / src / runtime / mips-arch.c
index a65a381..0ec497b 100644 (file)
@@ -1,7 +1,5 @@
 /*
 
 /*
 
- $Header$
-
  This code was written as part of the CMU Common Lisp project at
  Carnegie Mellon University, and has been placed in the public domain.
 
  This code was written as part of the CMU Common Lisp project at
  Carnegie Mellon University, and has been placed in the public domain.
 
@@ -9,9 +7,9 @@
 
 #include <stdio.h>
 
 
 #include <stdio.h>
 
+#include "sbcl.h"
 #include "runtime.h"
 #include "arch.h"
 #include "runtime.h"
 #include "arch.h"
-#include "sbcl.h"
 #include "globals.h"
 #include "validate.h"
 #include "os.h"
 #include "globals.h"
 #include "validate.h"
 #include "os.h"
 #include "breakpoint.h"
 #include "monitor.h"
 
 #include "breakpoint.h"
 #include "monitor.h"
 
-void arch_init()
+#include "genesis/constants.h"
+
+void
+arch_init()
 {
     return;
 }
 
 {
     return;
 }
 
-os_vm_address_t arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
+os_vm_address_t
+arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
 {
     /* Classic CMUCL comment:
 
 {
     /* Classic CMUCL comment:
 
@@ -36,87 +38,106 @@ os_vm_address_t arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *
     return (os_vm_address_t) siginfo->si_addr;
 }
 
     return (os_vm_address_t) siginfo->si_addr;
 }
 
-unsigned long 
-emulate_branch(os_context_t *context, unsigned long inst)
+static unsigned int
+emulate_branch(os_context_t *context, unsigned int 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;
+    unsigned int opcode = inst >> 26;
+    unsigned int r1 = (inst >> 21) & 0x1f;
+    unsigned int r2 = (inst >> 16) & 0x1f;
+    unsigned int r3 = (inst >> 11) & 0x1f;
+    unsigned int disp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
+    unsigned int jtgt = (*os_context_pc_addr(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2;
+    unsigned int tgt = *os_context_pc_addr(context);
 
     switch(opcode) {
 
     switch(opcode) {
+    case 0x0: /* jr, jalr */
+       switch(inst & 0x3f) {
+       case 0x08: /* jr */
+           tgt = *os_context_register_addr(context, r1);
+           break;
+       case 0x09: /* jalr */
+           tgt = *os_context_register_addr(context, r1);
+           *os_context_register_addr(context, r3)
+               = *os_context_pc_addr(context) + 4;
+           break;
+       }
+       break;
     case 0x1: /* bltz, bgez, bltzal, bgezal */
        switch((inst >> 16) & 0x1f) {
        case 0x00: /* bltz */
            if(*os_context_register_addr(context, r1) < 0)
     case 0x1: /* bltz, bgez, bltzal, bgezal */
        switch((inst >> 16) & 0x1f) {
        case 0x00: /* bltz */
            if(*os_context_register_addr(context, r1) < 0)
-               disp = bdisp;
+               tgt += disp;
            break;
        case 0x01: /* bgez */
            if(*os_context_register_addr(context, r1) >= 0)
            break;
        case 0x01: /* bgez */
            if(*os_context_register_addr(context, r1) >= 0)
-               disp = bdisp;
+               tgt += disp;
            break;
        case 0x10: /* bltzal */
            if(*os_context_register_addr(context, r1) < 0)
            break;
        case 0x10: /* bltzal */
            if(*os_context_register_addr(context, r1) < 0)
-               disp = bdisp;
-           *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
+               tgt += disp;
+           *os_context_register_addr(context, 31)
+               = *os_context_pc_addr(context) + 4;
            break;
        case 0x11: /* bgezal */
            if(*os_context_register_addr(context, r1) >= 0)
            break;
        case 0x11: /* bgezal */
            if(*os_context_register_addr(context, r1) >= 0)
-               disp = bdisp;
-           *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
+               tgt += disp;
+           *os_context_register_addr(context, 31)
+               = *os_context_pc_addr(context) + 4;
            break;
        }
        break;
     case 0x4: /* beq */
        if(*os_context_register_addr(context, r1)
           == *os_context_register_addr(context, r2))
            break;
        }
        break;
     case 0x4: /* beq */
        if(*os_context_register_addr(context, r1)
           == *os_context_register_addr(context, r2))
-           disp = bdisp;
+           tgt += disp;
        break;
     case 0x5: /* bne */
        if(*os_context_register_addr(context, r1) 
           != *os_context_register_addr(context, r2))
        break;
     case 0x5: /* bne */
        if(*os_context_register_addr(context, r1) 
           != *os_context_register_addr(context, r2))
-           disp = bdisp;
+           tgt += disp;
        break;
        break;
-    case 0x6: /* ble */
+    case 0x6: /* blez */
        if(*os_context_register_addr(context, r1)
        if(*os_context_register_addr(context, r1)
-          /* FIXME: One has to assume that the CMUCL gods of old have
-              got the sign issues right... but it might be worth
-              checking, someday */
           <= *os_context_register_addr(context, r2))
           <= *os_context_register_addr(context, r2))
-           disp = bdisp;
+           tgt += disp;
        break;
     case 0x7: /* bgtz */
        if(*os_context_register_addr(context, r1)
        break;
     case 0x7: /* bgtz */
        if(*os_context_register_addr(context, r1)
-          >= *os_context_register_addr(context, r2))
-           disp = bdisp;
+          > *os_context_register_addr(context, r2))
+           tgt += disp;
        break;
     case 0x2: /* j */
        break;
     case 0x2: /* j */
-       disp = jdisp;
+       tgt = jtgt;
        break;
     case 0x3: /* jal */
        break;
     case 0x3: /* jal */
-       disp = jdisp;
-       *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
+       tgt = jtgt;
+       *os_context_register_addr(context, 31)
+           = *os_context_pc_addr(context) + 4;
        break;
     }
        break;
     }
-    return (*os_context_pc_addr(context) + disp * 4);
+    return tgt;
 }
 
 }
 
-void arch_skip_instruction(os_context_t *context)
+void
+arch_skip_instruction(os_context_t *context)
 {
     /* Skip the offending instruction */
 {
     /* Skip the offending instruction */
-    if (os_context_bd_cause(context))
-        *os_context_pc_addr(context) = 
-           emulate_branch(context, 
-                          *(unsigned long *) *os_context_pc_addr(context));
-    else
+    if (os_context_bd_cause(context)) {
+       /* Currently, we never get here, because Linux' support for
+           bd_cause seems not terribly solid (c.f os_context_bd_cause
+           in mips-linux-os.c).  If a port to Irix comes along, this
+           code will be executed, because presumably Irix' support is
+           better (it can hardly be worse).  We lose() to remind the
+           porter to review this code.  -- CSR, 2002-09-06 */
+       lose("bd_cause branch taken; review code for new OS?\n");
+        *os_context_pc_addr(context)
+           = emulate_branch(context, *os_context_pc_addr(context));
+    } else
         *os_context_pc_addr(context) += 4;
         *os_context_pc_addr(context) += 4;
-
-    os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
 }
 
 }
 
-unsigned char *arch_internal_error_arguments(os_context_t *context)
+unsigned char *
+arch_internal_error_arguments(os_context_t *context)
 {
     if (os_context_bd_cause(context))
        return (unsigned char *)(*os_context_pc_addr(context) + 8);
 {
     if (os_context_bd_cause(context))
        return (unsigned char *)(*os_context_pc_addr(context) + 8);
@@ -124,45 +145,48 @@ unsigned char *arch_internal_error_arguments(os_context_t *context)
        return (unsigned char *)(*os_context_pc_addr(context) + 4);
 }
 
        return (unsigned char *)(*os_context_pc_addr(context) + 4);
 }
 
-boolean arch_pseudo_atomic_atomic(os_context_t *context)
+boolean
+arch_pseudo_atomic_atomic(os_context_t *context)
 {
     return *os_context_register_addr(context, reg_ALLOC) & 1;
 }
 
 {
     return *os_context_register_addr(context, reg_ALLOC) & 1;
 }
 
-#define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
-
-void arch_set_pseudo_atomic_interrupted(os_context_t *context)
+void
+arch_set_pseudo_atomic_interrupted(os_context_t *context)
 {
 {
-    *os_context_register_addr(context, reg_NL4) |= 1<<31;
+    *os_context_register_addr(context, reg_NL4) |= -1LL<<31;
 }
 
 }
 
-unsigned long arch_install_breakpoint(void *pc)
+unsigned long
+arch_install_breakpoint(void *pc)
 {
 {
-    unsigned long *ptr = (unsigned long *)pc;
-    unsigned long result = *ptr;
-    *ptr = (trap_Breakpoint << 16) | 0xd;
+    unsigned int *ptr = (unsigned int *)pc;
+    unsigned long result = (unsigned long) *ptr;
 
 
-    os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned long));
+    *ptr = (trap_Breakpoint << 16) | 0xd;
+    os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
 
     return result;
 }
 
 
     return result;
 }
 
-void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
+void
+arch_remove_breakpoint(void *pc, unsigned long orig_inst)
 {
 {
-    *(unsigned long *)pc = orig_inst;
+    unsigned int *ptr = (unsigned int *)pc;
 
 
-    os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
+    *ptr = (unsigned int) orig_inst;
+    os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
 }
 
 }
 
-static unsigned long *skipped_break_addr, displaced_after_inst;
+static unsigned int *skipped_break_addr, displaced_after_inst;
 static sigset_t orig_sigmask;
 
 static sigset_t orig_sigmask;
 
-void arch_do_displaced_inst(os_context_t *context,
-                           unsigned int orig_inst)
+void
+arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
 {
 {
-    unsigned long *pc = (unsigned long *)*os_context_pc_addr(context);
-    unsigned long *break_pc, *next_pc;
-    unsigned long next_inst;
+    unsigned int *pc = (unsigned int *)*os_context_pc_addr(context);
+    unsigned int *break_pc, *next_pc;
+    unsigned int next_inst;
     int opcode;
 
     orig_sigmask = *os_context_sigmask_addr(context);
     int opcode;
 
     orig_sigmask = *os_context_sigmask_addr(context);
@@ -179,71 +203,69 @@ void arch_do_displaced_inst(os_context_t *context,
     }
 
     /* Put the original instruction back. */
     }
 
     /* Put the original instruction back. */
-    *break_pc = orig_inst;
-    os_flush_icache((os_vm_address_t)break_pc, sizeof(unsigned long));
+    arch_remove_breakpoint(break_pc, orig_inst);
     skipped_break_addr = break_pc;
 
     /* Figure out where it goes. */
     opcode = next_inst >> 26;
     skipped_break_addr = break_pc;
 
     /* Figure out where it goes. */
     opcode = next_inst >> 26;
-    if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000)) {
-        
-        next_pc = emulate_branch(context, next_inst);
-    }
+    if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000))
+        next_pc = (unsigned int *)emulate_branch(context, next_inst);
     else
        next_pc = pc+1;
 
     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));
+    displaced_after_inst = arch_install_breakpoint(next_pc);
 }
 
 }
 
-static void sigtrap_handler(int signal, siginfo_t *info, void *void_context)
+static void
+sigill_handler(int signal, siginfo_t *info, void *void_context)
 {
     os_context_t *context = arch_os_get_context(&void_context);
 {
     os_context_t *context = arch_os_get_context(&void_context);
-    sigset_t *mask;
-    int code;
-    /* Don't disallow recursive breakpoint traps.  Otherwise, we can't */
-    /* use debugger breakpoints anywhere in here. */
-    mask = os_context_sigmask_addr(context);
-    sigsetmask(mask);
+
+    fake_foreign_function_call(context);
+    monitor_or_something();
+}
+
+static void
+sigtrap_handler(int signal, siginfo_t *info, void *void_context)
+{
+    os_context_t *context = arch_os_get_context(&void_context);
+    unsigned int code;
+
     code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
 
     switch (code) {
     code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
 
     switch (code) {
+    case trap_Halt:
+       fake_foreign_function_call(context);
+       lose("%%primitive halt called; the party is over.\n");
+
     case trap_PendingInterrupt:
        arch_skip_instruction(context);
        interrupt_handle_pending(context);
        break;
     case trap_PendingInterrupt:
        arch_skip_instruction(context);
        interrupt_handle_pending(context);
        break;
-       
-    case trap_Halt:
-       fake_foreign_function_call(context);
-       lose("%%primitive halt called; the party is over.\n");
-       
+
     case trap_Error:
     case trap_Cerror:
        interrupt_internal_error(signal, info, context, code==trap_Cerror);
        break;
     case trap_Error:
     case trap_Cerror:
        interrupt_internal_error(signal, info, context, code==trap_Cerror);
        break;
-       
+
     case trap_Breakpoint:
        handle_breakpoint(signal, info, context);
        break;
     case trap_Breakpoint:
        handle_breakpoint(signal, info, context);
        break;
-       
+
     case trap_FunEndBreakpoint:
        *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
     case trap_FunEndBreakpoint:
        *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
+       os_flush_icache((os_vm_address_t)*os_context_pc_addr(context), sizeof(unsigned int));
        break;
        break;
-       
+
     case trap_AfterBreakpoint:
     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 *)(*os_context_pc_addr(context)) = displaced_after_inst;
-       os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
+       arch_remove_breakpoint(os_context_pc_addr(context), displaced_after_inst);
+       displaced_after_inst = arch_install_breakpoint(skipped_break_addr);
        *os_context_sigmask_addr(context) = orig_sigmask;
        break;
 
     case 0x10:
        *os_context_sigmask_addr(context) = orig_sigmask;
        break;
 
     case 0x10:
-       /* Clear the flag */
-       *os_context_register_addr(context, reg_NL4) &= 0x7fffffff;
+       /* Clear the pseudo-atomic flag */
+       *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
        arch_skip_instruction(context);
        interrupt_handle_pending(context);
        return;
        arch_skip_instruction(context);
        interrupt_handle_pending(context);
        return;
@@ -254,22 +276,21 @@ static void sigtrap_handler(int signal, siginfo_t *info, void *void_context)
     }
 }
 
     }
 }
 
-/* FIXME: We must have one of these somewhere. Also, export
-   N-FIXNUM-TAG-BITS from Lispland and use it rather than 2 here. */
-#define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
+#define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
 
 
-void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
+static void
+sigfpe_handler(int signal, siginfo_t *info, void *void_context)
 {
 {
-    unsigned long bad_inst;
-    unsigned int op, rs, rt, rd, funct, dest;
+    unsigned int bad_inst;
+    unsigned int op, rs, rt, rd, funct, dest = 32;
     int immed;
     int immed;
-    long result;
+    unsigned int result;
     os_context_t *context = arch_os_get_context(&void_context);
 
     if (os_context_bd_cause(context))
     os_context_t *context = arch_os_get_context(&void_context);
 
     if (os_context_bd_cause(context))
-        bad_inst = *(unsigned long *)(*os_context_pc_addr(context) + 4);
+        bad_inst = *(unsigned int *)(*os_context_pc_addr(context) + 4);
     else
     else
-        bad_inst = *(unsigned long *)(*os_context_pc_addr(context));
+        bad_inst = *(unsigned int *)(*os_context_pc_addr(context));
 
     op = (bad_inst >> 26) & 0x3f;
     rs = (bad_inst >> 21) & 0x1f;
 
     op = (bad_inst >> 26) & 0x3f;
     rs = (bad_inst >> 21) & 0x1f;
@@ -288,8 +309,7 @@ void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
            /* Check to see if this is really a pa_interrupted hit */
            if (rs == reg_ALLOC && rt == reg_NL4) {
                *os_context_register_addr(context, reg_ALLOC)
            /* Check to see if this is really a pa_interrupted hit */
            if (rs == reg_ALLOC && rt == reg_NL4) {
                *os_context_register_addr(context, reg_ALLOC)
-                   += (*os_context_register_addr(context, reg_NL4)
-                       - PSEUDO_ATOMIC_INTERRUPTED_BIAS);
+                   += *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
                arch_skip_instruction(context);
                interrupt_handle_pending(context);
                return;
                arch_skip_instruction(context);
                interrupt_handle_pending(context);
                return;
@@ -304,10 +324,6 @@ void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
                - FIXNUM_VALUE(*os_context_register_addr(context, rt));
            dest = rd;
            break;
                - FIXNUM_VALUE(*os_context_register_addr(context, rt));
            dest = rd;
            break;
-           
-       default:
-           dest = 32;
-           break;
        }
        break;
        
        }
        break;
        
@@ -315,10 +331,6 @@ void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
        result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
        dest = rt;
        break;
        result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
        dest = rt;
        break;
-       
-    default:
-       dest = 32;
-       break;
     }
     
     if (dest < 32) {
     }
     
     if (dest < 32) {
@@ -328,8 +340,8 @@ void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
         *os_context_register_addr(context,dest) = alloc_number(result);
 
        *os_context_register_addr(context, reg_ALLOC) =
         *os_context_register_addr(context,dest) = alloc_number(result);
 
        *os_context_register_addr(context, reg_ALLOC) =
-           (unsigned long) dynamic_space_free_pointer;
-       
+           (unsigned int) dynamic_space_free_pointer;
+
         arch_skip_instruction(context);
        
     }
         arch_skip_instruction(context);
        
     }
@@ -337,22 +349,26 @@ void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
         interrupt_handle_now(signal, info, context);
 }
 
         interrupt_handle_now(signal, info, context);
 }
 
-void arch_install_interrupt_handlers()
+void
+arch_install_interrupt_handlers()
 {    
 {    
+    undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler);
     undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
     undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
 }
 
 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
 
     undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
     undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
 }
 
 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
 
-lispobj funcall0(lispobj function)
+lispobj
+funcall0(lispobj function)
 {
     lispobj *args = current_control_stack_pointer;
 
     return call_into_lisp(function, args, 0);
 }
 
 {
     lispobj *args = current_control_stack_pointer;
 
     return call_into_lisp(function, args, 0);
 }
 
-lispobj funcall1(lispobj function, lispobj arg0)
+lispobj
+funcall1(lispobj function, lispobj arg0)
 {
     lispobj *args = current_control_stack_pointer;
 
 {
     lispobj *args = current_control_stack_pointer;
 
@@ -362,7 +378,8 @@ lispobj funcall1(lispobj function, lispobj arg0)
     return call_into_lisp(function, args, 1);
 }
 
     return call_into_lisp(function, args, 1);
 }
 
-lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
+lispobj
+funcall2(lispobj function, lispobj arg0, lispobj arg1)
 {
     lispobj *args = current_control_stack_pointer;
 
 {
     lispobj *args = current_control_stack_pointer;
 
@@ -373,7 +390,8 @@ lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
     return call_into_lisp(function, args, 2);
 }
 
     return call_into_lisp(function, args, 2);
 }
 
-lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
+lispobj
+funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
 {
     lispobj *args = current_control_stack_pointer;
 
 {
     lispobj *args = current_control_stack_pointer;
 
@@ -384,4 +402,3 @@ lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
 
     return call_into_lisp(function, args, 3);
 }
 
     return call_into_lisp(function, args, 3);
 }
-