Message ID | BANLkTinXJEsQ2+xGr5+sO4uv2L4qXxp-cQ@mail.gmail.com |
---|---|
State | New |
Headers | show |
Hi, First, do you have some instructions on howto build Octeon usermode 64bit binaries. Second, I think we would prefer that the patch was split to smaller patches. At least the target-mips changes should be a separate patch. Some more comments included inline between the code. On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote: > >From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001 > From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk> > Date: Sat, 26 Mar 2011 11:53:11 +0500 > Subject: [PATCH] MIPS64 user mode emulation in QEMU > This patch adds support for Cavium Network's > Octeon 57XX user mode instructions. Octeon > 57xx is based on MIPS64. So this patch is > the first MIPS64 User Mode Emulation in QEMU > This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed) > work of HPCNL Lab at KICS-UET Lahore. > > > Signed-off-by: Khansa Butt <khansa@kics.edu.pk> > --- > configure | 1 + > default-configs/mips64-linux-user.mak | 1 + > exec.c | 1 + > linux-user/elfload.c | 15 +- > linux-user/main.c | 20 +- > linux-user/mips64/syscall.h | 2 + > linux-user/signal.c | 3 +- > linux-user/syscall.c | 2 + > target-mips/cpu.h | 16 + > target-mips/translate.c | 659 > ++++++++++++++++++++++++++++++++- > 10 files changed, 704 insertions(+), 16 deletions(-) > create mode 100644 default-configs/mips64-linux-user.mak > > diff --git a/configure b/configure > index 438219b..045a4ef 100755 > --- a/configure > +++ b/configure > @@ -1011,6 +1011,7 @@ cris-linux-user \ > m68k-linux-user \ > microblaze-linux-user \ > mips-linux-user \ > +mips64-linux-user \ > mipsel-linux-user \ > ppc-linux-user \ > ppc64-linux-user \ > diff --git a/default-configs/mips64-linux-user.mak > b/default-configs/mips64-linux-user.mak > new file mode 100644 > index 0000000..1598bfc > --- /dev/null > +++ b/default-configs/mips64-linux-user.mak > @@ -0,0 +1 @@ > +# Default configuration for mips64-linux-user > diff --git a/exec.c b/exec.c > index 49c28b1..ee3f78e 100644 > --- a/exec.c > +++ b/exec.c > @@ -2441,6 +2441,7 @@ int page_check_range(target_ulong start, target_ulong > len, int flags) > for (addr = start, len = end - start; > len != 0; > len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { > + addr &= qemu_host_page_mask; > p = page_find(addr >> TARGET_PAGE_BITS); Are you sure this will not generate ill effect on other target/host architecture combinations? > if( !p ) > return -1; > diff --git a/linux-user/elfload.c b/linux-user/elfload.c > index 33d776d..60fe85e 100644 > --- a/linux-user/elfload.c > +++ b/linux-user/elfload.c > @@ -16,6 +16,8 @@ > #include "qemu.h" > #include "disas.h" > > +extern int TARGET_OCTEON; > + > #ifdef _ARCH_PPC64 > #undef ARCH_DLINFO > #undef ELF_PLATFORM > @@ -25,6 +27,9 @@ > #undef ELF_ARCH > #endif > > +#define EF_MIPS_MARCH 16711680 > +#define E_MIPS_MACH_OCTEON 9109504 > + please use hexadecimal values. > #define ELF_OSABI ELFOSABI_SYSV > > /* from personality.h */ > @@ -1313,7 +1318,7 @@ static void load_elf_image(const char *image_name, int > image_fd, > vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr); > vaddr_ps = TARGET_ELF_PAGESTART(vaddr); > > - error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po, > + error = target_mmap(vaddr_ps, eppnt->p_memsz + vaddr_po, > elf_prot, MAP_PRIVATE | MAP_FIXED, > image_fd, eppnt->p_offset - vaddr_po); > if (error == -1) { > @@ -1588,7 +1593,13 @@ int load_elf_binary(struct linux_binprm * bprm, > struct target_pt_regs * regs, > If we do nothing, we'll have overwritten this when we re-use > bprm->buf > when we load the interpreter. */ > elf_ex = *(struct elfhdr *)bprm->buf; > - > +#if defined(TARGET_MIPS64) > + if ((elf_ex.e_flags & EF_MIPS_MARCH) == E_MIPS_MACH_OCTEON) { > + TARGET_OCTEON = 1; > + } else { > + TARGET_OCTEON = 0; > + } > +#endif > bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); > bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); > bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); > diff --git a/linux-user/main.c b/linux-user/main.c > index 0d627d6..8b4b90b 100644 > --- a/linux-user/main.c > +++ b/linux-user/main.c > @@ -1937,10 +1937,16 @@ static int do_store_exclusive(CPUMIPSState *env) > int d; > > addr = env->lladdr; > + /* 64 bit address is converted to 32 bit value so that a valid > + * l1_map value can be accessed. This thing is needed for target > + * mips64 and host 32 bit x86 > + */ > + addr &= qemu_host_page_mask; same as earlier. > page_addr = addr & TARGET_PAGE_MASK; > start_exclusive(); > mmap_lock(); > flags = page_get_flags(page_addr); > + addr = env->lladdr; > if ((flags & PAGE_READ) == 0) { > segv = 1; > } else { > @@ -1978,7 +1984,8 @@ static int do_store_exclusive(CPUMIPSState *env) > void cpu_loop(CPUMIPSState *env) > { > target_siginfo_t info; > - int trapnr, ret; > + int trapnr; > + abi_long ret; > unsigned int syscall_num; > > for(;;) { > @@ -1987,7 +1994,11 @@ void cpu_loop(CPUMIPSState *env) > cpu_exec_end(env); > switch(trapnr) { > case EXCP_SYSCALL: > +#if defined(TARGET_MIPS64) > + syscall_num = env->active_tc.gpr[2] - 5000; > +#else > syscall_num = env->active_tc.gpr[2] - 4000; > +#endif > env->active_tc.PC += 4; > if (syscall_num >= sizeof(mips_syscall_args)) { > ret = -ENOSYS; > @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env) > env->active_tc.gpr[5], > env->active_tc.gpr[6], > env->active_tc.gpr[7], > - arg5, arg6/*, arg7, arg8*/); > + env->active_tc.gpr[8], > + env->active_tc.gpr[9]/*, arg7, arg8*/); > } > if (ret == -TARGET_QEMU_ESIGRETURN) { > /* Returning from a successful sigreturn syscall. > @@ -2926,7 +2938,9 @@ int main(int argc, char **argv, char **envp) > #endif > #elif defined(TARGET_MIPS) > #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) > - cpu_model = "20Kc"; > + /* we use this model so that we can decode MIPS64r2 > + reserved instruction */ > + cpu_model = "MIPS64R2-generic"; > #else > cpu_model = "24Kf"; > #endif > diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h > index 668a2b9..1395e61 100644 > --- a/linux-user/mips64/syscall.h > +++ b/linux-user/mips64/syscall.h > @@ -217,5 +217,7 @@ struct target_pt_regs { > #define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ > > > +/* Nasty hack: define a fake errno value for use by sigreturn. */ > +#define TARGET_QEMU_ESIGRETURN 255 > > #define UNAME_MACHINE "mips64" > diff --git a/linux-user/signal.c b/linux-user/signal.c > index c846b8c..114116c 100644 > --- a/linux-user/signal.c > +++ b/linux-user/signal.c > @@ -2410,7 +2410,8 @@ void sparc64_get_context(CPUSPARCState *env) > #endif > #elif defined(TARGET_ABI_MIPSN64) > > -# warning signal handling not implemented > +/*this line is commented out to avoid compile time error*/ > +/*# warning signal handling not implemented*/ > > static void setup_frame(int sig, struct target_sigaction *ka, > target_sigset_t *set, CPUState *env) > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 499c4d7..47fef05 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long > arg1, > case TARGET_NR_set_thread_area: > #if defined(TARGET_MIPS) > ((CPUMIPSState *) cpu_env)->tls_value = arg1; > + /*tls entry is moved to k0 so that this can be used later*/ > + ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1; Does this affect the non-octeon mips ? > ret = 0; > break; > #elif defined(TARGET_CRIS) And someone else will need to comment the TCG changes. > diff --git a/target-mips/cpu.h b/target-mips/cpu.h > index 2419aa9..59bcc0f 100644 > --- a/target-mips/cpu.h > +++ b/target-mips/cpu.h > @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t; > #define MIPS_FPU_MAX 1 > #define MIPS_DSP_ACC 4 > > +typedef struct cavium_mul cavium_mul; > +struct cavium_mul { > + target_ulong MPL0; > + target_ulong MPL1; > + target_ulong MPL2; > + target_ulong P0; > + target_ulong P1; > + target_ulong P2; > +}; > +typedef struct cvmctl_register cvmctl_register; > +struct cvmctl_register { > + target_ulong cvmctl; > +}; > + > typedef struct TCState TCState; > struct TCState { > target_ulong gpr[32]; > @@ -178,6 +192,8 @@ struct CPUMIPSState { > TCState active_tc; > CPUMIPSFPUContext active_fpu; > > + cavium_mul Reg; > + cvmctl_register CvmCtlRegister; > uint32_t current_tc; > uint32_t current_fpu; > > diff --git a/target-mips/translate.c b/target-mips/translate.c > index cce77be..9c3d772 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -36,6 +36,15 @@ > #define GEN_HELPER 1 > #include "helper.h" > > +int TARGET_OCTEON; > +#if defined(TARGET_MIPS64) > +/*Macros for setting values of cvmctl registers*/ > +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000) > +#define KASUMI(cvmctl)(cvmctl | 0x20000000) > +#define IPPCI(cvmctl)(cvmctl | 0x380) > +#define IPTI(cvmctl)(cvmctl | 0x70) > +#endif > + > //#define MIPS_DEBUG_DISAS > //#define MIPS_DEBUG_SIGN_EXTENSIONS > > @@ -70,6 +79,11 @@ enum { > OPC_JAL = (0x03 << 26), > OPC_JALS = OPC_JAL | 0x5, > OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ > + /* Cavium Specific */ > + OPC_BBIT1 = (0x3a << 26), /*jump on bit set, cavium specific*/ > + OPC_BBIT132 = (0x3e << 26), /*jump on bit set(one of the upper 32 > bits)*/ > + OPC_BBIT0 = (0x32 << 26), /*jump on bit clear, cavium specific*/ > + OPC_BBIT032 = (0x36 << 26), /*jump on bit set(one of the upper 32 > bits)*/ > OPC_BEQL = (0x14 << 26), > OPC_BNE = (0x05 << 26), > OPC_BNEL = (0x15 << 26), > @@ -265,6 +279,31 @@ enum { > OPC_MADD = 0x00 | OPC_SPECIAL2, > OPC_MADDU = 0x01 | OPC_SPECIAL2, > OPC_MUL = 0x02 | OPC_SPECIAL2, > + /* Cavium Specific Instructions */ > + OPC_BADDU = 0x28 | OPC_SPECIAL2, > + OPC_DMUL = 0x03 | OPC_SPECIAL2, > + OPC_EXTS = 0x3a | OPC_SPECIAL2, > + OPC_EXTS32 = 0x3b | OPC_SPECIAL2, > + OPC_CINS = 0x32 | OPC_SPECIAL2, > + OPC_CINS32 = 0x33 | OPC_SPECIAL2, > + OPC_SEQI = 0x2e | OPC_SPECIAL2, > + OPC_SNEI = 0x2f | OPC_SPECIAL2, > + OPC_MTM0 = 0x08 | OPC_SPECIAL2, > + OPC_MTM1 = 0x0c | OPC_SPECIAL2, > + OPC_MTM2 = 0x0d | OPC_SPECIAL2, > + OPC_MTP0 = 0x09 | OPC_SPECIAL2, > + OPC_MTP1 = 0x0a | OPC_SPECIAL2, > + OPC_MTP2 = 0x0b | OPC_SPECIAL2, > + OPC_V3MULU = 0x11 | OPC_SPECIAL2, > + OPC_VMM0 = 0x10 | OPC_SPECIAL2, > + OPC_VMULU = 0x0f | OPC_SPECIAL2, > + OPC_POP = 0X2C | OPC_SPECIAL2, > + OPC_DPOP = 0X2D | OPC_SPECIAL2, > + OPC_SEQ = 0x2a | OPC_SPECIAL2, > + OPC_SNE = 0x2b | OPC_SPECIAL2, > + OPC_SAA = 0x18 | OPC_SPECIAL2, > + OPC_SAAD = 0x19 | OPC_SPECIAL2, > +/**************************************/ > OPC_MSUB = 0x04 | OPC_SPECIAL2, > OPC_MSUBU = 0x05 | OPC_SPECIAL2, > /* Loongson 2F */ > @@ -483,7 +522,7 @@ enum { > static TCGv_ptr cpu_env; > static TCGv cpu_gpr[32], cpu_PC; > static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], > cpu_ACX[MIPS_DSP_ACC]; > -static TCGv cpu_dspctrl, btarget, bcond; > +static TCGv cpu_dspctrl, btarget, bcond, mpl0, mpl1, mpl2, p0, p1, p2; > static TCGv_i32 hflags; > static TCGv_i32 fpu_fcr0, fpu_fcr31; > > @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext *ctx, > TCGv ret, TCGv arg0, TCGv > See the MIPS64 PRA manual, section 4.10. */ > if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && > !(ctx->hflags & MIPS_HFLAG_UX)) { > - tcg_gen_ext32s_i64(ret, ret); > + /*This function sign extend 32 bit value to 64 bit, was causing > error > + when ld instruction came.Thats why it is commmented out*/ > + /* tcg_gen_ext32s_i64(ret, ret);*/ > } > #endif > } > @@ -1419,7 +1460,33 @@ static void gen_arith_imm (CPUState *env, > DisasContext *ctx, uint32_t opc, > (void)opn; /* avoid a compiler warning */ > MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], > regnames[rs], uimm); > } > - > +#if defined(TARGET_MIPS64) > +/*set on equal immidiate/seton not equal immidiate*/ > +static void gen_set_imm(CPUState *env, uint32_t opc, int rt, int rs, > int16_t imm) > +{ > + target_ulong uimm; > + TCGv t0, t1; > + const char *opn = "imm set"; > + uimm = (uint16_t)imm; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + switch (opc) { > + case OPC_SEQI: > + tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); > + gen_load_gpr(t0, rt); > + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, 1); > + opn = "seqi"; > + break; > + case OPC_SNEI: > + tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); > + gen_load_gpr(t0, rt); > + gen_load_gpr(t1, 0); > + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rt], t1, t0); > + opn = "snei"; > + break; > + } > +} > +#endif > /* Logic with immediate operand */ > static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, > int16_t imm) > { > @@ -1583,13 +1650,196 @@ static void gen_shift_imm(CPUState *env, > DisasContext *ctx, uint32_t opc, > MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], > regnames[rs], uimm); > tcg_temp_free(t0); > } > +#if defined(TARGET_MIPS64) > +/* Addition and carry detection*/ > +static void gen_addc (TCGv arg1, TCGv arg2, TCGv res, TCGv c) > +{ > + tcg_gen_add_tl(res, arg1, arg2); > + tcg_gen_setcond_tl(TCG_COND_LTU, c, res, arg1); > +} > +static void gen_LMI (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, > + int rs, int rt, int rd) > +{ > + const char *opn = "LMI"; > + TCGv t0, t1; > + int nomul = env->CvmCtlRegister.cvmctl & 0x8000000; > + if (!nomul) { > + switch (opc) { > + case OPC_MTM0: > + tcg_gen_mov_tl(mpl0, cpu_gpr[rs]); > + tcg_gen_movi_tl(p0, 0); > + tcg_gen_movi_tl(p1, 0); > + tcg_gen_movi_tl(p2, 0); > + opn = "mtm0"; > + break; > + case OPC_MTM1: > + tcg_gen_mov_tl(mpl1, cpu_gpr[rs]); > + tcg_gen_movi_tl(p0, 0); > + tcg_gen_movi_tl(p1, 0); > + tcg_gen_movi_tl(p2, 0); > + opn = "mtm1"; > + break; > + case OPC_MTM2: > + tcg_gen_mov_tl(mpl2, cpu_gpr[rs]); > + tcg_gen_movi_tl(p0, 0); > + tcg_gen_movi_tl(p1, 0); > + tcg_gen_movi_tl(p2, 0); > + opn = "mtm2"; > + break; > + case OPC_MTP0: > + tcg_gen_mov_tl(p0, cpu_gpr[rs]); > + opn = "mtp0"; > + break; > + case OPC_MTP1: > + tcg_gen_mov_tl(p1, cpu_gpr[rs]); > + opn = "mtp1"; > + break; > + case OPC_MTP2: > + tcg_gen_mov_tl(p2, cpu_gpr[rs]); > + opn = "mtp2"; > + break; > + case OPC_VMM0: > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + gen_load_gpr(t1, rs); > + gen_helper_dmultu(t1, mpl0); > + gen_load_gpr(t0, rt); > + tcg_gen_add_tl(t0, t0, cpu_LO[0]); > + tcg_gen_add_tl(t0, t0, p0); > + gen_store_gpr(t0, rd); > + tcg_gen_mov_tl(mpl0, cpu_gpr[rd]); > + tcg_gen_movi_tl(p0, 0); > + tcg_gen_movi_tl(p1, 0); > + tcg_gen_movi_tl(p2, 0); > + tcg_temp_free(t0); > + tcg_temp_free(t1); > + opn = "vmm0"; > + break; > + case OPC_VMULU: > + { > + TCGv t2, c; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + t2 = tcg_temp_new(); > + c = tcg_temp_new(); > + gen_load_gpr(t1, rs); > + gen_load_gpr(t2, rt); > + gen_helper_dmultu(t1, mpl0); > + tcg_gen_mov_tl(t0, cpu_LO[0]); > + /*if carry comes due to addition of rt and LO register, > + * this carry should be added to HI register. > + */ > + gen_addc(t0, t2, t1, c); > > + tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c); > + /* t0 = t1 + p0 where t1 = LO+rt*/ > + gen_addc(t1, p0, t0, c); > + tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c); > + > + tcg_gen_mov_tl(cpu_gpr[rd], t0); > + tcg_gen_mov_tl(p0, cpu_HI[0]); > + tcg_temp_free(t0); > + tcg_temp_free(t1); > + tcg_temp_free(t2); > + opn = "vmulu"; > + break; > + } > + case OPC_V3MULU: > + { > + TCGv temp[4]; > + TCGv c; > + TCGv trs, trt, tc1, tc2, tc3; > + temp[0] = tcg_temp_new(); > + temp[1] = tcg_temp_new(); > + temp[2] = tcg_temp_new(); > + temp[3] = tcg_temp_new(); > + trs = tcg_temp_new(); > + trt = tcg_temp_new(); > + tc1 = tcg_temp_new(); > + tc2 = tcg_temp_new(); > + tc3 = tcg_temp_new(); > + c = tcg_temp_new(); > + gen_load_gpr(trs, rs); > + gen_load_gpr(trt, rt); > + /* rs × (MPL2 || MPL1 || MPL0) (192X64 bit multiplication) > */ > + gen_helper_dmultu(trs, mpl0); > + tcg_gen_mov_tl(temp[0], cpu_LO[0]); > + tcg_gen_mov_tl(temp[1], cpu_HI[0]); > + > + gen_helper_dmultu(trs, mpl1); > + tcg_gen_mov_tl(temp[2], cpu_HI[0]); > + gen_addc(cpu_LO[0], temp[1], tc1, tc2); > + gen_addc(temp[2], tc2, tc3, c); > + tcg_gen_mov_tl(temp[1], tc1); > + tcg_gen_mov_tl(temp[2], tc3); > + tcg_gen_mov_tl(temp[3], c); > + > + gen_helper_dmultu(trs, mpl2); > + tcg_gen_add_tl(temp[3], temp[3], cpu_HI[0]); > + gen_addc(cpu_LO[0], temp[2], tc1, tc2); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], tc2); > + /* Addition of rt in 256 bit result > + (t3 t2 t1 t0 contain result) */ > + gen_addc(temp[0], trt, tc1, c); > + tcg_gen_mov_tl(temp[0], tc1); > + gen_addc(temp[1], c, tc1, tc2); > + tcg_gen_mov_tl(temp[1], tc1); > + gen_addc(temp[2], tc2, tc1, c); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], c); > + /* Addition of p2 p1 p0 in 256 bit result */ > + gen_addc(temp[0], p0, tc1, c); > + tcg_gen_mov_tl(temp[0], tc1); > + gen_addc(temp[1], c, tc1, tc2); > + tcg_gen_mov_tl(temp[1], tc1); > + gen_addc(temp[2], tc2, tc1, c); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], c); > + > + gen_addc(temp[1], p1, tc1, c); > + tcg_gen_mov_tl(temp[1], tc1); > + gen_addc(temp[2], c, tc1, tc2); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], tc2); > + > + gen_addc(temp[2], p2, tc1, c); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], c); > + /* final step */ > + tcg_gen_mov_tl(cpu_gpr[rd], temp[0]); > + tcg_gen_mov_tl(p0, temp[1]); > + tcg_gen_mov_tl(p1, temp[2]); > + tcg_gen_mov_tl(p2, temp[3]); > + tcg_temp_free(temp[0]); > + tcg_temp_free(temp[1]); > + tcg_temp_free(temp[2]); > + tcg_temp_free(temp[3]); > + tcg_temp_free(trs); > + tcg_temp_free(trt); > + tcg_temp_free(tc1); > + tcg_temp_free(tc2); > + tcg_temp_free(tc3); > + tcg_temp_free(c); > + opn = "v3mulu"; > + break; > + } > + } > + > + } else { > + generate_exception(ctx, EXCP_RI); > + } > +} > + > + > +#endif > /* Arithmetic */ > static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, > int rd, int rs, int rt) > { > const char *opn = "arith"; > > + target_ulong mask = 0xFF; > if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB > && opc != OPC_DADD && opc != OPC_DSUB) { > /* If no destination, treat it as a NOP. > @@ -1637,6 +1887,22 @@ static void gen_arith (CPUState *env, DisasContext > *ctx, uint32_t opc, > } > opn = "addu"; > break; > + case OPC_BADDU: > + { > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + TCGv t2 = tcg_temp_new(); > + gen_load_gpr(t1, rs); > + gen_load_gpr(t2, rt); > + tcg_gen_andi_tl(t1, t1, mask); > + tcg_gen_andi_tl(t2, t2, mask); > + tcg_gen_add_tl(t0, t1, t2); > + tcg_gen_andi_tl(t0, t0, mask); > + gen_store_gpr(t0, rd); > + } > + > + opn = "baddu"; > + break; > case OPC_SUB: > { > TCGv t0 = tcg_temp_local_new(); > @@ -2013,7 +2279,74 @@ static void gen_HILO (DisasContext *ctx, uint32_t > opc, int reg) > (void)opn; /* avoid a compiler warning */ > MIPS_DEBUG("%s %s", opn, regnames[reg]); > } > +#if defined(TARGET_MIPS64) > +static void gen_seqsne (DisasContext *ctx, uint32_t opc, > + int rd, int rs, int rt) > +{ > + const char *opn = "seq/sne"; > + TCGv t0, t1; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + switch (opc) { > + case OPC_SEQ: > + { > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > + gen_load_gpr(t0, rd); > + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1); > + } > + opn = "seq"; > + break; > + case OPC_SNE: > + { > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > + gen_load_gpr(t0, rd); > + gen_load_gpr(t1, 0); > + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0); > + } > + opn = "sne"; > + break; > + default: > + MIPS_INVAL(opn); > + generate_exception(ctx, EXCP_RI); > + goto out; > + } > +out: > + tcg_temp_free(t0); > + tcg_temp_free(t1); > > +} > + > +static void gen_saa (CPUState *env, DisasContext *ctx, uint32_t opc, > + int rt, int base) > +{ > + const char *opn = "saa"; > + TCGv t0, t1, temp; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + temp = tcg_temp_new(); > + gen_load_gpr(t1, rt); > + gen_base_offset_addr(ctx, t0, base, 0); > + switch (opc) { > + case OPC_SAA: > + save_cpu_state(ctx, 1); > + op_ld_lw(temp, t0, ctx); > + tcg_gen_add_tl(temp, temp, t1); > + op_st_sw(temp, t0, ctx); > + opn = "saa"; > + break; > + case OPC_SAAD: > + save_cpu_state(ctx, 0); > + op_ld_ld(temp, t0, ctx); > + tcg_gen_add_tl(temp, temp, t1); > + op_st_sd(temp, t0, ctx); > + opn = "saad"; > + break; > + } > + > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > +#endif > static void gen_muldiv (DisasContext *ctx, uint32_t opc, > int rs, int rt) > { > @@ -2149,6 +2482,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t > opc, > gen_helper_dmult(t0, t1); > opn = "dmult"; > break; > + case OPC_DMUL: > + gen_helper_dmult(t0, t1); > + opn = "dmul"; > + break; > case OPC_DMULTU: > gen_helper_dmultu(t0, t1); > opn = "dmultu"; > @@ -2368,7 +2705,49 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, > MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); > tcg_temp_free(t0); > } > +#if defined(TARGET_MIPS64) > +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t opc, > + int rd, int rs, int rt) > +{ > + TCGv num = tcg_temp_new(); > + TCGv res = tcg_temp_new(); > + target_ulong maskb = 1; > + gen_load_gpr(num, rs); > + TCGv ones=tcg_temp_new(); > + gen_load_gpr(ones, 0); > + int x=1; > + tcg_gen_andi_tl(res, num, maskb); > + tcg_gen_add_tl(ones,ones, res); > + while (x <= 31) { > + tcg_gen_shri_i64(num, num, 1); > + tcg_gen_andi_tl(res, num, maskb); > + tcg_gen_add_tl(ones, ones, res); > + x++; > + } > + gen_store_gpr(ones, rd); > +} > +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t opc, > + int rd, int rs, int rt) > +{ > + TCGv num, res, ones; > + num = tcg_temp_new(); > + res = tcg_temp_new(); > + ones = tcg_temp_new(); > + target_ulong maskb = 1; > + gen_load_gpr(num, rs); > + int x = 1; > + tcg_gen_andi_tl(res, num, maskb); > + tcg_gen_mov_tl(ones, res); > > + while (x <= 63) { > + tcg_gen_shri_i64(num, num, 1); > + tcg_gen_andi_tl(res, num, maskb); > + tcg_gen_add_tl(ones, ones, res); > + x++; > + } > + gen_store_gpr(ones, rd); > +} > +#endif > /* Godson integer instructions */ > static void gen_loongson_integer (DisasContext *ctx, uint32_t opc, > int rd, int rs, int rt) > @@ -2705,6 +3084,7 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > target_ulong btgt = -1; > int blink = 0; > int bcond_compute = 0; > + target_ulong maskb; /* Used in BBIT0 and BBIT1*/ > TCGv t0 = tcg_temp_new(); > TCGv t1 = tcg_temp_new(); > > @@ -2730,6 +3110,39 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > } > btgt = ctx->pc + insn_bytes + offset; > break; > + case OPC_BBIT1: > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, 0); > + maskb = 1ULL << rt; > + tcg_gen_andi_tl(t0, t0, maskb); > + bcond_compute = 1; > + btgt = ctx->pc + insn_bytes + offset; > + break; > + case OPC_BBIT132: > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, 0); > + maskb = 1ULL << (rt + 32); > + tcg_gen_andi_tl(t0, t0, maskb); > + bcond_compute = 1; > + btgt = ctx->pc + insn_bytes + offset; > + break; > + case OPC_BBIT0: > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, 0); > + maskb = 1ULL << rt; > + tcg_gen_andi_tl(t0, t0, maskb); > + bcond_compute = 1; > + btgt = ctx->pc + insn_bytes + offset; > + break; > + case OPC_BBIT032: > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, 0); > + maskb = 1ULL << (rt + 32); > + tcg_gen_andi_tl(t0, t0, maskb); > + bcond_compute = 1; > + btgt = ctx->pc + insn_bytes + offset; > + break; > + > case OPC_BGEZ: > case OPC_BGEZAL: > case OPC_BGEZALS: > @@ -2888,6 +3301,18 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx, > regnames[rs], regnames[rt], btgt); > goto not_likely; > + case OPC_BBIT1: > + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > + goto not_likely; > + case OPC_BBIT132: > + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > + goto not_likely; > + case OPC_BBIT0: > + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); > + goto not_likely; > + case OPC_BBIT032: > + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); > + goto not_likely; > case OPC_BNEL: > tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx, > @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > tcg_temp_free(t0); > tcg_temp_free(t1); > } > +/*For cavium specific extract instructions*/ > +#if defined(TARGET_MIPS64) > +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int > rt, > + int rs, int lsb, int msb) > +{ > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + target_ulong mask; > + gen_load_gpr(t1, rs); > + switch (opc) { > + case OPC_EXTS: > + tcg_gen_shri_tl(t0, t1, lsb); > + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); > + /* To sign extened the remaining bits according to > + the msb of the bit field */ > + mask = 1ULL << msb; > + tcg_gen_andi_tl(t1, t0, mask); > + tcg_gen_addi_tl(t1, t1, -1); > + tcg_gen_not_i64(t1, t1); > + tcg_gen_or_tl(t0, t0, t1); > + gen_store_gpr(t0, rt); > + break; > + case OPC_EXTS32: > + tcg_gen_shri_tl(t0, t1, lsb + 32); > + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); > + mask = 1ULL << msb; > + tcg_gen_andi_tl(t1, t0, mask); > + tcg_gen_addi_tl(t1, t1, -1); > + tcg_gen_not_i64(t1, t1); > + tcg_gen_or_tl(t0, t0, t1); > + gen_store_gpr(t0, rt); > + break; > > + } > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > +#endif > /* special3 bitfield operations */ > static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, > int rs, int lsb, int msb) > @@ -3063,6 +3525,22 @@ static void gen_bitops (DisasContext *ctx, uint32_t > opc, int rt, > tcg_gen_andi_tl(t1, t1, mask); > tcg_gen_or_tl(t0, t0, t1); > break; > + case OPC_CINS: > + mask = (1ULL << (msb+1))-1; > + gen_load_gpr(t0, rt); > + tcg_gen_andi_tl(t0, t0, 0); > + tcg_gen_andi_tl(t1, t1, mask); > + tcg_gen_shli_tl(t1, t1, lsb); > + tcg_gen_or_tl(t0, t0, t1); > + break; > + case OPC_CINS32: > + mask = (1ULL << (msb+1))-1; > + gen_load_gpr(t0, rt); > + tcg_gen_andi_tl(t0, t0, 0); > + tcg_gen_andi_tl(t1, t1, mask); > + tcg_gen_shli_tl(t1, t1, (lsb+32)); > + tcg_gen_or_tl(t0, t0, t1); > + break; > #endif > default: > fail: > @@ -11605,7 +12083,7 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > int32_t offset; > int rs, rt, rd, sa; > uint32_t op, op1, op2; > - int16_t imm; > + int16_t imm, imm10; > > /* make sure instructions are on a word boundary */ > if (ctx->pc & 0x3) { > @@ -11634,6 +12112,9 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > rd = (ctx->opcode >> 11) & 0x1f; > sa = (ctx->opcode >> 6) & 0x1f; > imm = (int16_t)ctx->opcode; > + /* 10 bit Immediate value For SEQI,SNEI */ > + imm10 = (ctx->opcode >> 6) & 0x3ff; > + > switch (op) { > case OPC_SPECIAL: > op1 = MASK_SPECIAL(ctx->opcode); > @@ -11859,6 +12340,71 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > case OPC_MUL: > gen_arith(env, ctx, op1, rd, rs, rt); > break; > +#if defined(TARGET_MIPS64) > + > + > + case OPC_DMUL: > + check_insn(env, ctx, ISA_MIPS3); > + check_mips_64(ctx); > + gen_muldiv(ctx, op1, rs, rt); > + tcg_gen_mov_tl(cpu_gpr[rd], cpu_LO[0]); > + break; > + case OPC_CINS: > + check_insn(env, ctx, ISA_MIPS64R2); > + check_mips_64(ctx); > + gen_bitops(ctx, op1, rt, rs, sa, rd); > + break; > + case OPC_CINS32: > + check_mips_64(ctx); > + gen_bitops(ctx, op1, rt, rs, sa, rd); > + break; > + case OPC_MTM0: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTM1: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTM2: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTP0: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTP1: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTP2: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_VMULU: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_BADDU: > + gen_arith(env, ctx, op1, rd, rs, rt); > + break; > + case OPC_EXTS: > + check_mips_64(ctx); > + gen_exts(env, ctx, op1, rt, rs, sa, rd); > + break; > + case OPC_EXTS32: > + check_mips_64(ctx); > + gen_exts(env, ctx, op1, rt, rs, sa, rd); > + break; > + case OPC_SAA: > + gen_saa(env, ctx, op1, rt, rs); > + break; > + case OPC_SAAD: > + check_mips_64(ctx); > + gen_saa(env, ctx, op1, rt, rs); > + break; > +#endif > case OPC_CLO: > case OPC_CLZ: > check_insn(env, ctx, ISA_MIPS32); > @@ -11878,13 +12424,24 @@ static void decode_opc (CPUState *env, > DisasContext *ctx, int *is_branch) > break; > case OPC_DIV_G_2F: > case OPC_DIVU_G_2F: > - case OPC_MULT_G_2F: > case OPC_MULTU_G_2F: > case OPC_MOD_G_2F: > case OPC_MODU_G_2F: > check_insn(env, ctx, INSN_LOONGSON2F); > gen_loongson_integer(ctx, op1, rd, rs, rt); > break; > + case OPC_MULT_G_2F: > + if (!TARGET_OCTEON) { > + check_insn(env, ctx, INSN_LOONGSON2F); > + gen_loongson_integer(ctx, op1, rd, rs, rt); > + } else { > +#if defined(TARGET_MIPS64) > + /* Cavium Specific vmm0 */ > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > +#endif > + } > + break; > #if defined(TARGET_MIPS64) > case OPC_DCLO: > case OPC_DCLZ: > @@ -11892,7 +12449,6 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > check_mips_64(ctx); > gen_cl(ctx, op1, rd, rs); > break; > - case OPC_DMULT_G_2F: > case OPC_DMULTU_G_2F: > case OPC_DDIV_G_2F: > case OPC_DDIVU_G_2F: > @@ -11901,6 +12457,39 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > check_insn(env, ctx, INSN_LOONGSON2F); > gen_loongson_integer(ctx, op1, rd, rs, rt); > break; > + case OPC_DMULT_G_2F: > + if (!TARGET_OCTEON) { > + check_insn(env, ctx, INSN_LOONGSON2F); > + gen_loongson_integer(ctx, op1, rd, rs, rt); > + } else { > + /* Cavium Specific instruction v3mulu */ > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + } > + break; > + case OPC_SEQ: > + check_mips_64(ctx); > + gen_seqsne(ctx, op1, rd, rs, rt); > + break; > + case OPC_SNE: > + check_mips_64(ctx); > + gen_seqsne(ctx, op1, rd, rs, rt); > + break; > + case OPC_SEQI: > + check_mips_64(ctx); > + gen_set_imm(env, op1, rt, rs, imm10); > + break; > + case OPC_SNEI: > + check_mips_64(ctx); > + gen_set_imm(env, op1, rt, rs, imm10); > + break; > + case OPC_POP: > + insn_opc_pop(ctx, env, op1, rd, rs, rt); > + break; > + case OPC_DPOP: > + check_mips_64(ctx); > + insn_opc_dpop(ctx, env, op1, rd, rs, rt); > + break; > #endif > default: /* Invalid */ > MIPS_INVAL("special2"); > @@ -12192,10 +12781,32 @@ static void decode_opc (CPUState *env, > DisasContext *ctx, int *is_branch) > break; > > /* COP2. */ > - case OPC_LWC2: > - case OPC_LDC2: > - case OPC_SWC2: > - case OPC_SDC2: > + /* Conflicting opcodes with Cavium specific branch instructions > + if TARGET_OCTEON is set these opcodes will belong to Cavium */ > + case OPC_LWC2: /*BBIT0*/ > + if(TARGET_OCTEON) { > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > + *is_branch = 1; > + break; > + } > + case OPC_LDC2: /*BBIT032*/ > + if(TARGET_OCTEON) { > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > + *is_branch = 1; > + break; > + } > + case OPC_SWC2: /*BBIT1*/ > + if(TARGET_OCTEON) { > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > + *is_branch = 1; > + break; > + } > + case OPC_SDC2: /*BBIT132*/ > + if(TARGET_OCTEON) { > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > + *is_branch = 1; > + break; > + } > case OPC_CP2: > /* COP2: Not implemented. */ > generate_exception_err(ctx, EXCP_CpU, 2); > @@ -12584,6 +13195,18 @@ static void mips_tcg_init(void) > cpu_dspctrl = tcg_global_mem_new(TCG_AREG0, > offsetof(CPUState, > active_tc.DSPControl), > "DSPControl"); > + mpl0 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.MPL0), "MPL0"); > + mpl1 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.MPL1), "MPL1"); > + mpl2 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.MPL2), "MPL2"); > + p0 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.P0), "P0"); > + p1 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.P1), "P1"); > + p2 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.P2), "P2"); > bcond = tcg_global_mem_new(TCG_AREG0, > offsetof(CPUState, bcond), "bcond"); > btarget = tcg_global_mem_new(TCG_AREG0, > @@ -12607,6 +13230,18 @@ static void mips_tcg_init(void) > > #include "translate_init.c" > > +#if defined(TARGET_MIPS64) > + > +static void set_cvmctl_register(CPUMIPSState *env) > +{ > + env->CvmCtlRegister.cvmctl = env->CvmCtlRegister.cvmctl > + ^ env->CvmCtlRegister.cvmctl; > + env->CvmCtlRegister.cvmctl = > FUSE_START_BIT(env->CvmCtlRegister.cvmctl); > + env->CvmCtlRegister.cvmctl = KASUMI(env->CvmCtlRegister.cvmctl); > + env->CvmCtlRegister.cvmctl = IPPCI(env->CvmCtlRegister.cvmctl); > + env->CvmCtlRegister.cvmctl = IPTI(env->CvmCtlRegister.cvmctl); > +} > +#endif > CPUMIPSState *cpu_mips_init (const char *cpu_model) > { > CPUMIPSState *env; > @@ -12619,6 +13254,10 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model) > env->cpu_model = def; > env->cpu_model_str = cpu_model; > > +#if defined(TARGET_MIPS64) > + /*Function for setting cvmctl register*/ > + set_cvmctl_register(env); > +#endif > cpu_exec_init(env); > #ifndef CONFIG_USER_ONLY > mmu_init(env, def); > -- > 1.7.3.4
hiThanks for your review. I have Cavium Networks Octeon board so I can provide you MIPS64 bit binaries. I can not understand the second thing. if my concern is to reduce the patch size then again target-mips changes patch will produce a bigger sized patch because my major changes are in target-mips(translate.c).. so please guide me what should I do. I think Implementation of Octeon specific instruction should be in single patch what do you say?PS- --- On Tue, 3/29/11, Riku Voipio <riku.voipio@iki.fi> wrote: From: Riku Voipio <riku.voipio@iki.fi> Subject: Re: [Qemu-devel] MIPS64 user mode emulation Patch To: "Khansa Butt" <khansa@kics.edu.pk> Cc: qemu-devel@nongnu.org Date: Tuesday, March 29, 2011, 1:55 AM Hi, First, do you have some instructions on howto build Octeon usermode 64bit binaries. Second, I think we would prefer that the patch was split to smaller patches. At least the target-mips changes should be a separate patch. Some more comments included inline between the code. On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote: > >From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001 > From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk> > Date: Sat, 26 Mar 2011 11:53:11 +0500 > Subject: [PATCH] MIPS64 user mode emulation in QEMU > This patch adds support for Cavium Network's > Octeon 57XX user mode instructions. Octeon > 57xx is based on MIPS64. So this patch is > the first MIPS64 User Mode Emulation in QEMU > This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed) > work of HPCNL Lab at KICS-UET Lahore. > > > Signed-off-by: Khansa Butt <khansa@kics.edu.pk> > --- > configure | 1 + > default-configs/mips64-linux-user.mak | 1 + > exec.c | 1 + > linux-user/elfload.c | 15 +- > linux-user/main.c | 20 +- > linux-user/mips64/syscall.h | 2 + > linux-user/signal.c | 3 +- > linux-user/syscall.c | 2 + > target-mips/cpu.h | 16 + > target-mips/translate.c | 659 > ++++++++++++++++++++++++++++++++- > 10 files changed, 704 insertions(+), 16 deletions(-) > create mode 100644 default-configs/mips64-linux-user.mak > > diff --git a/configure b/configure > index 438219b..045a4ef 100755 > --- a/configure > +++ b/configure > @@ -1011,6 +1011,7 @@ cris-linux-user \ > m68k-linux-user \ > microblaze-linux-user \ > mips-linux-user \ > +mips64-linux-user \ > mipsel-linux-user \ > ppc-linux-user \ > ppc64-linux-user \ > diff --git a/default-configs/mips64-linux-user.mak > b/default-configs/mips64-linux-user.mak > new file mode 100644 > index 0000000..1598bfc > --- /dev/null > +++ b/default-configs/mips64-linux-user.mak > @@ -0,0 +1 @@ > +# Default configuration for mips64-linux-user > diff --git a/exec.c b/exec.c > index 49c28b1..ee3f78e 100644 > --- a/exec.c > +++ b/exec.c > @@ -2441,6 +2441,7 @@ int page_check_range(target_ulong start, target_ulong > len, int flags) > for (addr = start, len = end - start; > len != 0; > len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { > + addr &= qemu_host_page_mask; > p = page_find(addr >> TARGET_PAGE_BITS); Are you sure this will not generate ill effect on other target/host architecture combinations? > if( !p ) > return -1; > diff --git a/linux-user/elfload.c b/linux-user/elfload.c > index 33d776d..60fe85e 100644 > --- a/linux-user/elfload.c > +++ b/linux-user/elfload.c > @@ -16,6 +16,8 @@ > #include "qemu.h" > #include "disas.h" > > +extern int TARGET_OCTEON; > + > #ifdef _ARCH_PPC64 > #undef ARCH_DLINFO > #undef ELF_PLATFORM > @@ -25,6 +27,9 @@ > #undef ELF_ARCH > #endif > > +#define EF_MIPS_MARCH 16711680 > +#define E_MIPS_MACH_OCTEON 9109504 > + please use hexadecimal values. > #define ELF_OSABI ELFOSABI_SYSV > > /* from personality.h */ > @@ -1313,7 +1318,7 @@ static void load_elf_image(const char *image_name, int > image_fd, > vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr); > vaddr_ps = TARGET_ELF_PAGESTART(vaddr); > > - error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po, > + error = target_mmap(vaddr_ps, eppnt->p_memsz + vaddr_po, > elf_prot, MAP_PRIVATE | MAP_FIXED, > image_fd, eppnt->p_offset - vaddr_po); > if (error == -1) { > @@ -1588,7 +1593,13 @@ int load_elf_binary(struct linux_binprm * bprm, > struct target_pt_regs * regs, > If we do nothing, we'll have overwritten this when we re-use > bprm->buf > when we load the interpreter. */ > elf_ex = *(struct elfhdr *)bprm->buf; > - > +#if defined(TARGET_MIPS64) > + if ((elf_ex.e_flags & EF_MIPS_MARCH) == E_MIPS_MACH_OCTEON) { > + TARGET_OCTEON = 1; > + } else { > + TARGET_OCTEON = 0; > + } > +#endif > bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); > bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); > bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); > diff --git a/linux-user/main.c b/linux-user/main.c > index 0d627d6..8b4b90b 100644 > --- a/linux-user/main.c > +++ b/linux-user/main.c > @@ -1937,10 +1937,16 @@ static int do_store_exclusive(CPUMIPSState *env) > int d; > > addr = env->lladdr; > + /* 64 bit address is converted to 32 bit value so that a valid > + * l1_map value can be accessed. This thing is needed for target > + * mips64 and host 32 bit x86 > + */ > + addr &= qemu_host_page_mask; same as earlier. > page_addr = addr & TARGET_PAGE_MASK; > start_exclusive(); > mmap_lock(); > flags = page_get_flags(page_addr); > + addr = env->lladdr; > if ((flags & PAGE_READ) == 0) { > segv = 1; > } else { > @@ -1978,7 +1984,8 @@ static int do_store_exclusive(CPUMIPSState *env) > void cpu_loop(CPUMIPSState *env) > { > target_siginfo_t info; > - int trapnr, ret; > + int trapnr; > + abi_long ret; > unsigned int syscall_num; > > for(;;) { > @@ -1987,7 +1994,11 @@ void cpu_loop(CPUMIPSState *env) > cpu_exec_end(env); > switch(trapnr) { > case EXCP_SYSCALL: > +#if defined(TARGET_MIPS64) > + syscall_num = env->active_tc.gpr[2] - 5000; > +#else > syscall_num = env->active_tc.gpr[2] - 4000; > +#endif > env->active_tc.PC += 4; > if (syscall_num >= sizeof(mips_syscall_args)) { > ret = -ENOSYS; > @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env) > env->active_tc.gpr[5], > env->active_tc.gpr[6], > env->active_tc.gpr[7], > - arg5, arg6/*, arg7, arg8*/); > + env->active_tc.gpr[8], > + env->active_tc.gpr[9]/*, arg7, arg8*/); > } > if (ret == -TARGET_QEMU_ESIGRETURN) { > /* Returning from a successful sigreturn syscall. > @@ -2926,7 +2938,9 @@ int main(int argc, char **argv, char **envp) > #endif > #elif defined(TARGET_MIPS) > #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) > - cpu_model = "20Kc"; > + /* we use this model so that we can decode MIPS64r2 > + reserved instruction */ > + cpu_model = "MIPS64R2-generic"; > #else > cpu_model = "24Kf"; > #endif > diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h > index 668a2b9..1395e61 100644 > --- a/linux-user/mips64/syscall.h > +++ b/linux-user/mips64/syscall.h > @@ -217,5 +217,7 @@ struct target_pt_regs { > #define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ > > > +/* Nasty hack: define a fake errno value for use by sigreturn. */ > +#define TARGET_QEMU_ESIGRETURN 255 > > #define UNAME_MACHINE "mips64" > diff --git a/linux-user/signal.c b/linux-user/signal.c > index c846b8c..114116c 100644 > --- a/linux-user/signal.c > +++ b/linux-user/signal.c > @@ -2410,7 +2410,8 @@ void sparc64_get_context(CPUSPARCState *env) > #endif > #elif defined(TARGET_ABI_MIPSN64) > > -# warning signal handling not implemented > +/*this line is commented out to avoid compile time error*/ > +/*# warning signal handling not implemented*/ > > static void setup_frame(int sig, struct target_sigaction *ka, > target_sigset_t *set, CPUState *env) > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 499c4d7..47fef05 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long > arg1, > case TARGET_NR_set_thread_area: > #if defined(TARGET_MIPS) > ((CPUMIPSState *) cpu_env)->tls_value = arg1; > + /*tls entry is moved to k0 so that this can be used later*/ > + ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1; Does this affect the non-octeon mips ? > ret = 0; > break; > #elif defined(TARGET_CRIS) And someone else will need to comment the TCG changes. > diff --git a/target-mips/cpu.h b/target-mips/cpu.h > index 2419aa9..59bcc0f 100644 > --- a/target-mips/cpu.h > +++ b/target-mips/cpu.h > @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t; > #define MIPS_FPU_MAX 1 > #define MIPS_DSP_ACC 4 > > +typedef struct cavium_mul cavium_mul; > +struct cavium_mul { > + target_ulong MPL0; > + target_ulong MPL1; > + target_ulong MPL2; > + target_ulong P0; > + target_ulong P1; > + target_ulong P2; > +}; > +typedef struct cvmctl_register cvmctl_register; > +struct cvmctl_register { > + target_ulong cvmctl; > +}; > + > typedef struct TCState TCState; > struct TCState { > target_ulong gpr[32]; > @@ -178,6 +192,8 @@ struct CPUMIPSState { > TCState active_tc; > CPUMIPSFPUContext active_fpu; > > + cavium_mul Reg; > + cvmctl_register CvmCtlRegister; > uint32_t current_tc; > uint32_t current_fpu; > > diff --git a/target-mips/translate.c b/target-mips/translate.c > index cce77be..9c3d772 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -36,6 +36,15 @@ > #define GEN_HELPER 1 > #include "helper.h" > > +int TARGET_OCTEON; > +#if defined(TARGET_MIPS64) > +/*Macros for setting values of cvmctl registers*/ > +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000) > +#define KASUMI(cvmctl)(cvmctl | 0x20000000) > +#define IPPCI(cvmctl)(cvmctl | 0x380) > +#define IPTI(cvmctl)(cvmctl | 0x70) > +#endif > + > //#define MIPS_DEBUG_DISAS > //#define MIPS_DEBUG_SIGN_EXTENSIONS > > @@ -70,6 +79,11 @@ enum { > OPC_JAL = (0x03 << 26), > OPC_JALS = OPC_JAL | 0x5, > OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ > + /* Cavium Specific */ > + OPC_BBIT1 = (0x3a << 26), /*jump on bit set, cavium specific*/ > + OPC_BBIT132 = (0x3e << 26), /*jump on bit set(one of the upper 32 > bits)*/ > + OPC_BBIT0 = (0x32 << 26), /*jump on bit clear, cavium specific*/ > + OPC_BBIT032 = (0x36 << 26), /*jump on bit set(one of the upper 32 > bits)*/ > OPC_BEQL = (0x14 << 26), > OPC_BNE = (0x05 << 26), > OPC_BNEL = (0x15 << 26), > @@ -265,6 +279,31 @@ enum { > OPC_MADD = 0x00 | OPC_SPECIAL2, > OPC_MADDU = 0x01 | OPC_SPECIAL2, > OPC_MUL = 0x02 | OPC_SPECIAL2, > + /* Cavium Specific Instructions */ > + OPC_BADDU = 0x28 | OPC_SPECIAL2, > + OPC_DMUL = 0x03 | OPC_SPECIAL2, > + OPC_EXTS = 0x3a | OPC_SPECIAL2, > + OPC_EXTS32 = 0x3b | OPC_SPECIAL2, > + OPC_CINS = 0x32 | OPC_SPECIAL2, > + OPC_CINS32 = 0x33 | OPC_SPECIAL2, > + OPC_SEQI = 0x2e | OPC_SPECIAL2, > + OPC_SNEI = 0x2f | OPC_SPECIAL2, > + OPC_MTM0 = 0x08 | OPC_SPECIAL2, > + OPC_MTM1 = 0x0c | OPC_SPECIAL2, > + OPC_MTM2 = 0x0d | OPC_SPECIAL2, > + OPC_MTP0 = 0x09 | OPC_SPECIAL2, > + OPC_MTP1 = 0x0a | OPC_SPECIAL2, > + OPC_MTP2 = 0x0b | OPC_SPECIAL2, > + OPC_V3MULU = 0x11 | OPC_SPECIAL2, > + OPC_VMM0 = 0x10 | OPC_SPECIAL2, > + OPC_VMULU = 0x0f | OPC_SPECIAL2, > + OPC_POP = 0X2C | OPC_SPECIAL2, > + OPC_DPOP = 0X2D | OPC_SPECIAL2, > + OPC_SEQ = 0x2a | OPC_SPECIAL2, > + OPC_SNE = 0x2b | OPC_SPECIAL2, > + OPC_SAA = 0x18 | OPC_SPECIAL2, > + OPC_SAAD = 0x19 | OPC_SPECIAL2, > +/**************************************/ > OPC_MSUB = 0x04 | OPC_SPECIAL2, > OPC_MSUBU = 0x05 | OPC_SPECIAL2, > /* Loongson 2F */ > @@ -483,7 +522,7 @@ enum { > static TCGv_ptr cpu_env; > static TCGv cpu_gpr[32], cpu_PC; > static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], > cpu_ACX[MIPS_DSP_ACC]; > -static TCGv cpu_dspctrl, btarget, bcond; > +static TCGv cpu_dspctrl, btarget, bcond, mpl0, mpl1, mpl2, p0, p1, p2; > static TCGv_i32 hflags; > static TCGv_i32 fpu_fcr0, fpu_fcr31; > > @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext *ctx, > TCGv ret, TCGv arg0, TCGv > See the MIPS64 PRA manual, section 4.10. */ > if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && > !(ctx->hflags & MIPS_HFLAG_UX)) { > - tcg_gen_ext32s_i64(ret, ret); > + /*This function sign extend 32 bit value to 64 bit, was causing > error > + when ld instruction came.Thats why it is commmented out*/ > + /* tcg_gen_ext32s_i64(ret, ret);*/ > } > #endif > } > @@ -1419,7 +1460,33 @@ static void gen_arith_imm (CPUState *env, > DisasContext *ctx, uint32_t opc, > (void)opn; /* avoid a compiler warning */ > MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], > regnames[rs], uimm); > } > - > +#if defined(TARGET_MIPS64) > +/*set on equal immidiate/seton not equal immidiate*/ > +static void gen_set_imm(CPUState *env, uint32_t opc, int rt, int rs, > int16_t imm) > +{ > + target_ulong uimm; > + TCGv t0, t1; > + const char *opn = "imm set"; > + uimm = (uint16_t)imm; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + switch (opc) { > + case OPC_SEQI: > + tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); > + gen_load_gpr(t0, rt); > + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, 1); > + opn = "seqi"; > + break; > + case OPC_SNEI: > + tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); > + gen_load_gpr(t0, rt); > + gen_load_gpr(t1, 0); > + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rt], t1, t0); > + opn = "snei"; > + break; > + } > +} > +#endif > /* Logic with immediate operand */ > static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, > int16_t imm) > { > @@ -1583,13 +1650,196 @@ static void gen_shift_imm(CPUState *env, > DisasContext *ctx, uint32_t opc, > MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], > regnames[rs], uimm); > tcg_temp_free(t0); > } > +#if defined(TARGET_MIPS64) > +/* Addition and carry detection*/ > +static void gen_addc (TCGv arg1, TCGv arg2, TCGv res, TCGv c) > +{ > + tcg_gen_add_tl(res, arg1, arg2); > + tcg_gen_setcond_tl(TCG_COND_LTU, c, res, arg1); > +} > +static void gen_LMI (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, > + int rs, int rt, int rd) > +{ > + const char *opn = "LMI"; > + TCGv t0, t1; > + int nomul = env->CvmCtlRegister.cvmctl & 0x8000000; > + if (!nomul) { > + switch (opc) { > + case OPC_MTM0: > + tcg_gen_mov_tl(mpl0, cpu_gpr[rs]); > + tcg_gen_movi_tl(p0, 0); > + tcg_gen_movi_tl(p1, 0); > + tcg_gen_movi_tl(p2, 0); > + opn = "mtm0"; > + break; > + case OPC_MTM1: > + tcg_gen_mov_tl(mpl1, cpu_gpr[rs]); > + tcg_gen_movi_tl(p0, 0); > + tcg_gen_movi_tl(p1, 0); > + tcg_gen_movi_tl(p2, 0); > + opn = "mtm1"; > + break; > + case OPC_MTM2: > + tcg_gen_mov_tl(mpl2, cpu_gpr[rs]); > + tcg_gen_movi_tl(p0, 0); > + tcg_gen_movi_tl(p1, 0); > + tcg_gen_movi_tl(p2, 0); > + opn = "mtm2"; > + break; > + case OPC_MTP0: > + tcg_gen_mov_tl(p0, cpu_gpr[rs]); > + opn = "mtp0"; > + break; > + case OPC_MTP1: > + tcg_gen_mov_tl(p1, cpu_gpr[rs]); > + opn = "mtp1"; > + break; > + case OPC_MTP2: > + tcg_gen_mov_tl(p2, cpu_gpr[rs]); > + opn = "mtp2"; > + break; > + case OPC_VMM0: > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + gen_load_gpr(t1, rs); > + gen_helper_dmultu(t1, mpl0); > + gen_load_gpr(t0, rt); > + tcg_gen_add_tl(t0, t0, cpu_LO[0]); > + tcg_gen_add_tl(t0, t0, p0); > + gen_store_gpr(t0, rd); > + tcg_gen_mov_tl(mpl0, cpu_gpr[rd]); > + tcg_gen_movi_tl(p0, 0); > + tcg_gen_movi_tl(p1, 0); > + tcg_gen_movi_tl(p2, 0); > + tcg_temp_free(t0); > + tcg_temp_free(t1); > + opn = "vmm0"; > + break; > + case OPC_VMULU: > + { > + TCGv t2, c; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + t2 = tcg_temp_new(); > + c = tcg_temp_new(); > + gen_load_gpr(t1, rs); > + gen_load_gpr(t2, rt); > + gen_helper_dmultu(t1, mpl0); > + tcg_gen_mov_tl(t0, cpu_LO[0]); > + /*if carry comes due to addition of rt and LO register, > + * this carry should be added to HI register. > + */ > + gen_addc(t0, t2, t1, c); > > + tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c); > + /* t0 = t1 + p0 where t1 = LO+rt*/ > + gen_addc(t1, p0, t0, c); > + tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c); > + > + tcg_gen_mov_tl(cpu_gpr[rd], t0); > + tcg_gen_mov_tl(p0, cpu_HI[0]); > + tcg_temp_free(t0); > + tcg_temp_free(t1); > + tcg_temp_free(t2); > + opn = "vmulu"; > + break; > + } > + case OPC_V3MULU: > + { > + TCGv temp[4]; > + TCGv c; > + TCGv trs, trt, tc1, tc2, tc3; > + temp[0] = tcg_temp_new(); > + temp[1] = tcg_temp_new(); > + temp[2] = tcg_temp_new(); > + temp[3] = tcg_temp_new(); > + trs = tcg_temp_new(); > + trt = tcg_temp_new(); > + tc1 = tcg_temp_new(); > + tc2 = tcg_temp_new(); > + tc3 = tcg_temp_new(); > + c = tcg_temp_new(); > + gen_load_gpr(trs, rs); > + gen_load_gpr(trt, rt); > + /* rs × (MPL2 || MPL1 || MPL0) (192X64 bit multiplication) > */ > + gen_helper_dmultu(trs, mpl0); > + tcg_gen_mov_tl(temp[0], cpu_LO[0]); > + tcg_gen_mov_tl(temp[1], cpu_HI[0]); > + > + gen_helper_dmultu(trs, mpl1); > + tcg_gen_mov_tl(temp[2], cpu_HI[0]); > + gen_addc(cpu_LO[0], temp[1], tc1, tc2); > + gen_addc(temp[2], tc2, tc3, c); > + tcg_gen_mov_tl(temp[1], tc1); > + tcg_gen_mov_tl(temp[2], tc3); > + tcg_gen_mov_tl(temp[3], c); > + > + gen_helper_dmultu(trs, mpl2); > + tcg_gen_add_tl(temp[3], temp[3], cpu_HI[0]); > + gen_addc(cpu_LO[0], temp[2], tc1, tc2); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], tc2); > + /* Addition of rt in 256 bit result > + (t3 t2 t1 t0 contain result) */ > + gen_addc(temp[0], trt, tc1, c); > + tcg_gen_mov_tl(temp[0], tc1); > + gen_addc(temp[1], c, tc1, tc2); > + tcg_gen_mov_tl(temp[1], tc1); > + gen_addc(temp[2], tc2, tc1, c); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], c); > + /* Addition of p2 p1 p0 in 256 bit result */ > + gen_addc(temp[0], p0, tc1, c); > + tcg_gen_mov_tl(temp[0], tc1); > + gen_addc(temp[1], c, tc1, tc2); > + tcg_gen_mov_tl(temp[1], tc1); > + gen_addc(temp[2], tc2, tc1, c); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], c); > + > + gen_addc(temp[1], p1, tc1, c); > + tcg_gen_mov_tl(temp[1], tc1); > + gen_addc(temp[2], c, tc1, tc2); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], tc2); > + > + gen_addc(temp[2], p2, tc1, c); > + tcg_gen_mov_tl(temp[2], tc1); > + tcg_gen_add_tl(temp[3], temp[3], c); > + /* final step */ > + tcg_gen_mov_tl(cpu_gpr[rd], temp[0]); > + tcg_gen_mov_tl(p0, temp[1]); > + tcg_gen_mov_tl(p1, temp[2]); > + tcg_gen_mov_tl(p2, temp[3]); > + tcg_temp_free(temp[0]); > + tcg_temp_free(temp[1]); > + tcg_temp_free(temp[2]); > + tcg_temp_free(temp[3]); > + tcg_temp_free(trs); > + tcg_temp_free(trt); > + tcg_temp_free(tc1); > + tcg_temp_free(tc2); > + tcg_temp_free(tc3); > + tcg_temp_free(c); > + opn = "v3mulu"; > + break; > + } > + } > + > + } else { > + generate_exception(ctx, EXCP_RI); > + } > +} > + > + > +#endif > /* Arithmetic */ > static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, > int rd, int rs, int rt) > { > const char *opn = "arith"; > > + target_ulong mask = 0xFF; > if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB > && opc != OPC_DADD && opc != OPC_DSUB) { > /* If no destination, treat it as a NOP. > @@ -1637,6 +1887,22 @@ static void gen_arith (CPUState *env, DisasContext > *ctx, uint32_t opc, > } > opn = "addu"; > break; > + case OPC_BADDU: > + { > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + TCGv t2 = tcg_temp_new(); > + gen_load_gpr(t1, rs); > + gen_load_gpr(t2, rt); > + tcg_gen_andi_tl(t1, t1, mask); > + tcg_gen_andi_tl(t2, t2, mask); > + tcg_gen_add_tl(t0, t1, t2); > + tcg_gen_andi_tl(t0, t0, mask); > + gen_store_gpr(t0, rd); > + } > + > + opn = "baddu"; > + break; > case OPC_SUB: > { > TCGv t0 = tcg_temp_local_new(); > @@ -2013,7 +2279,74 @@ static void gen_HILO (DisasContext *ctx, uint32_t > opc, int reg) > (void)opn; /* avoid a compiler warning */ > MIPS_DEBUG("%s %s", opn, regnames[reg]); > } > +#if defined(TARGET_MIPS64) > +static void gen_seqsne (DisasContext *ctx, uint32_t opc, > + int rd, int rs, int rt) > +{ > + const char *opn = "seq/sne"; > + TCGv t0, t1; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + switch (opc) { > + case OPC_SEQ: > + { > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > + gen_load_gpr(t0, rd); > + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1); > + } > + opn = "seq"; > + break; > + case OPC_SNE: > + { > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > + gen_load_gpr(t0, rd); > + gen_load_gpr(t1, 0); > + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0); > + } > + opn = "sne"; > + break; > + default: > + MIPS_INVAL(opn); > + generate_exception(ctx, EXCP_RI); > + goto out; > + } > +out: > + tcg_temp_free(t0); > + tcg_temp_free(t1); > > +} > + > +static void gen_saa (CPUState *env, DisasContext *ctx, uint32_t opc, > + int rt, int base) > +{ > + const char *opn = "saa"; > + TCGv t0, t1, temp; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + temp = tcg_temp_new(); > + gen_load_gpr(t1, rt); > + gen_base_offset_addr(ctx, t0, base, 0); > + switch (opc) { > + case OPC_SAA: > + save_cpu_state(ctx, 1); > + op_ld_lw(temp, t0, ctx); > + tcg_gen_add_tl(temp, temp, t1); > + op_st_sw(temp, t0, ctx); > + opn = "saa"; > + break; > + case OPC_SAAD: > + save_cpu_state(ctx, 0); > + op_ld_ld(temp, t0, ctx); > + tcg_gen_add_tl(temp, temp, t1); > + op_st_sd(temp, t0, ctx); > + opn = "saad"; > + break; > + } > + > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > +#endif > static void gen_muldiv (DisasContext *ctx, uint32_t opc, > int rs, int rt) > { > @@ -2149,6 +2482,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t > opc, > gen_helper_dmult(t0, t1); > opn = "dmult"; > break; > + case OPC_DMUL: > + gen_helper_dmult(t0, t1); > + opn = "dmul"; > + break; > case OPC_DMULTU: > gen_helper_dmultu(t0, t1); > opn = "dmultu"; > @@ -2368,7 +2705,49 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, > MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); > tcg_temp_free(t0); > } > +#if defined(TARGET_MIPS64) > +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t opc, > + int rd, int rs, int rt) > +{ > + TCGv num = tcg_temp_new(); > + TCGv res = tcg_temp_new(); > + target_ulong maskb = 1; > + gen_load_gpr(num, rs); > + TCGv ones=tcg_temp_new(); > + gen_load_gpr(ones, 0); > + int x=1; > + tcg_gen_andi_tl(res, num, maskb); > + tcg_gen_add_tl(ones,ones, res); > + while (x <= 31) { > + tcg_gen_shri_i64(num, num, 1); > + tcg_gen_andi_tl(res, num, maskb); > + tcg_gen_add_tl(ones, ones, res); > + x++; > + } > + gen_store_gpr(ones, rd); > +} > +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t opc, > + int rd, int rs, int rt) > +{ > + TCGv num, res, ones; > + num = tcg_temp_new(); > + res = tcg_temp_new(); > + ones = tcg_temp_new(); > + target_ulong maskb = 1; > + gen_load_gpr(num, rs); > + int x = 1; > + tcg_gen_andi_tl(res, num, maskb); > + tcg_gen_mov_tl(ones, res); > > + while (x <= 63) { > + tcg_gen_shri_i64(num, num, 1); > + tcg_gen_andi_tl(res, num, maskb); > + tcg_gen_add_tl(ones, ones, res); > + x++; > + } > + gen_store_gpr(ones, rd); > +} > +#endif > /* Godson integer instructions */ > static void gen_loongson_integer (DisasContext *ctx, uint32_t opc, > int rd, int rs, int rt) > @@ -2705,6 +3084,7 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > target_ulong btgt = -1; > int blink = 0; > int bcond_compute = 0; > + target_ulong maskb; /* Used in BBIT0 and BBIT1*/ > TCGv t0 = tcg_temp_new(); > TCGv t1 = tcg_temp_new(); > > @@ -2730,6 +3110,39 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > } > btgt = ctx->pc + insn_bytes + offset; > break; > + case OPC_BBIT1: > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, 0); > + maskb = 1ULL << rt; > + tcg_gen_andi_tl(t0, t0, maskb); > + bcond_compute = 1; > + btgt = ctx->pc + insn_bytes + offset; > + break; > + case OPC_BBIT132: > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, 0); > + maskb = 1ULL << (rt + 32); > + tcg_gen_andi_tl(t0, t0, maskb); > + bcond_compute = 1; > + btgt = ctx->pc + insn_bytes + offset; > + break; > + case OPC_BBIT0: > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, 0); > + maskb = 1ULL << rt; > + tcg_gen_andi_tl(t0, t0, maskb); > + bcond_compute = 1; > + btgt = ctx->pc + insn_bytes + offset; > + break; > + case OPC_BBIT032: > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, 0); > + maskb = 1ULL << (rt + 32); > + tcg_gen_andi_tl(t0, t0, maskb); > + bcond_compute = 1; > + btgt = ctx->pc + insn_bytes + offset; > + break; > + > case OPC_BGEZ: > case OPC_BGEZAL: > case OPC_BGEZALS: > @@ -2888,6 +3301,18 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx, > regnames[rs], regnames[rt], btgt); > goto not_likely; > + case OPC_BBIT1: > + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > + goto not_likely; > + case OPC_BBIT132: > + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > + goto not_likely; > + case OPC_BBIT0: > + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); > + goto not_likely; > + case OPC_BBIT032: > + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); > + goto not_likely; > case OPC_BNEL: > tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx, > @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > tcg_temp_free(t0); > tcg_temp_free(t1); > } > +/*For cavium specific extract instructions*/ > +#if defined(TARGET_MIPS64) > +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int > rt, > + int rs, int lsb, int msb) > +{ > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + target_ulong mask; > + gen_load_gpr(t1, rs); > + switch (opc) { > + case OPC_EXTS: > + tcg_gen_shri_tl(t0, t1, lsb); > + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); > + /* To sign extened the remaining bits according to > + the msb of the bit field */ > + mask = 1ULL << msb; > + tcg_gen_andi_tl(t1, t0, mask); > + tcg_gen_addi_tl(t1, t1, -1); > + tcg_gen_not_i64(t1, t1); > + tcg_gen_or_tl(t0, t0, t1); > + gen_store_gpr(t0, rt); > + break; > + case OPC_EXTS32: > + tcg_gen_shri_tl(t0, t1, lsb + 32); > + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); > + mask = 1ULL << msb; > + tcg_gen_andi_tl(t1, t0, mask); > + tcg_gen_addi_tl(t1, t1, -1); > + tcg_gen_not_i64(t1, t1); > + tcg_gen_or_tl(t0, t0, t1); > + gen_store_gpr(t0, rt); > + break; > > + } > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > +#endif > /* special3 bitfield operations */ > static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, > int rs, int lsb, int msb) > @@ -3063,6 +3525,22 @@ static void gen_bitops (DisasContext *ctx, uint32_t > opc, int rt, > tcg_gen_andi_tl(t1, t1, mask); > tcg_gen_or_tl(t0, t0, t1); > break; > + case OPC_CINS: > + mask = (1ULL << (msb+1))-1; > + gen_load_gpr(t0, rt); > + tcg_gen_andi_tl(t0, t0, 0); > + tcg_gen_andi_tl(t1, t1, mask); > + tcg_gen_shli_tl(t1, t1, lsb); > + tcg_gen_or_tl(t0, t0, t1); > + break; > + case OPC_CINS32: > + mask = (1ULL << (msb+1))-1; > + gen_load_gpr(t0, rt); > + tcg_gen_andi_tl(t0, t0, 0); > + tcg_gen_andi_tl(t1, t1, mask); > + tcg_gen_shli_tl(t1, t1, (lsb+32)); > + tcg_gen_or_tl(t0, t0, t1); > + break; > #endif > default: > fail: > @@ -11605,7 +12083,7 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > int32_t offset; > int rs, rt, rd, sa; > uint32_t op, op1, op2; > - int16_t imm; > + int16_t imm, imm10; > > /* make sure instructions are on a word boundary */ > if (ctx->pc & 0x3) { > @@ -11634,6 +12112,9 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > rd = (ctx->opcode >> 11) & 0x1f; > sa = (ctx->opcode >> 6) & 0x1f; > imm = (int16_t)ctx->opcode; > + /* 10 bit Immediate value For SEQI,SNEI */ > + imm10 = (ctx->opcode >> 6) & 0x3ff; > + > switch (op) { > case OPC_SPECIAL: > op1 = MASK_SPECIAL(ctx->opcode); > @@ -11859,6 +12340,71 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > case OPC_MUL: > gen_arith(env, ctx, op1, rd, rs, rt); > break; > +#if defined(TARGET_MIPS64) > + > + > + case OPC_DMUL: > + check_insn(env, ctx, ISA_MIPS3); > + check_mips_64(ctx); > + gen_muldiv(ctx, op1, rs, rt); > + tcg_gen_mov_tl(cpu_gpr[rd], cpu_LO[0]); > + break; > + case OPC_CINS: > + check_insn(env, ctx, ISA_MIPS64R2); > + check_mips_64(ctx); > + gen_bitops(ctx, op1, rt, rs, sa, rd); > + break; > + case OPC_CINS32: > + check_mips_64(ctx); > + gen_bitops(ctx, op1, rt, rs, sa, rd); > + break; > + case OPC_MTM0: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTM1: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTM2: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTP0: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTP1: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_MTP2: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_VMULU: > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + break; > + case OPC_BADDU: > + gen_arith(env, ctx, op1, rd, rs, rt); > + break; > + case OPC_EXTS: > + check_mips_64(ctx); > + gen_exts(env, ctx, op1, rt, rs, sa, rd); > + break; > + case OPC_EXTS32: > + check_mips_64(ctx); > + gen_exts(env, ctx, op1, rt, rs, sa, rd); > + break; > + case OPC_SAA: > + gen_saa(env, ctx, op1, rt, rs); > + break; > + case OPC_SAAD: > + check_mips_64(ctx); > + gen_saa(env, ctx, op1, rt, rs); > + break; > +#endif > case OPC_CLO: > case OPC_CLZ: > check_insn(env, ctx, ISA_MIPS32); > @@ -11878,13 +12424,24 @@ static void decode_opc (CPUState *env, > DisasContext *ctx, int *is_branch) > break; > case OPC_DIV_G_2F: > case OPC_DIVU_G_2F: > - case OPC_MULT_G_2F: > case OPC_MULTU_G_2F: > case OPC_MOD_G_2F: > case OPC_MODU_G_2F: > check_insn(env, ctx, INSN_LOONGSON2F); > gen_loongson_integer(ctx, op1, rd, rs, rt); > break; > + case OPC_MULT_G_2F: > + if (!TARGET_OCTEON) { > + check_insn(env, ctx, INSN_LOONGSON2F); > + gen_loongson_integer(ctx, op1, rd, rs, rt); > + } else { > +#if defined(TARGET_MIPS64) > + /* Cavium Specific vmm0 */ > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > +#endif > + } > + break; > #if defined(TARGET_MIPS64) > case OPC_DCLO: > case OPC_DCLZ: > @@ -11892,7 +12449,6 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > check_mips_64(ctx); > gen_cl(ctx, op1, rd, rs); > break; > - case OPC_DMULT_G_2F: > case OPC_DMULTU_G_2F: > case OPC_DDIV_G_2F: > case OPC_DDIVU_G_2F: > @@ -11901,6 +12457,39 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > check_insn(env, ctx, INSN_LOONGSON2F); > gen_loongson_integer(ctx, op1, rd, rs, rt); > break; > + case OPC_DMULT_G_2F: > + if (!TARGET_OCTEON) { > + check_insn(env, ctx, INSN_LOONGSON2F); > + gen_loongson_integer(ctx, op1, rd, rs, rt); > + } else { > + /* Cavium Specific instruction v3mulu */ > + check_mips_64(ctx); > + gen_LMI(env, ctx, op1, rs, rt, rd); > + } > + break; > + case OPC_SEQ: > + check_mips_64(ctx); > + gen_seqsne(ctx, op1, rd, rs, rt); > + break; > + case OPC_SNE: > + check_mips_64(ctx); > + gen_seqsne(ctx, op1, rd, rs, rt); > + break; > + case OPC_SEQI: > + check_mips_64(ctx); > + gen_set_imm(env, op1, rt, rs, imm10); > + break; > + case OPC_SNEI: > + check_mips_64(ctx); > + gen_set_imm(env, op1, rt, rs, imm10); > + break; > + case OPC_POP: > + insn_opc_pop(ctx, env, op1, rd, rs, rt); > + break; > + case OPC_DPOP: > + check_mips_64(ctx); > + insn_opc_dpop(ctx, env, op1, rd, rs, rt); > + break; > #endif > default: /* Invalid */ > MIPS_INVAL("special2"); > @@ -12192,10 +12781,32 @@ static void decode_opc (CPUState *env, > DisasContext *ctx, int *is_branch) > break; > > /* COP2. */ > - case OPC_LWC2: > - case OPC_LDC2: > - case OPC_SWC2: > - case OPC_SDC2: > + /* Conflicting opcodes with Cavium specific branch instructions > + if TARGET_OCTEON is set these opcodes will belong to Cavium */ > + case OPC_LWC2: /*BBIT0*/ > + if(TARGET_OCTEON) { > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > + *is_branch = 1; > + break; > + } > + case OPC_LDC2: /*BBIT032*/ > + if(TARGET_OCTEON) { > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > + *is_branch = 1; > + break; > + } > + case OPC_SWC2: /*BBIT1*/ > + if(TARGET_OCTEON) { > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > + *is_branch = 1; > + break; > + } > + case OPC_SDC2: /*BBIT132*/ > + if(TARGET_OCTEON) { > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > + *is_branch = 1; > + break; > + } > case OPC_CP2: > /* COP2: Not implemented. */ > generate_exception_err(ctx, EXCP_CpU, 2); > @@ -12584,6 +13195,18 @@ static void mips_tcg_init(void) > cpu_dspctrl = tcg_global_mem_new(TCG_AREG0, > offsetof(CPUState, > active_tc.DSPControl), > "DSPControl"); > + mpl0 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.MPL0), "MPL0"); > + mpl1 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.MPL1), "MPL1"); > + mpl2 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.MPL2), "MPL2"); > + p0 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.P0), "P0"); > + p1 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.P1), "P1"); > + p2 = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, Reg.P2), "P2"); > bcond = tcg_global_mem_new(TCG_AREG0, > offsetof(CPUState, bcond), "bcond"); > btarget = tcg_global_mem_new(TCG_AREG0, > @@ -12607,6 +13230,18 @@ static void mips_tcg_init(void) > > #include "translate_init.c" > > +#if defined(TARGET_MIPS64) > + > +static void set_cvmctl_register(CPUMIPSState *env) > +{ > + env->CvmCtlRegister.cvmctl = env->CvmCtlRegister.cvmctl > + ^ env->CvmCtlRegister.cvmctl; > + env->CvmCtlRegister.cvmctl = > FUSE_START_BIT(env->CvmCtlRegister.cvmctl); > + env->CvmCtlRegister.cvmctl = KASUMI(env->CvmCtlRegister.cvmctl); > + env->CvmCtlRegister.cvmctl = IPPCI(env->CvmCtlRegister.cvmctl); > + env->CvmCtlRegister.cvmctl = IPTI(env->CvmCtlRegister.cvmctl); > +} > +#endif > CPUMIPSState *cpu_mips_init (const char *cpu_model) > { > CPUMIPSState *env; > @@ -12619,6 +13254,10 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model) > env->cpu_model = def; > env->cpu_model_str = cpu_model; > > +#if defined(TARGET_MIPS64) > + /*Function for setting cvmctl register*/ > + set_cvmctl_register(env); > +#endif > cpu_exec_init(env); > #ifndef CONFIG_USER_ONLY > mmu_init(env, def); > -- > 1.7.3.4
On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote: > Subject: [PATCH] MIPS64 user mode emulation in QEMU > This patch adds support for Cavium Network's > Octeon 57XX user mode instructions. Octeon > 57xx is based on MIPS64. So this patch is > the first MIPS64 User Mode Emulation in QEMU > This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed) > work of HPCNL Lab at KICS-UET Lahore. Thanks for doing this. As already noted, this patch should be split into at least two patches: one to add Octeon-specific instructions in target-mips/ and one adding the necessary linux-user bits. > +extern int TARGET_OCTEON; I don't think a global like this is the right way to go. Perhaps the elfload.c code should set a flag in image_info , which can then be used to set a flag in CPUMIPSState later on. If we must use a global variable, it should be declared in target-mips/cpu.h. > @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env) > env->active_tc.gpr[5], > env->active_tc.gpr[6], > env->active_tc.gpr[7], > - arg5, arg6/*, arg7, arg8*/); > + env->active_tc.gpr[8], > + env->active_tc.gpr[9]/*, arg7, arg8*/); > } > if (ret == -TARGET_QEMU_ESIGRETURN) { > /* Returning from a successful sigreturn syscall. This change breaks O32 binaries; it needs to be done in a different way. > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 499c4d7..47fef05 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long > arg1, > case TARGET_NR_set_thread_area: > #if defined(TARGET_MIPS) > ((CPUMIPSState *) cpu_env)->tls_value = arg1; > + /*tls entry is moved to k0 so that this can be used later*/ > + ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1; > ret = 0; > break; > #elif defined(TARGET_CRIS) I believe this is only correct for Octeon binaries; it's not how the rest of the MIPS world works. It therefore needs to be conditional on Octeon-ness. > --- a/target-mips/cpu.h > +++ b/target-mips/cpu.h > @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t; > #define MIPS_FPU_MAX 1 > #define MIPS_DSP_ACC 4 > > +typedef struct cavium_mul cavium_mul; > +struct cavium_mul { > + target_ulong MPL0; > + target_ulong MPL1; > + target_ulong MPL2; > + target_ulong P0; > + target_ulong P1; > + target_ulong P2; > +}; > +typedef struct cvmctl_register cvmctl_register; > +struct cvmctl_register { > + target_ulong cvmctl; > +}; The indentation here needs to be fixed. I don't think there's any reason why these need to be defined outside TCState, either. > diff --git a/target-mips/translate.c b/target-mips/translate.c > index cce77be..9c3d772 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -36,6 +36,15 @@ > #define GEN_HELPER 1 > #include "helper.h" > > +int TARGET_OCTEON; > +#if defined(TARGET_MIPS64) > +/*Macros for setting values of cvmctl registers*/ > +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000) > +#define KASUMI(cvmctl)(cvmctl | 0x20000000) > +#define IPPCI(cvmctl)(cvmctl | 0x380) > +#define IPTI(cvmctl)(cvmctl | 0x70) > +#endif Please follow existing style; spaces between the comment and comment markers (many examples in translate.c, not just here) and spaces between the macro argument list and definition. > @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext *ctx, > TCGv ret, TCGv arg0, TCGv > See the MIPS64 PRA manual, section 4.10. */ > if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && > !(ctx->hflags & MIPS_HFLAG_UX)) { > - tcg_gen_ext32s_i64(ret, ret); > + /*This function sign extend 32 bit value to 64 bit, was causing > error > + when ld instruction came.Thats why it is commmented out*/ > + /* tcg_gen_ext32s_i64(ret, ret);*/ > } > #endif > } Um, no. If you needed to comment this out, you have a bug someplace else. Don't paper over the bug here. > + case OPC_VMULU: > + case OPC_V3MULU: These two are large enough that they should be done as out-of-line helpers. Also, since all these new instructions are Octeon-specific, there should be checks emitted to ensure that they produce appropriate errors when non-Octeon hardware is being simulated, similar in style to check_mips_64. > /* Arithmetic */ > static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, > int rd, int rs, int rt) > { > const char *opn = "arith"; > > + target_ulong mask = 0xFF; I don't think it's really necessary to have this, but if you feel it's necessary, please move the declaration closer to the point of use. > +#if defined(TARGET_MIPS64) > +static void gen_seqsne (DisasContext *ctx, uint32_t opc, > + int rd, int rs, int rt) > +{ > + const char *opn = "seq/sne"; > + TCGv t0, t1; > + t0 = tcg_temp_new(); > + t1 = tcg_temp_new(); > + switch (opc) { > + case OPC_SEQ: > + { > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > + gen_load_gpr(t0, rd); > + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1); > + } > + opn = "seq"; > + break; This looks like you are comparing rd with itself? > + case OPC_SNE: > + { > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > + gen_load_gpr(t0, rd); > + gen_load_gpr(t1, 0); > + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0); You could use setcondi here by reversing the condition. > +#if defined(TARGET_MIPS64) > +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t opc, > + int rd, int rs, int rt) > +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t opc, > + int rd, int rs, int rt) These should also be done as out-of-line helpers. > @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > tcg_temp_free(t0); > tcg_temp_free(t1); > } > +/*For cavium specific extract instructions*/ > +#if defined(TARGET_MIPS64) > +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int > rt, > + int rs, int lsb, int msb) > +{ > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + target_ulong mask; > + gen_load_gpr(t1, rs); > + switch (opc) { > + case OPC_EXTS: > + tcg_gen_shri_tl(t0, t1, lsb); > + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); > + /* To sign extened the remaining bits according to > + the msb of the bit field */ > + mask = 1ULL << msb; > + tcg_gen_andi_tl(t1, t0, mask); > + tcg_gen_addi_tl(t1, t1, -1); > + tcg_gen_not_i64(t1, t1); > + tcg_gen_or_tl(t0, t0, t1); You can use tcg_gen_orc_tl here and elsewhere. -Nathan
On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote: > From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001 > From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk> > Date: Sat, 26 Mar 2011 11:53:11 +0500 > Subject: [PATCH] MIPS64 user mode emulation in QEMU > This patch adds support for Cavium Network's > Octeon 57XX user mode instructions. Octeon > 57xx is based on MIPS64. So this patch is > the first MIPS64 User Mode Emulation in QEMU > This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed) > work of HPCNL Lab at KICS-UET Lahore. > > > Signed-off-by: Khansa Butt <khansa@kics.edu.pk> > --- > configure | 1 + > default-configs/mips64-linux-user.mak | 1 + > exec.c | 1 + > linux-user/elfload.c | 15 +- > linux-user/main.c | 20 +- > linux-user/mips64/syscall.h | 2 + > linux-user/signal.c | 3 +- > linux-user/syscall.c | 2 + > target-mips/cpu.h | 16 + > target-mips/translate.c | 659 > ++++++++++++++++++++++++++++++++- > 10 files changed, 704 insertions(+), 16 deletions(-) > create mode 100644 default-configs/mips64-linux-user.mak Your patch actually contains 2 things - Support for Cavium Octeon instructions - Support for MIPS64 userland The 2 things are independent and should be submitted as two different patches. Also the support for Octeon instruction should not depend on a global variable, but should use the CPU features system already available. Please have a look at target-mips/translate_init.c to see how it works.
Please see inline comments highlighted in red. I will be sending 2 updated patches for mips64 user mode emulation. On Tue, Mar 29, 2011 at 1:55 PM, Riku Voipio <riku.voipio@iki.fi> wrote: > Hi, > > First, do you have some instructions on howto build Octeon usermode > 64bit binaries. Second, I think we would prefer that the patch was split > to smaller patches. At least the target-mips changes should be a separate > patch. > > Some more comments included inline between the code. > > On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote: > > >From cd88be1263d0fc9802cd4dd358ed0299c0d106b0 Mon Sep 17 00:00:00 2001 > > From: Khansa Butt & Ehsan-ul-Haq <khansa@kics.edu.pk> > > Date: Sat, 26 Mar 2011 11:53:11 +0500 > > Subject: [PATCH] MIPS64 user mode emulation in QEMU > > This patch adds support for Cavium Network's > > Octeon 57XX user mode instructions. Octeon > > 57xx is based on MIPS64. So this patch is > > the first MIPS64 User Mode Emulation in QEMU > > This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed) > > work of HPCNL Lab at KICS-UET Lahore. > > > > > > Signed-off-by: Khansa Butt <khansa@kics.edu.pk> > > --- > > configure | 1 + > > default-configs/mips64-linux-user.mak | 1 + > > exec.c | 1 + > > linux-user/elfload.c | 15 +- > > linux-user/main.c | 20 +- > > linux-user/mips64/syscall.h | 2 + > > linux-user/signal.c | 3 +- > > linux-user/syscall.c | 2 + > > target-mips/cpu.h | 16 + > > target-mips/translate.c | 659 > > ++++++++++++++++++++++++++++++++- > > 10 files changed, 704 insertions(+), 16 deletions(-) > > create mode 100644 default-configs/mips64-linux-user.mak > > > > diff --git a/configure b/configure > > index 438219b..045a4ef 100755 > > --- a/configure > > +++ b/configure > > @@ -1011,6 +1011,7 @@ cris-linux-user \ > > m68k-linux-user \ > > microblaze-linux-user \ > > mips-linux-user \ > > +mips64-linux-user \ > > mipsel-linux-user \ > > ppc-linux-user \ > > ppc64-linux-user \ > > diff --git a/default-configs/mips64-linux-user.mak > > b/default-configs/mips64-linux-user.mak > > new file mode 100644 > > index 0000000..1598bfc > > --- /dev/null > > +++ b/default-configs/mips64-linux-user.mak > > @@ -0,0 +1 @@ > > +# Default configuration for mips64-linux-user > > diff --git a/exec.c b/exec.c > > index 49c28b1..ee3f78e 100644 > > --- a/exec.c > > +++ b/exec.c > > @@ -2441,6 +2441,7 @@ int page_check_range(target_ulong start, > target_ulong > > len, int flags) > > for (addr = start, len = end - start; > > len != 0; > > len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { > > + addr &= qemu_host_page_mask; > > p = page_find(addr >> TARGET_PAGE_BITS); > > Are you sure this will not generate ill effect on other target/host > architecture > combinations? > > The line has been removed in order to avoid ill effects > > if( !p ) > > return -1; > > diff --git a/linux-user/elfload.c b/linux-user/elfload.c > > index 33d776d..60fe85e 100644 > > --- a/linux-user/elfload.c > > +++ b/linux-user/elfload.c > > @@ -16,6 +16,8 @@ > > #include "qemu.h" > > #include "disas.h" > > > > +extern int TARGET_OCTEON; > > + > > #ifdef _ARCH_PPC64 > > #undef ARCH_DLINFO > > #undef ELF_PLATFORM > > @@ -25,6 +27,9 @@ > > #undef ELF_ARCH > > #endif > > > > +#define EF_MIPS_MARCH 16711680 > > +#define E_MIPS_MACH_OCTEON 9109504 > > + > > please use hexadecimal values. > > > #define ELF_OSABI ELFOSABI_SYSV > > > > /* from personality.h */ > > @@ -1313,7 +1318,7 @@ static void load_elf_image(const char *image_name, > int > > image_fd, > > vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr); > > vaddr_ps = TARGET_ELF_PAGESTART(vaddr); > > > > - error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po, > > + error = target_mmap(vaddr_ps, eppnt->p_memsz + vaddr_po, > > elf_prot, MAP_PRIVATE | MAP_FIXED, > > image_fd, eppnt->p_offset - vaddr_po); > > if (error == -1) { > > @@ -1588,7 +1593,13 @@ int load_elf_binary(struct linux_binprm * bprm, > > struct target_pt_regs * regs, > > If we do nothing, we'll have overwritten this when we re-use > > bprm->buf > > when we load the interpreter. */ > > elf_ex = *(struct elfhdr *)bprm->buf; > > - > > +#if defined(TARGET_MIPS64) > > + if ((elf_ex.e_flags & EF_MIPS_MARCH) == E_MIPS_MACH_OCTEON) { > > + TARGET_OCTEON = 1; > > + } else { > > + TARGET_OCTEON = 0; > > + } > > +#endif > > bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); > > bprm->p = > copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); > > bprm->p = > copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); > > diff --git a/linux-user/main.c b/linux-user/main.c > > index 0d627d6..8b4b90b 100644 > > --- a/linux-user/main.c > > +++ b/linux-user/main.c > > @@ -1937,10 +1937,16 @@ static int do_store_exclusive(CPUMIPSState *env) > > int d; > > > > addr = env->lladdr; > > + /* 64 bit address is converted to 32 bit value so that a valid > > + * l1_map value can be accessed. This thing is needed for target > > + * mips64 and host 32 bit x86 > > + */ > > + addr &= qemu_host_page_mask; > > same as earlier. > The above line is changed with following code snippet #if defined(TARGET_MIPS64) +/* For MIPS64 on 32 bit host there is a need to make +* the page accessible to which the above 'addr' is belonged */ +#if HOST_LONG_BITS == 32 + int flag = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_WRITE_ORG; + page_set_flags(addr, addr + 4096, flag); +#endif +#endif > > > page_addr = addr & TARGET_PAGE_MASK; > > start_exclusive(); > > mmap_lock(); > > flags = page_get_flags(page_addr); > > + addr = env->lladdr; > > if ((flags & PAGE_READ) == 0) { > > segv = 1; > > } else { > > @@ -1978,7 +1984,8 @@ static int do_store_exclusive(CPUMIPSState *env) > > void cpu_loop(CPUMIPSState *env) > > { > > target_siginfo_t info; > > - int trapnr, ret; > > + int trapnr; > > + abi_long ret; > > unsigned int syscall_num; > > > > for(;;) { > > @@ -1987,7 +1994,11 @@ void cpu_loop(CPUMIPSState *env) > > cpu_exec_end(env); > > switch(trapnr) { > > case EXCP_SYSCALL: > > +#if defined(TARGET_MIPS64) > > + syscall_num = env->active_tc.gpr[2] - 5000; > > +#else > > syscall_num = env->active_tc.gpr[2] - 4000; > > +#endif > > env->active_tc.PC += 4; > > if (syscall_num >= sizeof(mips_syscall_args)) { > > ret = -ENOSYS; > > @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env) > > env->active_tc.gpr[5], > > env->active_tc.gpr[6], > > env->active_tc.gpr[7], > > - arg5, arg6/*, arg7, arg8*/); > > + env->active_tc.gpr[8], > > + env->active_tc.gpr[9]/*, arg7, arg8*/); > > } > > if (ret == -TARGET_QEMU_ESIGRETURN) { > > /* Returning from a successful sigreturn syscall. > > @@ -2926,7 +2938,9 @@ int main(int argc, char **argv, char **envp) > > #endif > > #elif defined(TARGET_MIPS) > > #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) > > - cpu_model = "20Kc"; > > + /* we use this model so that we can decode MIPS64r2 > > + reserved instruction */ > > + cpu_model = "MIPS64R2-generic"; > > #else > > cpu_model = "24Kf"; > > #endif > > diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h > > index 668a2b9..1395e61 100644 > > --- a/linux-user/mips64/syscall.h > > +++ b/linux-user/mips64/syscall.h > > @@ -217,5 +217,7 @@ struct target_pt_regs { > > #define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ > > > > > > +/* Nasty hack: define a fake errno value for use by sigreturn. */ > > +#define TARGET_QEMU_ESIGRETURN 255 > > > > #define UNAME_MACHINE "mips64" > > diff --git a/linux-user/signal.c b/linux-user/signal.c > > index c846b8c..114116c 100644 > > --- a/linux-user/signal.c > > +++ b/linux-user/signal.c > > @@ -2410,7 +2410,8 @@ void sparc64_get_context(CPUSPARCState *env) > > #endif > > #elif defined(TARGET_ABI_MIPSN64) > > > > -# warning signal handling not implemented > > +/*this line is commented out to avoid compile time error*/ > > +/*# warning signal handling not implemented*/ > > > > static void setup_frame(int sig, struct target_sigaction *ka, > > target_sigset_t *set, CPUState *env) > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > > index 499c4d7..47fef05 100644 > > --- a/linux-user/syscall.c > > +++ b/linux-user/syscall.c > > @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, > abi_long > > arg1, > > case TARGET_NR_set_thread_area: > > #if defined(TARGET_MIPS) > > ((CPUMIPSState *) cpu_env)->tls_value = arg1; > > + /*tls entry is moved to k0 so that this can be used later*/ > > + ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1; > > Does this affect the non-octeon mips ? > The above thing has been made Octeon specific. > > > ret = 0; > > break; > > #elif defined(TARGET_CRIS) > > And someone else will need to comment the TCG changes. > > > diff --git a/target-mips/cpu.h b/target-mips/cpu.h > > index 2419aa9..59bcc0f 100644 > > --- a/target-mips/cpu.h > > +++ b/target-mips/cpu.h > > @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t; > > #define MIPS_FPU_MAX 1 > > #define MIPS_DSP_ACC 4 > > > > +typedef struct cavium_mul cavium_mul; > > +struct cavium_mul { > > + target_ulong MPL0; > > + target_ulong MPL1; > > + target_ulong MPL2; > > + target_ulong P0; > > + target_ulong P1; > > + target_ulong P2; > > +}; > > +typedef struct cvmctl_register cvmctl_register; > > +struct cvmctl_register { > > + target_ulong cvmctl; > > +}; > > + > > typedef struct TCState TCState; > > struct TCState { > > target_ulong gpr[32]; > > @@ -178,6 +192,8 @@ struct CPUMIPSState { > > TCState active_tc; > > CPUMIPSFPUContext active_fpu; > > > > + cavium_mul Reg; > > + cvmctl_register CvmCtlRegister; > > uint32_t current_tc; > > uint32_t current_fpu; > > > > diff --git a/target-mips/translate.c b/target-mips/translate.c > > index cce77be..9c3d772 100644 > > --- a/target-mips/translate.c > > +++ b/target-mips/translate.c > > @@ -36,6 +36,15 @@ > > #define GEN_HELPER 1 > > #include "helper.h" > > > > +int TARGET_OCTEON; > > +#if defined(TARGET_MIPS64) > > +/*Macros for setting values of cvmctl registers*/ > > +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000) > > +#define KASUMI(cvmctl)(cvmctl | 0x20000000) > > +#define IPPCI(cvmctl)(cvmctl | 0x380) > > +#define IPTI(cvmctl)(cvmctl | 0x70) > > +#endif > > + > > //#define MIPS_DEBUG_DISAS > > //#define MIPS_DEBUG_SIGN_EXTENSIONS > > > > @@ -70,6 +79,11 @@ enum { > > OPC_JAL = (0x03 << 26), > > OPC_JALS = OPC_JAL | 0x5, > > OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ > > + /* Cavium Specific */ > > + OPC_BBIT1 = (0x3a << 26), /*jump on bit set, cavium specific*/ > > + OPC_BBIT132 = (0x3e << 26), /*jump on bit set(one of the upper 32 > > bits)*/ > > + OPC_BBIT0 = (0x32 << 26), /*jump on bit clear, cavium specific*/ > > + OPC_BBIT032 = (0x36 << 26), /*jump on bit set(one of the upper 32 > > bits)*/ > > OPC_BEQL = (0x14 << 26), > > OPC_BNE = (0x05 << 26), > > OPC_BNEL = (0x15 << 26), > > @@ -265,6 +279,31 @@ enum { > > OPC_MADD = 0x00 | OPC_SPECIAL2, > > OPC_MADDU = 0x01 | OPC_SPECIAL2, > > OPC_MUL = 0x02 | OPC_SPECIAL2, > > + /* Cavium Specific Instructions */ > > + OPC_BADDU = 0x28 | OPC_SPECIAL2, > > + OPC_DMUL = 0x03 | OPC_SPECIAL2, > > + OPC_EXTS = 0x3a | OPC_SPECIAL2, > > + OPC_EXTS32 = 0x3b | OPC_SPECIAL2, > > + OPC_CINS = 0x32 | OPC_SPECIAL2, > > + OPC_CINS32 = 0x33 | OPC_SPECIAL2, > > + OPC_SEQI = 0x2e | OPC_SPECIAL2, > > + OPC_SNEI = 0x2f | OPC_SPECIAL2, > > + OPC_MTM0 = 0x08 | OPC_SPECIAL2, > > + OPC_MTM1 = 0x0c | OPC_SPECIAL2, > > + OPC_MTM2 = 0x0d | OPC_SPECIAL2, > > + OPC_MTP0 = 0x09 | OPC_SPECIAL2, > > + OPC_MTP1 = 0x0a | OPC_SPECIAL2, > > + OPC_MTP2 = 0x0b | OPC_SPECIAL2, > > + OPC_V3MULU = 0x11 | OPC_SPECIAL2, > > + OPC_VMM0 = 0x10 | OPC_SPECIAL2, > > + OPC_VMULU = 0x0f | OPC_SPECIAL2, > > + OPC_POP = 0X2C | OPC_SPECIAL2, > > + OPC_DPOP = 0X2D | OPC_SPECIAL2, > > + OPC_SEQ = 0x2a | OPC_SPECIAL2, > > + OPC_SNE = 0x2b | OPC_SPECIAL2, > > + OPC_SAA = 0x18 | OPC_SPECIAL2, > > + OPC_SAAD = 0x19 | OPC_SPECIAL2, > > +/**************************************/ > > OPC_MSUB = 0x04 | OPC_SPECIAL2, > > OPC_MSUBU = 0x05 | OPC_SPECIAL2, > > /* Loongson 2F */ > > @@ -483,7 +522,7 @@ enum { > > static TCGv_ptr cpu_env; > > static TCGv cpu_gpr[32], cpu_PC; > > static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], > > cpu_ACX[MIPS_DSP_ACC]; > > -static TCGv cpu_dspctrl, btarget, bcond; > > +static TCGv cpu_dspctrl, btarget, bcond, mpl0, mpl1, mpl2, p0, p1, p2; > > static TCGv_i32 hflags; > > static TCGv_i32 fpu_fcr0, fpu_fcr31; > > > > @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext > *ctx, > > TCGv ret, TCGv arg0, TCGv > > See the MIPS64 PRA manual, section 4.10. */ > > if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && > > !(ctx->hflags & MIPS_HFLAG_UX)) { > > - tcg_gen_ext32s_i64(ret, ret); > > + /*This function sign extend 32 bit value to 64 bit, was causing > > error > > + when ld instruction came.Thats why it is commmented out*/ > > + /* tcg_gen_ext32s_i64(ret, ret);*/ > > } > > #endif > > } > > @@ -1419,7 +1460,33 @@ static void gen_arith_imm (CPUState *env, > > DisasContext *ctx, uint32_t opc, > > (void)opn; /* avoid a compiler warning */ > > MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], > > regnames[rs], uimm); > > } > > - > > +#if defined(TARGET_MIPS64) > > +/*set on equal immidiate/seton not equal immidiate*/ > > +static void gen_set_imm(CPUState *env, uint32_t opc, int rt, int rs, > > int16_t imm) > > +{ > > + target_ulong uimm; > > + TCGv t0, t1; > > + const char *opn = "imm set"; > > + uimm = (uint16_t)imm; > > + t0 = tcg_temp_new(); > > + t1 = tcg_temp_new(); > > + switch (opc) { > > + case OPC_SEQI: > > + tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); > > + gen_load_gpr(t0, rt); > > + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, 1); > > + opn = "seqi"; > > + break; > > + case OPC_SNEI: > > + tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); > > + gen_load_gpr(t0, rt); > > + gen_load_gpr(t1, 0); > > + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rt], t1, t0); > > + opn = "snei"; > > + break; > > + } > > +} > > +#endif > > /* Logic with immediate operand */ > > static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, > > int16_t imm) > > { > > @@ -1583,13 +1650,196 @@ static void gen_shift_imm(CPUState *env, > > DisasContext *ctx, uint32_t opc, > > MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], > > regnames[rs], uimm); > > tcg_temp_free(t0); > > } > > +#if defined(TARGET_MIPS64) > > +/* Addition and carry detection*/ > > +static void gen_addc (TCGv arg1, TCGv arg2, TCGv res, TCGv c) > > +{ > > + tcg_gen_add_tl(res, arg1, arg2); > > + tcg_gen_setcond_tl(TCG_COND_LTU, c, res, arg1); > > +} > > +static void gen_LMI (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, > > + int rs, int rt, int rd) > > +{ > > + const char *opn = "LMI"; > > + TCGv t0, t1; > > + int nomul = env->CvmCtlRegister.cvmctl & 0x8000000; > > + if (!nomul) { > > + switch (opc) { > > + case OPC_MTM0: > > + tcg_gen_mov_tl(mpl0, cpu_gpr[rs]); > > + tcg_gen_movi_tl(p0, 0); > > + tcg_gen_movi_tl(p1, 0); > > + tcg_gen_movi_tl(p2, 0); > > + opn = "mtm0"; > > + break; > > + case OPC_MTM1: > > + tcg_gen_mov_tl(mpl1, cpu_gpr[rs]); > > + tcg_gen_movi_tl(p0, 0); > > + tcg_gen_movi_tl(p1, 0); > > + tcg_gen_movi_tl(p2, 0); > > + opn = "mtm1"; > > + break; > > + case OPC_MTM2: > > + tcg_gen_mov_tl(mpl2, cpu_gpr[rs]); > > + tcg_gen_movi_tl(p0, 0); > > + tcg_gen_movi_tl(p1, 0); > > + tcg_gen_movi_tl(p2, 0); > > + opn = "mtm2"; > > + break; > > + case OPC_MTP0: > > + tcg_gen_mov_tl(p0, cpu_gpr[rs]); > > + opn = "mtp0"; > > + break; > > + case OPC_MTP1: > > + tcg_gen_mov_tl(p1, cpu_gpr[rs]); > > + opn = "mtp1"; > > + break; > > + case OPC_MTP2: > > + tcg_gen_mov_tl(p2, cpu_gpr[rs]); > > + opn = "mtp2"; > > + break; > > + case OPC_VMM0: > > + t0 = tcg_temp_new(); > > + t1 = tcg_temp_new(); > > + gen_load_gpr(t1, rs); > > + gen_helper_dmultu(t1, mpl0); > > + gen_load_gpr(t0, rt); > > + tcg_gen_add_tl(t0, t0, cpu_LO[0]); > > + tcg_gen_add_tl(t0, t0, p0); > > + gen_store_gpr(t0, rd); > > + tcg_gen_mov_tl(mpl0, cpu_gpr[rd]); > > + tcg_gen_movi_tl(p0, 0); > > + tcg_gen_movi_tl(p1, 0); > > + tcg_gen_movi_tl(p2, 0); > > + tcg_temp_free(t0); > > + tcg_temp_free(t1); > > + opn = "vmm0"; > > + break; > > + case OPC_VMULU: > > + { > > + TCGv t2, c; > > + t0 = tcg_temp_new(); > > + t1 = tcg_temp_new(); > > + t2 = tcg_temp_new(); > > + c = tcg_temp_new(); > > + gen_load_gpr(t1, rs); > > + gen_load_gpr(t2, rt); > > + gen_helper_dmultu(t1, mpl0); > > + tcg_gen_mov_tl(t0, cpu_LO[0]); > > + /*if carry comes due to addition of rt and LO register, > > + * this carry should be added to HI register. > > + */ > > + gen_addc(t0, t2, t1, c); > > > > + tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c); > > + /* t0 = t1 + p0 where t1 = LO+rt*/ > > + gen_addc(t1, p0, t0, c); > > + tcg_gen_add_tl(cpu_HI[0], cpu_HI[0], c); > > + > > + tcg_gen_mov_tl(cpu_gpr[rd], t0); > > + tcg_gen_mov_tl(p0, cpu_HI[0]); > > + tcg_temp_free(t0); > > + tcg_temp_free(t1); > > + tcg_temp_free(t2); > > + opn = "vmulu"; > > + break; > > + } > > + case OPC_V3MULU: > > + { > > + TCGv temp[4]; > > + TCGv c; > > + TCGv trs, trt, tc1, tc2, tc3; > > + temp[0] = tcg_temp_new(); > > + temp[1] = tcg_temp_new(); > > + temp[2] = tcg_temp_new(); > > + temp[3] = tcg_temp_new(); > > + trs = tcg_temp_new(); > > + trt = tcg_temp_new(); > > + tc1 = tcg_temp_new(); > > + tc2 = tcg_temp_new(); > > + tc3 = tcg_temp_new(); > > + c = tcg_temp_new(); > > + gen_load_gpr(trs, rs); > > + gen_load_gpr(trt, rt); > > + /* rs × (MPL2 || MPL1 || MPL0) (192X64 bit > multiplication) > > */ > > + gen_helper_dmultu(trs, mpl0); > > + tcg_gen_mov_tl(temp[0], cpu_LO[0]); > > + tcg_gen_mov_tl(temp[1], cpu_HI[0]); > > + > > + gen_helper_dmultu(trs, mpl1); > > + tcg_gen_mov_tl(temp[2], cpu_HI[0]); > > + gen_addc(cpu_LO[0], temp[1], tc1, tc2); > > + gen_addc(temp[2], tc2, tc3, c); > > + tcg_gen_mov_tl(temp[1], tc1); > > + tcg_gen_mov_tl(temp[2], tc3); > > + tcg_gen_mov_tl(temp[3], c); > > + > > + gen_helper_dmultu(trs, mpl2); > > + tcg_gen_add_tl(temp[3], temp[3], cpu_HI[0]); > > + gen_addc(cpu_LO[0], temp[2], tc1, tc2); > > + tcg_gen_mov_tl(temp[2], tc1); > > + tcg_gen_add_tl(temp[3], temp[3], tc2); > > + /* Addition of rt in 256 bit result > > + (t3 t2 t1 t0 contain result) */ > > + gen_addc(temp[0], trt, tc1, c); > > + tcg_gen_mov_tl(temp[0], tc1); > > + gen_addc(temp[1], c, tc1, tc2); > > + tcg_gen_mov_tl(temp[1], tc1); > > + gen_addc(temp[2], tc2, tc1, c); > > + tcg_gen_mov_tl(temp[2], tc1); > > + tcg_gen_add_tl(temp[3], temp[3], c); > > + /* Addition of p2 p1 p0 in 256 bit result */ > > + gen_addc(temp[0], p0, tc1, c); > > + tcg_gen_mov_tl(temp[0], tc1); > > + gen_addc(temp[1], c, tc1, tc2); > > + tcg_gen_mov_tl(temp[1], tc1); > > + gen_addc(temp[2], tc2, tc1, c); > > + tcg_gen_mov_tl(temp[2], tc1); > > + tcg_gen_add_tl(temp[3], temp[3], c); > > + > > + gen_addc(temp[1], p1, tc1, c); > > + tcg_gen_mov_tl(temp[1], tc1); > > + gen_addc(temp[2], c, tc1, tc2); > > + tcg_gen_mov_tl(temp[2], tc1); > > + tcg_gen_add_tl(temp[3], temp[3], tc2); > > + > > + gen_addc(temp[2], p2, tc1, c); > > + tcg_gen_mov_tl(temp[2], tc1); > > + tcg_gen_add_tl(temp[3], temp[3], c); > > + /* final step */ > > + tcg_gen_mov_tl(cpu_gpr[rd], temp[0]); > > + tcg_gen_mov_tl(p0, temp[1]); > > + tcg_gen_mov_tl(p1, temp[2]); > > + tcg_gen_mov_tl(p2, temp[3]); > > + tcg_temp_free(temp[0]); > > + tcg_temp_free(temp[1]); > > + tcg_temp_free(temp[2]); > > + tcg_temp_free(temp[3]); > > + tcg_temp_free(trs); > > + tcg_temp_free(trt); > > + tcg_temp_free(tc1); > > + tcg_temp_free(tc2); > > + tcg_temp_free(tc3); > > + tcg_temp_free(c); > > + opn = "v3mulu"; > > + break; > > + } > > + } > > + > > + } else { > > + generate_exception(ctx, EXCP_RI); > > + } > > +} > > + > > + > > +#endif > > /* Arithmetic */ > > static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, > > int rd, int rs, int rt) > > { > > const char *opn = "arith"; > > > > + target_ulong mask = 0xFF; > > if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB > > && opc != OPC_DADD && opc != OPC_DSUB) { > > /* If no destination, treat it as a NOP. > > @@ -1637,6 +1887,22 @@ static void gen_arith (CPUState *env, DisasContext > > *ctx, uint32_t opc, > > } > > opn = "addu"; > > break; > > + case OPC_BADDU: > > + { > > + TCGv t0 = tcg_temp_new(); > > + TCGv t1 = tcg_temp_new(); > > + TCGv t2 = tcg_temp_new(); > > + gen_load_gpr(t1, rs); > > + gen_load_gpr(t2, rt); > > + tcg_gen_andi_tl(t1, t1, mask); > > + tcg_gen_andi_tl(t2, t2, mask); > > + tcg_gen_add_tl(t0, t1, t2); > > + tcg_gen_andi_tl(t0, t0, mask); > > + gen_store_gpr(t0, rd); > > + } > > + > > + opn = "baddu"; > > + break; > > case OPC_SUB: > > { > > TCGv t0 = tcg_temp_local_new(); > > @@ -2013,7 +2279,74 @@ static void gen_HILO (DisasContext *ctx, uint32_t > > opc, int reg) > > (void)opn; /* avoid a compiler warning */ > > MIPS_DEBUG("%s %s", opn, regnames[reg]); > > } > > +#if defined(TARGET_MIPS64) > > +static void gen_seqsne (DisasContext *ctx, uint32_t opc, > > + int rd, int rs, int rt) > > +{ > > + const char *opn = "seq/sne"; > > + TCGv t0, t1; > > + t0 = tcg_temp_new(); > > + t1 = tcg_temp_new(); > > + switch (opc) { > > + case OPC_SEQ: > > + { > > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > > + gen_load_gpr(t0, rd); > > + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1); > > + } > > + opn = "seq"; > > + break; > > + case OPC_SNE: > > + { > > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > > + gen_load_gpr(t0, rd); > > + gen_load_gpr(t1, 0); > > + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0); > > + } > > + opn = "sne"; > > + break; > > + default: > > + MIPS_INVAL(opn); > > + generate_exception(ctx, EXCP_RI); > > + goto out; > > + } > > +out: > > + tcg_temp_free(t0); > > + tcg_temp_free(t1); > > > > +} > > + > > +static void gen_saa (CPUState *env, DisasContext *ctx, uint32_t opc, > > + int rt, int base) > > +{ > > + const char *opn = "saa"; > > + TCGv t0, t1, temp; > > + t0 = tcg_temp_new(); > > + t1 = tcg_temp_new(); > > + temp = tcg_temp_new(); > > + gen_load_gpr(t1, rt); > > + gen_base_offset_addr(ctx, t0, base, 0); > > + switch (opc) { > > + case OPC_SAA: > > + save_cpu_state(ctx, 1); > > + op_ld_lw(temp, t0, ctx); > > + tcg_gen_add_tl(temp, temp, t1); > > + op_st_sw(temp, t0, ctx); > > + opn = "saa"; > > + break; > > + case OPC_SAAD: > > + save_cpu_state(ctx, 0); > > + op_ld_ld(temp, t0, ctx); > > + tcg_gen_add_tl(temp, temp, t1); > > + op_st_sd(temp, t0, ctx); > > + opn = "saad"; > > + break; > > + } > > + > > + tcg_temp_free(t0); > > + tcg_temp_free(t1); > > +} > > +#endif > > static void gen_muldiv (DisasContext *ctx, uint32_t opc, > > int rs, int rt) > > { > > @@ -2149,6 +2482,10 @@ static void gen_muldiv (DisasContext *ctx, > uint32_t > > opc, > > gen_helper_dmult(t0, t1); > > opn = "dmult"; > > break; > > + case OPC_DMUL: > > + gen_helper_dmult(t0, t1); > > + opn = "dmul"; > > + break; > > case OPC_DMULTU: > > gen_helper_dmultu(t0, t1); > > opn = "dmultu"; > > @@ -2368,7 +2705,49 @@ static void gen_cl (DisasContext *ctx, uint32_t > opc, > > MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); > > tcg_temp_free(t0); > > } > > +#if defined(TARGET_MIPS64) > > +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t > opc, > > + int rd, int rs, int rt) > > +{ > > + TCGv num = tcg_temp_new(); > > + TCGv res = tcg_temp_new(); > > + target_ulong maskb = 1; > > + gen_load_gpr(num, rs); > > + TCGv ones=tcg_temp_new(); > > + gen_load_gpr(ones, 0); > > + int x=1; > > + tcg_gen_andi_tl(res, num, maskb); > > + tcg_gen_add_tl(ones,ones, res); > > + while (x <= 31) { > > + tcg_gen_shri_i64(num, num, 1); > > + tcg_gen_andi_tl(res, num, maskb); > > + tcg_gen_add_tl(ones, ones, res); > > + x++; > > + } > > + gen_store_gpr(ones, rd); > > +} > > +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t > opc, > > + int rd, int rs, int rt) > > +{ > > + TCGv num, res, ones; > > + num = tcg_temp_new(); > > + res = tcg_temp_new(); > > + ones = tcg_temp_new(); > > + target_ulong maskb = 1; > > + gen_load_gpr(num, rs); > > + int x = 1; > > + tcg_gen_andi_tl(res, num, maskb); > > + tcg_gen_mov_tl(ones, res); > > > > + while (x <= 63) { > > + tcg_gen_shri_i64(num, num, 1); > > + tcg_gen_andi_tl(res, num, maskb); > > + tcg_gen_add_tl(ones, ones, res); > > + x++; > > + } > > + gen_store_gpr(ones, rd); > > +} > > +#endif > > /* Godson integer instructions */ > > static void gen_loongson_integer (DisasContext *ctx, uint32_t opc, > > int rd, int rs, int rt) > > @@ -2705,6 +3084,7 @@ static void gen_compute_branch (DisasContext *ctx, > > uint32_t opc, > > target_ulong btgt = -1; > > int blink = 0; > > int bcond_compute = 0; > > + target_ulong maskb; /* Used in BBIT0 and BBIT1*/ > > TCGv t0 = tcg_temp_new(); > > TCGv t1 = tcg_temp_new(); > > > > @@ -2730,6 +3110,39 @@ static void gen_compute_branch (DisasContext *ctx, > > uint32_t opc, > > } > > btgt = ctx->pc + insn_bytes + offset; > > break; > > + case OPC_BBIT1: > > + gen_load_gpr(t0, rs); > > + gen_load_gpr(t1, 0); > > + maskb = 1ULL << rt; > > + tcg_gen_andi_tl(t0, t0, maskb); > > + bcond_compute = 1; > > + btgt = ctx->pc + insn_bytes + offset; > > + break; > > + case OPC_BBIT132: > > + gen_load_gpr(t0, rs); > > + gen_load_gpr(t1, 0); > > + maskb = 1ULL << (rt + 32); > > + tcg_gen_andi_tl(t0, t0, maskb); > > + bcond_compute = 1; > > + btgt = ctx->pc + insn_bytes + offset; > > + break; > > + case OPC_BBIT0: > > + gen_load_gpr(t0, rs); > > + gen_load_gpr(t1, 0); > > + maskb = 1ULL << rt; > > + tcg_gen_andi_tl(t0, t0, maskb); > > + bcond_compute = 1; > > + btgt = ctx->pc + insn_bytes + offset; > > + break; > > + case OPC_BBIT032: > > + gen_load_gpr(t0, rs); > > + gen_load_gpr(t1, 0); > > + maskb = 1ULL << (rt + 32); > > + tcg_gen_andi_tl(t0, t0, maskb); > > + bcond_compute = 1; > > + btgt = ctx->pc + insn_bytes + offset; > > + break; > > + > > case OPC_BGEZ: > > case OPC_BGEZAL: > > case OPC_BGEZALS: > > @@ -2888,6 +3301,18 @@ static void gen_compute_branch (DisasContext *ctx, > > uint32_t opc, > > MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx, > > regnames[rs], regnames[rt], btgt); > > goto not_likely; > > + case OPC_BBIT1: > > + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > > + goto not_likely; > > + case OPC_BBIT132: > > + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > > + goto not_likely; > > + case OPC_BBIT0: > > + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); > > + goto not_likely; > > + case OPC_BBIT032: > > + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); > > + goto not_likely; > > case OPC_BNEL: > > tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > > MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx, > > @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx, > > uint32_t opc, > > tcg_temp_free(t0); > > tcg_temp_free(t1); > > } > > +/*For cavium specific extract instructions*/ > > +#if defined(TARGET_MIPS64) > > +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int > > rt, > > + int rs, int lsb, int msb) > > +{ > > + TCGv t0 = tcg_temp_new(); > > + TCGv t1 = tcg_temp_new(); > > + target_ulong mask; > > + gen_load_gpr(t1, rs); > > + switch (opc) { > > + case OPC_EXTS: > > + tcg_gen_shri_tl(t0, t1, lsb); > > + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); > > + /* To sign extened the remaining bits according to > > + the msb of the bit field */ > > + mask = 1ULL << msb; > > + tcg_gen_andi_tl(t1, t0, mask); > > + tcg_gen_addi_tl(t1, t1, -1); > > + tcg_gen_not_i64(t1, t1); > > + tcg_gen_or_tl(t0, t0, t1); > > + gen_store_gpr(t0, rt); > > + break; > > + case OPC_EXTS32: > > + tcg_gen_shri_tl(t0, t1, lsb + 32); > > + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); > > + mask = 1ULL << msb; > > + tcg_gen_andi_tl(t1, t0, mask); > > + tcg_gen_addi_tl(t1, t1, -1); > > + tcg_gen_not_i64(t1, t1); > > + tcg_gen_or_tl(t0, t0, t1); > > + gen_store_gpr(t0, rt); > > + break; > > > > + } > > + tcg_temp_free(t0); > > + tcg_temp_free(t1); > > +} > > +#endif > > /* special3 bitfield operations */ > > static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, > > int rs, int lsb, int msb) > > @@ -3063,6 +3525,22 @@ static void gen_bitops (DisasContext *ctx, > uint32_t > > opc, int rt, > > tcg_gen_andi_tl(t1, t1, mask); > > tcg_gen_or_tl(t0, t0, t1); > > break; > > + case OPC_CINS: > > + mask = (1ULL << (msb+1))-1; > > + gen_load_gpr(t0, rt); > > + tcg_gen_andi_tl(t0, t0, 0); > > + tcg_gen_andi_tl(t1, t1, mask); > > + tcg_gen_shli_tl(t1, t1, lsb); > > + tcg_gen_or_tl(t0, t0, t1); > > + break; > > + case OPC_CINS32: > > + mask = (1ULL << (msb+1))-1; > > + gen_load_gpr(t0, rt); > > + tcg_gen_andi_tl(t0, t0, 0); > > + tcg_gen_andi_tl(t1, t1, mask); > > + tcg_gen_shli_tl(t1, t1, (lsb+32)); > > + tcg_gen_or_tl(t0, t0, t1); > > + break; > > #endif > > default: > > fail: > > @@ -11605,7 +12083,7 @@ static void decode_opc (CPUState *env, > DisasContext > > *ctx, int *is_branch) > > int32_t offset; > > int rs, rt, rd, sa; > > uint32_t op, op1, op2; > > - int16_t imm; > > + int16_t imm, imm10; > > > > /* make sure instructions are on a word boundary */ > > if (ctx->pc & 0x3) { > > @@ -11634,6 +12112,9 @@ static void decode_opc (CPUState *env, > DisasContext > > *ctx, int *is_branch) > > rd = (ctx->opcode >> 11) & 0x1f; > > sa = (ctx->opcode >> 6) & 0x1f; > > imm = (int16_t)ctx->opcode; > > + /* 10 bit Immediate value For SEQI,SNEI */ > > + imm10 = (ctx->opcode >> 6) & 0x3ff; > > + > > switch (op) { > > case OPC_SPECIAL: > > op1 = MASK_SPECIAL(ctx->opcode); > > @@ -11859,6 +12340,71 @@ static void decode_opc (CPUState *env, > DisasContext > > *ctx, int *is_branch) > > case OPC_MUL: > > gen_arith(env, ctx, op1, rd, rs, rt); > > break; > > +#if defined(TARGET_MIPS64) > > + > > + > > + case OPC_DMUL: > > + check_insn(env, ctx, ISA_MIPS3); > > + check_mips_64(ctx); > > + gen_muldiv(ctx, op1, rs, rt); > > + tcg_gen_mov_tl(cpu_gpr[rd], cpu_LO[0]); > > + break; > > + case OPC_CINS: > > + check_insn(env, ctx, ISA_MIPS64R2); > > + check_mips_64(ctx); > > + gen_bitops(ctx, op1, rt, rs, sa, rd); > > + break; > > + case OPC_CINS32: > > + check_mips_64(ctx); > > + gen_bitops(ctx, op1, rt, rs, sa, rd); > > + break; > > + case OPC_MTM0: > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > + break; > > + case OPC_MTM1: > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > + break; > > + case OPC_MTM2: > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > + break; > > + case OPC_MTP0: > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > + break; > > + case OPC_MTP1: > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > + break; > > + case OPC_MTP2: > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > + break; > > + case OPC_VMULU: > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > + break; > > + case OPC_BADDU: > > + gen_arith(env, ctx, op1, rd, rs, rt); > > + break; > > + case OPC_EXTS: > > + check_mips_64(ctx); > > + gen_exts(env, ctx, op1, rt, rs, sa, rd); > > + break; > > + case OPC_EXTS32: > > + check_mips_64(ctx); > > + gen_exts(env, ctx, op1, rt, rs, sa, rd); > > + break; > > + case OPC_SAA: > > + gen_saa(env, ctx, op1, rt, rs); > > + break; > > + case OPC_SAAD: > > + check_mips_64(ctx); > > + gen_saa(env, ctx, op1, rt, rs); > > + break; > > +#endif > > case OPC_CLO: > > case OPC_CLZ: > > check_insn(env, ctx, ISA_MIPS32); > > @@ -11878,13 +12424,24 @@ static void decode_opc (CPUState *env, > > DisasContext *ctx, int *is_branch) > > break; > > case OPC_DIV_G_2F: > > case OPC_DIVU_G_2F: > > - case OPC_MULT_G_2F: > > case OPC_MULTU_G_2F: > > case OPC_MOD_G_2F: > > case OPC_MODU_G_2F: > > check_insn(env, ctx, INSN_LOONGSON2F); > > gen_loongson_integer(ctx, op1, rd, rs, rt); > > break; > > + case OPC_MULT_G_2F: > > + if (!TARGET_OCTEON) { > > + check_insn(env, ctx, INSN_LOONGSON2F); > > + gen_loongson_integer(ctx, op1, rd, rs, rt); > > + } else { > > +#if defined(TARGET_MIPS64) > > + /* Cavium Specific vmm0 */ > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > +#endif > > + } > > + break; > > #if defined(TARGET_MIPS64) > > case OPC_DCLO: > > case OPC_DCLZ: > > @@ -11892,7 +12449,6 @@ static void decode_opc (CPUState *env, > DisasContext > > *ctx, int *is_branch) > > check_mips_64(ctx); > > gen_cl(ctx, op1, rd, rs); > > break; > > - case OPC_DMULT_G_2F: > > case OPC_DMULTU_G_2F: > > case OPC_DDIV_G_2F: > > case OPC_DDIVU_G_2F: > > @@ -11901,6 +12457,39 @@ static void decode_opc (CPUState *env, > DisasContext > > *ctx, int *is_branch) > > check_insn(env, ctx, INSN_LOONGSON2F); > > gen_loongson_integer(ctx, op1, rd, rs, rt); > > break; > > + case OPC_DMULT_G_2F: > > + if (!TARGET_OCTEON) { > > + check_insn(env, ctx, INSN_LOONGSON2F); > > + gen_loongson_integer(ctx, op1, rd, rs, rt); > > + } else { > > + /* Cavium Specific instruction v3mulu */ > > + check_mips_64(ctx); > > + gen_LMI(env, ctx, op1, rs, rt, rd); > > + } > > + break; > > + case OPC_SEQ: > > + check_mips_64(ctx); > > + gen_seqsne(ctx, op1, rd, rs, rt); > > + break; > > + case OPC_SNE: > > + check_mips_64(ctx); > > + gen_seqsne(ctx, op1, rd, rs, rt); > > + break; > > + case OPC_SEQI: > > + check_mips_64(ctx); > > + gen_set_imm(env, op1, rt, rs, imm10); > > + break; > > + case OPC_SNEI: > > + check_mips_64(ctx); > > + gen_set_imm(env, op1, rt, rs, imm10); > > + break; > > + case OPC_POP: > > + insn_opc_pop(ctx, env, op1, rd, rs, rt); > > + break; > > + case OPC_DPOP: > > + check_mips_64(ctx); > > + insn_opc_dpop(ctx, env, op1, rd, rs, rt); > > + break; > > #endif > > default: /* Invalid */ > > MIPS_INVAL("special2"); > > @@ -12192,10 +12781,32 @@ static void decode_opc (CPUState *env, > > DisasContext *ctx, int *is_branch) > > break; > > > > /* COP2. */ > > - case OPC_LWC2: > > - case OPC_LDC2: > > - case OPC_SWC2: > > - case OPC_SDC2: > > + /* Conflicting opcodes with Cavium specific branch instructions > > + if TARGET_OCTEON is set these opcodes will belong to Cavium */ > > + case OPC_LWC2: /*BBIT0*/ > > + if(TARGET_OCTEON) { > > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > > + *is_branch = 1; > > + break; > > + } > > + case OPC_LDC2: /*BBIT032*/ > > + if(TARGET_OCTEON) { > > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > > + *is_branch = 1; > > + break; > > + } > > + case OPC_SWC2: /*BBIT1*/ > > + if(TARGET_OCTEON) { > > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > > + *is_branch = 1; > > + break; > > + } > > + case OPC_SDC2: /*BBIT132*/ > > + if(TARGET_OCTEON) { > > + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); > > + *is_branch = 1; > > + break; > > + } > > case OPC_CP2: > > /* COP2: Not implemented. */ > > generate_exception_err(ctx, EXCP_CpU, 2); > > @@ -12584,6 +13195,18 @@ static void mips_tcg_init(void) > > cpu_dspctrl = tcg_global_mem_new(TCG_AREG0, > > offsetof(CPUState, > > active_tc.DSPControl), > > "DSPControl"); > > + mpl0 = tcg_global_mem_new(TCG_AREG0, > > + offsetof(CPUState, Reg.MPL0), "MPL0"); > > + mpl1 = tcg_global_mem_new(TCG_AREG0, > > + offsetof(CPUState, Reg.MPL1), "MPL1"); > > + mpl2 = tcg_global_mem_new(TCG_AREG0, > > + offsetof(CPUState, Reg.MPL2), "MPL2"); > > + p0 = tcg_global_mem_new(TCG_AREG0, > > + offsetof(CPUState, Reg.P0), "P0"); > > + p1 = tcg_global_mem_new(TCG_AREG0, > > + offsetof(CPUState, Reg.P1), "P1"); > > + p2 = tcg_global_mem_new(TCG_AREG0, > > + offsetof(CPUState, Reg.P2), "P2"); > > bcond = tcg_global_mem_new(TCG_AREG0, > > offsetof(CPUState, bcond), "bcond"); > > btarget = tcg_global_mem_new(TCG_AREG0, > > @@ -12607,6 +13230,18 @@ static void mips_tcg_init(void) > > > > #include "translate_init.c" > > > > +#if defined(TARGET_MIPS64) > > + > > +static void set_cvmctl_register(CPUMIPSState *env) > > +{ > > + env->CvmCtlRegister.cvmctl = env->CvmCtlRegister.cvmctl > > + ^ env->CvmCtlRegister.cvmctl; > > + env->CvmCtlRegister.cvmctl = > > FUSE_START_BIT(env->CvmCtlRegister.cvmctl); > > + env->CvmCtlRegister.cvmctl = KASUMI(env->CvmCtlRegister.cvmctl); > > + env->CvmCtlRegister.cvmctl = IPPCI(env->CvmCtlRegister.cvmctl); > > + env->CvmCtlRegister.cvmctl = IPTI(env->CvmCtlRegister.cvmctl); > > +} > > +#endif > > CPUMIPSState *cpu_mips_init (const char *cpu_model) > > { > > CPUMIPSState *env; > > @@ -12619,6 +13254,10 @@ CPUMIPSState *cpu_mips_init (const char > *cpu_model) > > env->cpu_model = def; > > env->cpu_model_str = cpu_model; > > > > +#if defined(TARGET_MIPS64) > > + /*Function for setting cvmctl register*/ > > + set_cvmctl_register(env); > > +#endif > > cpu_exec_init(env); > > #ifndef CONFIG_USER_ONLY > > mmu_init(env, def); > > -- > > 1.7.3.4 >
Please see the online comments highlighted in red. I'll be sending corrected Patches to the mailing list. On Wed, Mar 30, 2011 at 9:38 PM, Nathan Froyd <froydnj@codesourcery.com>wrote: > On Sat, Mar 26, 2011 at 11:58:37AM +0500, Khansa Butt wrote: > > Subject: [PATCH] MIPS64 user mode emulation in QEMU > > This patch adds support for Cavium Network's > > Octeon 57XX user mode instructions. Octeon > > 57xx is based on MIPS64. So this patch is > > the first MIPS64 User Mode Emulation in QEMU > > This is the team(Khansa Butt, Ehsan-ul-Haq, Abdul Qadeer, Abdul Waheed) > > work of HPCNL Lab at KICS-UET Lahore. > > Thanks for doing this. As already noted, this patch should be split > into at least two patches: one to add Octeon-specific instructions in > target-mips/ and one adding the necessary linux-user bits. > > > +extern int TARGET_OCTEON; > > I don't think a global like this is the right way to go. Perhaps the > elfload.c code should set a flag in image_info , which can then be used > to set a flag in CPUMIPSState later on. > A variable is declared in image_info to set a flag in CPUMIPSState and discarded a global variable @@ -51,6 +51,7 @@ struct image_info { abi_ulong arg_start; abi_ulong arg_end; int personality; + int elf_arch; > > If we must use a global variable, it should be declared in > target-mips/cpu.h. > > > @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env) > > env->active_tc.gpr[5], > > env->active_tc.gpr[6], > > env->active_tc.gpr[7], > > - arg5, arg6/*, arg7, arg8*/); > > + env->active_tc.gpr[8], > > + env->active_tc.gpr[9]/*, arg7, arg8*/); > > } > > if (ret == -TARGET_QEMU_ESIGRETURN) { > > /* Returning from a successful sigreturn syscall. > > This change breaks O32 binaries; it needs to be done in a different way. > The above line has been changed with following code snippet +#if defined(TARGET_MIPS64) + ret = do_syscall(env, env->active_tc.gpr[2], + env->active_tc.gpr[4], + env->active_tc.gpr[5], + env->active_tc.gpr[6], + env->active_tc.gpr[7], + env->active_tc.gpr[8], + env->active_tc.gpr[9]); +#else ret = do_syscall(env, env->active_tc.gpr[2], env->active_tc.gpr[4], env->active_tc.gpr[5], env->active_tc.gpr[6], env->active_tc.gpr[7], arg5, arg6/*, arg7, arg8*/); +#endif > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > > index 499c4d7..47fef05 100644 > > --- a/linux-user/syscall.c > > +++ b/linux-user/syscall.c > > @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, > abi_long > > arg1, > > case TARGET_NR_set_thread_area: > > #if defined(TARGET_MIPS) > > ((CPUMIPSState *) cpu_env)->tls_value = arg1; > > + /*tls entry is moved to k0 so that this can be used later*/ > > + ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1; > > ret = 0; > > break; > > #elif defined(TARGET_CRIS) > > I believe this is only correct for Octeon binaries; it's not how the > rest of the MIPS world works. It therefore needs to be conditional on > Octeon-ness. > > The above thing has been made octeon specific > > --- a/target-mips/cpu.h > > +++ b/target-mips/cpu.h > > @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t; > > #define MIPS_FPU_MAX 1 > > #define MIPS_DSP_ACC 4 > > > > +typedef struct cavium_mul cavium_mul; > > +struct cavium_mul { > > + target_ulong MPL0; > > + target_ulong MPL1; > > + target_ulong MPL2; > > + target_ulong P0; > > + target_ulong P1; > > + target_ulong P2; > > +}; > > +typedef struct cvmctl_register cvmctl_register; > > +struct cvmctl_register { > > + target_ulong cvmctl; > > +}; > > The indentation here needs to be fixed. I don't think there's any > reason why these need to be defined outside TCState, either. > Octeon register in TCState as follows @@ -171,6 +176,15 @@ struct TCState { target_ulong CP0_TCSchedule; target_ulong CP0_TCScheFBack; int32_t CP0_Debug_tcstatus; + /* Multiplier registers for Octeon */ + target_ulong MPL0; + target_ulong MPL1; + target_ulong MPL2; + target_ulong P0; + target_ulong P1; + target_ulong P2; + /* Octeon specific Coprocessor 0 register */ + target_ulong cvmctl; }; > > diff --git a/target-mips/translate.c b/target-mips/translate.c > > index cce77be..9c3d772 100644 > > --- a/target-mips/translate.c > > +++ b/target-mips/translate.c > > @@ -36,6 +36,15 @@ > > #define GEN_HELPER 1 > > #include "helper.h" > > > > +int TARGET_OCTEON; > > +#if defined(TARGET_MIPS64) > > +/*Macros for setting values of cvmctl registers*/ > > +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000) > > +#define KASUMI(cvmctl)(cvmctl | 0x20000000) > > +#define IPPCI(cvmctl)(cvmctl | 0x380) > > +#define IPTI(cvmctl)(cvmctl | 0x70) > > +#endif > > Please follow existing style; spaces between the comment and comment > markers (many examples in translate.c, not just here) and spaces between > the macro argument list and definition. > > > @@ -779,7 +818,9 @@ static inline void gen_op_addr_add (DisasContext > *ctx, > > TCGv ret, TCGv arg0, TCGv > > See the MIPS64 PRA manual, section 4.10. */ > > if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && > > !(ctx->hflags & MIPS_HFLAG_UX)) { > > - tcg_gen_ext32s_i64(ret, ret); > > + /*This function sign extend 32 bit value to 64 bit, was causing > > error > > + when ld instruction came.Thats why it is commmented out*/ > > + /* tcg_gen_ext32s_i64(ret, ret);*/ > > } > > #endif > > } > > Um, no. If you needed to comment this out, you have a bug someplace > else. Don't paper over the bug here. > The above behavior when ld instruction came was due to env->hflags had not been 'or' ed with mips64 user mode flag(MIPS_HFLAG_UX) so now following line is added in translate.c: cpu_rest() #ifdef TARGET_MIPS64 + env->hflags |= MIPS_HFLAG_UX; if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { env->hflags |= MIPS_HFLAG_F64; } > > + case OPC_VMULU: > > + case OPC_V3MULU: > > These two are large enough that they should be done as out-of-line > helpers. > Out-of-line helper function has been implemented > > Also, since all these new instructions are Octeon-specific, there should > be checks emitted to ensure that they produce appropriate errors when > non-Octeon hardware is being simulated, similar in style to > check_mips_64. > check for octeon specific instructions static inline void check_octeon(DisasContext *ctx, CPUState *env) +{ + if (!env->TARGET_OCTEON) + generate_exception(ctx, EXCP_RI); +} > > > /* Arithmetic */ > > static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, > > int rd, int rs, int rt) > > { > > const char *opn = "arith"; > > > > + target_ulong mask = 0xFF; > > I don't think it's really necessary to have this, but if you feel it's > necessary, please move the declaration closer to the point of use. > > > +#if defined(TARGET_MIPS64) > > +static void gen_seqsne (DisasContext *ctx, uint32_t opc, > > + int rd, int rs, int rt) > > +{ > > + const char *opn = "seq/sne"; > > + TCGv t0, t1; > > + t0 = tcg_temp_new(); > > + t1 = tcg_temp_new(); > > + switch (opc) { > > + case OPC_SEQ: > > + { > > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > > + gen_load_gpr(t0, rd); > > + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, 1); > > + } > > + opn = "seq"; > > + break; > > This looks like you are comparing rd with itself? > t0 is actually compared with 1. if t0 <1 then rd =1 for reference check slti instruction of mips64r2 switch (opc) { case OPC_SLTI: tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, uimm); opn = "slti"; > > + case OPC_SNE: > > + { > > + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); > > + gen_load_gpr(t0, rd); > > + gen_load_gpr(t1, 0); > > + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t1, t0); > > You could use setcondi here by reversing the condition. > This is set if not equal instruction. if rs != rt, rd has some value greater than 1 (because of tcg_gen_xor_tl) so if t1 < t0(in tcg_gen_setcond_tl) rd will be 1. that's wat we needed "set if not equal" > > +#if defined(TARGET_MIPS64) > > +static void insn_opc_pop (DisasContext *ctx, CPUState *env, uint32_t > opc, > > + int rd, int rs, int rt) > > +static void insn_opc_dpop (DisasContext *ctx, CPUState *env, uint32_t > opc, > > + int rd, int rs, int rt) > > These should also be done as out-of-line helpers. > > > @@ -2983,7 +3408,44 @@ static void gen_compute_branch (DisasContext *ctx, > > uint32_t opc, > > tcg_temp_free(t0); > > tcg_temp_free(t1); > > } > > +/*For cavium specific extract instructions*/ > > +#if defined(TARGET_MIPS64) > > +static void gen_exts (CPUState *env,DisasContext *ctx, uint32_t opc, int > > rt, > > + int rs, int lsb, int msb) > > +{ > > + TCGv t0 = tcg_temp_new(); > > + TCGv t1 = tcg_temp_new(); > > + target_ulong mask; > > + gen_load_gpr(t1, rs); > > + switch (opc) { > > + case OPC_EXTS: > > + tcg_gen_shri_tl(t0, t1, lsb); > > + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); > > + /* To sign extened the remaining bits according to > > + the msb of the bit field */ > > + mask = 1ULL << msb; > > + tcg_gen_andi_tl(t1, t0, mask); > > + tcg_gen_addi_tl(t1, t1, -1); > > + tcg_gen_not_i64(t1, t1); > > + tcg_gen_or_tl(t0, t0, t1); > > You can use tcg_gen_orc_tl here and elsewhere. > > -Nathan >
diff --git a/configure b/configure index 438219b..045a4ef 100755 --- a/configure +++ b/configure @@ -1011,6 +1011,7 @@ cris-linux-user \ m68k-linux-user \ microblaze-linux-user \ mips-linux-user \ +mips64-linux-user \ mipsel-linux-user \ ppc-linux-user \ ppc64-linux-user \ diff --git a/default-configs/mips64-linux-user.mak b/default-configs/mips64-linux-user.mak new file mode 100644 index 0000000..1598bfc --- /dev/null +++ b/default-configs/mips64-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for mips64-linux-user diff --git a/exec.c b/exec.c index 49c28b1..ee3f78e 100644 --- a/exec.c +++ b/exec.c @@ -2441,6 +2441,7 @@ int page_check_range(target_ulong start, target_ulong len, int flags) for (addr = start, len = end - start; len != 0; len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) { + addr &= qemu_host_page_mask; p = page_find(addr >> TARGET_PAGE_BITS); if( !p ) return -1; diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 33d776d..60fe85e 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -16,6 +16,8 @@ #include "qemu.h" #include "disas.h" +extern int TARGET_OCTEON; + #ifdef _ARCH_PPC64 #undef ARCH_DLINFO #undef ELF_PLATFORM @@ -25,6 +27,9 @@ #undef ELF_ARCH #endif +#define EF_MIPS_MARCH 16711680 +#define E_MIPS_MACH_OCTEON 9109504 + #define ELF_OSABI ELFOSABI_SYSV /* from personality.h */ @@ -1313,7 +1318,7 @@ static void load_elf_image(const char *image_name, int image_fd, vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr); vaddr_ps = TARGET_ELF_PAGESTART(vaddr); - error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po, + error = target_mmap(vaddr_ps, eppnt->p_memsz + vaddr_po, elf_prot, MAP_PRIVATE | MAP_FIXED, image_fd, eppnt->p_offset - vaddr_po); if (error == -1) { @@ -1588,7 +1593,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, If we do nothing, we'll have overwritten this when we re-use bprm->buf when we load the interpreter. */ elf_ex = *(struct elfhdr *)bprm->buf; - +#if defined(TARGET_MIPS64) + if ((elf_ex.e_flags & EF_MIPS_MARCH) == E_MIPS_MACH_OCTEON) { + TARGET_OCTEON = 1; + } else { + TARGET_OCTEON = 0; + } +#endif bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); diff --git a/linux-user/main.c b/linux-user/main.c index 0d627d6..8b4b90b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1937,10 +1937,16 @@ static int do_store_exclusive(CPUMIPSState *env) int d; addr = env->lladdr; + /* 64 bit address is converted to 32 bit value so that a valid + * l1_map value can be accessed. This thing is needed for target + * mips64 and host 32 bit x86 + */ + addr &= qemu_host_page_mask; page_addr = addr & TARGET_PAGE_MASK; start_exclusive(); mmap_lock(); flags = page_get_flags(page_addr); + addr = env->lladdr; if ((flags & PAGE_READ) == 0) { segv = 1; } else { @@ -1978,7 +1984,8 @@ static int do_store_exclusive(CPUMIPSState *env) void cpu_loop(CPUMIPSState *env) { target_siginfo_t info; - int trapnr, ret; + int trapnr; + abi_long ret; unsigned int syscall_num; for(;;) { @@ -1987,7 +1994,11 @@ void cpu_loop(CPUMIPSState *env) cpu_exec_end(env); switch(trapnr) { case EXCP_SYSCALL: +#if defined(TARGET_MIPS64) + syscall_num = env->active_tc.gpr[2] - 5000; +#else syscall_num = env->active_tc.gpr[2] - 4000; +#endif env->active_tc.PC += 4; if (syscall_num >= sizeof(mips_syscall_args)) { ret = -ENOSYS; @@ -2013,7 +2024,8 @@ void cpu_loop(CPUMIPSState *env) env->active_tc.gpr[5], env->active_tc.gpr[6], env->active_tc.gpr[7], - arg5, arg6/*, arg7, arg8*/); + env->active_tc.gpr[8], + env->active_tc.gpr[9]/*, arg7, arg8*/); } if (ret == -TARGET_QEMU_ESIGRETURN) { /* Returning from a successful sigreturn syscall. @@ -2926,7 +2938,9 @@ int main(int argc, char **argv, char **envp) #endif #elif defined(TARGET_MIPS) #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) - cpu_model = "20Kc"; + /* we use this model so that we can decode MIPS64r2 + reserved instruction */ + cpu_model = "MIPS64R2-generic"; #else cpu_model = "24Kf"; #endif diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index 668a2b9..1395e61 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -217,5 +217,7 @@ struct target_pt_regs { #define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ +/* Nasty hack: define a fake errno value for use by sigreturn. */ +#define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips64" diff --git a/linux-user/signal.c b/linux-user/signal.c index c846b8c..114116c 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -2410,7 +2410,8 @@ void sparc64_get_context(CPUSPARCState *env) #endif #elif defined(TARGET_ABI_MIPSN64) -# warning signal handling not implemented +/*this line is commented out to avoid compile time error*/ +/*# warning signal handling not implemented*/ static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUState *env) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 499c4d7..47fef05 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7195,6 +7195,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_set_thread_area: #if defined(TARGET_MIPS) ((CPUMIPSState *) cpu_env)->tls_value = arg1; + /*tls entry is moved to k0 so that this can be used later*/ + ((CPUMIPSState *) cpu_env)->active_tc.gpr[26] = arg1; ret = 0; break; #elif defined(TARGET_CRIS) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 2419aa9..59bcc0f 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -140,6 +140,20 @@ typedef struct mips_def_t mips_def_t; #define MIPS_FPU_MAX 1 #define MIPS_DSP_ACC 4 +typedef struct cavium_mul cavium_mul; +struct cavium_mul { + target_ulong MPL0; + target_ulong MPL1; + target_ulong MPL2; + target_ulong P0; + target_ulong P1; + target_ulong P2; +}; +typedef struct cvmctl_register cvmctl_register; +struct cvmctl_register { + target_ulong cvmctl; +}; + typedef struct TCState TCState; struct TCState { target_ulong gpr[32]; @@ -178,6 +192,8 @@ struct CPUMIPSState { TCState active_tc; CPUMIPSFPUContext active_fpu; + cavium_mul Reg; + cvmctl_register CvmCtlRegister; uint32_t current_tc; uint32_t current_fpu; diff --git a/target-mips/translate.c b/target-mips/translate.c index cce77be..9c3d772 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -36,6 +36,15 @@ #define GEN_HELPER 1 #include "helper.h" +int TARGET_OCTEON; +#if defined(TARGET_MIPS64) +/*Macros for setting values of cvmctl registers*/ +#define FUSE_START_BIT(cvmctl)(cvmctl | 0x80000000) +#define KASUMI(cvmctl)(cvmctl | 0x20000000) +#define IPPCI(cvmctl)(cvmctl | 0x380) +#define IPTI(cvmctl)(cvmctl | 0x70) +#endif + //#define MIPS_DEBUG_DISAS //#define MIPS_DEBUG_SIGN_EXTENSIONS @@ -70,6 +79,11 @@ enum { OPC_JAL = (0x03 << 26), OPC_JALS = OPC_JAL | 0x5, OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ + /* Cavium Specific */ + OPC_BBIT1 = (0x3a << 26), /*jump on bit set, cavium specific*/ + OPC_BBIT132 = (0x3e << 26), /*jump on bit set(one of the upper 32 bits)*/ + OPC_BBIT0 = (0x32 << 26), /*jump on bit clear, cavium specific*/ + OPC_BBIT032 = (0x36 << 26), /*jump on bit set(one of the upper 32 bits)*/ OPC_BEQL = (0x14 << 26),