summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/swp30.h
blob: eb34fb13eec93b153b2dbc074ff254d9d085c057 (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
237
238
239
240
241
242
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert

// Yamaha SWP30/30B, rompler/dsp combo

#ifndef MAME_SOUND_SWP30_H
#define MAME_SOUND_SWP30_H

#pragma once

#include "swp30d.h"

class swp30_device : public cpu_device, public device_sound_interface, public swp30_disassembler::info
{
public:
	enum { AS_REVERB = AS_IO };

	swp30_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 33868800);

	void map(address_map &map) ATTR_COLD;

protected:
	virtual void device_start() override ATTR_COLD;
	virtual void device_reset() override ATTR_COLD;
	virtual void sound_stream_update(sound_stream &stream) override;
	virtual uint32_t execute_min_cycles() const noexcept override;
	virtual uint32_t execute_max_cycles() const noexcept override;
	virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const noexcept override { return (clocks + 1) / 2; }
	virtual void execute_run() override;
	virtual space_config_vector memory_space_config() const override;
	virtual void state_import(const device_state_entry &entry) override;
	virtual void state_export(const device_state_entry &entry) override;
	virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
	virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;

private:
	enum {
		IDLE,
		ATTACK,
		DECAY1,
		DECAY2,
		RELEASE
	};

	struct mixer_slot {
		std::array<u16, 3> vol;
		std::array<u16, 3> route;
	};

	address_space_config m_program_config, m_rom_config, m_reverb_config;
	address_space *m_program, *m_rom, *m_reverb;
	memory_access<25, 2, -2, ENDIANNESS_LITTLE>::cache m_rom_cache;
	memory_access<18, 1, -1, ENDIANNESS_LITTLE>::cache m_reverb_cache;

	sound_stream *m_stream;

	static const std::array<s32, 0x80> attack_linear_step;
	static const std::array<s32, 0x20> decay_linear_step;
	static const std::array<s32, 16> panmap;
	static const std::array<u32, 0x400> pitch_base;
	std::array<s32,  0x80> m_global_step;
	std::array<s16, 0x100> m_dpcm;

	static const std::array<u32, 4> lfo_shape_centered_saw;
	static const std::array<u32, 4> lfo_shape_centered_tri;
	static const std::array<u32, 4> lfo_shape_offset_saw;
	static const std::array<u32, 4> lfo_shape_offset_tri;
	static const std::array<u8,  4> dpcm_offset;

	std::array<s32,  0x40> m_sample_start;
	std::array<s32,  0x40> m_sample_end;
	std::array<u32,  0x40> m_sample_address;
	std::array<u16,  0x40> m_pitch;

	std::array<u16,  0x40> m_attack;
	std::array<u16,  0x40> m_decay1;
	std::array<u16,  0x40> m_decay2;
	std::array<u16,  0x40> m_release_glo;
	std::array<u16,  0x40> m_lfo_step_pmod;
	std::array<u16,  0x40> m_lfo_amod;

	std::array<u32,  0x40> m_lfo_phase;
	std::array<s32,  0x40> m_sample_pos;
	std::array<s32,  0x40> m_envelope_level;
	std::array<s32,  0x40> m_envelope_timer;
	std::array<bool, 0x40> m_envelope_on_timer;
	std::array<bool, 0x40> m_decay2_done;
	std::array<u8,   0x40> m_envelope_mode;
	std::array<s32,  0x40> m_glo_level_cur;
	std::array<s32,  0x40> m_pan_l;
	std::array<s32,  0x40> m_pan_r;
	std::array<s16,  0x40> m_dpcm_current;
	std::array<s16,  0x40> m_dpcm_next;
	std::array<u32,  0x40> m_dpcm_address;
	std::array<s32,  0x40> m_dpcm_sum;

	std::array<u64, 0x180> m_meg_program;
	std::array<s16, 0x180> m_meg_const;
	std::array<u16,  0x80> m_meg_offset;
	std::array<u16,  0x18> m_meg_lfo;
	std::array<u16,     8> m_meg_map;

	std::array<mixer_slot, 0x80> m_mixer;

	std::array<s32,  0x40> m_meg_m;
	std::array<s32,  0x10> m_melo;
	std::array<s32,     2> m_meg_output;

	s32 m_sample_history[0x40][2][2];

	u32 m_waverom_adr, m_waverom_mode, m_waverom_val;
	u16 m_waverom_access;

	u16 m_lpf_cutoff[0x40], m_lpf_cutoff_inc[0x40], m_lpf_reso[0x40], m_hpf_cutoff[0x40];
	s16 m_eq_filter[0x40][6];

	u64 m_keyon_mask;
	u16 m_internal_adr;

	u16 m_meg_program_address;
	u16 m_meg_pc;
	int m_icount;

	// AWM2 per-channel registers
	u16 lpf_cutoff_r(offs_t offset);
	void lpf_cutoff_w(offs_t offset, u16 data);
	u16 lpf_cutoff_inc_r(offs_t offset);
	void lpf_cutoff_inc_w(offs_t offset, u16 data);
	u16 hpf_cutoff_r(offs_t offset);
	void hpf_cutoff_w(offs_t offset, u16 data);
	u16 lpf_reso_r(offs_t offset);
	void lpf_reso_w(offs_t offset, u16 data);
	u16 attack_r(offs_t offset);
	void attack_w(offs_t offset, u16 data);
	u16 decay1_r(offs_t offset);
	void decay1_w(offs_t offset, u16 data);
	u16 decay2_r(offs_t offset);
	void decay2_w(offs_t offset, u16 data);
	u16 release_glo_r(offs_t offset);
	void release_glo_w(offs_t offset, u16 data);
	template<int coef> u16 eq_filter_r(offs_t offset);
	template<int coef> void eq_filter_w(offs_t offset, u16 data);

	u16 sample_start_h_r(offs_t offset);
	u16 sample_start_l_r(offs_t offset);
	void sample_start_h_w(offs_t offset, u16 data);
	void sample_start_l_w(offs_t offset, u16 data);
	u16 sample_end_h_r(offs_t offset);
	u16 sample_end_l_r(offs_t offset);
	void sample_end_h_w(offs_t offset, u16 data);
	void sample_end_l_w(offs_t offset, u16 data);
	u16 sample_address_h_r(offs_t offset);
	u16 sample_address_l_r(offs_t offset);
	void sample_address_h_w(offs_t offset, u16 data);
	void sample_address_l_w(offs_t offset, u16 data);
	u16 pitch_r(offs_t offset);
	void pitch_w(offs_t offset, u16 data);

	u16 pan_r(offs_t offset);
	void pan_w(offs_t offset, u16 data);
	u16 dry_rev_r(offs_t offset);
	void dry_rev_w(offs_t offset, u16 data);
	u16 cho_var_r(offs_t offset);
	void cho_var_w(offs_t offset, u16 data);

	void lfo_step_pmod_w(offs_t offset, u16 data);
	u16 lfo_step_pmod_r(offs_t offset);
	void lfo_amod_w(offs_t offset, u16 data);
	u16 lfo_amod_r(offs_t offset);

	u16 internal_adr_r();
	void internal_adr_w(u16 data);
	u16 internal_r();
	template<int sel> u16 route_r(offs_t offset);
	template<int sel> void route_w(offs_t offset, u16 data);
	template<int sel> u16 vol_r(offs_t offset);
	template<int sel> void vol_w(offs_t offset, u16 data);

	// Envelope control
	void change_mode_attack_decay1(int chan);
	void change_mode_decay1_decay2(int chan);
	static bool istep(s32 &value, s32 limit, s32 step);
	static bool fpstep(s32 &value, s32 limit, s32 step);
	static s32 fpadd(s32 value, s32 step);
	static s32 fpsub(s32 value, s32 step);
	static s32 fpapply(s32 value, s32 sample);
	static s32 lpffpapply(s32 value, s32 sample);
	static s32 meg_att(s32 sample, s32 att);

	// Control registers
	template<int sel> u16 keyon_mask_r();
	template<int sel> void keyon_mask_w(u16 data);
	u16 keyon_r();
	void keyon_w(u16);
	u16 meg_prg_address_r();
	void meg_prg_address_w(u16 data);
	template<int sel> u16 meg_prg_r();
	template<int sel> void meg_prg_w(u16 data);
	template<int sel> u16 meg_map_r();
	template<int sel> void meg_map_w(u16 data);
	template<int sel> void waverom_adr_w(u16 data);
	template<int sel> u16 waverom_adr_r();
	template<int sel> void waverom_mode_w(u16 data);
	template<int sel> u16 waverom_mode_r();
	void waverom_access_w(u16 data);
	u16 waverom_access_r();
	u16 waverom_busy_r();
	template<int sel> u16 waverom_val_r();

	// MEG registers
	template<int sel> u16 meg_const_r(offs_t offset);
	template<int sel> void meg_const_w(offs_t offset, u16 data);
	template<int sel> u16 meg_offset_r(offs_t offset);
	template<int sel> void meg_offset_w(offs_t offset, u16 data);
	template<int sel> u16 meg_lfo_r(offs_t offset);
	template<int sel> void meg_lfo_w(offs_t offset, u16 data);

	void meg_prg_map(address_map &map) ATTR_COLD;
	u64 meg_prg_map_r(offs_t address);

	void meg_reverb_map(address_map &map) ATTR_COLD;

	virtual u16 swp30d_const_r(u16 address) const override;
	virtual u16 swp30d_offset_r(u16 address) const override;

	// Generic catch-all
	u16 snd_r(offs_t offset);
	void snd_w(offs_t offset, u16 data);

	inline auto &rchan(address_map &map, int idx) {
		return map(idx*2, idx*2+1).select(0x1f80);
	}

	inline auto &rctrl(address_map &map, int idx) {
		int slot = 0x40*(idx >> 1) | 0xe | (idx & 1);
		return map(slot*2, slot*2+1);
	}
};

DECLARE_DEVICE_TYPE(SWP30, swp30_device)

#endif // MAME_SOUND_SWP30_H