/**********************************************************/
/*                                                        */
/* SH2 emulator 1.60 (C source part)                      */
/* This part define only the initialisation stuff...      */
/* Emulation core itself is defined in the SH2a.asm file. */
/* Copyright 2002 Stéphane Dallongeville                  */
/*                                                        */
/**********************************************************/

#define SH2_VERSION "1.60"

// Message logging.
#include "macros/log_msg.h"

// C includes.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sh2.h"


/************************************************************/
/*                                                          */
/* Opcode Table :                                           */
/* Almost of the following table was taken from the         */
/* Tim's SH2 core (Retrodrives).                            */
/*                                                          */
/************************************************************/


typedef enum __ifmt
{
	IFMT_0,			// xxxx xxxx xxxx xxxx
	IFMT_n,			// xxxx nnnn xxxx xxxx
	IFMT_m,			// xxxx mmmm xxxx xxxx
	IFMT_nm,		// xxxx nnnn mmmm xxxx
	IFMT_md,		// xxxx xxxx mmmm dddd
	IFMT_nd4,		// xxxx xxxx nnnn dddd
	IFMT_nmd,		// xxxx nnnn mmmm dddd
	IFMT_d,			// xxxx xxxx dddd dddd
	IFMT_d12,		// xxxx dddd dddd dddd
	IFMT_nd8,		// xxxx nnnn dddd dddd
	IFMT_i,			// xxxx xxxx iiii iiii
	IFMT_ni,		// xxxx nnnn iiii iiii
} _IFMT;


typedef void (*SH2_INST_CALL)(void);


typedef struct
{
	_IFMT IFMT;
	uint32_t Mask;
	SH2_INST_CALL Func;
} PACKED_OP_TAB;

