summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/2608intf.cpp
blob: 6c31c2aea0f71b9a6c295bfa67551155c4c7012f (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
// license:BSD-3-Clause
// copyright-holders:Ernesto Corvi
/***************************************************************************

  2608intf.c

  The YM2608 emulator supports up to 2 chips.
  Each chip has the following connections:
  - Status Read / Control Write A
  - Port Read / Data Write A
  - Control Write B
  - Data Write B

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

#include "emu.h"
#include "2608intf.h"
#include "fm.h"

const ssg_callbacks ym2608_device::psgintf =
{
	&ym2608_device::psg_set_clock,
	&ym2608_device::psg_write,
	&ym2608_device::psg_read,
	&ym2608_device::psg_reset
};

/* IRQ Handler */
void ym2608_device::irq_handler(int irq)
{
	if (!m_irq_handler.isnull())
		m_irq_handler(irq);
}

/* Timer overflow callback from timer.c */
void ym2608_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	switch(id)
	{
	case 0:
		ym2608_timer_over(m_chip,0);
		break;

	case 1:
		ym2608_timer_over(m_chip,1);
		break;
	}
}

void ym2608_device::timer_handler(int c,int count,int clock)
{
	if( count == 0 || clock == 0 )
	{   /* Reset FM Timer */
		m_timer[c]->enable(false);
	}
	else
	{   /* Start FM Timer */
		attotime period = attotime::from_hz(clock) * count;

		if (!m_timer[c]->enable(true))
			m_timer[c]->adjust(period);
	}
}

//-------------------------------------------------
//  sound_stream_update - handle a stream update
//-------------------------------------------------

void ym2608_device::stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
	ym2608_update_one(m_chip, outputs, samples);
}

void ym2608_device::device_post_load()
{
	ym2608_postload(m_chip);
}

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

void ym2608_device::device_start()
{
	ay8910_device::device_start();

	int rate = clock()/72;

	m_irq_handler.resolve();

	/* Timer Handler set */
	m_timer[0] = timer_alloc(0);
	m_timer[1] = timer_alloc(1);

	/* stream system initialize */
	m_stream = machine().sound().stream_alloc(*this,0,2,rate, stream_update_delegate(&ym2608_device::stream_generate,this));

	/* initialize YM2608 */
	m_chip = ym2608_init(this,clock(),rate,
		&ym2608_device::static_internal_read_byte,
		&ym2608_device::static_external_read_byte, &ym2608_device::static_external_write_byte,
		&ym2608_device::static_timer_handler,&ym2608_device::static_irq_handler,&psgintf);
	assert_always(m_chip != nullptr, "Error creating YM2608 chip");
}

//-------------------------------------------------
//  device_clock_changed
//-------------------------------------------------

void ym2608_device::device_clock_changed()
{
	m_stream->set_sample_rate(clock() / 72);
	ym2608_clock_changed(m_chip, clock(), clock() / 72);
}

//-------------------------------------------------
//  device_stop - device-specific stop
//-------------------------------------------------

void ym2608_device::device_stop()
{
	ym2608_shutdown(m_chip);
}

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

void ym2608_device::device_reset()
{
	ym2608_reset_chip(m_chip);
}

//-------------------------------------------------
//  rom_bank_updated
//-------------------------------------------------

void ym2608_device::rom_bank_updated()
{
	m_stream->update();
}


u8 ym2608_device::read(offs_t offset)
{
	return ym2608_read(m_chip, offset & 3);
}

void ym2608_device::write(offs_t offset, u8 data)
{
	ym2608_write(m_chip, offset & 3, data);
}

DEFINE_DEVICE_TYPE(YM2608, ym2608_device, "ym2608", "YM2608 OPNA")

ym2608_device::ym2608_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: ay8910_device(mconfig, YM2608, tag, owner, clock, PSG_TYPE_YM, 1, 2)
	, device_rom_interface(mconfig, *this, 21)
	, m_stream(nullptr)
	, m_timer{ nullptr, nullptr }
	, m_chip(nullptr)
	, m_irq_handler(*this)
	, m_internal(*this, "internal")
{
}

ROM_START( ym2608 )
	ROM_REGION( 0x2000, "internal", 0 )
	/*
	This data is derived from the chip's output - internal ROM can't be read.
	It was verified, using real YM2608, that this ADPCM stream produces 100% correct output signal.
	*/
	// see YM2608_ADPCM_ROM_addr table in fm.c for current sample offsets
	// original offset comments from Jarek:
	// offset 0:
		/* Source: 01BD.ROM */
		/* Length: 448 / 0x000001C0 */
	// offset 0x1C0:
		/* Source: 02SD.ROM */
		/* Length: 640 / 0x00000280 */
	// offset 0x440:
		/* Source: 04TOP.ROM */
		/* Length: 5952 / 0x00001740 */
	// offset 0x1B80:
		/* Source: 08HH.ROM */
		/* Length: 384 / 0x00000180 */
	// offset 0x1D00
		/* Source: 10TOM.ROM */
		/* Length: 640 / 0x00000280 */
	// offset 0x1F80
		/* Source: 20RIM.ROM */
		/* Length: 128 / 0x00000080 */
	/* while this rom was dumped by output analysis, not decap, it was tested
	  by playing it back into the chip as an external adpcm sample and produced
	  an identical dac result. a decap would be nice to verify things 100%,
	  but there is currently no reason to think this rom dump is incorrect. */
	ROM_LOAD16_WORD( "ym2608_adpcm_rom.bin", 0x0000, 0x2000, CRC(23c9e0d8) SHA1(50b6c3e288eaa12ad275d4f323267bb72b0445df) )
ROM_END


const tiny_rom_entry *ym2608_device::device_rom_region() const
{
	return ROM_NAME( ym2608 );
}