statement.c File Reference

#include <stdio.h>
#include <assert.h>
#include "defines.h"
#include "statement.h"
#include "expr.h"
#include "util.h"
#include "link.h"
#include "sim.h"
#include "db.h"
#include "stmt_blk.h"

Functions

statementstatement_create (expression *exp, func_unit *funit, unsigned int ppline)
 Creates new statement structure.
void statement_queue_display ()
static void statement_queue_add (statement *stmt, int id, int type)
static void statement_queue_compare (statement *stmt)
void statement_size_elements (statement *stmt, func_unit *funit)
 Sizes all expressions for the given statement block.
void statement_db_write (statement *stmt, FILE *ofile, bool ids_issued)
 Writes specified statement to the specified output file.
void statement_db_write_tree (statement *stmt, FILE *ofile)
 Writes specified statement tree to the specified output file.
void statement_db_write_expr_tree (statement *stmt, FILE *ofile)
 Writes specified expression trees for given statement block to specified output file.
void statement_db_read (char **line, func_unit *curr_funit, int read_mode)
 Reads in statement line from specified string and stores statement in specified functional unit.
void statement_assign_expr_ids (statement *stmt, func_unit *funit)
 Assigns unique expression IDs to each expression in the given statement block.
bool statement_connect (statement *curr_stmt, statement *next_stmt, int conn_id)
 Connects statement sequence to next statement and sets stop bit.
static int statement_get_last_line_helper (statement *stmt, statement *base)
int statement_get_last_line (statement *stmt)
 Calculates the last line of the specified statement tree.
void statement_find_rhs_sigs (statement *stmt, str_link **head, str_link **tail)
 Creates a list of all signals on the RHS of expressions in the given statement block.
statementstatement_find_statement (statement *curr, int id)
 Searches for statement with ID in the given statement block.
bool statement_contains_expr_calling_stmt (statement *curr, statement *stmt)
 Searches the specified statement block for expression that calls the given stmt.
void statement_dealloc_recursive (statement *stmt, bool rm_stmt_blk)
void statement_dealloc (statement *stmt)
 Deallocates statement memory and associated expression tree from the heap.

Variables

char user_msg [USER_MSG_LENGTH]
exp_info exp_op_info [EXP_OP_NUM]
static stmt_loop_linkstmt_loop_head = NULL
static stmt_loop_linkstmt_loop_tail = NULL

Detailed Description

Author:
Trevor Williams (phase1geo@gmail.com)
Date:
5/1/2002
Statements are used to indicate flow of execution for a given always or initial block. Each statement is assigned to exactly one expression tree and it contains a pointer to the next statement if its expression tree evaluates to TRUE (non-zero value) or FALSE (zero value).
The head bit indicates that this statement should be loaded into the pre-simulation statement queue if any of its expressions change value in the current timestep. To begin with, the first statement in the always/initial block has this bit set, all other statements have this bit cleared.
The stop bits are used for CDD output. If a statement has these bits set, it will not traverse its next_true or next_false, respectively, paths when outputting. This is necessary when statement paths merge back to the same path or when statement loops are encountered. If this bit was not used, the statements output after the merge/loop would be output more than once. Consider the following Verilog code snippet:
 intial begin
        a = 0;
        if( a )
          b = 1;
        else
          b = 0;
        c = a | b;
 end
In this example there are five statements. They are the following:
  1.  a = 0; 
    
  2.  if( a ) 
    
  3.  b = 1; 
    
  4.  b = 0; 
    
  5.  c = a | b; 
    
Notice that the if statement has two paths. If a is TRUE, statement 3 is executed; otherwise, statement 4 is executed. Both statements 3 and 4 then merge to execute statement 5. If the entire statement tree were printed without a STOP bit, you can see that statement 5 would be output twice; once for the TRUE branch and once for the FALSE branch.
To eliminate this redundancy, the stop_true and stop_false bits are set on statement 4. The last statement of a TRUE path before merging always gets its stop bit set. Additionally, once a statement gets its stop bit set by the parser, this value must be maintained (never cleared).
Cyclic Statement Trees
Many times a statement tree will "loopback" on itself. These statement trees are considered to be cyclic in nature and, as such, must have leaf statements of the statement tree tied to the first statement of the tree. The following Verilog constructs have cyclic behavior: always, forever, for, repeat, and while.
Traversing Statement Tree
Starting at the head statement, the value of the head statement is determined to be TRUE or FALSE. If the value is TRUE (non-zero), the next_true path is taken. If the value is FALSE (zero), the next_false path is taken. For statements that express an assignment (or other statements that do not branch), both the next_true and next_false paths point to the same statement. For statements that express a wait-for-event (ex. wait, @, etc.), the next_true pointer will point to the next statement in the tree; however, the next_false pointer will point to NULL. This NULL assignment indicates to the statement simulation engine that this statement will receive the head bit and the current statement tree is finished for this timestep.

Function Documentation

void statement_assign_expr_ids ( statement stmt,
func_unit funit 
)

Assigns unique expression IDs to each expression in the given statement block.

Parameters:
stmt Pointer to statement block to traverse
funit Pointer to functional unit containing this statement block
Exceptions:
anonymous statement_assign_expr_ids statement_assign_expr_ids statement_assign_expr_ids expression_assign_expr_ids

Recursively traverses the entire statement block and assigns unique expression IDs for each expression tree that it finds.