const PACKED_OP_TAB InitOp[] = {
	{IFMT_nm, 0x300C, SH2I_ADD},
	{IFMT_ni, 0x7000, SH2I_ADDI},
	{IFMT_nm, 0x300E, SH2I_ADDC},
	{IFMT_nm, 0x300F, SH2I_ADDV},
	{IFMT_nm, 0x2009, SH2I_AND},
	{IFMT_i, 0xC900, SH2I_ANDI},
	{IFMT_i, 0xCD00, SH2I_ANDM},
	{IFMT_d, 0x8B00, SH2I_BF},
	{IFMT_0, 0x8BFD, SH2I_BFfast},
	{IFMT_d, 0x8F00, SH2I_BFS},
	{IFMT_0, 0x8FFD, SH2I_BFSfast},
	{IFMT_d12, 0xA000, SH2I_BRA},
	{IFMT_0, 0xAFFE, SH2I_BRAfast1},
	{IFMT_0, 0xAFFD, SH2I_BRAfast2},
	{IFMT_m, 0x0023, SH2I_BRAF},
	{IFMT_d12, 0xB000, SH2I_BSR},
	{IFMT_n, 0x0003, SH2I_BSRF},
	{IFMT_d, 0x8900, SH2I_BT},
	{IFMT_d, 0x8D00, SH2I_BTS},
	{IFMT_0, 0x0028, SH2I_CLRMAC},
	{IFMT_0, 0x0008, SH2I_CLRT},
	{IFMT_nm, 0x3000, SH2I_CMPEQ},
	{IFMT_nm, 0x3003, SH2I_CMPGE},
	{IFMT_nm, 0x3007, SH2I_CMPGT},
	{IFMT_nm, 0x3006, SH2I_CMPHI},
	{IFMT_nm, 0x3002, SH2I_CMPHS},
	{IFMT_n, 0x4015, SH2I_CMPPL},
	{IFMT_n, 0x4011, SH2I_CMPPZ},
	{IFMT_nm, 0x200C, SH2I_CMPSTR},
	{IFMT_i, 0x8800, SH2I_CMPIM},
	{IFMT_nm, 0x2007, SH2I_DIV0S},
	{IFMT_0, 0x0019, SH2I_DIV0U},
	{IFMT_nm, 0x3004, SH2I_DIV1},
	{IFMT_nm, 0x300D, SH2I_DMULS},
	{IFMT_nm, 0x3005, SH2I_DMULU},
	{IFMT_n, 0x4010, SH2I_DT},
	{IFMT_nm, 0x600E, SH2I_EXTSB},
	{IFMT_nm, 0x600F, SH2I_EXTSW},
	{IFMT_nm, 0x600C, SH2I_EXTUB},
	{IFMT_nm, 0x600D, SH2I_EXTUW},
	{IFMT_n, 0x402B, SH2I_JMP},
	{IFMT_n, 0x400B, SH2I_JSR},
	{IFMT_m, 0x400E, SH2I_LDCSR},
	{IFMT_m, 0x401E, SH2I_LDCGBR},
	{IFMT_m, 0x402E, SH2I_LDCVBR},
	{IFMT_m, 0x4007, SH2I_LDCMSR},
	{IFMT_m, 0x4017, SH2I_LDCMGBR},
	{IFMT_m, 0x4027, SH2I_LDCMVBR},
	{IFMT_m, 0x400A, SH2I_LDSMACH},
	{IFMT_m, 0x401A, SH2I_LDSMACL},
	{IFMT_m, 0x402A, SH2I_LDSPR},
	{IFMT_m, 0x4006, SH2I_LDSMMACH},
	{IFMT_m, 0x4016, SH2I_LDSMMACL},
	{IFMT_m, 0x4026, SH2I_LDSMPR},
	{IFMT_nm, 0x000F, SH2I_MACL},
	{IFMT_nm, 0x400F, SH2I_MACW},
	{IFMT_nm, 0x6003, SH2I_MOV},
	{IFMT_nm, 0x2000, SH2I_MOVBS},
	{IFMT_nm, 0x2001, SH2I_MOVWS},
	{IFMT_nm, 0x2002, SH2I_MOVLS},
	{IFMT_nm, 0x6000, SH2I_MOVBL},
	{IFMT_nm, 0x6001, SH2I_MOVWL},
	{IFMT_nm, 0x6002, SH2I_MOVLL},
	{IFMT_nm, 0x2004, SH2I_MOVBM},
	{IFMT_nm, 0x2005, SH2I_MOVWM},
	{IFMT_nm, 0x2006, SH2I_MOVLM},
	{IFMT_nm, 0x6004, SH2I_MOVBP},
	{IFMT_nm, 0x6005, SH2I_MOVWP},
	{IFMT_nm, 0x6006, SH2I_MOVLP},
	{IFMT_nm, 0x0004, SH2I_MOVBS0},
	{IFMT_nm, 0x0005, SH2I_MOVWS0},
	{IFMT_nm, 0x0006, SH2I_MOVLS0},
	{IFMT_nm, 0x000C, SH2I_MOVBL0},
	{IFMT_nm, 0x000D, SH2I_MOVWL0},
	{IFMT_nm, 0x000E, SH2I_MOVLL0},
	{IFMT_ni, 0xE000, SH2I_MOVI},
	{IFMT_nd8, 0x9000, SH2I_MOVWI},
	{IFMT_nd8, 0xD000, SH2I_MOVLI},
	{IFMT_d, 0xC400, SH2I_MOVBLG},
	{IFMT_d, 0xC500, SH2I_MOVWLG},
	{IFMT_d, 0xC600, SH2I_MOVLLG},
	{IFMT_d, 0xC000, SH2I_MOVBSG},
	{IFMT_d, 0xC100, SH2I_MOVWSG},
	{IFMT_d, 0xC200, SH2I_MOVLSG},
	{IFMT_nd4, 0x8000, SH2I_MOVBS4},
	{IFMT_nd4, 0x8100, SH2I_MOVWS4},
	{IFMT_nmd, 0x1000, SH2I_MOVLS4},
	{IFMT_md, 0x8400, SH2I_MOVBL4},
	{IFMT_md, 0x8500, SH2I_MOVWL4},
	{IFMT_nmd, 0x5000, SH2I_MOVLL4},
	{IFMT_d, 0xC700, SH2I_MOVA},
	{IFMT_n, 0x0029, SH2I_MOVT},
	{IFMT_nm, 0x0007, SH2I_MULL},
	{IFMT_nm, 0x200F, SH2I_MULS},
	{IFMT_nm, 0x200E, SH2I_MULU},
	{IFMT_nm, 0x600B, SH2I_NEG},
	{IFMT_nm, 0x600A, SH2I_NEGC},
	{IFMT_0, 0x0009, SH2I_NOP},
	{IFMT_nm, 0x6007, SH2I_NOT},
	{IFMT_nm, 0x200B, SH2I_OR},
	{IFMT_i, 0xCB00, SH2I_ORI},
	{IFMT_i, 0xCF00, SH2I_ORM},
	{IFMT_n, 0x4024, SH2I_ROTCL},
	{IFMT_n, 0x4025, SH2I_ROTCR},
	{IFMT_n, 0x4004, SH2I_ROTL},
	{IFMT_n, 0x4005, SH2I_ROTR},
	{IFMT_0, 0x002B, SH2I_RTE},
	{IFMT_0, 0x000B, SH2I_RTS},
	{IFMT_0, 0x0018, SH2I_SETT},
	{IFMT_n, 0x4020, SH2I_SHAL},
	{IFMT_n, 0x4021, SH2I_SHAR},
	{IFMT_n, 0x4000, SH2I_SHLL},
	{IFMT_n, 0x4008, SH2I_SHLL2},
	{IFMT_n, 0x4018, SH2I_SHLL8},
	{IFMT_n, 0x4028, SH2I_SHLL16},
	{IFMT_n, 0x4001, SH2I_SHLR},
	{IFMT_n, 0x4009, SH2I_SHLR2},
	{IFMT_n, 0x4019, SH2I_SHLR8},
	{IFMT_n, 0x4029, SH2I_SHLR16},
	{IFMT_0, 0x001B, SH2I_SLEEP},
	{IFMT_n, 0x0002, SH2I_STCSR},
	{IFMT_n, 0x0012, SH2I_STCGBR},
	{IFMT_n, 0x0022, SH2I_STCVBR},
	{IFMT_n, 0x4003, SH2I_STCMSR},
	{IFMT_n, 0x4013, SH2I_STCMGBR},
	{IFMT_n, 0x4023, SH2I_STCMVBR},
	{IFMT_n, 0x000A, SH2I_STSMACH},
	{IFMT_n, 0x001A, SH2I_STSMACL},
	{IFMT_n, 0x002A, SH2I_STSPR},
	{IFMT_n, 0x4002, SH2I_STSMMACH},
	{IFMT_n, 0x4012, SH2I_STSMMACL},
	{IFMT_n, 0x4022, SH2I_STSMPR},
	{IFMT_nm, 0x3008, SH2I_SUB},
	{IFMT_nm, 0x300A, SH2I_SUBC},
	{IFMT_nm, 0x300B, SH2I_SUBV},
	{IFMT_nm, 0x6008, SH2I_SWAPB},
	{IFMT_nm, 0x6009, SH2I_SWAPW},
	{IFMT_n, 0x401B, SH2I_TAS},
	{IFMT_i, 0xC300, SH2I_TRAPA},
	{IFMT_nm, 0x2008, SH2I_TST},
	{IFMT_i, 0xC800, SH2I_TSTI},
	{IFMT_i, 0xCC00, SH2I_TSTM},
	{IFMT_nm, 0x200A, SH2I_XOR},
	{IFMT_i, 0xCA00, SH2I_XORI},
	{IFMT_i, 0xCE00, SH2I_XORM},
	{IFMT_nm, 0x200D, SH2I_XTRCT},
	{0, 0x0000, NULL},
};

