about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-09-11 13:17:01 +0200
committerGitHub <noreply@github.com>2023-09-11 13:17:01 +0200
commit0913c94e46a138edb906bf4cb1e109519aff3bfe (patch)
tree26d05296f6fa4d5f1a320a41ca03c553b9436bad /src
parent5e52c735a67f4b40c38c6d8d2c00d104c31677fc (diff)
parent910a0ef8e1b98e5d20fdec7bae01a37d8ea25b1e (diff)
downloadbox64-0913c94e46a138edb906bf4cb1e109519aff3bfe.tar.gz
box64-0913c94e46a138edb906bf4cb1e109519aff3bfe.zip
Merge pull request #969 from ksco/thead
[RV64_DYNAREC] Added thead vendor extension detection
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/rv64_emitter.h153
-rw-r--r--src/include/debug.h13
-rw-r--r--src/main.c35
-rw-r--r--src/rv64detect.c66
4 files changed, 254 insertions, 13 deletions
diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h
index f23c6716..6457ad59 100644
--- a/src/dynarec/rv64/rv64_emitter.h
+++ b/src/dynarec/rv64/rv64_emitter.h
@@ -650,5 +650,158 @@ f28–31  ft8–11  FP temporaries                  Caller
 // Single-bit Set (Immediate)
 #define BSETI(rd, rs1, imm)         EMIT(R_type(0b0010100, imm, rs1, 0b001, rd, 0b0010011))
 