References statement_s::exp, expression_assign_expr_ids(), statement_s::next_false, statement_s::next_true, statement_s::part, PROFILE, PROFILE_END, statement_assign_expr_ids(), and statement_s::suppl.

Referenced by gen_item_assign_ids(), and statement_assign_expr_ids().

00561   { PROFILE(STATEMENT_ASSIGN_EXPR_IDS);
00562 
00563   if( stmt != NULL ) {
00564 
00565     /* Assign unique expression IDs */
00566     expression_assign_expr_ids( stmt->exp, funit );
00567 
00568     /* Traverse down the rest of the statement block */
00569     if( (stmt->next_true == stmt->next_false) && (stmt->suppl.part.stop_true == 0) ) {
00570       statement_assign_expr_ids( stmt->next_true, funit );
00571     } else {
00572       if( stmt->suppl.part.stop_false == 0 ) {
00573         statement_assign_expr_ids( stmt->next_false, funit );
00574       }
00575       if( stmt->suppl.part.stop_true == 0 ) {
00576         statement_assign_expr_ids( stmt->next_true, funit );
00577       }
00578     }
00579 
00580   }
00581 
00582   PROFILE_END;
00583 
00584 }

bool statement_connect ( statement curr_stmt,
statement next_stmt,
int  conn_id 
)

Connects statement sequence to next statement and sets stop bit.

Parameters:
curr_stmt Pointer to statement sequence to traverse.
next_stmt Pointer to statement to connect ends to.
conn_id Current connection identifier (used to eliminate infinite looping and connection overwrite)
Returns:
Returns TRUE if statement was connected to the given statement list; otherwise, returns FALSE.

Recursively traverses the specified stmt sequence. When it reaches a statement that has either next_true or next_false set to NULL, sets next_true and/or next_false of that statement to point to the next_stmt statement.

References statement_s::conn_id, statement_s::exp, EXPR_IS_CONTEXT_SWITCH, FALSE, statement_s::next_false, statement_s::next_true, statement_s::part, PROFILE, PROFILE_END, statement_connect(), statement_s::suppl, and TRUE.

Referenced by db_statement_connect(), and statement_connect().

00612   { PROFILE(STATEMENT_CONNECT);
00613 
00614   bool retval = FALSE;  /* Return value for this function */
00615 
00616   assert( curr_stmt != NULL );
00617   assert( next_stmt != NULL );
00618 
00619   /* Specify that this statement has been traversed */
00620   curr_stmt->conn_id = conn_id;
00621 
00622   //display( "In statement_connect", curr_stmt, next_stmt, conn_id );
00623 
00624   /* If both paths go to the same destination, only parse one path */
00625   if( curr_stmt->next_true == curr_stmt->next_false ) {
00626     
00627     /* If the TRUE path is NULL, connect it to the new statement */
00628     if( curr_stmt->next_true == NULL ) {
00629       //display( "Setting next_true to next_stmt", curr_stmt, next_stmt, conn_id );
00630       curr_stmt->next_true  = next_stmt;
00631       /* If the current statement is a wait statement, don't connect next_false path */
00632       if( !EXPR_IS_CONTEXT_SWITCH( curr_stmt->exp ) ) {
00633         //display( "Setting next_false to next_stmt", curr_stmt, next_stmt, conn_id );
00634         curr_stmt->next_false = next_stmt;
00635       }
00636       if( curr_stmt->next_true->conn_id == conn_id ) {
00637         //display( "Setting stop_true and stop_false", curr_stmt, next_stmt, conn_id );
00638         curr_stmt->suppl.part.stop_true  = 1;
00639         curr_stmt->suppl.part.stop_false = 1;
00640       } else {
00641         curr_stmt->next_true->conn_id = conn_id;
00642       }
00643       retval = TRUE;
00644     /* If the TRUE path leads to a loop/merge, set the stop bit and stop traversing */
00645     } else if( curr_stmt->next_true->conn_id == conn_id ) {
00646       //display( "Setting stop_true and stop_false", curr_stmt, next_stmt, conn_id );
00647       curr_stmt->suppl.part.stop_true  = 1;
00648       curr_stmt->suppl.part.stop_false = 1;
00649     /* Continue to traverse the TRUE path if the next_stmt does not match this statement */
00650     } else if( curr_stmt->next_true != next_stmt ) {
00651       //display( "Traversing next_true path", curr_stmt, next_stmt, conn_id );
00652       retval |= statement_connect( curr_stmt->next_true, next_stmt, conn_id );
00653     }
00654 
00655   } else {
00656 
00657     /* Traverse FALSE path */
00658     if( curr_stmt->next_false == NULL ) {
00659       if( !EXPR_IS_CONTEXT_SWITCH( curr_stmt->exp ) ) {
00660         //display( "Setting next_false to next_stmt", curr_stmt, next_stmt, conn_id );
00661         curr_stmt->next_false = next_stmt;
00662         if( curr_stmt->next_false->conn_id == conn_id ) {
00663           //display( "Setting stop_false", curr_stmt, next_stmt, conn_id );
00664           curr_stmt->suppl.part.stop_false = 1;
00665         } else {
00666           curr_stmt->next_false->conn_id = conn_id; 
00667         }
00668         retval = TRUE;
00669       }
00670     /* If the FALSE path leads to a loop/merge, set the stop bit and stop traversing */
00671     } else if( curr_stmt->next_false->conn_id == conn_id ) {
00672       //display( "Setting stop_false", curr_stmt, next_stmt, conn_id );
00673       curr_stmt->suppl.part.stop_false = 1;
00674     /* Continue to traverse the FALSE path if the next statement does not match this statement */
00675     } else if( (curr_stmt->next_false != next_stmt) ) {
00676       //display( "Traversing next_false path", curr_stmt, next_stmt, conn_id );
00677       retval |= statement_connect( curr_stmt->next_false, next_stmt, conn_id );
00678     }
00679 
00680     /* Traverse TRUE path */
00681     if( curr_stmt->next_true == NULL ) {
00682       //display( "Setting next_true to next_stmt", curr_stmt, next_stmt, conn_id );
00683       curr_stmt->next_true = next_stmt;
00684       if( curr_stmt->next_true->conn_id == conn_id ) {
00685         //display( "Setting stop_true", curr_stmt, next_stmt, conn_id );
00686         curr_stmt->suppl.part.stop_true = 1;
00687       } else {
00688         curr_stmt->next_true->conn_id = conn_id;
00689       }
00690       retval = TRUE;
00691     /* If the TRUE path leads to a loop/merge, set the stop bit and stop traversing */
00692     } else if( curr_stmt->next_true->conn_id == conn_id ) {
00693       //display( "Setting stop_true", curr_stmt, next_stmt, conn_id );
00694       curr_stmt->suppl.part.stop_true = 1;
00695     /* Continue to traverse the TRUE path if the next statement does not match this statement */
00696     } else if( curr_stmt->next_true != next_stmt ) {
00697       //display( "Traversing next_true path", curr_stmt, next_stmt, conn_id );
00698       retval |= statement_connect( curr_stmt->next_true, next_stmt, conn_id );
00699     }
00700 
00701   }
00702 
00703   PROFILE_END;
00704 
00705   return( retval );
00706 
00707 }

