/* DingusPPC - The Experimental PowerPC Macintosh emulator Copyright (C) 2018-21 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PPCEMU_H #define PPCEMU_H #include #include #include #include #include #include // Uncomment this to help debug the emulator further //#define EXHAUSTIVE_DEBUG 1 // Uncomment this to have a more graceful approach to illegal opcodes //#define ILLEGAL_OP_SAFE 1 // Uncomment this to use GCC built-in functions. #define USE_GCC_BUILTINS 1 // Uncomment this to use Visual Studio built-in functions. //#define USE_VS_BUILTINS 1 //#define CPU_PROFILING // enable CPU profiling enum endian_switch { big_end = 0, little_end = 1 }; typedef void (*PPCOpcode)(void); union FPR_storage { double dbl64_r; // double floating-point representation uint64_t int64_r; // double integer representation }; /** Except for the floating-point registers, all registers require 32 bits for representation. Floating-point registers need 64 bits. gpr = General Purpose Register fpr = Floating Point (FP) Register cr = Condition Register tbr = Time Base Register fpscr = FP Status and Condition Register spr = Special Register msr = Machine State Register sr = Segment Register **/ typedef struct struct_ppc_state { FPR_storage fpr[32]; uint32_t pc; // Referred as the CIA in the PPC manual uint32_t gpr[32]; uint32_t cr; uint32_t fpscr; uint32_t tbr[2]; uint32_t spr[1024]; uint32_t msr; uint32_t sr[16]; bool reserve; // reserve bit used for lwarx and stcwx } SetPRS; extern SetPRS ppc_state; /** symbolic names for frequently used SPRs */ enum SPR : int { MQ = 0, XER = 1, LR = 8, CTR = 9, DSISR = 18, DAR = 19, DEC = 22, SDR1 = 25, SRR0 = 26, SRR1 = 27, PVR = 287 }; /** symbolic names for frequently used SPRs */ enum TBR : int { TBL = 0, TBU = 1 }; /** symbolic names for common PPC processors */ enum PPC_VER : uint32_t { MPC601 = 0x00010001, MPC603 = 0x00030001, MPC604 = 0x00040001, MPC603E = 0x00060101, MPC750 = 0x00080200 }; /** typedef struct struct_ppc64_state { FPR_storage fpr [32]; uint64_t pc; //Referred as the CIA in the PPC manual uint64_t gpr [32]; uint32_t cr; uint32_t fpscr; uint32_t tbr [2]; uint64_t spr [1024]; uint32_t msr; uint32_t sr [16]; bool reserve; //reserve bit used for lwarx and stcwx } SetPRS64; extern SetPRS64 ppc_state64; **/ /** Specific SPRS to be weary of: USER MODEL SPR 1 - XER SPR 8 - Link Register / Branch b0 - Summary Overflow b1 - Overflow b2 - Carry b25-31 - Number of bytes to transfer SPR 9 - Count SUPERVISOR MODEL 19 is the Data Address Register 22 is the Decrementer 26, 27 are the Save and Restore Registers (SRR0, SRR1) 272 - 275 are the SPRGs 284 - 285 for writing to the TBR's. 528 - 535 are the Instruction BAT registers 536 - 543 are the Data BAT registers **/ extern uint32_t opcode_value; // used for interpreting opcodes extern uint64_t timebase_counter; extern uint64_t tbr_wr_timestamp; extern uint64_t tbr_wr_value; extern uint64_t tbr_freq_hz; // Additional steps to prevent overflow? extern int32_t add_result; extern int32_t simult_result; extern uint32_t uiadd_result; extern uint32_t uimult_result; extern uint32_t crf_d; extern uint32_t crf_s; extern uint32_t reg_s; extern uint32_t reg_d; extern uint32_t reg_a; extern uint32_t reg_b; extern uint32_t reg_c; extern uint32_t xercon; extern uint32_t cmp_c; extern uint32_t crm; extern uint32_t br_bo; extern uint32_t br_bi; extern uint32_t rot_sh; extern uint32_t rot_mb; extern uint32_t rot_me; extern uint32_t uimm; extern uint32_t grab_sr; extern uint32_t grab_inb; // This is for grabbing the number of immediate bytes for loading and storing extern uint32_t ppc_to; extern int32_t simm; extern int32_t adr_li; extern int32_t br_bd; // Used for GP calcs extern uint32_t ppc_result_a; extern uint32_t ppc_result_b; extern uint32_t ppc_result_c; extern uint32_t ppc_result_d; // Used for FP calcs extern uint64_t ppc_result64_a; extern uint64_t ppc_result64_b; extern uint64_t ppc_result64_c; extern uint64_t ppc_result64_d; /* The precise end of a basic block. */ enum class BB_end_kind { BB_NONE = 0, /* no basic block end is reached */ BB_BRANCH = 1, /* a branch instruction is encountered */ BB_EXCEPTION, /* an exception is occured */ BB_RFI, /* the rfi instruction is encountered */ BB_TIMER, /* timer queue changed */ }; enum CR_select : int32_t { CR0_field = (0xF << 28), CR1_field = (0xF << 24), }; enum CRx_bit : uint32_t { CR_SO = 28, CR_EQ = 29, CR_GT = 30, CR_LT = 31 }; enum CR1_bit : uint32_t { CR1_OX = 24, CR1_VX, CR1_FEX, CR1_FX, }; enum FPSCR : uint32_t { RN = 0x3, NI = 0x4, XE = 0x8, ZE = 0x10, UE = 0x20, OE = 0x40, VE = 0x80, VXCVI = 0x100, VXSQRT = 0x200, VXSOFT = 0x400, FPRF = 0x1F000, FPCC_FUNAN = 0x10000, FPCC_NEG = 0x8000, FPCC_POS = 0x4000, FPCC_ZERO = 0x2000, FPCC_FPRCD = 0x1000, FI = 0x20000, FR = 0x40000, VXVC = 0x80000, VXIMZ = 0x100000, VXZDZ = 0x200000, VXIDI = 0x400000, VXISI = 0x800000, VXSNAN = 0x1000000, XX = 0x2000000, ZX = 0x4000000, UX = 0x8000000, OX = 0x10000000, VX = 0x20000000, FEX = 0x40000000, FX = 0x80000000 }; //for inf and nan checks enum FPOP : int { DIV = 0x12, SUB = 0x14, ADD = 0x15, MUL = 0x19, FMSUB = 0x1C, FMADD = 0x1D, FNMSUB = 0x1E, FNMADD = 0x1F, }; /** PowerPC exception types. */ enum class Except_Type { EXC_SYSTEM_RESET = 1, EXC_MACHINE_CHECK, EXC_DSI, EXC_ISI, EXC_EXT_INT, EXC_ALIGNMENT, EXC_PROGRAM, EXC_NO_FPU, EXC_DECR, EXC_SYSCALL = 12, EXC_TRACE = 13 }; /** Programm Exception subclasses. */ enum Exc_Cause : uint32_t { FPU_OFF = 1 << (31 - 11), ILLEGAL_OP = 1 << (31 - 12), NOT_ALLOWED = 1 << (31 - 13), TRAP = 1 << (31 - 14), }; // extern bool bb_end; extern BB_end_kind bb_kind; extern jmp_buf exc_env; extern bool grab_return; extern bool power_on; extern bool is_601; // For PowerPC 601 Emulation extern bool is_altivec; // For Altivec Emulation extern bool is_64bit; // For PowerPC G5 Emulation extern bool rc_flag; // Record flag extern bool oe_flag; // Overflow flag // Important Addressing Integers extern uint32_t ppc_cur_instruction; extern uint32_t ppc_effective_address; extern uint32_t ppc_next_instruction_address; // Profiling Stats #ifdef CPU_PROFILING extern uint64_t num_executed_instrs; extern uint64_t num_supervisor_instrs; extern uint64_t num_int_loads; extern uint64_t num_int_stores; extern uint64_t exceptions_processed; #endif // Function prototypes extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version); extern void ppc_mmu_init(uint32_t cpu_version); void ppc_illegalop(); void ppc_fpu_off(); void ppc_ext_int(); //void ppc_opcode4(); void ppc_opcode16(); void ppc_opcode18(); void ppc_opcode19(); void ppc_opcode31(); void ppc_opcode59(); void ppc_opcode63(); void initialize_ppc_opcode_tables(); extern double fp_return_double(uint32_t reg); extern uint64_t fp_return_uint64(uint32_t reg); extern void ppc_grab_regsda(); extern void ppc_grab_regsdb(); extern void ppc_grab_regssa(); extern void ppc_grab_regssb(); extern void ppc_grab_regsdab(); extern void ppc_grab_regssab(); extern void ppc_grab_regsdasimm(); extern void ppc_grab_regsdauimm(); extern void ppc_grab_regsasimm(); extern void ppc_grab_regssauimm(); extern void ppc_store_result_regd(); extern void ppc_store_result_rega(); void ppc_changecrf0(uint32_t set_result); void ppc_fp_changecrf1(); /* Exception handlers. */ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits); [[noreturn]] void dbg_exception_handler(Except_Type exception_type, uint32_t srr1_bits); // MEMORY DECLARATIONS extern MemCtrlBase* mem_ctrl_instance; extern void add_ctx_sync_action(const std::function &); extern void do_ctx_sync(void); // The functions used by the PowerPC processor namespace dppc_interpreter { extern void ppc_bcctr(); extern void ppc_bcctrl(); extern void ppc_bclr(); extern void ppc_bclrl(); extern void ppc_crand(); extern void ppc_crandc(); extern void ppc_creqv(); extern void ppc_crnand(); extern void ppc_crnor(); extern void ppc_cror(); extern void ppc_crorc(); extern void ppc_crxor(); extern void ppc_isync(); extern void ppc_add(); extern void ppc_addc(); extern void ppc_adde(); extern void ppc_addme(); extern void ppc_addze(); extern void ppc_and(); extern void ppc_andc(); extern void ppc_cmp(); extern void ppc_cmpl(); extern void ppc_cntlzw(); extern void ppc_dcbf(); extern void ppc_dcbi(); extern void ppc_dcbst(); extern void ppc_dcbt(); extern void ppc_dcbtst(); extern void ppc_dcbz(); extern void ppc_divw(); extern void ppc_divwu(); extern void ppc_eciwx(); extern void ppc_ecowx(); extern void ppc_eieio(); extern void ppc_eqv(); extern void ppc_extsb(); extern void ppc_extsh(); extern void ppc_icbi(); extern void ppc_mftb(); extern void ppc_lhzux(); extern void ppc_lhzx(); extern void ppc_lhaux(); extern void ppc_lhax(); extern void ppc_lhbrx(); extern void ppc_lwarx(); extern void ppc_lbzux(); extern void ppc_lbzx(); extern void ppc_lwbrx(); extern void ppc_lwzux(); extern void ppc_lwzx(); extern void ppc_mcrxr(); extern void ppc_mfcr(); extern void ppc_mulhwu(); extern void ppc_mulhw(); extern void ppc_mullw(); extern void ppc_nand(); extern void ppc_neg(); extern void ppc_nor(); extern void ppc_or(); extern void ppc_orc(); extern void ppc_slw(); extern void ppc_srw(); extern void ppc_sraw(); extern void ppc_srawi(); extern void ppc_stbx(); extern void ppc_stbux(); extern void ppc_stfiwx(); extern void ppc_sthx(); extern void ppc_sthux(); extern void ppc_sthbrx(); extern void ppc_stwx(); extern void ppc_stwcx(); extern void ppc_stwux(); extern void ppc_stwbrx(); extern void ppc_subf(); extern void ppc_subfc(); extern void ppc_subfe(); extern void ppc_subfme(); extern void ppc_subfze(); extern void ppc_sync(); extern void ppc_tlbia(); extern void ppc_tlbie(); extern void ppc_tlbli(); extern void ppc_tlbld(); extern void ppc_tlbsync(); extern void ppc_tw(); extern void ppc_xor(); extern void ppc_lswi(); extern void ppc_lswx(); extern void ppc_stswi(); extern void ppc_stswx(); extern void ppc_mfsr(); extern void ppc_mfsrin(); extern void ppc_mtsr(); extern void ppc_mtsrin(); extern void ppc_mcrf(); extern void ppc_mtcrf(); extern void ppc_mfmsr(); extern void ppc_mfspr(); extern void ppc_mtmsr(); extern void ppc_mtspr(); extern void ppc_mtfsb0(); extern void ppc_mtfsb1(); extern void ppc_mcrfs(); extern void ppc_fmr(); extern void ppc_mffs(); extern void ppc_mtfsf(); extern void ppc_mtfsfi(); extern void ppc_addi(); extern void ppc_addic(); extern void ppc_addicdot(); extern void ppc_addis(); extern void ppc_andidot(); extern void ppc_andisdot(); extern void ppc_b(); extern void ppc_ba(); extern void ppc_bl(); extern void ppc_bla(); extern void ppc_bc(); extern void ppc_bca(); extern void ppc_bcl(); extern void ppc_bcla(); extern void ppc_cmpi(); extern void ppc_cmpli(); extern void ppc_lbz(); extern void ppc_lbzu(); extern void ppc_lha(); extern void ppc_lhau(); extern void ppc_lhz(); extern void ppc_lhzu(); extern void ppc_lwz(); extern void ppc_lwzu(); extern void ppc_lmw(); extern void ppc_mulli(); extern void ppc_ori(); extern void ppc_oris(); extern void ppc_rfi(); extern void ppc_rlwimi(); extern void ppc_rlwinm(); extern void ppc_rlwnm(); extern void ppc_sc(); extern void ppc_stb(); extern void ppc_stbu(); extern void ppc_sth(); extern void ppc_sthu(); extern void ppc_stw(); extern void ppc_stwu(); extern void ppc_stmw(); extern void ppc_subfic(); extern void ppc_twi(); extern void ppc_xori(); extern void ppc_xoris(); extern void ppc_lfs(); extern void ppc_lfsu(); extern void ppc_lfsx(); extern void ppc_lfsux(); extern void ppc_lfd(); extern void ppc_lfdu(); extern void ppc_lfdx(); extern void ppc_lfdux(); extern void ppc_stfs(); extern void ppc_stfsu(); extern void ppc_stfsx(); extern void ppc_stfsux(); extern void ppc_stfd(); extern void ppc_stfdu(); extern void ppc_stfdx(); extern void ppc_stfdux(); extern void ppc_fadd(); extern void ppc_fsub(); extern void ppc_fmul(); extern void ppc_fdiv(); extern void ppc_fadds(); extern void ppc_fsubs(); extern void ppc_fmuls(); extern void ppc_fdivs(); extern void ppc_fmadd(); extern void ppc_fmsub(); extern void ppc_fnmadd(); extern void ppc_fnmsub(); extern void ppc_fmadds(); extern void ppc_fmsubs(); extern void ppc_fnmadds(); extern void ppc_fnmsubs(); extern void ppc_fabs(); extern void ppc_fnabs(); extern void ppc_fneg(); extern void ppc_fsel(); extern void ppc_fres(); extern void ppc_fsqrts(); extern void ppc_fsqrt(); extern void ppc_frsqrte(); extern void ppc_frsp(); extern void ppc_fctiw(); extern void ppc_fctiwz(); extern void ppc_fcmpo(); extern void ppc_fcmpu(); // Power-specific instructions extern void power_abs(); extern void power_clcs(); extern void power_div(); extern void power_divs(); extern void power_doz(); extern void power_dozi(); extern void power_lscbx(); extern void power_maskg(); extern void power_maskir(); extern void power_mul(); extern void power_nabs(); extern void power_rlmi(); extern void power_rrib(); extern void power_sle(); extern void power_sleq(); extern void power_sliq(); extern void power_slliq(); extern void power_sllq(); extern void power_slq(); extern void power_sraiq(); extern void power_sraq(); extern void power_sre(); extern void power_srea(); extern void power_sreq(); extern void power_sriq(); extern void power_srliq(); extern void power_srlq(); extern void power_srq(); } // namespace dppc_interpreter // AltiVec instructions // 64-bit instructions // G5+ instructions extern uint64_t get_virt_time_ns(void); extern void ppc_main_opcode(void); extern void ppc_exec(void); extern void ppc_exec_single(void); extern void ppc_exec_until(uint32_t goal_addr); extern void ppc_exec_dbg(uint32_t start_addr, uint32_t size); /* debugging support API */ void print_fprs(void); /* print content of the floating-point registers */ uint64_t get_reg(std::string& reg_name); /* get content of the register reg_name */ void set_reg(std::string& reg_name, uint64_t val); /* set reg_name to val */ #endif /* PPCEMU_H */