Merge branch 'pre-master' into bt_dev
This commit is contained in:
commit
37cfc47ef9
|
|
@ -1,4 +1,4 @@
|
||||||
Compare four different 4-bit full adders,
|
Compare five different 4-bit full adders,
|
||||||
made of NAND gates
|
made of NAND gates
|
||||||
Simulating for 6400ns
|
Simulating for 6400ns
|
||||||
|
|
||||||
|
|
@ -21,3 +21,9 @@ Fully digital, event node based NAND gates
|
||||||
digital plotting into vcd file, display with gtkwave
|
digital plotting into vcd file, display with gtkwave
|
||||||
Simulation time 0.27s
|
Simulation time 0.27s
|
||||||
|
|
||||||
|
adder_esource
|
||||||
|
Uses the NAND variant of the E-type behavioral voltage source.
|
||||||
|
|
||||||
|
There are further variations of adder_Xspice in directory
|
||||||
|
examples/digital/auto_bridge.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
ADDER - 4 BIT BINARY ADDER USING E-SOURCE AND GATES
|
||||||
|
* behavioral gate description
|
||||||
|
|
||||||
|
*** SUBCIRCUIT DEFINITION
|
||||||
|
|
||||||
|
.SUBCKT 74HC00 in1 in2 out NVCC NVGND vcc1={vcc} tripdt1={tripdt}
|
||||||
|
.param Rout={60*4.0/(vcc1-0.5)} ; standard output driver
|
||||||
|
E1 out20 0 nand(2) in1 0 in2 0 ({vcc / 3}, 0) ({2 * vcc / 3}, {vcc})
|
||||||
|
Rout out20 out {Rout}
|
||||||
|
.ends
|
||||||
|
|
||||||
|
.param vcc=3 tripdt=6n
|
||||||
|
|
||||||
|
.include ../adder_common.inc
|
||||||
|
|
||||||
|
.END
|
||||||
|
|
@ -60,7 +60,7 @@ int donedico(dico_t *);
|
||||||
void dico_free_entry(entry_t *);
|
void dico_free_entry(entry_t *);
|
||||||
bool defsubckt(dico_t *, const struct card *);
|
bool defsubckt(dico_t *, const struct card *);
|
||||||
int findsubckt(dico_t *, const char *s);
|
int findsubckt(dico_t *, const char *s);
|
||||||
bool nupa_substitute(dico_t *, const char *s, char *r);
|
bool nupa_substitute(dico_t *, const char *s, char **lp);
|
||||||
bool nupa_assignment(dico_t *, const char *s, char mode);
|
bool nupa_assignment(dico_t *, const char *s, char mode);
|
||||||
bool nupa_subcktcall(dico_t *, const char *s, const char *x,
|
bool nupa_subcktcall(dico_t *, const char *s, const char *x,
|
||||||
char *inst_name);
|
char *inst_name);
|
||||||
|
|
|
||||||
|
|
@ -676,10 +676,12 @@ nupa_eval(struct card *card)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (c == 'P') { /* evaluate parameters */
|
if (c == 'P') { /* evaluate parameters */
|
||||||
// err = nupa_substitute(dico, dico->dynrefptr[linenum], s);
|
|
||||||
nupa_assignment(dicoS, dicoS->dynrefptr[linenum], 'N');
|
nupa_assignment(dicoS, dicoS->dynrefptr[linenum], 'N');
|
||||||
} else if (c == 'B') { /* substitute braces line */
|
} else if (c == 'B') { /* substitute braces line */
|
||||||
err = nupa_substitute(dicoS, dicoS->dynrefptr[linenum], s);
|
/* nupa_substitute() may reallocate line buffer. */
|
||||||
|
|
||||||
|
err = nupa_substitute(dicoS, dicoS->dynrefptr[linenum], &card->line);
|
||||||
|
s = card->line;
|
||||||
} else if (c == 'X') {
|
} else if (c == 'X') {
|
||||||
/* compute args of subcircuit, if required */
|
/* compute args of subcircuit, if required */
|
||||||
char *inst_name = copy_substring(s, skip_non_ws(s));
|
char *inst_name = copy_substring(s, skip_non_ws(s));
|
||||||
|
|
|
||||||
|
|
@ -1201,27 +1201,48 @@ evaluate_expr(dico_t *dico, DSTRINGPTR qstr_p, const char *t, const char * const
|
||||||
|
|
||||||
/********* interface functions for spice3f5 extension ***********/
|
/********* interface functions for spice3f5 extension ***********/
|
||||||
|
|
||||||
static char *
|
static bool
|
||||||
insertnumber(dico_t *dico, char * const s, DSTRINGPTR ustr_p)
|
insertnumber(dico_t *dico, char **lp, DSTRINGPTR ustr_p)
|
||||||
/* insert u in string s in place of the next placeholder number */
|
/* insert *ustr_p in string *lp in place of the next placeholder number */
|
||||||
{
|
{
|
||||||
const char *u = ds_get_buf(ustr_p);
|
const char *u = ds_get_buf(ustr_p);
|
||||||
|
char *s = *lp; // Point to line contents
|
||||||
char buf[ACT_CHARACTS+1];
|
long id;
|
||||||
|
int n;
|
||||||
long id = 0;
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
char *p = strstr(s, "numparm__________");
|
char *p = strstr(s, "numparm__________");
|
||||||
|
|
||||||
if (p &&
|
if (p &&
|
||||||
(1 == sscanf(p, "numparm__________%8lx%n", &id, &n)) &&
|
(1 == sscanf(p, "numparm__________%8lx%n", &id, &n)) &&
|
||||||
(n == ACT_CHARACTS) &&
|
(n == ACT_CHARACTS) &&
|
||||||
(id > 0) && (id < dynsubst + 1) &&
|
(id > 0) && (id < dynsubst + 1)) {
|
||||||
(snprintf(buf, sizeof(buf), "%-25s", u) == ACT_CHARACTS))
|
/* Found a target for substitution. */
|
||||||
{
|
|
||||||
memcpy(p, buf, ACT_CHARACTS);
|
n = ds_get_length(ustr_p);
|
||||||
return p + ACT_CHARACTS;
|
if (n <= ACT_CHARACTS) {
|
||||||
|
char buf[ACT_CHARACTS + 1];
|
||||||
|
|
||||||
|
/* Replace in place. */
|
||||||
|
|
||||||
|
snprintf(buf, sizeof buf, "%-*s", ACT_CHARACTS, u);
|
||||||
|
memcpy(p, buf, ACT_CHARACTS);
|
||||||
|
} else {
|
||||||
|
char *newline;
|
||||||
|
|
||||||
|
/* Requires reallocation. */
|
||||||
|
|
||||||
|
newline = malloc((p - s) + n + strlen(p + ACT_CHARACTS) + 1);
|
||||||
|
if (!newline) {
|
||||||
|
message(dico, "nupa_substitute failed: no memory\n");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
memcpy(newline, s, (p - s));
|
||||||
|
memcpy(newline + (p - s), u, n);
|
||||||
|
strcpy(newline + (p - s) + n, p + ACT_CHARACTS);
|
||||||
|
free(*lp);
|
||||||
|
*lp = newline;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
message
|
message
|
||||||
|
|
@ -1229,18 +1250,15 @@ insertnumber(dico_t *dico, char * const s, DSTRINGPTR ustr_p)
|
||||||
"insertnumber: fails.\n"
|
"insertnumber: fails.\n"
|
||||||
" s = \"%s\" u=\"%s\" id=%ld\n",
|
" s = \"%s\" u=\"%s\" id=%ld\n",
|
||||||
s, u, id);
|
s, u, id);
|
||||||
|
return TRUE;
|
||||||
/* swallow everything on failure */
|
|
||||||
return s + strlen(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nupa_substitute(dico_t *dico, const char *s, char *r)
|
nupa_substitute(dico_t *dico, const char *s, char **lp)
|
||||||
/* s: pointer to original source line.
|
/* s: pointer to original source line.
|
||||||
r: pointer to result line, already heavily modified wrt s
|
lp: pointer to result line pointer, line already heavily modified wrt s:
|
||||||
anywhere we find a 10-char numstring in r, substitute it.
|
anywhere we find a 25-char numstring in *lp, substitute it.
|
||||||
bug: wont flag overflow!
|
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
const char * const s_end = s + strlen(s);
|
const char * const s_end = s + strlen(s);
|
||||||
|
|
@ -1248,9 +1266,7 @@ nupa_substitute(dico_t *dico, const char *s, char *r)
|
||||||
|
|
||||||
DS_CREATE(qstr, 200); /* temp result dynamic string */
|
DS_CREATE(qstr, 200); /* temp result dynamic string */
|
||||||
|
|
||||||
|
|
||||||
while (s < s_end) {
|
while (s < s_end) {
|
||||||
|
|
||||||
char c = *s++;
|
char c = *s++;
|
||||||
|
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
|
|
@ -1289,14 +1305,14 @@ nupa_substitute(dico_t *dico, const char *s, char *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
s = kptr + 1;
|
s = kptr + 1;
|
||||||
r = insertnumber(dico, r, &qstr);
|
err = insertnumber(dico, lp, &qstr);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lend:
|
Lend:
|
||||||
ds_free(&qstr);
|
ds_free(&qstr);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task)
|
||||||
|
|
||||||
#ifdef HAS_PROGREP
|
#ifdef HAS_PROGREP
|
||||||
if (linecount > 0) {
|
if (linecount > 0) {
|
||||||
SetAnalyse( "Circuit2", (int) (1000.*actcount/linecount));
|
SetAnalyse( "Parse", (int) (1000.*actcount/linecount));
|
||||||
actcount++;
|
actcount++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -174,33 +174,81 @@ get_output( ARGS, double x )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
get_reverse_output( ARGS, double x )
|
||||||
|
{
|
||||||
|
int size = PARAM_SIZE(x);
|
||||||
|
double result = 0;
|
||||||
|
double slope = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* check if x beyond specified limits */
|
||||||
|
if ( x <= PARAM(x[0]) ) return PARAM(y[size-1]);
|
||||||
|
if ( x >= PARAM(x[size-1]) ) return PARAM(y[0]);
|
||||||
|
|
||||||
|
for ( i = 1; i < size; i++ )
|
||||||
|
if ( x > PARAM(x[i-1]) && x <= PARAM(x[i]) )
|
||||||
|
{
|
||||||
|
result = PARAM(y[size - i - 1]) + slope * (x - PARAM(x[i - 1]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cm_multi_input_pwl(ARGS)
|
cm_multi_input_pwl(ARGS)
|
||||||
{
|
{
|
||||||
const char* model = ( PARAM_NULL(model) == 1 ) ? "and" : PARAM(model);
|
const char* model = PARAM(model);
|
||||||
double output;
|
double output;
|
||||||
|
|
||||||
if ( ANALYSIS == TRANSIENT || ANALYSIS == DC )
|
if (INIT) {
|
||||||
{
|
int type;
|
||||||
if ( strcmp( model, "and" ) != 0 && strcmp( model, "or" ) != 0 &&
|
|
||||||
strcmp( model, "nand" ) != 0 && strcmp( model, "nor" ) != 0 )
|
if (!strcmp(model, "and"))
|
||||||
{
|
type = 0;
|
||||||
fprintf( stderr, "ERROR(cm_multi_input_pwl): unknown gate model type '%s'; expecting 'and|or|nand|nor'.\n", model );
|
else if (!strcmp(model, "nand"))
|
||||||
|
type = 1;
|
||||||
|
else if (!strcmp(model, "or"))
|
||||||
|
type = 2;
|
||||||
|
else if (!strcmp(model, "nor"))
|
||||||
|
type = 3;
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "ERROR(cm_multi_input_pwl): unknown gate model type "
|
||||||
|
"'%s'; expecting 'and|or|nand|nor'.\n", model );
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
if ( PARAM_SIZE(x) != PARAM_SIZE(y) )
|
STATIC_VAR(type) = type;
|
||||||
{
|
if ( PARAM_SIZE(x) != PARAM_SIZE(y) ) {
|
||||||
fprintf( stderr, "ERROR(cm_multi_input_pwl): 'x' and 'y' input vectors are not the same size!\n" );
|
fprintf(stderr, "ERROR(cm_multi_input_pwl): 'x' and 'y' input vectors are not the same size!\n" );
|
||||||
exit(-1);
|
if (PARAM_SIZE(x) > PARAM_SIZE(y))
|
||||||
}
|
PARAM_SIZE(x) = PARAM_SIZE(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ANALYSIS == TRANSIENT || ANALYSIS == DC ) {
|
||||||
/*
|
/*
|
||||||
Iterate through each input and find output value
|
Iterate through each input and find output value
|
||||||
and/nand: controlling input is chosen on the basis of the smallest value
|
and/nand: controlling input is chosen on the basis of the smallest value
|
||||||
or/nor: controlling input is chosen on the basis of the largest value
|
or/nor: controlling input is chosen on the basis of the largest value
|
||||||
*/
|
*/
|
||||||
if (strstr(model, "and")) output = get_output(mif_private, get_smallest_input(mif_private));
|
|
||||||
else output = get_output(mif_private, get_largest_input(mif_private));
|
|
||||||
|
|
||||||
|
switch (STATIC_VAR(type)) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
output = get_output(mif_private, get_smallest_input(mif_private));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
output = get_reverse_output(mif_private,
|
||||||
|
get_smallest_input(mif_private));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
output = get_output(mif_private, get_largest_input(mif_private));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
output = get_reverse_output(mif_private,
|
||||||
|
get_largest_input(mif_private));
|
||||||
|
break;
|
||||||
|
}
|
||||||
OUTPUT(out) = output;
|
OUTPUT(out) = output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,3 +49,11 @@ Limits: - - -
|
||||||
Vector: yes yes no
|
Vector: yes yes no
|
||||||
Vector_Bounds: [2 -] [2 -] -
|
Vector_Bounds: [2 -] [2 -] -
|
||||||
Null_Allowed: no no yes
|
Null_Allowed: no no yes
|
||||||
|
|
||||||
|
/* This is used internally to cache the model type. */
|
||||||
|
|
||||||
|
STATIC_VAR_TABLE:
|
||||||
|
|
||||||
|
Static_Var_Name: type
|
||||||
|
Description: "Internal copy of model type"
|
||||||
|
Data_Type: int
|
||||||
|
|
|
||||||
|
|
@ -63,22 +63,17 @@ NON-STANDARD FEATURES
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== MACROS ===========================*/
|
/*=== MACROS ===========================*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
|
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
|
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
|
|
@ -123,6 +118,13 @@ NON-STANDARD FEATURES
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Instances of this structure track digital input changes. */
|
||||||
|
|
||||||
|
struct d_data {
|
||||||
|
Digital_State_t i; // Input value.
|
||||||
|
double i_changed; // Time of input change.
|
||||||
|
};
|
||||||
|
|
||||||
/*=== CM_DAC_BRIDGE ROUTINE ===*/
|
/*=== CM_DAC_BRIDGE ROUTINE ===*/
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
|
|
@ -137,41 +139,35 @@ NON-STANDARD FEATURES
|
||||||
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 */
|
||||||
out_high, /* analog output value corresponding to '1'
|
out_high, /* analog output value corresponding to '1'
|
||||||
digital input */
|
digital input */
|
||||||
out_undef, /* analog output value corresponding to 'U'
|
out_undef, /* analog output value corresponding to 'U'
|
||||||
digital input */
|
digital input */
|
||||||
t_rise, /* rise time...used to produce d(out)/d(time)
|
t_rise, /* rise time...used to produce d(out)/d(time)
|
||||||
values for gradual change in analog output. */
|
values for gradual change in analog output. */
|
||||||
t_fall, /* fall time...used to produce d(out)/d(time)
|
t_fall, /* fall time...used to produce d(out)/d(time)
|
||||||
values for gradual change in analog output. */
|
values for gradual change in analog output. */
|
||||||
*out, /* array holding all output values */
|
*out, /* array holding all output values */
|
||||||
*out_old, /* array holding previous output values */
|
*out_old, /* array holding previous output values */
|
||||||
fraction, /* fraction of total rise or fall time to add to
|
level_inc, /* incremental level value out_high - out_low */
|
||||||
current time value for breakpoint calculation */
|
rise_slope, /* level_inc divided by t_rise */
|
||||||
level_inc, /* incremental level value out_high - out_low */
|
fall_slope, /* level_inc divided by t_fall */
|
||||||
rise_slope, /* level_inc divided by t_rise */
|
time_inc; /* time increment since last analog call */
|
||||||
fall_slope, /* level_inc divided by t_fall */
|
|
||||||
time_inc, /* time increment since last analog call */
|
|
||||||
test; /* testing variable */
|
|
||||||
|
|
||||||
int i, /* generic loop counter index */
|
int i, /* generic loop counter index */
|
||||||
size; /* number of input & output ports */
|
size; /* number of input & output ports */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Digital_State_t *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... */
|
/* determine "width" of the node bridge... */
|
||||||
|
|
||||||
size = PORT_SIZE(in);
|
size = PORT_SIZE(in);
|
||||||
|
|
||||||
|
|
||||||
/** Read in remaining model parameters **/
|
/** Read in remaining model parameters **/
|
||||||
|
|
||||||
out_low = PARAM(out_low);
|
out_low = PARAM(out_low);
|
||||||
|
|
@ -179,7 +175,6 @@ void cm_dac_bridge(ARGS)
|
||||||
t_rise = PARAM(t_rise);
|
t_rise = PARAM(t_rise);
|
||||||
t_fall = PARAM(t_fall);
|
t_fall = PARAM(t_fall);
|
||||||
|
|
||||||
|
|
||||||
/* Test to see if out_low and out_high were specified, but */
|
/* Test to see if out_low and out_high were specified, but */
|
||||||
/* out_undef was not... */
|
/* out_undef was not... */
|
||||||
/* 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. */
|
||||||
|
|
@ -187,86 +182,64 @@ void cm_dac_bridge(ARGS)
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/
|
if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/
|
||||||
|
|
||||||
|
|
||||||
/* Allocate storage for inputs */
|
/* Allocate storage for inputs */
|
||||||
cm_event_alloc(0, size * (int) sizeof(Digital_State_t));
|
|
||||||
|
|
||||||
|
cm_event_alloc(0, size * (int) sizeof(struct d_data));
|
||||||
|
|
||||||
/* Allocate storage for outputs */
|
/* Allocate storage for outputs */
|
||||||
|
|
||||||
/* retrieve previously-allocated discrete input and */
|
|
||||||
/* allocate storage for analog output values. */
|
|
||||||
|
|
||||||
/* allocate output space and obtain adresses */
|
|
||||||
cm_analog_alloc(0, size * (int) sizeof(double));
|
cm_analog_alloc(0, size * (int) sizeof(double));
|
||||||
|
|
||||||
/* assign discrete addresses */
|
/* Retrieve allocated addresses. */
|
||||||
in = in_old = (Digital_State_t *) cm_event_get_ptr(0,0);
|
|
||||||
|
|
||||||
/* assign analog addresses */
|
|
||||||
out = out_old = (double *) cm_analog_get_ptr(0,0);
|
|
||||||
|
|
||||||
|
in = in_old = (struct d_data *) cm_event_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; i++) {
|
||||||
in[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 */
|
for (i=0; i<size; i++) { /* assign addresses */
|
||||||
|
switch (in[i].i) {
|
||||||
switch (in[i]) {
|
case ZERO: out[i] = out_low;
|
||||||
|
|
||||||
case ZERO: out[i] = out_old[i] = out_low;
|
|
||||||
OUTPUT(out[i]) = out_old[i];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNKNOWN: out[i] = out_old[i] = out_undef;
|
case UNKNOWN: out[i] = out_undef;
|
||||||
OUTPUT(out[i]) = out_old[i];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ONE: out[i] = out_old[i] = out_high;
|
case ONE: out[i] = out_high;
|
||||||
OUTPUT(out[i]) = out_old[i];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
OUTPUT(out[i]) = out[i];
|
||||||
LOAD(in[i]) = PARAM(input_load);
|
LOAD(in[i]) = PARAM(input_load);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
return;
|
||||||
|
} else { /*** This is not an initialization pass...read in parameters,
|
||||||
else { /*** This is not an initialization pass...read in parameters,
|
|
||||||
retrieve storage addresses and calculate new outputs,
|
retrieve storage addresses and calculate new outputs,
|
||||||
if required. ***/
|
if required. ***/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Retrieve previous values... **/
|
/** Retrieve previous values... **/
|
||||||
|
|
||||||
/* assign discrete addresses */
|
/* assign discrete addresses */
|
||||||
in = (Digital_State_t *) cm_event_get_ptr(0,0);
|
|
||||||
in_old= (Digital_State_t *) cm_event_get_ptr(0,1);
|
in = (struct d_data *) cm_event_get_ptr(0, 0);
|
||||||
|
in_old= (struct d_data *) cm_event_get_ptr(0, 1);
|
||||||
|
|
||||||
/* assign analog addresses */
|
/* assign analog addresses */
|
||||||
out = (double *) cm_analog_get_ptr(0,0);
|
out = (double *) cm_analog_get_ptr(0, 0);
|
||||||
out_old = (double *) cm_analog_get_ptr(0,1);
|
out_old = (double *) cm_analog_get_ptr(0, 1);
|
||||||
|
|
||||||
/* read current input values */
|
/* read current input values */
|
||||||
for (i=0; i<size; i++) {
|
for (i=0; i<size; i++) {
|
||||||
in[i] = INPUT_STATE(in[i]);
|
in[i].i = INPUT_STATE(in[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,40 +247,33 @@ void cm_dac_bridge(ARGS)
|
||||||
switch (CALL_TYPE) {
|
switch (CALL_TYPE) {
|
||||||
|
|
||||||
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; i++) {
|
||||||
|
if (in[i].i != in_old[i].i) { /* if there has been a change... */
|
||||||
if (in[i] != in_old[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);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = TIME - T(1);
|
||||||
|
|
||||||
for (i=0; i<size; i++) {
|
for (i=0; i<size; i++) {
|
||||||
|
|
||||||
|
|
||||||
if ( 0.0 == TIME ) { /*** DC analysis ***/
|
if ( 0.0 == TIME ) { /*** DC analysis ***/
|
||||||
|
switch (in[i].i) {
|
||||||
switch (in[i]) {
|
|
||||||
|
case ONE:
|
||||||
case ONE:
|
|
||||||
out[i] = out_high;
|
out[i] = out_high;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -318,180 +284,137 @@ void cm_dac_bridge(ARGS)
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
out[i] = out_undef;
|
out[i] = out_undef;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
} else if ( in_old[i].i == in[i].i ) {
|
||||||
|
/*** Transient Analysis from here on. ***/
|
||||||
|
|
||||||
else /*** Transient Analysis ***/
|
/* There has been no change in
|
||||||
|
this digital input since the
|
||||||
|
last analog call... */
|
||||||
|
|
||||||
if ( in_old[i] == in[i] ) { /* There has been no change in
|
switch (in[i].i) {
|
||||||
this digital input since the
|
case ZERO:
|
||||||
last analog call... */
|
|
||||||
|
|
||||||
switch (in[i]) {
|
|
||||||
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;
|
||||||
out[i] = out_old[i] - fall_slope*time_inc;
|
if ( out_low > out[i])
|
||||||
if ( out_low > out[i]) out[i]=out_low;
|
out[i] = out_low;
|
||||||
|
} else { /* output at out_low */
|
||||||
}
|
|
||||||
else { /* output at out_low */
|
|
||||||
|
|
||||||
out[i] = out_low;
|
out[i] = 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;
|
||||||
out[i] = out_old[i] + rise_slope*time_inc;
|
if ( out_high < out[i])
|
||||||
if ( out_high < out[i]) out[i]=out_high;
|
out[i] = out_high;
|
||||||
|
} else { /* output at out_high */
|
||||||
}
|
|
||||||
else { /* output at out_high */
|
|
||||||
|
|
||||||
out[i] = out_high;
|
out[i] = 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;
|
||||||
out[i] = out_old[i] + (rise_slope * time_inc);
|
if ( out_undef < out[i])
|
||||||
if ( out_undef < out[i]) out[i]=out_undef;
|
out[i] = out_undef;
|
||||||
|
} else {
|
||||||
}
|
if (out_old[i] > out_undef) { /* output still falling */
|
||||||
else {
|
out[i] = out_old[i] - fall_slope * time_inc;
|
||||||
|
if ( out_undef > out[i])
|
||||||
if (out_old[i] > out_undef) { /* output still falling */
|
out[i] = out_undef;
|
||||||
|
} else { /* output at out_undef */
|
||||||
out[i] = out_old[i] - fall_slope*time_inc;
|
|
||||||
if ( out_undef > out[i]) out[i]=out_undef;
|
|
||||||
}
|
|
||||||
else { /* output at out_undef */
|
|
||||||
|
|
||||||
out[i] = out_undef;
|
out[i] = out_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else { /* There HAS been a change in this digital input
|
double when, iota, vout, interval[2];
|
||||||
since the last analog access...need to use the
|
int step, step_count;
|
||||||
old value of input to complete the breakpoint
|
|
||||||
slope before changing directions... */
|
|
||||||
|
|
||||||
|
/* There HAS been a change in this digital 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.
|
||||||
|
*/
|
||||||
|
|
||||||
switch (in_old[i]) {
|
iota = (T(0) - T(1)) * 1e-7; // Ignorable
|
||||||
|
if (T(0) - in[i].i_changed < iota) {
|
||||||
|
/* Previous input value in force for whole step. */
|
||||||
|
|
||||||
case ZERO:
|
step_count = 1;
|
||||||
if (out_old[i] > out_low) { /* output still dropping */
|
step = 0;
|
||||||
|
interval[0] = T(0) - T(1);
|
||||||
|
} else if (in[i].i_changed - T(1) < iota) {
|
||||||
|
/* New input value in force for whole step.
|
||||||
|
* Includes common no-change case where new == old.
|
||||||
|
*/
|
||||||
|
|
||||||
out[i] = out_old[i] - fall_slope*time_inc;
|
step_count = 2;
|
||||||
if ( out_low > out[i]) out[i]=out_low;
|
step = 1;
|
||||||
|
interval[1] = T(0) - T(1);
|
||||||
|
} else {
|
||||||
|
/* Calculate both sides of change. */
|
||||||
|
|
||||||
}
|
step_count = 2;
|
||||||
else { /* output at out_low */
|
step = 0;
|
||||||
|
interval[0] = in[i].i_changed - T(1);
|
||||||
out[i] = out_low;
|
interval[1] = T(0) - in[i].i_changed;
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ONE:
|
|
||||||
if (out_old[i] < out_high) { /* output still rising */
|
|
||||||
|
|
||||||
out[i] = out_old[i] + rise_slope*time_inc;
|
|
||||||
if ( out_high < out[i]) out[i]=out_high;
|
|
||||||
|
|
||||||
}
|
|
||||||
else { /* output at out_high */
|
|
||||||
|
|
||||||
out[i] = out_high;
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case UNKNOWN:
|
|
||||||
if (out_old[i] < out_undef) { /* output still rising */
|
|
||||||
|
|
||||||
out[i] = out_old[i] + (rise_slope * time_inc);
|
|
||||||
if ( out_undef < out[i]) out[i]=out_undef;
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
if (out_old[i] > out_undef) { /* output still falling */
|
|
||||||
|
|
||||||
out[i] = out_old[i] - fall_slope*time_inc;
|
|
||||||
if ( out_undef > out[i]) out[i]=out_undef;
|
|
||||||
}
|
|
||||||
else { /* output at out_undef */
|
|
||||||
|
|
||||||
out[i] = out_undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* determine required new breakpoint for the end of
|
|
||||||
the output analog transition & post */
|
|
||||||
|
|
||||||
switch (in[i]) {
|
|
||||||
|
|
||||||
case ONE: /* rising for all outputs */
|
|
||||||
fraction = (out_high - out[i]) / (out_high - out_low);
|
|
||||||
test = TIME + (fraction * t_rise);
|
|
||||||
cm_analog_set_perm_bkpt(test);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UNKNOWN: /* may be rising or falling */
|
|
||||||
|
|
||||||
if ( out_undef > out[i] ) { /* rising to U */
|
|
||||||
fraction = (out_undef - out[i]) / (out_high - out_low);
|
|
||||||
test = TIME + (fraction * t_rise);
|
|
||||||
cm_analog_set_perm_bkpt(test);
|
|
||||||
}
|
|
||||||
else { /* falling to U */
|
|
||||||
fraction = (out[i] - out_undef) / (out_high - out_low);
|
|
||||||
test = TIME + (fraction * t_fall);
|
|
||||||
cm_analog_set_perm_bkpt(test);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZERO: /* falling for all outputs */
|
|
||||||
fraction = (out[i] - out_low) / (out_high - out_low);
|
|
||||||
test = TIME + (fraction * t_fall);
|
|
||||||
cm_analog_set_perm_bkpt(test);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when = -1.0;
|
||||||
|
vout = out_old[i];
|
||||||
|
for (; step < step_count; ++step) {
|
||||||
|
Digital_State_t drive;
|
||||||
|
int last_step = (step == step_count - 1);
|
||||||
|
|
||||||
|
if (step == 0)
|
||||||
|
drive = in_old[i].i;
|
||||||
|
else
|
||||||
|
drive = in[i].i;
|
||||||
|
|
||||||
|
switch (drive) {
|
||||||
|
case ZERO:
|
||||||
|
if (vout <= out_low)
|
||||||
|
break;
|
||||||
|
vout -= fall_slope * interval[step];
|
||||||
|
if (vout < out_low)
|
||||||
|
vout = out_low;
|
||||||
|
else if (last_step)
|
||||||
|
when = (vout - out_low) / fall_slope;
|
||||||
|
break;
|
||||||
|
case ONE:
|
||||||
|
if (vout >= out_high)
|
||||||
|
break;
|
||||||
|
vout += rise_slope * interval[step];
|
||||||
|
if (vout > out_high)
|
||||||
|
vout = out_high;
|
||||||
|
else if (last_step)
|
||||||
|
when = (out_high - vout) / rise_slope;
|
||||||
|
break;
|
||||||
|
case UNKNOWN:
|
||||||
|
if (vout > out_undef) {
|
||||||
|
vout -= fall_slope * interval[step];
|
||||||
|
if (vout < out_undef)
|
||||||
|
vout = out_undef;
|
||||||
|
else if (last_step)
|
||||||
|
when = (vout - out_undef) / fall_slope;
|
||||||
|
} else {
|
||||||
|
vout += rise_slope * interval[step];
|
||||||
|
if (vout > out_undef)
|
||||||
|
vout = out_undef;
|
||||||
|
else if (last_step)
|
||||||
|
when = (out_undef - vout) / rise_slope;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (when > 0.0)
|
||||||
|
cm_analog_set_perm_bkpt(when + TIME);
|
||||||
|
out[i] = vout;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Output values... */
|
|
||||||
|
|
||||||
for (i=0; i<size; i++) {
|
|
||||||
|
|
||||||
OUTPUT(out[i]) = out[i];
|
OUTPUT(out[i]) = out[i];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue