libsidplayfp  0.3.5
WaveformGenerator.h
1 /*
2  * This file is part of reSID, a MOS6581 SID emulator engine.
3  * Copyright (C) 2004 Dag Lem <resid@nimrod.no>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * @author Ken Händel
20  *
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 
43 
44 private:
45  array<short>* model_wave;
46 
47  // PWout = (PWn/40.95)%
48  int pw;
49 
50  int shift_register;
51 
52  // Remaining time to fully reset shift register.
53  int shift_register_reset;
54  // Emulation of pipeline causing bit 19 to clock the shift register.
55  int shift_pipeline;
56 
57  int ring_msb_mask;
58  int no_noise;
59  int noise_output;
60  int no_noise_or_noise_output;
61  int no_pulse;
62  int pulse_output;
63 
67  int waveform;
68 
69  int floating_output_ttl;
70 
71  short* wave;
72 
73  int waveform_output;
74 
76  int accumulator;
77 
78  // Fout = (Fn*Fclk/16777216)Hz
79  int freq;
80 
84  bool test;
85  bool sync;
86 
87  // Tell whether the accumulator MSB was set high on this cycle.
88  bool msb_rising;
89 
90  short dac[4096];
91 
92 private:
93  void clock_shift_register();
94 
95  void write_shift_register();
96 
97  void reset_shift_register();
98 
99  void set_noise_output();
100 
101 public:
102  void setWaveformModels(array<short>* models);
103 
111  void setChipModel(const ChipModel chipModel);
112 
116  void clock();
117 
125  void synchronize(WaveformGenerator* syncDest, const WaveformGenerator* syncSource) const;
126 
131  model_wave(0),
132  pw(0),
133  shift_register(0),
134  shift_register_reset(0),
135  shift_pipeline(0),
136  ring_msb_mask(0),
137  no_noise(0),
138  noise_output(0),
139  no_noise_or_noise_output(no_noise | noise_output),
140  no_pulse(0),
141  pulse_output(0),
142  waveform(0),
143  floating_output_ttl(0),
144  wave(0),
145  waveform_output(0),
146  accumulator(0),
147  freq(0),
148  test(false),
149  sync(false),
150  msb_rising(false) {}
151 
157  void writeFREQ_LO(const unsigned char freq_lo);
158 
164  void writeFREQ_HI(const unsigned char freq_hi);
165 
173  void writePW_LO(const unsigned char pw_lo);
174 
180  void writePW_HI(const unsigned char pw_hi);
181 
188  void writeCONTROL_REG(const unsigned char control);
189 
193  void reset();
194 
201  short output(const WaveformGenerator* ringModulator);
202 
209  unsigned char readOSC() { return (unsigned char) (waveform_output >> 4); }
210 
214  int readAccumulator() const { return accumulator; }
215 
219  int readFreq() const { return freq; }
220 
224  bool readTest() const { return test; }
225 
229  bool readSync() const { return sync; }
230 };
231 
232 } // namespace reSIDfp
233 
234 #if RESID_INLINING || defined(WAVEFORMGENERATOR_CPP)
235 
236 namespace reSIDfp
237 {
238 
239 RESID_INLINE
241  if (test) {
242  if (shift_register_reset != 0 && -- shift_register_reset == 0) {
243  reset_shift_register();
244  }
245 
246  // The test bit sets pulse high.
247  pulse_output = 0xfff;
248  } else {
249  // Calculate new accumulator value;
250  const int accumulator_next = (accumulator + freq) & 0xffffff;
251  const int accumulator_bits_set = ~accumulator & accumulator_next;
252  accumulator = accumulator_next;
253 
254  // Check whether the MSB is set high. This is used for synchronization.
255  msb_rising = (accumulator_bits_set & 0x800000) != 0;
256 
257  // Shift noise register once for each time accumulator bit 19 is set high.
258  // The shift is delayed 2 cycles.
259  if ((accumulator_bits_set & 0x080000) != 0) {
260  // Pipeline: Detect rising bit, shift phase 1, shift phase 2.
261  shift_pipeline = 2;
262  }
263  else if (shift_pipeline != 0 && -- shift_pipeline == 0) {
264  clock_shift_register();
265  }
266  }
267 }
268 
269 RESID_INLINE
270 short WaveformGenerator::output(const WaveformGenerator* ringModulator) {
271  // Set output value.
272  if (waveform != 0) {
273  // The bit masks no_pulse and no_noise are used to achieve branch-free
274  // calculation of the output value.
275  const int ix = (accumulator ^ (ringModulator->accumulator & ring_msb_mask)) >> 12;
276  waveform_output = wave[ix] & (no_pulse | pulse_output) & no_noise_or_noise_output;
277  if (waveform > 0x8) {
278  // Combined waveforms write to the shift register.
279  write_shift_register();
280  }
281  } else {
282  // Age floating DAC input.
283  if (floating_output_ttl != 0 && -- floating_output_ttl == 0) {
284  waveform_output = 0;
285  }
286  }
287 
288  // The pulse level is defined as (accumulator >> 12) >= pw ? 0xfff : 0x000.
289  // The expression -((accumulator >> 12) >= pw) & 0xfff yields the same
290  // results without any branching (and thus without any pipeline stalls).
291  // NB! This expression relies on that the result of a boolean expression
292  // is either 0 or 1, and furthermore requires two's complement integer.
293  // A few more cycles may be saved by storing the pulse width left shifted
294  // 12 bits, and dropping the and with 0xfff (this is valid since pulse is
295  // used as a bit mask on 12 bit values), yielding the expression
296  // -(accumulator >= pw24). However this only results in negligible savings.
297 
298  // The result of the pulse width compare is delayed one cycle.
299  // Push next pulse level into pulse level pipeline.
300  pulse_output = ((accumulator >> 12) >= pw) ? 0xfff : 0x000;
301 
302  // DAC imperfections are emulated by using waveform_output as an index
303  // into a DAC lookup table. readOSC() uses waveform_output directly.
304  return dac[waveform_output];
305 }
306 
307 } // namespace reSIDfp
308 
309 #endif
310 
311 #endif