|
|
|
@ -9,24 +9,20 @@ Georgia Tech Research Corporation |
|
|
|
Atlanta, Georgia 30332 |
|
|
|
PROJECT A-8503-405 |
|
|
|
|
|
|
|
|
|
|
|
AUTHORS |
|
|
|
|
|
|
|
18 Jun 1991 Jeffrey P. Murray |
|
|
|
|
|
|
|
|
|
|
|
MODIFICATIONS |
|
|
|
|
|
|
|
7 Aug 1991 Jeffrey P. Murray |
|
|
|
2 Oct 1991 Jeffrey P. Murray |
|
|
|
|
|
|
|
|
|
|
|
SUMMARY |
|
|
|
|
|
|
|
This file contains the model-specific routines used to |
|
|
|
functionally describe the d_xnor code model. |
|
|
|
|
|
|
|
|
|
|
|
INTERFACES |
|
|
|
|
|
|
|
FILE ROUTINE CALLED |
|
|
|
@ -36,13 +32,10 @@ INTERFACES |
|
|
|
CMevt.c void *cm_event_alloc() |
|
|
|
void *cm_event_get_ptr() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
REFERENCED FILES |
|
|
|
|
|
|
|
Inputs from and outputs to ARGS structure. |
|
|
|
|
|
|
|
|
|
|
|
NON-STANDARD FEATURES |
|
|
|
|
|
|
|
NONE |
|
|
|
@ -51,70 +44,53 @@ NON-STANDARD FEATURES |
|
|
|
|
|
|
|
/*=== INCLUDE FILES ====================*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "ngspice/inertial.h" |
|
|
|
|
|
|
|
/*=== CONSTANTS ========================*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*=== MACROS ===========================*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*=== LOCAL VARIABLES & TYPEDEFS =======*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================== |
|
|
|
|
|
|
|
FUNCTION cm_toggle_bit() |
|
|
|
|
|
|
|
|
|
|
|
AUTHORS |
|
|
|
|
|
|
|
27 Sept 1991 Jeffrey P. Murray |
|
|
|
|
|
|
|
|
|
|
|
MODIFICATIONS |
|
|
|
|
|
|
|
NONE |
|
|
|
|
|
|
|
|
|
|
|
SUMMARY |
|
|
|
|
|
|
|
Alters the state of a passed digital variable to its |
|
|
|
complement. Thus, a ONE changes to a ZERO. A ZERO changes |
|
|
|
to a ONE, and an UNKNOWN remains unchanged. |
|
|
|
|
|
|
|
|
|
|
|
INTERFACES |
|
|
|
|
|
|
|
FILE ROUTINE CALLED |
|
|
|
|
|
|
|
N/A N/A |
|
|
|
|
|
|
|
|
|
|
|
RETURNED VALUE |
|
|
|
|
|
|
|
No returned value. Passed pointer to variable is used |
|
|
|
to redefine the variable value. |
|
|
|
|
|
|
|
|
|
|
|
GLOBAL VARIABLES |
|
|
|
|
|
|
|
NONE |
|
|
|
|
|
|
|
|
|
|
|
NON-STANDARD FEATURES |
|
|
|
|
|
|
|
NONE |
|
|
|
@ -124,7 +100,6 @@ NON-STANDARD FEATURES |
|
|
|
/*=== CM_TOGGLE_BIT ROUTINE ===*/ |
|
|
|
|
|
|
|
static void cm_toggle_bit(Digital_State_t *bit) |
|
|
|
|
|
|
|
{ |
|
|
|
/* Toggle bit from ONE to ZERO or vice versa, unless the |
|
|
|
bit value is UNKNOWN. In the latter case, return |
|
|
|
@ -138,7 +113,6 @@ static void cm_toggle_bit(Digital_State_t *bit) |
|
|
|
*bit = ONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -146,23 +120,19 @@ static void cm_toggle_bit(Digital_State_t *bit) |
|
|
|
|
|
|
|
FUNCTION cm_d_xnor() |
|
|
|
|
|
|
|
|
|
|
|
AUTHORS |
|
|
|
|
|
|
|
18 Jun 1991 Jeffrey P. Murray |
|
|
|
|
|
|
|
|
|
|
|
MODIFICATIONS |
|
|
|
|
|
|
|
7 Aug 1991 Jeffrey P. Murray |
|
|
|
2 Oct 1991 Jeffrey P. Murray |
|
|
|
|
|
|
|
|
|
|
|
SUMMARY |
|
|
|
|
|
|
|
This function implements the d_xnor code model. |
|
|
|
|
|
|
|
|
|
|
|
INTERFACES |
|
|
|
|
|
|
|
FILE ROUTINE CALLED |
|
|
|
@ -172,17 +142,14 @@ INTERFACES |
|
|
|
CMevt.c void *cm_event_alloc() |
|
|
|
void *cm_event_get_ptr() |
|
|
|
|
|
|
|
|
|
|
|
RETURNED VALUE |
|
|
|
|
|
|
|
Returns inputs and outputs via ARGS structure. |
|
|
|
|
|
|
|
|
|
|
|
GLOBAL VARIABLES |
|
|
|
|
|
|
|
NONE |
|
|
|
|
|
|
|
|
|
|
|
NON-STANDARD FEATURES |
|
|
|
|
|
|
|
NONE |
|
|
|
@ -199,126 +166,129 @@ NON-STANDARD FEATURES |
|
|
|
* Created 6/18/91 J.P.Murray * |
|
|
|
************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
void cm_d_xnor(ARGS) |
|
|
|
|
|
|
|
{ |
|
|
|
int i, /* generic loop counter index */ |
|
|
|
size; /* number of input & output ports */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Digital_State_t *out, /* temporary output for buffers */ |
|
|
|
*out_old, /* previous output for buffers */ |
|
|
|
Digital_State_t val, |
|
|
|
*out, /* temporary output for buffers */ |
|
|
|
input; /* temp storage for input bits */ |
|
|
|
|
|
|
|
|
|
|
|
/** Retrieve size value... **/ |
|
|
|
size = PORT_SIZE(in); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*** Setup required state variables ***/ |
|
|
|
|
|
|
|
if(INIT) { /* initial pass */ |
|
|
|
|
|
|
|
/* allocate storage for the outputs */ |
|
|
|
cm_event_alloc(0,sizeof(Digital_State_t)); |
|
|
|
|
|
|
|
for (i=0; i<size; i++) LOAD(in[i]) = PARAM(input_load); |
|
|
|
cm_event_alloc(0, sizeof (Digital_State_t)); |
|
|
|
|
|
|
|
/* retrieve storage for the outputs */ |
|
|
|
out = out_old = (Digital_State_t *) cm_event_get_ptr(0,0); |
|
|
|
/* Inertial delay? */ |
|
|
|
|
|
|
|
} |
|
|
|
else { /* Retrieve previous values */ |
|
|
|
STATIC_VAR(is_inertial) = |
|
|
|
cm_is_inertial(PARAM_NULL(inertial_delay) ? Not_set : |
|
|
|
PARAM(inertial_delay)); |
|
|
|
if (STATIC_VAR(is_inertial)) { |
|
|
|
/* Allocate storage for event time. */ |
|
|
|
|
|
|
|
/* retrieve storage for the outputs */ |
|
|
|
out = (Digital_State_t *) cm_event_get_ptr(0,0); |
|
|
|
out_old = (Digital_State_t *) cm_event_get_ptr(0,1); |
|
|
|
cm_event_alloc(1, sizeof (struct idata)); |
|
|
|
((struct idata *)cm_event_get_ptr(1, 0))->when = -1.0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Prepare initial output. */ |
|
|
|
|
|
|
|
out = (Digital_State_t *)cm_event_get_ptr(0, 0); |
|
|
|
*out = (Digital_State_t)(UNKNOWN + 1); // Force initial output. |
|
|
|
|
|
|
|
for (i=0; i<size; i++) LOAD(in[i]) = PARAM(input_load); |
|
|
|
} else { /* Retrieve previous values */ |
|
|
|
/* retrieve storage for the outputs */ |
|
|
|
|
|
|
|
out = (Digital_State_t *) cm_event_get_ptr(0,0); |
|
|
|
} |
|
|
|
|
|
|
|
/*** Calculate new output value based on inputs ***/ |
|
|
|
|
|
|
|
*out = ONE; |
|
|
|
val = ONE; |
|
|
|
for (i=0; i<size; i++) { |
|
|
|
|
|
|
|
/* make sure this input isn't floating... */ |
|
|
|
if ( FALSE == PORT_NULL(in) ) { |
|
|
|
|
|
|
|
/* if a 1, toggle bit value */ |
|
|
|
if ( ONE == (input = INPUT_STATE(in[i])) ) { |
|
|
|
cm_toggle_bit(out); |
|
|
|
} |
|
|
|
else { |
|
|
|
/* if an unknown input, set *out to unknown & break */ |
|
|
|
cm_toggle_bit(&val); |
|
|
|
} else { |
|
|
|
/* if an unknown input, set val to unknown & break */ |
|
|
|
if ( UNKNOWN == input ) { |
|
|
|
*out = UNKNOWN; |
|
|
|
val = UNKNOWN; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
/* at least one port is floating...output is unknown */ |
|
|
|
*out = UNKNOWN; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*** Check for change and output appropriate values ***/ |
|
|
|
|
|
|
|
/*** Determine analysis type and output appropriate values ***/ |
|
|
|
|
|
|
|
if (ANALYSIS == DC) { /** DC analysis...output w/o delays **/ |
|
|
|
|
|
|
|
OUTPUT_STATE(out) = *out; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { /** Transient Analysis **/ |
|
|
|
|
|
|
|
|
|
|
|
if ( *out != *out_old ) { /* output value is changing */ |
|
|
|
|
|
|
|
switch ( *out ) { |
|
|
|
if (val == *out) { /* output value is not changing */ |
|
|
|
OUTPUT_CHANGED(out) = FALSE; |
|
|
|
} else { |
|
|
|
switch (val) { |
|
|
|
|
|
|
|
/* fall to zero value */ |
|
|
|
case 0: OUTPUT_STATE(out) = ZERO; |
|
|
|
case 0: |
|
|
|
OUTPUT_DELAY(out) = PARAM(fall_delay); |
|
|
|
break; |
|
|
|
|
|
|
|
/* rise to one value */ |
|
|
|
case 1: OUTPUT_STATE(out) = ONE; |
|
|
|
case 1: |
|
|
|
OUTPUT_DELAY(out) = PARAM(rise_delay); |
|
|
|
break; |
|
|
|
|
|
|
|
/* unknown output */ |
|
|
|
default: |
|
|
|
OUTPUT_STATE(out) = *out = UNKNOWN; |
|
|
|
|
|
|
|
/* based on old value, add rise or fall delay */ |
|
|
|
if (0 == *out_old) { /* add rising delay */ |
|
|
|
if (0 == *out) { /* add rising delay */ |
|
|
|
OUTPUT_DELAY(out) = PARAM(rise_delay); |
|
|
|
} |
|
|
|
else { /* add falling delay */ |
|
|
|
} else { /* add falling delay */ |
|
|
|
OUTPUT_DELAY(out) = PARAM(fall_delay); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
else { /* output value not changing */ |
|
|
|
OUTPUT_CHANGED(out) = FALSE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
OUTPUT_STRENGTH(out) = STRONG; |
|
|
|
if (STATIC_VAR(is_inertial) && ANALYSIS == TRANSIENT) { |
|
|
|
struct idata *idp; |
|
|
|
|
|
|
|
} |
|
|
|
idp = (struct idata *)cm_event_get_ptr(1, 0); |
|
|
|
if (idp->when <= TIME) { |
|
|
|
/* Normal transition. */ |
|
|
|
|
|
|
|
idp->prev = *out; |
|
|
|
idp->when = TIME + OUTPUT_DELAY(out); // Actual output time |
|
|
|
} else if (val != idp->prev) { |
|
|
|
Digital_t ov = {idp->prev, STRONG}; |
|
|
|
|
|
|
|
/* Third value: cancel earlier change and output as usual. */ |
|
|
|
|
|
|
|
cm_schedule_output(1, 0, (idp->when - TIME) / 2.0, &ov); |
|
|
|
if (val == UNKNOWN) { |
|
|
|
/* Delay based in idp->prev, not *out. */ |
|
|
|
|
|
|
|
if (idp->prev == ZERO) |
|
|
|
OUTPUT_DELAY(out) = PARAM(rise_delay); |
|
|
|
else |
|
|
|
OUTPUT_DELAY(out) = PARAM(fall_delay); |
|
|
|
} |
|
|
|
idp->when = TIME + OUTPUT_DELAY(out); // Actual output time |
|
|
|
} else { |
|
|
|
/* Changing back: override pending change. */ |
|
|
|
|
|
|
|
OUTPUT_DELAY(out) = (idp->when - TIME) / 2.0; // Override |
|
|
|
idp->when = -1.0; |
|
|
|
} |
|
|
|
} |
|
|
|
*out = val; |
|
|
|
OUTPUT_STATE(out) = val; |
|
|
|
OUTPUT_STRENGTH(out) = STRONG; |
|
|
|
} |
|
|
|
} |