Contains functions for simulation engine. More...
#include "defines.h"
Go to the source code of this file.
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_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_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_expr_changed (expression *expr, const sim_time *time) |
Adds specified expression's statement to pre-simulation statement queue. | |
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_with_funit (func_unit *funit) |
Deallocates thread and removes it from parent and thread queue lists for specified functional unit. | |
void | sim_thread_push (thread *thr, const sim_time *time) |
Pushes given thread onto the active queue. | |
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. |
Contains functions for simulation engine.
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.
Updates and adds the given non-blocking assignment structure to the simulation queue.
nba | Pointer to non-blocking assignment to updated and add | |
lhs_lsb | LSB of left-hand-side vector to assign | |
lhs_msb | MSB of left-hand-side vector to assign | |
rhs_lsb | LSB of right-hand-side vector to assign from | |
rhs_msb | MSB of right-hand-side vector to assign from |
References nonblock_assign_s::added, nonblock_assign_s::lhs_lsb, nonblock_assign_s::lhs_msb, nba_queue_curr_size, PROFILE, PROFILE_END, nonblock_assign_s::rhs_lsb, nonblock_assign_s::rhs_msb, and nonblock_assign_s::suppl.
Referenced by expression_assign().
01226 { PROFILE(SIM_ADD_NONBLOCK_ASSIGN); 01227 01228 /* Update the non-blocking assignment structure */ 01229 nba->lhs_lsb = lhs_lsb; 01230 nba->lhs_msb = lhs_msb; 01231 nba->rhs_lsb = rhs_lsb; 01232 nba->rhs_msb = rhs_msb; 01233 01234 /* Add it to the simulation queue (if it has not been already) */ 01235 if( nba->suppl.added == 0 ) { 01236 nba_queue[nba_queue_curr_size++] = nba; 01237 nba->suppl.added = 1; 01238 } 01239 01240 PROFILE_END; 01241 01242 }
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.
Creates a new thread with the given information and adds the thread to the active queue to run. Returns a pointer to the newly created thread for joining/running purposes.
parent | Pointer to parent thread of the new thread to create (set to NULL if there is no parent thread) | |
stmt | Pointer to head statement to have new thread point to | |
funit | Pointer to functional unit that is creating this thread | |
time | Pointer to current simulation time |
References thread_s::active_children, thread_s::all, thread_s::curr, thread_s::curr_time, debug_mode, esuppl_u::eval_t, statement_s::exp, EXP_OP_ALWAYS_COMB, EXP_OP_ALWAYS_LATCH, FALSE, sim_time_s::final, flag_use_command_line_debug, sim_time_s::full, sim_time_s::hi, sim_time_s::lo, expression_s::op, thread_s::parent, esuppl_u::part, thread_s::part, statement_s::part, PROFILE, PROFILE_END, thread_s::queue_next, thread_s::queue_prev, expression_s::right, sim_create_thread(), sim_display_active_queue(), sim_display_all_list(), sim_display_thread(), sim_thread_insert_into_delay_queue(), expression_s::suppl, thread_s::suppl, statement_s::suppl, THR_ST_ACTIVE, and TRUE.
Referenced by expression_op_func__fork(), expression_op_func__func_call(), expression_op_func__nb_call(), expression_op_func__task_call(), and statement_db_read().
00661 { PROFILE(SIM_ADD_THREAD); 00662 00663 thread* thr = NULL; /* Pointer to added thread */ 00664 00665 /* Only add expression if it is the head statement of its statement block */ 00666 if( stmt->suppl.part.head == 1 ) { 00667 00668 /* Create thread, if needed */ 00669 thr = sim_create_thread( parent, stmt, funit ); 00670 00671 /* Initialize thread runtime components */ 00672 thr->suppl.all = 0; 00673 thr->active_children = 0; 00674 thr->queue_prev = NULL; 00675 thr->queue_next = NULL; 00676 00677 /* 00678 If the parent thread is specified, update our current time, increment the number of active children in the parent 00679 and add ourselves between the parent thread and its next pointer. 00680 */ 00681 if( thr->parent != NULL ) { 00682 00683 thr->curr_time = thr->parent->curr_time; 00684 thr->parent->active_children++; 00685 00686 /* Place ourselves between the parent and its queue_next pointer */ 00687 thr->queue_next = thr->parent->queue_next; 00688 thr->parent->queue_next = thr; 00689 if( thr->queue_next == NULL ) { 00690 active_tail = thr; 00691 } else { 00692 thr->queue_next->queue_prev = thr; 00693 } 00694 thr->queue_prev = thr->parent; 00695 thr->suppl.part.state = THR_ST_ACTIVE; /* We will place the thread immediately into the active queue */ 00696 00697 } else { 00698 00699 thr->curr_time = *time; 00700 00701 /* 00702 If this statement is an always_comb or always_latch, add it to the delay list and change its right 00703 expression so that it will be executed at time 0 after all initial and always blocks have completed 00704 */ 00705 if( (thr->curr->exp->op == EXP_OP_ALWAYS_COMB) || (thr->curr->exp->op == EXP_OP_ALWAYS_LATCH) ) { 00706 00707 sim_time tmp_time; 00708 00709 /* Add this thread into the delay queue at time 0 */ 00710 tmp_time.lo = 0; 00711 tmp_time.hi = 0; 00712 tmp_time.full = 0LL; 00713 tmp_time.final = FALSE; 00714 sim_thread_insert_into_delay_queue( thr, &tmp_time ); 00715 00716 /* Specify that this block should be evaluated */ 00717 thr->curr->exp->right->suppl.part.eval_t = 1; 00718 00719 } else { 00720 00721 /* If the statement block is specified as a final block, add it to the end of the delay queue */ 00722 if( thr->curr->suppl.part.final == 1 ) { 00723 00724 sim_time tmp_time; 00725 00726 tmp_time.lo = 0xffffffff; 00727 tmp_time.hi = 0xffffffff; 00728 tmp_time.full = UINT64(0xffffffffffffffff); 00729 tmp_time.final = TRUE; 00730 sim_thread_insert_into_delay_queue( thr, &tmp_time ); 00731 00732 /* Otherwise, add it to the active thread list */ 00733 } else { 00734 00735 if( active_head == NULL ) { 00736 active_head = active_tail = thr; 00737 } else { 00738 thr->queue_prev = active_tail; 00739 active_tail->queue_next = thr; 00740 active_tail = thr; 00741 } 00742 thr->suppl.part.state = THR_ST_ACTIVE; 00743 00744 } 00745 00746 } 00747 00748 } 00749 00750 #ifdef DEBUG_MODE 00751 if( debug_mode && !flag_use_command_line_debug ) { 00752 printf( "Adding thread: " ); 00753 sim_display_thread( thr, FALSE, TRUE ); 00754 printf( "After thread is added to active queue...\n" ); 00755 sim_display_active_queue(); 00756 sim_display_all_list(); 00757 } 00758 #endif 00759 00760 } 00761 00762 PROFILE_END; 00763 00764 return( thr ); 00765 00766 }
thread* sim_current_thread | ( | ) |
Returns a pointer to the current thread at the head of the active queue.
References PROFILE.
00303 { PROFILE(SIM_CURRENT_THREAD); 00304 00305 return( active_head ); 00306 00307 }
void sim_dealloc | ( | ) |
Deallocates all memory for simulator.
Deallocates all allocated memory for simulation code.
References thread_s::all_next, cli_debug_mode, exp_link_delete_list(), FALSE, free_safe, nba_queue_size, PROFILE, and PROFILE_END.
Referenced by covered_end_of_sim(), parse_and_score_dumpfile(), and parse_design().
01285 { PROFILE(SIM_DEALLOC); 01286 01287 thread* tmp; /* Temporary thread pointer */ 01288 01289 /* Deallocate each thread in the all_threads array */ 01290 while( all_head != NULL ) { 01291 tmp = all_head; 01292 all_head = all_head->all_next; 01293 free_safe( tmp, sizeof( thread ) ); 01294 } 01295 01296 all_head = all_tail = all_next = NULL; 01297 active_head = active_tail = NULL; 01298 delayed_head = delayed_tail = NULL; 01299 01300 /* Deallocate all static expressions, if there are any */ 01301 exp_link_delete_list( static_expr_head, FALSE ); 01302 01303 /* Deallocate the non-blocking assignment queue */ 01304 free_safe( nba_queue, (sizeof( nonblock_assign ) * nba_queue_size) ); 01305 01306 #ifdef DEBUG_MODE 01307 #ifndef VPI_ONLY 01308 /* Clear CLI debug mode */ 01309 cli_debug_mode = FALSE; 01310 #endif 01311 #endif 01312 01313 PROFILE_END; 01314 01315 }
void sim_display_active_queue | ( | ) |
Displays the current state of the active queue (for debug purposes only).
References sim_display_queue().
Referenced by sim_add_thread(), sim_kill_thread(), sim_thread_pop_head(), and sim_thread_push().
00258 { 00259 00260 sim_display_queue( active_head, active_tail ); 00261 00262 }
void sim_display_all_list | ( | ) |
Displays the state of all threads.
Displays the current state of the all_threads list (for debug purposes only).
References thread_s::all_next, FALSE, and sim_display_thread().
Referenced by sim_add_thread(), sim_kill_thread(), sim_thread_insert_into_delay_queue(), and sim_thread_push().
00276 { 00277 00278 thread* thr; /* Pointer to current thread */ 00279 00280 printf( "ALL THREADS:\n" ); 00281 00282 thr = all_head; 00283 while( thr != NULL ) { 00284 sim_display_thread( thr, FALSE, FALSE ); 00285 if( thr == all_head ) { 00286 printf( "H" ); 00287 } 00288 if( thr == all_tail ) { 00289 printf( "T" ); 00290 } 00291 if( thr == all_next ) { 00292 printf( "N" ); 00293 } 00294 printf( "\n" ); 00295 thr = thr->all_next; 00296 } 00297 00298 }
void sim_display_delay_queue | ( | ) |
Displays the current state of the delay queue (for debug purposes only).
References sim_display_queue().
Referenced by sim_simulate(), and sim_thread_insert_into_delay_queue().
00267 { 00268 00269 sim_display_queue( delayed_head, delayed_tail ); 00270 00271 }
Displays the given thread to standard output (for debug purposes only).
Displays the contents of the given thread to standard output.
thr | Pointer to thread to display to standard output | |
show_queue | If set to TRUE, displays queue_prev/queue_next; otherwise, displays all_prev/all_next | |
endl | If set to TRUE, prints a newline character |
References thread_s::all_next, thread_s::all_prev, thread_s::curr, thread_s::curr_time, statement_s::exp, expression_string_op(), sim_time_s::full, expression_s::id, expression_s::line, expression_s::op, thread_s::parent, thread_s::part, thread_s::queue_next, thread_s::queue_prev, thread_s::suppl, and thread_state_str.
Referenced by sim_add_thread(), sim_display_all_list(), and sim_display_queue().
00200 { 00201 00202 if( !endl ) { 00203 printf( " " ); 00204 } 00205 00206 /*@-duplicatequals -formatcode -formattype@*/ 00207 printf( "time %" FMT64 "u, ", thr->curr_time.full ); 00208 /*@=duplicatequals =formatcode =formattype@*/ 00209 00210 if( thr->curr == NULL ) { 00211 printf( "stmt NONE, " ); 00212 } else { 00213 printf( "stmt %d, ", thr->curr->exp->id ); 00214 printf( "%s, ", expression_string_op( thr->curr->exp->op ) ); 00215 printf( "line %d, ", thr->curr->exp->line ); 00216 } 00217 00218 printf( "state %s ", thread_state_str[thr->suppl.part.state] ); 00219 printf( "(%p, ", thr ); 00220 printf( "parent=%p, ", thr->parent ); 00221 printf( "prev=%p, ", (show_queue ? thr->queue_prev : thr->all_prev) ); 00222 printf( "next=%p) ", (show_queue ? thr->queue_next : thr->all_next) ); 00223 00224 if( endl ) { 00225 printf( "\n" ); 00226 } 00227 00228 }
void sim_expr_changed | ( | expression * | expr, | |
const sim_time * | time | |||
) |
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.
expr | Pointer to expression that contains a changed signal value | |
time | Specifies current simulation time for the thread to push |
References DEBUG, debug_mode, ESUPPL_IS_LEFT_CHANGED, ESUPPL_IS_RIGHT_CHANGED, ESUPPL_IS_ROOT, EXP_OP_COND, expr_stmt_u::expr, expression_string_op(), sim_time_s::full, statement_s::funit, funit_push_threads(), expression_s::id, expression_s::left, esuppl_u::left_changed, expression_s::line, expression_s::op, expression_s::parent, esuppl_u::part, print_output(), PROFILE, PROFILE_END, esuppl_u::right_changed, expr_stmt_u::stmt, expression_s::suppl, user_msg, and USER_MSG_LENGTH.
Referenced by fsm_table_set(), sim_add_statics(), and vsignal_propagate().
00513 { PROFILE(SIM_EXPR_CHANGED); 00514 00515 assert( expr != NULL ); 00516 00517 /* Set my left_changed bit to indicate to sim_expression that it should evaluate me */ 00518 expr->suppl.part.left_changed = 1; 00519 00520 while( ESUPPL_IS_ROOT( expr->suppl ) == 0 ) { 00521 00522 expression* parent = expr->parent->expr; 00523 00524 #ifdef DEBUG_MODE 00525 if( debug_mode ) { 00526 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: %" FMT64 "u", 00527 expr->id, expression_string_op( expr->op ), expr->line, 00528 ESUPPL_IS_LEFT_CHANGED( expr->suppl ), 00529 ESUPPL_IS_RIGHT_CHANGED( expr->suppl ), 00530 time->full ); 00531 assert( rv < USER_MSG_LENGTH ); 00532 print_output( user_msg, DEBUG, __FILE__, __LINE__ ); 00533 } 00534 #endif 00535 00536 /* If our expression is on the left of the parent, set the left_changed as needed */ 00537 if( (parent->left != NULL) && (parent->left->id == expr->id) ) { 00538 00539 /* If the bit we need to set is already set, stop iterating up tree */ 00540 if( ESUPPL_IS_LEFT_CHANGED( parent->suppl ) == 1 ) { 00541 break; 00542 } else { 00543 parent->suppl.part.left_changed = 1; 00544 if( parent->op == EXP_OP_COND ) { 00545 parent->suppl.part.right_changed = 1; 00546 } 00547 } 00548 00549 /* Otherwise, we assume that we match the right side */ 00550 } else { 00551 00552 /* If the bit we need to set is already set, stop iterating up tree */ 00553 if( ESUPPL_IS_RIGHT_CHANGED( parent->suppl ) == 1 ) { 00554 break; 00555 } else { 00556 parent->suppl.part.right_changed = 1; 00557 } 00558 00559 } 00560 00561 expr = parent; 00562 00563 } 00564 00565 /* If we reached the root expression, push our thread onto the active queue */ 00566 if( (ESUPPL_IS_ROOT( expr->suppl ) == 1) && (expr->parent->stmt != NULL) ) { 00567 00568 #ifdef DEBUG_MODE 00569 if( debug_mode ) { 00570 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: %" FMT64 "u", 00571 expr->id, expression_string_op( expr->op ), expr->line, 00572 ESUPPL_IS_LEFT_CHANGED( expr->suppl ), 00573 ESUPPL_IS_RIGHT_CHANGED( expr->suppl ), 00574 time->full ); 00575 assert( rv < USER_MSG_LENGTH ); 00576 print_output( user_msg, DEBUG, __FILE__, __LINE__ ); 00577 } 00578 #endif 00579 00580 funit_push_threads( expr->parent->stmt->funit, expr->parent->stmt, time ); 00581 00582 } 00583 00584 PROFILE_END; 00585 00586 }
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.
Recursively traverses specified expression tree, following the ESUPPL_IS_LEFT_CHANGED and ESUPPL_IS_RIGHT_CHANGED bits in the supplemental field. Once an expression is found that has neither bit set, perform the expression operation and move back up the tree. Once both left and right children have calculated values, perform the expression operation for the current expression, clear both changed bits and return.
expr | Pointer to expression to simulate | |
thr | Pointer to current thread that is being simulated | |
time | Pointer to current simulation time | |
lhs | Specifies if we should only traverse LHS expressions or RHS expressions |
References esuppl_u::clear_changed, DEBUG, debug_mode, ESUPPL_IS_LEFT_CHANGED, ESUPPL_IS_LHS, ESUPPL_IS_RIGHT_CHANGED, ESUPPL_IS_ROOT, EXP_OP_CASE, EXP_OP_CASEX, EXP_OP_CASEZ, EXP_OP_DELAY, EXP_OP_DLY_OP, expression_operate(), FALSE, expression_s::id, expression_s::left, esuppl_u::left_changed, expression_s::op, expression_s::parent, statement_s::part, thread_s::part, esuppl_u::part, print_output(), PROFILE, PROFILE_END, expression_s::right, esuppl_u::right_changed, sim_expression(), expr_stmt_u::stmt, statement_s::suppl, thread_s::suppl, expression_s::suppl, expression_s::table, TRUE, user_msg, and USER_MSG_LENGTH.
Referenced by expression_assign(), expression_op_func__add_a(), expression_op_func__and_a(), expression_op_func__arshift_a(), expression_op_func__divide_a(), expression_op_func__lshift_a(), expression_op_func__mod_a(), expression_op_func__multiply_a(), expression_op_func__or_a(), expression_op_func__rshift_a(), expression_op_func__sub_a(), expression_op_func__xor_a(), sim_expression(), and sim_thread().
00927 { PROFILE(SIM_EXPRESSION); 00928 00929 bool retval = FALSE; /* Return value for this function */ 00930 bool left_changed = FALSE; /* Signifies if left expression tree has changed value */ 00931 bool right_changed = FALSE; /* Signifies if right expression tree has changed value */ 00932 00933 assert( expr != NULL ); 00934 00935 /* If our LHS mode matches the needed LHS mode, continue */ 00936 if( ESUPPL_IS_LHS( expr->suppl ) == lhs ) { 00937 00938 #ifdef DEBUG_MODE 00939 if( debug_mode ) { 00940 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, " In sim_expression %d, left_changed %d, right_changed %d, thread %p", 00941 expr->id, ESUPPL_IS_LEFT_CHANGED( expr->suppl ), ESUPPL_IS_RIGHT_CHANGED( expr->suppl ), thr ); 00942 assert( rv < USER_MSG_LENGTH ); 00943 print_output( user_msg, DEBUG, __FILE__, __LINE__ ); 00944 } 00945 #endif 00946 00947 /* Traverse left child expression if it has changed */ 00948 if( ((ESUPPL_IS_LEFT_CHANGED( expr->suppl ) == 1) || 00949 (expr->op == EXP_OP_CASE) || 00950 (expr->op == EXP_OP_CASEX) || 00951 (expr->op == EXP_OP_CASEZ)) && 00952 ((expr->op != EXP_OP_DLY_OP) || (expr->left == NULL) || (expr->left->op != EXP_OP_DELAY)) ) { 00953 00954 /* Simulate the left expression if it has changed */ 00955 if( expr->left != NULL ) { 00956 expr->suppl.part.left_changed = expr->suppl.part.clear_changed; 00957 left_changed = sim_expression( expr->left, thr, time, lhs ); 00958 } else { 00959 expr->suppl.part.left_changed = 0; 00960 left_changed = TRUE; 00961 } 00962 00963 } 00964 00965 /* Traverse right child expression if it has changed */ 00966 if( (ESUPPL_IS_RIGHT_CHANGED( expr->suppl ) == 1) && 00967 ((expr->op != EXP_OP_DLY_OP) || !thr->suppl.part.exec_first) ) { 00968 00969 /* Simulate the right expression if it has changed */ 00970 if( expr->right != NULL ) { 00971 expr->suppl.part.right_changed = expr->suppl.part.clear_changed; 00972 right_changed = sim_expression( expr->right, thr, time, lhs ); 00973 } else { 00974 expr->suppl.part.right_changed = 0; 00975 right_changed = TRUE; 00976 } 00977 00978 } 00979 00980 /* 00981 Now perform expression operation for this expression if left or right 00982 expressions trees have changed. 00983 */ 00984 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) ) { 00985 retval = expression_operate( expr, thr, time ); 00986 } 00987 00988 } 00989 00990 PROFILE_END; 00991 00992 return( retval ); 00993 00994 }
void sim_finish | ( | ) |
Causes simulator to finish gracefully.
Causes the simulator to finish gracefully.
References FALSE, PROFILE, PROFILE_END, and simulate.
Referenced by expression_op_func__finish().
01208 { PROFILE(SIM_FINISH); 01209 01210 simulate = FALSE; 01211 01212 PROFILE_END; 01213 01214 }
void sim_initialize | ( | ) |
Initializes the simulator.
Allocates thread arrays for simulation and initializes the contents of the active_threads array.
References cli_ctrl_c(), cli_debug_mode, debug_mode, flag_use_command_line_debug, malloc_safe, nba_queue_curr_size, nba_queue_size, PROFILE, PROFILE_END, and sim_add_statics().
Referenced by covered_sim_calltf(), and parse_and_score_dumpfile().
01159 { PROFILE(SIM_INITIALIZE); 01160 01161 /* Create non-blocking assignment queue */ 01162 if( nba_queue_size > 0 ) { 01163 nba_queue = (nonblock_assign**)malloc_safe( sizeof( nonblock_assign ) * nba_queue_size ); 01164 nba_queue_curr_size = 0; 01165 } 01166 01167 /* Add static values */ 01168 sim_add_statics(); 01169 01170 #ifdef DEBUG_MODE 01171 #ifndef VPI_ONLY 01172 /* Set the CLI debug mode to the value of the general debug mode */ 01173 cli_debug_mode = debug_mode; 01174 01175 /* Add a signal handler for Ctrl-C if we are running in CLI mode */ 01176 if( flag_use_command_line_debug ) { 01177 signal( SIGINT, cli_ctrl_c ); 01178 } 01179 #endif 01180 #endif 01181 01182 PROFILE_END; 01183 01184 }
void sim_kill_thread_with_funit | ( | func_unit * | funit | ) |
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.
funit | Pointer to functional unit of thread to kill |
References thread_s::all_next, thread_s::funit, funit_is_child_of(), thread_s::part, PROFILE, PROFILE_END, and thread_s::suppl.
Referenced by expression_op_func__disable().
00864 { PROFILE(SIM_KILL_THREAD_WITH_FUNIT); 00865 00866 thread* thr; /* Pointer to current thread */ 00867 00868 assert( funit != NULL ); 00869 00870 /* Kill any threads that match the given functional unit or are children of it */ 00871 thr = all_head; 00872 while( thr != NULL ) { 00873 if( (thr->funit == funit) || (funit_is_child_of( funit, thr->funit )) ) { 00874 thr->suppl.part.kill = 1; 00875 } 00876 thr = thr->all_next; 00877 } 00878 00879 PROFILE_END; 00880 00881 }
void sim_perform_nba | ( | const sim_time * | time | ) |
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.
time | Current simulation time |
References nonblock_assign_s::added, cli_debug_mode, debug_mode, flag_use_command_line_debug, nonblock_assign_s::is_signed, nonblock_assign_s::lhs_lsb, nonblock_assign_s::lhs_msb, nonblock_assign_s::lhs_sig, nba_queue_curr_size, vsuppl_u::part, PROFILE, PROFILE_END, nonblock_assign_s::rhs_lsb, nonblock_assign_s::rhs_msb, nonblock_assign_s::rhs_vec, vsuppl_u::set, vector_s::suppl, nonblock_assign_s::suppl, vsignal_s::value, vector_part_select_push(), vsignal_display(), and vsignal_propagate().
Referenced by db_do_timestep().
01249 { PROFILE(SIM_PERFORM_NBA); 01250 01251 int i; 01252 bool changed; 01253 nonblock_assign* nba; 01254 01255 for( i=0; i<nba_queue_curr_size; i++ ) { 01256 nba = nba_queue[i]; 01257 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 ); 01258 nba->lhs_sig->value->suppl.part.set = 1; 01259 #ifdef DEBUG_MODE 01260 #ifndef VPI_ONLY 01261 if( debug_mode && (!flag_use_command_line_debug || cli_debug_mode) ) { 01262 if( i == 0 ) { 01263 printf( "Non-blocking assignments:\n" ); 01264 } 01265 printf( " " ); vsignal_display( nba->lhs_sig ); 01266 } 01267 #endif 01268 #endif 01269 if( changed ) { 01270 vsignal_propagate( nba->lhs_sig, time ); 01271 } 01272 nba->suppl.added = 0; 01273 } 01274 01275 /* Clear the nba queue */ 01276 nba_queue_curr_size = 0; 01277 01278 PROFILE_END; 01279 01280 }
Simulates current timestep.
This function is the heart of the simulation engine. It is called by the db_do_timestep() function in db.c and moves the statements and expressions into the appropriate simulation functions. See above explanation on this procedure.
time | Current simulation time from dumpfile or simulator |
References thread_s::curr_time, debug_mode, flag_use_command_line_debug, thread_s::part, PROFILE, PROFILE_END, thread_s::queue_next, thread_s::queue_prev, sim_display_delay_queue(), sim_thread(), simulate, thread_s::suppl, THR_ST_ACTIVE, and TIME_CMP_LE.
Referenced by db_do_timestep().
01118 { PROFILE(SIM_SIMULATE); 01119 01120 /* Simulate all threads in the active queue */ 01121 while( active_head != NULL ) { 01122 sim_thread( active_head, time ); 01123 } 01124 01125 while( (delayed_head != NULL) && TIME_CMP_LE(delayed_head->curr_time, *time) ) { 01126 01127 active_head = active_tail = delayed_head; 01128 delayed_head = delayed_head->queue_next; 01129 active_head->queue_prev = active_head->queue_next = NULL; 01130 if( delayed_head != NULL ) { 01131 delayed_head->queue_prev = NULL; 01132 } else { 01133 delayed_tail = NULL; 01134 } 01135 active_head->suppl.part.state = THR_ST_ACTIVE; 01136 01137 while( active_head != NULL ) { 01138 sim_thread( active_head, time ); 01139 } 01140 01141 } 01142 01143 #ifdef DEBUG_MODE 01144 if( debug_mode && !flag_use_command_line_debug ) { 01145 printf( "After delay simulation...\n" ); 01146 sim_display_delay_queue(); 01147 } 01148 #endif 01149 01150 PROFILE_END; 01151 01152 return( simulate ); 01153 01154 }
void sim_stop | ( | ) |
Causes the simulation to stop and enter into CLI mode.
Stops the simulation and gets the user to a CLI prompt, if possible.
References FALSE, force_stop, PROFILE, PROFILE_END, simulate, and TRUE.
Referenced by expression_op_func__stop().
01189 { PROFILE(SIM_STOP); 01190 01191 #ifdef DEBUG_MODE 01192 #ifndef VPI_ONLY 01193 force_stop = TRUE; 01194 #else 01195 simulate = FALSE; 01196 #endif 01197 #else 01198 simulate = FALSE; 01199 #endif 01200 01201 PROFILE_END; 01202 01203 }
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).
thr | Pointer to current thread to simulate | |
time | Current simulation time to simulate |
References cli_execute(), thread_s::curr, DEBUG, debug_mode, ESUPPL_IS_TRUE, statement_s::exp, EXP_OP_CASE, EXP_OP_CASEX, EXP_OP_CASEZ, EXP_OP_DEFAULT, EXP_OP_DELAY, EXP_OP_DLY_ASSIGN, EXPR_IS_CONTEXT_SWITCH, FALSE, sim_time_s::final, force_stop, thread_s::funit, expression_s::id, expression_s::left, statement_s::next_false, statement_s::next_true, expression_s::op, statement_s::part, thread_s::part, print_output(), PROFILE, PROFILE_END, reentrant_dealloc(), thread_s::ren, expression_s::right, sim_expression(), sim_kill_thread(), sim_thread_pop_head(), simulate, expression_s::suppl, statement_s::suppl, thread_s::suppl, user_msg, and USER_MSG_LENGTH.
Referenced by expression_op_func__func_call(), expression_op_func__nb_call(), and sim_simulate().
01005 { PROFILE(SIM_THREAD); 01006 01007 statement* stmt; /* Pointer to current statement to evaluate */ 01008 bool expr_changed = FALSE; /* Specifies if expression tree was modified in any way */ 01009 01010 /* If the thread has a reentrant structure assigned to it, pop it */ 01011 if( thr->ren != NULL ) { 01012 reentrant_dealloc( thr->ren, thr->funit, FALSE ); 01013 thr->ren = NULL; 01014 } 01015 01016 /* Set the value of stmt with the head_stmt */ 01017 stmt = thr->curr; 01018 01019 01020 while( (stmt != NULL) && !thr->suppl.part.kill && simulate ) { 01021 01022 #ifdef DEBUG_MODE 01023 #ifndef VPI_ONLY 01024 cli_execute( time, force_stop, stmt ); 01025 force_stop = FALSE; 01026 #endif 01027 #endif 01028 01029 /* Place expression in expression simulator and run */ 01030 expr_changed = sim_expression( stmt->exp, thr, time, FALSE ); 01031 01032 #ifdef DEBUG_MODE 01033 if( debug_mode ) { 01034 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, " Executed statement %d, expr changed %d, thread %p", stmt->exp->id, expr_changed, thr ); 01035 assert( rv < USER_MSG_LENGTH ); 01036 print_output( user_msg, DEBUG, __FILE__, __LINE__ ); 01037 } 01038 #endif 01039 01040 thr->curr = stmt; 01041 01042 /* Set exec_first to FALSE */ 01043 thr->suppl.part.exec_first = 0; 01044 01045 if( stmt->suppl.part.cont == 1 ) { 01046 /* If this is a continuous assignment, don't traverse next pointers. */ 01047 stmt = NULL; 01048 } else { 01049 if( ESUPPL_IS_TRUE( stmt->exp->suppl ) == 1 ) { 01050 stmt = stmt->next_true; 01051 } else { 01052 stmt = stmt->next_false; 01053 } 01054 } 01055 01056 } 01057 01058 /* If this is the last statement in the tree with no loopback, kill the current thread */ 01059 if( (expr_changed && 01060 (((thr->curr->next_true == NULL) && (thr->curr->next_false == NULL)) || 01061 (!EXPR_IS_CONTEXT_SWITCH( thr->curr->exp ) && !thr->curr->suppl.part.cont))) || 01062 (thr->curr == NULL) || 01063 (!expr_changed && (stmt == NULL) && 01064 ((thr->curr->exp->op == EXP_OP_CASE) || 01065 (thr->curr->exp->op == EXP_OP_CASEX) || 01066 (thr->curr->exp->op == EXP_OP_CASEZ) || 01067 (thr->curr->exp->op == EXP_OP_DEFAULT))) || 01068 thr->suppl.part.kill || 01069 !simulate ) { 01070 01071 #ifdef DEBUG_MODE 01072 if( debug_mode ) { 01073 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, "Completed thread %p, killing...\n", thr ); 01074 assert( rv < USER_MSG_LENGTH ); 01075 print_output( user_msg, DEBUG, __FILE__, __LINE__ ); 01076 } 01077 #endif 01078 01079 /* Destroy the thread */ 01080 sim_kill_thread( thr ); 01081 01082 /* Otherwise, we are switching contexts */ 01083 } else { 01084 01085 #ifdef DEBUG_MODE 01086 if( debug_mode ) { 01087 unsigned int rv = snprintf( user_msg, USER_MSG_LENGTH, "Switching context of thread %p...\n", thr ); 01088 assert( rv < USER_MSG_LENGTH ); 01089 print_output( user_msg, DEBUG, __FILE__, __LINE__ ); 01090 } 01091 #endif 01092 01093 /* Pop this packet out of the active queue */ 01094 if( ((thr->curr->exp->op != EXP_OP_DELAY) && 01095 ((thr->curr->exp->op != EXP_OP_DLY_ASSIGN) || (thr->curr->exp->right->left->op != EXP_OP_DELAY))) || 01096 time->final ) { 01097 sim_thread_pop_head(); 01098 } else { 01099 thr->suppl.part.exec_first = 1; 01100 } 01101 01102 } 01103 01104 PROFILE_END; 01105 01106 }
Inserts the given thread into the delay queue at the given time slot.
This function is called by the expression_op_func__delay() function.
thr | Pointer to the thread to add to the delay queue | |
time | Pointer to time to insert the given thread |
References thread_s::curr_time, debug_mode, flag_use_command_line_debug, sim_time_s::full, thread_s::part, PROFILE, PROFILE_END, thread_s::queue_next, thread_s::queue_prev, sim_display_all_list(), sim_display_delay_queue(), thread_s::suppl, THR_ST_ACTIVE, THR_ST_DELAYED, and TIME_CMP_GT.
Referenced by expression_op_func__delay(), and sim_add_thread().
00361 { PROFILE(SIM_THREAD_INSERT_INTO_DELAY_QUEUE); 00362 00363 thread* curr; /* Pointer to current thread in delayed queue to compare against */ 00364 00365 #ifdef DEBUG_MODE 00366 if( debug_mode && !flag_use_command_line_debug ) { 00367 printf( "Before delay thread is inserted for time %" FMT64 "u...\n", time->full ); 00368 } 00369 #endif 00370 00371 if( thr != NULL ) { 00372 00373 assert( thr->suppl.part.state != THR_ST_DELAYED ); 00374 00375 #ifdef DEBUG_MODE 00376 if( debug_mode && !flag_use_command_line_debug ) { 00377 sim_display_delay_queue(); 00378 } 00379 #endif 00380 00381 /* If the thread is currently in the active state, remove it from the active queue now */ 00382 if( thr->suppl.part.state == THR_ST_ACTIVE ) { 00383 00384 /* Move the head pointer */ 00385 active_head = active_head->queue_next; 00386 if( active_head == NULL ) { 00387 active_tail = NULL; 00388 } else { 00389 active_head->queue_prev = NULL; /* TBD - Placed here for help in debug */ 00390 } 00391 00392 } 00393 00394 /* Specify that the thread is queued and delayed */ 00395 thr->suppl.part.state = THR_ST_DELAYED; 00396 00397 /* Set the thread simulation time to the given time */ 00398 thr->curr_time = *time; 00399 00400 /* Add the given thread to the delayed queue in simulation time order */ 00401 if( delayed_head == NULL ) { 00402 delayed_head = delayed_tail = thr; 00403 thr->queue_prev = NULL; 00404 thr->queue_next = NULL; 00405 } else { 00406 curr = delayed_tail; 00407 while( (curr != NULL) && TIME_CMP_GT(curr->curr_time, *time) ) { 00408 curr = curr->queue_prev; 00409 } 00410 if( curr == NULL ) { 00411 thr->queue_prev = NULL; 00412 thr->queue_next = delayed_head; 00413 delayed_head->queue_prev = thr; 00414 delayed_head = thr; 00415 } else if( curr == delayed_tail ) { 00416 thr->queue_prev = delayed_tail; 00417 thr->queue_next = NULL; 00418 delayed_tail->queue_next = thr; 00419 delayed_tail = thr; 00420 } else { 00421 thr->queue_prev = curr; 00422 thr->queue_next = curr->queue_next; 00423 thr->queue_next->queue_prev = thr; 00424 curr->queue_next = thr; 00425 } 00426 } 00427 00428 #ifdef DEBUG_MODE 00429 if( debug_mode && !flag_use_command_line_debug ) { 00430 printf( "After delay thread is inserted...\n" ); 00431 sim_display_delay_queue(); 00432 sim_display_all_list(); 00433 } 00434 #endif 00435 00436 } 00437 00438 PROFILE_END; 00439 00440 }
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
thr | Pointer to thread to add to the tail of the simulation queue | |
time | Current simulation time of thread to push |
References thread_s::curr, thread_s::curr_time, debug_mode, statement_s::exp, EXP_OP_AEDGE, EXP_OP_ALWAYS_COMB, EXP_OP_ALWAYS_LATCH, EXP_OP_EOR, EXP_OP_NEDGE, EXP_OP_PEDGE, EXP_OP_SLIST, EXP_OP_WAIT, flag_use_command_line_debug, expression_s::op, thread_s::part, PROFILE, PROFILE_END, thread_s::queue_next, thread_s::queue_prev, sim_display_active_queue(), sim_display_all_list(), thread_s::suppl, and THR_ST_ACTIVE.
Referenced by funit_push_threads().
00450 { PROFILE(SIM_THREAD_PUSH); 00451 00452 exp_op_type op; /* Operation type of current expression in given thread */ 00453 00454 #ifdef DEBUG_MODE 00455 if( debug_mode && !flag_use_command_line_debug ) { 00456 printf( "Before thread is pushed...\n" ); 00457 sim_display_active_queue(); 00458 } 00459 #endif 00460 00461 /* Set the state to ACTIVE */ 00462 thr->suppl.part.state = THR_ST_ACTIVE; 00463 00464 /* Set the current time of the thread to the given value */ 00465 op = thr->curr->exp->op; 00466 if( (op == EXP_OP_PEDGE) || 00467 (op == EXP_OP_NEDGE) || 00468 (op == EXP_OP_AEDGE) || 00469 (op == EXP_OP_EOR) || 00470 (op == EXP_OP_WAIT) || 00471 (op == EXP_OP_SLIST) || 00472 (op == EXP_OP_ALWAYS_COMB) || 00473 (op == EXP_OP_ALWAYS_LATCH) ) { 00474 thr->curr_time = *time; 00475 } 00476 00477 /* Set the active next and prev pointers to NULL */ 00478 thr->queue_prev = thr->queue_next = NULL; 00479 00480 /* Add the given thread to the end of the active_threads queue */ 00481 if( active_head == NULL ) { 00482 active_head = active_tail = thr; 00483 } else { 00484 thr->queue_prev = active_tail; 00485 active_tail->queue_next = thr; 00486 active_tail = thr; 00487 } 00488 00489 #ifdef DEBUG_MODE 00490 if( debug_mode && !flag_use_command_line_debug ) { 00491 printf( "After thread is pushed...\n" ); 00492 sim_display_active_queue(); 00493 sim_display_all_list(); 00494 } 00495 #endif 00496 00497 PROFILE_END; 00498 00499 }