diff options
| author | Yang Liu <liuyang22@iscas.ac.cn> | 2023-03-24 03:25:22 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-23 20:25:22 +0100 |
| commit | dcc1a5db5274c2f23a342c5c8d4fe26e51723cb9 (patch) | |
| tree | 45366d29467d3548f8550a90554a36a3129d70d2 | |
| parent | 46ed52032dff341c0891105849e64b4273151bff (diff) | |
| download | box64-dcc1a5db5274c2f23a342c5c8d4fe26e51723cb9.tar.gz box64-dcc1a5db5274c2f23a342c5c8d4fe26e51723cb9.zip | |
[RV64_DYNAREC] Added more opcodes (#629)
* [RV64_DYNAREC] Added 66 83 /5 SUB opcode * [RV64_DYNAREC] Added 2D SUB opcode * [RV64_DYNAREC] Added F7 /3 NEG opcode * [RV64_DYNAREC] Added 66 2D SUB opcode * Fixed a typo * [RV64_DYNAREC] Added 66 0D OR opcode * [RV64_DYNAREC] Added 66 81,83 /4 AND opcode * [RV64_DYNAREC] Added 66 F7 /0,1 TEST opcode * [RV64_DYNAREC] Added 80 /1 OR opcode and fixed some potential issues
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00.c | 50 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_66.c | 56 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_logic.c | 7 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_math.c | 92 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 6 |
5 files changed, 187 insertions, 24 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c index b4b794fb..89b4305c 100644 --- a/src/dynarec/rv64/dynarec_rv64_00.c +++ b/src/dynarec/rv64/dynarec_rv64_00.c @@ -93,9 +93,9 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni INST_NAME("OR Gb, Eb"); SETFLAGS(X_ALL, SF_SET_PENDING); nextop = F8; - GETEB(x2, 0); + GETEB(x3, 0); GETGB(x1); - emit_or8(dyn, ninst, x1, x2, x3, x4); + emit_or8(dyn, ninst, x1, x3, x4, x5); GBBACK(x5); break; case 0x0B: @@ -151,9 +151,9 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni INST_NAME("AND Gb, Eb"); SETFLAGS(X_ALL, SF_SET_PENDING); nextop = F8; - GETEB(x2, 0); + GETEB(x3, 0); GETGB(x1); - emit_and8(dyn, ninst, x1, x2, x3, x4); + emit_and8(dyn, ninst, x1, x3, x4, x5); GBBACK(x5); break; case 0x23: @@ -197,6 +197,12 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni ANDI(xRAX, xRAX, ~0xff); OR(xRAX, xRAX, x1); break; + case 0x2D: + INST_NAME("SUB EAX, Id"); + SETFLAGS(X_ALL, SF_SET_PENDING); + i64 = F32S; + emit_sub32c(dyn, ninst, rex, xRAX, i64, x2, x3, x4, x5); + break; case 0x31: INST_NAME("XOR Ed, Gd"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -441,12 +447,20 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0x80: nextop = F8; switch((nextop>>3)&7) { - case 0: //ADD + case 0: // ADD INST_NAME("ADD Eb, Ib"); SETFLAGS(X_ALL, SF_SET_PENDING); GETEB(x1, 1); u8 = F8; - emit_add8c(dyn, ninst, x1, u8, x2, x4, x5); + emit_add8c(dyn, ninst, x1, u8, x3, x4, x5); + EBBACK(x3); + break; + case 1: // OR + INST_NAME("OR Eb, Ib"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEB(x1, 1); + u8 = F8; + emit_or8c(dyn, ninst, x1, u8, x3, x4, x5); EBBACK(x3); break; case 3: // SBB @@ -471,7 +485,7 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni SETFLAGS(X_ALL, SF_SET_PENDING); GETEB(x1, 1); u8 = F8; - emit_sub8c(dyn, ninst, x1, u8, x2, x3, x4, x5); + emit_sub8c(dyn, ninst, x1, u8, x3, x4, x5, x6); EBBACK(x3); break; case 7: // CMP @@ -1069,15 +1083,15 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 5: if(opcode==0xD0) { INST_NAME("SHR Eb, 1"); - MOV32w(x2, 1); + MOV32w(x4, 1); } else { INST_NAME("SHR Eb, CL"); - ANDI(x2, xRCX, 0x1F); + ANDI(x4, xRCX, 0x1F); } SETFLAGS(X_ALL, SF_PENDING); GETEB(x1, 0); - UFLAG_OP12(ed, x2); - SRLW(ed, ed, x2); + UFLAG_OP12(ed, x4); + SRLW(ed, ed, x4); EBBACK(x3); UFLAG_RES(ed); UFLAG_DF(x3, d_shr8); @@ -1085,15 +1099,15 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 7: if(opcode==0xD0) { INST_NAME("SAR Eb, 1"); - MOV32w(x2, 1); + MOV32w(x4, 1); } else { INST_NAME("SAR Eb, CL"); - ANDI(x2, xRCX, 0x1f); + ANDI(x4, xRCX, 0x1f); } SETFLAGS(X_ALL, SF_PENDING); GETSEB(x1, 0); - UFLAG_OP12(ed, x2) - SRA(ed, ed, x2); + UFLAG_OP12(ed, x4) + SRA(ed, ed, x4); EBBACK(x3); UFLAG_RES(ed); UFLAG_DF(x3, d_sar8); @@ -1368,13 +1382,13 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni ZEROUP(ed); WBACK; break; - /*case 3: + case 3: INST_NAME("NEG Ed"); SETFLAGS(X_ALL, SF_SET_PENDING); GETED(0); - emit_neg32(dyn, ninst, rex, ed, x3, x4); + emit_neg32(dyn, ninst, rex, ed, x3, x4, x5); WBACK; - break;*/ + break; case 4: INST_NAME("MUL EAX, Ed"); SETFLAGS(X_ALL, SF_PENDING); diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c index 222cb60c..2a6f8ad1 100644 --- a/src/dynarec/rv64/dynarec_rv64_66.c +++ b/src/dynarec/rv64/dynarec_rv64_66.c @@ -61,7 +61,18 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog); // addr-1, to "put back" opcode switch(opcode) { - + case 0x0D: + INST_NAME("OR AX, Iw"); + SETFLAGS(X_ALL, SF_SET_PENDING); + i32 = F16; + SLLI(x1, xRAX, 48); + SRLI(x1, x1, 48); + MOV32w(x2, i32); + emit_or16(dyn, ninst, x1, x2, x3, x4); + LUI(x3, 0xfff0); + AND(xRAX, xRAX, x3); + OR(xRAX, xRAX, x1); + break; case 0x0F: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break; @@ -86,6 +97,18 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni AND(xRAX, xRAX, x3); OR(xRAX, xRAX, x1); break; + case 0x2D: + INST_NAME("SUB AX, Iw"); + SETFLAGS(X_ALL, SF_SET_PENDING); + i32 = F16; + SLLI(x1, xRAX, 48); + SRLI(x1, x1, 48); + MOV32w(x2, i32); + emit_sub16(dyn, ninst, x1, x2, x3, x4, x5); + LUI(x2, 0xffff0); + AND(xRAX, xRAX, x2); + OR(xRAX, xRAX, x1); + break; case 0x3D: INST_NAME("CMP AX, Iw"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -122,7 +145,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0x83: nextop = F8; switch((nextop>>3)&7) { - case 0: //ADD + case 0: // ADD if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");} SETFLAGS(X_ALL, SF_SET_PENDING); GETEW(x1, (opcode==0x81)?2:1); @@ -140,7 +163,25 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_or16(dyn, ninst, x1, x5, x2, x4); EWBACK; break; - case 7: //CMP + case 4: // AND + if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEW(x1, (opcode==0x81)?2:1); + if(opcode==0x81) i16 = F16S; else i16 = F8S; + MOV64x(x5, i16); + emit_and16(dyn, ninst, x1, x5, x2, x4); + EWBACK; + break; + case 5: // SUB + if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEW(x1, (opcode==0x81)?2:1); + if(opcode==0x81) i16 = F16S; else i16 = F8S; + MOV32w(x5, i16); + emit_sub16(dyn, ninst, x1, x5, x2, x4, x5); + EWBACK; + break; + case 7: // CMP if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");} SETFLAGS(X_ALL, SF_SET_PENDING); GETEW(x1, (opcode==0x81)?2:1); @@ -343,6 +384,15 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0xF7: nextop = F8; switch((nextop>>3)&7) { + case 0: + case 1: + INST_NAME("TEST Ew, Iw"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEW(x1, 2); + u16 = F16; + MOV32w(x2, u16); + emit_test16(dyn, ninst, x1, x2, x3, x4, x5); + break; case 6: INST_NAME("DIV Ew"); SETFLAGS(X_ALL, SF_SET); diff --git a/src/dynarec/rv64/dynarec_rv64_emit_logic.c b/src/dynarec/rv64/dynarec_rv64_emit_logic.c index 0e928939..c3f09ea4 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_logic.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_logic.c @@ -381,3 +381,10 @@ void emit_or8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4) emit_pf(dyn, ninst, s1, s3, s4); } } + +// emit OR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch +void emit_or8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4) +{ + MOV32w(s2, c&0xff); + emit_or8(dyn, ninst, s1, s2, s3, s4); +} diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c index 74349328..d1cfaddb 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_math.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c @@ -354,6 +354,45 @@ void emit_sub8c(dynarec_rv64_t* dyn, int ninst, int s1, int c, int s2, int s3, i } } +// emit SUB16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch +void emit_sub16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5) +{ + CLEAR_FLAGS(); + IFX(X_PEND) { + SH(s1, xEmu, offsetof(x64emu_t, op1)); + SH(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s3, d_sub16); + } else IFX(X_ALL) { + SET_DFNONE(); + } + + IFX(X_AF | X_CF | X_OF) { + // for later flag calculation + NOT(s5, s1); + } + + SUBW(s1, s1, s2); + IFX(X_PEND) { + SH(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_SF) { + BGE(s1, xZR, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + SLLI(s1, s1, 48); + SRLI(s1, s1, 48); + + CALC_SUB_FLAGS(s5, s2, s1, s3, s4, 16); + IFX(X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + 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) { @@ -601,3 +640,56 @@ void emit_sbb32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s emit_pf(dyn, ninst, s1, s3, s4); } } + +// emit NEG32 instruction, from s1, store result in s1 using s2, s3 and s4 as scratch +void emit_neg32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4) +{ + CLEAR_FLAGS(); + IFX(X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, op1)); + SET_DF(s3, rex.w?d_neg64:d_neg32); + } else IFX(X_ALL) { + SET_DFNONE(); + } + IFX(X_AF | X_OF) { + ORI(s3, s1, 1); // s3 = op1 | op2 + ANDI(s4, s1, 1); // s4 = op1 & op2 + } + + NEG(s1, s1); + IFX(X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_AF | X_OF) { + NOT(s2, s1); // s2 = ~res + AND(s3, s2, s3); // s3 = ~res & (op1 | op2) + OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2) + IFX(X_AF) { + ANDI(s2, s3, 0x08); // AF: cc & 0x08 + BEQZ(s2, 8); + ORI(xFlags, xFlags, 1 << F_AF); + } + IFX(X_OF) { + SRLI(s3, s3, rex.w?62:30); + SRLI(s2, s3, 1); + XOR(s3, s3, s2); + ANDI(s3, s3, 1); // OF: xor of two MSB's of cc + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_OF2); + } + } + IFX(X_SF) { + BGE(s1, xZR, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + if (!rex.w) { + ZEROUP(s1); + } + IFX(X_PF) { + emit_pf(dyn, ninst, s1, s3, s2); + } + IFX(X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } +} diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index 60ab271b..d0f0b41d 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -781,14 +781,14 @@ void emit_xor32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i void emit_and32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); void emit_and32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4); void emit_or8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); -//void emit_or8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); +void emit_or8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4); //void emit_xor8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_xor8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); void emit_and8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); void emit_and8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); void emit_add16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_add16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); -//void emit_sub16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); +void emit_sub16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); //void emit_sub16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); void emit_or16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_or16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); @@ -814,7 +814,7 @@ void emit_sbb8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i void emit_sbb8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6); //void emit_sbb16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_sbb16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); -//void emit_neg32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4); +void emit_neg32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); //void emit_neg16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4); //void emit_neg8(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4); void emit_shl32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); |