libsidplayfp 2.4.2
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
42namespace reSIDfp
43{
44
168{
169private:
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
187public:
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
211namespace reSIDfp
212{
213
214RESID_INLINE
215int 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);
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