const PACKED_OP_TAB InitOpDS[] = {
	{IFMT_nm, 0x300C, SH2I_ADD_DS},
	{IFMT_ni, 0x7000, SH2I_ADDI_DS},
	{IFMT_nm, 0x300E, SH2I_ADDC_DS},
	{IFMT_nm, 0x300F, SH2I_ADDV_DS},
	{IFMT_nm, 0x2009, SH2I_AND_DS},
	{IFMT_i, 0xC900, SH2I_ANDI_DS},
	{IFMT_i, 0xCD00, SH2I_ANDM_DS},
	{IFMT_0, 0x0028, SH2I_CLRMAC_DS},
	{IFMT_0, 0x0008, SH2I_CLRT_DS},
	{IFMT_nm, 0x3000, SH2I_CMPEQ_DS},
	{IFMT_nm, 0x3003, SH2I_CMPGE_DS},
	{IFMT_nm, 0x3007, SH2I_CMPGT_DS},
	{IFMT_nm, 0x3006, SH2I_CMPHI_DS},
	{IFMT_nm, 0x3002, SH2I_CMPHS_DS},
	{IFMT_n, 0x4015, SH2I_CMPPL_DS},
	{IFMT_n, 0x4011, SH2I_CMPPZ_DS},
	{IFMT_nm, 0x200C, SH2I_CMPSTR_DS},
	{IFMT_i, 0x8800, SH2I_CMPIM_DS},
	{IFMT_nm, 0x2007, SH2I_DIV0S_DS},
	{IFMT_0, 0x0019, SH2I_DIV0U_DS},
	{IFMT_nm, 0x3004, SH2I_DIV1_DS},
	{IFMT_nm, 0x300D, SH2I_DMULS_DS},
	{IFMT_nm, 0x3005, SH2I_DMULU_DS},
	{IFMT_n, 0x4010, SH2I_DT_DS},
	{IFMT_nm, 0x600E, SH2I_EXTSB_DS},
	{IFMT_nm, 0x600F, SH2I_EXTSW_DS},
	{IFMT_nm, 0x600C, SH2I_EXTUB_DS},
	{IFMT_nm, 0x600D, SH2I_EXTUW_DS},
	{IFMT_m, 0x400E, SH2I_LDCSR_DS},
	{IFMT_m, 0x401E, SH2I_LDCGBR_DS},
	{IFMT_m, 0x402E, SH2I_LDCVBR_DS},
	{IFMT_m, 0x4007, SH2I_LDCMSR_DS},
	{IFMT_m, 0x4017, SH2I_LDCMGBR_DS},
	{IFMT_m, 0x4027, SH2I_LDCMVBR_DS},
	{IFMT_m, 0x400A, SH2I_LDSMACH_DS},
	{IFMT_m, 0x401A, SH2I_LDSMACL_DS},
	{IFMT_m, 0x402A, SH2I_LDSPR_DS},
	{IFMT_m, 0x4006, SH2I_LDSMMACH_DS},
	{IFMT_m, 0x4016, SH2I_LDSMMACL_DS},
	{IFMT_m, 0x4026, SH2I_LDSMPR_DS},
	{IFMT_nm, 0x000F, SH2I_MACL_DS},
	{IFMT_nm, 0x400F, SH2I_MACW_DS},
	{IFMT_nm, 0x6003, SH2I_MOV_DS},
	{IFMT_nm, 0x2000, SH2I_MOVBS_DS},
	{IFMT_nm, 0x2001, SH2I_MOVWS_DS},
	{IFMT_nm, 0x2002, SH2I_MOVLS_DS},
	{IFMT_nm, 0x6000, SH2I_MOVBL_DS},
	{IFMT_nm, 0x6001, SH2I_MOVWL_DS},
	{IFMT_nm, 0x6002, SH2I_MOVLL_DS},
	{IFMT_nm, 0x2004, SH2I_MOVBM_DS},
	{IFMT_nm, 0x2005, SH2I_MOVWM_DS},
	{IFMT_nm, 0x2006, SH2I_MOVLM_DS},
	{IFMT_nm, 0x6004, SH2I_MOVBP_DS},
	{IFMT_nm, 0x6005, SH2I_MOVWP_DS},
	{IFMT_nm, 0x6006, SH2I_MOVLP_DS},
	{IFMT_nm, 0x0004, SH2I_MOVBS0_DS},
	{IFMT_nm, 0x0005, SH2I_MOVWS0_DS},
	{IFMT_nm, 0x0006, SH2I_MOVLS0_DS},
	{IFMT_nm, 0x000C, SH2I_MOVBL0_DS},
	{IFMT_nm, 0x000D, SH2I_MOVWL0_DS},
	{IFMT_nm, 0x000E, SH2I_MOVLL0_DS},
	{IFMT_ni, 0xE000, SH2I_MOVI_DS},
	{IFMT_nd8, 0x9000, SH2I_MOVWI_DS},
	{IFMT_nd8, 0xD000, SH2I_MOVLI_DS},
	{IFMT_d, 0xC400, SH2I_MOVBLG_DS},
	{IFMT_d, 0xC500, SH2I_MOVWLG_DS},
	{IFMT_d, 0xC600, SH2I_MOVLLG_DS},
	{IFMT_d, 0xC000, SH2I_MOVBSG_DS},
	{IFMT_d, 0xC100, SH2I_MOVWSG_DS},
	{IFMT_d, 0xC200, SH2I_MOVLSG_DS},
	{IFMT_nd4, 0x8000, SH2I_MOVBS4_DS},
	{IFMT_nd4, 0x8100, SH2I_MOVWS4_DS},
	{IFMT_nmd, 0x1000, SH2I_MOVLS4_DS},
	{IFMT_md, 0x8400, SH2I_MOVBL4_DS},
	{IFMT_md, 0x8500, SH2I_MOVWL4_DS},
	{IFMT_nmd, 0x5000, SH2I_MOVLL4_DS},
	{IFMT_d, 0xC700, SH2I_MOVA_DS},
	{IFMT_n, 0x0029, SH2I_MOVT_DS},
	{IFMT_nm, 0x0007, SH2I_MULL_DS},
	{IFMT_nm, 0x200F, SH2I_MULS_DS},
	{IFMT_nm, 0x200E, SH2I_MULU_DS},
	{IFMT_nm, 0x600B, SH2I_NEG_DS},
	{IFMT_nm, 0x600A, SH2I_NEGC_DS},
	{IFMT_0, 0x0009, SH2I_NOP_DS},
	{IFMT_nm, 0x6007, SH2I_NOT_DS},
	{IFMT_nm, 0x200B, SH2I_OR_DS},
	{IFMT_i, 0xCB00, SH2I_ORI_DS},
	{IFMT_i, 0xCF00, SH2I_ORM_DS},
	{IFMT_n, 0x4024, SH2I_ROTCL_DS},
	{IFMT_n, 0x4025, SH2I_ROTCR_DS},
	{IFMT_n, 0x4004, SH2I_ROTL_DS},
	{IFMT_n, 0x4005, SH2I_ROTR_DS},
	{IFMT_0, 0x0018, SH2I_SETT_DS},
	{IFMT_n, 0x4020, SH2I_SHAL_DS},
	{IFMT_n, 0x4021, SH2I_SHAR_DS},
	{IFMT_n, 0x4000, SH2I_SHLL_DS},
	{IFMT_n, 0x4008, SH2I_SHLL2_DS},
	{IFMT_n, 0x4018, SH2I_SHLL8_DS},
	{IFMT_n, 0x4028, SH2I_SHLL16_DS},
	{IFMT_n, 0x4001, SH2I_SHLR_DS},
	{IFMT_n, 0x4009, SH2I_SHLR2_DS},
	{IFMT_n, 0x4019, SH2I_SHLR8_DS},
	{IFMT_n, 0x4029, SH2I_SHLR16_DS},
	{IFMT_0, 0x001B, SH2I_SLEEP_DS},
	{IFMT_n, 0x0002, SH2I_STCSR_DS},
	{IFMT_n, 0x0012, SH2I_STCGBR_DS},
	{IFMT_n, 0x0022, SH2I_STCVBR_DS},
	{IFMT_n, 0x4003, SH2I_STCMSR_DS},
	{IFMT_n, 0x4013, SH2I_STCMGBR_DS},
	{IFMT_n, 0x4023, SH2I_STCMVBR_DS},
	{IFMT_n, 0x000A, SH2I_STSMACH_DS},
	{IFMT_n, 0x001A, SH2I_STSMACL_DS},
	{IFMT_n, 0x002A, SH2I_STSPR_DS},
	{IFMT_n, 0x4002, SH2I_STSMMACH_DS},
	{IFMT_n, 0x4012, SH2I_STSMMACL_DS},
	{IFMT_n, 0x4022, SH2I_STSMPR_DS},
	{IFMT_nm, 0x3008, SH2I_SUB_DS},
	{IFMT_nm, 0x300A, SH2I_SUBC_DS},
	{IFMT_nm, 0x300B, SH2I_SUBV_DS},
	{IFMT_nm, 0x6008, SH2I_SWAPB_DS},
	{IFMT_nm, 0x6009, SH2I_SWAPW_DS},
	{IFMT_n, 0x401B, SH2I_TAS_DS},
	{IFMT_nm, 0x2008, SH2I_TST_DS},
	{IFMT_i, 0xC800, SH2I_TSTI_DS},
	{IFMT_i, 0xCC00, SH2I_TSTM_DS},
	{IFMT_nm, 0x200A, SH2I_XOR_DS},
	{IFMT_i, 0xCA00, SH2I_XORI_DS},
	{IFMT_i, 0xCE00, SH2I_XORM_DS},
	{IFMT_nm, 0x200D, SH2I_XTRCT_DS},
	{0, 0x0000, NULL},
};


