about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2023-03-19 17:28:33 +0800
committerGitHub <noreply@github.com>2023-03-19 10:28:33 +0100
commite1ca614f1c777ce332253945dabc9a043057976b (patch)
tree4c832549c32324ab0a28c2ae34d17165833a1a50 /src
parent01d1ea0b90ed171c33ff18b27966fabf652f4eba (diff)
downloadbox64-e1ca614f1c777ce332253945dabc9a043057976b.tar.gz
box64-e1ca614f1c777ce332253945dabc9a043057976b.zip
[RV64_DYNAREC] Added more opcode (#591)
* [RV64_DYNAREC] Added 84 TEST opcode

* [RV64_DYNAREC] Added 64 8B MOV opcode

* [RV64_DYNAREC] Added {B4,B5,B6,B7} MOV opcode

* [RV64_DYNAREC] Added 3C CMP opcode

* [RV64_DYNAREC] Added {81,83} /1 OR opcode

* [RV64_DYNAREC] Fixed MOV opcode
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00.c45
-rw-r--r--src/dynarec/rv64/dynarec_rv64_64.c85
-rw-r--r--src/dynarec/rv64/dynarec_rv64_66.c17
-rw-r--r--src/dynarec/rv64/dynarec_rv64_emit_logic.c32
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.c25
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h29
-rw-r--r--src/dynarec/rv64/rv64_emitter.h2
7 files changed, 229 insertions, 6 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c
index 926f3d6a..6f6be07a 100644
--- a/src/dynarec/rv64/dynarec_rv64_00.c
+++ b/src/dynarec/rv64/dynarec_rv64_00.c
@@ -149,7 +149,18 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             GETED(0);
             emit_cmp32(dyn, ninst, rex, gd, ed, x3, x4, x5, x6);
             break;
-
+        case 0x3C:
+            INST_NAME("CMP AL, Ib");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            u8 = F8;
+            ANDI(x1, xRAX, 0xff);
+            if(u8) {
+                MOV32w(x2, u8);
+                emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
+            } else {
+                emit_cmp8_0(dyn, ninst, x1, x3, x4);
+            }
+            break;
         case 0x50:
         case 0x51:
         case 0x52:
@@ -201,7 +212,9 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 }
             }
             break;
-            
+        case 0x64:
+            addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
+            break;
         case 0x66:
             addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
             break;
@@ -361,7 +374,14 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     DEFAULT;
             }
             break;
-
+        case 0x84:
+            INST_NAME("TEST Eb, Gb");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop=F8;
+            GETEB(x1, 0);
+            GETGB(x2);
+            emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
+            break;
         case 0x85:
             INST_NAME("TEST Ed, Gd");
             SETFLAGS(X_ALL, SF_SET_PENDING);
@@ -499,6 +519,25 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             MOV32w(x2, u8);
             emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
             break;
+        case 0xB4:
+        case 0xB5:
+        case 0xB6:
+        case 0xB7:
+            INST_NAME("MOV xH, Ib");
+            u8 = F8;
+            MOV32w(x1, u8);
+            if(rex.rex) {
+                gb1 = xRAX+(opcode&7)+(rex.b<<3);
+                ANDI(gb1, gb1, ~0xff);
+                OR(gb1, gb1, x1);
+            } else {
+                gb1 = xRAX+(opcode&3);
+                MOV64x(x2, 0xffffffffffff00ffLL);
+                AND(gb1, gb1, x2);
+                SLLI(x1, x1, 8);
+                OR(gb1, gb1, x1);
+            }
+            break;
         case 0xB8:
         case 0xB9:
         case 0xBA:
