diff options
Diffstat (limited to 'src/devices/cpu/m88000/m88000.cpp')
-rw-r--r-- | src/devices/cpu/m88000/m88000.cpp | 750 |
1 files changed, 542 insertions, 208 deletions
diff --git a/src/devices/cpu/m88000/m88000.cpp b/src/devices/cpu/m88000/m88000.cpp index f3921bc8667..ef088f49a80 100644 --- a/src/devices/cpu/m88000/m88000.cpp +++ b/src/devices/cpu/m88000/m88000.cpp @@ -5,22 +5,15 @@ * Motorola M88000 Family of RISC microprocessors. * * TODO: - * - cache/mmu interface - * - misaligned access exceptions - * - floating point exceptions - * - user/supervisor space - * - xip/fip/nip exception flag - * - pipeline and cycles counts + * - instruction cycle counts * - mc88110 * - little-endian mode */ #include "emu.h" -#include "debug/debugcpu.h" #include "m88000.h" #include "m88000d.h" -#define LOG_GENERAL (1U << 0) #define LOG_EXCEPTION (1U << 1) //#define VERBOSE (LOG_GENERAL|LOG_EXCEPTION) @@ -124,6 +117,30 @@ enum fcr_mask : u32 FPCR_MASK = 0x0000'c01f, }; +enum dmt_mask : u32 +{ + DMT_VALID = 0x0000'0001, // valid transaction bit + DMT_WRITE = 0x0000'0002, // read/write transaction bit + DMT_EN0 = 0x0000'0004, // byte enable 0 + DMT_EN1 = 0x0000'0008, // byte enable 1 + DMT_EN2 = 0x0000'0010, // byte enable 2 + DMT_EN3 = 0x0000'0020, // byte enable 3 + DMT_SD = 0x0000'0040, // sign-extend bit + DMT_DREG = 0x0000'0f80, // destination register + DMT_LOCK = 0x0000'1000, // bus lock + DMT_DOUB1 = 0x0000'2000, // double word + DMT_DAS = 0x0000'4000, // data address space + DMT_BO = 0x0000'8000, // byte ordering +}; + +constexpr static u32 DMT_EN() { return (DMT_EN3 | DMT_EN2 | DMT_EN1 | DMT_EN0); } + +// return data memory transaction byte enables given data width and address +template <typename T> static u32 DMT_EN(u32 const address) +{ + return (((DMT_EN() << (4 - sizeof(T))) & DMT_EN()) >> (address & 3)); +} + // device type definitions DEFINE_DEVICE_TYPE(MC88100, mc88100_device, "mc88100", "Motorola MC88100") @@ -131,9 +148,8 @@ mc88100_device::mc88100_device(const machine_config &mconfig, const char *tag, d : cpu_device(mconfig, MC88100, tag, owner, clock) , m_code_config("code", ENDIANNESS_BIG, 32, 32, 0) , m_data_config("data", ENDIANNESS_BIG, 32, 32, 0) - , m_xip(0) - , m_nip(0) - , m_fip(0) + , m_cmmu_d(*this, finder_base::DUMMY_TAG) + , m_cmmu_i(*this, finder_base::DUMMY_TAG) , m_sb(0) , m_r{ 0 } , m_cr{ 0 } @@ -153,15 +169,36 @@ std::unique_ptr<util::disasm_interface> mc88100_device::create_disassembler() device_memory_interface::space_config_vector mc88100_device::memory_space_config() const { - return space_config_vector { - std::make_pair(AS_PROGRAM, &m_code_config), - std::make_pair(AS_DATA, &m_data_config) - }; + if (has_configured_map(AS_DATA)) + return space_config_vector{ std::make_pair(AS_PROGRAM, &m_code_config), std::make_pair(AS_DATA, &m_data_config) }; + else + return space_config_vector{ std::make_pair(AS_PROGRAM, &m_code_config) }; +} + +bool mc88100_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) +{ + target_space = &space(spacenum); + + switch (intention) + { + case TR_READ: + case TR_WRITE: + if (m_cmmu_d) + return m_cmmu_d->translate(intention, address, m_cr[PSR] & PSR_MODE); + break; + + case TR_FETCH: + if (m_cmmu_i) + return m_cmmu_i->translate(intention, address, m_cr[PSR] & PSR_MODE); + break; + } + + return true; } void mc88100_device::device_start() { - space(AS_PROGRAM).cache(m_inst_cache); + space(AS_PROGRAM).specific(m_inst_space); if (has_configured_map(AS_DATA)) space(AS_DATA).specific(m_data_space); @@ -184,14 +221,19 @@ void mc88100_device::device_start() }).mask(IP_A); state_add(35, "SB", m_sb); - state_add(36 + PSR, "PSR", m_cr[PSR]).mask(PSR_MASK); - state_add(36 + VBR, "VBR", m_cr[VBR]).mask(VBR_MASK); + state_add(36 + PSR, "PSR", m_cr[PSR]); + state_add(36 + EPSR, "EPSR", m_cr[EPSR]); + state_add(36 + SSBR, "SSBR", m_cr[SSBR]); + state_add(36 + SXIP, "SXIP", m_cr[SXIP]); + state_add(36 + SNIP, "SNIP", m_cr[SNIP]); + state_add(36 + SFIP, "SFIP", m_cr[SFIP]); + state_add(36 + VBR, "VBR", m_cr[VBR]); state_add(36 + SR0, "sr0", m_cr[SR0]); state_add(36 + SR1, "sr1", m_cr[SR1]); state_add(36 + SR2, "sr2", m_cr[SR2]); state_add(36 + SR3, "sr3", m_cr[SR3]); - for (int i = 1; i < 32; i++) + for (int i = 0; i < 32; i++) state_add(i, string_format("r%d", i).c_str(), m_r[i]); save_item(NAME(m_xip)); @@ -215,50 +257,41 @@ void mc88100_device::device_reset() m_xip = 0; m_nip = 0; m_fip = IP_V; + + m_xop = 0; + m_nop = 0; + m_fop = 0; } void mc88100_device::execute_run() { while (m_icount > 0) { - // update shadow registers - if (!(m_cr[PSR] & PSR_SFRZ)) - { - m_cr[SXIP] = m_xip; - m_cr[SNIP] = m_nip; - m_cr[SFIP] = m_fip; - } - - // interrupt check - if (m_int_state && !(m_cr[PSR] & PSR_IND)) - { - exception(E_INTERRUPT); - - // notify debugger - if (machine().debug_flags & DEBUG_FLAG_ENABLED) - debug()->interrupt_hook(INPUT_LINE_IRQ0); - } - + // execute if (m_xip & IP_V) { debugger_instruction_hook(m_xip & IP_A); - execute(m_xop); + if (!(m_xip & IP_E)) + execute(m_xop); + else + exception(E_INSTRUCTION); + + // interrupt check + if (m_int_state && !(m_cr[PSR] & PSR_IND)) + exception(E_INTERRUPT); } // fetch if (m_fip & IP_V) - m_fop = m_inst_cache.read_dword(m_fip & IP_A); + fetch(m_fip, m_fop); - // next becomes execute + // advance pipeline m_xop = m_nop; m_xip = m_nip; - - // fetch becomes next m_nop = m_fop; m_nip = m_fip; - - // increment fetch + m_fip &= ~IP_E; m_fip += 4; m_icount--; @@ -267,8 +300,6 @@ void mc88100_device::execute_run() // decoding macros #define D BIT(inst, 21, 5) -#define D0 (((inst >> 21) + 0) & 31) -#define D1 (((inst >> 21) + 1) & 31) #define S1 BIT(inst, 16, 5) #define S1H (((inst >> 16) + 0) & 31) @@ -288,52 +319,40 @@ void mc88100_device::execute(u32 const inst) { // load/store/exchange immediate case 0x00: // xmem.bu: exchange register with memory unsigned byte - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_byte(m_r[S1] + IMM16); - m_data_space.write_byte(m_r[S1] + IMM16, u8(data)); - } + xmem<u8>(m_r[S1] + IMM16, D); break; case 0x01: // xmem: exchange register with memory word - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_dword(m_r[S1] + IMM16); - m_data_space.write_dword(m_r[S1] + IMM16, data); - } + xmem<u32>(m_r[S1] + IMM16, D); break; case 0x02: // ld.hu: load half word unsigned - m_r[D] = m_data_space.read_word(m_r[S1] + IMM16); + ld<u16>(m_r[S1] + IMM16, D); break; case 0x03: // ld.bu: load byte unsigned - m_r[D] = m_data_space.read_byte(m_r[S1] + IMM16); + ld<u8>(m_r[S1] + IMM16, D); break; case 0x04: // ld.d: load double word - m_r[D0] = m_data_space.read_dword(m_r[S1] + IMM16 + 0); - m_r[D1] = m_data_space.read_dword(m_r[S1] + IMM16 + 4); + ld<u64>(m_r[S1] + IMM16, D); break; case 0x05: // ld: load word - m_r[D] = m_data_space.read_dword(m_r[S1] + IMM16); + ld<u32>(m_r[S1] + IMM16, D); break; case 0x06: // ld.h: load half word - m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + IMM16))); + ld<s16>(m_r[S1] + IMM16, D); break; case 0x07: // ld.b: load byte - m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + IMM16))); + ld<s8>(m_r[S1] + IMM16, D); break; case 0x08: // st.d: store double word (unscaled) - m_data_space.write_dword(m_r[S1] + IMM16 + 0, m_r[D0]); - m_data_space.write_dword(m_r[S1] + IMM16 + 4, m_r[D1]); + st<u64>(m_r[S1] + IMM16, D); break; case 0x09: // st: store word (unscaled) - m_data_space.write_dword(m_r[S1] + IMM16, m_r[D]); + st<u32>(m_r[S1] + IMM16, D); break; case 0x0a: // st.h: store half word (unscaled) - m_data_space.write_word(m_r[S1] + IMM16, u16(m_r[D])); + st<u16>(m_r[S1] + IMM16, D); break; case 0x0b: // st.b: store byte (unscaled) - m_data_space.write_byte(m_r[S1] + IMM16, u8(m_r[D])); + st<u8>(m_r[S1] + IMM16, D); break; case 0x0c: // lda.d: load address double word (unscaled) case 0x0d: // lda: load address word (unscaled) @@ -379,7 +398,7 @@ void mc88100_device::execute(u32 const inst) if (!(m_cr[PSR] & PSR_SFD1)) { if (IMM16) - m_r[D] = s32(m_r[S1]) / s32(IMM16); + m_r[D] = m_r[S1] / IMM16; else exception(E_INT_DIVIDE); } @@ -419,7 +438,18 @@ void mc88100_device::execute(u32 const inst) { case 0x08: // ldcr: load from control register (privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = m_cr[CR]; + { + switch (CR) + { + case SSBR: m_r[D] = (m_cr[PSR] & PSR_SFRZ) ? m_cr[CR] : m_sb; break; + case SXIP: m_r[D] = (m_cr[PSR] & PSR_SFRZ) ? m_cr[CR] : m_xip; break; + case SNIP: m_r[D] = (m_cr[PSR] & PSR_SFRZ) ? m_cr[CR] : m_nip; break; + case SFIP: m_r[D] = (m_cr[PSR] & PSR_SFRZ) ? m_cr[CR] : m_fip; break; + default: + m_r[D] = m_cr[CR]; + break; + } + } else exception(E_PRIVILEGE); break; @@ -446,7 +476,17 @@ void mc88100_device::execute(u32 const inst) { u32 const data = m_r[S1]; - m_r[D] = m_cr[CR]; + switch (CR) + { + case SSBR: m_r[D] = (m_cr[PSR] & PSR_SFRZ) ? m_cr[CR] : m_sb; break; + case SXIP: m_r[D] = (m_cr[PSR] & PSR_SFRZ) ? m_cr[CR] : m_xip; break; + case SNIP: m_r[D] = (m_cr[PSR] & PSR_SFRZ) ? m_cr[CR] : m_nip; break; + case SFIP: m_r[D] = (m_cr[PSR] & PSR_SFRZ) ? m_cr[CR] : m_fip; break; + default: + m_r[D] = m_cr[CR]; + break; + } + set_cr(CR, data); } else @@ -507,42 +547,42 @@ void mc88100_device::execute(u32 const inst) break; // flow-control case 0x30: // br: unconditional branch - m_fip = m_xip + (s32(inst << 6) >> 4); + m_fip = m_xip + (util::sext(inst, 26) << 2); m_nip &= ~IP_V; break; case 0x31: // br.n: unconditional branch (delayed) - m_fip = m_xip + (s32(inst << 6) >> 4); + m_fip = m_xip + (util::sext(inst, 26) << 2); break; case 0x32: // bsr: branch to subroutine - m_fip = m_xip + (s32(inst << 6) >> 4); + m_fip = m_xip + (util::sext(inst, 26) << 2); m_r[1] = m_nip & IP_A; m_nip &= ~IP_V; break; case 0x33: // bsr.n: branch to subroutine (delayed) - m_fip = m_xip + (s32(inst << 6) >> 4); + m_fip = m_xip + (util::sext(inst, 26) << 2); m_r[1] = (m_nip & IP_A) + 4; break; case 0x34: // bb0: branch on bit clear if (!BIT(m_r[S1], D)) { - m_fip = m_xip + (s32(inst << 16) >> 14); + m_fip = m_xip + (util::sext(inst, 16) << 2); m_nip &= ~IP_V; } break; case 0x35: // bb0.n: branch on bit clear (delayed) if (!BIT(m_r[S1], D)) - m_fip = m_xip + (s32(inst << 16) >> 14); + m_fip = m_xip + (util::sext(inst, 16) << 2); break; case 0x36: // bb1: branch on bit set if (BIT(m_r[S1], D)) { - m_fip = m_xip + (s32(inst << 16) >> 14); + m_fip = m_xip + (util::sext(inst, 16) << 2); m_nip &= ~IP_V; } break; case 0x37: // bb1.n: branch on bit set (delayed) if (BIT(m_r[S1], D)) - m_fip = m_xip + (s32(inst << 16) >> 14); + m_fip = m_xip + (util::sext(inst, 16) << 2); break; case 0x38: case 0x39: @@ -551,13 +591,13 @@ void mc88100_device::execute(u32 const inst) case 0x3a: // bcnd: conditional branch if (condition(D, m_r[S1])) { - m_fip = m_xip + (s32(inst << 16) >> 14); + m_fip = m_xip + (util::sext(inst, 16) << 2); m_nip &= ~IP_V; } break; case 0x3b: // bcnd.n: conditional branch (delayed) if (condition(D, m_r[S1])) - m_fip = m_xip + (s32(inst << 16) >> 14); + m_fip = m_xip + (util::sext(inst, 16) << 2); break; case 0x3c: // bit field switch (BIT(inst, 10, 6)) @@ -584,7 +624,7 @@ void mc88100_device::execute(u32 const inst) unsigned const offset = inst & 31; if (width && (width + offset) < 32) - m_r[D] = s32(m_r[S1] << (32 - (width + offset))) >> (32 - width); + m_r[D] = util::sext(m_r[S1] >> offset, width); else m_r[D] = s32(m_r[S1]) >> offset; } @@ -656,78 +696,38 @@ void mc88100_device::execute(u32 const inst) switch (BIT(inst, 5, 11)) { case 0x000: // xmem.bu: exchange register with memory byte unsigned - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_byte(m_r[S1] + m_r[S2]); - m_data_space.write_byte(m_r[S1] + m_r[S2], u8(data)); - } + xmem<u8>(m_r[S1] + m_r[S2], D); break; case 0x008: // xmem.bu.usr: exchange register with memory byte unsigned user (privileged) if (m_cr[PSR] & PSR_MODE) - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_byte(m_r[S1] + m_r[S2]); - m_data_space.write_byte(m_r[S1] + m_r[S2], u8(data)); - } + xmem<u8,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x020: // xmem: exchange register with memory word - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_dword(m_r[S1] + m_r[S2]); - m_data_space.write_dword(m_r[S1] + m_r[S2], u32(data)); - } + xmem<u32>(m_r[S1] + m_r[S2], D); break; case 0x028: // xmem.usr: exchange register with memory word user (privileged) if (m_cr[PSR] & PSR_MODE) - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_dword(m_r[S1] + m_r[S2]); - m_data_space.write_dword(m_r[S1] + m_r[S2], u32(data)); - } + xmem<u32,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x010: // xmem.bu: exchange register with memory byte unsigned (scaled) - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_byte(m_r[S1] + (m_r[S2] << 0)); - m_data_space.write_byte(m_r[S1] + (m_r[S2] << 0), u8(data)); - } + xmem<u8>(m_r[S1] + (m_r[S2] << 0), D); break; case 0x018: // xmem.bu.usr: exchange register with memory byte unsigned user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_byte(m_r[S1] + (m_r[S2] << 0)); - m_data_space.write_byte(m_r[S1] + (m_r[S2] << 0), u8(data)); - } + xmem<u8,true>(m_r[S1] + (m_r[S2] << 0), D); else exception(E_PRIVILEGE); break; case 0x030: // xmem: exchange register with memory word (scaled) - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 2)); - m_data_space.write_dword(m_r[S1] + (m_r[S2] << 2), u32(data)); - } + xmem<u32>(m_r[S1] + (m_r[S2] << 2), D); break; case 0x038: // xmem.usr: exchange register with memory word user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - { - u32 const data = m_r[D]; - - m_r[D] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 2)); - m_data_space.write_dword(m_r[S1] + (m_r[S2] << 2), u32(data)); - } + xmem<u32,true>(m_r[S1] + (m_r[S2] << 2), D); else exception(E_PRIVILEGE); break; @@ -793,7 +793,7 @@ void mc88100_device::execute(u32 const inst) u32 const data = m_r[S1] + ~m_r[S2] + 1; // compute borrow out - if (carry(m_r[S1], ~m_r[S2], data)) + if (carry(m_r[S1], ~m_r[S2] + 1, data)) m_cr[PSR] |= PSR_C; else m_cr[PSR] &= ~PSR_C; @@ -809,7 +809,7 @@ void mc88100_device::execute(u32 const inst) u32 const data = m_r[S1] + ~m_r[S2] + !bool(m_cr[PSR] & PSR_C); // compute borrow out - if (carry(m_r[S1], ~m_r[S2], data)) + if (carry(m_r[S1], ~m_r[S2] + !bool(m_cr[PSR] & PSR_C), data)) m_cr[PSR] |= PSR_C; else m_cr[PSR] &= ~PSR_C; @@ -818,10 +818,11 @@ void mc88100_device::execute(u32 const inst) } break; case 0x340: // divu: unsigned integer divide (register) + case 0x348: if (!(m_cr[PSR] & PSR_SFD1)) { if (m_r[S2]) - m_r[D] = s32(m_r[S1]) / s32(m_r[S2]); + m_r[D] = m_r[S1] / m_r[S2]; else exception(E_INT_DIVIDE); } @@ -829,6 +830,7 @@ void mc88100_device::execute(u32 const inst) exception(E_SFU1_P); break; case 0x360: // mul: integer multiply (register) + case 0x368: if (!(m_cr[PSR] & PSR_SFD1)) m_r[D] = m_r[S1] * m_r[S2]; else @@ -898,7 +900,7 @@ void mc88100_device::execute(u32 const inst) u32 const data = m_r[S1] + ~m_r[S2] + 1; // compute borrow out - if (carry(m_r[S1], ~m_r[S2], data)) + if (carry(m_r[S1], ~m_r[S2] + 1, data)) m_cr[PSR] |= PSR_C; else m_cr[PSR] &= ~PSR_C; @@ -914,7 +916,7 @@ void mc88100_device::execute(u32 const inst) u32 const data = m_r[S1] + ~m_r[S2] + !bool(m_cr[PSR] & PSR_C); // compute borrow out - if (carry(m_r[S1], ~m_r[S2], data)) + if (carry(m_r[S1], ~m_r[S2] + !bool(m_cr[PSR] & PSR_C), data)) m_cr[PSR] |= PSR_C; else m_cr[PSR] &= ~PSR_C; @@ -923,6 +925,7 @@ void mc88100_device::execute(u32 const inst) } break; case 0x3c0: // div: signed integer divide (register) + case 0x3c8: if (!(m_cr[PSR] & PSR_SFD1)) { if (m_r[S2] && !BIT(m_r[S1], 31) && !BIT(m_r[S2], 31)) @@ -934,13 +937,14 @@ void mc88100_device::execute(u32 const inst) exception(E_SFU1_P); break; case 0x3e0: // cmp: integer compare (register) + case 0x3e8: m_r[D] = cmp(m_r[S1], m_r[S2]); break; // bit field register case 0x400: // clr: clear bit field (register) { - unsigned const width = (m_r[S2] >> 5) & 31; + unsigned const width = BIT(m_r[S2], 5, 5); unsigned const offset = m_r[S2] & 31; m_r[D] = m_r[S1] & ~(make_bitmask<u32>(width ? width : 32) << offset); @@ -948,7 +952,7 @@ void mc88100_device::execute(u32 const inst) break; case 0x440: // set: set bit field (register) { - unsigned const width = (m_r[S2] >> 5) & 31; + unsigned const width = BIT(m_r[S2], 5, 5); unsigned const offset = m_r[S2] & 31; m_r[D] = m_r[S1] | (make_bitmask<u32>(width ? width : 32) << offset); @@ -956,18 +960,18 @@ void mc88100_device::execute(u32 const inst) break; case 0x480: // ext: extract signed bit field (register) { - unsigned const width = (m_r[S2] >> 5) & 31; + unsigned const width = BIT(m_r[S2], 5, 5); unsigned const offset = m_r[S2] & 31; if (width && (width + offset) < 32) - m_r[D] = s32(m_r[S1] << (32 - (width + offset))) >> (32 - width); + m_r[D] = util::sext(m_r[S1] >> offset, width); else m_r[D] = s32(m_r[S1]) >> offset; } break; case 0x4c0: // extu: extract unsigned bit field (register) { - unsigned const width = (m_r[S2] >> 5) & 31; + unsigned const width = BIT(m_r[S2], 5, 5); unsigned const offset = m_r[S2] & 31; if (width) @@ -978,7 +982,7 @@ void mc88100_device::execute(u32 const inst) break; case 0x500: // mak: make bit field (register) { - unsigned const width = (m_r[S2] >> 5) & 31; + unsigned const width = BIT(m_r[S2], 5, 5); unsigned const offset = m_r[S2] & 31; if (width) @@ -1028,216 +1032,202 @@ void mc88100_device::execute(u32 const inst) case 0x7e0: // rte: return from exception (privileged) if (m_cr[PSR] & PSR_MODE) { - m_xip &= ~IP_V; + m_cr[PSR] = m_cr[EPSR]; + m_sb = m_cr[SSBR]; m_nip = m_cr[SNIP]; - m_nop = m_inst_cache.read_dword(m_nip & IP_A); - m_fip = m_cr[SFIP]; - m_sb = m_cr[SSBR]; - m_cr[PSR] = m_cr[EPSR]; + if (m_nip & IP_V) + fetch(m_nip, m_nop); + + if (!(m_cr[EPSR] & PSR_MODE)) + debugger_privilege_hook(); } else exception(E_PRIVILEGE); break; case 0x040: // ld.hu: load half word unsigned - m_r[D] = m_data_space.read_word(m_r[S1] + m_r[S2]); + ld<u16>(m_r[S1] + m_r[S2], D); break; case 0x048: // ld.hu.usr: load half word unsigned user (privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = m_data_space.read_word(m_r[S1] + m_r[S2]); + ld<u16,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x060: // ld.b: load byte unsigned - m_r[D] = m_data_space.read_byte(m_r[S1] + m_r[S2]); + ld<u8>(m_r[S1] + m_r[S2], D); break; case 0x068: // ld.b.usr: load byte unsigned user (privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = m_data_space.read_byte(m_r[S1] + m_r[S2]); + ld<u8,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x080: // ld.d: load double word - m_r[D0] = m_data_space.read_dword(m_r[S1] + m_r[S2] + 0); - m_r[D1] = m_data_space.read_dword(m_r[S1] + m_r[S2] + 4); + ld<u64>(m_r[S1] + m_r[S2], D); break; case 0x088: // ld.d.usr: load double word user (privileged) if (m_cr[PSR] & PSR_MODE) - { - m_r[D0] = m_data_space.read_dword(m_r[S1] + m_r[S2] + 0); - m_r[D1] = m_data_space.read_dword(m_r[S1] + m_r[S2] + 4); - } + ld<u64,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x0a0: // ld: load word - m_r[D] = m_data_space.read_dword(m_r[S1] + m_r[S2]); + ld<u32>(m_r[S1] + m_r[S2], D); break; case 0x0a8: // ld.usr: load word user (privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = m_data_space.read_dword(m_r[S1] + m_r[S2]); + ld<u32,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x0c0: // ld.h: load half word - m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + m_r[S2]))); + ld<s16>(m_r[S1] + m_r[S2], D); break; case 0x0c8: // ld.h.usr: load half word user (privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + m_r[S2]))); + ld<s16,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x0e0: // ld.b: load byte - m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + m_r[S2]))); + ld<s8>(m_r[S1] + m_r[S2], D); break; case 0x0e8: // ld.b.usr: load byte user (privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + m_r[S2]))); + ld<s8,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x050: // ld.hu: load half word unsigned (scaled) - m_r[D] = m_data_space.read_word(m_r[S1] + (m_r[S2] << 1)); + ld<u16>(m_r[S1] + (m_r[S2] << 1), D); break; case 0x058: // ld.hu.usr: load half word unsigned user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = m_data_space.read_word(m_r[S1] + (m_r[S2] << 1)); + ld<u16,true>(m_r[S1] + (m_r[S2] << 1), D); else exception(E_PRIVILEGE); break; case 0x070: // ld.b: load byte unsigned (scaled) - m_r[D] = m_data_space.read_byte(m_r[S1] + (m_r[S2] << 0)); + ld<u8>(m_r[S1] + (m_r[S2] << 0), D); break; case 0x078: // ld.b.usr: load byte unsigned user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = m_data_space.read_byte(m_r[S1] + (m_r[S2] << 0)); + ld<u8,true>(m_r[S1] + (m_r[S2] << 0), D); else exception(E_PRIVILEGE); break; case 0x090: // ld.d: load double word (scaled) - m_r[D0] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 3) + 0); - m_r[D1] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 3) + 4); + ld<u64>(m_r[S1] + (m_r[S2] << 3), D); break; case 0x098: // ld.d.usr: load double word user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - { - m_r[D0] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 3) + 0); - m_r[D1] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 3) + 4); - } + ld<u64,true>(m_r[S1] + (m_r[S2] << 3), D); else exception(E_PRIVILEGE); break; case 0x0b0: // ld: load word (scaled) - m_r[D] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 2)); + ld<u32>(m_r[S1] + (m_r[S2] << 2), D); break; case 0x0b8: // ld.usr: load word user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 2)); + ld<u32,true>(m_r[S1] + (m_r[S2] << 2),D); else exception(E_PRIVILEGE); break; case 0x0d0: // ld.h: load half word (scaled) - m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + (m_r[S2] << 1)))); + ld<s16>(m_r[S1] + (m_r[S2] << 1), D); break; case 0x0d8: // ld.h.usr: load half word user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + (m_r[S2] << 1)))); + ld<s16,true>(m_r[S1] + (m_r[S2] << 1), D); else exception(E_PRIVILEGE); break; case 0x0f0: // ld.b: load byte (scaled) - m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + (m_r[S2] << 1)))); + ld<s8>(m_r[S1] + (m_r[S2] << 0), D); break; case 0x0f8: // ld.b.usr: load byte user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + (m_r[S2] << 1)))); + ld<s8,true>(m_r[S1] + (m_r[S2] << 0), D); else exception(E_PRIVILEGE); break; case 0x100: // st.d: store double word - m_data_space.write_dword(m_r[S1] + m_r[S2] + 0, u32(m_r[D0])); - m_data_space.write_dword(m_r[S1] + m_r[S2] + 4, u32(m_r[D1])); + st<u64>(m_r[S1] + m_r[S2], D); break; case 0x108: // st.d.usr: store double word user (privileged) if (m_cr[PSR] & PSR_MODE) - { - m_data_space.write_dword(m_r[S1] + m_r[S2] + 0, u32(m_r[D0])); - m_data_space.write_dword(m_r[S1] + m_r[S2] + 4, u32(m_r[D1])); - } + st<u64,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x120: // st: store word - m_data_space.write_dword(m_r[S1] + m_r[S2], u32(m_r[D])); + st<u32>(m_r[S1] + m_r[S2], D); break; case 0x128: // st.usr: store word user (privileged) if (m_cr[PSR] & PSR_MODE) - m_data_space.write_dword(m_r[S1] + m_r[S2], u32(m_r[D])); + st<u32,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x140: // st.h: store half word - m_data_space.write_word(m_r[S1] + m_r[S2], u16(m_r[D])); + st<u16>(m_r[S1] + m_r[S2], D); break; case 0x148: // st.h.usr: store half word user (privileged) if (m_cr[PSR] & PSR_MODE) - m_data_space.write_word(m_r[S1] + m_r[S2], u16(m_r[D])); + st<u16,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x160: // st.b: store byte - m_data_space.write_byte(m_r[S1] + m_r[S2], u8(m_r[D])); + st<u8>(m_r[S1] + m_r[S2], D); break; case 0x168: // st.b.usr: store byte user (privileged) if (m_cr[PSR] & PSR_MODE) - m_data_space.write_byte(m_r[S1] + m_r[S2], u8(m_r[D])); + st<u8,true>(m_r[S1] + m_r[S2], D); else exception(E_PRIVILEGE); break; case 0x110: // st.d: store double word (scaled) - m_data_space.write_dword(m_r[S1] + (m_r[S2] << 3) + 0, u32(m_r[D0])); - m_data_space.write_dword(m_r[S1] + (m_r[S2] << 3) + 4, u32(m_r[D1])); + st<u64>(m_r[S1] + (m_r[S2] << 3), D); break; case 0x118: // st.d.usr: store double word user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - { - m_data_space.write_dword(m_r[S1] + (m_r[S2] << 3) + 0, u32(m_r[D0])); - m_data_space.write_dword(m_r[S1] + (m_r[S2] << 3) + 4, u32(m_r[D1])); - } + st<u64,true>(m_r[S1] + (m_r[S2] << 3), D); else exception(E_PRIVILEGE); break; case 0x130: // st: store word (scaled) - m_data_space.write_dword(m_r[S1] + (m_r[S2] << 2), u32(m_r[D])); + st<u32>(m_r[S1] + (m_r[S2] << 2), D); break; case 0x138: // st.usr: store word user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - m_data_space.write_dword(m_r[S1] + (m_r[S2] << 2), u32(m_r[D])); + st<u32,true>(m_r[S1] + (m_r[S2] << 2), D); else exception(E_PRIVILEGE); break; case 0x150: // st.h: store half word (scaled) - m_data_space.write_word(m_r[S1] + (m_r[S2] << 1), u16(m_r[D])); + st<u16>(m_r[S1] + (m_r[S2] << 1), D); break; case 0x158: // st.h.usr: store half word user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - m_data_space.write_word(m_r[S1] + (m_r[S2] << 1), u16(m_r[D])); + st<u16,true>(m_r[S1] + (m_r[S2] << 1), D); else exception(E_PRIVILEGE); break; case 0x170: // st.b: store byte (scaled) - m_data_space.write_byte(m_r[S1] + (m_r[S2] << 0), u8(m_r[D])); + st<u8>(m_r[S1] + (m_r[S2] << 0), D); break; case 0x178: // st.b.usr: store byte user (scaled, privileged) if (m_cr[PSR] & PSR_MODE) - m_data_space.write_byte(m_r[S1] + (m_r[S2] << 0), u8(m_r[D])); + st<u8,true>(m_r[S1] + (m_r[S2] << 0), D); else exception(E_PRIVILEGE); break; @@ -1293,7 +1283,21 @@ void mc88100_device::set_cr(unsigned const cr, u32 const data) break; case PSR: + if (data & PSR_SFRZ) + { + m_cr[SSBR] = m_sb; + m_cr[SXIP] = m_xip; + m_cr[SNIP] = m_nip; + m_cr[SFIP] = m_fip; + } + + if (!(data & PSR_MODE)) + debugger_privilege_hook(); + + [[fallthrough]]; case EPSR: + if (data & PSR_BO) + fatalerror("mc88100: little-endian mode not emulated (%s)\n", machine().describe_context()); m_cr[cr] = (m_cr[cr] & ~PSR_MASK) | (data & PSR_MASK); break; @@ -1360,23 +1364,46 @@ void mc88100_device::exception(unsigned vector, bool const trap) LOGMASKED(LOG_EXCEPTION, "exception %u xip 0x%08x\n", vector, m_xip & IP_A); if (!(m_cr[PSR] & PSR_SFRZ)) + { + m_cr[SSBR] = m_sb; + m_cr[SXIP] = m_xip; + m_cr[SNIP] = m_nip; + m_cr[SFIP] = m_fip; + m_cr[EPSR] = m_cr[PSR]; + } else if (!trap) vector = E_ERROR; + bool const supervisor = m_cr[PSR] & PSR_MODE; m_cr[PSR] |= PSR_MODE | PSR_SFD1 | PSR_IND | PSR_SFRZ; m_sb = 0; + if (vector != E_DATA) + { + m_cr[DMT0] = 0; + m_cr[DMT1] = 0; + m_cr[DMT2] = 0; + } + // invalidate execution and next instruction pointers m_xip &= ~IP_V; m_nip &= ~IP_V; - // set fetch instruction pointer + // update fetch instruction pointer m_fip = m_cr[VBR] | (vector << 3) | IP_V; // notify debugger - if ((vector != E_INTERRUPT) && (machine().debug_flags & DEBUG_FLAG_ENABLED)) - debug()->exception_hook(vector); + if (machine().debug_flags & DEBUG_FLAG_ENABLED) + { + if (vector == E_INTERRUPT) + debug()->interrupt_hook(INPUT_LINE_IRQ0, m_xip & IP_A); + else + debug()->exception_hook(vector); + + if (!supervisor) + debug()->privilege_hook(); + } } bool mc88100_device::condition(unsigned const m5, u32 const src) const @@ -1425,7 +1452,7 @@ u32 mc88100_device::cmp(u32 const src1, u32 const src2) const bool mc88100_device::carry(u32 const src1, u32 const src2, u32 const dest) const { - return ((BIT(src2, 31) && BIT(src1, 31)) || (!BIT(dest, 31) && (BIT(src2, 31) || BIT(src1, 31)))); + return BIT((src1 & src2) ^ ((src1 ^ src2) & ~dest), 31); } bool mc88100_device::overflow(u32 const src1, u32 const src2, u32 const dest) const @@ -1495,3 +1522,310 @@ void mc88100_device::fset(unsigned const td, unsigned const d, float64_t const d break; } } + +void mc88100_device::fetch(u32 &address, u32 &inst) +{ + if (m_cmmu_i) + { + std::optional<u32> data = m_cmmu_i->read<u32>(address & IP_A, m_cr[PSR] & PSR_MODE); + if (data.has_value()) + inst = data.value(); + else + address |= IP_E; + } + else + inst = m_inst_space.read_dword(address & IP_A); +} + +template <typename T, bool Usr> void mc88100_device::ld(u32 address, unsigned const reg) +{ + // alignment check + if (address & (sizeof(T) - 1)) + { + if (!(m_cr[PSR] & PSR_MXM)) + { + exception(E_MISALIGNED); + + return; + } + else + address &= ~(sizeof(T) - 1); + } + + if (m_cmmu_d) + { + if constexpr (sizeof(T) < 8) + { + std::optional<T> const data = m_cmmu_d->read<typename std::make_unsigned<T>::type>(address, (m_cr[PSR] & PSR_MODE) && !Usr); + + if (data.has_value() && reg) + m_r[reg] = std::is_signed<T>() ? s32(data.value()) : data.value(); + else if (!data.has_value()) + { + m_cr[DMT0] = (reg << 7) | DMT_EN<T>(address) | DMT_VALID; + m_cr[DMT1] = 0; + m_cr[DMT2] = 0; + if (std::is_signed<T>()) + m_cr[DMT0] |= DMT_SD; + if ((m_cr[PSR] & PSR_MODE) && !Usr) + m_cr[DMT0] |= DMT_DAS; + if ((m_cr[PSR] & PSR_BO)) + m_cr[DMT0] |= DMT_BO; + + m_cr[DMA0] = address & ~3; + m_cr[DMA1] = 0; + m_cr[DMA2] = 0; + + m_cr[DMD0] = 0; + m_cr[DMD1] = 0; + m_cr[DMD2] = 0; + + exception(E_DATA); + } + } + else + { + std::optional<u32> const hi = m_cmmu_d->read<u32>(address + 0, (m_cr[PSR] & PSR_MODE) && !Usr); + std::optional<u32> const lo = m_cmmu_d->read<u32>(address + 4, (m_cr[PSR] & PSR_MODE) && !Usr); + if (lo.has_value() && hi.has_value()) + { + if (reg != 0) + m_r[(reg + 0) & 31] = hi.value(); + if (reg != 31) + m_r[(reg + 1) & 31] = lo.value(); + } + else + { + m_cr[DMT0] = DMT_DOUB1 | (((reg + 0) & 31) << 7) | DMT_EN() | DMT_VALID; + m_cr[DMT1] = (((reg + 1) & 31) << 7) | DMT_EN() | DMT_VALID; + m_cr[DMT2] = 0; + if ((m_cr[PSR] & PSR_MODE) && !Usr) + { + m_cr[DMT0] |= DMT_DAS; + m_cr[DMT1] |= DMT_DAS; + } + if ((m_cr[PSR] & PSR_BO)) + { + m_cr[DMT0] |= DMT_BO; + m_cr[DMT1] |= DMT_BO; + } + + m_cr[DMA0] = address + 0; + m_cr[DMA1] = address + 4; + m_cr[DMA2] = 0; + + m_cr[DMD0] = 0; + m_cr[DMD1] = 0; + m_cr[DMD2] = 0; + + exception(E_DATA); + } + } + } + else + { + if constexpr (sizeof(T) == 1) + { + u32 const data = std::is_signed<T>() ? s32(T(m_data_space.read_byte(address))) : m_data_space.read_byte(address); + + if (reg) + m_r[reg] = data; + } + else if constexpr (sizeof(T) == 2) + { + u32 const data = std::is_signed<T>() ? s32(T(m_data_space.read_word(address))) : m_data_space.read_word(address); + + if (reg) + m_r[reg] = data; + } + else if constexpr (sizeof(T) == 4) + { + u32 const data = m_data_space.read_dword(address); + + if (reg) + m_r[reg] = data; + } + else if constexpr (sizeof(T) == 8) + { + u32 const hi = m_data_space.read_dword(address + 0); + u32 const lo = m_data_space.read_dword(address + 4); + + if (reg != 0) + m_r[(reg + 0) & 31] = hi; + if (reg != 31) + m_r[(reg + 1) & 31] = lo; + } + } +} + +template <typename T, bool Usr> void mc88100_device::st(u32 address, unsigned const reg) +{ + // alignment check + if (address & (sizeof(T) - 1)) + { + if (!(m_cr[PSR] & PSR_MXM)) + { + exception(E_MISALIGNED); + + return; + } + else + address &= ~(sizeof(T) - 1); + } + + if (m_cmmu_d) + { + if constexpr (sizeof(T) < 8) + { + if (!m_cmmu_d->write(address, T(m_r[reg]), (m_cr[PSR] & PSR_MODE) && !Usr)) + { + m_cr[DMT0] = DMT_EN<T>(address) | DMT_WRITE | DMT_VALID; + m_cr[DMT1] = 0; + m_cr[DMT2] = 0; + if ((m_cr[PSR] & PSR_MODE) && !Usr) + m_cr[DMT0] |= DMT_DAS; + if ((m_cr[PSR] & PSR_BO)) + m_cr[DMT0] |= DMT_BO; + + m_cr[DMA0] = address & ~3; + m_cr[DMA1] = 0; + m_cr[DMA2] = 0; + + m_cr[DMD0] = T(m_r[reg]); + m_cr[DMD1] = 0; + m_cr[DMD2] = 0; + + exception(E_DATA); + } + } + else + { + bool result = true; + result &= m_cmmu_d->write(address + 0, m_r[(reg + 0) & 31], (m_cr[PSR] & PSR_MODE) && !Usr); + result &= m_cmmu_d->write(address + 4, m_r[(reg + 1) & 31], (m_cr[PSR] & PSR_MODE) && !Usr); + + if (!result) + { + m_cr[DMT0] = DMT_DOUB1 | DMT_EN() | DMT_WRITE | DMT_VALID; + m_cr[DMT1] = DMT_EN() | DMT_WRITE | DMT_VALID; + m_cr[DMT2] = 0; + if ((m_cr[PSR] & PSR_MODE) && !Usr) + { + m_cr[DMT0] |= DMT_DAS; + m_cr[DMT1] |= DMT_DAS; + } + if ((m_cr[PSR] & PSR_BO)) + { + m_cr[DMT0] |= DMT_BO; + m_cr[DMT1] |= DMT_BO; + } + + m_cr[DMA0] = address + 0; + m_cr[DMA1] = address + 4; + m_cr[DMA2] = 0; + + m_cr[DMD0] = m_r[(reg + 0) & 31]; + m_cr[DMD1] = m_r[(reg + 1) & 31]; + m_cr[DMD2] = 0; + + exception(E_DATA); + } + } + } + else + { + if constexpr (sizeof(T) == 1) + m_data_space.write_byte(address, m_r[reg]); + else if constexpr (sizeof(T) == 2) + m_data_space.write_word(address, m_r[reg]); + else if constexpr (sizeof(T) == 4) + m_data_space.write_dword(address, m_r[reg]); + else if constexpr (sizeof(T) == 8) + { + m_data_space.write_dword(address + 0, m_r[(reg + 0) & 31]); + m_data_space.write_dword(address + 4, m_r[(reg + 1) & 31]); + } + } +} + +template <typename T, bool Usr> void mc88100_device::xmem(u32 address, unsigned const reg) +{ + // alignment check + if (address & (sizeof(T) - 1)) + { + if (!(m_cr[PSR] & PSR_MXM)) + exception(E_MISALIGNED); + else + address &= ~(sizeof(T) - 1); + } + + // save source value + T const src = m_r[reg]; + + if (m_cmmu_d) + { + // read destination + std::optional<T> const dst = m_cmmu_d->read<T>(address, (m_cr[PSR] & PSR_MODE) && !Usr); + if (dst.has_value()) + { + // update register + if (reg) + m_r[reg] = dst.value(); + + // write destination + if (m_cmmu_d->write<T>(address, src, (m_cr[PSR] & PSR_MODE) && !Usr)) + return; + } + + m_cr[DMT0] = DMT_DOUB1 | DMT_LOCK | (reg << 7) | DMT_EN<T>(address) | DMT_VALID; + m_cr[DMT1] = DMT_LOCK | DMT_EN<T>(address) | DMT_WRITE | DMT_VALID; + m_cr[DMT2] = 0; + if ((m_cr[PSR] & PSR_MODE) && !Usr) + { + m_cr[DMT0] |= DMT_DAS; + m_cr[DMT1] |= DMT_DAS; + } + if ((m_cr[PSR] & PSR_BO)) + { + m_cr[DMT0] |= DMT_BO; + m_cr[DMT1] |= DMT_BO; + } + + m_cr[DMA0] = address & ~3; + m_cr[DMA1] = address & ~3; + m_cr[DMA2] = 0; + + m_cr[DMD0] = 0; + m_cr[DMD1] = src; + m_cr[DMD2] = 0; + + exception(E_DATA); + } + else + { + if constexpr (sizeof(T) == 1) + { + // read destination + T const dst = m_data_space.read_byte(address); + + // update register + if (reg) + m_r[reg] = dst; + + // write destination + m_data_space.write_byte(address, src); + } + else if constexpr (sizeof(T) == 4) + { + // read destination + T const dst = m_data_space.read_dword(address); + + // update register + if (reg) + m_r[reg] = dst; + + // write destination + m_data_space.write_dword(address, src); + } + } +} |