ngspice/src/xspice/icm/digital/d_source/cfunc.mod

1252 lines
33 KiB
Modula-2

/*.......1.........2.........3.........4.........5.........6.........7.........8
================================================================================
FILE d_source/cfunc.mod
Copyright 1991
Georgia Tech Research Corporation, Atlanta, Ga. 30332
All Rights Reserved
PROJECT A-8503-405
AUTHORS
6 June 1991 Jeffrey P. Murray
MODIFICATIONS
30 Sept 1991 Jeffrey P. Murray
19 Aug 2012 Holger Vogt
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()
int cm_event_queue()
REFERENCED FILES
Inputs from and outputs to ARGS structure.
NON-STANDARD FEATURES
NONE
===============================================================================*/
/*=== INCLUDE FILES ====================*/
#include "d_source.h" /* ...contains macros & type defns.
for this model. 6/13/90 - JPM */
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
/*=== CONSTANTS ========================*/
#define MAX_STRING_SIZE 1024
/*=== MACROS ===========================*/
#if defined(__MINGW32__) || defined(_MSC_VER)
#define DIR_PATHSEP "\\"
#else
#define DIR_PATHSEP "/"
#endif
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
typedef struct {
int width, /* width of table...equal to size of out port */
depth; /* depth of table...equal to size of
"timepoints" array, and to the total
number of vectors retrieved from the
source.in file. */
double *all_timepoints; /* the storage array for the
timepoints, as read from file.
This will have size equal
to "depth" */
char **all_data; /* the storage array for the
output bit representations;
as read from file. This will have size equal
to width*depth, one short will hold a
12-state bit description. */
} Local_Data_t;
/* Type definition for each possible token returned. */
typedef enum token_type_s {CNV_NO_TOK,CNV_STRING_TOK} Cnv_Token_Type_t;
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
static void free_local_data(Local_Data_t *loc);
static void cm_d_source_callback(ARGS, Mif_Callback_Reason_t reason);
/*==============================================================================
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
==============================================================================*/
///XXX TODO: The CNVgettok, etc. functions are repeated in d_sorce and
///XXX TODO d_state. They should be put in a common place and built once
/*=== 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 */
int i;
/* allocate space big enough for the whole string */
if ((buf = (char *) tmalloc_raw(strlen(*s) + 1)) == (char *) NULL) {
cm_message_send("Unable to allocate buffer in CNVgettok()");
return (char *) NULL;
}
/* 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 */
txfree(buf);
return (char *) 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 */
{
char * const ret_str = (char *) tmalloc_raw(strlen(buf) + 1);
if (ret_str == (char *) NULL) {
cm_message_send("Unable to allocate return buffer "
"in CNVgettok()");
return (char *) NULL;
}
strcpy(ret_str, buf);
txfree(buf);
return ret_str;
}
} /* end of function CNVgettok */
/*==============================================================================
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)
{
/* storage for returned string */
/* get the token from the input line */
char * const ret_str = CNVgettok(s);
/* if no next token, return */
if (ret_str == (char *) NULL) {
*type = CNV_NO_TOK;
return (char *) NULL;
}
/* else, determine and return token type */
switch(*ret_str) {
default:
*type = CNV_STRING_TOK;
break;
}
return(ret_str);
} /* end of function CNVget_token */
/*==============================================================================
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(isupper_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_source_retrieve()
AUTHORS
15 Jul 1991 Jeffrey P. Murray
MODIFICATIONS
16 Jul 1991 Jeffrey P. Murray
30 Sep 1991 Jeffrey P. Murray
19 Aug 2012 H. Vogt
SUMMARY
Retrieves a bit value from a char character
INTERFACES
FILE ROUTINE CALLED
N/A N/A
RETURNED VALUE
Returns a Digital_t value.
GLOBAL VARIABLES
NONE
NON-STANDARD FEATURES
NONE
==============================================================================*/
/*=== Static CM_SOURCE_RETRIEVE ROUTINE ===*/
/**************************************************
* The following routine retrieves *
* the value passed to it by the out value. *
* *
* Created 7/15/91 J.P.Murray *
**************************************************/
static void cm_source_retrieve(char val, Digital_t *out)
{
int value = (int)val;
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_source_value()
AUTHORS
15 Jul 1991 Jeffrey P. Murray
MODIFICATIONS
16 Jul 1991 Jeffrey P. Murray
30 Sep 1991 Jeffrey P. Murray
19 Aug 2012 H. Vogt
SUMMARY
Retrieves a char per bit value from the array "all_data".
INTERFACES
FILE ROUTINE CALLED
N/A N/A
RETURNED VALUE
Returns data via *out pointer.
GLOBAL VARIABLES
NONE
NON-STANDARD FEATURES
NONE
==============================================================================*/
/*=== Static CM_GET_SOURCE_VALUE ROUTINE ===*/
/************************************************
* The following routine retrieves a bit *
* from all_data and stores them in out *
* *
* Created 8/19/12 H. Vogt *
************************************************/
static void cm_get_source_value(int row, int bit_number, char **all_data, Digital_t *out)
{
char val;
val = all_data[row][bit_number];
cm_source_retrieve(val,out);
}
/*==============================================================================
FUNCTION cm_read_source()
AUTHORS
15 Jul 1991 Jeffrey P. Murray
MODIFICATIONS
19 Jul 1991 Jeffrey P. Murray
30 Sep 1991 Jeffrey P. Murray
19 Aug 2012 H. Vogt
SUMMARY
This function reads the source file and stores the results
for later output by the model.
INTERFACES
FILE ROUTINE CALLED
N/A N/A
RETURNED VALUE
Returns output bits stored in "all_data" array,
time values in "all_timepoints" array,
return != 0 code if error.
GLOBAL VARIABLES
NONE
NON-STANDARD FEATURES
NONE
==============================================================================*/
/*=== Static CM_READ_SOURCE ROUTINE ===*/
/**************************************************
* The following routine reads the file *
* *source, parses the file, and stores *
* the values found there into the *bits & *
* *timepoints arrays. *
* *
* Created 7/15/91 J.P.Murray *
**************************************************/
static int cm_read_source(FILE *source, Local_Data_t *loc)
{
int i, /* indexing variable */
j, /* indexing variable */
num_tokens; /* number of tokens in a given string */
Cnv_Token_Type_t type; /* variable for testing token type returned. */
char temp[MAX_STRING_SIZE], /* holding string variable for testing
input from source.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 */
char bit_value; /* holding variable for value read from
source file which needs to be stored */
i = 0;
s = temp;
while ( fgets(s,MAX_STRING_SIZE,source) != 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)
txfree(token);
j++;
}
num_tokens = j;
/* If this number is incorrect, return with an error */
if ( (loc->width + 2) != num_tokens) {
return 2;
}
/* reset s to beginning... */
s = base_address;
/* set storage space for bits in a row and set them to 0*/
if ((loc->all_data[i] = (char *) tcalloc_raw(
(size_t) loc->width,
sizeof(char))) == (char *) NULL) {
cm_message_send("Unable to allocate buffer "
"for all_data bits in cm_d_source()");
return -1;
}
/** Retrieve each token, analyze, and **/
/** store the timepoint and bit information **/
for (j=0; j<(loc->width + 1); j++) {
token = CNVget_token(&s, &type);
if ( 0 == j ) { /* obtain timepoint value... */
/* convert to a floating point number... */
cnv_get_spice_value(token,&number);
loc->all_timepoints[i] = number;
/* provided this is not the first timepoint
to be written... */
if ( 0 != i ) {
/* if current timepoint value is not greater
than the previous value, then return with
an error message... */
if ( loc->all_timepoints[i] <= loc->all_timepoints[i-1] ) {
return 3;
}
}
}
else { /* obtain each bit value & set bits entry */
/* 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) {
return 4;
}
else { /* need to store this value in the all_data[] array */
loc->all_data[i][j-1] = bit_value;
}
}
if (token)
txfree(token);
}
i++;
}
s = temp;
}
}
return 0;
}
/*==============================================================================
FUNCTION cm_d_source()
AUTHORS
13 Jun 1991 Jeffrey P. Murray
MODIFICATIONS
8 Aug 1991 Jeffrey P. Murray
30 Sep 1991 Jeffrey P. Murray
19 Aug 2012 H. Vogt
SUMMARY
This function implements the d_source code model.
INTERFACES
FILE ROUTINE CALLED
CMmacros.h cm_message_send();
CMevt.c void *cm_event_alloc()
void *cm_event_get_ptr()
int cm_event_queue()
RETURNED VALUE
Returns inputs and outputs via ARGS structure.
GLOBAL VARIABLES
NONE
NON-STANDARD FEATURES
NONE
==============================================================================*/
/*=== CM_D_SOURCE ROUTINE ==============*/
/************************************************
* The following is the new model for *
* the digital source *
* *
* Created 8/19/12 H. Vogt *
************************************************/
void cm_d_source(ARGS)
{
int i, /* generic loop counter index */
err; /* integer for storage of error status */
/**** the state variables, memory allocation with cm_event_alloc *****/
char *bits, /* the storage array for the
output bit representations...
this will have size equal to width,
since one short will hold a 12-state
bit description. */
*bits_old; /* the storage array for old bit values */
int *row_index, /* current index into source tables */
*row_index_old; /* previous index into source tables */
double *timepoint, /* the storage array for the
timepoints, a single point */
*timepoint_old; /* the storage for the old timepoint */
/*********************************************************************/
volatile double /* enforce 64 bit precision, (equality comparison) */
test_double; /* test variable for doubles */
FILE *source; /* pointer to the source.in input
vector file */
Digital_t out; /* storage for each output bit */
char temp[MAX_STRING_SIZE], /* holding string variable for testing
input from source.in */
*s; /* main string variable */
const char *loading_error =
"\nERROR **\n D_SOURCE: source.in file "
"was not read successfully.";
Local_Data_t *loc; /* Pointer to local static data, not to be included
in the state vector (save memory!) */
/**** Setup required local and state variables ****/
/* local data will be setup once during INIT and never change again */
if(INIT) { /* initial pass */
/*** open file and count the number of vectors in it ***/
char* filename = PARAM(input_file);
source = fopen_with_path( filename, "r");
if (!source) {
char *lbuffer, *p;
lbuffer = getenv("NGSPICE_INPUT_DIR");
if (lbuffer && *lbuffer) {
p = (char *) tmalloc_raw(strlen(lbuffer) +
strlen(DIR_PATHSEP) + strlen(PARAM(input_file)) + 1);
if (p == (char *) NULL) {
cm_message_send("Unable to allocate buffer "
"for building file name in cm_d_source()");
return;
}
sprintf(p, "%s%s%s", lbuffer, DIR_PATHSEP, PARAM(input_file));
source = fopen(p, "r");
txfree(p);
}
if (!source)
cm_message_printf("cannot open file %s", PARAM(input_file));
}
/* increment counter if not a comment until EOF reached... */
i = 0;
if (source) {
s = temp;
while ( fgets(s,MAX_STRING_SIZE,source) != NULL) {
if ( '*' != s[0] ) {
while(isspace_c(*s) || (*s == '*'))
(s)++;
if ( *s != '\0' ) i++;
}
s = temp;
}
}
/*** allocate static storage for *loc ***/
if ((loc = (Local_Data_t *) (STATIC_VAR(locdata) = tcalloc_raw(1,
sizeof(Local_Data_t)))) == (Local_Data_t *) NULL) {
cm_message_send("Unable to allocate buffer "
"for building file name in cm_d_source()");
return;
}
/*** allocate storage for *index, *bits & *timepoint ***/
cm_event_alloc(0, sizeof(int));
cm_event_alloc(1, PORT_SIZE(out) * (int) sizeof(char));
cm_event_alloc(2, (int) sizeof(double));
/**** Get all pointers again (to avoid realloc problems) ****/
row_index = row_index_old = (int *) cm_event_get_ptr(0,0);
bits = bits_old = (char *) cm_event_get_ptr(1,0);
timepoint = timepoint_old = (double *) cm_event_get_ptr(2,0);
/* Initialize info values... */
*row_index = 0;
loc->depth = i;
/* Retrieve width of the source */
loc->width = PORT_SIZE(out);
/*** allocate storage for **all_data, & *all_timepoints ***/
if ((loc->all_timepoints = (double *) tcalloc_raw((size_t) i,
sizeof(double))) == (double *) NULL) {
cm_message_send("Unable to allocate all_timepoints "
"in cm_d_source()");
free_local_data(loc);
STATIC_VAR(locdata) = NULL;
return;
}
if ((loc->all_data = (char **) tcalloc_raw((size_t) i,
sizeof(char *))) == (char **) NULL) {
cm_message_send("Unable to allocate all_data "
"in cm_d_source()");
free_local_data(loc);
STATIC_VAR(locdata) = NULL;
return;
}
/* Send file pointer and the two array storage pointers */
/* to "cm_read_source()". This will return after */
/* reading the contents of source.in, and if no */
/* errors have occurred, the "*all_data" and "*all_timepoints" */
/* vectors will be loaded and the width and depth */
/* values supplied. */
if (source) {
rewind(source);
err = cm_read_source(source, loc);
} else {
err=1;
}
/* close source file */
if (source) {
fclose(source);
}
if (err) { /* problem occurred in load...send error msg. */
cm_message_send(loading_error);
switch (err)
{
case -1:
cm_message_send(" Allocation failure "
"while allocating memory for bits" );
break;
case 2:
cm_message_send(" d_source word length and number of columns in file differ." );
break;
case 3:
cm_message_send(" Time values in first column have to increase monotonically.");
break;
case 4:
cm_message_send(" Unknown bit value.");
break;
default:
break;
}
free_local_data(loc);
STATIC_VAR(locdata) = NULL;
return;
}
CALLBACK = cm_d_source_callback;
}
else { /*** Retrieve previous values ***/
if ((loc = (Local_Data_t *) STATIC_VAR (locdata)) ==
(Local_Data_t *) NULL) {
cm_message_send("Attempt to use unallocated Local_Data_t "
"in cm_d_source()");
}
/** Retrieve info... **/
row_index = (int *) cm_event_get_ptr(0,0);
row_index_old = (int *) cm_event_get_ptr(0,1);
/* Set old values to new... */
*row_index = *row_index_old;
/** Retrieve bits... **/
bits = (char *) cm_event_get_ptr(1,0);
bits_old = (char *) cm_event_get_ptr(1,1);
for (i=0; i<PORT_SIZE(out); i++) bits[i] = bits_old[i];
/** Retrieve timepoints... **/
timepoint = (double *) cm_event_get_ptr(2,0);
timepoint_old = (double *) cm_event_get_ptr(2,1);
/* Set old values to new... */
timepoint = timepoint_old;
}
/*** For the case of TIME==0.0, set special breakpoint ***/
if ( 0.0 == TIME ) {
test_double = loc->all_timepoints[*row_index];
if ( 0.0 == test_double && loc->depth > 0 ) { /* Set DC value */
/* reset current breakpoint */
test_double = loc->all_timepoints[*row_index];
cm_event_queue( test_double );
/* Output new values... */
for (i=0; i<loc->width; i++) {
/* retrieve output value */
cm_get_source_value(*row_index, i, loc->all_data, &out);
OUTPUT_STATE(out[i]) = out.state;
OUTPUT_STRENGTH(out[i]) = out.strength;
}
/* increment breakpoint */
(*row_index)++;
/* set next breakpoint as long as depth
has not been exceeded */
if ( *row_index < loc->depth ) {
test_double = loc->all_timepoints[*row_index] - 1.0e-10;
cm_event_queue( test_double );
}
}
else { /* Set breakpoint for first time index */
/* set next breakpoint as long as depth
has not been exceeded */
if ( *row_index < loc->depth ) {
test_double = loc->all_timepoints[*row_index] - 1.0e-10;
cm_event_queue( test_double );
}
for(i=0; i<loc->width; i++) {
OUTPUT_STATE(out[i]) = UNKNOWN;
OUTPUT_STRENGTH(out[i]) = UNDETERMINED;
}
}
}
else {
/*** Retrieve last index value and branch to appropriate ***
*** routine based on the last breakpoint's relationship ***
*** to the current time value. ***/
test_double = loc->all_timepoints[*row_index] - 1.0e-10;
if ( TIME < test_double ) { /* Breakpoint has not occurred */
/** Output hasn't changed...do nothing this time. **/
for (i=0; i<loc->width; i++) {
OUTPUT_CHANGED(out[i]) = FALSE;
}
if ( *row_index < loc->depth ) {
test_double = loc->all_timepoints[*row_index] - 1.0e-10;
cm_event_queue( test_double );
}
}
else /* Breakpoint has been reached or exceeded */
if ( TIME == test_double ) { /* Breakpoint reached */
/* reset current breakpoint */
test_double = loc->all_timepoints[*row_index] - 1.0e-10;
cm_event_queue( test_double );
/* Output new values... */
for (i=0; i<loc->width; i++) {
/* retrieve output value */
cm_get_source_value(*row_index, i , loc->all_data, &out);
OUTPUT_STATE(out[i]) = out.state;
OUTPUT_DELAY(out[i]) = 1.0e-10;
OUTPUT_STRENGTH(out[i]) = out.strength;
}
/* increment breakpoint */
(*row_index)++;
/* set next breakpoint as long as depth
has not been exceeded */
if ( *row_index < loc->depth ) {
test_double = loc->all_timepoints[*row_index] - 1.0e-10;
cm_event_queue( test_double );
}
}
else { /* Last source file breakpoint has been exceeded...
do not change the value of the output */
for (i=0; i<loc->width; i++) {
OUTPUT_CHANGED(out[i]) = FALSE;
}
}
}
} /* end of function cm_d_source */
/* This function frees resources when called with reason argument
* MIF_CB_DESTROY */
static void cm_d_source_callback(ARGS, Mif_Callback_Reason_t reason)
{
switch (reason) {
case MIF_CB_DESTROY: {
Local_Data_t *loc = (Local_Data_t *) STATIC_VAR(locdata);
if (loc != (Local_Data_t *) NULL) {
free_local_data(loc);
}
break;
}
}
} /* end of function cm_d_state_callback */
static void free_local_data(Local_Data_t *loc)
{
/* Immediate return if no structure */
if (loc == (Local_Data_t *) NULL) {
return;
}
/* Free all_data and internal allocations */
{
char ** const all_data = loc->all_data;
if (all_data != (char **) NULL) {
const int n = loc->width;
int i;
for (i = 0; i != n; ++i) { /* free individual allocs */
if (all_data[i] != (char *) NULL) {
txfree(all_data[i]);
}
}
txfree(all_data);
}
}
/* Free all_timepoints */
{
void * const p = loc->all_timepoints;
if (p != NULL) {
txfree(p);
}
}
txfree(loc);
} /* end of function free_local_data */