summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/segasnd.h
blob: 23a6638e9ab3ea37467aca9542016d3332ec3554 (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
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*************************************************************************

    Sega g80 common sound hardware

*************************************************************************/
#ifndef MAME_AUDIO_SEGASND_H
#define MAME_AUDIO_SEGASND_H

#pragma once

#include "cpu/mcs48/mcs48.h"
#include "machine/timer.h"

class segag80snd_common : public driver_device {
public:
	segag80snd_common(const machine_config &mconfig, device_type type, const char *tag) :
		driver_device(mconfig, type, tag),
		m_audiocpu(*this, "audiocpu")
	{ }

	virtual ~segag80snd_common() = default;

	DECLARE_WRITE_LINE_MEMBER(segaspeech_int_w);

	void sega_speech_board(machine_config &config);

protected:
	void speech_map(address_map &map);
	void speech_portmap(address_map &map);

	optional_device<cpu_device> m_audiocpu;
};

#define SEGASND_SEGASPEECH_REGION "segaspeech:speech"

class speech_sound_device : public device_t, public device_sound_interface
{
public:
	speech_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

	auto int_cb() { return m_int_cb.bind(); }

	DECLARE_WRITE8_MEMBER( data_w );
	DECLARE_WRITE8_MEMBER( control_w );

	DECLARE_READ_LINE_MEMBER( t0_r );
	DECLARE_READ_LINE_MEMBER( t1_r );
	DECLARE_READ8_MEMBER( p1_r );
	DECLARE_READ8_MEMBER( rom_r );
	DECLARE_WRITE8_MEMBER( p1_w );
	DECLARE_WRITE8_MEMBER( p2_w );

	DECLARE_WRITE_LINE_MEMBER(drq_w);

protected:
	// device-level overrides
	virtual void device_start() override;

	// sound stream update overrides
	virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;

private:
	devcb_write_line m_int_cb;
	required_memory_region m_speech;

	// internal state
	u8 m_drq;
	u8 m_latch;
	u8 m_t0;
	u8 m_p2;

	TIMER_CALLBACK_MEMBER( delayed_speech_w );
};

DECLARE_DEVICE_TYPE(SEGASPEECH, speech_sound_device)

class usb_sound_device : public device_t, public device_sound_interface
{
public:
	template <typename T> usb_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&maincpu_tag)
		: usb_sound_device(mconfig, tag, owner, clock)
	{
		m_maincpu.set_tag(maincpu_tag);
	}

	usb_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

	DECLARE_READ8_MEMBER( status_r );
	DECLARE_WRITE8_MEMBER( data_w );
	DECLARE_READ8_MEMBER( ram_r );
	DECLARE_WRITE8_MEMBER( ram_w );

	DECLARE_READ8_MEMBER( workram_r );
	DECLARE_WRITE8_MEMBER( workram_w );

	TIMER_DEVICE_CALLBACK_MEMBER( increment_t1_clock_timer_cb );

	void usb_map(address_map &map);
	void usb_map_rom(address_map &map);
	void usb_portmap(address_map &map);

protected:
	usb_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);

	// device-level overrides
	virtual void device_add_mconfig(machine_config &config) override;
	virtual void device_start() override;
	virtual void device_reset() override;

	// sound stream update overrides
	virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;

	required_device<i8035_device> m_ourcpu;
	required_device<cpu_device> m_maincpu;

private:
	struct g80_filter_state
	{
		g80_filter_state() { }

		void configure(double r, double c);
		double step_rc(double input);
		double step_cr(double input);

		double capval   = 0.0; // current capacitor value
		double exponent = 0.0; // constant exponent
	};


	struct timer8253
	{
		struct channel
		{
			channel() { }

			void clock();

			u8  holding     = 0; // holding until counts written? */
			u8  latchmode   = 0; // latching mode */
			u8  latchtoggle = 0; // latching state */
			u8  clockmode   = 0; // clocking mode */
			u8  bcdmode     = 0; // BCD mode? */
			u8  output      = 0; // current output value */
			u8  lastgate    = 0; // previous gate value */
			u8  gate        = 0; // current gate value */
			u8  subcount    = 0; // subcount (2MHz clocks per input clock) */
			u16 count       = 0; // initial count
			u16 remain      = 0; // current down counter value
		};

		timer8253() : env{ 0.0, 0.0, 0.0 } { }

		channel             chan[3];        // three channels' worth of information
		double              env[3];         // envelope value for each channel
		g80_filter_state    chan_filter[2]; // filter states for the first two channels
		g80_filter_state    gate1;          // first RC filter state
		g80_filter_state    gate2;          // second RC filter state
		u8                  config = 0;     // configuration for this timer
	};

	// internal state
	sound_stream            *m_stream;              // output stream
	u8                      m_in_latch;             // input latch
	u8                      m_out_latch;            // output latch
	u8                      m_last_p2_value;        // current P2 output value
	optional_shared_ptr<u8> m_program_ram;          // pointer to program RAM
	required_shared_ptr<u8> m_work_ram;             // pointer to work RAM
	u8                      m_work_ram_bank;        // currently selected work RAM bank
	u8                      m_t1_clock;             // T1 clock value
	u8                      m_t1_clock_mask;        // T1 clock mask (configured via jumpers)
	timer8253               m_timer_group[3];       // 3 groups of timers
	u8                      m_timer_mode[3];        // mode control for each group
	u32                     m_noise_shift;
	u8                      m_noise_state;
	u8                      m_noise_subcount;
	double                  m_gate_rc1_exp[2];
	double                  m_gate_rc2_exp[2];
	g80_filter_state        m_final_filter;
	g80_filter_state        m_noise_filters[5];

	TIMER_CALLBACK_MEMBER( delayed_usb_data_w );
	void timer_w(int which, u8 offset, u8 data);
	void env_w(int which, u8 offset, u8 data);

	DECLARE_READ8_MEMBER( p1_r );
	DECLARE_WRITE8_MEMBER( p1_w );
	DECLARE_WRITE8_MEMBER( p2_w );
	DECLARE_READ_LINE_MEMBER( t1_r );
};

DECLARE_DEVICE_TYPE(SEGAUSB, usb_sound_device)


class usb_rom_sound_device : public usb_sound_device
{
public:
	template <typename T> usb_rom_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&maincpu_tag)
		: usb_rom_sound_device(mconfig, tag, owner, clock)
	{
		m_maincpu.set_tag(maincpu_tag);
	}

	usb_rom_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

protected:
	// device-level overrides
	virtual void device_add_mconfig(machine_config &config) override;
};

DECLARE_DEVICE_TYPE(SEGAUSBROM, usb_rom_sound_device)

#endif // MAME_AUDIO_SEGASND_H