summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/imm6_76.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/imm6_76.cpp')
-rw-r--r--src/mame/machine/imm6_76.cpp204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/mame/machine/imm6_76.cpp b/src/mame/machine/imm6_76.cpp
new file mode 100644
index 00000000000..b30a1c5e9da
--- /dev/null
+++ b/src/mame/machine/imm6_76.cpp
@@ -0,0 +1,204 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+#include "emu.h"
+#include "imm6_76.h"
+
+#include <algorithm>
+
+
+DEFINE_DEVICE_TYPE(INTEL_IMM6_76, intel_imm6_76_device, "imm6_76", "Intel imm6-76 PROM programmer")
+
+
+intel_imm6_76_device::intel_imm6_76_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock)
+ : device_t(mconfig, INTEL_IMM6_76, tag, owner, clock)
+ , device_image_interface(mconfig, *this)
+ , m_cycle_tmr(nullptr), m_cycle_a_tmr(nullptr), m_prg_tmr(nullptr)
+ , m_di(0U), m_a(0U)
+ , m_do_enable(true), m_di_pos(true), m_do_pos(true)
+ , m_r_w(false), m_r_w_a(false)
+ , m_prgm_pwr(false)
+ , m_cycle(false), m_cycle_a(false), m_prg(false)
+{
+ std::fill(std::begin(m_data), std::end(m_data), 0U);
+}
+
+
+void intel_imm6_76_device::device_start()
+{
+ m_cycle_tmr = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(intel_imm6_76_device::cycle_expired), this));
+ m_cycle_a_tmr = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(intel_imm6_76_device::cycle_a_expired), this));
+ m_prg_tmr = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(intel_imm6_76_device::prg_expired), this));
+
+ save_item(NAME(m_data));
+ save_item(NAME(m_di));
+ save_item(NAME(m_a));
+ save_item(NAME(m_do_enable));
+ save_item(NAME(m_di_pos));
+ save_item(NAME(m_do_pos));
+ save_item(NAME(m_r_w));
+ save_item(NAME(m_r_w_a));
+ save_item(NAME(m_prgm_pwr));
+ save_item(NAME(m_cycle));
+ save_item(NAME(m_cycle_a));
+ save_item(NAME(m_prg));
+}
+
+
+image_init_result intel_imm6_76_device::call_load()
+{
+ if (length() != ARRAY_LENGTH(m_data))
+ return image_init_result::FAIL;
+ else if (fread(m_data, ARRAY_LENGTH(m_data)) != ARRAY_LENGTH(m_data))
+ return image_init_result::FAIL;
+ else
+ return image_init_result::PASS;
+}
+
+image_init_result intel_imm6_76_device::call_create(int format_type, util::option_resolution *format_options)
+{
+ std::fill(std::begin(m_data), std::end(m_data), 0U);
+ if (fwrite(m_data, ARRAY_LENGTH(m_data)) != ARRAY_LENGTH(m_data))
+ return image_init_result::FAIL;
+ else
+ return image_init_result::PASS;
+}
+
+void intel_imm6_76_device::call_unload()
+{
+ if (!is_readonly())
+ {
+ fseek(0, SEEK_SET);
+ fwrite(m_data, ARRAY_LENGTH(m_data));
+ }
+ std::fill(std::begin(m_data), std::end(m_data), 0U);
+}
+
+
+void intel_imm6_76_device::di_w(u8 data)
+{
+ if (data != m_di)
+ {
+ if (m_prg)
+ logerror("data inputs changed during write - PROM damage likely (%02X -> %02X)\n", m_di, data);
+ m_di = data;
+ }
+}
+
+void intel_imm6_76_device::a_w(u8 data)
+{
+ if (data != m_a)
+ {
+ if (m_prg)
+ logerror("address changed during write - PROM damage likely (%02X -> %02X)\n", m_a, data);
+ m_a = data;
+ }
+}
+
+u8 intel_imm6_76_device::do_r() const
+{
+ if (!m_do_enable)
+ {
+ return 0xffU;
+ }
+ else
+ {
+ u8 const data(!m_prg ? m_data[m_a] : m_di_pos ? ~m_di : m_di);
+ return m_do_pos ? ~data : data;
+ }
+}
+
+DECLARE_WRITE_LINE_MEMBER(intel_imm6_76_device::data_out_enable)
+{
+ m_do_enable = bool(state);
+}
+
+DECLARE_WRITE_LINE_MEMBER(intel_imm6_76_device::data_in_positive)
+{
+ if (bool(state) != m_di_pos)
+ {
+ if (m_prg)
+ logerror("input polarity changed during write - PROM damage likely (%c -> %c)\n", m_di_pos ? '+' : '-', bool(state) ? '+' : '-');
+ m_di_pos = bool(state);
+ }
+}
+
+DECLARE_WRITE_LINE_MEMBER(intel_imm6_76_device::data_out_positive)
+{
+ m_do_pos = !bool(state);
+}
+
+WRITE_LINE_MEMBER(intel_imm6_76_device::r_w)
+{
+ if (!m_r_w && !bool(state) && !m_cycle)
+ {
+ // half 9602 with Rx = 20kΩ, Cx = 22µF, 1N914 across capacitor
+ // wired to prevent re-triggering
+ m_cycle_tmr->adjust(attotime::from_msec(150));
+ trigger_prg();
+ m_cycle = true;
+ }
+ m_r_w = !bool(state);
+}
+
+WRITE_LINE_MEMBER(intel_imm6_76_device::r_w_a)
+{
+ if (!m_r_w_a && !bool(state) && !m_cycle_a)
+ {
+ // half 9602 with Rx = 20kΩ, Cx = 2.2µF, 1N914 across capacitor
+ // wired to prevent re-triggering
+ m_cycle_a_tmr->adjust(attotime::from_msec(15));
+ trigger_prg();
+ m_cycle_a = true;
+ }
+ m_r_w_a = !bool(state);
+}
+
+WRITE_LINE_MEMBER(intel_imm6_76_device::prgm_prom_pwr)
+{
+ if (!bool(state) != m_prgm_pwr)
+ {
+ if (m_prg)
+ logerror("programming power %s during write - PROM damage likely\n", bool(state) ? "disabled" : "enabled");
+ m_prgm_pwr = !bool(state);
+ }
+}
+
+
+TIMER_CALLBACK_MEMBER(intel_imm6_76_device::cycle_expired)
+{
+ m_cycle = false;
+}
+
+TIMER_CALLBACK_MEMBER(intel_imm6_76_device::cycle_a_expired)
+{
+ m_cycle_a = false;
+}
+
+TIMER_CALLBACK_MEMBER(intel_imm6_76_device::prg_expired)
+{
+ m_prg = false;
+}
+
+
+void intel_imm6_76_device::trigger_prg()
+{
+ if (!m_cycle && !m_cycle_a)
+ {
+ // half 9602 with Rx = 4.7kΩ + 20kΩ trimpot, Cx = 1.0µF
+ m_prg_tmr->adjust(attotime::from_usec(3250));
+ if (!m_prg)
+ {
+ if (m_prgm_pwr && is_loaded())
+ m_data[m_a] |= m_di_pos ? ~m_di : m_di; // PROM can't be erased electronically
+ m_prg = true;
+ }
+ else
+ {
+ logerror("write re-triggered - PROM damage likely\n");
+ }
+ }
+}