You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1997 lines
60 KiB
1997 lines
60 KiB
/*.......1.........2.........3.........4.........5.........6.........7.........8
|
|
================================================================================
|
|
|
|
FILE d_state/cfunc.mod
|
|
|
|
Public Domain
|
|
|
|
Georgia Tech Research Corporation
|
|
Atlanta, Georgia 30332
|
|
PROJECT A-8503-405
|
|
|
|
|
|
AUTHORS
|
|
|
|
6 June 1991 Jeffrey P. Murray
|
|
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sept 1991 Jeffrey P. Murray
|
|
|
|
|
|
SUMMARY
|
|
|
|
This file contains the model-specific routines used to
|
|
functionally describe the <model_name> code model.
|
|
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
CMmacros.h cm_message_send();
|
|
|
|
CMevt.c void *cm_event_alloc()
|
|
void *cm_event_get_ptr()
|
|
|
|
|
|
REFERENCED FILES
|
|
|
|
Inputs from and outputs to ARGS structure.
|
|
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
===============================================================================*/
|
|
|
|
/*=== INCLUDE FILES ====================*/
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
/*=== CONSTANTS ========================*/
|
|
|
|
#define MAX_STRING_SIZE 200
|
|
|
|
#define HEADER 1
|
|
#define CONTINUATION 2
|
|
|
|
#define OK 0
|
|
#define FAIL 1
|
|
|
|
/*=== MACROS ===========================*/
|
|
|
|
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
|
|
|
|
typedef struct {
|
|
int current_state, /* current state of the machine (similar to
|
|
current state of the union, current state
|
|
of the economy, etc. etc. 8-) */
|
|
index0, /* actual word number (0 to depth-1) in which the
|
|
first line of the current_state definition
|
|
may be found. */
|
|
indexN; /* word number (0 to depth-1) of the final curren_state
|
|
definition line...if a state is defined in only one
|
|
line, index0 and indexN will be equal. */
|
|
} Dynamic_State_t;
|
|
|
|
typedef struct {
|
|
int num_outputs,/* width of bits[] table...equal to size of out port.*/
|
|
num_inputs, /* width of inputs[] table...equal to size of in port*/
|
|
depth, /* depth of table...equal to size of
|
|
current_state & next_state arrays,
|
|
and to the total number of vectors
|
|
retrieved from the state.in file. */
|
|
*state, /* integer array holding the state
|
|
index values...note that each state will
|
|
have at least one and as many as 2^N
|
|
"words" assigned to it, where N = number
|
|
of input lines to the state machine. */
|
|
*next_state; /* integer array holding the next state
|
|
to jump to given the input values
|
|
held by the inputs[] array...note that each
|
|
state will have at least one and as many as 2^N
|
|
"words" assigned to it, where N = number
|
|
of input lines to the state machine. */
|
|
|
|
|
|
short *bits, /* the storage array for the
|
|
output bit representations...
|
|
this will have size equal to
|
|
(width * depth)/4, since one
|
|
short will hold four 12-state
|
|
bit descriptions. */
|
|
*inputs; /* the storage array for the
|
|
input bit representations...
|
|
this will have size equal to
|
|
(width * depth)/8, since one
|
|
short will hold eight 3-state
|
|
bit descriptions. */
|
|
} State_Table_t;
|
|
|
|
/* Type definition for each possible token returned. */
|
|
|
|
typedef enum token_type_s {CNV_NO_TOK,CNV_STRING_TOK} Cnv_Token_Type_t;
|
|
typedef char line_t[82]; /* A SPICE size line. <= 80 characters plus '\n\0' */
|
|
|
|
|
|
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION *CNVgettok()
|
|
|
|
AUTHORS
|
|
|
|
13 Jun 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
8 Aug 1991 Jeffrey P. Murray
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
This function obtains the next token from an input stream.
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns a string value representing the next token.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
|
|
/*=== Static CNVgettok ROUTINE ================*/
|
|
/*
|
|
Get the next token from the input string. The input string pointer
|
|
is advanced to the following token and the token from the input
|
|
string is copied to malloced storage and a pointer to that storage
|
|
is returned. The original input string is undisturbed.
|
|
*/
|
|
|
|
static char *CNVgettok(char **s)
|
|
|
|
{
|
|
|
|
char *buf; /* temporary storage to copy token into */
|
|
/*char *temp;*/ /* temporary storage to copy token into */
|
|
char *ret_str; /* storage for returned string */
|
|
|
|
int i;
|
|
|
|
/* allocate space big enough for the whole string */
|
|
|
|
buf = (char *) malloc(strlen(*s) + 1);
|
|
|
|
/* skip over any white space */
|
|
|
|
while(isspace_c(**s) || (**s == '=') ||
|
|
(**s == '(') || (**s == ')') || (**s == ','))
|
|
(*s)++;
|
|
|
|
/* isolate the next token */
|
|
|
|
switch(**s) {
|
|
|
|
case '\0': /* End of string found */
|
|
if(buf) free(buf);
|
|
return(NULL);
|
|
|
|
|
|
default: /* Otherwise, we are dealing with a */
|
|
/* string representation of a number */
|
|
/* or a mess o' characters. */
|
|
i = 0;
|
|
while( (**s != '\0') &&
|
|
(! ( isspace_c(**s) || (**s == '=') ||
|
|
(**s == '(') || (**s == ')') ||
|
|
(**s == ',')
|
|
) ) ) {
|
|
buf[i] = **s;
|
|
i++;
|
|
(*s)++;
|
|
}
|
|
buf[i] = '\0';
|
|
break;
|
|
}
|
|
|
|
/* skip over white space up to next token */
|
|
|
|
while(isspace_c(**s) || (**s == '=') ||
|
|
(**s == '(') || (**s == ')') || (**s == ','))
|
|
(*s)++;
|
|
|
|
/* make a copy using only the space needed by the string length */
|
|
|
|
|
|
ret_str = (char *) malloc(strlen(buf) + 1);
|
|
ret_str = strcpy(ret_str,buf);
|
|
|
|
if(buf) free(buf);
|
|
|
|
return(ret_str);
|
|
}
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION *CNVget_token()
|
|
|
|
AUTHORS
|
|
|
|
13 Jun 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
8 Aug 1991 Jeffrey P. Murray
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
This function obtains the next token from an input stream.
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns a string value representing the next token. Uses
|
|
*CNVget_tok.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CNVget_token ROUTINE =============*/
|
|
/*
|
|
Get the next token from the input string together with its type.
|
|
The input string pointer
|
|
is advanced to the following token and the token from the input
|
|
string is copied to malloced storage and a pointer to that storage
|
|
is returned. The original input string is undisturbed.
|
|
*/
|
|
|
|
static char *CNVget_token(char **s, Cnv_Token_Type_t *type)
|
|
|
|
{
|
|
|
|
char *ret_str; /* storage for returned string */
|
|
|
|
/* get the token from the input line */
|
|
|
|
ret_str = CNVgettok(s);
|
|
|
|
|
|
/* if no next token, return */
|
|
|
|
if(ret_str == NULL) {
|
|
*type = CNV_NO_TOK;
|
|
return(NULL);
|
|
}
|
|
|
|
/* else, determine and return token type */
|
|
|
|
switch(*ret_str) {
|
|
|
|
default:
|
|
*type = CNV_STRING_TOK;
|
|
break;
|
|
|
|
}
|
|
|
|
return(ret_str);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cnv_get_spice_value()
|
|
|
|
AUTHORS
|
|
|
|
??? Bill Kuhn
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
This function takes as input a string token from a SPICE
|
|
deck and returns a floating point equivalent value.
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns the floating point value in pointer *p_value. Also
|
|
returns an integer representing successful completion.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CNV_get_spice_value ROUTINE =============*/
|
|
|
|
/*
|
|
Function takes as input a string token from a SPICE
|
|
deck and returns a floating point equivalent value.
|
|
*/
|
|
|
|
|
|
static int cnv_get_spice_value(
|
|
char *str, /* IN - The value text e.g. 1.2K */
|
|
double *p_value ) /* OUT - The numerical value */
|
|
{
|
|
|
|
|
|
/* the following were "int4" devices - jpm */
|
|
size_t len;
|
|
size_t i;
|
|
int n_matched;
|
|
|
|
line_t val_str;
|
|
|
|
/*char *suffix;*/
|
|
char c = ' ';
|
|
char c1;
|
|
|
|
double scale_factor;
|
|
double value;
|
|
|
|
|
|
/* Scan the input string looking for an alpha character that is not */
|
|
/* 'e' or 'E'. Such a character is assumed to be an engineering */
|
|
/* suffix as defined in the Spice 2G.6 user's manual. */
|
|
|
|
len = strlen(str);
|
|
if( len > (sizeof(val_str) - 1))
|
|
len = sizeof(val_str) - 1;
|
|
|
|
for(i = 0; i < len; i++) {
|
|
c = str[i];
|
|
if( isalpha_c(c) && (c != 'E') && (c != 'e') )
|
|
break;
|
|
else if( isspace_c(c) )
|
|
break;
|
|
else
|
|
val_str[i] = c;
|
|
}
|
|
val_str[i] = '\0';
|
|
|
|
|
|
/* Determine the scale factor */
|
|
|
|
if( (i >= len) || (! isalpha_c(c)) )
|
|
scale_factor = 1.0;
|
|
else {
|
|
|
|
if(islower_c(c))
|
|
c = tolower_c(c);
|
|
|
|
switch(c) {
|
|
|
|
case 't':
|
|
scale_factor = 1.0e12;
|
|
break;
|
|
|
|
case 'g':
|
|
scale_factor = 1.0e9;
|
|
break;
|
|
|
|
case 'k':
|
|
scale_factor = 1.0e3;
|
|
break;
|
|
|
|
case 'u':
|
|
scale_factor = 1.0e-6;
|
|
break;
|
|
|
|
case 'n':
|
|
scale_factor = 1.0e-9;
|
|
break;
|
|
|
|
case 'p':
|
|
scale_factor = 1.0e-12;
|
|
break;
|
|
|
|
case 'f':
|
|
scale_factor = 1.0e-15;
|
|
break;
|
|
|
|
case 'm':
|
|
i++;
|
|
if(i >= len) {
|
|
scale_factor = 1.0e-3;
|
|
break;
|
|
}
|
|
c1 = str[i];
|
|
if(! isalpha_c(c1)) {
|
|
scale_factor = 1.0e-3;
|
|
break;
|
|
}
|
|
if(islower_c(c1))
|
|
c1 = toupper_c(c1);
|
|
if(c1 == 'E')
|
|
scale_factor = 1.0e6;
|
|
else if(c1 == 'I')
|
|
scale_factor = 25.4e-6;
|
|
else
|
|
scale_factor = 1.0e-3;
|
|
break;
|
|
|
|
default:
|
|
scale_factor = 1.0;
|
|
}
|
|
}
|
|
|
|
/* Convert the numeric portion to a float and multiply by the */
|
|
/* scale factor. */
|
|
|
|
n_matched = sscanf(val_str,"%le",&value);
|
|
|
|
if(n_matched < 1) {
|
|
*p_value = 0.0;
|
|
return(FAIL);
|
|
}
|
|
|
|
*p_value = value * scale_factor;
|
|
return(OK);
|
|
}
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_inputs_mask_and_retrieve()
|
|
|
|
AUTHORS
|
|
|
|
23 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
Masks off and retrieves a two-bit value from a short
|
|
integer word passed to the function, using an offset value.
|
|
This effectively handles retrieval of eight two-bit values
|
|
from a single short integer space in order to conserve memory.
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns a Digital_t value.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_INPUTS_MASK_AND_RETRIEVE ROUTINE ===*/
|
|
|
|
/**************************************************
|
|
* The following routine masks and retrieves *
|
|
* the value passed to it by the out value *
|
|
* by masking the appropriate bits in the *
|
|
* base integer. The particular bit affected *
|
|
* is determined by the bit_offset value. *
|
|
* *
|
|
* Created 7/23/91 J.P.Murray *
|
|
**************************************************/
|
|
|
|
static Digital_State_t cm_inputs_mask_and_retrieve(short base, int bit_offset)
|
|
{
|
|
|
|
|
|
int value; /* the hexadecimal value of the masked bit */
|
|
|
|
|
|
value = 0x0003 & (base >> (bit_offset * 2));
|
|
|
|
|
|
switch (value) {
|
|
case 0: return ZERO;
|
|
case 1: return ONE;
|
|
default: return UNKNOWN;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_set_indices()
|
|
|
|
AUTHORS
|
|
|
|
23 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine retrieves the current_state value
|
|
from the *states structure. It then searches the entire
|
|
state[] array to determine the index0 and indexN values
|
|
corresponding to the first and last entries in the
|
|
state[] array for the current state.
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns a status int value.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_SET_INDICES ROUTINE ===*/
|
|
|
|
/************************************************
|
|
* The following routine retrieves the *
|
|
* current_state value from the *states *
|
|
* structure. It then searches the entire *
|
|
* state[] array to determine the index0 and *
|
|
* indexN values corresponding to the first *
|
|
* and last entries in the state[] array for *
|
|
* the current state. *
|
|
* *
|
|
* Created 7/23/91 J.P. Murray *
|
|
************************************************/
|
|
|
|
|
|
static int cm_set_indices(Dynamic_State_t *states, State_Table_t *table)
|
|
{
|
|
int i, /* indexing variable */
|
|
index0_set, /* flag for index0 */
|
|
indexN_set; /* flag for index1 */
|
|
|
|
|
|
states->index0 = 0;
|
|
states->indexN = 0;
|
|
index0_set = 0;
|
|
indexN_set = 0;
|
|
|
|
for (i = 0; i < table->depth; i++) {
|
|
/* Loop through all states. */
|
|
|
|
if (table->state[i] == states->current_state) {
|
|
/* states match... */
|
|
|
|
/* if not already set, set index0... */
|
|
if ( 0 == index0_set ) {
|
|
states->index0 = i;
|
|
states->indexN = i;
|
|
index0_set = 1;
|
|
}
|
|
|
|
if ( 1 < (i - states->indexN) ) {
|
|
/* ERROR!! This means that a state match was
|
|
found in a nonn-contiguous portion of the
|
|
state.in file...this is not allowed! */
|
|
return TRUE;
|
|
}
|
|
else {
|
|
/* update indexN. */
|
|
states->indexN = i;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_compare_to_inputs()
|
|
|
|
AUTHORS
|
|
|
|
23 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine retrieves the
|
|
the inputs[] bit value pointed to by
|
|
the word_num and bit_num integers, compares
|
|
this value with the "in" state value, and
|
|
returns a "0" if they match, and a "1" if
|
|
they do not match.
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns a status int value.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_COMPARE_TO_INPUTS ROUTINE ===*/
|
|
|
|
/************************************************
|
|
* The following routine retrieves the *
|
|
* the inputs[] bit value pointed to by *
|
|
* the word_num and bit_num integers, compares *
|
|
* this value with the "in" state value, and *
|
|
* returns a "0" if they match, and a "1" if *
|
|
* they do not match. *
|
|
* *
|
|
* Created 7/23/91 J.P.Murray *
|
|
************************************************/
|
|
|
|
|
|
static int cm_compare_to_inputs(State_Table_t *table, int index,
|
|
int bit_number, Digital_State_t in)
|
|
{
|
|
int int1, /* temp storage variable */
|
|
bit_index, /* bits base address at which word bits will
|
|
be found */
|
|
bit_offset; /* offset from ram base address at which bit[0]
|
|
of the required word can be found */
|
|
|
|
short base; /* variable to hold current base integer for
|
|
comparison purposes. */
|
|
|
|
Digital_State_t out; /* output variable for state retrieved */
|
|
|
|
|
|
/* obtain offset value from index, word_width & bit_number */
|
|
int1 = index * table->num_inputs + bit_number;
|
|
|
|
bit_index = int1 >> 3;
|
|
bit_offset = int1 & 7;
|
|
|
|
/* retrieve entire base_address bits integer... */
|
|
base = table->inputs[bit_index];
|
|
|
|
/* for each offset, mask off the bits and determine values */
|
|
|
|
out = cm_inputs_mask_and_retrieve(base, bit_offset);
|
|
|
|
if ( out == in ) { /* bit matches */
|
|
return 0;
|
|
}
|
|
else
|
|
if ( out == UNKNOWN ) { /* bit compared to is a "don't care" */
|
|
return 0;
|
|
}
|
|
else { /* no match */
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_inputs_mask_and_store()
|
|
|
|
AUTHORS
|
|
|
|
22 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine masks and stores
|
|
the value passed to it by the out value
|
|
by masking the appropriate bits in the
|
|
base integer. The particular bit affected
|
|
is determined by the bit_offset value.
|
|
This routine stores to the inputs[] array.
|
|
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns a status int value.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_INPUTS_MASK_AND_STORE ROUTINE ===*/
|
|
|
|
/************************************************
|
|
* The following routine masks and stores *
|
|
* the value passed to it by the out value *
|
|
* by masking the appropriate bits in the *
|
|
* base integer. The particular bit affected *
|
|
* is determined by the bit_offset value. *
|
|
* This routine stores to the inputs[] array. *
|
|
* *
|
|
* Created 7/22/91 *
|
|
* Last Modified 7/22/91 J.P.Murray *
|
|
************************************************/
|
|
|
|
static void cm_inputs_mask_and_store(short *base,int bit_offset,int bit_value)
|
|
{
|
|
*base &= (short) ~ (0x0003 << (bit_offset * 2));
|
|
*base |= (short) (bit_value << (bit_offset * 2));
|
|
}
|
|
|
|
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_store_inputs_value()
|
|
|
|
AUTHORS
|
|
|
|
23 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine retrieves four-bit
|
|
data from short integer array "bits". The
|
|
integers are assumed to be at least two
|
|
bytes each, so each will hold four four-
|
|
bit values.
|
|
|
|
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
NONE
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_STORE_INPUTS_VALUE ROUTINE ===*/
|
|
|
|
/************************************************
|
|
* The following routine retrieves four-bit *
|
|
* data from short integer array "bits". The *
|
|
* integers are assumed to be at least two *
|
|
* bytes each, so each will hold four four- *
|
|
* bit values. *
|
|
* *
|
|
* Created 7/23/91 J.P.Murray *
|
|
************************************************/
|
|
|
|
static void cm_store_inputs_value(State_Table_t *table, int index,
|
|
int bit_number, int in_val)
|
|
|
|
{
|
|
int /*err,*/ /* error index value */
|
|
int1, /* temp storage variable */
|
|
bit_index, /* bits base address at which word bits will
|
|
be found */
|
|
bit_offset; /* offset from ram base address at which bit[0]
|
|
of the required word can be found */
|
|
|
|
short base; /* variable to hold current base integer for
|
|
comparison purposes. */
|
|
|
|
/* obtain offset value from word_number, word_width & bit_number */
|
|
|
|
int1 = index * table->num_inputs + bit_number;
|
|
|
|
bit_index = int1 >> 3;
|
|
bit_offset = int1 & 7;
|
|
|
|
/* retrieve entire base_address bits integer... */
|
|
base = table->inputs[bit_index];
|
|
|
|
/* for each offset, mask off the bits and store values */
|
|
cm_inputs_mask_and_store(&base,bit_offset,in_val);
|
|
|
|
/* store modified base value */
|
|
table->inputs[bit_index] = base;
|
|
}
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_bits_mask_and_store()
|
|
|
|
AUTHORS
|
|
|
|
22 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine masks and stores
|
|
the value passed to it by the out value
|
|
by masking the appropriate bits in the
|
|
base integer. The particular bit affected
|
|
is determined by the bit_offset value.
|
|
This routine stores to the bits[] array.
|
|
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns a status integer.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
|
|
/*=== Static CM_BITS_MASK_AND_STORE ROUTINE ===*/
|
|
|
|
/************************************************
|
|
* The following routine masks and stores *
|
|
* the value passed to it by the out value *
|
|
* by masking the appropriate bits in the *
|
|
* base integer. The particular bit affected *
|
|
* is determined by the bit_offset value. *
|
|
* This routine stores to the bits[] array. *
|
|
* *
|
|
* Created 7/22/91 *
|
|
* Last Modified 7/22/91 J.P.Murray *
|
|
************************************************/
|
|
|
|
static void cm_bits_mask_and_store(short *base,int bit_offset,int bit_value)
|
|
{
|
|
*base &= (short) ~ (0x000f << (bit_offset * 4));
|
|
*base |= (short) (bit_value << (bit_offset * 4));
|
|
}
|
|
|
|
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_bits_mask_and_retrieve()
|
|
|
|
AUTHORS
|
|
|
|
22 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine masks and retrieves
|
|
the value passed to it by the out value
|
|
by masking the appropriate bits in the
|
|
base integer. The particular bit affected
|
|
is determined by the bit_offset value.
|
|
|
|
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
NONE
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_BITS_MASK_AND_RETRIEVE ROUTINE ===*/
|
|
|
|
/**************************************************
|
|
* The following routine masks and retrieves *
|
|
* the value passed to it by the out value *
|
|
* by masking the appropriate bits in the *
|
|
* base integer. The particular bit affected *
|
|
* is determined by the ram_offset value. *
|
|
* *
|
|
* Created 7/22/91 *
|
|
* Last Modified 7/22/91 J.P.Murray *
|
|
**************************************************/
|
|
|
|
static void cm_bits_mask_and_retrieve(short base,int bit_offset,Digital_t *out)
|
|
{
|
|
|
|
|
|
int value; /* the hexadecimal value of the masked bit */
|
|
|
|
value = 0x000f & (base >> (bit_offset * 4));
|
|
|
|
|
|
switch (value) {
|
|
|
|
case 0: out->state = ZERO;
|
|
out->strength = STRONG;
|
|
break;
|
|
|
|
case 1: out->state = ONE;
|
|
out->strength = STRONG;
|
|
break;
|
|
|
|
case 2: out->state = UNKNOWN;
|
|
out->strength = STRONG;
|
|
break;
|
|
|
|
case 3: out->state = ZERO;
|
|
out->strength = RESISTIVE;
|
|
break;
|
|
|
|
case 4: out->state = ONE;
|
|
out->strength = RESISTIVE;
|
|
break;
|
|
|
|
case 5: out->state = UNKNOWN;
|
|
out->strength = RESISTIVE;
|
|
break;
|
|
|
|
case 6: out->state = ZERO;
|
|
out->strength = HI_IMPEDANCE;
|
|
break;
|
|
|
|
case 7: out->state = ONE;
|
|
out->strength = HI_IMPEDANCE;
|
|
break;
|
|
|
|
case 8: out->state = UNKNOWN;
|
|
out->strength = HI_IMPEDANCE;
|
|
break;
|
|
|
|
case 9: out->state = ZERO;
|
|
out->strength = UNDETERMINED;
|
|
break;
|
|
|
|
case 10: out->state = ONE;
|
|
out->strength = UNDETERMINED;
|
|
break;
|
|
|
|
case 11: out->state = UNKNOWN;
|
|
out->strength = UNDETERMINED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_get_bits_value()
|
|
|
|
AUTHORS
|
|
|
|
22 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
23 Jul 1991 Jeffrey P. Murray
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine retrieves four-bit
|
|
data from short integer array "bits". The
|
|
integers are assumed to be at least two
|
|
bytes each, so each will hold four four-
|
|
bit values.
|
|
|
|
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
NONE
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_GET_BITS_VALUE ROUTINE ===*/
|
|
|
|
/************************************************
|
|
* The following routine retrieves four-bit *
|
|
* data from short integer array "bits". The *
|
|
* integers are assumed to be at least two *
|
|
* bytes each, so each will hold four four- *
|
|
* bit values. *
|
|
* *
|
|
* Created 7/22/91 *
|
|
* Last Modified 7/23/91 J.P.Murray *
|
|
************************************************/
|
|
|
|
static void cm_get_bits_value(State_Table_t *table, int index,
|
|
int bit_number, Digital_t *out)
|
|
|
|
{
|
|
int /*err,*/ /* error index value */
|
|
int1, /* temp storage variable */
|
|
bit_index, /* bits base address at which word bits will
|
|
be found */
|
|
bit_offset; /* offset from ram base address at which bit[0]
|
|
of the required word can be found */
|
|
|
|
short base; /* variable to hold current base integer for
|
|
comparison purposes. */
|
|
|
|
|
|
|
|
/* obtain offset value from index, word_width & bit_number */
|
|
int1 = index * table->num_outputs + bit_number;
|
|
|
|
bit_index = int1 >> 2;
|
|
bit_offset = int1 & 3;
|
|
|
|
/* retrieve entire base_address bits integer... */
|
|
base = table->bits[bit_index];
|
|
|
|
/* for each offset, mask off the bits and determine values */
|
|
|
|
cm_bits_mask_and_retrieve(base,bit_offset,out);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_store_bits_value()
|
|
|
|
AUTHORS
|
|
|
|
23 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine retrieves four-bit
|
|
data from short integer array "bits". The
|
|
integers are assumed to be at least two
|
|
bytes each, so each will hold four four-
|
|
bit values.
|
|
|
|
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
NONE
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_STORE_BITS_VALUE ROUTINE ===*/
|
|
|
|
/************************************************
|
|
* The following routine retrieves four-bit *
|
|
* data from short integer array "bits". The *
|
|
* integers are assumed to be at least two *
|
|
* bytes each, so each will hold four four- *
|
|
* bit values. *
|
|
* *
|
|
* Created 7/23/91 *
|
|
* Last Modified 7/23/91 J.P.Murray *
|
|
************************************************/
|
|
|
|
static void cm_store_bits_value(State_Table_t *table, int index,
|
|
int bit_number, int in_val)
|
|
|
|
{
|
|
int /*err,*/ /* error index value */
|
|
int1, /* temp storage variable */
|
|
bit_index, /* bits base address at which word bits will
|
|
be found */
|
|
bit_offset; /* offset from ram base address at which bit[0]
|
|
of the required word can be found */
|
|
|
|
short base; /* variable to hold current base integer for
|
|
comparison purposes. */
|
|
|
|
|
|
/* obtain offset value from word_number, word_width &
|
|
bit_number */
|
|
int1 = index * table->num_outputs + bit_number;
|
|
|
|
bit_index = int1 >> 2;
|
|
bit_offset = int1 & 3;
|
|
|
|
/* retrieve entire base_address bits integer... */
|
|
base = table->bits[bit_index];
|
|
|
|
/* for each offset, mask off the bits and store values */
|
|
cm_bits_mask_and_store(&base,bit_offset,in_val);
|
|
|
|
/* store modified base value */
|
|
table->bits[bit_index] = base;
|
|
}
|
|
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_read_state_file()
|
|
|
|
AUTHORS
|
|
|
|
15 Jul 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
23 Jul 1991 Jeffrey P. Murray
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
The following routine reads the file
|
|
*state_file, parses the file, and stores
|
|
the values found there into the *state,
|
|
*bits, *inputs and *next_state arrays.
|
|
|
|
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
N/A N/A
|
|
|
|
|
|
RETURNED VALUE
|
|
|
|
Returns a status integer value.
|
|
|
|
GLOBAL VARIABLES
|
|
|
|
NONE
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
NONE
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== Static CM_READ_STATE_FILE ROUTINE ===*/
|
|
|
|
|
|
/**************************************************
|
|
* The following routine reads the file *
|
|
* *state_file, parses the file, and stores *
|
|
* the values found there into the *state, *
|
|
* *bits, *inputs and *next_state arrays. *
|
|
* *
|
|
* Created 7/15/91 *
|
|
* Last Modified 7/23/91 J.P.Murray *
|
|
**************************************************/
|
|
|
|
static int cm_read_state_file(FILE *state_file, State_Table_t *table)
|
|
{
|
|
int i, /* indexing variable */
|
|
j, /* indexing variable */
|
|
num_tokens, /* number of tokens in a given string */
|
|
/*bit_index,*/ /* index to which bits[] integer we are accessing */
|
|
/*bit_offset,*/ /* index to which bit within the current bits[]
|
|
integer we are accessing */
|
|
string_type; /* integer holding value corresponding to the
|
|
type of input string obtained:
|
|
1 = HEADER => State Header string
|
|
2 = CONTINUATION => a continuation line...
|
|
values of state and
|
|
bits must be retreived from
|
|
the previous string. */
|
|
/*int1;*/ /* temporary holding variable */
|
|
|
|
|
|
Cnv_Token_Type_t type; /* variable for testing token type returned. */
|
|
|
|
|
|
char temp[MAX_STRING_SIZE], /* holding string variable for testing
|
|
input from state.in */
|
|
*s, /* main string variable */
|
|
*base_address, /* storage location for base address
|
|
of string. */
|
|
*token; /* a particular token from the string */
|
|
|
|
|
|
double number; /* holding variable for timepoint values */
|
|
|
|
short bit_value=0; /* holding variable for value read from
|
|
state.in file which needs to be stored */
|
|
/*base;*/ /* holding variable for existing
|
|
non-masked bits[] integer */
|
|
if (!state_file) {
|
|
return 2;
|
|
}
|
|
|
|
i = 0;
|
|
s = temp;
|
|
while ( fgets(s,MAX_STRING_SIZE,state_file) != NULL) {
|
|
/* Test this string to see if it is whitespace... */
|
|
|
|
base_address = s;
|
|
while(isspace_c(*s) || (*s == '*'))
|
|
(s)++;
|
|
if ( *s != '\0' ) { /* This is not a blank line, so process... */
|
|
s = base_address;
|
|
|
|
if ( '*' != s[0] ) {
|
|
|
|
/* Count up total number of tokens including \0... */
|
|
j = 0;
|
|
type = CNV_STRING_TOK;
|
|
while ( type != CNV_NO_TOK ) {
|
|
token = CNVget_token(&s, &type);
|
|
if (token)
|
|
free(token);
|
|
j++;
|
|
}
|
|
num_tokens = (j-1);
|
|
|
|
/* Test the type of entry this number of
|
|
tokens represents. Valid types are:
|
|
|
|
a. State Header with state, bits, inputs
|
|
and next_state entries...total tokens
|
|
equals num_inputs + num_outputs + 3
|
|
(e.g. "5 0s 0s 0s 0 0 -> 6").
|
|
|
|
b. State continuation line with inputs
|
|
and next_state only...total tokens
|
|
equals num_inputs + 2.
|
|
(e.g. " 0 1 -> 7").
|
|
*/
|
|
|
|
if (3 + table->num_inputs + table->num_outputs == num_tokens) {
|
|
string_type = HEADER;
|
|
}
|
|
else {
|
|
if ( (2 + table->num_inputs) == num_tokens) {
|
|
string_type = CONTINUATION;
|
|
}
|
|
else { /* Number of tokens is incorrect */
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* reset s to beginning... */
|
|
s = base_address;
|
|
|
|
/** Retrieve each token, analyze, and **/
|
|
/** store the state, bits, inputs & **/
|
|
/** next_state information. **/
|
|
|
|
if ( HEADER == string_type ) { /**** header type loop ****/
|
|
|
|
for (j = 0;
|
|
j < table->num_inputs + table->num_outputs + 3;
|
|
j++) {
|
|
|
|
token = CNVget_token(&s, &type);
|
|
|
|
if(!token)
|
|
return 1;
|
|
|
|
if ( 0 == j ) { /* obtain state value... */
|
|
|
|
/* convert to a floating point number... */
|
|
cnv_get_spice_value(token,&number);
|
|
|
|
table->state[i] = (int)number;
|
|
|
|
|
|
}
|
|
else { /* obtain each bit value & set bits entry */
|
|
|
|
if ( table->num_outputs >= j ) {
|
|
|
|
/* preset this bit location */
|
|
bit_value = 12;
|
|
|
|
if (0 == strcmp(token,"0s")) bit_value = 0;
|
|
if (0 == strcmp(token,"1s")) bit_value = 1;
|
|
if (0 == strcmp(token,"Us")) bit_value = 2;
|
|
if (0 == strcmp(token,"0r")) bit_value = 3;
|
|
if (0 == strcmp(token,"1r")) bit_value = 4;
|
|
if (0 == strcmp(token,"Ur")) bit_value = 5;
|
|
if (0 == strcmp(token,"0z")) bit_value = 6;
|
|
if (0 == strcmp(token,"1z")) bit_value = 7;
|
|
if (0 == strcmp(token,"Uz")) bit_value = 8;
|
|
if (0 == strcmp(token,"0u")) bit_value = 9;
|
|
if (0 == strcmp(token,"1u")) bit_value = 10;
|
|
if (0 == strcmp(token,"Uu")) bit_value = 11;
|
|
|
|
/* if this bit was not recognized, return with an error */
|
|
if (12 == bit_value) {
|
|
free(token);
|
|
return 1;
|
|
}
|
|
else {
|
|
/* need to store this value in the bits[] array */
|
|
cm_store_bits_value(table, i, j - 1,
|
|
bit_value);
|
|
}
|
|
}
|
|
else { /* obtain inputs info... */
|
|
int idx;
|
|
|
|
if (table->num_outputs + table->num_inputs >= j) {
|
|
/* preset this bit location */
|
|
bit_value = 3;
|
|
|
|
if (0 == strcmp(token,"0")) bit_value = 0;
|
|
if (0 == strcmp(token,"1")) bit_value = 1;
|
|
if (0 == strcmp(token,"x")) bit_value = 2;
|
|
if (0 == strcmp(token,"X")) bit_value = 2;
|
|
|
|
/* if this bit was not recognized, return with an error */
|
|
if (3 == bit_value) {
|
|
free(token);
|
|
return 1;
|
|
}
|
|
else {
|
|
/* need to store this value in the inputs[] array */
|
|
idx = j - 1 - table->num_outputs;
|
|
cm_store_inputs_value(table, i, idx,
|
|
bit_value);
|
|
}
|
|
}
|
|
else { /* obtain next_state value */
|
|
idx = 1 + table->num_outputs +
|
|
table->num_inputs;
|
|
if (idx == j) {
|
|
/* skip the "->" token */
|
|
}
|
|
else {
|
|
/* convert to a floating point number... */
|
|
cnv_get_spice_value(token,&number);
|
|
|
|
table->next_state[i] = (int) number;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free(token);
|
|
}
|
|
}
|
|
else { /**** continuation type loop ****/
|
|
/* set state value to previous state value */
|
|
|
|
table->state[i] = table->state[i - 1];
|
|
|
|
/* set bits values to previous bits values */
|
|
for (j = 0; j < table->num_outputs; j++) {
|
|
|
|
/*** Store this bit value ***/
|
|
|
|
cm_store_bits_value(table, i, j, bit_value);
|
|
}
|
|
|
|
for (j=0; j<(2 + table->num_inputs); j++) {
|
|
|
|
token = CNVget_token(&s, &type);
|
|
|
|
if(!token)
|
|
return 1;
|
|
|
|
if ( j < table->num_inputs ) {
|
|
|
|
/* preset this bit location */
|
|
bit_value = 3;
|
|
|
|
if (0 == strcmp(token,"0")) bit_value = 0;
|
|
if (0 == strcmp(token,"1")) bit_value = 1;
|
|
if (0 == strcmp(token,"x")) bit_value = 2;
|
|
if (0 == strcmp(token,"X")) bit_value = 2;
|
|
|
|
/* if this bit was not recognized, return with an error */
|
|
if (3 == bit_value) {
|
|
free(token);
|
|
return 1;
|
|
}
|
|
else {
|
|
/* need to store this value in the inputs[] array */
|
|
cm_store_inputs_value(table, i, j, bit_value);
|
|
}
|
|
}
|
|
else { /* obtain next_state value */
|
|
if ( table->num_inputs == j ) {
|
|
/* skip the "->" token */
|
|
}
|
|
else {
|
|
/* convert to a floating point number... */
|
|
|
|
cnv_get_spice_value(token,&number);
|
|
table->next_state[i] = (int) number;
|
|
}
|
|
}
|
|
free(token);
|
|
}
|
|
|
|
}
|
|
i++;
|
|
}
|
|
s = temp;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Free allocated storage. */
|
|
|
|
static void callback(ARGS, Mif_Callback_Reason_t reason)
|
|
{
|
|
if (reason == MIF_CB_DESTROY) {
|
|
State_Table_t *table;
|
|
|
|
table = (State_Table_t *)STATIC_VAR(table);
|
|
if (!table)
|
|
return;
|
|
if (table->state)
|
|
free(table->state);
|
|
if (table->bits)
|
|
free(table->bits);
|
|
if (table->inputs)
|
|
free(table->inputs);
|
|
if (table->next_state)
|
|
free(table->next_state);
|
|
free(table);
|
|
STATIC_VAR(table) = NULL;
|
|
}
|
|
}
|
|
|
|
/*==============================================================================
|
|
|
|
FUNCTION cm_d_state()
|
|
|
|
AUTHORS
|
|
|
|
17 Jun 1991 Jeffrey P. Murray
|
|
|
|
MODIFICATIONS
|
|
|
|
20 Aug 1991 Jeffrey P. Murray
|
|
30 Sep 1991 Jeffrey P. Murray
|
|
|
|
SUMMARY
|
|
|
|
This function implements the d_state code model.
|
|
|
|
INTERFACES
|
|
|
|
FILE ROUTINE CALLED
|
|
|
|
CMmacros.h cm_message_send();
|
|
|
|
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
|
|
|
|
==============================================================================*/
|
|
|
|
/*=== CM_D_STATE ROUTINE ==============*/
|
|
|
|
/************************************************
|
|
* The following is the model for the *
|
|
* digital state machine for the *
|
|
* ATESSE Version 2.0 system. *
|
|
* *
|
|
* Created 7/17/91 *
|
|
* Last Modified 8/20/91 J.P.Murray *
|
|
************************************************/
|
|
|
|
|
|
void cm_d_state(ARGS)
|
|
{
|
|
int i, j, /* Generic loop counter indices. */
|
|
err=0, /* Integer for storage of error status. */
|
|
test; /* Testing integer. */
|
|
|
|
State_Table_t *table; /* Pointer to base address structure
|
|
for all state arrays. *table
|
|
contains the pointers to
|
|
state[], bits[], input[]
|
|
and next_state[] arrays. These
|
|
arrays are allocated using
|
|
calloc, so they do not take up
|
|
rotational storage space...only
|
|
the *states structure does that. */
|
|
Dynamic_State_t *states, /* Pointer to dynamic state structure. */
|
|
*states_old;
|
|
Digital_t in, out; /* Storage for each input and bit. */
|
|
|
|
Digital_State_t *clk, /* Storage for current and clock value. */
|
|
*clk_old, /* Previous clock value. */
|
|
*reset , /* Current reset value. */
|
|
*reset_old; /* Previous reset value. */
|
|
|
|
static char *index_error =
|
|
"\nERROR\n D_STATE: An error exists in the ordering of states "
|
|
"values\n in the states->state[] array. This is usually caused\n"
|
|
" by non-contiguous state definitions in the state.in file.\n";
|
|
|
|
/****** Setup required state variables ******/
|
|
|
|
if (INIT) { /* initial pass */
|
|
FILE *state_file; /* Pointer to the state.in input vector file. */
|
|
char temp[MAX_STRING_SIZE], /* Holding string variable for testing
|
|
input from state.in. */
|
|
*s; /* Main string variable. */
|
|
|
|
static char *open_error =
|
|
"\nERROR\n D_STATE: failed to open state file.\n";
|
|
static char *loading_error =
|
|
"\nERROR\n D_STATE: state file was not read successfully.\n "
|
|
"The most common cause of this problem is a\n "
|
|
"trailing blank line in the state.in file.\n";
|
|
|
|
/* Allocate storage for the state transition table. */
|
|
|
|
table = calloc(1, sizeof (State_Table_t));
|
|
STATIC_VAR(table) = table;
|
|
|
|
/*** open file and count the number of vectors in it ***/
|
|
state_file = fopen_with_path( PARAM(state_file), "r");
|
|
|
|
/* increment counter if not a comment until EOF reached... */
|
|
i = 0;
|
|
s = temp;
|
|
if (state_file != NULL)
|
|
while (fgets(s, MAX_STRING_SIZE, state_file) != NULL) {
|
|
if ( '*' != s[0] ) {
|
|
while (isspace_c(*s) || (*s == '*'))
|
|
(s)++;
|
|
if (*s != '\0')
|
|
i++;
|
|
}
|
|
s = temp;
|
|
}
|
|
|
|
/* Store depth value */
|
|
table->depth = i;
|
|
|
|
/* Retrieve widths for bits[] and inputs[] */
|
|
table->num_inputs = PORT_SIZE(in);
|
|
table->num_outputs = PORT_SIZE(out);
|
|
|
|
/* Assign storage for arrays to pointers in state table. */
|
|
table->state = (int *)calloc((size_t) (table->depth + 1), sizeof(int));
|
|
table->bits =(short *)calloc(
|
|
(size_t)(table->num_outputs * table->depth / 4 + 1),
|
|
sizeof (short));
|
|
table->inputs = (short *)calloc(
|
|
(size_t)(table->num_inputs * table->depth / 8 + 1),
|
|
sizeof (short));
|
|
table->next_state = (int *)calloc((size_t)(table->depth + 1),
|
|
sizeof (int));
|
|
CALLBACK = callback; // To free those allocations.
|
|
|
|
/*** allocate storage for *states... ***/
|
|
|
|
cm_event_alloc(0, sizeof (Dynamic_State_t));
|
|
|
|
/*** allocate storage for *clk, *clk_old, *reset & *reset_old... ***/
|
|
cm_event_alloc(1, sizeof (Digital_State_t));
|
|
cm_event_alloc(2, sizeof (Digital_State_t));
|
|
|
|
clk = clk_old = (Digital_State_t *)cm_event_get_ptr(1, 0);
|
|
*clk = ZERO;
|
|
reset = reset_old = (Digital_State_t *)cm_event_get_ptr(2, 0);
|
|
*reset = ZERO;
|
|
|
|
/*** Send file pointer and the four storage pointers ***/
|
|
/*** to "cm_read_state_file()". This will return after ***/
|
|
/*** reading the contents of state.in, and if no ***/
|
|
/*** errors have occurred, the "*state" and "*bits" ***/
|
|
/*** "*inputs", and "*next_state" vectors will be loaded ***/
|
|
/*** and the num_inputs, num_outputs and depth ***/
|
|
/*** values supplied. ***/
|
|
|
|
if (state_file) {
|
|
rewind(state_file);
|
|
err = cm_read_state_file(state_file, table);
|
|
} else {
|
|
err = 2;
|
|
}
|
|
|
|
if (err == 1) /* Problem occurred in load. */
|
|
cm_message_send(loading_error);
|
|
else if (err == 2) /* Problem opening the state file. */
|
|
cm_message_send(open_error);
|
|
|
|
if (err > 0) {
|
|
/* Reset arrays to zero */
|
|
for (i = 0; i < table->depth; i++) {
|
|
table->state[i] = 0;
|
|
table->next_state[i] = 0;
|
|
}
|
|
for (i=0; i<(test=(table->num_outputs * table->depth)/4); i++)
|
|
table->bits[i] = 0;
|
|
for (i=0; i<(test=(table->num_inputs * table->depth)/8); i++)
|
|
table->inputs[i] = 0;
|
|
return;
|
|
}
|
|
|
|
/* close state_file */
|
|
if (state_file)
|
|
fclose(state_file);
|
|
|
|
/* declare load values */
|
|
|
|
for (i = 0; i < table->num_inputs; i++) {
|
|
LOAD(in[i]) = PARAM(input_load);
|
|
}
|
|
|
|
LOAD(clk) = PARAM(clk_load);
|
|
|
|
if ( !PORT_NULL(reset) ) {
|
|
LOAD(reset) = PARAM(reset_load);
|
|
}
|
|
}
|
|
else { /**** Retrieve previous values ****/
|
|
|
|
table = (State_Table_t *)STATIC_VAR(table);
|
|
clk = (Digital_State_t *)cm_event_get_ptr(1, 0);
|
|
clk_old = (Digital_State_t *)cm_event_get_ptr(1, 1);
|
|
|
|
reset = (Digital_State_t *)cm_event_get_ptr(2, 0);
|
|
reset_old = (Digital_State_t *)cm_event_get_ptr(2, 1);
|
|
}
|
|
|
|
states = (Dynamic_State_t *)cm_event_get_ptr(0, 0);
|
|
states_old = (Dynamic_State_t *)cm_event_get_ptr(0, 1);
|
|
|
|
/******* Determine analysis type and output appropriate values *******/
|
|
|
|
if (0.0 == TIME) { /****** DC analysis...output w/o delays ******/
|
|
/* set current state to default */
|
|
states->current_state = PARAM(reset_state);
|
|
|
|
/* set indices for this state */
|
|
err = cm_set_indices(states, table);
|
|
if (err == TRUE) {
|
|
cm_message_send(index_error);
|
|
return;
|
|
}
|
|
|
|
/* Output new values... */
|
|
for (i=0; i < table->num_outputs; i++) {
|
|
|
|
/* retrieve output value */
|
|
cm_get_bits_value(table,states->index0,i,&out);
|
|
|
|
OUTPUT_STATE(out[i]) = out.state;
|
|
OUTPUT_STRENGTH(out[i]) = out.strength;
|
|
}
|
|
}
|
|
|
|
else { /****** Transient Analysis ******/
|
|
|
|
/*** load current input values if reset
|
|
is not connected, set to zero... ***/
|
|
*clk = INPUT_STATE(clk);
|
|
|
|
if ( PORT_NULL(reset) ) {
|
|
*reset = *reset_old = ZERO;
|
|
}
|
|
else {
|
|
*reset = INPUT_STATE(reset);
|
|
}
|
|
|
|
/***** Find input that has changed... *****/
|
|
|
|
/**** Test reset value for change ****/
|
|
if ( *reset != *reset_old ) { /* either reset or reset release */
|
|
switch ( *reset ) {
|
|
|
|
case ONE:
|
|
states->current_state = PARAM(reset_state);
|
|
|
|
/* set indices for this state */
|
|
err = cm_set_indices(states, table);
|
|
if ( err == TRUE ) {
|
|
cm_message_send(index_error);
|
|
return;
|
|
}
|
|
|
|
/* Output new values... */
|
|
for (i=0; i<table->num_outputs; i++) {
|
|
|
|
/* retrieve output value */
|
|
cm_get_bits_value(table, states->index0, i, &out);
|
|
|
|
OUTPUT_STATE(out[i]) = out.state;
|
|
OUTPUT_STRENGTH(out[i]) = out.strength;
|
|
OUTPUT_DELAY(out[i]) = PARAM(reset_delay);
|
|
}
|
|
break;
|
|
|
|
case ZERO:
|
|
case UNKNOWN:
|
|
/* output remains at current value */
|
|
for (i=0; i<table->num_outputs; i++) {
|
|
OUTPUT_CHANGED(out[i]) = FALSE;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
if ( ONE != *reset ) {
|
|
/**** model is not held to reset value ****/
|
|
/**** Test clk value for change ****/
|
|
if (*clk != *clk_old) { /* clock or clock release */
|
|
switch ( *clk ) {
|
|
|
|
case ONE:
|
|
|
|
/** active edge...need to find out if a match **/
|
|
/** exists between the current inputs and **/
|
|
/** any of the inputs which drive the state **/
|
|
/** machine to the next state...if so, we **/
|
|
/** will need to retrieve that state value, **/
|
|
/** and set the new index boundaries... **/
|
|
|
|
/* for each of the entries for the current_state... */
|
|
for (i=states->index0; i<=states->indexN; i++) {
|
|
|
|
/* first set err to zero... */
|
|
err = 0;
|
|
|
|
/* for each bit of the inputs value for this
|
|
entry...*/
|
|
for (j = 0; j < table->num_inputs; j++) {
|
|
|
|
/* retrieve the current input bit... */
|
|
in.state = INPUT_STATE(in[j]);
|
|
|
|
/* ...& compare to the corresponding
|
|
inputs[i] value. */
|
|
err = cm_compare_to_inputs(table, i, j,
|
|
in.state);
|
|
|
|
/* break if comparison was no-good... */
|
|
if (0 != err)
|
|
break;
|
|
}
|
|
|
|
/* if the comparison of the entire input
|
|
word was good, break out of this loop too... */
|
|
if ( 0 == err ) break;
|
|
}
|
|
|
|
/* if err == 0, then a match was found...otherwise,
|
|
we will not change states... */
|
|
|
|
if ( 0 == err ) {
|
|
/* use "i" to retrieve the next state value:
|
|
store this into current_state... */
|
|
|
|
states->current_state = table->next_state[i];
|
|
|
|
/* set indices for this new state */
|
|
err = cm_set_indices(states, table);
|
|
if ( err == TRUE ) {
|
|
cm_message_send(index_error);
|
|
return;
|
|
}
|
|
|
|
/* Output new values... */
|
|
for (i=0; i<table->num_outputs; i++) {
|
|
/* retrieve output value */
|
|
|
|
cm_get_bits_value(table, states->index0,
|
|
i, &out);
|
|
OUTPUT_STATE(out[i]) = out.state;
|
|
OUTPUT_STRENGTH(out[i]) = out.strength;
|
|
OUTPUT_DELAY(out[i]) = PARAM(clk_delay);
|
|
}
|
|
|
|
}
|
|
else { /* no change in state or in output */
|
|
|
|
for (i=0; i<table->num_outputs; i++) {
|
|
OUTPUT_CHANGED(out[i]) = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZERO:
|
|
case UNKNOWN:
|
|
|
|
/* no change in state or in output */
|
|
for (i=0; i<table->num_outputs; i++) {
|
|
OUTPUT_CHANGED(out[i]) = FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
else { /* input value must have changed...
|
|
return previous output value. */
|
|
|
|
for (i=0; i<table->num_outputs; i++) {
|
|
OUTPUT_CHANGED(out[i]) = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else { /* Reset is active...
|
|
return previous output values. */
|
|
|
|
for (i=0; i<table->num_outputs; i++) {
|
|
OUTPUT_CHANGED(out[i]) = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|