143 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			143 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * This file is part of libsidplayfp, a SID player engine. | ||
|  |  * | ||
|  |  * Copyright 2011-2022 Leandro Nini <drfiemost@users.sourceforge.net> | ||
|  |  * Copyright 2007-2010 Antti Lankila | ||
|  |  * Copyright 2004, 2010 Dag Lem <resid@nimrod.no> | ||
|  |  * | ||
|  |  * This program is free software; you can redistribute it and/or modify | ||
|  |  * it under the terms of the GNU General Public License as published by | ||
|  |  * the Free Software Foundation; either version 2 of the License, or | ||
|  |  * (at your option) any later version. | ||
|  |  * | ||
|  |  * This program is distributed in the hope that it will be useful, | ||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||
|  |  * GNU General Public License for more details. | ||
|  |  * | ||
|  |  * You should have received a copy of the GNU General Public License | ||
|  |  * along with this program; if not, write to the Free Software | ||
|  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | ||
|  |  */ | ||
|  | 
 | ||
|  | #ifndef INTEGRATOR8580_H
 | ||
|  | #define INTEGRATOR8580_H
 | ||
|  | 
 | ||
|  | #include "FilterModelConfig8580.h"
 | ||
|  | 
 | ||
|  | #include <stdint.h>
 | ||
|  | #include <cassert>
 | ||
|  | 
 | ||
|  | #include "siddefs-fp.h"
 | ||
|  | 
 | ||
|  | namespace reSIDfp | ||
|  | { | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * 8580 integrator | ||
|  |  * | ||
|  |  *                   +---C---+ | ||
|  |  *                   |       | | ||
|  |  *     vi -----Rfc---o--[A>--o-- vo | ||
|  |  *                   vx | ||
|  |  * | ||
|  |  *     IRfc + ICr = 0 | ||
|  |  *     IRfc + C*(vc - vc0)/dt = 0 | ||
|  |  *     dt/C*(IRfc) + vc - vc0 = 0 | ||
|  |  *     vc = vc0 - n*(IRfc(vi,vx)) | ||
|  |  *     vc = vc0 - n*(IRfc(vi,g(vc))) | ||
|  |  * | ||
|  |  * IRfc = K*W/L*(Vgst^2 - Vgdt^2) = n*((Vddt - vx)^2 - (Vddt - vi)^2) | ||
|  |  * | ||
|  |  * Rfc gate voltage is generated by an OP Amp and depends on chip temperature. | ||
|  |  */ | ||
|  | class Integrator8580 | ||
|  | { | ||
|  | private: | ||
|  |     mutable int vx; | ||
|  |     mutable int vc; | ||
|  | 
 | ||
|  |     unsigned short nVgt; | ||
|  |     unsigned short n_dac; | ||
|  | 
 | ||
|  |     const FilterModelConfig8580* fmc; | ||
|  | 
 | ||
|  | public: | ||
|  |     Integrator8580(const FilterModelConfig8580* fmc) : | ||
|  |         vx(0), | ||
|  |         vc(0), | ||
|  |         fmc(fmc) | ||
|  |     { | ||
|  |         setV(1.5); | ||
|  |     } | ||
|  | 
 | ||
|  |     /**
 | ||
|  |      * Set Filter Cutoff resistor ratio. | ||
|  |      */ | ||
|  |     void setFc(double wl) | ||
|  |     { | ||
|  |         // Normalized current factor, 1 cycle at 1MHz.
 | ||
|  |         // Fit in 5 bits.
 | ||
|  |         n_dac = fmc->getNormalizedCurrentFactor(wl); | ||
|  |     } | ||
|  | 
 | ||
|  |     /**
 | ||
|  |      * Set FC gate voltage multiplier. | ||
|  |      */ | ||
|  |     void setV(double v) | ||
|  |     { | ||
|  |         // Gate voltage is controlled by the switched capacitor voltage divider
 | ||
|  |         // Ua = Ue * v = 4.76v  1<v<2
 | ||
|  |         assert(v > 1.0 && v < 2.0); | ||
|  |         const double Vg = fmc->getVoiceDCVoltage() * v; | ||
|  |         const double Vgt = Vg - fmc->getVth(); | ||
|  | 
 | ||
|  |         // Vg - Vth, normalized so that translated values can be subtracted:
 | ||
|  |         // Vgt - x = (Vgt - t) - (x - t)
 | ||
|  |         nVgt = fmc->getNormalizedValue(Vgt); | ||
|  |     } | ||
|  | 
 | ||
|  |     int solve(int vi) const; | ||
|  | }; | ||
|  | 
 | ||
|  | } // namespace reSIDfp
 | ||
|  | 
 | ||
|  | #if RESID_INLINING || defined(INTEGRATOR8580_CPP)
 | ||
|  | 
 | ||
|  | namespace reSIDfp | ||
|  | { | ||
|  | 
 | ||
|  | RESID_INLINE | ||
|  | int Integrator8580::solve(int vi) const | ||
|  | { | ||
|  |     // Make sure we're not in subthreshold mode
 | ||
|  |     assert(vx < nVgt); | ||
|  | 
 | ||
|  |     // DAC voltages
 | ||
|  |     const unsigned int Vgst = nVgt - vx; | ||
|  |     const unsigned int Vgdt = (vi < nVgt) ? nVgt - vi : 0;  // triode/saturation mode
 | ||
|  | 
 | ||
|  |     const unsigned int Vgst_2 = Vgst * Vgst; | ||
|  |     const unsigned int Vgdt_2 = Vgdt * Vgdt; | ||
|  | 
 | ||
|  |     // DAC current, scaled by (1/m)*2^13*m*2^16*m*2^16*2^-15 = m*2^30
 | ||
|  |     const int n_I_dac = n_dac * (static_cast<int>(Vgst_2 - Vgdt_2) >> 15); | ||
|  | 
 | ||
|  |     // Change in capacitor charge.
 | ||
|  |     vc += n_I_dac; | ||
|  | 
 | ||
|  |     // vx = g(vc)
 | ||
|  |     const int tmp = (vc >> 15) + (1 << 15); | ||
|  |     assert(tmp < (1 << 16)); | ||
|  |     vx = fmc->getOpampRev(tmp); | ||
|  | 
 | ||
|  |     // Return vo.
 | ||
|  |     return vx - (vc >> 14); | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace reSIDfp
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif
 |