+/// THead vendor extension
+/// https://github.com/T-head-Semi/thead-extension-spec/releases
+
+// XTheadBa - Address calculation instructions
+
+// Add a shifted operand to a second operand.
+// reg[rd] := reg[rs1] + (reg[rs2] << imm2)
+#define TH_ADDSL(rd, rs1, rs2, imm2) EMIT(R_type(imm2&0b11, rs2, rs1, 0b001, rd, 0b0001011))
+
+// XTheadBb - Basic bit-manipulation
+
+// Perform a cyclic right shift.
+// reg[rd] := (reg[rs1] >> imm6) | (reg[rs1] << (xlen - imm6))
+#define TH_SRRI(rd, rs1, imm6) EMIT(I_type(0b000100000000|(imm6&0x3f), rs1, 0b001, rd, 0b0001011))
+
+// TODO
+// th.srriw rd, rs1, imm5 Cyclic right shift on word operand
+// th.ext rd, rs1, imm1, imm2 Extract and sign-extend bits
+// th.extu rd, rs1, imm1, imm2 Extract and zero-extend bits
+// th.ff0 rd, rs1 Find first '0'-bit
+// th.ff1 rd, rs1 Find first '1'-bit
+// th.rev rd, rs1 Reverse byte order
+// th.revw rd, rs1 Reverse byte order of word operand
+// th.tstnbz rd, rs1 Test for NUL bytes
+
+// XTheadBs - Single-bit instructions
+
+// Tests if a single bit is set.
+// if (reg[rs1] & (1 << imm6))
+//   rd := 1
+// else
+//   rd := 0
+#define TH_TST(rd, rs1, imm6) EMIT(I_type(0b100010000000|(imm6&0x3f), rs1, 0b001, rd, 0b0001011))
+
+
+// XTheadCondMov -  Conditional move
+
+// Move if equal zero.
+// if (reg[rs2] == 0x0)
+//   reg[rd] := reg[rs1]
+#define TH_MVEQZ(rd, rs1, rs2) EMIT(R_type(0b0100000, rs2, rs1, 0b001, rd, 0b0001011))
+
+// Move if not equal zero.
+// if (reg[rs2] != 0x0)
+//   reg[rd] := reg[rs1]
+#define TH_MVNEZ(rd, rs1, rs2) EMIT(R_type(0b0100001, rs2, rs1, 0b001, rd, 0b0001011))
+
+// XTheadMemIdx -  Indexed memory operations
+
+// Load indexed byte, increment address after loading.
+// rd := sign_extend(mem[rs1])
+// rs1 := rs1 + (sign_extend(imm5) << imm2)
+#define TH_LBIA(rd, rs1, imm5, imm2) EMIT(I_type(0b000110000000|((imm2&0b11)<<5)|(imm5&0x1f), rs1, 0b100, rd, 0b0001011))
+
+// TODO
+// th.lbib rd, (rs1), imm5, imm2 Load indexed byte
+// th.lbuia rd, (rs1), imm5, imm2 Load indexed unsigned byte
+// th.lbuib rd, (rs1), imm5, imm2 Load indexed unsigned byte
+// th.lhia rd, (rs1), imm5, imm2 Load indexed half-word
+// th.lhib rd, (rs1), imm5, imm2 Load indexed half-word
+// th.lhuia rd, (rs1), imm5, imm2 Load indexed unsigned half-word
+// th.lhuib rd, (rs1), imm5, imm2 Load indexed unsigned half-word
+// th.lwia rd, (rs1), imm5, imm2 Load indexed word
+// th.lwib rd, (rs1), imm5, imm2 Load indexed word
+// th.lwuia rd, (rs1), imm5, imm2 Load indexed unsigned word
+// th.lwuib rd, (rs1), imm5, imm2 Load indexed unsigned word
+// th.ldia rd, (rs1), imm5, imm2 Load indexed double-word
+// th.ldib rd, (rs1), imm5, imm2 Load indexed double-word
+// th.sbia rd, (rs1), imm5, imm2 Store indexed byte
+// th.sbib rd, (rs1), imm5, imm2 Store indexed byte
+// th.shia rd, (rs1), imm5, imm2 Store indexed half-word
+// th.shib rd, (rs1), imm5, imm2 Store indexed half-word
+// th.swia rd, (rs1), imm5, imm2 Store indexed word
+// th.swib rd, (rs1), imm5, imm2 Store indexed word
+// th.sdia rd, (rs1), imm5, imm2 Store indexed double-word
+// th.sdib rd, (rs1), imm5, imm2 Store indexed double-word
+// th.lrb rd, rs1, rs2, imm2 Load indexed byte
+// th.lrbu rd, rs1, rs2, imm2 Load indexed unsigned byte
+// th.lrh rd, rs1, rs2, imm2 Load indexed half-word
+// th.lrhu rd, rs1, rs2, imm2 Load indexed unsigned half-word
+// th.lrw rd, rs1, rs2, imm2 Load indexed word
+// th.lrwu rd, rs1, rs2, imm2 Load indexed unsigned word
+// th.lrd rd, rs1, rs2, imm2 Load indexed double-word
+// th.srb rd, rs1, rs2, imm2 Store indexed byte
+// th.srh rd, rs1, rs2, imm2 Store indexed half-word
+// th.srw rd, rs1, rs2, imm2 Store indexed word
+// th.srd rd, rs1, rs2, imm2 Store indexed double-word
+// th.lurb rd, rs1, rs2, imm2 Load unsigned indexed byte
+// th.lurbu rd, rs1, rs2, imm2 Load unsigned indexed unsigned byte
+// th.lurh rd, rs1, rs2, imm2 Load unsigned indexed half-word
+// th.lurhu rd, rs1, rs2, imm2 Load unsigned indexed unsigned half-word
+// th.lurw rd, rs1, rs2, imm2 Load unsigned indexed word
+// th.lurwu rd, rs1, rs2, imm2 Load unsigned indexed unsigned word
+// th.lurd rd, rs1, rs2, imm2 Load unsigned indexed double-word
+// th.surb rd, rs1, rs2, imm2 Store unsigned indexed byte
+// th.surh rd, rs1, rs2, imm2 Store unsigned indexed half-word
+// th.surw rd, rs1, rs2, imm2 Store unsigned indexed word
+// th.surd rd, rs1, rs2, imm2 Store unsigned indexed double-word
+
+// XTheadMemPair - Two-GPR memory operations
+
+
+// Load two 64-bit values from memory into two GPRs.
+// addr := rs1 + (zero_extend(imm2) << 4)
+// rd1 := mem[addr+7:addr]
+// rd2 := mem[addr+15:addr+8]
+#define TH_LDD(rd1, rd2, rs1, imm2) EMIT(R_type(0b1111100|(imm2&0b11), rd2, rs1, 0b100, rd1, 0b0001011))
+
+// TODO
+// th.lwd rd1, rd2, (rs1), imm2, 3 Load two signed 32-bit values
+// th.lwud rd1, rd2, (rs1), imm2, 3 Load two unsigned 32-bit values
+// th.sdd rd1, rd2, (rs1), imm2, 4 Store two 64-bit values
+// th.swd rd1, rd2, (rs1), imm2, 3 Store two 32-bit values
+
+// XTheadFMemIdx - Indexed memory operations for floating-point registers
+
+// Load indexed double-precision floating point value.
+// addr := rs1 + (rs2 << imm2)
+// rd := fmem[addr+7:addr]
+#define TH_FLRD(rd, rs1, rs2, imm2) EMIT(R_type(0b0110000|(imm2&0b11), rs2, rs1, 0b110, rd, 0b0001011))
+
+// TODO
+// th.flrw rd, rs1, rs2, imm2 Load indexed float
+// th.flurd rd, rs1, rs2, imm2 Load unsigned indexed double
+// th.flurw rd, rs1, rs2, imm2 Load unsigned indexed float
+// th.fsrd rd, rs1, rs2, imm2 Store indexed double
+// th.fsrw rd, rs1, rs2, imm2 Load indexed float
+// th.fsurd rd, rs1, rs2, imm2 Store unsigned indexed double
+// th.fsurw rd, rs1, rs2, imm2 Load unsigned indexed float
+
+// XTheadMac - Multiply-accumulate instructions
+
+// Compute multiply-add result of double-word operands.
+// M := reg[rs1] * reg[rs2]
+// reg[rd] := reg[rd] + M
+#define TH_MULA(rd, rs1, rs2) EMIT(R_type(0b0010000, rs2, rs1, 0b001, rd, 0b0001011))
+
+// TODO
+// th.mulah rd, rs1, rs2 Multiply-add half-words
+// th.mulaw rd, rs1, rs2 Multiply-add words
+// th.muls rd, rs1, rs2 Multiply-subtract double-words
+// th.mulsh rd, rs1, rs2 Multiply-subtract half-words
+// th.mulsw rd, rs1, rs2 Multiply-subtract words
+
+// XTheadFmv - Double-precision floating-point high-bit data transmission instructions
+
+// Read double-precision floating-point high-bit data
+// rd := fs1[63:32]
+#define TH_FMV_X_HW(rd, fs1) EMIT(R_type(0b1100000, 0, fs1, 0b001, rd, 0b0001011))
+
+// Write double-precision floating-point high-bit data
+// fs1[63:32] := rd
+#define TH_FMV_HW_X(rd, fs1) EMIT(R_type(0b1010000, 0, fs1, 0b001, rd, 0b0001011))
 
 #endif //__RV64_EMITTER_H__
