diff options
Diffstat (limited to 'trunk/src/emu/cpu/asap/asap.c')
-rw-r--r-- | trunk/src/emu/cpu/asap/asap.c | 1714 |
1 files changed, 1714 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/asap/asap.c b/trunk/src/emu/cpu/asap/asap.c new file mode 100644 index 00000000000..115278ec9a9 --- /dev/null +++ b/trunk/src/emu/cpu/asap/asap.c @@ -0,0 +1,1714 @@ +/*************************************************************************** + + asap.c + + Core implementation for the portable ASAP emulator. + ASAP = Atari Simplified Architecture Processor + + Special thanks to Mike Albaugh for clarification on a couple of fine points. + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "asap.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const UINT32 PS_CFLAG = 0x00000001; +const UINT32 PS_VFLAG = 0x00000002; +const UINT32 PS_ZFLAG = 0x00000004; +const UINT32 PS_NFLAG = 0x00000008; +const UINT32 PS_IFLAG = 0x00000010; +const UINT32 PS_PFLAG = 0x00000020; + +const int EXCEPTION_RESET = 0; +const int EXCEPTION_TRAP0 = 1; +const int EXCEPTION_TRAPF = 2; +const int EXCEPTION_INTERRUPT = 3; + +const int REGBASE = 0xffe0; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define SET_C_ADD(a,b) (m_cflag = (UINT32)(b) > (UINT32)(~(a))) +#define SET_C_SUB(a,b) (m_cflag = (UINT32)(b) <= (UINT32)(a)) +#define SET_V_ADD(r,a,b) (m_vflag = ~((a) ^ (b)) & ((a) ^ (r))) +#define SET_V_SUB(r,a,b) (m_vflag = ((a) ^ (b)) & ((a) ^ (r))) +#define SET_ZN(r) (m_znflag = (r)) +#define SET_ZNCV_ADD(r,a,b) SET_ZN(r); SET_C_ADD(a,b); SET_V_ADD(r,a,b) +#define SET_ZNCV_SUB(r,a,b) SET_ZN(r); SET_C_SUB(a,b); SET_V_SUB(r,a,b) + +#define SET_VFLAG(val) (m_vflag = (val) << 31) +#define SET_CFLAG(val) (m_cflag = (val)) + +#define GET_FLAGS() (m_cflag | \ + ((m_vflag >> 30) & PS_VFLAG) | \ + ((m_znflag == 0) << 2) | \ + ((m_znflag >> 28) & PS_NFLAG) | \ + (m_iflag << 4) | \ + (m_pflag << 5)) + +#define SET_FLAGS(v) do { \ + m_cflag = (v) & PS_CFLAG; \ + m_vflag = ((v) & PS_VFLAG) << 30; \ + m_znflag = ((v) & PS_ZFLAG) ? 0 : ((v) & PS_NFLAG) ? -1 : 1; \ + m_iflag = ((v) & PS_IFLAG) >> 4; \ + m_pflag = ((v) & PS_PFLAG) >> 5; \ + } while (0); + +#define OPCODE (m_op >> 27) +#define DSTREG ((m_op >> 22) & 31) +#define DSTVAL m_src2val[REGBASE + DSTREG] +#define SRC1REG ((m_op >> 16) & 31) +#define SRC1VAL m_src2val[REGBASE + SRC1REG] +#define SRC2VAL m_src2val[m_op & 0xffff] + + + +//************************************************************************** +// STATIC OPCODE TABLES +//************************************************************************** + +const asap_device::ophandler asap_device::s_opcodetable[32][4] = +{ + { &asap_device::trap0, &asap_device::trap0, &asap_device::trap0, &asap_device::trap0 }, + { &asap_device::noop, &asap_device::noop, &asap_device::noop, &asap_device::noop }, + { &asap_device::bsr, &asap_device::bsr_0, &asap_device::bsr, &asap_device::bsr_0 }, + { &asap_device::lea, &asap_device::noop, &asap_device::lea_c, &asap_device::lea_c0 }, + { &asap_device::leah, &asap_device::noop, &asap_device::leah_c, &asap_device::leah_c0 }, + { &asap_device::subr, &asap_device::noop, &asap_device::subr_c, &asap_device::subr_c0 }, + { &asap_device::xor_, &asap_device::noop, &asap_device::xor_c, &asap_device::xor_c0 }, + { &asap_device::xorn, &asap_device::noop, &asap_device::xorn_c, &asap_device::xorn_c0 }, + { &asap_device::add, &asap_device::noop, &asap_device::add_c, &asap_device::add_c0 }, + { &asap_device::sub, &asap_device::noop, &asap_device::sub_c, &asap_device::sub_c0 }, + { &asap_device::addc, &asap_device::noop, &asap_device::addc_c, &asap_device::addc_c0 }, + { &asap_device::subc, &asap_device::noop, &asap_device::subc_c, &asap_device::subc_c0 }, + { &asap_device::and_, &asap_device::noop, &asap_device::and_c, &asap_device::and_c0 }, + { &asap_device::andn, &asap_device::noop, &asap_device::andn_c, &asap_device::andn_c0 }, + { &asap_device::or_, &asap_device::noop, &asap_device::or_c, &asap_device::or_c0 }, + { &asap_device::orn, &asap_device::noop, &asap_device::orn_c, &asap_device::orn_c0 }, + { &asap_device::ld, &asap_device::ld_0, &asap_device::ld_c, &asap_device::ld_c0 }, + { &asap_device::ldh, &asap_device::ldh_0, &asap_device::ldh_c, &asap_device::ldh_c0 }, + { &asap_device::lduh, &asap_device::lduh_0, &asap_device::lduh_c, &asap_device::lduh_c0 }, + { &asap_device::sth, &asap_device::sth_0, &asap_device::sth_c, &asap_device::sth_c0 }, + { &asap_device::st, &asap_device::st_0, &asap_device::st_c, &asap_device::st_c0 }, + { &asap_device::ldb, &asap_device::ldb_0, &asap_device::ldb_c, &asap_device::ldb_c0 }, + { &asap_device::ldub, &asap_device::ldub_0, &asap_device::ldub_c, &asap_device::ldub_c0 }, + { &asap_device::stb, &asap_device::stb_0, &asap_device::stb_c, &asap_device::stb_c0 }, + { &asap_device::ashr, &asap_device::noop, &asap_device::ashr_c, &asap_device::ashr_c0 }, + { &asap_device::lshr, &asap_device::noop, &asap_device::lshr_c, &asap_device::lshr_c0 }, + { &asap_device::ashl, &asap_device::noop, &asap_device::ashl_c, &asap_device::ashl_c0 }, + { &asap_device::rotl, &asap_device::noop, &asap_device::rotl_c, &asap_device::rotl_c0 }, + { &asap_device::getps, &asap_device::noop, &asap_device::getps, &asap_device::noop }, + { &asap_device::putps, &asap_device::putps, &asap_device::putps, &asap_device::putps }, + { &asap_device::jsr, &asap_device::jsr_0, &asap_device::jsr_c, &asap_device::jsr_c0 }, + { &asap_device::trapf, &asap_device::trapf, &asap_device::trapf, &asap_device::trapf } +}; + +const asap_device::ophandler asap_device::s_conditiontable[16] = +{ + &asap_device::bsp, &asap_device::bmz, &asap_device::bgt, &asap_device::ble, + &asap_device::bge, &asap_device::blt, &asap_device::bhi, &asap_device::bls, + &asap_device::bcc, &asap_device::bcs, &asap_device::bpl, &asap_device::bmi, + &asap_device::bne, &asap_device::beq, &asap_device::bvc, &asap_device::bvs +}; + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +// device type definition +const device_type ASAP = &device_creator<asap_device>; + +//------------------------------------------------- +// asap_device - constructor +//------------------------------------------------- + +asap_device::asap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ASAP, "ASAP", tag, owner, clock), + m_program_config("program", ENDIANNESS_LITTLE, 32, 32), + m_pc(0), + m_pflag(0), + m_iflag(0), + m_cflag(0), + m_vflag(0), + m_znflag(0), + m_flagsio(0), + m_op(0), + m_ppc(0), + m_nextpc(0), + m_irq_state(0), + m_icount(0), + m_program(NULL), + m_direct(NULL) +{ + // initialize the src2val table to contain immediates for low values + for (int i = 0; i < REGBASE; i++) + m_src2val[i] = i; + + // build the opcode table + for (int op = 0; op < 32; op++) + for (int dst = 0; dst < 32; dst++) + for (int cond = 0; cond < 2; cond++) + if (op == 1) + m_opcode[(op << 6) + (dst << 1) + cond] = s_conditiontable[dst & 15]; + else if (cond && dst == 0) + m_opcode[(op << 6) + (dst << 1) + cond] = s_opcodetable[op][3]; + else if (cond) + m_opcode[(op << 6) + (dst << 1) + cond] = s_opcodetable[op][2]; + else if (dst == 0) + m_opcode[(op << 6) + (dst << 1) + cond] = s_opcodetable[op][1]; + else + m_opcode[(op << 6) + (dst << 1) + cond] = s_opcodetable[op][0]; +} + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void asap_device::device_start() +{ + // get our address spaces + m_program = space(AS_PROGRAM); + m_direct = &m_program->direct(); + + // register our state for the debugger + astring tempstr; + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add(STATE_GENSP, "GENSP", m_src2val[REGBASE + 31]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flagsio).callimport().callexport().formatstr("%6s").noshow(); + state_add(ASAP_PC, "PC", m_pc); + state_add(ASAP_PS, "PS", m_flagsio).callimport().callexport(); + for (int regnum = 0; regnum < 32; regnum++) + state_add(ASAP_R0 + regnum, tempstr.format("R%d", regnum), m_src2val[REGBASE + regnum]); + + // register our state for saving + save_item(NAME(m_pc)); + save_item(NAME(m_pflag)); + save_item(NAME(m_iflag)); + save_item(NAME(m_cflag)); + save_item(NAME(m_vflag)); + save_item(NAME(m_znflag)); + save_item(NAME(m_op)); + save_item(NAME(m_ppc)); + save_item(NAME(m_nextpc)); + save_item(NAME(m_irq_state)); + + // set our instruction counter + m_icountptr = &m_icount; +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void asap_device::device_reset() +{ + // initialize the state + m_src2val[REGBASE + 0] = 0; + m_pc = 0; + m_iflag = 0; + + m_ppc = 0; + m_nextpc = ~0; + m_irq_state = 0; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *asap_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void asap_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + case ASAP_PS: + SET_FLAGS(m_flagsio); + break; + } +} + + +//------------------------------------------------- +// state_export - export state from the device, +// to a known location where it can be read +//------------------------------------------------- + +void asap_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + case ASAP_PS: + m_flagsio = GET_FLAGS(); + break; + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void asap_device::state_string_export(const device_state_entry &entry, astring &string) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + string.printf("%c%c%c%c%c%c", + m_pflag ? 'P' : '.', + m_iflag ? 'I' : '.', + ((INT32)m_znflag < 0) ? 'N' : '.', + (m_znflag == 0) ? 'Z' : '.', + ((m_vflag >> 30) & PS_VFLAG) ? 'V' : '.', + m_cflag ? 'C' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 asap_device::disasm_min_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 asap_device::disasm_max_opcode_bytes() const +{ + return 12; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t asap_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( asap ); + return CPU_DISASSEMBLE_NAME(asap)(NULL, buffer, pc, oprom, opram, 0); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readop - read an opcode at the given address +//------------------------------------------------- + +inline UINT32 asap_device::readop(offs_t pc) +{ + return m_direct->read_decrypted_dword(pc); +} + + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 asap_device::readbyte(offs_t address) +{ + // no alignment issues with bytes + return m_program->read_byte(address); +} + + +//------------------------------------------------- +// readword - read a word at the given address +//------------------------------------------------- + +inline UINT16 asap_device::readword(offs_t address) +{ + // aligned reads are easy + if (!(address & 1)) + return m_program->read_word(address); + + // misaligned reads are tricky + return m_program->read_dword(address & ~3) >> (address & 3); +} + + +//------------------------------------------------- +// readlong - read a long at the given address +//------------------------------------------------- + +inline UINT32 asap_device::readlong(offs_t address) +{ + // aligned reads are easy + if (!(address & 3)) + return m_program->read_dword(address); + + // misaligned reads are tricky + return m_program->read_dword(address & ~3) >> (address & 3); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void asap_device::writebyte(offs_t address, UINT8 data) +{ + // no alignment issues with bytes + m_program->write_byte(address, data); +} + + +//------------------------------------------------- +// writeword - write a word at the given address +//------------------------------------------------- + +inline void asap_device::writeword(offs_t address, UINT16 data) +{ + // aligned writes are easy + if (!(address & 1)) + { + m_program->write_word(address, data); + return; + } + + // misaligned writes are tricky + if (!(address & 2)) + { + m_program->write_byte(address + 1, data); + m_program->write_byte(address + 2, data >> 8); + } + else + m_program->write_byte(address + 1, data); +} + + +//------------------------------------------------- +// writelong - write a long at the given address +//------------------------------------------------- + +inline void asap_device::writelong(offs_t address, UINT32 data) +{ + // aligned writes are easy + if (!(address & 3)) + { + m_program->write_dword(address, data); + return; + } + + // misaligned writes are tricky + switch (address & 3) + { + case 1: + m_program->write_byte(address, data); + m_program->write_word(address + 1, data >> 8); + break; + case 2: + m_program->write_word(address, data); + break; + case 3: + m_program->write_byte(address, data); + break; + } +} + + +//------------------------------------------------- +// generate_exception - generate an exception of +// the requested type +//------------------------------------------------- + +inline void asap_device::generate_exception(int exception) +{ + m_pflag = m_iflag; + m_iflag = 0; + + m_src2val[REGBASE + 30] = m_pc; + m_src2val[REGBASE + 31] = (m_nextpc == ~0) ? m_pc + 4 : m_nextpc; + + m_pc = 0x40 * exception; + m_nextpc = ~0; + + m_icount--; +} + + +//------------------------------------------------- +// check_irqs - check for pending IRQs +//------------------------------------------------- + +inline void asap_device::check_irqs() +{ + if (m_irq_state && m_iflag) + { + generate_exception(EXCEPTION_INTERRUPT); + standard_irq_callback(ASAP_IRQ0); + } +} + + + +//************************************************************************** +// CORE EXECUTION +//************************************************************************** + +inline void asap_device::fetch_instruction() +{ + // debugging + m_ppc = m_pc; + + // instruction fetch + m_op = readop(m_pc); + m_pc += 4; +} + +inline void asap_device::fetch_instruction_debug() +{ + // debugging + m_ppc = m_pc; + debugger_instruction_hook(this, m_pc); + + // instruction fetch + m_op = readop(m_pc); + m_pc += 4; +} + +inline void asap_device::execute_instruction() +{ + // parse the instruction + (this->*m_opcode[m_op >> 21])(); +} + + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 asap_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 asap_device::execute_max_cycles() const +{ + return 2; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 asap_device::execute_input_lines() const +{ + return 1; +} + + +void asap_device::execute_set_input(int inputnum, int state) +{ + m_irq_state = (state != CLEAR_LINE); +} + + +void asap_device::execute_run() +{ + // check for IRQs + check_irqs(); + + // core execution loop + if ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) == 0) + { + do + { + // fetch and execute the next instruction + fetch_instruction(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction(); + execute_instruction(); + + m_icount -= 4; + + } while (m_icount > 0); + } + else + { + do + { + // fetch and execute the next instruction + fetch_instruction_debug(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction_debug(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction_debug(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction_debug(); + execute_instruction(); + + m_icount -= 4; + + } while (m_icount > 0); + } +} + + + +//************************************************************************** +// OPCODE IMPLEMENTATIONS +//************************************************************************** + +void asap_device::noop() +{ +} + +/**************************** TRAP 0 ******************************/ + +void asap_device::trap0() +{ + generate_exception(EXCEPTION_TRAP0); +} + +/**************************** Bcc ******************************/ + +void asap_device::bsp() +{ + if ((INT32)m_znflag > 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bmz() +{ + if ((INT32)m_znflag <= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bgt() +{ + if (m_znflag != 0 && (INT32)(m_znflag ^ m_vflag) >= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::ble() +{ + if (m_znflag == 0 || (INT32)(m_znflag ^ m_vflag) < 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bge() +{ + if ((INT32)(m_znflag ^ m_vflag) >= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::blt() +{ + if ((INT32)(m_znflag ^ m_vflag) < 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bhi() +{ + if (m_znflag != 0 && m_cflag) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bls() +{ + if (m_znflag == 0 || !m_cflag) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bcc() +{ + if (!m_cflag) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bcs() +{ + if (m_cflag) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bpl() +{ + if ((INT32)m_znflag >= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bmi() +{ + if ((INT32)m_znflag < 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bne() +{ + if (m_znflag != 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::beq() +{ + if (m_znflag == 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bvc() +{ + if ((INT32)m_vflag >= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bvs() +{ + if ((INT32)m_vflag < 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +/**************************** BSR ******************************/ + +void asap_device::bsr() +{ + DSTVAL = m_pc + 4; + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; +} + +void asap_device::bsr_0() +{ + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; +} + +/**************************** LEA ******************************/ + +void asap_device::lea() +{ + DSTVAL = SRC1VAL + (SRC2VAL << 2); +} + +void asap_device::lea_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + (src2 << 2); + + SET_ZNCV_ADD(dst, src1, src2); + if (src1 & 0xc0000000) + SET_CFLAG(1); + if (((src1 ^ (src1 >> 1)) & 0x20000000) || (src1 ^ (src1 >> 2)) & 0x20000000) + SET_VFLAG(1); + DSTVAL = dst; +} + +void asap_device::lea_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + (src2 << 2); + + SET_ZNCV_ADD(dst, src1, src2); + if (src1 & 0xc0000000) + SET_CFLAG(1); + if (((src1 ^ (src1 >> 1)) & 0x20000000) || (src1 ^ (src1 >> 2)) & 0x20000000) + SET_VFLAG(1); +} + +/**************************** LEAH ******************************/ + +void asap_device::leah() +{ + DSTVAL = SRC1VAL + (SRC2VAL << 1); +} + +void asap_device::leah_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + (src2 << 1); + + SET_ZNCV_ADD(dst, src1, src2); + if (src1 & 0x80000000) + SET_CFLAG(1); + if ((src1 ^ (src1 >> 1)) & 0x40000000) + SET_VFLAG(1); + DSTVAL = dst; +} + +void asap_device::leah_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + (src2 << 1); + + SET_ZNCV_ADD(dst, src1, src2); + if (src1 & 0x80000000) + SET_CFLAG(1); + if ((src1 ^ (src1 >> 1)) & 0x40000000) + SET_VFLAG(1); +} + +/**************************** SUBR ******************************/ + +void asap_device::subr() +{ + DSTVAL = SRC2VAL - SRC1VAL; +} + +void asap_device::subr_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src2 - src1; + + SET_ZNCV_SUB(dst, src2, src1); + DSTVAL = dst; +} + +void asap_device::subr_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src2 - src1; + + SET_ZNCV_SUB(dst, src2, src1); +} + +/**************************** XOR ******************************/ + +void asap_device::xor_() +{ + DSTVAL = SRC1VAL ^ SRC2VAL; +} + +void asap_device::xor_c() +{ + UINT32 dst = SRC1VAL ^ SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::xor_c0() +{ + UINT32 dst = SRC1VAL ^ SRC2VAL; + SET_ZN(dst); +} + +/**************************** XOR ******************************/ + +void asap_device::xorn() +{ + DSTVAL = SRC1VAL ^ ~SRC2VAL; +} + +void asap_device::xorn_c() +{ + UINT32 dst = SRC1VAL ^ ~SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::xorn_c0() +{ + UINT32 dst = SRC1VAL ^ ~SRC2VAL; + SET_ZN(dst); +} + +/**************************** ADD ******************************/ + +void asap_device::add() +{ + DSTVAL = SRC1VAL + SRC2VAL; +} + +void asap_device::add_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + src2; + + SET_ZNCV_ADD(dst, src1, src2); + DSTVAL = dst; +} + +void asap_device::add_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + src2; + + SET_ZNCV_ADD(dst, src1, src2); +} + +/**************************** ADD ******************************/ + +void asap_device::sub() +{ + DSTVAL = SRC1VAL - SRC2VAL; +} + +void asap_device::sub_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 - src2; + + SET_ZNCV_SUB(dst, src1, src2); + DSTVAL = dst; +} + +void asap_device::sub_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 - src2; + + SET_ZNCV_SUB(dst, src1, src2); +} + +/**************************** ADDC ******************************/ + +void asap_device::addc() +{ + DSTVAL = SRC1VAL + SRC2VAL + m_cflag; +} + +void asap_device::addc_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + src2 + m_cflag; + + SET_ZNCV_ADD(dst, src1, src2); + DSTVAL = dst; +} + +void asap_device::addc_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + src2 + m_cflag; + + SET_ZNCV_ADD(dst, src1, src2); +} + +/**************************** SUBC ******************************/ + +void asap_device::subc() +{ + DSTVAL = SRC1VAL - SRC2VAL - 1 + m_cflag; +} + +void asap_device::subc_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 - src2 - 1 + m_cflag; + + SET_ZNCV_SUB(dst, src1, src2); + DSTVAL = dst; +} + +void asap_device::subc_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 - src2 - 1 + m_cflag; + + SET_ZNCV_SUB(dst, src1, src2); +} + +/**************************** AND ******************************/ + +void asap_device::and_() +{ + DSTVAL = SRC1VAL & SRC2VAL; +} + +void asap_device::and_c() +{ + UINT32 dst = SRC1VAL & SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::and_c0() +{ + UINT32 dst = SRC1VAL & SRC2VAL; + SET_ZN(dst); +} + +/**************************** ANDN ******************************/ + +void asap_device::andn() +{ + DSTVAL = SRC1VAL & ~SRC2VAL; +} + +void asap_device::andn_c() +{ + UINT32 dst = SRC1VAL & ~SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::andn_c0() +{ + UINT32 dst = SRC1VAL & ~SRC2VAL; + SET_ZN(dst); +} + +/**************************** OR ******************************/ + +void asap_device::or_() +{ + DSTVAL = SRC1VAL | SRC2VAL; +} + +void asap_device::or_c() +{ + UINT32 dst = SRC1VAL | SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::or_c0() +{ + UINT32 dst = SRC1VAL | SRC2VAL; + SET_ZN(dst); +} + +/**************************** ORN ******************************/ + +void asap_device::orn() +{ + DSTVAL = SRC1VAL | ~SRC2VAL; +} + +void asap_device::orn_c() +{ + UINT32 dst = SRC1VAL | ~SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::orn_c0() +{ + UINT32 dst = SRC1VAL | ~SRC2VAL; + SET_ZN(dst); +} + +/**************************** LD ******************************/ + +void asap_device::ld() +{ + DSTVAL = readlong(SRC1VAL + (SRC2VAL << 2)); +} + +void asap_device::ld_0() +{ + readlong(SRC1VAL + (SRC2VAL << 2)); +} + +void asap_device::ld_c() +{ + UINT32 dst = readlong(SRC1VAL + (SRC2VAL << 2)); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::ld_c0() +{ + UINT32 dst = readlong(SRC1VAL + (SRC2VAL << 2)); + SET_ZN(dst); +} + +/**************************** LDH ******************************/ + +void asap_device::ldh() +{ + DSTVAL = (INT16)readword(SRC1VAL + (SRC2VAL << 1)); +} + +void asap_device::ldh_0() +{ + readword(SRC1VAL + (SRC2VAL << 1)); +} + +void asap_device::ldh_c() +{ + UINT32 dst = (INT16)readword(SRC1VAL + (SRC2VAL << 1)); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::ldh_c0() +{ + UINT32 dst = (INT16)readword(SRC1VAL + (SRC2VAL << 1)); + SET_ZN(dst); +} + +/**************************** LDUH ******************************/ + +void asap_device::lduh() +{ + DSTVAL = readword(SRC1VAL + (SRC2VAL << 1)); +} + +void asap_device::lduh_0() +{ + readword(SRC1VAL + (SRC2VAL << 1)); +} + +void asap_device::lduh_c() +{ + UINT32 dst = readword(SRC1VAL + (SRC2VAL << 1)); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::lduh_c0() +{ + UINT32 dst = readword(SRC1VAL + (SRC2VAL << 1)); + SET_ZN(dst); +} + +/**************************** STH ******************************/ + +void asap_device::sth() +{ + writeword(SRC1VAL + (SRC2VAL << 1), DSTVAL); +} + +void asap_device::sth_0() +{ + writeword(SRC1VAL + (SRC2VAL << 1), 0); +} + +void asap_device::sth_c() +{ + UINT32 dst = (UINT16)DSTVAL; + SET_ZN(dst); + writeword(SRC1VAL + (SRC2VAL << 1), dst); +} + +void asap_device::sth_c0() +{ + SET_ZN(0); + writeword(SRC1VAL + (SRC2VAL << 1), 0); +} + +/**************************** ST ******************************/ + +void asap_device::st() +{ + writelong(SRC1VAL + (SRC2VAL << 2), DSTVAL); +} + +void asap_device::st_0() +{ + writelong(SRC1VAL + (SRC2VAL << 2), 0); +} + +void asap_device::st_c() +{ + UINT32 dst = DSTVAL; + SET_ZN(dst); + writelong(SRC1VAL + (SRC2VAL << 2), dst); +} + +void asap_device::st_c0() +{ + SET_ZN(0); + writelong(SRC1VAL + (SRC2VAL << 2), 0); +} + +/**************************** LDB ******************************/ + +void asap_device::ldb() +{ + DSTVAL = (INT8)readbyte(SRC1VAL + SRC2VAL); +} + +void asap_device::ldb_0() +{ + readbyte(SRC1VAL + SRC2VAL); +} + +void asap_device::ldb_c() +{ + UINT32 dst = (INT8)readbyte(SRC1VAL + SRC2VAL); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::ldb_c0() +{ + UINT32 dst = (INT8)readbyte(SRC1VAL + SRC2VAL); + SET_ZN(dst); +} + +/**************************** LDUB ******************************/ + +void asap_device::ldub() +{ + DSTVAL = readbyte(SRC1VAL + SRC2VAL); +} + +void asap_device::ldub_0() +{ + readbyte(SRC1VAL + SRC2VAL); +} + +void asap_device::ldub_c() +{ + UINT32 dst = readbyte(SRC1VAL + SRC2VAL); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::ldub_c0() +{ + UINT32 dst = readbyte(SRC1VAL + SRC2VAL); + SET_ZN(dst); +} + +/**************************** STB ******************************/ + +void asap_device::stb() +{ + writebyte(SRC1VAL + SRC2VAL, DSTVAL); +} + +void asap_device::stb_0() +{ + writebyte(SRC1VAL + SRC2VAL, 0); +} + +void asap_device::stb_c() +{ + UINT32 dst = (UINT8)DSTVAL; + SET_ZN(dst); + writebyte(SRC1VAL + SRC2VAL, dst); +} + +void asap_device::stb_c0() +{ + SET_ZN(0); + writebyte(SRC1VAL + SRC2VAL, 0); +} + +/**************************** ASHR ******************************/ + +void asap_device::ashr() +{ + UINT32 src2 = SRC2VAL; + DSTVAL = (src2 < 32) ? ((INT32)SRC1VAL >> src2) : ((INT32)SRC1VAL >> 31); +} + +void asap_device::ashr_c() +{ + UINT32 src2 = SRC2VAL; + m_cflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = (INT32)src1 >> src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = src1 << (32 - src2); + m_cflag = src1 >> 31; + } + DSTVAL = dst; + } + else + { + UINT32 dst = (INT32)SRC1VAL >> 31; + SET_ZN(dst); + DSTVAL = dst; + } +} + +void asap_device::ashr_c0() +{ + UINT32 src2 = SRC2VAL; + m_cflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = (INT32)src1 >> src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = src1 << (32 - src2); + m_cflag = src1 >> 31; + } + } + else + { + UINT32 dst = (INT32)SRC1VAL >> 31; + SET_ZN(dst); + } +} + +/**************************** LSHR ******************************/ + +void asap_device::lshr() +{ + UINT32 src2 = SRC2VAL; + DSTVAL = (src2 < 32) ? (SRC1VAL >> src2) : (SRC1VAL >> 31); +} + +void asap_device::lshr_c() +{ + UINT32 src2 = SRC2VAL; + m_cflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = src1 >> src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = src1 << (32 - src2); + m_cflag = src1 >> 31; + } + DSTVAL = dst; + } + else + { + UINT32 dst = SRC1VAL >> 31; + SET_ZN(dst); + DSTVAL = dst; + } +} + +void asap_device::lshr_c0() +{ + UINT32 src2 = SRC2VAL; + m_cflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = src1 >> src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = src1 << (32 - src2); + m_cflag = src1 >> 31; + } + } + else + { + SET_ZN(0); + DSTVAL = 0; + } +} + +/**************************** ASHL ******************************/ + +void asap_device::ashl() +{ + UINT32 src2 = SRC2VAL; + DSTVAL = (src2 < 32) ? (SRC1VAL << src2) : 0; +} + +void asap_device::ashl_c() +{ + UINT32 src2 = SRC2VAL; + m_cflag = m_vflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = src1 << src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = (INT32)src1 >> (32 - src2); + m_cflag = src1 & PS_CFLAG; + m_vflag = (src1 != ((INT32)dst >> 31)) << 31; + } + DSTVAL = dst; + } + else + { + SET_ZN(0); + DSTVAL = 0; + } +} + +void asap_device::ashl_c0() +{ + UINT32 src2 = SRC2VAL; + m_cflag = m_vflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = src1 << src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = (INT32)src1 >> (32 - src2); + m_cflag = src1 & PS_CFLAG; + m_vflag = (src1 != ((INT32)dst >> 31)) << 31; + } + } + else + SET_ZN(0); +} + +/**************************** ROTL ******************************/ + +void asap_device::rotl() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL & 31; + DSTVAL = (src1 << src2) | (src1 >> (32 - src2)); +} + +void asap_device::rotl_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL & 31; + UINT32 dst = (src1 << src2) | (src1 >> (32 - src2)); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::rotl_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL & 31; + UINT32 dst = (src1 << src2) | (src1 >> (32 - src2)); + SET_ZN(dst); +} + +/**************************** GETPS ******************************/ + +void asap_device::getps() +{ + DSTVAL = GET_FLAGS(); +} + +/**************************** PUTPS ******************************/ + +void asap_device::putps() +{ + UINT32 src2 = SRC2VAL & 0x3f; + SET_FLAGS(src2); + check_irqs(); +} + +/**************************** JSR ******************************/ + +void asap_device::jsr() +{ + DSTVAL = m_pc + 4; + m_nextpc = SRC1VAL + (SRC2VAL << 2); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; +} + +void asap_device::jsr_0() +{ + m_nextpc = SRC1VAL + (SRC2VAL << 2); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; +} + +void asap_device::jsr_c() +{ + DSTVAL = m_pc + 4; + m_nextpc = SRC1VAL + (SRC2VAL << 2); + m_iflag = m_pflag; + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + check_irqs(); +} + +void asap_device::jsr_c0() +{ + m_nextpc = SRC1VAL + (SRC2VAL << 2); + m_iflag = m_pflag; + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + check_irqs(); +} + +/**************************** TRAP F ******************************/ + +void asap_device::trapf() +{ + generate_exception(EXCEPTION_TRAPF); +} |