summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/cpu/sh/sh.h
blob: 87b6ca9d311176c398f0b89cb3cd075f3a41d745 (plain) (tree)































                                                                                                                     
                         





































































































































































































































































































                                                                                                                                                                                         
                                   





















































                                                                                                                           
 













































































                                                                                                                                                                         
 








                                                                                                        
// 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