void bfin_syscall (SIM_CPU *cpu) { SIM_DESC sd = CPU_STATE (cpu); const char * const *argv = (void *)STATE_PROG_ARGV (sd); host_callback *cb = STATE_CALLBACK (sd); bu32 args[6]; CB_SYSCALL sc; char *p; char _tbuf[1024 * 3], *tbuf = _tbuf, tstr[1024]; int fmt_ret_hex = 0; CB_SYSCALL_INIT (&sc); if (STATE_ENVIRONMENT (sd) == USER_ENVIRONMENT) { /* Linux syscall. */ sc.func = PREG (0); sc.arg1 = args[0] = DREG (0); sc.arg2 = args[1] = DREG (1); sc.arg3 = args[2] = DREG (2); sc.arg4 = args[3] = DREG (3); /*sc.arg5 =*/ args[4] = DREG (4); /*sc.arg6 =*/ args[5] = DREG (5); } else { /* libgloss syscall. */ sc.func = PREG (0); sc.arg1 = args[0] = GET_LONG (DREG (0)); sc.arg2 = args[1] = GET_LONG (DREG (0) + 4); sc.arg3 = args[2] = GET_LONG (DREG (0) + 8); sc.arg4 = args[3] = GET_LONG (DREG (0) + 12); /*sc.arg5 =*/ args[4] = GET_LONG (DREG (0) + 16); /*sc.arg6 =*/ args[5] = GET_LONG (DREG (0) + 20); } sc.p1 = (PTR) sd; sc.p2 = (PTR) cpu; sc.read_mem = sim_syscall_read_mem; sc.write_mem = sim_syscall_write_mem; /* Common cb_syscall() handles most functions. */ switch (cb_target_to_host_syscall (cb, sc.func)) { case CB_SYS_exit: tbuf += sprintf (tbuf, "exit(%i)", args[0]); sim_engine_halt (sd, cpu, NULL, PCREG, sim_exited, sc.arg1); #ifdef CB_SYS_argc case CB_SYS_argc: tbuf += sprintf (tbuf, "argc()"); sc.result = count_argc (argv); break; case CB_SYS_argnlen: { tbuf += sprintf (tbuf, "argnlen(%u)", args[0]); if (sc.arg1 < count_argc (argv)) sc.result = strlen (argv[sc.arg1]); else sc.result = -1; } break; case CB_SYS_argn: { tbuf += sprintf (tbuf, "argn(%u)", args[0]); if (sc.arg1 < count_argc (argv)) { const char *argn = argv[sc.arg1]; int len = strlen (argn); int written = sc.write_mem (cb, &sc, sc.arg2, argn, len + 1); if (written == len + 1) sc.result = sc.arg2; else sc.result = -1; } else sc.result = -1; } break; #endif case CB_SYS_gettimeofday: { struct timeval _tv, *tv = &_tv; struct timezone _tz, *tz = &_tz; tbuf += sprintf (tbuf, "gettimeofday(%#x, %#x)", args[0], args[1]); if (sc.arg1 == 0) tv = NULL; if (sc.arg2 == 0) tz = NULL; sc.result = gettimeofday (tv, tz); if (sc.result == 0) { bu32 t; if (tv) { t = tv->tv_sec; sc.write_mem (cb, &sc, sc.arg1, (void *)&t, 4); t = tv->tv_usec; sc.write_mem (cb, &sc, sc.arg1 + 4, (void *)&t, 4); } if (sc.arg2) { t = tz->tz_minuteswest; sc.write_mem (cb, &sc, sc.arg1, (void *)&t, 4); t = tz->tz_dsttime; sc.write_mem (cb, &sc, sc.arg1 + 4, (void *)&t, 4); } } else goto sys_finish; } break; case CB_SYS_ioctl: /* XXX: hack just enough to get basic stdio w/uClibc ... */ tbuf += sprintf (tbuf, "ioctl(%i, %#x, %u)", args[0], args[1], args[2]); if (sc.arg2 == 0x5401) { sc.result = !isatty (sc.arg1); sc.errcode = 0; } else { sc.result = -1; sc.errcode = TARGET_EINVAL; } break; case CB_SYS_mmap2: { static bu32 heap = BFIN_DEFAULT_MEM_SIZE / 2; fmt_ret_hex = 1; tbuf += sprintf (tbuf, "mmap2(%#x, %u, %#x, %#x, %i, %u)", args[0], args[1], args[2], args[3], args[4], args[5]); sc.errcode = 0; if (sc.arg4 & 0x20 /*MAP_ANONYMOUS*/) /* XXX: We don't handle zeroing, but default is all zeros. */; else if (args[4] >= MAX_CALLBACK_FDS) sc.errcode = TARGET_ENOSYS; else { #ifdef HAVE_PREAD char *data = xmalloc (sc.arg2); /* XXX: Should add a cb->pread. */ if (pread (cb->fdmap[args[4]], data, sc.arg2, args[5] << 12) == sc.arg2) sc.write_mem (cb, &sc, heap, data, sc.arg2); else sc.errcode = TARGET_EINVAL; free (data); #else sc.errcode = TARGET_ENOSYS; #endif } if (sc.errcode) { sc.result = -1; break; } sc.result = heap; heap += sc.arg2; /* Keep it page aligned. */ heap = ALIGN (heap, 4096); break; } case CB_SYS_munmap: /* XXX: meh, just lie for mmap(). */ tbuf += sprintf (tbuf, "munmap(%#x, %u)", args[0], args[1]); sc.result = 0; break; case CB_SYS_dup2: tbuf += sprintf (tbuf, "dup2(%i, %i)", args[0], args[1]); if (sc.arg1 >= MAX_CALLBACK_FDS || sc.arg2 >= MAX_CALLBACK_FDS) { sc.result = -1; sc.errcode = TARGET_EINVAL; } else { sc.result = dup2 (cb->fdmap[sc.arg1], cb->fdmap[sc.arg2]); goto sys_finish; } break; case CB_SYS__llseek: tbuf += sprintf (tbuf, "llseek(%i, %u, %u, %#x, %u)", args[0], args[1], args[2], args[3], args[4]); sc.func = TARGET_LINUX_SYS_lseek; if (sc.arg2) { sc.result = -1; sc.errcode = TARGET_EINVAL; } else { sc.arg2 = sc.arg3; sc.arg3 = args[4]; cb_syscall (cb, &sc); if (sc.result != -1) { bu32 z = 0; sc.write_mem (cb, &sc, args[3], (void *)&sc.result, 4); sc.write_mem (cb, &sc, args[3] + 4, (void *)&z, 4); } } break; /* XXX: Should add a cb->pread. */ case CB_SYS_pread: tbuf += sprintf (tbuf, "pread(%i, %#x, %u, %i)", args[0], args[1], args[2], args[3]); if (sc.arg1 >= MAX_CALLBACK_FDS) { sc.result = -1; sc.errcode = TARGET_EINVAL; } else { long old_pos, read_result, read_errcode; /* Get current filepos. */ sc.func = TARGET_LINUX_SYS_lseek; sc.arg2 = 0; sc.arg3 = SEEK_CUR; cb_syscall (cb, &sc); if (sc.result == -1) break; old_pos = sc.result; /* Move to the new pos. */ sc.func = TARGET_LINUX_SYS_lseek; sc.arg2 = args[3]; sc.arg3 = SEEK_SET; cb_syscall (cb, &sc); if (sc.result == -1) break; /* Read the data. */ sc.func = TARGET_LINUX_SYS_read; sc.arg2 = args[1]; sc.arg3 = args[2]; cb_syscall (cb, &sc); read_result = sc.result; read_errcode = sc.errcode; /* Move back to the old pos. */ sc.func = TARGET_LINUX_SYS_lseek; sc.arg2 = old_pos; sc.arg3 = SEEK_SET; cb_syscall (cb, &sc); sc.result = read_result; sc.errcode = read_errcode; } break; case CB_SYS_getcwd: tbuf += sprintf (tbuf, "getcwd(%#x, %u)", args[0], args[1]); p = alloca (sc.arg2); if (getcwd (p, sc.arg2) == NULL) { sc.result = -1; sc.errcode = TARGET_EINVAL; } else { sc.write_mem (cb, &sc, sc.arg1, p, sc.arg2); sc.result = sc.arg1; } break; case CB_SYS_stat64: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "stat64(%#x:\"%s\", %u)", args[0], tstr, args[1]); cb->stat_map = stat_map_64; sc.func = TARGET_LINUX_SYS_stat; cb_syscall (cb, &sc); cb->stat_map = stat_map_32; break; case CB_SYS_lstat64: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "lstat64(%#x:\"%s\", %u)", args[0], tstr, args[1]); cb->stat_map = stat_map_64; sc.func = TARGET_LINUX_SYS_lstat; cb_syscall (cb, &sc); cb->stat_map = stat_map_32; break; case CB_SYS_fstat64: tbuf += sprintf (tbuf, "fstat64(%#x, %u)", args[0], args[1]); cb->stat_map = stat_map_64; sc.func = TARGET_LINUX_SYS_fstat; cb_syscall (cb, &sc); cb->stat_map = stat_map_32; break; case CB_SYS_ftruncate64: tbuf += sprintf (tbuf, "ftruncate64(%u, %u)", args[0], args[1]); sc.func = TARGET_LINUX_SYS_ftruncate; cb_syscall (cb, &sc); break; case CB_SYS_getuid: case CB_SYS_getuid32: tbuf += sprintf (tbuf, "getuid()"); sc.result = getuid (); goto sys_finish; case CB_SYS_getgid: case CB_SYS_getgid32: tbuf += sprintf (tbuf, "getgid()"); sc.result = getgid (); goto sys_finish; case CB_SYS_setuid: sc.arg1 &= 0xffff; case CB_SYS_setuid32: tbuf += sprintf (tbuf, "setuid(%u)", args[0]); sc.result = setuid (sc.arg1); goto sys_finish; case CB_SYS_setgid: sc.arg1 &= 0xffff; case CB_SYS_setgid32: tbuf += sprintf (tbuf, "setgid(%u)", args[0]); sc.result = setgid (sc.arg1); goto sys_finish; case CB_SYS_getpid: tbuf += sprintf (tbuf, "getpid()"); sc.result = getpid (); goto sys_finish; case CB_SYS_kill: tbuf += sprintf (tbuf, "kill(%u, %i)", args[0], args[1]); /* Only let the app kill itself. */ if (sc.arg1 != getpid ()) { sc.result = -1; sc.errcode = TARGET_EPERM; } else { #ifdef HAVE_KILL sc.result = kill (sc.arg1, sc.arg2); goto sys_finish; #else sc.result = -1; sc.errcode = TARGET_ENOSYS; #endif } break; case CB_SYS_open: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "open(%#x:\"%s\", %#x, %o)", args[0], tstr, args[1], args[2]); goto case_default; case CB_SYS_close: tbuf += sprintf (tbuf, "close(%i)", args[0]); goto case_default; case CB_SYS_read: tbuf += sprintf (tbuf, "read(%i, %#x, %u)", args[0], args[1], args[2]); goto case_default; case CB_SYS_write: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[1])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "write(%i, %#x:\"%s\", %u)", args[0], args[1], tstr, args[2]); goto case_default; case CB_SYS_lseek: tbuf += sprintf (tbuf, "lseek(%i, %i, %i)", args[0], args[1], args[2]); goto case_default; case CB_SYS_unlink: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "unlink(%#x:\"%s\")", args[0], tstr); goto case_default; case CB_SYS_truncate: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "truncate(%#x:\"%s\", %i)", args[0], tstr, args[1]); goto case_default; case CB_SYS_ftruncate: tbuf += sprintf (tbuf, "ftruncate(%i, %i)", args[0], args[1]); goto case_default; case CB_SYS_rename: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "rename(%#x:\"%s\", ", args[0], tstr); if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[1])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "%#x:\"%s\")", args[1], tstr); goto case_default; case CB_SYS_stat: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "stat(%#x:\"%s\", %#x)", args[0], tstr, args[1]); goto case_default; case CB_SYS_fstat: tbuf += sprintf (tbuf, "fstat(%i, %#x)", args[0], args[1]); goto case_default; case CB_SYS_lstat: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "lstat(%#x:\"%s\", %#x)", args[0], tstr, args[1]); goto case_default; case CB_SYS_pipe: tbuf += sprintf (tbuf, "pipe(%#x, %#x)", args[0], args[1]); goto case_default; default: tbuf += sprintf (tbuf, "???_%i(%#x, %#x, %#x, %#x, %#x, %#x)", sc.func, args[0], args[1], args[2], args[3], args[4], args[5]); case_default: cb_syscall (cb, &sc); break; sys_finish: if (sc.result == -1) { cb->last_errno = errno; sc.errcode = cb->get_errno (cb); } } TRACE_EVENTS (cpu, "syscall_%i(%#x, %#x, %#x, %#x, %#x, %#x) = %li (error = %i)", sc.func, args[0], args[1], args[2], args[3], args[4], args[5], sc.result, sc.errcode); tbuf += sprintf (tbuf, " = "); if (STATE_ENVIRONMENT (sd) == USER_ENVIRONMENT) { if (sc.result == -1) { tbuf += sprintf (tbuf, "-1 (error = %i)", sc.errcode); if (sc.errcode == cb_host_to_target_errno (cb, ENOSYS)) { sim_io_eprintf (sd, "bfin-sim: %#x: unimplemented syscall %i\n", PCREG, sc.func); } SET_DREG (0, -sc.errcode); } else { if (fmt_ret_hex) tbuf += sprintf (tbuf, "%#lx", sc.result); else tbuf += sprintf (tbuf, "%lu", sc.result); SET_DREG (0, sc.result); } } else { tbuf += sprintf (tbuf, "%lu (error = %i)", sc.result, sc.errcode); SET_DREG (0, sc.result); SET_DREG (1, sc.result2); SET_DREG (2, sc.errcode); } TRACE_SYSCALL (cpu, "%s", _tbuf); }
void decode_opc(DisasContext * ctx) { #if 0 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); #endif switch (ctx->opcode) { case 0x0019: /* div0u */ gen_op_div0u(); return; case 0x000b: /* rts */ CHECK_NOT_DELAY_SLOT gen_op_rts(); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0028: /* clrmac */ gen_op_clrmac(); return; case 0x0048: /* clrs */ gen_op_clrs(); return; case 0x0008: /* clrt */ gen_op_clrt(); return; case 0x0038: /* ldtlb */ assert(0); /* XXXXX */ return; case 0x004b: /* rte */ CHECK_NOT_DELAY_SLOT gen_op_rte(); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0058: /* sets */ gen_op_sets(); return; case 0x0018: /* sett */ gen_op_sett(); return; case 0xfbfb: /* frchg */ gen_op_frchg(); ctx->flags |= MODE_CHANGE; return; case 0xf3fb: /* fschg */ gen_op_fschg(); ctx->flags |= MODE_CHANGE; return; case 0x0009: /* nop */ return; case 0x001b: /* sleep */ assert(0); /* XXXXX */ return; } switch (ctx->opcode & 0xf000) { case 0x1000: /* mov.l Rm,@(disp,Rn) */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_addl_imm_T1(B3_0 * 4); gen_op_stl_T0_T1(ctx); return; case 0x5000: /* mov.l @(disp,Rm),Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_addl_imm_T0(B3_0 * 4); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0xe000: /* mov.l #imm,Rn */ gen_op_movl_imm_rN(B7_0s, REG(B11_8)); return; case 0x9000: /* mov.w @(disp,PC),Rn */ gen_op_movl_imm_T0(ctx->pc + 4 + B7_0 * 2); gen_op_ldw_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0xd000: /* mov.l @(disp,PC),Rn */ gen_op_movl_imm_T0((ctx->pc + 4 + B7_0 * 4) & ~3); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x7000: /* add.l #imm,Rn */ gen_op_add_imm_rN(B7_0s, REG(B11_8)); return; case 0xa000: /* bra disp */ CHECK_NOT_DELAY_SLOT gen_op_bra(ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2); ctx->flags |= DELAY_SLOT; return; case 0xb000: /* bsr disp */ CHECK_NOT_DELAY_SLOT gen_op_bsr(ctx->pc + 4, ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2); ctx->flags |= DELAY_SLOT; return; } switch (ctx->opcode & 0xf00f) { case 0x6003: /* mov Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x2000: /* mov.b Rm,@Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stb_T0_T1(ctx); return; case 0x2001: /* mov.w Rm,@Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stw_T0_T1(ctx); return; case 0x2002: /* mov.l Rm,@Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stl_T0_T1(ctx); return; case 0x6000: /* mov.b @Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldb_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x6001: /* mov.w @Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldw_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x6002: /* mov.l @Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x2004: /* mov.b Rm,@-Rn */ gen_op_dec1_rN(REG(B11_8)); gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stb_T0_T1(ctx); return; case 0x2005: /* mov.w Rm,@-Rn */ gen_op_dec2_rN(REG(B11_8)); gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stw_T0_T1(ctx); return; case 0x2006: /* mov.l Rm,@-Rn */ gen_op_dec4_rN(REG(B11_8)); gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stl_T0_T1(ctx); return; case 0x6004: /* mov.b @Rm+,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldb_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); gen_op_inc1_rN(REG(B7_4)); return; case 0x6005: /* mov.w @Rm+,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldw_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); gen_op_inc2_rN(REG(B7_4)); return; case 0x6006: /* mov.l @Rm+,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); gen_op_inc4_rN(REG(B7_4)); return; case 0x0004: /* mov.b Rm,@(R0,Rn) */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_add_rN_T1(REG(0)); gen_op_stb_T0_T1(ctx); return; case 0x0005: /* mov.w Rm,@(R0,Rn) */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_add_rN_T1(REG(0)); gen_op_stw_T0_T1(ctx); return; case 0x0006: /* mov.l Rm,@(R0,Rn) */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_add_rN_T1(REG(0)); gen_op_stl_T0_T1(ctx); return; case 0x000c: /* mov.b @(R0,Rm),Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); gen_op_ldb_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x000d: /* mov.w @(R0,Rm),Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); gen_op_ldw_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x000e: /* mov.l @(R0,Rm),Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x6008: /* swap.b Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_swapb_T0(); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x6009: /* swap.w Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_swapw_T0(); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x200d: /* xtrct Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_xtrct_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x300c: /* add Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_T0_rN(REG(B11_8)); return; case 0x300e: /* addc Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_addc_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x300f: /* addv Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_addv_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x2009: /* and Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_and_T0_rN(REG(B11_8)); return; case 0x3000: /* cmp/eq Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_cmp_eq_T0_T1(); return; case 0x3003: /* cmp/ge Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_cmp_ge_T0_T1(); return; case 0x3007: /* cmp/gt Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_cmp_gt_T0_T1(); return; case 0x3006: /* cmp/hi Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_cmp_hi_T0_T1(); return; case 0x3002: /* cmp/hs Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_cmp_hs_T0_T1(); return; case 0x200c: /* cmp/str Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_cmp_str_T0_T1(); return; case 0x2007: /* div0s Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_div0s_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x3004: /* div1 Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_div1_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x300d: /* dmuls.l Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_dmulsl_T0_T1(); return; case 0x3005: /* dmulu.l Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_dmulul_T0_T1(); return; case 0x600e: /* exts.b Rm,Rn */ gen_op_movb_rN_T0(REG(B7_4)); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x600f: /* exts.w Rm,Rn */ gen_op_movw_rN_T0(REG(B7_4)); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x600c: /* extu.b Rm,Rn */ gen_op_movub_rN_T0(REG(B7_4)); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x600d: /* extu.w Rm,Rn */ gen_op_movuw_rN_T0(REG(B7_4)); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x000f: /* mac.l @Rm+,@Rn- */ gen_op_movl_rN_T0(REG(B11_8)); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_T1(); gen_op_movl_rN_T1(REG(B7_4)); gen_op_ldl_T0_T0(ctx); gen_op_macl_T0_T1(); gen_op_inc4_rN(REG(B7_4)); gen_op_inc4_rN(REG(B11_8)); return; case 0x400f: /* mac.w @Rm+,@Rn+ */ gen_op_movl_rN_T0(REG(B11_8)); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_T1(); gen_op_movl_rN_T1(REG(B7_4)); gen_op_ldl_T0_T0(ctx); gen_op_macw_T0_T1(); gen_op_inc2_rN(REG(B7_4)); gen_op_inc2_rN(REG(B11_8)); return; case 0x0007: /* mul.l Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_mull_T0_T1(); return; case 0x200f: /* muls.w Rm,Rn */ gen_op_movw_rN_T0(REG(B7_4)); gen_op_movw_rN_T1(REG(B11_8)); gen_op_mulsw_T0_T1(); return; case 0x200e: /* mulu.w Rm,Rn */ gen_op_movuw_rN_T0(REG(B7_4)); gen_op_movuw_rN_T1(REG(B11_8)); gen_op_muluw_T0_T1(); return; case 0x600b: /* neg Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_neg_T0(); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x600a: /* negc Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_negc_T0(); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x6007: /* not Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_not_T0(); gen_op_movl_T0_rN(REG(B11_8)); return; case 0x200b: /* or Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_or_T0_rN(REG(B11_8)); return; case 0x400c: /* shad Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_shad_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x400d: /* shld Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_shld_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x3008: /* sub Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_sub_T0_rN(REG(B11_8)); return; case 0x300a: /* subc Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_subc_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x300b: /* subv Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_subv_T0_T1(); gen_op_movl_T1_rN(REG(B11_8)); return; case 0x2008: /* tst Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_tst_T0_T1(); return; case 0x200a: /* xor Rm,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_xor_T0_rN(REG(B11_8)); return; case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0110) break; /* illegal instruction */ gen_op_fmov_drN_DT0(DREG(B7_4)); gen_op_fmov_DT0_drN(DREG(B11_8)); } else { gen_op_fmov_frN_FT0(FREG(B7_4)); gen_op_fmov_FT0_frN(FREG(B11_8)); } return; case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0010) break; /* illegal instruction */ gen_op_fmov_drN_DT0(DREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stfq_DT0_T1(ctx); } else { gen_op_fmov_frN_FT0(FREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stfl_FT0_T1(ctx); } return; case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfq_T0_DT0(ctx); gen_op_fmov_DT0_drN(DREG(B11_8)); } else { gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfl_T0_FT0(ctx); gen_op_fmov_FT0_frN(FREG(B11_8)); } return; case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfq_T0_DT0(ctx); gen_op_fmov_DT0_drN(DREG(B11_8)); gen_op_inc8_rN(REG(B7_4)); } else { gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfl_T0_FT0(ctx); gen_op_fmov_FT0_frN(FREG(B11_8)); gen_op_inc4_rN(REG(B7_4)); } return; case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_dec8_rN(REG(B11_8)); gen_op_fmov_drN_DT0(DREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stfq_DT0_T1(ctx); } else { gen_op_dec4_rN(REG(B11_8)); gen_op_fmov_frN_FT0(FREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stfl_FT0_T1(ctx); } return; case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); gen_op_ldfq_T0_DT0(ctx); gen_op_fmov_DT0_drN(DREG(B11_8)); } else { gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); gen_op_ldfl_T0_FT0(ctx); gen_op_fmov_FT0_frN(FREG(B11_8)); } return; case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0010) break; /* illegal instruction */ gen_op_fmov_drN_DT0(DREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_add_rN_T1(REG(0)); gen_op_stfq_DT0_T1(ctx); } else { gen_op_fmov_frN_FT0(FREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_add_rN_T1(REG(0)); gen_op_stfl_FT0_T1(ctx); } return; case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ if (ctx->fpscr & FPSCR_PR) { if (ctx->opcode & 0x0110) break; /* illegal instruction */ gen_op_fmov_drN_DT1(DREG(B7_4)); gen_op_fmov_drN_DT0(DREG(B11_8)); } else { gen_op_fmov_frN_FT1(FREG(B7_4)); gen_op_fmov_frN_FT0(FREG(B11_8)); } switch (ctx->opcode & 0xf00f) { case 0xf000: /* fadd Rm,Rn */ ctx->fpscr & FPSCR_PR ? gen_op_fadd_DT() : gen_op_fadd_FT(); break; case 0xf001: /* fsub Rm,Rn */ ctx->fpscr & FPSCR_PR ? gen_op_fsub_DT() : gen_op_fsub_FT(); break; case 0xf002: /* fmul Rm,Rn */ ctx->fpscr & FPSCR_PR ? gen_op_fmul_DT() : gen_op_fmul_FT(); break; case 0xf003: /* fdiv Rm,Rn */ ctx->fpscr & FPSCR_PR ? gen_op_fdiv_DT() : gen_op_fdiv_FT(); break; case 0xf004: /* fcmp/eq Rm,Rn */ return; case 0xf005: /* fcmp/gt Rm,Rn */ return; } if (ctx->fpscr & FPSCR_PR) { gen_op_fmov_DT0_drN(DREG(B11_8)); } else { gen_op_fmov_FT0_frN(FREG(B11_8)); } return; } switch (ctx->opcode & 0xff00) { case 0xc900: /* and #imm,R0 */ gen_op_and_imm_rN(B7_0, REG(0)); return; case 0xcd00: /* and.b #imm,@(R0+GBR) */ gen_op_movl_rN_T0(REG(0)); gen_op_addl_GBR_T0(); gen_op_movl_T0_T1(); gen_op_ldb_T0_T0(ctx); gen_op_and_imm_T0(B7_0); gen_op_stb_T0_T1(ctx); return; case 0x8b00: /* bf label */ CHECK_NOT_DELAY_SLOT gen_conditional_jump(ctx, ctx->pc + 2, ctx->pc + 4 + B7_0s * 2); ctx->flags |= BRANCH_CONDITIONAL; return; case 0x8f00: /* bf/s label */ CHECK_NOT_DELAY_SLOT gen_op_bf_s(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2); ctx->flags |= DELAY_SLOT_CONDITIONAL; return; case 0x8900: /* bt label */ CHECK_NOT_DELAY_SLOT gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, ctx->pc + 2); ctx->flags |= BRANCH_CONDITIONAL; return; case 0x8d00: /* bt/s label */ CHECK_NOT_DELAY_SLOT gen_op_bt_s(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2); ctx->flags |= DELAY_SLOT_CONDITIONAL; return; case 0x8800: /* cmp/eq #imm,R0 */ gen_op_movl_rN_T0(REG(0)); gen_op_cmp_eq_imm_T0(B7_0s); return; case 0xc400: /* mov.b @(disp,GBR),R0 */ gen_op_stc_gbr_T0(); gen_op_addl_imm_T0(B7_0); gen_op_ldb_T0_T0(ctx); gen_op_movl_T0_rN(REG(0)); return; case 0xc500: /* mov.w @(disp,GBR),R0 */ gen_op_stc_gbr_T0(); gen_op_addl_imm_T0(B7_0); gen_op_ldw_T0_T0(ctx); gen_op_movl_T0_rN(REG(0)); return; case 0xc600: /* mov.l @(disp,GBR),R0 */ gen_op_stc_gbr_T0(); gen_op_addl_imm_T0(B7_0); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_rN(REG(0)); return; case 0xc000: /* mov.b R0,@(disp,GBR) */ gen_op_stc_gbr_T0(); gen_op_addl_imm_T0(B7_0); gen_op_movl_T0_T1(); gen_op_movl_rN_T0(REG(0)); gen_op_stb_T0_T1(ctx); return; case 0xc100: /* mov.w R0,@(disp,GBR) */ gen_op_stc_gbr_T0(); gen_op_addl_imm_T0(B7_0); gen_op_movl_T0_T1(); gen_op_movl_rN_T0(REG(0)); gen_op_stw_T0_T1(ctx); return; case 0xc200: /* mov.l R0,@(disp,GBR) */ gen_op_stc_gbr_T0(); gen_op_addl_imm_T0(B7_0); gen_op_movl_T0_T1(); gen_op_movl_rN_T0(REG(0)); gen_op_stl_T0_T1(ctx); return; case 0x8000: /* mov.b R0,@(disp,Rn) */ gen_op_movl_rN_T0(REG(0)); gen_op_movl_rN_T1(REG(B7_4)); gen_op_addl_imm_T1(B3_0); gen_op_stb_T0_T1(ctx); return; case 0x8100: /* mov.w R0,@(disp,Rn) */ gen_op_movl_rN_T0(REG(0)); gen_op_movl_rN_T1(REG(B7_4)); gen_op_addl_imm_T1(B3_0 * 2); gen_op_stw_T0_T1(ctx); return; case 0x8400: /* mov.b @(disp,Rn),R0 */ gen_op_movl_rN_T0(REG(0)); gen_op_movl_rN_T1(REG(B7_4)); gen_op_addl_imm_T1(B3_0); gen_op_stb_T0_T1(ctx); return; case 0x8500: /* mov.w @(disp,Rn),R0 */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_addl_imm_T0(B3_0 * 2); gen_op_ldw_T0_T0(ctx); gen_op_movl_T0_rN(REG(0)); return; case 0xc700: /* mova @(disp,PC),R0 */ gen_op_movl_imm_rN(((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3, REG(0)); return; case 0xcb00: /* or #imm,R0 */ gen_op_or_imm_rN(B7_0, REG(0)); return; case 0xcf00: /* or.b #imm,@(R0+GBR) */ gen_op_movl_rN_T0(REG(0)); gen_op_addl_GBR_T0(); gen_op_movl_T0_T1(); gen_op_ldb_T0_T0(ctx); gen_op_or_imm_T0(B7_0); gen_op_stb_T0_T1(ctx); return; case 0xc300: /* trapa #imm */ CHECK_NOT_DELAY_SLOT gen_op_movl_imm_PC(ctx->pc); gen_op_trapa(B7_0); ctx->flags |= BRANCH; return; case 0xc800: /* tst #imm,R0 */ gen_op_tst_imm_rN(B7_0, REG(0)); return; case 0xcc00: /* tst #imm,@(R0+GBR) */ gen_op_movl_rN_T0(REG(0)); gen_op_addl_GBR_T0(); gen_op_ldb_T0_T0(ctx); gen_op_tst_imm_T0(B7_0); return; case 0xca00: /* xor #imm,R0 */ gen_op_xor_imm_rN(B7_0, REG(0)); return; case 0xce00: /* xor.b #imm,@(R0+GBR) */ gen_op_movl_rN_T0(REG(0)); gen_op_addl_GBR_T0(); gen_op_movl_T0_T1(); gen_op_ldb_T0_T0(ctx); gen_op_xor_imm_T0(B7_0); gen_op_stb_T0_T1(ctx); return; } switch (ctx->opcode & 0xf08f) { case 0x408e: /* ldc Rm,Rn_BANK */ gen_op_movl_rN_rN(REG(B11_8), ALTREG(B6_4)); return; case 0x4087: /* ldc.l @Rm+,Rn_BANK */ gen_op_movl_rN_T0(REG(B11_8)); gen_op_ldl_T0_T0(ctx); gen_op_movl_T0_rN(ALTREG(B6_4)); gen_op_inc4_rN(REG(B11_8)); return; case 0x0082: /* stc Rm_BANK,Rn */ gen_op_movl_rN_rN(ALTREG(B6_4), REG(B11_8)); return; case 0x4083: /* stc.l Rm_BANK,@-Rn */ gen_op_dec4_rN(REG(B11_8)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_movl_rN_T0(ALTREG(B6_4)); gen_op_stl_T0_T1(ctx); return; } switch (ctx->opcode & 0xf0ff) { case 0x0023: /* braf Rn */ CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); gen_op_braf_T0(ctx->pc + 4); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0003: /* bsrf Rn */ CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); gen_op_bsrf_T0(ctx->pc + 4); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x4015: /* cmp/pl Rn */ gen_op_movl_rN_T0(REG(B11_8)); gen_op_cmp_pl_T0(); return; case 0x4011: /* cmp/pz Rn */ gen_op_movl_rN_T0(REG(B11_8)); gen_op_cmp_pz_T0(); return; case 0x4010: /* dt Rn */ gen_op_dt_rN(REG(B11_8)); return; case 0x402b: /* jmp @Rn */ CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); gen_op_jmp_T0(); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x400b: /* jsr @Rn */ CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); gen_op_jsr_T0(ctx->pc + 4); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; #define LDST(reg,ldnum,ldpnum,ldop,stnum,stpnum,stop,extrald) \ case ldnum: \ gen_op_movl_rN_T0 (REG(B11_8)); \ gen_op_##ldop##_T0_##reg (); \ extrald \ return; \ case ldpnum: \ gen_op_movl_rN_T0 (REG(B11_8)); \ gen_op_ldl_T0_T0 (ctx); \ gen_op_inc4_rN (REG(B11_8)); \ gen_op_##ldop##_T0_##reg (); \ extrald \ return; \ case stnum: \ gen_op_##stop##_##reg##_T0 (); \ gen_op_movl_T0_rN (REG(B11_8)); \ return; \ case stpnum: \ gen_op_##stop##_##reg##_T0 (); \ gen_op_dec4_rN (REG(B11_8)); \ gen_op_movl_rN_T1 (REG(B11_8)); \ gen_op_stl_T0_T1 (ctx); \ return; LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |= MODE_CHANGE;) LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,) LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,) LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,) LDST(spc, 0x404e, 0x4047, ldc, 0x0042, 0x4043, stc,) LDST(dbr, 0x40fa, 0x40f6, ldc, 0x00fa, 0x40f2, stc,) LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,) LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,) LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,) LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,) LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |= MODE_CHANGE;) case 0x00c3: /* movca.l R0,@Rm */