daedalus/Source/DynaRec/ARM/CodeGeneratorARM.h

247 lines
No EOL
13 KiB
C++

/*
Copyright (C) 2020 MasterFeizz
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include "DynaRec/CodeGenerator.h"
#include "AssemblyWriterARM.h"
#include "DynarecTargetARM.h"
#include "DynaRec/TraceRecorder.h"
#include "N64RegisterCacheARM.h"
#include <stack>
// XXXX For GenerateCompare_S/D
#define FLAG_SWAP 0x100
#define FLAG_C_LT (0x41) // jne- le
#define FLAG_C_LE (FLAG_SWAP|0x41) // je - ! gt
#define FLAG_C_EQ (FLAG_SWAP|0x40) // je - ! eq
typedef u32 (*ReadMemoryFunction)( u32 address );
class CCodeGeneratorARM : public CCodeGenerator, public CAssemblyWriterARM
{
public:
CCodeGeneratorARM( CAssemblyBuffer * p_primary, CAssemblyBuffer * p_secondary );
virtual void Initialise( u32 entry_address, u32 exit_address, u32 * hit_counter, const void * p_base, const SRegisterUsageInfo & register_usage );
void SetRegisterSpanList(const SRegisterUsageInfo& register_usage, bool loops_to_self);
virtual void Finalise( ExceptionHandlerFn p_exception_handler_fn, const std::vector< CJumpLocation > & exception_handler_jumps, const std::vector< RegisterSnapshotHandle>& exception_handler_snapshots );
virtual void UpdateRegisterCaching( u32 instruction_idx );
virtual RegisterSnapshotHandle GetRegisterSnapshot();
virtual CCodeLabel GetEntryPoint() const;
virtual CCodeLabel GetCurrentLocation() const;
virtual u32 GetCompiledCodeSize() const;
virtual CJumpLocation GenerateExitCode( u32 exit_address, u32 jump_address, u32 num_instructions, CCodeLabel next_fragment );
virtual void GenerateEretExitCode( u32 num_instructions, CIndirectExitMap * p_map );
virtual void GenerateIndirectExitCode( u32 num_instructions, CIndirectExitMap * p_map );
virtual void GenerateBranchHandler( CJumpLocation branch_handler_jump, RegisterSnapshotHandle snapshot );
virtual CJumpLocation GenerateOpCode( const STraceEntry& ti, bool branch_delay_slot, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump);
virtual CJumpLocation ExecuteNativeFunction( CCodeLabel speed_hack, bool check_return );
private:
void ExpireOldIntervals(u32 instruction_idx);
void SpillAtInterval(const SRegisterSpan& live_span);
void GetVar(EArmReg arm_reg, const u32* p_var);
void SetVar( const u32 * p_var, u32 value );
void SetVar(const u32* p_var, EArmReg reg);
void SetFloatVar(const f32* p_var, EArmVfpReg reg);
void GetFloatVar( EArmVfpReg dst_reg, const f32 * p_var );
void SetDoubleVar(const f64* p_var, EArmVfpReg reg);
void GetDoubleVar( EArmVfpReg dst_reg, const f64 * p_var );
EArmReg GetRegisterNoLoad( EN64Reg n64_reg, u32 lo_hi_idx, EArmReg scratch_reg );
EArmReg GetRegisterNoLoadLo( EN64Reg n64_reg, EArmReg scratch_reg ) { return GetRegisterNoLoad( n64_reg, 0, scratch_reg ); }
EArmReg GetRegisterNoLoadHi( EN64Reg n64_reg, EArmReg scratch_reg ) { return GetRegisterNoLoad( n64_reg, 1, scratch_reg ); }
EArmReg GetRegisterAndLoad( EN64Reg n64_reg, u32 lo_hi_idx, EArmReg scratch_reg );
EArmReg GetRegisterAndLoadLo( EN64Reg n64_reg, EArmReg scratch_reg ) { return GetRegisterAndLoad( n64_reg, 0, scratch_reg ); }
EArmReg GetRegisterAndLoadHi( EN64Reg n64_reg, EArmReg scratch_reg ) { return GetRegisterAndLoad( n64_reg, 1, scratch_reg ); }
void GetRegisterValue(EArmReg arm_reg, EN64Reg n64_reg, u32 lo_hi_idx);
void LoadRegister( EArmReg arm_reg, EN64Reg n64_reg, u32 lo_hi_idx );
void LoadRegisterLo( EArmReg arm_reg, EN64Reg n64_reg ) { LoadRegister(arm_reg, n64_reg, 0); }
void LoadRegisterHi( EArmReg arm_reg, EN64Reg n64_reg ) { LoadRegister(arm_reg, n64_reg, 1); }
void PrepareCachedRegister(EN64Reg n64_reg, u32 lo_hi_idx);
void PrepareCachedRegisterLo(EN64Reg n64_reg) { PrepareCachedRegister(n64_reg, 0); }
void PrepareCachedRegisterHi(EN64Reg n64_reg) { PrepareCachedRegister(n64_reg, 1); }
void FlushRegister(CN64RegisterCacheARM& cache, EN64Reg n64_reg, u32 lo_hi_idx, bool invalidate);
void FlushAllRegisters(CN64RegisterCacheARM& cache, bool invalidate);
void FlushAllFloatingPointRegisters( CN64RegisterCacheARM & cache, bool invalidate );
void RestoreAllRegisters(CN64RegisterCacheARM& current_cache, CN64RegisterCacheARM& new_cache);
void UpdateRegister(EN64Reg n64_reg, EArmReg arm_reg, bool options);
EArmVfpReg GetFloatRegisterAndLoad( EN64FloatReg n64_reg );
EArmVfpReg GetDoubleRegisterAndLoad( EN64FloatReg n64_reg );
void UpdateFloatRegister( EN64FloatReg n64_reg );
void UpdateDoubleRegister( EN64FloatReg n64_reg );
const CN64RegisterCacheARM& GetRegisterCacheFromHandle(RegisterSnapshotHandle snapshot) const;
void StoreRegister(EN64Reg n64_reg, u32 lo_hi_idx, EArmReg arm_reg);
void StoreRegisterLo(EN64Reg n64_reg, EArmReg arm_reg) { StoreRegister(n64_reg, 0, arm_reg); }
void StoreRegisterHi(EN64Reg n64_reg, EArmReg arm_reg) { StoreRegister(n64_reg, 1, arm_reg); }
void SetRegister64(EN64Reg n64_reg, s32 lo_value, s32 hi_value);
void SetRegister32s(EN64Reg n64_reg, s32 value);
void SetRegister(EN64Reg n64_reg, u32 lo_hi_idx, u32 value);
CJumpLocation GenerateBranchAlways( CCodeLabel target );
CJumpLocation GenerateBranchIfSet( const u32 * p_var, CCodeLabel target );
CJumpLocation GenerateBranchIfNotSet( const u32 * p_var, CCodeLabel target );
CJumpLocation GenerateBranchIfEqual( const u32 * p_var, u32 value, CCodeLabel target );
CJumpLocation GenerateBranchIfNotEqual( const u32 * p_var, u32 value, CCodeLabel target );
CJumpLocation GenerateBranchIfNotEqual( EArmReg reg_a, u32 value, CCodeLabel target );
void GenerateGenericR4300( OpCode op_code, CPU_Instruction p_instruction );
void GenerateExceptionHander( ExceptionHandlerFn p_exception_handler_fn, const std::vector< CJumpLocation > & exception_handler_jumps, const std::vector< RegisterSnapshotHandle>& exception_handler_snapshots );
bool mSpCachedInESI; // Is sp cached in ESI?
u32 mSetSpPostUpdate; // Set Sp base counter after this update
u32 mEntryAddress;
CAssemblyBuffer * mpPrimary;
CAssemblyBuffer * mpSecondary;
RegisterSpanList mRegisterSpanList;
// For register allocation
RegisterSpanList mActiveIntervals;
std::stack<EArmReg> mAvailableRegisters;
CCodeLabel mLoopTop;
bool mUseFixedRegisterAllocation;
std::vector< CN64RegisterCacheARM > mRegisterSnapshots;
CN64RegisterCacheARM mRegisterCache;
bool mQuickLoad;
bool mFloatCMPIsValid;
bool mMultIsValid;
private:
bool GenerateCACHE( EN64Reg base, s16 offset, u32 cache_op );
typedef u32 (*ReadMemoryFunction)( u32 address, u32 current_pc );
typedef void (*WriteMemoryFunction)( u32 address, u32 value, u32 current_pc );
void GenerateStore( u32 address, EArmReg arm_src, EN64Reg base, s16 offset, u8 twiddle, u8 bits, WriteMemoryFunction p_write_memory );
bool GenerateSW(u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateSWC1( u32 address, bool branch_delay_slot, u32 ft, EN64Reg base, s16 offset );
bool GenerateSDC1( u32 address, bool branch_delay_slot, u32 ft, EN64Reg base, s16 offset );
bool GenerateSH( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateSD( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateSB( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
void GenerateLoad( u32 address, EArmReg arm_dest, EN64Reg base, s16 offset, u8 twiddle, u8 bits, bool is_signed, ReadMemoryFunction p_read_memory );
bool GenerateLW( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateLD( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateLB( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateLBU( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateLH( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateLHU( u32 address, bool branch_delay_slot, EN64Reg rt, EN64Reg base, s16 offset );
bool GenerateLWC1( u32 address, bool branch_delay_slot, u32 ft, EN64Reg base, s16 offset );
bool GenerateLDC1( u32 address, bool branch_delay_slot, u32 ft, EN64Reg base, s16 offset );
void GenerateLUI( EN64Reg rt, s16 immediate );
void GenerateADDIU( EN64Reg rt, EN64Reg rs, s16 immediate );
void GenerateANDI( EN64Reg rt, EN64Reg rs, u16 immediate );
void GenerateORI( EN64Reg rt, EN64Reg rs, u16 immediate );
void GenerateXORI( EN64Reg rt, EN64Reg rs, u16 immediate );
void GenerateSLTI( EN64Reg rt, EN64Reg rs, s16 immediate, bool is_unsigned );
void GenerateDADDIU( EN64Reg rt, EN64Reg rs, s16 immediate );
void GenerateDADDU( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateDSUBU( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateJAL( u32 address );
void GenerateJALR( EN64Reg rs, EN64Reg rd, u32 address, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump );
//Special Op
void GenerateMFC0( EN64Reg rt, u32 fs );
void GenerateMFC1( EN64Reg rt, u32 fs );
void GenerateMTC1( u32 fs, EN64Reg rt );
void GenerateCFC1( EN64Reg rt, u32 fs );
void GenerateCTC1( u32 fs, EN64Reg rt );
void GenerateSLL( EN64Reg rd, EN64Reg rt, u32 sa );
void GenerateSRL( EN64Reg rd, EN64Reg rt, u32 sa );
void GenerateSRA( EN64Reg rd, EN64Reg rt, u32 sa );
void GenerateSLLV( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateSRLV( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateSRAV( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateOR( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateAND( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateXOR( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateNOR( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateJR( EN64Reg rs, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump );
void GenerateADDU( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateSUBU( EN64Reg rd, EN64Reg rs, EN64Reg rt );
void GenerateMULT( EN64Reg rs, EN64Reg rt, bool is_unsigned );
void GenerateDIV( EN64Reg rs, EN64Reg rt );
void GenerateDIVU( EN64Reg rs, EN64Reg rt );
void GenerateMFLO( EN64Reg rd );
void GenerateMFHI( EN64Reg rd );
void GenerateMTLO( EN64Reg rs );
void GenerateMTHI( EN64Reg rs );
void GenerateSLT( EN64Reg rd, EN64Reg rs, EN64Reg rt , bool is_unsigned );
//Branch
void GenerateBEQ( EN64Reg rs, EN64Reg rt, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump );
void GenerateBNE( EN64Reg rs, EN64Reg rt, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump );
void GenerateBLEZ( EN64Reg rs, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump );
void GenerateBGEZ( EN64Reg rs, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump );
void GenerateBLTZ( EN64Reg rs, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump );
void GenerateBGTZ( EN64Reg rs, const SBranchDetails * p_branch, CJumpLocation * p_branch_jump );
// CoPro1
void GenerateADD_S( u32 fd, u32 fs, u32 ft );
void GenerateSUB_S( u32 fd, u32 fs, u32 ft );
void GenerateMUL_S( u32 fd, u32 fs, u32 ft );
void GenerateDIV_S( u32 fd, u32 fs, u32 ft );
void GenerateSQRT_S( u32 fd, u32 fs );
void GenerateABS_S( u32 fd, u32 fs );
void GenerateMOV_S( u32 fd, u32 fs );
void GenerateNEG_S( u32 fd, u32 fs );
void GenerateTRUNC_W_S( u32 fd, u32 fs );
void GenerateCVT_D_S( u32 fd, u32 fs );
void GenerateCMP_S( u32 fs, u32 ft, EArmCond cond, u8 E );
void GenerateADD_D( u32 fd, u32 fs, u32 ft );
void GenerateSUB_D( u32 fd, u32 fs, u32 ft );
void GenerateMUL_D( u32 fd, u32 fs, u32 ft );
void GenerateDIV_D( u32 fd, u32 fs, u32 ft );
void GenerateSQRT_D( u32 fd, u32 fs );
void GenerateABS_D( u32 fd, u32 fs );
void GenerateMOV_D( u32 fd, u32 fs );
void GenerateNEG_D( u32 fd, u32 fs );
void GenerateTRUNC_W_D( u32 fd, u32 fs );
void GenerateCVT_S_D( u32 fd, u32 fs );
void GenerateCMP_D( u32 fs, u32 ft, EArmCond cond, u8 E );
};