/*
	In case you wonder, the extern "C" stuff are for the assembly code on beagleboard/pandora
*/
#include <memory>
#include <map>
#include "types.h"
#include "decoder.h"
#pragma once

typedef void (*DynarecCodeEntryPtr)();
typedef std::shared_ptr<RuntimeBlockInfo> RuntimeBlockInfoPtr;

#define CODE_SIZE   (16*1024*1024)

#ifdef NO_MMU
#define TEMP_CODE_SIZE (0)
#else
#define TEMP_CODE_SIZE (1024*1024)
#endif

extern u8* CodeCache;

struct RuntimeBlockInfo_Core
{
	u32 addr;
	DynarecCodeEntryPtr code;
	u32 lookups;
};

struct RuntimeBlockInfo: RuntimeBlockInfo_Core
{
	bool Setup(u32 pc,fpscr_t fpu_cfg);
	const char* hash();

	u32 vaddr;

	u32 host_code_size;	   /* in bytes */
	u32 sh4_code_size;      /* in bytes */

	u32 runs;
	s32 staging_runs;

	fpscr_t fpu_cfg;
	u32 guest_cycles;
	u32 guest_opcodes;
	u32 host_opcodes;
	bool has_fpu_op;
	u32 blockcheck_failures;
	bool temp_block;

	u32 BranchBlock; /* if not 0xFFFFFFFF then jump target */
	u32 NextBlock;   /* if not 0xFFFFFFFF then next block (by position) */

	/* 0 if not available */
	RuntimeBlockInfo* pBranchBlock;
	RuntimeBlockInfo* pNextBlock; 

	u32 relink_offset;
	u32 relink_data;
	u32 csc_RetCache; /* only for stats for now */

	BlockEndType BlockType;
	bool has_jcond;

	vector<shil_opcode> oplist;

	bool contains_code(u8* ptr)
	{
		return ((size_t)(ptr-(u8*)code)) < host_code_size;
	}

	virtual ~RuntimeBlockInfo();

	virtual u32 Relink()=0;
	virtual void Relocate(void* dst)=0;
	
	//predecessors references
	vector<RuntimeBlockInfoPtr> pre_refs;

	void AddRef(RuntimeBlockInfoPtr other);
	void RemRef(RuntimeBlockInfoPtr other);

	void Discard();
	void UpdateRefs();
	void SetProtectedFlags();

	u32 memops;
	u32 linkedmemops;
	std::map<void*, u32> memory_accesses;	// key is host pc when access is made, value is opcode id
	bool read_only;
};

void bm_WriteBlockMap(const string& file);

extern "C" {
__attribute__((used)) DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr);
__attribute__((used)) DynarecCodeEntryPtr DYNACALL bm_GetCodeByVAddr(u32 addr);
}

RuntimeBlockInfoPtr bm_GetBlock2(void* dynarec_code);
RuntimeBlockInfoPtr bm_GetStaleBlock(void* dynarec_code);
RuntimeBlockInfoPtr DYNACALL bm_GetBlock(u32 addr);

void bm_AddBlock(RuntimeBlockInfo* blk);
void bm_DiscardBlock(RuntimeBlockInfo* block);
void bm_Reset();
void bm_ResetCache();
void bm_ResetTempCache(bool full);
void bm_Periodical_1s();

void bm_Init();
void bm_Term();

void bm_vmem_pagefill(void** ptr,u32 PAGE_SZ);
bool bm_RamWriteAccess(void *p);
void bm_RamWriteAccess(u32 addr);
static inline bool bm_IsRamPageProtected(u32 addr)
{
	extern bool unprotected_pages[RAM_SIZE_MAX/PAGE_SIZE];
	addr &= RAM_MASK;
	return !unprotected_pages[addr / PAGE_SIZE];
}
