unsigned int opcode = inst >> 26;
unsigned int r1 = (inst >> 21) & 0x1f;
unsigned int r2 = (inst >> 16) & 0x1f;
- unsigned int bdisp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
- unsigned int jdisp = (inst&0x3ffffff) << 2;
- unsigned int disp = 0;
+ 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) {
+ 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)
- disp = bdisp;
+ tgt += disp;
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)
- disp = bdisp;
+ 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)
- disp = bdisp;
+ tgt += disp;
*os_context_register_addr(context, 31)
= *os_context_pc_addr(context) + 4;
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))
- disp = bdisp;
+ tgt += disp;
break;
case 0x6: /* blez */
if(*os_context_register_addr(context, r1)
<= *os_context_register_addr(context, r2))
- disp = bdisp;
+ tgt += disp;
break;
case 0x7: /* bgtz */
if(*os_context_register_addr(context, r1)
> *os_context_register_addr(context, r2))
- disp = bdisp;
+ tgt += disp;
break;
case 0x2: /* j */
- disp = jdisp;
+ tgt = jtgt;
break;
case 0x3: /* jal */
- disp = jdisp;
+ tgt = jtgt;
*os_context_register_addr(context, 31)
= *os_context_pc_addr(context) + 4;
break;
}
- return *os_context_pc_addr(context) + disp;
+ return tgt;
}
void
= emulate_branch(context, *os_context_pc_addr(context));
} else
*os_context_pc_addr(context) += 4;
-
- os_flush_icache((os_vm_address_t)*os_context_pc_addr(context),
- sizeof(unsigned int));
}
unsigned char *
sigtrap_handler(int signal, siginfo_t *info, void *void_context)
{
os_context_t *context = arch_os_get_context(&void_context);
- sigset_t *mask;
unsigned int code;
- sigset_t ss;
- /* Don't disallow recursive breakpoint traps. Otherwise, we can't
- use debugger breakpoints anywhere in here. */
- mask = os_context_sigmask_addr(context);
- sigprocmask(SIG_SETMASK, mask, NULL);
code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
switch (code) {
case trap_PendingInterrupt:
arch_skip_instruction(context);
- sigemptyset(&ss);
- sigaddset(&ss,SIGTRAP);
- sigprocmask(SIG_UNBLOCK,&ss,0);
interrupt_handle_pending(context);
break;