libsidplayfp  1.0.3
WaveformGenerator.h
00001 /*
00002  * This file is part of libsidplayfp, a SID player engine.
00003  *
00004  * Copyright 2011-2013 Leandro Nini <drfiemost@users.sourceforge.net>
00005  * Copyright 2007-2010 Antti Lankila
00006  * Copyright 2004 Dag Lem <resid@nimrod.no>
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00021  */
00022 
00023 #ifndef WAVEFORMGENERATOR_H
00024 #define WAVEFORMGENERATOR_H
00025 
00026 #include "siddefs-fp.h"
00027 #include "array.h"
00028 
00029 namespace reSIDfp
00030 {
00031 
00046 class WaveformGenerator
00047 {
00048 private:
00049     array<short>* model_wave;
00050 
00051     // PWout = (PWn/40.95)%
00052     int pw;
00053 
00054     int shift_register;
00055 
00059     int shift_register_reset;
00060 
00064     int shift_pipeline;
00065 
00066     int ring_msb_mask;
00067     int no_noise;
00068     int noise_output;
00069     int no_noise_or_noise_output;
00070     int no_pulse;
00071     int pulse_output;
00072 
00076     int waveform;
00077 
00078     int floating_output_ttl;
00079 
00080     short* wave;
00081 
00082     int waveform_output;
00083 
00085     int accumulator;
00086 
00087     // Fout  = (Fn*Fclk/16777216)Hz
00088     int freq;
00089 
00093     bool test;
00094     bool sync;
00095 
00099     bool msb_rising;
00100 
00101     short dac[4096];
00102 
00103 private:
00104     void clock_shift_register();
00105 
00106     void write_shift_register();
00107 
00108     void reset_shift_register();
00109 
00110     void set_noise_output();
00111 
00112 public:
00113     void setWaveformModels(array<short>* models);
00114 
00122     void setChipModel(ChipModel chipModel);
00123 
00127     void clock();
00128 
00137     void synchronize(WaveformGenerator* syncDest, const WaveformGenerator* syncSource) const;
00138 
00142     WaveformGenerator() :
00143         model_wave(0),
00144         pw(0),
00145         shift_register(0),
00146         shift_register_reset(0),
00147         shift_pipeline(0),
00148         ring_msb_mask(0),
00149         no_noise(0),
00150         noise_output(0),
00151         no_noise_or_noise_output(no_noise | noise_output),
00152         no_pulse(0),
00153         pulse_output(0),
00154         waveform(0),
00155         floating_output_ttl(0),
00156         wave(0),
00157         waveform_output(0),
00158         accumulator(0),
00159         freq(0),
00160         test(false),
00161         sync(false),
00162         msb_rising(false) {}
00163 
00169     void writeFREQ_LO(unsigned char freq_lo) { freq = (freq & 0xff00) | (freq_lo & 0xff); }
00170 
00176     void writeFREQ_HI(unsigned char freq_hi) { freq = (freq_hi << 8 & 0xff00) | (freq & 0xff); }
00177 
00186     void writePW_LO(unsigned char pw_lo) { pw = (pw & 0xf00) | (pw_lo & 0x0ff); }
00187 
00193     void writePW_HI(unsigned char pw_hi) { pw = (pw_hi << 8 & 0xf00) | (pw & 0x0ff); }
00194 
00200     void writeCONTROL_REG(unsigned char control);
00201 
00205     void reset();
00206 
00213     short output(const WaveformGenerator* ringModulator);
00214 
00220     unsigned char readOSC() const { return (unsigned char)(waveform_output >> 4); }
00221 
00225     int readAccumulator() const { return accumulator; }
00226 
00230     int readFreq() const { return freq; }
00231 
00235     bool readTest() const { return test; }
00236 
00240     bool readSync() const { return sync; }
00241 };
00242 
00243 } // namespace reSIDfp
00244 
00245 #if RESID_INLINING || defined(WAVEFORMGENERATOR_CPP)
00246 
00247 namespace reSIDfp
00248 {
00249 
00250 RESID_INLINE
00251 void WaveformGenerator::clock()
00252 {
00253     if (test)
00254     {
00255         if (shift_register_reset != 0 && -- shift_register_reset == 0)
00256         {
00257             reset_shift_register();
00258         }
00259 
00260         // The test bit sets pulse high.
00261         pulse_output = 0xfff;
00262     }
00263     else
00264     {
00265         // Calculate new accumulator value;
00266         const int accumulator_next = (accumulator + freq) & 0xffffff;
00267         const int accumulator_bits_set = ~accumulator & accumulator_next;
00268         accumulator = accumulator_next;
00269 
00270         // Check whether the MSB is set high. This is used for synchronization.
00271         msb_rising = (accumulator_bits_set & 0x800000) != 0;
00272 
00273         // Shift noise register once for each time accumulator bit 19 is set high.
00274         // The shift is delayed 2 cycles.
00275         if ((accumulator_bits_set & 0x080000) != 0)
00276         {
00277             // Pipeline: Detect rising bit, shift phase 1, shift phase 2.
00278             shift_pipeline = 2;
00279         }
00280         else if (shift_pipeline != 0 && -- shift_pipeline == 0)
00281         {
00282             clock_shift_register();
00283         }
00284     }
00285 }
00286 
00287 RESID_INLINE
00288 short WaveformGenerator::output(const WaveformGenerator* ringModulator)
00289 {
00290     // Set output value.
00291     if (waveform != 0)
00292     {
00293         // The bit masks no_pulse and no_noise are used to achieve branch-free
00294         // calculation of the output value.
00295         const int ix = (accumulator ^ (ringModulator->accumulator & ring_msb_mask)) >> 12;
00296         waveform_output = wave[ix] & (no_pulse | pulse_output) & no_noise_or_noise_output;
00297 
00298         if (waveform > 0x8)
00299         {
00300             // Combined waveforms write to the shift register.
00301             write_shift_register();
00302         }
00303     }
00304     else
00305     {
00306         // Age floating DAC input.
00307         if (floating_output_ttl != 0 && -- floating_output_ttl == 0)
00308         {
00309             waveform_output = 0;
00310         }
00311     }
00312 
00313     // The pulse level is defined as (accumulator >> 12) >= pw ? 0xfff : 0x000.
00314     // The expression -((accumulator >> 12) >= pw) & 0xfff yields the same
00315     // results without any branching (and thus without any pipeline stalls).
00316     // NB! This expression relies on that the result of a boolean expression
00317     // is either 0 or 1, and furthermore requires two's complement integer.
00318     // A few more cycles may be saved by storing the pulse width left shifted
00319     // 12 bits, and dropping the and with 0xfff (this is valid since pulse is
00320     // used as a bit mask on 12 bit values), yielding the expression
00321     // -(accumulator >= pw24). However this only results in negligible savings.
00322 
00323     // The result of the pulse width compare is delayed one cycle.
00324     // Push next pulse level into pulse level pipeline.
00325     pulse_output = ((accumulator >> 12) >= pw) ? 0xfff : 0x000;
00326 
00327     // DAC imperfections are emulated by using waveform_output as an index
00328     // into a DAC lookup table. readOSC() uses waveform_output directly.
00329     return dac[waveform_output];
00330 }
00331 
00332 } // namespace reSIDfp
00333 
00334 #endif
00335 
00336 #endif