bool statement_contains_expr_calling_stmt ( statement curr,
statement stmt 
)

Searches the specified statement block for expression that calls the given stmt.

Returns:
Returns TRUE if the given statement contains the given expression; otherwise, returns FALSE.
Parameters:
curr Pointer to current statement to traverse
stmt Pointer to statement to find in the associated expression tree

References statement_s::exp, expression_contains_expr_calling_stmt(), statement_s::next_false, statement_s::next_true, statement_s::part, PROFILE, PROFILE_END, statement_contains_expr_calling_stmt(), and statement_s::suppl.

Referenced by funit_remove_stmt_blks_calling_stmt(), gen_item_remove_if_contains_expr_calling_stmt(), and statement_contains_expr_calling_stmt().

00876   { PROFILE(STATEMENT_CONTAINS_EXPR_CALLING_STMT);
00877 
00878   bool contains = (curr != NULL) &&
00879                   (expression_contains_expr_calling_stmt( curr->exp, stmt ) ||
00880                   ((curr->suppl.part.stop_true == 0) &&
00881                     statement_contains_expr_calling_stmt( curr->next_true, stmt )) ||
00882                   ((curr->next_false != curr->next_false) &&
00883                    (curr->suppl.part.stop_false == 0) &&
00884                     statement_contains_expr_calling_stmt( curr->next_false, stmt )));
00885 
00886   PROFILE_END;
00887 
00888   return( contains );
00889 
00890 }

statement* statement_create ( expression exp,
func_unit funit,
unsigned int  ppline 
)

Creates new statement structure.

Returns:
Returns pointer to the newly created statement.

Creates a new statement structure from heap memory and initializes it with the specified parameter information.

Parameters:
exp Pointer to root expression of expression tree for this statement
funit Pointer to functional unit that this statement exists in
ppline File line from the preprocessed file

References statement_s::all, statement_s::conn_id, statement_s::exp, statement_s::funit, statement_s::head, malloc_safe, statement_s::next_false, statement_s::next_true, expression_s::parent, statement_s::ppline, PROFILE, PROFILE_END, expr_stmt_u::stmt, and statement_s::suppl.

Referenced by db_create_statement(), fsm_arg_parse_state(), and statement_db_read().

00138   { PROFILE(STATEMENT_CREATE);
00139 
00140   statement* stmt;  /* Pointer to newly created statement */
00141 
00142   stmt                    = (statement*)malloc_safe( sizeof( statement ) );
00143   stmt->exp               = exp;
00144   stmt->exp->parent->stmt = stmt;
00145   stmt->next_true         = NULL;
00146   stmt->next_false        = NULL;
00147   stmt->head              = NULL;
00148   stmt->conn_id           = 0;
00149   stmt->suppl.all         = 0;
00150   stmt->funit             = funit;
00151   stmt->ppline            = ppline;
00152 
00153   PROFILE_END;
00154 
00155   return( stmt );
00156 
00157 }

void statement_db_read ( char **  line,
func_unit curr_funit,
int  read_mode 
)

Reads in statement line from specified string and stores statement in specified functional unit.

Parameters:
line Pointer to current line of file being read.
curr_funit Pointer to current module.
read_mode If set to REPORT, adds statement to head of list; otherwise, adds statement to tail.
Exceptions:
anonymous Throw Throw

Reads in the contents of the statement from the specified line, creates a statement structure to hold the contents.

