124 lines
4.9 KiB
C++
124 lines
4.9 KiB
C++
// Header file for native generator interface
|
|
|
|
#pragma once
|
|
#include "blockmanager.h"
|
|
#include "oslib/host_context.h"
|
|
|
|
// When NO_RWX is enabled there's two address-spaces, one executable and
|
|
// one writtable. The emitter and most of the code in rec-* will work with
|
|
// the RW pointer. However the fpcb table and other pointers during execution
|
|
// (ie. exceptions) are RX pointers. These two macros convert between them by
|
|
// sub/add the pointer offset. CodeCache will point to the RW pointer for simplicity.
|
|
#ifdef FEAT_NO_RWX_PAGES
|
|
extern ptrdiff_t cc_rx_offset;
|
|
#define CC_RW2RX(ptr) (void*)(((uintptr_t)(ptr)) + cc_rx_offset)
|
|
#define CC_RX2RW(ptr) (void*)(((uintptr_t)(ptr)) - cc_rx_offset)
|
|
#else
|
|
#define CC_RW2RX(ptr) (ptr)
|
|
#define CC_RX2RW(ptr) (ptr)
|
|
#endif
|
|
|
|
//Called from ngen_FailedToFindBlock
|
|
DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock(u32 pc);
|
|
DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock_pc();
|
|
//Called when a block check failed, and the block needs to be invalidated
|
|
DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 addr);
|
|
//Called to compile code @pc
|
|
DynarecCodeEntryPtr rdv_CompilePC(u32 blockcheck_failures);
|
|
//Finds or compiles code @pc
|
|
DynarecCodeEntryPtr rdv_FindOrCompile();
|
|
// Registers a custom FailedToFindBlock handler function
|
|
void rdv_SetFailedToFindBlockHandler(void (*handler)());
|
|
|
|
//code -> pointer to code of block, dpc -> if dynamic block, pc. if cond, 0 for next, 1 for branch
|
|
void* DYNACALL rdv_LinkBlock(u8* code,u32 dpc);
|
|
|
|
//Value to be returned when the block manager failed to find a block,
|
|
//should call rdv_FailedToFindBlock and then jump to the return value
|
|
// Set with rdv_SetFailedToFindBlockHandler(). Internal use only.
|
|
extern void (*ngen_FailedToFindBlock)();
|
|
|
|
//Canonical callback interface
|
|
enum CanonicalParamType
|
|
{
|
|
CPT_u32,
|
|
CPT_u32rv,
|
|
CPT_u64rvL,
|
|
CPT_u64rvH,
|
|
CPT_f32,
|
|
CPT_f32rv,
|
|
CPT_ptr,
|
|
};
|
|
|
|
bool rdv_readMemImmediate(u32 addr, int size, void*& ptr, bool& isRam, u32& physAddr, RuntimeBlockInfo* block = nullptr);
|
|
bool rdv_writeMemImmediate(u32 addr, int size, void*& ptr, bool& isRam, u32& physAddr, RuntimeBlockInfo* block = nullptr);
|
|
|
|
class Sh4CodeBuffer
|
|
{
|
|
public:
|
|
// Return the current position of the code buffer, where new code should be emitted.
|
|
void *get();
|
|
// Advance the buffer position by 'size' bytes.
|
|
void advance(u32 size);
|
|
// Return the available free space in bytes.
|
|
u32 getFreeSpace();
|
|
// Return a pointer to the beginning of the code buffer.
|
|
void *getBase();
|
|
// Return the full size of the code buffer.
|
|
// Note that the code buffer may be partitioned (long term blocks, short term blocks) so the full size
|
|
// might be greater than what getFreeSpace() returns when the buffer is empty.
|
|
u32 getSize();
|
|
|
|
// Select the long term or temporary buffer (internal use)
|
|
void useTempBuffer(bool enable) { tempBuffer = enable; }
|
|
// Reset main or temp code buffer position to 0 (internal use)
|
|
void reset(bool temporary);
|
|
|
|
private:
|
|
u32 lastAddr = 0;
|
|
u32 tempLastAddr = 0;
|
|
bool tempBuffer = false;
|
|
};
|
|
|
|
class Sh4Dynarec
|
|
{
|
|
public:
|
|
// Initialize the dynarec, which should keep a reference to the passed code buffer to generate code later.
|
|
virtual void init(Sh4CodeBuffer& codeBuffer) = 0;
|
|
// Compile the given block.
|
|
// If smc_checks is true, add self-modifying code detection.
|
|
// If optimize is true, use fast memory accesses if possible, that will be rewritten if they fail.
|
|
virtual void compile(RuntimeBlockInfo* block, bool smc_checks, bool optimise) = 0;
|
|
// Signal the dynarec that the code buffer has been cleared. It should re-generate its main loop if needed.
|
|
virtual void reset() {}
|
|
// Run the code.
|
|
// cntx points right after the Sh4RCB struct, which corresponds to the start of the 512 MB virtual address space
|
|
// (if available).
|
|
virtual void mainloop(void* cntx) = 0;
|
|
// An SH4 exception has occurred. The dynarec should abort execution of the current block and longjmp to its main loop
|
|
// to execute the exception handler.
|
|
virtual void handleException(host_context_t& context) = 0;
|
|
// Rewrite the memory access at host PC address 'faultAddress'. This fast memory access failed and should be rewritten
|
|
// to use mem access handlers.
|
|
virtual bool rewrite(host_context_t& context, void *faultAddress) = 0;
|
|
// Allocate a new block information structure.
|
|
virtual RuntimeBlockInfo *allocateBlock() {
|
|
return new RuntimeBlockInfo();
|
|
}
|
|
|
|
// Dynarec canonical implementation callback methods.
|
|
// Used to call default implementation of shil ops that the dynarec doesn't implement.
|
|
// Start call
|
|
virtual void canonStart(const shil_opcode *op) = 0;
|
|
// Pass input parameter or retrieve return parameter
|
|
virtual void canonParam(const shil_opcode *op, const shil_param *param, CanonicalParamType paramType) = 0;
|
|
// Call the implementation
|
|
virtual void canonCall(const shil_opcode *op, void *function) = 0;
|
|
// Finish call
|
|
virtual void canonFinish(const shil_opcode *op) = 0;
|
|
|
|
virtual ~Sh4Dynarec() = default;
|
|
};
|
|
|
|
extern Sh4Dynarec *sh4Dynarec;
|