/* $Id: cfunc.tpl,v 1.1 91/03/18 19:01:04 bill Exp $ */
/*.......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
                                   

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 */

                                      

/*=== CONSTANTS ========================*/

#define MAX_STRING_SIZE 200



/*=== MACROS ===========================*/



  
/*=== LOCAL VARIABLES & TYPEDEFS =======*/                         

typedef struct { 
    int index,  /* current index into source tables                 */
        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.                                  */
} Source_Table_Info_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 ===*/





                   

/*==============================================================================

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 = (void *) tmalloc(strlen(*s) + 1);

    /* skip over any white space */

    while(isspace(**s) || (**s == '=') ||
          (**s == '(') || (**s == ')') || (**s == ','))
          (*s)++;

    /* isolate the next token */

    switch(**s) {

    case '\0':           /* End of string found */
        tfree(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(**s) || (**s == '=') || 
                    (**s == '(') || (**s == ')') || 
                    (**s == ',') 
             ) )  ) {
            buf[i] = **s;
            i++;
            (*s)++;
        }
        buf[i] = '\0';
        break;
    }

    /* skip over white space up to next token */

    while(isspace(**s) || (**s == '=') ||
          (**s == '(') || (**s == ')') || (**s == ','))
          (*s)++;

    /* make a copy using only the space needed by the string length */


    ret_str = (void *) tmalloc(strlen(buf) + 1);
    ret_str = strcpy(ret_str,buf);

    tfree(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(str,p_value)

char    *str;        /* IN - The value text e.g. 1.2K */
float   *p_value;    /* OUT - The numerical value     */
{


    /* the following were "int4" devices - jpm */
    int    len;
    int    i;
    int    n_matched;

    line_t  val_str;

    char    *suffix;
    char    c;
    char    c1;

    float   scale_factor;
    float   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 != 'E') && (c != 'e') )
            break;
        else if( isspace(c) )
            break;
        else
            val_str[i] = c;
    }
    val_str[i] = '\0';


    /* Determine the scale factor */

    if( (i >= len) || (! isalpha(c)) )
        scale_factor = 1.0;
    else {

        if(isupper(c))
            c = tolower(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(c1)) {
                scale_factor = 1.0e-3;
                break;
            }
            if(islower(c1))
                c1 = toupper(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,"%e",&value);

    if(n_matched < 1) {
        *p_value = 0.0;
        return(FAIL);
    }

    *p_value = value * scale_factor;
    return(OK);
}



                                    

/*==============================================================================

FUNCTION cm_source_mask_and_retrieve()

AUTHORS                      

    15 Jul 1991     Jeffrey P. Murray

MODIFICATIONS   

    16 Jul 1991     Jeffrey P. Murray
    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_SOURCE_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/15/91               J.P.Murray      *
**************************************************/

