// license:BSD-3-Clause
// copyright-holders:David Haywood
#ifndef MAME_CPU_SH_SH_H
#define MAME_CPU_SH_SH_H
#pragma once
#include "cpu/drcfe.h"
#include "cpu/drcuml.h"
#include "cpu/drcumlsh.h"
/***************************************************************************
DEBUGGING
**************************************************************************/
#define DISABLE_FAST_REGISTERS (0) // set to 1 to turn off usage of register caching
#define SINGLE_INSTRUCTION_MODE (0)
#define SET_EA (0) // makes slower but "shows work" in the EA fake register like the interpreter
#if SET_EA
#define SETEA(x) UML_MOV(block, mem(&m_sh2_state->ea), ireg(x))
#else
#define SETEA(x)
#endif
/***************************************************************************
CONSTANTS
***************************************************************************/
/* speed up delay loops, bail out of tight loops (can cause timer issues) */
#define BUSY_LOOP_HACKS 0
/* compilation boundaries -- how far back/forward does the analysis extend? */
#define COMPILE_BACKWARDS_BYTES 64
#define COMPILE_FORWARDS_BYTES 256
#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/2) + (COMPILE_FORWARDS_BYTES/2))
#define COMPILE_MAX_SEQUENCE 64
#define SH2DRC_STRICT_VERIFY 0x0001 /* verify all instructions */
#define SH2DRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */
#define SH2DRC_STRICT_PCREL 0x0004 /* do actual loads on MOVLI/MOVWI instead of collapsing to immediates */
#define SH2DRC_COMPATIBLE_OPTIONS (SH2DRC_STRICT_VERIFY | SH2DRC_FLUSH_PC | SH2DRC_STRICT_PCREL)
#define SH2DRC_FASTEST_OPTIONS (0)
/* size of the execution code cache */
#define CACHE_SIZE (32 * 1024 * 1024)
#define SH2_MAX_FASTRAM 4
/* map variables */
#define MAPVAR_PC M0
#define MAPVAR_CYCLES M1
/* exit codes */
#define EXECUTE_OUT_OF_CYCLES 0
#define EXECUTE_MISSING_CODE 1
#define EXECUTE_UNMAPPED_CODE 2
#define EXECUTE_RESET_CACHE 3
#define PROBE_ADDRESS ~0
#define CPU_TYPE_SH1 (0)
#define CPU_TYPE_SH2 (1)
#define CPU_TYPE_SH3 (2)
#define CPU_TYPE_SH4 (3)
#define Rn ((opcode>>8)&15)
#define Rm ((opcode>>4)&15)
/* Bits in SR */
#define SH_T 0x00000001
#define SH_S 0x00000002
#define SH_I 0x000000f0
#define SH_Q 0x00000100
#define SH_M 0x00000200
#define SH_FLAGS (SH_M|SH_Q|SH_I|SH_S|SH_T)
#define REGFLAG_R(n) (1 << (n))
/* register flags 1 */
#define REGFLAG_PR (1 << 0)
#define REGFLAG_MACL (1 << 1)
#define REGFLAG_MACH (1 << 2)
#define REGFLAG_GBR (1 << 3)
#define REGFLAG_VBR (1 << 4)
#define REGFLAG_SR (1 << 5)
/***************************************************************************
MACROS
***************************************************************************/
#define SH2_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0)) // sh2
#define SH34LE_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(0,6)) // naomi
#define SH34BE_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(6,0)) // cave
#define R32(reg) m_regmap[reg]
extern unsigned DasmSH2(std::ostream &stream, unsigned pc, uint16_t opcode);
enum
{
SH4_PC = 1, SH_SR, SH4_PR, SH4_GBR, SH4_VBR, SH4_DBR, SH4_MACH, SH4_MACL,
SH4_R0, SH4_R1, SH4_R2, SH4_R3, SH4_R4, SH4_R5, SH4_R6, SH4_R7,
SH4_R8, SH4_R9, SH4_R10, SH4_R11, SH4_R12, SH4_R13, SH4_R14, SH4_R15, SH4_EA
};
class sh_common_execution : public cpu_device
{
public:
sh_common_execution(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness, address_map_constructor internal)
: cpu_device(mconfig, type, tag, owner, clock)
, m_sh2_state(nullptr)
, m_cache(CACHE_SIZE + sizeof(internal_sh2_state))
, m_drcuml(nullptr)
, m_drcoptions(0)
, m_entry(nullptr)
, m_read8(nullptr)
, m_write8(nullptr)
, m_read16(nullptr)
, m_write16(nullptr)
, m_read32(nullptr)
, m_write32(nullptr)
, m_interrupt(nullptr)
, m_nocode(nullptr)
, m_out_of_cycles(nullptr)
, m_xor(0)
{ }
// Data that needs to be stored close to the generated DRC code
struct internal_sh2_state
{
uint32_t pc;
uint32_t pr;
uint32_t sr;
uint32_t mach;
uint32_t macl;
uint32_t r[16];
uint32_t ea;
uint32_t pending_irq;
uint32_t pending_nmi;
int32_t irqline;
uint32_t evec; // exception vector for DRC
uint32_t irqsr; // IRQ-time old SR for DRC
uint32_t target; // target for jmp/jsr/etc so the delay slot can't kill it
int internal_irq_level;
int icount;
uint8_t sleep_mode;
uint32_t arg0; /* print_debug argument 1 */
uint32_t arg1;
uint32_t gbr;
uint32_t vbr;
uint32_t m_delay;
};
internal_sh2_state *m_sh2_state;
virtual uint8_t RB(offs_t A) = 0;
virtual uint16_t RW(offs_t A) = 0;
virtual uint32_t RL(offs_t A) = 0;
virtual void WB(offs_t A, uint8_t V) = 0;
virtual void WW(offs_t A, uint16_t V) = 0;
virtual void WL(offs_t A, uint32_t V) = 0;
protected:
void ADD(uint32_t m, uint32_t n);
void ADDI(uint32_t i, uint32_t n);
void ADDC(uint32_t m, uint32_t n);
void ADDV(uint32_t m, uint32_t n);
void AND(uint32_t m, uint32_t n);
void ANDI(uint32_t i);
void ANDM(uint32_t i);
void BF(uint32_t d);
void BFS(uint32_t d);
void BRA(uint32_t d);
void BRAF(uint32_t m);
void BSR(uint32_t d);
void BSRF(uint32_t m);
void BT(uint32_t d);
void BTS(uint32_t d);
void CLRMAC();
void CLRT();
void CMPEQ(uint32_t m, uint32_t n);
void CMPGE(uint32_t m, uint32_t n);
void CMPGT(uint32_t m, uint32_t n);
void CMPHI(uint32_t m, uint32_t n);
void CMPHS(uint32_t m, uint32_t n);
void CMPPL(uint32_t n);
void CMPPZ(uint32_t n);
void CMPSTR(uint32_t m, uint32_t n);
void CMPIM(uint32_t i);
void DIV0S(uint32_t m, uint32_t n);
void DIV0U();
void DIV1(uint32_t m, uint32_t n);
void DMULS(uint32_t m, uint32_t n);
void DMULU(uint32_t m, uint32_t n);
void DT(uint32_t n);
void EXTSB(uint32_t m, uint32_t n);
void EXTSW(uint32_t m, uint32_t n);
void EXTUB(uint32_t m, uint32_t n);
void EXTUW(uint32_t m, uint32_t n);
void JMP(uint32_t m);
void JSR(uint32_t m);
void LDCGBR(uint32_t m);
void LDCVBR(uint32_t m);
void LDCMGBR(uint32_t m);
void LDCMVBR(uint32_t m);
void LDSMACH(uint32_t m);
void LDSMACL(uint32_t m);
void LDSPR(uint32_t m);
void LDSMMACH(uint32_t m);
void LDSMMACL(uint32_t m);
void LDSMPR(uint32_t m);
void MAC_L(uint32_t m, uint32_t n);
void MAC_W(uint32_t m, uint32_t n);
void MOV(uint32_t m, uint32_t n);
void MOVBS(uint32_t m, uint32_t n);
void MOVWS(uint32_t m, uint32_t n);
void MOVLS(uint32_t m, uint32_t n);
void MOVBL(uint32_t m, uint32_t n);
void MOVWL(uint32_t m, uint32_t n);
void MOVLL(uint32_t m, uint32_t n);
void MOVBM(uint32_t m, uint32_t n);
void MOVWM(uint32_t m, uint32_t n);
void MOVLM(uint32_t m, uint32_t n);
void MOVBP(uint32_t m, uint32_t n);
void MOVWP(uint32_t m, uint32_t n);
void MOVLP(uint32_t m, uint32_t n);
void MOVBS0(uint32_t m, uint32_t n);
void MOVWS0(uint32_t m, uint32_t n);
void MOVLS0(uint32_t m, uint32_t n);
void MOVBL0(uint32_t m, uint32_t n);
void MOVWL0(uint32_t m, uint32_t n);
void MOVLL0(uint32_t m, uint32_t n);
void MOVI(uint32_t i, uint32_t n);
void MOVWI(uint32_t d, uint32_t n);
void MOVLI(uint32_t d, uint32_t n);
void MOVBLG(uint32_t d);
void MOVWLG(uint32_t d);
void MOVLLG(uint32_t d);
void MOVBSG(uint32_t d);
void MOVWSG(uint32_t d);
void MOVLSG(uint32_t d);
void MOVBS4(uint32_t d, uint32_t n);
void MOVWS4(uint32_t d, uint32_t n);
void MOVLS4(uint32_t m, uint32_t d, uint32_t n);
void MOVBL4(uint32_t m, uint32_t d);
void MOVWL4(uint32_t m, uint32_t d);
void MOVLL4(uint32_t m, uint32_t d, uint32_t n);
void MOVA(uint32_t d);
void MOVT(uint32_t n);
void MULL(uint32_t m, uint32_t n);
void MULS(uint32_t m, uint32_t n);
void MULU(uint32_t m, uint32_t n);
void NEG(uint32_t m, uint32_t n);
void NEGC(uint32_t m, uint32_t n);
void NOP(void);
void NOT(uint32_t m, uint32_t n);
void OR(uint32_t m, uint32_t n);
void ORI(uint32_t i);
void ORM(uint32_t i);
void ROTCL(uint32_t n);
void ROTCR(uint32_t n);
void ROTL(uint32_t n);
void ROTR(uint32_t n);
void RTS();
void SETT();
void SHAL(uint32_t n);
void SHAR(uint32_t n);
void SHLL(uint32_t n);
void SHLL2(uint32_t n);
void SHLL8(uint32_t n);
void SHLL16(uint32_t n);
void SHLR(uint32_t n);
void SHLR2(uint32_t n);
void SHLR8(uint32_t n);
void SHLR16(uint32_t n);
void SLEEP();
void STCSR(uint32_t n);
void STCGBR(uint32_t n);
void STCVBR(uint32_t n);
void STCMSR(uint32_t n);
void STCMGBR(uint32_t n);
void STCMVBR(uint32_t n);
void STSMACH(uint32_t n);
void STSMACL(uint32_t n);
void STSPR(uint32_t n);
void STSMMACH(uint32_t n);
void STSMMACL(uint32_t n);
void STSMPR(uint32_t n);
void SUB(uint32_t m, uint32_t n);
void SUBC(uint32_t m, uint32_t n);
void SUBV(uint32_t m, uint32_t n);
void SWAPB(uint32_t m, uint32_t n);
void SWAPW(uint32_t m, uint32_t n);
void TAS(uint32_t n);
void TST(uint32_t m, uint32_t n);
void TSTI(uint32_t i);
void TSTM(uint32_t i);
void XOR(uint32_t m, uint32_t n);
void XORI(uint32_t i);
void XORM(uint32_t i);
void XTRCT(uint32_t m, uint32_t n);
void op0010(uint16_t opcode);
void op0011(uint16_t opcode);
void op0110(uint16_t opcode);
void op1000(uint16_t opcode);
void op1100(uint16_t opcode);
void execute_one(const uint16_t opcode);
virtual void execute_one_0000(uint16_t opcode);
virtual void execute_one_4000(uint16_t opcode);
virtual void execute_one_f000(uint16_t opcode) = 0;
virtual void RTE() = 0;
virtual void LDCSR(const uint16_t opcode) = 0;
virtual void LDCMSR(const uint16_t opcode) = 0;
virtual void TRAPA(uint32_t i) = 0;
virtual void ILLEGAL() = 0;
drc_cache m_cache; /* pointer to the DRC code cache */
public:
/* fast RAM */
uint32_t m_fastram_select;
struct
{
offs_t start; /* start of the RAM block */
offs_t end; /* end of the RAM block */
bool readonly; /* true if read-only */
void * base; /* base in memory where the RAM lives */
} m_fastram[SH2_MAX_FASTRAM];
int m_pcfsel; // last pcflush entry set
uint32_t m_pcflushes[16]; // pcflush entries
virtual void init_drc_frontend() = 0;
void drc_start();
void sh2drc_add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base);
direct_read_data *m_direct;
address_space *m_program;
std::unique_ptr<drcuml_state> m_drcuml; /* DRC UML generator state */
uint32_t m_drcoptions; /* configurable DRC options */
/* internal stuff */
uint8_t m_cache_dirty; /* true if we need to flush the cache */
/* register mappings */
uml::parameter m_regmap[16]; /* parameter to register mappings for all 16 integer registers */
uml::code_handle * m_entry; /* entry point */
uml::code_handle * m_read8; /* read byte */
uml::code_handle * m_write8; /* write byte */
uml::code_handle * m_read16; /* read half */
uml::code_handle * m_write16; /* write half */
uml::code_handle * m_read32; /* read word */
uml::code_handle * m_write32; /* write word */
uml::code_handle * m_interrupt; /* interrupt */
uml::code_handle * m_nocode; /* nocode */
uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */
/* internal compiler state */
struct compiler_state
{
uint32_t cycles; /* accumulated cycles */
uint8_t checkints; /* need to check interrupts before next instruction */
uml::code_label labelnum; /* index for local labels */
};
virtual void sh2_exception(const char *message, int irqline) { fatalerror("sh2_exception in base classs\n"); };
virtual void generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, bool allow_exception) = 0;
virtual bool generate_group_0_RTE(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
virtual bool generate_group_4_LDCSR(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
virtual bool generate_group_4_LDCMSR(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
virtual bool generate_group_12_TRAPA(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
bool generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc);
virtual bool generate_group_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
bool generate_group_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
bool generate_group_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, uint32_t ovrpc);
virtual bool generate_group_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
bool generate_group_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
bool generate_group_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
bool generate_group_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
virtual bool generate_group_15(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint16_t opcode, int in_delay_slot, uint32_t ovrpc);
void func_printf_probe();
void func_unimplemented();
void func_MAC_W();
void func_MAC_L();
void func_DIV1();
void func_ADDV();
void func_SUBV();
int m_cpu_type;
uint32_t m_am;
bool m_isdrc;
int m_xor;
void sh2drc_set_options(uint32_t options);
void sh2drc_add_pcflush(offs_t address);
virtual void static_generate_entry_point() = 0;
virtual void static_generate_memory_accessor(int size, int iswrite, const char *name, uml::code_handle **handleptr) = 0;
virtual const opcode_desc* get_desclist(offs_t pc) = 0;
uint32_t epc(const opcode_desc *desc);
void alloc_handle(drcuml_state *drcuml, uml::code_handle **handleptr, const char *name);
void load_fast_iregs(drcuml_block *block);
void save_fast_iregs(drcuml_block *block);
const char *log_desc_flags_to_string(uint32_t flags);
void log_register_list(drcuml_state *drcuml, const char *string, const uint32_t *reglist, const uint32_t *regnostarlist);
void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent);
void log_add_disasm_comment(drcuml_block *block, uint32_t pc, uint32_t op);
void generate_delay_slot(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc);
void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast);
void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, uint32_t ovrpc);
void static_generate_nocode_handler();
void static_generate_out_of_cycles();
void code_flush_cache();
void execute_run_drc();
void code_compile_block(uint8_t mode, offs_t pc);
protected:
// device-level overrides
virtual void device_start() override;
};
class sh_frontend : public drc_frontend
{
public:
sh_frontend(sh_common_execution *device, uint32_t window_start, uint32_t window_end, uint32_t max_sequence);
protected:
virtual uint16_t read_word(opcode_desc &desc);
virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override;
private:
bool describe_group_2(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
bool describe_group_3(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
bool describe_group_6(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
bool describe_group_8(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
bool describe_group_12(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
protected:
virtual bool describe_group_0(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
virtual bool describe_group_4(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode);
virtual bool describe_group_15(opcode_desc &desc, const opcode_desc *prev, uint16_t opcode) = 0;
sh_common_execution *m_sh;
};
#endif // MAME_CPU_SH2_SH2_H