summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/sound/disc_mth.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/sound/disc_mth.c')
-rw-r--r--trunk/src/emu/sound/disc_mth.c2771
1 files changed, 2771 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/disc_mth.c b/trunk/src/emu/sound/disc_mth.c
new file mode 100644
index 00000000000..4fe5b39d310
--- /dev/null
+++ b/trunk/src/emu/sound/disc_mth.c
@@ -0,0 +1,2771 @@
+/************************************************************************
+ *
+ * MAME - Discrete sound system emulation library
+ *
+ * Written by Keith Wilkins (mame@esplexo.co.uk)
+ *
+ * (c) K.Wilkins 2000
+ * (c) D.Renaud 2003-2004
+ *
+ ************************************************************************
+ *
+ * DST_ADDDER - Multichannel adder
+ * DST_BITS_DECODE - Decode Bits from input node
+ * DST_CLAMP - Simple signal clamping circuit
+ * DST_COMP_ADDER - Selectable parallel component circuit
+ * DST_DAC_R1 - R1 Ladder DAC with cap filtering
+ * DST_DIODE_MIX - Diode mixer
+ * DST_DIVIDE - Division function
+ * DST_GAIN - Gain Factor
+ * DST_INTEGRATE - Integration circuits
+ * DST_LOGIC_INV - Logic level invertor
+ * DST_LOGIC_AND - Logic AND gate 4 input
+ * DST_LOGIC_NAND - Logic NAND gate 4 input
+ * DST_LOGIC_OR - Logic OR gate 4 input
+ * DST_LOGIC_NOR - Logic NOR gate 4 input
+ * DST_LOGIC_XOR - Logic XOR gate 2 input
+ * DST_LOGIC_NXOR - Logic NXOR gate 2 input
+ * DST_LOGIC_DFF - Logic D-type flip/flop
+ * DST_LOGIC_JKFF - Logic JK-type flip/flop
+ * DST_LOGIC_SHIFT - Logic Shift Register
+ * DST_LOOKUP_TABLE - Return value from lookup table
+ * DST_MIXER - Final Mixer Stage
+ * DST_MULTIPLEX - 1 of x Multiplexer/switch
+ * DST_ONESHOT - One shot pulse generator
+ * DST_RAMP - Ramp up/down
+ * DST_SAMPHOLD - Sample & Hold Implementation
+ * DST_SWITCH - Switch implementation
+ * DST_ASWITCH - Analog switch
+ * DST_TRANSFORM - Multiple math functions
+ * DST_OP_AMP - Op Amp circuits
+ * DST_OP_AMP_1SHT - Op Amp One Shot
+ * DST_TVCA_OP_AMP - Triggered op amp voltage controlled amplifier
+ * DST_XTIME_BUFFER - Buffer/Invertor gate implementation using X_TIME
+ * DST_XTIME_AND - AND/NAND gate implementation using X_TIME
+ * DST_XTIME_OR - OR/NOR gate implementation using X_TIME
+ * DST_XTIME_XOR - XOR/XNOR gate implementation using X_TIME
+ *
+ ************************************************************************/
+
+#include <float.h>
+
+
+
+/************************************************************************
+ *
+ * DST_ADDER - This is a 4 channel input adder with enable function
+ *
+ * input[0] - Enable input value
+ * input[1] - Channel0 input value
+ * input[2] - Channel1 input value
+ * input[3] - Channel2 input value
+ * input[4] - Channel3 input value
+ *
+ ************************************************************************/
+#define DST_ADDER__ENABLE DISCRETE_INPUT(0)
+#define DST_ADDER__IN0 DISCRETE_INPUT(1)
+#define DST_ADDER__IN1 DISCRETE_INPUT(2)
+#define DST_ADDER__IN2 DISCRETE_INPUT(3)
+#define DST_ADDER__IN3 DISCRETE_INPUT(4)
+
+DISCRETE_STEP(dst_adder)
+{
+ if(DST_ADDER__ENABLE)
+ {
+ set_output(0, DST_ADDER__IN0 + DST_ADDER__IN1 + DST_ADDER__IN2 + DST_ADDER__IN3);
+ }
+ else
+ {
+ set_output(0, 0);
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_COMP_ADDER - Selectable parallel component adder
+ *
+ * input[0] - Bit Select
+ *
+ * Also passed discrete_comp_adder_table structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DST_COMP_ADDER__SELECT DISCRETE_INPUT(0)
+
+DISCRETE_STEP(dst_comp_adder)
+{
+ int select;
+
+ select = (int)DST_COMP_ADDER__SELECT;
+ assert(select < 256);
+ set_output(0, m_total[select]);
+}
+
+DISCRETE_RESET(dst_comp_adder)
+{
+ DISCRETE_DECLARE_INFO(discrete_comp_adder_table)
+
+ int i, bit;
+ int bit_length = info->length;
+
+ assert(bit_length <= 8);
+
+ /* pre-calculate all possible values to speed up step routine */
+ for(i = 0; i < 256; i++)
+ {
+ switch (info->type)
+ {
+ case DISC_COMP_P_CAPACITOR:
+ m_total[i] = info->cDefault;
+ for(bit = 0; bit < bit_length; bit++)
+ {
+ if (i & (1 << bit))
+ m_total[i] += info->c[bit];
+ }
+ break;
+ case DISC_COMP_P_RESISTOR:
+ m_total[i] = (info->cDefault != 0) ? 1.0 / info->cDefault : 0;
+ for(bit = 0; bit < bit_length; bit++)
+ {
+ if ((i & (1 << bit)) && (info->c[bit] != 0))
+ m_total[i] += 1.0 / info->c[bit];
+ }
+ if (m_total[i] != 0)
+ m_total[i] = 1.0 / m_total[i];
+ break;
+ }
+ }
+ set_output(0, m_total[0]);
+}
+
+/************************************************************************
+ *
+ * DST_CLAMP - Simple signal clamping circuit
+ *
+ * input[0] - Input value
+ * input[1] - Minimum value
+ * input[2] - Maximum value
+ *
+ ************************************************************************/
+#define DST_CLAMP__IN DISCRETE_INPUT(0)
+#define DST_CLAMP__MIN DISCRETE_INPUT(1)
+#define DST_CLAMP__MAX DISCRETE_INPUT(2)
+
+DISCRETE_STEP(dst_clamp)
+{
+ if (DST_CLAMP__IN < DST_CLAMP__MIN)
+ set_output(0, DST_CLAMP__MIN);
+ else if (DST_CLAMP__IN > DST_CLAMP__MAX)
+ set_output(0, DST_CLAMP__MAX);
+ else
+ set_output(0, DST_CLAMP__IN);
+}
+
+
+/************************************************************************
+ *
+ * DST_DAC_R1 - R1 Ladder DAC with cap smoothing
+ *
+ * input[0] - Binary Data Input
+ * input[1] - Data On Voltage (3.4 for TTL)
+ *
+ * also passed discrete_dac_r1_ladder structure
+ *
+ * Mar 2004, D Renaud.
+ * Nov 2010, D Renaud. - optimized for speed
+ ************************************************************************/
+#define DST_DAC_R1__DATA DISCRETE_INPUT(0)
+#define DST_DAC_R1__VON DISCRETE_INPUT(1)
+
+DISCRETE_STEP(dst_dac_r1)
+{
+ int data = (int)DST_DAC_R1__DATA;
+ double v = m_v_step[data];
+ double x_time = DST_DAC_R1__DATA - data;
+ double last_v = m_last_v;
+
+ m_last_v = v;
+
+ if (x_time > 0)
+ v = x_time * (v - last_v) + last_v;
+
+ /* Filter if needed, else just output voltage */
+ if (m_has_c_filter)
+ {
+ double v_diff = v - m_v_out;
+ /* optimization - if charged close enough to voltage */
+ if (fabs(v_diff) < 0.000001)
+ m_v_out = v;
+ else
+ {
+ m_v_out += v_diff * m_exponent;
+ }
+ }
+ else
+ m_v_out = v;
+
+ set_output(0, m_v_out);
+}
+
+DISCRETE_RESET(dst_dac_r1)
+{
+ DISCRETE_DECLARE_INFO(discrete_dac_r1_ladder)
+
+ int bit;
+ int ladderLength = info->ladderLength;
+ int total_steps = 1 << ladderLength;
+ double r_total = 0;
+ double i_bias;
+ double v_on = DST_DAC_R1__VON;
+
+ m_last_v = 0;
+
+ /* Calculate the Millman current of the bias circuit */
+ if (info->rBias > 0)
+ i_bias = info->vBias / info->rBias;
+ else
+ i_bias = 0;
+
+ /*
+ * We will do a small amount of error checking.
+ * But if you are an idiot and pass a bad ladder table
+ * then you deserve a crash.
+ */
+ if (ladderLength < 2 && info->rBias == 0 && info->rGnd == 0)
+ {
+ /* You need at least 2 resistors for a ladder */
+ m_device->discrete_log("dst_dac_r1_reset - Ladder length too small");
+ }
+ if (ladderLength > DISC_LADDER_MAXRES )
+ {
+ m_device->discrete_log("dst_dac_r1_reset - Ladder length exceeds DISC_LADDER_MAXRES");
+ }
+
+ /*
+ * Calculate the total of all resistors in parallel.
+ * This is the combined resistance of the voltage sources.
+ * This is used for the charging curve.
+ */
+ for(bit = 0; bit < ladderLength; bit++)
+ {
+ if (info->r[bit] > 0)
+ r_total += 1.0 / info->r[bit];
+ }
+ if (info->rBias > 0) r_total += 1.0 / info->rBias;
+ if (info->rGnd > 0) r_total += 1.0 / info->rGnd;
+ r_total = 1.0 / r_total;
+
+ m_v_out = 0;
+
+ if (info->cFilter > 0)
+ {
+ m_has_c_filter = 1;
+ /* Setup filter constant */
+ m_exponent = RC_CHARGE_EXP(r_total * info->cFilter);
+ }
+ else
+ m_has_c_filter = 0;
+
+ /* pre-calculate all possible values to speed up step routine */
+ for(int i = 0; i < total_steps; i++)
+ {
+ double i_total = i_bias;
+ for (bit = 0; bit < ladderLength; bit++)
+ {
+ /* Add up currents of ON circuits per Millman. */
+
+ /* ignore if no resistor present */
+ if (EXPECTED(info->r[bit] > 0))
+ {
+ double i_bit;
+ int bit_val = (i >> bit) & 0x01;
+
+ if (bit_val != 0)
+ i_bit = v_on / info->r[bit];
+ else
+ i_bit = 0;
+ i_total += i_bit;
+ }
+ }
+ m_v_step[i] = i_total * r_total;
+ }
+}
+
+
+/************************************************************************
+*
+ * DST_DIODE_MIX - Diode Mixer
+ *
+ * input[0] - Input 0
+ * .....
+ *
+ * Dec 2004, D Renaud.
+ ************************************************************************/
+#define DST_DIODE_MIX_INP_OFFSET 0
+#define DST_DIODE_MIX__INP(addr) DISCRETE_INPUT(DST_DIODE_MIX_INP_OFFSET + addr)
+
+DISCRETE_STEP(dst_diode_mix)
+{
+ double val, max = 0;
+ int addr;
+
+ for (addr = 0; addr < m_size; addr++)
+ {
+ val = DST_DIODE_MIX__INP(addr) - m_v_junction[addr];
+ if (val > max) max = val;
+ }
+ if (max < 0) max = 0;
+ set_output(0, max);
+}
+
+DISCRETE_RESET(dst_diode_mix)
+{
+ DISCRETE_DECLARE_INFO(double)
+
+ int addr;
+
+ m_size = this->active_inputs() - DST_DIODE_MIX_INP_OFFSET;
+ assert(m_size <= 8);
+
+ for (addr = 0; addr < m_size; addr++)
+ {
+ if (info == NULL)
+ {
+ /* setup default junction voltage */
+ m_v_junction[addr] = 0.5;
+ }
+ else
+ {
+ /* use supplied junction voltage */
+ m_v_junction[addr] = *info++;
+ }
+ }
+ this->step();
+}
+
+
+/************************************************************************
+ *
+ * DST_DIVIDE - Programmable divider with enable
+ *
+ * input[0] - Enable input value
+ * input[1] - Channel0 input value
+ * input[2] - Divisor
+ *
+ ************************************************************************/
+#define DST_DIVIDE__ENABLE DISCRETE_INPUT(0)
+#define DST_DIVIDE__IN DISCRETE_INPUT(1)
+#define DST_DIVIDE__DIV DISCRETE_INPUT(2)
+
+DISCRETE_STEP(dst_divide)
+{
+ if(DST_DIVIDE__ENABLE)
+ {
+ if(DST_DIVIDE__DIV == 0)
+ {
+ set_output(0, DBL_MAX); /* Max out but don't break */
+ m_device->discrete_log("dst_divider_step() - Divide by Zero attempted in NODE_%02d.\n",this->index());
+ }
+ else
+ {
+ set_output(0, DST_DIVIDE__IN / DST_DIVIDE__DIV);
+ }
+ }
+ else
+ {
+ set_output(0, 0);
+ }
+}
+
+
+/************************************************************************
+ *
+ * DST_GAIN - This is a programmable gain module with enable function
+ *
+ * input[0] - Channel0 input value
+ * input[1] - Gain value
+ * input[2] - Final addition offset
+ *
+ ************************************************************************/
+#define DST_GAIN__IN DISCRETE_INPUT(0)
+#define DST_GAIN__GAIN DISCRETE_INPUT(1)
+#define DST_GAIN__OFFSET DISCRETE_INPUT(2)
+
+DISCRETE_STEP(dst_gain)
+{
+ set_output(0, DST_GAIN__IN * DST_GAIN__GAIN + DST_GAIN__OFFSET);
+}
+
+
+/************************************************************************
+ *
+ * DST_INTEGRATE - Integration circuits
+ *
+ * input[0] - Trigger 0
+ * input[1] - Trigger 1
+ *
+ * also passed discrete_integrate_info structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DST_INTEGRATE__TRG0 DISCRETE_INPUT(0)
+#define DST_INTEGRATE__TRG1 DISCRETE_INPUT(1)
+
+static int dst_trigger_function(int trig0, int trig1, int trig2, int function)
+{
+ int result = 1;
+ switch (function)
+ {
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG0:
+ result = trig0;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV:
+ result = !trig0;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG1:
+ result = trig1;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG1_INV:
+ result = !trig1;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG2:
+ result = trig2;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG2_INV:
+ result = !trig2;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_AND:
+ result = trig0 && trig1;
+ break;
+ case DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_NAND:
+ result = !(trig0 && trig1);
+ break;
+ }
+
+ return (result);
+}
+
+DISCRETE_STEP(dst_integrate)
+{
+ DISCRETE_DECLARE_INFO(discrete_integrate_info)
+
+ int trig0, trig1;
+ double i_neg = 0; /* current into - input */
+ double i_pos = 0; /* current into + input */
+
+ switch (info->type)
+ {
+ case DISC_INTEGRATE_OP_AMP_1:
+ if (DST_INTEGRATE__TRG0 != 0)
+ {
+ /* This forces the cap to completely charge,
+ * and the output to go to it's max value.
+ */
+ m_v_out = m_v_max_out;
+ set_output(0, m_v_out);
+ return;
+ }
+ m_v_out -= m_change;
+ break;
+
+ case DISC_INTEGRATE_OP_AMP_1 | DISC_OP_AMP_IS_NORTON:
+ i_neg = m_v_max_in / info->r1;
+ i_pos = (DST_INTEGRATE__TRG0 - OP_AMP_NORTON_VBE) / info->r2;
+ if (i_pos < 0) i_pos = 0;
+ m_v_out += (i_pos - i_neg) / this->sample_rate() / info->c;
+ break;
+
+ case DISC_INTEGRATE_OP_AMP_2 | DISC_OP_AMP_IS_NORTON:
+ trig0 = (int)DST_INTEGRATE__TRG0;
+ trig1 = (int)DST_INTEGRATE__TRG1;
+ i_neg = dst_trigger_function(trig0, trig1, 0, info->f0) ? m_v_max_in_d / info->r1 : 0;
+ i_pos = dst_trigger_function(trig0, trig1, 0, info->f1) ? m_v_max_in / info->r2 : 0;
+ i_pos += dst_trigger_function(trig0, trig1, 0, info->f2) ? m_v_max_in_d / info->r3 : 0;
+ m_v_out += (i_pos - i_neg) / this->sample_rate() / info->c;
+ break;
+ }
+
+ /* Clip the output. */
+ if (m_v_out < 0) m_v_out = 0;
+ if (m_v_out > m_v_max_out) m_v_out = m_v_max_out;
+
+ set_output(0, m_v_out);
+}
+
+DISCRETE_RESET(dst_integrate)
+{
+ DISCRETE_DECLARE_INFO(discrete_integrate_info)
+
+ double i, v;
+
+ if (info->type & DISC_OP_AMP_IS_NORTON)
+ {
+ m_v_max_out = info->vP - OP_AMP_NORTON_VBE;
+ m_v_max_in = info->v1 - OP_AMP_NORTON_VBE;
+ m_v_max_in_d = m_v_max_in - OP_AMP_NORTON_VBE;
+ }
+ else
+ {
+ m_v_max_out = info->vP - OP_AMP_VP_RAIL_OFFSET;
+
+ v = info->v1 * info->r3 / (info->r2 + info->r3); /* vRef */
+ v = info->v1 - v; /* actual charging voltage */
+ i = v / info->r1;
+ m_change = i / this->sample_rate() / info->c;
+ }
+ m_v_out = 0;
+ set_output(0, m_v_out);
+}
+
+
+/************************************************************************
+ *
+ * DST_LOGIC_INV - Logic invertor gate implementation
+ *
+ * input[0] - Enable
+ * input[1] - input[0] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_INV__IN DISCRETE_INPUT(0)
+
+DISCRETE_STEP(dst_logic_inv)
+{
+ set_output(0, DST_LOGIC_INV__IN ? 0.0 : 1.0);
+}
+
+/************************************************************************
+ *
+ * DST_BITS_DECODE - Decode Bits from input node
+ *
+ ************************************************************************/
+#define DST_BITS_DECODE__IN DISCRETE_INPUT(0)
+#define DST_BITS_DECODE__FROM DISCRETE_INPUT(1)
+#define DST_BITS_DECODE__TO DISCRETE_INPUT(2)
+#define DST_BITS_DECODE__VOUT DISCRETE_INPUT(3)
+
+DISCRETE_STEP(dst_bits_decode)
+{
+ int new_val = DST_BITS_DECODE__IN;
+ int last_val = m_last_val;
+ int last_had_x_time = m_last_had_x_time;
+
+ if (last_val != new_val || last_had_x_time)
+ {
+ int i, new_bit, last_bit, last_bit_had_x_time, bit_changed;
+ double x_time = DST_BITS_DECODE__IN - new_val;
+ int from = m_from;
+ int count = m_count;
+ int decode_x_time = m_decode_x_time;
+ int has_x_time = x_time > 0 ? 1 : 0;
+ double out = 0;
+ double v_out = DST_BITS_DECODE__VOUT;
+
+ for (i = 0; i < count; i++ )
+ {
+ new_bit = (new_val >> (i + from)) & 1;
+ last_bit = (last_val >> (i + from)) & 1;
+ last_bit_had_x_time = (last_had_x_time >> (i + from)) & 1;
+ bit_changed = last_bit != new_bit ? 1 : 0;
+
+ if (!bit_changed && !last_bit_had_x_time)
+ continue;
+
+ if (decode_x_time)
+ {
+ out = new_bit;
+ if (bit_changed)
+ out += x_time;
+ }
+ else
+ {
+ out = v_out;
+ if (has_x_time && bit_changed)
+ {
+ if (new_bit)
+ out *= x_time;
+ else
+ out *= (1.0 - x_time);
+ }
+ else
+ out *= new_bit;
+ }
+ set_output(i, out);
+ if (has_x_time && bit_changed)
+ /* set */
+ m_last_had_x_time |= 1 << (i + from);
+ else
+ /* clear */
+ m_last_had_x_time &= ~(1 << (i + from));
+ }
+ m_last_val = new_val;
+ }
+}
+
+DISCRETE_RESET(dst_bits_decode)
+{
+ m_from = DST_BITS_DECODE__FROM;
+ m_count = DST_BITS_DECODE__TO - m_from + 1;
+ if (DST_BITS_DECODE__VOUT == 0)
+ m_decode_x_time = 1;
+ else
+ m_decode_x_time = 0;
+ m_last_had_x_time = 0;
+
+ this->step();
+}
+
+
+/************************************************************************
+ *
+ * DST_LOGIC_AND - Logic AND gate implementation
+ *
+ * input[0] - input[0] value
+ * input[1] - input[1] value
+ * input[2] - input[2] value
+ * input[3] - input[3] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_AND__IN0 DISCRETE_INPUT(0)
+#define DST_LOGIC_AND__IN1 DISCRETE_INPUT(1)
+#define DST_LOGIC_AND__IN2 DISCRETE_INPUT(2)
+#define DST_LOGIC_AND__IN3 DISCRETE_INPUT(3)
+
+DISCRETE_STEP(dst_logic_and)
+{
+ set_output(0, (DST_LOGIC_AND__IN0 && DST_LOGIC_AND__IN1 && DST_LOGIC_AND__IN2 && DST_LOGIC_AND__IN3)? 1.0 : 0.0);
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_NAND - Logic NAND gate implementation
+ *
+ * input[0] - input[0] value
+ * input[1] - input[1] value
+ * input[2] - input[2] value
+ * input[3] - input[3] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_NAND__IN0 DISCRETE_INPUT(0)
+#define DST_LOGIC_NAND__IN1 DISCRETE_INPUT(1)
+#define DST_LOGIC_NAND__IN2 DISCRETE_INPUT(2)
+#define DST_LOGIC_NAND__IN3 DISCRETE_INPUT(3)
+
+DISCRETE_STEP(dst_logic_nand)
+{
+ set_output(0, (DST_LOGIC_NAND__IN0 && DST_LOGIC_NAND__IN1 && DST_LOGIC_NAND__IN2 && DST_LOGIC_NAND__IN3)? 0.0 : 1.0);
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_OR - Logic OR gate implementation
+ *
+ * input[0] - input[0] value
+ * input[1] - input[1] value
+ * input[2] - input[2] value
+ * input[3] - input[3] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_OR__IN0 DISCRETE_INPUT(0)
+#define DST_LOGIC_OR__IN1 DISCRETE_INPUT(1)
+#define DST_LOGIC_OR__IN2 DISCRETE_INPUT(2)
+#define DST_LOGIC_OR__IN3 DISCRETE_INPUT(3)
+
+DISCRETE_STEP(dst_logic_or)
+{
+ set_output(0, (DST_LOGIC_OR__IN0 || DST_LOGIC_OR__IN1 || DST_LOGIC_OR__IN2 || DST_LOGIC_OR__IN3) ? 1.0 : 0.0);
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_NOR - Logic NOR gate implementation
+ *
+ * input[0] - input[0] value
+ * input[1] - input[1] value
+ * input[2] - input[2] value
+ * input[3] - input[3] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_NOR__IN0 DISCRETE_INPUT(0)
+#define DST_LOGIC_NOR__IN1 DISCRETE_INPUT(1)
+#define DST_LOGIC_NOR__IN2 DISCRETE_INPUT(2)
+#define DST_LOGIC_NOR__IN3 DISCRETE_INPUT(3)
+
+DISCRETE_STEP(dst_logic_nor)
+{
+ set_output(0, (DST_LOGIC_NOR__IN0 || DST_LOGIC_NOR__IN1 || DST_LOGIC_NOR__IN2 || DST_LOGIC_NOR__IN3) ? 0.0 : 1.0);
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_XOR - Logic XOR gate implementation
+ *
+ * input[0] - input[0] value
+ * input[1] - input[1] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_XOR__IN0 DISCRETE_INPUT(0)
+#define DST_LOGIC_XOR__IN1 DISCRETE_INPUT(1)
+
+DISCRETE_STEP(dst_logic_xor)
+{
+ set_output(0, ((DST_LOGIC_XOR__IN0 && !DST_LOGIC_XOR__IN1) || (!DST_LOGIC_XOR__IN0 && DST_LOGIC_XOR__IN1)) ? 1.0 : 0.0);
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_NXOR - Logic NXOR gate implementation
+ *
+ * input[0] - input[0] value
+ * input[1] - input[1] value
+ *
+ ************************************************************************/
+#define DST_LOGIC_XNOR__IN0 DISCRETE_INPUT(0)
+#define DST_LOGIC_XNOR__IN1 DISCRETE_INPUT(1)
+
+DISCRETE_STEP(dst_logic_nxor)
+{
+ set_output(0, ((DST_LOGIC_XNOR__IN0 && !DST_LOGIC_XNOR__IN1) || (!DST_LOGIC_XNOR__IN0 && DST_LOGIC_XNOR__IN1)) ? 0.0 : 1.0);
+}
+
+
+/************************************************************************
+ *
+ * DST_LOGIC_DFF - Standard D-type flip-flop implementation
+ *
+ * input[0] - /Reset
+ * input[1] - /Set
+ * input[2] - clock
+ * input[3] - data
+ *
+ ************************************************************************/
+#define DST_LOGIC_DFF__RESET !DISCRETE_INPUT(0)
+#define DST_LOGIC_DFF__SET !DISCRETE_INPUT(1)
+#define DST_LOGIC_DFF__CLOCK DISCRETE_INPUT(2)
+#define DST_LOGIC_DFF__DATA DISCRETE_INPUT(3)
+
+DISCRETE_STEP(dst_logic_dff)
+{
+ int clk = (int)DST_LOGIC_DFF__CLOCK;
+
+ if (DST_LOGIC_DFF__RESET)
+ set_output(0, 0);
+ else if (DST_LOGIC_DFF__SET)
+ set_output(0, 1);
+ else if (!m_last_clk && clk) /* low to high */
+ set_output(0, DST_LOGIC_DFF__DATA);
+ m_last_clk = clk;
+}
+
+DISCRETE_RESET(dst_logic_dff)
+{
+ m_last_clk = 0;
+ set_output(0, 0);
+}
+
+
+/************************************************************************
+ *
+ * DST_LOGIC_JKFF - Standard JK-type flip-flop implementation
+ *
+ * input[0] - /Reset
+ * input[1] - /Set
+ * input[2] - clock
+ * input[3] - J
+ * input[4] - K
+ *
+ ************************************************************************/
+#define DST_LOGIC_JKFF__RESET !DISCRETE_INPUT(0)
+#define DST_LOGIC_JKFF__SET !DISCRETE_INPUT(1)
+#define DST_LOGIC_JKFF__CLOCK DISCRETE_INPUT(2)
+#define DST_LOGIC_JKFF__J DISCRETE_INPUT(3)
+#define DST_LOGIC_JKFF__K DISCRETE_INPUT(4)
+
+DISCRETE_STEP(dst_logic_jkff)
+{
+ int clk = (int)DST_LOGIC_JKFF__CLOCK;
+ int j = (int)DST_LOGIC_JKFF__J;
+ int k = (int)DST_LOGIC_JKFF__K;
+
+ if (DST_LOGIC_JKFF__RESET)
+ m_v_out = 0;
+ else if (DST_LOGIC_JKFF__SET)
+ m_v_out = 1;
+ else if (m_last_clk && !clk) /* high to low */
+ {
+ if (!j)
+ {
+ /* J=0, K=0 - Hold */
+ if (k)
+ /* J=0, K=1 - Reset */
+ m_v_out = 0;
+ }
+ else
+ {
+ if (!k)
+ /* J=1, K=0 - Set */
+ m_v_out = 1;
+ else
+ /* J=1, K=1 - Toggle */
+ m_v_out = !(int)m_v_out;
+ }
+ }
+ m_last_clk = clk;
+ set_output(0, m_v_out);
+}
+
+DISCRETE_RESET(dst_logic_jkff)
+{
+ m_last_clk = 0;
+ m_v_out = 0;
+ set_output(0, m_v_out);
+}
+
+/************************************************************************
+ *
+ * DST_LOGIC_SHIFT - Shift Register implementation
+ *
+ ************************************************************************/
+#define DST_LOGIC_SHIFT__IN DISCRETE_INPUT(0)
+#define DST_LOGIC_SHIFT__RESET DISCRETE_INPUT(1)
+#define DST_LOGIC_SHIFT__CLK DISCRETE_INPUT(2)
+#define DST_LOGIC_SHIFT__SIZE DISCRETE_INPUT(3)
+#define DST_LOGIC_SHIFT__OPTIONS DISCRETE_INPUT(4)
+
+DISCRETE_STEP(dst_logic_shift)
+{
+ double cycles;
+ double ds_clock;
+ int clock = 0, inc = 0;
+
+ int input_bit = (DST_LOGIC_SHIFT__IN != 0) ? 1 : 0;
+ ds_clock = DST_LOGIC_SHIFT__CLK;
+ if (m_clock_type == DISC_CLK_IS_FREQ)
+ {
+ /* We need to keep clocking the internal clock even if in reset. */
+ cycles = (m_t_left + this->sample_time()) * ds_clock;
+ inc = (int)cycles;
+ m_t_left = (cycles - inc) / ds_clock;
+ }
+ else
+ {
+ clock = (int)ds_clock;
+ }
+
+ /* If reset enabled then set output to the reset value. No x_time in reset. */
+ if(((DST_LOGIC_SHIFT__RESET == 0) ? 0 : 1) == m_reset_on_high)
+ {
+ m_shift_data = 0;
+ set_output(0, 0);
+ return;
+ }
+
+ /* increment clock */
+ switch (m_clock_type)
+ {
+ case DISC_CLK_ON_F_EDGE:
+ case DISC_CLK_ON_R_EDGE:
+ /* See if the clock has toggled to the proper edge */
+ clock = (clock != 0);
+ if (m_last != clock)
+ {
+ m_last = clock;
+ if (m_clock_type == clock)
+ {
+ /* Toggled */
+ inc = 1;
+ }
+ }
+ break;
+
+ case DISC_CLK_BY_COUNT:
+ /* Clock number of times specified. */
+ inc = clock;
+ break;
+ }
+
+ if (inc > 0)
+ {
+ if (m_shift_r)
+ {
+ m_shift_data >>= 1;
+ m_shift_data |= input_bit << ((int)DST_LOGIC_SHIFT__SIZE - 1);
+ inc--;
+ m_shift_data >>= inc;
+ }
+ else
+ {
+ m_shift_data <<= 1;
+ m_shift_data |= input_bit;
+ inc--;
+ m_shift_data <<= inc;
+ }
+ m_shift_data &= m_bit_mask;
+ }
+
+ set_output(0, m_shift_data);
+}
+
+DISCRETE_RESET(dst_logic_shift)
+{
+ m_bit_mask = (1 << (int)DST_LOGIC_SHIFT__SIZE) - 1;
+ m_clock_type = (int)DST_LOGIC_SHIFT__OPTIONS & DISC_CLK_MASK;
+ m_reset_on_high = ((int)DST_LOGIC_SHIFT__OPTIONS & DISC_LOGIC_SHIFT__RESET_H) ? 1 : 0;
+ m_shift_r = ((int)DST_LOGIC_SHIFT__OPTIONS & DISC_LOGIC_SHIFT__RIGHT) ? 1 : 0;
+
+ m_t_left = 0;
+ m_last = 0;
+ m_shift_data = 0;
+ set_output(0, 0);
+}
+
+/************************************************************************
+ *
+ * DST_LOOKUP_TABLE - Return value from lookup table
+ *
+ * input[0] - Input 1
+ * input[1] - Table size
+ *
+ * Also passed address of the lookup table
+ *
+ * Feb 2007, D Renaud.
+ ************************************************************************/
+#define DST_LOOKUP_TABLE__IN DISCRETE_INPUT(0)
+#define DST_LOOKUP_TABLE__SIZE DISCRETE_INPUT(1)
+
+DISCRETE_STEP(dst_lookup_table)
+{
+ DISCRETE_DECLARE_INFO(double)
+
+ int addr = DST_LOOKUP_TABLE__IN;
+
+ if (addr < 0 || addr >= DST_LOOKUP_TABLE__SIZE)
+ set_output(0, 0);
+ else
+ set_output(0, info[addr]);
+}
+
+
+/************************************************************************
+ *
+ * DST_MIXER - Mixer/Gain stage
+ *
+ * input[0] - Enable input value
+ * input[1] - Input 1
+ * input[2] - Input 2
+ * input[3] - Input 3
+ * input[4] - Input 4
+ * input[5] - Input 5
+ * input[6] - Input 6
+ * input[7] - Input 7
+ * input[8] - Input 8
+ *
+ * Also passed discrete_mixer_info structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+/*
+ * The input resistors can be a combination of static values and nodes.
+ * If a node is used then its value is in series with the static value.
+ * Also if a node is used and its value is 0, then that means the
+ * input is disconnected from the circuit.
+ *
+ * There are 3 basic types of mixers, defined by the 2 types. The
+ * op amp mixer is further defined by the prescence of rI. This is a
+ * brief explanation.
+ *
+ * DISC_MIXER_IS_RESISTOR
+ * The inputs are high pass filtered if needed, using (rX || rF) * cX.
+ * Then Millman is used for the voltages.
+ * r = (1/rF + 1/r1 + 1/r2...)
+ * i = (v1/r1 + v2/r2...)
+ * v = i * r
+ *
+ * DISC_MIXER_IS_OP_AMP - no rI
+ * This is just a summing circuit.
+ * The inputs are high pass filtered if needed, using rX * cX.
+ * Then a modified Millman is used for the voltages.
+ * i = ((vRef - v1)/r1 + (vRef - v2)/r2...)
+ * v = i * rF
+ *
+ * DISC_MIXER_IS_OP_AMP_WITH_RI
+ * The inputs are high pass filtered if needed, using (rX + rI) * cX.
+ * Then Millman is used for the voltages including vRef/rI.
+ * r = (1/rI + 1/r1 + 1/r2...)
+ * i = (vRef/rI + v1/r1 + v2/r2...)
+ * The voltage is then modified by an inverting amp formula.
+ * v = vRef + (rF/rI) * (vRef - (i * r))
+ */
+#define DST_MIXER__ENABLE DISCRETE_INPUT(0)
+#define DST_MIXER__IN(bit) DISCRETE_INPUT(bit + 1)
+
+DISCRETE_STEP(dst_mixer)
+{
+ DISCRETE_DECLARE_INFO(discrete_mixer_desc)
+
+ double v, vTemp, r_total, rTemp, rTemp2 = 0;
+ double i = 0; /* total current of inputs */
+ int bit, connected;
+
+ /* put commonly used stuff in local variables for speed */
+ int r_node_bit_flag = m_r_node_bit_flag;
+ int c_bit_flag = m_c_bit_flag;
+ int bit_mask = 1;
+ int has_rF = (info->rF != 0);
+ int type = m_type;
+ double v_ref = info->vRef;
+ double rI = info->rI;
+
+ if (EXPECTED(DST_MIXER__ENABLE))
+ {
+ r_total = m_r_total;
+
+ if (UNEXPECTED(m_r_node_bit_flag != 0))
+ {
+ /* loop and do any high pass filtering for connected caps */
+ /* but first see if there is an r_node for the current path */
+ /* if so, then the exponents need to be re-calculated */
+ for (bit = 0; bit < m_size; bit++)
+ {
+ rTemp = info->r[bit];
+ connected = 1;
+ vTemp = DST_MIXER__IN(bit);
+
+ /* is there a resistor? */
+ if (r_node_bit_flag & bit_mask)
+ {
+ /* a node has the possibility of being disconnected from the circuit. */
+ if (*m_r_node[bit] == 0)
+ connected = 0;
+ else
+ {
+ /* value currently holds resistance */
+ rTemp += *m_r_node[bit];
+ r_total += 1.0 / rTemp;
+ /* is there a capacitor? */
+ if (c_bit_flag & bit_mask)
+ {
+ switch (type)
+ {
+ case DISC_MIXER_IS_RESISTOR:
+ /* is there an rF? */
+ if (has_rF)
+ {
+ rTemp2 = RES_2_PARALLEL(rTemp, info->rF);
+ break;
+ }
+ /* else, fall through and just use the resistor value */
+ case DISC_MIXER_IS_OP_AMP:
+ rTemp2 = rTemp;
+ break;
+ case DISC_MIXER_IS_OP_AMP_WITH_RI:
+ rTemp2 = rTemp + rI;
+ break;
+ }
+ /* Re-calculate exponent if resistor is a node and has changed value */
+ if (*m_r_node[bit] != m_r_last[bit])
+ {
+ m_exponent_rc[bit] = RC_CHARGE_EXP(rTemp2 * info->c[bit]);
+ m_r_last[bit] = *m_r_node[bit];
+ }
+ }
+ }
+ }
+
+ if (connected)
+ {
+ /* is there a capacitor? */
+ if (c_bit_flag & bit_mask)
+ {
+ /* do input high pass filtering if needed. */
+ m_v_cap[bit] += (vTemp - v_ref - m_v_cap[bit]) * m_exponent_rc[bit];
+ vTemp -= m_v_cap[bit];
+ }
+ i += ((type == DISC_MIXER_IS_OP_AMP) ? v_ref - vTemp : vTemp) / rTemp;
+ }
+ bit_mask = bit_mask << 1;
+ }
+ }
+ else if (UNEXPECTED(c_bit_flag != 0))
+ {
+ /* no r_nodes, so just do high pass filtering */
+ for (bit = 0; bit < m_size; bit++)
+ {
+ vTemp = DST_MIXER__IN(bit);
+
+ if (c_bit_flag & (1 << bit))
+ {
+ /* do input high pass filtering if needed. */
+ m_v_cap[bit] += (vTemp - v_ref - m_v_cap[bit]) * m_exponent_rc[bit];
+ vTemp -= m_v_cap[bit];
+ }
+ i += ((type == DISC_MIXER_IS_OP_AMP) ? v_ref - vTemp : vTemp) / info->r[bit];
+ }
+ }
+ else
+ {
+ /* no r_nodes or c_nodes, mixing only */
+ if (UNEXPECTED(type == DISC_MIXER_IS_OP_AMP))
+ {
+ for (bit = 0; bit < m_size; bit++)
+ i += ( v_ref - DST_MIXER__IN(bit) ) / info->r[bit];
+ }
+ else
+ {
+ for (bit = 0; bit < m_size; bit++)
+ i += DST_MIXER__IN(bit) / info->r[bit];
+ }
+ }
+
+ if (UNEXPECTED(type == DISC_MIXER_IS_OP_AMP_WITH_RI))
+ i += v_ref / rI;
+
+ r_total = 1.0 / r_total;
+
+ /* If resistor network or has rI then Millman is used.
+ * If op-amp then summing formula is used. */
+ v = i * ((type == DISC_MIXER_IS_OP_AMP) ? info->rF : r_total);
+
+ if (UNEXPECTED(type == DISC_MIXER_IS_OP_AMP_WITH_RI))
+ v = v_ref + (m_gain * (v_ref - v));
+
+ /* Do the low pass filtering for cF */
+ if (EXPECTED(info->cF != 0))
+ {
+ if (UNEXPECTED(r_node_bit_flag != 0))
+ {
+ /* Re-calculate exponent if resistor nodes are used */
+ m_exponent_c_f = RC_CHARGE_EXP(r_total * info->cF);
+ }
+ m_v_cap_f += (v - v_ref - m_v_cap_f) * m_exponent_c_f;
+ v = m_v_cap_f;
+ }
+
+ /* Do the high pass filtering for cAmp */
+ if (EXPECTED(info->cAmp != 0))
+ {
+ m_v_cap_amp += (v - m_v_cap_amp) * m_exponent_c_amp;
+ v -= m_v_cap_amp;
+ }
+ set_output(0, v * info->gain);
+ }
+ else
+ {
+ set_output(0, 0);
+ }
+}
+
+
+DISCRETE_RESET(dst_mixer)
+{
+ DISCRETE_DECLARE_INFO(discrete_mixer_desc)
+
+ int bit;
+ double rTemp = 0;
+
+ /* link to r_node outputs */
+ m_r_node_bit_flag = 0;
+ for (bit = 0; bit < 8; bit++)
+ {
+ m_r_node[bit] = m_device->node_output_ptr(info->r_node[bit]);
+ if (m_r_node[bit] != NULL)
+ {
+ m_r_node_bit_flag |= 1 << bit;
+ }
+
+ /* flag any caps */
+ if (info->c[bit] != 0)
+ m_c_bit_flag |= 1 << bit;
+ }
+
+ m_size = this->active_inputs() - 1;
+
+ /*
+ * THERE IS NO ERROR CHECKING!!!!!!!!!
+ * If you pass a bad ladder table
+ * then you deserve a crash.
+ */
+
+ m_type = info->type;
+ if ((info->type == DISC_MIXER_IS_OP_AMP) && (info->rI != 0))
+ m_type = DISC_MIXER_IS_OP_AMP_WITH_RI;
+
+ /*
+ * Calculate the total of all resistors in parallel.
+ * This is the combined resistance of the voltage sources.
+ * Also calculate the exponents while we are here.
+ */
+ m_r_total = 0;
+ for(bit = 0; bit < m_size; bit++)
+ {
+ if ((info->r[bit] != 0) && !info->r_node[bit] )
+ {
+ m_r_total += 1.0 / info->r[bit];
+ }
+
+ m_v_cap[bit] = 0;
+ m_exponent_rc[bit] = 0;
+ if ((info->c[bit] != 0) && !info->r_node[bit])
+ {
+ switch (m_type)
+ {
+ case DISC_MIXER_IS_RESISTOR:
+ /* is there an rF? */
+ if (info->rF != 0)
+ {
+ rTemp = 1.0 / ((1.0 / info->r[bit]) + (1.0 / info->rF));
+ break;
+ }
+ /* else, fall through and just use the resistor value */
+ case DISC_MIXER_IS_OP_AMP:
+ rTemp = info->r[bit];
+ break;
+ case DISC_MIXER_IS_OP_AMP_WITH_RI:
+ rTemp = info->r[bit] + info->rI;
+ break;
+ }
+ /* Setup filter constants */
+ m_exponent_rc[bit] = RC_CHARGE_EXP(rTemp * info->c[bit]);
+ }
+ }
+
+ if (info->rF != 0)
+ {
+ if (m_type == DISC_MIXER_IS_RESISTOR) m_r_total += 1.0 / info->rF;
+ }
+ if (m_type == DISC_MIXER_IS_OP_AMP_WITH_RI) m_r_total += 1.0 / info->rI;
+
+ m_v_cap_f = 0;
+ m_exponent_c_f = 0;
+ if (info->cF != 0)
+ {
+ /* Setup filter constants */
+ m_exponent_c_f = RC_CHARGE_EXP(((info->type == DISC_MIXER_IS_OP_AMP) ? info->rF : (1.0 / m_r_total)) * info->cF);
+ }
+
+ m_v_cap_amp = 0;
+ m_exponent_c_amp = 0;
+ if (info->cAmp != 0)
+ {
+ /* Setup filter constants */
+ /* We will use 100k ohms as an average final stage impedance. */
+ /* Your amp/speaker system will have more effect on incorrect filtering then any value used here. */
+ m_exponent_c_amp = RC_CHARGE_EXP(RES_K(100) * info->cAmp);
+ }
+
+ if (m_type == DISC_MIXER_IS_OP_AMP_WITH_RI) m_gain = info->rF / info->rI;
+
+ set_output(0, 0);
+}
+
+
+/************************************************************************
+ *
+ * DST_MULTIPLEX - 1 of x multiplexer/switch
+ *
+ * input[0] - switch position
+ * input[1] - input[0]
+ * input[2] - input[1]
+ * .....
+ *
+ * Dec 2004, D Renaud.
+ ************************************************************************/
+#define DST_MULTIPLEX__ADDR DISCRETE_INPUT(0)
+#define DST_MULTIPLEX__INP(addr) DISCRETE_INPUT(1 + addr)
+
+DISCRETE_STEP(dst_multiplex)
+{
+ int addr;
+
+ addr = DST_MULTIPLEX__ADDR; /* FP to INT */
+ if ((addr >= 0) && (addr < m_size))
+ {
+ set_output(0, DST_MULTIPLEX__INP(addr));
+ }
+ else
+ {
+ /* Bad address. We will leave the output alone. */
+ m_device->discrete_log("NODE_%02d - Address = %d. Out of bounds\n", this->index(), addr);
+ }
+}
+
+DISCRETE_RESET(dst_multiplex)
+{
+ m_size = this->active_inputs() - 1;
+
+ this->step();
+}
+
+
+/************************************************************************
+ *
+ * DST_ONESHOT - Usage of node_description values for one shot pulse
+ *
+ * input[0] - Reset value
+ * input[1] - Trigger value
+ * input[2] - Amplitude value
+ * input[3] - Width of oneshot pulse
+ * input[4] - type R/F edge, Retriggerable?
+ *
+ * Complete re-write Jan 2004, D Renaud.
+ ************************************************************************/
+#define DST_ONESHOT__RESET DISCRETE_INPUT(0)
+#define DST_ONESHOT__TRIG DISCRETE_INPUT(1)
+#define DST_ONESHOT__AMP DISCRETE_INPUT(2)
+#define DST_ONESHOT__WIDTH DISCRETE_INPUT(3)
+#define DST_ONESHOT__TYPE (int)DISCRETE_INPUT(4)
+
+DISCRETE_STEP(dst_oneshot)
+{
+ int trigger = (DST_ONESHOT__TRIG != 0);
+
+ /* If the state is triggered we will need to countdown later */
+ int do_count = m_state;
+
+ if (UNEXPECTED(DST_ONESHOT__RESET))
+ {
+ /* Hold in Reset */
+ set_output(0, 0);
+ m_state = 0;
+ }
+ else
+ {
+ /* are we at an edge? */
+ if (UNEXPECTED(trigger != m_last_trig))
+ {
+ /* There has been a trigger edge */
+ m_last_trig = trigger;
+
+ /* Is it the proper edge trigger */
+ if ((m_type & DISC_ONESHOT_REDGE) ? trigger : !trigger)
+ {
+ if (!m_state)
+ {
+ /* We have first trigger */
+ m_state = 1;
+ set_output(0, (m_type & DISC_OUT_ACTIVE_LOW) ? 0 : DST_ONESHOT__AMP);
+ m_countdown = DST_ONESHOT__WIDTH;
+ }
+ else
+ {
+ /* See if we retrigger */
+ if (m_type & DISC_ONESHOT_RETRIG)
+ {
+ /* Retrigger */
+ m_countdown = DST_ONESHOT__WIDTH;
+ do_count = 0;
+ }
+ }
+ }
+ }
+
+ if (UNEXPECTED(do_count))
+ {
+ m_countdown -= this->sample_time();
+ if(m_countdown <= 0.0)
+ {
+ set_output(0, (m_type & DISC_OUT_ACTIVE_LOW) ? DST_ONESHOT__AMP : 0);
+ m_countdown = 0;
+ m_state = 0;
+ }
+ }
+ }
+}
+
+
+DISCRETE_RESET(dst_oneshot)
+{
+ m_countdown = 0;
+ m_state = 0;
+
+ m_last_trig = 0;
+ m_type = DST_ONESHOT__TYPE;
+
+ set_output(0, (m_type & DISC_OUT_ACTIVE_LOW) ? DST_ONESHOT__AMP : 0);
+}
+
+
+/************************************************************************
+ *
+ * DST_RAMP - Ramp up/down model usage
+ *
+ * input[0] - Enable ramp
+ * input[1] - Ramp Reverse/Forward switch
+ * input[2] - Gradient, change/sec
+ * input[3] - Start value
+ * input[4] - End value
+ * input[5] - Clamp value when disabled
+ *
+ ************************************************************************/
+#define DST_RAMP__ENABLE DISCRETE_INPUT(0)
+#define DST_RAMP__DIR DISCRETE_INPUT(1)
+#define DST_RAMP__GRAD DISCRETE_INPUT(2)
+#define DST_RAMP__START DISCRETE_INPUT(3)
+#define DST_RAMP__END DISCRETE_INPUT(4)
+#define DST_RAMP__CLAMP DISCRETE_INPUT(5)
+
+DISCRETE_STEP(dst_ramp)
+{
+ if(DST_RAMP__ENABLE)
+ {
+ if (!m_last_en)
+ {
+ m_last_en = 1;
+ m_v_out = DST_RAMP__START;
+ }
+ if(m_dir ? DST_RAMP__DIR : !DST_RAMP__DIR) m_v_out += m_step;
+ else m_v_out -= m_step;
+ /* Clamp to min/max */
+ if(m_dir ? (m_v_out < DST_RAMP__START)
+ : (m_v_out > DST_RAMP__START)) m_v_out = DST_RAMP__START;
+ if(m_dir ? (m_v_out > DST_RAMP__END)
+ : (m_v_out < DST_RAMP__END)) m_v_out = DST_RAMP__END;
+ }
+ else
+ {
+ m_last_en = 0;
+ /* Disabled so clamp to output */
+ m_v_out = DST_RAMP__CLAMP;
+ }
+
+ set_output(0, m_v_out);
+}
+
+DISCRETE_RESET(dst_ramp)
+{
+ m_v_out = DST_RAMP__CLAMP;
+ m_step = DST_RAMP__GRAD / this->sample_rate();
+ m_dir = ((DST_RAMP__END - DST_RAMP__START) == abs(DST_RAMP__END - DST_RAMP__START));
+ m_last_en = 0;
+}
+
+
+/************************************************************************
+ *
+ * DST_SAMPHOLD - Sample & Hold Implementation
+ *
+ * input[0] - input[0] value
+ * input[1] - clock node
+ * input[2] - clock type
+ *
+ ************************************************************************/
+#define DST_SAMPHOLD__IN0 DISCRETE_INPUT(0)
+#define DST_SAMPHOLD__CLOCK DISCRETE_INPUT(1)
+#define DST_SAMPHOLD__TYPE DISCRETE_INPUT(2)
+
+DISCRETE_STEP(dst_samphold)
+{
+ switch(m_clocktype)
+ {
+ case DISC_SAMPHOLD_REDGE:
+ /* Clock the whole time the input is rising */
+ if (DST_SAMPHOLD__CLOCK > m_last_input) set_output(0, DST_SAMPHOLD__IN0);
+ break;
+ case DISC_SAMPHOLD_FEDGE:
+ /* Clock the whole time the input is falling */
+ if(DST_SAMPHOLD__CLOCK < m_last_input) set_output(0, DST_SAMPHOLD__IN0);
+ break;
+ case DISC_SAMPHOLD_HLATCH:
+ /* Output follows input if clock != 0 */
+ if( DST_SAMPHOLD__CLOCK) set_output(0, DST_SAMPHOLD__IN0);
+ break;
+ case DISC_SAMPHOLD_LLATCH:
+ /* Output follows input if clock == 0 */
+ if (DST_SAMPHOLD__CLOCK == 0) set_output(0, DST_SAMPHOLD__IN0);
+ break;
+ default:
+ m_device->discrete_log("dst_samphold_step - Invalid clocktype passed");
+ break;
+ }
+ /* Save the last value */
+ m_last_input = DST_SAMPHOLD__CLOCK;
+}
+
+DISCRETE_RESET(dst_samphold)
+{
+ set_output(0, 0);
+ m_last_input = -1;
+ /* Only stored in here to speed up and save casting in the step function */
+ m_clocktype = (int)DST_SAMPHOLD__TYPE;
+ this->step();
+}
+
+
+/************************************************************************
+ *
+ * DST_SWITCH - Programmable 2 pole switch module with enable function
+ *
+ * input[0] - Enable input value
+ * input[1] - switch position
+ * input[2] - input[0]
+ * input[3] - input[1]
+ *
+ ************************************************************************/
+#define DST_SWITCH__ENABLE DISCRETE_INPUT(0)
+#define DST_SWITCH__SWITCH DISCRETE_INPUT(1)
+#define DST_SWITCH__IN0 DISCRETE_INPUT(2)
+#define DST_SWITCH__IN1 DISCRETE_INPUT(3)
+
+DISCRETE_STEP(dst_switch)
+{
+ if(DST_SWITCH__ENABLE)
+ {
+ set_output(0, DST_SWITCH__SWITCH ? DST_SWITCH__IN1 : DST_SWITCH__IN0);
+ }
+ else
+ {
+ set_output(0, 0);
+ }
+}
+
+/************************************************************************
+ *
+ * DST_ASWITCH - Analog switch
+ *
+ * input[1] - Control
+ * input[2] - Input
+ * input[3] - Threshold for enable
+ *
+ ************************************************************************/
+#define DST_ASWITCH__CTRL DISCRETE_INPUT(0)
+#define DST_ASWITCH__IN DISCRETE_INPUT(1)
+#define DST_ASWITCH__THRESHOLD DISCRETE_INPUT(2)
+
+
+DISCRETE_STEP(dst_aswitch)
+{
+ set_output(0, DST_ASWITCH__CTRL > DST_ASWITCH__THRESHOLD ? DST_ASWITCH__IN : 0);
+}
+
+/************************************************************************
+ *
+ * DST_TRANSFORM - Programmable math module
+ *
+ * input[0] - Channel0 input value
+ * input[1] - Channel1 input value
+ * input[2] - Channel2 input value
+ * input[3] - Channel3 input value
+ * input[4] - Channel4 input value
+ *
+ ************************************************************************/
+#define MAX_TRANS_STACK 16
+
+struct double_stack {
+public:
+ double_stack() : p(&stk[0]) { }
+ inline void push(double v)
+ {
+ //Store THEN increment
+ assert(p <= &stk[MAX_TRANS_STACK-1]);
+ *p++ = v;
+ }
+ inline double pop(void)
+ {
+ //decrement THEN read
+ assert(p > &stk[0]);
+ p--;
+ return *p;
+ }
+private:
+ double stk[MAX_TRANS_STACK];
+ double *p;
+};
+
+DISCRETE_STEP(dst_transform)
+{
+ double_stack stack;
+ double top;
+
+ enum token *fPTR = &precomp[0];
+
+ top = HUGE_VAL;
+
+ while(*fPTR != TOK_END)
+ {
+ switch (*fPTR++)
+ {
+ case TOK_MULT: top = stack.pop() * top; break;
+ case TOK_DIV: top = stack.pop() / top; break;
+ case TOK_ADD: top = stack.pop() + top; break;
+ case TOK_MINUS: top = stack.pop() - top; break;
+ case TOK_0: stack.push(top); top = I_IN0(); break;
+ case TOK_1: stack.push(top); top = I_IN1(); break;
+ case TOK_2: stack.push(top); top = I_IN2(); break;
+ case TOK_3: stack.push(top); top = I_IN3(); break;
+ case TOK_4: stack.push(top); top = I_IN4(); break;
+ case TOK_DUP: stack.push(top); break;
+ case TOK_ABS: top = fabs(top); break; /* absolute value */
+ case TOK_NEG: top = -top; break; /* * -1 */
+ case TOK_NOT: top = !top; break; /* Logical NOT of Last Value */
+ case TOK_EQUAL: top = (int)stack.pop() == (int)top; break; /* Logical = */
+ case TOK_GREATER: top = (stack.pop() > top); break; /* Logical > */
+ case TOK_LESS: top = (stack.pop() < top); break; /* Logical < */
+ case TOK_AND: top = (int)stack.pop() & (int)top; break; /* Bitwise AND */
+ case TOK_OR: top = (int)stack.pop() | (int)top; break; /* Bitwise OR */
+ case TOK_XOR: top = (int)stack.pop() ^ (int)top; break; /* Bitwise XOR */
+ case TOK_END: break; /* please compiler */
+ }
+ }
+ set_output(0, top);
+}
+
+DISCRETE_RESET(dst_transform)
+{
+ const char *fPTR = (const char *)this->custom_data();
+ enum token *p = &precomp[0];
+
+ while(*fPTR != 0)
+ {
+ switch (*fPTR++)
+ {
+ case '*': *p = TOK_MULT; break;
+ case '/': *p = TOK_DIV; break;
+ case '+': *p = TOK_ADD; break;
+ case '-': *p = TOK_MINUS; break;
+ case '0': *p = TOK_0; break;
+ case '1': *p = TOK_1; break;
+ case '2': *p = TOK_2; break;
+ case '3': *p = TOK_3; break;
+ case '4': *p = TOK_4; break;
+ case 'P': *p = TOK_DUP; break;
+ case 'a': *p = TOK_ABS; break; /* absolute value */
+ case 'i': *p = TOK_NEG; break; /* * -1 */
+ case '!': *p = TOK_NOT; break; /* Logical NOT of Last Value */
+ case '=': *p = TOK_EQUAL; break; /* Logical = */
+ case '>': *p = TOK_GREATER; break; /* Logical > */
+ case '<': *p = TOK_LESS; break; /* Logical < */
+ case '&': *p = TOK_AND; break; /* Bitwise AND */
+ case '|': *p = TOK_OR; break; /* Bitwise OR */
+ case '^': *p = TOK_XOR; break; /* Bitwise XOR */
+ default:
+ m_device->discrete_log("dst_transform_step - Invalid function type/variable passed: %s",(const char *)this->custom_data());
+ /* that is enough to fatalerror */
+ fatalerror("dst_transform_step - Invalid function type/variable passed: %s", (const char *)this->custom_data());
+ break;
+ }
+ p++;
+ }
+ *p = TOK_END;
+}
+
+/************************************************************************
+ *
+ * DST_OP_AMP - op amp circuits
+ *
+ * input[0] - Enable
+ * input[1] - Input 0
+ * input[2] - Input 1
+ *
+ * also passed discrete_op_amp_info structure
+ *
+ * Mar 2007, D Renaud.
+ ************************************************************************/
+#define DST_OP_AMP__ENABLE DISCRETE_INPUT(0)
+#define DST_OP_AMP__INP0 DISCRETE_INPUT(1)
+#define DST_OP_AMP__INP1 DISCRETE_INPUT(2)
+
+DISCRETE_STEP(dst_op_amp)
+{
+ DISCRETE_DECLARE_INFO(discrete_op_amp_info)
+
+ double i_pos = 0;
+ double i_neg = 0;
+ double i = 0;
+ double v_out;
+
+ if (DST_OP_AMP__ENABLE)
+ {
+ switch (info->type)
+ {
+ case DISC_OP_AMP_IS_NORTON:
+ /* work out neg pin current */
+ if (m_has_r1)
+ {
+ i_neg = (DST_OP_AMP__INP0 - OP_AMP_NORTON_VBE) / info->r1;
+ if (i_neg < 0) i_neg = 0;
+ }
+ i_neg += m_i_fixed;
+
+ /* work out neg pin current */
+ i_pos = (DST_OP_AMP__INP1 - OP_AMP_NORTON_VBE) / info->r2;
+ if (i_pos < 0) i_pos = 0;
+
+ /* work out current across r4 */
+ i = i_pos - i_neg;
+
+ if (m_has_cap)
+ {
+ if (m_has_r4)
+ {
+ /* voltage across r4 charging cap */
+ i *= info->r4;
+ /* exponential charge */
+ m_v_cap += (i - m_v_cap) * m_exponent;
+ }
+ else
+ /* linear charge */
+ m_v_cap += i / m_exponent;
+ v_out = m_v_cap;
+ }
+ else
+ if (m_has_r4)
+ v_out = i * info->r4;
+ else
+ /* output just swings to rail when there is no r4 */
+ if (i > 0)
+ v_out = m_v_max;
+ else
+ v_out = 0;
+
+ /* clamp output */
+ if (v_out > m_v_max) v_out = m_v_max;
+ else if (v_out < info->vN) v_out = info->vN;
+ m_v_cap = v_out;
+
+ set_output(0, v_out);
+ break;
+
+ default:
+ set_output(0, 0);
+ }
+ }
+ else
+ set_output(0, 0);
+}
+
+DISCRETE_RESET(dst_op_amp)
+{
+ DISCRETE_DECLARE_INFO(discrete_op_amp_info)
+
+ m_has_r1 = info->r1 > 0;
+ m_has_r4 = info->r4 > 0;
+
+ m_v_max = info->vP - OP_AMP_NORTON_VBE;
+
+ m_v_cap = 0;
+ if (info->c > 0)
+ {
+ m_has_cap = 1;
+ /* Setup filter constants */
+ if (m_has_r4)
+ {
+ /* exponential charge */
+ m_exponent = RC_CHARGE_EXP(info->r4 * info->c);
+ }
+ else
+ /* linear charge */
+ m_exponent = this->sample_rate() * info->c;
+ }
+
+ if (info->r3 > 0)
+ m_i_fixed = (info->vP - OP_AMP_NORTON_VBE) / info->r3;
+ else
+ m_i_fixed = 0;
+}
+
+
+/************************************************************************
+ *
+ * DST_OP_AMP_1SHT - op amp one shot circuits
+ *
+ * input[0] - Trigger
+ *
+ * also passed discrete_op_amp_1sht_info structure
+ *
+ * Mar 2007, D Renaud.
+ ************************************************************************/
+#define DST_OP_AMP_1SHT__TRIGGER DISCRETE_INPUT(0)
+
+DISCRETE_STEP(dst_op_amp_1sht)
+{
+ DISCRETE_DECLARE_INFO(discrete_op_amp_1sht_info)
+
+ double i_pos;
+ double i_neg;
+ double v;
+
+ /* update trigger circuit */
+ i_pos = (DST_OP_AMP_1SHT__TRIGGER - m_v_cap2) / info->r2;
+ i_pos += m_v_out / info->r5;
+ m_v_cap2 += (DST_OP_AMP_1SHT__TRIGGER - m_v_cap2) * m_exponent2;
+
+ /* calculate currents and output */
+ i_neg = (m_v_cap1 - OP_AMP_NORTON_VBE) / info->r3;
+ if (i_neg < 0) i_neg = 0;
+ i_neg += m_i_fixed;
+
+ if (i_pos > i_neg) m_v_out = m_v_max;
+ else m_v_out = info->vN;
+
+ /* update c1 */
+ /* rough value of voltage at anode of diode if discharging */
+ v = m_v_out + 0.6;
+ if (m_v_cap1 > m_v_out)
+ {
+ /* discharge */
+ if (m_v_cap1 > v)
+ /* immediate discharge through diode */
+ m_v_cap1 = v;
+ else
+ /* discharge through r4 */
+ m_v_cap1 += (m_v_out - m_v_cap1) * m_exponent1d;
+ }
+ else
+ /* charge */
+ m_v_cap1 += ((m_v_out - OP_AMP_NORTON_VBE) * m_r34ratio + OP_AMP_NORTON_VBE - m_v_cap1) * m_exponent1c;
+
+ set_output(0, m_v_out);
+}
+
+DISCRETE_RESET(dst_op_amp_1sht)
+{
+ DISCRETE_DECLARE_INFO(discrete_op_amp_1sht_info)
+
+ m_exponent1c = RC_CHARGE_EXP(RES_2_PARALLEL(info->r3, info->r4) * info->c1);
+ m_exponent1d = RC_CHARGE_EXP(info->r4 * info->c1);
+ m_exponent2 = RC_CHARGE_EXP(info->r2 * info->c2);
+ m_i_fixed = (info->vP - OP_AMP_NORTON_VBE) / info->r1;
+ m_v_cap1 = m_v_cap2 = 0;
+ m_v_max = info->vP - OP_AMP_NORTON_VBE;
+ m_r34ratio = info->r3 / (info->r3 + info->r4);
+}
+
+
+/************************************************************************
+ *
+ * DST_TVCA_OP_AMP - trigged op-amp VCA
+ *
+ * input[0] - Trigger 0
+ * input[1] - Trigger 1
+ * input[2] - Trigger 2
+ * input[3] - Input 0
+ * input[4] - Input 1
+ *
+ * also passed discrete_op_amp_tvca_info structure
+ *
+ * Mar 2004, D Renaud.
+ ************************************************************************/
+#define DST_TVCA_OP_AMP__TRG0 DISCRETE_INPUT(0)
+#define DST_TVCA_OP_AMP__TRG1 DISCRETE_INPUT(1)
+#define DST_TVCA_OP_AMP__TRG2 DISCRETE_INPUT(2)
+#define DST_TVCA_OP_AMP__INP0 DISCRETE_INPUT(3)
+#define DST_TVCA_OP_AMP__INP1 DISCRETE_INPUT(4)
+
+DISCRETE_STEP(dst_tvca_op_amp)
+{
+ DISCRETE_DECLARE_INFO(discrete_op_amp_tvca_info)
+
+ int trig0, trig1, trig2, f3;
+ double i2 = 0; /* current through r2 */
+ double i3 = 0; /* current through r3 */
+ double i_neg = 0; /* current into - input */
+ double i_pos = 0; /* current into + input */
+ double i_out = 0; /* current at output */
+
+ double v_out;
+
+ trig0 = (int)DST_TVCA_OP_AMP__TRG0;
+ trig1 = (int)DST_TVCA_OP_AMP__TRG1;
+ trig2 = (int)DST_TVCA_OP_AMP__TRG2;
+ f3 = dst_trigger_function(trig0, trig1, trig2, info->f3);
+
+ if ((info->r2 != 0) && dst_trigger_function(trig0, trig1, trig2, info->f0))
+ {
+ /* r2 is present, so we assume Input 0 is connected and valid. */
+ i2 = (DST_TVCA_OP_AMP__INP0 - OP_AMP_NORTON_VBE) / info->r2;
+ if ( i2 < 0) i2 = 0;
+ }
+
+ if ((info->r3 != 0) && dst_trigger_function(trig0, trig1, trig2, info->f1))
+ {
+ /* r2 is present, so we assume Input 1 is connected and valid. */
+ /* Function F1 is not grounding the circuit. */
+ i3 = (DST_TVCA_OP_AMP__INP1 - OP_AMP_NORTON_VBE) / info->r3;
+ if ( i3 < 0) i3 = 0;
+ }
+
+ /* Calculate current going in to - input. */
+ i_neg = m_i_fixed + i2 + i3;
+
+ /* Update the c1 cap voltage. */
+ if (dst_trigger_function(trig0, trig1, trig2, info->f2))
+ {
+ /* F2 is not grounding the circuit so we charge the cap. */
+ m_v_cap1 += (m_v_trig[f3] - m_v_cap1) * m_exponent_c[f3];
+ }
+ else
+ {
+ /* F2 is at ground. The diode blocks this so F2 and r5 are out of circuit.
+ * So now the discharge rate is dependent upon F3.
+ * If F3 is at ground then we discharge to 0V through r6.
+ * If F3 is out of circuit then we discharge to OP_AMP_NORTON_VBE through r6+r7. */
+ m_v_cap1 += ((f3 ? OP_AMP_NORTON_VBE : 0.0) - m_v_cap1) * m_exponent_d[f3];
+ }
+
+ /* Calculate c1 current going in to + input. */
+ i_pos = (m_v_cap1 - OP_AMP_NORTON_VBE) / m_r67;
+ if ((i_pos < 0) || !f3) i_pos = 0;
+
+ /* Update the c2 cap voltage and current. */
+ if (info->r9 != 0)
+ {
+ f3 = dst_trigger_function(trig0, trig1, trig2, info->f4);
+ m_v_cap2 += ((f3 ? m_v_trig2 : 0) - m_v_cap2) * m_exponent2[f3];
+ i_pos += m_v_cap2 / info->r9;
+ }
+
+ /* Update the c3 cap voltage and current. */
+ if (info->r11 != 0)
+ {
+ f3 = dst_trigger_function(trig0, trig1, trig2, info->f5);
+ m_v_cap3 += ((f3 ? m_v_trig3 : 0) - m_v_cap3) * m_exponent3[f3];
+ i_pos += m_v_cap3 / info->r11;
+ }
+
+ /* Calculate output current. */
+ i_out = i_pos - i_neg;
+ if (i_out < 0) i_out = 0;
+
+ /* Convert to voltage for final output. */
+ if (m_has_c4)
+ {
+ if (m_has_r4)
+ {
+ /* voltage across r4 charging cap */
+ i_out *= info->r4;
+ /* exponential charge */
+ m_v_cap4 += (i_out - m_v_cap4) * m_exponent4;
+ }
+ else
+ /* linear charge */
+ m_v_cap4 += i_out / m_exponent4;
+ if (m_v_cap4 < 0)
+ m_v_cap4 = 0;
+ v_out = m_v_cap4;
+ }
+ else
+ v_out = i_out * info->r4;
+
+
+
+ /* Clip the output if needed. */
+ if (v_out > m_v_out_max) v_out = m_v_out_max;
+
+ set_output(0, v_out);
+}
+
+DISCRETE_RESET(dst_tvca_op_amp)
+{
+ DISCRETE_DECLARE_INFO(discrete_op_amp_tvca_info)
+
+ m_r67 = info->r6 + info->r7;
+
+ m_v_out_max = info->vP - OP_AMP_NORTON_VBE;
+ /* This is probably overkill because R5 is usually much lower then r6 or r7,
+ * but it is better to play it safe. */
+ m_v_trig[0] = (info->v1 - 0.6) * RES_VOLTAGE_DIVIDER(info->r5, info->r6);
+ m_v_trig[1] = (info->v1 - 0.6 - OP_AMP_NORTON_VBE) * RES_VOLTAGE_DIVIDER(info->r5, m_r67) + OP_AMP_NORTON_VBE;
+ m_i_fixed = m_v_out_max / info->r1;
+
+ m_v_cap1 = 0;
+ /* Charge rate through r5 */
+ /* There can be a different charge rates depending on function F3. */
+ m_exponent_c[0] = RC_CHARGE_EXP(RES_2_PARALLEL(info->r5, info->r6) * info->c1);
+ m_exponent_c[1] = RC_CHARGE_EXP(RES_2_PARALLEL(info->r5, m_r67) * info->c1);
+ /* Discharge rate through r6 + r7 */
+ m_exponent_d[1] = RC_CHARGE_EXP(m_r67 * info->c1);
+ /* Discharge rate through r6 */
+ if (info->r6 != 0)
+ {
+ m_exponent_d[0] = RC_CHARGE_EXP(info->r6 * info->c1);
+ }
+ m_v_cap2 = 0;
+ m_v_trig2 = (info->v2 - 0.6 - OP_AMP_NORTON_VBE) * RES_VOLTAGE_DIVIDER(info->r8, info->r9);
+ m_exponent2[0] = RC_CHARGE_EXP(info->r9 * info->c2);
+ m_exponent2[1] = RC_CHARGE_EXP(RES_2_PARALLEL(info->r8, info->r9) * info->c2);
+ m_v_cap3 = 0;
+ m_v_trig3 = (info->v3 - 0.6 - OP_AMP_NORTON_VBE) * RES_VOLTAGE_DIVIDER(info->r10, info->r11);
+ m_exponent3[0] = RC_CHARGE_EXP(info->r11 * info->c3);
+ m_exponent3[1] = RC_CHARGE_EXP(RES_2_PARALLEL(info->r10, info->r11) * info->c3);
+ m_v_cap4 = 0;
+ if (info->r4 != 0) m_has_r4 = 1;
+ if (info->c4 != 0) m_has_c4 = 1;
+ if (m_has_r4 && m_has_c4)
+ m_exponent4 = RC_CHARGE_EXP(info->r4 * info->c4);
+
+ this->step();
+}
+
+
+/* the different logic and xtime states */
+enum
+{
+ XTIME__IN0_0__IN1_0__IN0_NOX__IN1_NOX = 0,
+ XTIME__IN0_0__IN1_0__IN0_NOX__IN1_X,
+ XTIME__IN0_0__IN1_0__IN0_X__IN1_NOX,
+ XTIME__IN0_0__IN1_0__IN0_X__IN1_X,
+ XTIME__IN0_0__IN1_1__IN0_NOX__IN1_NOX,
+ XTIME__IN0_0__IN1_1__IN0_NOX__IN1_X,
+ XTIME__IN0_0__IN1_1__IN0_X__IN1_NOX,
+ XTIME__IN0_0__IN1_1__IN0_X__IN1_X,
+ XTIME__IN0_1__IN1_0__IN0_NOX__IN1_NOX,
+ XTIME__IN0_1__IN1_0__IN0_NOX__IN1_X,
+ XTIME__IN0_1__IN1_0__IN0_X__IN1_NOX,
+ XTIME__IN0_1__IN1_0__IN0_X__IN1_X,
+ XTIME__IN0_1__IN1_1__IN0_NOX__IN1_NOX,
+ XTIME__IN0_1__IN1_1__IN0_NOX__IN1_X,
+ XTIME__IN0_1__IN1_1__IN0_X__IN1_NOX,
+ XTIME__IN0_1__IN1_1__IN0_X__IN1_X
+};
+
+
+/************************************************************************
+ *
+ * DST_XTIME_BUFFER - Buffer/Invertor gate implementation using X_TIME
+ *
+ * If OUT_LOW and OUT_HIGH are defined then the output will be energy.
+ * If they are both 0, then the output will be X_TIME logic.
+ *
+ ************************************************************************/
+#define DST_XTIME_BUFFER__IN DISCRETE_INPUT(0)
+#define DST_XTIME_BUFFER_OUT_LOW DISCRETE_INPUT(1)
+#define DST_XTIME_BUFFER_OUT_HIGH DISCRETE_INPUT(2)
+#define DST_XTIME_BUFFER_INVERT DISCRETE_INPUT(3)
+
+DISCRETE_STEP(dst_xtime_buffer)
+{
+ int in0 = (int)DST_XTIME_BUFFER__IN;
+ int out = in0;
+ int out_is_energy = 1;
+
+ double x_time = DST_XTIME_BUFFER__IN - in0;
+
+ double out_low = DST_XTIME_BUFFER_OUT_LOW;
+ double out_high = DST_XTIME_BUFFER_OUT_HIGH;
+
+ if (out_low ==0 && out_high == 0)
+ out_is_energy = 0;
+
+ if (DST_XTIME_BUFFER_INVERT != 0)
+ out ^= 1;
+
+ if (out_is_energy)
+ {
+ if (x_time > 0)
+ {
+ double diff = out_high - out_low;
+ diff = out ? diff * x_time : diff * (1.0 - x_time);
+ set_output(0, out_low + diff);
+ }
+ else
+ set_output(0, out ? out_high : out_low);
+ }
+ else
+ set_output(0, out + x_time);
+}
+
+
+/************************************************************************
+ *
+ * DST_XTIME_AND - AND/NAND gate implementation using X_TIME
+ *
+ * If OUT_LOW and OUT_HIGH are defined then the output will be energy.
+ * If they are both 0, then the output will be X_TIME logic.
+ *
+ ************************************************************************/
+#define DST_XTIME_AND__IN0 DISCRETE_INPUT(0)
+#define DST_XTIME_AND__IN1 DISCRETE_INPUT(1)
+#define DST_XTIME_AND_OUT_LOW DISCRETE_INPUT(2)
+#define DST_XTIME_AND_OUT_HIGH DISCRETE_INPUT(3)
+#define DST_XTIME_AND_INVERT DISCRETE_INPUT(4)
+
+DISCRETE_STEP(dst_xtime_and)
+{
+ int in0 = (int)DST_XTIME_AND__IN0;
+ int in1 = (int)DST_XTIME_AND__IN1;
+ int out = 0;
+ int out_is_energy = 1;
+
+ double x_time = 0;
+ double x_time0 = DST_XTIME_AND__IN0 - in0;
+ double x_time1 = DST_XTIME_AND__IN1 - in1;
+
+ int in0_has_xtime = x_time0 > 0 ? 1 : 0;
+ int in1_has_xtime = x_time1 > 0 ? 1 : 0;
+
+ double out_low = DST_XTIME_AND_OUT_LOW;
+ double out_high = DST_XTIME_AND_OUT_HIGH;
+
+ if (out_low ==0 && out_high == 0)
+ out_is_energy = 0;
+
+ switch ((in0 << 3) | (in1 << 2) | (in0_has_xtime < 1) | in1_has_xtime)
+ {
+ // these are all 0
+ //case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_NOX:
+ //case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_NOX:
+ //case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_NOX:
+ //case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_X:
+ //case XTIME__IN0_0__IN1_0__IN0_X__IN1_NOX:
+ //case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_X:
+ //case XTIME__IN0_1__IN1_0__IN0_X__IN1_NOX:
+ // break;
+
+ case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_NOX:
+ out = 1;
+ break;
+
+ case XTIME__IN0_0__IN1_1__IN0_X__IN1_NOX:
+ /*
+ * in0 1 ------
+ * 0 -------
+ * ...^....^...
+ *
+ * in1 1 -------------
+ * 0
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ x_time = x_time0;
+ break;
+
+ case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_X:
+ /*
+ * in0 1 -------------
+ * 0
+ * ...^....^...
+ *
+ * in1 1 ------
+ * 0 -------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ x_time = x_time1;
+ break;
+
+ case XTIME__IN0_0__IN1_0__IN0_X__IN1_X:
+ /*
+ * in0 1 ----- -------
+ * 0 -------- ------
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ------ --------
+ * ...^....^... ...^....^...
+ *
+ * out 1 ----- -----
+ * 0 ------- -------
+ * ...^....^... ...^....^...
+ */
+ // use x_time of input that went to 0 first/longer
+ if (x_time0 >= x_time1)
+ x_time = x_time0;
+ else
+ x_time = x_time1;
+ break;
+
+ case XTIME__IN0_0__IN1_1__IN0_X__IN1_X:
+ /*
+ * in0 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * out 1 --
+ * 0 ----- ----- ------------
+ * ...^....^... ...^....^...
+ */
+ // may have went high for a bit in this cycle
+ //if (x_time0 < x_time1)
+ // x_time = time1 - x_time0;
+ break;
+
+ case XTIME__IN0_1__IN1_0__IN0_X__IN1_X:
+ /*
+ * in0 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * out 1 --
+ * 0 ----- ----- ------------
+ * ...^....^... ...^....^...
+ */
+ // may have went high for a bit in this cycle
+ //if (x_time0 > x_time1)
+ // x_time = x_time0 - x_time1;
+ break;
+
+ case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_X:
+ /*
+ * in0 1 ------------
+ * 0
+ * ...^....^...
+ *
+ * in1 1 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ out = 1;
+ x_time = x_time1;
+ break;
+
+ case XTIME__IN0_1__IN1_1__IN0_X__IN1_NOX:
+ /*
+ * in1 0 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * in1 1 ------------
+ * 0
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ out = 1;
+ x_time = x_time0;
+ break;
+
+ case XTIME__IN0_1__IN1_1__IN0_X__IN1_X:
+ /*
+ * in0 1 ------ --------
+ * 0 ------ ----
+ * ...^....^... ...^....^...
+ *
+ * in1 1 -------- ------
+ * 0 ---- ------
+ * ...^....^... ...^....^...
+ *
+ * out 1 ------ ------
+ * 0 ------ ------
+ * ...^....^... ...^....^...
+ */
+ out = 1;
+ if (x_time0 < x_time1)
+ x_time = x_time0;
+ else
+ x_time = x_time1;
+ break;
+ }
+
+ if (DST_XTIME_AND_INVERT != 0)
+ out ^= 1;
+
+ if (out_is_energy)
+ {
+ if (x_time > 0)
+ {
+ double diff = out_high - out_low;
+ diff = out ? diff * x_time : diff * (1.0 - x_time);
+ set_output(0, out_low + diff);
+ }
+ else
+ set_output(0, out ? out_high : out_low);
+ }
+ else
+ set_output(0, out + x_time);
+}
+
+
+/************************************************************************
+ *
+ * DST_XTIME_OR - OR/NOR gate implementation using X_TIME
+ *
+ * If OUT_LOW and OUT_HIGH are defined then the output will be energy.
+ * If they are both 0, then the output will be X_TIME logic.
+ *
+ ************************************************************************/
+#define DST_XTIME_OR__IN0 DISCRETE_INPUT(0)
+#define DST_XTIME_OR__IN1 DISCRETE_INPUT(1)
+#define DST_XTIME_OR_OUT_LOW DISCRETE_INPUT(2)
+#define DST_XTIME_OR_OUT_HIGH DISCRETE_INPUT(3)
+#define DST_XTIME_OR_INVERT DISCRETE_INPUT(4)
+
+DISCRETE_STEP(dst_xtime_or)
+{
+ int in0 = (int)DST_XTIME_OR__IN0;
+ int in1 = (int)DST_XTIME_OR__IN1;
+ int out = 1;
+ int out_is_energy = 1;
+
+ double x_time = 0;
+ double x_time0 = DST_XTIME_OR__IN0 - in0;
+ double x_time1 = DST_XTIME_OR__IN1 - in1;
+
+ int in0_has_xtime = x_time0 > 0 ? 1 : 0;
+ int in1_has_xtime = x_time1 > 0 ? 1 : 0;
+
+ double out_low = DST_XTIME_OR_OUT_LOW;
+ double out_high = DST_XTIME_OR_OUT_HIGH;
+
+ if (out_low ==0 && out_high == 0)
+ out_is_energy = 0;
+
+ switch ((in0 << 3) | (in1 << 2) | (in0_has_xtime < 1) | in1_has_xtime)
+ {
+ // these are all 1
+ //case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_NOX:
+ //case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_NOX:
+ //case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_NOX:
+ //case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_X:
+ //case XTIME__IN0_0__IN1_1__IN0_X__IN1_NOX:
+ //case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_X:
+ //case XTIME__IN0_1__IN1_1__IN0_X__IN1_NOX:
+ // break;
+
+ case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_NOX:
+ out = 0;
+ break;
+
+ case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_X:
+ /*
+ * in0 1
+ * 0 -------------
+ * ...^....^...
+ *
+ * in1 1 ------
+ * 0 -------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ out = 0;
+ x_time = x_time1;
+ break;
+
+ case XTIME__IN0_0__IN1_0__IN0_X__IN1_NOX:
+ /*
+ * in0 1 ------
+ * 0 -------
+ * ...^....^...
+ *
+ * in1 1
+ * 0 -------------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ out = 0;
+ x_time = x_time0;
+ break;
+
+ case XTIME__IN0_0__IN1_0__IN0_X__IN1_X:
+ /*
+ * in0 1 ----- -------
+ * 0 -------- ------
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ------ --------
+ * ...^....^... ...^....^...
+ *
+ * out 1 ------- -------
+ * 0 ----- -----
+ * ...^....^... ...^....^...
+ */
+ out = 0;
+ // use x_time of input that was 1 last/longer
+ // this means at 0 for less x_time
+ if (x_time0 > x_time1)
+ x_time = x_time1;
+ else
+ x_time = x_time0;
+ break;
+
+ case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_X:
+ /*
+ * in0 1
+ * 0 ------------
+ * ...^....^...
+ *
+ * in1 1 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ x_time = x_time1;
+ break;
+
+ case XTIME__IN0_1__IN1_0__IN0_X__IN1_NOX:
+ /*
+ * in0 1 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * in1 1
+ * 0 ------------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ x_time = x_time0;
+ break;
+
+ case XTIME__IN0_0__IN1_1__IN0_X__IN1_X:
+ /*
+ * in0 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * out 1 ------------ ----- -----
+ * 0 --
+ * ...^....^... ...^....^...
+ */
+ // if (x_time0 > x_time1)
+ /* Not sure if it is better to use 1
+ * or the total energy which would smear the switch points together.
+ * Let's try just using 1 */
+ //x_time = xtime_0 - xtime_1;
+ break;
+
+ case XTIME__IN0_1__IN1_0__IN0_X__IN1_X:
+ /*
+ * in0 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * out 1 ------------ ----- -----
+ * 0 --
+ * ...^....^... ...^....^...
+ */
+ //if (x_time0 < x_time1)
+ /* Not sure if it is better to use 1
+ * or the total energy which would smear the switch points together.
+ * Let's try just using 1 */
+ //x_time = xtime_1 - xtime_0;
+ break;
+
+ case XTIME__IN0_1__IN1_1__IN0_X__IN1_X:
+ /*
+ * in0 1 ------ --------
+ * 0 ------ ----
+ * ...^....^... ...^....^...
+ *
+ * in1 1 -------- ------
+ * 0 ---- ------
+ * ...^....^... ...^....^...
+ *
+ * out 1 -------- --------
+ * 0 ---- ----
+ * ...^....^... ...^....^...
+ */
+ if (x_time0 > x_time1)
+ x_time = x_time0;
+ else
+ x_time = x_time1;
+ break;
+ }
+
+ if (DST_XTIME_OR_INVERT != 0)
+ out ^= 1;
+
+ if (out_is_energy)
+ {
+ if (x_time > 0)
+ {
+ double diff = out_high - out_low;
+ diff = out ? diff * x_time : diff * (1.0 - x_time);
+ set_output(0, out_low + diff);
+ }
+ else
+ set_output(0, out ? out_high : out_low);
+ }
+ else
+ set_output(0, out + x_time);
+}
+
+
+/************************************************************************
+ *
+ * DST_XTIME_XOR - XOR/XNOR gate implementation using X_TIME
+ *
+ * If OUT_LOW and OUT_HIGH are defined then the output will be energy.
+ * If they are both 0, then the output will be X_TIME logic.
+ *
+ ************************************************************************/
+#define DST_XTIME_XOR__IN0 DISCRETE_INPUT(0)
+#define DST_XTIME_XOR__IN1 DISCRETE_INPUT(1)
+#define DST_XTIME_XOR_OUT_LOW DISCRETE_INPUT(2)
+#define DST_XTIME_XOR_OUT_HIGH DISCRETE_INPUT(3)
+#define DST_XTIME_XOR_INVERT DISCRETE_INPUT(4)
+
+DISCRETE_STEP(dst_xtime_xor)
+{
+ int in0 = (int)DST_XTIME_XOR__IN0;
+ int in1 = (int)DST_XTIME_XOR__IN1;
+ int out = 1;
+ int out_is_energy = 1;
+
+ double x_time = 0;
+ double x_time0 = DST_XTIME_XOR__IN0 - in0;
+ double x_time1 = DST_XTIME_XOR__IN1 - in1;
+
+ int in0_has_xtime = x_time0 > 0 ? 1 : 0;
+ int in1_has_xtime = x_time1 > 0 ? 1 : 0;
+
+ double out_low = DST_XTIME_XOR_OUT_LOW;
+ double out_high = DST_XTIME_XOR_OUT_HIGH;
+
+ if (out_low ==0 && out_high == 0)
+ out_is_energy = 0;
+
+ switch ((in0 << 3) | (in1 << 2) | (in0_has_xtime < 1) | in1_has_xtime)
+ {
+ // these are all 1
+ //case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_NOX:
+ //case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_NOX:
+ // break;
+
+ case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_NOX:
+ case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_NOX:
+ out = 0;
+ break;
+
+ case XTIME__IN0_1__IN1_0__IN0_X__IN1_NOX:
+ /*
+ * in0 1 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * in1 1
+ * 0 ------------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ case XTIME__IN0_0__IN1_1__IN0_X__IN1_NOX:
+ /*
+ * in0 1 ------
+ * 0 -------
+ * ...^....^...
+ *
+ * in1 1 -------------
+ * 0
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ x_time = x_time0;
+ break;
+
+ case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_X:
+ /*
+ * in0 1
+ * 0 ------------
+ * ...^....^...
+ *
+ * in1 1 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_X:
+ /*
+ * in0 1 -------------
+ * 0
+ * ...^....^...
+ *
+ * in1 1 ------
+ * 0 -------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ x_time = x_time1;
+ break;
+
+ case XTIME__IN0_0__IN1_0__IN0_X__IN1_NOX:
+ /*
+ * in0 1 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * in1 1
+ * 0 ------------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ case XTIME__IN0_1__IN1_1__IN0_X__IN1_NOX:
+ /*
+ * in1 0 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * in1 1 ------------
+ * 0
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ out = 0;
+ x_time = x_time0;
+ break;
+
+ case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_X:
+ /*
+ * in0 1
+ * 0 ------------
+ * ...^....^...
+ *
+ * in1 1 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_X:
+ /*
+ * in0 1 ------------
+ * 0
+ * ...^....^...
+ *
+ * in1 1 ------
+ * 0 ------
+ * ...^....^...
+ *
+ * out 1 ------
+ * 0 ------
+ * ...^....^...
+ */
+ out = 0;
+ x_time = x_time1;
+ break;
+
+ case XTIME__IN0_0__IN1_0__IN0_X__IN1_X:
+ /*
+ * in0 1 ----- -------
+ * 0 ------- -----
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * out 1 -- --
+ * 0 ----- ----- ----- -----
+ * ...^....^... ...^....^...
+ */
+ case XTIME__IN0_1__IN1_1__IN0_X__IN1_X:
+ /*
+ * in0 1 ------ --------
+ * 0 ------ ----
+ * ...^....^... ...^....^...
+ *
+ * in1 1 -------- ------
+ * 0 ---- ------
+ * ...^....^... ...^....^...
+ *
+ * out 1 -- --
+ * 0 ---- ------ ---- ------
+ * ...^....^... ...^....^...
+ */
+ out = 0;
+ /* Not sure if it is better to use 0
+ * or the total energy which would smear the switch points together.
+ * Let's try just using 0 */
+ // x_time = abs(x_time0 - x_time1);
+ break;
+
+ case XTIME__IN0_0__IN1_1__IN0_X__IN1_X:
+ /*
+ * in0 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * out 1 ----- ----- ----- -----
+ * 0 -- --
+ * ...^....^... ...^....^...
+ */
+ case XTIME__IN0_1__IN1_0__IN0_X__IN1_X:
+ /*
+ * in0 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * in1 1 ------- -----
+ * 0 ----- -------
+ * ...^....^... ...^....^...
+ *
+ * out 1 ----- ----- ----- -----
+ * 0 -- --
+ * ...^....^... ...^....^...
+ */
+ /* Not sure if it is better to use 1
+ * or the total energy which would smear the switch points together.
+ * Let's try just using 1 */
+ // x_time = 1.0 - abs(x_time0 - x_time1);
+ break;
+}
+
+ if (DST_XTIME_XOR_INVERT != 0)
+ out ^= 1;
+
+ if (out_is_energy)
+ {
+ if (x_time > 0)
+ {
+ double diff = out_high - out_low;
+ diff = out ? diff * x_time : diff * (1.0 - x_time);
+ set_output(0, out_low + diff);
+ }
+ else
+ set_output(0, out ? out_high : out_low);
+ }
+ else
+ set_output(0, out + x_time);
+}