libsidplayfp  2.4.0
Integrator6581.h
1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  * Copyright 2011-2022 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 INTEGRATOR6581_H
24 #define INTEGRATOR6581_H
25 
26 #include "FilterModelConfig6581.h"
27 
28 #include <stdint.h>
29 #include <cassert>
30 
31 // uncomment to enable use of the slope factor
32 // in the EKV model
33 // actually produces worse results, needs investigation
34 //#define SLOPE_FACTOR
35 
36 #ifdef SLOPE_FACTOR
37 # include <cmath>
38 #endif
39 
40 #include "siddefs-fp.h"
41 
42 namespace reSIDfp
43 {
44 
168 {
169 private:
170  unsigned int nVddt_Vw_2;
171  mutable int vx;
172  mutable int vc;
173 
174 #ifdef SLOPE_FACTOR
175  // Slope factor n = 1/k
176  // where k is the gate coupling coefficient
177  // k = Cox/(Cox+Cdep) ~ 0.7 (depends on gate voltage)
178  mutable double n;
179 #endif
180  const unsigned short nVddt;
181  const unsigned short nVt;
182  const unsigned short nVmin;
183  const unsigned short nSnake;
184 
185  const FilterModelConfig6581* fmc;
186 
187 public:
189  double WL_snake) :
190  nVddt_Vw_2(0),
191  vx(0),
192  vc(0),
193 #ifdef SLOPE_FACTOR
194  n(1.4),
195 #endif
196  nVddt(fmc->getNormalizedValue(fmc->getVddt())),
197  nVt(fmc->getNormalizedValue(fmc->getVth())),
198  nVmin(fmc->getNVmin()),
199  nSnake(fmc->getNormalizedCurrentFactor(WL_snake)),
200  fmc(fmc) {}
201 
202  void setVw(unsigned short Vw) { nVddt_Vw_2 = ((nVddt - Vw) * (nVddt - Vw)) >> 1; }
203 
204  int solve(int vi) const;
205 };
206 
207 } // namespace reSIDfp
208 
209 #if RESID_INLINING || defined(INTEGRATOR_CPP)
210 
211 namespace reSIDfp
212 {
213 
214 RESID_INLINE
215 int Integrator6581::solve(int vi) const
216 {
217  // Make sure Vgst>0 so we're not in subthreshold mode
218  assert(vx < nVddt);
219 
220  // Check that transistor is actually in triode mode
221  // Vds < Vgs - Vth
222  assert(vi < nVddt);
223 
224  // "Snake" voltages for triode mode calculation.
225  const unsigned int Vgst = nVddt - vx;
226  const unsigned int Vgdt = nVddt - vi;
227 
228  const unsigned int Vgst_2 = Vgst * Vgst;
229  const unsigned int Vgdt_2 = Vgdt * Vgdt;
230 
231  // "Snake" current, scaled by (1/m)*2^13*m*2^16*m*2^16*2^-15 = m*2^30
232  const int n_I_snake = nSnake * (static_cast<int>(Vgst_2 - Vgdt_2) >> 15);
233 
234  // VCR gate voltage. // Scaled by m*2^16
235  // Vg = Vddt - sqrt(((Vddt - Vw)^2 + Vgdt^2)/2)
236  const int nVg = static_cast<int>(fmc->getVcr_nVg((nVddt_Vw_2 + (Vgdt_2 >> 1)) >> 16));
237 #ifdef SLOPE_FACTOR
238  const double nVp = static_cast<double>(nVg - nVt) / n; // Pinch-off voltage
239  const int kVg = static_cast<int>(nVp + 0.5) - nVmin;
240 #else
241  const int kVg = (nVg - nVt) - nVmin;
242 #endif
243 
244  // VCR voltages for EKV model table lookup.
245  const int kVgt_Vs = (vx < kVg) ? kVg - vx : 0;
246  assert(kVgt_Vs < (1 << 16));
247  const int kVgt_Vd = (vi < kVg) ? kVg - vi : 0;
248  assert(kVgt_Vd < (1 << 16));
249 
250  // VCR current, scaled by m*2^15*2^15 = m*2^30
251  const unsigned int If = static_cast<unsigned int>(fmc->getVcr_n_Ids_term(kVgt_Vs)) << 15;
252  const unsigned int Ir = static_cast<unsigned int>(fmc->getVcr_n_Ids_term(kVgt_Vd)) << 15;
253 #ifdef SLOPE_FACTOR
254  const double iVcr = static_cast<double>(If - Ir);
255  const int n_I_vcr = static_cast<int>((iVcr * n) + 0.5);
256 #else
257  const int n_I_vcr = If - Ir;
258 #endif
259 
260 #ifdef SLOPE_FACTOR
261  // estimate new slope factor based on gate voltage
262  const double gamma = 1.0; // body effect factor
263  const double phi = 0.8; // bulk Fermi potential
264  const double Vp = nVp / fmc->getN16();
265  n = 1. + (gamma / (2. * sqrt(Vp + phi + 4. * fmc->getUt())));
266  assert((n > 1.2) && (n < 1.8));
267 #endif
268 
269  // Change in capacitor charge.
270  vc += n_I_snake + n_I_vcr;
271 
272  // vx = g(vc)
273  const int tmp = (vc >> 15) + (1 << 15);
274  assert(tmp < (1 << 16));
275  vx = fmc->getOpampRev(tmp);
276 
277  // Return vo.
278  return vx - (vc >> 14);
279 }
280 
281 } // namespace reSIDfp
282 
283 #endif
284 
285 #endif
Definition: FilterModelConfig6581.h:43
Definition: Integrator6581.h:168