diff options
Diffstat (limited to 'src/devices/cpu/powerpc')
-rw-r--r-- | src/devices/cpu/powerpc/ppc.h | 121 | ||||
-rw-r--r-- | src/devices/cpu/powerpc/ppc_dasm.cpp | 649 | ||||
-rw-r--r-- | src/devices/cpu/powerpc/ppc_dasm.h | 35 | ||||
-rw-r--r-- | src/devices/cpu/powerpc/ppccom.cpp | 249 | ||||
-rw-r--r-- | src/devices/cpu/powerpc/ppccom.h | 12 | ||||
-rw-r--r-- | src/devices/cpu/powerpc/ppcdrc.cpp | 271 | ||||
-rw-r--r-- | src/devices/cpu/powerpc/ppcfe.cpp | 96 |
7 files changed, 980 insertions, 453 deletions
diff --git a/src/devices/cpu/powerpc/ppc.h b/src/devices/cpu/powerpc/ppc.h index 4e4e1e144e2..ce715b59dc1 100644 --- a/src/devices/cpu/powerpc/ppc.h +++ b/src/devices/cpu/powerpc/ppc.h @@ -13,12 +13,16 @@ #pragma once +#include "ppc_dasm.h" + #include "cpu/drcfe.h" #include "cpu/drcuml.h" #include "cpu/drcumlsh.h" #include "divtlb.h" +#include <algorithm> + /*************************************************************************** CONSTANTS @@ -75,9 +79,18 @@ enum PPC_R30, PPC_R31, PPC_CR, + PPC_MQ, PPC_LR, PPC_CTR, PPC_XER, + PPC_BAT0U, + PPC_BAT0L, + PPC_BAT1U, + PPC_BAT1L, + PPC_BAT2U, + PPC_BAT2L, + PPC_BAT3U, + PPC_BAT3L, PPC_F0, PPC_F1, @@ -147,7 +160,6 @@ enum PPC_SR15 }; - /* compiler-specific options */ #define PPCDRC_STRICT_VERIFY 0x0001 /* verify all instructions */ #define PPCDRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */ @@ -212,7 +224,10 @@ public: void set_bus_frequency(uint32_t bus_frequency) { c_bus_frequency = bus_frequency; } void set_bus_frequency(const XTAL &xtal) { set_bus_frequency(xtal.value()); } - void ppc_set_dcstore_callback(write32_delegate callback); + void set_serial_clock(uint32_t serial_clock) { c_serial_clock = serial_clock; } + void set_serial_clock(const XTAL &xtal) { set_serial_clock(xtal.value()); } + + void ppc_set_dcstore_callback(write32sm_delegate callback); void ppcdrc_set_options(uint32_t options); void ppcdrc_add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base); @@ -245,20 +260,19 @@ public: protected: // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_stop() override; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual void device_stop() override ATTR_COLD; // device_execute_interface overrides - virtual uint32_t execute_min_cycles() const override { return 1; } - virtual uint32_t execute_max_cycles() const override { return 40; } - virtual uint32_t execute_input_lines() const override { return 1; } + virtual uint32_t execute_min_cycles() const noexcept override { return 1; } + virtual uint32_t execute_max_cycles() const noexcept override { return 40; } virtual void execute_run() override; virtual void execute_set_input(int inputnum, int state) override; // device_memory_interface overrides virtual space_config_vector memory_space_config() const override; - virtual bool memory_translate(int spacenum, int intention, offs_t &address) override; + virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) override; // device_state_interface overrides virtual void state_export(const device_state_entry &entry) override; @@ -292,7 +306,10 @@ protected: address_space_config m_program_config; address_space *m_program; + memory_access<32, 2, 0, ENDIANNESS_BIG>::cache m_cache32; + memory_access<32, 3, 0, ENDIANNESS_BIG>::cache m_cache64; uint32_t c_bus_frequency; + uint32_t c_serial_clock; struct internal_ppc_state { @@ -461,29 +478,39 @@ protected: /* architectural distinctions */ powerpc_flavor m_flavor; - uint32_t m_cap; - uint8_t m_cache_line_size; - uint32_t m_tb_divisor; + uint32_t m_cap; + uint8_t m_cache_line_size; + uint32_t m_tb_divisor; /* PowerPC 4xx-specific state */ /* PowerPC 4XX-specific serial port state */ struct ppc4xx_spu_state { - uint8_t regs[9]; - uint8_t txbuf; - uint8_t rxbuf; + ppc4xx_spu_state(device_t &owner) : timer(nullptr), tx_cb(owner) { } + + void clear() + { + std::fill(std::begin(regs), std::end(regs), 0); + txbuf = rxbuf = 0; + std::fill(std::begin(rxbuffer), std::end(rxbuffer), 0); + rxin = rxout = 0; + } + + uint8_t regs[9]; + uint8_t txbuf; + uint8_t rxbuf; emu_timer * timer; - uint8_t rxbuffer[256]; - uint32_t rxin, rxout; - write8_delegate tx_cb; + uint8_t rxbuffer[256]; + uint32_t rxin, rxout; + write8smo_delegate tx_cb; }; ppc4xx_spu_state m_spu; emu_timer * m_fit_timer; emu_timer * m_pit_timer; emu_timer * m_wdog_timer; - uint32_t m_pit_reload; - uint32_t m_irqstate; + uint32_t m_pit_reload; + uint32_t m_irqstate; emu_timer * m_buffered_dma_timer[4]; int m_buffered_dma_rate[4]; @@ -493,17 +520,20 @@ protected: uint32_t m_system_clock; uint32_t m_cpu_clock; + uint32_t m_serial_clock; uint64_t m_tb_zero_cycles; uint64_t m_dec_zero_cycles; + uint64_t m_rtc_zero_cycles; emu_timer * m_decrementer_int_timer; - read32_delegate m_dcr_read_func; - write32_delegate m_dcr_write_func; - write32_delegate m_dcstore_cb; + read32sm_delegate m_dcr_read_func; + write32sm_delegate m_dcr_write_func; + + write32sm_delegate m_dcstore_cb; - read32_delegate m_ext_dma_read_cb[4]; - write32_delegate m_ext_dma_write_cb[4]; + read32_delegate::array<4> m_ext_dma_read_cb; + write32sm_delegate::array<4> m_ext_dma_write_cb; /* PowerPC function pointers for memory accesses/exceptions */ #ifdef PPC_H_INCLUDED_FROM_PPC_C @@ -623,7 +653,7 @@ protected: void set_timebase(uint64_t newtb); uint32_t get_decrementer(); void set_decrementer(uint32_t newdec); - uint32_t ppccom_translate_address_internal(int intention, offs_t &address); + uint32_t ppccom_translate_address_internal(int intention, bool debug, offs_t &address); void ppc4xx_set_irq_line(uint32_t bitmask, int state); int ppc4xx_get_irq_line(uint32_t bitmask); void ppc4xx_dma_update_irq_states(); @@ -672,6 +702,8 @@ protected: void log_register_list(const char *string, const uint32_t *reglist, const uint32_t *regnostarlist); void log_opcode_desc(const opcode_desc *desclist, int indent); +private: + powerpc_disassembler m_dasm; }; @@ -679,9 +711,6 @@ protected: //{ //public: // ppc403_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); -// -//protected: -// virtual uint32_t execute_input_lines() const { return 8; } //}; // // @@ -689,9 +718,6 @@ protected: //{ //public: // ppc405_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); -// -//protected: -// virtual uint32_t execute_input_lines() const { return 8; } //}; @@ -734,6 +760,9 @@ class ppc601_device : public ppc_device { public: ppc601_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; }; @@ -743,26 +772,36 @@ public: ppc604_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; +class ppc740_device : public ppc_device +{ +public: + ppc740_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class ppc750_device : public ppc_device +{ +public: + ppc750_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; class ppc4xx_device : public ppc_device { public: - void ppc4xx_spu_set_tx_handler(write8_delegate callback); + void ppc4xx_spu_set_tx_handler(write8smo_delegate callback); void ppc4xx_spu_receive_byte(uint8_t byteval); void ppc4xx_set_dma_read_handler(int channel, read32_delegate callback, int rate); - void ppc4xx_set_dma_write_handler(int channel, write32_delegate callback, int rate); - void ppc4xx_set_dcr_read_handler(read32_delegate dcr_read_func); - void ppc4xx_set_dcr_write_handler(write32_delegate dcr_write_func); + void ppc4xx_set_dma_write_handler(int channel, write32sm_delegate callback, int rate); + void ppc4xx_set_dcr_read_handler(read32sm_delegate dcr_read_func); + void ppc4xx_set_dcr_write_handler(write32sm_delegate dcr_write_func); - DECLARE_READ8_MEMBER( ppc4xx_spu_r ); - DECLARE_WRITE8_MEMBER( ppc4xx_spu_w ); + uint8_t ppc4xx_spu_r(offs_t offset); + void ppc4xx_spu_w(offs_t offset, uint8_t data); - void internal_ppc4xx(address_map &map); + void internal_ppc4xx(address_map &map) ATTR_COLD; protected: ppc4xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, powerpc_flavor flavor, uint32_t cap, uint32_t tb_divisor); - virtual uint32_t execute_input_lines() const override { return 5; } virtual void execute_set_input(int inputnum, int state) override; }; @@ -798,5 +837,7 @@ DECLARE_DEVICE_TYPE(MPC8240, mpc8240_device) DECLARE_DEVICE_TYPE(PPC403GA, ppc403ga_device) DECLARE_DEVICE_TYPE(PPC403GCX, ppc403gcx_device) DECLARE_DEVICE_TYPE(PPC405GP, ppc405gp_device) +DECLARE_DEVICE_TYPE(PPC740, ppc740_device) +DECLARE_DEVICE_TYPE(PPC750, ppc750_device) #endif // MAME_CPU_POWERPC_PPC_H diff --git a/src/devices/cpu/powerpc/ppc_dasm.cpp b/src/devices/cpu/powerpc/ppc_dasm.cpp index aad939efffe..85ed3914e3e 100644 --- a/src/devices/cpu/powerpc/ppc_dasm.cpp +++ b/src/devices/cpu/powerpc/ppc_dasm.cpp @@ -28,219 +28,331 @@ * and print instructions. */ +constexpr int I_COMMON = powerpc_disassembler::I_POWER | powerpc_disassembler::I_POWERPC; + const powerpc_disassembler::IDESCR powerpc_disassembler::itab[] = { - { "add", D_OP(31)|D_XO(266), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "addc", D_OP(31)|D_XO(10), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "adde", D_OP(31)|D_XO(138), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "addi", D_OP(14), M_RT|M_RA|M_SIMM, F_RT_RA_0_SIMM, 0 }, - { "addic", D_OP(12), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, - { "addic.", D_OP(13), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, - { "addis", D_OP(15), M_RT|M_RA|M_SIMM, F_ADDIS, 0 }, - { "addme", D_OP(31)|D_XO(234), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, - { "addze", D_OP(31)|D_XO(202), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, - { "and", D_OP(31)|D_XO(28), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "andc", D_OP(31)|D_XO(60), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "andi.", D_OP(28), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, - { "andis.", D_OP(29), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, - { "b", D_OP(18), M_LI|M_AA|M_LK, F_LI, FL_AA|FL_LK }, - { "bc", D_OP(16), M_BO|M_BI|M_BD|M_AA|M_LK, F_BCx, FL_AA|FL_LK }, - { "bcctr", D_OP(19)|D_XO(528), M_BO|M_BI|M_LK, F_BO_BI, FL_LK }, - { "bclr", D_OP(19)|D_XO(16), M_BO|M_BI|M_LK, F_BO_BI, FL_LK|FL_SO }, - { "cmp", D_OP(31)|D_XO(0), M_CRFD|M_RA|M_RB, F_CMP, 0 }, - { "cmpd", D_OP(31)|D_XO(0)|M_L,M_CRFD|M_RA|M_RB, F_CMP, 0 }, - { "cmpi", D_OP(11), M_CRFD|M_RA|M_SIMM, F_CMP_SIMM, 0 }, - { "cmpdi", D_OP(11)|M_L, M_CRFD|M_RA|M_SIMM, F_CMP_SIMM, 0 }, - { "cmpl", D_OP(31)|D_XO(32), M_CRFD|M_RA|M_RB, F_CMP, 0 }, - { "cmpld", D_OP(31)|D_XO(32)|M_L,M_CRFD|M_RA|M_RB, F_CMP, 0 }, - { "cmpli", D_OP(10), M_CRFD|M_RA|M_UIMM, F_CMP_UIMM, 0 }, - { "cmpldi", D_OP(10)|M_L, M_CRFD|M_RA|M_UIMM, F_CMP_UIMM, 0 }, - { "cntlzw", D_OP(31)|D_XO(26), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, - { "crand", D_OP(19)|D_XO(257), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, - { "crandc", D_OP(19)|D_XO(129), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, - { "creqv", D_OP(19)|D_XO(289), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, - { "crnand", D_OP(19)|D_XO(225), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, - { "crnor", D_OP(19)|D_XO(33), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, - { "cror", D_OP(19)|D_XO(449), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, - { "crorc", D_OP(19)|D_XO(417), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, - { "crxor", D_OP(19)|D_XO(193), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, - { "dcba", D_OP(31)|D_XO(758), M_RA|M_RB, F_RA_0_RB, 0 }, - { "dcbf", D_OP(31)|D_XO(86), M_RA|M_RB, F_RA_0_RB, 0 }, - { "dcbi", D_OP(31)|D_XO(470), M_RA|M_RB, F_RA_0_RB, 0 }, - { "dcbst", D_OP(31)|D_XO(54), M_RA|M_RB, F_RA_0_RB, 0 }, - { "dcbt", D_OP(31)|D_XO(278), M_RA|M_RB, F_RA_0_RB, 0 }, - { "dcbtst", D_OP(31)|D_XO(246), M_RA|M_RB, F_RA_0_RB, 0 }, - { "dcbz", D_OP(31)|D_XO(1014),M_RA|M_RB, F_RA_0_RB, 0 }, - { "dccci", D_OP(31)|D_XO(454), M_RA|M_RB, F_RA_0_RB, 0 }, - { "dcread", D_OP(31)|D_XO(486), M_RA|M_RB, F_RT_RA_RB, 0 }, - { "divw", D_OP(31)|D_XO(491), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "divwu", D_OP(31)|D_XO(459), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "dsa", D_OP(31)|D_XO(628), 0, 0, 0 }, - { "eciwx", D_OP(31)|D_XO(310), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "ecowx", D_OP(31)|D_XO(438), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "eieio", D_OP(31)|D_XO(854), 0, F_NONE, 0 }, - { "eqv", D_OP(31)|D_XO(284), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "esa", D_OP(31)|D_XO(596), 0, 0, 0 }, - { "extsb", D_OP(31)|D_XO(954), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, - { "extsh", D_OP(31)|D_XO(922), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, - { "fabs", D_OP(63)|D_XO(264), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fadd", D_OP(63)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, - { "fadds", D_OP(59)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, - { "fcmpo", D_OP(63)|D_XO(32), M_CRFD|M_RA|M_RB, F_FCMP, 0 }, - { "fcmpu", D_OP(63)|D_XO(0), M_CRFD|M_RA|M_RB, F_FCMP, 0 }, - { "fctiw", D_OP(63)|D_XO(14), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fctiwz", D_OP(63)|D_XO(15), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fdiv", D_OP(63)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, - { "fdivs", D_OP(59)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, - { "fmadd", D_OP(63)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fmadds", D_OP(59)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fmr", D_OP(63)|D_XO(72), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fmsub", D_OP(63)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fmsubs", D_OP(59)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fmul", D_OP(63)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC }, - { "fmuls", D_OP(59)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC }, - { "fnabs", D_OP(63)|D_XO(136), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fneg", D_OP(63)|D_XO(40), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fnmadd", D_OP(63)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fnmadds",D_OP(59)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fnmsub", D_OP(63)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fnmsubs",D_OP(59)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fres", D_OP(59)|D_XO(24), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "frsp", D_OP(63)|D_XO(12), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "frsqrte",D_OP(63)|D_XO(26), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fsel", D_OP(63)|D_XO(23), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, - { "fsqrt", D_OP(63)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fsqrts", D_OP(59)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, - { "fsub", D_OP(63)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, - { "fsubs", D_OP(59)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, - { "icbi", D_OP(31)|D_XO(982), M_RA|M_RB, F_RA_0_RB, 0 }, - { "icbt", D_OP(31)|D_XO(262), M_RA|M_RB, F_RA_0_RB, 0 }, - { "iccci", D_OP(31)|D_XO(966), M_RA|M_RB, F_RA_0_RB, 0 }, - { "icread", D_OP(31)|D_XO(998), M_RA|M_RB, F_RA_0_RB, 0 }, - { "isync", D_OP(19)|D_XO(150), 0, F_NONE, 0 }, - { "lbz", D_OP(34), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "lbzu", D_OP(35), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, - { "lbzux", D_OP(31)|D_XO(119), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, - { "lbzx", D_OP(31)|D_XO(87), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "lfd", D_OP(50), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, - { "lfdu", D_OP(51), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, - { "lfdux", D_OP(31)|D_XO(631), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, - { "lfdx", D_OP(31)|D_XO(599), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, - { "lfs", D_OP(48), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, - { "lfsu", D_OP(49), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, - { "lfsux", D_OP(31)|D_XO(567), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, - { "lfsx", D_OP(31)|D_XO(535), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, - { "lha", D_OP(42), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "lhau", D_OP(43), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, - { "lhaux", D_OP(31)|D_XO(375), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, - { "lhax", D_OP(31)|D_XO(343), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "lhbrx", D_OP(31)|D_XO(790), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "lhz", D_OP(40), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "lhzu", D_OP(41), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, - { "lhzux", D_OP(31)|D_XO(311), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, - { "lhzx", D_OP(31)|D_XO(279), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "lmw", D_OP(46), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "lswi", D_OP(31)|D_XO(597), M_RT|M_RA|M_NB, F_RT_RA_0_NB, FL_CHECK_LSWI }, - { "lswx", D_OP(31)|D_XO(533), M_RT|M_RA|M_RB, F_RT_RA_0_RB, FL_CHECK_LSWX }, - { "lwarx", D_OP(31)|D_XO(20), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "lwbrx", D_OP(31)|D_XO(534), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "lwz", D_OP(32), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "lwzu", D_OP(33), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, - { "lwzux", D_OP(31)|D_XO(55), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, - { "lwzx", D_OP(31)|D_XO(23), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "mcrf", D_OP(19)|D_XO(0), M_CRFD|M_CRFS, F_CRFD_CRFS, 0 }, - { "mcrfs", D_OP(63)|D_XO(64), M_CRFD|M_CRFS, F_CRFD_CRFS, 0 }, - { "mcrxr", D_OP(31)|D_XO(512), M_CRFD, F_MCRXR, 0 }, - { "mfcr", D_OP(31)|D_XO(19), M_RT, F_RT, 0 }, - { "mfdcr", D_OP(31)|D_XO(323), M_RT|M_DCR, F_RT_DCR, 0 }, - { "mffs", D_OP(63)|D_XO(583), M_RT|M_RC, F_MFFSx, FL_RC }, - { "mfmsr", D_OP(31)|D_XO(83), M_RT, F_RT, 0 }, - { "mfspr", D_OP(31)|D_XO(339), M_RT|M_SPR, F_RT_SPR, 0 }, - { "mfsr", D_OP(31)|D_XO(595), M_RT|M_SR, F_MFSR, 0 }, - { "mfsrin", D_OP(31)|D_XO(659), M_RT|M_RB, F_RT_RB, 0 }, - { "mftb", D_OP(31)|D_XO(371), M_RT|M_TBR, F_RT_SPR, 0 }, - { "mtcrf", D_OP(31)|D_XO(144), M_RT|M_CRM, F_MTCRF, 0 }, - { "mtdcr", D_OP(31)|D_XO(451), M_RT|M_DCR, F_MTDCR, 0 }, - { "mtfsb0", D_OP(63)|D_XO(70), M_CRBD|M_RC, F_FCRBD, FL_RC }, - { "mtfsb1", D_OP(63)|D_XO(38), M_CRBD|M_RC, F_FCRBD, FL_RC }, - { "mtfsf", D_OP(63)|D_XO(711), M_FM|M_RB|M_RC, F_MTFSFx, FL_RC }, - { "mtfsfi", D_OP(63)|D_XO(134), M_CRFD|M_IMM|M_RC, F_MTFSFIx, FL_RC }, - { "mtmsr", D_OP(31)|D_XO(146), M_RT, F_RT, 0 }, - { "mtspr", D_OP(31)|D_XO(467), M_RT|M_SPR, F_MTSPR, 0 }, - { "mtsr", D_OP(31)|D_XO(210), M_RT|M_SR, F_MTSR, 0 }, - { "mtsrin", D_OP(31)|D_XO(242), M_RT|M_RB, F_RT_RB, 0 }, - { "mulhw", D_OP(31)|D_XO(75), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC }, - { "mulhwu", D_OP(31)|D_XO(11), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC }, - { "mulli", D_OP(7), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, - { "mullw", D_OP(31)|D_XO(235), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "nand", D_OP(31)|D_XO(476), M_RA|M_RT|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "neg", D_OP(31)|D_XO(104), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, - { "nor", D_OP(31)|D_XO(124), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "or", D_OP(31)|D_XO(444), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "orc", D_OP(31)|D_XO(412), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "ori", D_OP(24), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, - { "oris", D_OP(25), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, - { "rfi", D_OP(19)|D_XO(50), 0, F_NONE, 0 }, - { "rfci", D_OP(19)|D_XO(51), 0, F_NONE, 0 }, - { "rlwimi", D_OP(20), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC }, - { "rlwinm", D_OP(21), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC }, - { "rlwnm", D_OP(23), M_RT|M_RA|M_RB|M_MB|M_ME|M_RC, F_RLWNMx, FL_RC }, - { "sc", D_OP(17)|2, 0, F_NONE, 0 }, - { "slw", D_OP(31)|D_XO(24), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "sraw", D_OP(31)|D_XO(792), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "srawi", D_OP(31)|D_XO(824), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC }, - { "srw", D_OP(31)|D_XO(536), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "stb", D_OP(38), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "stbu", D_OP(39), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, - { "stbux", D_OP(31)|D_XO(247), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, - { "stbx", D_OP(31)|D_XO(215), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "stfd", D_OP(54), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, - { "stfdu", D_OP(55), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, - { "stfdux", D_OP(31)|D_XO(759), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, - { "stfdx", D_OP(31)|D_XO(727), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, - { "stfiwx", D_OP(31)|D_XO(983), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, - { "stfs", D_OP(52), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, - { "stfsu", D_OP(53), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, - { "stfsux", D_OP(31)|D_XO(695), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, - { "stfsx", D_OP(31)|D_XO(663), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, - { "sth", D_OP(44), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "sthbrx", D_OP(31)|D_XO(918), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "sthu", D_OP(45), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, - { "sthux", D_OP(31)|D_XO(439), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, - { "sthx", D_OP(31)|D_XO(407), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "stmw", D_OP(47), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "stswi", D_OP(31)|D_XO(725), M_RT|M_RA|M_NB, F_RT_RA_0_NB, 0 }, - { "stswx", D_OP(31)|D_XO(661), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "stw", D_OP(36), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, - { "stwbrx", D_OP(31)|D_XO(662), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "stwcx.", D_OP(31)|D_XO(150)|1, M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "stwu", D_OP(37), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, - { "stwux", D_OP(31)|D_XO(183), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, - { "stwx", D_OP(31)|D_XO(151), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, - { "subf", D_OP(31)|D_XO(40), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "subfc", D_OP(31)|D_XO(8), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "subfe", D_OP(31)|D_XO(136), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, - { "subfic", D_OP(8), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, - { "subfme", D_OP(31)|D_XO(232), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, - { "subfze", D_OP(31)|D_XO(200), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, - { "sync", D_OP(31)|D_XO(598), 0, F_NONE, 0 }, - { "tlbia", D_OP(31)|D_XO(370), 0, F_NONE, 0 }, - { "tlbie", D_OP(31)|D_XO(306), M_RB, F_RB, 0 }, - { "tlbsync",D_OP(31)|D_XO(566), 0, F_NONE, 0 }, - { "tw", D_OP(31)|D_XO(4), M_TO|M_RA|M_RB, F_TW, 0 }, - { "twi", D_OP(3), M_TO|M_RA|M_SIMM, F_TWI, 0 }, - { "wrtee", D_OP(31)|D_XO(131), M_RT, F_RT, 0 }, - { "wrteei", D_OP(31)|D_XO(163), 0, 0, 0 }, - { "xor", D_OP(31)|D_XO(316), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, - { "xori", D_OP(26), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, - { "xoris", D_OP(27), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "a", D_OP(31)|D_XO(10), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "abs", D_OP(31)|D_XO(360), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWER }, + { "add", D_OP(31)|D_XO(266), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "addc", D_OP(31)|D_XO(10), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "adde", D_OP(31)|D_XO(138), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "addi", D_OP(14), M_RT|M_RA|M_SIMM, F_RT_RA_0_SIMM, 0, I_POWERPC }, + { "addic", D_OP(12), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWERPC }, + { "addic.", D_OP(13), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWERPC }, + { "addis", D_OP(15), M_RT|M_RA|M_SIMM, F_ADDIS, 0, I_POWERPC }, + { "addme", D_OP(31)|D_XO(234), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWERPC }, + { "addze", D_OP(31)|D_XO(202), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWERPC }, + { "ae", D_OP(31)|D_XO(138), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "ai", D_OP(12), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWER }, + { "ai.", D_OP(13), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWER }, + { "ame", D_OP(31)|D_XO(234), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWER }, + { "and", D_OP(31)|D_XO(28), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_COMMON }, + { "andc", D_OP(31)|D_XO(60), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_COMMON }, + { "andi.", D_OP(28), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWERPC }, + { "andil.", D_OP(28), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWER }, + { "andis.", D_OP(29), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWERPC }, + { "andiu.", D_OP(29), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWER }, + { "aze", D_OP(31)|D_XO(202), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWER }, + { "b", D_OP(18), M_LI|M_AA|M_LK, F_LI, FL_AA|FL_LK, I_COMMON }, + { "bc", D_OP(16), M_BO|M_BI|M_BD|M_AA|M_LK, F_BCx, FL_AA|FL_LK, I_COMMON }, + { "bcc", D_OP(19)|D_XO(528), M_BO|M_BI|M_LK, F_BO_BI, FL_LK, I_POWER }, + { "bcctr", D_OP(19)|D_XO(528), M_BO|M_BI|M_LK, F_BO_BI, FL_LK, I_POWERPC }, + { "bclr", D_OP(19)|D_XO(16), M_BO|M_BI|M_LK, F_BO_BI, FL_LK|FL_SO, I_POWERPC }, + { "bcr", D_OP(19)|D_XO(16), M_BO|M_BI|M_LK, F_BO_BI, FL_LK|FL_SO, I_POWER }, + { "cal", D_OP(14), M_RT|M_RA|M_SIMM, F_RT_D_RA_0, 0, I_POWER }, + { "cau", D_OP(15), M_RT|M_RA|M_SIMM, F_ADDIS, 0, I_POWER }, + { "cax", D_OP(31)|D_XO(266), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "clcs", D_OP(31)|D_XO(531), M_RT|M_RA, F_RT_RA, 0, I_POWER }, + { "clf", D_OP(31)|D_XO(118), M_RA|M_RB, F_RA_0_RB, 0, I_POWER }, + { "cli", D_OP(31)|D_XO(502), M_RA|M_RB, F_RA_0_RB, 0, I_POWER }, + { "cmp", D_OP(31)|D_XO(0), M_CRFD|M_RA|M_RB, F_CMP, 0, I_COMMON }, + { "cmpd", D_OP(31)|D_XO(0)|M_L,M_CRFD|M_RA|M_RB, F_CMP, 0, I_POWERPC }, + { "cmpi", D_OP(11), M_CRFD|M_RA|M_SIMM, F_CMP_SIMM, 0, I_COMMON }, + { "cmpdi", D_OP(11)|M_L, M_CRFD|M_RA|M_SIMM, F_CMP_SIMM, 0, I_POWERPC }, + { "cmpl", D_OP(31)|D_XO(32), M_CRFD|M_RA|M_RB, F_CMP, 0, I_COMMON }, + { "cmpld", D_OP(31)|D_XO(32)|M_L,M_CRFD|M_RA|M_RB, F_CMP, 0, I_POWERPC }, + { "cmpli", D_OP(10), M_CRFD|M_RA|M_UIMM, F_CMP_UIMM, 0, I_COMMON }, + { "cmpldi", D_OP(10)|M_L, M_CRFD|M_RA|M_UIMM, F_CMP_UIMM, 0, I_POWERPC }, + { "cntlz", D_OP(31)|D_XO(26), M_RT|M_RA|M_RC, F_RA_RT, FL_RC, I_POWER }, + { "cntlzw", D_OP(31)|D_XO(26), M_RT|M_RA|M_RC, F_RA_RT, FL_RC, I_POWERPC }, + { "crand", D_OP(19)|D_XO(257), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0, I_COMMON }, + { "crandc", D_OP(19)|D_XO(129), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0, I_COMMON }, + { "creqv", D_OP(19)|D_XO(289), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0, I_COMMON }, + { "crnand", D_OP(19)|D_XO(225), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0, I_COMMON }, + { "crnor", D_OP(19)|D_XO(33), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0, I_COMMON }, + { "cror", D_OP(19)|D_XO(449), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0, I_COMMON }, + { "crorc", D_OP(19)|D_XO(417), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0, I_COMMON }, + { "crxor", D_OP(19)|D_XO(193), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0, I_COMMON }, + { "dcba", D_OP(31)|D_XO(758), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "dcbf", D_OP(31)|D_XO(86), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "dcbi", D_OP(31)|D_XO(470), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "dcbst", D_OP(31)|D_XO(54), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "dcbt", D_OP(31)|D_XO(278), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "dcbtst", D_OP(31)|D_XO(246), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "dcbz", D_OP(31)|D_XO(1014),M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "dclst", D_OP(31)|D_XO(630), M_RA|M_RB, F_RA_0_RB, 0, I_POWER }, + { "dclz", D_OP(31)|D_XO(1014),M_RA|M_RB, F_RA_0_RB, 0, I_POWER }, + { "dcs", D_OP(31)|D_XO(598), 0, F_NONE, 0, I_POWER }, + { "dccci", D_OP(31)|D_XO(454), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "dcread", D_OP(31)|D_XO(486), M_RA|M_RB, F_RT_RA_RB, 0, I_POWERPC }, + { "div", D_OP(31)|D_XO(331), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "divs", D_OP(31)|D_XO(363), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "divw", D_OP(31)|D_XO(491), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "divwu", D_OP(31)|D_XO(459), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "doz", D_OP(31)|D_XO(264), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "dozi", D_OP(9), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWER }, + { "dsa", D_OP(31)|D_XO(628), 0, 0, 0, I_POWERPC }, + { "eciwx", D_OP(31)|D_XO(310), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "ecowx", D_OP(31)|D_XO(438), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "eieio", D_OP(31)|D_XO(854), 0, F_NONE, 0, I_POWERPC }, + { "eqv", D_OP(31)|D_XO(284), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_COMMON }, + { "esa", D_OP(31)|D_XO(596), 0, 0, 0, I_POWERPC }, + { "exts", D_OP(31)|D_XO(922), M_RT|M_RA|M_RC, F_RA_RT, FL_RC, I_POWER }, + { "extsb", D_OP(31)|D_XO(954), M_RT|M_RA|M_RC, F_RA_RT, FL_RC, I_POWERPC }, + { "extsh", D_OP(31)|D_XO(922), M_RT|M_RA|M_RC, F_RA_RT, FL_RC, I_POWERPC }, + { "fa", D_OP(63)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWER }, + { "fabs", D_OP(63)|D_XO(264), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_COMMON }, + { "fadd", D_OP(63)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWERPC }, + { "fadds", D_OP(59)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWERPC }, + { "fcir", D_OP(63)|D_XO(14), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_POWER }, + { "fcirz", D_OP(63)|D_XO(15), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_POWER }, + { "fcmpo", D_OP(63)|D_XO(32), M_CRFD|M_RA|M_RB, F_FCMP, 0, I_COMMON }, + { "fcmpu", D_OP(63)|D_XO(0), M_CRFD|M_RA|M_RB, F_FCMP, 0, I_COMMON }, + { "fctiw", D_OP(63)|D_XO(14), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_POWERPC }, + { "fctiwz", D_OP(63)|D_XO(15), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_POWERPC }, + { "fd", D_OP(63)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWER }, + { "fdiv", D_OP(63)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWERPC }, + { "fdivs", D_OP(59)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWERPC }, + { "fm", D_OP(63)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC, I_POWER }, + { "fma", D_OP(63)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWER }, + { "fmadd", D_OP(63)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fmadds", D_OP(59)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fmr", D_OP(63)|D_XO(72), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_COMMON }, + { "fms", D_OP(63)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWER }, + { "fmsub", D_OP(63)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fmsubs", D_OP(59)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fmul", D_OP(63)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC, I_POWERPC }, + { "fmuls", D_OP(59)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC, I_POWERPC }, + { "fnabs", D_OP(63)|D_XO(136), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_COMMON }, + { "fneg", D_OP(63)|D_XO(40), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_COMMON }, + { "fnma", D_OP(63)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWER }, + { "fnmadd", D_OP(63)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fnmadds",D_OP(59)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fnms", D_OP(63)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWER }, + { "fnmsub", D_OP(63)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fnmsubs",D_OP(59)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fres", D_OP(59)|D_XO(24), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_POWERPC }, + { "frsp", D_OP(63)|D_XO(12), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_COMMON }, + { "frsqrte",D_OP(63)|D_XO(26), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_POWERPC }, + { "fs", D_OP(63)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWER }, + { "fsel", D_OP(63)|D_XO(23), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC, I_POWERPC }, + { "fsqrt", D_OP(63)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_POWERPC }, + { "fsqrts", D_OP(59)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC, I_POWERPC }, + { "fsub", D_OP(63)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWERPC }, + { "fsubs", D_OP(59)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC, I_POWERPC }, + { "icbi", D_OP(31)|D_XO(982), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "icbt", D_OP(31)|D_XO(262), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "iccci", D_OP(31)|D_XO(966), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "icread", D_OP(31)|D_XO(998), M_RA|M_RB, F_RA_0_RB, 0, I_POWERPC }, + { "ics", D_OP(19)|D_XO(150), 0, F_NONE, 0, I_POWER }, + { "isync", D_OP(19)|D_XO(150), 0, F_NONE, 0, I_POWERPC }, + { "l", D_OP(32), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_POWER }, + { "lbz", D_OP(34), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_COMMON }, + { "lbzu", D_OP(35), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT, I_COMMON }, + { "lbzux", D_OP(31)|D_XO(119), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT, I_COMMON }, + { "lbzx", D_OP(31)|D_XO(87), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_COMMON }, + { "lfd", D_OP(50), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0, I_COMMON }, + { "lfdu", D_OP(51), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA, I_COMMON }, + { "lfdux", D_OP(31)|D_XO(631), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA, I_COMMON }, + { "lfdx", D_OP(31)|D_XO(599), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_COMMON }, + { "lfs", D_OP(48), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0, I_COMMON }, + { "lfsu", D_OP(49), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA, I_COMMON }, + { "lfsux", D_OP(31)|D_XO(567), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA, I_COMMON }, + { "lfsx", D_OP(31)|D_XO(535), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_COMMON }, + { "lha", D_OP(42), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_COMMON }, + { "lhau", D_OP(43), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT, I_COMMON }, + { "lhaux", D_OP(31)|D_XO(375), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT, I_COMMON }, + { "lhax", D_OP(31)|D_XO(343), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_COMMON }, + { "lhbrx", D_OP(31)|D_XO(790), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_COMMON }, + { "lhz", D_OP(40), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_COMMON }, + { "lhzu", D_OP(41), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT, I_COMMON }, + { "lhzux", D_OP(31)|D_XO(311), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT, I_COMMON }, + { "lhzx", D_OP(31)|D_XO(279), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_COMMON }, + { "lm", D_OP(46), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_POWER }, + { "lmw", D_OP(46), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_POWERPC }, + { "lscbx", D_OP(31)|D_XO(277), M_RT|M_RA|M_RB|M_RC, F_RT_RA_0_RB, FL_RC, I_POWER }, + { "lsi", D_OP(31)|D_XO(597), M_RT|M_RA|M_NB, F_RT_RA_0_NB, FL_CHECK_LSWI, I_POWER }, + { "lswi", D_OP(31)|D_XO(597), M_RT|M_RA|M_NB, F_RT_RA_0_NB, FL_CHECK_LSWI, I_POWERPC }, + { "lswx", D_OP(31)|D_XO(533), M_RT|M_RA|M_RB, F_RT_RA_0_RB, FL_CHECK_LSWX, I_POWERPC }, + { "lsx", D_OP(31)|D_XO(533), M_RT|M_RA|M_RB, F_RT_RA_0_RB, FL_CHECK_LSWX, I_POWER }, + { "lu", D_OP(33), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT, I_POWER }, + { "lux", D_OP(31)|D_XO(55), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT, I_POWER }, + { "lwarx", D_OP(31)|D_XO(20), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "lwbrx", D_OP(31)|D_XO(534), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "lwz", D_OP(32), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_POWERPC }, + { "lwzu", D_OP(33), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT, I_POWERPC }, + { "lwzux", D_OP(31)|D_XO(55), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT, I_POWERPC }, + { "lwzx", D_OP(31)|D_XO(23), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "lx", D_OP(31)|D_XO(23), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWER }, + { "maskg", D_OP(31)|D_XO(29), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "maskir", D_OP(31)|D_XO(541), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "mcrf", D_OP(19)|D_XO(0), M_CRFD|M_CRFS, F_CRFD_CRFS, 0, I_COMMON }, + { "mcrfs", D_OP(63)|D_XO(64), M_CRFD|M_CRFS, F_CRFD_CRFS, 0, I_COMMON }, + { "mcrxr", D_OP(31)|D_XO(512), M_CRFD, F_MCRXR, 0, I_COMMON }, + { "mfcr", D_OP(31)|D_XO(19), M_RT, F_RT, 0, I_COMMON }, + { "mfdcr", D_OP(31)|D_XO(323), M_RT|M_DCR, F_RT_DCR, 0, I_POWERPC }, + { "mffs", D_OP(63)|D_XO(583), M_RT|M_RC, F_MFFSx, FL_RC, I_COMMON }, + { "mfmsr", D_OP(31)|D_XO(83), M_RT, F_RT, 0, I_COMMON }, + { "mfspr", D_OP(31)|D_XO(339), M_RT|M_SPR, F_RT_SPR, 0, I_COMMON }, + { "mfsr", D_OP(31)|D_XO(595), M_RT|M_SR, F_MFSR, 0, I_COMMON }, + { "mfsri", D_OP(31)|D_XO(627), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWER }, + { "mfsrin", D_OP(31)|D_XO(659), M_RT|M_RB, F_RT_RB, 0, I_POWERPC }, + { "mftb", D_OP(31)|D_XO(371), M_RT|M_TBR, F_RT_SPR, 0, I_POWERPC }, + { "mtcrf", D_OP(31)|D_XO(144), M_RT|M_CRM, F_MTCRF, 0, I_COMMON }, + { "mtdcr", D_OP(31)|D_XO(451), M_RT|M_DCR, F_MTDCR, 0, I_POWERPC }, + { "mtfsb0", D_OP(63)|D_XO(70), M_CRBD|M_RC, F_FCRBD, FL_RC, I_COMMON }, + { "mtfsb1", D_OP(63)|D_XO(38), M_CRBD|M_RC, F_FCRBD, FL_RC, I_COMMON }, + { "mtfsf", D_OP(63)|D_XO(711), M_FM|M_RB|M_RC, F_MTFSFx, FL_RC, I_COMMON }, + { "mtfsfi", D_OP(63)|D_XO(134), M_CRFD|M_IMM|M_RC, F_MTFSFIx, FL_RC, I_COMMON }, + { "mtmsr", D_OP(31)|D_XO(146), M_RT, F_RT, 0, I_COMMON }, + { "mtspr", D_OP(31)|D_XO(467), M_RT|M_SPR, F_MTSPR, 0, I_COMMON }, + { "mtsr", D_OP(31)|D_XO(210), M_RT|M_SR, F_MTSR, 0, I_COMMON }, + { "mtsri", D_OP(31)|D_XO(242), M_RT|M_RB, F_RT_RB, 0, I_POWER }, + { "mtsrin", D_OP(31)|D_XO(242), M_RT|M_RB, F_RT_RB, 0, I_POWERPC }, + { "mul", D_OP(31)|D_XO(107), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "mulhw", D_OP(31)|D_XO(75), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC, I_POWERPC }, + { "mulhwu", D_OP(31)|D_XO(11), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC, I_POWERPC }, + { "muli", D_OP(7), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWER }, + { "mulli", D_OP(7), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWERPC }, + { "mullw", D_OP(31)|D_XO(235), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "muls", D_OP(31)|D_XO(235), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "nabs", D_OP(31)|D_XO(488), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWER }, + { "nand", D_OP(31)|D_XO(476), M_RA|M_RT|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_COMMON }, + { "neg", D_OP(31)|D_XO(104), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_COMMON }, + { "nor", D_OP(31)|D_XO(124), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_COMMON }, + { "or", D_OP(31)|D_XO(444), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_COMMON }, + { "orc", D_OP(31)|D_XO(412), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_COMMON }, + { "ori", D_OP(24), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWERPC }, + { "oril", D_OP(24), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWER }, + { "oris", D_OP(25), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWERPC }, + { "oriu", D_OP(25), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWER }, + { "rac", D_OP(31)|D_XO(818), M_RT|M_RA|M_RB|M_RC, F_RT_RA_0_RB, FL_RC, I_POWER }, + { "rfi", D_OP(19)|D_XO(50), 0, F_NONE, FL_SO, I_COMMON }, + { "rfci", D_OP(19)|D_XO(51), 0, F_NONE, FL_SO, I_POWERPC }, + { "rfsvc", D_OP(19)|D_XO(82), M_LK, F_NONE, FL_LK|FL_SO, I_POWER }, + { "rlimi", D_OP(20), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC, I_POWER }, + { "rlinm", D_OP(21), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC, I_POWER }, + { "rlmi", D_OP(22), M_RT|M_RA|M_RB|M_MB|M_ME|M_RC, F_RA_RT_RB_MB_ME, FL_RC, I_POWER }, + { "rlnm", D_OP(23), M_RT|M_RA|M_RB|M_MB|M_ME|M_RC, F_RA_RT_RB_MB_ME, FL_RC, I_POWER }, + { "rlwimi", D_OP(20), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC, I_POWERPC }, + { "rlwinm", D_OP(21), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC, I_POWERPC }, + { "rlwnm", D_OP(23), M_RT|M_RA|M_RB|M_MB|M_ME|M_RC, F_RA_RT_RB_MB_ME, FL_RC, I_POWERPC }, + { "rrib", D_OP(31)|D_XO(537), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "sc", D_OP(17)|2, 0, F_NONE, 0, I_POWERPC }, + { "sf", D_OP(31)|D_XO(8), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "sfe", D_OP(31)|D_XO(136), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWER }, + { "sfi", D_OP(8), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWER }, + { "sfme", D_OP(31)|D_XO(232), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWER }, + { "sfze", D_OP(31)|D_XO(200), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWER }, + { "sl", D_OP(31)|D_XO(24), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "sle", D_OP(31)|D_XO(153), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "sleq", D_OP(31)|D_XO(217), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "sliq", D_OP(31)|D_XO(184), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC, I_POWER }, + { "slliq", D_OP(31)|D_XO(248), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC, I_POWER }, + { "sllq", D_OP(31)|D_XO(216), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "slq", D_OP(31)|D_XO(152), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "slw", D_OP(31)|D_XO(24), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWERPC }, + { "sr", D_OP(31)|D_XO(536), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "sra", D_OP(31)|D_XO(792), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "srai", D_OP(31)|D_XO(824), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC, I_POWER }, + { "sraiq", D_OP(31)|D_XO(952), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC, I_POWER }, + { "sraq", D_OP(31)|D_XO(920), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "sraw", D_OP(31)|D_XO(792), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWERPC }, + { "srawi", D_OP(31)|D_XO(824), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC, I_POWERPC }, + { "sre", D_OP(31)|D_XO(665), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "srea", D_OP(31)|D_XO(921), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "sreq", D_OP(31)|D_XO(729), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "sriq", D_OP(31)|D_XO(696), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC, I_POWER }, + { "srliq", D_OP(31)|D_XO(184), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC, I_POWER }, + { "srlq", D_OP(31)|D_XO(728), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "srq", D_OP(31)|D_XO(664), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWER }, + { "srw", D_OP(31)|D_XO(536), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_POWERPC }, + { "st", D_OP(36), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_POWER }, + { "stb", D_OP(38), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_COMMON }, + { "stbrx", D_OP(31)|D_XO(662), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWER }, + { "stbu", D_OP(39), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA, I_COMMON }, + { "stbux", D_OP(31)|D_XO(247), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA, I_COMMON }, + { "stbx", D_OP(31)|D_XO(215), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_COMMON }, + { "stfd", D_OP(54), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0, I_COMMON }, + { "stfdu", D_OP(55), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA, I_COMMON }, + { "stfdux", D_OP(31)|D_XO(759), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA, I_COMMON }, + { "stfdx", D_OP(31)|D_XO(727), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_COMMON }, + { "stfiwx", D_OP(31)|D_XO(983), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_POWERPC }, + { "stfs", D_OP(52), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0, I_COMMON }, + { "stfsu", D_OP(53), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA, I_COMMON }, + { "stfsux", D_OP(31)|D_XO(695), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA, I_COMMON }, + { "stfsx", D_OP(31)|D_XO(663), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_COMMON }, + { "sth", D_OP(44), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_COMMON }, + { "sthbrx", D_OP(31)|D_XO(918), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_COMMON }, + { "sthu", D_OP(45), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA, I_COMMON }, + { "sthux", D_OP(31)|D_XO(439), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA, I_COMMON }, + { "sthx", D_OP(31)|D_XO(407), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_COMMON }, + { "stm", D_OP(47), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_POWER }, + { "stmw", D_OP(47), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_POWERPC }, + { "stsi", D_OP(31)|D_XO(725), M_RT|M_RA|M_NB, F_RT_RA_0_NB, 0, I_POWER }, + { "stswi", D_OP(31)|D_XO(725), M_RT|M_RA|M_NB, F_RT_RA_0_NB, 0, I_POWERPC }, + { "stswx", D_OP(31)|D_XO(661), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "stsx", D_OP(31)|D_XO(661), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWER }, + { "stu", D_OP(37), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA, I_POWER }, + { "stux", D_OP(31)|D_XO(183), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA, I_POWER }, + { "stw", D_OP(36), M_RT|M_RA|M_D, F_RT_D_RA_0, 0, I_POWERPC }, + { "stwbrx", D_OP(31)|D_XO(662), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "stwcx.", D_OP(31)|D_XO(150)|1, M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "stwu", D_OP(37), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA, I_POWERPC }, + { "stwux", D_OP(31)|D_XO(183), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA, I_POWERPC }, + { "stwx", D_OP(31)|D_XO(151), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWERPC }, + { "stx", D_OP(31)|D_XO(151), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0, I_POWER }, + { "subf", D_OP(31)|D_XO(40), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "subfc", D_OP(31)|D_XO(8), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "subfe", D_OP(31)|D_XO(136), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC, I_POWERPC }, + { "subfic", D_OP(8), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0, I_POWERPC }, + { "subfme", D_OP(31)|D_XO(232), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWERPC }, + { "subfze", D_OP(31)|D_XO(200), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC, I_POWERPC }, + { "svc", D_OP(17)|2, M_BD|M_AA|M_LK, F_SC, FL_AA|FL_LK, I_POWER }, + { "sync", D_OP(31)|D_XO(598), 0, F_NONE, 0, I_POWERPC }, + { "t", D_OP(31)|D_XO(4), M_TO|M_RA|M_RB, F_TW, 0, I_POWER }, + { "ti", D_OP(3), M_TO|M_RA|M_SIMM, F_TWI, 0, I_POWER }, + { "tlbi", D_OP(31)|D_XO(306), M_RB, F_RB, 0, I_POWER }, + { "tlbia", D_OP(31)|D_XO(370), 0, F_NONE, 0, I_POWERPC }, + { "tlbie", D_OP(31)|D_XO(306), M_RB, F_RB, 0, I_POWERPC }, + { "tlbsync",D_OP(31)|D_XO(566), 0, F_NONE, 0, I_POWERPC }, + { "tw", D_OP(31)|D_XO(4), M_TO|M_RA|M_RB, F_TW, 0, I_POWERPC }, + { "twi", D_OP(3), M_TO|M_RA|M_SIMM, F_TWI, 0, I_POWERPC }, + { "wrtee", D_OP(31)|D_XO(131), M_RT, F_RT, 0, I_POWERPC }, + { "wrteei", D_OP(31)|D_XO(163), 0, 0, 0, I_POWERPC }, + { "xor", D_OP(31)|D_XO(316), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC, I_COMMON }, + { "xori", D_OP(26), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWERPC }, + { "xoril", D_OP(26), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWER }, + { "xoris", D_OP(27), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWERPC }, + { "xoriu", D_OP(27), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0, I_POWER }, /* * PowerPC 603e/EC603e-specific instructions */ - { "tlbld", D_OP(31)|D_XO(978), M_RB, F_RB, 0 }, - { "tlbli", D_OP(31)|D_XO(1010),M_RB, F_RB, 0 } + { "tlbld", D_OP(31)|D_XO(978), M_RB, F_RB, 0, I_POWERPC }, + { "tlbli", D_OP(31)|D_XO(1010),M_RB, F_RB, 0, I_POWERPC }, + + // POWER2 instructions + { "lfq", D_OP(56), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0, I_POWER }, + { "lfqu", D_OP(57), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0, I_POWER }, + { "lfqux", D_OP(31)|D_XO(823), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_POWER }, + { "lfqx", D_OP(31)|D_XO(791), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_POWER }, + { "stfq", D_OP(60), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0, I_POWER }, + { "stfqu", D_OP(61), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0, I_POWER }, + { "stfqux", D_OP(31)|D_XO(951), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_POWER }, + { "stfqx", D_OP(31)|D_XO(919), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0, I_POWER }, }; /* @@ -360,6 +472,12 @@ std::string powerpc_disassembler::SPR(int spr_field) case SPR4XX_PBL2: return "pbl2"; case SPR4XX_PBU2: return "pbu2"; + // POWER SPR indexes + case 0: return "mq"; + case 4: return "rtcu"; + case 5: return "rtcl"; + case 6: return "dec"; + default: return util::string_format("%d", spr); } } @@ -441,8 +559,8 @@ std::string powerpc_disassembler::DecodeSigned16(uint32_t op, int do_unsigned) int16_t s; s = G_SIMM(op); - if (do_unsigned) // sign extend to unsigned 32-bits - return util::string_format("0x%04X", (uint32_t) s); + if (do_unsigned) + return util::string_format("0x%04X", (uint16_t) s); else // print as signed 16 bits { if (s < 0) @@ -461,24 +579,11 @@ std::string powerpc_disassembler::DecodeSigned16(uint32_t op, int do_unsigned) * Generate a mask from bit MB through ME (PPC-style backwards bit numbering.) */ -uint32_t powerpc_disassembler::Mask(int mb, int me) +uint32_t powerpc_disassembler::Mask(unsigned const mb, unsigned const me) { - uint32_t i, mask; - - mb &= 31; - me &= 31; - - i = mb; - mask = 0; - while (1) - { - mask |= (1 << (31 - i)); - if (i == me) - break; - i = (i + 1) & 31; - } - - return mask; + return (mb > me) ? + (0xffffffffU >> mb) | (0xffffffffU << (31 - me)) : + (0xffffffffU >> mb) & (0xffffffffU << (31 - me)); } /* @@ -488,7 +593,7 @@ uint32_t powerpc_disassembler::Mask(int mb, int me) * otherwise false to indicate disassembly should carry on as normal. */ -bool powerpc_disassembler::Simplified(uint32_t op, uint32_t vpc, std::string &signed16, std::string &mnem, std::string &oprs) +bool powerpc_disassembler::Simplified(uint32_t op, uint32_t vpc, std::string &signed16, std::string &mnem, std::string &oprs, offs_t &flags) { uint32_t value, disp; @@ -558,35 +663,11 @@ bool powerpc_disassembler::Simplified(uint32_t op, uint32_t vpc, std::string &si mnem += "xori"; // xoris rA,rT,UIMM -> xori rA,rT,UIMM<<16 oprs = util::string_format("r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16); } - else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(20)) - { - value = Mask(G_MB(op), G_ME(op)); - mnem += "rlwimi"; // rlwimi[.] rA,rT,SH,MB,ME -> rlwimi[.] rA,rT,SH,MASK - if (op & M_RC) mnem += "."; - oprs = util::string_format("r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), value); - } - else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(21)) - { - value = Mask(G_MB(op), G_ME(op)); - if (G_SH(op) == 0) // rlwinm[.] rA,rT,0,MB,ME -> and[.] rA,rT,MASK - { - mnem += "and"; - if (op & M_RC) mnem += "."; - oprs = util::string_format("r%d,r%d,0x%08X", G_RA(op), G_RT(op), value); - } - else // rlwinm[.] rA,rT,SH,MASK - { - mnem += "rlwinm"; - if (op & M_RC) mnem += "."; - oprs = util::string_format("r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), value); - } - } - else if ((op & ~(M_RT|M_RA|M_RB|M_MB|M_ME|M_RC)) == D_OP(23)) + else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(21) && G_SH(op) == 0) { - value = Mask(G_MB(op), G_ME(op)); - mnem += "rlwnm"; // rlwnm[.] rA,rT,SH,MB,ME -> rlwnm[.] rA,rT,SH,MASK + mnem += "and"; // rl[w]inm[.] rA,rT,0,MB,ME -> and[.] rA,rT,MASK if (op & M_RC) mnem += "."; - oprs = util::string_format("r%d,r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_RB(op), value); + oprs = util::string_format("r%d,r%d,0x%08X", G_RA(op), G_RT(op), Mask(G_MB(op), G_ME(op))); } else if ((op & ~(M_BO|M_BI|M_BD|M_AA|M_LK)) == D_OP(16)) { @@ -599,16 +680,20 @@ bool powerpc_disassembler::Simplified(uint32_t op, uint32_t vpc, std::string &si case 0x04: case 0x05: case 0x06: case 0x07: mnem += "b"; mnem += crnbit[G_BI(op) & 3]; + flags |= STEP_COND; break; case 0x0c: case 0x0d: case 0x0e: case 0x0f: mnem += "b"; mnem += crbit[G_BI(op) & 3]; + flags |= STEP_COND; break; case 0x10: case 0x11: case 0x18: case 0x19: mnem += "bdnz"; + flags |= STEP_COND; break; case 0x12: case 0x13: case 0x1a: case 0x1b: mnem += "bdz"; + flags |= STEP_COND; break; case 0x14: case 0x15: case 0x16: case 0x17: case 0x1c: case 0x1d: case 0x1e: case 0x1f: @@ -618,7 +703,11 @@ bool powerpc_disassembler::Simplified(uint32_t op, uint32_t vpc, std::string &si return false; } - if (op & M_LK) mnem += "l"; + if (op & M_LK) + { + mnem += "l"; + flags |= STEP_OVER; + } if (op & M_AA) mnem += "a"; if (!(G_BO(op) & 0x10) && G_BI(op) / 4 != 0) @@ -633,16 +722,20 @@ bool powerpc_disassembler::Simplified(uint32_t op, uint32_t vpc, std::string &si case 0x04: case 0x05: case 0x06: case 0x07: mnem += "b"; mnem += crnbit[G_BI(op) & 3]; + flags |= STEP_COND; break; case 0x0c: case 0x0d: case 0x0e: case 0x0f: mnem += "b"; mnem += crbit[G_BI(op) & 3]; + flags |= STEP_COND; break; case 0x10: case 0x11: case 0x18: case 0x19: mnem += "bdnz"; + flags |= STEP_COND; break; case 0x12: case 0x13: case 0x1a: case 0x1b: mnem += "bdz"; + flags |= STEP_COND; break; case 0x14: case 0x15: case 0x16: case 0x17: case 0x1c: case 0x1d: case 0x1e: case 0x1f: @@ -652,8 +745,19 @@ bool powerpc_disassembler::Simplified(uint32_t op, uint32_t vpc, std::string &si return false; } - mnem += (G_XO(op) == 528) ? "ctr" : "lr"; - if (op & M_LK) mnem += "l"; + if (G_XO(op) == 528) + mnem += "ctr"; + else + { + mnem += "lr"; + if (!(op & M_LK)) + flags |= STEP_OUT; + } + if (op & M_LK) + { + mnem += "l"; + flags |= STEP_OVER; + } if (op & M_AA) mnem += "a"; if (!(G_BO(op) & 0x10) && G_BI(op) / 4 != 0) @@ -696,7 +800,7 @@ offs_t powerpc_disassembler::dasm_one(std::ostream &stream, uint32_t pc, uint32_ * Try simplified forms first, then real instructions */ - if( Simplified(op, pc, signed16, mnem, oprs) ) { + if( Simplified(op, pc, signed16, mnem, oprs, flags) ) { util::stream_format(stream, "%s", mnem); for( j = mnem.size(); j < 10; j++ ) { util::stream_format(stream, " "); @@ -711,7 +815,7 @@ offs_t powerpc_disassembler::dasm_one(std::ostream &stream, uint32_t pc, uint32_ for (i = 0; i < sizeof(itab) / sizeof(IDESCR); i++) { - if ((op & ~itab[i].mask) == itab[i].match) // check for match + if ((itab[i].implementation & m_implementation) && (op & ~itab[i].mask) == itab[i].match) // check for match { /* * Base mnemonic followed be O, ., L, A @@ -764,21 +868,19 @@ offs_t powerpc_disassembler::dasm_one(std::ostream &stream, uint32_t pc, uint32_ break; case F_LI: - disp = G_LI(op) * 4; - if (disp & 0x02000000) // sign extend - disp |= 0xfc000000; + disp = util::sext(G_LI(op) * 4, 26); oprs = util::string_format("0x%08X", disp + ((op & M_AA) ? 0 : pc)); break; case F_BCx: - disp = G_BD(op) * 4; - if (disp & 0x00008000) - disp |= 0xffff0000; + disp = util::sext(G_BD(op) * 4, 16); if (G_BO(op) & 0x10) // BI is ignored (don't print CR bit) oprs = util::string_format("0x%02X,%d,0x%08X", G_BO(op), G_BI(op), disp + ((op & M_AA) ? 0 : pc)); else // BI gives us the condition bit oprs = util::string_format("0x%02X,cr%d[%s],0x%08X", G_BO(op), G_BI(op) / 4, crbit[G_BI(op) & 3], disp + ((op & M_AA) ? 0 : pc)); + if ((G_BO(op) & 0x14) != 0x14) + flags |= STEP_COND; break; case F_BO_BI: @@ -786,6 +888,8 @@ offs_t powerpc_disassembler::dasm_one(std::ostream &stream, uint32_t pc, uint32_ oprs = util::string_format("0x%02X,%d", G_BO(op), G_BI(op)); else oprs = util::string_format("0x%02X,cr%d[%s]", G_BO(op), G_BI(op) / 4, crbit[G_BI(op) & 3]); + if ((G_BO(op) & 0x14) != 0x14) + flags |= STEP_COND; break; case F_CMP: @@ -958,11 +1062,11 @@ offs_t powerpc_disassembler::dasm_one(std::ostream &stream, uint32_t pc, uint32_ break; case F_RA_RT_SH_MB_ME: - oprs = util::string_format("r%d,r%d,%d,%d,%d", G_RA(op), G_RT(op), G_SH(op), G_MB(op), G_ME(op)); + oprs = util::string_format("r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), Mask(G_MB(op), G_ME(op))); break; - case F_RLWNMx: - oprs = util::string_format("r%d,r%d,r%d,%d,%d", G_RA(op), G_RT(op), G_RB(op), G_MB(op), G_ME(op)); + case F_RA_RT_RB_MB_ME: + oprs = util::string_format("r%d,r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_RB(op), Mask(G_MB(op), G_ME(op))); break; case F_SRAWIx: @@ -981,7 +1085,18 @@ offs_t powerpc_disassembler::dasm_one(std::ostream &stream, uint32_t pc, uint32_ oprs = util::string_format("%d,r%d,%s", G_TO(op), G_RA(op), signed16); break; + case F_SC: + if (op & M_AA) + oprs = util::string_format("0x%04X", (op & 0x0000fffc) >> 2); + else + oprs = util::string_format("%d,%d,%d", (op & 0x00000fe0) >> 5, (op & 0x0000f000) >> 12, (op & 0x0000001c) >> 2); + break; + case F_NONE: + if ((op >> 26) == 17) // SC (PowerPC) + flags |= STEP_OVER; + [[fallthrough]]; + default: break; } diff --git a/src/devices/cpu/powerpc/ppc_dasm.h b/src/devices/cpu/powerpc/ppc_dasm.h index 5fab7dfe074..1f5ff6dba00 100644 --- a/src/devices/cpu/powerpc/ppc_dasm.h +++ b/src/devices/cpu/powerpc/ppc_dasm.h @@ -20,15 +20,25 @@ #pragma once + class powerpc_disassembler : public util::disasm_interface { public: - powerpc_disassembler() = default; + enum implementation : int + { + I_POWER = 1 << 0, + I_POWERPC = 1 << 1, + }; + + powerpc_disassembler(implementation impl = I_POWERPC) + : m_implementation(impl) + { + }; virtual ~powerpc_disassembler() = default; virtual u32 opcode_alignment() const override; virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; - static offs_t dasm_one(std::ostream &stream, uint32_t pc, uint32_t op); + offs_t dasm_one(std::ostream &stream, uint32_t pc, uint32_t op); private: /* @@ -91,8 +101,9 @@ private: F_FRT_FRA_FRB, // frT, frA, frB F_FRT_FRA_FRC, // frT, frA, frC F_RA_RT_SH_MB_ME, // rA, rT, SH, MB, ME - F_RLWNMx, // rT, rA, rB, MB, ME only used by RLWNMx - F_RT_RB // rT, rB + F_RA_RT_RB_MB_ME, // rA, rT, rB, MB, ME + F_RT_RB, // rT, rB + F_SC // LEV, FL1, FL2 or SV only used by SVC (POWER) }; /* @@ -126,6 +137,7 @@ private: // bit pattern to determine a match) int format; // operand format int flags; // flags + int implementation; }; static const IDESCR itab[]; @@ -135,8 +147,19 @@ private: static std::string SPR(int spr_field); static std::string DCR(int dcr_field); static std::string DecodeSigned16(uint32_t op, int do_unsigned); - static uint32_t Mask(int mb, int me); - static bool Simplified(uint32_t op, uint32_t vpc, std::string &signed16, std::string &mnem, std::string &oprs); + static uint32_t Mask(unsigned const mb, unsigned const me); + bool Simplified(uint32_t op, uint32_t vpc, std::string &signed16, std::string &mnem, std::string &oprs, offs_t &flags); + + implementation const m_implementation; +}; + +class power_disassembler : public powerpc_disassembler +{ +public: + power_disassembler() + : powerpc_disassembler(implementation::I_POWER) + { + }; }; #endif diff --git a/src/devices/cpu/powerpc/ppccom.cpp b/src/devices/cpu/powerpc/ppccom.cpp index 4a8a071f903..4e76a3efbb2 100644 --- a/src/devices/cpu/powerpc/ppccom.cpp +++ b/src/devices/cpu/powerpc/ppccom.cpp @@ -205,6 +205,8 @@ DEFINE_DEVICE_TYPE(MPC8240, mpc8240_device, "mpc8240", "IBM PowerPC MPC82 DEFINE_DEVICE_TYPE(PPC403GA, ppc403ga_device, "ppc403ga", "IBM PowerPC 403GA") DEFINE_DEVICE_TYPE(PPC403GCX, ppc403gcx_device, "ppc403gcx", "IBM PowerPC 403GCX") DEFINE_DEVICE_TYPE(PPC405GP, ppc405gp_device, "ppc405gp", "IBM PowerPC 405GP") +DEFINE_DEVICE_TYPE(PPC740, ppc740_device, "ppc740", "IBM PowerPC 740") +DEFINE_DEVICE_TYPE(PPC750, ppc750_device, "ppc750", "IBM PowerPC 750") ppc_device::ppc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int address_bits, int data_bits, powerpc_flavor flavor, uint32_t cap, uint32_t tb_divisor, address_map_constructor internal_map) @@ -212,15 +214,23 @@ ppc_device::ppc_device(const machine_config &mconfig, device_type type, const ch , device_vtlb_interface(mconfig, *this, AS_PROGRAM) , m_program_config("program", ENDIANNESS_BIG, data_bits, address_bits, 0, internal_map) , c_bus_frequency(0) + , c_serial_clock(0) , m_core(nullptr) , m_bus_freq_multiplier(1) , m_flavor(flavor) , m_cap(cap) , m_tb_divisor(tb_divisor) + , m_spu(*this) + , m_dcr_read_func(*this) + , m_dcr_write_func(*this) + , m_dcstore_cb(*this) + , m_ext_dma_read_cb(*this) + , m_ext_dma_write_cb(*this) , m_cache(CACHE_SIZE + sizeof(internal_ppc_state)) , m_drcuml(nullptr) , m_drcfe(nullptr) , m_drcoptions(0) + , m_dasm(powerpc_disassembler()) { m_program_config.m_logaddr_width = 32; m_program_config.m_page_shift = POWERPC_MIN_PAGE_SHIFT; @@ -271,15 +281,31 @@ mpc8240_device::mpc8240_device(const machine_config &mconfig, const char *tag, d } ppc601_device::ppc601_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : ppc_device(mconfig, PPC601, tag, owner, clock, 32, 64, PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_MFIOC | PPCCAP_601BAT, 0/* no TB */, address_map_constructor()) + : ppc_device(mconfig, PPC601, tag, owner, clock, 32, 64, PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_MFIOC | PPCCAP_601BAT | PPCCAP_LEGACY_POWER, 0 /* no TB */, address_map_constructor()) { } +std::unique_ptr<util::disasm_interface> ppc601_device::create_disassembler() +{ + // 601 has both POWER and PowerPC instructions + return std::make_unique<powerpc_disassembler>((powerpc_disassembler::implementation)(powerpc_disassembler::I_POWER|powerpc_disassembler::I_POWERPC)); +} + ppc604_device::ppc604_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppc_device(mconfig, PPC604, tag, owner, clock, 32, 64, PPC_MODEL_604, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU, 4, address_map_constructor()) { } +ppc740_device::ppc740_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ppc_device(mconfig, PPC740, tag, owner, clock, 32, 64, PPC_MODEL_740, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU | PPCCAP_750_TLB , 4, address_map_constructor()) +{ +} + +ppc750_device::ppc750_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ppc_device(mconfig, PPC750, tag, owner, clock, 32, 64, PPC_MODEL_750, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU | PPCCAP_750_TLB, 4, address_map_constructor()) +{ +} + void ppc4xx_device::internal_ppc4xx(address_map &map) { map(0x40000000, 0x4000000f).rw(FUNC(ppc4xx_device::ppc4xx_spu_r), FUNC(ppc4xx_device::ppc4xx_spu_w)); @@ -326,9 +352,9 @@ device_memory_interface::space_config_vector ppc_device::memory_space_config() c static inline bool page_access_allowed(int transtype, uint8_t key, uint8_t protbits) { if (key == 0) - return (transtype == TRANSLATE_WRITE) ? (protbits != 3) : true; + return (transtype == device_memory_interface::TR_WRITE) ? (protbits != 3) : true; else - return (transtype == TRANSLATE_WRITE) ? (protbits == 2) : (protbits != 0); + return (transtype == device_memory_interface::TR_WRITE) ? (protbits == 2) : (protbits != 0); } @@ -449,9 +475,9 @@ inline void ppc_device::set_decrementer(uint32_t newdec) if (PRINTF_DECREMENTER) { uint64_t total = total_cycles(); - osd_printf_debug("set_decrementer: olddec=%08X newdec=%08X divisor=%d totalcyc=%08X%08X timer=%08X%08X\n", + osd_printf_debug("set_decrementer: olddec=%08X newdec=%08X divisor=%d totalcyc=%016X timer=%016X\n", curdec, newdec, m_tb_divisor, - (uint32_t)(total >> 32), (uint32_t)total, (uint32_t)(cycles_until_done >> 32), (uint32_t)cycles_until_done); + total, cycles_until_done); } m_dec_zero_cycles = total_cycles() + cycles_until_done; @@ -485,8 +511,7 @@ static inline int is_qnan_double(double x) { uint64_t xi = *(uint64_t*)&x; return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && - ((xi & 0x0007fffffffffffU) == 0x000000000000000U) && - ((xi & 0x000800000000000U) == 0x000800000000000U) ); + ((xi & 0x0008000000000000U) == 0x0008000000000000U) ); } @@ -694,7 +719,7 @@ void ppc_device::device_start() m_sebr = 0; m_ser = 0; - memset(&m_spu, 0, sizeof(m_spu)); + m_spu.clear(); m_pit_reload = 0; m_irqstate = 0; memset(m_buffered_dma_rate, 0, sizeof(m_buffered_dma_rate)); @@ -702,6 +727,7 @@ void ppc_device::device_start() m_cpu_clock = 0; m_tb_zero_cycles = 0; m_dec_zero_cycles = 0; + m_rtc_zero_cycles = 0; m_arg1 = 0; m_fastram_select = 0; @@ -711,58 +737,64 @@ void ppc_device::device_start() m_debugger_temp = 0; + m_serial_clock = 0; + m_cache_line_size = 32; m_cpu_clock = clock(); m_program = &space(AS_PROGRAM); if(m_cap & PPCCAP_4XX) { - auto cache = m_program->cache<2, 0, ENDIANNESS_BIG>(); - m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; - m_prptr = [cache](offs_t address) -> const void * { return cache->read_ptr(address); }; + m_program->cache(m_cache32); + m_pr32 = [this](offs_t address) -> u32 { return m_cache32.read_dword(address); }; + m_prptr = [this](offs_t address) -> const void * { return m_cache32.read_ptr(address); }; } else { - auto cache = m_program->cache<3, 0, ENDIANNESS_BIG>(); - m_pr32 = [cache](offs_t address) -> u32 { return cache->read_dword(address); }; + m_program->cache(m_cache64); + m_pr32 = [this](offs_t address) -> u32 { return m_cache64.read_dword(address); }; if(space_config()->m_endianness != ENDIANNESS_NATIVE) - m_prptr = [cache](offs_t address) -> const void * { - const u32 *ptr = static_cast<u32 *>(cache->read_ptr(address & ~7)); + m_prptr = [this](offs_t address) -> const void * { + const u32 *ptr = static_cast<u32 *>(m_cache64.read_ptr(address & ~7)); if(!(address & 4)) ptr++; return ptr; }; else - m_prptr = [cache](offs_t address) -> const void * { - const u32 *ptr = static_cast<u32 *>(cache->read_ptr(address & ~7)); + m_prptr = [this](offs_t address) -> const void * { + const u32 *ptr = static_cast<u32 *>(m_cache64.read_ptr(address & ~7)); if(address & 4) ptr++; return ptr; }; } m_system_clock = c_bus_frequency != 0 ? c_bus_frequency : clock(); - m_dcr_read_func = read32_delegate(); - m_dcr_write_func = write32_delegate(); + m_dcr_read_func.set(nullptr); + m_dcr_write_func.set(nullptr); m_tb_divisor = (m_tb_divisor * clock() + m_system_clock / 2 - 1) / m_system_clock; + m_serial_clock = c_serial_clock != 0 ? c_serial_clock : 3'686'400; // TODO: get rid of this hard-coded magic number + if (m_serial_clock > m_system_clock / 2) + fatalerror("%s: PPC: serial clock (%d) must not be more than half of the system clock (%d)\n", tag(), m_serial_clock, m_system_clock); + /* allocate a timer for the compare interrupt */ if ((m_cap & PPCCAP_OEA) && (m_tb_divisor)) - m_decrementer_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::decrementer_int_callback), this)); + m_decrementer_int_timer = timer_alloc(FUNC(ppc_device::decrementer_int_callback), this); /* and for the 4XX interrupts if needed */ if (m_cap & PPCCAP_4XX) { - m_fit_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_fit_callback), this)); - m_pit_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_pit_callback), this)); - m_spu.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_spu_callback), this)); + m_fit_timer = timer_alloc(FUNC(ppc_device::ppc4xx_fit_callback), this); + m_pit_timer = timer_alloc(FUNC(ppc_device::ppc4xx_pit_callback), this); + m_spu.timer = timer_alloc(FUNC(ppc_device::ppc4xx_spu_callback), this); } if (m_cap & PPCCAP_4XX) { - m_buffered_dma_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); - m_buffered_dma_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); - m_buffered_dma_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); - m_buffered_dma_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); + m_buffered_dma_timer[0] = timer_alloc(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this); + m_buffered_dma_timer[1] = timer_alloc(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this); + m_buffered_dma_timer[2] = timer_alloc(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this); + m_buffered_dma_timer[3] = timer_alloc(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this); m_buffered_dma_rate[0] = 10000; m_buffered_dma_rate[1] = 10000; @@ -806,6 +838,11 @@ void ppc_device::device_start() state_add(PPC_PC, "PC", m_core->pc).formatstr("%08X"); state_add(PPC_MSR, "MSR", m_core->msr).formatstr("%08X"); state_add(PPC_CR, "CR", m_debugger_temp).callimport().callexport().formatstr("%08X"); + // If the legacy POWER instructions exist, that implies MQ is used and should be shown + if (m_cap & PPCCAP_LEGACY_POWER) + { + state_add(PPC_MQ, "MQ", m_core->spr[SPR601_MQ]).formatstr("%08X"); + } state_add(PPC_LR, "LR", m_core->spr[SPR_LR]).formatstr("%08X"); state_add(PPC_CTR, "CTR", m_core->spr[SPR_CTR]).formatstr("%08X"); state_add(PPC_XER, "XER", m_debugger_temp).callimport().callexport().formatstr("%08X"); @@ -836,7 +873,6 @@ void ppc_device::device_start() state_add(STATE_GENPC, "GENPC", m_core->pc).noshow(); state_add(STATE_GENPCBASE, "CURPC", m_core->pc).noshow(); - state_add(STATE_GENSP, "GENSP", m_core->r[31]).noshow(); state_add(STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).noshow().formatstr("%1s"); set_icountptr(m_core->icount); @@ -851,15 +887,15 @@ void ppc_device::device_start() for (int regnum = 0; regnum < 32; regnum++) { char buf[10]; - sprintf(buf, "r%d", regnum); + snprintf(buf, 10, "r%d", regnum); m_drcuml->symbol_add(&m_core->r[regnum], sizeof(m_core->r[regnum]), buf); - sprintf(buf, "fpr%d", regnum); + snprintf(buf, 10, "fpr%d", regnum); m_drcuml->symbol_add(&m_core->f[regnum], sizeof(m_core->f[regnum]), buf); } for (int regnum = 0; regnum < 8; regnum++) { char buf[10]; - sprintf(buf, "cr%d", regnum); + snprintf(buf, 10, "cr%d", regnum); m_drcuml->symbol_add(&m_core->cr[regnum], sizeof(m_core->cr[regnum]), buf); } m_drcuml->symbol_add(&m_core->xerso, sizeof(m_core->xerso), "xerso"); @@ -1144,7 +1180,7 @@ void ppc_device::device_reset() m_dec_zero_cycles = total_cycles(); if (m_tb_divisor) { - decrementer_int_callback(nullptr, 0); + decrementer_int_callback(0); } } @@ -1195,7 +1231,7 @@ void ppc_device::device_reset() std::unique_ptr<util::disasm_interface> ppc_device::create_disassembler() { - return std::make_unique<powerpc_disassembler>(); + return std::make_unique<powerpc_disassembler>(powerpc_disassembler::I_POWERPC); } @@ -1208,7 +1244,7 @@ void ppc_device::ppccom_dcstore_callback() { if (!m_dcstore_cb.isnull()) { - m_dcstore_cb(*m_program, m_core->param0, 0, 0xffffffff); + m_dcstore_cb(m_core->param0, 0); } } @@ -1224,10 +1260,10 @@ void ppc_device::ppccom_dcstore_callback() filling -------------------------------------------------*/ -uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &address) +uint32_t ppc_device::ppccom_translate_address_internal(int intention, bool debug, offs_t &address) { - int transpriv = ((intention & TRANSLATE_USER_MASK) == 0); // 1 for supervisor, 0 for user - int transtype = intention & TRANSLATE_TYPE_MASK; + int transpriv = ((intention & TR_USER) == 0); // 1 for supervisor, 0 for user + int transtype = intention & TR_TYPE; offs_t hash, hashbase, hashmask; int batbase, batnum, hashnum; uint32_t segreg; @@ -1240,7 +1276,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad fatalerror("MMU enabled but not supported!\n"); /* only check if PE is enabled */ - if (transtype == TRANSLATE_WRITE && (m_core->msr & MSR4XX_PE)) + if (transtype == TR_WRITE && (m_core->msr & MSR4XX_PE)) { /* are we within one of the protection ranges? */ int inrange1 = ((address >> 12) >= (m_core->spr[SPR4XX_PBL1] >> 12) && (address >> 12) < (m_core->spr[SPR4XX_PBU1] >> 12)); @@ -1259,7 +1295,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad return 0x001; /* also no translation necessary if translation is disabled */ - if ((transtype == TRANSLATE_FETCH && (m_core->msr & MSROEA_IR) == 0) || (transtype != TRANSLATE_FETCH && (m_core->msr & MSROEA_DR) == 0)) + if ((transtype == TR_FETCH && (m_core->msr & MSROEA_IR) == 0) || (transtype != TR_FETCH && (m_core->msr & MSROEA_DR) == 0)) return 0x001; /* first scan the appropriate BAT */ @@ -1269,9 +1305,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad { uint32_t upper = m_core->spr[SPROEA_IBAT0U + 2*batnum + 0]; uint32_t lower = m_core->spr[SPROEA_IBAT0U + 2*batnum + 1]; - int privbit = ((intention & TRANSLATE_USER_MASK) == 0) ? 3 : 2; - -// printf("bat %d upper = %08x privbit %d\n", batnum, upper, privbit); + int privbit = ((intention & TR_USER) == 0) ? 3 : 2; // is this pair valid? if (lower & 0x40) @@ -1286,7 +1320,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad /* verify protection; if we fail, return false and indicate a protection violation */ if (!page_access_allowed(transtype, key, upper & 3)) { - return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_PROTECTED | ((transtype == TR_WRITE) ? DSISR_STORE : 0); } /* otherwise we're good */ @@ -1299,7 +1333,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad } else { - batbase = (transtype == TRANSLATE_FETCH) ? SPROEA_IBAT0U : SPROEA_DBAT0U; + batbase = (transtype == TR_FETCH) ? SPROEA_IBAT0U : SPROEA_DBAT0U; for (batnum = 0; batnum < 4; batnum++) { @@ -1318,7 +1352,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad /* verify protection; if we fail, return false and indicate a protection violation */ if (!page_access_allowed(transtype, 1, lower & 3)) { - return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_PROTECTED | ((transtype == TR_WRITE) ? DSISR_STORE : 0); } /* otherwise we're good */ @@ -1340,13 +1374,13 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad /* look up the segment register */ segreg = m_core->sr[address >> 28]; - if (transtype == TRANSLATE_FETCH && (segreg & 0x10000000)) - return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + if (transtype == TR_FETCH && (segreg & 0x10000000)) + return DSISR_PROTECTED | ((transtype == TR_WRITE) ? DSISR_STORE : 0); /* check for memory-forced I/O */ if (m_cap & PPCCAP_MFIOC) { - if ((transtype != TRANSLATE_FETCH) && ((segreg & 0x87f00000) == 0x87f00000)) + if ((transtype != TR_FETCH) && ((segreg & 0x87f00000) == 0x87f00000)) { address = ((segreg & 0xf)<<28) | (address & 0x0fffffff); return 1; @@ -1369,12 +1403,12 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad m_core->mmu603_cmp = 0x80000000 | ((segreg & 0xffffff) << 7) | (0 << 6) | ((address >> 22) & 0x3f); m_core->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask); m_core->mmu603_hash[1] = hashbase | ((~hash << 6) & hashmask); - if ((entry & (VTLB_FLAG_FIXED | VTLB_FLAG_VALID)) == (VTLB_FLAG_FIXED | VTLB_FLAG_VALID)) + if ((entry & (FLAG_FIXED | FLAG_VALID)) == (FLAG_FIXED | FLAG_VALID)) { address = (entry & 0xfffff000) | (address & 0x00000fff); return 0x001; } - return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_NOT_FOUND | ((transtype == TR_WRITE) ? DSISR_STORE : 0); } /* loop twice over hashes */ @@ -1397,13 +1431,13 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad /* verify protection; if we fail, return false and indicate a protection violation */ if (!page_access_allowed(transtype, (segreg >> (29 + transpriv)) & 1, pteglower & 3)) - return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_PROTECTED | ((transtype == TR_WRITE) ? DSISR_STORE : 0); /* update page table bits */ - if (!(intention & TRANSLATE_DEBUG_MASK)) + if (!debug) { pteglower |= 0x100; - if (transtype == TRANSLATE_WRITE) + if (transtype == TR_WRITE) pteglower |= 0x080; ptegptr[BYTE_XOR_BE(ptenum * 2 + 1)] = pteglower; } @@ -1419,7 +1453,7 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad } /* we failed to find any match: not found */ - return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + return DSISR_NOT_FOUND | ((transtype == TR_WRITE) ? DSISR_STORE : 0); } @@ -1428,14 +1462,16 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad from logical to physical -------------------------------------------------*/ -bool ppc_device::memory_translate(int spacenum, int intention, offs_t &address) +bool ppc_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) { + target_space = &space(spacenum); + /* only applies to the program address space */ if (spacenum != AS_PROGRAM) return true; /* translation is successful if the internal routine returns 0 or 1 */ - return (ppccom_translate_address_internal(intention, address) <= 1); + return (ppccom_translate_address_internal(intention, true, address) <= 1); } @@ -1445,7 +1481,10 @@ bool ppc_device::memory_translate(int spacenum, int intention, offs_t &address) void ppc_device::ppccom_tlb_fill() { - vtlb_fill(m_core->param0, m_core->param1); + offs_t address = m_core->param0; + if(ppccom_translate_address_internal(m_core->param1, false, address) > 1) + return; + vtlb_fill(m_core->param0, address, m_core->param1); } @@ -1476,14 +1515,14 @@ void ppc_device::ppccom_get_dsisr() if (m_core->param1 & 1) { - intent = TRANSLATE_WRITE; + intent = TR_WRITE; } else { - intent = TRANSLATE_READ; + intent = TR_READ; } - m_core->param1 = ppccom_translate_address_internal(intent, m_core->param0); + m_core->param1 = ppccom_translate_address_internal(intent, false, m_core->param0); } /*------------------------------------------------- @@ -1527,11 +1566,11 @@ void ppc_device::ppccom_execute_tlbl() entrynum = ((address >> 12) & 0x1f) | (machine().rand() & 0x20) | (isitlb ? 0x40 : 0); /* determine the flags */ - flags = VTLB_FLAG_VALID | VTLB_READ_ALLOWED | VTLB_FETCH_ALLOWED; + flags = FLAG_VALID | READ_ALLOWED | FETCH_ALLOWED; if (m_core->spr[SPR603_RPA] & 0x80) - flags |= VTLB_WRITE_ALLOWED; + flags |= WRITE_ALLOWED; if (isitlb) - flags |= VTLB_FETCH_ALLOWED; + flags |= FETCH_ALLOWED; /* load the entry */ vtlb_load(entrynum, 1, address, (m_core->spr[SPR603_RPA] & 0xfffff000) | flags); @@ -1604,6 +1643,29 @@ void ppc_device::ppccom_execute_mfspr() } } + /* handle 601 specific SPRs (POWER holdovers) */ + if (m_flavor == PPC_MODEL_601) + { + switch (m_core->param0) + { + case SPR601_PWRDEC: + m_core->param1 = get_decrementer(); + return; + + case SPR601_RTCUR_PWR: + m_core->param1 = (total_cycles() - m_rtc_zero_cycles) / clock(); + return; + + case SPR601_RTCLR_PWR: + { + const uint64_t remainder = (total_cycles() - m_rtc_zero_cycles) % clock(); + const double seconds = remainder / clock(); // get fractional seconds + m_core->param1 = (uint64_t)(seconds * 1'000'000'000); // and convert to nanoseconds + } + return; + } + } + /* handle 602 SPRs */ if (m_flavor == PPC_MODEL_602) { // TODO: Which are read/write only? @@ -1747,6 +1809,21 @@ void ppc_device::ppccom_execute_mtspr() } } + /* handle 601 specific POWER-holdover SPRs */ + if (m_flavor == PPC_MODEL_601) + { + switch (m_core->param0) + { + case SPR601_MQ: + m_core->spr[m_core->param0] = m_core->param1; + return; + + case SPR601_RTCUW_PWR: + m_rtc_zero_cycles = total_cycles(); + break; + } + } + /* handle 602 SPRs */ if (m_flavor == PPC_MODEL_602) { @@ -1828,9 +1905,9 @@ void ppc_device::ppccom_execute_mtspr() case SPR4XX_TCR: m_core->spr[SPR4XX_TCR] = m_core->param1 | (oldval & PPC4XX_TCR_WRC_MASK); if ((oldval ^ m_core->spr[SPR4XX_TCR]) & PPC4XX_TCR_FIE) - ppc4xx_fit_callback(nullptr, false); + ppc4xx_fit_callback(false); if ((oldval ^ m_core->spr[SPR4XX_TCR]) & PPC4XX_TCR_PIE) - ppc4xx_pit_callback(nullptr, false); + ppc4xx_pit_callback(false); return; /* timer status register */ @@ -1843,7 +1920,7 @@ void ppc_device::ppccom_execute_mtspr() case SPR4XX_PIT: m_core->spr[SPR4XX_PIT] = m_core->param1; m_pit_reload = m_core->param1; - ppc4xx_pit_callback(nullptr, false); + ppc4xx_pit_callback(false); return; /* timebase */ @@ -1913,12 +1990,12 @@ void ppc_device::ppccom_execute_mfdcr() /* default handling */ if (m_dcr_read_func.isnull()) { osd_printf_debug("DCR %03X read\n", m_core->param0); - if (m_core->param0 < ARRAY_LENGTH(m_dcr)) + if (m_core->param0 < std::size(m_dcr)) m_core->param1 = m_dcr[m_core->param0]; else m_core->param1 = 0; } else { - m_core->param1 = m_dcr_read_func(*m_program,m_core->param0,0xffffffff); + m_core->param1 = m_dcr_read_func(m_core->param0); } } @@ -2005,10 +2082,10 @@ void ppc_device::ppccom_execute_mtdcr() /* default handling */ if (m_dcr_write_func.isnull()) { osd_printf_debug("DCR %03X write = %08X\n", m_core->param0, m_core->param1); - if (m_core->param0 < ARRAY_LENGTH(m_dcr)) + if (m_core->param0 < std::size(m_dcr)) m_dcr[m_core->param0] = m_core->param1; } else { - m_dcr_write_func(*m_program,m_core->param0,m_core->param1,0xffffffff); + m_dcr_write_func(m_core->param0,m_core->param1); } } @@ -2093,7 +2170,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::decrementer_int_callback ) for detecting datacache stores with dcbst -------------------------------------------------*/ -void ppc_device::ppc_set_dcstore_callback(write32_delegate callback) +void ppc_device::ppc_set_dcstore_callback(write32sm_delegate callback) { m_dcstore_cb = callback; } @@ -2365,7 +2442,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_buffered_dma_callback ) { uint8_t data = m_program->read_byte(dmaregs[DCR4XX_DMADA0]); if (!m_ext_dma_write_cb[dmachan].isnull()) - (m_ext_dma_write_cb[dmachan])(*m_program, 1, data, 0xffffffff); + (m_ext_dma_write_cb[dmachan])(1, data); dmaregs[DCR4XX_DMADA0] += destinc; } while (!ppc4xx_dma_decrement_count(dmachan)); break; @@ -2376,7 +2453,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_buffered_dma_callback ) { uint16_t data = m_program->read_word(dmaregs[DCR4XX_DMADA0]); if (!m_ext_dma_write_cb[dmachan].isnull()) - (m_ext_dma_write_cb[dmachan])(*m_program, 2, data, 0xffffffff); + (m_ext_dma_write_cb[dmachan])(2, data); dmaregs[DCR4XX_DMADA0] += destinc; } while (!ppc4xx_dma_decrement_count(dmachan)); break; @@ -2387,7 +2464,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_buffered_dma_callback ) { uint32_t data = m_program->read_dword(dmaregs[DCR4XX_DMADA0]); if (!m_ext_dma_write_cb[dmachan].isnull()) - (m_ext_dma_write_cb[dmachan])(*m_program, 4, data, 0xffffffff); + (m_ext_dma_write_cb[dmachan])(4, data); dmaregs[DCR4XX_DMADA0] += destinc; } while (!ppc4xx_dma_decrement_count(dmachan)); break; @@ -2656,7 +2733,7 @@ void ppc_device::ppc4xx_spu_rx_data(uint8_t data) uint32_t new_rxin; /* fail if we are going to overflow */ - new_rxin = (m_spu.rxin + 1) % ARRAY_LENGTH(m_spu.rxbuffer); + new_rxin = (m_spu.rxin + 1) % std::size(m_spu.rxbuffer); if (new_rxin == m_spu.rxout) fatalerror("ppc4xx_spu_rx_data: buffer overrun!\n"); @@ -2678,7 +2755,7 @@ void ppc_device::ppc4xx_spu_timer_reset() /* if we're enabled, reset at the current baud rate */ if (enabled) { - attotime clockperiod = attotime::from_hz((m_dcr[DCR4XX_IOCR] & 0x02) ? 3686400 : 33333333); + attotime clockperiod = attotime::from_hz((m_dcr[DCR4XX_IOCR] & 0x02) ? m_serial_clock : m_system_clock); int divisor = ((m_spu.regs[SPU4XX_BAUD_DIVISOR_H] * 256 + m_spu.regs[SPU4XX_BAUD_DIVISOR_L]) & 0xfff) + 1; int bpc = 7 + ((m_spu.regs[SPU4XX_CONTROL] & 8) >> 3) + 1 + (m_spu.regs[SPU4XX_CONTROL] & 1); attotime charperiod = clockperiod * (divisor * 16 * bpc); @@ -2710,7 +2787,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_spu_callback ) { /* if we have a transmit handler, send it that way */ if (!m_spu.tx_cb.isnull()) - (m_spu.tx_cb)(*m_program, 0, m_spu.txbuf, 0xff); + (m_spu.tx_cb)(m_spu.txbuf); /* indicate that we have moved it to the shift register */ m_spu.regs[SPU4XX_LINE_STATUS] |= 0x04; @@ -2735,7 +2812,7 @@ TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_spu_callback ) /* consume the byte and advance the out pointer */ rxbyte = m_spu.rxbuffer[m_spu.rxout]; - m_spu.rxout = (m_spu.rxout + 1) % ARRAY_LENGTH(m_spu.rxbuffer); + m_spu.rxout = (m_spu.rxout + 1) % std::size(m_spu.rxbuffer); /* if we're not full, copy data to the buffer and update the line status */ if (!(m_spu.regs[SPU4XX_LINE_STATUS] & 0x80)) @@ -2766,7 +2843,7 @@ updateirq: ppc4xx_spu_r - serial port read handler -------------------------------------------------*/ -READ8_MEMBER( ppc4xx_device::ppc4xx_spu_r ) +uint8_t ppc4xx_device::ppc4xx_spu_r(offs_t offset) { uint8_t result = 0xff; @@ -2778,7 +2855,7 @@ READ8_MEMBER( ppc4xx_device::ppc4xx_spu_r ) break; default: - if (offset < ARRAY_LENGTH(m_spu.regs)) + if (offset < std::size(m_spu.regs)) result = m_spu.regs[offset]; break; } @@ -2792,7 +2869,7 @@ READ8_MEMBER( ppc4xx_device::ppc4xx_spu_r ) ppc4xx_spu_w - serial port write handler -------------------------------------------------*/ -WRITE8_MEMBER( ppc4xx_device::ppc4xx_spu_w ) +void ppc4xx_device::ppc4xx_spu_w(offs_t offset, uint8_t data) { uint8_t oldstate, newstate; @@ -2842,7 +2919,7 @@ WRITE8_MEMBER( ppc4xx_device::ppc4xx_spu_w ) break; default: - if (offset < ARRAY_LENGTH(m_spu.regs)) + if (offset < std::size(m_spu.regs)) m_spu.regs[offset] = data; break; } @@ -2855,7 +2932,7 @@ WRITE8_MEMBER( ppc4xx_device::ppc4xx_spu_w ) specific TX handler configuration -------------------------------------------------*/ -void ppc4xx_device::ppc4xx_spu_set_tx_handler(write8_delegate callback) +void ppc4xx_device::ppc4xx_spu_set_tx_handler(write8smo_delegate callback) { m_spu.tx_cb = callback; } @@ -2887,7 +2964,7 @@ void ppc4xx_device::ppc4xx_set_dma_read_handler(int channel, read32_delegate cal specific external DMA write handler configuration -------------------------------------------------*/ -void ppc4xx_device::ppc4xx_set_dma_write_handler(int channel, write32_delegate callback, int rate) +void ppc4xx_device::ppc4xx_set_dma_write_handler(int channel, write32sm_delegate callback, int rate) { m_ext_dma_write_cb[channel] = callback; m_buffered_dma_rate[channel] = rate; @@ -2897,7 +2974,7 @@ void ppc4xx_device::ppc4xx_set_dma_write_handler(int channel, write32_delegate c ppc4xx_set_dcr_read_handler -------------------------------------------------*/ -void ppc4xx_device::ppc4xx_set_dcr_read_handler(read32_delegate dcr_read_func) +void ppc4xx_device::ppc4xx_set_dcr_read_handler(read32sm_delegate dcr_read_func) { m_dcr_read_func = dcr_read_func; @@ -2907,7 +2984,7 @@ void ppc4xx_device::ppc4xx_set_dcr_read_handler(read32_delegate dcr_read_func) ppc4xx_set_dcr_write_handler -------------------------------------------------*/ -void ppc4xx_device::ppc4xx_set_dcr_write_handler(write32_delegate dcr_write_func) +void ppc4xx_device::ppc4xx_set_dcr_write_handler(write32sm_delegate dcr_write_func) { m_dcr_write_func = dcr_write_func; } diff --git a/src/devices/cpu/powerpc/ppccom.h b/src/devices/cpu/powerpc/ppccom.h index 918ca62a4c4..da12935a5cc 100644 --- a/src/devices/cpu/powerpc/ppccom.h +++ b/src/devices/cpu/powerpc/ppccom.h @@ -64,7 +64,8 @@ #define PPCCAP_MFIOC 0x40 /* TRUE if we have memory-forced I/O controller interface accesses */ #define PPCCAP_601BAT 0x80 /* TRUE if we're doing 601-style BATs (unified I/D, different bit layout) */ #define PPCCAP_604_MMU 0x100 /* TRUE if we have 604-class MMU features */ - +#define PPCCAP_750_TLB 0x200 /* TRUE if we have the extended 740/750 series TLB */ +#define PPCCAP_LEGACY_POWER 0x400 /* TRUE if we support the legacy POWER instructions */ /* exception types */ enum @@ -171,6 +172,14 @@ enum SPR4XX_PBL2 = 0x3fe, /* R/W 403GA 406GA Protection Bound Lower 2 */ SPR4XX_PBU2 = 0x3ff, /* R/W 403GA 406GA Protection Bound Upper 2 */ + /* PowerPC 601 POWER back compatibility SPR indexes */ + SPR601_MQ = 0x000, /* R/W Muliplicand/Quotient for 601 POWER instructions */ + SPR601_RTCUR_PWR = 0x004, /* R Counts up number set in SPR 20 once per second, POWER only */ + SPR601_RTCLR_PWR = 0x005, /* R Number of nanoseconds between the seconds counted in SPR 4 */ + SPR601_PWRDEC = 0x006, /* R Decrementer register mirror for POWER compatibilty */ + SPR601_RTCUW_PWR = 0x014, /* W Seconds counter, set here and read SPR 4 */ + SPR601_RTCLW_PWR = 0x015, /* W Nanoseconds counter, not clear what writing here does */ + /* PowerPC 602 SPR register indexes */ SPR602_TCR = 0x3d8, /* 602 */ SPR602_IBR = 0x3da, /* 602 */ @@ -198,7 +207,6 @@ enum SPR603_HID2 = 0x3f3 /* R/W 603 */ }; - /* PowerPC 4XX DCR register indexes */ enum { diff --git a/src/devices/cpu/powerpc/ppcdrc.cpp b/src/devices/cpu/powerpc/ppcdrc.cpp index 120328a50a0..b9c7484f1f9 100644 --- a/src/devices/cpu/powerpc/ppcdrc.cpp +++ b/src/devices/cpu/powerpc/ppcdrc.cpp @@ -2,7 +2,7 @@ // copyright-holders:Aaron Giles /*************************************************************************** - ppcdrc.c + ppcdrc.cpp Universal machine language-based PowerPC emulator. @@ -18,12 +18,10 @@ #include "ppc.h" #include "ppccom.h" #include "ppcfe.h" -#include "ppc_dasm.h" #include "cpu/drcfe.h" #include "cpu/drcuml.h" #include "cpu/drcumlsh.h" -#include "debugger.h" @@ -118,7 +116,7 @@ inline void ppc_device::load_fast_iregs(drcuml_block &block) { int regnum; - for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + for (regnum = 0; regnum < std::size(m_regmap); regnum++) { if (m_regmap[regnum].is_int_register()) { @@ -137,7 +135,7 @@ void ppc_device::save_fast_iregs(drcuml_block &block) { int regnum; - for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + for (regnum = 0; regnum < std::size(m_regmap); regnum++) { if (m_regmap[regnum].is_int_register()) { @@ -149,7 +147,7 @@ void ppc_device::save_fast_iregs(drcuml_block &block) inline void ppc_device::load_fast_fregs(drcuml_block &block) { - for (int regnum = 0; regnum < ARRAY_LENGTH(m_fdregmap); regnum++) + for (int regnum = 0; regnum < std::size(m_fdregmap); regnum++) { if (m_fdregmap[regnum].is_float_register()) { @@ -160,7 +158,7 @@ inline void ppc_device::load_fast_fregs(drcuml_block &block) void ppc_device::save_fast_fregs(drcuml_block &block) { - for (int regnum = 0; regnum < ARRAY_LENGTH(m_fdregmap); regnum++) + for (int regnum = 0; regnum < std::size(m_fdregmap); regnum++) { if (m_fdregmap[regnum].is_float_register()) { @@ -268,7 +266,7 @@ void ppc_device::ppcdrc_set_options(uint32_t options) void ppc_device::ppcdrc_add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base) { - if (m_fastram_select < ARRAY_LENGTH(m_fastram)) + if (m_fastram_select < std::size(m_fastram)) { m_fastram[m_fastram_select].start = start; m_fastram[m_fastram_select].end = end; @@ -285,7 +283,7 @@ void ppc_device::ppcdrc_add_fastram(offs_t start, offs_t end, uint8_t readonly, void ppc_device::ppcdrc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles) { - if (m_hotspot_select < ARRAY_LENGTH(m_hotspot)) + if (m_hotspot_select < std::size(m_hotspot)) { m_hotspot[m_hotspot_select].pc = pc; m_hotspot[m_hotspot_select].opcode = opcode; @@ -383,7 +381,7 @@ void ppc_device::code_compile_block(uint8_t mode, offs_t pc) const opcode_desc *desclist; bool override = false; - g_profiler.start(PROFILER_DRC_COMPILE); + auto profile = g_profiler.start(PROFILER_DRC_COMPILE); /* get a description of this sequence */ desclist = m_drcfe->describe_code(pc); @@ -467,7 +465,6 @@ void ppc_device::code_compile_block(uint8_t mode, offs_t pc) /* end the sequence */ block.end(); - g_profiler.stop(); succeeded = true; } catch (drcuml_block::abort_compilation &) @@ -778,11 +775,11 @@ void ppc_device::static_generate_tlb_mismatch() UML_SHR(block, I1, I0, 12); // shr i1,i0,12 UML_LOAD(block, I2, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0 - UML_MOV(block, mem(&m_core->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH + UML_MOV(block, mem(&m_core->param1), TR_FETCH); // mov [param1],TR_FETCH UML_CALLC(block, (c_function)cfunc_ppccom_mismatch, this); UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc UML_LOAD(block, I1, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword - UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED + UML_TEST(block, I1, FETCH_ALLOWED); // test i1,FETCH_ALLOWED UML_JMPc(block, COND_Z, isi = label++); // jmp isi,z UML_CMP(block, I2, 0); // cmp i2,0 UML_JMPc(block, COND_NZ, exit = label++); // jmp exit,nz @@ -1010,9 +1007,9 @@ void ppc_device::static_generate_memory_accessor(int mode, int size, int iswrite int ramnum; if (mode & MODE_USER) - translate_type = iswrite ? TRANSLATE_WRITE_USER : TRANSLATE_READ_USER; + translate_type = iswrite ? TR_UWRITE : TR_UREAD; else - translate_type = iswrite ? TRANSLATE_WRITE : TRANSLATE_READ; + translate_type = iswrite ? TR_WRITE : TR_READ; /* begin generating */ drcuml_block &block(m_drcuml->begin_block(1024)); @@ -1024,32 +1021,30 @@ void ppc_device::static_generate_memory_accessor(int mode, int size, int iswrite /* check for unaligned accesses and break into two */ if (!ismasked && size != 1) { - /* in little-endian mode, anything misaligned generates an exception */ if ((mode & MODE_LITTLE_ENDIAN) || masked == nullptr || !(m_cap & PPCCAP_MISALIGNED)) { + /* in little-endian mode, anything misaligned generates an exception */ UML_TEST(block, I0, size - 1); // test i0,size-1 - UML_JMPc(block, COND_NZ, alignex = label++); // jmp alignex,nz + UML_JMPc(block, COND_NZ, alignex = label++); // jmp alignex,nz } - - /* in big-endian mode, it's more complicated */ else { - /* 8-byte accesses must be word-aligned */ + /* in big-endian mode, it's more complicated */ if (size == 8) { + /* 8-byte accesses must be word-aligned */ UML_TEST(block, I0, 3); // test i0,3 - UML_JMPc(block, COND_NZ, alignex = label++); // jmp alignex,nz + UML_JMPc(block, COND_NZ, alignex = label++); // jmp alignex,nz /* word aligned accesses need to be broken up */ UML_TEST(block, I0, 4); // test i0,4 UML_JMPc(block, COND_NZ, unaligned = label++); // jmp unaligned, nz } - - /* unaligned 2 and 4 byte accesses need to be broken up */ else { + /* unaligned 2 and 4 byte accesses need to be broken up */ UML_TEST(block, I0, size - 1); // test i0,size-1 - UML_JMPc(block, COND_NZ, unaligned = label++); // jmp unaligned,nz + UML_JMPc(block, COND_NZ, unaligned = label++); // jmp unaligned,nz } } } @@ -1057,18 +1052,18 @@ void ppc_device::static_generate_memory_accessor(int mode, int size, int iswrite /* general case: assume paging and perform a translation */ if (((m_cap & PPCCAP_OEA) && (mode & MODE_DATA_TRANSLATION)) || (iswrite && (m_cap & PPCCAP_4XX) && (mode & MODE_PROTECTION))) { - UML_SHR(block, I3, I0, 12); // shr i3,i0,12 - UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword - UML_TEST(block, I3, (uint64_t)1 << translate_type); // test i3,1 << translate_type - UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z - UML_LABEL(block, tlbreturn = label++); // tlbreturn: - UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000 + UML_SHR(block, I3, I0, 12); // shr i3,i0,12 + UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4); // load i3,[vtlb],i3,dword + UML_TEST(block, I3, (uint64_t)1 << translate_type); // test i3,1 << translate_type + UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z + UML_LABEL(block, tlbreturn = label++); // tlbreturn: + UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000 } else if (m_cap & PPCCAP_4XX) UML_AND(block, I0, I0, 0x7fffffff); // and i0,i0,0x7fffffff UML_XOR(block, I0, I0, (mode & MODE_LITTLE_ENDIAN) ? (8 - size) : 0); // xor i0,i0,8-size - if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0) + if (!debugger_enabled()) for (ramnum = 0; ramnum < PPC_MAX_FASTRAM; ramnum++) if (m_fastram[ramnum].base != nullptr && (!iswrite || !m_fastram[ramnum].readonly)) { @@ -1468,7 +1463,7 @@ void ppc_device::static_generate_lsw_entries(int mode) char temp[20]; /* allocate a handle */ - sprintf(temp, "lsw%d", regnum); + snprintf(temp, 20, "lsw%d", regnum); alloc_handle(m_drcuml.get(), &m_lsw[mode][regnum], temp); UML_HANDLE(block, *m_lsw[mode][regnum]); // handle lsw<regnum> UML_LABEL(block, regnum); // regnum: @@ -1520,7 +1515,7 @@ void ppc_device::static_generate_stsw_entries(int mode) char temp[20]; /* allocate a handle */ - sprintf(temp, "stsw%d", regnum); + snprintf(temp, 20, "stsw%d", regnum); alloc_handle(m_drcuml.get(), &m_stsw[mode][regnum], temp); UML_HANDLE(block, *m_stsw[mode][regnum]); // handle stsw<regnum> UML_LABEL(block, regnum); // regnum: @@ -1716,7 +1711,7 @@ void ppc_device::generate_sequence_instruction(drcuml_block &block, compiler_sta } /* if we are debugging, call the debugger */ - if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + if (debugger_enabled()) { UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc save_fast_iregs(block); // <save fastregs> @@ -1739,25 +1734,31 @@ void ppc_device::generate_sequence_instruction(drcuml_block &block, compiler_sta if (PRINTF_MMU) { const char *text = "Compiler page fault @ %08X\n"; - UML_MOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text + if (sizeof(uintptr_t) == 8) + UML_DMOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text + else + UML_MOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug } UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0 } - /* validate our TLB entry at this PC; if we fail, we need to handle it */ - if ((desc->flags & OPFLAG_VALIDATE_TLB) && (m_core->mode & MODE_DATA_TRANSLATION)) + // validate our TLB entry at this PC; if we fail, we need to handle it + // TODO: this code is highly sus based on the PPC architecture manual, but I'll only disable for 601 for now + if ((desc->flags & OPFLAG_VALIDATE_TLB) && (m_core->mode & MODE_DATA_TRANSLATION) && !(m_cap & PPCCAP_601BAT)) { const vtlb_entry *tlbtable = vtlb_table(); - /* if we currently have a valid TLB read entry, we just verify */ if (tlbtable[desc->pc >> 12] != 0) { if (PRINTF_MMU) { const char *text = "Checking TLB at @ %08X\n"; - UML_MOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text + if (sizeof(uintptr_t) == 8) + UML_DMOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text + else + UML_MOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug } @@ -1772,7 +1773,10 @@ void ppc_device::generate_sequence_instruction(drcuml_block &block, compiler_sta if (PRINTF_MMU) { const char *text = "No valid TLB @ %08X\n"; - UML_MOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text + if (sizeof(uintptr_t) == 8) + UML_DMOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text + else + UML_MOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug } @@ -2018,6 +2022,23 @@ bool ppc_device::generate_opcode(drcuml_block &block, compiler_state *compiler, // muls rd,rd,ra,simm return true; + case 0x9: /* DOZI (POWER) */ + assert(m_cap & PPCCAP_LEGACY_POWER); + + UML_AND(block, I0, op, 0xffff); + UML_CMP(block, R32(G_RA(op)), I0); // cmp ra, I0 + UML_JMPc(block, COND_B, compiler->labelnum); // bae 0: + + UML_XOR(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RD(op))); // xor rd, rd, rd (rd = 0) + UML_JMP(block, compiler->labelnum + 1); // jmp 1: + + UML_LABEL(block, compiler->labelnum++); // 0: + UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), I0); + UML_ADD(block, R32(G_RD(op)), R32(G_RD(op)), 0x1); + + UML_LABEL(block, compiler->labelnum++); // 1: + return true; + case 0x0e: /* ADDI */ UML_ADD(block, R32(G_RD(op)), R32Z(G_RA(op)), (int16_t)G_SIMM(op)); // add rd,ra,simm return true; @@ -2250,12 +2271,15 @@ bool ppc_device::generate_opcode(drcuml_block &block, compiler_state *compiler, case 0x2e: /* LMW */ UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) UML_MOV(block, mem(&m_core->tempaddr), R32Z(G_RA(op))); // mov [tempaddr],ra + for (int regnum = G_RD(op); regnum < 32; regnum++) { UML_ADD(block, I0, mem(&m_core->tempaddr), (int16_t)G_SIMM(op) + 4 * (regnum - G_RD(op))); // add i0,[tempaddr],simm + 4*(regnum-rd) UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align - UML_MOV(block, R32(regnum), I0); // mov regnum,i0 + + if (regnum != G_RA(op) || ((m_cap & PPCCAP_4XX) && regnum == 31)) + UML_MOV(block, R32(regnum), I0); // mov regnum,i0 } generate_update_cycles(block, compiler, desc->pc + 4, true); // <update cycles> return true; @@ -2672,10 +2696,19 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co case 0x0eb: /* MULLWx */ case 0x2eb: /* MULLWOx */ - UML_MULS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // muls rd,rd,ra,rb + // The flags are calculated based on the resulting 32-bit value from the 32x32=32 multiplication + // reference: example 4 https://www.ibm.com/docs/en/aix/7.2?topic=set-mullw-muls-multiply-low-word-instruction + UML_MULSLW(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // mulslw rd,ra,rb generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), false);// <update flags> return true; + case 0x6b: /* MUL (POWER) */ + assert(m_cap & PPCCAP_LEGACY_POWER); + + UML_MULU(block, SPR32(SPR601_MQ), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // mulu mq, rd, ra, rb + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV | XER_SO : 0), false); // <update flags> + return true; + case 0x1cb: /* DIVWUx */ case 0x3cb: /* DIVWUOx */ UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0 @@ -2703,6 +2736,68 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co UML_LABEL(block, compiler->labelnum++); // 1: return true; + case 0x14b: /* DIV (POWER) */ + assert(m_cap & PPCCAP_LEGACY_POWER); + + UML_MOV(block, I0, R32(G_RA(op))); + UML_MOV(block, I1, SPR32(SPR601_MQ)); + UML_DSHL(block, I0, I0, 32); // I0 = RA << 32 + UML_DOR(block, I0, I0, I1); // I0 |= MQ + UML_JMPc(block, COND_NZ, compiler->labelnum); // bne 0: + + UML_MOV(block, R32(G_RD(op)), 0x0); // mov rd, #0 + if (op & M_OE) + { + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 + } + if (op & M_RC) + { + UML_MOV(block, CR32(0), 0x2); // CR = EQ + UML_AND(block, CR32(0), CR32(0), ~0x1); + UML_OR(block, CR32(0), CR32(0), XERSO32); + } + + UML_JMP(block, compiler->labelnum + 1); // jmp 1: + + UML_LABEL(block, compiler->labelnum++); + UML_MOV(block, I1, R32(G_RB(op))); + UML_DSEXT(block, I1, I1, SIZE_DWORD); + UML_DDIVS(block, I0, I1, I0, I1); + UML_MOV(block, R32(G_RD(op)), I0); + UML_MOV(block, SPR32(SPR601_MQ), I1); + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV | XER_SO : 0), false); // <update flags> + UML_LABEL(block, compiler->labelnum++); // 1: + return true; + + case 0x16b: /* DIVS (POWER) */ + assert(m_cap & PPCCAP_LEGACY_POWER); + + UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0 + UML_JMPc(block, COND_NZ, compiler->labelnum); // bne 0: + + UML_MOV(block, R32(G_RD(op)), 0x0); // mov rd, #0 + if (op & M_OE) + { + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 + } + if (op & M_RC) + { + UML_MOV(block, CR32(0), 0x2); // CR = EQ + UML_AND(block, CR32(0), CR32(0), ~0x1); + UML_OR(block, CR32(0), CR32(0), XERSO32); + } + + UML_JMP(block, compiler->labelnum + 1); // jmp 1: + + UML_LABEL(block, compiler->labelnum++); // 0: + UML_DIVS(block, R32(G_RD(op)), SPR32(SPR601_MQ), R32(G_RA(op)), R32(G_RB(op))); // divs rd,mq,ra,rb + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), false); // <update flags> + + UML_LABEL(block, compiler->labelnum++); // 1: + return true; + case 0x1eb: /* DIVWx */ case 0x3eb: /* DIVWOx */ UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0 @@ -2756,6 +2851,78 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co UML_LABEL(block, compiler->labelnum++); // 3: return true; + case 0x108: /* DOZ (POWER) */ + assert(m_cap & PPCCAP_LEGACY_POWER); + + UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra, rb + UML_JMPc(block, COND_B, compiler->labelnum); // bae 0: + + UML_XOR(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RD(op))); // xor rd, rd, rd (rd = 0) + UML_JMP(block, compiler->labelnum+1); // jmp 1: + + UML_LABEL(block, compiler->labelnum++); // 0: + UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); + UML_ADD(block, R32(G_RD(op)), R32(G_RD(op)), 0x1); + + UML_LABEL(block, compiler->labelnum++); // 1: + if (op & M_OE) + { + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 + } + if (op & M_RC) + { + UML_TEST(block, R32(G_RD(op)), ~0); // test rd,~0 + generate_compute_flags(block, desc, op & M_RC, 0, false); // <update flags> + } + return true; + + case 0x168: /* ABS (POWER) */ + case 0x1e8: /* NABS (POWER) */ + assert(m_cap & PPCCAP_LEGACY_POWER); + + // is rA already the correct sign (positive for ABS, negative for NABS)? + UML_CMP(block, R32(G_RA(op)), 0); + if (op & 0x080) + { + UML_JMPc(block, COND_L, compiler->labelnum); // bl 0: + } + else + { + UML_JMPc(block, COND_GE, compiler->labelnum); // bge 0: + } + + UML_SUB(block, I0, 0, R32(G_RA(op))); // sub 0, ra (make positive) + UML_JMP(block, compiler->labelnum + 1); // jmp 1: + + UML_LABEL(block, compiler->labelnum++); // 0: + UML_MOV(block, I0, R32(G_RA(op))); + + UML_LABEL(block, compiler->labelnum++); // 1: + UML_MOV(block, R32(G_RD(op)), I0); // mov rd, I0 + if (op & M_RC) + { + UML_GETFLGS(block, I0, FLAG_Z | FLAG_V | FLAG_C | FLAG_S); // getflgs i0,zvcs + UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_DWORD, SCALE_x4); // load i0,cmp_cr_table,i0,dword + } + if (op & M_OE) + { + UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] + } + return true; + + case 0x21d: /* MASKIR (POWER) */ + UML_AND(block, I0, R32(G_RS(op)), R32(G_RB(op))); // and i0, rs, rb + UML_XOR(block, I1, R32(G_RB(op)), 0xffffffff); // xor i1, rb, 0xffffffff + UML_AND(block, I1, I1, R32(G_RA(op))); // and i1, i1, ra + UML_OR(block, R32(G_RA(op)), I0, I1); // or ra, i0, i1 + if (op & M_RC) + { + UML_GETFLGS(block, R32(G_RA(op)), FLAG_Z | FLAG_V | FLAG_C | FLAG_S); // getflgs i0,zvcs + UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_DWORD, SCALE_x4); // load i0,cmp_cr_table,i0,dword + } + return true; + case 0x01c: /* ANDx */ UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // and ra,rs,rb generate_compute_flags(block, desc, op & M_RC, 0, false); // <update flags> @@ -3066,9 +3233,11 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co case 0x215: /* LSWX */ UML_ADD(block, mem(&m_core->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb - UML_AND(block, mem(&m_core->swcount), SPR32(SPR_XER), 0x7f); // and [swcount],[xer],0x7f - UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), mem(&m_core->swcount));// sub icount,icount,[swcount] - UML_CALLHc(block, COND_NZ, *m_lsw[m_core->mode][G_RD(op)]); // call lsw[rd],nz + UML_AND(block, I0, SPR32(SPR_XER), 0x7f); // and i0,[xer],0x7f + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I0);// sub icount,icount,i0 + UML_MOV(block, mem(&m_core->swcount), I0); // mov [swcount],i0 + UML_TEST(block, I0, I0); // test i0,i0 + UML_CALLHc(block, COND_NZ, *m_lsw[m_core->mode][G_RD(op)]); // call lsw[rd] generate_update_cycles(block, compiler, desc->pc + 4, true); // <update cycles> return true; @@ -3218,8 +3387,10 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co case 0x295: /* STSWX */ UML_ADD(block, mem(&m_core->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb - UML_AND(block, mem(&m_core->swcount), SPR32(SPR_XER), 0x7f); // and [swcount],[xer],0x7f - UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), mem(&m_core->swcount));// sub icount,icount,[swcount] + UML_AND(block, I0, SPR32(SPR_XER), 0x7f); // and i0,[xer],0x7f + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I0);// sub icount,icount,i0 + UML_MOV(block, mem(&m_core->swcount), I0); // mov [swcount],i0 + UML_TEST(block, I0, I0); // test i0,i0 UML_CALLHc(block, COND_NZ, *m_stsw[m_core->mode][G_RD(op)]); // call stsw[rd] generate_update_cycles(block, compiler, desc->pc + 4, true); // <update cycles> return true; @@ -3405,7 +3576,7 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co return true; case 0x200: /* MCRXR */ - UML_ROLAND(block, I0, SPR32(SPR_XER), 28, 0x0f); // roland i0,[xer],28,0x0f + UML_ROLAND(block, I0, SPR32(SPR_XER), 4, 0x0f); // roland i0,[xer],4,0x0f UML_SHL(block, I1, XERSO32, 3); // shl i1,[xerso],3 UML_OR(block, CR32(G_CRFD(op)), I0, I1); // or [crd],i0,i1 UML_AND(block, SPR32(SPR_XER), SPR32(SPR_XER), ~0xf0000000); // and [xer],[xer],~0xf0000000 @@ -3793,7 +3964,7 @@ void ppc_device::log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32 if (m_drcuml->logging()) { std::ostringstream stream; - powerpc_disassembler::dasm_one(stream, pc, op); + m_dasm.dasm_one(stream, pc, op); block.append_comment("%08X: %s", pc, stream.str()); // comment } } @@ -3982,7 +4153,7 @@ void ppc_device::log_opcode_desc(const opcode_desc *desclist, int indent) if (desclist->flags & OPFLAG_VIRTUAL_NOOP) buffer << "<virtual nop>"; else - powerpc_disassembler::dasm_one(buffer, desclist->pc, desclist->opptr.l[0]); + m_dasm.dasm_one(buffer, desclist->pc, desclist->opptr.l[0]); } else buffer << "???"; diff --git a/src/devices/cpu/powerpc/ppcfe.cpp b/src/devices/cpu/powerpc/ppcfe.cpp index fbb6ae3a313..1e8fb105ee1 100644 --- a/src/devices/cpu/powerpc/ppcfe.cpp +++ b/src/devices/cpu/powerpc/ppcfe.cpp @@ -74,7 +74,7 @@ bool ppc_device::frontend::describe(opcode_desc &desc, const opcode_desc *prev) int regnum; // compute the physical PC - if (!m_ppc.memory_translate(AS_PROGRAM, TRANSLATE_FETCH, desc.physpc)) + if (m_ppc.ppccom_translate_address_internal(TR_FETCH, false, desc.physpc) > 1) { // uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and // mark as needing to validate; otherwise, just end the sequence here @@ -119,6 +119,16 @@ bool ppc_device::frontend::describe(opcode_desc &desc, const opcode_desc *prev) desc.cycles = 2; // ??? return true; + case 0x09: // DOZI (POWER) + if (!(m_ppc.m_cap & PPCCAP_LEGACY_POWER)) + { + return false; + } + + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RD(op)); + return true; + case 0x0e: // ADDI case 0x0f: // ADDIS GPR_USED_OR_ZERO(desc, G_RA(op)); @@ -289,8 +299,12 @@ bool ppc_device::frontend::describe(opcode_desc &desc, const opcode_desc *prev) case 0x2e: // LMW GPR_USED_OR_ZERO(desc, G_RA(op)); + for (regnum = G_RD(op); regnum < 32; regnum++) - GPR_MODIFIED(desc, regnum); + { + if (regnum != G_RA(op) || ((m_ppc.m_cap & PPCCAP_4XX) && regnum == 31)) + GPR_MODIFIED(desc, regnum); + } desc.flags |= OPFLAG_READS_MEMORY; desc.cycles = 32 - G_RD(op); return true; @@ -711,6 +725,7 @@ bool ppc_device::frontend::describe_1f(uint32_t op, opcode_desc &desc, const opc case 0x136: // ECIWX if (!(m_ppc.m_cap & PPCCAP_VEA)) return false; + [[fallthrough]]; case 0x014: // LWARX case 0x017: // LWZX case 0x057: // LBZX @@ -920,6 +935,7 @@ bool ppc_device::frontend::describe_1f(uint32_t op, opcode_desc &desc, const opc case 0x1b6: // ECOWX if (!(m_ppc.m_cap & PPCCAP_VEA)) return false; + [[fallthrough]]; case 0x096: // STWCX. case 0x097: // STWX case 0x0d7: // STBX @@ -1150,6 +1166,81 @@ bool ppc_device::frontend::describe_1f(uint32_t op, opcode_desc &desc, const opc return false; desc.flags |= OPFLAG_CAN_CHANGE_MODES | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_END_SEQUENCE; return true; + + case 0x14b: // DIV (POWER) + case 0x16b: // DIVS (POWER) + if (!(m_ppc.m_cap & PPCCAP_LEGACY_POWER)) + { + return false; + } + + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x6b: // MUL (POWER) + if (!(m_ppc.m_cap & PPCCAP_LEGACY_POWER)) + { + return false; + } + + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x108: // DOZ (POWER) + if (!(m_ppc.m_cap & PPCCAP_LEGACY_POWER)) + { + return false; + } + + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x168: // ABS (POWER) + case 0x1e8: // NABS (POWER) + if (!(m_ppc.m_cap & PPCCAP_LEGACY_POWER)) + { + return false; + } + + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x21d: // MASKIR (POWER) + if (!(m_ppc.m_cap & PPCCAP_LEGACY_POWER)) + { + return false; + } + + GPR_USED(desc, G_RS(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RA(op)); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; } return false; @@ -1339,6 +1430,7 @@ bool ppc_device::frontend::describe_3f(uint32_t op, opcode_desc &desc, const opc case 0x00e: // FCTIWx case 0x00f: // FCTIWZx FPSCR_MODIFIED(desc, 4); + [[fallthrough]]; case 0x028: // FNEGx case 0x048: // FMRx case 0x088: // FNABSx |