Add new capabilities to the adc/dac_bridge XSPICE code models.
If either bridge has a single analog connection and two or more digital connections it will act as a conventional multi-bit ADC or DAC. When the low threshold is higher than the high threshold, adc_bridge acts as a Schmitt trigger.
This commit is contained in:
parent
37b6fda497
commit
0f0f80f34f
|
|
@ -96,10 +96,21 @@ NON-STANDARD FEATURES
|
||||||
|
|
||||||
static Digital_State_t get_out_value(double in, double low, double high)
|
static Digital_State_t get_out_value(double in, double low, double high)
|
||||||
{
|
{
|
||||||
if (in >= high)
|
if (low <= high) {
|
||||||
return ONE;
|
/* Normal operation. */
|
||||||
else if (in <= low)
|
|
||||||
return ZERO;
|
if (in >= high)
|
||||||
|
return ONE;
|
||||||
|
else if (in <= low)
|
||||||
|
return ZERO;
|
||||||
|
} else {
|
||||||
|
/* (low > high)! Schmitt triger. */
|
||||||
|
|
||||||
|
if (in >= low)
|
||||||
|
return ONE;
|
||||||
|
else if (in <= high)
|
||||||
|
return ZERO;
|
||||||
|
}
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,22 +121,34 @@ void cm_adc_bridge(ARGS)
|
||||||
in_high; /* analog output value corresponding to '1'
|
in_high; /* analog output value corresponding to '1'
|
||||||
digital input */
|
digital input */
|
||||||
int i, /* generic loop counter index */
|
int i, /* generic loop counter index */
|
||||||
size; /* number of input & output ports */
|
size_in, /* number of input ports */
|
||||||
|
size_out; /* number of output ports */
|
||||||
|
|
||||||
Digital_State_t *out, /* base address of array holding all output
|
Digital_State_t *out, /* base address of array holding all output
|
||||||
values plus their previous values */
|
values plus their previous values */
|
||||||
test; /* temp holding variable for digital states */
|
test; /* temp holding variable for digital states */
|
||||||
|
|
||||||
/* determine "width" of the node bridge... */
|
|
||||||
|
|
||||||
size = PORT_SIZE(in);
|
|
||||||
in_high = PARAM(in_high);
|
in_high = PARAM(in_high);
|
||||||
in_low = PARAM(in_low);
|
in_low = PARAM(in_low);
|
||||||
|
|
||||||
|
/* determine "width" of the node bridge... */
|
||||||
|
|
||||||
|
size_in = PORT_SIZE(in);
|
||||||
|
size_out = PORT_SIZE(out);
|
||||||
|
|
||||||
if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/
|
if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/
|
||||||
|
if (size_in != size_out) {
|
||||||
|
if (size_in != 1) {
|
||||||
|
cm_message_printf("Error: %d input ports with %d outputs",
|
||||||
|
size_in, size_out);
|
||||||
|
} else if (in_low >= in_high) {
|
||||||
|
cm_message_printf("Error: bad threshold values (low > high)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate storage for outputs */
|
/* Allocate storage for outputs */
|
||||||
|
|
||||||
cm_event_alloc(0, size * (int) sizeof(Digital_State_t));
|
cm_event_alloc(0, size_out * (int) sizeof(Digital_State_t));
|
||||||
|
|
||||||
/* Get discrete addresses */
|
/* Get discrete addresses */
|
||||||
|
|
||||||
|
|
@ -133,7 +156,7 @@ void cm_adc_bridge(ARGS)
|
||||||
|
|
||||||
/* Ensure output on first call. */
|
/* Ensure output on first call. */
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size_out; i++)
|
||||||
out[i] = UNKNOWN + 1;
|
out[i] = UNKNOWN + 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -143,13 +166,75 @@ void cm_adc_bridge(ARGS)
|
||||||
|
|
||||||
out = (Digital_State_t *) cm_event_get_ptr(0, 0);
|
out = (Digital_State_t *) cm_event_get_ptr(0, 0);
|
||||||
|
|
||||||
|
if (size_in != size_out) {
|
||||||
|
if (size_in != 1) {
|
||||||
|
if (size_in < size_out)
|
||||||
|
size_out = size_in;
|
||||||
|
else
|
||||||
|
size_in = size_out;
|
||||||
|
} else {
|
||||||
|
double in;
|
||||||
|
|
||||||
|
/* Single-input, multi-bit output option. */
|
||||||
|
|
||||||
|
in = (INPUT(in[0]) - in_low) / (in_high - in_low);
|
||||||
|
switch (CALL_TYPE) {
|
||||||
|
case ANALOG:
|
||||||
|
for (i = 0; i < size_out; i++) {
|
||||||
|
test = (in >= 0.5);
|
||||||
|
if (test != out[i]) {
|
||||||
|
/* call for event breakpoint... */
|
||||||
|
|
||||||
|
cm_event_queue(TIME);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (test)
|
||||||
|
in -= 0.5;
|
||||||
|
in *= 2.0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EVENT: /** discrete call...lots to do **/
|
||||||
|
for (i = 0; i < size_out; i++) {
|
||||||
|
test = (in >= 0.5);
|
||||||
|
if (test != out[i]) {
|
||||||
|
switch (test) {
|
||||||
|
case ZERO:
|
||||||
|
OUTPUT_DELAY(out[i]) = PARAM(fall_delay);
|
||||||
|
break;
|
||||||
|
case ONE:
|
||||||
|
OUTPUT_DELAY(out[i]) = PARAM(rise_delay);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out[i] = test;
|
||||||
|
OUTPUT_STATE(out[i]) = test;
|
||||||
|
OUTPUT_STRENGTH(out[i]) = STRONG;
|
||||||
|
} else {
|
||||||
|
OUTPUT_CHANGED(out[i]) = FALSE;
|
||||||
|
}
|
||||||
|
if (test)
|
||||||
|
in -= 0.5;
|
||||||
|
in *= 2.0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Normal, multiple single-bit conversion output option. */
|
||||||
|
|
||||||
switch (CALL_TYPE) {
|
switch (CALL_TYPE) {
|
||||||
case ANALOG: /** analog call...check for breakpoint calls. **/
|
case ANALOG: /** analog call...check for breakpoint calls. **/
|
||||||
/* loop through all inputs... */
|
/* loop through all inputs... */
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size_out; i++) {
|
||||||
test = get_out_value(INPUT(in[i]), in_low, in_high);
|
test = get_out_value(INPUT(in[i]), in_low, in_high);
|
||||||
if (test != out[i]) {
|
if (test != out[i]) {
|
||||||
/* call for event breakpoint... */
|
/* call for event breakpoint... */
|
||||||
|
|
||||||
cm_event_queue(TIME);
|
cm_event_queue(TIME);
|
||||||
|
|
@ -161,9 +246,9 @@ void cm_adc_bridge(ARGS)
|
||||||
case EVENT: /** discrete call...lots to do **/
|
case EVENT: /** discrete call...lots to do **/
|
||||||
/* loop through all inputs... */
|
/* loop through all inputs... */
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size_out; i++) {
|
||||||
test = get_out_value(INPUT(in[i]), in_low, in_high);
|
test = get_out_value(INPUT(in[i]), in_low, in_high);
|
||||||
if (test != out[i]) {
|
if (test != out[i]) {
|
||||||
/* Post changed value. */
|
/* Post changed value. */
|
||||||
|
|
||||||
OUTPUT_STATE(out[i]) = test;
|
OUTPUT_STATE(out[i]) = test;
|
||||||
|
|
@ -175,6 +260,12 @@ void cm_adc_bridge(ARGS)
|
||||||
OUTPUT_DELAY(out[i]) = PARAM(rise_delay);
|
OUTPUT_DELAY(out[i]) = PARAM(rise_delay);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (in_low > in_high) {
|
||||||
|
/* Input is in hysteresis band. */
|
||||||
|
|
||||||
|
OUTPUT_CHANGED(out[i]) = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (out[i] == ZERO)
|
if (out[i] == ZERO)
|
||||||
OUTPUT_DELAY(out[i]) = PARAM(rise_delay);
|
OUTPUT_DELAY(out[i]) = PARAM(rise_delay);
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,11 @@ Spice_Model_Name: adc_bridge
|
||||||
C_Function_Name: cm_adc_bridge
|
C_Function_Name: cm_adc_bridge
|
||||||
Description: "analog-to-digital converter node bridge"
|
Description: "analog-to-digital converter node bridge"
|
||||||
|
|
||||||
|
/* Input and output are vector ports. If port numbers are equal the
|
||||||
|
* device acts as a set of individual comparators (use %vd or %id for
|
||||||
|
* differential inputs. With a single input and multiple outputs,
|
||||||
|
* it is a single ADC with multi-bit output.
|
||||||
|
*/
|
||||||
|
|
||||||
PORT_TABLE:
|
PORT_TABLE:
|
||||||
|
|
||||||
|
|
@ -32,11 +37,12 @@ Description: "input" "output"
|
||||||
Direction: in out
|
Direction: in out
|
||||||
Default_Type: v d
|
Default_Type: v d
|
||||||
Allowed_Types: [v,vd,i,id,vnam] [d]
|
Allowed_Types: [v,vd,i,id,vnam] [d]
|
||||||
Vector: yes yes
|
Vector: yes yes
|
||||||
Vector_Bounds: - -
|
Vector_Bounds: - -
|
||||||
Null_Allowed: no no
|
Null_Allowed: no no
|
||||||
|
|
||||||
|
|
||||||
|
/* If in_low > in_high the adc_bridge has hysteresis - a Schmitt trigger. */
|
||||||
|
|
||||||
PARAMETER_TABLE:
|
PARAMETER_TABLE:
|
||||||
|
|
||||||
|
|
@ -72,3 +78,15 @@ Limits: [1e-12 -] [1e-12 -]
|
||||||
Vector: no no
|
Vector: no no
|
||||||
Vector_Bounds: - -
|
Vector_Bounds: - -
|
||||||
Null_Allowed: yes yes
|
Null_Allowed: yes yes
|
||||||
|
|
||||||
|
|
||||||
|
PARAMETER_TABLE:
|
||||||
|
|
||||||
|
Parameter_Name: family
|
||||||
|
Description: "Logic family for bridging"
|
||||||
|
Data_Type: string
|
||||||
|
Default_Value: -
|
||||||
|
Limits: -
|
||||||
|
Vector: no
|
||||||
|
Vector_Bounds: -
|
||||||
|
Null_Allowed: yes
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,16 @@ AUTHORS
|
||||||
|
|
||||||
3 Jun 1991 Jeffrey P. Murray
|
3 Jun 1991 Jeffrey P. Murray
|
||||||
|
|
||||||
|
|
||||||
MODIFICATIONS
|
MODIFICATIONS
|
||||||
|
|
||||||
16 Aug 1991 Jeffrey P. Murray
|
16 Aug 1991 Jeffrey P. Murray
|
||||||
2 Oct 1991 Jeffrey P. Murray
|
2 Oct 1991 Jeffrey P. Murray
|
||||||
|
|
||||||
|
|
||||||
SUMMARY
|
SUMMARY
|
||||||
|
|
||||||
This file contains the model-specific routines used to
|
This file contains the model-specific routines used to
|
||||||
functionally describe the dac_bridge code model.
|
functionally describe the dac_bridge code model.
|
||||||
|
|
||||||
|
|
||||||
INTERFACES
|
INTERFACES
|
||||||
|
|
||||||
FILE ROUTINE CALLED
|
FILE ROUTINE CALLED
|
||||||
|
|
@ -38,11 +35,9 @@ INTERFACES
|
||||||
CMevt.c void *cm_event_alloc()
|
CMevt.c void *cm_event_alloc()
|
||||||
void *cm_event_get_ptr()
|
void *cm_event_get_ptr()
|
||||||
|
|
||||||
|
|
||||||
REFERENCED FILES
|
REFERENCED FILES
|
||||||
|
|
||||||
Inputs from and outputs to ARGS structure.
|
Inputs from and outputs to ARGS structure.
|
||||||
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
NON-STANDARD FEATURES
|
||||||
|
|
||||||
|
|
@ -115,8 +110,7 @@ NON-STANDARD FEATURES
|
||||||
|
|
||||||
NONE
|
NONE
|
||||||
|
|
||||||
==============================================================================*/
|
=============================================================================*/
|
||||||
|
|
||||||
|
|
||||||
/* Instances of this structure track digital input changes. */
|
/* Instances of this structure track digital input changes. */
|
||||||
|
|
||||||
|
|
@ -125,6 +119,29 @@ struct d_data {
|
||||||
double i_changed; // Time of input change.
|
double i_changed; // Time of input change.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Relative output value for multi-bit input. */
|
||||||
|
|
||||||
|
static double get_out_val(struct d_data *dp, int size)
|
||||||
|
{
|
||||||
|
double v;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = size - 1, v = 0.0; i >= 0; --i) {
|
||||||
|
v /= 2.0;
|
||||||
|
switch (dp[i].i) {
|
||||||
|
case ONE:
|
||||||
|
v += 0.5;
|
||||||
|
break;
|
||||||
|
case UNKNOWN:
|
||||||
|
v += 0.25;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
/*=== CM_DAC_BRIDGE ROUTINE ===*/
|
/*=== CM_DAC_BRIDGE ROUTINE ===*/
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
|
|
@ -135,9 +152,7 @@ struct d_data {
|
||||||
* Created 6/3/91 J.P.Murray *
|
* Created 6/3/91 J.P.Murray *
|
||||||
************************************************/
|
************************************************/
|
||||||
|
|
||||||
|
|
||||||
void cm_dac_bridge(ARGS)
|
void cm_dac_bridge(ARGS)
|
||||||
|
|
||||||
{
|
{
|
||||||
double out_low, /* analog output value corresponding to '0'
|
double out_low, /* analog output value corresponding to '0'
|
||||||
digital input */
|
digital input */
|
||||||
|
|
@ -157,18 +172,16 @@ void cm_dac_bridge(ARGS)
|
||||||
time_inc; /* time increment since last analog call */
|
time_inc; /* time increment since last analog call */
|
||||||
|
|
||||||
int i, /* generic loop counter index */
|
int i, /* generic loop counter index */
|
||||||
size; /* number of input & output ports */
|
multi, /* Multi-bit in, single real out. */
|
||||||
|
size_in, /* number of input ports */
|
||||||
|
size_out; /* number of output ports */
|
||||||
|
|
||||||
struct d_data *in, /* base address of array holding all input
|
struct d_data *in, /* base address of array holding all input
|
||||||
values */
|
values */
|
||||||
*in_old; /* array holding previous input values */
|
*in_old; /* array holding previous input values */
|
||||||
|
|
||||||
|
|
||||||
/* determine "width" of the node bridge... */
|
/* Read in model parameters. **/
|
||||||
|
|
||||||
size = PORT_SIZE(in);
|
|
||||||
|
|
||||||
/** Read in remaining model parameters **/
|
|
||||||
|
|
||||||
out_low = PARAM(out_low);
|
out_low = PARAM(out_low);
|
||||||
out_high = PARAM(out_high);
|
out_high = PARAM(out_high);
|
||||||
|
|
@ -180,20 +193,38 @@ void cm_dac_bridge(ARGS)
|
||||||
/* if so, take out_undef as mean of out_high and out_low. */
|
/* if so, take out_undef as mean of out_high and out_low. */
|
||||||
|
|
||||||
if (!PARAM_NULL(out_low) && !PARAM_NULL(out_high) &&
|
if (!PARAM_NULL(out_low) && !PARAM_NULL(out_high) &&
|
||||||
PARAM_NULL(out_undef) ) {
|
PARAM_NULL(out_undef)) {
|
||||||
out_undef = out_low + (out_high - out_low) / 2.0;
|
out_undef = out_low + (out_high - out_low) / 2.0;
|
||||||
} else {
|
} else {
|
||||||
out_undef = PARAM(out_undef);
|
out_undef = PARAM(out_undef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* determine "width" of the node bridge... */
|
||||||
|
|
||||||
|
size_in = PORT_SIZE(in);
|
||||||
|
size_out = PORT_SIZE(out);
|
||||||
|
multi = (size_in != size_out && size_out == 1);
|
||||||
|
if (!multi) {
|
||||||
|
if (size_in < size_out)
|
||||||
|
size_out = size_in;
|
||||||
|
else
|
||||||
|
size_in = size_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/
|
if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/
|
||||||
|
if (size_in != size_out && size_out != 1) {
|
||||||
|
cm_message_printf("Error: %d input ports with %d outputs",
|
||||||
|
size_in, size_out);
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate storage for inputs */
|
/* Allocate storage for inputs */
|
||||||
|
|
||||||
cm_event_alloc(0, size * (int) sizeof(struct d_data));
|
cm_event_alloc(0, size_in * (int)sizeof(struct d_data));
|
||||||
|
|
||||||
/* Allocate storage for outputs */
|
/* Allocate storage for outputs */
|
||||||
|
|
||||||
cm_analog_alloc(0, size * (int) sizeof(double));
|
cm_analog_alloc(0, size_out * (int)sizeof(double));
|
||||||
|
|
||||||
/* Retrieve allocated addresses. */
|
/* Retrieve allocated addresses. */
|
||||||
|
|
||||||
|
|
@ -201,88 +232,202 @@ void cm_dac_bridge(ARGS)
|
||||||
out = (double *) cm_analog_get_ptr(0, 0);
|
out = (double *) cm_analog_get_ptr(0, 0);
|
||||||
|
|
||||||
/* read current input values */
|
/* read current input values */
|
||||||
for (i=0; i<size; i++) {
|
for (i = 0; i < size_in; i++) {
|
||||||
in[i].i = INPUT_STATE(in[i]);
|
in[i].i = INPUT_STATE(in[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output initial analog levels based on input values */
|
/* Output initial analog levels based on input values */
|
||||||
|
|
||||||
for (i=0; i<size; i++) { /* assign addresses */
|
if (multi) {
|
||||||
switch (in[i].i) {
|
/* Multi-bit input, single_output. */
|
||||||
|
|
||||||
|
OUTPUT(out[0]) = *out =
|
||||||
|
get_out_val(in, size_in) * (out_high - out_low) + out_low;
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < size_in; i++) { /* assign addresses */
|
||||||
|
switch (in[i].i) {
|
||||||
case ZERO: out[i] = out_low;
|
case ZERO: out[i] = out_low;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNKNOWN: out[i] = out_undef;
|
case UNKNOWN: out[i] = out_undef;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ONE: out[i] = out_high;
|
case ONE: out[i] = out_high;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
OUTPUT(out[i]) = out[i];
|
||||||
}
|
}
|
||||||
OUTPUT(out[i]) = out[i];
|
}
|
||||||
|
for (i = 0; i < size_in; i++)
|
||||||
LOAD(in[i]) = PARAM(input_load);
|
LOAD(in[i]) = PARAM(input_load);
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
} else { /*** This is not an initialization pass...read in parameters,
|
|
||||||
retrieve storage addresses and calculate new outputs,
|
|
||||||
if required. ***/
|
|
||||||
|
|
||||||
/** Retrieve previous values... **/
|
|
||||||
|
|
||||||
/* assign discrete addresses */
|
|
||||||
|
|
||||||
in = (struct d_data *) cm_event_get_ptr(0, 0);
|
|
||||||
in_old= (struct d_data *) cm_event_get_ptr(0, 1);
|
|
||||||
|
|
||||||
/* assign analog addresses */
|
|
||||||
out = (double *) cm_analog_get_ptr(0, 0);
|
|
||||||
out_old = (double *) cm_analog_get_ptr(0, 1);
|
|
||||||
|
|
||||||
/* read current input values */
|
|
||||||
for (i=0; i<size; i++) {
|
|
||||||
in[i].i = INPUT_STATE(in[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is not an initialization pass...read in parameters,
|
||||||
|
retrieve storage addresses and calculate new outputs, if required.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Retrieve previous values... **/
|
||||||
|
|
||||||
|
in = (struct d_data *) cm_event_get_ptr(0, 0);
|
||||||
|
in_old= (struct d_data *) cm_event_get_ptr(0, 1);
|
||||||
|
|
||||||
|
/* assign analog addresses */
|
||||||
|
out = (double *) cm_analog_get_ptr(0, 0);
|
||||||
|
out_old = (double *) cm_analog_get_ptr(0, 1);
|
||||||
|
|
||||||
|
/* read current input values */
|
||||||
|
for (i = 0; i < size_in; i++) {
|
||||||
|
in[i].i = INPUT_STATE(in[i]);
|
||||||
|
}
|
||||||
|
|
||||||
switch (CALL_TYPE) {
|
switch (CALL_TYPE) {
|
||||||
|
double when, iota, vout, interval[2];
|
||||||
|
int step, step_count;
|
||||||
|
|
||||||
case EVENT: /** discrete call... **/
|
case EVENT: /** discrete call... **/
|
||||||
/* Test to see if any change has occurred in an input */
|
/* Test to see if any change has occurred in an input */
|
||||||
/* since the last digital call... */
|
/* since the last digital call... */
|
||||||
|
|
||||||
for (i=0; i<size; i++) {
|
for (i = 0; i < size_in; i++) {
|
||||||
if (in[i].i != in_old[i].i) { /* if there has been a change... */
|
if (in[i].i != in_old[i].i) { /* if there has been a change... */
|
||||||
in[i].i_changed = TIME;
|
|
||||||
|
|
||||||
/* post current time as a breakpoint */
|
/* post current time as a breakpoint */
|
||||||
|
|
||||||
cm_analog_set_perm_bkpt(TIME);
|
cm_analog_set_perm_bkpt(TIME);
|
||||||
|
|
||||||
|
if (multi) {
|
||||||
|
in[0].i_changed = TIME;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
in[i].i_changed = TIME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ANALOG: /** analog call... **/
|
case ANALOG: /** analog call... **/
|
||||||
|
|
||||||
level_inc = out_high - out_low;
|
level_inc = out_high - out_low;
|
||||||
rise_slope = level_inc / t_rise;
|
rise_slope = level_inc / t_rise;
|
||||||
fall_slope = level_inc / t_fall;
|
fall_slope = level_inc / t_fall;
|
||||||
|
|
||||||
time_inc = TIME - T(1);
|
time_inc = T(0) - T(1);
|
||||||
|
|
||||||
for (i=0; i<size; i++) {
|
if (multi) {
|
||||||
|
double v, target;
|
||||||
|
int changed;
|
||||||
|
|
||||||
|
/* Multi-bit input, single_output. */
|
||||||
|
|
||||||
|
v = get_out_val(in, size_in);
|
||||||
|
if (TIME == 0.0) {
|
||||||
|
OUTPUT(out[0]) = *out = v * level_inc + out_low;;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vout = (out_old[0] - out_low) / level_inc; // Normalise.
|
||||||
|
|
||||||
|
for (i = 0, changed = 0; i < size_in; i++) {
|
||||||
|
if (in_old[i].i != in[i].i) {
|
||||||
|
changed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
if (vout < v) {
|
||||||
|
/* Continue rising. */
|
||||||
|
|
||||||
|
vout += time_inc / t_rise;
|
||||||
|
if (vout > v)
|
||||||
|
vout = v;
|
||||||
|
} else {
|
||||||
|
/* Continue falling. */
|
||||||
|
|
||||||
|
vout -= time_inc / t_fall;
|
||||||
|
if (vout < v)
|
||||||
|
vout = v;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* There has been a change in input since the last
|
||||||
|
analog access. Determine when the change occurred
|
||||||
|
and calculate the current output, then set a breakpoint
|
||||||
|
for completion of the current transition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
iota = time_inc * 1e-7; // Ignorable
|
||||||
|
if (T(0) - in[0].i_changed < iota) {
|
||||||
|
/* Previous input value in force for whole step. */
|
||||||
|
|
||||||
|
step_count = 1;
|
||||||
|
step = 0;
|
||||||
|
interval[0] = time_inc;
|
||||||
|
} else if (in[0].i_changed - T(1) < iota) {
|
||||||
|
/* New input value in force for whole step.
|
||||||
|
* Includes common no-change case where new == old.
|
||||||
|
*/
|
||||||
|
|
||||||
|
step_count = 2;
|
||||||
|
step = 1;
|
||||||
|
interval[1] = time_inc;
|
||||||
|
} else {
|
||||||
|
/* Calculate both sides of change. */
|
||||||
|
|
||||||
|
step_count = 2;
|
||||||
|
step = 0;
|
||||||
|
interval[0] = in[0].i_changed - T(1);
|
||||||
|
interval[1] = T(0) - in[0].i_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
when = -1.0;
|
||||||
|
for (; step < step_count; ++step) {
|
||||||
|
int last_step = (step == step_count - 1);
|
||||||
|
|
||||||
|
if (step == 0)
|
||||||
|
target = get_out_val(in_old, size_in);
|
||||||
|
else
|
||||||
|
target = v;
|
||||||
|
|
||||||
|
if (target > vout) {
|
||||||
|
/* Rising. */
|
||||||
|
|
||||||
|
vout += interval[step] / t_rise;
|
||||||
|
if (vout > v)
|
||||||
|
vout = v;
|
||||||
|
else if (last_step)
|
||||||
|
when = (v - vout) * t_rise;
|
||||||
|
} else if (target < vout) {
|
||||||
|
/* Falling. */
|
||||||
|
|
||||||
|
vout -= interval[step] / t_fall;
|
||||||
|
if (vout < v)
|
||||||
|
vout = v;
|
||||||
|
else if (last_step)
|
||||||
|
when = (vout - v) * t_fall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (when > 0.0)
|
||||||
|
cm_analog_set_perm_bkpt(when + TIME);
|
||||||
|
}
|
||||||
|
out[0] = vout * level_inc + out_low;
|
||||||
|
OUTPUT(out[0]) = out[0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiple single-bit conversions. */
|
||||||
|
|
||||||
|
for (i = 0; i < size_in; i++) {
|
||||||
if ( 0.0 == TIME ) { /*** DC analysis ***/
|
if ( 0.0 == TIME ) { /*** DC analysis ***/
|
||||||
switch (in[i].i) {
|
switch (in[i].i) {
|
||||||
|
|
||||||
case ONE:
|
case ONE:
|
||||||
out[i] = out_high;
|
vout = out_high;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZERO:
|
case ZERO:
|
||||||
out[i] = out_low;
|
vout = out_low;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
out[i] = out_undef;
|
vout = out_undef;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if ( in_old[i].i == in[i].i ) {
|
} else if ( in_old[i].i == in[i].i ) {
|
||||||
|
|
@ -295,44 +440,41 @@ void cm_dac_bridge(ARGS)
|
||||||
switch (in[i].i) {
|
switch (in[i].i) {
|
||||||
case ZERO:
|
case ZERO:
|
||||||
if (out_old[i] > out_low) { /* output still dropping */
|
if (out_old[i] > out_low) { /* output still dropping */
|
||||||
out[i] = out_old[i] - fall_slope * time_inc;
|
vout = out_old[i] - fall_slope * time_inc;
|
||||||
if ( out_low > out[i])
|
if (out_low > vout)
|
||||||
out[i] = out_low;
|
vout = out_low;
|
||||||
} else { /* output at out_low */
|
} else { /* output at out_low */
|
||||||
out[i] = out_low;
|
vout = out_low;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ONE:
|
case ONE:
|
||||||
if (out_old[i] < out_high) { /* output still rising */
|
if (out_old[i] < out_high) { /* output still rising */
|
||||||
out[i] = out_old[i] + rise_slope * time_inc;
|
vout = out_old[i] + rise_slope * time_inc;
|
||||||
if ( out_high < out[i])
|
if (out_high < vout)
|
||||||
out[i] = out_high;
|
vout = out_high;
|
||||||
} else { /* output at out_high */
|
} else { /* output at out_high */
|
||||||
out[i] = out_high;
|
vout = out_high;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
if (out_old[i] < out_undef) { /* output still rising */
|
if (out_old[i] < out_undef) { /* output still rising */
|
||||||
out[i] = out_old[i] + rise_slope * time_inc;
|
vout = out_old[i] + rise_slope * time_inc;
|
||||||
if ( out_undef < out[i])
|
if (out_undef < vout)
|
||||||
out[i] = out_undef;
|
vout = out_undef;
|
||||||
} else {
|
} else {
|
||||||
if (out_old[i] > out_undef) { /* output still falling */
|
if (out_old[i] > out_undef) { /* output still falling */
|
||||||
out[i] = out_old[i] - fall_slope * time_inc;
|
vout = out_old[i] - fall_slope * time_inc;
|
||||||
if ( out_undef > out[i])
|
if (out_undef > vout)
|
||||||
out[i] = out_undef;
|
vout = out_undef;
|
||||||
} else { /* output at out_undef */
|
} else { /* output at out_undef */
|
||||||
out[i] = out_undef;
|
vout = out_undef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
double when, iota, vout, interval[2];
|
|
||||||
int step, step_count;
|
|
||||||
|
|
||||||
/* There HAS been a change in this digital input
|
/* There HAS been a change in this digital input
|
||||||
since the last analog access. Determine when the change
|
since the last analog access. Determine when the change
|
||||||
occurred and calculate the current output, then
|
occurred and calculate the current output, then
|
||||||
|
|
@ -412,9 +554,8 @@ void cm_dac_bridge(ARGS)
|
||||||
}
|
}
|
||||||
if (when > 0.0)
|
if (when > 0.0)
|
||||||
cm_analog_set_perm_bkpt(when + TIME);
|
cm_analog_set_perm_bkpt(when + TIME);
|
||||||
out[i] = vout;
|
|
||||||
}
|
}
|
||||||
OUTPUT(out[i]) = out[i];
|
OUTPUT(out[i]) = out[i] = vout;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue