//------------------------------------------------------------------------------ //"sc_object::detach" // // This method detaches this object instance from the object hierarchy. // It is called in two places: ~sc_object() and sc_process_b::kill_process(). //------------------------------------------------------------------------------ void sc_object::detach() { if (m_simc) { // REMOVE OBJECT FROM THE OBJECT MANAGER: sc_object_manager* object_manager = m_simc->get_object_manager(); object_manager->remove_object(m_name); // REMOVE OBJECT FROM PARENT'S LIST OF OBJECTS: if ( m_parent ) m_parent->remove_child_object( this ); else m_simc->remove_child_object( this ); // ORPHAN THIS OBJECT'S CHILDREN: #if 0 // #### ::std::<sc_object*> children_p = &get_child_objects(); int child_n = children_p->size(); sc_object* parent_p; for ( int child_i = 0; child_i < child_n; child_i++ ) { (*children_p)[child_i]->m_parent = 0; } #endif } }
//------------------------------------------------------------------------------ //"sc_method_process::enable_process" // // This method enables the execution of this process, and if requested, its // descendants. If the process was suspended and has a resumption pending it // will be dispatched in the next delta cycle. Otherwise the state will be // adjusted to indicate it is no longer suspended, but no immediate execution // will occur. //------------------------------------------------------------------------------ void sc_method_process::enable_process( sc_descendant_inclusion_info descendants ) { // IF NEEDED PROPOGATE THE RESUME REQUEST THROUGH OUR DESCENDANTS: if ( descendants == SC_INCLUDE_DESCENDANTS ) { const std::vector<sc_object*>& children = get_child_objects(); int child_n = children.size(); for ( int child_i = 0; child_i < child_n; child_i++ ) { sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]); if ( child_p ) child_p->enable_process(descendants); } } // ENABLE THIS OBJECT INSTANCE: // // If it was disabled and ready to run then put it on the run queue. m_state = m_state & ~ps_bit_disabled; if ( m_state == ps_bit_ready_to_run ) { m_state = ps_normal; if ( next_runnable() == 0 ) simcontext()->push_runnable_method(this); } }
//------------------------------------------------------------------------------ //"sc_process_b::reset_process" // // This inline method changes the reset state of this object instance and // conditionally its descendants. // // Notes: // (1) It is called for sync_reset_on() and sync_reset_off(). It is not used // for signal sensitive resets, though all reset flow ends up in // reset_changed(). // // Arguments: // rt = source of the reset: // * reset_asynchronous - sc_process_handle::reset() // * reset_synchronous_off - sc_process_handle::sync_reset_off() // * reset_synchronous_on - sc_process_handle::sync_reset_on() // descendants = indication of how to process descendants. //------------------------------------------------------------------------------ void sc_process_b::reset_process( reset_type rt, sc_descendant_inclusion_info descendants ) { // PROCESS THIS OBJECT INSTANCE'S DESCENDANTS IF REQUESTED TO: if ( descendants == SC_INCLUDE_DESCENDANTS ) { const std::vector<sc_object*> children = get_child_objects(); int child_n = children.size(); for ( int child_i = 0; child_i < child_n; child_i++ ) { sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]); if ( child_p ) child_p->reset_process(rt, descendants); } } // PROCESS THIS OBJECT INSTANCE: switch (rt) { // One-shot asynchronous reset: remove dynamic sensitivity and throw: // // If this is an sc_method only throw if it is active. case reset_asynchronous: if ( sc_get_status() != SC_RUNNING ) { report_error(SC_ID_RESET_PROCESS_WHILE_NOT_RUNNING_); } else { remove_dynamic_events(); throw_reset(true); } break; // Turn on sticky synchronous reset: use standard reset mechanism. case reset_synchronous_on: if ( m_sticky_reset == false ) { m_sticky_reset = true; reset_changed( false, true ); } break; // Turn off sticky synchronous reset: use standard reset mechanism. default: if ( m_sticky_reset == true ) { m_sticky_reset = false; reset_changed( false, false ); } break; } }
//------------------------------------------------------------------------------ //"sc_method_process::kill_process" // // This method removes throws a kill for this object instance. It calls the // sc_process_b::kill_process() method to perform low level clean up. //------------------------------------------------------------------------------ void sc_method_process::kill_process(sc_descendant_inclusion_info descendants) { // IF THE SIMULATION HAS NOT BEEN INITIALIZED YET THAT IS AN ERROR: if ( sc_get_status() == SC_ELABORATION ) { report_error( SC_ID_KILL_PROCESS_WHILE_UNITIALIZED_ ); } // IF NEEDED, PROPOGATE THE KILL REQUEST THROUGH OUR DESCENDANTS: if ( descendants == SC_INCLUDE_DESCENDANTS ) { const std::vector<sc_object*> children = get_child_objects(); int child_n = children.size(); for ( int child_i = 0; child_i < child_n; child_i++ ) { sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]); if ( child_p ) child_p->kill_process(descendants); } } // IF THE PROCESS IS CURRENTLY UNWINDING OR IS ALREADY A ZOMBIE // IGNORE THE KILL: if ( m_unwinding ) { SC_REPORT_WARNING( SC_ID_PROCESS_ALREADY_UNWINDING_, name() ); return; } if ( m_state & ps_bit_zombie ) return; // REMOVE OUR PROCESS FROM EVENTS, ETC., AND IF ITS THE ACTIVE PROCESS // THROW ITS KILL. // // Note we set the throw status to kill regardless if we throw or not. // That lets check_for_throws stumble across it if we were in the call // chain when the kill call occurred. if ( next_runnable() != 0 ) simcontext()->remove_runnable_method( this ); disconnect_process(); m_throw_status = THROW_KILL; if ( sc_get_current_process_b() == this ) { throw sc_unwind_exception( this, false ); } }
// +---------------------------------------------------------------------------- // |"sc_object::orphan_child_objects" // | // | This method moves the children of this object instance to be children // | of the simulator. // +---------------------------------------------------------------------------- void sc_object::orphan_child_objects() { std::vector< sc_object* > const & children = get_child_objects(); std::vector< sc_object* >::const_iterator it = children.begin(), end = children.end(); for( ; it != end; ++it ) { (*it)->m_parent = NULL; simcontext()->add_child_object(*it); } }
//------------------------------------------------------------------------------ //"sc_method_process::throw_user" // // This virtual method is invoked when a user exception is to be thrown. // If requested it will also throw the exception to the children of this // object instance. Since this is a method no throw will occur for this // object instance. The children will be awakened from youngest child to // eldest. // helper_p -> object to use to throw the exception. // descendants = indicator of whether this process' children should also // be suspended //------------------------------------------------------------------------------ void sc_method_process::throw_user( const sc_throw_it_helper& helper, sc_descendant_inclusion_info descendants ) { // IF THE SIMULATION IS NOT ACTUALLY RUNNING THIS IS AN ERROR: if ( sc_get_status() != SC_RUNNING ) { report_error( SC_ID_THROW_IT_WHILE_NOT_RUNNING_ ); } // IF NEEDED PROPOGATE THE THROW REQUEST THROUGH OUR DESCENDANTS: if ( descendants == SC_INCLUDE_DESCENDANTS ) { const std::vector<sc_object*> children = get_child_objects(); int child_n = children.size(); for ( int child_i = 0; child_i < child_n; child_i++ ) { sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]); if ( child_p ) { DEBUG_MSG(DEBUG_NAME,child_p,"about to throw user on"); child_p->throw_user(helper, descendants); } } } #if 0 // shouldn't we throw, if we're currently running? if ( sc_get_current_process_b() == (sc_process_b*)this ) { remove_dynamic_events(); m_throw_status = THROW_USER; if ( m_throw_helper_p != 0 ) delete m_throw_helper_p; m_throw_helper_p = helper.clone(); m_throw_helper_p->throw_it(); } // throw_it HAS NO EFFECT ON A METHOD, ISSUE A WARNING: else #endif { SC_REPORT_WARNING( SC_ID_THROW_IT_IGNORED_, name() ); } }
//------------------------------------------------------------------------------ //"sc_method_process::suspend_process" // // This virtual method suspends this process and its children if requested to. // descendants = indicator of whether this process' children should also // be suspended //------------------------------------------------------------------------------ void sc_method_process::suspend_process( sc_descendant_inclusion_info descendants ) { // IF NEEDED PROPOGATE THE SUSPEND REQUEST THROUGH OUR DESCENDANTS: if ( descendants == SC_INCLUDE_DESCENDANTS ) { const std::vector<sc_object*>& children = get_child_objects(); int child_n = children.size(); for ( int child_i = 0; child_i < child_n; child_i++ ) { sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]); if ( child_p ) child_p->suspend_process(descendants); } } // CORNER CASE CHECKS, THE FOLLOWING ARE ERRORS: // (a) if this method has a reset_signal_is specification // (b) if this method is in synchronous reset if ( !sc_allow_process_control_corners && m_has_reset_signal ) { report_error(SC_ID_PROCESS_CONTROL_CORNER_CASE_, "attempt to suspend a method that has a reset signal"); } else if ( !sc_allow_process_control_corners && m_sticky_reset ) { report_error(SC_ID_PROCESS_CONTROL_CORNER_CASE_, "attempt to suspend a method in synchronous reset"); } // SUSPEND OUR OBJECT INSTANCE: // // (1) If we are on the runnable queue then set suspended and ready_to_run, // and remove ourselves from the run queue. // (2) If this is a self-suspension then a resume should cause immediate // scheduling of the process. m_state = m_state | ps_bit_suspended; if ( next_runnable() != 0 ) { m_state = m_state | ps_bit_ready_to_run; simcontext()->remove_runnable_method( this ); } if ( sc_get_current_process_b() == DCAST<sc_process_b*>(this) ) { m_state = m_state | ps_bit_ready_to_run; } }
//------------------------------------------------------------------------------ //"sc_method_process::resume_process" // // This method resumes the execution of this process, and if requested, its // descendants. If the process was suspended and has a resumption pending it // will be dispatched in the next delta cycle. Otherwise the state will be // adjusted to indicate it is no longer suspended, but no immediate execution // will occur. //------------------------------------------------------------------------------ void sc_method_process::resume_process( sc_descendant_inclusion_info descendants ) { // IF NEEDED PROPOGATE THE RESUME REQUEST THROUGH OUR DESCENDANTS: if ( descendants == SC_INCLUDE_DESCENDANTS ) { const std::vector<sc_object*>& children = get_child_objects(); int child_n = children.size(); for ( int child_i = 0; child_i < child_n; child_i++ ) { sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]); if ( child_p ) child_p->resume_process(descendants); } } // BY DEFAULT THE CORNER CASE IS AN ERROR: if ( !sc_allow_process_control_corners && (m_state & ps_bit_disabled) && (m_state & ps_bit_suspended) ) { m_state = m_state & ~ps_bit_suspended; report_error( SC_ID_PROCESS_CONTROL_CORNER_CASE_, "call to resume() on a disabled suspended method"); } // CLEAR THE SUSPENDED BIT: m_state = m_state & ~ps_bit_suspended; // RESUME OBJECT INSTANCE: // // If this is not a self-resume and the method is ready to run then // put it on the runnable queue. if ( m_state & ps_bit_ready_to_run ) { m_state = m_state & ~ps_bit_ready_to_run; if ( next_runnable() == 0 && ( sc_get_current_process_b() != DCAST<sc_process_b*>(this) ) ) { simcontext()->push_runnable_method(this); remove_dynamic_events(); } } }
//------------------------------------------------------------------------------ // Function: get_children // Returns vector of pointers to children // // Returns: // vec - vector of pointers to children //------------------------------------------------------------------------------ std::vector<uvm_component*> uvm_component::get_children() { std::vector<sc_object*> child_vec; std::vector<uvm_component*> child_comp_vec; uvm_component* comp = NULL; child_vec = get_child_objects(); for (int i = 0; i < child_vec.size(); i++) { comp = DCAST<uvm_component*>(child_vec[i]); if (comp != NULL) child_comp_vec.push_back(comp); } return child_comp_vec; }
//------------------------------------------------------------------------------ //"sc_method_process::disable_process" // // This virtual method disables this process and its children if requested to. // descendants = indicator of whether this process' children should also // be suspended //------------------------------------------------------------------------------ void sc_method_process::disable_process( sc_descendant_inclusion_info descendants ) { // IF NEEDED PROPOGATE THE SUSPEND REQUEST THROUGH OUR DESCENDANTS: if ( descendants == SC_INCLUDE_DESCENDANTS ) { const std::vector<sc_object*>& children = get_child_objects(); int child_n = children.size(); for ( int child_i = 0; child_i < child_n; child_i++ ) { sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]); if ( child_p ) child_p->disable_process(descendants); } } // DON'T ALLOW CORNER CASE BY DEFAULT: if ( !sc_allow_process_control_corners ) { switch( m_trigger_type ) { case AND_LIST_TIMEOUT: case EVENT_TIMEOUT: case OR_LIST_TIMEOUT: case TIMEOUT: report_error( SC_ID_PROCESS_CONTROL_CORNER_CASE_, "attempt to disable a method with timeout wait" ); break; default: break; } } // DISABLE OUR OBJECT INSTANCE: m_state = m_state | ps_bit_disabled; // IF THIS CALL IS BEFORE THE SIMULATION DON'T RUN THE METHOD: if ( !sc_is_running() ) { sc_get_curr_simcontext()->remove_runnable_method(this); } }