Hi Richard, On Tue, Feb 09, 2016 at 04:50:52PM +0000, James Hogan wrote: > > @@ -589,6 +608,50 @@ static void tcg_out_movi(TCGContext *s, TCGType type, > > } > > if (TCG_TARGET_REG_BITS == 32 || arg == (int32_t)arg) { > > tcg_out_opc_imm(s, OPC_LUI, ret, TCG_REG_ZERO, arg >> 16); > > + } else if (use_mips32r6_instructions) { > > + tcg_target_long disp = arg - (intptr_t)s->code_ptr; > > + if (disp == sextract32(disp, 2, 19) * 4) { > > + tcg_out_opc_pc19(s, OPC_ADDIUPC, ret, disp >> 2); > > + return; > > + } else if ((disp & ~(tcg_target_long)0xffff) > > + == sextract32(disp, 16, 16) * 0x10000) { > > + tcg_out_opc_imm(s, OPC_ALUIPC, ret, 0, disp >> 16); > > I think ret and 0 are the wrong way around here. You're putting 0 in rs > (the destination register), which causes a seg fault. > > OUT: [size=56] > 0xfff30b0064: lw s1,-8(s0) > 0xfff30b0068: bnezalc zero,s1,0xfff30b0090 > 0xfff30b006c: nop > 0xfff30b0070: j 0xfff0000000 > 0xfff30b0074: nop > 0xfff30b0078: lui s1,0xbfc0 > 0xfff30b007c: ori s1,s1,0x580 > 0xfff30b0080: sd s1,256(s0) > 0xfff30b0084: aluipc zero,0xfeb7 > 0xfff30b0088: j 0xfff30b0034 > 0xfff30b008c: ori v0,v0,0x4010 > 0xfff30b0090: aluipc zero,0xfeb7 > 0xfff30b0094: j 0xfff30b0034 > 0xfff30b0098: ori v0,v0,0x4013 Actually, still not quite right. ALUIPC does dest <- ~0xffff & (PC + sign_extend(imm16<<16)) which is effectively dest <- PC & ~0xffff + sign_extend(imm16<<16) so disp should be between arg and code_ptr & ~0xffff, i.e. something like this I think: diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 8205ea4e159f..9a5d31478797 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -666,12 +666,13 @@ static void tcg_out_movi(TCGContext *s, TCGType type, tcg_out_opc_imm(s, OPC_LUI, ret, TCG_REG_ZERO, arg >> 16); } else if (use_mips32r6_instructions) { tcg_target_long disp = arg - (intptr_t)s->code_ptr; + tcg_target_long disphi = arg - ((intptr_t)s->code_ptr & ~(tcg_target_long)0xffff); if (disp == sextract32(disp, 2, 19) * 4) { tcg_out_opc_pc19(s, OPC_ADDIUPC, ret, disp >> 2); return; - } else if ((disp & ~(tcg_target_long)0xffff) - == sextract32(disp, 16, 16) * 0x10000) { - tcg_out_opc_imm(s, OPC_ALUIPC, 0, ret, disp >> 16); + } else if ((disphi & ~(tcg_target_long)0xffff) + == sextract32(disphi, 16, 16) * 0x10000) { + tcg_out_opc_imm(s, OPC_ALUIPC, 0, ret, disphi >> 16); } else { TCGReg in = TCG_REG_ZERO; tcg_target_long tmp = (int16_t)arg; Otherwise, in this case its trying to load the immediate 0xfff1c30000 relative to 0xfff30b0084, and calculates a disp of FEB7FF7C, which is truncated to 0xFEB7. The result is then: 0xfff30b0000 + (int)0xfeb70000 = 0xfff1c20000 which is off by 64KiB. With the above change we get: disphi = 0xfeb80000 and the result is then: 0xfff30b0000 + (int)0xfeb80000 = 0xfff1c30000 Cheers James