summaryrefslogtreecommitdiffstats
path: root/src/devices/machine/upd7002.cpp
blob: b00d44066e58bec47e4f032d4c89de9e1ed12e20 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// license:BSD-3-Clause
// copyright-holders:Gordon Jefferyes
/******************************************************************************
    uPD7002 Analogue to Digital Converter

    MESS Driver By:

    Gordon Jefferyes
    mess_bbc@gjeffery.dircon.co.uk

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

#include "emu.h"
#include "upd7002.h"


/* Device Interface */

DEFINE_DEVICE_TYPE(UPD7002, upd7002_device, "upd7002", "uPD7002 ADC")

upd7002_device::upd7002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, UPD7002, tag, owner, clock), m_status(0), m_data1(0), m_data0(0), m_digitalvalue(0), m_conversion_counter(0)
{
}

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

void upd7002_device::device_start()
{
	m_get_analogue_cb.bind_relative_to(*owner());
	m_eoc_cb.bind_relative_to(*owner());

	// register for state saving
	save_item(NAME(m_status));
	save_item(NAME(m_data1));
	save_item(NAME(m_data0));
	save_item(NAME(m_digitalvalue));
	save_item(NAME(m_conversion_counter));
}

//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void upd7002_device::device_reset()
{
	m_status = 0;
	m_data1 = 0;
	m_data0 = 0;
	m_digitalvalue = 0;
	m_conversion_counter = 0;
}


/*****************************************************************************
 Implementation
*****************************************************************************/


READ_LINE_MEMBER( upd7002_device::eoc_r )
{
	return (m_status>>7)&0x01;
}


void upd7002_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	switch (id)
	{
	case TIMER_CONVERSION_COMPLETE:
		{
		int counter_value = param;
		if (counter_value==m_conversion_counter)
		{
			// this really always does a 12 bit conversion
			m_data1 = m_digitalvalue>>8;
			m_data0 = m_digitalvalue&0xf0;

			// set the status register with top 2 MSB, not busy and conversion complete
			m_status = (m_status & 0x0f)|((m_data1 & 0xc0)>>2)|0x40;

			// call the EOC function with EOC from status
			// eoc_r(0) this has just been set to 0
			if (!m_eoc_cb.isnull()) m_eoc_cb(0);
			m_conversion_counter=0;
		}
		break;
		}
	default:
		assert_always(false, "Unknown id in upd7002_device::device_timer");
	}
}


uint8_t upd7002_device::read(offs_t offset)
{
	switch(offset&0x03)
	{
		case 0:
			return m_status;

		case 1:
			return m_data1;

		case 2: case 3:
			return m_data0;
	}
	return 0;
}



void upd7002_device::write(offs_t offset, uint8_t data)
{
	/* logerror("write to uPD7002 $%02X = $%02X\n",offset,data); */

	switch(offset&0x03)
	{
		case 0:
		/*
		Data Latch/AD start
		    D0 and D1 together define which one of the four input channels is selected
		    D2 flag input, normally set to 0????
		    D3 defines whether an 8 (0) or 12 (1) bit resolution conversion should occur
		    D4 to D7 not used.

		    an 8  bit conversion typically takes 4ms
		    an 12 bit conversion typically takes 10ms

		    writing to this register will initiate a conversion.
		*/

		/* set D6=0 busy ,D7=1 conversion not complete */
		m_status=(data & 0x0f) | 0x80;

		// call the EOC function with EOC from status
		// eoc_r(0) this has just been set to 1
		if (!m_eoc_cb.isnull()) m_eoc_cb(1);

		/* the uPD7002 works by sampling the analogue value at the start of the conversion
		   so it is read hear and stored until the end of the A to D conversion */

		// this function should return a 16 bit value.
		m_digitalvalue = m_get_analogue_cb(m_status & 0x03);

		m_conversion_counter++;

		// call a timer to start the conversion
		if (m_status & 0x08)
		{
			// 12 bit conversion takes 10ms
			timer_set(attotime::from_msec(10), TIMER_CONVERSION_COMPLETE, m_conversion_counter);
		} else {
			// 8 bit conversion takes 4ms
			timer_set(attotime::from_msec(4), TIMER_CONVERSION_COMPLETE, m_conversion_counter);
		}
		break;

		case 1: case 2:
		/* Nothing */
		break;

		case 3:
		/* Test Mode: Used for inspecting the device, The data input-output terminals assume an input
		      state and are connected to the A/D counter. Therefore, the A/D conversion data
		      read out after this is meaningless.
		*/
		break;
	}
}