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