about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorphorcys <phorcys@126.com>2025-04-24 17:28:42 +0800
committerGitHub <noreply@github.com>2025-04-24 11:28:42 +0200
commit7158405b7326f9817db3c2b75f2ea863450732a5 (patch)
treebd019be0019ab3b61f41f9c9a43159ca0534d26a /src
parente059506d5e4a90a216094787f396f8ce058e7c21 (diff)
downloadbox64-7158405b7326f9817db3c2b75f2ea863450732a5.tar.gz
box64-7158405b7326f9817db3c2b75f2ea863450732a5.zip
[LA64_DYNAREC] Add POPCNT/TZCNT/LZCNT ops. (#2566)
66.f3.0f.b8/bc/bd POPCNT/TZCNT/LZCNT 16bits ops
f3.0f.bd LZCNT
fix f3.0f.bc TZCNT (GETED/RESTORE_EFLAGS x1 conflict)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_66.c1
-rw-r--r--src/dynarec/la64/dynarec_la64_66f30f.c125
-rw-r--r--src/dynarec/la64/dynarec_la64_f30f.c42
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h2
-rw-r--r--src/dynarec/la64/la64_emitter.h8
5 files changed, 170 insertions, 8 deletions
diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c
index c075f3c1..ce5a1845 100644
--- a/src/dynarec/la64/dynarec_la64_66.c
+++ b/src/dynarec/la64/dynarec_la64_66.c
@@ -114,6 +114,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             switch (rep) {
                 case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
                 case 1: addr = dynarec64_66F20F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
+                case 2: addr = dynarec64_66F30F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;                
                 default:
                     DEFAULT;
             }
diff --git a/src/dynarec/la64/dynarec_la64_66f30f.c b/src/dynarec/la64/dynarec_la64_66f30f.c
new file mode 100644
index 00000000..4d46c8ba
--- /dev/null
+++ b/src/dynarec/la64/dynarec_la64_66f30f.c
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "box64cpu.h"
+#include "emu/x64emu_private.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+
+#include "la64_printer.h"
+#include "dynarec_la64_private.h"
+#include "dynarec_la64_functions.h"
+#include "../dynarec_helper.h"
+
+uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
+{
+    (void)ip;
+    (void)need_epilog;
+
+    uint8_t opcode = F8;
+    uint8_t nextop, u8, s8;
+    int32_t i32;
+    uint8_t gd, ed;
+    uint8_t wback, wb1, wb2, gback;
+    uint8_t eb1, eb2;
+    int64_t j64;
+    uint64_t tmp64u, tmp64u2;
+    int v0, v1;
+    int q0, q1;
+    int d0, d1;
+    int64_t fixedaddress, gdoffset;
+    int unscaled;
+
+    MAYUSE(d0);
+    MAYUSE(d1);
+    MAYUSE(q0);
+    MAYUSE(q1);
+    MAYUSE(eb1);
+    MAYUSE(eb2);
+    MAYUSE(j64);
+
+    switch (opcode) {
+        case 0xB8:
+            INST_NAME("POPCNT Gw, Ew");
+            SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
+            SET_DFNONE();
+            nextop = F8;
+            GETGD;
+            GETEW(x4, 0);
+            v0 = fpu_get_scratch(dyn);
+            VINSGR2VR_H(v0, ed, 0);
+            VPCNT_H(v0, v0);
+            VPICKVE2GR_HU(gd, v0, 0);
+            IFX (X_ALL) {
+                if (la64_lbt) {
+                    X64_SET_EFLAGS(xZR, X_ALL);
+                    BNEZ_MARK(gd);
+                    ADDI_D(x5, xZR, 1 << F_ZF);
+                    X64_SET_EFLAGS(x5, X_ZF);
+                } else {
+                    CLEAR_FLAGS(x2);
+                    BNEZ_MARK(gd);
+                    ORI(xFlags, xFlags, 1 << F_ZF);
+                }
+                MARK;
+            }
+            break;
+        case 0xBC:
+            INST_NAME("TZCNT Gw, Ew");
+            SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
+            SET_DFNONE();
+            nextop = F8;
+            GETEW(x5, 0);
+            GETGD;
+            RESTORE_EFLAGS(x1);
+            /*
+                ZF is set if gd is zero, unset non-zero.
+                CF is set if ed is zero, unset non-zero.
+                OF, SF, PF, and AF flags are undefined
+            */
+            CLEAR_FLAGS(x2);
+            ADDI_D(x4, xZR, -1);
+            BSTRINS_D(x4, ed, 15, 0);
+            CTZ_W(gd, x4);
+            BNE(gd, xZR, 4 + 4);
+            ORI(xFlags, xFlags, 1 << F_ZF);
+            SRLI_W(x5, gd, 4); // maximum value is 16, F_CF = 0
+            OR(xFlags, xFlags, x5);
+            SPILL_EFLAGS();
+            break;
+        case 0xBD:
+            INST_NAME("LZCNT Gw, Ew");
+            SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
+            SET_DFNONE();
+            nextop = F8;
+            GETEW(x5, 0);
+            GETGD;
+            RESTORE_EFLAGS(x1);
+            /*
+                ZF is set if gd is zero, unset non-zero.
+                CF is set if ed is zero, unset non-zero.
+                OF, SF, PF, and AF flags are undefined
+            */
+            CLEAR_FLAGS(x2);
+            ADDI_D(x4, xZR, -1);
+            BSTRINS_D(x4, ed, 31, 16);
+            CLZ_W(gd, x4);
+            BNE(gd, xZR, 4 + 4);
+            ORI(xFlags, xFlags, 1 << F_ZF);
+            SRLI_W(x5, gd, 4); // maximum value is 16, F_CF = 0
+            OR(xFlags, xFlags, x5);
+            SPILL_EFLAGS();
+            break;
+        default:
+            DEFAULT;
+    }
+    return addr;
+}
diff --git a/src/dynarec/la64/dynarec_la64_f30f.c b/src/dynarec/la64/dynarec_la64_f30f.c
index 22078287..df53bfb3 100644
--- a/src/dynarec/la64/dynarec_la64_f30f.c
+++ b/src/dynarec/la64/dynarec_la64_f30f.c
@@ -445,17 +445,43 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
                 ZEROUP2(x4, ed);
                 ed = x4;
             }
