#pragma once #include "types.h" #include "stdclass.h" enum Sh4RegType { //GPRs reg_r0, reg_r1, reg_r2, reg_r3, reg_r4, reg_r5, reg_r6, reg_r7, reg_r8, reg_r9, reg_r10, reg_r11, reg_r12, reg_r13, reg_r14, reg_r15, //FPU, bank 0 reg_fr_0, reg_fr_1, reg_fr_2, reg_fr_3, reg_fr_4, reg_fr_5, reg_fr_6, reg_fr_7, reg_fr_8, reg_fr_9, reg_fr_10, reg_fr_11, reg_fr_12, reg_fr_13, reg_fr_14, reg_fr_15, //FPU, bank 1 reg_xf_0, reg_xf_1, reg_xf_2, reg_xf_3, reg_xf_4, reg_xf_5, reg_xf_6, reg_xf_7, reg_xf_8, reg_xf_9, reg_xf_10, reg_xf_11, reg_xf_12, reg_xf_13, reg_xf_14, reg_xf_15, //GPR Interrupt bank reg_r0_Bank, reg_r1_Bank, reg_r2_Bank, reg_r3_Bank, reg_r4_Bank, reg_r5_Bank, reg_r6_Bank, reg_r7_Bank, //Misc regs reg_gbr, reg_ssr, reg_spc, reg_sgr, reg_dbr, reg_vbr, reg_mach, reg_macl, reg_pr, reg_fpul, reg_nextpc, reg_sr_status, //Only the status bits reg_sr_T, //Only T reg_old_fpscr, reg_fpscr, reg_pc_dyn, //Write only, for dynarec only (dynamic block exit address) reg_temp, sh4_reg_count, /* These are virtual registers, used by the dynarec decoder */ regv_dr_0, regv_dr_2, regv_dr_4, regv_dr_6, regv_dr_8, regv_dr_10, regv_dr_12, regv_dr_14, regv_xd_0, regv_xd_2, regv_xd_4, regv_xd_6, regv_xd_8, regv_xd_10, regv_xd_12, regv_xd_14, regv_fv_0, regv_fv_4, regv_fv_8, regv_fv_12, regv_xmtrx, regv_fmtrx, NoReg=-1 }; //Varius sh4 registers union sr_status_t { struct { u32 T_h : 1;//<<0 u32 S : 1;//<<1 u32 rsvd0 : 2;//<<2 u32 IMASK : 4;//<<4 u32 Q : 1;//<<8 u32 M : 1;//<<9 u32 rsvd1 : 5;//<<10 u32 FD : 1;//<<15 u32 rsvd2 : 12;//<<16 u32 BL : 1;//<<28 u32 RB : 1;//<<29 u32 MD : 1;//<<20 u32 rsvd3 : 1;//<<31 }; u32 status; }; #define STATUS_MASK 0x700083F2 //Status register bitfield struct sr_t { union { struct { u32 T_h : 1;//<<0 u32 S : 1;//<<1 u32 rsvd0 : 2;//<<2 u32 IMASK : 4;//<<4 u32 Q : 1;//<<8 u32 M : 1;//<<9 u32 rsvd1 : 5;//<<10 u32 FD : 1;//<<15 u32 rsvd2 : 12;//<<16 u32 BL : 1;//<<28 u32 RB : 1;//<<29 u32 MD : 1;//<<20 u32 rsvd3 : 1;//<<31 }; u32 status; }; u32 T; }; //FPSCR (fpu status and control register) bitfield struct fpscr_t { union { u32 full; struct { u32 RM : 2; u32 finexact : 1; u32 funderflow : 1; u32 foverflow : 1; u32 fdivbyzero : 1; u32 finvalidop : 1; u32 einexact : 1; u32 eunderflow : 1; u32 eoverflow : 1; u32 edivbyzero : 1; u32 einvalidop : 1; u32 cinexact : 1; u32 cunderflow : 1; u32 coverflow : 1; u32 cdivbyzero : 1; u32 cinvalid : 1; u32 cfpuerr : 1; u32 DN : 1; u32 PR : 1; u32 SZ : 1; u32 FR : 1; u32 pad : 10; }; struct { u32 _nil : 2+1+1+1+1+4+8+1; u32 PR_SZ : 2; u32 nilz : 11; }; }; }; //sh4 interface struct sh4_if { void (*Run)(); void (*Stop)(); void (*Step)(); void (*Reset)(bool hard); void (*Init)(); void (*Term)(); void (*ResetCache)(); bool (*IsCpuRunning)(); }; extern sh4_if sh4_cpu; struct alignas(64) Sh4Context { union { struct { f32 xffr[32]; u32 r[16]; union { u64 full; struct { u32 l; u32 h; }; } mac; u32 r_bank[8]; u32 gbr,ssr,spc,sgr,dbr,vbr; u32 pr,fpul; u32 pc; u32 jdyn; sr_t sr; fpscr_t fpscr; sr_status_t old_sr; fpscr_t old_fpscr; u32 CpuRunning; int sh4_sched_next; u32 interrupt_pend; u32 temp_reg; int cycle_counter; }; u64 raw[64-8]; }; }; struct alignas(32) SQBuffer { u8 data[32]; }; void DYNACALL do_sqw_mmu(u32 dst); void DYNACALL do_sqw_nommu_area_3(u32 dst, const SQBuffer *sqb); void DYNACALL do_sqw_nommu_area_3_nonvmem(u32 dst, const SQBuffer *sqb); void DYNACALL do_sqw_nommu_full(u32 dst, const SQBuffer *sqb); typedef void DYNACALL sqw_fp(u32 dst, const SQBuffer *sqb); #define FPCB_SIZE (RAM_SIZE_MAX/2) #define FPCB_MASK (FPCB_SIZE -1) #if HOST_CPU == CPU_ARM // The arm32 dynarec context register (r8) points past the end of the Sh4RCB struct. // To get a pointer to the fpcb table, we substract sizeof(Sh4RCB), which we // want to be an i8r4 value that can be substracted in one op (such as 0x4100000) #define FPCB_PAD 0x100000 #else #define FPCB_PAD 0x10000 #endif struct alignas(PAGE_SIZE) Sh4RCB { void* fpcb[FPCB_SIZE]; u8 _pad[FPCB_PAD - sizeof(Sh4Context) - sizeof(SQBuffer) * 2 - sizeof(void *)]; sqw_fp* do_sqw_nommu; SQBuffer sq_buffer[2]; Sh4Context cntx; }; extern Sh4RCB* p_sh4rcb; static inline u32 sh4_sr_GetFull() { return (p_sh4rcb->cntx.sr.status & STATUS_MASK) | p_sh4rcb->cntx.sr.T; } static inline void sh4_sr_SetFull(u32 value) { p_sh4rcb->cntx.sr.status=value & STATUS_MASK; p_sh4rcb->cntx.sr.T=value&1; } #define do_sqw_nommu sh4rcb.do_sqw_nommu #define sh4rcb (*p_sh4rcb) #define Sh4cntx (sh4rcb.cntx) //Get an interface to sh4 interpreter void Get_Sh4Interpreter(sh4_if* cpu); void Get_Sh4Recompiler(sh4_if* cpu); u32* GetRegPtr(u32 reg); enum Sh4ExceptionCode : u16 { Sh4Ex_PowerOnReset = 0, Sh4Ex_ManualReset = 0x20, Sh4Ex_TlbMissRead = 0x40, Sh4Ex_TlbMissWrite = 0x60, Sh4Ex_TlbInitPageWrite = 0x80, Sh4Ex_TlbProtViolRead = 0xa0, Sh4Ex_TlbProtViolWrite = 0xc0, Sh4Ex_AddressErrorRead = 0xe0, Sh4Ex_AddressErrorWrite = 0x100, Sh4Ex_FpuError = 0x120, Sh4Ex_FpuDisabled = 0x800, Sh4Ex_SlotFpuDisabled = 0x820, Sh4Ex_TlbMultiHit = 0x140, Sh4Ex_Trap = 0x160, Sh4Ex_IllegalInstr = 0x180, Sh4Ex_SlotIllegalInstr = 0x1a0, Sh4Ex_NmiInterrupt = 0x1c0, Sh4Ex_UserBreak = 0x1e0, Sh4Ex_ExtInterrupt0 = 0x200, Sh4Ex_ExtInterrupt1 = 0x220, Sh4Ex_ExtInterrupt2 = 0x240, Sh4Ex_ExtInterrupt3 = 0x260, Sh4Ex_ExtInterrupt4 = 0x280, Sh4Ex_ExtInterrupt5 = 0x2a0, Sh4Ex_ExtInterrupt6 = 0x2c0, Sh4Ex_ExtInterrupt7 = 0x2e0, Sh4Ex_ExtInterrupt8 = 0x300, Sh4Ex_ExtInterrupt9 = 0x320, Sh4Ex_ExtInterruptA = 0x340, Sh4Ex_ExtInterruptB = 0x360, Sh4Ex_ExtInterruptC = 0x380, Sh4Ex_ExtInterruptD = 0x3a0, Sh4Ex_ExtInterruptE = 0x3c0, Sh4Ex_TMU0 = 0x400, Sh4Ex_TMU1 = 0x420, Sh4Ex_TMU2 = 0x440, Sh4Ex_TMU2_TICPI2 = 0x460, Sh4Ex_RTC_ATI = 0x480, Sh4Ex_RTC_PRI = 0x4a0, Sh4Ex_RTC_CUI = 0x4c0, Sh4Ex_SCI_ERI = 0x4e0, Sh4Ex_SCI_RXI = 0x500, Sh4Ex_SCI_TXI = 0x520, Sh4Ex_SCI_TEI = 0x540, Sh4Ex_WDT = 0x560, Sh4Ex_REF_RCMI = 0x580, Sh4Ex_REF_ROVI = 0x5a0, Sh4Ex_HUDI = 0x600, Sh4Ex_GPIO = 0x620, Sh4Ex_DMAC_DTME0 = 0x640, Sh4Ex_DMAC_DTME1 = 0x680, Sh4Ex_DMAC_DTME2 = 0x680, Sh4Ex_DMAC_DTME3 = 0x6a0, Sh4Ex_DMAC_DMAE = 0x6c0, Sh4Ex_SCIF_ERI = 0x700, Sh4Ex_SCIF_RXI = 0x720, Sh4Ex_SCIF_BRI = 0x740, Sh4Ex_SCIF_TXI = 0x760, };