/* Default READ/WRITE callback */
/*******************************/


uint8_t FASTCALL Def_READB(uint32_t adr)
{
	LOG_MSG(sh2, LOG_MSG_LEVEL_DEBUG1,
		"SH2 read byte at %.8X\n", adr);
	return 0;
}

uint16_t FASTCALL Def_READW(uint32_t adr)
{
	LOG_MSG(sh2, LOG_MSG_LEVEL_DEBUG1,
		"SH2 read word at %.8X\n", adr);
	return 0;
}

uint32_t FASTCALL Def_READL(uint32_t adr)
{
	LOG_MSG(sh2, LOG_MSG_LEVEL_DEBUG1,
		"SH2 read long at %.8X\n", adr);
	return 0;
}

void FASTCALL Def_WRITEB(uint32_t adr, uint8_t data)
{
	LOG_MSG(sh2, LOG_MSG_LEVEL_DEBUG1,
		"SH2 write byte %.2X at %.8X\n", data, adr);
}

void FASTCALL Def_WRITEW (uint32_t adr, uint16_t data)
{
	LOG_MSG(sh2, LOG_MSG_LEVEL_DEBUG1,
		"SH2 write word %.4X at %.8X\n", data, adr);
}

void FASTCALL Def_WRITEL (uint32_t adr, uint32_t data)
{
	LOG_MSG(sh2, LOG_MSG_LEVEL_DEBUG1,
		"SH2 write long %.8X at %.8X\n", data, adr);
}