-            RESTORE_EFLAGS(x1);
-            ANDI(xFlags, xFlags, ~((1 << F_ZF) | (1 << F_CF)));
-            BNE_MARK(ed, xZR);
-            ORI(xFlags, xFlags, 1 << F_CF);
-            MOV32w(gd, rex.w ? 64 : 32);
-            SPILL_EFLAGS();
-            B_NEXT_nocond;
-            MARK;
+            RESTORE_EFLAGS(x6);
+            /*
+                ZF is set if gd is zero, unset non-zero.
+                CF is set if ed is zero, unset non-zero.
+                OF, SF, PF, and AF flags are undefined
+            */
+            CLEAR_FLAGS(x2);
             CTZxw(gd, ed);
             BNE(gd, xZR, 4 + 4);
             ORI(xFlags, xFlags, 1 << F_ZF);
+            SRLI_W(x5, gd, rex.w ? 6 : 5); // maximum value is 64/32, F_CF = 0
+            OR(xFlags, xFlags, x5);
+            SPILL_EFLAGS();
+            break;
+        case 0xBD:
+            INST_NAME("LZCNT Gd, Ed");
+            SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
+            SET_DFNONE();
+            nextop = F8;
+            GETED(0);
+            GETGD;
+            if (!rex.w && MODREG) {
+                ZEROUP2(x4, ed);
+                ed = x4;
+            }
+            RESTORE_EFLAGS(x6);
+            /*
+                ZF is set if gd is zero, unset non-zero.
+                CF is set if ed is zero, unset non-zero.
+                OF, SF, PF, and AF flags are undefined
+            */
+            CLEAR_FLAGS(x2);
+            CLZxw(gd, ed);
+            BNE(gd, xZR, 4 + 4);
+            ORI(xFlags, xFlags, 1 << F_ZF);
+            SRLI_W(x5, gd, rex.w ? 6 : 5); // maximum value is 64/32, F_CF = 0
+            OR(xFlags, xFlags, x5);
             SPILL_EFLAGS();
             break;
         case 0xC2:
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index 105a502d..7d472bf6 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -886,6 +886,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define dynarec64_660F   STEPNAME(dynarec64_660F)
 #define dynarec64_66F0   STEPNAME(dynarec64_66F0)
 #define dynarec64_66F20F STEPNAME(dynarec64_66F20F)
+#define dynarec64_66F30F STEPNAME(dynarec64_66F30F)
 #define dynarec64_F0     STEPNAME(dynarec64_F0)
 #define dynarec64_F20F   STEPNAME(dynarec64_F20F)
 
@@ -1149,6 +1150,7 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
 uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
 uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
 uintptr_t dynarec64_66F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
+uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
 uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
 uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
 
diff --git a/src/dynarec/la64/la64_emitter.h b/src/dynarec/la64/la64_emitter.h
index 2fc43905..41a87db9 100644
--- a/src/dynarec/la64/la64_emitter.h
+++ b/src/dynarec/la64/la64_emitter.h
@@ -540,6 +540,14 @@ f24-f31  fs0-fs7   Static registers                Callee
         }                  \
     } while (0)
 
+#define CLZxw(rd, rj)      \
+    do {                   \
+        if (rex.w) {       \
+            CLZ_D(rd, rj); \
+        } else {           \
+            CLZ_W(rd, rj); \
+        }                  \
+    } while (0)
 
 // GR[rd] = SignExtend(GR[rj][7:0], GRLEN)
 #define EXT_W_B(rd, rj) EMIT(type_2R(0b0000000000000000010111, rj, rd))