mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 10:10:25 -10:00
[RV64] Added some basic infrastructure for the Dynarec (and 1 opcode)
This commit is contained in:
1 parent
dd171198f1
commit
5a9b89600e
34 files changed
+1894
-159
No files matched your search
+55
-1
@@ -30,23 +30,27 @@ if(LARCH64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RV64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC ON CACHE BOOL "")
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(PPC64LE)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A OR M1)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A)
|
||||
set(PAGE16K OFF CACHE BOOL "")
|
||||
@@ -66,6 +70,7 @@ endif()
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
|
||||
option(RV64_DYNAREC "Set to ON to use RISC-V Dynamic Recompilation" ${RV64_DYNAREC})
|
||||
option(PAGE8K "Set to ON if host device have PageSize of 8K (instead of 4K)" ${PAGE8K})
|
||||
option(PAGE16K "Set to ON if host device have PageSize of 16K (instead of 4K)" ${PAGE16K})
|
||||
option(PAGE64K "Set to ON if host device have PageSize of 64K (instead of 4K)" ${PAGE64K})
|
||||
@@ -208,6 +213,12 @@ if(ARM_DYNAREC)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/arm64")
|
||||
set(DYNAREC ON)
|
||||
elseif(RV64_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DRV64)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/rv64")
|
||||
set(DYNAREC ON)
|
||||
else()
|
||||
set(DYNAREC OFF)
|
||||
endif()
|
||||
@@ -575,6 +586,49 @@ if(ARM_DYNAREC)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(RV64_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_next.S"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_lock.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_helper.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_tests.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_math.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_logic.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_emit_shift.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_00.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_0f.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_64.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_65.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_67.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_d8.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_d9.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_da.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_db.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_dc.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_dd.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_de.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_df.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f0.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_660f.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_6664.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66f0.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f20f.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DYNAREC)
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.h"
|
||||
|
||||
@@ -1753,3 +1753,65 @@ void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
MVNw_REG(s4, s4);
|
||||
BFIw(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
|
||||
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
{
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
if(box64_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[reset_n].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n));
|
||||
if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2);
|
||||
if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " ==> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n));
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " -> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n));
|
||||
if(dyn->n.combined1 || dyn->n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2);
|
||||
if(dyn->n.stack_push || dyn->n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, "\n");
|
||||
}
|
||||
#endif //HAVE_TRACE
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
}
|
||||
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
if(dyn->n.stack_pop) {
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
else
|
||||
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
|
||||
}
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
dyn->n.news = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
}
|
||||
@@ -969,6 +969,8 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_reset_cache STEPNAME(fpu_reset_cache)
|
||||
#define fpu_propagate_stack STEPNAME(fpu_propagate_stack)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#define mmx_purgecache STEPNAME(mmx_purgecache)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
@@ -1154,6 +1156,10 @@ void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn);
|
||||
// reset the cache with n
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n);
|
||||
// propagate stack state
|
||||
void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
// purge MMX cache
|
||||
|
||||
@@ -18,6 +18,15 @@
|
||||
#define dynarec_native_t dynarec_la464_t
|
||||
|
||||
|
||||
#elif defined(RV64)
|
||||
#include "rv64/rv64_printer.h"
|
||||
#include "rv64/dynarec_rv64_private.h"
|
||||
#include "rv64/dynarec_rv64_functions.h"
|
||||
|
||||
#define instruction_native_t instruction_rv64_t
|
||||
#define dynarec_native_t dynarec_rv64_t
|
||||
|
||||
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "arm64/dynarec_arm64_helper.h"
|
||||
#elif defined(LA464)
|
||||
#include "la464/dynarec_la464_helper.h"
|
||||
#elif defined(RV64)
|
||||
#include "rv64/dynarec_rv64_helper.h"
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
@@ -325,7 +325,7 @@ static void fillPredecessors(dynarec_native_t* dyn)
|
||||
}
|
||||
|
||||
// updateNeed goes backward, from last intruction to top
|
||||
static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
static int updateNeed(dynarec_native_t* dyn, int ninst, uint8_t need) {
|
||||
while (ninst>=0) {
|
||||
// need pending but instruction is only a subset: remove pend and use an X_ALL instead
|
||||
need |= dyn->insts[ninst].x64.need_after;
|
||||
|
||||
@@ -60,44 +60,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
dyn->f.pending = 0;
|
||||
fpu_reset(dyn);
|
||||
} else {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
if(box64_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[reset_n].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n));
|
||||
if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2);
|
||||
if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " ==> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n));
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " -> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n));
|
||||
if(dyn->n.combined1 || dyn->n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2);
|
||||
if(dyn->n.stack_push || dyn->n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, "\n");
|
||||
}
|
||||
#endif //HAVE_TRACE
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
fpu_reset_cache(dyn, ninst, reset_n);
|
||||
dyn->f = dyn->insts[reset_n].f_exit;
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Float\n");
|
||||
@@ -112,21 +75,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
|
||||
reset_n = -1;
|
||||
} else if(ninst && (dyn->insts[ninst].pred_sz!=1 || dyn->insts[ninst].pred[0]!=ninst-1))
|
||||
dyn->last_ip = 0; // reset IP if some jump are comming here
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
if(dyn->n.stack_pop) {
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
else
|
||||
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
|
||||
}
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
dyn->n.news = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
NEW_INST;
|
||||
if(dyn->insts[ninst].pred_sz>1) {SMSTART();}
|
||||
fpu_reset_scratch(dyn);
|
||||
|
||||
@@ -15,6 +15,13 @@ void la464_epilog() EXPORTDYN;
|
||||
#define native_next la464_next
|
||||
#define native_prolog la464_prolog
|
||||
#define native_epilog la464_epilog
|
||||
#elif defined(RV64)
|
||||
void rv64_next(void) EXPORTDYN;
|
||||
void rv64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void rv64_epilog() EXPORTDYN;
|
||||
#define native_next rv64_next
|
||||
#define native_prolog rv64_prolog
|
||||
#define native_epilog rv64_epilog
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,46 @@
|
||||
#define native_lock_decifnot0(A) arm64_lock_decifnot0(A)
|
||||
#define native_lock_store(A, B) arm64_lock_store(A, B)
|
||||
|
||||
#elif defined(RV64)
|
||||
#include "rv64/rv64_lock.h"
|
||||
|
||||
#define USE_CAS
|
||||
// RV64 is quite strict (or at least strongly recommand) on what you can do between an LD.A and an SD.A
|
||||
// That basicaly forbid to call a function, so there cannot be READ / WRITE separated
|
||||
// And so need to use a Compare and Swap mecanism instead
|
||||
|
||||
// no byte or 2-bytes atomic access on RISC-V
|
||||
#define native_lock_xchg(A, B) rv64_lock_xchg(A, B)
|
||||
#define native_lock_xchg_d(A, B) rv64_lock_xchg_d(A, B)
|
||||
#define native_lock_storeifref(A, B, C) rv64_lock_storeifref(A, B, C)
|
||||
#define native_lock_storeifref_d(A, B, C) rv64_lock_storeifref_d(A, B, C)
|
||||
#define native_lock_storeifref2_d(A, B, C) rv64_lock_storeifref2_d(A, B, C)
|
||||
#define native_lock_storeifnull(A, B) rv64_lock_storeifnull(A, B)
|
||||
#define native_lock_storeifnull_d(A, B) rv64_lock_storeifnull_d(A, B)
|
||||
#define native_lock_decifnot0b(A) rv64_lock_decifnot0b(A)
|
||||
#define native_lock_storeb(A, B) rv64_lock_storeb(A, B)
|
||||
#define native_lock_incif0(A) rv64_lock_incif0(A)
|
||||
#define native_lock_decifnot0(A) rv64_lock_decifnot0(A)
|
||||
#define native_lock_store(A, B) rv64_lock_store(A, B)
|
||||
#define native_lock_cas_d(A, B, C) rv64_lock_cas_d(A, B, C)
|
||||
#define native_lock_cas_dd(A, B, C) rv64_lock_cas_dd(A, B, C)
|
||||
|
||||
#define native_lock_xchg_b(A, B) rv64_lock_xchg_b(A, B)
|
||||
#define native_lock_cas_b(A, B, C) rv64_lock_cas_b(A, B, C)
|
||||
#define native_lock_cas_h(A, B, C) rv64_lock_cas_h(A, B, C)
|
||||
|
||||
#define native_lock_read_b(A) tmpcas=*(uint8_t*)(A)
|
||||
#define native_lock_write_b(A, B) rv64_lock_cas_b(A, tmpcas, B)
|
||||
#define native_lock_read_h(A) tmpcas=*(uint16_t*)(A)
|
||||
#define native_lock_write_h(A, B) rv64_lock_cas_h(A, tmpcas, B)
|
||||
#define native_lock_read_d(A) tmpcas=*(uint32_t*)(A)
|
||||
#define native_lock_write_d(A, B) rv64_lock_cas_d(A, tmpcas, B)
|
||||
#define native_lock_read_dd(A) tmpcas=*(uint64_t*)(A)
|
||||
#define native_lock_write_dd(A, B) rv64_lock_cas_dd(A, tmpcas, B)
|
||||
// there is no atomic move on 16bytes, so faking it
|
||||
#define native_lock_read_dq(A, B, C) *A=tmpcas=((uint64_t*)(C))[0]; *B=((uint64_t*)(C))[1];
|
||||
#define native_lock_write_dq(A, B, C) rv64_lock_cas_dq(C, A, tmpcas, B);
|
||||
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <signal.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 "bridge.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_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
|
||||
int isSimpleWrapper(wrapper_t fun);
|
||||
|
||||
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)
|
||||
{
|
||||
uint8_t nextop, opcode;
|
||||
uint8_t gd, ed;
|
||||
int8_t i8;
|
||||
int32_t i32, tmp;
|
||||
int64_t i64, j64;
|
||||
uint8_t u8;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
int64_t fixedaddress;
|
||||
int lock;
|
||||
int cacheupd = 0;
|
||||
|
||||
opcode = F8;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(wb);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
INST_NAME("PUSH reg");
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
if(gd==xRSP) {
|
||||
MV(x1, gd);
|
||||
gd = x1;
|
||||
}
|
||||
SUBI(xRSP, xRSP, 8);
|
||||
SD_I12(gd, xRSP, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "signals.h"
|
||||
#include "dynarec_rv64.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
#include "rv64_lock.h"
|
||||
|
||||
void fpu_reset_scratch(dynarec_rv64_t* dyn)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_rv64_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
|
||||
{
|
||||
(void)dyn; (void)ninst;
|
||||
|
||||
uint32_t tested = (1<<parity)-1;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 0; // direct register, no parity...
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = (sib>>3)&7;
|
||||
if((sib&0x7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
if (sib_reg!=4) {
|
||||
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
|
||||
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
|
||||
} else {
|
||||
// just a constant...
|
||||
return (tmp&tested)?0:1;
|
||||
}
|
||||
} else {
|
||||
if(sib_reg==4 && parity<3)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
tmp+=addr+delta;
|
||||
return (tmp&tested)?0:1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
(void)dyn; (void)addr; (void)ninst;
|
||||
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return addr;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
|
||||
int isNativeCall(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
{
|
||||
(void)dyn;
|
||||
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(int32_t*)(addr+a)
|
||||
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
if(PK(0)==0xff && PK(1)==0x25) { // "absolute" jump, maybe the GOT (well, RIP relative in fact)
|
||||
uintptr_t a1 = addr + 6 + (PK32(2)); // need to add a check to see if the address is from the GOT !
|
||||
addr = (uintptr_t)getAlternate(*(void**)a1);
|
||||
}
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
onebridge_t *b = (onebridge_t*)(addr);
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
|
||||
// found !
|
||||
if(retn) *retn = (b->C3==0xC2)?b->N:0;
|
||||
if(calladdress) *calladdress = addr+1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#undef PK32
|
||||
#undef PK
|
||||
}
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_rv64_t* dyn, int ninst)
|
||||
{
|
||||
// check flags cache
|
||||
if(dyn->insts[ninst].f_entry.dfnone || dyn->insts[ninst].f_entry.pending)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].x64.state_flags)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int isPred(dynarec_rv64_t* dyn, int ninst, int pred) {
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
if(dyn->insts[ninst].pred[i]==pred)
|
||||
return pred;
|
||||
return -1;
|
||||
}
|
||||
int getNominalPred(dynarec_rv64_t* dyn, int ninst) {
|
||||
if((ninst<=0) || !dyn->insts[ninst].pred_sz)
|
||||
return -1;
|
||||
if(isPred(dyn, ninst, ninst-1)!=-1)
|
||||
return ninst-1;
|
||||
return dyn->insts[ninst].pred[0];
|
||||
}
|
||||
|
||||
uint8_t extract_byte(uint32_t val, void* address){
|
||||
int idx = (((uintptr_t)address)&3)*8;
|
||||
return (val>>idx)&0xff;
|
||||
}
|
||||
uint32_t insert_byte(uint32_t val, uint8_t b, void* address){
|
||||
int idx = (((uintptr_t)address)&3)*8;
|
||||
val&=~(0xff<<idx);
|
||||
val|=(((uint32_t)b)<<idx);
|
||||
return val;
|
||||
}
|
||||
|
||||
// will go badly if address is unaligned
|
||||
uint16_t extract_half(uint32_t val, void* address){
|
||||
int idx = (((uintptr_t)address)&3)*8;
|
||||
return (val>>idx)&0xffff;
|
||||
}
|
||||
uint32_t insert_half(uint32_t val, uint16_t h, void* address){
|
||||
int idx = (((uintptr_t)address)&3)*8;
|
||||
val&=~(0xffff<<idx);
|
||||
val|=(((uint32_t)h)<<idx);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t rv64_lock_xchg_b(void* addr, uint8_t val)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint32_t* aligned = (uint32_t*)(((uintptr_t)addr)&~3);
|
||||
do {
|
||||
ret = *aligned;
|
||||
} while(rv64_lock_cas_d(aligned, ret, insert_byte(ret, val, addr)));
|
||||
return extract_byte(ret, addr);
|
||||
}
|
||||
|
||||
int rv64_lock_cas_b(void* addr, uint8_t ref, uint8_t val)
|
||||
{
|
||||
uint32_t* aligned = (uint32_t*)(((uintptr_t)addr)&~3);
|
||||
uint32_t tmp = *aligned;
|
||||
return rv64_lock_cas_d(aligned, tmp, insert_byte(tmp, val, addr));
|
||||
}
|
||||
|
||||
int rv64_lock_cas_h(void* addr, uint16_t ref, uint16_t val)
|
||||
{
|
||||
uint32_t* aligned = (uint32_t*)(((uintptr_t)addr)&~3);
|
||||
uint32_t tmp = *aligned;
|
||||
return rv64_lock_cas_d(aligned, tmp, insert_half(tmp, val, addr));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef __DYNAREC_RV64_FUNCTIONS_H__
|
||||
#define __DYNAREC_RV64_FUNCTIONS_H__
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynarec_rv64_s dynarec_rv64_t;
|
||||
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_rv64_t* dyn);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_rv64_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_rv64_t* dyn, int ninst, int pred);
|
||||
int getNominalPred(dynarec_rv64_t* dyn, int ninst);
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_rv64_t* dyn, int ninst);
|
||||
|
||||
#endif //__DYNAREC_RV64_FUNCTIONS_H__
|
||||
@@ -0,0 +1,166 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <assert.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 "../dynablock_private.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "rv64_printer.h"
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "dynarec_rv64_helper.h"
|
||||
|
||||
|
||||
void jump_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ip); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Jump to epilog\n");
|
||||
|
||||
if(reg) {
|
||||
if(reg!=xRIP) {
|
||||
MV(xRIP, reg);
|
||||
}
|
||||
} else {
|
||||
GETIP_(ip);
|
||||
}
|
||||
TABLE64(x2, (uintptr_t)rv64_epilog);
|
||||
SMEND();
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Jump to next\n");
|
||||
|
||||
if(reg) {
|
||||
if(reg!=xRIP) {
|
||||
MV(xRIP, reg);
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
MAYUSE(tbl);
|
||||
TABLE64(x3, tbl);
|
||||
SRLI(x2, xRIP, JMPTABL_START3);
|
||||
SLLI(x2, x2, 3);
|
||||
LD_I12(x3, x3, x2);
|
||||
LUI(x4, JMPTABLE_MASK2); // x4 = mask
|
||||
SRLI(x2, xRIP, JMPTABL_START2);
|
||||
AND(x2, x2, x4);
|
||||
SLLI(x2, x2, 3);
|
||||
LD_I12(x3, x3, x2);
|
||||
if(JMPTABLE_MASK2!=JMPTABLE_MASK1) {
|
||||
LUI(x4, JMPTABLE_MASK1); // x4 = mask
|
||||
}
|
||||
SRLI(x2, xRIP, JMPTABL_START1);
|
||||
AND(x2, x2, x4);
|
||||
SLLI(x2, x2, 3);
|
||||
LD_I12(x3, x3, x2);
|
||||
if(JMPTABLE_MASK1!=JMPTABLE_MASK0) {
|
||||
LUI(x4, JMPTABLE_MASK0); // x4 = mask
|
||||
}
|
||||
AND(x2, x2, x4);
|
||||
SLLI(x2, x2, 3);
|
||||
LD_I12(x2, x3, x2);
|
||||
} else {
|
||||
uintptr_t p = getJumpTableAddress64(ip);
|
||||
MAYUSE(p);
|
||||
TABLE64(x3, p);
|
||||
GETIP_(ip);
|
||||
LD_I12(x2, x3, 0);
|
||||
}
|
||||
if(reg!=A1) {
|
||||
MV(A1, xRIP);
|
||||
}
|
||||
CLEARIP();
|
||||
#ifdef HAVE_TRACE
|
||||
//MOVx(x3, 15); no access to PC reg
|
||||
#endif
|
||||
SMEND();
|
||||
JALR(x2); // save LR...
|
||||
}
|
||||
|
||||
void fpu_reset(dynarec_rv64_t* dyn)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
void fpu_reset_cache(dynarec_rv64_t* dyn, int ninst, int reset_n)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
void fpu_purgecache(dynarec_rv64_t* dyn, int ninst, int next, int s1, int s2, int s3)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
void fpu_propagate_stack(dynarec_rv64_t* dyn, int ninst)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
void mmx_purgecache(dynarec_rv64_t* dyn, int ninst, int next, int s1)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void x87_purgecache(dynarec_rv64_t* dyn, int ninst, int next, int s1, int s2, int s3)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
#endif
|
||||
void fpu_pushcache(dynarec_rv64_t* dyn, int ninst, int s1, int not07)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
void fpu_popcache(dynarec_rv64_t* dyn, int ninst, int s1, int not07)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
void rv64_move64(dynarec_rv64_t* dyn, int ninst, int reg, int64_t val)
|
||||
{
|
||||
if((val&0b111111111111)==val) {
|
||||
// simple 12bit value
|
||||
MOV_U12(reg, (val&0b111111111111));
|
||||
return;
|
||||
}
|
||||
if(((val>>32)<<32)==val) {
|
||||
// 32bits value
|
||||
LUI(reg, (val>>12));
|
||||
ORI(reg, reg, (val&0b111111111111));
|
||||
return;
|
||||
}
|
||||
//TODO: optimize that latter
|
||||
LUI(reg, (val>>44));
|
||||
ORI(reg, reg, ((val>>32)&0b111111111111));
|
||||
SLLI(reg, reg, 12);
|
||||
ORI(reg, reg, ((val>>20)&0b111111111111));
|
||||
SLLI(reg, reg, 12);
|
||||
ORI(reg, reg, ((val>>8)&0b111111111111));
|
||||
SLLI(reg, reg, 8);
|
||||
ORI(reg, reg, (val&0b111111111111));
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
#ifndef __DYNAREC_RV64_HELPER_H__
|
||||
#define __DYNAREC_RV64_HELPER_H__
|
||||
|
||||
// undef to get Close to SSE Float->int conversions
|
||||
//#define PRECISE_CVT
|
||||
|
||||
#if STEP == 0
|
||||
#include "dynarec_rv64_pass0.h"
|
||||
#elif STEP == 1
|
||||
#include "dynarec_rv64_pass1.h"
|
||||
#elif STEP == 2
|
||||
#include "dynarec_rv64_pass2.h"
|
||||
#elif STEP == 3
|
||||
#include "dynarec_rv64_pass3.h"
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "rv64_emitter.h"
|
||||
#include "../emu/x64primop.h"
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F8S *(int8_t*)(addr++)
|
||||
#define F16 *(uint16_t*)(addr+=2, addr-2)
|
||||
#define F16S *(int16_t*)(addr+=2, addr-2)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S *(int32_t*)(addr+=4, addr-4)
|
||||
#define F32S64 (uint64_t)(int64_t)F32S
|
||||
#define F64 *(uint64_t*)(addr+=8, addr-8)
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK16(a) *(uint16_t*)(addr+a)
|
||||
#define PK32(a) *(uint32_t*)(addr+a)
|
||||
#define PK64(a) *(uint64_t*)(addr+a)
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
|
||||
|
||||
// Strong mem emulation helpers
|
||||
// Sequence of Read will trigger a DMB on "first" read if strongmem is 2
|
||||
// Squence of Write will trigger a DMB on "last" write if strongmem is 1
|
||||
// Opcode will read
|
||||
#define SMREAD() if(!dyn->smread && box64_dynarec_strongmem>1) {SMDMB();}
|
||||
// Opcode will read with option forced lock
|
||||
#define SMREADLOCK(lock) if(lock || (!dyn->smread && box64_dynarec_strongmem>1)) {SMDMB();}
|
||||
// Opcode migh read (depend on nextop)
|
||||
#define SMMIGHTREAD() if(!MODREG) {SMREAD();}
|
||||
// Opcode has wrote
|
||||
#define SMWRITE() dyn->smwrite=1
|
||||
// Opcode has wrote (strongmem>1 only)
|
||||
#define SMWRITE2() if(box64_dynarec_strongmem>1) dyn->smwrite=1
|
||||
// Opcode has wrote with option forced lock
|
||||
#define SMWRITELOCK(lock) if(lock) {SMDMB();} else dyn->smwrite=1
|
||||
// Opcode migh have wrote (depend on nextop)
|
||||
#define SMMIGHTWRITE() if(!MODREG) {SMWRITE();}
|
||||
// Start of sequence
|
||||
#define SMSTART() SMEND()
|
||||
// End of sequence
|
||||
#define SMEND() if(dyn->smwrite && box64_dynarec_strongmem) {FENCE();} dyn->smwrite=0; dyn->smread=0;
|
||||
// Force a Data memory barrier (for LOCK: prefix)
|
||||
#define SMDMB() FENCE(); dyn->smwrite=0; dyn->smread=1
|
||||
|
||||
//LOCK_* define
|
||||
#define LOCK_LOCK (int*)1
|
||||
|
||||
#ifndef MAYSETFLAGS
|
||||
#define MAYSETFLAGS()
|
||||
#endif
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef SETFLAGS
|
||||
#define SETFLAGS(A, B) \
|
||||
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A, C)
|
||||
#endif
|
||||
#ifndef BARRIER
|
||||
#define BARRIER(A)
|
||||
#endif
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
|
||||
#ifndef TABLE64
|
||||
#define TABLE64(A, V)
|
||||
#endif
|
||||
|
||||
#if STEP < 2
|
||||
#define GETIP(A)
|
||||
#define GETIP_(A)
|
||||
#else
|
||||
// put value in the Table64 even if not using it for now to avoid difference between Step2 and Step3. Needs to be optimized later...
|
||||
#define GETIP(A) \
|
||||
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
|
||||
uint64_t _delta_ip = (A)-dyn->last_ip; \
|
||||
dyn->last_ip += _delta_ip; \
|
||||
if(_delta_ip) { \
|
||||
ADDI(xRIP, xRIP, _delta_ip); \
|
||||
} \
|
||||
} else { \
|
||||
dyn->last_ip = (A); \
|
||||
if(dyn->last_ip<0xffffffff) { \
|
||||
MOV64x(xRIP, dyn->last_ip); \
|
||||
} else \
|
||||
TABLE64(xRIP, dyn->last_ip); \
|
||||
}
|
||||
#define GETIP_(A) \
|
||||
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
|
||||
uint64_t _delta_ip = (A)-dyn->last_ip; \
|
||||
if(_delta_ip) {ADDI(xRIP, xRIP, _delta_ip);} \
|
||||
} else { \
|
||||
if((A)<0xffffffff) { \
|
||||
MOV64x(xRIP, (A)); \
|
||||
} else \
|
||||
TABLE64(xRIP, (A)); \
|
||||
}
|
||||
#endif
|
||||
#define CLEARIP() dyn->last_ip=0
|
||||
|
||||
|
||||
#define MODREG ((nextop&0xC0)==0xC0)
|
||||
|
||||
void rv64_epilog();
|
||||
void* rv64_next(x64emu_t* emu, uintptr_t addr);
|
||||
|
||||
#ifndef STEPNAME
|
||||
#define STEPNAME3(N,M) N##M
|
||||
#define STEPNAME2(N,M) STEPNAME3(N,M)
|
||||
#define STEPNAME(N) STEPNAME2(N, STEP)
|
||||
#endif
|
||||
|
||||
#define native_pass STEPNAME(native_pass)
|
||||
|
||||
#define dynarec64_00 STEPNAME(dynarec64_00)
|
||||
#define dynarec64_0F STEPNAME(dynarec64_0F)
|
||||
#define dynarec64_64 STEPNAME(dynarec64_64)
|
||||
#define dynarec64_65 STEPNAME(dynarec64_65)
|
||||
#define dynarec64_66 STEPNAME(dynarec64_66)
|
||||
#define dynarec64_67 STEPNAME(dynarec64_67)
|
||||
#define dynarec64_D8 STEPNAME(dynarec64_D8)
|
||||
#define dynarec64_D9 STEPNAME(dynarec64_D9)
|
||||
#define dynarec64_DA STEPNAME(dynarec64_DA)
|
||||
#define dynarec64_DB STEPNAME(dynarec64_DB)
|
||||
#define dynarec64_DC STEPNAME(dynarec64_DC)
|
||||
#define dynarec64_DD STEPNAME(dynarec64_DD)
|
||||
#define dynarec64_DE STEPNAME(dynarec64_DE)
|
||||
#define dynarec64_DF STEPNAME(dynarec64_DF)
|
||||
#define dynarec64_F0 STEPNAME(dynarec64_F0)
|
||||
#define dynarec64_660F STEPNAME(dynarec64_660F)
|
||||
#define dynarec64_6664 STEPNAME(dynarec64_6664)
|
||||
#define dynarec64_66F0 STEPNAME(dynarec64_66F0)
|
||||
#define dynarec64_F20F STEPNAME(dynarec64_F20F)
|
||||
#define dynarec64_F30F STEPNAME(dynarec64_F30F)
|
||||
|
||||
#define geted STEPNAME(geted)
|
||||
#define geted32 STEPNAME(geted32)
|
||||
#define geted16 STEPNAME(geted16)
|
||||
#define jump_to_epilog STEPNAME(jump_to_epilog)
|
||||
#define jump_to_next STEPNAME(jump_to_next)
|
||||
#define ret_to_epilog STEPNAME(ret_to_epilog)
|
||||
#define retn_to_epilog STEPNAME(retn_to_epilog)
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog)
|
||||
#define call_c STEPNAME(call_c)
|
||||
#define call_n STEPNAME(call_n)
|
||||
#define grab_segdata STEPNAME(grab_segdata)
|
||||
#define emit_cmp8 STEPNAME(emit_cmp8)
|
||||
#define emit_cmp16 STEPNAME(emit_cmp16)
|
||||
#define emit_cmp32 STEPNAME(emit_cmp32)
|
||||
#define emit_cmp8_0 STEPNAME(emit_cmp8_0)
|
||||
#define emit_cmp16_0 STEPNAME(emit_cmp16_0)
|
||||
#define emit_cmp32_0 STEPNAME(emit_cmp32_0)
|
||||
#define emit_test8 STEPNAME(emit_test8)
|
||||
#define emit_test16 STEPNAME(emit_test16)
|
||||
#define emit_test32 STEPNAME(emit_test32)
|
||||
#define emit_add32 STEPNAME(emit_add32)
|
||||
#define emit_add32c STEPNAME(emit_add32c)
|
||||
#define emit_add8 STEPNAME(emit_add8)
|
||||
#define emit_add8c STEPNAME(emit_add8c)
|
||||
#define emit_sub32 STEPNAME(emit_sub32)
|
||||
#define emit_sub32c STEPNAME(emit_sub32c)
|
||||
#define emit_sub8 STEPNAME(emit_sub8)
|
||||
#define emit_sub8c STEPNAME(emit_sub8c)
|
||||
#define emit_or32 STEPNAME(emit_or32)
|
||||
#define emit_or32c STEPNAME(emit_or32c)
|
||||
#define emit_xor32 STEPNAME(emit_xor32)
|
||||
#define emit_xor32c STEPNAME(emit_xor32c)
|
||||
#define emit_and32 STEPNAME(emit_and32)
|
||||
#define emit_and32c STEPNAME(emit_and32c)
|
||||
#define emit_or8 STEPNAME(emit_or8)
|
||||
#define emit_or8c STEPNAME(emit_or8c)
|
||||
#define emit_xor8 STEPNAME(emit_xor8)
|
||||
#define emit_xor8c STEPNAME(emit_xor8c)
|
||||
#define emit_and8 STEPNAME(emit_and8)
|
||||
#define emit_and8c STEPNAME(emit_and8c)
|
||||
#define emit_add16 STEPNAME(emit_add16)
|
||||
#define emit_add16c STEPNAME(emit_add16c)
|
||||
#define emit_sub16 STEPNAME(emit_sub16)
|
||||
#define emit_sub16c STEPNAME(emit_sub16c)
|
||||
#define emit_or16 STEPNAME(emit_or16)
|
||||
#define emit_or16c STEPNAME(emit_or16c)
|
||||
#define emit_xor16 STEPNAME(emit_xor16)
|
||||
#define emit_xor16c STEPNAME(emit_xor16c)
|
||||
#define emit_and16 STEPNAME(emit_and16)
|
||||
#define emit_and16c STEPNAME(emit_and16c)
|
||||
#define emit_inc32 STEPNAME(emit_inc32)
|
||||
#define emit_inc16 STEPNAME(emit_inc16)
|
||||
#define emit_inc8 STEPNAME(emit_inc8)
|
||||
#define emit_dec32 STEPNAME(emit_dec32)
|
||||
#define emit_dec16 STEPNAME(emit_dec16)
|
||||
#define emit_dec8 STEPNAME(emit_dec8)
|
||||
#define emit_adc32 STEPNAME(emit_adc32)
|
||||
#define emit_adc32c STEPNAME(emit_adc32c)
|
||||
#define emit_adc8 STEPNAME(emit_adc8)
|
||||
#define emit_adc8c STEPNAME(emit_adc8c)
|
||||
#define emit_adc16 STEPNAME(emit_adc16)
|
||||
#define emit_adc16c STEPNAME(emit_adc16c)
|
||||
#define emit_sbb32 STEPNAME(emit_sbb32)
|
||||
#define emit_sbb32c STEPNAME(emit_sbb32c)
|
||||
#define emit_sbb8 STEPNAME(emit_sbb8)
|
||||
#define emit_sbb8c STEPNAME(emit_sbb8c)
|
||||
#define emit_sbb16 STEPNAME(emit_sbb16)
|
||||
#define emit_sbb16c STEPNAME(emit_sbb16c)
|
||||
#define emit_neg32 STEPNAME(emit_neg32)
|
||||
#define emit_neg16 STEPNAME(emit_neg16)
|
||||
#define emit_neg8 STEPNAME(emit_neg8)
|
||||
#define emit_shl32 STEPNAME(emit_shl32)
|
||||
#define emit_shl32c STEPNAME(emit_shl32c)
|
||||
#define emit_shr32 STEPNAME(emit_shr32)
|
||||
#define emit_shr32c STEPNAME(emit_shr32c)
|
||||
#define emit_sar32c STEPNAME(emit_sar32c)
|
||||
#define emit_rol32c STEPNAME(emit_rol32c)
|
||||
#define emit_ror32c STEPNAME(emit_ror32c)
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
|
||||
#define x87_do_push STEPNAME(x87_do_push)
|
||||
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
|
||||
#define x87_do_pop STEPNAME(x87_do_pop)
|
||||
#define x87_get_current_cache STEPNAME(x87_get_current_cache)
|
||||
#define x87_get_cache STEPNAME(x87_get_cache)
|
||||
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
|
||||
#define x87_get_st STEPNAME(x87_get_st)
|
||||
#define x87_get_st_empty STEPNAME(x87_get_st)
|
||||
#define x87_refresh STEPNAME(x87_refresh)
|
||||
#define x87_forget STEPNAME(x87_forget)
|
||||
#define x87_reget_st STEPNAME(x87_reget_st)
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
#define x87_swapreg STEPNAME(x87_swapreg)
|
||||
#define x87_setround STEPNAME(x87_setround)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
#define sse_setround STEPNAME(sse_setround)
|
||||
#define mmx_get_reg STEPNAME(mmx_get_reg)
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
#define sse_get_reg STEPNAME(sse_get_reg)
|
||||
#define sse_get_reg_empty STEPNAME(sse_get_reg_empty)
|
||||
#define sse_forget_reg STEPNAME(sse_forget_reg)
|
||||
#define sse_purge07cache STEPNAME(sse_purge07cache)
|
||||
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_reset_cache STEPNAME(fpu_reset_cache)
|
||||
#define fpu_propagate_stack STEPNAME(fpu_propagate_stack)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#define mmx_purgecache STEPNAME(mmx_purgecache)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
#ifdef HAVE_TRACE
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
#define rv64_move64 STEPNAME(rv64_move64)
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
//uintptr_t geted(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
//uintptr_t geted32(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int* l, int s, int delta);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
//uintptr_t geted16(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, int s);
|
||||
|
||||
|
||||
// generic x64 helper
|
||||
void jump_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
//void ret_to_epilog(dynarec_rv64_t* dyn, int ninst);
|
||||
//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 emit_cmp8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
//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);
|
||||
//void emit_cmp8_0(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
//void emit_cmp16_0(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
//void emit_cmp32_0(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
//void emit_test8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
//void emit_test16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
//void emit_test32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_add32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
|
||||
//void emit_add8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_add8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
//void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_sub32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
|
||||
//void emit_sub8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_sub8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5);
|
||||
//void emit_or32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_or32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
|
||||
//void emit_xor32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_xor32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
|
||||
//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_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_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);
|
||||
//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);
|
||||
//void emit_and16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_and16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
//void emit_inc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
//void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
//void emit_inc8(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
//void emit_dec32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
//void emit_dec16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
//void emit_dec8(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
//void emit_adc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_adc32c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
//void emit_adc8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_adc8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5);
|
||||
//void emit_adc16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_adc16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
//void emit_sbb32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_sbb32c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
//void emit_sbb8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_sbb8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5);
|
||||
//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_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);
|
||||
//void emit_shl32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
//void emit_shr32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_shr32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
//void emit_sar32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
//void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
//void emit_ror32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
//void emit_shrd32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
//void emit_shld32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
|
||||
//void emit_pf(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
|
||||
// x87 helper
|
||||
// cache of the local stack counter, to avoid upadte at every call
|
||||
//void x87_stackcount(dynarec_rv64_t* dyn, int ninst, int scratch);
|
||||
// fpu push. Return the Dd value to be used
|
||||
//int x87_do_push(dynarec_rv64_t* dyn, int ninst, int s1, int t);
|
||||
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
|
||||
//void x87_do_push_empty(dynarec_rv64_t* dyn, int ninst, int s1);
|
||||
// fpu pop. All previous returned Dd should be considered invalid
|
||||
//void x87_do_pop(dynarec_rv64_t* dyn, int ninst, int s1);
|
||||
// get cache index for a x87 reg, return -1 if cache doesn't exist
|
||||
//int x87_get_current_cache(dynarec_rv64_t* dyn, int ninst, int st, int t);
|
||||
// get cache index for a x87 reg, create the entry if needed
|
||||
//int x87_get_cache(dynarec_rv64_t* dyn, int ninst, int populate, int s1, int s2, int a, int t);
|
||||
// get neoncache index for a x87 reg
|
||||
//int x87_get_neoncache(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int a);
|
||||
// get vfpu register for a x87 reg, create the entry if needed
|
||||
//int x87_get_st(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// get vfpu register for a x87 reg, create the entry if needed. Do not fetch the Stx if not already in cache
|
||||
//int x87_get_st_empty(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// refresh a value from the cache ->emu (nothing done if value is not cached)
|
||||
//void x87_refresh(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh a value from the cache ->emu and then forget the cache (nothing done if value is not cached)
|
||||
//void x87_forget(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh the cache value from emu
|
||||
//void x87_reget_st(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// swap 2 x87 regs
|
||||
//void x87_swapreg(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int a, int b);
|
||||
// Set rounding according to cw flags, return reg to restore flags
|
||||
//int x87_setround(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Restore round flag
|
||||
//void x87_restoreround(dynarec_rv64_t* dyn, int ninst, int s1);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
//int sse_setround(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
//void CacheTransform(dynarec_rv64_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
|
||||
void rv64_move64(dynarec_rv64_t* dyn, int ninst, int reg, int64_t val);
|
||||
|
||||
#if STEP < 2
|
||||
#define CHECK_CACHE() 0
|
||||
#else
|
||||
#define CHECK_CACHE() (cacheupd = CacheNeedsTransform(dyn, ninst))
|
||||
#endif
|
||||
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_rv64_t* dyn);
|
||||
// reset the cache with n
|
||||
void fpu_reset_cache(dynarec_rv64_t* dyn, int ninst, int reset_n);
|
||||
// propagate stack state
|
||||
void fpu_propagate_stack(dynarec_rv64_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers)
|
||||
void fpu_purgecache(dynarec_rv64_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
// purge MMX cache
|
||||
void mmx_purgecache(dynarec_rv64_t* dyn, int ninst, int next, int s1);
|
||||
// purge x87 cache
|
||||
void x87_purgecache(dynarec_rv64_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#endif
|
||||
void fpu_pushcache(dynarec_rv64_t* dyn, int ninst, int s1, int not07);
|
||||
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 rep, 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);
|
||||
//uintptr_t dynarec64_D8(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_D9(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_DA(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_DB(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_DC(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_DD(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_DE(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_DF(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_F0(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_660F(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_6664(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_66F0(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_F20F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
|
||||
#if STEP < 2
|
||||
#define PASS2(A)
|
||||
#else
|
||||
#define PASS2(A) A
|
||||
#endif
|
||||
|
||||
#if STEP < 3
|
||||
#define PASS3(A)
|
||||
#else
|
||||
#define PASS3(A) A
|
||||
#endif
|
||||
|
||||
#if STEP < 3
|
||||
#define MAYUSE(A) (void)A
|
||||
#else
|
||||
#define MAYUSE(A)
|
||||
#endif
|
||||
|
||||
#endif //__DYNAREC_RV64_HELPER_H__
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rv64_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block
|
||||
void CreateJmpNext(void* addr, void* next)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
uintptr_t diff = (intptr_t)next - (intptr_t)addr;
|
||||
AUIPC(x2, diff>>12);
|
||||
LD_I12(x2, x2, diff&0b111111111111);
|
||||
BR(x2);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
#define INIT uintptr_t sav_addr=addr
|
||||
#define FINI \
|
||||
dyn->isize = addr-sav_addr; \
|
||||
dyn->insts[ninst].x64.addr = addr; \
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x64.use_flags = A; dyn->f.dfnone = 1;\
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = B; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0;
|
||||
#define EMIT(A)
|
||||
#define JUMP(A, C) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst+1].x64.barrier = A
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_native_t*)customRealloc(dyn->insts, sizeof(instruction_native_t)*dyn->cap*2);\
|
||||
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_native_t)*dyn->cap); \
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
dyn->insts[ninst].x64.addr = ip; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;}
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
dyn->insts[ninst].x64.has_next = (ok>0)?1:0;
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box64_dynarec_log>=LOG_INFO) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
PKip(7), PKip(8), PKip(9), \
|
||||
PKip(10),PKip(11),PKip(12), \
|
||||
PKip(13),PKip(14)); \
|
||||
printFunctionAddr(ip, " => "); \
|
||||
dynarec_log(LOG_NONE, "\n"); \
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f
|
||||
|
||||
#define INST_NAME(name)
|
||||
@@ -0,0 +1,19 @@
|
||||
#define INIT dyn->native_size = 0
|
||||
#define FINI \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst].x64.size>dyn->insts[ninst].size)?dyn->insts[ninst].x64.size:dyn->insts[ninst].size)/15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->native_size+=4
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
if(isInstClean(dyn, ninst) && dyn->last_ip!=ip) \
|
||||
dyn->last_ip = 0; \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst-1].x64.size>dyn->insts[ninst-1].size)?dyn->insts[ninst-1].x64.size:dyn->insts[ninst-1].size)/15; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
|
||||
#define INST_NAME(name)
|
||||
#define TABLE64(A, V) {Table64(dyn, (V)); EMIT(0); EMIT(0);}
|
||||
@@ -0,0 +1,53 @@
|
||||
#define INIT
|
||||
#define FINI \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst].x64.size, dyn->insts[ninst].size/4); \
|
||||
addInst(dyn->instsize, &dyn->insts_size, 0, 0);
|
||||
#define EMIT(A) \
|
||||
if(box64_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (uint32_t)(A), rv64_print(A, (uintptr_t)dyn->block));} \
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; dyn->native_size += 4; \
|
||||
dyn->insts[ninst].size2 += 4
|
||||
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
if(dyn->last_ip!=ip) dyn->last_ip = 0; \
|
||||
} \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4);
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
if(box64_dynarec_dump) {\
|
||||
printf_x64_instruction(my_context->dec, &dyn->insts[ninst].x64, name); \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d/%d", \
|
||||
(box64_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->native_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
ninst, \
|
||||
dyn->insts[ninst].x64.barrier, \
|
||||
dyn->insts[ninst].x64.state_flags, \
|
||||
dyn->f.pending, \
|
||||
dyn->f.dfnone, \
|
||||
dyn->insts[ninst].x64.may_set?"may":"set", \
|
||||
dyn->insts[ninst].x64.set_flags, \
|
||||
dyn->insts[ninst].x64.gen_flags, \
|
||||
dyn->insts[ninst].x64.use_flags, \
|
||||
dyn->insts[ninst].x64.need_before, \
|
||||
dyn->insts[ninst].x64.need_after, \
|
||||
dyn->smread, dyn->smwrite); \
|
||||
if(dyn->insts[ninst].pred_sz) { \
|
||||
dynarec_log(LOG_NONE, ", pred="); \
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)\
|
||||
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);\
|
||||
} \
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts>=0)\
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);\
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)\
|
||||
dynarec_log(LOG_NONE, ", jmp=out"); \
|
||||
if(dyn->last_ip) \
|
||||
dynarec_log(LOG_NONE, ", last_ip=%p", (void*)dyn->last_ip);\
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); AUIPC(A, (val64offset>>12)); LD_I12(A, A, (val64offset&0b111111111111));}
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef __DYNAREC_RV64_PRIVATE_H_
|
||||
#define __DYNAREC_RV64_PRIVATE_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../dynarec_private.h"
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct instsize_s instsize_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_rv64_s {
|
||||
instruction_x64_t x64;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, or barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
int pred_sz; // size of predecessor list
|
||||
int *pred; // predecessor array
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
int barrier_maybe;
|
||||
flagcache_t f_exit; // flags status at end of intruction
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
} instruction_rv64_t;
|
||||
|
||||
typedef struct dynarec_rv64_s {
|
||||
instruction_rv64_t* insts;
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
uint32_t isize; // size in byte of x64 instructions included
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t native_start; // start of the arm code
|
||||
size_t native_size; // size of emitted arm code
|
||||
uintptr_t last_ip; // last set IP in RIP (or NULL if unclean state) TODO: move to a cache something
|
||||
uint64_t* table64; // table of 64bits value
|
||||
int table64size;// size of table (will be appended at end of executable code)
|
||||
int table64cap;
|
||||
uintptr_t tablestart;
|
||||
flagcache_t f;
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
uint8_t smread; // for strongmem model emulation
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uintptr_t forward; // address of the last end of code while testing forward
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
} dynarec_rv64_t;
|
||||
|
||||
void add_next(dynarec_rv64_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_rv64_t *dyn, uintptr_t addr);
|
||||
int is_nops(dynarec_rv64_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_rv64_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
int Table64(dynarec_rv64_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
|
||||
//TODO: GO_TRACE() !
|
||||
#define GO_TRACE()
|
||||
|
||||
#endif //__DYNAREC_RV64_PRIVATE_H_
|
||||
@@ -0,0 +1,202 @@
|
||||
#ifndef __RV64_EMITTER_H__
|
||||
#define __RV64_EMITTER_H__
|
||||
/*
|
||||
RV64 Emitter
|
||||
|
||||
*/
|
||||
|
||||
// RV64 ABI
|
||||
/*
|
||||
reg name description saver
|
||||
------------------------------------------------------
|
||||
x0 zero Hard-wired zero —
|
||||
x1 ra Return address Caller
|
||||
x2 sp Stack pointer Callee
|
||||
x3 gp Global pointer —
|
||||
x4 tp Thread pointer —
|
||||
x5–7 t0–2 Temporaries Caller
|
||||
x8 s0/fp Saved register/frame pointer Callee
|
||||
x9 s1 Saved register Callee
|
||||
x10–11 a0–1 Function arguments/return val. Caller
|
||||
x12–17 a2–7 Function arguments Caller
|
||||
x18–27 s2–11 Saved registers Callee
|
||||
x28–31 t3–6 Temporaries Caller
|
||||
-------------------------------------------------------
|
||||
f0–7 ft0–7 FP temporaries Caller
|
||||
f8–9 fs0–1 FP saved registers Callee
|
||||
f10–11 fa0–1 FP arguments/return values Caller
|
||||
f12–17 fa2–7 FP arguments Caller
|
||||
f18–27 fs2–11 FP saved registers Callee
|
||||
f28–31 ft8–11 FP temporaries Caller
|
||||
*/
|
||||
// x86 Register mapping
|
||||
#define xRAX 16
|
||||
#define xRCX 17
|
||||
#define xRDX 18
|
||||
#define xRBX 19
|
||||
#define xRSP 20
|
||||
#define xRBP 21
|
||||
#define xRSI 22
|
||||
#define xRDI 23
|
||||
#define xR8 24
|
||||
#define xR9 25
|
||||
#define xR10 26
|
||||
#define xR11 27
|
||||
#define xR12 28
|
||||
#define xR13 29
|
||||
#define xR14 30
|
||||
#define xR15 31
|
||||
#define xFlags 5
|
||||
#define xRIP 6
|
||||
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
#define wECX xRCX
|
||||
#define wEDX xRDX
|
||||
#define wEBX xRBX
|
||||
#define wESP xRSP
|
||||
#define wEBP xRBP
|
||||
#define wESI xRSI
|
||||
#define wEDI xRDI
|
||||
#define wR8 xR8
|
||||
#define wR9 xR9
|
||||
#define wR10 xR10
|
||||
#define wR11 xR11
|
||||
#define wR12 xR12
|
||||
#define wR13 xR13
|
||||
#define wR14 xR14
|
||||
#define wR15 xR15
|
||||
#define wFlags xFlags
|
||||
// scratch registers
|
||||
#define x1 11
|
||||
#define x2 12
|
||||
#define x3 13
|
||||
#define x4 14
|
||||
#define x5 15
|
||||
#define x6 7
|
||||
// 32bits version of scratch
|
||||
#define w1 x1
|
||||
#define w2 x2
|
||||
#define w3 x3
|
||||
#define w4 x4
|
||||
#define w5 x5
|
||||
#define w6 x6
|
||||
#define w7 x7
|
||||
// emu is r10
|
||||
#define xEmu 10
|
||||
// RV64 RA
|
||||
#define xRA 1
|
||||
#define xSP 2
|
||||
// RV64 args
|
||||
#define A0 10
|
||||
#define A1 11
|
||||
// xZR reg is 0
|
||||
#define xZR 0
|
||||
#define wZR xZR
|
||||
|
||||
// MOVE64x is quite complex, so use a function for this
|
||||
#define MOV64x(A, B) rv64_move64(dyn, ninst, A, B)
|
||||
|
||||
// ZERO the upper part
|
||||
#define ZEROUP(r) SLLI(r, r, 32); SRLI(r, r, 32)
|
||||
|
||||
#define R_type(funct7, rs2, rs1, funct3, rd, opcode) ((funct7)<<25 | (rs2)<<20 | (rs1)<<15 | (funct3)<<12 | (rd)<<7 | (opcode))
|
||||
#define I_type(imm12, rs1, funct3, rd, opcode) ((imm12)<<20 | (rs1)<<15 | (funct3)<<12 | (rd)<<7 | (opcode))
|
||||
#define S_type(imm12, rs2, rs1, funct3, opcode) (((imm12)>>5)<<25 | (rs2)<<20 | (rs1)<<15 | (funct3)<<12 | ((imm12)&31)<<7 | (opcode))
|
||||
#define B_type(imm13, rs2, rs1, funct3, opcode) ((((imm13)>>12)&1)<<31 | (((imm13)>>5)&63)<<25 | (rs)<<20 | (rs1)<<15 | (funct3)<<13 | (((imm13)>>1)&15)<<8 | (((imm13)>>11)&1)<<7 | (opcode))
|
||||
#define U_type(imm32, rd, opcode) (((imm32)>>12)<<12 | (rd)<<7 | (opcode))
|
||||
#define J_type(imm21, rd, opcode) ((((imm21)>>20)&1)<<31 | (((imm21)>>1)&0b1111111111)<<21 | (((imm21)>>11)&1)<<20 | (((imm21)>>12)&0b11111111)<<12 | (rd)<<7 | (opcode))
|
||||
|
||||
// RV32I
|
||||
// put imm20 in the [31:12] bits of rd, zero [11:0] and sign extend bits31
|
||||
#define LUI(rd, imm20) EMIT(U_type((imm20)<<12, rd, 0b0110111))
|
||||
// put PC+imm20 in rd
|
||||
#define AUIPC(rd, imm20) EMIT(U_type((imm20)>>12, rd, 0b0010111))
|
||||
|
||||
#define JAL_gen(rd, imm21) J_type(imm21, rd, 0b1101111)
|
||||
// Unconditionnal branch, no return address set
|
||||
#define B(imm21) EMIT(JAL_gen(xZR, imm21))
|
||||
// Uncondiftionnal branch, return set to xRA
|
||||
#define JAL(imm21) EMIT(JAL_gen(xRA, imm21))
|
||||
|
||||
#define JALR_gen(rd, rs1, imm12) I_type(imm12, rs1, 0b000, rd, 0b1100111)
|
||||
// Unconditionnal branch to r, no return address set
|
||||
#define BR(r) EMIT(JALR_gen(xZR, r, 0))
|
||||
// Unconditionnal branch to r+i12, no return address set
|
||||
#define BR_I12(r, imm12) EMIT(JALR_gen(xZR, r, (imm12)&0b111111111111))
|
||||
// Unconditionnal branch to r, return address set to xRA
|
||||
#define JALR(r) EMIT(JALR_gen(xRA, r, 0))
|
||||
// Unconditionnal branch to r+i12, return address set to xRA
|
||||
#define JALR_I12(r, imm12) EMIT(JALR_gen(xRA, r, (imm12)&0b111111111111))
|
||||
|
||||
// rd = rs1 + imm12
|
||||
#define ADDI(rd, rs1, imm12) EMIT(I_type((imm12)&0b111111111111, rs1, 0b000, rd, 0b0010011))
|
||||
// rd = rs1 - imm12 (pseudo instruction)
|
||||
#define SUBI(rd, rs1, imm12) EMIT(I_type((-imm12)&0b111111111111, rs1, 0b000, rd, 0b0010011))
|
||||
// rd = (rs1<imm12)?1:0
|
||||
#define SLTI(rd, rs1, imm12) EMIT(I_type((imm12)&0b111111111111, rs1, 0b010, rd, 0b0010011))
|
||||
// rd = (rs1<imm12)?1:0 unsigned
|
||||
#define SLTIU(rd, rs1, imm12) EMIT(I_type((imm12)&0b111111111111, rs1, 0b011, rd, 0b0010011))
|
||||
// rd = rs1 ^ imm12
|
||||
#define XORI(rd, rs1, imm12) EMIT(I_type((imm12)&0b111111111111, rs1, 0b100, rd, 0b0010011))
|
||||
// rd = rs1 | imm12
|
||||
#define ORI(rd, rs1, imm12) EMIT(I_type((imm12)&0b111111111111, rs1, 0b110, rd, 0b0010011))
|
||||
// rd = rs1 & imm12
|
||||
#define ANDI(rd, rs1, imm12) EMIT(I_type((imm12)&0b111111111111, rs1, 0b101, rd, 0b0010011))
|
||||
|
||||
// rd = imm12
|
||||
#define MOV_U12(rd, imm12) ADDI(rd, xZR, imm12)
|
||||
// nop
|
||||
#define NOP() ADDI(xZR, xZR, 0)
|
||||
|
||||
// rd = rs1 + rs2
|
||||
#define ADD(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b000, rd, 0b0110011))
|
||||
// rd = rs1 - rs2
|
||||
#define SUB(rd, rs1, rs2) EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, 0b0110011))
|
||||
// rd = rs1<<rs2
|
||||
#define SLL(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b001, rd, 0b0110011))
|
||||
// rd = (rs1<rs2)?1:0
|
||||
#define SLT(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b010, rd, 0b0110011))
|
||||
// rd = (rs1<rs2)?1:0 Unsigned
|
||||
#define SLTU(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b011, rd, 0b0110011))
|
||||
// rd = rs1 ^ rs2
|
||||
#define XOR(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b100, rd, 0b0110011))
|
||||
// rd = rs1>>rs2 logical
|
||||
#define SRL(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b101, rd, 0b0110011))
|
||||
// rd = rs1>>rs2 aritmetic
|
||||
#define SRA(rd, rs1, rs2) EMIT(R_type(0b0100000, rs2, rs1, 0b101, rd, 0b0110011))
|
||||
// rd = rs1 | rs2
|
||||
#define OR(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b110, rd, 0b0110011))
|
||||
// rd = rs1 & rs2
|
||||
#define AND(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b111, rd, 0b0110011))
|
||||
|
||||
// rd = rs1 (pseudo instruction)
|
||||
#define MV(rd, rs1) ADDI(rd, rs1, 0)
|
||||
// rd = !rs1
|
||||
#define NOT(rd, rs1) XORI(rd, rs1, -1)
|
||||
// rd = -rs1
|
||||
#define NEG(rd, rs1) SUB(rd, xZR, rs1)
|
||||
|
||||
#define FENCE_gen(pred, succ) (((pred)<<24) | ((succ)<<20) | 0b0001111)
|
||||
#define FENCE() EMIT(FENCE_gen(3, 3))
|
||||
|
||||
#define FENCE_I_gen() ((0b001<<12) | 0b0001111)
|
||||
#define FENCE_I() EMIT(FENCE_I_gen())
|
||||
|
||||
// RV64I
|
||||
#define LWU_gen(rd, rs1, imm12) I_type(imm12, rs1, 0b110, rd, 0b0000011)
|
||||
|
||||
// rd = [rs1 + imm12]
|
||||
#define LD_I12(rd, rs1, imm12) EMIT(I_type(imm12, rs1, 0b011, rd, 0b0000011))
|
||||
// [rs1 + imm12] = rs2
|
||||
#define SD_I12(rs2, rs1, imm12) EMIT(S_type(imm12, rs2, rs1, 0b011, 0b0100011))
|
||||
|
||||
// Shift Left Immediate
|
||||
#define SLLI(rd, rs1, imm6) EMIT(I_type(imm6, rs1, 0b001, rd, 0b0010011))
|
||||
// Shift Right Logical Immediate
|
||||
#define SRLI(rd, rs1, imm6) EMIT(I_type(imm6, rs1, 0b101, rd, 0b0010011))
|
||||
// Shift Right Aritmetic Immediate
|
||||
#define SRAI(rd, rs1, imm6) EMIT(I_type((imm6)|(0b010000<<6), rs1, 0b101, rd, 0b0010011))
|
||||
|
||||
|
||||
#endif //__RV64_EMITTER_H__
|
||||
@@ -0,0 +1,61 @@
|
||||
//riscv epilog for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global rv64_epilog
|
||||
rv64_epilog:
|
||||
//update register -> emu
|
||||
sd x16, (a0)
|
||||
sd x17, 8(a0)
|
||||
sd x18, 16(a0)
|
||||
sd x19, 24(a0)
|
||||
sd x20, 32(a0)
|
||||
sd x21, 40(a0)
|
||||
sd x22, 48(a0)
|
||||
sd x23, 56(a0)
|
||||
sd x24, 64(a0)
|
||||
sd x25, 72(a0)
|
||||
sd x26, 80(a0)
|
||||
sd x27, 88(a0)
|
||||
sd x28, 96(a0)
|
||||
sd x29, 104(a0)
|
||||
sd x30, 112(a0)
|
||||
sd x31, 120(a0)
|
||||
sd x5, 128(a0) //xFlags
|
||||
sd x6, 136(a0) // put back reg value in emu, including EIP (so x27 must be EIP now)
|
||||
//restore all used register
|
||||
ld ra, (sp) // save ra
|
||||
ld x8, 8(sp) // save fp
|
||||
ld x18, 16(sp)
|
||||
ld x19, 24(sp)
|
||||
ld x20, 32(sp)
|
||||
ld x21, 40(sp)
|
||||
ld x22, 48(sp)
|
||||
ld x23, 56(sp)
|
||||
ld x24, 64(sp)
|
||||
ld x25, 72(sp)
|
||||
ld x26, 80(sp)
|
||||
ld x27, 88(sp)
|
||||
fsd f8, 96(sp)
|
||||
fsd f9, 104(sp)
|
||||
addi sp, sp, (8 * 14)
|
||||
//end, return...
|
||||
ret
|
||||
|
||||
|
||||
.global rv64_epilog_fast
|
||||
rv64_epilog_fast:
|
||||
//restore all used register
|
||||
ld ra, (sp) // save ra
|
||||
ld x8, 8(sp) // save fp
|
||||
ld x16, 16(sp)
|
||||
ld x17, 24(sp)
|
||||
fld f8, 32(sp)
|
||||
fld f9, 40(sp)
|
||||
addi sp, sp, (8 * (2+4))
|
||||
//end, return...
|
||||
ret
|
||||
@@ -5,16 +5,6 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global rv64_lock_read_b
|
||||
.global rv64_lock_write_b
|
||||
.global rv64_lock_read_h
|
||||
.global rv64_lock_write_h
|
||||
.global rv64_lock_read_d
|
||||
.global rv64_lock_write_d
|
||||
.global rv64_lock_read_dd
|
||||
.global rv64_lock_write_dd
|
||||
.global rv64_lock_read_dq
|
||||
.global rv64_lock_write_dq
|
||||
.global rv64_lock_xchg
|
||||
.global rv64_lock_xchg_d
|
||||
.global rv64_lock_storeifnull
|
||||
@@ -27,77 +17,9 @@
|
||||
.global rv64_lock_incif0
|
||||
.global rv64_lock_decifnot0
|
||||
.global rv64_lock_store
|
||||
|
||||
rv64_lock_read_b:
|
||||
// address is a0, return is a0
|
||||
lr.w.aqrl a0, (a0)
|
||||
andi a0, a0, 0xff
|
||||
ret
|
||||
|
||||
rv64_lock_write_b:
|
||||
// address is a0, value is a1, return is a0
|
||||
andi a1, a1, 0xff
|
||||
sc.w.aqrl a0, a1, (a0)
|
||||
snez a0, a0
|
||||
ret
|
||||
|
||||
rv64_lock_read_h:
|
||||
// address is a0, return is a0
|
||||
lr.w.aqrl a0, (a0)
|
||||
slli a0, a0, 48
|
||||
srli a0, a0, 48
|
||||
ret
|
||||
|
||||
rv64_lock_write_h:
|
||||
// address is a0, value is a1, return is a0
|
||||
slli a1, a1, 48
|
||||
srli a1, a1, 48
|
||||
sc.w.aqrl a0, a1, (a0)
|
||||
snez a0, a0
|
||||
ret
|
||||
|
||||
rv64_lock_read_d:
|
||||
// address is a0, return is a0
|
||||
lr.w.aqrl a0, (a0)
|
||||
ret
|
||||
|
||||
|
||||
rv64_lock_write_d:
|
||||
// address is a0, value is a1, return is a0
|
||||
sc.w.aqrl a0, a1, (a0)
|
||||
snez a0, a0
|
||||
ret
|
||||
|
||||
rv64_lock_read_dd:
|
||||
// address is a0, return is a0
|
||||
lr.d.aqrl a0, (a0)
|
||||
ret
|
||||
|
||||
rv64_lock_write_dd:
|
||||
// address is a0, value is a1, return is a0
|
||||
sc.d.aqrl a0, a1, (a0)
|
||||
snez a0, a0
|
||||
ret
|
||||
|
||||
rv64_lock_read_dq:
|
||||
// address is a2, return a0, a1
|
||||
fence rw, rw
|
||||
lr.d a3, (a2)
|
||||
sd a3, (a0)
|
||||
addi a2, a2, 8
|
||||
lr.d a3, (a2)
|
||||
sd a3, (a1)
|
||||
ret
|
||||
|
||||
rv64_lock_write_dq:
|
||||
// address is a2, value is a0, a1, return is a0
|
||||
sc.d a3, a0, (a2)
|
||||
addi a2, a2, 8
|
||||
sc.d a4, a1, (a2)
|
||||
fence rw, rw
|
||||
add a0, a3, a4
|
||||
snez a0, a0
|
||||
ret
|
||||
.global rv64_lock_cas_d
|
||||
.global rv64_lock_cas_dd
|
||||
.global rv64_lock_cas_dq
|
||||
|
||||
rv64_lock_xchg:
|
||||
// address is a0, value is a1, return old value in a0
|
||||
@@ -220,3 +142,32 @@ rv64_lock_store:
|
||||
sw a1, 0(a0)
|
||||
fence rw, rw
|
||||
ret
|
||||
|
||||
rv64_lock_cas_d:
|
||||
lr.w t0, (a0)
|
||||
bne t0, a1, 1f
|
||||
sc.w a0, a2, (a0)
|
||||
ret
|
||||
1:
|
||||
li a0, 1
|
||||
ret
|
||||
|
||||
rv64_lock_cas_dd:
|
||||
lr.d t0, (a0)
|
||||
bne t0, a1, 1f
|
||||
sc.d a0, a2, (a0)
|
||||
ret
|
||||
1:
|
||||
li a0, 1
|
||||
ret
|
||||
|
||||
rv64_lock_cas_dq:
|
||||
mv a4, a0
|
||||
lr.d t0, (a0)
|
||||
bne t0, a1, 1f
|
||||
sc.d a0, a2, (a0)
|
||||
sd a3,(a4)
|
||||
ret
|
||||
1:
|
||||
li a0, 1
|
||||
ret
|
||||
@@ -2,30 +2,11 @@
|
||||
#define __RV64_LOCK__H__
|
||||
#include <stdint.h>
|
||||
|
||||
// Atomic read of ADDR
|
||||
extern uint8_t rv64_lock_read_b(void* addr);
|
||||
// Atomic store for ADDR, return 0 if ok, 1 if not
|
||||
extern int rv64_lock_write_b(void* addr, uint8_t val);
|
||||
// Atomicaly store val at [p] if old [p] is ref. Return 0 if OK, 1 is not. p needs to be aligned
|
||||
extern int rv64_lock_cas_d(void* p, int32_t ref, int32_t val);
|
||||
|
||||
// Atomic read of ADDR
|
||||
extern uint16_t rv64_lock_read_h(void* addr);
|
||||
// Atomic store for ADDR, return 0 if ok, 1 if not
|
||||
extern int rv64_lock_write_h(void* addr, uint16_t val);
|
||||
|
||||
// Atoomic read of ADDR
|
||||
extern uint32_t rv64_lock_read_d(void* addr);
|
||||
// Atomic store for ADDR, return 0 if ok, 1 if not
|
||||
extern int rv64_lock_write_d(void* addr, uint32_t val);
|
||||
|
||||
// Atomic read of ADDR
|
||||
extern uint64_t rv64_lock_read_dd(void* addr);
|
||||
// Atomic store for ADDR, return 0 if ok, 1 if not
|
||||
extern int rv64_lock_write_dd(void* addr, uint64_t val);
|
||||
|
||||
// Atomic read of ADDR
|
||||
extern void rv64_lock_read_dq(uint64_t * a, uint64_t* b, void* addr);
|
||||
// Atomic store for ADDR, return 0 if ok, 1 if not
|
||||
extern int rv64_lock_write_dq(uint64_t a, uint64_t b, void* addr);
|
||||
// Atomicaly store val at [p] if old [p] is ref. Return 0 if OK, 1 is not. p needs to be aligned
|
||||
extern int rv64_lock_cas_dd(void* p, int64_t ref, int64_t val);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uintptr_t rv64_lock_xchg(void* p, uintptr_t val);
|
||||
@@ -63,4 +44,17 @@ extern int rv64_lock_decifnot0(void*p);
|
||||
// atomic store (with memory barrier)
|
||||
extern void rv64_lock_store(void*p, uint32_t v);
|
||||
|
||||
// (mostly) Atomicaly store val1 and val2 at [p] if old [p] is ref. Return 0 if OK, 1 is not. p needs to be aligned
|
||||
extern int rv64_lock_cas_dq(void* p, uint64_t ref, uint64_t val1, uint64_t val2);
|
||||
|
||||
// Not defined in assembler but in dynarec_rv64_functions
|
||||
uint8_t extract_byte(uint32_t val, void* address);
|
||||
uint32_t insert_byte(uint32_t val, uint8_t b, void* address);
|
||||
uint16_t extract_half(uint32_t val, void* address);
|
||||
uint32_t insert_half(uint32_t val, uint16_t h, void* address);
|
||||
|
||||
uint8_t rv64_lock_xchg_b(void* addr, uint8_t v);
|
||||
extern int rv64_lock_cas_b(void* p, uint8_t ref, uint8_t val);
|
||||
extern int rv64_lock_cas_h(void* p, uint16_t ref, uint16_t val);
|
||||
|
||||
#endif //__RV64_LOCK__H__
|
||||
@@ -0,0 +1,47 @@
|
||||
//riscv update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address of table to as 2nd parameter
|
||||
//ip is at r12
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern LinkNext
|
||||
|
||||
.global rv64_next
|
||||
|
||||
.8byte 0 // NULL pointer before rv64_next, for getDB
|
||||
rv64_next:
|
||||
// emu is a0
|
||||
// IP address is a1
|
||||
addi sp, sp, -(8 * 8)
|
||||
sd a0, (sp)
|
||||
sd a1, 8(sp)
|
||||
sd x5, 16(sp)
|
||||
sd x6, 24(sp)
|
||||
sd x28, 32(sp)
|
||||
sd x29, 40(sp)
|
||||
sd x30, 48(sp)
|
||||
sd x31, 56(sp)
|
||||
|
||||
mv a2, ra // "from" is in ra, so put in a2
|
||||
addi a3, sp, 24 // a3 is address to change rip
|
||||
// call the function
|
||||
1:
|
||||
auipc a4, %pcrel_hi(LinkNext)
|
||||
jalr a4, %pcrel_lo(1b)
|
||||
// preserve return value
|
||||
mv a3, a0
|
||||
// pop regs
|
||||
ld a0, (sp)
|
||||
ld a1, 8(sp)
|
||||
ld x5, 16(sp)
|
||||
ld x6, 24(sp)
|
||||
ld x28, 32(sp)
|
||||
ld x29, 40(sp)
|
||||
ld x30, 48(sp)
|
||||
ld x31, 56(sp)
|
||||
addi sp, sp, (8 * 8)
|
||||
// return offset is jump address
|
||||
jr a3
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rv64_printer.h"
|
||||
#include "debug.h"
|
||||
|
||||
const char* rv64_print(uint32_t opcode, uintptr_t addr)
|
||||
{
|
||||
static char buff[200];
|
||||
|
||||
snprintf(buff, sizeof(buff), "%08X ???", __builtin_bswap32(opcode));
|
||||
return buff;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef _RV64_PRINTER_H_
|
||||
#define _RV64_PRINTER_H_
|
||||
#include <stdint.h>
|
||||
|
||||
const char* rv64_print(uint32_t opcode, uint64_t addr);
|
||||
|
||||
#endif //_RV64_PRINTER_H_
|
||||
@@ -0,0 +1,49 @@
|
||||
//arm prologue for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern rv64_next
|
||||
|
||||
.global rv64_prolog
|
||||
rv64_prolog:
|
||||
//save all 18 used register
|
||||
addi sp, sp, -(8 * 14)
|
||||
sd ra, (sp) // save ra
|
||||
sd x8, 8(sp) // save fp
|
||||
sd x18, 16(sp)
|
||||
sd x19, 24(sp)
|
||||
sd x20, 32(sp)
|
||||
sd x21, 40(sp)
|
||||
sd x22, 48(sp)
|
||||
sd x23, 56(sp)
|
||||
sd x24, 64(sp)
|
||||
sd x25, 72(sp)
|
||||
sd x26, 80(sp)
|
||||
sd x27, 88(sp)
|
||||
fsd f8, 96(sp)
|
||||
fsd f9, 104(sp)
|
||||
// save f18-f27 too probably
|
||||
//setup emu -> register
|
||||
ld x16, (a0)
|
||||
ld x17, 8(a0)
|
||||
ld x18, 16(a0)
|
||||
ld x19, 24(a0)
|
||||
ld x20, 32(a0)
|
||||
ld x21, 40(a0)
|
||||
ld x22, 48(a0)
|
||||
ld x23, 56(a0)
|
||||
ld x24, 64(a0)
|
||||
ld x25, 72(a0)
|
||||
ld x26, 80(a0)
|
||||
ld x27, 88(a0)
|
||||
ld x28, 96(a0)
|
||||
ld x29, 104(a0)
|
||||
ld x30, 112(a0)
|
||||
ld x31, 120(a0)
|
||||
ld x5, 128(a0) //xFlags
|
||||
ld x6, 136(a0) // xRIP
|
||||
jalr a1
|
||||
@@ -424,10 +424,14 @@ x64emurun:
|
||||
GB = EB->byte[0];
|
||||
EB->byte[0] = tmp8u;
|
||||
} else {
|
||||
#ifdef USE_CAS
|
||||
GB = native_lock_xchg_b(EB, GB);
|
||||
#else
|
||||
do {
|
||||
tmp8u = native_lock_read_b(EB);
|
||||
} while(native_lock_write_b(EB, GB));
|
||||
GB = tmp8u;
|
||||
#endif
|
||||
}
|
||||
// dynarec use need it's own mecanism
|
||||
#else
|
||||
@@ -461,10 +465,14 @@ x64emurun:
|
||||
if(rex.w) {
|
||||
GD->q[0] = native_lock_xchg(ED, GD->q[0]);
|
||||
} else {
|
||||
#ifdef USE_CAS
|
||||
GD->q[0] = native_lock_xchg(ED, GD->dword[0]);
|
||||
#else
|
||||
do {
|
||||
tmp32u = native_lock_read_d(ED);
|
||||
} while(native_lock_write_d(ED, GD->dword[0]));
|
||||
GD->q[0] = tmp32u;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -34,6 +34,9 @@ uintptr_t Run66F0(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
int64_t tmp64s;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
reg64_t *oped, *opgd;
|
||||
#ifdef USE_CAS
|
||||
uint64_t tmpcas;
|
||||
#endif
|
||||
|
||||
opcode = F8;
|
||||
// REX prefix before the F0 are ignored
|
||||
|
||||
@@ -36,6 +36,9 @@ uintptr_t RunF0(x64emu_t *emu, rex_t rex, uintptr_t addr)
|
||||
int64_t tmp64s;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
reg64_t *oped, *opgd;
|
||||
#ifdef USE_CAS
|
||||
uint64_t tmpcas;
|
||||
#endif
|
||||
|
||||
opcode = F8;
|
||||
// REX prefix before the F0 are ignored
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef __DYNAREC_RV64_H_
|
||||
#define __DYNAREC_RV64_H_
|
||||
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
void CancelBlock64();
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr);
|
||||
|
||||
#endif //__DYNAREC_RV64_H_
|
||||
@@ -481,6 +481,25 @@ void copyUCTXreg2Emu(x64emu_t* emu, ucontext_t* p, uintptr_t ip) {
|
||||
emu->regs[_R15].q[0] = p->uc_mcontext.__gregs[30];
|
||||
emu->ip.q[0] = ip;
|
||||
emu->eflags.x64 = p->uc_mcontext.__gregs[31];
|
||||
#elif defined(RV64)
|
||||
emu->regs[_AX].q[0] = p->uc_mcontext.__gregs[16];
|
||||
emu->regs[_CX].q[0] = p->uc_mcontext.__gregs[17];
|
||||
emu->regs[_DX].q[0] = p->uc_mcontext.__gregs[18];
|
||||
emu->regs[_BX].q[0] = p->uc_mcontext.__gregs[19];
|
||||
emu->regs[_SP].q[0] = p->uc_mcontext.__gregs[20];
|
||||
emu->regs[_BP].q[0] = p->uc_mcontext.__gregs[21];
|
||||
emu->regs[_SI].q[0] = p->uc_mcontext.__gregs[22];
|
||||
emu->regs[_DI].q[0] = p->uc_mcontext.__gregs[23];
|
||||
emu->regs[_R8].q[0] = p->uc_mcontext.__gregs[24];
|
||||
emu->regs[_R9].q[0] = p->uc_mcontext.__gregs[25];
|
||||
emu->regs[_R10].q[0] = p->uc_mcontext.__gregs[26];
|
||||
emu->regs[_R11].q[0] = p->uc_mcontext.__gregs[27];
|
||||
emu->regs[_R12].q[0] = p->uc_mcontext.__gregs[28];
|
||||
emu->regs[_R13].q[0] = p->uc_mcontext.__gregs[29];
|
||||
emu->regs[_R14].q[0] = p->uc_mcontext.__gregs[30];
|
||||
emu->regs[_R15].q[0] = p->uc_mcontext.__gregs[31];
|
||||
emu->ip.q[0] = ip;
|
||||
emu->eflags.x64 = p->uc_mcontext.__gregs[5];
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
@@ -512,6 +531,13 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
|
||||
if(db) {
|
||||
frame = (uintptr_t)p->uc_mcontext.__gregs[12+_SP];
|
||||
}
|
||||
#elif defined(RV64)
|
||||
ucontext_t *p = (ucontext_t *)ucntx;
|
||||
void * pc = (void*)p->uc_mcontext.__gregs[0];
|
||||
dynablock_t* db = (dynablock_t*)cur_db;//FindDynablockFromNativeAddress(pc);
|
||||
if(db) {
|
||||
frame = (uintptr_t)p->uc_mcontext.__gregs[16+_SP];
|
||||
}
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
@@ -604,6 +630,26 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
|
||||
sigcontext->uc_mcontext.gregs[X64_R15] = p->uc_mcontext.__gregs[30];
|
||||
sigcontext->uc_mcontext.gregs[X64_RIP] = getX64Address(db, (uintptr_t)pc);
|
||||
}
|
||||
#elif defined(RV64)
|
||||
if(db) {
|
||||
sigcontext->uc_mcontext.gregs[X64_RAX] = p->uc_mcontext.__gregs[16];
|
||||
sigcontext->uc_mcontext.gregs[X64_RCX] = p->uc_mcontext.__gregs[17];
|
||||
sigcontext->uc_mcontext.gregs[X64_RDX] = p->uc_mcontext.__gregs[18];
|
||||
sigcontext->uc_mcontext.gregs[X64_RBX] = p->uc_mcontext.__gregs[19];
|
||||
sigcontext->uc_mcontext.gregs[X64_RSP] = p->uc_mcontext.__gregs[20];
|
||||
sigcontext->uc_mcontext.gregs[X64_RBP] = p->uc_mcontext.__gregs[21];
|
||||
sigcontext->uc_mcontext.gregs[X64_RSI] = p->uc_mcontext.__gregs[22];
|
||||
sigcontext->uc_mcontext.gregs[X64_RDI] = p->uc_mcontext.__gregs[23];
|
||||
sigcontext->uc_mcontext.gregs[X64_R8] = p->uc_mcontext.__gregs[24];
|
||||
sigcontext->uc_mcontext.gregs[X64_R9] = p->uc_mcontext.__gregs[25];
|
||||
sigcontext->uc_mcontext.gregs[X64_R10] = p->uc_mcontext.__gregs[26];
|
||||
sigcontext->uc_mcontext.gregs[X64_R11] = p->uc_mcontext.__gregs[27];
|
||||
sigcontext->uc_mcontext.gregs[X64_R12] = p->uc_mcontext.__gregs[28];
|
||||
sigcontext->uc_mcontext.gregs[X64_R13] = p->uc_mcontext.__gregs[29];
|
||||
sigcontext->uc_mcontext.gregs[X64_R14] = p->uc_mcontext.__gregs[30];
|
||||
sigcontext->uc_mcontext.gregs[X64_R15] = p->uc_mcontext.__gregs[31];
|
||||
sigcontext->uc_mcontext.gregs[X64_RIP] = getX64Address(db, (uintptr_t)pc);
|
||||
}
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
@@ -902,6 +948,13 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
ejb->emu->xmm[2].u128 = fpsimd->vregs[2];
|
||||
ejb->emu->xmm[3].u128 = fpsimd->vregs[3];
|
||||
}*/
|
||||
#elif defined(RV64)
|
||||
/*if(fpsimd) {
|
||||
ejb->emu->xmm[0].u128 = fpsimd->vregs[0];
|
||||
ejb->emu->xmm[1].u128 = fpsimd->vregs[1];
|
||||
ejb->emu->xmm[2].u128 = fpsimd->vregs[2];
|
||||
ejb->emu->xmm[3].u128 = fpsimd->vregs[3];
|
||||
}*/
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
@@ -1036,6 +1089,14 @@ exit(-1);
|
||||
x64pc = getX64Address(db, (uintptr_t)pc);
|
||||
rsp = (void*)p->uc_mcontext.__gregs[12+_SP];
|
||||
}
|
||||
#elif defined(RV64)
|
||||
if(db && p->uc_mcontext.__gregs[10]>0x10000) {
|
||||
emu = (x64emu_t*)p->uc_mcontext.__gregs[10];
|
||||
}
|
||||
if(db) {
|
||||
x64pc = getX64Address(db, (uintptr_t)pc);
|
||||
rsp = (void*)p->uc_mcontext.__gregs[16+_SP];
|
||||
}
|
||||
#else
|
||||
#error Unsupported Architecture
|
||||
#endif //arch
|
||||
@@ -1165,6 +1226,18 @@ exit(-1);
|
||||
for (int i=-4; i<4; ++i) {
|
||||
printf_log(log_minimum, "%sRSP%c0x%02x:0x%016lx", (i%4)?" ":"\n", i<0?'-':'+', abs(i)*8, *(uintptr_t*)(rsp+i*8));
|
||||
}
|
||||
#elif defined(RV64)
|
||||
if(db) {
|
||||
shown_regs = 1;
|
||||
for (int i=0; i<16; ++i) {
|
||||
if(!(i%4)) printf_log(log_minimum, "\n");
|
||||
printf_log(log_minimum, "%s:0x%016llx ", reg_name[i], p->uc_mcontext.__gregs[16+i]);
|
||||
}
|
||||
}
|
||||
if(rsp!=addr)
|
||||
for (int i=-4; i<4; ++i) {
|
||||
printf_log(log_minimum, "%sRSP%c0x%02x:0x%016lx", (i%4)?" ":"\n", i<0?'-':'+', abs(i)*8, *(uintptr_t*)(rsp+i*8));
|
||||
}
|
||||
#else
|
||||
#warning TODO
|
||||
#endif
|
||||
@@ -1203,6 +1276,8 @@ void my_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
void * pc = (void*)p->uc_mcontext.pc;
|
||||
#elif defined(LA464)
|
||||
void * pc = (void*)p->uc_mcontext.__pc;
|
||||
#elif defined(RV64)
|
||||
void * pc = (void*)p->uc_mcontext.__gregs[0];
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
@@ -353,6 +353,9 @@ HWCAP2_ECV
|
||||
#elif defined(LA464)
|
||||
printf_log(LOG_INFO, "Dynarec for LoongArch");
|
||||
printf_log(LOG_INFO, " PageSize:%zd ", box64_pagesize);
|
||||
#elif defined(RV64)
|
||||
printf_log(LOG_INFO, "Dynarec for RISC-V");
|
||||
printf_log(LOG_INFO, " PageSize:%zd ", box64_pagesize);
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user