/* SH2 Initialisation C functions */
/**********************************/


// IMPORTANT : *Fetch have to be DWORD aligned !!!!

void SH2_Add_Fetch(SH2_CONTEXT *SH2, uint32_t low_adr, uint32_t high_adr, uint16_t *Fetch)
{
	uint32_t i;
	
	for (i = 0; i < 0x100; i++)
	{
		if (SH2->Fetch_Region[i].Fetch_Reg == NULL)
		{
			SH2->Fetch_Region[i].Low_Adr = low_adr;
			SH2->Fetch_Region[i].High_Adr = high_adr;
			SH2->Fetch_Region[i].Fetch_Reg = &Fetch[0 - (low_adr >> 1)];
			break;
		}
	}
}


// IMPORTANT : *Fetch have to be DWORD aligned !!!!

void SH2_Set_Fetch_Reg(SH2_CONTEXT *SH2, uint32_t reg, uint32_t low_adr,
		       uint32_t high_adr, uint16_t *Fetch)
{
	reg &= 0xFF;
	
	SH2->Fetch_Region[reg].Low_Adr = low_adr;
	SH2->Fetch_Region[reg].High_Adr = high_adr;
	SH2->Fetch_Region[reg].Fetch_Reg = &Fetch[0 - (low_adr >> 1)];
}