diff --git a/src/dynarec/rv64/dynarec_rv64_64.c b/src/dynarec/rv64/dynarec_rv64_64.c
new file mode 100644
index 00000000..bbcdc681
--- /dev/null
+++ b/src/dynarec/rv64/dynarec_rv64_64.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "dynarec.h"
+#include "emu/x64emu_private.h"
+#include "emu/x64run_private.h"
+#include "x64run.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+#include "custommem.h"
+
+#include "rv64_printer.h"
+#include "dynarec_rv64_private.h"
+#include "dynarec_rv64_helper.h"
+#include "dynarec_rv64_functions.h"
+
+#define GETG        gd = ((nextop&0x38)>>3)+(rex.r<<3)
+
+uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
+{
+    (void)ip; (void)rep; (void)need_epilog;
+
+    uint8_t opcode = F8;
+    uint8_t nextop;
+    uint8_t u8;
+    uint8_t gd, ed, eb1, eb2, gb1, gb2;
+    uint8_t wback, wb1, wb2, wb;
+    int64_t i64, j64;
+    int v0, v1;
+    int q0;
+    int d0;
+    int64_t fixedaddress;
+    int unscaled;
+    MAYUSE(eb1);
+    MAYUSE(eb2);
+    MAYUSE(wb1);
+    MAYUSE(wb2);
+    MAYUSE(gb1);
+    MAYUSE(gb2);
+    MAYUSE(j64);
+    MAYUSE(d0);
+    MAYUSE(q0);
+    MAYUSE(v0);
+    MAYUSE(v1);
+
+    while((opcode==0xF2) || (opcode==0xF3)) {
+        rep = opcode-0xF1;
+        opcode = F8;
+    }
+    // REX prefix before the F0 are ignored
+    rex.rex = 0;
+    while(opcode>=0x40 && opcode<=0x4f) {
+        rex.rex = opcode;
+        opcode = F8;
+    }
+
+    switch(opcode) {
+        case 0x8B:
+            INST_NAME("MOV Gd, Seg:Ed");
+            grab_segdata(dyn, addr, ninst, x4, seg);
+            nextop=F8;
+            GETGD;
+            if(MODREG) {   // reg <= reg
+                MVxw(gd, xRAX+(nextop&7)+(rex.b<<3));
+            } else {       // mem <= reg
+                SMREAD();
+                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0);
+                ADD(x4, ed, x4);
+                LDxw(gd, x4, 0);
+            }
+            break;
+        default:
+            DEFAULT;
+    }
+    return addr;
+}
diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c
index 6348728c..86446b7a 100644
--- a/src/dynarec/rv64/dynarec_rv64_66.c
+++ b/src/dynarec/rv64/dynarec_rv64_66.c
@@ -85,6 +85,23 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             // just use regular conditional jump
             return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
 
+        case 0x81:
+        case 0x83:
+            nextop = F8;
+            switch((nextop>>3)&7) {
+                case 1: // OR
+                    if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR 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_or16(dyn, ninst, x1, x5, x2, x4);
+                    EWBACK;
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
         case 0xC1:
             nextop = F8;
             switch((nextop>>3)&7) {
diff --git a/src/dynarec/rv64/dynarec_rv64_emit_logic.c b/src/dynarec/rv64/dynarec_rv64_emit_logic.c
index 4d399fd8..6076a159 100644
--- a/src/dynarec/rv64/dynarec_rv64_emit_logic.c
+++ b/src/dynarec/rv64/dynarec_rv64_emit_logic.c
@@ -96,6 +96,37 @@ void emit_xor32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
     }
 }
 
+// emit OR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
+void emit_or16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4) {
+    CLEAR_FLAGS();
+    IFX(X_PEND) {
+        SET_DF(s3, d_or16);
+    } else IFX(X_ALL) {
+        SET_DFNONE(s3);
+    }
+
+    OR(s1, s1, s2);
+    SLLI(s1, s1, 48);
+    SRLI(s1, s1, 48);
+    IFX(X_PEND) {
+        SD(s1, xEmu, offsetof(x64emu_t, res));
+    }
+
+    IFX(X_SF) {
+        SRLI(s3, s1, 15);
+        BEQZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+
+    IFX(X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, F_ZF);
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
+
 // emit OR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
 void emit_or32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
 {
@@ -110,6 +141,7 @@ void emit_or32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
 
     // test sign bit before zeroup.
     IFX(X_SF) {
+        if (!rex.w) SEXT_W(s1, s1);
         BGE(s1, xZR, 8);
         ORI(xFlags, xFlags, 1 << F_SF);
     }
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c
index 41343cf2..a57c27dd 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.c
+++ b/src/dynarec/rv64/dynarec_rv64_helper.c
@@ -481,6 +481,31 @@ void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w)
     SET_NODF();
 }
 
+void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment)
+{
+    (void)addr;
+    int64_t j64;
+    MAYUSE(j64);
+    MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment==_FS)?"FS":"GS");
+    int t1 = x1, t2 = x4;
+    if(reg==t1) ++t1;
+    if(reg==t2) ++t2;
+    LWU(t2, xEmu, offsetof(x64emu_t, segs_serial[segment]));
+    LD(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
+    if(segment==_GS) {
+        CBNZ_MARKSEG(t2);   // fast check
+    } else {
+        LD(t1, xEmu, offsetof(x64emu_t, context));
+        LWU(t1, t1, offsetof(box64context_t, sel_serial));
+        SUBW(t1, t1, t2);
+        CBZ_MARKSEG(t1);
+    }
+    MOV64x(x1, segment);
+    call_c(dyn, ninst, GetSegmentBaseEmu, t2, reg, 1, 0);
+    MARKSEG;
+    MESSAGE(LOG_DUMP, "----%s Offset\n", (segment==_FS)?"FS":"GS");
+}
+
 void fpu_reset(dynarec_rv64_t* dyn)
 {
     //TODO
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index dca0f1da..82a0fbab 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -176,6 +176,20 @@
                     wb1 = 1;                    \
                     ed = i;                     \
                 }
