summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/msm5205.h
blob: 7e6ef5f91f9d14d27f7184899f4a16ac27c5c243 (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
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
#ifndef MAME_SOUND_MSM5205_H
#define MAME_SOUND_MSM5205_H

#pragma once

/* an interface for the MSM5205 and similar chips */

#define MCFG_MSM5205_PRESCALER_SELECTOR(select) \
	downcast<msm5205_device &>(*device).set_prescaler_selector((msm5205_device::select));

#define MCFG_MSM5205_VCK_CALLBACK(cb) \
	devcb = &downcast<msm5205_device &>(*device).set_vck_callback((DEVCB_##cb));

#define MCFG_MSM5205_VCLK_CB(cb) \
	devcb = &downcast<msm5205_device &>(*device).set_vck_legacy_callback((DEVCB_##cb));

#define MCFG_MSM6585_PRESCALER_SELECTOR(select) \
	downcast<msm5205_device &>(*device).set_prescaler_selector((msm6585_device::select));

#define MCFG_MSM6585_VCK_CALLBACK(cb) \
	devcb = &downcast<msm5205_device &>(*device).set_vck_callback((DEVCB_##cb));


class msm5205_device : public device_t, public device_sound_interface
{
public:
	/* MSM5205 default master clock is 384KHz */
	static constexpr int S96_3B = 0;     /* prescaler 1/96(4KHz) , data 3bit */
	static constexpr int S48_3B = 1;     /* prescaler 1/48(8KHz) , data 3bit */
	static constexpr int S64_3B = 2;     /* prescaler 1/64(6KHz) , data 3bit */
	static constexpr int SEX_3B = 3;     /* VCK slave mode       , data 3bit */
	static constexpr int S96_4B = 4;     /* prescaler 1/96(4KHz) , data 4bit */
	static constexpr int S48_4B = 5;     /* prescaler 1/48(8KHz) , data 4bit */
	static constexpr int S64_4B = 6;     /* prescaler 1/64(6KHz) , data 4bit */
	static constexpr int SEX_4B = 7;     /* VCK slave mode       , data 4bit */

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

	void set_prescaler_selector(int select)
	{
		m_s1 = BIT(select, 1);
		m_s2 = BIT(select, 0);
		m_bitwidth = (select & 4) ? 4 : 3;
	}
	template <class Object> devcb_base &set_vck_callback(Object &&cb) { return m_vck_cb.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_vck_legacy_callback(Object &&cb) { return m_vck_legacy_cb.set_callback(std::forward<Object>(cb)); }

	// reset signal should keep for 2cycle of VCLK
	DECLARE_WRITE_LINE_MEMBER(reset_w);

	// adpcmata is latched after vclk_interrupt callback
	void write_data(int data);
	DECLARE_WRITE8_MEMBER(data_w) { write_data(data); }

	// VCLK slave mode option
	// if VCLK and reset or data is changed at the same time,
	// call vclk_w after data_w and reset_w.
	DECLARE_WRITE_LINE_MEMBER(vclk_w);

	// option , selected pin selector
	void playmode_w(int select);
	DECLARE_WRITE_LINE_MEMBER(s1_w);
	DECLARE_WRITE_LINE_MEMBER(s2_w);

protected:
	enum
	{
		TIMER_VCK,
		TIMER_ADPCM_CAPTURE
	};

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

	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void device_clock_changed() override;
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;

	void update_adpcm();

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

	void compute_tables();
	virtual int get_prescaler() const;

	// internal state
	sound_stream *m_stream;     // number of stream system
	emu_timer *m_vck_timer;     // VCK callback timer
	emu_timer *m_capture_timer; // delay after VCK active edge for ADPCM input capture
	u8 m_data;                  // next adpcm data
	bool m_vck;                 // VCK signal
	bool m_reset;               // reset pin signal
	bool m_s1;                  // prescaler selector S1
	bool m_s2;                  // prescaler selector S2
	u8 m_bitwidth;              // bit width selector -3B/4B
	s32 m_signal;               // current ADPCM signal
	s32 m_step;                 // current ADPCM step
	int m_diff_lookup[49*16];

	devcb_write_line m_vck_cb;
	devcb_write_line m_vck_legacy_cb;
};


class msm6585_device : public msm5205_device
{
public:
	/* MSM6585 default master clock is 640KHz */
	static constexpr int S160  = 4 + 8;  /* prescaler 1/160(4KHz), data 4bit */
	static constexpr int S40   = 5 + 8;  /* prescaler 1/40(16KHz), data 4bit */
	static constexpr int S80   = 6 + 8;  /* prescaler 1/80 (8KHz), data 4bit */
	static constexpr int S20   = 7 + 8;  /* prescaler 1/20(32KHz), data 4bit */

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

protected:
	virtual int get_prescaler() const override;

	// device-level overrides
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;

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


DECLARE_DEVICE_TYPE(MSM5205, msm5205_device)
DECLARE_DEVICE_TYPE(MSM6585, msm6585_device)

#endif // MAME_SOUND_MSM5205_H