#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include "defines.h"
#include "expr.h"
#include "func_unit.h"
#include "instance.h"
#include "iter.h"
#include "link.h"
#include "reentrant.h"
#include "sim.h"
#include "util.h"
#include "vector.h"
#include "vsignal.h"
Functions | |
| void | sim_display_thread (const thread *thr, bool show_queue, bool endl) |
| Displays the given thread to standard output (for debug purposes only). | |
| void | sim_display_queue (thread *queue_head, thread *queue_tail) |
| void | sim_display_active_queue () |
| Displays the current state of the active queue (for debug purposes only). | |
| void | sim_display_delay_queue () |
| Displays the current state of the delay queue (for debug purposes only). | |
| void | sim_display_all_list () |
| Displays the state of all threads. | |
| thread * | sim_current_thread () |
| Returns a pointer to the current thread at the head of the active queue. | |
| void | sim_thread_pop_head () |
| void | sim_thread_insert_into_delay_queue (thread *thr, const sim_time *time) |
| Inserts the given thread into the delay queue at the given time slot. | |
| void | sim_thread_push (thread *thr, const sim_time *time) |
| Pushes given thread onto the active queue. | |
| void | sim_expr_changed (expression *expr, const sim_time *time) |
| Adds specified expression's statement to pre-simulation statement queue. | |
| thread * | sim_create_thread (thread *parent, statement *stmt, func_unit *funit) |
| thread * | sim_add_thread (thread *parent, statement *stmt, func_unit *funit, const sim_time *time) |
| Creates a thread for the given statement and adds it to the thread simulation queue. | |
| void | sim_kill_thread (thread *thr) |
| void | sim_kill_thread_with_funit (func_unit *funit) |
| Deallocates thread and removes it from parent and thread queue lists for specified functional unit. | |
| void | sim_add_statics () |
| bool | sim_expression (expression *expr, thread *thr, const sim_time *time, bool lhs) |
| Simulates a given expression tree, only performing needed operations as it traverses the tree. | |
| void | sim_thread (thread *thr, const sim_time *time) |
| Simulates one thread until it has either completed or enters a context switch. | |
| bool | sim_simulate (const sim_time *time) |
| Simulates current timestep. | |
| void | sim_initialize () |
| Initializes the simulator. | |
| void | sim_stop () |
| Causes the simulation to stop and enter into CLI mode. | |
| void | sim_finish () |
| Causes simulator to finish gracefully. | |
| void | sim_add_nonblock_assign (nonblock_assign *nba, int lhs_lsb, int lhs_msb, int rhs_lsb, int rhs_msb) |
| Updates the given non-blocking assign structure and adds it to the non-blocking assignment queue. | |
| void | sim_perform_nba (const sim_time *time) |
| Performs non-blocking assignment for currently queued assignment items for the current timestep. | |
| void | sim_dealloc () |
| Deallocates all memory for simulator. | |
Variables | |
| char | user_msg [USER_MSG_LENGTH] |
| bool | debug_mode |
| exp_info | exp_op_info [EXP_OP_NUM] |
| inst_link * | inst_head |
| bool | flag_use_command_line_debug |
| exp_link * | static_expr_head = NULL |
| exp_link * | static_expr_tail = NULL |
| thread * | all_head = NULL |
| thread * | all_tail = NULL |
| thread * | all_next = NULL |
| thread * | active_head = NULL |
| thread * | active_tail = NULL |
| thread * | delayed_head = NULL |
| thread * | delayed_tail = NULL |
| const char * | thread_state_str [4] = {"NONE", "ACTIVE", "DELAYED", "WAITING"} |
| bool | simulate = TRUE |
| bool | force_stop = FALSE |
| nonblock_assign ** | nba_queue = NULL |
| int | nba_queue_size = 0 |
| int | nba_queue_curr_size = 0 |
|
||||||||||||||||||||||||
|
Updates the given non-blocking assign structure and adds it to the non-blocking assignment queue. Updates and adds the given non-blocking assignment structure to the simulation queue.
01227 { PROFILE(SIM_ADD_NONBLOCK_ASSIGN);
01228
01229 /* Update the non-blocking assignment structure */
01230 nba->lhs_lsb = lhs_lsb;
01231 nba->lhs_msb = lhs_msb;
01232 nba->rhs_lsb = rhs_lsb;
01233 nba->rhs_msb = rhs_msb;
01234
01235 /* Add it to the simulation queue (if it has not been already) */
01236 if( nba->suppl.added == 0 ) {
01237 nba_queue[nba_queue_curr_size++] = nba;
01238 nba->suppl.added = 1;
01239 }
01240
01241 PROFILE_END;
01242
01243 }
|
|
|
Iterates through static expression list and causes the simulator to evaluate these expressions at simulation time.
00888 { PROFILE(SIM_ADD_STATICS);
00889
00890 exp_link* curr; /* Pointer to current expression link */
00891 sim_time time; /* Current simulation time */
00892
00893 /* Initialize the time to 0 */
00894 time.lo = 0;
00895 time.hi = 0;
00896 time.full = 0;
00897 time.final = FALSE;
00898
00899 curr = static_expr_head;
00900 while( curr != NULL ) {
00901 sim_expr_changed( curr->exp, &time );
00902 curr = curr->next;
00903 }
00904
00905 exp_link_delete_list( static_expr_head, FALSE );
00906 static_expr_head = static_expr_tail = NULL;
00907
00908 PROFILE_END;
00909
00910 }
|
|
||||||||||||||||||||
|
Creates a thread for the given statement and adds it to the thread simulation queue.
00662 { PROFILE(SIM_ADD_THREAD);
00663
00664 thread* thr = NULL; /* Pointer to added thread */
00665
00666 /* Only add expression if it is the head statement of its statement block */
00667 if( stmt->suppl.part.head == 1 ) {
00668
00669 /* Create thread, if needed */
00670 thr = sim_create_thread( parent, stmt, funit );
00671
00672 /* Initialize thread runtime components */
00673 thr->suppl.all = 0;
00674 thr->active_children = 0;
00675 thr->queue_prev = NULL;
00676 thr->queue_next = NULL;
00677
00678 /*
00679 If the parent thread is specified, update our current time, increment the number of active children in the parent
00680 and add ourselves between the parent thread and its next pointer.
00681 */
00682 if( thr->parent != NULL ) {
00683
00684 thr->curr_time = thr->parent->curr_time;
00685 thr->parent->active_children++;
00686
00687 /* Place ourselves between the parent and its queue_next pointer */
00688 thr->queue_next = thr->parent->queue_next;
00689 thr->parent->queue_next = thr;
00690 if( thr->queue_next == NULL ) {
00691 active_tail = thr;
00692 } else {
00693 thr->queue_next->queue_prev = thr;
00694 }
00695 thr->queue_prev = thr->parent;
00696 thr->suppl.part.state = THR_ST_ACTIVE; /* We will place the thread immediately into the active queue */
00697
00698 } else {
00699
00700 thr->curr_time = *time;
00701
00702 /*
00703 If this statement is an always_comb or always_latch, add it to the delay list and change its right
00704 expression so that it will be executed at time 0 after all initial and always blocks have completed
00705 */
00706 if( (thr->curr->exp->op == EXP_OP_ALWAYS_COMB) || (thr->curr->exp->op == EXP_OP_ALWAYS_LATCH) ) {
00707
00708 sim_time tmp_time;
00709
00710 /* Add this thread into the delay queue at time 0 */
00711 tmp_time.lo = 0;
00712 tmp_time.hi = 0;
00713 tmp_time.full = 0LL;
00714 tmp_time.final = FALSE;
00715 sim_thread_insert_into_delay_queue( thr, &tmp_time );
00716
00717 /* Specify that this block should be evaluated */
00718 thr->curr->exp->right->suppl.part.eval_t = 1;
00719
00720 } else {
00721
00722 /* If the statement block is specified as a final block, add it to the end of the delay queue */
00723 if( thr->curr->suppl.part.final == 1 ) {
00724
00725 sim_time tmp_time;
00726
00727 tmp_time.lo = 0xffffffff;
00728 tmp_time.hi = 0xffffffff;
00729 tmp_time.full = UINT64(0xffffffffffffffff);
00730 tmp_time.final = TRUE;
00731 sim_thread_insert_into_delay_queue( thr, &tmp_time );
00732
00733 /* Otherwise, add it to the active thread list */
00734 } else {
00735
00736 if( active_head == NULL ) {
00737 active_head = active_tail = thr;
00738 } else {
00739 thr->queue_prev = active_tail;
00740 active_tail->queue_next = thr;
00741 active_tail = thr;
00742 }
00743 thr->suppl.part.state = THR_ST_ACTIVE;
00744
00745 }
00746
00747 }
00748
00749 }
00750
00751 #ifdef DEBUG_MODE
00752 if( debug_mode && !flag_use_command_line_debug ) {
00753 printf( "Adding thread: " );
00754 sim_display_thread( thr, FALSE, TRUE );
00755 printf( "After thread is added to active queue...\n" );
00756 sim_display_active_queue();
00757 sim_display_all_list();
00758 }
00759 #endif
00760
00761 }
00762
00763 PROFILE_END;
00764
00765 return( thr );
00766
00767 }
|
|
||||||||||||||||
|
00600 { PROFILE(SIM_CREATE_THREAD);
00601
00602 thread* thr; /* Pointer to newly allocated thread */
00603
00604 /* If the next thread to use is empty, create a new one and add it to the end of the all pool */
00605 if( all_next == NULL ) {
00606
00607 /* Allocate the new thread */
00608 thr = (thread*)malloc_safe( sizeof( thread ) );
00609 thr->all_prev = NULL;
00610 thr->all_next = NULL;
00611
00612 /* Place newly allocated thread in the all_threads pool */
00613 if( all_head == NULL ) {
00614 all_head = all_tail = thr;
00615 } else {
00616 thr->all_prev = all_tail;
00617 all_tail->all_next = thr;
00618 all_tail = thr;
00619 }
00620
00621 /* Otherwise, select the next thread and advance the all_next pointer */
00622 } else {
00623
00624 thr = all_next;
00625 all_next = all_next->all_next;
00626
00627 }
00628
00629 /* Initialize the contents of the thread */
00630 thr->funit = funit;
00631 thr->parent = parent;
00632 thr->curr = stmt;
00633 thr->ren = NULL;
00634 thr->suppl.all = 0; /* Sets the current state of the thread to NONE */
00635 thr->curr_time.lo = 0;
00636 thr->curr_time.hi = 0;
00637 thr->curr_time.full = 0LL;
00638 thr->curr_time.final = FALSE;
00639 thr->queue_prev = NULL;
00640 thr->queue_next = NULL;
00641
00642 /* Add this thread to the given functional unit */
00643 funit_add_thread( funit, thr );
00644
00645 PROFILE_END;
00646
00647 return( thr );
00648
00649 }
|
|
|
Returns a pointer to the current thread at the head of the active queue.
00304 { PROFILE(SIM_CURRENT_THREAD);
00305
00306 return( active_head );
00307
00308 }
|
|
|
Deallocates all memory for simulator. Deallocates all allocated memory for simulation code.
01286 { PROFILE(SIM_DEALLOC);
01287
01288 thread* tmp; /* Temporary thread pointer */
01289
01290 /* Deallocate each thread in the all_threads array */
01291 while( all_head != NULL ) {
01292 tmp = all_head;
01293 all_head = all_head->all_next;
01294 free_safe( tmp, sizeof( thread ) );
01295 }
01296
01297 all_head = all_tail = all_next = NULL;
01298 active_head = active_tail = NULL;
01299 delayed_head = delayed_tail = NULL;
01300
01301 /* Deallocate all static expressions, if there are any */
01302 exp_link_delete_list( static_expr_head, FALSE );
01303
01304 /* Deallocate the non-blocking assignment queue */
01305 free_safe( nba_queue, (sizeof( nonblock_assign ) * nba_queue_size) );
01306
01307 #ifdef DEBUG_MODE
01308 #ifndef VPI_ONLY
01309 /* Clear CLI debug mode */
01310 cli_debug_mode = FALSE;
01311 #endif
01312 #endif
01313
01314 PROFILE_END;
01315
01316 }
|
|
|
Displays the current state of the active queue (for debug purposes only). Displays the current state of the active queue (for debug purposes only).
00259 {
00260
00261 sim_display_queue( active_head, active_tail );
00262
00263 }
|
|
|
Displays the state of all threads. Displays the current state of the all_threads list (for debug purposes only).
00277 {
00278
00279 thread* thr; /* Pointer to current thread */
00280
00281 printf( "ALL THREADS:\n" );
00282
00283 thr = all_head;
00284 while( thr != NULL ) {
00285 sim_display_thread( thr, FALSE, FALSE );
00286 if( thr == all_head ) {
00287 printf( "H" );
00288 }
00289 if( thr == all_tail ) {
00290 printf( "T" );
00291 }
00292 if( thr == all_next ) {
00293 printf( "N" );
00294 }
00295 printf( "\n" );
00296 thr = thr->all_next;
00297 }
00298
00299 }
|
|
|
Displays the current state of the delay queue (for debug purposes only). Displays the current state of the delay queue (for debug purposes only).
00268 {
00269
00270 sim_display_queue( delayed_head, delayed_tail );
00271
00272 }
|
|
||||||||||||
|
Displays the current state of the active queue (for debug purposes only).
00237 {
00238
00239 thread* thr; /* Pointer to current thread */
00240
00241 thr = queue_head;
00242 while( thr != NULL ) {
00243 sim_display_thread( thr, TRUE, FALSE );
00244 if( thr == queue_head ) {
00245 printf( "H" );
00246 }
00247 if( thr == queue_tail ) {
00248 printf( "T" );
00249 }
00250 printf( "\n" );
00251 thr = thr->queue_next;
00252 }
00253
00254 }
|
|
||||||||||||||||
|
Displays the given thread to standard output (for debug purposes only). Displays the contents of the given thread to standard output.
00201 {
00202
00203 if( !endl ) {
00204 printf( " " );
00205 }
00206
00207 /*@-duplicatequals -formattype@*/
00208 printf( "time %llu, ", thr->curr_time.full );
00209 /*@=duplicatequals =formattype@*/
00210
00211 if( thr->curr == NULL ) {
00212 printf( "stmt NONE, " );
00213 } else {
00214 printf( "stmt %d, ", thr->curr->exp->id );
00215 printf( "%s, ", expression_string_op( thr->curr->exp->op ) );
00216 printf( "line %d, ", thr->curr->exp->line );
00217 }
00218
00219 printf( "state %s ", thread_state_str[thr->suppl.part.state] );
00220 printf( "(%p, ", thr );
00221 printf( "parent=%p, ", thr->parent );
00222 printf( "prev=%p, ", (show_queue ? thr->queue_prev : thr->all_prev) );
00223 printf( "next=%p) ", (show_queue ? thr->queue_next : thr->all_next) );
00224
00225 if( endl ) {
00226 printf( "\n" );
00227 }
00228
00229 }
|
|
||||||||||||
|
Adds specified expression's statement to pre-simulation statement queue. Traverses up expression tree pointed to by leaf node expr, setting the CHANGED bits as it reaches the root expression. When the root expression is found, the statement pointed to by the root's parent pointer is added to the pre-simulation statement queue for simulation at the end of the timestep. If, upon traversing the tree, an expression is found to already be have a CHANGED bit set, we know that the statement has already been added, so stop here and do not add the statement again.
00514 { PROFILE(SIM_EXPR_CHANGED);
00515
00516 assert( expr != NULL );
00517
00518 /* Set my left_changed bit to indicate to sim_expression that it should evaluate me */
00519 expr->suppl.part.left_changed = 1;
00520
00521 while( ESUPPL_IS_ROOT( expr->suppl ) == 0 ) {
00522
00523 expression* parent = expr->parent->expr;
00524
00525 #ifdef DEBUG_MODE
00526 if( debug_mode ) {
00527 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, "In sim_expr_changed, expr %d, op %s, line %d, left_changed: %d, right_changed: %d, time: %llu",
00528 expr->id, expression_string_op( expr->op ), expr->line,
00529 ESUPPL_IS_LEFT_CHANGED( expr->suppl ),
00530 ESUPPL_IS_RIGHT_CHANGED( expr->suppl ),
00531 time->full );
00532 assert( rv < USER_MSG_LENGTH );
00533 print_output( user_msg, DEBUG, __FILE__, __LINE__ );
00534 }
00535 #endif
00536
00537 /* If our expression is on the left of the parent, set the left_changed as needed */
00538 if( (parent->left != NULL) && (parent->left->id == expr->id) ) {
00539
00540 /* If the bit we need to set is already set, stop iterating up tree */
00541 if( ESUPPL_IS_LEFT_CHANGED( parent->suppl ) == 1 ) {
00542 break;
00543 } else {
00544 parent->suppl.part.left_changed = 1;
00545 if( parent->op == EXP_OP_COND ) {
00546 parent->suppl.part.right_changed = 1;
00547 }
00548 }
00549
00550 /* Otherwise, we assume that we match the right side */
00551 } else {
00552
00553 /* If the bit we need to set is already set, stop iterating up tree */
00554 if( ESUPPL_IS_RIGHT_CHANGED( parent->suppl ) == 1 ) {
00555 break;
00556 } else {
00557 parent->suppl.part.right_changed = 1;
00558 }
00559
00560 }
00561
00562 expr = parent;
00563
00564 }
00565
00566 /* If we reached the root expression, push our thread onto the active queue */
00567 if( (ESUPPL_IS_ROOT( expr->suppl ) == 1) && (expr->parent->stmt != NULL) ) {
00568
00569 #ifdef DEBUG_MODE
00570 if( debug_mode ) {
00571 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, "In sim_expr_changed, expr %d, op %s, line %d, left_changed: %d, right_changed: %d, time: %llu",
00572 expr->id, expression_string_op( expr->op ), expr->line,
00573 ESUPPL_IS_LEFT_CHANGED( expr->suppl ),
00574 ESUPPL_IS_RIGHT_CHANGED( expr->suppl ),
00575 time->full );
00576 assert( rv < USER_MSG_LENGTH );
00577 print_output( user_msg, DEBUG, __FILE__, __LINE__ );
00578 }
00579 #endif
00580
00581 funit_push_threads( expr->parent->stmt->funit, expr->parent->stmt, time );
00582
00583 }
00584
00585 PROFILE_END;
00586
00587 }
|
|
||||||||||||||||||||
|
Simulates a given expression tree, only performing needed operations as it traverses the tree.
00928 { PROFILE(SIM_EXPRESSION);
00929
00930 bool retval = FALSE; /* Return value for this function */
00931 bool left_changed = FALSE; /* Signifies if left expression tree has changed value */
00932 bool right_changed = FALSE; /* Signifies if right expression tree has changed value */
00933
00934 assert( expr != NULL );
00935
00936 /* If our LHS mode matches the needed LHS mode, continue */
00937 if( ESUPPL_IS_LHS( expr->suppl ) == lhs ) {
00938
00939 #ifdef DEBUG_MODE
00940 if( debug_mode ) {
00941 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, " In sim_expression %d, left_changed %d, right_changed %d, thread %p",
00942 expr->id, ESUPPL_IS_LEFT_CHANGED( expr->suppl ), ESUPPL_IS_RIGHT_CHANGED( expr->suppl ), thr );
00943 assert( rv < USER_MSG_LENGTH );
00944 print_output( user_msg, DEBUG, __FILE__, __LINE__ );
00945 }
00946 #endif
00947
00948 /* Traverse left child expression if it has changed */
00949 if( ((ESUPPL_IS_LEFT_CHANGED( expr->suppl ) == 1) ||
00950 (expr->op == EXP_OP_CASE) ||
00951 (expr->op == EXP_OP_CASEX) ||
00952 (expr->op == EXP_OP_CASEZ)) &&
00953 ((expr->op != EXP_OP_DLY_OP) || (expr->left == NULL) || (expr->left->op != EXP_OP_DELAY)) ) {
00954
00955 /* Simulate the left expression if it has changed */
00956 if( expr->left != NULL ) {
00957 expr->suppl.part.left_changed = expr->suppl.part.clear_changed;
00958 left_changed = sim_expression( expr->left, thr, time, lhs );
00959 } else {
00960 expr->suppl.part.left_changed = 0;
00961 left_changed = TRUE;
00962 }
00963
00964 }
00965
00966 /* Traverse right child expression if it has changed */
00967 if( (ESUPPL_IS_RIGHT_CHANGED( expr->suppl ) == 1) &&
00968 ((expr->op != EXP_OP_DLY_OP) || !thr->suppl.part.exec_first) ) {
00969
00970 /* Simulate the right expression if it has changed */
00971 if( expr->right != NULL ) {
00972 expr->suppl.part.right_changed = expr->suppl.part.clear_changed;
00973 right_changed = sim_expression( expr->right, thr, time, lhs );
00974 } else {
00975 expr->suppl.part.right_changed = 0;
00976 right_changed = TRUE;
00977 }
00978
00979 }
00980
00981 /*
00982 Now perform expression operation for this expression if left or right
00983 expressions trees have changed.
00984 */
00985 if( (ESUPPL_IS_ROOT( expr->suppl ) == 0) || (expr->parent->stmt == NULL) || (expr->parent->stmt->suppl.part.cont == 0) || left_changed || right_changed || (expr->table != NULL) ) {
00986 retval = expression_operate( expr, thr, time );
00987 }
00988
00989 }
00990
00991 PROFILE_END;
00992
00993 return( retval );
00994
00995 }
|
|
|
Causes simulator to finish gracefully. Causes the simulator to finish gracefully.
01209 { PROFILE(SIM_FINISH);
01210
01211 simulate = FALSE;
01212
01213 PROFILE_END;
01214
01215 }
|
|
|
Initializes the simulator. Allocates thread arrays for simulation and initializes the contents of the active_threads array.
01160 { PROFILE(SIM_INITIALIZE);
01161
01162 /* Create non-blocking assignment queue */
01163 if( nba_queue_size > 0 ) {
01164 nba_queue = (nonblock_assign**)malloc_safe( sizeof( nonblock_assign ) * nba_queue_size );
01165 nba_queue_curr_size = 0;
01166 }
01167
01168 /* Add static values */
01169 sim_add_statics();
01170
01171 #ifdef DEBUG_MODE
01172 #ifndef VPI_ONLY
01173 /* Set the CLI debug mode to the value of the general debug mode */
01174 cli_debug_mode = debug_mode;
01175
01176 /* Add a signal handler for Ctrl-C if we are running in CLI mode */
01177 if( flag_use_command_line_debug ) {
01178 signal( SIGINT, cli_ctrl_c );
01179 }
01180 #endif
01181 #endif
01182
01183 PROFILE_END;
01184
01185 }
|
|
|
Removes the specified thread from its parent and the thread simulation queue and finally deallocates the specified thread.
00775 { PROFILE(SIM_KILL_THREAD);
00776
00777 assert( thr != NULL );
00778
00779 #ifdef DEBUG_MODE
00780 if( debug_mode && !flag_use_command_line_debug ) {
00781 printf( "Thread queue before thread is killed...\n" );
00782 sim_display_active_queue();
00783 }
00784 #endif
00785
00786 if( thr->parent != NULL ) {
00787
00788 /* Decrement the active children by one */
00789 thr->parent->active_children--;
00790
00791 /* If we are the last child, re-insert the parent in our place (setting active_head to the parent) */
00792 if( thr->parent->active_children == 0 ) {
00793 thr->parent->queue_next = thr->queue_next;
00794 if( thr->queue_next == NULL ) {
00795 active_tail = thr->parent;
00796 } else {
00797 thr->queue_next->queue_prev = thr->parent;
00798 }
00799 active_head = thr->parent;
00800 thr->parent->curr_time = thr->curr_time;
00801 thr->parent->suppl.part.state = THR_ST_ACTIVE; /* Specify that the parent thread is now back in the active queue */
00802 } else {
00803 active_head = active_head->queue_next;
00804 if( active_head == NULL ) {
00805 active_tail = NULL;
00806 }
00807 }
00808
00809 } else {
00810
00811 active_head = active_head->queue_next;
00812 if( active_head == NULL ) {
00813 active_tail = NULL;
00814 } else {
00815 active_head->queue_prev = NULL; /* Here for debug purposes - TBD */
00816 }
00817
00818 }
00819
00820 /* Check to make sure that the thread is not in the waiting state */
00821 assert( thr->suppl.part.state != THR_ST_WAITING );
00822
00823 /* Remove this thread from its functional unit */
00824 funit_delete_thread( thr->funit, thr );
00825
00826 /* Finally, park this thread at the end of the all_queue (if its not already there) */
00827 if( thr != all_tail ) {
00828 if( thr == all_head ) {
00829 all_head = thr->all_next;
00830 all_head->all_prev = NULL;
00831 } else {
00832 thr->all_prev->all_next = thr->all_next;
00833 thr->all_next->all_prev = thr->all_prev;
00834 }
00835 thr->all_prev = all_tail;
00836 thr->all_next = NULL;
00837 all_tail->all_next = thr;
00838 all_tail = thr;
00839 }
00840
00841 /* If the all_next pointer is NULL, point it to the moved thread */
00842 if( all_next == NULL ) {
00843 all_next = all_tail;
00844 }
00845
00846 #ifdef DEBUG_MODE
00847 if( debug_mode && !flag_use_command_line_debug ) {
00848 printf( "Thread queue after thread is killed...\n" );
00849 sim_display_active_queue();
00850 sim_display_all_list();
00851 }
00852 #endif
00853
00854 PROFILE_END;
00855
00856 }
|
|
|
Deallocates thread and removes it from parent and thread queue lists for specified functional unit. Searches the current state of the active queue for the thread containing the specified head statement. If a thread was found to match, kill it. This function is called whenever the DISABLE statement is run.
00865 { PROFILE(SIM_KILL_THREAD_WITH_FUNIT);
00866
00867 thread* thr; /* Pointer to current thread */
00868
00869 assert( funit != NULL );
00870
00871 /* Kill any threads that match the given functional unit or are children of it */
00872 thr = all_head;
00873 while( thr != NULL ) {
00874 if( (thr->funit == funit) || (funit_is_child_of( funit, thr->funit )) ) {
00875 thr->suppl.part.kill = 1;
00876 }
00877 thr = thr->all_next;
00878 }
00879
00880 PROFILE_END;
00881
00882 }
|
|
|
Performs non-blocking assignment for currently queued assignment items for the current timestep. Performs non-blocking assignment for the nba elements in the current nba simulation queue.
01250 { PROFILE(SIM_PERFORM_NBA);
01251
01252 int i;
01253 bool changed;
01254 nonblock_assign* nba;
01255
01256 for( i=0; i<nba_queue_curr_size; i++ ) {
01257 nba = nba_queue[i];
01258 changed = vector_part_select_push( nba->lhs_sig->value, nba->lhs_lsb, nba->lhs_msb, nba->rhs_vec, nba->rhs_lsb, nba->rhs_msb, nba->suppl.is_signed );
01259 nba->lhs_sig->value->suppl.part.set = 1;
01260 #ifdef DEBUG_MODE
01261 #ifndef VPI_ONLY
01262 if( debug_mode && (!flag_use_command_line_debug || cli_debug_mode) ) {
01263 if( i == 0 ) {
01264 printf( "Non-blocking assignments:\n" );
01265 }
01266 printf( " " ); vsignal_display( nba->lhs_sig );
01267 }
01268 #endif
01269 #endif
01270 if( changed ) {
01271 vsignal_propagate( nba->lhs_sig, time );
01272 }
01273 nba->suppl.added = 0;
01274 }
01275
01276 /* Clear the nba queue */
01277 nba_queue_curr_size = 0;
01278
01279 PROFILE_END;
01280
01281 }
|
|
|
Simulates current timestep.
01119 { PROFILE(SIM_SIMULATE);
01120
01121 /* Simulate all threads in the active queue */
01122 while( active_head != NULL ) {
01123 sim_thread( active_head, time );
01124 }
01125
01126 while( (delayed_head != NULL) && TIME_CMP_LE(delayed_head->curr_time, *time) ) {
01127
01128 active_head = active_tail = delayed_head;
01129 delayed_head = delayed_head->queue_next;
01130 active_head->queue_prev = active_head->queue_next = NULL;
01131 if( delayed_head != NULL ) {
01132 delayed_head->queue_prev = NULL;
01133 } else {
01134 delayed_tail = NULL;
01135 }
01136 active_head->suppl.part.state = THR_ST_ACTIVE;
01137
01138 while( active_head != NULL ) {
01139 sim_thread( active_head, time );
01140 }
01141
01142 }
01143
01144 #ifdef DEBUG_MODE
01145 if( debug_mode && !flag_use_command_line_debug ) {
01146 printf( "After delay simulation...\n" );
01147 sim_display_delay_queue();
01148 }
01149 #endif
01150
01151 PROFILE_END;
01152
01153 return( simulate );
01154
01155 }
|
|
|
Causes the simulation to stop and enter into CLI mode. Stops the simulation and gets the user to a CLI prompt, if possible.
01190 { PROFILE(SIM_STOP);
01191
01192 #ifdef DEBUG_MODE
01193 #ifndef VPI_ONLY
01194 force_stop = TRUE;
01195 #else
01196 simulate = FALSE;
01197 #endif
01198 #else
01199 simulate = FALSE;
01200 #endif
01201
01202 PROFILE_END;
01203
01204 }
|
|
||||||||||||
|
Simulates one thread until it has either completed or enters a context switch. Performs statement simulation as described above. Calls expression simulator if the associated root expression is specified that signals have changed value within it. Continues to run for current statement tree until statement tree hits a wait-for-event condition (or we reach the end of a simulation tree).
01006 { PROFILE(SIM_THREAD);
01007
01008 statement* stmt; /* Pointer to current statement to evaluate */
01009 bool expr_changed = FALSE; /* Specifies if expression tree was modified in any way */
01010
01011 /* If the thread has a reentrant structure assigned to it, pop it */
01012 if( thr->ren != NULL ) {
01013 reentrant_dealloc( thr->ren, thr->funit, FALSE );
01014 thr->ren = NULL;
01015 }
01016
01017 /* Set the value of stmt with the head_stmt */
01018 stmt = thr->curr;
01019
01020
01021 while( (stmt != NULL) && !thr->suppl.part.kill && simulate ) {
01022
01023 #ifdef DEBUG_MODE
01024 #ifndef VPI_ONLY
01025 cli_execute( time, force_stop, stmt );
01026 force_stop = FALSE;
01027 #endif
01028 #endif
01029
01030 /* Place expression in expression simulator and run */
01031 expr_changed = sim_expression( stmt->exp, thr, time, FALSE );
01032
01033 #ifdef DEBUG_MODE
01034 if( debug_mode ) {
01035 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, " Executed statement %d, expr changed %d, thread %p", stmt->exp->id, expr_changed, thr );
01036 assert( rv < USER_MSG_LENGTH );
01037 print_output( user_msg, DEBUG, __FILE__, __LINE__ );
01038 }
01039 #endif
01040
01041 thr->curr = stmt;
01042
01043 /* Set exec_first to FALSE */
01044 thr->suppl.part.exec_first = 0;
01045
01046 if( stmt->suppl.part.cont == 1 ) {
01047 /* If this is a continuous assignment, don't traverse next pointers. */
01048 stmt = NULL;
01049 } else {
01050 if( ESUPPL_IS_TRUE( stmt->exp->suppl ) == 1 ) {
01051 stmt = stmt->next_true;
01052 } else {
01053 stmt = stmt->next_false;
01054 }
01055 }
01056
01057 }
01058
01059 /* If this is the last statement in the tree with no loopback, kill the current thread */
01060 if( (expr_changed &&
01061 (((thr->curr->next_true == NULL) && (thr->curr->next_false == NULL)) ||
01062 (!EXPR_IS_CONTEXT_SWITCH( thr->curr->exp ) && !thr->curr->suppl.part.cont))) ||
01063 (thr->curr == NULL) ||
01064 (!expr_changed && (stmt == NULL) &&
01065 ((thr->curr->exp->op == EXP_OP_CASE) ||
01066 (thr->curr->exp->op == EXP_OP_CASEX) ||
01067 (thr->curr->exp->op == EXP_OP_CASEZ) ||
01068 (thr->curr->exp->op == EXP_OP_DEFAULT))) ||
01069 thr->suppl.part.kill ||
01070 !simulate ) {
01071
01072 #ifdef DEBUG_MODE
01073 if( debug_mode ) {
01074 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, "Completed thread %p, killing...\n", thr );
01075 assert( rv < USER_MSG_LENGTH );
01076 print_output( user_msg, DEBUG, __FILE__, __LINE__ );
01077 }
01078 #endif
01079
01080 /* Destroy the thread */
01081 sim_kill_thread( thr );
01082
01083 /* Otherwise, we are switching contexts */
01084 } else {
01085
01086 #ifdef DEBUG_MODE
01087 if( debug_mode ) {
01088 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, "Switching context of thread %p...\n", thr );
01089 assert( rv < USER_MSG_LENGTH );
01090 print_output( user_msg, DEBUG, __FILE__, __LINE__ );
01091 }
01092 #endif
01093
01094 /* Pop this packet out of the active queue */
01095 if( ((thr->curr->exp->op != EXP_OP_DELAY) &&
01096 ((thr->curr->exp->op != EXP_OP_DLY_ASSIGN) || (thr->curr->exp->right->left->op != EXP_OP_DELAY))) ||
01097 time->final ) {
01098 sim_thread_pop_head();
01099 } else {
01100 thr->suppl.part.exec_first = 1;
01101 }
01102
01103 }
01104
01105 PROFILE_END;
01106
01107 }
|
|
||||||||||||
|
Inserts the given thread into the delay queue at the given time slot. This function is called by the expression_op_func__delay() function.
00362 { PROFILE(SIM_THREAD_INSERT_INTO_DELAY_QUEUE);
00363
00364 thread* curr; /* Pointer to current thread in delayed queue to compare against */
00365
00366 #ifdef DEBUG_MODE
00367 if( debug_mode && !flag_use_command_line_debug ) {
00368 printf( "Before delay thread is inserted for time %llu...\n", time->full );
00369 }
00370 #endif
00371
00372 if( thr != NULL ) {
00373
00374 assert( thr->suppl.part.state != THR_ST_DELAYED );
00375
00376 #ifdef DEBUG_MODE
00377 if( debug_mode && !flag_use_command_line_debug ) {
00378 sim_display_delay_queue();
00379 }
00380 #endif
00381
00382 /* If the thread is currently in the active state, remove it from the active queue now */
00383 if( thr->suppl.part.state == THR_ST_ACTIVE ) {
00384
00385 /* Move the head pointer */
00386 active_head = active_head->queue_next;
00387 if( active_head == NULL ) {
00388 active_tail = NULL;
00389 } else {
00390 active_head->queue_prev = NULL; /* TBD - Placed here for help in debug */
00391 }
00392
00393 }
00394
00395 /* Specify that the thread is queued and delayed */
00396 thr->suppl.part.state = THR_ST_DELAYED;
00397
00398 /* Set the thread simulation time to the given time */
00399 thr->curr_time = *time;
00400
00401 /* Add the given thread to the delayed queue in simulation time order */
00402 if( delayed_head == NULL ) {
00403 delayed_head = delayed_tail = thr;
00404 thr->queue_prev = NULL;
00405 thr->queue_next = NULL;
00406 } else {
00407 curr = delayed_tail;
00408 while( (curr != NULL) && TIME_CMP_GT(curr->curr_time, *time) ) {
00409 curr = curr->queue_prev;
00410 }
00411 if( curr == NULL ) {
00412 thr->queue_prev = NULL;
00413 thr->queue_next = delayed_head;
00414 delayed_head->queue_prev = thr;
00415 delayed_head = thr;
00416 } else if( curr == delayed_tail ) {
00417 thr->queue_prev = delayed_tail;
00418 thr->queue_next = NULL;
00419 delayed_tail->queue_next = thr;
00420 delayed_tail = thr;
00421 } else {
00422 thr->queue_prev = curr;
00423 thr->queue_next = curr->queue_next;
00424 thr->queue_next->queue_prev = thr;
00425 curr->queue_next = thr;
00426 }
00427 }
00428
00429 #ifdef DEBUG_MODE
00430 if( debug_mode && !flag_use_command_line_debug ) {
00431 printf( "After delay thread is inserted...\n" );
00432 sim_display_delay_queue();
00433 sim_display_all_list();
00434 }
00435 #endif
00436
00437 }
00438
00439 PROFILE_END;
00440
00441 }
|
|
|
Pops the head thread from the active queue without deallocating the thread.
00313 { PROFILE(SIM_THREAD_POP_HEAD);
00314
00315 thread* thr = active_head; /* Pointer to head of active queue */
00316
00317 #ifdef DEBUG_MODE
00318 if( debug_mode && !flag_use_command_line_debug ) {
00319 printf( "Before thread is popped from active queue...\n" );
00320 sim_display_active_queue();
00321 }
00322 #endif
00323
00324 /* Move the head pointer */
00325 active_head = active_head->queue_next;
00326 if( active_head == NULL ) {
00327 active_tail = NULL;
00328 } else {
00329 active_head->queue_prev = NULL; /* TBD - Placed here for help in debug */
00330 }
00331
00332 /* Advance the curr pointer if we call sim_add_thread */
00333 if( (thr->curr->exp->op == EXP_OP_FORK) ||
00334 (thr->curr->exp->op == EXP_OP_JOIN) || /* TBD */
00335 (thr->curr->exp->op == EXP_OP_FUNC_CALL) ||
00336 (thr->curr->exp->op == EXP_OP_TASK_CALL) ||
00337 (thr->curr->exp->op == EXP_OP_NB_CALL) ) {
00338 thr->curr = thr->curr->next_true;
00339 thr->suppl.part.state = THR_ST_NONE;
00340 } else {
00341 thr->suppl.part.state = THR_ST_WAITING;
00342 thr->suppl.part.exec_first = 1;
00343 }
00344
00345 #ifdef DEBUG_MODE
00346 if( debug_mode && !flag_use_command_line_debug ) {
00347 printf( "After thread is popped from active queue...\n" );
00348 sim_display_active_queue();
00349 }
00350 #endif
00351
00352 PROFILE_END;
00353
00354 }
|
|
||||||||||||
|
Pushes given thread onto the active queue. Adds the specified thread to the end of the current simulation queue. This function gets called whenever a head statement has a signal change or the head statement is a delay operation and
00451 { PROFILE(SIM_THREAD_PUSH);
00452
00453 exp_op_type op; /* Operation type of current expression in given thread */
00454
00455 #ifdef DEBUG_MODE
00456 if( debug_mode && !flag_use_command_line_debug ) {
00457 printf( "Before thread is pushed...\n" );
00458 sim_display_active_queue();
00459 }
00460 #endif
00461
00462 /* Set the state to ACTIVE */
00463 thr->suppl.part.state = THR_ST_ACTIVE;
00464
00465 /* Set the current time of the thread to the given value */
00466 op = thr->curr->exp->op;
00467 if( (op == EXP_OP_PEDGE) ||
00468 (op == EXP_OP_NEDGE) ||
00469 (op == EXP_OP_AEDGE) ||
00470 (op == EXP_OP_EOR) ||
00471 (op == EXP_OP_WAIT) ||
00472 (op == EXP_OP_SLIST) ||
00473 (op == EXP_OP_ALWAYS_COMB) ||
00474 (op == EXP_OP_ALWAYS_LATCH) ) {
00475 thr->curr_time = *time;
00476 }
00477
00478 /* Set the active next and prev pointers to NULL */
00479 thr->queue_prev = thr->queue_next = NULL;
00480
00481 /* Add the given thread to the end of the active_threads queue */
00482 if( active_head == NULL ) {
00483 active_head = active_tail = thr;
00484 } else {
00485 thr->queue_prev = active_tail;
00486 active_tail->queue_next = thr;
00487 active_tail = thr;
00488 }
00489
00490 #ifdef DEBUG_MODE
00491 if( debug_mode && !flag_use_command_line_debug ) {
00492 printf( "After thread is pushed...\n" );
00493 sim_display_active_queue();
00494 sim_display_all_list();
00495 }
00496 #endif
00497
00498 PROFILE_END;
00499
00500 }
|
|
|
Pointer to head of active thread list. |
|
|
Pointer to tail of active thread list. |
|
|
Head of list of all allocated threads. |
|
|
Pointer to next thread to allocate. |
|
|
Tail of list of all allocated threads. |
|
|
If set to TRUE, causes debug information to be spewed to screen. |
|
|
Pointer to head of delayed thread list. |
|
|
Pointer to tail of delayed thread list. |
|
|
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. |
|
|
Specifies whether the command-line debugger should be enabled |
|
|
Causes simulation to stop and invoke the CLI prompt, if possible. |
|
|
|
|
|
Non-blocking assignment queue. |
|
|
The current number of nba structures in the nba_queue. |
|
|
The allocated size of the non-blocking assignment queue. |
|
|
Global variable used to cause simulator to stop simulation. Do not directly modify this variable! |
|
|
Pointer to head of expression list that contains all expressions that contain static (non-changing) values. These expressions will be forced to be simulated, making sure that correct coverage numbers for expressions containing static values is maintained. |
|
|
Pointer to tail of expression list that contains all expressions that contain static (non-changing) values. These expressions will be forced to be simulated, making sure that correct coverage numbers for expressions containing static values is maintained. |
|
|
List of thread state string names. |
|
|
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. |
1.3.4