static void cm_source_mask_and_retrieve(short base,int bit_offset,Digital_t *out)
{
                                                              

    short value;  /* the hexadecimal value of the masked bit  */



    switch (bit_offset) {                            
    case 0:    
        break;

    case 1:
        base = base >> 4;
        break;

    case 2:
        base = base >> 8;
        break;

    case 3:
        base = base >> 12;
        break;
    }


    value = 0x000f & base;


    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_source_mask_and_store()

AUTHORS                      

    15 Jul 1991     Jeffrey P. Murray

MODIFICATIONS   

    16 Jul 1991     Jeffrey P. Murray
    30 Sep 1991     Jeffrey P. Murray

SUMMARY

    Masks off and stores a two-bit value to a short
    integer word passed to the function, using an offset value. 
    This effectively handles storage of eight two-bit values 
    to a single short integer space in order to conserve memory.

INTERFACES       

    FILE                 ROUTINE CALLED     
 
    N/A                  N/A


RETURNED VALUE
    
    Returns updated *base value.

GLOBAL VARIABLES
    
    NONE

NON-STANDARD FEATURES

    NONE

==============================================================================*/

/*=== Static CM_SOURCE_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 ram_offset value.      *
*                                               *
*   Created 7/15/91               J.P.Murray    *
************************************************/

static int cm_source_mask_and_store(short *base,int bit_offset,int bit_value)
{
    switch (bit_offset) {                            
    case 0:    
        *base = *base & 0xfff0;
        break;

    case 1:
        *base = *base & 0xff0f;
        bit_value = bit_value << 4;
        break;

    case 2:
        *base = *base & 0xf0ff;
        bit_value = bit_value << 8;
        break;

    case 3:
        *base = *base & 0x0fff;
        bit_value = bit_value << 12;
        break;
    }
     
    *base = *base | bit_value;
}




/*==============================================================================

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

SUMMARY

    Retrieves four-bit data from short integer array "source".

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 four-bit *
*   data from short integer array "source". The *
*   integers are assumed to be at least two     *
*   bytes each, so each will hold four four-    *
*   bit values.                                 *
*                                               *
*   Created 7/15/91               J.P.Murray    *
************************************************/

static void cm_get_source_value(int word_width,int bit_number,int index,
                         short *bits, 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. */
                                        
    double   double1,
             double2;      /* holding variables for modf routine */



    /* obtain offset value from index, word_width & bit_number */
    int1 = index * word_width + bit_number;
    double1 = int1 / 4.0;
    modf(double1, &double2);
    bit_index = double2;
    bit_offset = int1 - (double2 * 4.0);

    /* retrieve entire base_address bits integer... */
    base = bits[bit_index];
                         
    /* for each offset, mask off the bits and determine values */

    cm_source_mask_and_retrieve(base,bit_offset,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

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 "bits" array.

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,short *bits,double *timepoints,
                   Source_Table_Info_t *info)
{
    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   */
             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 source.in */
                              *s,   /* main string variable */
                   *base_address,   /* storage location for base address
                                       of string.   */    
                          *token;   /* a particular token from the string   */
   

    float                 number;   /* holding variable for timepoint values */                                             
                                                 
    double               double1,   /* temporary holding variable   */
                         double2;   /* temporary holding variable   */

    short              bit_value,   /* holding variable for value read from
                                       source file which needs to be stored */
                            base;   /* holding variable for existing 
                                       non-masked bits[] integer  */

    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(*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);
                    j++;
                }
                num_tokens = j;
        
                /* If this number is incorrect, return with an error    */
                if ( (info->width + 2) != num_tokens) {
                    return 1;
                }
        
                /* reset s to beginning... */                     
                s = base_address;
        
                /** Retrieve each token, analyze, and       **/
                /** store the timepoint and bit information **/
                for (j=0; j<(info->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);
        
                        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 ( timepoints[i] <= timepoints[i-1] ) {
                                return 1;
                            }
                        }    
    
                    }
                    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 1;                            
                        }
                        else { /* need to store this value in the bits[] array */
                                                                                    
                            /* obtain offset value from word_number, word_width & 
                               bit_number */
                            int1 = i * info->width + (j-1);
                            double1 = int1 / 4.0;
                            modf(double1, &double2);
                            bit_index = double2;
                            bit_offset = int1 - (double2 * 4.0);
                        
                            /* retrieve entire base_address bits integer... */
                            base = bits[bit_index];
                                                 
                            /* for each offset, mask off the bits and store values */
                            cm_source_mask_and_store(&base,bit_offset,bit_value);
                                                  
                            /* store modified base value */
                            bits[bit_index] = base;                   
                        }
                    }       
                }
                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

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 model for the       *
*   digital source for the                      *
*   ATESSE Version 2.0 system.                  *
*                                               *
*   Created 6/13/91               J.P.Murray    *
************************************************/


