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 <kha...@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 <kha...@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