libsidplayfp 2.16.1
filter8580new.h
1// ---------------------------------------------------------------------------
2// This file is part of reSID, a MOS6581 SID emulator engine.
3// Copyright (C) 2010 Dag Lem <resid@nimrod.no>
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18// ---------------------------------------------------------------------------
19
20#ifndef RESID_FILTER_H
21#define RESID_FILTER_H
22
23#include "resid-config.h"
24
25#include <cassert>
26#include <cstdlib>
27
28namespace reSID
29{
30
31// ----------------------------------------------------------------------------
32// The SID filter is modeled with a two-integrator-loop biquadratic filter,
33// which has been confirmed by Bob Yannes to be the actual circuit used in
34// the SID chip.
35//
36// Measurements show that excellent emulation of the SID filter is achieved,
37// except when high resonance is combined with high sustain levels.
38// In this case the SID op-amps are performing less than ideally and are
39// causing some peculiar behavior of the SID filter. This however seems to
40// have more effect on the overall amplitude than on the color of the sound.
41//
42// The theory for the filter circuit can be found in "Microelectric Circuits"
43// by Adel S. Sedra and Kenneth C. Smith.
44// The circuit is modeled based on the explanation found there except that
45// an additional inverter is used in the feedback from the bandpass output,
46// allowing the summer op-amp to operate in single-ended mode. This yields
47// filter outputs with levels independent of Q, which corresponds with the
48// results obtained from a real SID.
49//
50// We have been able to model the summer and the two integrators of the circuit
51// to form components of an IIR filter.
52// Vhp is the output of the summer, Vbp is the output of the first integrator,
53// and Vlp is the output of the second integrator in the filter circuit.
54//
55// According to Bob Yannes, the active stages of the SID filter are not really
56// op-amps. Rather, simple NMOS inverters are used. By biasing an inverter
57// into its region of quasi-linear operation using a feedback resistor from
58// input to output, a MOS inverter can be made to act like an op-amp for
59// small signals centered around the switching threshold.
60//
61// In 2008, Michael Huth facilitated closer investigation of the SID 6581
62// filter circuit by publishing high quality microscope photographs of the die.
63// Tommi Lempinen has done an impressive work on re-vectorizing and annotating
64// the die photographs, substantially simplifying further analysis of the
65// filter circuit.
66//
67// The filter schematics below are reverse engineered from these re-vectorized
68// and annotated die photographs. While the filter first depicted in reSID 0.9
69// is a correct model of the basic filter, the schematics are now completed
70// with the audio mixer and output stage, including details on intended
71// relative resistor values. Also included are schematics for the NMOS FET
72// voltage controlled resistors (VCRs) used to control cutoff frequency, the
73// DAC which controls the VCRs, the NMOS op-amps, and the output buffer.
74//
75//
76// SID 6581 filter / mixer / output
77// --------------------------------
78//
79// ---------------------------------------------------
80// | |
81// | --1R1-- \-- D7 |
82// | ---R1-- | | |
83// | | | |--2R1-- \--| D6 |
84// | ------------<A]-----| | $17 |
85// | | |--4R1-- \--| D5 1=open | (3.5R1)
86// | | | | |
87// | | --8R1-- \--| D4 | (7.0R1)
88// | | | |
89// $17 | | (CAP2B) | (CAP1B) |
90// 0=to mixer | --R8-- ---R8-- ---C---| ---C---|
91// 1=to filter | | | | | | | |
92// ------R8--|-----[A>--|--Rw-----[A>--|--Rw-----[A>--|
93// ve (EXT IN) | | | |
94// D3 \ ---------------R8--| | | (CAP2A) | (CAP1A)
95// | v3 | | vhp | vbp | vlp
96// D2 | \ -----------R8--| ----- | |
97// | | v2 | | | |
98// D1 | | \ -------R8--| | ---------------- |
99// | | | v1 | | | |
100// D0 | | | \ ---R8-- | | ---------------------------
101// | | | | | | |
102// R6 R6 R6 R6 R6 R6 R6
103// | | | | $18 | | | $18
104// | \ | | D7: 1=open \ \ \ D6 - D4: 0=open
105// | | | | | | |
106// --------------------------------- 12V
107// |
108// | D3 --/ --1R4-- |
109// | ---R8-- | | ---R3-- |
110// | | | D2 |--/ --2R4--| | | ||--
111// ------[A>---------| |-----[A>-----||
112// D1 |--/ --4R4--| (4.25R2) ||--
113// $18 | | |
114// 0=open D0 --/ --8R4-- (8.75R2) |
115//
116// vo (AUDIO
117// OUT)
118//
119//
120// v1 - voice 1
121// v2 - voice 2
122// v3 - voice 3
123// ve - ext in
124// vhp - highpass output
125// vbp - bandpass output
126// vlp - lowpass output
127// vo - audio out
128// [A> - single ended inverting op-amp (self-biased NMOS inverter)
129// Rn - "resistors", implemented with custom NMOS FETs
130// Rw - cutoff frequency resistor (VCR)
131// C - capacitor
132//
133// Notes:
134//
135// R2 ~ 2.0*R1
136// R6 ~ 6.0*R1
137// R8 ~ 8.0*R1
138// R24 ~ 24.0*R1
139//
140// The Rn "resistors" in the circuit are implemented with custom NMOS FETs,
141// probably because of space constraints on the SID die. The silicon substrate
142// is laid out in a narrow strip or "snake", with a strip length proportional
143// to the intended resistance. The polysilicon gate electrode covers the entire
144// silicon substrate and is fixed at 12V in order for the NMOS FET to operate
145// in triode mode (a.k.a. linear mode or ohmic mode).
146//
147// Even in "linear mode", an NMOS FET is only an approximation of a resistor,
148// as the apparant resistance increases with increasing drain-to-source
149// voltage. If the drain-to-source voltage should approach the gate voltage
150// of 12V, the NMOS FET will enter saturation mode (a.k.a. active mode), and
151// the NMOS FET will not operate anywhere like a resistor.
152//
153//
154//
155// NMOS FET voltage controlled resistor (VCR)
156// ------------------------------------------
157//
158// Vw
159//
160// |
161// |
162// R1
163// |
164// --R1--|
165// | __|__
166// | -----
167// | | |
168// vi ---------- -------- vo
169// | |
170// ----R24----
171//
172//
173// vi - input
174// vo - output
175// Rn - "resistors", implemented with custom NMOS FETs
176// Vw - voltage from 11-bit DAC (frequency cutoff control)
177//
178// Notes:
179//
180// An approximate value for R24 can be found by using the formula for the
181// filter cutoff frequency:
182//
183// FCmin = 1/(2*pi*Rmax*C)
184//
185// Assuming that a the setting for minimum cutoff frequency in combination with
186// a low level input signal ensures that only negligible current will flow
187// through the transistor in the schematics above, values for FCmin and C can
188// be substituted in this formula to find Rmax.
189// Using C = 470pF and FCmin = 220Hz (measured value), we get:
190//
191// FCmin = 1/(2*pi*Rmax*C)
192// Rmax = 1/(2*pi*FCmin*C) = 1/(2*pi*220*470e-12) ~ 1.5MOhm
193//
194// From this it follows that:
195// R24 = Rmax ~ 1.5MOhm
196// R1 ~ R24/24 ~ 64kOhm
197// R2 ~ 2.0*R1 ~ 128kOhm
198// R6 ~ 6.0*R1 ~ 384kOhm
199// R8 ~ 8.0*R1 ~ 512kOhm
200//
201// Note that these are only approximate values for one particular SID chip,
202// due to process variations the values can be substantially different in
203// other chips.
204//
205//
206//
207// Filter frequency cutoff DAC
208// ---------------------------
209//
210//
211// 12V 10 9 8 7 6 5 4 3 2 1 0 VGND
212// | | | | | | | | | | | | | Missing
213// 2R 2R 2R 2R 2R 2R 2R 2R 2R 2R 2R 2R 2R termination
214// | | | | | | | | | | | | |
215// Vw ----R---R---R---R---R---R---R---R---R---R---R-- ---
216//
217// Bit on: 12V
218// Bit off: 5V (VGND)
219//
220// As is the case with all MOS 6581 DACs, the termination to (virtual) ground
221// at bit 0 is missing.
222//
223// Furthermore, the control of the two VCRs imposes a load on the DAC output
224// which varies with the input signals to the VCRs. This can be seen from the
225// VCR figure above.
226//
227//
228//
229// "Op-amp" (self-biased NMOS inverter)
230// ------------------------------------
231//
232//
233// 12V
234//
235// |
236// -----------|
237// | |
238// | ------|
239// | | |
240// | | ||--
241// | --||
242// | ||--
243// ||-- |
244// vi -----|| |--------- vo
245// ||-- | |
246// | ||-- |
247// |-------|| |
248// | ||-- |
249// ||-- | |
250// --|| | |
251// | ||-- | |
252// | | | |
253// | -----------| |
254// | | |
255// | |
256// | GND |
257// | |
258// ----------------------
259//
260//
261// vi - input
262// vo - output
263//
264// Notes:
265//
266// The schematics above are laid out to show that the "op-amp" logically
267// consists of two building blocks; a saturated load NMOS inverter (on the
268// right hand side of the schematics) with a buffer / bias input stage
269// consisting of a variable saturated load NMOS inverter (on the left hand
270// side of the schematics).
271//
272// Provided a reasonably high input impedance and a reasonably low output
273// impedance, the "op-amp" can be modeled as a voltage transfer function
274// mapping input voltage to output voltage.
275//
276//
277//
278// Output buffer (NMOS voltage follower)
279// -------------------------------------
280//
281//
282// 12V
283//
284// |
285// |
286// ||--
287// vi -----||
288// ||--
289// |
290// |------ vo
291// | (AUDIO
292// Rext OUT)
293// |
294// |
295//
296// GND
297//
298// vi - input
299// vo - output
300// Rext - external resistor, 1kOhm
301//
302// Notes:
303//
304// The external resistor Rext is needed to complete the NMOS voltage follower,
305// this resistor has a recommended value of 1kOhm.
306//
307// Die photographs show that actually, two NMOS transistors are used in the
308// voltage follower. However the two transistors are coupled in parallel (all
309// terminals are pairwise common), which implies that we can model the two
310// transistors as one.
311//
312// ----------------------------------------------------------------------------
313//
314// SID 8580 filter / mixer / output
315// --------------------------------
316//
317// +---------------------------------------------------+
318// | $17 +----Rf-+ |
319// | | | |
320// | D4&!D5 o- \-R3-o |
321// | | | $17 |
322// | !D4&!D5 o- \-R2-o |
323// | | | +---R8-- \--+ !D6&D7 |
324// | D4&!D5 o- \-R1-o | | |
325// | | | o---RC-- \--o D6&D7 |
326// | +---------o--<A]--o--o | |
327// | | o---R4-- \--o D6&!D7 |
328// | | | | |
329// | | +---Ri-- \--o !D6&!D7 |
330// | | | |
331// $17 | | (CAP2B) | (CAP1B) |
332// 0=to mixer | +--R7--+ +---R7--+ +---C---o +---C---o
333// 1=to filter | | | | | | | |
334// +------R7--o--o--[A>--o--Rfc-o--[A>--o--Rfc-o--[A>--o
335// ve (EXT IN) | | | |
336// D3 \ --------------R12--o | | (CAP2A) | (CAP1A)
337// | v3 | | vhp | vbp | vlp
338// D2 | \ -----------R7--o +-----+ | |
339// | | v2 | | | |
340// D1 | | \ -------R7--o | +----------------+ |
341// | | | v1 | | | |
342// D0 | | | \ ---R7--+ | | +---------------------------+
343// | | | | | | |
344// R9 R5 R5 R5 R5 R5 R5
345// | | | | $18 | | | $18
346// | \ | | D7: 1=open \ \ \ D6 - D4: 0=open
347// | | | | | | |
348// +---o---o---o-------------o---o---+
349// |
350// | D3 +--/ --1R4--+
351// | +---R8--+ | | +---R2--+
352// | | | D2 o--/ --2R4--o | |
353// +---o--[A>--o------o o--o--[A>--o-- vo (AUDIO OUT)
354// D1 o--/ --4R4--o
355// $18 | |
356// 0=open D0 +--/ --8R4--+
357//
358//
359//
360//
361// R1 = 15.3*Ri
362// R2 = 7.3*Ri
363// R3 = 4.7*Ri
364// Rf = 1.4*Ri
365// R4 = 1.4*Ri
366// R8 = 2.0*Ri
367// RC = 2.8*Ri
368//
369//
370//
371// Op-amps
372// -------
373// Unlike the 6581, the 8580 has real OpAmps.
374//
375// Temperature compensated differential amplifier:
376//
377// 9V
378//
379// |
380// +-------o-o-o-------+
381// | | | |
382// | R R |
383// +--|| | | ||--+
384// ||---o o---||
385// +--|| | | ||--+
386// | | | |
387// o-----+ | | o--- Va
388// | | | | |
389// +--|| | | | ||--+
390// ||-o-+---+---||
391// +--|| | | ||--+
392// | | | |
393// | |
394// GND | | GND
395// ||--+ +--||
396// in- -----|| ||------ in+
397// ||----o----||
398// |
399// 8 Current sink
400// |
401//
402// GND
403//
404// Inverter + non-inverting output amplifier:
405//
406// Va ---o---||-------------------o--------------------+
407// | | 9V |
408// | +----------+----------+ | |
409// | 9V | | 9V | ||--+ |
410// | | | 9V | | +-|| |
411// | R | | | ||--+ ||--+ |
412// | | | ||--+ +--|| o---o--- Vout
413// | o---o---|| ||--+ ||--+
414// | | ||--+ o-----||
415// | ||--+ | ||--+ ||--+
416// +-----|| o-----|| |
417// ||--+ | ||--+
418// | R | GND
419// |
420// GND GND
421// GND
422//
423//
424//
425// Virtual ground
426// --------------
427// A PolySi resitive voltage divider provides the voltage
428// for the non-inverting input of the filter op-amps.
429//
430// 5V
431// +----------+
432// | | |\ |
433// R1 +---|-\ |
434// 5V | |A >---o--- Vref
435// o-------|+/
436// | | |/
437// R10 R4
438// | |
439// o---+
440// |
441// R10
442// |
443//
444// GND
445//
446// Rn = n*R1
447//
448//
449//
450// Rfc - freq control DAC resistance ladder
451// ----------------------------------------
452// The resistance for the bandpass and lowpass integrator stages of the filter are determined
453// by an 11 bit DAC driven by the FC register.
454// If all 11 bits are '0', the impedance of the DAC would be "infinitely high".
455// To get around this, there is an 11 input NOR gate below the DAC sensing those 11 bits.
456// If they are all 0, the NOR gate gives the gate control voltage to the 12 bit DAC LSB.
457//
458//
459//
460// Crystal stabilized precision switched capacitor voltage divider
461// ---------------------------------------------------------------
462// There is a FET working as a temperature sensor close to the DACs which changes the gate voltage
463// of the frequency control DACs according to the temperature, to reduce its effects on the filter curve.
464// An asynchronous 3 bit binary counter, running at the speed of PHI2, drives two big capacitors
465// which AC resistance is then used as a voltage divider.
466// This implicates that frequency difference between PAL and NTSC might shift the filter curve by 4% or such.
467//
468// https://en.wikipedia.org/wiki/Switched_capacitor
469//
470// |\ OpAmp has a smaller capacitor
471// Vref ---|+\ than the other OPs
472// |A >---o--- Vdac
473// o-------|-/ |
474// | |/ |
475// | |
476// C1 | C2 |
477// +---||---o---+ +---o-----||-------o
478// | | | | | |
479// o----+ | ----- | |
480// | | | ----- +----+ +-----+
481// | ----- | | | |
482// | ----- | ----- |
483// | | | ----- |
484// | +-----------+ | |
485// | /Q Q | +-------+
486// GND +-----------+ FET close to DAC
487// | clk/8 | working as temperature sensor
488// +-----------+
489// | |
490// clk1 clk2
491//
492
493// Compile-time computation of op-amp summer and mixer table offsets.
494
495// The highpass summer has 2 - 6 inputs (bandpass, lowpass, and 0 - 4 voices).
496template<int i>
497struct summer_offset
498{
499 enum { value = summer_offset<i - 1>::value + ((2 + i - 1) << 16) };
500};
501
502template<>
503struct summer_offset<0>
504{
505 enum { value = 0 };
506};
507
508// The mixer has 0 - 7 inputs (0 - 4 voices and 0 - 3 filter outputs).
509template<int i>
510struct mixer_offset
511{
512 enum { value = mixer_offset<i - 1>::value + ((i - 1) << 16) };
513};
514
515template<>
516struct mixer_offset<1>
517{
518 enum { value = 1 };
519};
520
521template<>
522struct mixer_offset<0>
523{
524 enum { value = 0 };
525};
526
527
528class Filter
529{
530public:
531 Filter();
532
533 void enable_filter(bool enable);
534 void adjust_filter_bias(double dac_bias);
535 void set_chip_model(chip_model model);
536 void set_voice_mask(reg4 mask);
537
538 void clock(int voice1, int voice2, int voice3);
539 void clock(cycle_count delta_t, int voice1, int voice2, int voice3);
540 void reset();
541
542 // Write registers.
543 void writeFC_LO(reg8);
544 void writeFC_HI(reg8);
545 void writeRES_FILT(reg8);
546 void writeMODE_VOL(reg8);
547
548 // SID audio input (16 bits).
549 void input(short sample);
550
551 // SID audio output (16 bits).
552 short output();
553
554protected:
555 void set_sum_mix();
556 void set_w0();
557
558 // Filter enabled.
559 bool enabled;
560
561 // Filter cutoff frequency.
562 reg12 fc;
563
564 // Filter resonance.
565 reg8 res;
566
567 // Selects which voices to route through the filter.
568 reg8 filt;
569
570 // Selects which filter outputs to route into the mixer.
571 reg4 mode;
572
573 // Output master volume.
574 reg4 vol;
575
576 // Used to mask out EXT IN if not connected, and for test purposes
577 // (voice muting).
578 reg8 voice_mask;
579
580 // Select which inputs to route into the summer / mixer.
581 // These are derived from filt, mode, and voice_mask.
582 reg8 sum;
583 reg8 mix;
584
585 // State of filter.
586 int Vhp; // highpass
587 int Vbp; // bandpass
588 int Vbp_x, Vbp_vc;
589 int Vlp; // lowpass
590 int Vlp_x, Vlp_vc;
591 // Filter / mixer inputs.
592 int ve;
593 int v3;
594 int v2;
595 int v1;
596
597 chip_model sid_model;
598
599 typedef struct {
600 unsigned short vx;
601 short dvx;
602 } opamp_t;
603
604 typedef struct {
605 int kVddt; // K*(Vdd - Vth)
606 int voice_scale_s14;
607 int voice_DC;
608 int ak;
609 int bk;
610 int vc_min;
611 int vc_max;
612 int filterGain;
613 double vo_N16; // Fixed point scaling for 16 bit op-amp output.
614
615 // Reverse op-amp transfer function.
616 unsigned short opamp_rev[1 << 16];
617 // Lookup tables for gain and summer op-amps in output stage / filter.
618 unsigned short summer[summer_offset<5>::value];
619 unsigned short gain[16][1 << 16];
620 unsigned short resonance[16][1 << 16];
621 unsigned short mixer[mixer_offset<8>::value];
622 // Cutoff frequency DAC output voltage table. FC is an 11 bit register.
623 unsigned short f0_dac[1 << 11];
624 } model_filter_t;
625
626 // 6581 only
627 // Cutoff frequency DAC voltage, resonance.
628 int Vddt_Vw_2, Vw_bias;
629
630 static int n_snake;
631
632 // 8580 only
633 int n_dac;
634
635 static int n_param;
636
637 // DAC gate voltage
638 int nVgt;
639
640 //int solve_gain(opamp_t* opamp, int n, int vi_t, int& x, model_filter_t& mf);
641 int solve_gain_d(opamp_t* opamp, double n, int vi_t, int& x, model_filter_t& mf);
642 int solve_integrate_6581(int dt, int vi_t, int& x, int& vc, model_filter_t& mf);
643 int solve_integrate_8580(int dt, int vi_t, int& x, int& vc, model_filter_t& mf);
644
645 // VCR - 6581 only.
646 static unsigned short vcr_kVg[1 << 16];
647 static unsigned short vcr_n_Ids_term[1 << 16];
648 // Common parameters.
649 static model_filter_t model_filter[2];
650
651friend class SID;
652
653private:
654 class Randomnoise
655 {
656 private:
657 int buffer[1024];
658 mutable int index = 0;
659 public:
660 Randomnoise()
661 {
662 for (int i=0; i<1024; i++)
663 buffer[i] = rand() % (1<<19);
664 }
665 int getNoise() const { index = (index + 1) & 0x3ff; return buffer[index]; }
666 };
667
668 Randomnoise rnd;
669};
670
671
672// ----------------------------------------------------------------------------
673// Inline functions.
674// The following functions are defined inline because they are called every
675// time a sample is calculated.
676// ----------------------------------------------------------------------------
677
678#if RESID_INLINING || defined(RESID_FILTER_CC)
679
680// ----------------------------------------------------------------------------
681// SID clocking - 1 cycle.
682// ----------------------------------------------------------------------------
683RESID_INLINE
684void Filter::clock(int voice1, int voice2, int voice3)
685{
686 model_filter_t& f = model_filter[sid_model];
687
688 v1 = ((voice1*f.voice_scale_s14 + rnd.getNoise()) >> 18) + f.voice_DC;
689 v2 = ((voice2*f.voice_scale_s14 + rnd.getNoise()) >> 18) + f.voice_DC;
690 v3 = ((voice3*f.voice_scale_s14 + rnd.getNoise()) >> 18) + f.voice_DC;
691
692 // Sum inputs routed into the filter.
693 int Vi = 0;
694 int offset = 0;
695
696 switch (sum & 0xf) {
697 case 0x0:
698 Vi = 0;
699 offset = summer_offset<0>::value;
700 break;
701 case 0x1:
702 Vi = v1;
703 offset = summer_offset<1>::value;
704 break;
705 case 0x2:
706 Vi = v2;
707 offset = summer_offset<1>::value;
708 break;
709 case 0x3:
710 Vi = v2 + v1;
711 offset = summer_offset<2>::value;
712 break;
713 case 0x4:
714 Vi = v3;
715 offset = summer_offset<1>::value;
716 break;
717 case 0x5:
718 Vi = v3 + v1;
719 offset = summer_offset<2>::value;
720 break;
721 case 0x6:
722 Vi = v3 + v2;
723 offset = summer_offset<2>::value;
724 break;
725 case 0x7:
726 Vi = v3 + v2 + v1;
727 offset = summer_offset<3>::value;
728 break;
729 case 0x8:
730 Vi = ve;
731 offset = summer_offset<1>::value;
732 break;
733 case 0x9:
734 Vi = ve + v1;
735 offset = summer_offset<2>::value;
736 break;
737 case 0xa:
738 Vi = ve + v2;
739 offset = summer_offset<2>::value;
740 break;
741 case 0xb:
742 Vi = ve + v2 + v1;
743 offset = summer_offset<3>::value;
744 break;
745 case 0xc:
746 Vi = ve + v3;
747 offset = summer_offset<2>::value;
748 break;
749 case 0xd:
750 Vi = ve + v3 + v1;
751 offset = summer_offset<3>::value;
752 break;
753 case 0xe:
754 Vi = ve + v3 + v2;
755 offset = summer_offset<3>::value;
756 break;
757 case 0xf:
758 Vi = ve + v3 + v2 + v1;
759 offset = summer_offset<4>::value;
760 break;
761 }
762
763 // Calculate filter outputs.
764 if (sid_model == 0) {
765 // MOS 6581.
766 Vlp = solve_integrate_6581(1, Vbp, Vlp_x, Vlp_vc, f);
767 Vbp = solve_integrate_6581(1, Vhp, Vbp_x, Vbp_vc, f);
768 }
769 else {
770 // MOS 8580.
771 Vlp = solve_integrate_8580(1, Vbp, Vlp_x, Vlp_vc, f);
772 Vbp = solve_integrate_8580(1, Vhp, Vbp_x, Vbp_vc, f);
773 }
774
775 assert((Vbp >= 0) && (Vbp < (1 << 16)));
776 const int idx = offset + f.resonance[res][Vbp] + Vlp + Vi;
777 assert((idx >= 0) && (idx < summer_offset<5>::value));
778 Vhp = f.summer[idx];
779}
780
781// ----------------------------------------------------------------------------
782// SID clocking - delta_t cycles.
783// ----------------------------------------------------------------------------
784RESID_INLINE
785void Filter::clock(cycle_count delta_t, int voice1, int voice2, int voice3)
786{
787 model_filter_t& f = model_filter[sid_model];
788
789 v1 = ((voice1*f.voice_scale_s14 + rnd.getNoise()) >> 18) + f.voice_DC;
790 v2 = ((voice2*f.voice_scale_s14 + rnd.getNoise()) >> 18) + f.voice_DC;
791 v3 = ((voice3*f.voice_scale_s14 + rnd.getNoise()) >> 18) + f.voice_DC;
792
793 // Enable filter on/off.
794 // This is not really part of SID, but is useful for testing.
795 // On slow CPUs it may be necessary to bypass the filter to lower the CPU
796 // load.
797 if (unlikely(!enabled)) {
798 return;
799 }
800
801 // Sum inputs routed into the filter.
802 int Vi = 0;
803 int offset = 0;
804
805 switch (sum & 0xf) {
806 case 0x0:
807 Vi = 0;
808 offset = summer_offset<0>::value;
809 break;
810 case 0x1:
811 Vi = v1;
812 offset = summer_offset<1>::value;
813 break;
814 case 0x2:
815 Vi = v2;
816 offset = summer_offset<1>::value;
817 break;
818 case 0x3:
819 Vi = v2 + v1;
820 offset = summer_offset<2>::value;
821 break;
822 case 0x4:
823 Vi = v3;
824 offset = summer_offset<1>::value;
825 break;
826 case 0x5:
827 Vi = v3 + v1;
828 offset = summer_offset<2>::value;
829 break;
830 case 0x6:
831 Vi = v3 + v2;
832 offset = summer_offset<2>::value;
833 break;
834 case 0x7:
835 Vi = v3 + v2 + v1;
836 offset = summer_offset<3>::value;
837 break;
838 case 0x8:
839 Vi = ve;
840 offset = summer_offset<1>::value;
841 break;
842 case 0x9:
843 Vi = ve + v1;
844 offset = summer_offset<2>::value;
845 break;
846 case 0xa:
847 Vi = ve + v2;
848 offset = summer_offset<2>::value;
849 break;
850 case 0xb:
851 Vi = ve + v2 + v1;
852 offset = summer_offset<3>::value;
853 break;
854 case 0xc:
855 Vi = ve + v3;
856 offset = summer_offset<2>::value;
857 break;
858 case 0xd:
859 Vi = ve + v3 + v1;
860 offset = summer_offset<3>::value;
861 break;
862 case 0xe:
863 Vi = ve + v3 + v2;
864 offset = summer_offset<3>::value;
865 break;
866 case 0xf:
867 Vi = ve + v3 + v2 + v1;
868 offset = summer_offset<4>::value;
869 break;
870 }
871
872 // Maximum delta cycles for filter fixpoint iteration to converge
873 // is approximately 3.
874 cycle_count delta_t_flt = 3;
875
876 if (sid_model == 0) {
877 // MOS 6581.
878 while (delta_t) {
879 if (unlikely(delta_t < delta_t_flt)) {
880 delta_t_flt = delta_t;
881 }
882
883 // Calculate filter outputs.
884 Vlp = solve_integrate_6581(delta_t_flt, Vbp, Vlp_x, Vlp_vc, f);
885 Vbp = solve_integrate_6581(delta_t_flt, Vhp, Vbp_x, Vbp_vc, f);
886 assert((Vbp >= 0) && (Vbp < (1 << 16)));
887 const int idx = offset + f.resonance[res][Vbp] + Vlp + Vi;
888 assert((idx >= 0) && (idx < summer_offset<5>::value));
889 Vhp = f.summer[idx];
890
891 delta_t -= delta_t_flt;
892 }
893 }
894 else {
895 // MOS 8580.
896 while (delta_t) {
897 if (unlikely(delta_t < delta_t_flt)) {
898 delta_t_flt = delta_t;
899 }
900
901 // Calculate filter outputs.
902 Vlp = solve_integrate_8580(delta_t_flt, Vbp, Vlp_x, Vlp_vc, f);
903 Vbp = solve_integrate_8580(delta_t_flt, Vhp, Vbp_x, Vbp_vc, f);
904 assert((Vbp >= 0) && (Vbp < (1 << 16)));
905 const int idx = offset + f.resonance[res][Vbp] + Vlp + Vi;
906 assert((idx >= 0) && (idx < summer_offset<5>::value));
907 Vhp = f.summer[idx];
908
909 delta_t -= delta_t_flt;
910 }
911 }
912}
913
914
915// ----------------------------------------------------------------------------
916// SID audio input (16 bits).
917// ----------------------------------------------------------------------------
918RESID_INLINE
919void Filter::input(short sample)
920{
921 // Scale to three times the peak-to-peak for one voice and add the op-amp
922 // "zero" DC level.
923 // NB! Adding the op-amp "zero" DC level is a (wildly inaccurate)
924 // approximation of feeding the input through an AC coupling capacitor.
925 // This could be implemented as a separate filter circuit, however the
926 // primary use of the emulator is not to process external signals.
927 // The upside is that the MOS8580 "digi boost" works without a separate (DC)
928 // input interface.
929 // Note that the input is 16 bits, compared to the 20 bit voice output.
930 model_filter_t& f = model_filter[sid_model];
931 ve = (sample*f.voice_scale_s14*3 >> 14) + f.mixer[0];
932}
933
934
935// ----------------------------------------------------------------------------
936// SID audio output (16 bits).
937// ----------------------------------------------------------------------------
938RESID_INLINE
939short Filter::output()
940{
941 model_filter_t& f = model_filter[sid_model];
942
943 // Writing the switch below manually would be tedious and error-prone;
944 // it is rather generated by the following Perl program:
945
946 /*
947my @i = qw(v1 v2 v3 ve Vlp Vbp Vhp);
948for my $mix (0..2**@i-1) {
949 print sprintf(" case 0x%02x:\n", $mix);
950 my @sumVoice;
951 my @sumFilt;
952 my $bit = 0;
953 for (@i) {
954 if ($bit < 4) {
955 unshift(@sumVoice, $_) if $mix & (1 << $bit);
956 } else {
957 unshift(@sumFilt, $_) if $mix & (1 << $bit);
958 }
959 $bit += 1;
960 }
961 my $sum;
962 if (@sumFilt) {
963 $sumV = (@sumVoice) ? " + ".join(" + ", @sumVoice) : "";
964 $sum = "((((".join(" + ", @sumFilt).") * f.filterGain) + dc_offset) >> 12)" . $sumV;
965 } else {
966 $sum = join(" + ", @sumVoice) || "0";
967 }
968 print " Vi = $sum;\n";
969 print " offset = mixer_offset<" . (@sumVoice+@sumFilt) . ">::value;\n";
970 print " break;\n";
971}
972 */
973
974 // Sum inputs routed into the mixer.
975 int Vi = 0;
976 int offset = 0;
977 const int dc_offset = 32767 * ((1 << 12) - f.filterGain);
978
979 switch (mix & 0x7f) {
980 case 0x00:
981 Vi = 0;
982 offset = mixer_offset<0>::value;
983 break;
984 case 0x01:
985 Vi = v1;
986 offset = mixer_offset<1>::value;
987 break;
988 case 0x02:
989 Vi = v2;
990 offset = mixer_offset<1>::value;
991 break;
992 case 0x03:
993 Vi = v2 + v1;
994 offset = mixer_offset<2>::value;
995 break;
996 case 0x04:
997 Vi = v3;
998 offset = mixer_offset<1>::value;
999 break;
1000 case 0x05:
1001 Vi = v3 + v1;
1002 offset = mixer_offset<2>::value;
1003 break;
1004 case 0x06:
1005 Vi = v3 + v2;
1006 offset = mixer_offset<2>::value;
1007 break;
1008 case 0x07:
1009 Vi = v3 + v2 + v1;
1010 offset = mixer_offset<3>::value;
1011 break;
1012 case 0x08:
1013 Vi = ve;
1014 offset = mixer_offset<1>::value;
1015 break;
1016 case 0x09:
1017 Vi = ve + v1;
1018 offset = mixer_offset<2>::value;
1019 break;
1020 case 0x0a:
1021 Vi = ve + v2;
1022 offset = mixer_offset<2>::value;
1023 break;
1024 case 0x0b:
1025 Vi = ve + v2 + v1;
1026 offset = mixer_offset<3>::value;
1027 break;
1028 case 0x0c:
1029 Vi = ve + v3;
1030 offset = mixer_offset<2>::value;
1031 break;
1032 case 0x0d:
1033 Vi = ve + v3 + v1;
1034 offset = mixer_offset<3>::value;
1035 break;
1036 case 0x0e:
1037 Vi = ve + v3 + v2;
1038 offset = mixer_offset<3>::value;
1039 break;
1040 case 0x0f:
1041 Vi = ve + v3 + v2 + v1;
1042 offset = mixer_offset<4>::value;
1043 break;
1044 case 0x10:
1045 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12);
1046 offset = mixer_offset<1>::value;
1047 break;
1048 case 0x11:
1049 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + v1;
1050 offset = mixer_offset<2>::value;
1051 break;
1052 case 0x12:
1053 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + v2;
1054 offset = mixer_offset<2>::value;
1055 break;
1056 case 0x13:
1057 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + v2 + v1;
1058 offset = mixer_offset<3>::value;
1059 break;
1060 case 0x14:
1061 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + v3;
1062 offset = mixer_offset<2>::value;
1063 break;
1064 case 0x15:
1065 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v1;
1066 offset = mixer_offset<3>::value;
1067 break;
1068 case 0x16:
1069 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v2;
1070 offset = mixer_offset<3>::value;
1071 break;
1072 case 0x17:
1073 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v2 + v1;
1074 offset = mixer_offset<4>::value;
1075 break;
1076 case 0x18:
1077 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + ve;
1078 offset = mixer_offset<2>::value;
1079 break;
1080 case 0x19:
1081 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v1;
1082 offset = mixer_offset<3>::value;
1083 break;
1084 case 0x1a:
1085 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v2;
1086 offset = mixer_offset<3>::value;
1087 break;
1088 case 0x1b:
1089 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v2 + v1;
1090 offset = mixer_offset<4>::value;
1091 break;
1092 case 0x1c:
1093 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3;
1094 offset = mixer_offset<3>::value;
1095 break;
1096 case 0x1d:
1097 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v1;
1098 offset = mixer_offset<4>::value;
1099 break;
1100 case 0x1e:
1101 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2;
1102 offset = mixer_offset<4>::value;
1103 break;
1104 case 0x1f:
1105 Vi = ((((Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2 + v1;
1106 offset = mixer_offset<5>::value;
1107 break;
1108 case 0x20:
1109 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12);
1110 offset = mixer_offset<1>::value;
1111 break;
1112 case 0x21:
1113 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + v1;
1114 offset = mixer_offset<2>::value;
1115 break;
1116 case 0x22:
1117 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + v2;
1118 offset = mixer_offset<2>::value;
1119 break;
1120 case 0x23:
1121 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + v2 + v1;
1122 offset = mixer_offset<3>::value;
1123 break;
1124 case 0x24:
1125 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + v3;
1126 offset = mixer_offset<2>::value;
1127 break;
1128 case 0x25:
1129 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + v3 + v1;
1130 offset = mixer_offset<3>::value;
1131 break;
1132 case 0x26:
1133 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + v3 + v2;
1134 offset = mixer_offset<3>::value;
1135 break;
1136 case 0x27:
1137 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + v3 + v2 + v1;
1138 offset = mixer_offset<4>::value;
1139 break;
1140 case 0x28:
1141 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + ve;
1142 offset = mixer_offset<2>::value;
1143 break;
1144 case 0x29:
1145 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v1;
1146 offset = mixer_offset<3>::value;
1147 break;
1148 case 0x2a:
1149 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v2;
1150 offset = mixer_offset<3>::value;
1151 break;
1152 case 0x2b:
1153 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v2 + v1;
1154 offset = mixer_offset<4>::value;
1155 break;
1156 case 0x2c:
1157 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v3;
1158 offset = mixer_offset<3>::value;
1159 break;
1160 case 0x2d:
1161 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v1;
1162 offset = mixer_offset<4>::value;
1163 break;
1164 case 0x2e:
1165 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2;
1166 offset = mixer_offset<4>::value;
1167 break;
1168 case 0x2f:
1169 Vi = ((((Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2 + v1;
1170 offset = mixer_offset<5>::value;
1171 break;
1172 case 0x30:
1173 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12);
1174 offset = mixer_offset<2>::value;
1175 break;
1176 case 0x31:
1177 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v1;
1178 offset = mixer_offset<3>::value;
1179 break;
1180 case 0x32:
1181 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v2;
1182 offset = mixer_offset<3>::value;
1183 break;
1184 case 0x33:
1185 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v2 + v1;
1186 offset = mixer_offset<4>::value;
1187 break;
1188 case 0x34:
1189 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3;
1190 offset = mixer_offset<3>::value;
1191 break;
1192 case 0x35:
1193 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v1;
1194 offset = mixer_offset<4>::value;
1195 break;
1196 case 0x36:
1197 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v2;
1198 offset = mixer_offset<4>::value;
1199 break;
1200 case 0x37:
1201 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v2 + v1;
1202 offset = mixer_offset<5>::value;
1203 break;
1204 case 0x38:
1205 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve;
1206 offset = mixer_offset<3>::value;
1207 break;
1208 case 0x39:
1209 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v1;
1210 offset = mixer_offset<4>::value;
1211 break;
1212 case 0x3a:
1213 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v2;
1214 offset = mixer_offset<4>::value;
1215 break;
1216 case 0x3b:
1217 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v2 + v1;
1218 offset = mixer_offset<5>::value;
1219 break;
1220 case 0x3c:
1221 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3;
1222 offset = mixer_offset<4>::value;
1223 break;
1224 case 0x3d:
1225 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v1;
1226 offset = mixer_offset<5>::value;
1227 break;
1228 case 0x3e:
1229 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2;
1230 offset = mixer_offset<5>::value;
1231 break;
1232 case 0x3f:
1233 Vi = ((((Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2 + v1;
1234 offset = mixer_offset<6>::value;
1235 break;
1236 case 0x40:
1237 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12);
1238 offset = mixer_offset<1>::value;
1239 break;
1240 case 0x41:
1241 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + v1;
1242 offset = mixer_offset<2>::value;
1243 break;
1244 case 0x42:
1245 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + v2;
1246 offset = mixer_offset<2>::value;
1247 break;
1248 case 0x43:
1249 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + v2 + v1;
1250 offset = mixer_offset<3>::value;
1251 break;
1252 case 0x44:
1253 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + v3;
1254 offset = mixer_offset<2>::value;
1255 break;
1256 case 0x45:
1257 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + v3 + v1;
1258 offset = mixer_offset<3>::value;
1259 break;
1260 case 0x46:
1261 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + v3 + v2;
1262 offset = mixer_offset<3>::value;
1263 break;
1264 case 0x47:
1265 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + v3 + v2 + v1;
1266 offset = mixer_offset<4>::value;
1267 break;
1268 case 0x48:
1269 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + ve;
1270 offset = mixer_offset<2>::value;
1271 break;
1272 case 0x49:
1273 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + ve + v1;
1274 offset = mixer_offset<3>::value;
1275 break;
1276 case 0x4a:
1277 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + ve + v2;
1278 offset = mixer_offset<3>::value;
1279 break;
1280 case 0x4b:
1281 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + ve + v2 + v1;
1282 offset = mixer_offset<4>::value;
1283 break;
1284 case 0x4c:
1285 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + ve + v3;
1286 offset = mixer_offset<3>::value;
1287 break;
1288 case 0x4d:
1289 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v1;
1290 offset = mixer_offset<4>::value;
1291 break;
1292 case 0x4e:
1293 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2;
1294 offset = mixer_offset<4>::value;
1295 break;
1296 case 0x4f:
1297 Vi = ((((Vhp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2 + v1;
1298 offset = mixer_offset<5>::value;
1299 break;
1300 case 0x50:
1301 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12);
1302 offset = mixer_offset<2>::value;
1303 break;
1304 case 0x51:
1305 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + v1;
1306 offset = mixer_offset<3>::value;
1307 break;
1308 case 0x52:
1309 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + v2;
1310 offset = mixer_offset<3>::value;
1311 break;
1312 case 0x53:
1313 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + v2 + v1;
1314 offset = mixer_offset<4>::value;
1315 break;
1316 case 0x54:
1317 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3;
1318 offset = mixer_offset<3>::value;
1319 break;
1320 case 0x55:
1321 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v1;
1322 offset = mixer_offset<4>::value;
1323 break;
1324 case 0x56:
1325 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v2;
1326 offset = mixer_offset<4>::value;
1327 break;
1328 case 0x57:
1329 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v2 + v1;
1330 offset = mixer_offset<5>::value;
1331 break;
1332 case 0x58:
1333 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve;
1334 offset = mixer_offset<3>::value;
1335 break;
1336 case 0x59:
1337 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v1;
1338 offset = mixer_offset<4>::value;
1339 break;
1340 case 0x5a:
1341 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v2;
1342 offset = mixer_offset<4>::value;
1343 break;
1344 case 0x5b:
1345 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v2 + v1;
1346 offset = mixer_offset<5>::value;
1347 break;
1348 case 0x5c:
1349 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3;
1350 offset = mixer_offset<4>::value;
1351 break;
1352 case 0x5d:
1353 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v1;
1354 offset = mixer_offset<5>::value;
1355 break;
1356 case 0x5e:
1357 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2;
1358 offset = mixer_offset<5>::value;
1359 break;
1360 case 0x5f:
1361 Vi = ((((Vhp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2 + v1;
1362 offset = mixer_offset<6>::value;
1363 break;
1364 case 0x60:
1365 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12);
1366 offset = mixer_offset<2>::value;
1367 break;
1368 case 0x61:
1369 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + v1;
1370 offset = mixer_offset<3>::value;
1371 break;
1372 case 0x62:
1373 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + v2;
1374 offset = mixer_offset<3>::value;
1375 break;
1376 case 0x63:
1377 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + v2 + v1;
1378 offset = mixer_offset<4>::value;
1379 break;
1380 case 0x64:
1381 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + v3;
1382 offset = mixer_offset<3>::value;
1383 break;
1384 case 0x65:
1385 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + v3 + v1;
1386 offset = mixer_offset<4>::value;
1387 break;
1388 case 0x66:
1389 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + v3 + v2;
1390 offset = mixer_offset<4>::value;
1391 break;
1392 case 0x67:
1393 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + v3 + v2 + v1;
1394 offset = mixer_offset<5>::value;
1395 break;
1396 case 0x68:
1397 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + ve;
1398 offset = mixer_offset<3>::value;
1399 break;
1400 case 0x69:
1401 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v1;
1402 offset = mixer_offset<4>::value;
1403 break;
1404 case 0x6a:
1405 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v2;
1406 offset = mixer_offset<4>::value;
1407 break;
1408 case 0x6b:
1409 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v2 + v1;
1410 offset = mixer_offset<5>::value;
1411 break;
1412 case 0x6c:
1413 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v3;
1414 offset = mixer_offset<4>::value;
1415 break;
1416 case 0x6d:
1417 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v1;
1418 offset = mixer_offset<5>::value;
1419 break;
1420 case 0x6e:
1421 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2;
1422 offset = mixer_offset<5>::value;
1423 break;
1424 case 0x6f:
1425 Vi = ((((Vhp + Vbp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2 + v1;
1426 offset = mixer_offset<6>::value;
1427 break;
1428 case 0x70:
1429 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12);
1430 offset = mixer_offset<3>::value;
1431 break;
1432 case 0x71:
1433 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v1;
1434 offset = mixer_offset<4>::value;
1435 break;
1436 case 0x72:
1437 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v2;
1438 offset = mixer_offset<4>::value;
1439 break;
1440 case 0x73:
1441 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v2 + v1;
1442 offset = mixer_offset<5>::value;
1443 break;
1444 case 0x74:
1445 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3;
1446 offset = mixer_offset<4>::value;
1447 break;
1448 case 0x75:
1449 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v1;
1450 offset = mixer_offset<5>::value;
1451 break;
1452 case 0x76:
1453 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v2;
1454 offset = mixer_offset<5>::value;
1455 break;
1456 case 0x77:
1457 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + v3 + v2 + v1;
1458 offset = mixer_offset<6>::value;
1459 break;
1460 case 0x78:
1461 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve;
1462 offset = mixer_offset<4>::value;
1463 break;
1464 case 0x79:
1465 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v1;
1466 offset = mixer_offset<5>::value;
1467 break;
1468 case 0x7a:
1469 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v2;
1470 offset = mixer_offset<5>::value;
1471 break;
1472 case 0x7b:
1473 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v2 + v1;
1474 offset = mixer_offset<6>::value;
1475 break;
1476 case 0x7c:
1477 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3;
1478 offset = mixer_offset<5>::value;
1479 break;
1480 case 0x7d:
1481 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v1;
1482 offset = mixer_offset<6>::value;
1483 break;
1484 case 0x7e:
1485 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2;
1486 offset = mixer_offset<6>::value;
1487 break;
1488 case 0x7f:
1489 Vi = ((((Vhp + Vbp + Vlp) * f.filterGain) + dc_offset) >> 12) + ve + v3 + v2 + v1;
1490 offset = mixer_offset<7>::value;
1491 break;
1492 }
1493
1494 // Sum the inputs in the mixer and run the mixer output through the gain.
1495 const int idx1 = offset + Vi;
1496 assert((idx1 >= 0) && (idx1 < mixer_offset<8>::value));
1497 const int idx2 = f.mixer[idx1];
1498 assert((idx2 >= 0) && (idx2 < (1 << 16)));
1499 return (short)(f.gain[vol][idx2] - (1 << 15));
1500}
1501
1502
1503/*
1504Find output voltage in inverting gain and inverting summer SID op-amp
1505circuits, using a combination of Newton-Raphson and bisection.
1506
1507 ---R2--
1508 | |
1509 vi ---R1-----[A>----- vo
1510 vx
1511
1512From Kirchoff's current law it follows that
1513
1514 IR1f + IR2r = 0
1515
1516Substituting the triode mode transistor model K*W/L*(Vgst^2 - Vgdt^2)
1517for the currents, we get:
1518
1519 n*((Vddt - vx)^2 - (Vddt - vi)^2) + (Vddt - vx)^2 - (Vddt - vo)^2 = 0
1520
1521Our root function f can thus be written as:
1522
1523 f = (n + 1)*(Vddt - vx)^2 - n*(Vddt - vi)^2 - (Vddt - vo)^2 = 0
1524
1525We are using the mapping function x = vo - vx -> vx. We thus substitute
1526for vo = vx + x and get:
1527
1528 f(vx) = (n + 1)*(Vddt - vx)^2 - n*(Vddt - vi)^2 - (Vddt - (vx + x))^2 = 0
1529
1530Using substitution constants
1531
1532 a = n + 1
1533 b = Vddt
1534 c = n*(Vddt - vi)^2
1535
1536the equations for the root function can be written and expanded as:
1537
1538 f(vx) = a*(b - vx)^2 - c - (b - (vx + x))^2
1539 = a*(b^2 + vx^2 - 2*b*vx) - c - (b^2 + (vx + x)^2 - 2*b*(vx + x))
1540 = a*b^2 + a*vx^2 - 2*a*b*vx - c - b^2 - (vx + x)^2 + 2*b*(vx + x)
1541 = a*b^2 + a*vx^2 - 2*a*b*vx - c - b^2 - vx^2 - x^2 - 2*x*vx + 2*b*vx + 2*b*x
1542
1543Then we calculate the derivative:
1544
1545 f'(vx) = 2*a*vx - 2*a*b - 2*vx - 2*x + 2*b
1546 = 2*(a*vx - a*b - vx - x + b)
1547 = 2*(a*(vx - b) + b - (vx + x))
1548 = 2*(b - (vx + x) - a*(b - vx))
1549 = 2*(b - vo - a*(b - vx))
1550
1551Given f'(x) = df/dx, we have the resulting
1552
1553 df = 2*((b - (vx + x)) - a*(b - vx))*dvx
1554*/
1555#if 0
1556RESID_INLINE
1557int Filter::solve_gain(opamp_t* opamp, int n, int vi, int& x, model_filter_t& mf)
1558{
1559 // Note that all variables are translated and scaled in order to fit
1560 // in 16 bits. It is not necessary to explicitly translate the variables here,
1561 // since they are all used in subtractions which cancel out the translation:
1562 // (a - t) - (b - t) = a - b
1563
1564 // Start off with an estimate of x and a root bracket [ak, bk].
1565 // f is increasing, so that f(ak) < 0 and f(bk) > 0.
1566 int ak = mf.ak, bk = mf.bk;
1567
1568 int a = n + (1 << 7); // Scaled by 2^7
1569 int b = mf.kVddt; // Scaled by m*2^16
1570 int b_vi = b - vi; // Scaled by m*2^16
1571 if (b_vi < 0) b_vi = 0;
1572 int c = n*int(unsigned(b_vi)*unsigned(b_vi) >> 12); // Scaled by m^2*2^27
1573
1574 for (;;) {
1575 int xk = x;
1576
1577 // Calculate f and df.
1578 int vx = opamp[x].vx; // Scaled by m*2^16
1579 int dvx = opamp[x].dvx; // Scaled by 2^11
1580
1581 // f = a*(b - vx)^2 - c - (b - vo)^2
1582 // df = 2*((b - vo)*(dvx + 1) - a*(b - vx)*dvx)
1583 //
1584 int vo = vx + (x << 1) - (1 << 16);
1585 if (vo >= (1 << 16)) {
1586 vo = (1 << 16) - 1;
1587 }
1588 else if (vo < 0) {
1589 vo = 0;
1590 }
1591 int b_vx = b - vx;
1592 if (b_vx < 0) b_vx = 0;
1593 int b_vo = b - vo;
1594 if (b_vo < 0) b_vo = 0;
1595 // The dividend is scaled by m^2*2^27.
1596 int f = a*int(unsigned(b_vx)*unsigned(b_vx) >> 12) - c - int(unsigned(b_vo)*unsigned(b_vo) >> 5);
1597 // The divisor is scaled by m*2^11.
1598 int df = ((b_vo*(dvx + (1 << 11)) >> 1) - (a*(b_vx*dvx >> 8))) >> 14;
1599 // The resulting quotient is thus scaled by m*2^16.
1600
1601 // Newton-Raphson step: xk1 = xk - f(xk)/f'(xk)
1602 // If f(xk) or f'(xk) are zero then we can't improve further.
1603 if (df) {
1604 x -= f/df;
1605 }
1606 if (unlikely(x == xk)) {
1607 // No further root improvement possible.
1608 return vo;
1609 }
1610
1611 // Narrow down root bracket.
1612 if (f < 0) {
1613 // f(xk) < 0
1614 ak = xk;
1615 }
1616 else {
1617 // f(xk) > 0
1618 bk = xk;
1619 }
1620
1621 if (unlikely(x <= ak) || unlikely(x >= bk)) {
1622 // Bisection step (ala Dekker's method).
1623 x = (ak + bk) >> 1;
1624 if (unlikely(x == ak)) {
1625 // No further bisection possible.
1626 return vo;
1627 }
1628 }
1629 }
1630}
1631#endif
1632RESID_INLINE
1633int Filter::solve_gain_d(opamp_t* opamp, double n, int vi, int& x, model_filter_t& mf)
1634{
1635 // Note that all variables are translated and scaled in order to fit
1636 // in 16 bits. It is not necessary to explicitly translate the variables here,
1637 // since they are all used in subtractions which cancel out the translation:
1638 // (a - t) - (b - t) = a - b
1639
1640 // Start off with an estimate of x and a root bracket [ak, bk].
1641 // f is increasing, so that f(ak) < 0 and f(bk) > 0.
1642 int ak = mf.ak, bk = mf.bk;
1643
1644 double a = n + 1.;
1645 int b = mf.kVddt; // Scaled by m*2^16
1646 double b_vi = b > vi ? double(b - vi) : 0.; // Scaled by m*2^16
1647 double c = n*(b_vi*b_vi); // Scaled by m^2*2^32
1648
1649 for (;;) {
1650 int xk = x;
1651
1652 // Calculate f and df.
1653 int vx = opamp[x].vx; // Scaled by m*2^16
1654 int dvx = opamp[x].dvx; // Scaled by m*2^11
1655
1656 // f = a*(b - vx)^2 - c - (b - vo)^2
1657 // df = 2*((b - vo) - a*(b - vx))*dvx
1658 //
1659 int vo = vx + (x << 1) - (1 << 16);
1660 if (vo > (1 << 16) - 1) {
1661 vo = (1 << 16) - 1;
1662 }
1663 else if (vo < 0) {
1664 vo = 0;
1665 }
1666 double b_vx = b > vx ? double(b - vx) : 0.;
1667 double b_vo = b > vo ? double(b - vo) : 0.;
1668 // The dividend is scaled by m^2*2^32.
1669 double f = a*(b_vx*b_vx) - c - (b_vo*b_vo);
1670 // The divisor is scaled by m*2^27.
1671 double df = 2.*(b_vo - a*b_vx)*double(dvx);
1672 // The resulting quotient is thus scaled by m*2^5.
1673
1674 // Newton-Raphson step: xk1 = xk - f(xk)/f'(xk)
1675 // If f(xk) or f'(xk) are zero then we can't improve further.
1676 if (df) {
1677 // Multiply by 2^11 so it's scaled by m*2^16.
1678 x -= int(double(1<<11)*f/df);
1679 }
1680 if (unlikely(x == xk)) {
1681 // No further root improvement possible.
1682 return vo;
1683 }
1684
1685 // Narrow down root bracket.
1686 if (f < 0) {
1687 // f(xk) < 0
1688 ak = xk;
1689 }
1690 else {
1691 // f(xk) > 0
1692 bk = xk;
1693 }
1694
1695 if (unlikely(x <= ak) || unlikely(x >= bk)) {
1696 // Bisection step (ala Dekker's method).
1697 x = (ak + bk) >> 1;
1698 if (unlikely(x == ak)) {
1699 // No further bisection possible.
1700 return vo;
1701 }
1702 }
1703 }
1704}
1705
1706
1707/*
1708Find output voltage in inverting integrator SID op-amp circuits, using a
1709single fixpoint iteration step.
1710
1711A circuit diagram of a MOS 6581 integrator is shown below.
1712
1713 ---C---
1714 | |
1715 vi -----Rw-------[A>----- vo
1716 | | vx
1717 --Rs--
1718
1719From Kirchoff's current law it follows that
1720
1721 IRw + IRs + ICr = 0
1722
1723Using the formula for current through a capacitor, i = C*dv/dt, we get
1724
1725 IRw + IRs + C*(vc - vc0)/dt = 0
1726 dt/C*(IRw + IRs) + vc - vc0 = 0
1727 vc = vc0 - n*(IRw(vi,vx) + IRs(vi,vx))
1728
1729which may be rewritten as the following iterative fixpoint function:
1730
1731 vc = vc0 - n*(IRw(vi,g(vc)) + IRs(vi,g(vc)))
1732
1733To accurately calculate the currents through Rs and Rw, we need to use
1734transistor models. Rs has a gate voltage of Vdd = 12V, and can be
1735assumed to always be in triode mode. For Rw, the situation is rather
1736more complex, as it turns out that this transistor will operate in
1737both subthreshold, triode, and saturation modes.
1738
1739The Shichman-Hodges transistor model routinely used in textbooks may
1740be written as follows:
1741
1742 Ids = 0 , Vgst < 0 (subthreshold mode)
1743 Ids = K/2*W/L*(2*Vgst - Vds)*Vds , Vgst >= 0, Vds < Vgst (triode mode)
1744 Ids = K/2*W/L*Vgst^2 , Vgst >= 0, Vds >= Vgst (saturation mode)
1745
1746 where
1747 K = u*Cox (conductance)
1748 W/L = ratio between substrate width and length
1749 Vgst = Vg - Vs - Vt (overdrive voltage)
1750
1751This transistor model is also called the quadratic model.
1752
1753Note that the equation for the triode mode can be reformulated as
1754independent terms depending on Vgs and Vgd, respectively, by the
1755following substitution:
1756
1757 Vds = Vgst - (Vgst - Vds) = Vgst - Vgdt
1758
1759 Ids = K/2*W/L*(2*Vgst - Vds)*Vds
1760 = K/2*W/L*(2*Vgst - (Vgst - Vgdt)*(Vgst - Vgdt)
1761 = K/2*W/L*(Vgst + Vgdt)*(Vgst - Vgdt)
1762 = K/2*W/L*(Vgst^2 - Vgdt^2)
1763
1764This turns out to be a general equation which covers both the triode
1765and saturation modes (where the second term is 0 in saturation mode).
1766The equation is also symmetrical, i.e. it can calculate negative
1767currents without any change of parameters (since the terms for drain
1768and source are identical except for the sign).
1769
1770FIXME: Subthreshold as function of Vgs, Vgd.
1771 Ids = I0*e^(Vgst/(n*VT)) , Vgst < 0 (subthreshold mode)
1772
1773The remaining problem with the textbook model is that the transition
1774from subthreshold the triode/saturation is not continuous.
1775
1776Realizing that the subthreshold and triode/saturation modes may both
1777be defined by independent (and equal) terms of Vgs and Vds,
1778respectively, the corresponding terms can be blended into (equal)
1779continuous functions suitable for table lookup.
1780
1781The EKV model (Enz, Krummenacher and Vittoz) essentially performs this
1782blending using an elegant mathematical formulation:
1783
1784 Ids = Is*(if - ir)
1785 Is = ((2*u*Cox*Ut^2)/k)*W/L
1786 if = ln^2(1 + e^((k*(Vg - Vt) - Vs)/(2*Ut))
1787 ir = ln^2(1 + e^((k*(Vg - Vt) - Vd)/(2*Ut))
1788
1789For our purposes, the EKV model preserves two important properties
1790discussed above:
1791
1792- It consists of two independent terms, which can be represented by
1793 the same lookup table.
1794- It is symmetrical, i.e. it calculates current in both directions,
1795 facilitating a branch-free implementation.
1796
1797Rw in the circuit diagram above is a VCR (voltage controlled resistor),
1798as shown in the circuit diagram below.
1799
1800 Vw
1801
1802 |
1803 Vdd |
1804 |---|
1805 _|_ |
1806 -- --| Vg
1807 | __|__
1808 | ----- Rw
1809 | | |
1810 vi ------------ -------- vo
1811
1812
1813In order to calculalate the current through the VCR, its gate voltage
1814must be determined.
1815
1816Assuming triode mode and applying Kirchoff's current law, we get the
1817following equation for Vg:
1818
1819u*Cox/2*W/L*((Vddt - Vg)^2 - (Vddt - vi)^2 + (Vddt - Vg)^2 - (Vddt - Vw)^2) = 0
18202*(Vddt - Vg)^2 - (Vddt - vi)^2 - (Vddt - Vw)^2 = 0
1821(Vddt - Vg) = sqrt(((Vddt - vi)^2 + (Vddt - Vw)^2)/2)
1822
1823Vg = Vddt - sqrt(((Vddt - vi)^2 + (Vddt - Vw)^2)/2)
1824
1825*/
1826RESID_INLINE
1827int Filter::solve_integrate_6581(int dt, int vi, int& vx, int& vc, model_filter_t& mf)
1828{
1829 // Note that all variables are translated and scaled in order to fit
1830 // in 16 bits. It is not necessary to explicitly translate the variables here,
1831 // since they are all used in subtractions which cancel out the translation:
1832 // (a - t) - (b - t) = a - b
1833
1834 int kVddt = mf.kVddt; // Scaled by m*2^16
1835
1836 // "Snake" voltages for triode mode calculation.
1837 unsigned int Vgst = kVddt - vx;
1838 unsigned int Vgdt = kVddt - vi;
1839 unsigned int Vgdt_2 = Vgdt*Vgdt;
1840
1841 // "Snake" current, scaled by (1/m)*2^13*m*2^16*m*2^16*2^-15 = m*2^30
1842 int n_I_snake = n_snake*(int(Vgst*Vgst - Vgdt_2) >> 15);
1843
1844 // VCR gate voltage. // Scaled by m*2^16
1845 // Vg = Vddt - sqrt(((Vddt - Vw)^2 + Vgdt^2)/2)
1846 int kVg = vcr_kVg[(Vddt_Vw_2 + (Vgdt_2 >> 1)) >> 16];
1847
1848 // VCR voltages for EKV model table lookup.
1849 int Vgs = kVg - vx + (1 << 15);
1850 int Vgd = kVg - vi + (1 << 15);
1851
1852 // VCR current, scaled by m*2^15*2^15 = m*2^30
1853 int n_I_vcr = int(unsigned(vcr_n_Ids_term[Vgs] - vcr_n_Ids_term[Vgd]) << 15);
1854
1855 // Change in capacitor charge.
1856 vc -= (n_I_snake + n_I_vcr)*dt;
1857
1858/*
1859 // FIXME: Determine whether this check is necessary.
1860 if (vc < mf.vc_min) {
1861 vc = mf.vc_min;
1862 }
1863 else if (vc > mf.vc_max) {
1864 vc = mf.vc_max;
1865 }
1866*/
1867
1868 // vx = g(vc)
1869 const int idx = (vc >> 15) + (1 << 15);
1870 assert((idx >= 0) && (idx < (1 << 16)));
1871 vx = mf.opamp_rev[idx];
1872
1873 // Return vo.
1874 return vx + (vc >> 14);
1875}
1876
1877/*
1878The 8580 integrator is similar to those found in 6581
1879but the resistance is formed by multiple NMOS transistors
1880in parallel controlled by the fc bits where the gate voltage
1881is driven by a temperature dependent voltage divider.
1882
1883 ---C---
1884 | |
1885 vi -----Rfc------[A>----- vo
1886 vx
1887
1888 IRfc + ICr = 0
1889 IRfc + C*(vc - vc0)/dt = 0
1890 dt/C*(IRfc) + vc - vc0 = 0
1891 vc = vc0 - n*(IRfc(vi,vx))
1892 vc = vc0 - n*(IRfc(vi,g(vc)))
1893
1894IRfc = K/2*W/L*(Vgst^2 - Vgdt^2) = n*((Vgt - vx)^2 - (Vgt - vi)^2)
1895*/
1896RESID_INLINE
1897int Filter::solve_integrate_8580(int dt, int vi, int& vx, int& vc, model_filter_t& mf)
1898{
1899 // Note that all variables are translated and scaled in order to fit
1900 // in 16 bits. It is not necessary to explicitly translate the variables here,
1901 // since they are all used in subtractions which cancel out the translation:
1902 // (a - t) - (b - t) = a - b
1903
1904 // Dac voltages.
1905 unsigned int Vgst = nVgt - vx;
1906 unsigned int Vgdt = (vi < nVgt) ? nVgt - vi : 0; // triode/saturation mode
1907
1908 // Dac current, scaled by (1/m)*2^13*m*2^16*m*2^16*2^-15 = m*2^30
1909 int n_I_rfc = (n_dac*(int(Vgst*Vgst - Vgdt*Vgdt) >> 15)) >> 4;
1910
1911 // Change in capacitor charge.
1912 vc -= n_I_rfc*dt;
1913
1914 // vx = g(vc)
1915 const int idx = (vc >> 15) + (1 << 15);
1916 assert((idx >= 0) && (idx < (1 << 16)));
1917 vx = mf.opamp_rev[idx];
1918
1919 // Return vo.
1920 return vx + (vc >> 14);
1921}
1922
1923#endif // RESID_INLINING || defined(RESID_FILTER_CC)
1924
1925} // namespace reSID
1926
1927#endif // not RESID_FILTER_H