void cm_d_source(ARGS) 
{
    int                    i,   /* generic loop counter index */
                         err,   /* integer for storage of error status  */
                        test,   /* testing integer  */   
                       dummy;   /* temp holding variable  */   


    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.    */
                   *bits_old;   /* the storage array for old bit values */ 


    double       *timepoints,   /* the storage array for the 
                                   timepoints...this will have size equal 
                                   to "depth"   */
             *timepoints_old,   /* the storage array for the old timepoints */
                 test_double,   /* test variable for doubles    */
                double_dummy;   /* fake holding double  */   



    FILE                 *source;   /* pointer to the source.in input
                                       vector file */


    Source_Table_Info_t    *info,   /* storage location for source
                                       index and depth info. */
                       *info_old;   /* storage location for old info */

                                                                   
    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 */ 


    char *loading_error = "\n***ERROR***\nD_SOURCE: source.in file was not read successfully. \n";

    



    /**** Setup required state variables ****/

    if(INIT) {  /* initial pass */ 
                                        


        /*** open file and count the number of vectors in it ***/
        source = fopen( PARAM(input_file), "r");

        /* 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(*s) || (*s == '*')) 
                        (s)++;
                  if ( *s != '\0' ) i++;
              }
              s = temp;
          }
        }

        /*** allocate storage for *index, *bits & *timepoints ***/

        info = info_old = (Source_Table_Info_t *) 
                          cm_event_alloc(0,sizeof(Source_Table_Info_t));
        

                                                           
        modf( (PORT_SIZE(out) * i / 4), &double_dummy );
        dummy = double_dummy + 1;

        bits = bits_old = (short *) cm_event_alloc(1,(dummy * sizeof(short)));
                         
        timepoints = timepoints_old = (double *) 
                     cm_event_alloc(2,i * sizeof(double));
                                       

        /**** Get all pointers again (to avoid realloc problems) ****/
        info = info_old = (Source_Table_Info_t *) cm_event_get_ptr(0,0);
        bits = bits_old = (short *) cm_event_get_ptr(1,0);
        timepoints = timepoints_old = (double *) cm_event_get_ptr(2,0);




        /* Initialize info values... */

        info->index = 0;
        info->depth = i;

        /* Retrieve width of the source */
        info->width = PORT_SIZE(out);


        /* Initialize *bits & *timepoints to zero */

        for (i=0; i<dummy; i++) bits[i] = 0;

        for (i=0; i<info->depth; i++) timepoints[i] = 0;


                                        



        /* 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 "*bits" and "*timepoints"  */
        /* vectors will be loaded and the width and depth       */
        /* values supplied.                                     */

        if (source) {
          rewind(source);
          err = cm_read_source(source,bits,timepoints,info);
        } else {
          err=1;
        }




        if (err) { /* problem occurred in load...send error msg. */

            cm_message_send(loading_error);

            /* Reset *bits & *timepoints to zero */
            for (i=0; i<(test = (info->width*info->depth)/4); i++) bits[i] = 0;
            for (i=0; i<info->depth; i++) timepoints[i] = 0;
        }

        /* close source file */
        if (source)
            fclose(source);

    }
    else {      /*** Retrieve previous values ***/

        /** Retrieve info... **/
        info = (Source_Table_Info_t *) cm_event_get_ptr(0,0);
        info_old  = (Source_Table_Info_t *) cm_event_get_ptr(0,1);

        /* Set old values to new... */
        info->index = info_old->index;
        info->depth = info_old->depth;
        info->width = info_old->width;

                                                               

        /** Retrieve bits... **/
        bits = (short *) cm_event_get_ptr(1,0);
        bits_old = (short *) cm_event_get_ptr(1,1);

        /* Set old values to new... */
        modf( (info->width * info->depth / 4), &double_dummy );
        dummy = double_dummy + 1;


        for (i=0; i<dummy; i++) bits[i] = bits_old[i];

                                     

        /** Retrieve timepoints... **/
        timepoints = (double *) cm_event_get_ptr(2,0);
        timepoints_old = (double *) cm_event_get_ptr(2,1);

        /* Set old values to new... */
        for (i=0; i<info->depth; i++) 
            timepoints[i] = timepoints_old[i];

                                         
    }

    /*** For the case of TIME==0.0, set special breakpoint ***/

    if ( 0.0 == TIME ) {
                                    
        test_double = timepoints[info->index];
        if ( 0.0 == test_double && info->depth > 0 ) { /* Set DC value */

            /* reset current breakpoint */
            test_double = timepoints[info->index];
            cm_event_queue( test_double );
                                              
            /* Output new values... */
            for (i=0; i<info->width; i++) {
    
                /* retrieve output value */
                cm_get_source_value(info->width,i,info->index,bits,&out);
    
                OUTPUT_STATE(out[i]) = out.state;
                OUTPUT_STRENGTH(out[i]) = out.strength;

            }
         
            /* increment breakpoint */
            (info->index)++;
    
    
            /* set next breakpoint as long as depth 
               has not been exceeded    */
            if ( info->index < info->depth ) {
                test_double = timepoints[info->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 ( info->index < info->depth ) {
                test_double = timepoints[info->index] - 1.0e-10;
                cm_event_queue( test_double );
            }
            for(i=0; i<info->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 = timepoints[info->index] - 1.0e-10;

        if ( TIME < test_double ) { /* Breakpoint has not occurred */
    
            /** Output hasn't changed...do nothing this time. **/
            for (i=0; i<info->width; i++) {
                OUTPUT_CHANGED(out[i]) = FALSE;
            }                                                     
     
            if ( info->index < info->depth ) {
                test_double = timepoints[info->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 = timepoints[info->index] - 1.0e-10;
            cm_event_queue( test_double );
                                              
            /* Output new values... */
            for (i=0; i<info->width; i++) {
    
                /* retrieve output value */
                cm_get_source_value(info->width,i,info->index,bits,&out);
    
                OUTPUT_STATE(out[i]) = out.state;
                OUTPUT_DELAY(out[i]) = 1.0e-10;
                OUTPUT_STRENGTH(out[i]) = out.strength;
            }
    
    
    
            /* increment breakpoint */
            (info->index)++;
    
    
            /* set next breakpoint as long as depth 
               has not been exceeded    */
            if ( info->index < info->depth ) {
                test_double = timepoints[info->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<info->width; i++) {
                OUTPUT_CHANGED(out[i]) = FALSE;
            }                                                     
        }
    }                 
}



