diff options
| author | Leslie Zhai <zhaixiang@loongson.cn> | 2024-11-25 15:12:20 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-25 08:12:20 +0100 |
| commit | c30a392fe863aca59a6be34c03c0fa226b576de8 (patch) | |
| tree | 7f83b5b133b23def9c1e46216877e18bd1f3ed52 | |
| parent | d8c16de2ec48fe699d8ba17e2730f473b12d69bb (diff) | |
| download | box64-c30a392fe863aca59a6be34c03c0fa226b576de8.tar.gz box64-c30a392fe863aca59a6be34c03c0fa226b576de8.zip | |
[LA64_DYNAREC] Add adc8, adc8c, adc16 and testadc (#2069)
* [LA64_DYNAREC] Add adc8, adc8c, adc16 and testadc * [LA64_DYNAREC] Add missing testcase * [LA64_DYNAREC] Change ANDI+OR to BSTRINS_D for ADC AL, Ib and removed testadc * [LA64_DYNAREC] clang-format
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 46 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_64.c | 10 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_66.c | 47 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_math.c | 159 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_f0.c | 25 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 6 |
6 files changed, 293 insertions, 0 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index 9f618456..c1ac8fa0 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -167,6 +167,16 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + case 0x10: + INST_NAME("ADC Eb, Gb"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETEB(x1, 0); + GETGB(x2); + emit_adc8(dyn, ninst, x1, x2, x4, x5, x6); + EBBACK(); + break; case 0x11: INST_NAME("ADC Ed, Gd"); READFLAGS(X_CF); @@ -177,6 +187,16 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_adc32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6); WBACK; break; + case 0x12: + INST_NAME("ADC Gb, Eb"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETEB(x2, 0); + GETGB(x1); + emit_adc8(dyn, ninst, x1, x2, x4, x6, x5); + GBBACK(); + break; case 0x13: INST_NAME("ADC Gd, Ed"); READFLAGS(X_CF); @@ -186,6 +206,23 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni GETED(0); emit_adc32(dyn, ninst, rex, gd, ed, x3, x4, x5, x6); break; + case 0x14: + INST_NAME("ADC AL, Ib"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + u8 = F8; + ANDI(x1, xRAX, 0xff); + emit_adc8c(dyn, ninst, x1, u8, x3, x4, x5, x6); + BSTRINS_D(xRAX, x1, 7, 0); + break; + case 0x15: + INST_NAME("ADC EAX, Id"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + i64 = F32S; + MOV64xw(x1, i64); + emit_adc32(dyn, ninst, rex, xRAX, x1, x3, x4, x5, x6); + break; case 0x18: INST_NAME("SBB Eb, Gb"); READFLAGS(X_CF); @@ -666,6 +703,15 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_or8c(dyn, ninst, x1, u8, x2, x4, x5); EBBACK(); break; + case 2: // ADC + INST_NAME("ADC Eb, Ib"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEB(x1, 1); + u8 = F8; + emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5, x6); + EBBACK(); + break; case 3: // SBB INST_NAME("SBB Eb, Ib"); READFLAGS(X_CF); diff --git a/src/dynarec/la64/dynarec_la64_64.c b/src/dynarec/la64/dynarec_la64_64.c index fb10e453..55f834b7 100644 --- a/src/dynarec/la64/dynarec_la64_64.c +++ b/src/dynarec/la64/dynarec_la64_64.c @@ -118,6 +118,16 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_or8c(dyn, ninst, x1, u8, x2, x4, x5); EBBACK(); break; + case 2: // ADC + INST_NAME("ADC Eb, Ib"); + grab_segdata(dyn, addr, ninst, x1, seg); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEBO(x1, 1); + u8 = F8; + emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5, x6); + EBBACK(); + break; case 3: // SBB INST_NAME("SBB Eb, Ib"); grab_segdata(dyn, addr, ninst, x1, seg); diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c index bfe64ef1..d720b4cf 100644 --- a/src/dynarec/la64/dynarec_la64_66.c +++ b/src/dynarec/la64/dynarec_la64_66.c @@ -119,6 +119,36 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + case 0x11: + INST_NAME("ADC Ew, Gw"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETGW(x2); + GETEW(x1, 0); + emit_adc16(dyn, ninst, x1, x2, x4, x6, x5); + EWBACK; + break; + case 0x13: + INST_NAME("ADC Gw, Ew"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETGW(x1); + GETEW(x2, 0); + emit_adc16(dyn, ninst, x1, x2, x4, x6, x5); + GWBACK; + break; + case 0x15: + INST_NAME("ADC AX, Iw"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + u64 = F16; + BSTRPICK_D(x1, xRAX, 15, 0); + MOV64x(x2, u64); + emit_adc16(dyn, ninst, x1, x2, x3, x4, x5); + BSTRINSz(xRAX, x1, 15, 0); + break; case 0x19: INST_NAME("SBB Ew, Gw"); READFLAGS(X_CF); @@ -295,6 +325,23 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_or16(dyn, ninst, x1, x5, x2, x4); EWBACK; break; + case 2: // ADC + if (opcode == 0x81) { + INST_NAME("ADC Ew, Iw"); + } else { + INST_NAME("ADC Ew, Ib"); + } + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEW(x1, (opcode == 0x81) ? 2 : 1); + if (opcode == 0x81) + u64 = F16; + else + u64 = (uint16_t)(int16_t)F8S; + MOV64x(x5, u64); + emit_adc16(dyn, ninst, x1, x5, x2, x4, x6); + EWBACK; + break; case 4: // AND if (opcode == 0x81) { INST_NAME("AND Ew, Iw"); diff --git a/src/dynarec/la64/dynarec_la64_emit_math.c b/src/dynarec/la64/dynarec_la64_emit_math.c index aa8f6a13..56c38b8d 100644 --- a/src/dynarec/la64/dynarec_la64_emit_math.c +++ b/src/dynarec/la64/dynarec_la64_emit_math.c @@ -1029,6 +1029,165 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s } } +// emit ADC8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch +void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5) +{ + IFX (X_PEND) { + ST_H(s1, xEmu, offsetof(x64emu_t, op1)); + ST_H(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s3, d_adc8); + } else IFX (X_ALL) { + SET_DFNONE(); + } + + if (la64_lbt) { + ADC_B(s3, s1, s2); + + IFX (X_ALL) { + X64_ADC_B(s1, s2); + } + MV(s1, s3); + IFX (X_PEND) { + ST_W(s1, xEmu, offsetof(x64emu_t, res)); + } + return; + } + + IFX (X_AF | X_OF) { + OR(s4, s1, s2); // s4 = op1 | op2 + AND(s5, s1, s2); // s5 = op1 & op2 + } + + ADD_D(s1, s1, s2); + ANDI(s3, xFlags, 1 << F_CF); + ADD_D(s1, s1, s3); + + CLEAR_FLAGS(s3); + IFX (X_PEND) { + ST_W(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX (X_AF | X_OF) { + ANDN(s3, s4, s1); // s3 = ~res & (op1 | op2) + OR(s3, s3, s5); // cc = (~res & (op1 | op2)) | (op1 & op2) + IFX (X_AF) { + ANDI(s4, s3, 0x08); // AF: cc & 0x08 + BEQZ(s4, 8); + ORI(xFlags, xFlags, 1 << F_AF); + } + IFX (X_OF) { + SRLI_D(s3, s3, 6); + SRLI_D(s4, s3, 1); + XOR(s3, s3, s4); + ANDI(s3, s3, 1); // OF: xor of two MSB's of cc + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_OF); + } + } + IFX (X_CF) { + SRLI_D(s3, s1, 8); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_CF); + } + + ANDI(s1, s1, 0xff); + + IFX (X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX (X_SF) { + SRLI_D(s3, s1, 7); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + IFX (X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } +} + +// emit ADC8 instruction, from s1, const c, store result in s1 using s3, s4, s5 and s6 as scratch +void emit_adc8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6) +{ + MOV32w(s5, c & 0xff); + emit_adc8(dyn, ninst, s1, s5, s3, s4, s6); +} + +// emit ADC16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch +void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5) +{ + IFX (X_PEND) { + ST_H(s1, xEmu, offsetof(x64emu_t, op1)); + ST_H(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s3, d_adc16); + } else IFX (X_ALL) { + SET_DFNONE(); + } + + if (la64_lbt) { + ADC_H(s3, s1, s2); + + IFX (X_ALL) { + X64_ADC_H(s1, s2); + } + MV(s1, s3); + IFX (X_PEND) { + ST_W(s1, xEmu, offsetof(x64emu_t, res)); + } + return; + } + + IFX (X_AF | X_OF) { + OR(s4, s1, s2); // s4 = op1 | op2 + AND(s5, s1, s2); // s5 = op1 & op2 + } + + ADD_D(s1, s1, s2); + ANDI(s3, xFlags, 1 << F_CF); + ADD_D(s1, s1, s3); + + CLEAR_FLAGS(s3); + IFX (X_PEND) { + ST_W(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX (X_AF | X_OF) { + ANDN(s3, s4, s1); // s3 = ~res & (op1 | op2) + OR(s3, s3, s5); // cc = (~res & (op1 | op2)) | (op1 & op2) + IFX (X_AF) { + ANDI(s4, s3, 0x08); // AF: cc & 0x08 + BEQZ(s4, 8); + ORI(xFlags, xFlags, 1 << F_AF); + } + IFX (X_OF) { + SRLI_D(s3, s3, 14); + SRLI_D(s4, s3, 1); + XOR(s3, s3, s4); + ANDI(s3, s3, 1); // OF: xor of two MSB's of cc + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_OF); + } + } + IFX (X_CF) { + SRLI_D(s3, s1, 16); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_CF); + } + + BSTRPICK_D(s1, s1, 15, 0); + + IFX (X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX (X_SF) { + SRLI_D(s3, s1, 15); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + IFX (X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } +} + // emit ADC32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6) { diff --git a/src/dynarec/la64/dynarec_la64_f0.c b/src/dynarec/la64/dynarec_la64_f0.c index 22457c0d..c92e9406 100644 --- a/src/dynarec/la64/dynarec_la64_f0.c +++ b/src/dynarec/la64/dynarec_la64_f0.c @@ -402,6 +402,31 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + case 0x11: + INST_NAME("LOCK ADC Ed, Gd"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETGD; + SMDMB(); + if (MODREG) { + ed = xRAX + (nextop & 7) + (rex.b << 3); + emit_adc32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6); + } else { + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0); + MARKLOCK; + LLxw(x1, wback, 0); + ADDxw(x3, x1, gd); + ANDI(x4, xFlags, 1 << F_CF); + ADDxw(x3, x3, x4); + SCxw(x3, wback, 0); + BEQZ_MARKLOCK(x3); + IFX (X_ALL | X_PEND) { + emit_adc32(dyn, ninst, rex, x1, gd, x3, x4, x5, x6); + } + } + SMDMB(); + break; case 0x29: INST_NAME("LOCK SUB Ed, Gd"); SETFLAGS(X_ALL, SF_SET_PENDING); diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index b6069c61..12ebe679 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -801,6 +801,9 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define emit_add8c STEPNAME(emit_add8c) #define emit_add16 STEPNAME(emit_add16) #define emit_adc32 STEPNAME(emit_adc32) +#define emit_adc8 STEPNAME(emit_adc8) +#define emit_adc8c STEPNAME(emit_adc8c) +#define emit_adc16 STEPNAME(emit_adc16) #define emit_sub16 STEPNAME(emit_sub16) #define emit_sub32 STEPNAME(emit_sub32) #define emit_sub32c STEPNAME(emit_sub32c) @@ -903,6 +906,9 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4); void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4); void emit_add16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6); +void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); +void emit_adc8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6); +void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_sub16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5); |