openMSX
YMF262.hh
Go to the documentation of this file.
1#ifndef YMF262_HH
2#define YMF262_HH
3
5
6#include "EmuTimer.hh"
7
8#include "EmuTime.hh"
9#include "FixedPoint.hh"
10#include "IRQHelper.hh"
11#include "SimpleDebuggable.hh"
12#include "serialize_meta.hh"
13
14#include <array>
15#include <cstdint>
16#include <memory>
17#include <span>
18#include <string>
19
20namespace openmsx {
21
22class DeviceConfig;
23
24class YMF262 final : private ResampledSoundDevice, private EmuTimerCallback
25{
26public:
27 // sin-wave entries
28 static constexpr int SIN_BITS = 10;
29 static constexpr int SIN_LEN = 1 << SIN_BITS;
30 static constexpr int SIN_MASK = SIN_LEN - 1;
31
32public:
33 YMF262(const std::string& name, const DeviceConfig& config,
34 bool isYMF278);
35 ~YMF262();
36
37 void reset(EmuTime::param time);
38 void writeReg (unsigned r, uint8_t v, EmuTime::param time);
39 void writeReg512(unsigned r, uint8_t v, EmuTime::param time);
40 [[nodiscard]] uint8_t readReg(unsigned reg) const;
41 [[nodiscard]] uint8_t peekReg(unsigned reg) const;
42 [[nodiscard]] uint8_t readStatus();
43 [[nodiscard]] uint8_t peekStatus() const;
44
45 void setMixLevel(uint8_t x, EmuTime::param time);
46
47 template<typename Archive>
48 void serialize(Archive& ar, unsigned version);
49
50public:
53
57
58private:
59 class Channel;
60
61 class Slot {
62 public:
63 Slot();
64 [[nodiscard]] int op_calc(unsigned phase, unsigned lfo_am) const;
65 void FM_KEYON(uint8_t key_set);
66 void FM_KEYOFF(uint8_t key_clr);
67 void advanceEnvelopeGenerator(unsigned egCnt);
68 void advancePhaseGenerator(Channel& ch, unsigned lfo_pm);
69 void update_ar_dr();
70 void update_rr();
71 void calc_fc(const Channel& ch);
72
75 void setFeedbackShift(uint8_t value) {
76 fb_shift = value ? 9 - value : 0;
77 }
78
79 template<typename Archive>
80 void serialize(Archive& ar, unsigned version);
81
82 // Phase Generator
83 FreqIndex Cnt{0}; // frequency counter
84 FreqIndex Incr{0}; // frequency counter step
85 int* connect{nullptr}; // slot output pointer
86 std::array<int, 2> op1_out{0, 0}; // slot1 output for feedback
87
88 // Envelope Generator
89 unsigned TL{0}; // total level: TL << 2
90 unsigned TLL{0}; // adjusted now TL
91 int volume{0}; // envelope counter
92 int sl{0}; // sustain level: sl_tab[SL]
93
94 std::span<const unsigned, SIN_LEN> waveTable; // waveform select
95
96 EnvelopeState state{EG_OFF}; // EG: phase type
97 unsigned eg_m_ar{0}; // (attack state)
98 unsigned eg_m_dr{0}; // (decay state)
99 unsigned eg_m_rr{0}; // (release state)
100 uint8_t eg_sh_ar{0}; // (attack state)
101 uint8_t eg_sel_ar{0}; // (attack state)
102 uint8_t eg_sh_dr{0}; // (decay state)
103 uint8_t eg_sel_dr{0}; // (decay state)
104 uint8_t eg_sh_rr{0}; // (release state)
105 uint8_t eg_sel_rr{0}; // (release state)
106
107 uint8_t key{0}; // 0 = KEY OFF, >0 = KEY ON
108
109 uint8_t fb_shift{0}; // PG: feedback shift value
110 bool CON{false}; // PG: connection (algorithm) type
111 bool eg_type{false}; // EG: percussive/non-percussive mode
112
113 // LFO
114 uint8_t AMmask{0}; // LFO Amplitude Modulation enable mask
115 bool vib{false}; // LFO Phase Modulation enable flag (active high)
116
117 uint8_t ar{0}; // attack rate: AR<<2
118 uint8_t dr{0}; // decay rate: DR<<2
119 uint8_t rr{0}; // release rate:RR<<2
120 uint8_t KSR{0}; // key scale rate
121 uint8_t ksl{0}; // key scale level
122 uint8_t ksr{0}; // key scale rate: kcode>>KSR
123 uint8_t mul{0}; // multiple: mul_tab[ML]
124 };
125
126 class Channel {
127 public:
128 void chan_calc(unsigned lfo_am);
129 void chan_calc_ext(unsigned lfo_am);
130
131 template<typename Archive>
132 void serialize(Archive& ar, unsigned version);
133
134 std::array<Slot, 2> slot;
135
136 int block_fnum{0}; // block+fnum
137 FreqIndex fc{0}; // Freq. Increment base
138 unsigned ksl_base{0}; // KeyScaleLevel Base step
139 uint8_t kcode{0}; // key code (for key scaling)
140
141 // there are 12 2-operator channels which can be combined in pairs
142 // to form six 4-operator channel, they are:
143 // 0 and 3,
144 // 1 and 4,
145 // 2 and 5,
146 // 9 and 12,
147 // 10 and 13,
148 // 11 and 14
149 bool extended{false}; // set if this channel forms up a 4op channel with
150 // another channel (only used by first of pair of
151 // channels, ie 0,1,2 and 9,10,11)
152 };
153
154 // SoundDevice
155 [[nodiscard]] float getAmplificationFactorImpl() const override;
156 void generateChannels(std::span<float*> bufs, unsigned num) override;
157
158 void callback(uint8_t flag) override;
159
160 void writeRegDirect(unsigned r, uint8_t v, EmuTime::param time);
161 void init_tables();
162 void setStatus(uint8_t flag);
163 void resetStatus(uint8_t flag);
164 void changeStatusMask(uint8_t flag);
165 void advance();
166
167 [[nodiscard]] unsigned genPhaseHighHat();
168 [[nodiscard]] unsigned genPhaseSnare();
169 [[nodiscard]] unsigned genPhaseCymbal();
170
171 void chan_calc_rhythm(unsigned lfo_am);
172 void set_mul(unsigned sl, uint8_t v);
173 void set_ksl_tl(unsigned sl, uint8_t v);
174 void set_ar_dr(unsigned sl, uint8_t v);
175 void set_sl_rr(unsigned sl, uint8_t v);
176 [[nodiscard]] bool checkMuteHelper() const;
177
178 [[nodiscard]] bool isExtended(unsigned ch) const;
179 [[nodiscard]] Channel& getFirstOfPair(unsigned ch);
180 [[nodiscard]] Channel& getSecondOfPair(unsigned ch);
181
182 struct Debuggable final : SimpleDebuggable {
183 Debuggable(MSXMotherBoard& motherBoard, const std::string& name);
184 [[nodiscard]] uint8_t read(unsigned address) override;
185 void write(unsigned address, uint8_t value, EmuTime::param time) override;
186 } debuggable;
187
188 // Bitmask for register 0x04
189 static constexpr int R04_ST1 = 0x01; // Timer1 Start
190 static constexpr int R04_ST2 = 0x02; // Timer2 Start
191 static constexpr int R04_MASK_T2 = 0x20; // Mask Timer2 flag
192 static constexpr int R04_MASK_T1 = 0x40; // Mask Timer1 flag
193 static constexpr int R04_IRQ_RESET = 0x80; // IRQ RESET
194
195 // Bitmask for status register
196 static constexpr int STATUS_T2 = R04_MASK_T2;
197 static constexpr int STATUS_T1 = R04_MASK_T1;
198 // Timers (see EmuTimer class for details about timing)
199 const std::unique_ptr<EmuTimer> timer1; // 80.8us OPL4 ( 80.5us OPL3)
200 const std::unique_ptr<EmuTimer> timer2; // 323.1us OPL4 (321.8us OPL3)
201
202 IRQHelper irq;
203
204 std::array<int, 18> chanOut = {}; // 18 channels
205
206 std::array<uint8_t, 512> reg = {};
207 std::array<Channel, 18> channel; // OPL3 chips have 18 channels
208
209 std::array<int, 18 * 4> pan; // channels output masks 4 per channel
210 // 0xffffffff = enable
211 unsigned eg_cnt{0}; // global envelope generator counter
212 unsigned noise_rng{1}; // 23 bit noise shift register
213
214 // LFO
215 using LFOAMIndex = FixedPoint< 6>;
216 using LFOPMIndex = FixedPoint<10>;
217 LFOAMIndex lfo_am_cnt{0};
218 LFOPMIndex lfo_pm_cnt{0};
219 bool lfo_am_depth{false};
220 uint8_t lfo_pm_depth_range{0};
221
222 uint8_t rhythm{0}; // Rhythm mode
223 bool nts{false}; // NTS (note select)
224 bool OPL3_mode{false}; // OPL3 extension enable flag
225
226 uint8_t status{0}; // status flag
227 uint8_t status2{0};
228 uint8_t statusMask{0}; // status mask
229
230 bool alreadySignaledNEW2{false};
231 const bool isYMF278; // true iff this is actually a YMF278
232 // ATM only used for NEW2 bit
233};
235
236} // namespace openmsx
237
238#endif
Debuggable(const Debuggable &)=delete
virtual byte read(unsigned address, EmuTime::param time)
void write(unsigned address, byte value) override
static constexpr int SIN_LEN
Definition YMF262.hh:29
uint8_t readReg(unsigned reg) const
Definition YMF262.cc:1023
void reset(EmuTime::param time)
Definition YMF262.cc:1396
uint8_t peekStatus() const
Definition YMF262.cc:1480
void setMixLevel(uint8_t x, EmuTime::param time)
Definition YMF262.cc:1500
uint8_t readStatus()
Definition YMF262.cc:1472
static constexpr int SIN_BITS
Definition YMF262.hh:28
static constexpr int SIN_MASK
Definition YMF262.hh:30
FixedPoint< 16 > FreqIndex
16.16 fixed point type for frequency calculations
Definition YMF262.hh:52
void serialize(Archive &ar, unsigned version)
Definition YMF262.cc:1661
void writeReg(unsigned r, uint8_t v, EmuTime::param time)
Definition YMF262.cc:1034
uint8_t peekReg(unsigned reg) const
Definition YMF262.cc:1029
void writeReg512(unsigned r, uint8_t v, EmuTime::param time)
Definition YMF262.cc:1042
This file implemented 3 utility functions:
Definition Autofire.cc:11
void serialize(Archive &ar, T &t, unsigned version)
IntHelper< IRQSource > IRQHelper
Definition IRQHelper.hh:122
#define SERIALIZE_CLASS_VERSION(CLASS, VERSION)