diff --git a/src/include/debug.h b/src/include/debug.h
index 9bfc5c89..acd842c2 100644
--- a/src/include/debug.h
+++ b/src/include/debug.h
@@ -40,6 +40,15 @@ extern int rv64_zba;
 extern int rv64_zbb;
 extern int rv64_zbc;
 extern int rv64_zbs;
+extern int rv64_xtheadba;
+extern int rv64_xtheadbb;
+extern int rv64_xtheadbs;
+extern int rv64_xtheadcondmov;
+extern int rv64_xtheadmemidx;
+extern int rv64_xtheadmempair;
+extern int rv64_xtheadfmemidx;
+extern int rv64_xtheadmac;
+extern int rv64_xtheadfmv;
 #endif
 #endif
 extern int box64_libcef;
@@ -100,7 +109,7 @@ void printf_ftrace(const char* fmt, ...);
 #ifdef BUILD_DYNAMIC
 #define EXPORTDYN __attribute__((visibility("default")))
 #else
-#define EXPORTDYN 
+#define EXPORTDYN
 #endif
 
 void init_malloc_hook(void);
@@ -123,7 +132,7 @@ extern void* __libc_memalign(size_t, size_t);
 #define box_realloc     __libc_realloc
 #define box_calloc      __libc_calloc
 #define box_free        __libc_free
-#define box_memalign    __libc_memalign 
+#define box_memalign    __libc_memalign
 extern char* box_strdup(const char* s);
 extern char* box_realpath(const char* path, char* ret);
 
diff --git a/src/main.c b/src/main.c
index e8ebe74d..377eea1f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -79,6 +79,15 @@ int rv64_zba = 0;
 int rv64_zbb = 0;
 int rv64_zbc = 0;
 int rv64_zbs = 0;
