diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index 126d28ed524..af82ec72f1e 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -13,7 +13,7 @@ -- Dynamic recompiler objects -------------------------------------------------- -if (CPUS["SH2"]~=null or CPUS["MIPS"]~=null or CPUS["POWERPC"]~=null or CPUS["RSP"]~=null or CPUS["ARM7"]~=null or CPUS["ADSP21062"]~=null) then +if (CPUS["SH2"]~=null or CPUS["MIPS"]~=null or CPUS["POWERPC"]~=null or CPUS["RSP"]~=null or CPUS["ARM7"]~=null or CPUS["ADSP21062"]~=null or CPUS["MB86235"]~=null) then files { MAME_DIR .. "src/devices/cpu/drcbec.cpp", MAME_DIR .. "src/devices/cpu/drcbec.h", @@ -1064,6 +1064,9 @@ if (CPUS["MB86235"]~=null) then files { MAME_DIR .. "src/devices/cpu/mb86235/mb86235.cpp", MAME_DIR .. "src/devices/cpu/mb86235/mb86235.h", + MAME_DIR .. "src/devices/cpu/mb86235/mb86235drc.cpp", + MAME_DIR .. "src/devices/cpu/mb86235/mb86235fe.cpp", + MAME_DIR .. "src/devices/cpu/mb86235/mb86235fe.h", } end diff --git a/src/devices/cpu/mb86235/mb86235.cpp b/src/devices/cpu/mb86235/mb86235.cpp index c2641521ad4..eb589c83d13 100644 --- a/src/devices/cpu/mb86235/mb86235.cpp +++ b/src/devices/cpu/mb86235/mb86235.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Angelo Salese, ElSemi +// copyright-holders:Angelo Salese, ElSemi, Ville Linde /***************************************************************************** * * MB86235 "TGPx4" (c) Fujitsu @@ -14,69 +14,163 @@ #include "emu.h" #include "debugger.h" #include "mb86235.h" - - -const device_type MB86235 = &device_creator; +#include "mb86235fe.h" +#define CACHE_SIZE (1 * 1024 * 1024) +#define COMPILE_BACKWARDS_BYTES 128 +#define COMPILE_FORWARDS_BYTES 512 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) +#define COMPILE_MAX_SEQUENCE 64 -#define mb86235_readop(A) m_program->read_dword(A) -#define mb86235_readmem(A) m_program->read_dword(A) -#define mb86235_writemem(A,B) m_program->write_dword((A),B) + +const device_type MB86235 = &device_creator; + + +static ADDRESS_MAP_START(internal_abus, AS_DATA, 32, mb86235_device) + AM_RANGE(0x000000, 0x0003ff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(internal_bbus, AS_IO, 32, mb86235_device) + AM_RANGE(0x000000, 0x0003ff) AM_RAM +ADDRESS_MAP_END -/*********************************** - * illegal opcodes - ***********************************/ -void mb86235_cpu_device::mb86235_illegal() -{ - //logerror("mb86235 illegal opcode at 0x%04x\n", m_pc); - m_icount -= 1; -} /* Execute cycles */ -void mb86235_cpu_device::execute_run() +void mb86235_device::execute_run() { - uint32_t opcode; - - do - { - debugger_instruction_hook(this, m_pc); - - opcode = mb86235_readop(m_pc); - //m_pc++; - - switch( opcode ) - { - default: - mb86235_illegal(); - break; - } - - } while( m_icount > 0 ); + run_drc(); } -void mb86235_cpu_device::device_start() +void mb86235_device::device_start() { m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_dataa = &space(AS_DATA); + m_datab = &space(AS_IO); + + m_core = (mb86235_internal_state *)m_cache.alloc_near(sizeof(mb86235_internal_state)); + memset(m_core, 0, sizeof(mb86235_internal_state)); + + + // init UML generator + uint32_t umlflags = 0; + m_drcuml = std::make_unique(*this, m_cache, umlflags, 1, 24, 0); + + // add UML symbols + m_drcuml->symbol_add(&m_core->pc, sizeof(m_core->pc), "pc"); + m_drcuml->symbol_add(&m_core->icount, sizeof(m_core->icount), "icount"); + + for (int i = 0; i < 8; i++) + { + char buf[10]; + sprintf(buf, "aa%d", i); + m_drcuml->symbol_add(&m_core->aa[i], sizeof(m_core->aa[i]), buf); + sprintf(buf, "ab%d", i); + m_drcuml->symbol_add(&m_core->ab[i], sizeof(m_core->ab[i]), buf); + sprintf(buf, "ma%d", i); + m_drcuml->symbol_add(&m_core->ma[i], sizeof(m_core->ma[i]), buf); + sprintf(buf, "mb%d", i); + m_drcuml->symbol_add(&m_core->mb[i], sizeof(m_core->mb[i]), buf); + sprintf(buf, "ar%d", i); + m_drcuml->symbol_add(&m_core->ar[i], sizeof(m_core->ar[i]), buf); + } + + m_drcuml->symbol_add(&m_core->flags.az, sizeof(m_core->flags.az), "flags_az"); + m_drcuml->symbol_add(&m_core->flags.an, sizeof(m_core->flags.an), "flags_an"); + m_drcuml->symbol_add(&m_core->flags.av, sizeof(m_core->flags.av), "flags_av"); + m_drcuml->symbol_add(&m_core->flags.au, sizeof(m_core->flags.au), "flags_au"); + m_drcuml->symbol_add(&m_core->flags.ad, sizeof(m_core->flags.ad), "flags_ad"); + m_drcuml->symbol_add(&m_core->flags.zc, sizeof(m_core->flags.zc), "flags_zc"); + m_drcuml->symbol_add(&m_core->flags.il, sizeof(m_core->flags.il), "flags_il"); + m_drcuml->symbol_add(&m_core->flags.nr, sizeof(m_core->flags.nr), "flags_nr"); + m_drcuml->symbol_add(&m_core->flags.zd, sizeof(m_core->flags.zd), "flags_zd"); + m_drcuml->symbol_add(&m_core->flags.mn, sizeof(m_core->flags.mn), "flags_mn"); + m_drcuml->symbol_add(&m_core->flags.mz, sizeof(m_core->flags.mz), "flags_mz"); + m_drcuml->symbol_add(&m_core->flags.mv, sizeof(m_core->flags.mv), "flags_mv"); + m_drcuml->symbol_add(&m_core->flags.mu, sizeof(m_core->flags.mu), "flags_mu"); + m_drcuml->symbol_add(&m_core->flags.md, sizeof(m_core->flags.md), "flags_md"); + + + m_drcuml->symbol_add(&m_core->arg0, sizeof(m_core->arg0), "arg0"); + m_drcuml->symbol_add(&m_core->arg1, sizeof(m_core->arg1), "arg1"); + m_drcuml->symbol_add(&m_core->arg2, sizeof(m_core->arg2), "arg2"); + m_drcuml->symbol_add(&m_core->arg3, sizeof(m_core->arg3), "arg3"); + m_drcuml->symbol_add(&m_core->alutemp, sizeof(m_core->alutemp), "alutemp"); + m_drcuml->symbol_add(&m_core->multemp, sizeof(m_core->multemp), "multemp"); + + m_drcuml->symbol_add(&m_core->pcs_ptr, sizeof(m_core->pcs_ptr), "pcs_ptr"); + + + m_drcfe = std::make_unique(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, COMPILE_MAX_SEQUENCE); + + for (int i = 0; i < 8; i++) + { + m_regmap[i] = uml::mem(&m_core->aa[i]); + m_regmap[i + 8] = uml::mem(&m_core->ab[i]); + m_regmap[i + 16] = uml::mem(&m_core->ma[i]); + m_regmap[i + 24] = uml::mem(&m_core->mb[i]); + } - save_item(NAME(m_pc)); - save_item(NAME(m_flags)); // Register state for debugger - //state_add( CP1610_R0, "PC", m_pc ).formatstr("%02X"); - state_add( STATE_GENPC, "GENPC", m_pc ).noshow(); - state_add( STATE_GENPCBASE, "CURPC", m_pc ).noshow(); - state_add( STATE_GENFLAGS, "GENFLAGS", m_flags ).noshow(); + state_add(MB86235_PC, "PC", m_core->pc).formatstr("%08X"); + state_add(MB86235_AR0, "AR0", m_core->ar[0]).formatstr("%08X"); + state_add(MB86235_AR1, "AR1", m_core->ar[1]).formatstr("%08X"); + state_add(MB86235_AR2, "AR2", m_core->ar[2]).formatstr("%08X"); + state_add(MB86235_AR3, "AR3", m_core->ar[3]).formatstr("%08X"); + state_add(MB86235_AR4, "AR4", m_core->ar[4]).formatstr("%08X"); + state_add(MB86235_AR5, "AR5", m_core->ar[5]).formatstr("%08X"); + state_add(MB86235_AR6, "AR6", m_core->ar[6]).formatstr("%08X"); + state_add(MB86235_AR7, "AR7", m_core->ar[7]).formatstr("%08X"); + state_add(MB86235_AA0, "AA0", m_core->aa[0]).formatstr("%08X"); + state_add(MB86235_AA1, "AA1", m_core->aa[1]).formatstr("%08X"); + state_add(MB86235_AA2, "AA2", m_core->aa[2]).formatstr("%08X"); + state_add(MB86235_AA3, "AA3", m_core->aa[3]).formatstr("%08X"); + state_add(MB86235_AA4, "AA4", m_core->aa[4]).formatstr("%08X"); + state_add(MB86235_AA5, "AA5", m_core->aa[5]).formatstr("%08X"); + state_add(MB86235_AA6, "AA6", m_core->aa[6]).formatstr("%08X"); + state_add(MB86235_AA7, "AA7", m_core->aa[7]).formatstr("%08X"); + state_add(MB86235_AB0, "AB0", m_core->ab[0]).formatstr("%08X"); + state_add(MB86235_AB1, "AB1", m_core->ab[1]).formatstr("%08X"); + state_add(MB86235_AB2, "AB2", m_core->ab[2]).formatstr("%08X"); + state_add(MB86235_AB3, "AB3", m_core->ab[3]).formatstr("%08X"); + state_add(MB86235_AB4, "AB4", m_core->ab[4]).formatstr("%08X"); + state_add(MB86235_AB5, "AB5", m_core->ab[5]).formatstr("%08X"); + state_add(MB86235_AB6, "AB6", m_core->ab[6]).formatstr("%08X"); + state_add(MB86235_AB7, "AB7", m_core->ab[7]).formatstr("%08X"); + state_add(MB86235_MA0, "MA0", m_core->ma[0]).formatstr("%08X"); + state_add(MB86235_MA1, "MA1", m_core->ma[1]).formatstr("%08X"); + state_add(MB86235_MA2, "MA2", m_core->ma[2]).formatstr("%08X"); + state_add(MB86235_MA3, "MA3", m_core->ma[3]).formatstr("%08X"); + state_add(MB86235_MA4, "MA4", m_core->ma[4]).formatstr("%08X"); + state_add(MB86235_MA5, "MA5", m_core->ma[5]).formatstr("%08X"); + state_add(MB86235_MA6, "MA6", m_core->ma[6]).formatstr("%08X"); + state_add(MB86235_MA7, "MA7", m_core->ma[7]).formatstr("%08X"); + state_add(MB86235_MB0, "MB0", m_core->mb[0]).formatstr("%08X"); + state_add(MB86235_MB1, "MB1", m_core->mb[1]).formatstr("%08X"); + state_add(MB86235_MB2, "MB2", m_core->mb[2]).formatstr("%08X"); + state_add(MB86235_MB3, "MB3", m_core->mb[3]).formatstr("%08X"); + state_add(MB86235_MB4, "MB4", m_core->mb[4]).formatstr("%08X"); + state_add(MB86235_MB5, "MB5", m_core->mb[5]).formatstr("%08X"); + state_add(MB86235_MB6, "MB6", m_core->mb[6]).formatstr("%08X"); + state_add(MB86235_MB7, "MB7", m_core->mb[7]).formatstr("%08X"); + state_add(STATE_GENPC, "GENPC", m_core->pc ).noshow(); - m_icountptr = &m_icount; + m_icountptr = &m_core->icount; + + m_core->fp0 = 0.0f; } -void mb86235_cpu_device::device_reset() +void mb86235_device::device_reset() { + flush_cache(); + + m_core->pc = 0; } #if 0 @@ -102,29 +196,62 @@ void mb86235_cpu_device::execute_set_input(int irqline, int state) } #endif -mb86235_cpu_device::mb86235_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +mb86235_device::mb86235_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : cpu_device(mconfig, MB86235, "MB86235", tag, owner, clock, "mb86235", __FILE__) , m_program_config("program", ENDIANNESS_LITTLE, 64, 32, -3) + , m_dataa_config("data_a", ENDIANNESS_LITTLE, 32, 24, -2, ADDRESS_MAP_NAME(internal_abus)) + , m_datab_config("data_b", ENDIANNESS_LITTLE, 32, 10, -2, ADDRESS_MAP_NAME(internal_bbus)) + , m_cache(CACHE_SIZE + sizeof(mb86235_internal_state)) + , m_drcuml(nullptr) + , m_drcfe(nullptr) { } -void mb86235_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const +void mb86235_device::state_string_export(const device_state_entry &entry, std::string &str) const { switch (entry.index()) { case STATE_GENFLAGS: - str = string_format("%c%c%c%c", - m_flags & 0x80 ? 'S':'.', - m_flags & 0x40 ? 'Z':'.', - m_flags & 0x20 ? 'V':'.', - m_flags & 0x10 ? 'C':'.'); + str = string_format("?"); break; } } -offs_t mb86235_cpu_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) +offs_t mb86235_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) { extern CPU_DISASSEMBLE( mb86235 ); return CPU_DISASSEMBLE_NAME(mb86235)(this, stream, pc, oprom, opram, options); } + + +void mb86235_device::fifoin_w(uint64_t data) +{ + if (m_core->fifoin.num >= FIFOIN_SIZE) + { + fatalerror("fifoin_w: pushing to full fifo"); + } + + printf("FIFOIN push %08X%08X\n", (uint32_t)(data >> 32), (uint32_t)(data)); + + m_core->fifoin.data[m_core->fifoin.wpos] = data; + + m_core->fifoin.wpos++; + m_core->fifoin.wpos &= FIFOIN_SIZE-1; + m_core->fifoin.num++; +} + +bool mb86235_device::is_fifoin_full() +{ + return m_core->fifoin.num >= FIFOIN_SIZE; +} + +uint64_t mb86235_device::fifoout0_r() +{ + fatalerror("fifoout0_r"); +} + +bool mb86235_device::is_fifoout0_empty() +{ + return m_core->fifoout0.num == 0; +} \ No newline at end of file diff --git a/src/devices/cpu/mb86235/mb86235.h b/src/devices/cpu/mb86235/mb86235.h index 8a8bd867609..b189b9ab5ab 100644 --- a/src/devices/cpu/mb86235/mb86235.h +++ b/src/devices/cpu/mb86235/mb86235.h @@ -11,20 +11,62 @@ #ifndef __MB86235_H__ #define __MB86235_H__ -#if 0 -enum -{ - MB86235_R0=1, MB86235_R1, MB86235_R2, MB86235_R3, - MB86235_R4, MB86235_R5, MB86235_R6, MB86235_R7 -}; -#endif +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" + +class mb86235_frontend; -class mb86235_cpu_device : public cpu_device + + +#define OP_USERFLAG_FIFOIN 0x1 +#define OP_USERFLAG_FIFOOUT0 0x2 +#define OP_USERFLAG_FIFOOUT1 0x4 +#define OP_USERFLAG_REPEAT 0x8 +#define OP_USERFLAG_REPEATED_OP 0x10 +#define OP_USERFLAG_ALU_PRP_UPDATE 0x100 +#define OP_USERFLAG_MUL_PRP_UPDATE 0x200 +#define OP_USERFLAG_XFER_PRP_UPDATE 0x400 +#define OP_USERFLAG_ALU_PWP_UPDATE 0x800 +#define OP_USERFLAG_MUL_PWP_UPDATE 0x1000 +#define OP_USERFLAG_XFER_PWP_UPDATE 0x2000 + + +class mb86235_device : public cpu_device { + friend class mb86235_frontend; + public: // construction/destruction - mb86235_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, uint32_t _clock); + mb86235_device(const machine_config &mconfig, const char *_tag, device_t *_owner, uint32_t clock); + + void unimplemented_op(); + void unimplemented_alu(); + void unimplemented_control(); + void unimplemented_xfer1(); + void unimplemented_double_xfer1(); + void unimplemented_double_xfer2(); + void pcs_overflow(); + void pcs_underflow(); + + void fifoin_w(uint64_t data); + bool is_fifoin_full(); + uint64_t fifoout0_r(); + bool is_fifoout0_empty(); + + enum + { + MB86235_PC = 1, + MB86235_AA0, MB86235_AA1, MB86235_AA2, MB86235_AA3, MB86235_AA4, MB86235_AA5, MB86235_AA6, MB86235_AA7, + MB86235_AB0, MB86235_AB1, MB86235_AB2, MB86235_AB3, MB86235_AB4, MB86235_AB5, MB86235_AB6, MB86235_AB7, + MB86235_MA0, MB86235_MA1, MB86235_MA2, MB86235_MA3, MB86235_MA4, MB86235_MA5, MB86235_MA6, MB86235_MA7, + MB86235_MB0, MB86235_MB1, MB86235_MB2, MB86235_MB3, MB86235_MB4, MB86235_MB5, MB86235_MB6, MB86235_MB7, + MB86235_AR0, MB86235_AR1, MB86235_AR2, MB86235_AR3, MB86235_AR4, MB86235_AR5, MB86235_AR6, MB86235_AR7, + }; + + const int FIFOIN_SIZE = 16; + const int FIFOOUT0_SIZE = 16; + const int FIFOOUT1_SIZE = 16; protected: // device-level overrides @@ -39,7 +81,7 @@ protected: //virtual void execute_set_input(int inputnum, int state); // device_memory_interface overrides - virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override { return (spacenum == AS_PROGRAM) ? &m_program_config : nullptr; } + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override { return (spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_dataa_config : (spacenum == AS_IO) ? &m_datab_config : nullptr); } // device_state_interface overrides virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; @@ -49,16 +91,154 @@ protected: virtual uint32_t disasm_max_opcode_bytes() const override { return 8; } virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override; + direct_read_data *m_direct; + private: + + struct mb86235_flags + { + uint32_t az; + uint32_t an; + uint32_t av; + uint32_t au; + uint32_t ad; + uint32_t zc; + uint32_t il; + uint32_t nr; + uint32_t zd; + uint32_t mn; + uint32_t mz; + uint32_t mv; + uint32_t mu; + uint32_t md; + }; + + struct fifo + { + int rpos; + int wpos; + int num; + uint64_t data[16]; + }; + + struct mb86235_internal_state + { + uint32_t pc; + uint32_t aa[8]; + uint32_t ab[8]; + uint32_t ma[8]; + uint32_t mb[8]; + uint32_t ar[8]; + + uint32_t sp; + uint32_t eb; + uint32_t eo; + uint32_t rpc; + uint32_t lpc; + + uint32_t prp; + uint32_t pwp; + uint32_t pr[24]; + + uint32_t mod; + mb86235_flags flags; + + int icount; + + uint32_t arg0; + uint32_t arg1; + uint32_t arg2; + uint32_t arg3; + uint64_t arg64; + + uint32_t pcs[4]; + int pcs_ptr; + + uint32_t jmpdest; + uint32_t alutemp; + uint32_t multemp; + uint32_t condtemp; + + uint32_t pdr; + uint32_t ddr; + + float fp0; + + fifo fifoin; + fifo fifoout0; + fifo fifoout1; + }; + + mb86235_internal_state *m_core; + + drc_cache m_cache; + std::unique_ptr m_drcuml; + std::unique_ptr m_drcfe; + uml::parameter m_regmap[32]; + + uml::code_handle *m_entry; /* entry point */ + uml::code_handle *m_nocode; /* nocode exception handler */ + uml::code_handle *m_out_of_cycles; /* out of cycles exception handler */ + uml::code_handle *m_clear_fifo_in; + uml::code_handle *m_clear_fifo_out0; + uml::code_handle *m_clear_fifo_out1; + uml::code_handle *m_read_fifo_in; + uml::code_handle *m_write_fifo_out0; + uml::code_handle *m_write_fifo_out1; + uml::code_handle *m_read_abus; + uml::code_handle *m_write_abus; + address_space_config m_program_config; + address_space_config m_dataa_config; + address_space_config m_datab_config; - uint8_t m_pc; /* registers */ - uint8_t m_flags; /* flags */ address_space *m_program; - int m_icount; + address_space *m_dataa; + address_space *m_datab; - void mb86235_illegal(); + /* internal compiler state */ + struct compiler_state + { + uint32_t cycles; /* accumulated cycles */ + uint8_t checkints; /* need to check interrupts before next instruction */ + uml::code_label labelnum; /* index for local labels */ + }; + void run_drc(); + void flush_cache(); + void alloc_handle(drcuml_state *drcuml, uml::code_handle **handleptr, const char *name); + void compile_block(offs_t pc); + void load_fast_iregs(drcuml_block *block); + void save_fast_iregs(drcuml_block *block); + void static_generate_entry_point(); + void static_generate_nocode_handler(); + void static_generate_out_of_cycles(); + void static_generate_fifo(); + void static_generate_memory_accessors(); + void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, bool allow_exception); + bool generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_alu(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int aluop, bool alu_temp); + void generate_mul(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int mulop, bool mul_temp); + void generate_pre_control(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_control(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_xfer1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_double_xfer1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_xfer2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_double_xfer2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_xfer3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_ea(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int md, int arx, int ary, int disp); + void generate_reg_read(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int reg, uml::parameter dst); + void generate_reg_write(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int reg, uml::parameter src); + void generate_alumul_input(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int reg, uml::parameter dst, bool fp, bool mul); + uml::parameter get_alu1_input(int reg); + uml::parameter get_alu_output(int reg); + uml::parameter get_mul1_input(int reg); + void generate_condition(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int cc, bool not, uml::code_label skip_label, bool condtemp); + void generate_branch_target(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int type, int ef2); + bool has_register_clash(const opcode_desc *desc, int outreg); + bool aluop_has_result(int aluop); }; diff --git a/src/devices/cpu/mb86235/mb86235drc.cpp b/src/devices/cpu/mb86235/mb86235drc.cpp new file mode 100644 index 00000000000..cd0f8e07030 --- /dev/null +++ b/src/devices/cpu/mb86235/mb86235drc.cpp @@ -0,0 +1,1775 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde + +/****************************************************************************** + + MB86235 UML recompiler core + +******************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mb86235.h" +#include "mb86235fe.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +/* + TODO: + - check jump condition before parallel ALU/MUL (flags!) + - PR update after all operations (double update at 0x26) + +*/ + + + + +using namespace uml; + + +// map variables +#define MAPVAR_PC M0 +#define MAPVAR_CYCLES M1 + +// exit codes +#define EXECUTE_OUT_OF_CYCLES 0 +#define EXECUTE_MISSING_CODE 1 +#define EXECUTE_UNMAPPED_CODE 2 +#define EXECUTE_RESET_CACHE 3 + + +#define AR(reg) mem(&m_core->ar[(reg)]) +#define AA(reg) m_regmap[(reg)] +#define AB(reg) m_regmap[(reg)+8] +#define MA(reg) m_regmap[(reg)+16] +#define MB(reg) m_regmap[(reg)+24] +#define FLAGS_AZ mem(&m_core->flags.az) +#define FLAGS_AN mem(&m_core->flags.an) +#define FLAGS_AV mem(&m_core->flags.av) +#define FLAGS_AU mem(&m_core->flags.au) +#define FLAGS_AD mem(&m_core->flags.ad) +#define FLAGS_ZC mem(&m_core->flags.zc) +#define FLAGS_IL mem(&m_core->flags.il) +#define FLAGS_NR mem(&m_core->flags.nr) +#define FLAGS_ZD mem(&m_core->flags.zd) +#define FLAGS_MN mem(&m_core->flags.mn) +#define FLAGS_MZ mem(&m_core->flags.mz) +#define FLAGS_MV mem(&m_core->flags.mv) +#define FLAGS_MU mem(&m_core->flags.mu) +#define FLAGS_MD mem(&m_core->flags.md) + +#define PRP mem(&m_core->prp) +#define PWP mem(&m_core->pwp) +#define RPC mem(&m_core->rpc) +#define LPC mem(&m_core->lpc) + +#define AZ_CALC_REQUIRED ((desc->regreq[1] & 0x1) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AN_CALC_REQUIRED ((desc->regreq[1] & 0x2) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AV_CALC_REQUIRED ((desc->regreq[1] & 0x4) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AU_CALC_REQUIRED ((desc->regreq[1] & 0x8) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AD_CALC_REQUIRED ((desc->regreq[1] & 0x10) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define ZC_CALC_REQUIRED ((desc->regreq[1] & 0x20) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define IL_CALC_REQUIRED ((desc->regreq[1] & 0x40) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define NR_CALC_REQUIRED ((desc->regreq[1] & 0x80) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define ZD_CALC_REQUIRED ((desc->regreq[1] & 0x100) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MN_CALC_REQUIRED ((desc->regreq[1] & 0x200) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MZ_CALC_REQUIRED ((desc->regreq[1] & 0x400) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MV_CALC_REQUIRED ((desc->regreq[1] & 0x800) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MU_CALC_REQUIRED ((desc->regreq[1] & 0x1000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MD_CALC_REQUIRED ((desc->regreq[1] & 0x2000) || desc->flags & OPFLAG_IN_DELAY_SLOT) + +#define FIFOIN_RPOS mem(&m_core->fifoin.rpos) +#define FIFOIN_WPOS mem(&m_core->fifoin.wpos) +#define FIFOIN_NUM mem(&m_core->fifoin.num) +#define FIFOOUT0_RPOS mem(&m_core->fifoout0.rpos) +#define FIFOOUT0_WPOS mem(&m_core->fifoout0.wpos) +#define FIFOOUT0_NUM mem(&m_core->fifoout0.num) +#define FIFOOUT1_RPOS mem(&m_core->fifoout1.rpos) +#define FIFOOUT1_WPOS mem(&m_core->fifoout1.wpos) +#define FIFOOUT1_NUM mem(&m_core->fifoout1.num) + + +inline void mb86235_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) +{ + if (*handleptr == nullptr) + *handleptr = drcuml->handle_alloc(name); +} + + + +static void cfunc_unimplemented(void *param) +{ + mb86235_device *cpu = (mb86235_device *)param; + cpu->unimplemented_op(); +} + +static void cfunc_unimplemented_alu(void *param) +{ + mb86235_device *cpu = (mb86235_device *)param; + cpu->unimplemented_alu(); +} + +static void cfunc_unimplemented_control(void *param) +{ + mb86235_device *cpu = (mb86235_device *)param; + cpu->unimplemented_control(); +} + +static void cfunc_unimplemented_xfer1(void *param) +{ + mb86235_device *cpu = (mb86235_device *)param; + cpu->unimplemented_xfer1(); +} + +static void cfunc_unimplemented_double_xfer1(void *param) +{ + mb86235_device *cpu = (mb86235_device *)param; + cpu->unimplemented_double_xfer1(); +} + +static void cfunc_unimplemented_double_xfer2(void *param) +{ + mb86235_device *cpu = (mb86235_device *)param; + cpu->unimplemented_double_xfer2(); +} + +static void cfunc_pcs_overflow(void *param) +{ + mb86235_device *cpu = (mb86235_device *)param; + cpu->pcs_overflow(); +} + +static void cfunc_pcs_underflow(void *param) +{ + mb86235_device *cpu = (mb86235_device *)param; + cpu->pcs_underflow(); +} + + + +void mb86235_device::unimplemented_op() +{ + uint64_t op = m_core->arg64; + printf("MB86235: PC=%08X: Unimplemented op %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op)); + fatalerror("MB86235: PC=%08X: Unimplemented op %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op)); +} + +void mb86235_device::unimplemented_alu() +{ + uint32_t op = m_core->arg0; + printf("MB86235: PC=%08X: Unimplemented alu %02X\n", m_core->pc, op); + fatalerror("MB86235: PC=%08X: Unimplemented alu %02X\n", m_core->pc, op); +} + +void mb86235_device::unimplemented_control() +{ + uint32_t cop = m_core->arg0; + printf("MB86235: PC=%08X: Unimplemented control %02X\n", m_core->pc, cop); + fatalerror("MB86235: PC=%08X: Unimplemented control %02X\n", m_core->pc, cop); +} + +void mb86235_device::unimplemented_xfer1() +{ + uint64_t op = m_core->arg64; + printf("MB86235: PC=%08X: Unimplemented xfer1 %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op)); + fatalerror("MB86235: PC=%08X: Unimplemented xfer1 %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op)); +} + +void mb86235_device::unimplemented_double_xfer1() +{ + uint64_t op = m_core->arg64; + printf("MB86235: PC=%08X: Unimplemented double xfer1 %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op)); + fatalerror("MB86235: PC=%08X: Unimplemented double xfer1 %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op)); +} + +void mb86235_device::unimplemented_double_xfer2() +{ + uint64_t op = m_core->arg64; + printf("MB86235: PC=%08X: Unimplemented double xfer2 %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op)); + fatalerror("MB86235: PC=%08X: Unimplemented double xfer2 %04X%08X\n", m_core->pc, (uint32_t)(op >> 32), (uint32_t)(op)); +} + +void mb86235_device::pcs_overflow() +{ + printf("MB86235: PC=%08X: PCS overflow\n", m_core->pc); + fatalerror("MB86235: PC=%08X: PCS overflow\n", m_core->pc); +} + +void mb86235_device::pcs_underflow() +{ + printf("MB86235: PC=%08X: PCS underflow\n", m_core->pc); + fatalerror("MB86235: PC=%08X: PCS underflow\n", m_core->pc); +} + + + + +/*------------------------------------------------- +load_fast_iregs - load any fast integer +registers +-------------------------------------------------*/ + +inline void mb86235_device::load_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + { + if (m_regmap[regnum].is_int_register()) + { + } + } +} + + +/*------------------------------------------------- +save_fast_iregs - save any fast integer +registers +-------------------------------------------------*/ + +void mb86235_device::save_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + { + if (m_regmap[regnum].is_int_register()) + { + } + } +} + + + + +void mb86235_device::run_drc() +{ + drcuml_state *drcuml = m_drcuml.get(); + int execute_result; + + /* execute */ + do + { + execute_result = drcuml->execute(*m_entry); + + /* if we need to recompile, do it */ + if (execute_result == EXECUTE_MISSING_CODE) + { + compile_block(m_core->pc); + } + else if (execute_result == EXECUTE_UNMAPPED_CODE) + { + fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_core->pc); + } + else if (execute_result == EXECUTE_RESET_CACHE) + { + flush_cache(); + } + } while (execute_result != EXECUTE_OUT_OF_CYCLES); +} + +void mb86235_device::compile_block(offs_t pc) +{ + compiler_state compiler = { 0 }; + + const opcode_desc *seqhead, *seqlast; + const opcode_desc *desclist; + bool override = false; + + drcuml_block *block; + + desclist = m_drcfe->describe_code(pc); + + bool succeeded = false; + while (!succeeded) + { + try + { + block = m_drcuml->begin_block(4096); + + for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next()) + { + const opcode_desc *curdesc; + uint32_t nextpc; + + /* determine the last instruction in this sequence */ + for (seqlast = seqhead; seqlast != nullptr; seqlast = seqlast->next()) + if (seqlast->flags & OPFLAG_END_SEQUENCE) + break; + assert(seqlast != nullptr); + + /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ + if (override || m_drcuml->hash_exists(0, seqhead->pc)) + UML_HASH(block, 0, seqhead->pc); // hash mode,pc + + /* if we already have a hash, and this is the first sequence, assume that we */ + /* are recompiling due to being out of sync and allow future overrides */ + else if (seqhead == desclist) + { + override = true; + UML_HASH(block, 0, seqhead->pc); // hash mode,pc + } + + /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ + else + { + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc + UML_HASHJMP(block, 0, seqhead->pc, *m_nocode); // hashjmp <0>,seqhead->pc,nocode + continue; + } + + /* label this instruction, if it may be jumped to locally */ + if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc + + /* iterate over instructions in the sequence and compile them */ + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) + generate_sequence_instruction(block, &compiler, curdesc); + + /* if we need to return to the start, do it */ + if (seqlast->flags & OPFLAG_RETURN_TO_START) + nextpc = pc; + /* otherwise we just go to the next instruction */ + else + nextpc = seqlast->pc + (seqlast->skipslots + 1); + + /* count off cycles and go there */ + generate_update_cycles(block, &compiler, nextpc, true); // + + if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc) + UML_HASHJMP(block, 0, nextpc, *m_nocode); // hashjmp ,nextpc,nocode + } + + block->end(); + succeeded = true; + } + catch (drcuml_block::abort_compilation &) + { + flush_cache(); + } + } +} + + + +void mb86235_device::static_generate_entry_point() +{ + code_label skip = 1; + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(20); + + /* forward references */ + alloc_handle(m_drcuml.get(), &m_nocode, "nocode"); + + alloc_handle(m_drcuml.get(), &m_entry, "entry"); + UML_HANDLE(block, *m_entry); // handle entry + + load_fast_iregs(block); // + + /* generate a hash jump via the current mode and PC */ + UML_HASHJMP(block, 0, mem(&m_core->pc), *m_nocode); // hashjmp ,,nocode + + block->end(); +} + + +void mb86235_device::static_generate_nocode_handler() +{ + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(m_drcuml.get(), &m_nocode, "nocode"); + UML_HANDLE(block, *m_nocode); // handle nocode + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_core->pc), I0); // mov [pc],i0 + save_fast_iregs(block); // + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + + block->end(); +} + +void mb86235_device::static_generate_out_of_cycles() +{ + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(m_drcuml.get(), &m_out_of_cycles, "out_of_cycles"); + UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_core->pc), I0); // mov ,i0 + save_fast_iregs(block); // + UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES + + block->end(); +} + +void mb86235_device::static_generate_fifo() +{ + drcuml_block *block; + + // clear fifo in + block = m_drcuml->begin_block(20); + + alloc_handle(m_drcuml.get(), &m_clear_fifo_in, "clear_fifo_in"); + UML_HANDLE(block, *m_clear_fifo_in); + UML_MOV(block, FIFOIN_NUM, 0); + UML_MOV(block, FIFOIN_RPOS, 0); + UML_MOV(block, FIFOIN_WPOS, 0); + UML_RET(block); + + block->end(); + + // clear fifo out0 + block = m_drcuml->begin_block(20); + + alloc_handle(m_drcuml.get(), &m_clear_fifo_out0, "clear_fifo_out0"); + UML_HANDLE(block, *m_clear_fifo_out0); + UML_MOV(block, FIFOOUT0_NUM, 0); + UML_MOV(block, FIFOOUT0_RPOS, 0); + UML_MOV(block, FIFOOUT0_WPOS, 0); + UML_RET(block); + + block->end(); + + // clear fifo out1 + block = m_drcuml->begin_block(20); + + alloc_handle(m_drcuml.get(), &m_clear_fifo_out1, "clear_fifo_out1"); + UML_HANDLE(block, *m_clear_fifo_out1); + UML_MOV(block, FIFOOUT1_NUM, 0); + UML_MOV(block, FIFOOUT1_RPOS, 0); + UML_MOV(block, FIFOOUT1_WPOS, 0); + UML_RET(block); + + block->end(); + + // read fifo in + block = m_drcuml->begin_block(32); + alloc_handle(m_drcuml.get(), &m_read_fifo_in, "read_fifo_in"); + UML_HANDLE(block, *m_read_fifo_in); + UML_MOV(block, I1, FIFOIN_RPOS); + UML_LOAD(block, I0, m_core->fifoin.data, I1, SIZE_QWORD, SCALE_x8); + UML_ADD(block, I1, I1, 1); + UML_AND(block, I1, I1, FIFOIN_SIZE-1); + UML_MOV(block, FIFOIN_RPOS, I1); + UML_SUB(block, FIFOIN_NUM, FIFOIN_NUM, 1); + UML_RET(block); + + block->end(); + + // write fifo out0 + block = m_drcuml->begin_block(32); + alloc_handle(m_drcuml.get(), &m_write_fifo_out0, "write_fifo_out0"); + UML_HANDLE(block, *m_write_fifo_out0); + // TODO + UML_RET(block); + + block->end(); + + // write fifo out1 + block = m_drcuml->begin_block(32); + alloc_handle(m_drcuml.get(), &m_write_fifo_out1, "write_fifo_out1"); + UML_HANDLE(block, *m_write_fifo_out1); + // TODO + UML_RET(block); + + block->end(); +} + +void mb86235_device::static_generate_memory_accessors() +{ + drcuml_block *block; + code_label label = 1; + + // A-Bus read handler + // I0 = address + // I1 = return data + // I2 = trashed + block = m_drcuml->begin_block(128); + + alloc_handle(m_drcuml.get(), &m_read_abus, "read_abus"); + UML_HANDLE(block, *m_read_abus); + UML_CMP(block, I0, 0x400); + UML_JMPc(block, COND_GE, label); + // internal A-RAM + UML_SHL(block, I0, I0, 2); + UML_READ(block, I1, I0, SIZE_DWORD, SPACE_DATA); + UML_RET(block); + // external + UML_LABEL(block, label++); + UML_AND(block, I0, I0, 0x3fff); + UML_AND(block, I2, mem(&m_core->eb), ~0x3fff); + UML_OR(block, I0, I0, I2); + UML_SHL(block, I0, I0, 2); + UML_READ(block, I1, I0, SIZE_DWORD, SPACE_DATA); + UML_RET(block); + + block->end(); + + // A-Bus write handler + // I0 = address + // I1 = data + // I2 = trashed + block = m_drcuml->begin_block(128); + + alloc_handle(m_drcuml.get(), &m_write_abus, "write_abus"); + UML_HANDLE(block, *m_write_abus); + UML_CMP(block, I0, 0x400); + UML_JMPc(block, COND_GE, label); + // internal A-RAM + UML_SHL(block, I0, I0, 2); + UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_DATA); + UML_RET(block); + // external + UML_LABEL(block, label++); + UML_AND(block, I0, I0, 0x3fff); + UML_AND(block, I2, mem(&m_core->eb), ~0x3fff); + UML_OR(block, I0, I0, I2); + UML_SHL(block, I0, I0, 2); + UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_DATA); + UML_RET(block); + + block->end(); +} + + +void mb86235_device::flush_cache() +{ + /* empty the transient cache contents */ + m_drcuml->reset(); + + try + { + // generate the entry point and out-of-cycles handlers + static_generate_entry_point(); + static_generate_nocode_handler(); + static_generate_out_of_cycles(); + + // generate utility functions + static_generate_fifo(); + + // generate exception handlers + + // generate memory accessors + static_generate_memory_accessors(); + } + catch (drcuml_block::abort_compilation &) + { + fatalerror("Error generating MB86235 static handlers\n"); + } +} + + + +void mb86235_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + /* add an entry for the log */ + // if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) + // log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]); + + /* set the PC map variable */ + UML_MAPVAR(block, MAPVAR_PC, desc->pc); // mapvar PC,desc->pc + + /* accumulate total cycles */ + compiler->cycles += desc->cycles; + + /* update the icount map variable */ + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles + + /* if we are debugging, call the debugger */ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); // + UML_DEBUG(block, desc->pc); // debug desc->pc + } + + /* if we hit an unmapped address, fatal error */ + if (desc->flags & OPFLAG_COMPILER_UNMAPPED) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); // + UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE + } + + /* if this is an invalid opcode, generate the exception now */ + // if (desc->flags & OPFLAG_INVALID_OPCODE) + // UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000 + + /* unless this is a virtual no-op, it's a regular instruction */ + if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) + { + /* compile the instruction */ + if (!generate_opcode(block, compiler, desc)) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]); // dmov [arg64],*desc->opptr.q + UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented,ppc + } + } +} + +void mb86235_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, bool allow_exception) +{ + /* account for cycles */ + if (compiler->cycles > 0) + { + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), MAPVAR_CYCLES); // sub icount,icount,cycles + UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 + if (allow_exception) + UML_EXHc(block, COND_S, *m_out_of_cycles, param); // exh out_of_cycles,nextpc + } + compiler->cycles = 0; +} + + +void mb86235_device::generate_ea(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int md, int arx, int ary, int disp) +{ + // Calculates EA into register I0 + + switch (md) + { + case 0x1: // @ARx++ + UML_MOV(block, I0, AR(arx)); + UML_ADD(block, AR(arx), AR(arx), 1); + break; + case 0x4: // @ARx+ARy + UML_ADD(block, I0, AR(arx), AR(ary)); + break; + case 0xa: // @ARx+disp12 + UML_ADD(block, I0, AR(arx), disp); + break; + + default: + fatalerror("generate_ea: md = %02X, PC = %08X", md, desc->pc); + break; + } +} + + + +void mb86235_device::generate_reg_read(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int reg, uml::parameter dst) +{ + switch (reg) + { + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + // AA0-7 + UML_MOV(block, dst, AA(reg & 7)); + break; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + // AR0-7 + UML_MOV(block, dst, AR(reg & 7)); + break; + + case 0x30: // PR + UML_LOAD(block, dst, m_core->pr, PRP, SIZE_DWORD, SCALE_x4); + if (!(desc->userflags & OP_USERFLAG_ALU_PRP_UPDATE) && !(desc->userflags & OP_USERFLAG_MUL_PRP_UPDATE)) // alu/mul have priority on PRP update + { + UML_ADD(block, PRP, PRP, 1); + UML_CMP(block, PRP, 24); + UML_MOVc(block, COND_GE, PRP, 0); + } + break; + + case 0x31: // FI + UML_CALLH(block, *m_read_fifo_in); + UML_MOV(block, dst, I0); + break; + + default: + fatalerror("generate_reg_read: unimplemented register %02X at %08X", reg, desc->pc); + break; + } +} + + +void mb86235_device::generate_reg_write(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int reg, uml::parameter src) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + // MA0-7 + UML_MOV(block, MA(reg & 7), src); + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + // AA0-7 + UML_MOV(block, AA(reg & 7), src); + break; + + case 0x10: // EB + UML_MOV(block, mem(&m_core->eb), src); + break; + + case 0x13: // EO + UML_MOV(block, mem(&m_core->eo), src); + break; + + case 0x14: // SP + UML_MOV(block, mem(&m_core->sp), src); + break; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + // AR0-7 + UML_MOV(block, AR(reg & 7), src); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + // MB0-7 + UML_MOV(block, MB(reg & 7), src); + break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + // AB0-7 + UML_MOV(block, AB(reg & 7), src); + break; + + case 0x30: // PR + UML_STORE(block, m_core->pr, PWP, src, SIZE_DWORD, SCALE_x4); + if (!(desc->userflags & OP_USERFLAG_ALU_PWP_UPDATE) && !(desc->userflags & OP_USERFLAG_MUL_PWP_UPDATE)) // alu/mul have priority on PWP update + { + UML_ADD(block, PWP, PWP, 1); + UML_CMP(block, PWP, 24); + UML_MOVc(block, COND_GE, PWP, 0); + } + break; + + case 0x34: // PDR + UML_MOV(block, mem(&m_core->pdr), src); + break; + + case 0x35: // DDR + UML_MOV(block, mem(&m_core->ddr), src); + break; + + case 0x36: // PRP + UML_MOV(block, PRP, src); + break; + + case 0x37: // PWP + UML_MOV(block, PWP, src); + break; + + default: + fatalerror("generate_reg_write: unimplemented register %02X at %08X", reg, desc->pc); + break; + } +} + +bool mb86235_device::has_register_clash(const opcode_desc *desc, int outreg) +{ + switch (outreg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + // MA0-7 + if (desc->regin[0] & (1 << (16 + (outreg & 7)))) return true; + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + // MB0-7 + if (desc->regin[0] & (1 << (24 + (outreg & 7)))) return true; + break; + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + // AA0-7 + if (desc->regin[0] & (1 << (outreg & 7))) return true; + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + // AB0-7 + if (desc->regin[0] & (1 << (8 + (outreg & 7)))) return true; + break; + } + return false; +} + +bool mb86235_device::aluop_has_result(int aluop) +{ + switch (aluop) + { + case 0x04: // FCMP + case 0x07: // NOP + case 0x14: // CMP + return false; + + default: + break; + } + return true; +} + + + +bool mb86235_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + uint64_t opcode = desc->opptr.q[0]; + + bool fifoin_check = false; + bool fifoout0_check = false; + bool fifoout1_check = false; + + // enable fifo in check if this opcode or the delay slot reads from FIFO + if (desc->userflags & OP_USERFLAG_FIFOIN) + fifoin_check = true; + if (desc->delayslots > 0) + { + if (desc->delay.first()->userflags & OP_USERFLAG_FIFOIN) + fifoin_check = true; + } + + // enable fifoout0 check if this opcode or the delay slot writes to FIFO0 + if (desc->userflags & OP_USERFLAG_FIFOOUT0) + fifoout0_check = true; + if (desc->delayslots > 0) + { + if (desc->delay.first()->userflags & OP_USERFLAG_FIFOOUT0) + fifoout0_check = true; + } + + // enable fifoout1 check if this opcode or the delay slot writes to FIFO1 + if (desc->userflags & OP_USERFLAG_FIFOOUT1) + fifoout1_check = true; + if (desc->delayslots > 0) + { + if (desc->delay.first()->userflags & OP_USERFLAG_FIFOOUT1) + fifoout1_check = true; + } + + // insert FIFO IN check if needed + if (fifoin_check) + { + code_label not_empty = compiler->labelnum++; + UML_CMP(block, FIFOIN_NUM, 0); + UML_JMPc(block, COND_G, not_empty); + + UML_MOV(block, mem(&m_core->icount), 0); + UML_EXH(block, *m_out_of_cycles, desc->pc); + + UML_LABEL(block, not_empty); + } + + // insert FIFO OUT0 check if needed + if (fifoout0_check) + { + fatalerror("generate_opcode: fifoout0_check"); + } + + // insert FIFO OUT1 check if needed + if (fifoout1_check) + { + fatalerror("generate_opcode: fifoout1_check"); + } + + + switch ((opcode >> 61) & 7) + { + case 0: // ALU / MUL / double transfer (type 1) + { + bool alu_temp = has_register_clash(desc, (opcode >> 42) & 0x1f) && aluop_has_result((opcode >> 56) & 0x1f); + bool mul_temp = has_register_clash(desc, (opcode >> 27) & 0x1f); + generate_alu(block, compiler, desc, (opcode >> 42) & 0x7ffff, alu_temp); + generate_mul(block, compiler, desc, (opcode >> 27) & 0x7fff, mul_temp); + generate_double_xfer1(block, compiler, desc); + if (alu_temp) UML_MOV(block, get_alu_output((opcode >> 42) & 0x1f), mem(&m_core->alutemp)); + if (mul_temp) UML_MOV(block, get_alu_output((opcode >> 27) & 0x1f), mem(&m_core->multemp)); + break; + } + case 1: // ALU / MUL / transfer (type 1) + { + bool alu_temp = has_register_clash(desc, (opcode >> 42) & 0x1f) && aluop_has_result((opcode >> 56) & 0x1f); + bool mul_temp = has_register_clash(desc, (opcode >> 27) & 0x1f); + generate_alu(block, compiler, desc, (opcode >> 42) & 0x7ffff, alu_temp); + generate_mul(block, compiler, desc, (opcode >> 27) & 0x7fff, mul_temp); + generate_xfer1(block, compiler, desc); + if (alu_temp) UML_MOV(block, get_alu_output((opcode >> 42) & 0x1f), mem(&m_core->alutemp)); + if (mul_temp) UML_MOV(block, get_alu_output((opcode >> 27) & 0x1f), mem(&m_core->multemp)); + break; + } + case 2: // ALU / MUL / control + { + generate_pre_control(block, compiler, desc); + generate_alu(block, compiler, desc, (opcode >> 42) & 0x7ffff, false); + generate_mul(block, compiler, desc, (opcode >> 27) & 0x7fff, false); + generate_control(block, compiler, desc); + break; + } + case 4: // ALU or MUL / double transfer (type 2) + { + bool comp_temp; + if (opcode & ((uint64_t)(1) << 41)) + { + comp_temp = has_register_clash(desc, (opcode >> 42) & 0x1f) && aluop_has_result((opcode >> 56) & 0x1f); + generate_alu(block, compiler, desc, (opcode >> 42) & 0x7ffff, comp_temp); + } + else + { + comp_temp = has_register_clash(desc, (opcode >> 42) & 0x1f); + generate_mul(block, compiler, desc, (opcode >> 42) & 0x7fff, comp_temp); + } + generate_double_xfer2(block, compiler, desc); + if (comp_temp) + { + if (opcode & ((uint64_t)(1) << 41)) + UML_MOV(block, get_alu_output((opcode >> 42) & 0x1f), mem(&m_core->alutemp)); + else + UML_MOV(block, get_alu_output((opcode >> 42) & 0x1f), mem(&m_core->multemp)); + } + break; + } + case 5: // ALU or MUL / transfer (type 2) + { + bool comp_temp; + if (opcode & ((uint64_t)(1) << 41)) + { + comp_temp = has_register_clash(desc, (opcode >> 42) & 0x1f) && aluop_has_result((opcode >> 56) & 0x1f); + generate_alu(block, compiler, desc, (opcode >> 42) & 0x7ffff, comp_temp); + } + else + { + comp_temp = has_register_clash(desc, (opcode >> 42) & 0x1f); + generate_mul(block, compiler, desc, (opcode >> 42) & 0x7fff, comp_temp); + } + generate_xfer2(block, compiler, desc); + if (comp_temp) + { + if (opcode & ((uint64_t)(1) << 41)) + UML_MOV(block, get_alu_output((opcode >> 42) & 0x1f), mem(&m_core->alutemp)); + else + UML_MOV(block, get_alu_output((opcode >> 42) & 0x1f), mem(&m_core->multemp)); + } + break; + } + case 6: // ALU or MUL / control + { + generate_pre_control(block, compiler, desc); + if (opcode & ((uint64_t)(1) << 41)) + generate_alu(block, compiler, desc, (opcode >> 42) & 0x7ffff, false); + else + generate_mul(block, compiler, desc, (opcode >> 42) & 0x7fff, false); + generate_control(block, compiler, desc); + break; + } + case 7: // transfer (type 3) + { + generate_xfer3(block, compiler, desc); + break; + } + + default: + return false; + } + + // handle repeat + if (desc->userflags & OP_USERFLAG_REPEATED_OP) + { + code_label no_repeat = compiler->labelnum++; + UML_SUB(block, RPC, RPC, 1); + UML_CMP(block, RPC, 0); + UML_JMPc(block, COND_LE, no_repeat); + + generate_update_cycles(block, compiler, desc->pc, true); + if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) + UML_JMP(block, desc->pc | 0x80000000); + else + UML_HASHJMP(block, 0, desc->pc, *m_nocode); + + UML_LABEL(block, no_repeat); + } + + return true; +} + + + +void mb86235_device::generate_alumul_input(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int reg, uml::parameter dst, bool fp, bool mul) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + if (mul) + UML_MOV(block, dst, MA(reg & 7)); + else + UML_MOV(block, dst, AA(reg & 7)); + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + if (mul) + UML_MOV(block, dst, MB(reg & 7)); + else + UML_MOV(block, dst, AB(reg & 7)); + break; + + case 0x10: // PR + UML_LOAD(block, dst, m_core->pr, PRP, SIZE_DWORD, SCALE_x4); + UML_ADD(block, PWP, PWP, 1); + UML_CMP(block, PWP, 24); + UML_MOVc(block, COND_GE, PWP, 0); + break; + case 0x11: // PR++ + UML_LOAD(block, dst, m_core->pr, PRP, SIZE_DWORD, SCALE_x4); + UML_ADD(block, PRP, PRP, 1); + UML_CMP(block, PRP, 24); + UML_MOVc(block, COND_GE, PRP, 0); + break; + case 0x12: // PR-- + UML_LOAD(block, dst, m_core->pr, PRP, SIZE_DWORD, SCALE_x4); + UML_SUB(block, PRP, PRP, 1); + UML_CMP(block, PRP, 0); + UML_MOVc(block, COND_L, PRP, 23); + break; + case 0x13: // PR#0 + UML_LOAD(block, dst, m_core->pr, PRP, SIZE_DWORD, SCALE_x4); + UML_MOV(block, PRP, 0); + break; + + case 0x18: // 0 / -1.0E+0 + if (fp) + UML_MOV(block, dst, 0xbf800000); + else + UML_MOV(block, dst, 0); + break; + + case 0x19: // 1 / 0.0E+0 + if (fp) + UML_MOV(block, dst, 0); + else + UML_MOV(block, dst, 1); + break; + + case 0x1a: // -1 / 0.5+0 + if (fp) + UML_MOV(block, dst, 0x3f000000); + else + UML_MOV(block, dst, -1); + break; + + case 0x1b: // 1.0E+0 + UML_MOV(block, dst, 0x3f800000); + break; + + case 0x1c: // 1.5E+0 + UML_MOV(block, dst, 0x3fc00000); + break; + + case 0x1d: // 2.0E+0 + UML_MOV(block, dst, 0x40000000); + break; + + case 0x1e: // 3.0E+0 + UML_MOV(block, dst, 0x40400000); + break; + + case 0x1f: // 5.0E+0 + UML_MOV(block, dst, 0x40a00000); + break; + + default: + fatalerror("generate_alu_input: invalid register %02X", reg); + } +} + +uml::parameter mb86235_device::get_alu_output(int reg) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + return MA(reg & 7); + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + return MB(reg & 7); + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + return AA(reg & 7); + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + return AB(reg & 7); + } + return uml::parameter(0); +} + +uml::parameter mb86235_device::get_alu1_input(int reg) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + return AA(reg & 7); + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + return AB(reg & 7); + } + return uml::parameter(0); +} + +uml::parameter mb86235_device::get_mul1_input(int reg) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + return MA(reg & 7); + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + return MB(reg & 7); + } + return uml::parameter(0); +} + + + +void mb86235_device::generate_alu(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int aluop, bool alutemp) +{ + int i1 = (aluop >> 10) & 0xf; + int i2 = (aluop >> 5) & 0x1f; + int io = aluop & 0x1f; + int op = (aluop >> 14) & 0x1f; + + switch (op) + { + case 0x00: // FADD + generate_alumul_input(block, compiler, desc, i2, I0, true, false); + UML_FSCOPYI(block, F0, I0); + UML_FSCOPYI(block, F1, get_alu1_input(i1)); + UML_FSADD(block, F0, F0, F1); + UML_ICOPYFS(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), F0); + if (AN_CALC_REQUIRED || AZ_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + // TODO: AV flag + // TODO: AU flag + // TODO: AD flag + break; + + case 0x02: // FSUB + generate_alumul_input(block, compiler, desc, i2, I0, true, false); + UML_FSCOPYI(block, F0, I0); + UML_FSCOPYI(block, F1, get_alu1_input(i1)); + UML_FSSUB(block, F0, F0, F1); + UML_ICOPYFS(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), F0); + if (AN_CALC_REQUIRED || AZ_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + // TODO: AV flag + // TODO: AU flag + // TODO: AD flag + break; + + case 0x04: // FCMP + generate_alumul_input(block, compiler, desc, i2, I0, true, false); + UML_FSCOPYI(block, F0, I0); + UML_FSCOPYI(block, F1, get_alu1_input(i1)); + UML_FSCMP(block, F0, F1); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + // TODO: AV flag + // TODO: AU flag + // TODO: AD flag + break; + + case 0x05: // FABS + UML_AND(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), get_alu1_input(i1), 0x7fffffff); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + if (AN_CALC_REQUIRED) UML_MOV(block, FLAGS_AN, 0); + // TODO: AD flag + break; + + case 0x06: // FABC + generate_alumul_input(block, compiler, desc, i2, I0, true, false); + UML_AND(block, I0, I0, 0x7fffffff); + UML_AND(block, I1, get_alu1_input(i1), 0x7fffffff); + UML_FSCOPYI(block, F0, I0); + UML_FSCOPYI(block, F1, I1); + UML_FSCMP(block, F0, F1); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + if (AU_CALC_REQUIRED) UML_MOV(block, FLAGS_AU, 1); + // TODO: AD flag + break; + + case 0x07: // NOP + break; + + case 0x0d: // CIF + generate_alumul_input(block, compiler, desc, i1, I1, true, false); + UML_FSFRINT(block, F0, I1, SIZE_DWORD); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_CMP(block, I1, 0); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_L, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_E, FLAGS_AZ); + UML_ICOPYFS(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), F0); + break; + + case 0x0e: // CFI + { + code_label truncate = compiler->labelnum++; + code_label end = compiler->labelnum++; + UML_FSCOPYI(block, F0, get_alu1_input(i1)); + UML_TEST(block, mem(&m_core->mod), 0x80); + UML_JMPc(block, COND_Z, truncate); + UML_FSTOINT(block, I0, F0, SIZE_DWORD, ROUND_ROUND); + UML_JMP(block, end); + UML_LABEL(block, truncate); + UML_FSTOINT(block, I0, F0, SIZE_DWORD, ROUND_TRUNC); + UML_LABEL(block, end); + + UML_CMP(block, I0, 0xff800000); + UML_MOVc(block, COND_L, I0, 0xff800000); + if (AV_CALC_REQUIRED) UML_MOVc(block, COND_L, FLAGS_AV, 1); + UML_CMP(block, I0, 0x007fffff); + UML_MOVc(block, COND_G, I0, 0x007fffff); + if (AV_CALC_REQUIRED) UML_MOVc(block, COND_G, FLAGS_AV, 1); + if (AN_CALC_REQUIRED || AZ_CALC_REQUIRED) + UML_CMP(block, I0, 0); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_L, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + UML_MOV(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), I0); + break; + } + + case 0x10: // ADD + generate_alumul_input(block, compiler, desc, i2, I1, false, false); + UML_ADD(block, I0, I1, get_alu1_input(i1)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, FLAGS_AN); + UML_CMP(block, I0, 0xff800000); + UML_MOVc(block, COND_L, I0, 0xff800000); + if (AV_CALC_REQUIRED) UML_MOVc(block, COND_L, FLAGS_AV, 1); + UML_CMP(block, I0, 0x007fffff); + UML_MOVc(block, COND_G, I0, 0x007fffff); + if (AV_CALC_REQUIRED) UML_MOVc(block, COND_G, FLAGS_AV, 1); + UML_MOV(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), I0); + break; + + case 0x14: // CMP + generate_alumul_input(block, compiler, desc, i2, I1, false, false); + UML_SUB(block, I0, I1, get_alu1_input(i1)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, FLAGS_AN); + if (AV_CALC_REQUIRED) + { + UML_CMP(block, I0, 0xff800000); + UML_MOVc(block, COND_L, FLAGS_AV, 1); + UML_CMP(block, I0, 0x007fffff); + UML_MOVc(block, COND_G, FLAGS_AV, 1); + } + break; + + case 0x16: // ATR + UML_MOV(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), get_alu1_input(i1)); + break; + + case 0x18: // AND + generate_alumul_input(block, compiler, desc, i2, I0, false, false); + UML_AND(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), I0, get_alu1_input(i1)); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_AZ); + if (AV_CALC_REQUIRED) UML_MOV(block, FLAGS_AV, 0); + if (AU_CALC_REQUIRED) UML_MOV(block, FLAGS_AU, 0); + break; + + case 0x1c: // LSR + generate_alumul_input(block, compiler, desc, i1, I0, false, false); + UML_SHR(block, I0, I0, i2); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_CMP(block, I0, 0); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_L, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_E, FLAGS_AZ); + if (AV_CALC_REQUIRED) UML_MOV(block, FLAGS_AV, 0); + if (AU_CALC_REQUIRED) UML_MOV(block, FLAGS_AU, 0); + UML_MOV(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), I0); + break; + + case 0x1d: // LSL + generate_alumul_input(block, compiler, desc, i1, I0, false, false); + UML_SHL(block, I0, I0, i2); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_CMP(block, I0, 0); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_L, FLAGS_AN); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_E, FLAGS_AZ); + if (AV_CALC_REQUIRED) UML_MOV(block, FLAGS_AV, 0); + if (AU_CALC_REQUIRED) UML_MOV(block, FLAGS_AU, 0); + UML_MOV(block, alutemp ? mem(&m_core->alutemp) : get_alu_output(io), I0); + break; + + default: + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_MOV(block, mem(&m_core->arg0), op); + UML_CALLC(block, cfunc_unimplemented_alu, this); + break; + } +} + +void mb86235_device::generate_mul(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int mulop, bool multemp) +{ + int i1 = (mulop >> 10) & 0xf; + int i2 = (mulop >> 5) & 0x1f; + int io = mulop & 0x1f; + int m = mulop & 0x4000; + + if (m) + { + // FMUL + generate_alumul_input(block, compiler, desc, i2, I1, true, true); + UML_FSCOPYI(block, F1, I1); + UML_FSCOPYI(block, F0, get_mul1_input(i1)); + UML_FSMUL(block, F1, F0, F1); + if (MZ_CALC_REQUIRED || MN_CALC_REQUIRED) + UML_FSCMP(block, F1, mem(&m_core->fp0)); + if (MZ_CALC_REQUIRED) UML_SETc(block, COND_E, FLAGS_MZ); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, FLAGS_MN); + // TODO: MV flag + // TODO: MU flag + // TODO: MD flag + UML_ICOPYFS(block, multemp ? mem(&m_core->multemp) : get_alu_output(io), F1); + } + else + { + // MUL + generate_alumul_input(block, compiler, desc, i2, I1, false, true); + UML_MULS(block, I0, I0, I1, get_mul1_input(i1)); + if (MZ_CALC_REQUIRED) UML_SETc(block, COND_Z, FLAGS_MZ); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_S, FLAGS_MN); + UML_CMP(block, I0, 0xff800000); + UML_MOVc(block, COND_L, I0, 0xff800000); + if (MV_CALC_REQUIRED) UML_MOVc(block, COND_L, FLAGS_MV, 1); + UML_CMP(block, I0, 0x007fffff); + UML_MOVc(block, COND_G, I0, 0x007fffff); + if (MV_CALC_REQUIRED) UML_MOVc(block, COND_G, FLAGS_MV, 1); + UML_MOV(block, multemp ? mem(&m_core->multemp) : get_alu_output(io), I0); + } +} + + +void mb86235_device::generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + // I0 = target pc for dynamic branches + + compiler_state compiler_temp = *compiler; + + // save branch target + if (desc->targetpc == BRANCH_TARGET_DYNAMIC) + { + UML_MOV(block, mem(&m_core->jmpdest), I0); // mov [jmpdest],i0 + } + + // compile delay slots + generate_sequence_instruction(block, &compiler_temp, desc->delay.first()); + + // update cycles and hash jump + if (desc->targetpc != BRANCH_TARGET_DYNAMIC) + { + generate_update_cycles(block, &compiler_temp, desc->targetpc, true); + if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) + UML_JMP(block, desc->targetpc | 0x80000000); // jmp targetpc | 0x80000000 + else + UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp 0,targetpc,nocode + } + else + { + generate_update_cycles(block, &compiler_temp, mem(&m_core->jmpdest), true); + UML_HASHJMP(block, 0, mem(&m_core->jmpdest), *m_nocode); // hashjmp 0,jmpdest,nocode + } + + // update compiler label + compiler->labelnum = compiler_temp.labelnum; + + /* reset the mapvar to the current cycles and account for skipped slots */ + compiler->cycles += desc->skipslots; + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles +} + + +void mb86235_device::generate_branch_target(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int type, int ef2) +{ + // Calculates dynamic targets into I0 + + switch (type) + { + case 0x0: break; + case 0x1: break; + case 0x2: // ARx + { + int reg = (ef2 >> 6) & 7; + UML_MOV(block, I0, AR(reg)); + break; + } + default: + fatalerror("generate_branch_target: type %02X at %08X", type, desc->pc); + break; + } +} + + +void mb86235_device::generate_condition(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int cc, bool not, uml::code_label skip_label, bool condtemp) +{ + switch (cc) + { + case 0x00: // MN + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_MN, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x01: // MZ + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_MZ, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x02: // MV + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_MV, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x03: // MU + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_MU, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x04: // ZD + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_ZD, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x05: // NR + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_NR, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x06: // IL + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_IL, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x07: // ZC + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_ZC, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x08: // AN + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_AN, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x09: // AZ + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_AZ, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x0a: // AV + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_AV, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x0b: // AU + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_AU, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x0c: // MD + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_MD, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + case 0x0d: // AD + UML_CMP(block, condtemp ? mem(&m_core->condtemp) : FLAGS_AD, 0); + UML_JMPc(block, not ? COND_NE : COND_E, skip_label); + break; + default: + fatalerror("generate_condition: unimplemented cc %02X at %08X", cc, desc->pc); + break; + } +} + + +void mb86235_device::generate_control(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + uint64_t op = desc->opptr.q[0]; + int ef1 = (op >> 16) & 0x3f; + int ef2 = op & 0xffff; + int cop = (op >> 22) & 0x1f; + int rel12 = (op & 0x800) ? (0xfffff000 | (op & 0xfff)) : (op & 0xfff); + + switch (cop) + { + case 0x00: // NOP + break; + + case 0x03: // + if (ef1 == 1) // CLRFI + UML_CALLH(block, *m_clear_fifo_in); + else if (ef1 == 2) // CLRFO + { + UML_CALLH(block, *m_clear_fifo_out0); + UML_CALLH(block, *m_clear_fifo_out1); + } + else if (ef1 == 3) // CLRF + { + UML_CALLH(block, *m_clear_fifo_in); + UML_CALLH(block, *m_clear_fifo_out0); + UML_CALLH(block, *m_clear_fifo_out1); + } + break; + + case 0x08: // SETM #imm16 + UML_MOV(block, mem(&m_core->mod), ef2); + break; + + case 0x10: // DBcc + { + code_label skip_label = compiler->labelnum++; + + generate_branch_target(block, compiler, desc, (op >> 12) & 0xf, ef2); + generate_condition(block, compiler, desc, ef1, false, skip_label, true); + generate_branch(block, compiler, desc); + UML_LABEL(block, skip_label); + break; + } + + case 0x11: // DBNcc + { + code_label skip_label = compiler->labelnum++; + + generate_branch_target(block, compiler, desc, (op >> 12) & 0xf, ef2); + generate_condition(block, compiler, desc, ef1, true, skip_label, true); + generate_branch(block, compiler, desc); + UML_LABEL(block, skip_label); + break; + } + + case 0x12: // DJMP + { + generate_branch_target(block, compiler, desc, (op >> 12) & 0xf, ef2); + generate_branch(block, compiler, desc); + break; + } + + case 0x1a: // DCALL + { + // push PC + code_label no_overflow = compiler->labelnum++; + UML_CMP(block, mem(&m_core->pcs_ptr), 4); + UML_JMPc(block, COND_L, no_overflow); + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_CALLC(block, cfunc_pcs_overflow, this); + + UML_LABEL(block, no_overflow); + UML_STORE(block, m_core->pcs, mem(&m_core->pcs_ptr), desc->pc + 2, SIZE_DWORD, SCALE_x4); + UML_ADD(block, mem(&m_core->pcs_ptr), mem(&m_core->pcs_ptr), 1); + + generate_branch_target(block, compiler, desc, (op >> 12) & 0xf, ef2); + generate_branch(block, compiler, desc); + break; + } + + case 0x1b: // DRET + { + // pop PC + code_label no_underflow = compiler->labelnum++; + UML_CMP(block, mem(&m_core->pcs_ptr), 0); + UML_JMPc(block, COND_G, no_underflow); + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_CALLC(block, cfunc_pcs_underflow, this); + + UML_LABEL(block, no_underflow); + UML_SUB(block, mem(&m_core->pcs_ptr), mem(&m_core->pcs_ptr), 1); + UML_LOAD(block, I0, m_core->pcs, mem(&m_core->pcs_ptr), SIZE_DWORD, SCALE_x4); + + generate_branch(block, compiler, desc); + break; + } + + default: + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_MOV(block, mem(&m_core->arg0), cop); + UML_CALLC(block, cfunc_unimplemented_control, this); + break; + } +} + +void mb86235_device::generate_xfer1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]); + UML_CALLC(block, cfunc_unimplemented_xfer1, this); +} + +void mb86235_device::generate_double_xfer1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]); + UML_CALLC(block, cfunc_unimplemented_double_xfer1, this); +} + +void mb86235_device::generate_xfer2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + uint64_t opcode = desc->opptr.q[0]; + + int op = (opcode >> 39) & 3; + int trm = (opcode >> 38) & 1; + int dir = (opcode >> 37) & 1; + int sr = (opcode >> 31) & 0x7f; + int dr = (opcode >> 24) & 0x7f; + int ary = (opcode >> 4) & 7; + int md = opcode & 0xf; + + int disp14 = (opcode >> 7) & 0x3fff; + if (disp14 & 0x2000) disp14 |= 0xffffc000; + + if (op == 0) // MOV2 + { + if (trm == 0) + { + if (sr == 0x58) + { + // MOV2 #imm24, DR + generate_reg_write(block, compiler, desc, dr & 0x3f, uml::parameter(opcode & 0xffffff)); + } + else + { + if ((sr & 0x40) == 0) + { + generate_reg_read(block, compiler, desc, sr & 0x3f, I1); + } + else + { + generate_ea(block, compiler, desc, md, sr & 7, ary, disp14); + if (sr & 0x20) // RAM-B + { + UML_SHL(block, I0, I0, 2); + UML_READ(block, I1, I0, SIZE_DWORD, SPACE_IO); + } + else // RAM-A + { + UML_CALLH(block, *m_read_abus); + } + } + + if ((dr & 0x40) == 0) + { + generate_reg_write(block, compiler, desc, dr & 0x3f, I1); + } + else + { + generate_ea(block, compiler, desc, md, dr & 7, ary, disp14); + if (dr & 0x20) // RAM-B + { + UML_SHL(block, I0, I0, 2); + UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_IO); + } + else // RAM-A + { + UML_CALLH(block, *m_write_abus); + } + } + } + } + else + { + // external transfer + if (dir == 0) + { + generate_reg_read(block, compiler, desc, dr & 0x3f, I0); + UML_ADD(block, I1, mem(&m_core->eb), mem(&m_core->eo)); + UML_ADD(block, I1, I1, disp14); + UML_SHL(block, I1, I1, 2); + UML_WRITE(block, I1, I0, SIZE_DWORD, SPACE_DATA); + } + else + { + UML_ADD(block, I1, mem(&m_core->eb), mem(&m_core->eo)); + UML_ADD(block, I1, I1, disp14); + UML_SHL(block, I1, I1, 2); + UML_READ(block, I0, I1, SIZE_DWORD, SPACE_DATA); + generate_reg_write(block, compiler, desc, dr & 0x3f, I0); + } + + // update EO + UML_ADD(block, mem(&m_core->eo), mem(&m_core->eo), disp14); + } + } + else if (op == 2) // MOV4 + { + fatalerror("generate_xfer2 MOV4 at %08X (%08X%08X)", desc->pc, (uint32_t)(opcode >> 32), (uint32_t)(opcode)); + } +} + +void mb86235_device::generate_double_xfer2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]); + UML_CALLC(block, cfunc_unimplemented_double_xfer2, this); +} + +void mb86235_device::generate_xfer3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + uint64_t opcode = desc->opptr.q[0]; + + uint32_t imm = (uint32_t)(opcode >> 27); + int dr = (opcode >> 19) & 0x7f; + int ary = (opcode >> 4) & 7; + int md = opcode & 0xf; + + int disp = (opcode >> 7) & 0xfff; + if (disp & 0x800) disp |= 0xfffff800; + + switch (dr >> 5) + { + case 0: + case 1: // reg + generate_reg_write(block, compiler, desc, dr & 0x3f, uml::parameter(imm)); + break; + + case 2: // RAM-A + generate_ea(block, compiler, desc, md, dr & 7, ary, disp); + UML_MOV(block, I1, imm); + UML_CALLH(block, *m_write_abus); + break; + + case 3: // RAM-B + generate_ea(block, compiler, desc, md, dr & 7, ary, disp); + UML_SHL(block, I0, I0, 2); + UML_WRITE(block, I0, imm, SIZE_DWORD, SPACE_IO); + break; + } +} + + +void mb86235_device::generate_pre_control(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + uint64_t op = desc->opptr.q[0]; + int ef1 = (op >> 16) & 0x3f; + int ef2 = op & 0xffff; + int cop = (op >> 22) & 0x1f; + + switch (cop) + { + case 0x10: // DBcc + case 0x11: // DBNcc + case 0x18: // DCcc + case 0x19: // DCNcc + switch (ef1) + { + case 0x00: UML_MOV(block, mem(&m_core->condtemp), FLAGS_MN); break; // MN + case 0x01: UML_MOV(block, mem(&m_core->condtemp), FLAGS_MZ); break; // MZ + case 0x02: UML_MOV(block, mem(&m_core->condtemp), FLAGS_MV); break; // MV + case 0x03: UML_MOV(block, mem(&m_core->condtemp), FLAGS_MU); break; // MU + case 0x04: UML_MOV(block, mem(&m_core->condtemp), FLAGS_ZD); break; // ZD + case 0x05: UML_MOV(block, mem(&m_core->condtemp), FLAGS_NR); break; // NR + case 0x06: UML_MOV(block, mem(&m_core->condtemp), FLAGS_IL); break; // IL + case 0x07: UML_MOV(block, mem(&m_core->condtemp), FLAGS_ZC); break; // ZC + case 0x08: UML_MOV(block, mem(&m_core->condtemp), FLAGS_AN); break; // AN + case 0x09: UML_MOV(block, mem(&m_core->condtemp), FLAGS_AZ); break; // AZ + case 0x0a: UML_MOV(block, mem(&m_core->condtemp), FLAGS_AV); break; // AV + case 0x0b: UML_MOV(block, mem(&m_core->condtemp), FLAGS_AU); break; // AU + case 0x0c: UML_MOV(block, mem(&m_core->condtemp), FLAGS_MD); break; // MD + case 0x0d: UML_MOV(block, mem(&m_core->condtemp), FLAGS_AD); break; // AD + default: + fatalerror("generate_pre_control: unimplemented cc %02X at %08X", ef1, desc->pc); + break; + } + break; + + case 0x14: // DBBC ARx:y, rel12 + // TODO: copy ARx + UML_MOV(block, mem(&m_core->condtemp), AR((ef2 >> 13) & 7)); + break; + + case 0x15: // DBBS ARx:y, rel12 + // TODO: copy ARx + UML_MOV(block, mem(&m_core->condtemp), AR((ef2 >> 13) & 7)); + break; + + default: + break; + } +} diff --git a/src/devices/cpu/mb86235/mb86235fe.cpp b/src/devices/cpu/mb86235/mb86235fe.cpp new file mode 100644 index 00000000000..7bebe4b06dd --- /dev/null +++ b/src/devices/cpu/mb86235/mb86235fe.cpp @@ -0,0 +1,845 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde + +/****************************************************************************** + + Front-end for MB86235 recompiler + +******************************************************************************/ + +#include "emu.h" +#include "mb86235fe.h" + + +#define AA_USED(desc,x) do { (desc).regin[0] |= 1 << (x); } while(0) +#define AA_MODIFIED(desc,x) do { (desc).regout[0] |= 1 << (x); } while(0) +#define AB_USED(desc,x) do { (desc).regin[0] |= 1 << (8+x); } while(0) +#define AB_MODIFIED(desc,x) do { (desc).regout[0] |= 1 << (8+x); } while(0) +#define MA_USED(desc,x) do { (desc).regin[0] |= 1 << (16+x); } while(0) +#define MA_MODIFIED(desc,x) do { (desc).regout[0] |= 1 << (16+x); } while(0) +#define MB_USED(desc,x) do { (desc).regin[0] |= 1 << (24+x); } while(0) +#define MB_MODIFIED(desc,x) do { (desc).regout[0] |= 1 << (24+x); } while(0) +#define AR_USED(desc,x) do { (desc).regin[1] |= 1 << (24+x); } while(0) +#define AR_MODIFIED(desc,x) do { (desc).regout[1] |= 1 << (24+x); } while(0) + +#define AZ_USED(desc) do { (desc).regin[1] |= 1 << 0; } while (0) +#define AZ_MODIFIED(desc) do { (desc).regout[1] |= 1 << 0; } while (0) +#define AN_USED(desc) do { (desc).regin[1] |= 1 << 1; } while (0) +#define AN_MODIFIED(desc) do { (desc).regout[1] |= 1 << 1; } while (0) +#define AV_USED(desc) do { (desc).regin[1] |= 1 << 2; } while (0) +#define AV_MODIFIED(desc) do { (desc).regout[1] |= 1 << 2; } while (0) +#define AU_USED(desc) do { (desc).regin[1] |= 1 << 3; } while (0) +#define AU_MODIFIED(desc) do { (desc).regout[1] |= 1 << 3; } while (0) +#define AD_USED(desc) do { (desc).regin[1] |= 1 << 4; } while (0) +#define AD_MODIFIED(desc) do { (desc).regout[1] |= 1 << 4; } while (0) +#define ZC_USED(desc) do { (desc).regin[1] |= 1 << 5; } while (0) +#define ZC_MODIFIED(desc) do { (desc).regout[1] |= 1 << 5; } while (0) +#define IL_USED(desc) do { (desc).regin[1] |= 1 << 6; } while (0) +#define IL_MODIFIED(desc) do { (desc).regout[1] |= 1 << 6; } while (0) +#define NR_USED(desc) do { (desc).regin[1] |= 1 << 7; } while (0) +#define NR_MODIFIED(desc) do { (desc).regout[1] |= 1 << 7; } while (0) +#define ZD_USED(desc) do { (desc).regin[1] |= 1 << 8; } while (0) +#define ZD_MODIFIED(desc) do { (desc).regout[1] |= 1 << 8; } while (0) +#define MN_USED(desc) do { (desc).regin[1] |= 1 << 9; } while (0) +#define MN_MODIFIED(desc) do { (desc).regout[1] |= 1 << 9; } while (0) +#define MZ_USED(desc) do { (desc).regin[1] |= 1 << 10; } while (0) +#define MZ_MODIFIED(desc) do { (desc).regout[1] |= 1 << 10; } while (0) +#define MV_USED(desc) do { (desc).regin[1] |= 1 << 11; } while (0) +#define MV_MODIFIED(desc) do { (desc).regout[1] |= 1 << 11; } while (0) +#define MU_USED(desc) do { (desc).regin[1] |= 1 << 12; } while (0) +#define MU_MODIFIED(desc) do { (desc).regout[1] |= 1 << 12; } while (0) +#define MD_USED(desc) do { (desc).regin[1] |= 1 << 13; } while (0) +#define MD_MODIFIED(desc) do { (desc).regout[1] |= 1 << 13; } while (0) + + +mb86235_frontend::mb86235_frontend(mb86235_device *core, uint32_t window_start, uint32_t window_end, uint32_t max_sequence) + : drc_frontend(*core, window_start, window_end, max_sequence), + m_core(core) +{ +} + + +bool mb86235_frontend::describe(opcode_desc &desc, const opcode_desc *prev) +{ + uint64_t opcode = desc.opptr.q[0] = m_core->m_direct->read_qword(desc.pc * 8, 0); + + desc.length = 1; + desc.cycles = 1; + + // repeatable instruction needs an entry point + if (prev != nullptr) + { + if (prev->userflags & OP_USERFLAG_REPEAT) + { + desc.flags |= OPFLAG_IS_BRANCH_TARGET; + desc.userflags |= OP_USERFLAG_REPEATED_OP; + } + } + + switch ((opcode >> 61) & 7) + { + case 0: // ALU / MUL / double transfer (type 1) + describe_alu(desc, (opcode >> 42) & 0x7ffff); + describe_mul(desc, (opcode >> 27) & 0x7fff); + describe_double_xfer1(desc); + break; + case 1: // ALU / MUL / transfer (type 1) + describe_alu(desc, (opcode >> 42) & 0x7ffff); + describe_mul(desc, (opcode >> 27) & 0x7fff); + describe_xfer1(desc); + break; + case 2: // ALU / MUL / control + describe_alu(desc, (opcode >> 42) & 0x7ffff); + describe_mul(desc, (opcode >> 27) & 0x7fff); + describe_control(desc); + break; + case 4: // ALU or MUL / double transfer (type 2) + if (opcode & ((uint64_t)(1) << 41)) + describe_alu(desc, (opcode >> 42) & 0x7ffff); + else + describe_mul(desc, (opcode >> 42) & 0x7fff); + describe_double_xfer2(desc); + break; + case 5: // ALU or MUL / transfer (type 2) + if (opcode & ((uint64_t)(1) << 41)) + describe_alu(desc, (opcode >> 42) & 0x7ffff); + else + describe_mul(desc, (opcode >> 42) & 0x7fff); + describe_xfer2(desc); + break; + case 6: // ALU or MUL / control + if (opcode & ((uint64_t)(1) << 41)) + describe_alu(desc, (opcode >> 42) & 0x7ffff); + else + describe_mul(desc, (opcode >> 42) & 0x7fff); + describe_control(desc); + break; + case 7: // transfer (type 3) + describe_xfer3(desc); + break; + + default: + return false; + } + + return true; +} + +void mb86235_frontend::describe_alu_input(opcode_desc &desc, int reg) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + AA_USED(desc, reg & 7); + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + AB_USED(desc, reg & 7); + break; + + case 0x10: // PR + case 0x11: // PR++ + case 0x12: // PR-- + case 0x13: // PR#0 + desc.userflags |= OP_USERFLAG_ALU_PRP_UPDATE; + break; + + + default: + break; + } +} + +void mb86235_frontend::describe_mul_input(opcode_desc &desc, int reg) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + MA_USED(desc, reg & 7); + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + MB_USED(desc, reg & 7); + break; + + case 0x10: // PR + case 0x11: // PR++ + case 0x12: // PR-- + case 0x13: // PR#0 + desc.userflags |= OP_USERFLAG_MUL_PRP_UPDATE; + break; + + default: + break; + } +} + +void mb86235_frontend::describe_alumul_output(opcode_desc &desc, int reg) +{ + switch (reg >> 3) + { + case 0: + MA_MODIFIED(desc, reg & 7); + break; + + case 1: + MB_MODIFIED(desc, reg & 7); + break; + + case 2: + AA_MODIFIED(desc, reg & 7); + break; + + case 3: + AB_MODIFIED(desc, reg & 7); + break; + + default: + break; + } +} + +void mb86235_frontend::describe_reg_read(opcode_desc &desc, int reg) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + // MA0-7 + MA_USED(desc, reg & 7); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + // AA0-7 + AA_USED(desc, reg & 7); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + // AR0-7 + AR_USED(desc, reg & 7); + break; + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + // MB0-7 + MB_USED(desc, reg & 7); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + // AB0-7 + AB_USED(desc, reg & 7); + break; + + case 0x31: // FI + desc.userflags |= OP_USERFLAG_FIFOIN; + desc.flags |= OPFLAG_IS_BRANCH_TARGET; // fifo check makes this a branch target + break; + + case 0x32: // FO0 + break; + case 0x33: // FO1 + break; + + case 0x10: // EB + case 0x11: // EBU + case 0x12: // EBL + case 0x13: // EO + case 0x15: // ST + case 0x16: // MOD + case 0x17: // LRPC + case 0x34: // PDR + case 0x35: // DDR + case 0x36: // PRP + case 0x37: // PWP + break; + + case 0x30: // PR + desc.userflags |= OP_USERFLAG_XFER_PRP_UPDATE; + break; + } +} + +void mb86235_frontend::describe_reg_write(opcode_desc &desc, int reg) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + // MA0-7 + MA_MODIFIED(desc, reg & 7); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + // AA0-7 + AA_MODIFIED(desc, reg & 7); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + // AR0-7 + AR_MODIFIED(desc, reg & 7); + break; + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + // MB0-7 + MB_MODIFIED(desc, reg & 7); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + // AB0-7 + AB_MODIFIED(desc, reg & 7); + break; + + case 0x31: // FI + break; + + case 0x32: // FO0 + desc.userflags |= OP_USERFLAG_FIFOOUT0; + desc.flags |= OPFLAG_IS_BRANCH_TARGET; // fifo check makes this a branch target + break; + case 0x33: // FO1 + desc.userflags |= OP_USERFLAG_FIFOOUT1; + desc.flags |= OPFLAG_IS_BRANCH_TARGET; // fifo check makes this a branch target + break; + + case 0x10: // EB + case 0x11: // EBU + case 0x12: // EBL + case 0x13: // EO + case 0x15: // ST + case 0x16: // MOD + case 0x17: // LRPC + case 0x34: // PDR + case 0x35: // DDR + case 0x36: // PRP + case 0x37: // PWP + break; + + case 0x30: // PR + desc.userflags |= OP_USERFLAG_XFER_PWP_UPDATE; + break; + } +} + + +void mb86235_frontend::describe_alu(opcode_desc &desc, uint32_t aluop) +{ + int i1 = (aluop >> 10) & 0xf; + int i2 = (aluop >> 5) & 0x1f; + int io = aluop & 0x1f; + int op = (aluop >> 14) & 0x1f; + + switch (op) + { + case 0x00: // FADD + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + break; + case 0x01: // FADDZ + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + ZC_MODIFIED(desc); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x02: // FSUB + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x03: // FSUBZ + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + ZC_MODIFIED(desc); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x04: // FCMP + describe_alu_input(desc, i1); describe_alu_input(desc, i2); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x05: // FABS + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x06: // FABC + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AU_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x07: // NOP + break; + case 0x08: // FEA + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x09: // FES + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AU_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x0a: // FRCP + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + ZD_MODIFIED(desc); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AU_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x0b: // FRSQ + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + NR_MODIFIED(desc); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AU_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x0c: // FLOG + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + IL_MODIFIED(desc); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x0d: // CIF + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + break; + case 0x0e: // CFI + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AD_MODIFIED(desc); + break; + case 0x0f: // CFIB + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AD_MODIFIED(desc); + AU_MODIFIED(desc); + break; + case 0x10: // ADD + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + break; + case 0x11: // ADDZ + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + ZC_MODIFIED(desc); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + break; + case 0x12: // SUB + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + break; + case 0x13: // SUBZ + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + ZC_MODIFIED(desc); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + break; + case 0x14: // CMP + describe_alu_input(desc, i1); describe_alu_input(desc, i2); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + break; + case 0x15: // ABS + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + break; + case 0x16: // ATR + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + break; + case 0x17: // ATRZ + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + ZC_MODIFIED(desc); + break; + case 0x18: // AND + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + break; + case 0x19: // OR + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + break; + case 0x1a: // XOR + describe_alu_input(desc, i1); describe_alu_input(desc, i2); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + break; + case 0x1b: // NOT + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + break; + case 0x1c: // LSR + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + break; + case 0x1d: // LSL + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + AV_MODIFIED(desc); + AU_MODIFIED(desc); + break; + case 0x1e: // ASR + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + break; + case 0x1f: // ASL + describe_alu_input(desc, i1); describe_alumul_output(desc, io); + AN_MODIFIED(desc); + AZ_MODIFIED(desc); + break; + } +} + +void mb86235_frontend::describe_mul(opcode_desc &desc, uint32_t mulop) +{ + int i1 = (mulop >> 10) & 0xf; + int i2 = (mulop >> 5) & 0x1f; + int io = mulop & 0x1f; + int m = mulop & 0x4000; + + describe_mul_input(desc, i1); + describe_mul_input(desc, i2); + describe_alumul_output(desc, io); + + if (m) + { + // FMUL + MN_MODIFIED(desc); + MZ_MODIFIED(desc); + MV_MODIFIED(desc); + MU_MODIFIED(desc); + MD_MODIFIED(desc); + } + else + { + // MUL + MN_MODIFIED(desc); + MZ_MODIFIED(desc); + MV_MODIFIED(desc); + } +} + +void mb86235_frontend::describe_ea(opcode_desc &desc, int md, int arx, int ary, int disp) +{ + switch (md) + { + case 0x0: // @ARx + AR_USED(desc, arx); + break; + case 0x1: // @ARx++ + AR_USED(desc, arx); AR_MODIFIED(desc, arx); + break; + case 0x2: // @ARx-- + AR_USED(desc, arx); AR_MODIFIED(desc, arx); + break; + case 0x3: // @ARx++disp + AR_USED(desc, arx); AR_MODIFIED(desc, arx); + break; + case 0x4: // @ARx+ARy + AR_USED(desc, arx); AR_USED(desc, ary); + break; + case 0x5: // @ARx+ARy++ + AR_USED(desc, arx); AR_USED(desc, ary); AR_MODIFIED(desc, ary); + break; + case 0x6: // @ARx+ARy-- + AR_USED(desc, arx); AR_USED(desc, ary); AR_MODIFIED(desc, ary); + break; + case 0x7: // @ARx+ARy++disp + AR_USED(desc, arx); AR_USED(desc, ary); AR_MODIFIED(desc, ary); + break; + case 0x8: // @ARx+ARyU + AR_USED(desc, arx); AR_USED(desc, ary); + break; + case 0x9: // @ARx+ARyL + AR_USED(desc, arx); AR_USED(desc, ary); + break; + case 0xa: // @ARx+disp + AR_USED(desc, arx); + break; + case 0xb: // @ARx+ARy+disp + AR_USED(desc, arx); AR_USED(desc, ary); + break; + case 0xc: // @disp + break; + case 0xd: // @ARx+[ARy++] + AR_USED(desc, arx); AR_USED(desc, ary); AR_MODIFIED(desc, ary); + break; + case 0xe: // @ARx+[ARy--] + AR_USED(desc, arx); AR_USED(desc, ary); AR_MODIFIED(desc, ary); + break; + case 0xf: // @ARx+[ARy++disp] + AR_USED(desc, arx); AR_USED(desc, ary); AR_MODIFIED(desc, ary); + break; + } +} + +void mb86235_frontend::describe_xfer1(opcode_desc &desc) +{ + uint64_t opcode = desc.opptr.q[0]; + fatalerror("mb86235_frontend: describe_xfer1 at %08X (%08X%08X)", desc.pc, (uint32_t)(opcode >> 32), (uint32_t)(opcode)); +} + +void mb86235_frontend::describe_double_xfer1(opcode_desc &desc) +{ + uint64_t opcode = desc.opptr.q[0]; + fatalerror("mb86235_frontend: describe_double_xfer1 at %08X (%08X%08X)", desc.pc, (uint32_t)(opcode >> 32), (uint32_t)(opcode)); +} + +void mb86235_frontend::describe_xfer2(opcode_desc &desc) +{ + uint64_t opcode = desc.opptr.q[0]; + + int op = (opcode >> 39) & 3; + int trm = (opcode >> 38) & 1; + int dir = (opcode >> 37) & 1; + int sr = (opcode >> 31) & 0x7f; + int dr = (opcode >> 24) & 0x7f; + int ary = (opcode >> 4) & 7; + int md = opcode & 0xf; + int disp14 = (opcode >> 7) & 0x3fff; + + if (op == 0) // MOV2 + { + if (trm == 0) + { + if ((sr & 0x40) == 0) + { + describe_reg_read(desc, sr & 0x3f); + } + else if (sr == 0x58) + { + // MOV2 #imm24, DR + } + else + { + describe_ea(desc, md, sr & 7, ary, disp14); + desc.flags |= OPFLAG_READS_MEMORY; + } + + if ((dr & 0x40) == 0) + { + describe_reg_write(desc, dr & 0x3f); + } + else + { + describe_ea(desc, md, dr & 7, ary, disp14); + desc.flags |= OPFLAG_WRITES_MEMORY; + } + } + else + { + // external transfer + if (dir == 0) + { + describe_reg_read(desc, dr & 0x3f); + desc.flags |= OPFLAG_WRITES_MEMORY; + } + else + { + describe_reg_write(desc, dr & 0x3f); + desc.flags |= OPFLAG_READS_MEMORY; + } + } + } + else if (op == 2) // MOV4 + { + fatalerror("mb86235_frontend: describe_xfer2 MOV4 at %08X (%08X%08X)", desc.pc, (uint32_t)(opcode >> 32), (uint32_t)(opcode)); + } + +} + +void mb86235_frontend::describe_double_xfer2(opcode_desc &desc) +{ + uint64_t opcode = desc.opptr.q[0]; + fatalerror("mb86235_frontend: describe_double_xfer2 at %08X (%08X%08X)", desc.pc, (uint32_t)(opcode >> 32), (uint32_t)(opcode)); +} + +void mb86235_frontend::describe_xfer3(opcode_desc &desc) +{ + uint64_t opcode = desc.opptr.q[0]; + + int dr = (opcode >> 19) & 0x7f; + int disp = (opcode >> 7) & 0xfff; + int ary = (opcode >> 4) & 7; + int md = opcode & 0xf; + + switch (dr >> 4) + { + case 0: + case 1: // reg + describe_reg_write(desc, dr & 0x3f); + break; + + case 2: // RAM-A + case 3: // RAM-B + desc.flags |= OPFLAG_WRITES_MEMORY; + describe_ea(desc, md, dr & 7, ary, disp); + break; + } +} + +void mb86235_frontend::describe_control(opcode_desc &desc) +{ + int ef1 = (desc.opptr.q[0] >> 16) & 0x3f; + int ef2 = desc.opptr.q[0] & 0xffff; + int cop = (desc.opptr.q[0] >> 22) & 0x1f; + int rel12 = (desc.opptr.q[0] & 0x800) ? (0xfffff000 | (desc.opptr.q[0] & 0xfff)) : (desc.opptr.q[0] & 0xfff); + + switch (cop) + { + case 0x00: // NOP + break; + case 0x01: // REP + if (ef1 != 0) // ARx + AR_USED(desc, (ef2 >> 12) & 7); + + desc.userflags |= OP_USERFLAG_REPEAT; + break; + case 0x02: // SETL + if (ef1 != 0) // ARx + AR_USED(desc, (ef2 >> 12) & 7); + break; + case 0x03: // CLRFI/CLRFO/CLRF + break; + case 0x04: // PUSH + describe_reg_read(desc, (ef2 >> 6) & 0x3f); + break; + case 0x05: // POP + describe_reg_write(desc, (ef2 >> 6) & 0x3f); + break; + case 0x08: // SETM #imm16 + break; + case 0x09: // SETM #imm3, CBSA + break; + case 0x0a: // SETM #imm3, CBSB + break; + case 0x0b: // SETM #imm1, RF + break; + case 0x0c: // SETM #imm1, RDY + break; + case 0x0d: // SETM #imm1, WAIT + break; + case 0x13: // DBLP rel12 + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + rel12; + desc.delayslots = 1; + break; + case 0x14: // DBBC ARx:y, rel12 + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + rel12; + desc.delayslots = 1; + AR_USED(desc, ((desc.opptr.q[0] >> 13) & 7)); + break; + case 0x15: // DBBS ARx:y, rel12 + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + rel12; + desc.delayslots = 1; + AR_USED(desc, ((desc.opptr.q[0] >> 13) & 7)); + break; + case 0x1b: // DRET + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + break; + + case 0x10: // DBcc + case 0x11: // DBNcc + case 0x18: // DCcc + case 0x19: // DCNcc + { + switch ((desc.opptr.q[0] >> 12) & 0xf) + { + case 0x0: desc.targetpc = ef2 & 0xfff; break; + case 0x1: desc.targetpc = desc.pc + rel12; break; + case 0x2: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x3: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x4: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x5: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x6: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x7: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x8: desc.targetpc = BRANCH_TARGET_DYNAMIC; break; + case 0x9: desc.targetpc = BRANCH_TARGET_DYNAMIC; break; + case 0xa: desc.targetpc = BRANCH_TARGET_DYNAMIC; break; + case 0xb: desc.targetpc = BRANCH_TARGET_DYNAMIC; break; + case 0xc: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0xd: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0xe: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0xf: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + } + + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.delayslots = 1; + break; + } + + case 0x1a: // DCALL + case 0x12: // DJMP + { + switch ((desc.opptr.q[0] >> 12) & 0xf) + { + case 0x0: desc.targetpc = ef2 & 0xfff; break; + case 0x1: desc.targetpc = desc.pc + rel12; break; + case 0x2: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x3: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x4: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x5: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x6: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x7: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0x8: desc.targetpc = BRANCH_TARGET_DYNAMIC; break; + case 0x9: desc.targetpc = BRANCH_TARGET_DYNAMIC; break; + case 0xa: desc.targetpc = BRANCH_TARGET_DYNAMIC; break; + case 0xb: desc.targetpc = BRANCH_TARGET_DYNAMIC; break; + case 0xc: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0xd: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0xe: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + case 0xf: desc.targetpc = BRANCH_TARGET_DYNAMIC; describe_reg_read(desc, (ef2 >> 6) & 0x3f); break; + } + + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.delayslots = 1; + break; + } + } +} \ No newline at end of file diff --git a/src/devices/cpu/mb86235/mb86235fe.h b/src/devices/cpu/mb86235/mb86235fe.h new file mode 100644 index 00000000000..ef8bff02df8 --- /dev/null +++ b/src/devices/cpu/mb86235/mb86235fe.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde + +/****************************************************************************** + + Front-end for MB86235 recompiler + +******************************************************************************/ + +#pragma once + +#include "mb86235.h" +#include "cpu/drcfe.h" + +#ifndef __MB86235FE_H__ +#define __MB86235FE_H__ + +class mb86235_frontend : public drc_frontend +{ +public: + mb86235_frontend(mb86235_device *core, uint32_t window_start, uint32_t window_end, uint32_t max_sequence); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override; + +private: + + mb86235_device *m_core; + + void describe_alu(opcode_desc &desc, uint32_t aluop); + void describe_mul(opcode_desc &desc, uint32_t mulop); + void describe_xfer1(opcode_desc &desc); + void describe_double_xfer1(opcode_desc &desc); + void describe_xfer2(opcode_desc &desc); + void describe_double_xfer2(opcode_desc &desc); + void describe_xfer3(opcode_desc &desc); + void describe_control(opcode_desc &desc); + void describe_alu_input(opcode_desc &desc, int reg); + void describe_mul_input(opcode_desc &desc, int reg); + void describe_alumul_output(opcode_desc &desc, int reg); + void describe_reg_read(opcode_desc &desc, int reg); + void describe_reg_write(opcode_desc &desc, int reg); + void describe_ea(opcode_desc &desc, int md, int arx, int ary, int disp); +}; + +#endif /* __MB86235FE_H__ */ diff --git a/src/mame/drivers/model2.cpp b/src/mame/drivers/model2.cpp index a39977bc375..82d693dfca4 100644 --- a/src/mame/drivers/model2.cpp +++ b/src/mame/drivers/model2.cpp @@ -752,14 +752,42 @@ WRITE32_MEMBER(model2_state::copro_function_port_w) //logerror("copro_function_port_w: %08X, %08X, %08X\n", data, offset, mem_mask); if (m_dsp_type == DSP_TYPE_SHARC) copro_fifoin_push(machine().device("dsp"), d,offset,mem_mask); - else + else if (m_dsp_type == DSP_TYPE_TGP) copro_fifoin_push(machine().device("tgp"), d,offset,mem_mask); + else if (m_dsp_type == DSP_TYPE_TGPX4) + { + if (m_tgpx4->is_fifoin_full()) + printf("trying to push to full fifo! (function port)\n"); + + m_tgpx4->fifoin_w(d); + } } READ32_MEMBER(model2_state::copro_fifo_r) { //logerror("copro_fifo_r: %08X, %08X\n", offset, mem_mask); - return copro_fifoout_pop(space,offset,mem_mask); + if (m_dsp_type == DSP_TYPE_SHARC || m_dsp_type == DSP_TYPE_TGP) + { + return copro_fifoout_pop(space, offset, mem_mask); + } + else + { + // TODO + printf("FIFO OUT read\n"); + if (m_tgpx4->is_fifoout0_empty()) + { + /* Reading from empty FIFO causes the i960 to enter wait state */ + downcast(space.device()).i960_stall(); + /* spin the main cpu and let the TGP catch up */ + space.device().execute().spin_until_time(attotime::from_usec(100)); + printf("stalled\n"); + } + else + { + return (uint32_t)(m_tgpx4->fifoout0_r()); + } + } + return 0; } WRITE32_MEMBER(model2_state::copro_fifo_w) @@ -774,6 +802,19 @@ WRITE32_MEMBER(model2_state::copro_fifo_w) { m_tgp_program[m_coprocnt] = data; } + else if (m_dsp_type == DSP_TYPE_TGPX4) + { + if (m_coprocnt & 1) + { + m_tgpx4_program[m_coprocnt / 2] &= 0xffffffffU; + m_tgpx4_program[m_coprocnt / 2] |= u64(data) << 32; + } + else + { + m_tgpx4_program[m_coprocnt / 2] &= 0xffffffff00000000U; + m_tgpx4_program[m_coprocnt / 2] |= data; + } + } m_coprocnt++; } @@ -785,8 +826,16 @@ WRITE32_MEMBER(model2_state::copro_fifo_w) //osd_printf_debug("copro_fifo_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, space.device().safe_pc()); if (m_dsp_type == DSP_TYPE_SHARC) copro_fifoin_push(machine().device("dsp"), data,offset,mem_mask); - else + else if (m_dsp_type == DSP_TYPE_TGP) copro_fifoin_push(machine().device("tgp"), data,offset,mem_mask); + else if (m_dsp_type == DSP_TYPE_TGPX4) + { + if (m_tgpx4->is_fifoin_full()) + printf("trying to push to full fifo!\n"); + + printf("push %08X at %08X\n", data, space.device().safe_pc()); + m_tgpx4->fifoin_w(data); + } } } @@ -1624,7 +1673,8 @@ static ADDRESS_MAP_START( model2c_crx_mem, AS_PROGRAM, 32, model2_state ) AM_RANGE(0x00200000, 0x0023ffff) AM_RAM AM_RANGE(0x00804000, 0x00807fff) AM_READWRITE(geo_prg_r, geo_prg_w) - AM_RANGE(0x00884000, 0x00887fff) AM_READWRITE(copro_prg_r, copro_prg_w) + AM_RANGE(0x00880000, 0x00883fff) AM_WRITE(copro_function_port_w) + AM_RANGE(0x00884000, 0x00887fff) AM_READWRITE(copro_fifo_r, copro_fifo_w) AM_RANGE(0x00980000, 0x00980003) AM_READWRITE(copro_ctl1_r,copro_ctl1_w) AM_RANGE(0x00980008, 0x0098000b) AM_WRITE(geo_ctl1_w ) diff --git a/src/mame/includes/model2.h b/src/mame/includes/model2.h index 09348dd51af..8fc3829aa4d 100644 --- a/src/mame/includes/model2.h +++ b/src/mame/includes/model2.h @@ -5,6 +5,7 @@ #include "audio/segam1audio.h" #include "machine/eepromser.h" #include "cpu/i960/i960.h" +#include "cpu/mb86235/mb86235.h" #include "sound/scsp.h" #include "machine/315-5881_crypt.h" #include "machine/315-5838_317-0229_comp.h" @@ -67,7 +68,7 @@ public: optional_device m_audiocpu; optional_device m_tgp; optional_device m_dsp; - optional_device m_tgpx4; + optional_device m_tgpx4; optional_device m_drivecpu; required_device m_eeprom; required_device m_screen;