summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2019-07-15 22:28:19 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2019-07-15 22:28:19 +0700
commit1f9fd834aff1b348f1ba099179ca15eb602e102c (patch)
treeab175c2642b989159e306dd70f938c5a2c19c6f9
parente2863920b5cd81b2fa8e51338382d02102c9e434 (diff)
wtl3132: new device
-rw-r--r--scripts/src/machine.lua12
-rw-r--r--src/devices/machine/wtl3132.cpp521
-rw-r--r--src/devices/machine/wtl3132.h171
3 files changed, 704 insertions, 0 deletions
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