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
34namespace reSIDfp
35{
36
160{
161private:
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
183public:
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
213namespace reSIDfp
214{
215
216RESID_INLINE
217int 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