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
|
// BSD 3-Clause License
//
// Copyright (c) 2021, Aaron Giles
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef YMFM_SSG_H
#define YMFM_SSG_H
#pragma once
#include "ymfm.h"
namespace ymfm
{
//*********************************************************
// OVERRIDE INTERFACE
//*********************************************************
// ======================> ssg_override
// this class describes a simple interface to allow the internal SSG to be
// overridden with another implementation
class ssg_override
{
public:
virtual ~ssg_override() = default;
// reset our status
virtual void ssg_reset() = 0;
// read/write to the SSG registers
virtual uint8_t ssg_read(uint32_t regnum) = 0;
virtual void ssg_write(uint32_t regnum, uint8_t data) = 0;
// notification when the prescale has changed
virtual void ssg_prescale_changed() = 0;
};
//*********************************************************
// REGISTER CLASS
//*********************************************************
// ======================> ssg_registers
//
// SSG register map:
//
// System-wide registers:
// 06 ---xxxxx Noise period
// 07 x------- I/O B in(0) or out(1)
// -x------ I/O A in(0) or out(1)
// --x----- Noise enable(0) or disable(1) for channel C
// ---x---- Noise enable(0) or disable(1) for channel B
// ----x--- Noise enable(0) or disable(1) for channel A
// -----x-- Tone enable(0) or disable(1) for channel C
// ------x- Tone enable(0) or disable(1) for channel B
// -------x Tone enable(0) or disable(1) for channel A
// 0B xxxxxxxx Envelope period fine
// 0C xxxxxxxx Envelope period coarse
// 0D ----x--- Envelope shape: continue
// -----x-- Envelope shape: attack/decay
// ------x- Envelope shape: alternate
// -------x Envelope shape: hold
// 0E xxxxxxxx 8-bit parallel I/O port A
// 0F xxxxxxxx 8-bit parallel I/O port B
//
// Per-channel registers:
// 00,02,04 xxxxxxxx Tone period (fine) for channel A,B,C
// 01,03,05 ----xxxx Tone period (coarse) for channel A,B,C
// 08,09,0A ---x---- Mode: fixed(0) or variable(1) for channel A,B,C
// ----xxxx Amplitude for channel A,B,C
//
class ssg_registers
{
public:
// constants
static constexpr uint32_t OUTPUTS = 3;
static constexpr uint32_t CHANNELS = 3;
static constexpr uint32_t REGISTERS = 0x10;
static constexpr uint32_t ALL_CHANNELS = (1 << CHANNELS) - 1;
// constructor
ssg_registers() { }
// reset to initial state
void reset();
// save/restore
void save_restore(ymfm_saved_state &state);
// direct read/write access
uint8_t read(uint32_t index) { return m_regdata[index]; }
void write(uint32_t index, uint8_t data) { m_regdata[index] = data; }
// system-wide registers
uint32_t noise_period() const { return bitfield(m_regdata[0x06], 0, 5); }
uint32_t io_b_out() const { return bitfield(m_regdata[0x07], 7); }
uint32_t io_a_out() const { return bitfield(m_regdata[0x07], 6); }
uint32_t envelope_period() const { return m_regdata[0x0b] | (m_regdata[0x0c] << 8); }
uint32_t envelope_continue() const { return bitfield(m_regdata[0x0d], 3); }
uint32_t envelope_attack() const { return bitfield(m_regdata[0x0d], 2); }
uint32_t envelope_alternate() const { return bitfield(m_regdata[0x0d], 1); }
uint32_t envelope_hold() const { return bitfield(m_regdata[0x0d], 0); }
uint32_t io_a_data() const { return m_regdata[0x0e]; }
uint32_t io_b_data() const { return m_regdata[0x0f]; }
// per-channel registers
uint32_t ch_noise_enable_n(uint32_t choffs) const { return bitfield(m_regdata[0x07], 3 + choffs); }
uint32_t ch_tone_enable_n(uint32_t choffs) const { return bitfield(m_regdata[0x07], 0 + choffs); }
uint32_t ch_tone_period(uint32_t choffs) const { return m_regdata[0x00 + 2 * choffs] | (bitfield(m_regdata[0x01 + 2 * choffs], 0, 4) << 8); }
uint32_t ch_envelope_enable(uint32_t choffs) const { return bitfield(m_regdata[0x08 + choffs], 4); }
uint32_t ch_amplitude(uint32_t choffs) const { return bitfield(m_regdata[0x08 + choffs], 0, 4); }
private:
// internal state
uint8_t m_regdata[REGISTERS]; // register data
};
// ======================> ssg_engine
class ssg_engine
{
public:
static constexpr int OUTPUTS = ssg_registers::OUTPUTS;
static constexpr int CHANNELS = ssg_registers::CHANNELS;
static constexpr int CLOCK_DIVIDER = 8;
using output_data = ymfm_output<OUTPUTS>;
// constructor
ssg_engine(ymfm_interface &intf);
// configure an override
void override(ssg_override &override) { m_override = &override; }
// reset our status
void reset();
// save/restore
void save_restore(ymfm_saved_state &state);
// master clocking function
void clock();
// compute sum of channel outputs
void output(output_data &output);
// read/write to the SSG registers
uint8_t read(uint32_t regnum);
void write(uint32_t regnum, uint8_t data);
// return a reference to our interface
ymfm_interface &intf() { return m_intf; }
// return a reference to our registers
ssg_registers ®s() { return m_regs; }
// true if we are overridden
bool overridden() const { return (m_override != nullptr); }
// indicate the prescale has changed
void prescale_changed() { if (m_override != nullptr) m_override->ssg_prescale_changed(); }
private:
// internal state
ymfm_interface &m_intf; // reference to the interface
uint32_t m_tone_count[3]; // current tone counter
uint32_t m_tone_state[3]; // current tone state
uint32_t m_envelope_count; // envelope counter
uint32_t m_envelope_state; // envelope state
uint32_t m_noise_count; // current noise counter
uint32_t m_noise_state; // current noise state
ssg_registers m_regs; // registers
ssg_override *m_override; // override interface
};
}
#endif // YMFM_SSG_H
|