// license:BSD-3-Clause
// copyright-holders:Curt Coder
/**********************************************************************
National Semiconductor ADC0808/ADC0809 8-Bit A/D Converter emulation
**********************************************************************/
#include "emu.h"
#include "adc0808.h"
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
// device type definition
const device_type ADC0808 = &device_creator<adc0808_device>;
//-------------------------------------------------
// adc0808_device - constructor
//-------------------------------------------------
adc0808_device::adc0808_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, ADC0808, "ADC0808", tag, owner, clock, "adc0808", __FILE__),
m_out_eoc_cb(*this),
m_address(0),
m_start(0),
m_eoc(0),
m_next_eoc(0), m_sar(0),
m_cycle(0),
m_bit(0), m_cycle_timer(nullptr)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void adc0808_device::device_start()
{
// resolve callbacks
m_out_eoc_cb.resolve_safe();
m_in_vref_pos_cb.bind_relative_to(*owner());
m_in_vref_neg_cb.bind_relative_to(*owner());
m_in_in_0_cb.bind_relative_to(*owner());
m_in_in_1_cb.bind_relative_to(*owner());
m_in_in_2_cb.bind_relative_to(*owner());
m_in_in_3_cb.bind_relative_to(*owner());
m_in_in_4_cb.bind_relative_to(*owner());
m_in_in_5_cb.bind_relative_to(*owner());
m_in_in_6_cb.bind_relative_to(*owner());
m_in_in_7_cb.bind_relative_to(*owner());
// allocate timers
m_cycle_timer = timer_alloc();
m_cycle_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
// register for state saving
save_item(NAME(m_address));
save_item(NAME(m_start));
save_item(NAME(m_eoc));
save_item(NAME(m_next_eoc));
save_item(NAME(m_sar));
save_item(NAME(m_cycle));
save_item(NAME(m_bit));
}
//-------------------------------------------------
// device_timer - handler timer events
//-------------------------------------------------
void adc0808_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
if (!m_start)
{
if (m_cycle == 7)
{
m_bit++;
if (m_bit == 8)
{
/* sample input */
double vref_pos = m_in_vref_pos_cb();
double vref_neg = m_in_vref_neg_cb();
double input = 0;
switch (m_address)
{
case 0:
input = m_in_in_0_cb();
break;
case 1:
input = m_in_in_1_cb();
break;
case 2:
input = m_in_in_2_cb();
break;
case 3:
input = m_in_in_3_cb();
break;
case 4:
input = m_in_in_4_cb();
break;
case 5:
input = m_in_in_5_cb();
break;
case 6:
input = m_in_in_6_cb();
break;
case 7:
input = m_in_in_7_cb();
break;
}
m_sar = (255 * (input - vref_neg)) / (vref_pos - vref_neg);
/* trigger end of conversion */
m_next_eoc = 1;
}
}
}
if (m_cycle == 0)
{
/* set end of conversion pin */
if (m_next_eoc != m_eoc)
{
m_out_eoc_cb(m_next_eoc);
m_eoc = m_next_eoc;
}
}
m_cycle++;
if (m_cycle == 8)
{
m_cycle = 0;
}
}
//-------------------------------------------------
// data_r - data read
//-------------------------------------------------
READ8_MEMBER( adc0808_device::data_r )
{
return m_sar;
}
//-------------------------------------------------
// ale_w - address write
//-------------------------------------------------
WRITE8_MEMBER( adc0808_device::ale_w )
{
m_address = data;
}
//-------------------------------------------------
// start_w - start conversion
//-------------------------------------------------
WRITE_LINE_MEMBER( adc0808_device::start_w )
{
if (!m_start && state) // rising edge
{
// reset registers
m_sar = 0;
m_bit = 0;
}
else if (m_start && !state) // falling edge
{
// start conversion
m_next_eoc = 0;
}
m_start = state;
}