void SH2_Add_ReadB(SH2_CONTEXT *SH2, uint32_t low_adr, uint32_t high_adr, SH2_RB *Func)
{
	uint32_t i;
	
	for (i = (low_adr & 0xFF); i <= (high_adr & 0xFF); i++)
		SH2->Read_Byte[i] = Func;
}


void SH2_Add_ReadW(SH2_CONTEXT *SH2, uint32_t low_adr, uint32_t high_adr, SH2_RW *Func)
{
	uint32_t i;
	
	for (i = (low_adr & 0xFF); i <= (high_adr & 0xFF); i++)
		SH2->Read_Word[i] = Func;
}


void SH2_Add_ReadL(SH2_CONTEXT *SH2, uint32_t low_adr, uint32_t high_adr, SH2_RL *Func)
{
	uint32_t i;
	
	for (i = (low_adr & 0xFF); i <= (high_adr & 0xFF); i++)
		SH2->Read_Long[i] = Func;
}


void SH2_Add_WriteB(SH2_CONTEXT *SH2, uint32_t low_adr, uint32_t high_adr, SH2_WB *Func)
{
	uint32_t i;
	
	for (i = (low_adr & 0xFF); i <= (high_adr & 0xFF); i++)
		SH2->Write_Byte[i] = Func;
}


void SH2_Add_WriteW(SH2_CONTEXT *SH2, uint32_t low_adr, uint32_t high_adr, SH2_WW *Func)
{
	uint32_t i;
	
	for (i = (low_adr & 0xFF); i <= (high_adr & 0xFF); i++)
		SH2->Write_Word[i] = Func;
}


