[RV64] Added some basic infrastructure for the Dynarec (and 1 opcode)

This commit is contained in:
ptitSeb committed 2023-03-11 21:44:13 +00:00
1 parent dd171198f1
commit 5a9b89600e
34 files changed
+1894 -159

No files matched your search

+55 -1
View File
@@ -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"
+62
View File
@@ -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;
}
+6
View File
@@ -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
+9
View File
@@ -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
+2
View File
@@ -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
+1 -1
View File
@@ -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;
+2 -53
View File
@@ -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);
+7
View File
@@ -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
+40
View File
@@ -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
+79
View File
@@ -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;
}
+207
View File
@@ -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));
}
+26
View File
@@ -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__
+166
View File
@@ -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));
}
+475
View File
@@ -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__
+13
View File
@@ -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);
}
+50
View File
@@ -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"); \
}
+11
View File
@@ -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)
+19
View File
@@ -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);}
+53
View File
@@ -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));}
+80
View File
@@ -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_
+202
View File
@@ -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__
+61
View File
@@ -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
+32 -81
View File
@@ -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
+17 -23
View File
@@ -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__
+47
View File
@@ -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
+14
View File
@@ -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;
}
+7
View File
@@ -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_
+49
View File
@@ -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
+8
View File
@@ -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
+3
View File
@@ -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
+3
View File
@@ -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
+10
View File
@@ -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_
+75
View File
@@ -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
+3
View File
@@ -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