libsidplayfp  1.2.2
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 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 
29 namespace reSIDfp
30 {
31 
47 {
48 private:
49  matrix_t* model_wave;
50 
51  // PWout = (PWn/40.95)%
52  int pw;
53 
54  int shift_register;
55 
59  int shift_register_reset;
60 
64  int shift_pipeline;
65 
66  int ring_msb_mask;
67  int no_noise;
68  int noise_output;
69  int no_noise_or_noise_output;
70  int no_pulse;
71  int pulse_output;
72 
76  int waveform;
77 
78  int floating_output_ttl;
79 
80  short* wave;
81 
82  int waveform_output;
83 
85  int accumulator;
86 
87  // Fout = (Fn*Fclk/16777216)Hz
88  int freq;
89 
93  bool test;
94  bool sync;
95 
99  bool msb_rising;
100 
101  short dac[4096];
102 
103 private:
104  void clock_shift_register();
105 
106  void write_shift_register();
107 
108  void reset_shift_register();
109 
110  void set_noise_output();
111 
112 public:
113  void setWaveformModels(matrix_t* models);
114 
122  void setChipModel(ChipModel chipModel);
123 
127  void clock();
128 
137  void synchronize(WaveformGenerator* syncDest, const WaveformGenerator* syncSource) const;
138 
143  model_wave(0),
144  pw(0),
145  shift_register(0),
146  shift_register_reset(0),
147  shift_pipeline(0),
148  ring_msb_mask(0),
149  no_noise(0),
150  noise_output(0),
151  no_noise_or_noise_output(no_noise | noise_output),
152  no_pulse(0),
153  pulse_output(0),
154  waveform(0),
155  floating_output_ttl(0),
156  wave(0),
157  waveform_output(0),
158  accumulator(0),
159  freq(0),
160  test(false),
161  sync(false),
162  msb_rising(false) {}
163 
169  void writeFREQ_LO(unsigned char freq_lo) { freq = (freq & 0xff00) | (freq_lo & 0xff); }
170 
176  void writeFREQ_HI(unsigned char freq_hi) { freq = (freq_hi << 8 & 0xff00) | (freq & 0xff); }
177 
186  void writePW_LO(unsigned char pw_lo) { pw = (pw & 0xf00) | (pw_lo & 0x0ff); }
187 
193  void writePW_HI(unsigned char pw_hi) { pw = (pw_hi << 8 & 0xf00) | (pw & 0x0ff); }
194 
200  void writeCONTROL_REG(unsigned char control);
201 
205  void reset();
206 
213  short output(const WaveformGenerator* ringModulator);
214 
220  unsigned char readOSC() const { return (unsigned char)(waveform_output >> 4); }
221 
225  int readAccumulator() const { return accumulator; }
226 
230  int readFreq() const { return freq; }
231 
235  bool readTest() const { return test; }
236 
240  bool readSync() const { return sync; }
241 };
242 
243 } // namespace reSIDfp
244 
245 #if RESID_INLINING || defined(WAVEFORMGENERATOR_CPP)
246 
247 namespace reSIDfp
248 {
249 
250 RESID_INLINE
252 {
253  if (test)
254  {
255  if (shift_register_reset != 0 && --shift_register_reset == 0)
256  {
257  reset_shift_register();
258  }
259 
260  // The test bit sets pulse high.
261  pulse_output = 0xfff;
262  }
263  else
264  {
265  // Calculate new accumulator value;
266  const int accumulator_next = (accumulator + freq) & 0xffffff;
267  const int accumulator_bits_set = ~accumulator & accumulator_next;
268  accumulator = accumulator_next;
269 
270  // Check whether the MSB is set high. This is used for synchronization.
271  msb_rising = (accumulator_bits_set & 0x800000) != 0;
272 
273  // Shift noise register once for each time accumulator bit 19 is set high.
274  // The shift is delayed 2 cycles.
275  if ((accumulator_bits_set & 0x080000) != 0)
276  {
277  // Pipeline: Detect rising bit, shift phase 1, shift phase 2.
278  shift_pipeline = 2;
279  }
280  else if (shift_pipeline != 0 && --shift_pipeline == 0)
281  {
282  clock_shift_register();
283  }
284  }
285 }
286 
287 RESID_INLINE
288 short WaveformGenerator::output(const WaveformGenerator* ringModulator)
289 {
290  // Set output value.
291  if (waveform != 0)
292  {
293  // The bit masks no_pulse and no_noise are used to achieve branch-free
294  // calculation of the output value.
295  const int ix = (accumulator ^ (ringModulator->accumulator & ring_msb_mask)) >> 12;
296  waveform_output = wave[ix] & (no_pulse | pulse_output) & no_noise_or_noise_output;
297 
298  if (waveform > 0x8)
299  {
300  // Combined waveforms that include noise
301  // write to the shift register.
302  write_shift_register();
303  }
304  }
305  else
306  {
307  // Age floating DAC input.
308  if (floating_output_ttl != 0 && --floating_output_ttl == 0)
309  {
310  waveform_output = 0;
311  }
312  }
313 
314  // The pulse level is defined as (accumulator >> 12) >= pw ? 0xfff : 0x000.
315  // The expression -((accumulator >> 12) >= pw) & 0xfff yields the same
316  // results without any branching (and thus without any pipeline stalls).
317  // NB! This expression relies on that the result of a boolean expression
318  // is either 0 or 1, and furthermore requires two's complement integer.
319  // A few more cycles may be saved by storing the pulse width left shifted
320  // 12 bits, and dropping the and with 0xfff (this is valid since pulse is
321  // used as a bit mask on 12 bit values), yielding the expression
322  // -(accumulator >= pw24). However this only results in negligible savings.
323 
324  // The result of the pulse width compare is delayed one cycle.
325  // Push next pulse level into pulse level pipeline.
326  pulse_output = ((accumulator >> 12) >= pw) ? 0xfff : 0x000;
327 
328  // DAC imperfections are emulated by using waveform_output as an index
329  // into a DAC lookup table. readOSC() uses waveform_output directly.
330  return dac[waveform_output];
331 }
332 
333 } // namespace reSIDfp
334 
335 #endif
336 
337 #endif
Definition: array.h:41
int readFreq() const
Definition: WaveformGenerator.h:230
void writeCONTROL_REG(unsigned char control)
Definition: WaveformGenerator.cpp:135
void writePW_LO(unsigned char pw_lo)
Definition: WaveformGenerator.h:186
void writeFREQ_LO(unsigned char freq_lo)
Definition: WaveformGenerator.h:169
unsigned char readOSC() const
Definition: WaveformGenerator.h:220
bool readTest() const
Definition: WaveformGenerator.h:235
void writeFREQ_HI(unsigned char freq_hi)
Definition: WaveformGenerator.h:176
bool readSync() const
Definition: WaveformGenerator.h:240
WaveformGenerator()
Definition: WaveformGenerator.h:142
int readAccumulator() const
Definition: WaveformGenerator.h:225
short output(const WaveformGenerator *ringModulator)
Definition: WaveformGenerator.h:288
void clock()
Definition: WaveformGenerator.h:251
void reset()
Definition: WaveformGenerator.cpp:195
void setChipModel(ChipModel chipModel)
Definition: WaveformGenerator.cpp:96
void synchronize(WaveformGenerator *syncDest, const WaveformGenerator *syncSource) const
Definition: WaveformGenerator.cpp:124
void writePW_HI(unsigned char pw_hi)
Definition: WaveformGenerator.h:193
Definition: WaveformGenerator.h:46