References statement_s::all, exp_link_s::exp, func_unit_s::exp_head, exp_link_find(), FALSE, FATAL, func_unit_s::first_stmt, FUNIT_AFUNCTION, FUNIT_ANAMED_BLOCK, FUNIT_ATASK, FUNIT_FUNCTION, FUNIT_NAMED_BLOCK, FUNIT_TASK, statement_s::head, statement_s::next_false, statement_s::next_true, statement_s::part, print_output(), PROFILE, PROFILE_END, READ_MODE_NO_MERGE, sim_add_thread(), statement_create(), statement_queue_add(), statement_queue_compare(), stmt_link_s::stmt, func_unit_s::stmt_head, stmt_link_add(), stmt_link_find(), func_unit_s::stmt_tail, statement_s::suppl, Throw, TRUE, and func_unit_s::type.

Referenced by db_read(), and funit_db_mod_merge().

00436   { PROFILE(STATEMENT_DB_READ);
00437 
00438   int          id;             /* ID of root expression that is associated with this statement */
00439   int          true_id;        /* ID of root expression that is associated with the next_true statement */
00440   int          false_id;       /* ID of root expression that is associated with the next_false statement */
00441   int          head_id;
00442   statement*   stmt;           /* Pointer to newly created statement */
00443   exp_link*    expl;           /* Pointer to found expression link */
00444   stmt_link*   stmtl;          /* Pointer to found statement link */
00445   int          chars_read;     /* Number of characters read from line */
00446   uint32       suppl;          /* Supplemental field value */
00447   unsigned int ppline;         /* Preprocessor file line */
00448   uint32       first_col;     /* First column */
00449 
00450   if( sscanf( *line, "%d %u %u %x %d %d %d%n", &id, &ppline, &first_col, &suppl, &true_id, &false_id, &head_id, &chars_read ) == 7 ) {
00451 
00452     *line = *line + chars_read;
00453 
00454     if( curr_funit == NULL ) {
00455 
00456       print_output( "Internal error:  statement in database written before its functional unit", FATAL, __FILE__, __LINE__ );
00457       Throw 0;
00458 
00459     } else {
00460 
00461       /* Find associated root expression */
00462       expl = exp_link_find( id, curr_funit->exp_head );
00463       assert( expl != NULL );
00464 
00465       stmt = statement_create( expl->exp, curr_funit, ppline );
00466       stmt->suppl.all = suppl;
00467 
00468       /*
00469        If this statement is a head statement and the current functional unit is a task, function or named block,
00470        set the curr_funit->first_stmt pointer to this statement.
00471       */
00472       if( (stmt->suppl.part.head == 1) &&
00473           ((curr_funit->type == FUNIT_TASK)        ||
00474            (curr_funit->type == FUNIT_ATASK)       ||
00475            (curr_funit->type == FUNIT_FUNCTION)    ||
00476            (curr_funit->type == FUNIT_AFUNCTION)   ||
00477            (curr_funit->type == FUNIT_NAMED_BLOCK) ||
00478            (curr_funit->type == FUNIT_ANAMED_BLOCK)) ) {
00479         curr_funit->first_stmt = stmt;
00480       }
00481 
00482       /* Find and link next_true */
00483       if( true_id == id ) {
00484         stmt->next_true = stmt;
00485       } else if( true_id != 0 ) {
00486         stmtl = stmt_link_find( true_id, curr_funit->stmt_head );
00487         if( stmtl == NULL ) {
00488           /* Add to statement loop queue */
00489           statement_queue_add( stmt, true_id, 0 );
00490         } else {
00491           stmt->next_true = stmtl->stmt;
00492         }
00493         /* Check against statement queue */
00494         statement_queue_compare( stmt );
00495       }
00496 
00497       /* Find and link next_false */
00498       if( false_id == id ) {
00499         stmt->next_false = stmt;
00500       } else if( false_id != 0 ) {
00501         stmtl = stmt_link_find( false_id, curr_funit->stmt_head );
00502         if( stmtl == NULL ) {
00503           statement_queue_add( stmt, false_id, 1 );
00504         } else {
00505           stmt->next_false = stmtl->stmt;
00506         }
00507         statement_queue_compare( stmt );
00508       }
00509 
00510       /* Find and link head */
00511       if( head_id == id ) {
00512         stmt->head = stmt;
00513       } else if( head_id != 0 ) {
00514         stmtl = stmt_link_find( head_id, curr_funit->stmt_head );
00515         if( stmtl == NULL ) {
00516           statement_queue_add( stmt, head_id, 2 );
00517         } else {
00518           stmt->head = stmtl->stmt;
00519         }
00520         statement_queue_compare( stmt );
00521       }
00522 
00523       /* Add the statement to the functional unit list */
00524       (void)stmt_link_add( stmt, TRUE, &(curr_funit->stmt_head), &(curr_funit->stmt_tail) );
00525 
00526       /*
00527        Possibly add statement to presimulation queue (if the current functional unit is a task
00528        or function, do not add this to the presimulation queue (this will be added when the expression
00529        is called.
00530       */
00531       if( (read_mode == READ_MODE_NO_MERGE) && (stmt->suppl.part.is_called == 0) ) {
00532         sim_time tmp_time = {0,0,0,FALSE};
00533         (void)sim_add_thread( NULL, stmt, curr_funit, &tmp_time );
00534       }
00535 
00536     }
00537 
00538   } else {
00539 
00540     print_output( "Unable to read statement value", FATAL, __FILE__, __LINE__ );
00541     Throw 0;
00542 
00543   }
00544 
00545   PROFILE_END;
00546 
00547 }

void statement_db_write ( statement stmt,
FILE *  ofile,
bool  ids_issued 
)

Writes specified statement to the specified output file.