void SH2_Add_WriteL(SH2_CONTEXT *SH2, uint32_t low_adr, uint32_t high_adr, SH2_WL *Func)
{
	uint32_t i;
	
	for (i = (low_adr & 0xFF); i <= (high_adr & 0xFF); i++)
		SH2->Write_Long[i] = Func;
}


void SH2_Map_Cache_Trough(SH2_CONTEXT *SH2)
{
	uint32_t i;
	
	for (i = 0; i < 0x10; i++)
	{
		SH2->Read_Byte[i + 0x20] = SH2->Read_Byte[i];
		SH2->Read_Word[i + 0x20] = SH2->Read_Word[i];
		SH2->Read_Long[i + 0x20] = SH2->Read_Long[i];
		SH2->Write_Byte[i + 0x20] = SH2->Write_Byte[i];
		SH2->Write_Word[i + 0x20] = SH2->Write_Word[i];
		SH2->Write_Long[i + 0x20] = SH2->Write_Long[i];
	}
}


void SH2_Init(SH2_CONTEXT *SH2, uint32_t slave)
{
	static uint32_t SH2_Initialised = 0;
	int32_t i, j, m, q, s, t, il;
	void *OP_Table_Temp[0x10000];
	
	if (!SH2_Initialised)
	{
		LOG_MSG(sh2, LOG_MSG_LEVEL_DEBUG1,
			"Starting to log");
		
		// Unpacking the 'normal' opcode jump table
		
		for (i = 0; i < 0x10000; i++)
			OP_Table_Temp[i] = SH2I_ILLEGAL;
		
		i = -1;
		
		while (InitOp[++i].Func != NULL)
		{
			switch (InitOp[i].IFMT)
			{
				case IFMT_0:
					OP_Table_Temp[InitOp[i].Mask] = InitOp[i].Func;
					break;
				
				case IFMT_n:
				case IFMT_m:
					for (j = 0; j < 0x10; j++)
					{
						OP_Table_Temp[InitOp[i].Mask | (j << 8)] = InitOp[i].Func;
					}
					break;
				
				case IFMT_nm:
					for (j = 0; j < 0x100; j++)
					{
						OP_Table_Temp[InitOp[i].Mask | (j << 4)] = InitOp[i].Func;
					}
					break;
				
				case IFMT_md:
				case IFMT_nd4:
				case IFMT_d:
				case IFMT_i:
					for (j = 0; j < 0x100; j++)
					{
						OP_Table_Temp[InitOp[i].Mask | j] = InitOp[i].Func;
					}
					break;
				
				case IFMT_nmd:
				case IFMT_d12:
				case IFMT_nd8:
				case IFMT_ni:
					for (j = 0; j < 0x1000; j++)
					{
						OP_Table_Temp[InitOp[i].Mask | j] = InitOp[i].Func;
					}
				break;
			}
		}
		
		// Big Endian Opcode, we need to "byte-swap" the opcode table pointer
		
		for (i = 0; i < 0x10000; i++)
		{
			// TODO: Replace this with a byteswap macro.
			j = (i >> 8) & 0xFF;
			j |= (i & 0xFF) << 8;
		
			OP_Table[j] = OP_Table_Temp[i];
		}
		
		// Now we unpack the 'Delay Slot' opcode jump table
		
		for (i = 0; i < 0x10000; i++)
			OP_Table_Temp[i] = SH2I_ILLEGAL_DS;
		
		i = -1;
		
		while (InitOpDS[++i].Func != NULL)
		{
			switch (InitOpDS[i].IFMT)
			{
				case IFMT_0:
					OP_Table_Temp[InitOpDS[i].Mask] = InitOpDS[i].Func;
					break;
				
				case IFMT_n:
				case IFMT_m:
					for (j = 0; j < 0x10; j++)
					{
						OP_Table_Temp[InitOpDS[i].Mask | (j << 8)] = InitOpDS[i].Func;
					}
					break;
				
				case IFMT_nm:
					for (j = 0; j < 0x100; j++)
					{
						OP_Table_Temp[InitOpDS[i].Mask | (j << 4)] = InitOpDS[i].Func;
					}
					break;
				
				case IFMT_md:
				case IFMT_nd4:
				case IFMT_d:
				case IFMT_i:
					for (j = 0; j < 0x100; j++)
					{
						OP_Table_Temp[InitOpDS[i].Mask | j] = InitOpDS[i].Func;
					}
					break;
				
				case IFMT_nmd:
				case IFMT_d12:
				case IFMT_nd8:
				case IFMT_ni:
					for (j = 0; j < 0x1000; j++)
					{
						OP_Table_Temp[InitOpDS[i].Mask | j] = InitOpDS[i].Func;
					}
					break;
			}
		}
		
		// Big Indian Opcode, we need to "byte-swap" the opcode table pointer
		
		for (i = 0; i < 0x10000; i++)
		{
			// TODO: Replace this with a byteswap macro.
			j = (i >> 8) & 0xFF;
			j |= (i & 0xFF) << 8;
			
			OPDS_Table[j] = OP_Table_Temp[i];
		}
		
		// Fast SR Set table initialisation
		
		for (i = 0; i < 0x400; i++)
		{
			t = (i & 0x001) >> 0;
			s = (i & 0x002) >> 1;
			q = (i & 0x100) >> 8;
			m = (i & 0x200) >> 9;
			il = (i & 0x0F0) >> 4;
			
			Set_SR_Table[i] = (t << 0) | (s << 8) | (il << 16) | (m << 25) | (q << 24);
			
			LOG_MSG(sh2, LOG_MSG_LEVEL_DEBUG2,
				"SR Table %.3X = %.8X\n", i, Set_SR_Table[i]);
		}
		
		SH2_Initialised = 1;
	}
	
	memset(SH2, 0, sizeof(SH2_CONTEXT));
	
	// Default initialisation memory...
	
	SH2_Add_ReadB (SH2, 0x00, 0xFF, Def_READB);
	SH2_Add_ReadW (SH2, 0x00, 0xFF, Def_READW);
	SH2_Add_ReadL (SH2, 0x00, 0xFF, Def_READL);
	SH2_Add_WriteB (SH2, 0x00, 0xFF, Def_WRITEB);
	SH2_Add_WriteW (SH2, 0x00, 0xFF, Def_WRITEW);
	SH2_Add_WriteL (SH2, 0x00, 0xFF, Def_WRITEL);
	
	SH2_Add_ReadB (SH2, 0xC0, 0xC0, SH2_Read_Byte_C0);
	SH2_Add_ReadW (SH2, 0xC0, 0xC0, SH2_Read_Word_C0);
	SH2_Add_ReadL (SH2, 0xC0, 0xC0, SH2_Read_Long_C0);
	SH2_Add_WriteB (SH2, 0xC0, 0xC0, SH2_Write_Byte_C0);
	SH2_Add_WriteW (SH2, 0xC0, 0xC0, SH2_Write_Word_C0);
	SH2_Add_WriteL (SH2, 0xC0, 0xC0, SH2_Write_Long_C0);
	
	SH2_Add_ReadB (SH2, 0xFF, 0xFF, SH2_Read_Byte_FF);
	SH2_Add_ReadW (SH2, 0xFF, 0xFF, SH2_Read_Word_FF);
	SH2_Add_ReadL (SH2, 0xFF, 0xFF, SH2_Read_Long_FF);
	SH2_Add_WriteB (SH2, 0xFF, 0xFF, SH2_Write_Byte_FF);
	SH2_Add_WriteW (SH2, 0xFF, 0xFF, SH2_Write_Word_FF);
	SH2_Add_WriteL (SH2, 0xFF, 0xFF, SH2_Write_Long_FF);
	
	SH2->WDT_Tab[0] = 16 - 1;
	SH2->WDT_Tab[1] = 16 - 6;
	SH2->WDT_Tab[2] = 16 - 7;
	SH2->WDT_Tab[3] = 16 - 8;
	SH2->WDT_Tab[4] = 16 - 9;
	SH2->WDT_Tab[5] = 16 - 10;
	SH2->WDT_Tab[6] = 16 - 12;
	SH2->WDT_Tab[7] = 16 - 13;
	
	SH2->FRT_Tab[0] = 8 - 3;
	SH2->FRT_Tab[1] = 8 - 5;
	SH2->FRT_Tab[2] = 8 - 7;
	SH2->FRT_Tab[3] = 0;		// not supported !
	
	SH2->BCR1 = 0x03F0;
	if (slave)
		SH2->BCR1 |= 0x8000;
}