+//GETGB will use i for gd
+#define GETGB(i) if(rex.rex) {                                \
+                    gb1 = xRAX+((nextop&0x38)>>3)+(rex.r<<3); \
+                    gb2 = 0;                                  \
+                } else {                                      \
+                    gd = (nextop&0x38)>>3;                    \
+                    gb2 = ((gd&4)>>2);                        \
+                    gb1 = xRAX+(gd&3);                        \
+                }                                             \
+                gd = i;                                       \
+                MV(gd, gb1);                                  \
+                if (gb2) SRLI(gd, gd, gb2*8);                 \
+                ANDI(gd, gd, 0xff);
+
 // CALL will use x6 for the call address. Return value can be put in ret (unless ret is -1)
 // R0 will not be pushed/popd if ret is -2
 #define CALL(F, ret) call_c(dyn, ninst, F, x6, ret, 1, 0)
@@ -233,6 +247,15 @@
     j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;\
     B(j64)
 
+// Branch to MARKSEG if reg is 0 (use j64)
+#define CBZ_MARKSEG(reg)    \
+    j64 = GETMARKSEG-(dyn->native_size);   \
+    BEQZ(reg, j64);
+// Branch to MARKSEG if reg is not 0 (use j64)
+#define CBNZ_MARKSEG(reg)              \
+    j64 = GETMARKSEG-(dyn->native_size);   \
+    BNEZ(reg, 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))
 #define IFXX(A) if((dyn->insts[ninst].x64.gen_flags==(A)))
@@ -605,7 +628,7 @@ void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, int n);
 //void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits);
 void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
 void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w);
-//void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment);
+void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment);
 void emit_cmp8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6);
 //void emit_cmp16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_cmp32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6);
@@ -640,7 +663,7 @@ void emit_and32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
 //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_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_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);
 //void emit_xor16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 //void emit_xor16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
@@ -745,7 +768,7 @@ void fpu_popcache(dynarec_rv64_t* dyn, int ninst, int s1, int not07);
 
 uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
 uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
-//uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
+uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
 //uintptr_t dynarec64_65(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep,int* ok, int* need_epilog);
 uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
 //uintptr_t dynarec64_67(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h
index 4a87ecba..484deb36 100644
--- a/src/dynarec/rv64/rv64_emitter.h
+++ b/src/dynarec/rv64/rv64_emitter.h
@@ -174,6 +174,8 @@ f28–31  ft8–11  FP temporaries                  Caller
 // rd = rs1 - rs2
 #define SUB(rd, rs1, rs2)           EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, 0b0110011))
 // rd = rs1 - rs2
+#define SUBW(rd, rs1, rs2)          EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, 0b0111011))
+// rd = rs1 - rs2
 #define SUBxw(rd, rs1, rs2)         EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, rex.w?0b0110011:0b0111011))
 // rd = rs1<<rs2
 #define SLL(rd, rs1, rs2)           EMIT(R_type(0b0000000, rs2, rs1, 0b001, rd, 0b0110011))