Recursively writes the contents of the specified statement tree (and its associated expression trees to the specified output stream.

Parameters:
stmt Pointer to statement to write out value
ofile Pointer to output file to write statement line to
ids_issued Specifies that IDs were issued just prior to calling this function

References statement_s::all, expression_s::col, DB_TYPE_STATEMENT, statement_s::exp, expression_get_id(), statement_s::head, statement_s::next_false, statement_s::next_true, expression_s::part, statement_s::ppline, PROFILE, PROFILE_END, and statement_s::suppl.

Referenced by funit_db_write(), and statement_db_write_tree().

00332   { PROFILE(STATEMENT_DB_WRITE);
00333 
00334   assert( stmt != NULL );
00335 
00336   /* Write out contents of this statement last */
00337   fprintf( ofile, "%d %d %u %u %x %d %d %d",
00338     DB_TYPE_STATEMENT,
00339     expression_get_id( stmt->exp, ids_issued ),
00340     stmt->ppline,
00341     stmt->exp->col.part.first,
00342     (stmt->suppl.all & 0xff),
00343     ((stmt->next_true   == NULL) ? 0 : expression_get_id( stmt->next_true->exp, ids_issued )),
00344     ((stmt->next_false  == NULL) ? 0 : expression_get_id( stmt->next_false->exp, ids_issued )),
00345     ((stmt->head        == NULL) ? 0 : expression_get_id( stmt->head->exp, ids_issued ))
00346   );
00347 
00348   fprintf( ofile, "\n" );
00349 
00350   PROFILE_END;
00351 
00352 }

void statement_db_write_expr_tree ( statement stmt,
FILE *  ofile 
)

Writes specified expression trees for given statement block to specified output file.

Parameters:
stmt Pointer to specified statement tree to display
ofile Pointer to output file to write

Traverses the specified statement block, writing all expression trees to specified output file.

References statement_s::exp, expression_db_write_tree(), statement_s::next_false, statement_s::next_true, statement_s::part, PROFILE, PROFILE_END, statement_db_write_expr_tree(), and statement_s::suppl.

Referenced by gen_item_db_write_expr_tree(), and statement_db_write_expr_tree().

00397   { PROFILE(STATEMENT_DB_WRITE_EXPR_TREE);
00398 
00399   if( stmt != NULL ) {
00400 
00401     /* Output ourselves first */
00402     expression_db_write_tree( stmt->exp, ofile );
00403 
00404     /* Traverse down the rest of the statement block */
00405     if( (stmt->next_true == stmt->next_false) && (stmt->suppl.part.stop_true == 0) ) {
00406       statement_db_write_expr_tree( stmt->next_true, ofile );
00407     } else {
00408       if( stmt->suppl.part.stop_false == 0 ) {
00409         statement_db_write_expr_tree( stmt->next_false, ofile );
00410       }
00411       if( stmt->suppl.part.stop_true == 0 ) {
00412         statement_db_write_expr_tree( stmt->next_true, ofile );
00413       }
00414     }
00415 
00416   }
00417 
00418   PROFILE_END;
00419 
00420 }

void statement_db_write_tree ( statement stmt,
FILE *  ofile 
)

Writes specified statement tree to the specified output file.

Parameters:
stmt Pointer to root of statement tree to output
ofile Pointer to output file to write statements to

Traverses specified statement tree, outputting all statements within that tree.

References statement_s::next_false, statement_s::next_true, statement_s::part, PROFILE, PROFILE_END, statement_db_write(), statement_db_write_tree(), statement_s::suppl, and TRUE.

Referenced by gen_item_db_write(), and statement_db_write_tree().

00363   { PROFILE(STATEMENT_DB_WRITE_TREE);
00364 
00365   if( stmt != NULL ) {
00366 
00367     /* Traverse down the rest of the statement block */
00368     if( (stmt->next_true == stmt->next_false) && (stmt->suppl.part.stop_true == 0) ) {
00369       statement_db_write_tree( stmt->next_true, ofile );
00370     } else {
00371       if( stmt->suppl.part.stop_false == 0 ) {
00372         statement_db_write_tree( stmt->next_false, ofile );
00373       }
00374       if( stmt->suppl.part.stop_true == 0 ) {
00375         statement_db_write_tree( stmt->next_true, ofile );
00376       }
00377     }
00378 
00379     /* Output ourselves first */
00380     statement_db_write( stmt, ofile, TRUE );
00381 
00382   }
00383 
00384   PROFILE_END;
00385 
00386 }

void statement_dealloc ( statement stmt  ) 

Deallocates statement memory and associated expression tree from the heap.

Deallocates specified statement from heap memory. Does not remove attached expression (this is assumed to be cleaned up by the expression list removal function).

Parameters:
stmt Pointer to statement to deallocate

References free_safe, PROFILE, and PROFILE_END.

Referenced by db_create_statement(), fsm_var_cleanup(), and stmt_link_delete_list().

00951   { PROFILE(STATEMENT_DEALLOC);
00952 
00953   if( stmt != NULL ) {
00954  
00955     /* Finally, deallocate this statement */
00956     free_safe( stmt, sizeof( statement ) );
00957 
00958   }
00959 
00960   PROFILE_END;
00961 
00962 }

void statement_dealloc_recursive ( statement stmt,
bool  rm_stmt_blk 
)

Recursively deallocates specified statement tree.

Parameters:
stmt Pointer to head of statement tree to deallocate
rm_stmt_blk If set to TRUE, removes the statement block this statement points to (if any)

References db_remove_statement_from_current_funit(), expression_s::elem, ESUPPL_TYPE, ETYPE_FUNIT, statement_s::exp, EXP_OP_FORK, EXP_OP_NB_CALL, func_unit_s::first_stmt, free_safe, expression_s::funit, FUNIT_NO_SCORE, statement_s::next_false, statement_s::next_true, expression_s::op, statement_s::part, PROFILE, PROFILE_END, statement_dealloc_recursive(), stmt_blk_add_to_remove_list(), statement_s::suppl, expression_s::suppl, and func_unit_s::type.

Referenced by db_remove_statement(), gen_item_dealloc(), statement_dealloc_recursive(), and stmt_blk_remove().

00898   { PROFILE(STATEMENT_DEALLOC_RECURSIVE);
00899     
00900   if( stmt != NULL ) {
00901   
00902     assert( stmt->exp != NULL );
00903 
00904     /* If we are a named block or fork call statement, remove that statement block */
00905     if( (stmt->exp->op == EXP_OP_NB_CALL) || (stmt->exp->op == EXP_OP_FORK) ) {
00906 
00907       if( rm_stmt_blk && (ESUPPL_TYPE( stmt->exp->suppl ) == ETYPE_FUNIT) && (stmt->exp->elem.funit->type != FUNIT_NO_SCORE) ) {
00908         stmt_blk_add_to_remove_list( stmt->exp->elem.funit->first_stmt );
00909       }
00910 
00911     }
00912 
00913     /* Remove TRUE path */
00914     if( stmt->next_true == stmt->next_false ) {
00915 
00916       if( stmt->suppl.part.stop_true == 0 ) {
00917         statement_dealloc_recursive( stmt->next_true, rm_stmt_blk );
00918       }
00919 
00920     } else {
00921 
00922       if( stmt->suppl.part.stop_true == 0 ) {
00923         statement_dealloc_recursive( stmt->next_true, rm_stmt_blk );
00924       }
00925   
00926       /* Remove FALSE path */
00927       if( stmt->suppl.part.stop_false == 0 ) {
00928         statement_dealloc_recursive( stmt->next_false, rm_stmt_blk );
00929       }
00930 
00931     }
00932 
00933     /* Disconnect statement from current functional unit */
00934     db_remove_statement_from_current_funit( stmt );
00935 
00936     free_safe( stmt, sizeof( statement ) );
00937     
00938   }
00939 
00940   PROFILE_END;
00941   
00942 }

void statement_find_rhs_sigs ( statement stmt,
str_link **  head,
str_link **  tail 
)

Creates a list of all signals on the RHS of expressions in the given statement block.

Searches the specified statement block and returns a list of all signals on the right-hand-side of expressions.

Parameters:
stmt Pointer to current statement block to traverse
head Pointer to head of signal name list that will contain a list of all RHS signals
tail Pointer to tail of signal name list that will contain a list of all RHS signals

References expression_s::elem, statement_s::exp, EXP_OP_FORK, EXP_OP_NB_CALL, expression_find_rhs_sigs(), func_unit_s::first_stmt, expression_s::funit, statement_s::next_false, statement_s::next_true, expression_s::op, statement_s::part, PROFILE, PROFILE_END, statement_find_rhs_sigs(), and statement_s::suppl.

Referenced by db_create_sensitivity_list(), and statement_find_rhs_sigs().

00780   { PROFILE(STATEMENT_FIND_RHS_SIGS);
00781 
00782   if( stmt != NULL ) {
00783 
00784     if( (stmt->exp->op == EXP_OP_NB_CALL) || (stmt->exp->op == EXP_OP_FORK) ) {
00785 
00786       statement_find_rhs_sigs( stmt->exp->elem.funit->first_stmt, head, tail );
00787 
00788     } else {
00789 
00790       /* Find all RHS signals in this statement's expression tree */
00791       expression_find_rhs_sigs( stmt->exp, head, tail );
00792 
00793     }
00794 
00795     /* If both true and false paths lead to same statement, just traverse the true path */
00796     if( stmt->next_true == stmt->next_false ) {
00797 
00798       if( stmt->suppl.part.stop_true == 0 ) {
00799         statement_find_rhs_sigs( stmt->next_true, head, tail );
00800       }
00801 
00802     /* Otherwise, traverse both true and false paths */
00803     } else {
00804 
00805       if( stmt->suppl.part.stop_true == 0 ) {
00806         statement_find_rhs_sigs( stmt->next_true, head, tail );
00807       }
00808 
00809       if( stmt->suppl.part.stop_false == 0 ) {
00810         statement_find_rhs_sigs( stmt->next_false, head, tail );
00811       }
00812 
00813     }
00814 
00815   }
00816 
00817   PROFILE_END;
00818 
00819 }

statement* statement_find_statement ( statement curr,
int  id 
)

Searches for statement with ID in the given statement block.

Returns:
Returns a pointer to the found statement found within the given statement block. If the statement ID could not be found, returns NULL.

Recursively searches the given statement block for the expression that matches the given ID.

Parameters:
curr Pointer to current statement in statement block being evaluated
id Statement ID to find

References statement_s::exp, expression_s::id, statement_s::next_false, statement_s::next_true, statement_s::part, PROFILE, PROFILE_END, statement_find_statement(), and statement_s::suppl.

Referenced by generate_remove_stmt_helper(), and statement_find_statement().

00831   { PROFILE(STATEMENT_FIND_STATEMENT);
00832 
00833   statement* found = NULL;  /* Pointer to found statement */
00834 
00835   if( curr != NULL ) {
00836 
00837     if( curr->exp->id == id ) {
00838 
00839       found = curr;
00840 
00841     } else {
00842 
00843       /* If both true and false paths lead to same item, just traverse the true path */
00844       if( curr->next_true == curr->next_false ) {
00845 
00846         if( curr->suppl.part.stop_true == 0 ) {
00847           found = statement_find_statement( curr->next_true, id );
00848         }
00849 
00850       /* Otherwise, traverse both true and false paths */
00851       } else if( (curr->suppl.part.stop_true == 0) &&
00852                  ((found = statement_find_statement( curr->next_true, id )) == NULL) ) {
00853 
00854         if( curr->suppl.part.stop_false == 0 ) {
00855           found = statement_find_statement( curr->next_false, id );
00856         }
00857 
00858       }
00859 
00860     }
00861 
00862   }
00863 
00864   PROFILE_END;
00865 
00866   return( found );
00867 
00868 }

int statement_get_last_line ( statement stmt  ) 

Calculates the last line of the specified statement tree.

Returns:
Returns the last line number in the given statement.
Parameters:
stmt Pointer to statement to get last line number for

References PROFILE, PROFILE_END, and statement_get_last_line_helper().

Referenced by race_handle_race_condition().

00762   { PROFILE(STATEMENT_GET_LAST_LINE);
00763 
00764   int retval = statement_get_last_line_helper( stmt, stmt );
00765 
00766   PROFILE_END;
00767 
00768   return( retval );
00769 
00770 }

static int statement_get_last_line_helper ( statement stmt,
statement base 
) [static]
Parameters:
stmt Pointer to current statement to look at.
base Pointer to root statement in statement tree.
Returns:
Returns the last line number of the specified statement tree.

Recursively iterates through the specified statement tree searching for the last statement in each false/true path (the one whose next pointer points to the head statement). Once it is found, its expression is parsed for its last line and this value is returned. If both the false and tru paths have been parsed, the highest numbered line is returned.

References statement_s::exp, expression_get_last_line_expr(), expression_s::line, statement_s::next_false, statement_s::next_true, statement_s::part, PROFILE, PROFILE_END, and statement_s::suppl.

Referenced by statement_get_last_line().

00724   { PROFILE(STATEMENT_GET_LAST_LINE_HELPER);
00725 
00726   expression* last_exp;         /* Pointer to last expression in the statement tree */
00727   int         last_false = -1;  /* Last false path line number */ 
00728   int         last_true  = -1;  /* Last true path line number */
00729 
00730   if( stmt != NULL ) {
00731 
00732     /* Check out/traverse false path */
00733     if( (stmt->next_false == NULL) || (stmt->next_false == base) ) {
00734       last_exp   = expression_get_last_line_expr( stmt->exp );
00735       last_false = last_exp->line;
00736     } else if( stmt->suppl.part.stop_false == 0 ) {
00737       last_false = statement_get_last_line_helper( stmt->next_false, base );
00738     }
00739 
00740     /* Check out/traverse true path */
00741     if( (stmt->next_true == NULL) || (stmt->next_true == base) ) {
00742       last_exp  = expression_get_last_line_expr( stmt->exp );
00743       last_true = last_exp->line;
00744     } else if( stmt->suppl.part.stop_true == 0 ) {
00745       last_true = statement_get_last_line_helper( stmt->next_true, base );
00746     }
00747 
00748   }
00749 
00750   PROFILE_END;
00751 
00752   /* Return the greater of the two path last lines */
00753   return( (last_false > last_true) ? last_false : last_true );
00754 
00755 }

static void statement_queue_add ( statement stmt,
int  id,
int  type 
) [static]
Parameters:
stmt Pointer of statement waiting to be linked.
id ID of statement to be read out later.
next_true Set to TRUE if the specified ID is for the next_true statement.

Creates a new statement loop link for the specified parameters and adds this element to the top of the statement loop queue.

References stmt_loop_link_s::id, malloc_safe, stmt_loop_link_s::next, PROFILE, PROFILE_END, stmt_loop_link_s::stmt, and stmt_loop_link_s::type.

Referenced by statement_db_read().

00195   { PROFILE(STATEMENT_QUEUE_ADD);
00196 
00197   stmt_loop_link* sll;  /* Pointer to newly created statement loop link */
00198 
00199   /* Create statement loop link element */
00200   sll = (stmt_loop_link*)malloc_safe( sizeof( stmt_loop_link ) );
00201 
00202   /* Populate statement loop link with specified parameters */
00203   sll->stmt = stmt;
00204   sll->id   = id;
00205   sll->type = type;
00206   sll->next = NULL;
00207 
00208   /* Add to top of statement loop queue */
00209   if( stmt_loop_head == NULL ) {
00210     stmt_loop_head = stmt_loop_tail = sll;
00211   } else {
00212     stmt_loop_tail->next = sll;
00213     stmt_loop_tail       = sll;
00214   }
00215 
00216   PROFILE_END;
00217 
00218 }

static void statement_queue_compare ( statement stmt  )  [static]
Parameters:
stmt Pointer to statement being read out of the CDD.

Compares the specified statement against the top of the statement loop queue. If an ID in the queue matches this statement's ID, the element is removed and the next_true and next_false pointers of the stored statement are pointed to the specified statement. The next head is also compared against this statement and the process is repeated until a match is not found.

References statement_s::exp, free_safe, statement_s::head, stmt_loop_link_s::id, expression_s::id, stmt_loop_link_s::next, statement_s::next_false, statement_s::next_true, PROFILE, PROFILE_END, stmt_loop_link_s::stmt, and stmt_loop_link_s::type.

Referenced by statement_db_read().

00231   { PROFILE(STATEMENT_QUEUE_COMPARE);
00232 
00233   stmt_loop_link* sll;       /* Pointer to current element in statement loop list */
00234   stmt_loop_link* tsll;      /* Temporary pointer to current element in statement loop list */
00235   stmt_loop_link* last_sll;  /* Pointer to last parsed element in statement loop list */
00236 
00237   sll      = stmt_loop_head;
00238   last_sll = NULL;
00239 
00240   while( sll != NULL ) {
00241 
00242     /* If we have a match */
00243     if( stmt->exp->id == sll->id ) {
00244 
00245       /* Set next_true and next_false pointers */
00246       if( (sll->stmt->next_true == NULL) && (sll->type == 0) ) {
00247         sll->stmt->next_true = stmt;
00248       }
00249       if( (sll->stmt->next_false == NULL) && (sll->type == 1) ) {
00250         sll->stmt->next_false = stmt;
00251       }
00252       if( (sll->stmt->head == NULL) && (sll->type == 2) ) {
00253         sll->stmt->head = stmt;
00254       }
00255        
00256       /* Remove this element from the list */
00257       if( (stmt_loop_head == sll) && (stmt_loop_tail == sll) ) {
00258         stmt_loop_head = stmt_loop_tail = NULL;
00259       } else if( stmt_loop_head == sll ) {
00260         stmt_loop_head = sll->next;
00261       } else if( stmt_loop_tail == sll ) {
00262         stmt_loop_tail       = last_sll;
00263         stmt_loop_tail->next = NULL;
00264       } else {
00265         last_sll->next = sll->next;
00266       }
00267 
00268       /* Deallocate the current element */
00269       tsll = sll;
00270       sll  = sll->next;
00271       free_safe( tsll, sizeof( stmt_loop_link ) );
00272 
00273     } else {
00274 
00275       last_sll = sll;
00276       sll      = sll->next;
00277 
00278     }
00279 
00280   }
00281 
00282   PROFILE_END;
00283 
00284 }

void statement_queue_display (  ) 

Displays the current contents of the statement loop list for debug purposes only.

References statement_s::exp, expression_string(), stmt_loop_link_s::id, stmt_loop_link_s::next, stmt_loop_link_s::stmt, and stmt_loop_link_s::type.

00162                                {
00163 
00164   stmt_loop_link* sll;  /* Pointer to current statement loop link */
00165 
00166   printf( "Statement loop list:\n" );
00167 
00168   sll = stmt_loop_head;
00169   while( sll != NULL ) {
00170     printf( "  id: %d, type: %d, stmt: %s  ", sll->id, sll->type, expression_string( sll->stmt->exp ) );
00171     if( sll == stmt_loop_head ) {
00172       printf( "H" );
00173     }
00174     if( sll == stmt_loop_tail ) {
00175       printf( "T" );
00176     }
00177     printf( "\n" );
00178     sll = sll->next;
00179   }
00180 
00181 }

void statement_size_elements ( statement stmt,
func_unit funit 
)

Sizes all expressions for the given statement block.

Parameters:
stmt Pointer to statement block to size elements for
funit Pointer to functional unit containing this statement block
Exceptions:
anonymous expression_resize statement_size_elements statement_size_elements statement_size_elements

Recursively sizes all elements for the given statement block.

References statement_s::exp, expression_resize(), FALSE, statement_s::next_false, statement_s::next_true, statement_s::part, PROFILE, PROFILE_END, statement_size_elements(), statement_s::suppl, and TRUE.

Referenced by gen_item_resize_stmts_and_sigs(), and statement_size_elements().

00297   { PROFILE(STATEMENT_SIZE_ELEMENTS);
00298 
00299   if( stmt != NULL ) {
00300 
00301     /* Size the current statement */
00302     expression_resize( stmt->exp, funit, TRUE, FALSE );
00303 
00304     /* Iterate to the next statement */
00305     if( stmt->next_true == stmt->next_false ) {
00306       if( stmt->suppl.part.stop_true == 0 ) {
00307         statement_size_elements( stmt->next_true, funit );
00308       }
00309     } else {
00310       if( stmt->suppl.part.stop_false == 0 ) {
00311         statement_size_elements( stmt->next_false, funit );
00312       }
00313       if( stmt->suppl.part.stop_true == 0 ) {
00314         statement_size_elements( stmt->next_true, funit );
00315       }
00316     }
00317 
00318   }
00319 
00320   PROFILE_END;
00321 
00322 }


Variable Documentation

exp_info exp_op_info[EXP_OP_NUM]

Array containing static information about expression operation types. NOTE: This structure MUST be updated if a new expression is added! The third argument is an initialization to the exp_info_s structure.

stmt_loop_link* stmt_loop_head = NULL [static]

Pointer to head of statement loop list.

stmt_loop_link* stmt_loop_tail = NULL [static]

Pointer to tail of statement loop list.

char user_msg[USER_MSG_LENGTH]

Holds some output that will be displayed via the print_output command. This is created globally so that memory does not need to be reallocated for each function that wishes to use it.

Generated on Sun Nov 21 00:55:41 2010 for Covered by  doxygen 1.6.3