From eceeca25099659db833470dc9241131838ba76db Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Thu, 29 Feb 2024 11:27:24 +0700 Subject: pc532: add floating-point unit * ns32381: add new device * ns32k: refactor slave interface * ns32k: fix format 9 instruction decoding --- src/devices/cpu/ns32000/common.h | 85 ++-- src/devices/cpu/ns32000/ns32000.cpp | 102 ++-- src/devices/cpu/ns32000/ns32000d.cpp | 10 +- src/devices/machine/ns32081.cpp | 877 ++++++++++++++++++++--------------- src/devices/machine/ns32081.h | 107 ++++- src/devices/machine/ns32082.cpp | 58 +-- src/devices/machine/ns32082.h | 23 +- src/devices/machine/ns32382.cpp | 39 +- src/devices/machine/ns32382.h | 16 +- src/mame/homebrew/pc532.cpp | 22 +- 10 files changed, 767 insertions(+), 572 deletions(-) diff --git a/src/devices/cpu/ns32000/common.h b/src/devices/cpu/ns32000/common.h index a93259617c9..fa978729b49 100644 --- a/src/devices/cpu/ns32000/common.h +++ b/src/devices/cpu/ns32000/common.h @@ -32,38 +32,6 @@ namespace ns32000 }; } -class ns32000_state_interface -{ -public: - virtual void state_add(device_state_interface &parent, int &index) = 0; -}; - -class ns32000_fpu_interface - : public device_interface - , public ns32000_state_interface -{ -protected: - ns32000_fpu_interface(machine_config const &mconfig, device_t &device) - : device_interface(device, "ns32000_fpu") - { - } -}; - -class ns32000_mmu_interface - : public device_interface - , public ns32000_state_interface -{ -public: - enum translate_result : unsigned { COMPLETE, CANCEL, ABORT }; - virtual translate_result translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool flag = false, bool suppress = false) = 0; - -protected: - ns32000_mmu_interface(machine_config const &mconfig, device_t &device) - : device_interface(device, "ns32000_mmu") - { - } -}; - class ns32000_slave_interface : public device_interface { public: @@ -75,6 +43,14 @@ public: { } + enum slave_idbyte : u8 + { + FORMAT_9 = 0x3e, // fpu + FORMAT_11 = 0xbe, // fpu + FORMAT_12 = 0xfe, // fpu + FORMAT_14 = 0x1e, // mmu + }; + enum slave_status : u16 { SLAVE_Q = 0x0001, // quit (1=error) @@ -87,6 +63,8 @@ public: SLAVE_OK = 0, }; + virtual void state_add(device_state_interface &parent, int &index) = 0; + protected: ns32000_slave_interface(machine_config const &mconfig, device_t &device, char const *type) : device_interface(device, type) @@ -97,31 +75,52 @@ protected: devcb_write_line m_out_scb; }; -class ns32000_slow_slave_interface : public ns32000_slave_interface +class ns32000_fpu_interface : public ns32000_slave_interface +{ +protected: + ns32000_fpu_interface(machine_config const &mconfig, device_t &device) + : ns32000_slave_interface(mconfig, device) + { + } +}; + +class ns32000_mmu_interface : public ns32000_slave_interface { public: - virtual void write_id(u16 data) = 0; - virtual void write_op(u16 data) = 0; - virtual u16 read_st(int *icount = nullptr) = 0; - virtual u16 read_op() = 0; + enum translate_result : unsigned { COMPLETE, CANCEL, ABORT }; + virtual translate_result translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool flag = false, bool suppress = false) = 0; protected: - ns32000_slow_slave_interface(machine_config const &mconfig, device_t &device) + ns32000_mmu_interface(machine_config const &mconfig, device_t &device) : ns32000_slave_interface(mconfig, device) { } }; -class ns32000_fast_slave_interface : public ns32000_slave_interface +class ns32000_slow_slave_interface : public device_interface +{ +public: + virtual u16 slow_status(int *icount = nullptr) = 0; + virtual u16 slow_read() = 0; + virtual void slow_write(u16 data) = 0; + +protected: + ns32000_slow_slave_interface(machine_config const &mconfig, device_t &device) + : device_interface(device, "ns32000_slave_slow") + { + } +}; + +class ns32000_fast_slave_interface : public device_interface { public: - virtual u32 read_st32(int *icount = nullptr) = 0; - virtual u32 read() = 0; - virtual void write(u32 data) = 0; + virtual u32 fast_status(int *icount = nullptr) = 0; + virtual u32 fast_read() = 0; + virtual void fast_write(u32 data) = 0; protected: ns32000_fast_slave_interface(machine_config const &mconfig, device_t &device) - : ns32000_slave_interface(mconfig, device) + : device_interface(device, "ns32000_slave_fast") { } }; diff --git a/src/devices/cpu/ns32000/ns32000.cpp b/src/devices/cpu/ns32000/ns32000.cpp index d28d25b03ad..6fef593dfd8 100644 --- a/src/devices/cpu/ns32000/ns32000.cpp +++ b/src/devices/cpu/ns32000/ns32000.cpp @@ -3128,14 +3128,14 @@ template void ns32000_device::execute } } break; - case 0x3e: + case ns32000_slave_interface::FORMAT_9: // format 9: xxxx xyyy yyoo ofii 0011 1110 if (m_cfg & CFG_F) { u16 const opword = fetch(bytes); addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) }; - size_code const size_f = BIT(opword, 0) ? SIZE_D : SIZE_Q; + size_code const size_f = BIT(opword, 2) ? SIZE_D : SIZE_Q; size_code const size = size_code(opword & 3); switch (BIT(opword, 3, 3)) @@ -3234,7 +3234,7 @@ template void ns32000_device::execute case 0x7e: // format 10 interrupt(UND); break; - case 0xbe: + case ns32000_slave_interface::FORMAT_11: // format 11: xxxx xyyy yyoo oo0f 1011 1110 if (m_cfg & CFG_F) { @@ -3366,7 +3366,7 @@ template void ns32000_device::execute else interrupt(UND); break; - case 0xfe: + case ns32000_slave_interface::FORMAT_12: // format 12: xxxx xyyy yyoo oo0f 1111 1110 if ((m_cfg & CFG_F) && type() == NS32332) { @@ -3459,7 +3459,7 @@ template void ns32000_device::execute case 0x9e: // format 13 interrupt(UND); break; - case 0x1e: + case ns32000_slave_interface::FORMAT_14: // format 14: xxxx xsss s0oo ooii 0001 1110 if (!(m_psr & PSR_U)) { @@ -3671,7 +3671,7 @@ template u16 ns32000_device::slave(u8 { switch (opbyte) { - case 0x1e: + case ns32000_slave_interface::FORMAT_14: if (!m_mmu) fatalerror("slave mmu coprocessor not configured (%s)\n", machine().describe_context()); @@ -3681,9 +3681,9 @@ template u16 ns32000_device::slave(u8 return slave_slow(dynamic_cast(*m_mmu), opbyte, opword, op1, op2); break; - case 0x3e: - case 0xbe: - case 0xfe: + case ns32000_slave_interface::FORMAT_9: + case ns32000_slave_interface::FORMAT_11: + case ns32000_slave_interface::FORMAT_12: if (!m_fpu) fatalerror("slave fpu coprocessor not configured (%s)\n", machine().describe_context()); @@ -3701,8 +3701,8 @@ template u16 ns32000_device::slave(u8 template u16 ns32000_device::slave_slow(ns32000_slow_slave_interface &slave, u8 opbyte, u16 opword, addr_mode op1, addr_mode op2) { - slave.write_id(opbyte); - slave.write_op(swapendian_int16(opword)); + slave.slow_write(opbyte); + slave.slow_write(swapendian_int16(opword)); if ((op1.access == READ || op1.access == RMW) && !(op1.type == REG && op1.slave)) { @@ -3711,20 +3711,20 @@ template u16 ns32000_device::slave_sl switch (op1.size) { case SIZE_B: - slave.write_op(u8(data)); + slave.slow_write(u8(data)); break; case SIZE_W: - slave.write_op(u16(data)); + slave.slow_write(u16(data)); break; case SIZE_D: - slave.write_op(u16(data >> 0)); - slave.write_op(u16(data >> 16)); + slave.slow_write(u16(data >> 0)); + slave.slow_write(u16(data >> 16)); break; case SIZE_Q: - slave.write_op(u16(data >> 0)); - slave.write_op(u16(data >> 16)); - slave.write_op(u16(data >> 32)); - slave.write_op(u16(data >> 48)); + slave.slow_write(u16(data >> 0)); + slave.slow_write(u16(data >> 16)); + slave.slow_write(u16(data >> 32)); + slave.slow_write(u16(data >> 48)); break; } } @@ -3732,8 +3732,8 @@ template u16 ns32000_device::slave_sl { u32 const data = ea(op1); - slave.write_op(u16(data >> 0)); - slave.write_op(u16(data >> 16)); + slave.slow_write(u16(data >> 0)); + slave.slow_write(u16(data >> 16)); // single-byte memory read cycle mem_read(ns32000::ST_ODT, data, true); @@ -3746,41 +3746,41 @@ template u16 ns32000_device::slave_sl switch (op2.size) { case SIZE_B: - slave.write_op(u8(data)); + slave.slow_write(u8(data)); break; case SIZE_W: - slave.write_op(u16(data)); + slave.slow_write(u16(data)); break; case SIZE_D: - slave.write_op(u16(data >> 0)); - slave.write_op(u16(data >> 16)); + slave.slow_write(u16(data >> 0)); + slave.slow_write(u16(data >> 16)); break; case SIZE_Q: - slave.write_op(u16(data >> 0)); - slave.write_op(u16(data >> 16)); - slave.write_op(u16(data >> 32)); - slave.write_op(u16(data >> 48)); + slave.slow_write(u16(data >> 0)); + slave.slow_write(u16(data >> 16)); + slave.slow_write(u16(data >> 32)); + slave.slow_write(u16(data >> 48)); break; } } - u16 const status = slave.read_st(&m_icount); + u16 const status = slave.slow_status(&m_icount); if (!(status & ns32000_slave_interface::SLAVE_Q)) { if ((op2.access == WRITE || op2.access == RMW) && !(op2.type == REG && op2.slave)) { - u64 data = slave.read_op(); + u64 data = slave.slow_read(); switch (op2.size) { case SIZE_D: - data |= u64(slave.read_op()) << 16; + data |= u64(slave.slow_read()) << 16; break; case SIZE_Q: - data |= u64(slave.read_op()) << 16; - data |= u64(slave.read_op()) << 32; - data |= u64(slave.read_op()) << 48; + data |= u64(slave.slow_read()) << 16; + data |= u64(slave.slow_read()) << 32; + data |= u64(slave.slow_read()) << 48; break; default: break; @@ -3795,7 +3795,7 @@ template u16 ns32000_device::slave_sl template u16 ns32000_device::slave_fast(ns32000_fast_slave_interface &slave, u8 opbyte, u16 opword, addr_mode op1, addr_mode op2) { - slave.write(u32(opbyte) << 24 | u32(swapendian_int16(opword)) << 8); + slave.fast_write(u32(opbyte) << 24 | u32(swapendian_int16(opword)) << 8); if ((op1.access == READ || op1.access == RMW) && !(op1.type == REG && op1.slave)) { @@ -3804,17 +3804,17 @@ template u16 ns32000_device::slave_fa switch (op1.size) { case SIZE_B: - slave.write(u8(data)); + slave.fast_write(u8(data)); break; case SIZE_W: - slave.write(u16(data)); + slave.fast_write(u16(data)); break; case SIZE_D: - slave.write(u32(data)); + slave.fast_write(u32(data)); break; case SIZE_Q: - slave.write(u32(data >> 0)); - slave.write(u32(data >> 32)); + slave.fast_write(u32(data >> 0)); + slave.fast_write(u32(data >> 32)); break; } } @@ -3822,7 +3822,7 @@ template u16 ns32000_device::slave_fa { u32 const data = ea(op1); - slave.write(u32(data)); + slave.fast_write(u32(data)); // single-byte memory read cycle mem_read(ns32000::ST_ODT, data, true); @@ -3835,32 +3835,32 @@ template u16 ns32000_device::slave_fa switch (op2.size) { case SIZE_B: - slave.write(u8(data)); + slave.fast_write(u8(data)); break; case SIZE_W: - slave.write(u16(data)); + slave.fast_write(u16(data)); break; case SIZE_D: - slave.write(u32(data)); + slave.fast_write(u32(data)); break; case SIZE_Q: - slave.write(u32(data >> 0)); - slave.write(u32(data >> 32)); + slave.fast_write(u32(data >> 0)); + slave.fast_write(u32(data >> 32)); break; } } // TODO: status is optional in fast protocol - u32 const status = slave.read_st32(&m_icount); + u32 const status = slave.fast_status(&m_icount); if (!(status & ns32000_slave_interface::SLAVE_Q)) { if ((op2.access == WRITE || op2.access == RMW) && !(op2.type == REG && op2.slave)) { - u64 data = slave.read(); + u64 data = slave.fast_read(); if (op2.size == SIZE_Q) - data |= u64(slave.read()) << 32; + data |= u64(slave.fast_read()) << 32; gen_write(op2, data); } @@ -4162,7 +4162,7 @@ void ns32532_device::spr(unsigned reg, addr_mode const mode, bool user, unsigned u16 ns32532_device::slave(u8 opbyte, u16 opword, addr_mode op1, addr_mode op2) { - if (opbyte == 0x1e) + if (opbyte == FORMAT_14) { switch (BIT(opword, 2, 4)) { diff --git a/src/devices/cpu/ns32000/ns32000d.cpp b/src/devices/cpu/ns32000/ns32000d.cpp index 4b9c49f813d..170e2c7ae88 100644 --- a/src/devices/cpu/ns32000/ns32000d.cpp +++ b/src/devices/cpu/ns32000/ns32000d.cpp @@ -461,7 +461,7 @@ offs_t ns32000_disassembler::disassemble(std::ostream &stream, offs_t pc, data_b u16 const opword = opcodes.r16(pc + bytes); bytes += 2; addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) }; - size_code const size_f = BIT(opword, 0) ? SIZE_D : SIZE_Q; + size_code const size_f = BIT(opword, 2) ? SIZE_D : SIZE_Q; size_code const size = size_code(opword & 3); switch (BIT(opword, 3, 3)) @@ -473,7 +473,7 @@ offs_t ns32000_disassembler::disassemble(std::ostream &stream, offs_t pc, data_b mode[0].size_i(size); mode[1].size_f(size_f); decode(mode, pc, opcodes, bytes); - util::stream_format(stream, "MOV%c%c %s, %s", size_char[size], BIT(opword, 0) ? 'F' : 'L', mode[0].mode, mode[1].mode); + util::stream_format(stream, "MOV%c%c %s, %s", size_char[size], BIT(opword, 2) ? 'F' : 'L', mode[0].mode, mode[1].mode); break; case 1: // LFSR src @@ -508,7 +508,7 @@ offs_t ns32000_disassembler::disassemble(std::ostream &stream, offs_t pc, data_b mode[0].size_f(size_f); mode[1].size_i(size); decode(mode, pc, opcodes, bytes); - util::stream_format(stream, "ROUND%c%c %s, %s", BIT(opword, 0) ? 'F' : 'L', size_char[size], mode[0].mode, mode[1].mode); + util::stream_format(stream, "ROUND%c%c %s, %s", BIT(opword, 2) ? 'F' : 'L', size_char[size], mode[0].mode, mode[1].mode); break; case 5: // TRUNCfi src,dst @@ -517,7 +517,7 @@ offs_t ns32000_disassembler::disassemble(std::ostream &stream, offs_t pc, data_b mode[0].size_f(size_f); mode[1].size_i(size); decode(mode, pc, opcodes, bytes); - util::stream_format(stream, "TRUNC%c%c %s, %s", BIT(opword, 0) ? 'F' : 'L', size_char[size], mode[0].mode, mode[1].mode); + util::stream_format(stream, "TRUNC%c%c %s, %s", BIT(opword, 2) ? 'F' : 'L', size_char[size], mode[0].mode, mode[1].mode); break; case 6: // SFSR dst @@ -534,7 +534,7 @@ offs_t ns32000_disassembler::disassemble(std::ostream &stream, offs_t pc, data_b mode[0].size_f(size_f); mode[1].size_i(size); decode(mode, pc, opcodes, bytes); - util::stream_format(stream, "FLOOR%c%c %s, %s", BIT(opword, 0) ? 'F' : 'L', size_char[size], mode[0].mode, mode[1].mode); + util::stream_format(stream, "FLOOR%c%c %s, %s", BIT(opword, 2) ? 'F' : 'L', size_char[size], mode[0].mode, mode[1].mode); break; } } diff --git a/src/devices/machine/ns32081.cpp b/src/devices/machine/ns32081.cpp index ca648423701..ab406a84d04 100644 --- a/src/devices/machine/ns32081.cpp +++ b/src/devices/machine/ns32081.cpp @@ -8,7 +8,9 @@ * - Microprocessor Databook, Series 32000, NSC800, 1989 Edition, National Semiconductor * * TODO: - * - NS32381 + * - poly/scalb/logb/dot + * - ns32381 timing + * - no-result operations */ #include "emu.h" @@ -21,6 +23,7 @@ #include "logmacro.h" DEFINE_DEVICE_TYPE(NS32081, ns32081_device, "ns32081", "National Semiconductor NS32081 Floating-Point Unit") +DEFINE_DEVICE_TYPE(NS32381, ns32381_device, "ns32381", "National Semiconductor NS32381 Floating-Point Unit") enum fsr_mask : u32 { @@ -31,6 +34,7 @@ enum fsr_mask : u32 FSR_IF = 0x00000040, // inexact result flag FSR_RM = 0x00000180, // rounding mode FSR_SWF = 0x0000fe00, // software field + FSR_RMB = 0x00010000, // (32381 only) register modify bit }; enum rm_mask : u32 @@ -61,149 +65,159 @@ enum state : unsigned RESULT = 5, // result word available }; -enum idbyte : u8 -{ - FORMAT_9 = 0x3e, - FORMAT_11 = 0xbe, -}; - enum operand_length : unsigned { LENGTH_F = 4, // single precision LENGTH_L = 8, // double precision }; -enum size_code : unsigned -{ - SIZE_B = 0, - SIZE_W = 1, - SIZE_D = 3, -}; - -ns32081_device::ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) - : device_t(mconfig, NS32081, tag, owner, clock) - , ns32000_slow_slave_interface(mconfig, *this) +ns32081_device_base::ns32081_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) , ns32000_fpu_interface(mconfig, *this) { } -void ns32081_device::device_start() +void ns32081_device_base::device_start() { save_item(NAME(m_fsr)); - save_item(NAME(m_f)); + save_item(NAME(m_state)); save_item(NAME(m_idbyte)); save_item(NAME(m_opword)); + save_item(STRUCT_MEMBER(m_op, expected)); save_item(STRUCT_MEMBER(m_op, issued)); save_item(STRUCT_MEMBER(m_op, value)); - save_item(NAME(m_status)); - save_item(NAME(m_state)); + save_item(NAME(m_status)); save_item(NAME(m_tcy)); m_complete = timer_alloc(FUNC(ns32081_device::complete), this); } -void ns32081_device::device_reset() +void ns32081_device_base::device_reset() { m_fsr = 0; - std::fill(std::begin(m_f), std::end(m_f), 0); - m_state = IDLE; + m_idbyte = 0; + m_opword = 0; + m_status = 0; + m_tcy = 0; } -void ns32081_device::state_add(device_state_interface &parent, int &index) +void ns32081_device_base::state_add(device_state_interface &parent, int &index) { parent.state_add(index++, "FSR", m_fsr).formatstr("%04X"); - - for (unsigned i = 0; i < 8; i++) - parent.state_add(index++, util::string_format("F%d", i).c_str(), m_f[i]).formatstr("%08X"); } -u16 ns32081_device::read_st(int *icount) +template T ns32081_device_base::read() { - if (m_state == STATUS) + if (m_state == RESULT && m_op[2].issued < m_op[2].expected) { - m_state = (m_op[2].issued == m_op[2].expected) ? IDLE : RESULT; + T const data = m_op[2].value >> (m_op[2].issued * 8); - if (icount) - *icount -= m_tcy; + m_op[2].issued += sizeof(T); - LOG("read_st status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy, - (m_state == RESULT ? "results pending" : "complete"), machine().describe_context()); + LOG("read %d data 0x%0*x (%s)\n", + m_op[2].issued / sizeof(T), sizeof(T) * 2, data, machine().describe_context()); - return m_status; + if (m_op[2].issued == m_op[2].expected) + { + LOG("read complete\n"); + m_state = IDLE; + } + + return data; } - logerror("protocol error reading status word (%s)\n", machine().describe_context()); + logerror("read protocol error (%s)\n", machine().describe_context()); return 0; } -u16 ns32081_device::read_op() +template void ns32081_device_base::write(T data) { - if (m_state == RESULT && m_op[2].issued < m_op[2].expected) + switch (m_state) { - u16 const data = u16(m_op[2].value >> (m_op[2].issued * 8)); - LOG("read_op word %d data 0x%04x (%s)\n", m_op[2].issued >> 1, data, machine().describe_context()); - - m_op[2].issued += 2; + case IDLE: + if (sizeof(T) == 4) + { + // decode instruction + if (!decode(BIT(data, 24, 8), swapendian_int16(BIT(data, 8, 16)))) + return; - if (m_op[2].issued == m_op[2].expected) + m_state = OPERAND; + } + else { - LOG("read_op last result word issued\n"); - m_state = IDLE; + LOG("write idbyte 0x%04x (%s)\n", data, machine().describe_context()); + if ((data == FORMAT_9) || (data == FORMAT_11) || (type() == NS32381 && data == FORMAT_12)) + { + // record idbyte + m_idbyte = data; + + m_state = OPERATION; + } } + break; - return data; - } + case OPERATION: + LOG("write opword 0x%0*x (%s)\n", sizeof(T) * 2, data, machine().describe_context()); - logerror("protocol error reading result word (%s)\n", machine().describe_context()); - return 0; -} + // decode instruction + decode(m_idbyte, swapendian_int16(data)); -void ns32081_device::write_id(u16 data) -{ - bool const match = (data == FORMAT_9) || (data == FORMAT_11); + m_state = OPERAND; + break; - if (match) - { - LOG("write_id match 0x%04x (%s)\n", data, machine().describe_context()); - m_state = OPERATION; - } - else - { - LOG("write_id ignore 0x%04x (%s)\n", data, machine().describe_context()); - m_state = IDLE; + case OPERAND: + // check awaiting operand data + if (m_op[0].issued < m_op[0].expected || m_op[1].issued < m_op[1].expected) + { + unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1; + operand &op = m_op[n]; + + LOG("write operand %d data 0x%0*x (%s)\n", + n, sizeof(T) * 2, data, machine().describe_context()); + + // insert data into operand value + op.value |= u64(data) << (op.issued * 8); + op.issued += sizeof(T); + } + else + logerror("write protocol error unexpected operand data 0x%0*x (%s)\n", + sizeof(T) * 2, data, machine().describe_context()); + break; } - m_idbyte = u8(data); + // start execution when all operands are available + if (m_state == OPERAND && m_op[0].issued >= m_op[0].expected && m_op[1].issued >= m_op[1].expected) + execute(); } -void ns32081_device::write_op(u16 data) +bool ns32081_device_base::decode(u8 const idbyte, u16 const opword) { - switch (m_state) - { - case OPERATION: - m_opword = swapendian_int16(data); - LOG("write_op opword 0x%04x (%s)\n", m_opword, machine().describe_context()); + LOG("decode idbyte 0x%02x opword 0x%04x (%s)\n", idbyte, opword, machine().describe_context()); - // initialize operands - for (operand &op : m_op) - { - op.expected = 0; - op.issued = 0; - op.value = 0; - } + m_idbyte = idbyte; + m_opword = opword; + + // initialize operands + for (operand &op : m_op) + { + op.expected = 0; + op.issued = 0; + op.value = 0; + } - // decode operands - if (m_idbyte == FORMAT_9) + switch (m_idbyte) + { + case FORMAT_9: { // format 9: 1111 1222 22oo ofii unsigned const f_length = BIT(m_opword, 2) ? LENGTH_F : LENGTH_L; unsigned const size = m_opword & 3; - switch ((m_opword >> 3) & 7) + switch (BIT(m_opword, 3, 3)) { case 0: // movif m_op[0].expected = size + 1; @@ -231,10 +245,11 @@ void ns32081_device::write_op(u16 data) break; } } - else if (m_idbyte == FORMAT_11) + break; + case FORMAT_11: { // format 11: 1111 1222 22oo oo0f - unsigned const opcode = (m_opword >> 2) & 15; + unsigned const opcode = BIT(m_opword, 2, 4); unsigned const f_length = BIT(m_opword, 0) ? LENGTH_F : LENGTH_L; m_op[0].expected = f_length; @@ -247,69 +262,65 @@ void ns32081_device::write_op(u16 data) if (opcode != 2) m_op[2].expected = f_length; } - - // operand 1 in register - if (m_op[0].expected && !(m_opword & 0xc000)) + break; + case FORMAT_12: { - // exclude integer operands - if (m_idbyte == FORMAT_11 || ((m_opword >> 3) & 7) > 1) - { - unsigned const reg = (m_opword >> 11) & 7; - LOG("write_op read f%d\n", reg); - - m_op[0].value = m_f[reg ^ 0]; - if (m_op[0].expected == 8) - m_op[0].value |= u64(m_f[reg ^ 1]) << 32; + // format 12: 1111 1222 22oo oo0f + unsigned const f_length = BIT(m_opword, 0) ? LENGTH_F : LENGTH_L; - m_op[0].issued = m_op[0].expected; + switch (BIT(m_opword, 2, 4)) + { + case 2: // polyf + case 3: // dotf + m_op[0].expected = f_length; + m_op[1].expected = f_length; + break; + case 4: // scalbf + m_op[0].expected = f_length; + m_op[1].expected = f_length; + m_op[2].expected = f_length; + break; + case 5: // logbf + m_op[0].expected = f_length; + m_op[2].expected = f_length; + break; } } + break; + default: + LOG("decode idbyte 0x%02x unknown (%s)\n", m_idbyte, machine().describe_context()); + return false; + } - // operand 2 in register - if (m_op[1].expected && !(m_opword & 0x0600)) + // operand 1 in register + if (m_op[0].expected && !BIT(m_opword, 14, 2)) + { + // exclude integer operands + if (m_idbyte != FORMAT_9 || (BIT(m_opword, 3, 3) > 1)) { - unsigned const reg = (m_opword >> 6) & 7; - LOG("write_op read f%d\n", reg); + reg_get(m_op[0].expected, m_op[0].value, BIT(m_opword, 11, 3)); - m_op[1].value = m_f[reg ^ 0]; - if (m_op[1].expected == 8) - m_op[1].value |= u64(m_f[reg ^ 1]) << 32; - - m_op[1].issued = m_op[1].expected; + m_op[0].issued = m_op[0].expected; } + } - m_state = OPERAND; - break; - - case OPERAND: - // check awaiting operand word - if (m_op[0].issued < m_op[0].expected || m_op[1].issued < m_op[1].expected) - { - unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1; - operand &op = m_op[n]; - - LOG("write_op op%d data 0x%04x (%s)\n", n, data, machine().describe_context()); + // operand 2 in register + if (m_op[1].expected && !BIT(m_opword, 9, 2)) + { + reg_get(m_op[1].expected, m_op[1].value, BIT(m_opword, 6, 3)); - // insert word into operand value - op.value |= u64(data) << (op.issued * 8); - op.issued += 2; - } - else - logerror("protocol error unexpected operand word 0x%04x (%s)\n", data, machine().describe_context()); - break; + m_op[1].issued = m_op[1].expected; } - // start execution when all operands are available - if (m_state == OPERAND && m_op[0].issued >= m_op[0].expected && m_op[1].issued >= m_op[1].expected) - execute(); + return true; } -void ns32081_device::execute() +void ns32081_device_base::execute() { - softfloat_exceptionFlags = 0; u32 const fsr = m_fsr; m_fsr &= ~FSR_TT; + softfloat_exceptionFlags = 0; m_status = 0; m_tcy = 0; @@ -317,235 +328,247 @@ void ns32081_device::execute() { case FORMAT_9: // format 9: 1111 1222 22oo ofii + switch (BIT(m_opword, 3, 3)) { - bool const single = BIT(m_opword, 2); - unsigned const f_length = single ? LENGTH_F : LENGTH_L; - unsigned const size = m_opword & 3; - - switch ((m_opword >> 3) & 7) + case 0: + // MOVif src,dest + // gen,gen + // read.i,write.f { - case 0: - // MOVif src,dest - // gen,gen - // read.i,write.f - { - s32 const src = - (size == SIZE_D) ? s32(m_op[0].value) : - (size == SIZE_W) ? s16(m_op[0].value) : - s8(m_op[0].value); - - if (single) - m_op[2].value = i32_to_f32(src).v; - else - m_op[2].value = i32_to_f64(src).v; - m_op[2].expected = f_length; - m_tcy = 53; - } - break; - case 1: - // LFSR src - // gen - // read.D - m_fsr = u16(m_op[0].value); - - switch (m_fsr & FSR_RM) - { - case RM_N: softfloat_roundingMode = softfloat_round_near_even; break; - case RM_Z: softfloat_roundingMode = softfloat_round_minMag; break; - case RM_U: softfloat_roundingMode = softfloat_round_max; break; - case RM_D: softfloat_roundingMode = softfloat_round_min; break; - } - m_tcy = 18; - break; - case 2: - // MOVLF src,dest - // gen,gen - // read.L,write.F - m_op[2].value = f64_to_f32(float64_t{ m_op[0].value }).v; - m_op[2].expected = f_length; - m_tcy = (m_opword & 0xc000) ? 23 : 27; - break; - case 3: - // MOVFL src,dest - // gen,gen - // read.F,write.L - m_op[2].value = f32_to_f64(float32_t{ u32(m_op[0].value) }).v; - m_op[2].expected = f_length; - m_tcy = (m_opword & 0xc000) ? 22 : 26; - break; - case 4: - // ROUNDfi src,dest - // gen,gen - // read.f,write.i - if (single) - m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_near_even, true); - else - m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_near_even, true); - - if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value)) - || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value)) - || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value))) - softfloat_exceptionFlags |= softfloat_flag_overflow; + s32 const src = util::sext(m_op[0].value, m_op[0].expected * 8); - m_op[2].expected = size + 1; - m_tcy = (m_opword & 0xc000) ? 53 : 66; - break; - case 5: - // TRUNCfi src,dest - // gen,gen - // read.f,write.i - if (single) - m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_minMag, true); + if (m_op[2].expected == LENGTH_F) + m_op[2].value = i32_to_f32(src).v; else - m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_minMag, true); + m_op[2].value = i32_to_f64(src).v; - if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value)) - || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value)) - || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value))) - softfloat_exceptionFlags |= softfloat_flag_overflow; - - m_op[2].expected = size + 1; - m_tcy = (m_opword & 0xc000) ? 53 : 66; - break; - case 6: - // SFSR dest - // gen - // write.D - m_op[2].value = fsr; - m_op[2].expected = 4; - m_tcy = 13; - break; - case 7: - // FLOORfi src,dest - // gen,gen - // read.f,write.i - if (single) - m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_min, true); - else - m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_min, true); - - if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value)) - || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value)) - || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value))) - softfloat_exceptionFlags |= softfloat_flag_overflow; - - m_op[2].expected = size + 1; - m_tcy = (m_opword & 0xc000) ? 53 : 66; - break; + m_tcy = 53; + } + break; + case 1: + // LFSR src + // gen + // read.D + m_fsr = u16(m_op[0].value); + + switch (m_fsr & FSR_RM) + { + case RM_N: softfloat_roundingMode = softfloat_round_near_even; break; + case RM_Z: softfloat_roundingMode = softfloat_round_minMag; break; + case RM_U: softfloat_roundingMode = softfloat_round_max; break; + case RM_D: softfloat_roundingMode = softfloat_round_min; break; } + m_tcy = 18; + break; + case 2: + // MOVLF src,dest + // gen,gen + // read.L,write.F + m_op[2].value = f64_to_f32(float64_t{ m_op[0].value }).v; + + m_tcy = BIT(m_opword, 14, 2) ? 23 : 27; + break; + case 3: + // MOVFL src,dest + // gen,gen + // read.F,write.L + m_op[2].value = f32_to_f64(float32_t{ u32(m_op[0].value) }).v; + + m_tcy = BIT(m_opword, 14, 2) ? 22 : 26; + break; + case 4: + // ROUNDfi src,dest + // gen,gen + // read.f,write.i + if (m_op[0].expected == LENGTH_F) + m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_near_even, true); + else + m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_near_even, true); + + if (s64(m_op[2].value) != util::sext(m_op[2].value, m_op[2].expected * 8)) + softfloat_exceptionFlags |= softfloat_flag_overflow; + + m_tcy = BIT(m_opword, 14, 2) ? 53 : 66; + break; + case 5: + // TRUNCfi src,dest + // gen,gen + // read.f,write.i + if (m_op[0].expected == LENGTH_F) + m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_minMag, true); + else + m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_minMag, true); + + if (s64(m_op[2].value) != util::sext(m_op[2].value, m_op[2].expected * 8)) + softfloat_exceptionFlags |= softfloat_flag_overflow; + + m_tcy = BIT(m_opword, 14, 2) ? 53 : 66; + break; + case 6: + // SFSR dest + // gen + // write.D + m_op[2].value = fsr; + + m_tcy = 13; + break; + case 7: + // FLOORfi src,dest + // gen,gen + // read.f,write.i + if (m_op[0].expected == LENGTH_F) + m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_min, true); + else + m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_min, true); + + if (s64(m_op[2].value) != util::sext(m_op[2].value, m_op[2].expected * 8)) + softfloat_exceptionFlags |= softfloat_flag_overflow; + + m_tcy = BIT(m_opword, 14, 2) ? 53 : 66; + break; } break; case FORMAT_11: - // format 11: 1111122222oooo0f + // format 11: 1111 1222 22oo oo0f + switch (BIT(m_opword, 2, 4)) { - bool const single = BIT(m_opword, 0); - unsigned const f_length = single ? LENGTH_F : LENGTH_L; - - switch ((m_opword >> 2) & 15) - { - case 0x0: - // ADDf src,dest - // gen,gen - // read.f,rmw.f - if (single) - m_op[2].value = f32_add(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v; - else - m_op[2].value = f64_add(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v; - m_op[2].expected = f_length; - m_tcy = (m_opword & 0xc600) ? 70 : 74; - break; - case 0x1: - // MOVf src,dest - // gen,gen - // read.f,write.f - m_op[2].value = m_op[0].value; - m_op[2].expected = f_length; - m_tcy = (m_opword & 0xc000) ? 23 : 27; - break; - case 0x2: - // CMPf src1,src2 - // gen,gen - // read.f,read.f - if (m_op[0].value == m_op[1].value) - m_status |= SLAVE_Z; - if ((single && f32_le(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) })) - || (!single && f64_le(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }))) - m_status |= SLAVE_N; - m_tcy = (m_opword & 0xc600) ? 45 : 49; - break; - case 0x3: - // Trap(SLAVE) - m_fsr |= TT_ILL; - m_status = SLAVE_Q; - break; - case 0x4: - // SUBf src,dest - // gen,gen - // read.f,rmw.f - if (single) - m_op[2].value = f32_sub(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v; - else - m_op[2].value = f64_sub(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v; - m_op[2].expected = f_length; - m_tcy = (m_opword & 0xc600) ? 70 : 74; - break; - case 0x5: - // NEGf src,dest - // gen,gen - // read.f,write.f - if (single) + case 0x0: + // ADDf src,dest + // gen,gen + // read.f,rmw.f + if (m_op[0].expected == LENGTH_F) + m_op[2].value = f32_add(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v; + else + m_op[2].value = f64_add(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v; + + m_tcy = (m_opword & 0xc600) ? 70 : 74; + break; + case 0x1: + // MOVf src,dest + // gen,gen + // read.f,write.f + m_op[2].value = m_op[0].value; + + m_tcy = BIT(m_opword, 14, 2) ? 23 : 27; + break; + case 0x2: + // CMPf src1,src2 + // gen,gen + // read.f,read.f + if (m_op[0].value == m_op[1].value) + m_status |= SLAVE_Z; + if ((m_op[0].expected == LENGTH_F && f32_le(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) })) + || (m_op[0].expected == LENGTH_L && f64_le(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }))) + m_status |= SLAVE_N; + + m_tcy = (m_opword & 0xc600) ? 45 : 49; + break; + case 0x3: + // Trap(SLAVE) + m_fsr |= TT_ILL; + m_status = SLAVE_Q; + break; + case 0x4: + // SUBf src,dest + // gen,gen + // read.f,rmw.f + if (m_op[0].expected == LENGTH_F) + m_op[2].value = f32_sub(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v; + else + m_op[2].value = f64_sub(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v; + + m_tcy = (m_opword & 0xc600) ? 70 : 74; + break; + case 0x5: + // NEGf src,dest + // gen,gen + // read.f,write.f + if (m_op[0].expected == LENGTH_F) + m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v; + else + m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v; + + m_tcy = BIT(m_opword, 14, 2) ? 20 : 24; + break; + case 0x8: + // DIVf src,dest + // gen,gen + // read.f,rmw.f + if (m_op[0].expected == LENGTH_F) + m_op[2].value = f32_div(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v; + else + m_op[2].value = f64_div(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v; + + m_tcy = ((m_opword & 0xc600) ? 55 : 59) + (m_op[0].expected == LENGTH_F ? 30 : 60); + break; + case 0x9: + // Trap(SLAVE) + m_fsr |= TT_ILL; + m_status = SLAVE_Q; + break; + case 0xc: + // MULf src,dest + // gen,gen + // read.f,rmw.f + if (m_op[0].expected == LENGTH_F) + m_op[2].value = f32_mul(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v; + else + m_op[2].value = f64_mul(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v; + + m_tcy = ((m_opword & 0xc600) ? 30 : 34) + (m_op[0].expected == LENGTH_F ? 14 : 28); + break; + case 0xd: + // ABSf src,dest + // gen,gen + // read.f,write.f + if (m_op[0].expected == LENGTH_F) + if (f32_lt(float32_t{ u32(m_op[0].value) }, float32_t{ 0 })) m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v; else + m_op[2].value = float32_t{ u32(m_op[0].value) }.v; + else + if (f64_lt(float64_t{ m_op[0].value }, float64_t{ 0 })) m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v; - m_op[2].expected = f_length; - m_tcy = (m_opword & 0xc000) ? 20 : 24; - break; - case 0x8: - // DIVf src,dest - // gen,gen - // read.f,rmw.f - if (single) - m_op[2].value = f32_div(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v; else - m_op[2].value = f64_div(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v; - m_op[2].expected = f_length; - m_tcy = ((m_opword & 0xc600) ? 55 : 59) + (single ? 30 : 60); - break; - case 0x9: - // Trap(SLAVE) - m_fsr |= TT_ILL; - m_status = SLAVE_Q; - break; - case 0xc: - // MULf src,dest - // gen,gen - // read.f,rmw.f - if (single) - m_op[2].value = f32_mul(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v; - else - m_op[2].value = f64_mul(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v; - m_op[2].expected = f_length; - m_tcy = ((m_opword & 0xc600) ? 30 : 34) + (single ? 14 : 28); - break; - case 0xd: - // ABSf src,dest - // gen,gen - // read.f,write.f - if (single) - if (f32_lt(float32_t{ u32(m_op[0].value) }, float32_t{ 0 })) - m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v; - else - m_op[2].value = float32_t{ u32(m_op[0].value) }.v; - else - if (f64_lt(float64_t{ m_op[0].value }, float64_t{ 0 })) - m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v; - else - m_op[2].value = float64_t{ m_op[0].value }.v; - m_op[2].expected = f_length; - m_tcy = (m_opword & 0xc000) ? 20 : 24; - break; - } + m_op[2].value = float64_t{ m_op[0].value }.v; + + m_tcy = BIT(m_opword, 14, 2) ? 20 : 24; + break; + } + break; + + case FORMAT_12: + // format 12: 1111 1222 22oo oo0f + switch (BIT(m_opword, 2, 4)) + { + case 0x2: + // POLYf src1,src2 + // gen,gen + // read.f,read.f + m_fsr |= FSR_RMB; + break; + case 0x3: + // DOTf src1,src2 + // gen,gen + // read.f,read.f + m_fsr |= FSR_RMB; + break; + case 0x4: + // SCALBf src,dest + // gen,gen + // read.f,rmw.f + break; + case 0x5: + // LOGBf src,dest + // gen,gen + // read.f,write.f + break; + default: + // Trap(SLAVE) + m_fsr |= TT_ILL; + m_status = SLAVE_Q; + break; } break; } @@ -595,47 +618,177 @@ void ns32081_device::execute() "addf", "movf", "cmpf", nullptr, "subf", "negf", nullptr, nullptr, "divf", nullptr, nullptr, nullptr, "mulf", "absf", nullptr, nullptr }; + static char const *format12[] = + { + nullptr, nullptr, "polyf", "dotf", "scalbf", "logbf", nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr + }; + + char const *operation = nullptr; + switch (m_idbyte) + { + case FORMAT_9: operation = format9[BIT(m_opword, 3, 3)]; break; + case FORMAT_11: operation = format11[BIT(m_opword, 2, 4)]; break; + case FORMAT_12: operation = format12[BIT(m_opword, 2, 4)]; break; + } if (m_status & SLAVE_Q) - LOG("execute %s 0x%x,0x%x exception\n", - (m_idbyte == FORMAT_9) - ? format9[(m_opword >> 3) & 7] - : format11[(m_opword >> 2) & 15], - m_op[0].value, m_op[1].value); + LOG("execute %s 0x%x,0x%x exception\n", operation, m_op[0].value, m_op[1].value); else - LOG("execute %s 0x%x,0x%x result 0x%x\n", - (m_idbyte == FORMAT_9) - ? format9[(m_opword >> 3) & 7] - : format11[(m_opword >> 2) & 15], - m_op[0].value, m_op[1].value, m_op[2].value); + LOG("execute %s 0x%x,0x%x result 0x%x\n", operation, m_op[0].value, m_op[1].value, m_op[2].value); } // write-back floating point register results - if (m_op[2].expected && !(m_opword & 0x0600)) + if (m_op[2].expected && !BIT(m_opword, 9, 2)) { // exclude integer results (roundfi, truncfi, sfsr, floorfi) - if (m_idbyte == FORMAT_11 || ((m_opword >> 3) & 7) < 4) + if (m_idbyte != FORMAT_9 || (BIT(m_opword, 3, 3) < 4)) { - unsigned const reg = (m_opword >> 6) & 7; + reg_set(BIT(m_opword, 6, 3), m_op[2].expected, m_op[2].value); - LOG("execute write-back f%d\n", reg); - - m_f[reg ^ 0] = u32(m_op[2].value >> 0); - if (m_op[2].expected == 8) - m_f[reg ^ 1] = u32(m_op[2].value >> 32); + if (type() == NS32381) + m_fsr |= FSR_RMB; m_op[2].issued = m_op[2].expected; } } - m_state = STATUS; - if (!m_out_scb.isunset()) m_complete->adjust(attotime::from_ticks(m_tcy, clock())); + + m_state = STATUS; +} + +u16 ns32081_device_base::status(int *icount) +{ + if (m_state == STATUS) + { + m_state = (m_op[2].issued == m_op[2].expected) ? IDLE : RESULT; + + if (icount) + *icount -= m_tcy; + + LOG("status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy, + (m_state == RESULT ? "results pending" : "complete"), machine().describe_context()); + + return m_status; + } + + logerror("status protocol error (%s)\n", machine().describe_context()); + return 0; } -void ns32081_device::complete(s32 param) +void ns32081_device_base::complete(s32 param) { m_out_scb(0); m_out_scb(1); } + +ns32081_device::ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : ns32081_device_base(mconfig, NS32081, tag, owner, clock) + , ns32000_slow_slave_interface(mconfig, *this) +{ +} + +void ns32081_device::device_start() +{ + ns32081_device_base::device_start(); + + save_item(NAME(m_f)); +} + +void ns32081_device::device_reset() +{ + ns32081_device_base::device_reset(); + + std::fill(std::begin(m_f), std::end(m_f), 0); +} + +void ns32081_device::state_add(device_state_interface &parent, int &index) +{ + ns32081_device_base::state_add(parent, index); + + for (unsigned i = 0; i < 8; i++) + parent.state_add(index++, util::string_format("F%d", i).c_str(), m_f[i]).formatstr("%08X"); +} + +void ns32081_device::reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const +{ + op_value = m_f[reg ^ 0]; + if (op_size == LENGTH_L) + op_value |= u64(m_f[reg ^ 1]) << 32; + + if (op_size == LENGTH_L) + LOG("reg_get f%d:%d data 0x%016x\n", reg ^ 1, reg ^ 0, op_value); + else + LOG("reg_get f%d data 0x%08x\n", reg, op_value); +} + +void ns32081_device::reg_set(unsigned const reg, unsigned const op_size, u64 const op_value) +{ + if (op_size == LENGTH_L) + LOG("reg_set f%d:%d data 0x%016x\n", reg ^ 1, reg ^ 0, op_value); + else + LOG("reg_set f%d data 0x%08x\n", reg, op_value); + + m_f[reg ^ 0] = u32(op_value >> 0); + if (op_size == LENGTH_L) + m_f[reg ^ 1] = u32(op_value >> 32); +} + +ns32381_device::ns32381_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : ns32081_device_base(mconfig, NS32381, tag, owner, clock) + , ns32000_slow_slave_interface(mconfig, *this) + , ns32000_fast_slave_interface(mconfig, *this) +{ +} + +void ns32381_device::device_start() +{ + ns32081_device_base::device_start(); + + save_item(NAME(m_l)); +} + +void ns32381_device::device_reset() +{ + std::fill(std::begin(m_l), std::end(m_l), 0); +} + +void ns32381_device::state_add(device_state_interface &parent, int &index) +{ + ns32081_device_base::state_add(parent, index); + + for (unsigned i = 0; i < 8; i++) + parent.state_add(index++, util::string_format("L%d", i).c_str(), m_l[i]).formatstr("%016X"); +} + +void ns32381_device::reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const +{ + if (op_size == LENGTH_L) + op_value = m_l[reg]; + else if (reg & 1) + op_value = m_l[reg & 6] >> 32; + else + op_value = u32(m_l[reg & 6]); + + if (op_size == LENGTH_L) + LOG("reg_get l%d data 0x%016x\n", reg, op_value); + else + LOG("reg_get f%d data 0x%08x\n", reg, op_value); +} + +void ns32381_device::reg_set(unsigned const reg, unsigned const op_size, u64 const op_value) +{ + if (op_size == LENGTH_L) + LOG("reg_set l%d data 0x%016x\n", reg, op_value); + else + LOG("reg_set f%d data 0x%08x\n", reg, op_value); + + if (op_size == LENGTH_L) + m_l[reg] = op_value; + else if (reg & 1) + m_l[reg & 6] = (op_value << 32) | u32(m_l[reg & 6]); + else + m_l[reg & 6] = (m_l[reg & 6] & 0xffff'ffff'0000'0000ULL) | u32(op_value); +} diff --git a/src/devices/machine/ns32081.h b/src/devices/machine/ns32081.h index 89847175e43..12a50d9434d 100644 --- a/src/devices/machine/ns32081.h +++ b/src/devices/machine/ns32081.h @@ -8,54 +8,119 @@ #include "cpu/ns32000/common.h" -class ns32081_device +class ns32081_device_base : public device_t - , public ns32000_slow_slave_interface , public ns32000_fpu_interface { -public: - ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); - - virtual void state_add(device_state_interface &parent, int &index) override; - - virtual u16 read_st(int *icount = nullptr) override; - virtual u16 read_op() override; - - virtual void write_id(u16 data) override; - virtual void write_op(u16 data) override; - protected: + ns32081_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock); + // device_t implementation virtual void device_start() override; virtual void device_reset() override; + // ns32000_slave_interface implementation + virtual void state_add(device_state_interface &parent, int &index) override; + + // slave interface handlers + template T read(); + template void write(T data); + + // execution helpers + bool decode(u8 const idbyte, u16 const opword); void execute(); + u16 status(int *icount); void complete(s32 param); + // register helpers + virtual void reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const = 0; + virtual void reg_set(unsigned const reg, unsigned const op_size, u64 const op_value) = 0; + private: emu_timer *m_complete; - // registers - u32 m_fsr; - u32 m_f[8]; + u32 m_fsr; // floating-point status register // operating state + u32 m_state; u8 m_idbyte; u16 m_opword; struct operand { - unsigned expected; - unsigned issued; + u32 expected; + u32 issued; u64 value; } m_op[3]; u16 m_status; + u32 m_tcy; +}; - // implementation state - unsigned m_state; - unsigned m_tcy; +class ns32081_device + : public ns32081_device_base + , public ns32000_slow_slave_interface +{ +public: + ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + // ns32000_slave_interface implementation + virtual void state_add(device_state_interface &parent, int &index) override; + + // ns32000_slow_slave_interface implementation + virtual u16 slow_status(int *icount = nullptr) override { return status(icount); } + virtual u16 slow_read() override { return read(); } + virtual void slow_write(u16 data) override { write(data); } + +protected: + // device_t implementation + virtual void device_start() override; + virtual void device_reset() override; + + // register helpers + virtual void reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const override; + virtual void reg_set(unsigned const reg, unsigned const op_size, u64 const op_value) override; + +private: + // registers + u32 m_f[8]; +}; + +class ns32381_device + : public ns32081_device_base + , public ns32000_slow_slave_interface + , public ns32000_fast_slave_interface +{ +public: + ns32381_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + // ns32000_slave_interface implementation + virtual void state_add(device_state_interface &parent, int &index) override; + + // ns32000_slow_slave_interface implementation + virtual u16 slow_status(int *icount = nullptr) override { return status(icount); } + virtual u16 slow_read() override { return read(); } + virtual void slow_write(u16 data) override { write(data); } + + // ns32000_fast_slave_interface implementation + virtual u32 fast_status(int *icount = nullptr) override { return status(icount); } + virtual u32 fast_read() override { return read(); } + virtual void fast_write(u32 data) override { write(data); } + +protected: + // device_t implementation + virtual void device_start() override; + virtual void device_reset() override; + + // register helpers + virtual void reg_get(unsigned const op_size, u64 &op_value, unsigned const reg) const override; + virtual void reg_set(unsigned const reg, unsigned const op_size, u64 const op_value) override; + +private: + // registers + u64 m_l[8]; }; DECLARE_DEVICE_TYPE(NS32081, ns32081_device) +DECLARE_DEVICE_TYPE(NS32381, ns32381_device) #endif // MAME_MACHINE_NS32081_H diff --git a/src/devices/machine/ns32082.cpp b/src/devices/machine/ns32082.cpp index e58cf546e62..4fb26bf5219 100644 --- a/src/devices/machine/ns32082.cpp +++ b/src/devices/machine/ns32082.cpp @@ -34,11 +34,6 @@ enum state : unsigned RESULT = 6, // result word available }; -enum idbyte : u8 -{ - FORMAT_14 = 0x1e, -}; - enum reg_mask : unsigned { BPR0 = 0x0, // breakpoint register 0 @@ -127,8 +122,8 @@ enum eia_mask : u32 ns32082_device::ns32082_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : device_t(mconfig, NS32082, tag, owner, clock) - , ns32000_slow_slave_interface(mconfig, *this) , ns32000_mmu_interface(mconfig, *this) + , ns32000_slow_slave_interface(mconfig, *this) , m_bpr{} , m_pf{} , m_sc(0) @@ -172,7 +167,7 @@ void ns32082_device::state_add(device_state_interface &parent, int &index) parent.state_add(index++, "MSR", m_msr).formatstr("%08X"); } -u16 ns32082_device::read_st(int *icount) +u16 ns32082_device::slow_status(int *icount) { if (m_state == STATUS) { @@ -181,63 +176,54 @@ u16 ns32082_device::read_st(int *icount) if (icount) *icount -= m_tcy; - LOG("read_st status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy, + LOG("status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy, (m_state == RESULT ? "results pending" : "complete"), machine().describe_context()); return m_status; } - logerror("read_st protocol error reading status word (%s)\n", machine().describe_context()); + logerror("status protocol error (%s)\n", machine().describe_context()); return 0; } -u16 ns32082_device::read_op() +u16 ns32082_device::slow_read() { if (m_state == RESULT && m_op[2].issued < m_op[2].expected) { u16 const data = u16(m_op[2].value >> (m_op[2].issued * 8)); - LOG("read_op word %d data 0x%04x (%s)\n", m_op[2].issued >> 1, data, machine().describe_context()); + LOG("read %d data 0x%04x (%s)\n", m_op[2].issued >> 1, data, machine().describe_context()); m_op[2].issued += 2; if (m_op[2].issued == m_op[2].expected) { - LOG("read_op last result word issued\n"); + LOG("read complete\n"); m_state = IDLE; } return data; } - logerror("read_op protocol error reading result word (%s)\n", machine().describe_context()); + logerror("read protocol error (%s)\n", machine().describe_context()); return 0; } -void ns32082_device::write_id(u16 data) -{ - bool const match = (data == FORMAT_14); - - if (match) - { - LOG("write_id match 0x%04x (%s)\n", data, machine().describe_context()); - m_state = OPERATION; - } - else - { - LOG("write_id ignore 0x%04x (%s)\n", data, machine().describe_context()); - m_state = IDLE; - } - - m_idbyte = u8(data); -} - -void ns32082_device::write_op(u16 data) +void ns32082_device::slow_write(u16 data) { switch (m_state) { + case IDLE: + LOG("write idbyte 0x%04x (%s)\n", data, machine().describe_context()); + if (data == FORMAT_14) + { + m_idbyte = u8(data); + m_state = OPERATION; + } + break; + case OPERATION: m_opword = swapendian_int16(data); - LOG("write_op opword 0x%04x (%s)\n", m_opword, machine().describe_context()); + LOG("write opword 0x%04x (%s)\n", m_opword, machine().describe_context()); m_tcy = 0; @@ -282,14 +268,16 @@ void ns32082_device::write_op(u16 data) unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1; operand &op = m_op[n]; - LOG("write_op op%d data 0x%04x (%s)\n", n, data, machine().describe_context()); + LOG("write operand %d data 0x%04x (%s)\n", + n, data, machine().describe_context()); // insert word into operand value op.value |= u64(data) << (op.issued * 8); op.issued += 2; } else - logerror("write_op protocol error unexpected operand word 0x%04x (%s)\n", data, machine().describe_context()); + logerror("write protocol error unexpected operand data 0x%04x (%s)\n", + data, machine().describe_context()); break; } diff --git a/src/devices/machine/ns32082.h b/src/devices/machine/ns32082.h index 41986941bb2..b8232e25116 100644 --- a/src/devices/machine/ns32082.h +++ b/src/devices/machine/ns32082.h @@ -10,24 +10,25 @@ class ns32082_device : public device_t - , public ns32000_slow_slave_interface , public ns32000_mmu_interface + , public ns32000_slow_slave_interface { public: ns32082_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + // ns32000_slave_interface implementation virtual void state_add(device_state_interface &parent, int &index) override; - virtual u16 read_st(int *icount = nullptr) override; - virtual u16 read_op() override; - - virtual void write_id(u16 data) override; - virtual void write_op(u16 data) override; + // ns32000_slow_slave_interface implementation + virtual u16 slow_status(int *icount = nullptr) override; + virtual u16 slow_read() override; + virtual void slow_write(u16 data) override; + // ns32000_mmu_interface implementation virtual translate_result translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool pfs = false, bool suppress = false) override; protected: - // device_t overrides + // device_t implementation virtual void device_start() override; virtual void device_reset() override; @@ -51,16 +52,16 @@ private: u16 m_opword; struct operand { - unsigned expected; - unsigned issued; + u32 expected; + u32 issued; u64 value; } m_op[3]; u16 m_status; // implementation state - unsigned m_state; - unsigned m_tcy; + u32 m_state; + u32 m_tcy; }; DECLARE_DEVICE_TYPE(NS32082, ns32082_device) diff --git a/src/devices/machine/ns32382.cpp b/src/devices/machine/ns32382.cpp index 18250bb80dd..105bc55b1a2 100644 --- a/src/devices/machine/ns32382.cpp +++ b/src/devices/machine/ns32382.cpp @@ -2,7 +2,7 @@ // copyright-holders:Patrick Mackinlay /* - * National Semiconductor 32382 Memory Management Unit. + * National Semiconductor NS32382 Memory Management Unit. * * Sources: * - Microprocessor Databook, Series 32000, NSC800, 1989 Edition, National Semiconductor @@ -23,7 +23,7 @@ #include "logmacro.h" -DEFINE_DEVICE_TYPE(NS32382, ns32382_device, "ns32382", "National Semiconductor 32382 Memory Management Unit") +DEFINE_DEVICE_TYPE(NS32382, ns32382_device, "ns32382", "National Semiconductor NS32382 Memory Management Unit") enum state : unsigned { @@ -35,11 +35,6 @@ enum state : unsigned RESULT = 6, // result word available }; -enum idbyte : u8 -{ - FORMAT_14 = 0x1e, -}; - enum reg_mask : unsigned { BAR = 0x0, // breakpoint address register @@ -125,8 +120,8 @@ enum va_mask : u32 ns32382_device::ns32382_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : device_t(mconfig, NS32382, tag, owner, clock) - , ns32000_fast_slave_interface(mconfig, *this) , ns32000_mmu_interface(mconfig, *this) + , ns32000_fast_slave_interface(mconfig, *this) { } @@ -165,7 +160,7 @@ void ns32382_device::state_add(device_state_interface &parent, int &index) parent.state_add(index++, "MSR", m_msr).formatstr("%08X"); } -u32 ns32382_device::read_st32(int *icount) +u32 ns32382_device::fast_status(int *icount) { if (m_state == STATUS) { @@ -174,48 +169,49 @@ u32 ns32382_device::read_st32(int *icount) if (icount) *icount -= m_tcy; - LOG("read_st status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy, + LOG("status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy, (m_state == RESULT ? "results pending" : "complete"), machine().describe_context()); return m_status; } - logerror("read_st protocol error reading status (%s)\n", machine().describe_context()); + logerror("status protocol error (%s)\n", machine().describe_context()); return 0; } -u32 ns32382_device::read() +u32 ns32382_device::fast_read() { if (m_state == RESULT && m_op[2].issued < m_op[2].expected) { u32 const data = u32(m_op[2].value >> (m_op[2].issued * 8)); - LOG("read_op dword %d data 0x%08x (%s)\n", m_op[2].issued >> 2, data, machine().describe_context()); + LOG("read %d data 0x%08x (%s)\n", m_op[2].issued >> 2, data, machine().describe_context()); m_op[2].issued += 4; if (m_op[2].issued == m_op[2].expected) { - LOG("read_op last result dword issued\n"); + LOG("read complete\n"); m_state = IDLE; } return data; } - logerror("read_op protocol error reading result dword (%s)\n", machine().describe_context()); + logerror("read protocol error (%s)\n", machine().describe_context()); return 0; } -void ns32382_device::write(u32 data) +void ns32382_device::fast_write(u32 data) { switch (m_state) { case IDLE: if (BIT(data, 24, 8) == FORMAT_14) { - LOG("write_fast match 0x%08x (%s)\n", data, machine().describe_context()); - m_opword = swapendian_int16(data >> 8); + + LOG("write idbyte 0x%02x opword 0x%04x (%s)\n", FORMAT_14, m_opword, machine().describe_context()); + m_tcy = 0; // initialize operands @@ -254,14 +250,15 @@ void ns32382_device::write(u32 data) unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1; operand &op = m_op[n]; - LOG("write_op op%d data 0x%04x (%s)\n", n, data, machine().describe_context()); + LOG("write opword 0x%08x (%s)\n", data, machine().describe_context()); // insert dword into operand value op.value |= u64(data) << (op.issued * 8); op.issued += 4; } else - logerror("write_fast protocol error unexpected operand 0x%08x (%s)\n", data, machine().describe_context()); + logerror("write protocol error unexpected operand data 0x%08x (%s)\n", + data, machine().describe_context()); break; } @@ -274,7 +271,7 @@ void ns32382_device::execute() { m_status = 0; - // format 14: xxxx xsss s0oo ooii 0001 1110 + // format 14: xxxx xsss s0oo ooii unsigned const quick = BIT(m_opword, 7, 4); switch (BIT(m_opword, 2, 4)) diff --git a/src/devices/machine/ns32382.h b/src/devices/machine/ns32382.h index eea3a0ef7d4..a60c6d27f5f 100644 --- a/src/devices/machine/ns32382.h +++ b/src/devices/machine/ns32382.h @@ -10,25 +10,25 @@ class ns32382_device : public device_t - , public ns32000_fast_slave_interface , public ns32000_mmu_interface + , public ns32000_fast_slave_interface { public: ns32382_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); - // ns32000_slave_interface overrides + // ns32000_slave_interface implementation virtual void state_add(device_state_interface &parent, int &index) override; - // ns32000_fast_slave_interface overrides - virtual u32 read_st32(int *icount = nullptr) override; - virtual void write(u32 data) override; - virtual u32 read() override; + // ns32000_fast_slave_interface implementation + virtual u32 fast_status(int *icount = nullptr) override; + virtual u32 fast_read() override; + virtual void fast_write(u32 data) override; - // ns32000_mmu_interface overrides + // ns32000_mmu_interface implementation virtual translate_result translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool pfs = false, bool debug = false) override; protected: - // device_t overrides + // device_t implementation virtual void device_start() override; virtual void device_reset() override; diff --git a/src/mame/homebrew/pc532.cpp b/src/mame/homebrew/pc532.cpp index b168505b8f3..d05b9f317e2 100644 --- a/src/mame/homebrew/pc532.cpp +++ b/src/mame/homebrew/pc532.cpp @@ -10,7 +10,6 @@ * - https://www.nic.funet.fi/pub/misc/pc532/ * * TODO: - * - ns32381 * - et532 * * WIP: @@ -47,7 +46,7 @@ public: pc532_state(machine_config const &mconfig, device_type type, char const *tag) : driver_device(mconfig, type, tag) , m_cpu(*this, "cpu") - //, m_fpu(*this, "fpu") + , m_fpu(*this, "fpu") , m_icu(*this, "icu") , m_rtc(*this, "rtc") , m_ncr5380(*this, "slot:7:ncr5380") @@ -61,7 +60,6 @@ public: { } - void init(); void pc532(machine_config &config); protected: @@ -71,7 +69,7 @@ protected: template void cpu_map(address_map &map); required_device m_cpu; - //required_device m_fpu; + required_device m_fpu; required_device m_icu; required_device m_rtc; @@ -113,12 +111,6 @@ private: m_state; }; -void pc532_state::init() -{ - // HACK: disable unemulated FPU - m_eprom[0x7c00 >> 2] &= ~0x02; -} - void pc532_state::machine_start() { // install phantom rtc using memory taps @@ -312,8 +304,8 @@ void pc532_state::pc532(machine_config &config) // ODT required because system software uses explicit MOV instead of RETI instructions m_cpu->set_addrmap(ns32000::ST_ODT, &pc532_state::cpu_map); - //NS32381(config, m_fpu, 50_MHz_XTAL / 2); - //m_cpu->set_fpu(m_fpu); + NS32381(config, m_fpu, 50_MHz_XTAL / 2); + m_cpu->set_fpu(m_fpu); NS32202(config, m_icu, 3.6864_MHz_XTAL); m_icu->out_int().set_inputline(m_cpu, INPUT_LINE_IRQ0).invert(); @@ -327,7 +319,7 @@ void pc532_state::pc532(machine_config &config) NSCSI_CONNECTOR(config, "slot:1", scsi_devices, nullptr, false); NSCSI_CONNECTOR(config, "slot:2", scsi_devices, nullptr, false); NSCSI_CONNECTOR(config, "slot:3", scsi_devices, nullptr, false); - NSCSI_CONNECTOR(config, "slot:7").option_set("ncr5380", NCR5380).machine_config( + NSCSI_CONNECTOR(config, "slot:7").option_set("ncr5380", NCR5380).machine_config( // DP8490 [this](device_t *device) { ncr5380_device &ncr5380(downcast(*device)); @@ -412,5 +404,5 @@ ROM_END } // anonymous namespace -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP(1989, pc532, 0, 0, pc532, 0, pc532_state, init, "George Scolaro", "pc532", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW) +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP(1989, pc532, 0, 0, pc532, 0, pc532_state, empty_init, "George Scolaro", "pc532", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW) -- cgit v1.2.3