2013-12-19 17:10:14 +00:00
/*
Tiny cute block manager . Doesn ' t keep block graphs or anything fancy . . .
Its based on a simple hashed - lists idea
*/
# include <algorithm>
2019-06-19 09:01:33 +00:00
# include <set>
# include <map>
2013-12-19 17:10:14 +00:00
# include "blockmanager.h"
# include "ngen.h"
# include "../sh4_core.h"
# include "hw/sh4/sh4_mem.h"
2019-07-07 22:03:44 +00:00
# include "hw/sh4/sh4_opcode_list.h"
2019-03-25 10:53:13 +00:00
# include "hw/sh4/sh4_sched.h"
2013-12-19 17:10:14 +00:00
# if HOST_OS==OS_LINUX && defined(DYNA_OPROF)
# include <opagent.h>
op_agent_t oprofHandle ;
# endif
2015-07-25 06:39:35 +00:00
# if FEAT_SHREC != DYNAREC_NONE
2013-12-19 17:10:14 +00:00
2019-06-19 09:01:33 +00:00
typedef std : : vector < RuntimeBlockInfoPtr > bm_List ;
typedef std : : set < RuntimeBlockInfoPtr > bm_Set ;
typedef std : : map < void * , RuntimeBlockInfoPtr > bm_Map ;
2013-12-19 17:10:14 +00:00
2019-09-30 13:47:05 +00:00
static bm_Set all_temp_blocks ;
static bm_List del_blocks ;
2013-12-24 00:56:44 +00:00
2019-06-19 09:01:33 +00:00
bool unprotected_pages [ RAM_SIZE_MAX / PAGE_SIZE ] ;
static std : : set < RuntimeBlockInfo * > blocks_per_page [ RAM_SIZE_MAX / PAGE_SIZE ] ;
2013-12-19 17:10:14 +00:00
2019-09-30 13:47:05 +00:00
static bm_Map blkmap ;
2019-06-19 09:01:33 +00:00
// Stats
u32 protected_blocks ;
u32 unprotected_blocks ;
2013-12-19 17:10:14 +00:00
2015-08-09 04:30:40 +00:00
# define FPCA(x) ((DynarecCodeEntryPtr&)sh4rcb.fpcb[(x>>1)&FPCB_MASK])
2013-12-19 17:10:14 +00:00
2019-03-25 10:53:13 +00:00
// addr must be a physical address
2019-05-12 20:02:57 +00:00
// This returns an executable address
2019-09-30 13:47:05 +00:00
static DynarecCodeEntryPtr DYNACALL bm_GetCode ( u32 addr )
2013-12-19 17:10:14 +00:00
{
2019-08-30 21:35:10 +00:00
DynarecCodeEntryPtr rv = FPCA ( addr ) ;
2013-12-19 17:10:14 +00:00
2019-04-19 09:45:05 +00:00
return rv ;
2013-12-19 17:10:14 +00:00
}
2019-03-25 10:53:13 +00:00
// addr must be a virtual address
2019-05-12 20:02:57 +00:00
// This returns an executable address
2019-04-15 16:02:34 +00:00
DynarecCodeEntryPtr DYNACALL bm_GetCodeByVAddr ( u32 addr )
2013-12-19 17:10:14 +00:00
{
2019-03-25 10:53:13 +00:00
# ifndef NO_MMU
if ( ! mmu_enabled ( ) )
# endif
2019-04-19 09:45:05 +00:00
return bm_GetCode ( addr ) ;
2019-03-25 10:53:13 +00:00
# ifndef NO_MMU
else
{
if ( addr & 1 )
{
switch ( addr )
{
2019-04-15 16:02:34 +00:00
# ifdef USE_WINCE_HACK
2019-03-25 10:53:13 +00:00
case 0xfffffde7 : // GetTickCount
// This should make this syscall faster
r [ 0 ] = sh4_sched_now64 ( ) * 1000 / SH4_MAIN_CLOCK ;
next_pc = pr ;
break ;
2019-04-15 16:02:34 +00:00
case 0xfffffd05 : // QueryPerformanceCounter(u64 *)
{
u32 paddr ;
if ( mmu_data_translation < MMU_TT_DWRITE , u64 > ( r [ 4 ] , paddr ) = = MMU_ERROR_NONE )
{
_vmem_WriteMem64 ( paddr , sh4_sched_now64 ( ) > > 4 ) ;
r [ 0 ] = 1 ;
next_pc = pr ;
}
else
{
Do_Exception ( addr , 0xE0 , 0x100 ) ;
}
}
break ;
# endif
2019-03-25 10:53:13 +00:00
default :
Do_Exception ( addr , 0xE0 , 0x100 ) ;
break ;
}
2019-04-15 16:02:34 +00:00
addr = next_pc ;
2019-03-25 10:53:13 +00:00
}
2019-04-15 16:02:34 +00:00
u32 paddr ;
2019-05-26 11:30:05 +00:00
u32 rv = mmu_instruction_translation ( addr , paddr ) ;
2019-04-15 16:02:34 +00:00
if ( rv ! = MMU_ERROR_NONE )
{
DoMMUException ( addr , rv , MMU_TT_IREAD ) ;
2019-05-26 11:30:05 +00:00
mmu_instruction_translation ( next_pc , paddr ) ;
2019-03-25 10:53:13 +00:00
}
2019-04-15 16:02:34 +00:00
2019-04-19 09:45:05 +00:00
return bm_GetCode ( paddr ) ;
2019-03-25 10:53:13 +00:00
}
# endif
2013-12-19 17:10:14 +00:00
}
2019-03-25 10:53:13 +00:00
// addr must be a physical address
2019-05-12 20:02:57 +00:00
// This returns an executable address
2019-06-19 09:01:33 +00:00
RuntimeBlockInfoPtr DYNACALL bm_GetBlock ( u32 addr )
2013-12-19 17:10:14 +00:00
{
2019-05-12 20:02:57 +00:00
DynarecCodeEntryPtr cde = bm_GetCode ( addr ) ; // Returns RX ptr
2013-12-19 17:10:14 +00:00
2019-05-12 20:02:57 +00:00
if ( cde = = ngen_FailedToFindBlock )
2019-06-19 09:01:33 +00:00
return NULL ;
2013-12-19 17:10:14 +00:00
else
2019-05-12 20:02:57 +00:00
return bm_GetBlock ( ( void * ) cde ) ; // Returns RX pointer
2013-12-19 17:10:14 +00:00
}
2019-05-12 20:02:57 +00:00
// This takes a RX address and returns the info block ptr (RW space)
2019-06-19 09:01:33 +00:00
RuntimeBlockInfoPtr bm_GetBlock ( void * dynarec_code )
2013-12-19 17:10:14 +00:00
{
2019-06-19 09:01:33 +00:00
if ( blkmap . empty ( ) )
return NULL ;
2019-05-12 20:02:57 +00:00
void * dynarecrw = CC_RX2RW ( dynarec_code ) ;
2019-06-19 09:01:33 +00:00
// Returns a block who's code addr is bigger than dynarec_code (or end)
auto iter = blkmap . upper_bound ( dynarecrw ) ;
2019-06-21 14:18:34 +00:00
if ( iter = = blkmap . begin ( ) )
return NULL ;
2019-06-19 09:01:33 +00:00
iter - - ; // Need to go back to find the potential candidate
// However it might be out of bounds, check for that
2019-06-21 14:18:34 +00:00
if ( ( u8 * ) iter - > second - > code + iter - > second - > host_code_size < ( u8 * ) dynarec_code )
2019-06-19 09:01:33 +00:00
return NULL ;
verify ( iter - > second - > contains_code ( ( u8 * ) dynarecrw ) ) ;
return iter - > second ;
}
2019-09-30 13:47:05 +00:00
static void bm_CleanupDeletedBlocks ( )
2019-06-19 09:01:33 +00:00
{
del_blocks . clear ( ) ;
2013-12-19 17:10:14 +00:00
}
2019-05-12 20:02:57 +00:00
// Takes RX pointer and returns a RW pointer
2019-06-19 09:01:33 +00:00
RuntimeBlockInfoPtr bm_GetStaleBlock ( void * dynarec_code )
2013-12-19 17:10:14 +00:00
{
2019-05-12 20:02:57 +00:00
void * dynarecrw = CC_RX2RW ( dynarec_code ) ;
2019-06-19 09:01:33 +00:00
if ( del_blocks . empty ( ) )
return NULL ;
// Start from the end to get the youngest one
auto it = del_blocks . end ( ) ;
do
{
it - - ;
if ( ( * it ) - > contains_code ( ( u8 * ) dynarecrw ) )
return * it ;
} while ( it ! = del_blocks . begin ( ) ) ;
return NULL ;
2013-12-19 17:10:14 +00:00
}
void bm_AddBlock ( RuntimeBlockInfo * blk )
{
2019-06-19 09:01:33 +00:00
RuntimeBlockInfoPtr block ( blk ) ;
if ( block - > temp_block )
all_temp_blocks . insert ( block ) ;
auto iter = blkmap . find ( ( void * ) blk - > code ) ;
if ( iter ! = blkmap . end ( ) ) {
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " DUP: %08X %p %08X %p " , iter - > second - > addr , iter - > second - > code , block - > addr , block - > code ) ;
2013-12-19 17:10:14 +00:00
verify ( false ) ;
}
2019-06-19 09:01:33 +00:00
blkmap [ ( void * ) block - > code ] = block ;
2013-12-19 17:10:14 +00:00
2019-06-19 09:01:33 +00:00
verify ( ( void * ) bm_GetCode ( block - > addr ) = = ( void * ) ngen_FailedToFindBlock ) ;
FPCA ( block - > addr ) = ( DynarecCodeEntryPtr ) CC_RW2RX ( block - > code ) ;
2013-12-19 17:10:14 +00:00
# ifdef DYNA_OPROF
if ( oprofHandle )
{
char fname [ 512 ] ;
2019-06-19 09:01:33 +00:00
sprintf ( fname , " sh4:%08X,c:%d,s:%d,h:%d " , block - > addr , block - > guest_cycles , block - > guest_opcodes , block - > host_opcodes ) ;
2013-12-19 17:10:14 +00:00
2019-06-19 09:01:33 +00:00
if ( op_write_native_code ( oprofHandle , fname , ( uint64_t ) block - > code , ( void * ) block - > code , block - > host_code_size ) ! = 0 )
2013-12-19 17:10:14 +00:00
{
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " op_write_native_code error " ) ;
2013-12-19 17:10:14 +00:00
}
}
# endif
}
2019-06-19 09:01:33 +00:00
void bm_DiscardBlock ( RuntimeBlockInfo * block )
2019-03-25 10:53:13 +00:00
{
2019-06-19 09:01:33 +00:00
// Remove from block map
auto it = blkmap . find ( ( void * ) block - > code ) ;
verify ( it ! = blkmap . end ( ) ) ;
RuntimeBlockInfoPtr block_ptr = it - > second ;
blkmap . erase ( it ) ;
block_ptr - > pNextBlock = NULL ;
block_ptr - > pBranchBlock = NULL ;
block_ptr - > Relink ( ) ;
// Remove from jump table
verify ( ( void * ) bm_GetCode ( block_ptr - > addr ) = = ( void * ) block_ptr - > code ) ;
FPCA ( block_ptr - > addr ) = ngen_FailedToFindBlock ;
if ( block_ptr - > temp_block )
all_temp_blocks . erase ( block_ptr ) ;
del_blocks . push_back ( block_ptr ) ;
block_ptr - > Discard ( ) ;
2019-03-25 10:53:13 +00:00
}
2013-12-19 17:10:14 +00:00
void bm_Periodical_1s ( )
{
2019-06-19 09:01:33 +00:00
bm_CleanupDeletedBlocks ( ) ;
2013-12-19 17:10:14 +00:00
}
2019-05-10 16:57:28 +00:00
void bm_vmem_pagefill ( void * * ptr , u32 size_bytes )
2013-12-19 17:10:14 +00:00
{
2019-08-30 21:35:10 +00:00
for ( size_t i = 0 ; i < size_bytes / sizeof ( ptr [ 0 ] ) ; i + + )
2013-12-19 17:10:14 +00:00
{
ptr [ i ] = ( void * ) ngen_FailedToFindBlock ;
}
}
void bm_Reset ( )
2019-06-19 09:01:33 +00:00
{
bm_ResetCache ( ) ;
bm_CleanupDeletedBlocks ( ) ;
protected_blocks = 0 ;
unprotected_blocks = 0 ;
2019-07-04 07:36:22 +00:00
// Windows cannot lock/unlock a region spanning more than one VirtualAlloc or MapViewOfFile
// so we have to unlock each region individually
// No need for this mess in 4GB mode since windows doesn't use it
2019-07-09 21:52:19 +00:00
if ( settings . platform . ram_size = = 16 * 1024 * 1024 )
{
mem_region_unlock ( virt_ram_base + 0x0C000000 , RAM_SIZE ) ;
mem_region_unlock ( virt_ram_base + 0x0D000000 , RAM_SIZE ) ;
mem_region_unlock ( virt_ram_base + 0x0E000000 , RAM_SIZE ) ;
mem_region_unlock ( virt_ram_base + 0x0F000000 , RAM_SIZE ) ;
}
else
{
mem_region_unlock ( virt_ram_base + 0x0C000000 , RAM_SIZE ) ;
mem_region_unlock ( virt_ram_base + 0x0E000000 , RAM_SIZE ) ;
}
2019-06-19 09:01:33 +00:00
if ( _nvmem_4gb_space ( ) )
{
mem_region_unlock ( virt_ram_base + 0x8C000000 , 0x90000000 - 0x8C000000 ) ;
mem_region_unlock ( virt_ram_base + 0xAC000000 , 0xB0000000 - 0xAC000000 ) ;
}
}
static void bm_LockPage ( u32 addr )
{
addr = addr & ( RAM_MASK - PAGE_MASK ) ;
2019-08-28 12:08:13 +00:00
if ( ! mmu_enabled ( ) | | ! _nvmem_4gb_space ( ) )
2019-06-19 09:01:33 +00:00
mem_region_lock ( virt_ram_base + 0x0C000000 + addr , PAGE_SIZE ) ;
if ( _nvmem_4gb_space ( ) )
{
mem_region_lock ( virt_ram_base + 0x8C000000 + addr , PAGE_SIZE ) ;
mem_region_lock ( virt_ram_base + 0xAC000000 + addr , PAGE_SIZE ) ;
// TODO wraps
}
}
static void bm_UnlockPage ( u32 addr )
{
addr = addr & ( RAM_MASK - PAGE_MASK ) ;
2019-08-28 12:08:13 +00:00
if ( ! mmu_enabled ( ) | | ! _nvmem_4gb_space ( ) )
2019-06-19 09:01:33 +00:00
mem_region_unlock ( virt_ram_base + 0x0C000000 + addr , PAGE_SIZE ) ;
if ( _nvmem_4gb_space ( ) )
{
mem_region_unlock ( virt_ram_base + 0x8C000000 + addr , PAGE_SIZE ) ;
mem_region_unlock ( virt_ram_base + 0xAC000000 + addr , PAGE_SIZE ) ;
// TODO wraps
}
}
void bm_ResetCache ( )
2013-12-19 17:10:14 +00:00
{
ngen_ResetBlocks ( ) ;
_vmem_bm_reset ( ) ;
2019-09-30 13:47:05 +00:00
for ( const auto & it : blkmap )
2013-12-19 17:10:14 +00:00
{
2019-06-19 09:01:33 +00:00
RuntimeBlockInfoPtr block = it . second ;
block - > relink_data = 0 ;
block - > pNextBlock = 0 ;
block - > pBranchBlock = 0 ;
// needed for the transition to full mmu. Could perhaps limit it to the current block.
block - > Relink ( ) ;
// Avoid circular references
block - > Discard ( ) ;
del_blocks . push_back ( block ) ;
2013-12-19 17:10:14 +00:00
}
blkmap . clear ( ) ;
2019-06-19 09:01:33 +00:00
// blkmap includes temp blocks as well
all_temp_blocks . clear ( ) ;
for ( auto & block_list : blocks_per_page )
block_list . clear ( ) ;
// FIXME Grandia II doesn't like it. intermittent reset when pressing start (except if disabling SSA?? TBC)
memset ( unprotected_pages , 0 , sizeof ( unprotected_pages ) ) ;
2013-12-19 17:10:14 +00:00
# ifdef DYNA_OPROF
if ( oprofHandle )
{
for ( int i = 0 ; i < del_blocks . size ( ) ; i + + )
{
if ( op_unload_native_code ( oprofHandle , ( uint64_t ) del_blocks [ i ] - > code ) ! = 0 )
{
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " op_unload_native_code error " ) ;
2013-12-19 17:10:14 +00:00
}
}
}
# endif
}
2019-04-19 09:45:05 +00:00
void bm_ResetTempCache ( bool full )
{
if ( ! full )
{
2019-09-30 13:47:05 +00:00
for ( const auto & block : all_temp_blocks )
2019-04-19 09:45:05 +00:00
{
FPCA ( block - > addr ) = ngen_FailedToFindBlock ;
2019-06-19 09:01:33 +00:00
blkmap . erase ( ( void * ) block - > code ) ;
2019-04-19 09:45:05 +00:00
}
}
del_blocks . insert ( del_blocks . begin ( ) , all_temp_blocks . begin ( ) , all_temp_blocks . end ( ) ) ;
all_temp_blocks . clear ( ) ;
}
2013-12-19 17:10:14 +00:00
void bm_Init ( )
{
# ifdef DYNA_OPROF
oprofHandle = op_open_agent ( ) ;
if ( oprofHandle = = 0 )
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " bm: Failed to open oprofile " ) ;
2013-12-19 17:10:14 +00:00
else
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " bm: Oprofile integration enabled ! " ) ;
2013-12-19 17:10:14 +00:00
# endif
2019-06-19 09:01:33 +00:00
bm_Reset ( ) ;
2013-12-19 17:10:14 +00:00
}
void bm_Term ( )
{
# ifdef DYNA_OPROF
if ( oprofHandle ) op_close_agent ( oprofHandle ) ;
oprofHandle = 0 ;
# endif
2018-10-29 15:10:39 +00:00
bm_Reset ( ) ;
2013-12-19 17:10:14 +00:00
}
void bm_WriteBlockMap ( const string & file )
{
FILE * f = fopen ( file . c_str ( ) , " wb " ) ;
if ( f )
{
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " Writing block map ! " ) ;
2019-06-19 09:01:33 +00:00
for ( auto & it : blkmap )
2013-12-19 17:10:14 +00:00
{
2019-06-19 09:01:33 +00:00
RuntimeBlockInfoPtr & block = it . second ;
fprintf ( f , " block: %d:%08X:%p:%d:%d:%d \n " , block - > BlockType , block - > addr , block - > code , block - > host_code_size , block - > guest_cycles , block - > guest_opcodes ) ;
for ( size_t j = 0 ; j < block - > oplist . size ( ) ; j + + )
fprintf ( f , " \t op: %zd:%d:%s \n " , j , block - > oplist [ j ] . guest_offs , block - > oplist [ j ] . dissasm ( ) . c_str ( ) ) ;
2013-12-19 17:10:14 +00:00
}
fclose ( f ) ;
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " Finished writing block map " ) ;
2013-12-19 17:10:14 +00:00
}
}
2019-09-30 13:47:05 +00:00
void sh4_jitsym ( FILE * out )
{
for ( const auto & it : blkmap )
{
const RuntimeBlockInfoPtr & block = it . second ;
fprintf ( out , " %p %d %08X \n " , block - > code , block - > host_code_size , block - > addr ) ;
}
}
#if 0
2013-12-19 17:10:14 +00:00
u32 GetLookup ( RuntimeBlockInfo * elem )
{
2013-12-24 00:56:44 +00:00
return elem - > lookups ;
2013-12-19 17:10:14 +00:00
}
bool UDgreater ( RuntimeBlockInfo * elem1 , RuntimeBlockInfo * elem2 )
2013-12-24 00:56:44 +00:00
{
2013-12-19 17:10:14 +00:00
return elem1 - > runs > elem2 - > runs ;
}
bool UDgreater2 ( RuntimeBlockInfo * elem1 , RuntimeBlockInfo * elem2 )
{
return elem1 - > runs * elem1 - > host_opcodes > elem2 - > runs * elem2 - > host_opcodes ;
}
bool UDgreater3 ( RuntimeBlockInfo * elem1 , RuntimeBlockInfo * elem2 )
{
return elem1 - > runs * elem1 - > host_opcodes / elem1 - > guest_cycles > elem2 - > runs * elem2 - > host_opcodes / elem2 - > guest_cycles ;
}
void bm_PrintTopBlocks ( )
{
double total_lups = 0 ;
double total_runs = 0 ;
double total_cycles = 0 ;
double total_hops = 0 ;
double total_sops = 0 ;
for ( size_t i = 0 ; i < all_blocks . size ( ) ; i + + )
{
total_lups + = GetLookup ( all_blocks [ i ] ) ;
total_cycles + = all_blocks [ i ] - > runs * all_blocks [ i ] - > guest_cycles ;
total_hops + = all_blocks [ i ] - > runs * all_blocks [ i ] - > host_opcodes ;
total_sops + = all_blocks [ i ] - > runs * all_blocks [ i ] - > guest_opcodes ;
total_runs + = all_blocks [ i ] - > runs ;
}
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " Total lookups: %.0fKRuns, %.0fKLuops, Total cycles: %.0fMhz, Total Hops: %.0fMips, Total Sops: %.0fMips! " , total_runs / 1000 , total_lups / 1000 , total_cycles / 1000 / 1000 , total_hops / 1000 / 1000 , total_sops / 1000 / 1000 ) ;
2013-12-19 17:10:14 +00:00
total_hops / = 100 ;
total_cycles / = 100 ;
total_runs / = 100 ;
double sel_hops = 0 ;
for ( size_t i = 0 ; i < ( all_blocks . size ( ) / 100 ) ; i + + )
{
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " Block %08X: %p, r: %d (c: %d, s: %d, h: %d) (r: %.2f%%, c: %.2f%%, h: %.2f%%) " ,
2013-12-19 17:10:14 +00:00
all_blocks [ i ] - > addr , all_blocks [ i ] - > code , all_blocks [ i ] - > runs ,
all_blocks [ i ] - > guest_cycles , all_blocks [ i ] - > guest_opcodes , all_blocks [ i ] - > host_opcodes ,
all_blocks [ i ] - > runs / total_runs ,
all_blocks [ i ] - > guest_cycles * all_blocks [ i ] - > runs / total_cycles ,
all_blocks [ i ] - > host_opcodes * all_blocks [ i ] - > runs / total_hops ) ;
sel_hops + = all_blocks [ i ] - > host_opcodes * all_blocks [ i ] - > runs ;
}
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " >-< %.2f%% covered in top 1%% blocks " , sel_hops / total_hops ) ;
2013-12-19 17:10:14 +00:00
size_t i ;
for ( i = all_blocks . size ( ) / 100 ; sel_hops / total_hops < 50 ; i + + )
{
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " Block %08X: %p, r: %d (c: %d, s: %d, h: %d) (r: %.2f%%, c: %.2f%%, h: %.2f%%) " ,
2013-12-19 17:10:14 +00:00
all_blocks [ i ] - > addr , all_blocks [ i ] - > code , all_blocks [ i ] - > runs ,
all_blocks [ i ] - > guest_cycles , all_blocks [ i ] - > guest_opcodes , all_blocks [ i ] - > host_opcodes ,
all_blocks [ i ] - > runs / total_runs ,
all_blocks [ i ] - > guest_cycles * all_blocks [ i ] - > runs / total_cycles ,
all_blocks [ i ] - > host_opcodes * all_blocks [ i ] - > runs / total_hops ) ;
sel_hops + = all_blocks [ i ] - > host_opcodes * all_blocks [ i ] - > runs ;
}
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " >-< %.2f%% covered in top %.2f%% blocks " , sel_hops / total_hops , i * 100.0 / all_blocks . size ( ) ) ;
2013-12-19 17:10:14 +00:00
}
void bm_Sort ( )
{
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " !!!!!!!!!!!!!!!!!!! BLK REPORT !!!!!!!!!!!!!!!!!!!! " ) ;
2013-12-19 17:10:14 +00:00
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " ---- Blocks: Sorted based on Runs ! ---- " ) ;
2013-12-19 17:10:14 +00:00
std : : sort ( all_blocks . begin ( ) , all_blocks . end ( ) , UDgreater ) ;
bm_PrintTopBlocks ( ) ;
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " <><><><><><><><><><><><><><><><><><><><><><><><><> " ) ;
2013-12-19 17:10:14 +00:00
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " ---- Blocks: Sorted based on hops ! ---- " ) ;
2013-12-19 17:10:14 +00:00
std : : sort ( all_blocks . begin ( ) , all_blocks . end ( ) , UDgreater2 ) ;
bm_PrintTopBlocks ( ) ;
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " <><><><><><><><><><><><><><><><><><><><><><><><><> " ) ;
2013-12-19 17:10:14 +00:00
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " ---- Blocks: Sorted based on wefs ! ---- " ) ;
2013-12-19 17:10:14 +00:00
std : : sort ( all_blocks . begin ( ) , all_blocks . end ( ) , UDgreater3 ) ;
bm_PrintTopBlocks ( ) ;
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " ^^^^^^^^^^^^^^^^^^^ END REPORT ^^^^^^^^^^^^^^^^^^^ " ) ;
2013-12-19 17:10:14 +00:00
for ( size_t i = 0 ; i < all_blocks . size ( ) ; i + + )
{
all_blocks [ i ] - > runs = 0 ;
}
}
2019-06-19 09:01:33 +00:00
# endif
2013-12-19 17:10:14 +00:00
RuntimeBlockInfo : : ~ RuntimeBlockInfo ( )
{
2019-06-19 20:55:47 +00:00
if ( sh4_code_size ! = 0 )
{
if ( read_only )
protected_blocks - - ;
else
unprotected_blocks - - ;
}
2013-12-19 17:10:14 +00:00
}
2019-06-19 09:01:33 +00:00
void RuntimeBlockInfo : : AddRef ( RuntimeBlockInfoPtr other )
2013-12-19 17:10:14 +00:00
{
pre_refs . push_back ( other ) ;
}
2019-06-19 09:01:33 +00:00
void RuntimeBlockInfo : : RemRef ( RuntimeBlockInfoPtr other )
2013-12-19 17:10:14 +00:00
{
2019-06-19 09:01:33 +00:00
bm_List : : iterator it = std : : find ( pre_refs . begin ( ) , pre_refs . end ( ) , other ) ;
if ( it ! = pre_refs . end ( ) )
pre_refs . erase ( it ) ;
2013-12-19 17:10:14 +00:00
}
2019-06-19 09:01:33 +00:00
void RuntimeBlockInfo : : Discard ( )
{
// Update references
for ( RuntimeBlockInfoPtr & ref : pre_refs )
{
if ( ref - > NextBlock = = vaddr )
ref - > pNextBlock = NULL ;
if ( ref - > BranchBlock = = vaddr )
ref - > pBranchBlock = NULL ;
ref - > relink_data = 0 ;
ref - > Relink ( ) ;
}
pre_refs . clear ( ) ;
2013-12-19 17:10:14 +00:00
2019-06-19 09:01:33 +00:00
if ( read_only )
{
// Remove this block from the per-page block lists
for ( u32 addr = this - > addr & ~ PAGE_MASK ; addr < this - > addr + this - > sh4_code_size ; addr + = PAGE_SIZE )
{
2019-09-30 13:47:05 +00:00
auto & block_list = blocks_per_page [ ( addr & RAM_MASK ) / PAGE_SIZE ] ;
2019-06-19 09:01:33 +00:00
block_list . erase ( this ) ;
}
}
}
void RuntimeBlockInfo : : SetProtectedFlags ( )
{
2019-06-21 14:18:34 +00:00
// Don't write protect rom and BIOS/IP.BIN (Grandia II)
2019-08-30 12:11:15 +00:00
if ( ! IsOnRam ( addr ) | | ( addr & 0x1FFF0000 ) = = 0x0c000000 )
2019-06-19 09:01:33 +00:00
{
this - > read_only = false ;
unprotected_blocks + + ;
return ;
}
for ( u32 addr = this - > addr & ~ PAGE_MASK ; addr < this - > addr + sh4_code_size ; addr + = PAGE_SIZE )
{
if ( unprotected_pages [ ( addr & RAM_MASK ) / PAGE_SIZE ] )
{
this - > read_only = false ;
unprotected_blocks + + ;
return ;
}
}
this - > read_only = true ;
protected_blocks + + ;
for ( u32 addr = this - > addr & ~ PAGE_MASK ; addr < this - > addr + sh4_code_size ; addr + = PAGE_SIZE )
{
2019-09-30 13:47:05 +00:00
auto & block_list = blocks_per_page [ ( addr & RAM_MASK ) / PAGE_SIZE ] ;
if ( block_list . empty ( ) )
bm_LockPage ( addr ) ;
block_list . insert ( this ) ;
2019-06-19 09:01:33 +00:00
}
}
void bm_RamWriteAccess ( u32 addr )
{
addr & = RAM_MASK ;
if ( unprotected_pages [ addr / PAGE_SIZE ] )
{
2019-07-01 10:17:51 +00:00
ERROR_LOG ( DYNAREC , " Page %08x already unprotected " , addr ) ;
2019-06-19 09:01:33 +00:00
die ( " Fatal error " ) ;
}
unprotected_pages [ addr / PAGE_SIZE ] = true ;
bm_UnlockPage ( addr ) ;
set < RuntimeBlockInfo * > & block_list = blocks_per_page [ addr / PAGE_SIZE ] ;
vector < RuntimeBlockInfo * > list_copy ;
list_copy . insert ( list_copy . begin ( ) , block_list . begin ( ) , block_list . end ( ) ) ;
2019-07-01 10:17:51 +00:00
if ( ! list_copy . empty ( ) )
DEBUG_LOG ( DYNAREC , " bm_RamWriteAccess write access to %08x pc %08x " , addr , next_pc ) ;
2019-06-19 09:01:33 +00:00
for ( auto & block : list_copy )
{
bm_DiscardBlock ( block ) ;
}
verify ( block_list . empty ( ) ) ;
}
2019-06-19 20:55:47 +00:00
bool bm_RamWriteAccess ( void * p )
2019-06-19 09:01:33 +00:00
{
if ( _nvmem_4gb_space ( ) )
{
if ( ( u8 * ) p < virt_ram_base | | ( u8 * ) p > = virt_ram_base + 0x100000000L )
return false ;
}
else
{
if ( ( u8 * ) p < virt_ram_base | | ( u8 * ) p > = virt_ram_base + 0x20000000 )
return false ;
}
u32 addr = ( u8 * ) p - virt_ram_base ;
2019-08-28 12:08:13 +00:00
if ( mmu_enabled ( ) & & _nvmem_4gb_space ( ) & & ( addr & 0x80000000 ) = = 0 )
2019-06-19 09:01:33 +00:00
// If mmu enabled, let vmem32 manage user space
// shouldn't be necessary since it's called first
return false ;
if ( ! IsOnRam ( addr ) | | ( ( addr > > 29 ) > 0 & & ( addr > > 29 ) < 4 ) ) // system RAM is not mapped to 20, 40 and 60 because of laziness
return false ;
bm_RamWriteAccess ( addr ) ;
return true ;
}
2019-07-07 22:03:44 +00:00
bool print_stats = true ;
2013-12-19 17:10:14 +00:00
void fprint_hex ( FILE * d , const char * init , u8 * ptr , u32 & ofs , u32 limit )
{
int base = ofs ;
int cnt = 0 ;
while ( ofs < limit )
{
if ( cnt = = 32 )
{
fputs ( " \n " , d ) ;
cnt = 0 ;
}
if ( cnt = = 0 )
fprintf ( d , " %s:%d: " , init , ofs - base ) ;
fprintf ( d , " %02X " , ptr [ ofs + + ] ) ;
cnt + + ;
}
fputs ( " \n " , d ) ;
}
void print_blocks ( )
{
FILE * f = 0 ;
if ( print_stats )
{
2015-08-28 23:28:51 +00:00
f = fopen ( get_writable_data_path ( " /blkmap.lst " ) . c_str ( ) , " w " ) ;
2013-12-19 17:10:14 +00:00
print_stats = 0 ;
2019-07-01 10:17:51 +00:00
INFO_LOG ( DYNAREC , " Writing blocks to %p " , f ) ;
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
for ( auto it : blkmap )
2013-12-19 17:10:14 +00:00
{
2019-07-07 22:03:44 +00:00
RuntimeBlockInfoPtr blk = it . second ;
2013-12-19 17:10:14 +00:00
if ( f )
{
2019-07-07 22:03:44 +00:00
fprintf ( f , " block: %p \n " , blk . get ( ) ) ;
2019-03-25 10:53:13 +00:00
fprintf ( f , " vaddr: %08X \n " , blk - > vaddr ) ;
fprintf ( f , " paddr: %08X \n " , blk - > addr ) ;
2013-12-19 17:10:14 +00:00
fprintf ( f , " hash: %s \n " , blk - > hash ( ) ) ;
2019-09-29 21:14:38 +00:00
fprintf ( f , " hash_rloc: %s \n " , blk - > hash ( ) ) ;
2019-02-16 13:16:50 +00:00
fprintf ( f , " code: %p \n " , blk - > code ) ;
2013-12-19 17:10:14 +00:00
fprintf ( f , " runs: %d \n " , blk - > runs ) ;
fprintf ( f , " BlockType: %d \n " , blk - > BlockType ) ;
fprintf ( f , " NextBlock: %08X \n " , blk - > NextBlock ) ;
fprintf ( f , " BranchBlock: %08X \n " , blk - > BranchBlock ) ;
2019-02-16 13:16:50 +00:00
fprintf ( f , " pNextBlock: %p \n " , blk - > pNextBlock ) ;
fprintf ( f , " pBranchBlock: %p \n " , blk - > pBranchBlock ) ;
2013-12-19 17:10:14 +00:00
fprintf ( f , " guest_cycles: %d \n " , blk - > guest_cycles ) ;
fprintf ( f , " guest_opcodes: %d \n " , blk - > guest_opcodes ) ;
fprintf ( f , " host_opcodes: %d \n " , blk - > host_opcodes ) ;
2019-02-16 13:16:50 +00:00
fprintf ( f , " il_opcodes: %zd \n " , blk - > oplist . size ( ) ) ;
2013-12-19 17:10:14 +00:00
u32 hcode = 0 ;
s32 gcode = - 1 ;
u8 * pucode = ( u8 * ) blk - > code ;
size_t j = 0 ;
fprintf ( f , " { \n " ) ;
for ( ; j < blk - > oplist . size ( ) ; j + + )
{
2019-06-19 09:01:33 +00:00
shil_opcode * op = & blk - > oplist [ j ] ;
2019-07-07 22:03:44 +00:00
//fprint_hex(f,"//h:",pucode,hcode,op->host_offs);
2013-12-19 17:10:14 +00:00
if ( gcode ! = op - > guest_offs )
{
gcode = op - > guest_offs ;
2019-03-25 10:53:13 +00:00
u32 rpc = blk - > vaddr + gcode ;
2019-03-25 12:53:49 +00:00
# ifndef NO_MMU
2019-03-25 10:53:13 +00:00
try {
2019-03-25 12:53:49 +00:00
# endif
2019-03-25 10:53:13 +00:00
u16 op = IReadMem16 ( rpc ) ;
2013-12-19 17:10:14 +00:00
2019-03-25 10:53:13 +00:00
char temp [ 128 ] ;
OpDesc [ op ] - > Disassemble ( temp , rpc , op ) ;
2013-12-19 17:10:14 +00:00
2019-03-25 10:53:13 +00:00
fprintf ( f , " //g: %04X %s \n " , op , temp ) ;
2019-03-25 12:53:49 +00:00
# ifndef NO_MMU
2019-03-25 10:53:13 +00:00
} catch ( SH4ThrownException & ex ) {
fprintf ( f , " //g: ???? (page fault) \n " ) ;
}
2019-03-25 12:53:49 +00:00
# endif
2013-12-19 17:10:14 +00:00
}
string s = op - > dissasm ( ) ;
2019-03-25 10:53:13 +00:00
fprintf ( f , " //il:%d:%d: %s \n " , op - > guest_offs , op - > host_offs , s . c_str ( ) ) ;
2013-12-19 17:10:14 +00:00
}
2019-07-07 22:03:44 +00:00
//fprint_hex(f,"//h:",pucode,hcode,blk->host_code_size);
2013-12-19 17:10:14 +00:00
fprintf ( f , " } \n " ) ;
}
2019-06-19 09:01:33 +00:00
blk - > runs = 0 ;
2013-12-19 17:10:14 +00:00
}
if ( f ) fclose ( f ) ;
}
2015-07-25 06:39:35 +00:00
# endif
2013-12-19 17:10:14 +00:00