summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/imm6_76.cpp
blob: b30a1c5e9dada0b2d4a864572187d264faf6c510 (plain) (tree)











































































































































































































                                                                                                                                                         
// 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");
		}
	}
}