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
40namespace reSIDfp
41{
42
166{
167private:
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
189public:
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
219namespace reSIDfp
220{
221
222RESID_INLINE
223int 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