summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/ics2115.h
blob: 8703c2583446e7e7a4466e43e247ec03100c2d1f (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
// license:BSD-3-Clause
// copyright-holders:Alex Marshall,nimitz,austere
#ifndef MAME_SOUND_ICS2115_H
#define MAME_SOUND_ICS2115_H

#pragma once


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

// ======================> ics2115_device

class ics2115_device : public device_t, public device_sound_interface, public device_memory_interface
{
public:
	static constexpr feature_type imperfect_features() { return feature::SOUND; } // Incorrect/Unverified interrupt, interpolation;
	// current ramping behavior is seems like incorrect?

	// construction/destruction
	ics2115_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

	auto irq() { return m_irq_cb.bind(); }

	u8 read(offs_t offset);
	void write(offs_t offset, u8 data);

	// 16-bit read / write handlers (when /IOCS16 is low)
	u16 word_r(offs_t offset, u16 mem_mask);
	void word_w(offs_t offset, u16 data, u16 mem_mask);
	TIMER_CALLBACK_MEMBER(timer_cb_0);
	TIMER_CALLBACK_MEMBER(timer_cb_1);

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

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

	// device_memory_interface configuration
	virtual space_config_vector memory_space_config() const override;

	address_space_config m_data_config;

private:
	static constexpr u16 revision = 0x1;

	struct ics2115_voice {
		struct {
			s32 left;
			u32 acc, start, end;
			u16 fc;
			u8 ctl, saddr;
		} osc;

		struct {
			s32 left;
			u32 add;
			u32 start, end;
			u32 acc;
			u16 regacc;
			u8 incr;
			u8 pan, mode;
		} vol;

		union {
			struct {
				u8 ulaw       : 1;
				u8 stop       : 1;   //stops wave + vol envelope
				u8 eightbit   : 1;
				u8 loop       : 1;
				u8 loop_bidir : 1;
				u8 irq        : 1;
				u8 invert     : 1;
				u8 irq_pending: 1;
				//IRQ on variable?
			} bitflags;
			u8 value;
		} osc_conf;

		union {
			struct {
				u8 done       : 1;   //indicates ramp has stopped
				u8 stop       : 1;   //stops the ramp
				u8 rollover   : 1;   //rollover (TODO)
				u8 loop       : 1;
				u8 loop_bidir : 1;
				u8 irq        : 1;   //enable IRQ generation
				u8 invert     : 1;   //invert direction
				u8 irq_pending: 1;   //(read only) IRQ pending
				//noenvelope == (done | disable)
			} bitflags;
			u8 value;
		} vol_ctrl;

		//Possibly redundant state. => improvements of wavetable logic
		//may lead to its elimination.
		union {
			struct {
				u8 on         : 1;
				u8 ramp       : 7;       // 100 0000 = 0x40 maximum
			} bitflags;
			u8 value;
		} state;

		bool playing();
		int update_volume_envelope();
		int update_oscillator();
		void update_ramp();
	};

	//internal register helper functions
	u16 reg_read();
	void reg_write(u16 data, u16 mem_mask);
	void recalc_timer(int timer);
	void keyon();
	void recalc_irq();

	//stream helper functions
	int fill_output(ics2115_voice& voice, stream_sample_t *outputs[2], int samples);
	stream_sample_t get_sample(ics2115_voice& voice);
	u8 read_sample(ics2115_voice& voice, u32 addr) { return m_cache.read_byte((voice.osc.saddr << 20) | (addr & 0xfffff)); }

	sound_stream *m_stream;

	// internal state
	memory_access<24, 0, 0, ENDIANNESS_LITTLE>::cache m_cache;
	required_region_ptr<u8> m_rom;
	devcb_write_line m_irq_cb;

	s16 m_ulaw[256];
	u16 m_volume[4096];
	static const int volume_bits = 15;

	ics2115_voice m_voice[32];
	struct {
		u8 scale, preset;
		emu_timer *timer;
		u64 period;  /* in nsec */
	} m_timer[2];

	u8 m_active_osc;
	u8 m_osc_select;
	u8 m_reg_select;
	u8 m_irq_enabled, m_irq_pending;
	bool m_irq_on;

	/*
		Unknown variable, seems to be effected by 0x12. Further investigation
		Required.
	*/
	u8 m_vmode;
};


// device type definition
DECLARE_DEVICE_TYPE(ICS2115, ics2115_device)

#endif // MAME_SOUND_ICS2115_H