libsidplayfp 1.8.8
WaveformGenerator.h
1/*
2 * This file is part of libsidplayfp, a SID player engine.
3 *
4 * Copyright 2011-2013 Leandro Nini <drfiemost@users.sourceforge.net>
5 * Copyright 2007-2010 Antti Lankila
6 * Copyright 2004,2010 Dag Lem <resid@nimrod.no>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#ifndef WAVEFORMGENERATOR_H
24#define WAVEFORMGENERATOR_H
25
26#include "siddefs-fp.h"
27#include "array.h"
28
29namespace reSIDfp
30{
31
87{
88private:
89 matrix_t* model_wave;
90
91 short* wave;
92
93 // PWout = (PWn/40.95)%
94 int pw;
95
96 unsigned int shift_register;
97
99 int shift_register_reset;
100
102 int shift_pipeline;
103
104 int ring_msb_mask;
105 int no_noise;
106 int noise_output;
107 int no_noise_or_noise_output;
108 int no_pulse;
109 int pulse_output;
110
112 int waveform;
113
114 int floating_output_ttl;
115
116 int waveform_output;
117
119 int accumulator;
120
121 // Fout = (Fn*Fclk/16777216)Hz
122 int freq;
123
125
126 bool test;
127 bool sync;
129
131 bool msb_rising;
132
133 short dac[4096];
134
135private:
136 void clock_shift_register();
137
138 void write_shift_register();
139
140 void reset_shift_register();
141
142 void set_noise_output();
143
144public:
145 void setWaveformModels(matrix_t* models);
146
154 void setChipModel(ChipModel chipModel);
155
159 void clock();
160
169 void synchronize(WaveformGenerator* syncDest, const WaveformGenerator* syncSource) const;
170
175 model_wave(0),
176 wave(0),
177 pw(0),
178 shift_register(0),
179 shift_register_reset(0),
180 shift_pipeline(0),
181 ring_msb_mask(0),
182 no_noise(0),
183 noise_output(0),
184 no_noise_or_noise_output(no_noise | noise_output),
185 no_pulse(0),
186 pulse_output(0),
187 waveform(0),
188 floating_output_ttl(0),
189 waveform_output(0),
190 accumulator(0),
191 freq(0),
192 test(false),
193 sync(false),
194 msb_rising(false) {}
195
201 void writeFREQ_LO(unsigned char freq_lo) { freq = (freq & 0xff00) | (freq_lo & 0xff); }
202
208 void writeFREQ_HI(unsigned char freq_hi) { freq = (freq_hi << 8 & 0xff00) | (freq & 0xff); }
209
218 void writePW_LO(unsigned char pw_lo) { pw = (pw & 0xf00) | (pw_lo & 0x0ff); }
219
225 void writePW_HI(unsigned char pw_hi) { pw = (pw_hi << 8 & 0xf00) | (pw & 0x0ff); }
226
232 void writeCONTROL_REG(unsigned char control);
233
237 void reset();
238
246 short output(const WaveformGenerator* ringModulator);
247
251 unsigned char readOSC() const { return (unsigned char)(waveform_output >> 4); }
252
256 int readAccumulator() const { return accumulator; }
257
261 int readFreq() const { return freq; }
262
266 bool readTest() const { return test; }
267
271 bool readSync() const { return sync; }
272};
273
274} // namespace reSIDfp
275
276#if RESID_INLINING || defined(WAVEFORMGENERATOR_CPP)
277
278namespace reSIDfp
279{
280
281RESID_INLINE
283{
284 if (unlikely(test))
285 {
286 if (unlikely(shift_register_reset != 0) && unlikely(--shift_register_reset == 0))
287 {
288 reset_shift_register();
289 }
290
291 // The test bit sets pulse high.
292 pulse_output = 0xfff;
293 }
294 else
295 {
296 // Calculate new accumulator value;
297 const int accumulator_next = (accumulator + freq) & 0xffffff;
298 const int accumulator_bits_set = ~accumulator & accumulator_next;
299 accumulator = accumulator_next;
300
301 // Check whether the MSB is set high. This is used for synchronization.
302 msb_rising = (accumulator_bits_set & 0x800000) != 0;
303
304 // Shift noise register once for each time accumulator bit 19 is set high.
305 // The shift is delayed 2 cycles.
306 if (unlikely((accumulator_bits_set & 0x080000) != 0))
307 {
308 // Pipeline: Detect rising bit, shift phase 1, shift phase 2.
309 shift_pipeline = 2;
310 }
311 else if (unlikely(shift_pipeline != 0) && --shift_pipeline == 0)
312 {
313 clock_shift_register();
314 }
315 }
316}
317
318RESID_INLINE
320{
321 // Set output value.
322 if (likely(waveform != 0))
323 {
324 // The bit masks no_pulse and no_noise are used to achieve branch-free
325 // calculation of the output value.
326 const int ix = (accumulator ^ (ringModulator->accumulator & ring_msb_mask)) >> 12;
327 waveform_output = wave[ix] & (no_pulse | pulse_output) & no_noise_or_noise_output;
328
329 if (unlikely(waveform > 0x8))
330 {
331 // Combined waveforms that include noise
332 // write to the shift register.
333 write_shift_register();
334 }
335 }
336 else
337 {
338 // Age floating DAC input.
339 if (likely(floating_output_ttl != 0) && unlikely(--floating_output_ttl == 0))
340 {
341 waveform_output = 0;
342 }
343 }
344
345 // The pulse level is defined as (accumulator >> 12) >= pw ? 0xfff : 0x000.
346 // The expression -((accumulator >> 12) >= pw) & 0xfff yields the same
347 // results without any branching (and thus without any pipeline stalls).
348 // NB! This expression relies on that the result of a boolean expression
349 // is either 0 or 1, and furthermore requires two's complement integer.
350 // A few more cycles may be saved by storing the pulse width left shifted
351 // 12 bits, and dropping the and with 0xfff (this is valid since pulse is
352 // used as a bit mask on 12 bit values), yielding the expression
353 // -(accumulator >= pw24). However this only results in negligible savings.
354
355 // The result of the pulse width compare is delayed one cycle.
356 // Push next pulse level into pulse level pipeline.
357 pulse_output = ((accumulator >> 12) >= pw) ? 0xfff : 0x000;
358
359 // DAC imperfections are emulated by using waveform_output as an index
360 // into a DAC lookup table. readOSC() uses waveform_output directly.
361 return dac[waveform_output];
362}
363
364} // namespace reSIDfp
365
366#endif
367
368#endif
Definition: array.h:42
Definition: WaveformGenerator.h:87
void synchronize(WaveformGenerator *syncDest, const WaveformGenerator *syncSource) const
Definition: WaveformGenerator.cpp:124
bool readTest() const
Definition: WaveformGenerator.h:266
int readAccumulator() const
Definition: WaveformGenerator.h:256
void clock()
Definition: WaveformGenerator.h:282
void writePW_HI(unsigned char pw_hi)
Definition: WaveformGenerator.h:225
void writeFREQ_HI(unsigned char freq_hi)
Definition: WaveformGenerator.h:208
int readFreq() const
Definition: WaveformGenerator.h:261
void writePW_LO(unsigned char pw_lo)
Definition: WaveformGenerator.h:218
unsigned char readOSC() const
Definition: WaveformGenerator.h:251
void writeFREQ_LO(unsigned char freq_lo)
Definition: WaveformGenerator.h:201
void writeCONTROL_REG(unsigned char control)
Definition: WaveformGenerator.cpp:135
WaveformGenerator()
Definition: WaveformGenerator.h:174
void setChipModel(ChipModel chipModel)
Definition: WaveformGenerator.cpp:96
short output(const WaveformGenerator *ringModulator)
Definition: WaveformGenerator.h:319
bool readSync() const
Definition: WaveformGenerator.h:271
void reset()
Definition: WaveformGenerator.cpp:202