daedalus/Source/Core/Memory.h
2023-12-06 08:52:37 +08:00

329 lines
11 KiB
C++

/*
Copyright (C) 2001 StrmnNrmn
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
#ifndef CORE_MEMORY_H_
#define CORE_MEMORY_H_
#include "Ultra/ultra_rcp.h"
#include "System/AtomicPrimitives.h"
#include "System/Endian.h"
#include <array>
enum MEMBANKTYPE
{
MEM_UNUSED = 0, // Simplifies code so that we don't have to check for illegal memory accesses
MEM_RD_RAM, // 8 or 4 Mb (4/8*1024*1024)
MEM_SP_MEM, // 0x2000
MEM_PIF_RAM, // 0x40
MEM_RD_REG0, // 0x30 // This has changed - used to be 1Mb
MEM_SP_REG, // 0x20
MEM_SP_PC_REG, // 0x10 // SP_PC_REG + SP_IBITS_REG
MEM_DPC_REG, // 0x20
MEM_MI_REG, // 0x10
MEM_VI_REG, // 0x38
MEM_AI_REG, // 0x18
MEM_PI_REG, // 0x34
MEM_RI_REG, // 0x20
MEM_SI_REG, // 0x1C
MEM_SAVE, // 0x20000 128KBytes EEPROM (512 bytes), 4X EEPROM (2Kbytes), SRAM (32Kbytes), FlashRAM (128Kbytes)
MEM_MEMPACK, // 0x20000 MEMPack 32Kbytes * 4 = 128KBytes
NUM_MEM_BUFFERS
};
static const u32 MEMORY_4_MEG( 4*1024*1024 );
static const u32 MEMORY_8_MEG( 8*1024*1024 );
#define MAX_RAM_ADDRESS MEMORY_8_MEG
using mReadFunction = const void * (*)(u32 address);
using mWriteFunction = void(*)(u32 address, u32 value);
struct MemFuncWrite
{
u8 *pWrite;
mWriteFunction WriteFunc;
};
struct MemFuncRead
{
u8 *pRead;
mReadFunction ReadFunc;
};
extern u32 gRamSize;
#ifdef DAEDALUS_PROFILE_EXECUTION
extern u32 gTLBReadHit;
extern u32 gTLBWriteHit;
#endif
extern void * g_pMemoryBuffers[NUM_MEM_BUFFERS];
extern const u32 MemoryRegionSizes[NUM_MEM_BUFFERS];
bool Memory_Init();
void Memory_Fini();
bool Memory_Reset();
void Memory_Cleanup();
using MemFastFunction = void * (*)(u32 address);
using MemWriteValueFunction = void (*)(u32 address, u32 value);
#ifndef DAEDALUS_SILENT
using InternalMemFastFunction = bool (*)(u32 address, void ** p_translated);
#endif
extern MemFuncRead g_MemoryLookupTableRead[0x4000];
extern MemFuncWrite g_MemoryLookupTableWrite[0x4000];
// Fast memory access
inline const void* ReadAddress( u32 address )
{
const MemFuncRead & m( g_MemoryLookupTableRead[ address >> 18 ] );
// Access through pointer with no function calls at all (Fast)
if( m.pRead )
return (void*)( m.pRead + address );
// Need to go through the HW access handlers or TLB (Slow)
return m.ReadFunc( address );
}
inline void WriteAddress( u32 address, u32 value )
{
const MemFuncWrite & m( g_MemoryLookupTableWrite[ address >> 18 ] );
// Access through pointer with no function calls at all (Fast)
if( m.pWrite )
{
*(u32*)( m.pWrite + address ) = value;
return;
}
// Need to go through the HW access handlers or TLB (Slow)
m.WriteFunc( address, value );
}
#ifndef DAEDALUS_SILENT
bool Memory_GetInternalReadAddress(u32 address, void ** p_translated);
#endif
//////////////////////////////////////////////////////////////
// Quick Read/Write methods that require a base returned by
// ReadAddress or Memory_GetInternalReadAddress etc
inline u64 QuickRead64Bits( u8 *p_base, u32 offset )
{
u64 data = *(u64 *)(p_base + offset);
return (data>>32) + (data<<32);
}
inline u32 QuickRead32Bits( u8 *p_base, u32 offset )
{
return *(u32 *)(p_base + offset);
}
inline u16 QuickRead16Bits( u8 *p_base, u32 offset )
{
return *(u16 *)((uintptr_t)(p_base + offset) ^ U16_TWIDDLE);
}
inline void QuickWrite16Bits( u8 *p_base, u32 offset, u16 value)
{
*(u16 *)((uintptr_t)(p_base + offset) ^ U16_TWIDDLE) = value;
}
inline void QuickWrite64Bits( u8 *p_base, u32 offset, u64 value )
{
u64 data = (value>>32) + (value<<32);
*(u64 *)(p_base + offset) = data;
}
inline void QuickWrite32Bits( u8 *p_base, u32 offset, u32 value )
{
*(u32 *)(p_base + offset) = value;
}
inline void QuickWrite32Bits( u8 *p_base, u32 value )
{
*(u32 *)(p_base) = value;
}
// Useful defines for making code look nicer:
#define g_pu8RamBase ((u8*)g_pMemoryBuffers[MEM_RD_RAM])
#define g_ps8RamBase ((s8*)g_pMemoryBuffers[MEM_RD_RAM])
#define g_pu16RamBase ((u16*)g_pMemoryBuffers[MEM_RD_RAM])
#define g_pu32RamBase ((u32*)g_pMemoryBuffers[MEM_RD_RAM])
#define g_pu8SpMemBase ((u8*)g_pMemoryBuffers[MEM_SP_MEM])
#define g_ps8SpMemBase ((s8*)g_pMemoryBuffers[MEM_SP_MEM])
#define g_pu16SpMemBase ((u16*)g_pMemoryBuffers[MEM_SP_MEM])
#define g_pu32SpMemBase ((u32*)g_pMemoryBuffers[MEM_SP_MEM])
#define g_pu8SpDmemBase ((u8*)g_pMemoryBuffers[MEM_SP_MEM] + SP_DMA_DMEM)
#define g_pu8SpImemBase ((u8*)g_pMemoryBuffers[MEM_SP_MEM] + SP_DMA_IMEM)
#define MEMORY_SIZE_RDRAM 0x400000
#define MEMORY_SIZE_EXRDRAM 0x400000
#define MEMORY_SIZE_RDRAM_DEFAULT MEMORY_SIZE_RDRAM + MEMORY_SIZE_EXRDRAM
#define MEMORY_SIZE_RAMREGS0 0x30
#define MEMORY_SIZE_RAMREGS4 0x30
#define MEMORY_SIZE_RAMREGS8 0x30
#define MEMORY_SIZE_SPMEM 0x2000
#define MEMORY_SIZE_SPREG_1 0x24
#define MEMORY_SIZE_SPREG_2 0x8
#define MEMORY_SIZE_DPC 0x20
#define MEMORY_SIZE_DPS 0x10
#define MEMORY_SIZE_MI 0x10
#define MEMORY_SIZE_VI 0x50
#define MEMORY_SIZE_AI 0x18
#define MEMORY_SIZE_PI 0x4C
#define MEMORY_SIZE_RI 0x20
#define MEMORY_SIZE_SI 0x1C
#define MEMORY_SIZE_C2A1 0x8000
#define MEMORY_SIZE_C1A1 0x8000
#define MEMORY_SIZE_C2A2 0x20000
#define MEMORY_SIZE_GIO_REG 0x804
#define MEMORY_SIZE_C1A3 0x8000
#define MEMORY_SIZE_PIF 0x800
#define MEMORY_SIZE_DUMMY 0x10000
#define MEMORY_START_RDRAM 0x00000000
#define MEMORY_START_EXRDRAM 0x00400000
#define MEMORY_START_RAMREGS0 0x03F00000
#define MEMORY_START_RAMREGS4 0x03F04000
#define MEMORY_START_RAMREGS8 0x03F80000
#define MEMORY_START_SPMEM 0x04000000
#define MEMORY_START_SPREG_1 0x04040000
#define MEMORY_START_SPREG_2 0x04080000
#define MEMORY_START_DPC 0x04100000
#define MEMORY_START_DPS 0x04200000
#define MEMORY_START_MI 0x04300000
#define MEMORY_START_VI 0x04400000
#define MEMORY_START_AI 0x04500000
#define MEMORY_START_PI 0x04600000
#define MEMORY_START_RI 0x04700000
#define MEMORY_START_SI 0x04800000
#define MEMORY_START_C2A1 0x05000000
#define MEMORY_START_C1A1 0x06000000
#define MEMORY_START_C2A2 0x08000000
#define MEMORY_START_ROM_IMAGE 0x10000000
#define MEMORY_START_GIO 0x18000000
#define MEMORY_START_PIF 0x1FC00000
#define MEMORY_START_C1A3 0x1FD00000
#define MEMORY_START_DUMMY 0x1FFF0000
#define FLASHRAM_READ_ADDR 0x08000000
#define FLASHRAM_WRITE_ADDR 0x08010000
extern u8 * g_pu8RamBase_8000;
//extern u8 * g_pu8RamBase_A000;
#ifdef DAEDALUS_ENDIAN_BIG
inline u64 Read64Bits( u32 address ) { return *(u64 *)ReadAddress( address ); }
inline u32 Read32Bits( u32 address ) { return *(u32 *)ReadAddress( address ); }
inline u16 Read16Bits( u32 address ) { return *(u16 *)ReadAddress( address ); }
inline u8 Read8Bits( u32 address ) { return *(u8 *)ReadAddress( address ); }
inline void Write64Bits( u32 address, u64 data ) { *(u64 *)ReadAddress( address ) = data; }
inline void Write32Bits( u32 address, u32 data ) { WriteAddress(address, data); }
inline void Write16Bits( u32 address, u16 data ) { *(u16 *)ReadAddress(address) = data; }
inline void Write8Bits( u32 address, u8 data ) { *(u8 *)ReadAddress(address) = data;}
#elif( DAEDALUS_ENDIAN_LITTLE)
inline u64 Read64Bits( u32 address ) { u64 data = *(u64 *)ReadAddress( address ); data = (data>>32) + (data<<32); return data; }
inline u32 Read32Bits( u32 address ) { return *(u32 *)ReadAddress( address ); }
inline u16 Read16Bits( u32 address ) { return *(u16 *)ReadAddress( address ^ U16_TWIDDLE ); }
inline u8 Read8Bits( u32 address ) { return *(u8 *)ReadAddress( address ^ U8_TWIDDLE ); }
inline void Write64Bits( u32 address, u64 data ) { *(u64 *)ReadAddress( address ) = (data>>32) + (data<<32); }
inline void Write32Bits( u32 address, u32 data ) { WriteAddress(address, data); }
inline void Write16Bits( u32 address, u16 data ) { *(u16 *)ReadAddress(address ^ U16_TWIDDLE) = data; }
inline void Write8Bits( u32 address, u8 data ) { *(u8 *)ReadAddress(address ^ U8_TWIDDLE) = data;}
#else
#error No DAEDALUS_ENDIAN_MODE specified
#endif
//inline void Write64Bits_NoSwizzle( u32 address, u64 data ){ *(u64 *)WriteAddress( address ) = (data>>32) + (data<<32); }
inline void Write32Bits_NoSwizzle( u32 address, u32 data ) { WriteAddress(address, data); }
inline void Write16Bits_NoSwizzle( u32 address, u16 data ) { *(u16 *)ReadAddress(address) = data; }
inline void Write8Bits_NoSwizzle( u32 address, u8 data ) { *(u8 *)ReadAddress(address) = data;}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
// Register Macros //
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
#define REGISTER_FUNCTIONS( set, base_reg, memory_buffer ) \
inline void Memory_##set##_SetRegister( u32 reg, u32 value ) \
{ \
((u32 *)g_pMemoryBuffers[memory_buffer])[ (reg - base_reg) / 4 ] = value; \
} \
\
inline u32 Memory_##set##_GetRegister( u32 reg ) \
{ \
return ((u32 *)g_pMemoryBuffers[memory_buffer])[ (reg - base_reg) / 4 ]; \
} \
\
inline u32 Memory_##set##_SetRegisterBits( u32 reg, u32 and_bits, u32 or_bits ) \
{ \
u32 * p( &((u32 *)g_pMemoryBuffers[memory_buffer])[ (reg - base_reg) / 4 ] ); \
return AtomicBitSet( p, and_bits, or_bits ); \
} \
\
inline u32 Memory_##set##_SetRegisterBits( u32 reg, u32 value ) \
{ \
u32 * p( &((u32 *)g_pMemoryBuffers[memory_buffer])[ (reg - base_reg) / 4 ] ); \
return AtomicBitSet( p, 0xffffffff, value ); \
} \
\
inline u32 Memory_##set##_ClrRegisterBits( u32 reg, u32 value ) \
{ \
u32 * p( &((u32 *)g_pMemoryBuffers[memory_buffer])[ (reg - base_reg) / 4 ] ); \
return AtomicBitSet( p, ~value, 0 ); \
} \
\
inline u32 * set##_REG_ADDRESS( u32 reg ) \
{ \
return &((u32 *)g_pMemoryBuffers[memory_buffer])[(reg - base_reg) / 4]; \
}
REGISTER_FUNCTIONS( MI, MI_BASE_REG, MEM_MI_REG )
REGISTER_FUNCTIONS( SP, SP_BASE_REG, MEM_SP_REG )
REGISTER_FUNCTIONS( PC, SP_PC_REG, MEM_SP_PC_REG )
REGISTER_FUNCTIONS( AI, AI_BASE_REG, MEM_AI_REG )
REGISTER_FUNCTIONS( VI, VI_BASE_REG, MEM_VI_REG )
REGISTER_FUNCTIONS( SI, SI_BASE_REG, MEM_SI_REG )
REGISTER_FUNCTIONS( PI, PI_BASE_REG, MEM_PI_REG )
REGISTER_FUNCTIONS( DPC, DPC_BASE_REG, MEM_DPC_REG )
#undef REGISTER_FUNCTIONS
#endif // CORE_MEMORY_H_