diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 39435e18798..82d77e9ab18 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -4082,3 +4082,15 @@ if (MACHINES["EDLC"]~=null) then MAME_DIR .. "src/devices/machine/edlc.h", } end + +--------------------------------------------------- +-- +--@src/devices/machine/wtl3132.h,MACHINES["WTL3132"] = true +--------------------------------------------------- + +if (MACHINES["WTL3132"]~=null) then + files { + MAME_DIR .. "src/devices/machine/wtl3132.cpp", + MAME_DIR .. "src/devices/machine/wtl3132.h", + } +end diff --git a/src/devices/machine/wtl3132.cpp b/src/devices/machine/wtl3132.cpp new file mode 100644 index 00000000000..0be0cac8edd --- /dev/null +++ b/src/devices/machine/wtl3132.cpp @@ -0,0 +1,521 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * An emulation of the Weitek 3132 floating point data path. + * + * Sources: + * - http://www.bitsavers.org/components/weitek/dataSheets/WTL-3132_3332_XL-3132_32-Bit_Floating_Point_Data_Path_Oct88.pdf + * + * TODO: + * - reciprocal via lookup table + * - fully analyze reversed C bus case + * - testing/logging undefined cases + */ + +#include "emu.h" +#include "wtl3132.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_REGS (1U << 1) +#define LOG_IO (1U << 2) +#define LOG_BYPASS (1U << 3) + +#define VERBOSE (LOG_GENERAL|LOG_REGS|LOG_IO|LOG_BYPASS) +#include "logmacro.h" + +ALLOW_SAVE_TYPE(float32_t); + +// helper for extracting opcode fields +#define OPF(c, x) ((c & M_##x) >> S_##x) + +DEFINE_DEVICE_TYPE(WTL3132, wtl3132_device, "wtl3132", "Weitek 3132") + +wtl3132_device::wtl3132_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, WTL3132, tag, owner, clock) + , m_fpcn_cb(*this) + , m_fpex_cb(*this) + , m_zero_cb(*this) +{ +} + +void wtl3132_device::device_start() +{ + m_fpcn_cb.resolve_safe(); + m_fpex_cb.resolve_safe(); + m_zero_cb.resolve_safe(); + + save_item(NAME(m_fpcn_state)); + save_item(NAME(m_fpex_state)); + save_item(NAME(m_zero_state)); + + save_item(NAME(m_c_port)); + save_item(NAME(m_x_port)); + save_item(NAME(m_x_in)); + save_item(NAME(m_x_out)); + + save_item(NAME(m_slot)); + save_item(NAME(m_head)); + + save_item(NAME(m_mode)); + save_item(NAME(m_f)); + save_item(NAME(m_t1)); + save_item(NAME(m_t2)); + save_item(NAME(m_t3)); + save_item(NAME(m_cr)); + save_item(NAME(m_sr)); + save_item(NAME(m_zr)); + + save_item(NAME(m_c_bus_data)); + save_item(NAME(m_c_bus_addr)); + save_item(NAME(m_c_bus_cwen)); + + save_item(NAME(m_ma_in)); + save_item(NAME(m_mb_in)); + save_item(NAME(m_m_out)); + + save_item(NAME(m_aa_in)); + save_item(NAME(m_ab_in)); + save_item(NAME(m_a_out)); +} + +void wtl3132_device::device_reset() +{ + m_abort = 1; + m_neut = 1; + m_stall = 1; + + m_fpcn_state = 1; + m_fpex_state = 1; + m_zero_state = 1; + + // initialize pipeline with fnop to minimize logging noise + for (u64 &slot : m_slot) + slot = (F_FSUB << S_F) | M_CWEN | M_ABIN | M_ADST; + m_head = 0; + + m_mode = 0; +} + +void wtl3132_device::clk_w(int state) +{ + // ignore falling edges for now + if (!state) + return; + + // precompute pipeline slot indixes + unsigned const index0 = (m_head + 4) & 3; + unsigned const index1 = (m_head + 3) & 3; + unsigned const index2 = (m_head + 2) & 3; + unsigned const index3 = (m_head + 1) & 3; + + LOG("code 0x%09x slot %d %s\n", m_c_port, index0, disassemble(m_c_port)); + + // store the next instruction in the pipeline + m_slot[index0] = m_c_port; + + // STALL- and ABORT- prevent all processing of the next instruction + if (!m_stall || !m_abort) + { + LOG("slot %d stage instruction %s\n", index0, !m_stall ? "stalled" : "aborted"); + m_slot[index0] |= M_CANCEL; + } + + // retire pipeline stages in fifo order simplifying dependency forwarding + if (!(m_slot[index3] & M_CANCEL)) + stage4(index3); + + if (!(m_slot[index2] & M_CANCEL)) + stage3(index2); + + if (!(m_slot[index1] & M_CANCEL)) + stage2(index1); + + if (!(m_slot[index0] & M_CANCEL)) + stage1(index0); + + // write to the register file after the first pipeline stage has completed + // to ensure the effective 4 cycle delay for non-bypassed register access + if (!m_c_bus_cwen && !(m_slot[index3] & M_CANCEL)) + { + m_f[m_c_bus_addr] = m_c_bus_data; + LOGMASKED(LOG_REGS, "slot %d stage 4 f%d = %f\n", index3, m_c_bus_addr, u2f(m_c_bus_data.v)); + } + + // NEUT- and ABORT- prevent writeback of the previous instruction, but + // allow i/o to complete normally + if (!m_neut || !m_abort) + { + LOG("slot %d stage instruction %s\n", index1, !m_neut ? "neutralized" : "aborted"); + m_slot[index1] |= M_CANCEL; + } + + m_head = index3; +} + +void wtl3132_device::stage1(unsigned const index) +{ + u64 const code = m_slot[index]; + + // A and B buses are loaded from registers by default + float32_t a_bus = m_f[OPF(code, AADD)]; + float32_t b_bus = m_f[OPF(code, BADD)]; + + // C-to-A bus internal bypass + if (((m_mode & MODE_IBA) && !m_c_bus_cwen && OPF(code, AADD) == m_c_bus_addr)) + { + a_bus = m_c_bus_data; + LOGMASKED(LOG_BYPASS, "slot %d stage 1 C-to-A internal bypass %f\n", index, u2f(m_c_bus_data.v)); + } + + // C-to-B bus internal bypass + if (((m_mode & MODE_IBB) && !m_c_bus_cwen && OPF(code, BADD) == m_c_bus_addr)) + { + b_bus = m_c_bus_data; + LOGMASKED(LOG_BYPASS, "slot %d stage 1 C-to-B internal bypass %f\n", index, u2f(m_c_bus_data.v)); + } + + // perform i/o + switch (OPF(code, IOCT)) + { + case 1: // floadrc + m_f[OPF(code, DADD)] = m_x_port; + // FIXME: floadrc uses c bus, preventing result writeback except for flut + m_x_in = m_x_port; + LOGMASKED(LOG_IO, "slot %d stage 1 floadrc f%d = %f\n", index, OPF(code, DADD), u2f(m_x_port.v)); + break; + case 2: // fstore + // C-to-X output bypass + if ((m_mode & MODE_OBP) && !m_c_bus_cwen && OPF(code, DADD) == m_c_bus_addr) + { + m_x_out = m_c_bus_data; + LOGMASKED(LOG_BYPASS, "slot %d stage 1 C-to-X output bypass %f\n", index, u2f(m_c_bus_data.v)); + } + else + m_x_out = m_f[OPF(code, DADD)]; + break; + case 3: // fload + m_f[OPF(code, DADD)] = m_x_port; + LOGMASKED(LOG_IO, "slot %d stage 1 fload f%d = %f\n", index, OPF(code, DADD), u2f(m_x_port.v)); + + // X-to-A bus input bypass + if ((m_mode & MODE_IBP) && OPF(code, AADD) == OPF(code, DADD)) + { + a_bus = m_x_port; + LOGMASKED(LOG_BYPASS, "slot %d stage 1 X-to-A input bypass %f\n", index, u2f(m_x_port.v)); + } + break; + } + + // perform status and mode register operations + switch (OPF(code, F)) + { + case F_MISC: + switch (OPF(code, BADD)) + { + case MF_FCLSR: + m_sr = false; + break; + case MF_FSTSR: + m_x_port.v = m_sr; + break; + + case MF_FMODE: + { + // check polarity inversion + bool const polarity = bool(m_mode & MODE_FXH) ^ bool((OPF(code, CADD) << 5) & MODE_FXH); + + // update mode + m_mode = (OPF(code, ABIN) << 10) | (OPF(code, CADD) << 5) | OPF(code, AADD); + if (!(m_mode & MODE_FXO)) + m_sr = false; + + // force line update + if (polarity) + m_fpex_state = !m_sr; + } + break; + } + } + + // select and load multiplier inputs + m_ma_in = a_bus; + m_mb_in = OPF(code, MBIN) ? m_x_in : b_bus; + + // buffer accumulator inputs + m_aa_in[0] = a_bus; + m_ab_in[0] = b_bus; +} + +void wtl3132_device::stage2(unsigned const index) +{ + u64 const code = m_slot[index]; + + // load AAin from multiplier output or buffered A bus + m_aa_in[1] = (OPF(code, F) & 4) ? m_m_out : m_aa_in[0]; + + // load ABin from source specified by ABIN opcode field + switch (OPF(code, ABIN)) + { + case 0: m_ab_in[1] = m_x_in; break; + case 1: m_ab_in[1] = m_ab_in[0]; break; + case 2: m_ab_in[1] = m_t2; break; + case 3: m_ab_in[1] = m_t1; break; + case 4: m_ab_in[1] = m_t3; break; + + case 6: m_ab_in[1] = i32_to_f32(2); break; + case 7: m_ab_in[1] = i32_to_f32(0); break; + } + + // execute multiply and optional negate + switch (OPF(code, F)) + { + case F_FMNA: + case F_FMNS: + // multiply and negate + m_m_out = f32_mul(f32_mul(m_ma_in, m_mb_in), i32_to_f32(-1)); + LOG("slot %d stage 2 -(%f * %f) == %f\n", index, u2f(m_ma_in.v), u2f(m_mb_in.v), u2f(m_m_out.v)); + break; + case F_FMAC: + // multiply + m_m_out = f32_mul(m_ma_in, m_mb_in); + LOG("slot %d stage 2 %f * %f == %f\n", index, u2f(m_ma_in.v), u2f(m_mb_in.v), u2f(m_m_out.v)); + break; + } + + // complete fstore + if (OPF(code, IOCT) == 2) + { + m_x_port = m_x_out; + LOGMASKED(LOG_IO, "slot %d stage 2 fstore %f\n", index, u2f(m_x_out.v)); + } +} + +void wtl3132_device::stage3(unsigned const index) +{ + u64 const code = m_slot[index]; + + softfloat_exceptionFlags = 0; + + // execute accumulator operation + switch (OPF(code, F)) + { + case F_MISC: + switch (OPF(code, BADD)) + { + case MF_FABS: + if (f32_lt(m_aa_in[1], i32_to_f32(0))) + m_a_out = f32_mul(m_aa_in[1], i32_to_f32(-1)); + else + m_a_out = m_aa_in[1]; + + if (m_mode & MODE_RTN) + m_cr = f32_eq(m_a_out, i32_to_f32(0)); + LOG("slot %d stage 3 fabs %f == %f\n", index, u2f(m_aa_in[1].v), u2f(m_a_out.v)); + break; + case MF_FLOAT: + if ((m_mode & MODE_RTN) && OPF(code, ENCN) == 1) + m_cr = (m_aa_in[1].v & 0xff000000) && (~m_aa_in[1].v & 0xff000000); + + m_a_out = i32_to_f32(m_aa_in[1].v); + LOG("slot %d stage 3 float 0x%08x == %f\n", index, m_aa_in[1].v, u2f(m_a_out.v)); + break; + case MF_FIX: + if ((m_mode & MODE_RTN) && OPF(code, ENCN) == 1) + m_cr = f32_lt(m_aa_in[1], i32_to_f32(-4194304)) || f32_lt(i32_to_f32(4194304), m_aa_in[1]); + + m_a_out.v = (f32_to_i32(m_aa_in[1], (m_mode & MODE_RTN) ? + softfloat_round_near_even : softfloat_round_min, false) << 8) >> 8; + LOG("slot %d stage 3 fix %f == 0x%08x\n", index, u2f(m_aa_in[1].v), m_a_out.v); + break; + case MF_FLUT: + // TODO: replace with lookup table + m_a_out = f32_div(i32_to_f32(1), m_aa_in[1]); + LOG("slot %d stage 3 flut %f == %f\n", index, u2f(m_aa_in[1].v), u2f(m_a_out.v)); + break; + } + break; + case F_FSUBR: + m_a_out = f32_sub(m_ab_in[1], m_aa_in[1]); + LOG("slot %d stage 3 fsubr %f - %f == %f\n", index, u2f(m_ab_in[1].v), u2f(m_aa_in[1].v), u2f(m_a_out.v)); + break; + case F_FSUB: + m_a_out = f32_sub(m_aa_in[1], m_ab_in[1]); + LOG("slot %d stage 3 fsub %f - %f == %f\n", index, u2f(m_aa_in[1].v), u2f(m_ab_in[1].v), u2f(m_a_out.v)); + break; + case F_FADD: + m_a_out = f32_add(m_aa_in[1], m_ab_in[1]); + LOG("slot %d stage 3 fadd %f + %f == %f\n", index, u2f(m_aa_in[1].v), u2f(m_ab_in[1].v), u2f(m_a_out.v)); + break; + + case F_FMNA: + m_a_out = f32_add(m_m_out, m_ab_in[1]); + LOG("slot %d stage 3 fmna %f + %f == %f\n", index, u2f(m_m_out.v), u2f(m_ab_in[1].v), u2f(m_a_out.v)); + break; + case F_FMNS: + m_a_out = f32_sub(m_m_out, m_ab_in[1]); + LOG("slot %d stage 3 fmns %f - %f == %f\n", index, u2f(m_m_out.v), u2f(m_ab_in[1].v), u2f(m_a_out.v)); + break; + case F_FMAC: + m_a_out = f32_add(m_m_out, m_ab_in[1]); + LOG("slot %d stage 3 fmac %f + %f == %f\n", index, u2f(m_m_out.v), u2f(m_ab_in[1].v), u2f(m_a_out.v)); + break; + } + + // update condition, zero and status registers + if (OPF(code, F)) + { + switch (OPF(code, ENCN)) + { + case 1: + m_cr = f32_le(m_a_out, i32_to_f32(0)); + m_zr = f32_eq(m_a_out, i32_to_f32(0)); + break; + case 2: + m_cr = f32_lt(m_a_out, i32_to_f32(0)); + m_zr = f32_eq(m_a_out, i32_to_f32(0)); + break; + case 3: + m_cr = f32_eq(m_a_out, i32_to_f32(0)); + m_zr = f32_eq(m_a_out, i32_to_f32(0)); + break; + } + + if ((m_mode & MODE_FXH) || !m_sr) + m_sr = softfloat_exceptionFlags & softfloat_flag_overflow; + } +} + +void wtl3132_device::stage4(unsigned const index) +{ + u64 const code = m_slot[index]; + + // update C bus + m_c_bus_data = m_a_out; + m_c_bus_addr = OPF(code, CADD); + m_c_bus_cwen = OPF(code, CWEN); + + // update temporary registers + switch (OPF(code, ADST)) + { + case 0: m_t3 = m_a_out; LOGMASKED(LOG_REGS, "slot %d stage 4 t3 = %f\n", index, u2f(m_t3.v)); break; + case 1: m_t2 = m_a_out; LOGMASKED(LOG_REGS, "slot %d stage 4 t2 = %f\n", index, u2f(m_t2.v)); break; + case 2: m_t1 = m_a_out; LOGMASKED(LOG_REGS, "slot %d stage 4 t1 = %f\n", index, u2f(m_t1.v)); break; + } + + // update output lines + if (m_cr ^ m_fpcn_state) + { + m_fpcn_state = m_cr; + m_fpcn_cb(m_fpcn_state); + } + + if (m_sr ^ m_fpex_state) + { + m_fpex_state = m_sr; + m_fpex_cb(!(m_fpex_state ^ bool(m_mode & MODE_FXH))); + } + + if (m_zr ^ m_zero_state) + { + m_zero_state = m_zr; + m_zero_cb(m_zero_state); + } +} + +std::string wtl3132_device::disassemble(u64 const code) +{ + std::string alu = ""; + + switch (OPF(code, F)) + { + case F_MISC: + switch (OPF(code, BADD)) + { + case MF_FCLSR: alu = std::string("fclsr"); break; + case MF_FSTSR: alu = std::string("fstsr"); break; + + case MF_FMODE: alu = util::string_format("fmode 0x%04x", (OPF(code, ABIN) << 10) | (OPF(code, CADD) << 5) | OPF(code, AADD)); break; + case MF_FABS: alu = util::string_format("fabs %4s, %-12s", reg(OPF(code, AADD)), adst(code)); break; + case MF_FLOAT: alu = util::string_format("float %4s, %-12s", reg(OPF(code, AADD)), adst(code)); break; + case MF_FIX: alu = util::string_format("fix %4s, %-12s", reg(OPF(code, AADD)), adst(code)); break; + case MF_FLUT: alu = util::string_format("flut %4s, %-4s", reg(OPF(code, AADD)), reg(OPF(code, CADD))); break; + + } + break; + case F_FSUBR: alu = util::string_format("fsubr %4s, %4s, %-12s", reg(OPF(code, AADD)), abin(code), adst(code)); break; + case F_FSUB: + if (!OPF(code, CWEN) || OPF(code, ADST) != 3 || OPF(code, ENCN)) + alu = util::string_format("fsub %4s, %4s, %-12s", reg(OPF(code, AADD)), abin(code), adst(code)); + else + alu = std::string("fnop"); + break; + case F_FADD: + if (!OPF(code, CWEN) || OPF(code, ADST) != 3 || OPF(code, ENCN) || OPF(code, ABIN) != 7) + alu = util::string_format("fadd %4s, %4s, %-12s", reg(OPF(code, AADD)), abin(code), adst(code)); + else + alu = std::string("fnop"); + break; + + case F_FMNA: alu = util::string_format("fmna %4s, %4s, %4s, %-12s", reg(OPF(code, AADD)), mbin(code), abin(code), adst(code)); break; + case F_FMNS: alu = util::string_format("fmns %4s, %4s, %4s, %-12s", reg(OPF(code, AADD)), mbin(code), abin(code), adst(code)); break; + case F_FMAC: alu = util::string_format("fmac %4s, %4s, %4s, %-12s", reg(OPF(code, AADD)), mbin(code), abin(code), adst(code)); break; + } + + switch (OPF(code, IOCT)) + { + case 1: return util::string_format("%-32s ; floadrc %4s", alu, reg(OPF(code, DADD))); break; + case 2: return util::string_format("%-32s ; fstore %4s", alu, reg(OPF(code, DADD))); break; + case 3: return util::string_format("%-32s ; fload %4s", alu, reg(OPF(code, DADD))); break; + default: + return alu; + } +} + +std::string wtl3132_device::reg(unsigned const reg) +{ + return util::string_format(".f%d", reg); +} + +std::string wtl3132_device::mbin(u64 const code) +{ + switch (OPF(code, MBIN)) + { + case 0: return util::string_format(".f%d", OPF(code, BADD)); + case 1: return util::string_format("Cbus"); + } + + // can't happen + return std::string(); +} + +std::string wtl3132_device::abin(u64 const code) +{ + switch (OPF(code, ABIN)) + { + case 0: return util::string_format("Cbus"); + case 1: return util::string_format(".f%d", OPF(code, BADD)); + case 2: return util::string_format(".t2"); + case 3: return util::string_format(".t1"); + case 4: return util::string_format(".t3"); + + case 6: return util::string_format("2"); + case 7: return util::string_format("0"); + } + + return std::string(); +} + +std::string wtl3132_device::adst(u64 const code) +{ + switch (OPF(code, ADST)) + { + case 0: return OPF(code, CWEN) ? util::string_format(".t3") : util::string_format(".f%d and .t3", OPF(code, CADD)); + case 1: return OPF(code, CWEN) ? util::string_format(".t2") : util::string_format(".f%d and .t2", OPF(code, CADD)); + case 2: return OPF(code, CWEN) ? util::string_format(".t1") : util::string_format(".f%d and .t1", OPF(code, CADD)); + case 3: return OPF(code, CWEN) ? std::string() : util::string_format(".f%d", OPF(code, CADD)); + } + + // can't happen + return std::string(); +} diff --git a/src/devices/machine/wtl3132.h b/src/devices/machine/wtl3132.h new file mode 100644 index 00000000000..23bf9e17744 --- /dev/null +++ b/src/devices/machine/wtl3132.h @@ -0,0 +1,171 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_MACHINE_WTL3132_H +#define MAME_MACHINE_WTL3132_H + +#pragma once + +#include "softfloat3/source/include/softfloat.h" + +class wtl3132_device : public device_t +{ +public: + wtl3132_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + // output lines + auto out_fpcn() { return m_fpcn_cb.bind(); } + auto out_fpex() { return m_fpex_cb.bind(); } + auto out_zero() { return m_zero_cb.bind(); } + + // code and data ports + void c_port_w(u64 data) { m_c_port = data; } + u32 x_port_r() { return m_x_port.v; } + void x_port_w(u32 data) { m_x_port.v = data; } + + // input lines + void abort_w(int state) { m_abort = state; } + void clk_w(int state); + void neut_w(int state) { m_neut = state; } + void stall_w(int state) { m_stall = state; } + + // disassembly helpers + static std::string disassemble(u64 const code); + static std::string reg(unsigned const reg); + static std::string mbin(u64 const code); + static std::string abin(u64 const code); + static std::string adst(u64 const code); + + enum code_mask : u64 + { + // opcode is 34 bits wide + M_ENCN = 0x0'00000003, // condition output select + M_MBIN = 0x0'00000004, // mbin input select + M_ADST = 0x0'00000018, // alu destination select + M_ABIN = 0x0'000000e0, // abin input select + M_DADD = 0x0'00001f00, // d port register address + M_IOCT = 0x0'00006000, // i/o control + M_CWEN = 0x0'00008000, // c port write enable (active low) + M_CADD = 0x0'001f0000, // c port register address + M_BADD = 0x0'03e00000, // b port register address + M_AADD = 0x0'7c000000, // a port register address + M_F = 0x3'80000000, // function code + + // internal pipeline control flag + M_CANCEL = 0x80000000'00000000, // cancelled + }; + + enum code_shift : unsigned + { + S_ENCN = 0, // condition output select + S_MBIN = 2, // mbin input select + S_ADST = 3, // alu destination select + S_ABIN = 5, // abin input select + S_DADD = 8, // d port register address + S_IOCT = 13, // i/o control + S_CWEN = 15, // c port write enable (active low) + S_CADD = 16, // c port register address + S_BADD = 21, // b port register address + S_AADD = 26, // a port register address + S_F = 31, // function code + }; + + enum function_code : unsigned + { + F_MISC = 0, // miscellaneous + F_FSUBR = 1, // negate and add + F_FSUB = 2, // subtract + F_FADD = 3, // add + F_FMNA = 5, // multiply, negate and add + F_FMNS = 6, // multiply, negate and subtract + F_FMAC = 7, // multiply and accumulate + }; + + enum misc_code : unsigned + { + MF_FCLSR = 0, // clear status register + MF_FSTSR = 1, // read status register + MF_FMODE = 3, // load mode register + MF_FABS = 4, // absolute value + MF_FLOAT = 5, // fixed-to-float + MF_FIX = 6, // float-to-fixed + MF_FLUT = 7, // lookup operation + }; + + enum mode_mask : u16 + { + MODE_IBA = 0x0001, // internal bypass A enable + MODE_RTN = 0x0002, // round to nearest + MODE_IBP = 0x0008, // input bypass enable + MODE_OBP = 0x0010, // output bypass enable + MODE_FXO = 0x0020, // fpex overflow enable + MODE_CPL = 0x0040, // coprocessor load enable + MODE_FXH = 0x0100, // fpex active high + MODE_DBP = 0x0200, // double pump enable (3332 only) + MODE_IBB = 0x0800, // internal bypass B enable + MODE_YLI = 0x1000, // Y late input enable (3332 only) + }; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + + void stage1(unsigned const index); + void stage2(unsigned const index); + void stage3(unsigned const index); + void stage4(unsigned const index); + +private: + devcb_write_line m_fpcn_cb; + devcb_write_line m_fpex_cb; + devcb_write_line m_zero_cb; + + // output line state + bool m_fpcn_state; + bool m_fpex_state; + bool m_zero_state; + + // port state + u64 m_c_port; + float32_t m_x_port; + float32_t m_x_in; + float32_t m_x_out; + + // input line state + int m_abort; + int m_neut; + int m_stall; + + // pipeline state + u64 m_slot[4]; + unsigned m_head; + + // registers + u16 m_mode; + float32_t m_f[32]; + float32_t m_t1; + float32_t m_t2; + float32_t m_t3; + bool m_cr; + bool m_sr; + bool m_zr; + + // C bus + float32_t m_c_bus_data; + unsigned m_c_bus_addr; + bool m_c_bus_cwen; + + // multiplier inputs and output + float32_t m_ma_in; + float32_t m_mb_in; + float32_t m_m_out; + + // accumulator buffers, inputs and output + float32_t m_aa_in[2]; + float32_t m_ab_in[2]; + float32_t m_a_out; +}; + +DECLARE_DEVICE_TYPE(WTL3132, wtl3132_device) + +#endif // MAME_MACHINE_WTL3132_H