diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2023-03-18 13:23:43 +0000 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2023-03-18 13:23:43 +0000 |
| commit | cad38fe6dacaba5e01372e14486a3f486b25fd38 (patch) | |
| tree | 830dba65fa7b6a15e85fc6e0f59905ed62eca98e /src | |
| parent | f5bfb537da3a1ea8d24c573875602d211fc51cf5 (diff) | |
| download | box64-cad38fe6dacaba5e01372e14486a3f486b25fd38.tar.gz box64-cad38fe6dacaba5e01372e14486a3f486b25fd38.zip | |
[RV64_DYNAREC] Added F7 except /3 opcodes, plus some fixes (and test05 run all in dynarec now)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00.c | 160 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_tests.c | 35 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 63 | ||||
| -rw-r--r-- | src/dynarec/rv64/rv64_emitter.h | 23 |
4 files changed, 268 insertions, 13 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c index b654d1a9..882f3e52 100644 --- a/src/dynarec/rv64/dynarec_rv64_00.c +++ b/src/dynarec/rv64/dynarec_rv64_00.c @@ -238,10 +238,10 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni SRLI(x3, gd, 32); UFLAG_OP1(x3); UFLAG_DF(x3, d_imul32); - ZEROUP(gd); } else { MULxw(gd, ed, x4); } + ZEROUP(gd); } break; @@ -476,10 +476,11 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0x99: INST_NAME("CDQ"); if(rex.w) { - SRLI(xRDX, xRAX, 63); + SRAI(xRDX, xRAX, 63); } else { SLLI(xRDX, xRAX, 32); - SRLI(xRDX, xRDX, 63); + SRAI(xRDX, xRDX, 63); + ZEROUP(xRDX); } break; @@ -885,6 +886,159 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni *ok = 0; break; + case 0xF7: + nextop = F8; + switch((nextop>>3)&7) { + case 0: + case 1: + INST_NAME("TEST Ed, Id"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDH(x1, 4); + i64 = F32S; + emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5); + break; + case 2: + INST_NAME("NOT Ed"); + GETED(0); + XORI(ed, ed, -1); + if(!rex.w && MODREG) + ZEROUP(ed); + WBACK; + break; + /*case 3: + INST_NAME("NEG Ed"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETED(0); + emit_neg32(dyn, ninst, rex, ed, x3, x4); + WBACK; + break;*/ + case 4: + INST_NAME("MUL EAX, Ed"); + SETFLAGS(X_ALL, SF_PENDING); + UFLAG_DF(x2, rex.w?d_mul64:d_mul32); + GETED(0); + if(rex.w) { + if(ed==xRDX) gd=x3; else gd=xRDX; + MULHU(gd, xRAX, ed); + MUL(xRAX, xRAX, ed); + if(gd!=xRDX) {MV(xRDX, gd);} + } else { + MUL(xRDX, xRAX, ed); //64 <- 32x32 + AND(xRAX, xRDX, xMASK); + SRLI(xRDX, xRDX, 32); + } + UFLAG_RES(xRAX); + UFLAG_OP1(xRDX); + break; + case 5: + INST_NAME("IMUL EAX, Ed"); + SETFLAGS(X_ALL, SF_PENDING); + UFLAG_DF(x2, rex.w?d_imul64:d_imul32); + GETSED(0); + if(rex.w) { + if(ed==xRDX) gd=x3; else gd=xRDX; + MULH(gd, xRAX, ed); + MUL(xRAX, xRAX, ed); + if(gd!=xRDX) {MV(xRDX, gd);} + } else { + MUL(xRDX, xRAX, ed); //64 <- 32x32 + AND(xRAX, xRDX, xMASK); + SRLI(xRDX, xRDX, 32); + } + UFLAG_RES(xRAX); + UFLAG_OP1(xRDX); + break; + case 6: + INST_NAME("DIV Ed"); + SETFLAGS(X_ALL, SF_SET); + if(!rex.w) { + SET_DFNONE(x2); + GETED(0); + SLLI(x3, xRDX, 32); + AND(x2, xRAX, xMASK); + OR(x3, x3, x2); + if(MODREG) { + MV(x4, ed); + ed = x4; + } + DIVU(x2, x3, ed); + REMU(xRDX, x3, ed); + AND(xRAX, x2, xMASK); + ZEROUP(xRDX); + } else { + if(ninst + && dyn->insts[ninst-1].x64.addr + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31 + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) { + SET_DFNONE(x2); + GETED(0); + DIVU(x2, xRAX, ed); + REMU(xRDX, xRAX, ed); + MV(xRAX, x2); + } else { + GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + BEQ_MARK(xRDX, xZR); + if(ed!=x1) {MV(x1, ed);} + CALL(div64, -1); + B_NEXT_nocond; + MARK; + DIVU(x2, xRAX, ed); + REMU(xRDX, xRAX, ed); + MV(xRAX, x2); + SET_DFNONE(x2); + } + } + break; + case 7: + INST_NAME("IDIV Ed"); + SETFLAGS(X_ALL, SF_SET); + if(!rex.w) { + SET_DFNONE(x2) + GETSED(0); + SLLI(x3, xRDX, 32); + AND(x2, xRAX, xMASK); + OR(x3, x3, x2); + DIV(x2, x3, ed); + REM(xRDX, x3, ed); + AND(xRAX, x2, xMASK); + ZEROUP(xRDX); + } else { + if(ninst && dyn->insts + && dyn->insts[ninst-1].x64.addr + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x48 + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0x99) { + SET_DFNONE(x2) + GETED(0); + DIV(x2, xRAX, ed); + REM(xRDX, xRAX, ed); + AND(xRAX, x2, xMASK); + } else { + GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + //Need to see if RDX==0 and RAX not signed + // or RDX==-1 and RAX signed + BNE_MARK2(xRDX, xZR); + BLT_MARK(xRAX, xZR); + MARK2; + NOT(x2, xRDX); + BNE_MARK3(x2, xZR); + BLT_MARK(xRAX, xZR); + MARK3; + if(ed!=x1) MV(x1, ed); + CALL((void*)idiv64, -1); + B_NEXT_nocond; + MARK; + DIV(x2, xRAX, ed); + REM(xRDX, xRAX, ed); + MV(xRAX, x2); + SET_DFNONE(x2) + } + } + break; + default: + DEFAULT; + }; + break; + case 0xFF: nextop = F8; switch((nextop>>3)&7) { diff --git a/src/dynarec/rv64/dynarec_rv64_emit_tests.c b/src/dynarec/rv64/dynarec_rv64_emit_tests.c index 59f2b495..9ea95d20 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_tests.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_tests.c @@ -186,3 +186,38 @@ void emit_test32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int emit_pf(dyn, ninst, s3, s4, s5); } } + +// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch +void emit_test32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5) +{ + CLEAR_FLAGS(); + IFX_PENDOR0 { + SET_DF(s3, rex.w?d_tst64:d_tst32); + } else { + SET_DFNONE(s4); + } + + if(c>=-2048 && c<=2047) + ANDI(s3, s1, c); + else { + MOV64x(s3, c); + AND(s3, s1, s3); // res = s1 & s2 + } + + IFX_PENDOR0 { + SDxw(s3, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_SF) { + if (!rex.w) ZEROUP(s3); + SRLI(s4, s3, rex.w?63:31); + BEQZ(s4, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + IFX(X_ZF) { + BNEZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX(X_PF) { + emit_pf(dyn, ninst, s3, s4, s5); + } +} diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index 9ae48da5..f05dc57e 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -72,7 +72,23 @@ LDxw(x1, wback, fixedaddress); \ ed = x1; \ } - +// GETSED can use r1 for ed, and r2 for wback. ed will be sign extended! +#define GETSED(D) if(MODREG) { \ + ed = xRAX+(nextop&7)+(rex.b<<3); \ + wback = 0; \ + if(!rex.w) { \ + ADDW(x1, ed, xZR); \ + ed = x1; \ + } \ + } else { \ + SMREAD() \ + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, D); \ + if(rex.w) \ + LD(x1, wback, fixedaddress); \ + else \ + LW(x1, wback, fixedaddress); \ + ed = x1; \ + } // GETEDx can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI #define GETEDx(D) if(MODREG) { \ ed = xRAX+(nextop&7)+(rex.b<<3); \ @@ -83,6 +99,16 @@ LD(x1, wback, fixedaddress); \ ed = x1; \ } +//GETEDH can use hint for ed, and r1 or r2 for wback (depending on hint). wback is 0 if ed is xEAX..xEDI +#define GETEDH(hint, D) if(MODREG) { \ + ed = xRAX+(nextop&7)+(rex.b<<3); \ + wback = 0; \ + } else { \ + SMREAD(); \ + addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, ed, &fixedaddress, rex, NULL, 1, D); \ + LDxw(hint, wback, fixedaddress); \ + ed = hint; \ + } //GETEWW will use i for ed, and can use w for wback. #define GETEWW(w, i, D) if(MODREG) { \ wback = xRAX+(nextop&7)+(rex.b<<3);\ @@ -173,22 +199,39 @@ #define MARKLOCK dyn->insts[ninst].marklock = dyn->native_size #define GETMARKLOCK dyn->insts[ninst].marklock +#define Bxx_gen(OP, M, reg1, reg2) \ + j64 = GET##M - dyn->native_size; \ + B##OP (reg1, reg2, j64) + // Branch to MARK if reg1==reg2 (use j64) -#define BEQ_MARK(reg1, reg2) \ - j64 = GETMARK-(dyn->native_size); \ - BEQ(reg1, reg2, j64) +#define BEQ_MARK(reg1, reg2) Bxx_gen(EQ, MARK, reg1, reg2) // Branch to MARK if reg1!=reg2 (use j64) -#define BNE_MARK(reg1, reg2) \ - j64 = GETMARK-(dyn->native_size); \ - BNE(reg1, reg2, j64) +#define BNE_MARK(reg1, reg2) Bxx_gen(NE, MARK, reg1, reg2) +// Branch to MARK if reg1<reg2 (use j64) +#define BLT_MARK(reg1, reg2) Bxx_gen(LT, MARK, reg1, reg2) +// Branch to MARK2 if reg1==reg2 (use j64) +#define BEQ_MARK2(reg1, reg2) Bxx_gen(EQ, MARK2, reg1,reg2) +// Branch to MARK2 if reg1!=reg2 (use j64) +#define BNE_MARK2(reg1, reg2) Bxx_gen(NE, MARK2, reg1,reg2) +// Branch to MARK2 if reg1<>reg2 (use j64) +#define BLT_MARK2(reg1, reg2) Bxx_gen(LT, MARK2, reg1,reg2) +// Branch to MARK3 if reg1==reg2 (use j64) +#define BEQ_MARK3(reg1, reg2) Bxx_gen(EQ, MARK3, reg1, reg2) +// Branch to MARK3 if reg1!=reg2 (use j64) +#define BNE_MARK3(reg1, reg2) Bxx_gen(NE, MARK3, reg1, reg2) + // Branch to NEXT if reg1==0 (use j64) -#define CBZ_NEXT(reg1) \ +#define CBZ_NEXT(reg1) \ j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0; \ BEQ(reg1, xZR, j64) // Branch to NEXT if reg1!=0 (use j64) -#define CBNZ_NEXT(reg1) \ +#define CBNZ_NEXT(reg1) \ j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0; \ BNE(reg1, xZR, j64) +// Branch to next instruction unconditionnal (use j64) +#define B_NEXT_nocond \ + j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;\ + B(j64) #define IFX(A) if((dyn->insts[ninst].x64.gen_flags&(A))) #define IFX_PENDOR0 if((dyn->insts[ninst].x64.gen_flags&(X_PEND) || !dyn->insts[ninst].x64.gen_flags)) @@ -439,6 +482,7 @@ void* rv64_next(x64emu_t* emu, uintptr_t addr); #define emit_test8 STEPNAME(emit_test8) #define emit_test16 STEPNAME(emit_test16) #define emit_test32 STEPNAME(emit_test32) +#define emit_test32c STEPNAME(emit_test32) #define emit_add32 STEPNAME(emit_add32) #define emit_add32c STEPNAME(emit_add32c) #define emit_add8 STEPNAME(emit_add8) @@ -568,6 +612,7 @@ void emit_cmp32_0(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s3, int //void emit_test8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); //void emit_test16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_test32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); +void emit_test32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5); void emit_add32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5); //void emit_add8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h index 7f13eb10..a7528827 100644 --- a/src/dynarec/rv64/rv64_emitter.h +++ b/src/dynarec/rv64/rv64_emitter.h @@ -293,14 +293,35 @@ f28–31 ft8–11 FP temporaries Caller #define SRAIxw(rd, rs1, imm) if (rex.w) { SRAI(rd, rs1, imm); } else { SRAIW(rd, rs1, imm); } // RV32M -// rd = rs1 * rs2 +// rd =(lower) rs1 * rs2 (both signed) #define MUL(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b000, rd, 0b0110011)) +// rd =(upper) rs1 * rs2 (both signed) #define MULH(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b001, rd, 0b0110011)) +// rd =(upper) (signed)rs1 * (unsigned)rs2 +#define MULHSU(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b010, rd, 0b0110011)) +// rd =(upper) rs1 * rs2 (both unsigned) +#define MULHU(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b011, rd, 0b0110011)) +// rd =(upper) rs1 / rs2 +#define DIV(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b100, rd, 0b0110011)) +#define DIVU(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b101, rd, 0b0110011)) +// rd = rs1 mod rs2 +#define REM(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b110, rd, 0b0110011)) +#define REMU(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b111, rd, 0b0110011)) // RV64M // rd = rs1 * rs2 #define MULW(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b000, rd, 0b0111011)) // rd = rs1 * rs2 #define MULxw(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b000, rd, rex.w?0b0110011:0b0111011)) +// rd = rs1 / rs2 +#define DIVW(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b100, rd, 0b0111011)) +#define DIVxw(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b100, rd, rex.w?0b0110011:0b0111011)) +#define DIVUW(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b101, rd, 0b0111011)) +#define DIVUxw(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b101, rd, rex.w?0b0110011:0b0111011)) +// rd = rs1 mod rs2 +#define REMW(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b110, rd, 0b0111011)) +#define REMxw(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b110, rd, rex.w?0b0110011:0b0111011)) +#define REMUW(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b111, rd, 0b0111011)) +#define REMUxw(rd, rs1, rs2) EMIT(R_type(0b0000001, rs2, rs1, 0b111, rd, rex.w?0b0110011:0b0111011)) #endif //__RV64_EMITTER_H__ |