diff options
Diffstat (limited to 'src/mame/machine/imm6_76.cpp')
-rw-r--r-- | src/mame/machine/imm6_76.cpp | 204 |
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"); + } + } +} |