diff options
| author | Yang Liu <liuyang22@iscas.ac.cn> | 2023-03-13 17:32:29 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-13 10:32:29 +0100 |
| commit | 170ab57f55fc6bdf9138554459fa1606d95bf153 (patch) | |
| tree | 4851db4e04dfbaa1d65f468bc8adc2b12ce5d2d9 /src | |
| parent | 874054f3bbf7289b858d66be0453ff1220d05382 (diff) | |
| download | box64-170ab57f55fc6bdf9138554459fa1606d95bf153.tar.gz box64-170ab57f55fc6bdf9138554459fa1606d95bf153.zip | |
[RV64_DYNAREC] Added (81/83) SUB opcode (#554)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00.c | 17 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_math.c | 131 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 2 |
3 files changed, 108 insertions, 42 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c index 0094f1ff..489d870e 100644 --- a/src/dynarec/rv64/dynarec_rv64_00.c +++ b/src/dynarec/rv64/dynarec_rv64_00.c @@ -76,6 +76,23 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni SUBI(xRSP, xRSP, 8); break; + case 0x81: + case 0x83: + nextop = F8; + switch((nextop>>3)&7) { + case 5: + if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETED((opcode==0x81)?4:1); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + emit_sub32c(dyn, ninst, rex, ed, i64, x2, x3, x4, x5); + WBACK; + break; + default: + DEFAULT; + } + break; + case 0x89: INST_NAME("MOV Ed, Gd"); nextop=F8; diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c index 1c11a515..ca8b4349 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_math.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c @@ -23,10 +23,57 @@ #include "dynarec_rv64_functions.h" #include "dynarec_rv64_helper.h" +#define CALC_SUB_FLAGS() \ + IFX(X_PEND) { \ + SDxw(s1, xEmu, offsetof(x64emu_t, res)); \ + } \ + \ + IFX(X_AF | X_CF | X_OF) { \ + /* calc borrow chain */ \ + /* bc = (res & (~op1 | op2)) | (~op1 & op2) */ \ + OR(s3, s5, s2); \ + AND(s4, s1, s3); \ + AND(s5, s5, s2); \ + OR(s4, s4, s5); \ + IFX(X_AF) { \ + /* af = bc & 0x8 */ \ + ANDI(s3, s4, 8); \ + BEQZ(s3, 4); \ + ORI(xFlags, xFlags, 1 << F_AF); \ + } \ + IFX(X_CF) { \ + /* cf = bc & (rex.w?(1<<63):(1<<31)) */ \ + SRLI(s3, s4, rex.w?63:31); \ + BEQZ(s3, 4); \ + ORI(xFlags, xFlags, 1 << F_CF); \ + } \ + IFX(X_OF) { \ + /* of = ((bc >> rex.w?62:30) ^ (bc >> rex.w?63:31)) & 0x1; */ \ + SRLI(s3, s4, rex.w?62:30); \ + SRLI(s4, s3, 1); \ + XOR(s3, s3, s4); \ + ANDI(s3, s3, 1); \ + BEQZ(s3, 4); \ + ORI(xFlags, xFlags, 1 << F_OF); \ + } \ + } \ + IFX(X_ZF) { \ + BEQZ(s1, 4); \ + ORI(xFlags, xFlags, 1 << F_ZF); \ + } \ + IFX(X_SF) { \ + SRLI(s3, s1, rex.w?63:31); \ + BEQZ(s3, 4); \ + ORI(xFlags, xFlags, 1 << F_SF); \ + } \ + IFX(X_PF) { \ + emit_pf(dyn, ninst, s1, s3, s4); \ + } \ + // emit SUB32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5) { - CLEAR_FLAGS() + CLEAR_FLAGS(); IFX(X_PEND) { SDxw(s1, xEmu, offsetof(x64emu_t, op1)); SDxw(s2, xEmu, offsetof(x64emu_t, op2)); @@ -35,56 +82,58 @@ void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s SET_DFNONE(s3); } - IFX(X_AF) { - // for later borrow chain calculation + IFX(X_AF | X_CF | X_OF) { + // for later flag calculation NOT(s5, s1); } SUBxw(s1, s1, s2); + CALC_SUB_FLAGS(); +} + + +// emit SUB32 instruction, from s1, constant c, store result in s1 using s2, s3, s4 and s5 as scratch +void emit_sub32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5) +{ + CLEAR_FLAGS(); + if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND)) + { + // special case when doing math on RSP and only PEND is needed: ignoring it! + if (c > -2048 && c <= 2048) { + ADDI(s1, s1, -c); + } else { + MOV64x(s2, c); + SUBxw(s1, s1, s2); + } + return; + } IFX(X_PEND) { - SDxw(s1, xEmu, offsetof(x64emu_t, res)); + SDxw(s1, xEmu, offsetof(x64emu_t, op1)); + MOV64x(s2, c); + SDxw(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s3, rex.w?d_sub64:d_sub32); + } else IFX(X_ALL) { + SET_DFNONE(s3); } IFX(X_AF | X_CF | X_OF) { - // calc borrow chain - // bc = (res & (~op1 | op2)) | (~op1 & op2) - OR(s3, s5, s2); - AND(s4, s1, s3); - AND(s5, s5, s2); - OR(s4, s4, s5); - IFX(X_AF) { - // af = bc & 0x8 - ANDI(s3, s4, 8); - BEQZ(s3, 4); - ORI(xFlags, xFlags, 1 << F_AF); - } - IFX(X_CF) { - // cf = bc & (rex.w?(1<<63):(1<<31)) - SRLI(s3, s4, rex.w?63:31); - BEQZ(s3, 4); - ORI(xFlags, xFlags, 1 << F_CF); - } - IFX(X_OF) { - // of = ((bc >> rex.w?62:30) ^ (bc >> rex.w?63:31)) & 0x1; - SRLI(s3, s4, rex.w?62:30); - SRLI(s4, s3, 1); - XOR(s3, s3, s4); - ANDI(s3, s3, 1); - BEQZ(s3, 4); - ORI(xFlags, xFlags, 1 << F_OF); - } - } - IFX(X_ZF) { - BEQZ(s1, 4); - ORI(xFlags, xFlags, 1 << F_ZF); + // for later flag calculation + NOT(s5, s1); } - IFX(X_SF) { - SRLI(s3, s1, rex.w?63:31); - BEQZ(s3, 4); - ORI(xFlags, xFlags, 1 << F_SF); + + if (c > -2048 && c <= 2048) { + ADDI(s1, s1, -c); + } else { + IFX(X_PEND) {} else {MOV64x(s2, c);} + SUBxw(s1, s1, s2); } - IFX(X_PF) { - emit_pf(dyn, ninst, s1, s3, s4); + + IFX(X_AF | X_CF | X_OF) { + IFX(X_PEND) {} + else if (c > -2048 && c <= 2048) { + MOV64x(s2, c); + } } + CALC_SUB_FLAGS(); } diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index 3b347d77..53702fab 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -342,7 +342,7 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst); //void emit_add8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_add8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); -//void emit_sub32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5); +void emit_sub32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5); //void emit_sub8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_sub8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5); //void emit_or32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); |