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