+int rv64_xtheadba = 0;
+int rv64_xtheadbb = 0;
+int rv64_xtheadbs = 0;
+int rv64_xtheadcondmov = 0;
+int rv64_xtheadmemidx = 0;
+int rv64_xtheadmempair = 0;
+int rv64_xtheadfmemidx = 0;
+int rv64_xtheadmac = 0;
+int rv64_xtheadfmv = 0;
 #endif
 #else   //DYNAREC
 int box64_dynarec = 0;
@@ -208,7 +217,7 @@ void my_child_fork()
 {
     if(ftrace_has_pid) {
         // open a new ftrace...
-        if(!ftrace_name) 
+        if(!ftrace_name)
             fclose(ftrace);
         openFTrace(NULL);
     }
@@ -372,6 +381,16 @@ HWCAP2_ECV
     if(rv64_zbb) printf_log(LOG_INFO, " Zbb");
     if(rv64_zbc) printf_log(LOG_INFO, " Zbc");
     if(rv64_zbs) printf_log(LOG_INFO, " Zbs");
+    if(rv64_xtheadba) printf_log(LOG_INFO, " XTheadBa");
+    if(rv64_xtheadbb) printf_log(LOG_INFO, " XTheadBb");
+    if(rv64_xtheadbs) printf_log(LOG_INFO, " XTheadBs");
+    if(rv64_xtheadcondmov) printf_log(LOG_INFO, " XTheadCondMov");
+    if(rv64_xtheadmemidx) printf_log(LOG_INFO, " XTheadMemIdx");
+    if(rv64_xtheadmempair) printf_log(LOG_INFO, " XTheadMemPair");
+    if(rv64_xtheadfmemidx) printf_log(LOG_INFO, " XTheadFMemIdx");
+    if(rv64_xtheadmac) printf_log(LOG_INFO, " XTheadMac");
+    if(rv64_xtheadfmv) printf_log(LOG_INFO, " XTheadFmv");
+
     printf_log(LOG_INFO, " PageSize:%zd ", box64_pagesize);
 #else
 #error Unsupported architecture
@@ -888,7 +907,7 @@ int GatherEnv(char*** dest, char** env, char* prog)
 {
     // Add all but BOX64_* environnement
     // but add 2 for default BOX64_PATH and BOX64_LD_LIBRARY_PATH
-    char** p = env;    
+    char** p = env;
     int idx = 0;
     int path = 0;
     int ld_path = 0;
@@ -1200,7 +1219,7 @@ void endBox64()
 {
     if(!my_context || box64_quit)
         return;
-    
+
     endMallocHook();
     x64emu_t* emu = thread_get_emu();
     // atexit first
@@ -1323,7 +1342,7 @@ int main(int argc, const char **argv, char **env) {
             }
         }
     }
-    
+
     const char* prog = argv[1];
     int nextarg = 1;
     // check if some options are passed
@@ -1351,7 +1370,7 @@ int main(int argc, const char **argv, char **env) {
     if(!box64_nobanner)
         PrintBox64Version();
     // precheck, for win-preload
-    if(strstr(prog, "wine-preloader")==(prog+strlen(prog)-strlen("wine-preloader")) 
+    if(strstr(prog, "wine-preloader")==(prog+strlen(prog)-strlen("wine-preloader"))
      || strstr(prog, "wine64-preloader")==(prog+strlen(prog)-strlen("wine64-preloader"))) {
         // wine-preloader detecter, skipping it if next arg exist and is an x86 binary
         int x64 = (nextarg<argc)?FileIsX64ELF(argv[nextarg]):0;
@@ -1372,8 +1391,8 @@ int main(int argc, const char **argv, char **env) {
     int ld_libs_args = -1;
     // check if this is wine
     if(!strcmp(prog, "wine64")
-     || !strcmp(prog, "wine64-development") 
-     || !strcmp(prog, "wine") 
+     || !strcmp(prog, "wine64-development")
+     || !strcmp(prog, "wine")
      || (strlen(prog)>5 && !strcmp(prog+strlen(prog)-strlen("/wine"), "/wine"))
      || (strlen(prog)>7 && !strcmp(prog+strlen(prog)-strlen("/wine64"), "/wine64"))) {
         const char* prereserve = getenv("WINEPRELOADRESERVE");
@@ -1391,7 +1410,7 @@ int main(int argc, const char **argv, char **env) {
             }
         }
         box64_wine = 1;
-    } else 
+    } else
     // check if ld-musl-x86_64.so.1 is used
     if(strstr(prog, "ld-musl-x86_64.so.1")) {
         printf_log(LOG_INFO, "BOX64: ld-musl detected, trying to workaround and use system ld-linux\n");
diff --git a/src/rv64detect.c b/src/rv64detect.c
index 9976d1d7..e1b3b40a 100644
--- a/src/rv64detect.c
+++ b/src/rv64detect.c
@@ -11,7 +11,7 @@
 // Detect RV64 extensions, by executing on of the opcode with a SIGILL signal handler
 
 static sigjmp_buf sigbuf = {0};
-typedef void(*vFii_t)(int, int);
+typedef void(*vFiip_t)(int, int, void*);
 static void detect_sigill(int sig)
 {
     siglongjmp(sigbuf, 1);
@@ -19,6 +19,7 @@ static void detect_sigill(int sig)
 
 static int Check(void* block)
 {
+    static uint64_t buf[2] = {0};
     // Clear instruction cache
     __clear_cache(block, block+box64_pagesize);
     // Setup SIGILL signal handler
@@ -28,7 +29,7 @@ static int Check(void* block)
         signal(SIGILL, old);
         return 0;
     }
-    ((vFii_t)block)(0, 1);
+    ((vFiip_t)block)(0, 1, buf);
     // done...
     signal(SIGILL, old);
     return 1;
@@ -43,6 +44,9 @@ void RV64_Detect_Function()
     }
     uint32_t* block;
     #define EMIT(A) *block = (A); ++block
+
+    // Official extensions
+
     // Test Zba with ADDUW
     block = (uint32_t*)my_block;
     ADDUW(A0, A0, A1);
@@ -64,7 +68,63 @@ void RV64_Detect_Function()
     BR(xRA);
     rv64_zbs = Check(my_block);
 
+    // THead vendor extensions
+
+    // Test XTheadBa with TH_ADDSL
+    block = (uint32_t*)my_block;
+    TH_ADDSL(A0, A0, A1, 1);
+    BR(xRA);
+    rv64_xtheadba = Check(my_block);
+
+    // Test XTheadBb with TH_SRRI
+    block = (uint32_t*)my_block;
+    TH_SRRI(A0, A1, 1);
+    BR(xRA);
+    rv64_xtheadbb = Check(my_block);
+
+    // Test XTheadBs with TH_TST
+    block = (uint32_t*)my_block;
+    TH_TST(A0, A1, 1);
+    BR(xRA);
+    rv64_xtheadbs = Check(my_block);
+
+    // Test XTheadCondMov with TH_MVEQZ
+    block = (uint32_t*)my_block;
+    TH_MVEQZ(A0, A0, A1);
+    BR(xRA);
+    rv64_xtheadcondmov = Check(my_block);
+
+    // Test XTheadMemIdx with TH_LBIA
+    block = (uint32_t*)my_block;
+    TH_LBIA(A0, A2, 1, 1);
+    BR(xRA);
+    rv64_xtheadmemidx = Check(my_block);
+
+    // Test XTheadMemPair with TH_LDD
+    block = (uint32_t*)my_block;
+    TH_LDD(A0, A1, A2, 0);
+    BR(xRA);
+    rv64_xtheadmempair = Check(my_block);
+
+    // Test XTheadFMemIdx with TH_FLRD
+    block = (uint32_t*)my_block;
+    TH_FLRD(A0, A2, xZR, 0);
+    BR(xRA);
+    rv64_xtheadfmemidx = Check(my_block);
+
+    // Test XTheadMac with TH_MULA
+    block = (uint32_t*)my_block;
+    TH_MULA(A0, A0, A1);
+    BR(xRA);
+    rv64_xtheadmac = Check(my_block);
+
+    // Test XTheadFmv with TH_FMV_X_HW
+    block = (uint32_t*)my_block;
+    TH_FMV_X_HW(A0, A1);
+    BR(xRA);
+    rv64_xtheadfmv = Check(my_block);
+
     // Finish
     // Free the memory my_block
     munmap(my_block, box64_pagesize);
-}
\ No newline at end of file
+}