summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/upd7004.cpp
blob: ceb54d09acb290a1f72b7a701676fda64d499432 (plain) (tree)
1
2
3
4
5
6
7
8







                                                                            


                          































































































































































                                                                                                                           
// license: BSD-3-Clause
// copyright-holders: Dirk Best
/***************************************************************************

    µPD7004

    10-bit 8 Channel A/D Converter

    TODO:
    - Serial modes
    - 2s complement output

***************************************************************************/

#include "emu.h"
#include "upd7004.h"

#define VERBOSE 0
#include "logmacro.h"


//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(UPD7004, upd7004_device, "upd7004", "UPD7004 A/D Converter")

// permit our enum to be saved
ALLOW_SAVE_TYPE(upd7004_device::state);


//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  upd7004_device - constructor
//-------------------------------------------------

upd7004_device::upd7004_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, UPD7004, tag, owner, clock),
	m_eoc_cb(*this), m_eoc_ff_cb(*this),
	m_in_cb{ {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this} },
	m_state(STATE_IDLE),
	m_cycle_timer(nullptr),
	m_div(1), m_code(false), m_address(0), m_sar(0x3ff)
{
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void upd7004_device::device_start()
{
	// resolve callbacks
	m_eoc_cb.resolve_safe();
	m_eoc_ff_cb.resolve_safe();

	for (int i = 0; i < 8; i++)
		m_in_cb[i].resolve_safe(0x3ff);

	// allocate timers
	m_cycle_timer = timer_alloc();
	m_cycle_timer->adjust(attotime::never);

	// register for save states
	save_item(NAME(m_state));
	save_item(NAME(m_div));
	save_item(NAME(m_code));
	save_item(NAME(m_address));
	save_item(NAME(m_sar));
}

//-------------------------------------------------
//  device_timer - handler timer events
//-------------------------------------------------

void upd7004_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	switch (m_state)
	{
		case STATE_IDLE:
			m_cycle_timer->adjust(attotime::never);
			break;

		case STATE_CONVERSION_START:
			m_sar = m_in_cb[m_address](0);

			// the conversion takes 96 to 104 cycles
			m_state = STATE_CONVERSION_DONE;
			m_cycle_timer->adjust(attotime::from_ticks(100, clock() / m_div));

			break;

		case STATE_CONVERSION_DONE:
		{
			// set eoc
			m_eoc_cb(1);
			m_eoc_ff_cb(1);

			m_state = STATE_IDLE;
			m_cycle_timer->adjust(attotime::never);

			LOG("Conversion finished, result: %03x\n", m_sar);

			break;
		}
	}
}


//**************************************************************************
//  INTERFACE
//**************************************************************************

READ8_MEMBER(upd7004_device::read)
{
	uint8_t data = 0xff;

	// connected to a flip-flop, cleared on read
	m_eoc_ff_cb(0);

	switch (offset)
	{
	case 0:
		// low-byte data output
		data = (m_sar & 0x03) << 6;
		break;

	case 1:
		// high-byte data output
		data = (m_sar >> 2) & 0xff;
		break;
	}

	return data;
}

WRITE8_MEMBER(upd7004_device::write)
{
	switch (offset)
	{
	case 0:
		// address set
		m_address = data & 0x07;

		// reset eoc
		m_eoc_cb(0);

		// start conversion timer
		m_state = STATE_CONVERSION_START;
		m_cycle_timer->adjust(attotime::from_hz(clock() / m_div));

		LOG("Select address %d\n", m_address);

		break;

	case 1:
		// initialize
		m_div = 1 << (data & 0x03);
		m_code = data & 0x04;

		logerror("Initialize with clock division ratio %d, %s data\n", m_div, m_code ? "2s complement" : "binary");

		if (m_code)
			logerror("Warning: 2s complement data unimplemented\n");

		break;
	}
}