Fix potential threading issues with resid and residfp.
This commit is contained in:
parent
f3b44f7730
commit
7200229af3
5 changed files with 254 additions and 232 deletions
|
@ -17,6 +17,8 @@
|
|||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#define RESID_ENVELOPE_CC
|
||||
|
||||
#include "envelope.h"
|
||||
|
@ -156,18 +158,22 @@ unsigned short EnvelopeGenerator::model_dac[2][1 << 8] = {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Constructor.
|
||||
// ----------------------------------------------------------------------------
|
||||
static std::mutex g_class_init_mutex;
|
||||
static bool g_class_init = false;
|
||||
|
||||
EnvelopeGenerator::EnvelopeGenerator()
|
||||
{
|
||||
static bool class_init;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(g_class_init_mutex);
|
||||
if (!g_class_init) {
|
||||
// Build DAC lookup tables for 8-bit DACs.
|
||||
// MOS 6581: 2R/R ~ 2.20, missing termination resistor.
|
||||
build_dac_table(model_dac[0], 8, 2.20, false);
|
||||
// MOS 8580: 2R/R ~ 2.00, correct termination.
|
||||
build_dac_table(model_dac[1], 8, 2.00, true);
|
||||
|
||||
if (!class_init) {
|
||||
// Build DAC lookup tables for 8-bit DACs.
|
||||
// MOS 6581: 2R/R ~ 2.20, missing termination resistor.
|
||||
build_dac_table(model_dac[0], 8, 2.20, false);
|
||||
// MOS 8580: 2R/R ~ 2.00, correct termination.
|
||||
build_dac_table(model_dac[1], 8, 2.00, true);
|
||||
|
||||
class_init = true;
|
||||
g_class_init = true;
|
||||
}
|
||||
}
|
||||
|
||||
set_chip_model(MOS6581);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#define RESID_FILTER_CC
|
||||
|
||||
#ifdef _M_ARM
|
||||
|
@ -191,231 +193,235 @@ Filter::model_filter_t Filter::model_filter[2];
|
|||
// ----------------------------------------------------------------------------
|
||||
// Constructor.
|
||||
// ----------------------------------------------------------------------------
|
||||
static std::mutex g_class_init_mutex;
|
||||
static bool g_class_init = false;
|
||||
|
||||
Filter::Filter()
|
||||
{
|
||||
static bool class_init;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(g_class_init_mutex);
|
||||
if (!g_class_init) {
|
||||
// Temporary table for op-amp transfer function.
|
||||
int* opamp = new int[1 << 16];
|
||||
|
||||
if (!class_init) {
|
||||
// Temporary table for op-amp transfer function.
|
||||
int* opamp = new int[1 << 16];
|
||||
for (int m = 0; m < 2; m++) {
|
||||
model_filter_init_t& fi = model_filter_init[m];
|
||||
model_filter_t& mf = model_filter[m];
|
||||
|
||||
for (int m = 0; m < 2; m++) {
|
||||
model_filter_init_t& fi = model_filter_init[m];
|
||||
model_filter_t& mf = model_filter[m];
|
||||
// Convert op-amp voltage transfer to 16 bit values.
|
||||
double vmin = fi.opamp_voltage[0][0];
|
||||
double opamp_max = fi.opamp_voltage[0][1];
|
||||
double kVddt = fi.k*(fi.Vdd - fi.Vth);
|
||||
double vmax = kVddt < opamp_max ? opamp_max : kVddt;
|
||||
double denorm = vmax - vmin;
|
||||
double norm = 1.0/denorm;
|
||||
|
||||
// Convert op-amp voltage transfer to 16 bit values.
|
||||
double vmin = fi.opamp_voltage[0][0];
|
||||
double opamp_max = fi.opamp_voltage[0][1];
|
||||
double kVddt = fi.k*(fi.Vdd - fi.Vth);
|
||||
double vmax = kVddt < opamp_max ? opamp_max : kVddt;
|
||||
double denorm = vmax - vmin;
|
||||
double norm = 1.0/denorm;
|
||||
// Scaling and translation constants.
|
||||
double N16 = norm*((1u << 16) - 1);
|
||||
double N30 = norm*((1u << 30) - 1);
|
||||
double N31 = norm*((1u << 31) - 1);
|
||||
mf.vo_N16 = (int)(N16); // FIXME: Remove?
|
||||
|
||||
// Scaling and translation constants.
|
||||
double N16 = norm*((1u << 16) - 1);
|
||||
double N30 = norm*((1u << 30) - 1);
|
||||
double N31 = norm*((1u << 31) - 1);
|
||||
mf.vo_N16 = (int)(N16); // FIXME: Remove?
|
||||
// The "zero" output level of the voices.
|
||||
// The digital range of one voice is 20 bits; create a scaling term
|
||||
// for multiplication which fits in 11 bits.
|
||||
double N14 = norm*(1u << 14);
|
||||
mf.voice_scale_s14 = (int)(N14*fi.voice_voltage_range);
|
||||
mf.voice_DC = (int)(N16*(fi.voice_DC_voltage - vmin));
|
||||
|
||||
// The "zero" output level of the voices.
|
||||
// The digital range of one voice is 20 bits; create a scaling term
|
||||
// for multiplication which fits in 11 bits.
|
||||
double N14 = norm*(1u << 14);
|
||||
mf.voice_scale_s14 = (int)(N14*fi.voice_voltage_range);
|
||||
mf.voice_DC = (int)(N16*(fi.voice_DC_voltage - vmin));
|
||||
// Vdd - Vth, normalized so that translated values can be subtracted:
|
||||
// k*Vddt - x = (k*Vddt - t) - (x - t)
|
||||
mf.kVddt = (int)(N16*(kVddt - vmin) + 0.5);
|
||||
|
||||
// Vdd - Vth, normalized so that translated values can be subtracted:
|
||||
// k*Vddt - x = (k*Vddt - t) - (x - t)
|
||||
mf.kVddt = (int)(N16*(kVddt - vmin) + 0.5);
|
||||
// Normalized snake current factor, 1 cycle at 1MHz.
|
||||
// Fit in 5 bits.
|
||||
mf.n_snake = (int)(denorm*(1 << 13)*(fi.uCox/(2*fi.k)*fi.WL_snake*1.0e-6/fi.C) + 0.5);
|
||||
|
||||
// Normalized snake current factor, 1 cycle at 1MHz.
|
||||
// Fit in 5 bits.
|
||||
mf.n_snake = (int)(denorm*(1 << 13)*(fi.uCox/(2*fi.k)*fi.WL_snake*1.0e-6/fi.C) + 0.5);
|
||||
// Create lookup table mapping op-amp voltage across output and input
|
||||
// to input voltage: vo - vx -> vx
|
||||
// FIXME: No variable length arrays in ISO C++, hardcoding to max 50
|
||||
// points.
|
||||
// double_point scaled_voltage[fi.opamp_voltage_size];
|
||||
double_point scaled_voltage[50];
|
||||
|
||||
// Create lookup table mapping op-amp voltage across output and input
|
||||
// to input voltage: vo - vx -> vx
|
||||
// FIXME: No variable length arrays in ISO C++, hardcoding to max 50
|
||||
// points.
|
||||
// double_point scaled_voltage[fi.opamp_voltage_size];
|
||||
double_point scaled_voltage[50];
|
||||
for (int i = 0; i < fi.opamp_voltage_size; i++) {
|
||||
// The target output range is 16 bits, in order to fit in an unsigned
|
||||
// short.
|
||||
//
|
||||
// The y axis is temporarily scaled to 31 bits for maximum accuracy in
|
||||
// the calculated derivative.
|
||||
//
|
||||
// Values are normalized using
|
||||
//
|
||||
// x_n = m*2^N*(x - xmin)
|
||||
//
|
||||
// and are translated back later (for fixed point math) using
|
||||
//
|
||||
// m*2^N*x = x_n - m*2^N*xmin
|
||||
//
|
||||
scaled_voltage[fi.opamp_voltage_size - 1 - i][0] = int((N16*(fi.opamp_voltage[i][1] - fi.opamp_voltage[i][0]) + (1 << 16))/2 + 0.5);
|
||||
scaled_voltage[fi.opamp_voltage_size - 1 - i][1] = N31*(fi.opamp_voltage[i][0] - vmin);
|
||||
}
|
||||
|
||||
for (int i = 0; i < fi.opamp_voltage_size; i++) {
|
||||
// The target output range is 16 bits, in order to fit in an unsigned
|
||||
// short.
|
||||
// Clamp x to 16 bits (rounding may cause overflow).
|
||||
if (scaled_voltage[fi.opamp_voltage_size - 1][0] >= (1 << 16)) {
|
||||
// The last point is repeated.
|
||||
scaled_voltage[fi.opamp_voltage_size - 1][0] =
|
||||
scaled_voltage[fi.opamp_voltage_size - 2][0] = (1 << 16) - 1;
|
||||
}
|
||||
|
||||
interpolate(scaled_voltage, scaled_voltage + fi.opamp_voltage_size - 1,
|
||||
PointPlotter<int>(opamp), 1.0);
|
||||
|
||||
// Store both fn and dfn in the same table.
|
||||
mf.ak = (int)scaled_voltage[0][0];
|
||||
mf.bk = (int)scaled_voltage[fi.opamp_voltage_size - 1][0];
|
||||
int j;
|
||||
for (j = 0; j < mf.ak; j++) {
|
||||
opamp[j] = 0;
|
||||
}
|
||||
int f = opamp[j] - (opamp[j + 1] - opamp[j]);
|
||||
for (; j <= mf.bk; j++) {
|
||||
int fp = f;
|
||||
f = opamp[j]; // Scaled by m*2^31
|
||||
// m*2^31*dy/1 = (m*2^31*dy)/(m*2^16*dx) = 2^15*dy/dx
|
||||
int df = f - fp; // Scaled by 2^15
|
||||
|
||||
// High 16 bits (15 bits + sign bit): 2^11*dfn
|
||||
// Low 16 bits (unsigned): m*2^16*(fn - xmin)
|
||||
opamp[j] = ((df << (16 + 11 - 15)) & ~0xffff) | (f >> 15);
|
||||
}
|
||||
for (; j < (1 << 16); j++) {
|
||||
opamp[j] = 0;
|
||||
}
|
||||
|
||||
// Create lookup tables for gains / summers.
|
||||
|
||||
// 4 bit "resistor" ladders in the bandpass resonance gain and the audio
|
||||
// output gain necessitate 16 gain tables.
|
||||
// From die photographs of the bandpass and volume "resistor" ladders
|
||||
// it follows that gain ~ vol/8 and 1/Q ~ ~res/8 (assuming ideal
|
||||
// op-amps and ideal "resistors").
|
||||
for (int n8 = 0; n8 < 16; n8++) {
|
||||
int n = n8 << 4; // Scaled by 2^7
|
||||
int x = mf.ak;
|
||||
for (int vi = 0; vi < (1 << 16); vi++) {
|
||||
mf.gain[n8][vi] = solve_gain(opamp, n, vi, x, mf);
|
||||
}
|
||||
}
|
||||
|
||||
// The filter summer operates at n ~ 1, and has 5 fundamentally different
|
||||
// input configurations (2 - 6 input "resistors").
|
||||
//
|
||||
// The y axis is temporarily scaled to 31 bits for maximum accuracy in
|
||||
// the calculated derivative.
|
||||
// Note that all "on" transistors are modeled as one. This is not
|
||||
// entirely accurate, since the input for each transistor is different,
|
||||
// and transistors are not linear components. However modeling all
|
||||
// transistors separately would be extremely costly.
|
||||
int offset = 0;
|
||||
int size;
|
||||
for (int k = 0; k < 5; k++) {
|
||||
int idiv = 2 + k; // 2 - 6 input "resistors".
|
||||
int n_idiv = idiv << 7; // n*idiv, scaled by 2^7
|
||||
size = idiv << 16;
|
||||
int x = mf.ak;
|
||||
for (int vi = 0; vi < size; vi++) {
|
||||
mf.summer[offset + vi] =
|
||||
solve_gain(opamp, n_idiv, vi/idiv, x, mf);
|
||||
}
|
||||
offset += size;
|
||||
}
|
||||
|
||||
// The audio mixer operates at n ~ 8/6, and has 8 fundamentally different
|
||||
// input configurations (0 - 7 input "resistors").
|
||||
//
|
||||
// Values are normalized using
|
||||
//
|
||||
// x_n = m*2^N*(x - xmin)
|
||||
//
|
||||
// and are translated back later (for fixed point math) using
|
||||
//
|
||||
// m*2^N*x = x_n - m*2^N*xmin
|
||||
//
|
||||
scaled_voltage[fi.opamp_voltage_size - 1 - i][0] = int((N16*(fi.opamp_voltage[i][1] - fi.opamp_voltage[i][0]) + (1 << 16))/2 + 0.5);
|
||||
scaled_voltage[fi.opamp_voltage_size - 1 - i][1] = N31*(fi.opamp_voltage[i][0] - vmin);
|
||||
}
|
||||
// All "on", transistors are modeled as one - see comments above for
|
||||
// the filter summer.
|
||||
offset = 0;
|
||||
size = 1; // Only one lookup element for 0 input "resistors".
|
||||
for (int l = 0; l < 8; l++) {
|
||||
int idiv = l; // 0 - 7 input "resistors".
|
||||
int n_idiv = (idiv << 7)*8/6; // n*idiv, scaled by 2^7
|
||||
if (idiv == 0) {
|
||||
// Avoid division by zero; the result will be correct since
|
||||
// n_idiv = 0.
|
||||
idiv = 1;
|
||||
}
|
||||
int x = mf.ak;
|
||||
for (int vi = 0; vi < size; vi++) {
|
||||
mf.mixer[offset + vi] =
|
||||
solve_gain(opamp, n_idiv, vi/idiv, x, mf);
|
||||
}
|
||||
offset += size;
|
||||
size = (l + 1) << 16;
|
||||
}
|
||||
|
||||
// Clamp x to 16 bits (rounding may cause overflow).
|
||||
if (scaled_voltage[fi.opamp_voltage_size - 1][0] >= (1 << 16)) {
|
||||
// The last point is repeated.
|
||||
scaled_voltage[fi.opamp_voltage_size - 1][0] =
|
||||
scaled_voltage[fi.opamp_voltage_size - 2][0] = (1 << 16) - 1;
|
||||
}
|
||||
// Create lookup table mapping capacitor voltage to op-amp input voltage:
|
||||
// vc -> vx
|
||||
for (int m = 0; m < (1 << 16); m++) {
|
||||
mf.opamp_rev[m] = opamp[m] & 0xffff;
|
||||
}
|
||||
|
||||
interpolate(scaled_voltage, scaled_voltage + fi.opamp_voltage_size - 1,
|
||||
PointPlotter<int>(opamp), 1.0);
|
||||
mf.vc_max = (int)(N30*(fi.opamp_voltage[0][1] - fi.opamp_voltage[0][0]));
|
||||
mf.vc_min = (int)(N30*(fi.opamp_voltage[fi.opamp_voltage_size - 1][1] - fi.opamp_voltage[fi.opamp_voltage_size - 1][0]));
|
||||
|
||||
// Store both fn and dfn in the same table.
|
||||
mf.ak = (int)scaled_voltage[0][0];
|
||||
mf.bk = (int)scaled_voltage[fi.opamp_voltage_size - 1][0];
|
||||
int j;
|
||||
for (j = 0; j < mf.ak; j++) {
|
||||
opamp[j] = 0;
|
||||
}
|
||||
int f = opamp[j] - (opamp[j + 1] - opamp[j]);
|
||||
for (; j <= mf.bk; j++) {
|
||||
int fp = f;
|
||||
f = opamp[j]; // Scaled by m*2^31
|
||||
// m*2^31*dy/1 = (m*2^31*dy)/(m*2^16*dx) = 2^15*dy/dx
|
||||
int df = f - fp; // Scaled by 2^15
|
||||
|
||||
// High 16 bits (15 bits + sign bit): 2^11*dfn
|
||||
// Low 16 bits (unsigned): m*2^16*(fn - xmin)
|
||||
opamp[j] = ((df << (16 + 11 - 15)) & ~0xffff) | (f >> 15);
|
||||
}
|
||||
for (; j < (1 << 16); j++) {
|
||||
opamp[j] = 0;
|
||||
}
|
||||
|
||||
// Create lookup tables for gains / summers.
|
||||
|
||||
// 4 bit "resistor" ladders in the bandpass resonance gain and the audio
|
||||
// output gain necessitate 16 gain tables.
|
||||
// From die photographs of the bandpass and volume "resistor" ladders
|
||||
// it follows that gain ~ vol/8 and 1/Q ~ ~res/8 (assuming ideal
|
||||
// op-amps and ideal "resistors").
|
||||
for (int n8 = 0; n8 < 16; n8++) {
|
||||
int n = n8 << 4; // Scaled by 2^7
|
||||
int x = mf.ak;
|
||||
for (int vi = 0; vi < (1 << 16); vi++) {
|
||||
mf.gain[n8][vi] = solve_gain(opamp, n, vi, x, mf);
|
||||
// DAC table.
|
||||
int bits = 11;
|
||||
build_dac_table(mf.f0_dac, bits, fi.dac_2R_div_R, fi.dac_term);
|
||||
for (int n = 0; n < (1 << bits); n++) {
|
||||
mf.f0_dac[n] = (unsigned short)(N16*(fi.dac_zero + mf.f0_dac[n]*fi.dac_scale/(1 << bits) - vmin) + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// The filter summer operates at n ~ 1, and has 5 fundamentally different
|
||||
// input configurations (2 - 6 input "resistors").
|
||||
//
|
||||
// Note that all "on" transistors are modeled as one. This is not
|
||||
// entirely accurate, since the input for each transistor is different,
|
||||
// and transistors are not linear components. However modeling all
|
||||
// transistors separately would be extremely costly.
|
||||
int offset = 0;
|
||||
int size;
|
||||
for (int k = 0; k < 5; k++) {
|
||||
int idiv = 2 + k; // 2 - 6 input "resistors".
|
||||
int n_idiv = idiv << 7; // n*idiv, scaled by 2^7
|
||||
size = idiv << 16;
|
||||
int x = mf.ak;
|
||||
for (int vi = 0; vi < size; vi++) {
|
||||
mf.summer[offset + vi] =
|
||||
solve_gain(opamp, n_idiv, vi/idiv, x, mf);
|
||||
}
|
||||
offset += size;
|
||||
// Free temporary table.
|
||||
delete[] opamp;
|
||||
|
||||
// VCR - 6581 only.
|
||||
model_filter_init_t& fi = model_filter_init[0];
|
||||
|
||||
double N16 = model_filter[0].vo_N16;
|
||||
double vmin = N16*fi.opamp_voltage[0][0];
|
||||
double k = fi.k;
|
||||
double kVddt = N16*(k*(fi.Vdd - fi.Vth));
|
||||
|
||||
for (int i = 0; i < (1 << 16); i++) {
|
||||
// The table index is right-shifted 16 times in order to fit in
|
||||
// 16 bits; the argument to sqrt is thus multiplied by (1 << 16).
|
||||
//
|
||||
// The returned value must be corrected for translation. Vg always
|
||||
// takes part in a subtraction as follows:
|
||||
//
|
||||
// k*Vg - Vx = (k*Vg - t) - (Vx - t)
|
||||
//
|
||||
// I.e. k*Vg - t must be returned.
|
||||
double Vg = kVddt - sqrt((double)i*(1 << 16));
|
||||
vcr_kVg[i] = (unsigned short)(k*Vg - vmin + 0.5);
|
||||
}
|
||||
|
||||
// The audio mixer operates at n ~ 8/6, and has 8 fundamentally different
|
||||
// input configurations (0 - 7 input "resistors").
|
||||
//
|
||||
// All "on", transistors are modeled as one - see comments above for
|
||||
// the filter summer.
|
||||
offset = 0;
|
||||
size = 1; // Only one lookup element for 0 input "resistors".
|
||||
for (int l = 0; l < 8; l++) {
|
||||
int idiv = l; // 0 - 7 input "resistors".
|
||||
int n_idiv = (idiv << 7)*8/6; // n*idiv, scaled by 2^7
|
||||
if (idiv == 0) {
|
||||
// Avoid division by zero; the result will be correct since
|
||||
// n_idiv = 0.
|
||||
idiv = 1;
|
||||
}
|
||||
int x = mf.ak;
|
||||
for (int vi = 0; vi < size; vi++) {
|
||||
mf.mixer[offset + vi] =
|
||||
solve_gain(opamp, n_idiv, vi/idiv, x, mf);
|
||||
}
|
||||
offset += size;
|
||||
size = (l + 1) << 16;
|
||||
/*
|
||||
EKV model:
|
||||
|
||||
Ids = Is*(if - ir)
|
||||
Is = 2*u*Cox*Ut^2/k*W/L
|
||||
if = ln^2(1 + e^((k*(Vg - Vt) - Vs)/(2*Ut))
|
||||
ir = ln^2(1 + e^((k*(Vg - Vt) - Vd)/(2*Ut))
|
||||
*/
|
||||
double kVt = fi.k*fi.Vth;
|
||||
double Ut = fi.Ut;
|
||||
double Is = 2*fi.uCox*Ut*Ut/fi.k*fi.WL_vcr;
|
||||
// Normalized current factor for 1 cycle at 1MHz.
|
||||
double N15 = N16/2;
|
||||
double n_Is = N15*1.0e-6/fi.C*Is;
|
||||
|
||||
// kVg_Vx = k*Vg - Vx
|
||||
// I.e. if k != 1.0, Vg must be scaled accordingly.
|
||||
for (int kVg_Vx = 0; kVg_Vx < (1 << 16); kVg_Vx++) {
|
||||
double log_term = log1p(exp((kVg_Vx/N16 - kVt)/(2*Ut)));
|
||||
// Scaled by m*2^15
|
||||
vcr_n_Ids_term[kVg_Vx] = (unsigned short)(n_Is*log_term*log_term);
|
||||
}
|
||||
|
||||
// Create lookup table mapping capacitor voltage to op-amp input voltage:
|
||||
// vc -> vx
|
||||
for (int m = 0; m < (1 << 16); m++) {
|
||||
mf.opamp_rev[m] = opamp[m] & 0xffff;
|
||||
}
|
||||
|
||||
mf.vc_max = (int)(N30*(fi.opamp_voltage[0][1] - fi.opamp_voltage[0][0]));
|
||||
mf.vc_min = (int)(N30*(fi.opamp_voltage[fi.opamp_voltage_size - 1][1] - fi.opamp_voltage[fi.opamp_voltage_size - 1][0]));
|
||||
|
||||
// DAC table.
|
||||
int bits = 11;
|
||||
build_dac_table(mf.f0_dac, bits, fi.dac_2R_div_R, fi.dac_term);
|
||||
for (int n = 0; n < (1 << bits); n++) {
|
||||
mf.f0_dac[n] = (unsigned short)(N16*(fi.dac_zero + mf.f0_dac[n]*fi.dac_scale/(1 << bits) - vmin) + 0.5);
|
||||
}
|
||||
g_class_init = true;
|
||||
}
|
||||
|
||||
// Free temporary table.
|
||||
delete[] opamp;
|
||||
|
||||
// VCR - 6581 only.
|
||||
model_filter_init_t& fi = model_filter_init[0];
|
||||
|
||||
double N16 = model_filter[0].vo_N16;
|
||||
double vmin = N16*fi.opamp_voltage[0][0];
|
||||
double k = fi.k;
|
||||
double kVddt = N16*(k*(fi.Vdd - fi.Vth));
|
||||
|
||||
for (int i = 0; i < (1 << 16); i++) {
|
||||
// The table index is right-shifted 16 times in order to fit in
|
||||
// 16 bits; the argument to sqrt is thus multiplied by (1 << 16).
|
||||
//
|
||||
// The returned value must be corrected for translation. Vg always
|
||||
// takes part in a subtraction as follows:
|
||||
//
|
||||
// k*Vg - Vx = (k*Vg - t) - (Vx - t)
|
||||
//
|
||||
// I.e. k*Vg - t must be returned.
|
||||
double Vg = kVddt - sqrt((double)i*(1 << 16));
|
||||
vcr_kVg[i] = (unsigned short)(k*Vg - vmin + 0.5);
|
||||
}
|
||||
|
||||
/*
|
||||
EKV model:
|
||||
|
||||
Ids = Is*(if - ir)
|
||||
Is = 2*u*Cox*Ut^2/k*W/L
|
||||
if = ln^2(1 + e^((k*(Vg - Vt) - Vs)/(2*Ut))
|
||||
ir = ln^2(1 + e^((k*(Vg - Vt) - Vd)/(2*Ut))
|
||||
*/
|
||||
double kVt = fi.k*fi.Vth;
|
||||
double Ut = fi.Ut;
|
||||
double Is = 2*fi.uCox*Ut*Ut/fi.k*fi.WL_vcr;
|
||||
// Normalized current factor for 1 cycle at 1MHz.
|
||||
double N15 = N16/2;
|
||||
double n_Is = N15*1.0e-6/fi.C*Is;
|
||||
|
||||
// kVg_Vx = k*Vg - Vx
|
||||
// I.e. if k != 1.0, Vg must be scaled accordingly.
|
||||
for (int kVg_Vx = 0; kVg_Vx < (1 << 16); kVg_Vx++) {
|
||||
double log_term = log1p(exp((kVg_Vx/N16 - kVt)/(2*Ut)));
|
||||
// Scaled by m*2^15
|
||||
vcr_n_Ids_term[kVg_Vx] = (unsigned short)(n_Is*log_term*log_term);
|
||||
}
|
||||
|
||||
class_init = true;
|
||||
}
|
||||
|
||||
enable_filter(true);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#define RESID_WAVE_CC
|
||||
|
||||
#include "wave.h"
|
||||
|
@ -60,34 +62,38 @@ unsigned short WaveformGenerator::model_dac[2][1 << 12] = {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Constructor.
|
||||
// ----------------------------------------------------------------------------
|
||||
static std::mutex g_class_init_mutex;
|
||||
static bool g_class_init = false;
|
||||
|
||||
WaveformGenerator::WaveformGenerator()
|
||||
{
|
||||
static bool class_init;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(g_class_init_mutex);
|
||||
if (!g_class_init) {
|
||||
// Calculate tables for normal waveforms.
|
||||
accumulator = 0;
|
||||
for (int i = 0; i < (1 << 12); i++) {
|
||||
reg24 msb = accumulator & 0x800000;
|
||||
|
||||
if (!class_init) {
|
||||
// Calculate tables for normal waveforms.
|
||||
accumulator = 0;
|
||||
for (int i = 0; i < (1 << 12); i++) {
|
||||
reg24 msb = accumulator & 0x800000;
|
||||
// Noise mask, triangle, sawtooth, pulse mask.
|
||||
// The triangle calculation is made branch-free, just for the hell of it.
|
||||
model_wave[0][0][i] = model_wave[1][0][i] = 0xfff;
|
||||
model_wave[0][1][i] = model_wave[1][1][i] =
|
||||
((accumulator ^ -!!msb) >> 11) & 0xffe;
|
||||
model_wave[0][2][i] = model_wave[1][2][i] = accumulator >> 12;
|
||||
model_wave[0][4][i] = model_wave[1][4][i] = 0xfff;
|
||||
|
||||
// Noise mask, triangle, sawtooth, pulse mask.
|
||||
// The triangle calculation is made branch-free, just for the hell of it.
|
||||
model_wave[0][0][i] = model_wave[1][0][i] = 0xfff;
|
||||
model_wave[0][1][i] = model_wave[1][1][i] =
|
||||
((accumulator ^ -!!msb) >> 11) & 0xffe;
|
||||
model_wave[0][2][i] = model_wave[1][2][i] = accumulator >> 12;
|
||||
model_wave[0][4][i] = model_wave[1][4][i] = 0xfff;
|
||||
accumulator += 0x1000;
|
||||
}
|
||||
|
||||
accumulator += 0x1000;
|
||||
// Build DAC lookup tables for 12-bit DACs.
|
||||
// MOS 6581: 2R/R ~ 2.20, missing termination resistor.
|
||||
build_dac_table(model_dac[0], 12, 2.20, false);
|
||||
// MOS 8580: 2R/R ~ 2.00, correct termination.
|
||||
build_dac_table(model_dac[1], 12, 2.00, true);
|
||||
|
||||
class_init = true;
|
||||
}
|
||||
|
||||
// Build DAC lookup tables for 12-bit DACs.
|
||||
// MOS 6581: 2R/R ~ 2.20, missing termination resistor.
|
||||
build_dac_table(model_dac[0], 12, 2.20, false);
|
||||
// MOS 8580: 2R/R ~ 2.00, correct termination.
|
||||
build_dac_table(model_dac[1], 12, 2.00, true);
|
||||
|
||||
class_init = true;
|
||||
}
|
||||
|
||||
sync_source = this;
|
||||
|
|
|
@ -172,6 +172,8 @@ short calculateCombinedWaveform(CombinedWaveformConfig config, int waveform, int
|
|||
|
||||
matrix_t* WaveformCalculator::buildTable(ChipModel model)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(CACHE_LOCK);
|
||||
|
||||
const CombinedWaveformConfig* cfgArray = config[model == MOS6581 ? 0 : 1];
|
||||
|
||||
cw_cache_t::iterator lb = CACHE.lower_bound(cfgArray);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define WAVEFORMCALCULATOR_h
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
#include "siddefs-fp.h"
|
||||
#include "array.h"
|
||||
|
@ -95,6 +96,7 @@ private:
|
|||
typedef std::map<const CombinedWaveformConfig*, matrix_t> cw_cache_t;
|
||||
|
||||
private:
|
||||
std::mutex CACHE_LOCK;
|
||||
cw_cache_t CACHE;
|
||||
|
||||
WaveformCalculator() {}
|
||||
|
|
Loading…
Reference in a new issue