summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/es8712.cpp
blob: 9440bd7ce6083edd620e5ac94e656a81507d9f9c (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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
// license:BSD-3-Clause
// copyright-holders:Quench, David Graves, R. Belmont
/**********************************************************************************************
 *
 *  ES8712 Sound Controller chip for MSM5205/6585 and 74157-type TTL pair
 *  Chip is branded by Excellent Systems, probably OEM'd.
 *
 *  Samples are currently looped, but whether they should and how, is unknown.
 *  Interface to the chip is also not 100% clear.
 *
 *  Current implementation is based from :
 *  gcpinbal.cpp, by David Graves & R. Belmont.
 *  splitted by cam900
 *
 *  It seems that the ES8712 is actually a programmable counter which can stream
 *  ADPCM samples when hooked up to a ROM and a M5205 or M6585 (whose VCK signal
 *  can drive the counter). Neither of these seem to be used in conjunction with
 *  the ES8712 on Dream 9 and Dream 9 Final, which suggests it may have been used
 *  for an entirely different purpose there (perhaps to do with video timing).
 *
 **********************************************************************************************/


#include "emu.h"
#include "es8712.h"


// device type definition
DEFINE_DEVICE_TYPE(ES8712, es8712_device, "es8712", "Excellent Systems ES8712 Sound Controller")


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

//-------------------------------------------------
//  es8712_device - constructor
//-------------------------------------------------

es8712_device::es8712_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, ES8712, tag, owner, clock)
	, device_rom_interface(mconfig, *this, 20) // TODO : 20 address bits?
	, m_adpcm_select(*this, "adpcm_select")
	, m_msm(*this, finder_base::DUMMY_TAG)
	, m_reset_handler(*this)
	, m_msm_write_cb(*this)
	, m_playing(0)
	, m_base_offset(0)
	, m_start(0)
	, m_end(0)
	, m_adpcm_trigger(0)
{ }


//-------------------------------------------------
//  device_add_mconfig - device-specific machine
//  configuration addiitons
//-------------------------------------------------

MACHINE_CONFIG_START(es8712_device::device_add_mconfig)
	MCFG_DEVICE_ADD("adpcm_select", HCT157, 0) // TODO : gcpinbal case, differs per games?
	MCFG_74157_OUT_CB(WRITE8(*this, es8712_device, msm_w))
MACHINE_CONFIG_END


//-------------------------------------------------
//  device_start - start emulation of an ES8712 chip
//-------------------------------------------------

void es8712_device::device_start()
{
	m_reset_handler.resolve_safe();
	m_msm_write_cb.resolve_safe();

	es8712_state_save_register();
}


//-------------------------------------------------
//  device_reset - stop emulation of an ES8712-compatible chip
//-------------------------------------------------

void es8712_device::device_reset()
{
	if (m_playing)
	{
		m_playing = 0;
	}
	if (m_msm.found())
		m_msm->reset_w(1);

	m_reset_handler(CLEAR_LINE);
}


//-------------------------------------------------
//  rom_bank_updated - nothing for now
//-------------------------------------------------

void es8712_device::rom_bank_updated()
{
}


//-------------------------------------------------
//   state save support for MAME
//-------------------------------------------------

void es8712_device::es8712_state_save_register()
{
	save_item(NAME(m_playing));

	save_item(NAME(m_base_offset));

	save_item(NAME(m_start));
	save_item(NAME(m_end));

	save_item(NAME(m_adpcm_trigger));
}


//-------------------------------------------------
//  play -- Begin playing the addressed sample
//-------------------------------------------------

void es8712_device::play()
{
	assert(m_msm.found());
	if (m_start < m_end)
	{
		if (!m_playing)
		{
			logerror("Playing sample range %06x-%06x\n", m_start, m_end);
			m_playing = 1;
			m_msm->reset_w(0);
			m_reset_handler(CLEAR_LINE);
			m_base_offset = m_start;
		}
	}
	/* invalid samples go here */
	else
	{
		logerror("Request to play invalid sample range %06x-%06x\n", m_start, m_end);

		if (m_playing)
		{
			/* update the stream */
			m_playing = 0;
			m_reset_handler(ASSERT_LINE);
		}
	}
}



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

     write -- generic data write functions

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

/**********************************************************************************************
 *
 *  offset  Start       End
 *          0hmmll  -  0HMMLL
 *    00    ----ll
 *    01    --mm--
 *    02    0h----
 *    03               ----LL
 *    04               --MM--
 *    05               0H----
 *    06           Go!
 *
 * Offsets are written in the order -> 00, 02, 01, 03, 05, 04, 06
 * Offset 06 is written with the same value as offset 04.
 *
***********************************************************************************************/

WRITE8_MEMBER(es8712_device::write)
{
	switch (offset)
	{
		case 00:    m_start &= 0x000fff00;
					m_start |= ((data & 0xff) <<  0); break;
		case 01:    m_start &= 0x000f00ff;
					m_start |= ((data & 0xff) <<  8); break;
		case 02:    m_start &= 0x0000ffff;
					m_start |= ((data & 0x0f) << 16); break;
		case 03:    m_end   &= 0x000fff00;
					m_end   |= ((data & 0xff) <<  0); break;
		case 04:    m_end   &= 0x000f00ff;
					m_end   |= ((data & 0xff) <<  8); break;
		case 05:    m_end   &= 0x0000ffff;
					m_end   |= ((data & 0x0f) << 16); break;
		case 06:
					play(); break;
		default:    break;
	}
	m_start &= 0xfffff; m_end &= 0xfffff;
}

READ8_MEMBER(es8712_device::read)
{
	// busy state (other bits unknown)
	if (offset == 0)
		return m_playing ? 1 : 0;

	return 0;
}

WRITE8_MEMBER(es8712_device::msm_w)
{
	m_msm_write_cb(offset, data);
}

WRITE_LINE_MEMBER(es8712_device::msm_int)
{
	if (!state || !m_playing)
		return;
	if (m_base_offset >= 0x100000 || m_base_offset > m_end)
	{
		m_playing = 0;
		m_msm->reset_w(1);
		m_reset_handler(ASSERT_LINE);
		//m_base_offset = m_start;
		m_adpcm_trigger = 0;
	}
	else
	{
		m_adpcm_select->write_ab(read_byte(m_base_offset));
		m_adpcm_select->select_w(m_adpcm_trigger);
		m_adpcm_trigger ^= 1;
		if (m_adpcm_trigger == 0)
			m_base_offset++;
	}
}