/******************************************************************* * * DESCRIPTION: class TransportDelayCell * * AUTHOR: Amir Barylko & Jorge Beyoglonian * Version 2: Daniel Rodriguez. * Version 3: Gabriel Wainer * Version 4: Qi (Jacky) Liu * * EMAIL: mailto://amir@dc.uba.ar * mailto://jbeyoglo@dc.uba.ar * mailto://drodrigu@dc.uba.ar * mailto://liuqi@sce.carleton.ca * * DATE: 27/06/1998 * DATE: 03/07/1999 (v2) * DATE: 06/02/2000 * DATE: 11/01/2006 (v4) * * Suggested changes: * 21/04/2001 - Alejandro Troccoli. * In the output queue, save the output time instead of the delay. * This saves processing time because it is no longer necessary to update the remaining time * every time a new internal transition occurs. * *******************************************************************/ // ** include files **// #include "tdcell.h" // header class #include "message.h" // class InternalMessage #include "coupcell.h" // CoupledCell #include "realfunc.h" // calculateWithQuantum #include "strutil.h" #include "JackyDebugStream.h" //jacky-debug-mode /******************************************************************* * TRANSPORT DELAY CELL STATE *******************************************************************/ /****************************************************************** * Method: operator= ******************************************************************/ TDCellState &TDCellState::operator=(TDCellState& thisState) { (AtomicCellState &)*this = (AtomicCellState &)thisState; queueVal = thisState.queueVal; transientVal = thisState.transientVal; //JACKY_SYNC recordTime = thisState.recordTime; //JACKY_PORTIN_FIRST [2006-01-06] //copy the saved values of state variables at the beginning of Round 0 vars_round0 = thisState.vars_round0; //JACKY_STATE_VAR [2006-01-10] return *this; } /************************************************************************ * Method: copyState ************************************************************************/ void TDCellState::copyState(BasicState *rhs){ //JACKY_REVISION 10-17-2005 *this = *((TDCellState *) rhs); } /*************************************** * Method: getSize() ***************************************/ int TDCellState::getSize() const { return sizeof(TDCellState); } /************************************************************************ * TRANSPORT DELAY CELL ************************************************************************/ TransportDelayCell::TransportDelayCell( const CellPosition& cellPos, const string &name, const LocalTransAdmin::Function &fn ) : AtomicCell( cellPos, name, fn ) { } /******************************************************************* * Method: initializeCell ********************************************************************/ void TransportDelayCell::initializeCell() { AtomicCell::initializeCell(); //This function requires the cell state to be already created. if ( UseQuantum().Active() ) QuantumValue( Real(UseQuantum().Value()) ); } /******************************************************************* * Method: initFunction * Description: ********************************************************************/ Model &TransportDelayCell::initFunction() { PortList::iterator cursor; #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); #endif //To start the simulation, hold in for 0 time and queue the present value in the output queue list. //This will cause all models to evaluate their local transition function at time zero. for (cursor = outNCPortList().begin(); cursor != outNCPortList().end(); cursor++) { string out_port(cursor->second->name()); string in_port(calculateInPort(out_port)); TDCellState::QueueValue QV(out_port, value(in_port)); //create a QueueValueWithFlag, pair< QueueValue, boolFlag > //the default value for the boolFlag is FALSE TDCellState::QueueValueWithFlag QVF(QV, false); //element of TransientQueue //create a QueueValueWithScheduleTime, pair< QueueValue, VTime > //the scheduleTime is set to Zero //JACKY_TDCELL [2006-01-11] TDCellState::QueueValueWithScheduleTime QVST(QV, VTime::Zero); #ifdef JACKY_DEBUG jacky_os << "\t------------> TDCell::initFunction() -> push element on the Queue" << endl << flush; jacky_os << "\t------------> TDCell::initFunction() -> push element <" << out_port << " = " << value(in_port) << " / flag = FALSE> on the TransientQueue!" << endl << flush; #endif //JACKY_SYNC //push the QueueValueWithFlag, pair , onto the transient queue //initialize T to the initial value on the neighborChange & in_XXX ports of the cell transientVal().push_back( QVF ); //JACKY_TDCELL [2006-01-11] push the QVST on to the Queue queueVal().push_back( TDCellState::QueueElement( VTime::Zero, QVST ) ); } //JACKY_PORTIN_FIRST [2006-01-06] initialize the RT to Zero setRecordTime( VTime::Zero ); //JACKY_STATE_VAR [2006-01-10] //save the StateVars (variables) in AtomicCellState to the StateVars (vars_round0) in TDCellState recordStateVariables() = cellStateVariables(); #ifdef JACKY_DEBUG jacky_os << "\t[2006-01-10] StateVariables in AtomicCellState = " << cellStateVariables().asString() << endl << flush; jacky_os << "\t[2006-01-10] Recorded StateVariables in TDCellState = " << recordStateVariables().asString() << endl << flush; #endif holdIn(AtomicState::active, VTime::Zero); #ifdef JACKY_DEBUG //this is the number to record the number of the Round in the multiple-round message passing roundNum = 0; #endif //end JACKY_DEBUG return *this; } /******************************************************************* * Method: externalFunction ********************************************************************/ Model &TransportDelayCell::externalFunction( const MessageBag &msgs ) { //Jacky: this function is to set the received Y message to the input port on this cell // Must be called at the very beginning of this function to ensure that the P value is updated!!! localTransitionConfluent( msgs ); #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << endl << "\t------------->TDCell::externalFunction() called() " << endl << flush; #endif /* #ifdef JACKY_DEBUG jacky_os << "[~~PORT~~] inputPort() [in] -> " << flush; if( inputPort().size() == 0 ){ jacky_os << "NO InputPort -----" << endl << flush; } else { PortList::const_iterator inputPortCursor = inputPort().begin(); for( ; inputPortCursor != inputPort().end(); inputPortCursor++ ){ jacky_os << inputPortCursor->second->name() << " " << flush; } jacky_os << endl << flush; } jacky_os << "[~~PORT~~] outPortList() [output] -> " << flush; if( outPortList().size() == 0 ){ jacky_os << "NO OutputPort -----" << endl << flush; } else { PortList::const_iterator outPortCursor = outPortList().begin(); for( ; outPortCursor != outPortList().end(); outPortCursor++ ){ jacky_os << outPortCursor->second->name() << " " << flush; } jacky_os << endl << flush; } jacky_os << "[~~PORT~~] inNCPortList() [Xports] -> " << flush; if( inNCPortList().size() == 0 ){ jacky_os << "NO Xport -----" << endl << flush; } else { PortList::const_iterator inNCPortCursor = inNCPortList().begin(); for( ; inNCPortCursor != inNCPortList().end(); inNCPortCursor++ ){ jacky_os << inNCPortCursor->second->name() << " " << flush; } jacky_os << endl << flush; } jacky_os << "[~~PORT~~] outNCPortList() [Yports] -> " << flush; if( outNCPortList().size() == 0 ){ jacky_os << "NO Yport -----" << endl << flush; } else { PortList::const_iterator outNCPortCursor = outNCPortList().begin(); for( ; outNCPortCursor != outNCPortList().end(); outNCPortCursor++ ){ jacky_os << outNCPortCursor->second->name() << " " << flush; } jacky_os << endl << flush; } jacky_os << "[~~PORT~~] NCPortNames() [NCPortNames] -> " << flush; if( NCPorts().size() == 0 ){ jacky_os << "NO NCPortNames -----" << endl << flush; } else { list::const_iterator ncPortNameCursor = NCPorts().begin(); for( ; ncPortNameCursor != NCPorts().end(); ncPortNameCursor++ ){ jacky_os << (*ncPortNameCursor) << " " << flush; } jacky_os << endl << flush; } #endif */ //JACKY_TDCELL [2006-01-11] bool timeChanged; //let's check whether there is a time change (usually time advance, but time //can go back in case of a rollback) if( getRecordTime() != msgs.time() ){ //there is a time change #ifdef JACKY_DEBUG jacky_os << "\t\t!!!!! TDCell::externalFunction() Time Change !!!!!" << endl << flush; jacky_os << "\t\t Before Update: RT = " << getRecordTime().asString() << endl << flush; #endif //update the RT setRecordTime( msgs.time() ); // [2006-01-13] // This seems not necessary since we will reset all values on the transient queue // to the previous values anyway ! //reset the flags in TransientValue to FALSE for the new time resetTransientFlags( transientVal() ); //JACKY_TDCELL [2006-01-11] set the "time change" flag to true timeChanged = true; //JACKY_TDCELL [2006-01-13] // Now, the simulated time has changed, this time change could happen in one the // following two scenarios: // 1. If this cell is imminent, the time change is triggered by an @ message from // the NC. In this case, the outputFunction and internalFunction have been called // before this function. // -> a> // if this cell's neighborhood is defined to include (0,0), i.e. the cell itself, // the Y message from the outputFunction has been received by this cell itself ( // this is done by function localTransitionConfluent( msgs ), which must be called // at the very beginning of this function!!!!) // // Thus, the previousValue (P) is updated to be the last newValue (N) & the last // transientValue (T). Therefore, we have P = T = last N. // [P is actually the cell's current state value!] // // -> b> // if the cell's neighborhood does not include (0,0), the Y message sent by this // cell will not be received by this cell itself. Thus, P is NOT updated to the // last N (which is also the last T). Therefore, P != T & P != last N // // 2. If this cell is not imminent at all, the time change is triggered by some X messages // from the cell's neighbors followed by a * message. In this case, the outputFunction // and internalFunction is NOT called before this function. // -> As a result, this cell has no chance to update its P to T (or the last N). So // P may or may not be equal to T // // As we can see, P != T can happen in 1.b> or in 2. In order to make the following conditions // for "new state change", "change back", and "change further" correct, we have to update T to // be P whenever we detect a time change! // Update T = P just like we did in the initFunction! PortList::iterator port_cursor; for (port_cursor = outNCPortList().begin(); port_cursor != outNCPortList().end(); port_cursor++) { string out_port(port_cursor->second->name()); // output port name string in_port(calculateInPort(out_port)); // corresponding input port name Real currentPreviousValue = value(in_port); //set the T value on this output port, flag = FALSE setTransientValue(out_port, currentPreviousValue); //Note: this will reset the flags in transient values to FALSE as well, so // we can spare calling resetTransientFlags() } //end for [update T to P] //Now we can make sure P = T when we enter the if conditions for any NEW TIME! //end [2006-01-13] #ifdef JACKY_DEBUG jacky_os << "\t TDCell::externalFunction() After Update: RT = " << getRecordTime().asString() << endl << flush; jacky_os << "\t Reset flags in TQ to FALSE!!!!-------" << endl << flush; jacky_os << "\t [2006-01-13] NOTE: T is set to P for this new time!!!!" << endl << flush; //reset the round number to 0 roundNum = 0; #endif //end JACKY_DEBUG //JACKY_STATE_VAR [2006-01-10] save the state variables in the RV recordStateVariables() = cellStateVariables(); #ifdef JACKY_DEBUG jacky_os << "\t[2006-01-10] TDCell ROUND " << roundNum << ", save state variables, SV = " << recordStateVariables().asString() << endl << flush; #endif //end JACKY_DEBUG } //end if time change else { //JACKY_TDCELL [2006-01-11] //set the "time change" flag to false timeChanged = false; #ifdef JACKY_DEBUG //No time change happens, so these are the following rounds! ++roundNum; //increase the number of the round #endif //end JACKY_DEBUG } //This is should be removed once the new Cell Devs definition language is //approved and considers multiple messages from external models bool executedLocal = false; //here, delay is the default delay as defined in the MA file VTime delay( static_cast( parent() )->defaultDelay() ) ; //[2006-01-11] //this is the current simulated time, which is also the schedule time for all queue elements VTime actualTime( msgs.time() ); //JACKY_STATE_VAR [2006-01-10] //Before we evaluate the transition functions, reset the state variables using the recorded one cellStateVariables() = recordStateVariables(); #ifdef JACKY_DEBUG jacky_os << "\t[2006-01-10] TDCell: ROUND " << roundNum << " Restore state variables, V = " << cellStateVariables().asString() << endl << flush; #endif //end JACKY_DEBUG list tv; //Jacky: a list of , NewValues! ////////////////////////////////////////////////////////////////////// //Right now, for this implementation, give priority to portInTransitions //This should be changed! for ( MessageBag::iterator cursor = msgs.begin(); cursor != msgs.end(); cursor++) { ExternalMessage msg = *((ExternalMessage *)(*cursor)); if( !executedLocal && !isInNCPort( msg.port().name() ) ) { string functionName = inputPortFunction()[ msg.port().name() ]; if (functionName == DEFAULT_FUNCTION_InPort) { PortValue pv(msg.port().name(), msg.value()); tv.push_back(pv); } else { // sino es un PortInTransition valido VirtualPortList *vpl = new VirtualPortList; getOutPorts(vpl); tv = SingleLocalTransAdmin::Instance().evaluate( functionName, neighborhood(), &(inputPortValues()), delay, actualTime, vpl, this, msg.port().name() ) ; delete vpl; }//if executedLocal = true; }//if else if ( executedLocal && !isInNCPort( msg.port().name() ) ) { cerr << "At: " << msgs.time() << endl; cerr << "Warning: Current implementation can not handle multiple messages" << " from external models!!. Some messages have been ignored!" << endl; MASSERTMSG( false, "TDCell::externalFunction() -> check the EV file! Multiple inputs to a cell at the same time!" ); } }//for //If there were no messages in ports that were not neighbor ports if ( !executedLocal ) { VirtualPortList *vpl = new VirtualPortList; getOutPorts(vpl); tv = SingleLocalTransAdmin::Instance().evaluate( localFunction(), neighborhood(), NULL, delay, actualTime, vpl, this ) ; delete vpl; } #ifdef JACKY_DEBUG jacky_os << "\t\tTDCell::externalFunction() resulting (tv) is ---------------------- " << endl << flush; list::iterator tv_it; for (tv_it = tv.begin(); tv_it != tv.end(); tv_it++){ jacky_os << "\t\t\t" << tv_it->first << " = " << (tv_it->second).value() << endl << flush; } jacky_os << "\t\tTDCell::externalFunction() BEFORE COMPARISON, [transientQ] is ==========" << endl << flush; TDCellState::TransientQueue::const_iterator transientQ_it; //print the Transient Queue for (transientQ_it = transientVal().begin(); transientQ_it != transientVal().end(); transientQ_it++){ jacky_os << "\t\t" << (transientQ_it->first).first // portName << " = " << (transientQ_it->first).second.value() << " / "<< flush; // portValue if(transientQ_it->second == true){ // flag in TQ jacky_os << "flag = TRUE" << endl << flush; } else { jacky_os << "flag = FALSE" << endl << flush; } } #endif /////////////////////////////////////////////////////////////////////// Real ltb; // Previous value (P) Real tranValue; // Transient value (T) //JACKY_SYNC bool tranValueFlag; // Transient flag (TF) //JACKY_PORTIN_FIRST [2006-01-06] //[2006-01-11] //valueTime is the output time (OT) when the internal event on the queue will be output VTime valueTime = actualTime + delay; list::iterator pvCursor; //cout << "Cell: " << cellPosition().print() << endl; //cout << "UseQuantum().Active() " << UseQuantum().Active() << " UseDynQuantum().Active() " // << UseDynQuantum().Active() << endl; //cout << "tv = " << tv.asString() << " ltb = " << ltb.asString() << endl; //cout << "valueWithQuantum(tv, QuantumValue() = " << valueWithQuantum(tv, QuantumValue()).asString() << endl; //cout << "valueWithQuantum(ltb, QuantumValue() = " << valueWithQuantum(ltb, QuantumValue()).asString() << endl; #ifdef JACKY_DEBUG int for_count = 0; #endif /****************************************************************************************************************** ** Jacky Note: ** "tv" (a list of ) ---> contains the NewValues calculated from the inputPortFunction & the ** localFunction. ** In the following iteration over the "tv" list, we first get the PreviousValues from the corresponding ** "neighborChange" or "in_XXX" or other input ports in "ltb", and then compare the corresponding NewValue in ** "tv" and the PreviousValue in "ltb" ** 1. if a> Quantization (static or dynamic) is used && the quantized values are different OR ** b> Quantization is NOT used && the values are different ** -> state change happens! insert element onto the Queue ** 2. if dynamic quantization is used, adjust the Quantum size based on the comparison of the quantized values ** ** In my revision, the transientVal list holds temporary values on all output port of the cell ** We will go through the values in the "tv" (the NewValues), compare the three values: ** A> previous value : "ltb" ** B> transient value: value in the TransientQueue ** C> new value : value in the "tv" ** There are 5 possibilities [see document] */ //iterate over all new values for (pvCursor = tv.begin(); pvCursor != tv.end(); pvCursor++){ #ifdef JACKY_DEBUG jacky_os << "\t\t***TDCell::externalFunction() for(" << for_count << ") NEW value: <" << pvCursor->first << " = " << (pvCursor->second).value() << ">" << endl << flush; #endif string in_port = calculateInPort(pvCursor->first); string out_port = calculateOutPort(pvCursor->first); ltb = value(in_port); //Jacky: P tranValue = getTransientValue(out_port); //Jacky: T tranValueFlag = getTransientValueFlag(out_port); //Jacky: TF #ifdef JACKY_DEBUG jacky_os << "[PORT TRANSFER] tv::portName = " << pvCursor->first << " / in_port = " << in_port << " / corresponding out_port = " << out_port << endl << flush; jacky_os << "\t\t\t PREVIOUS value: <" << in_port << " = " << ltb.value() << ">" << endl << flush; jacky_os << "\t\t\t TRANSIENT value: <" << out_port << " = " << tranValue.value() << "> [flag = " << flush; if( tranValueFlag == true ){ jacky_os << "TRUE" << endl << flush; } else { jacky_os << "FALSE" << endl << flush; } jacky_os << "\t\t for(" << for_count << ") BEFORE: Queue size = " << queueVal().size() << " : " << endl << flush; list::iterator q_it; int q_count = 0; //print the current Queue for (q_it = queueVal().begin(); q_it != queueVal().end(); q_it++){ jacky_os << "\t\t\t[" << ++q_count << "] OT = " << (q_it->first).asString() //output time << " / " << (q_it->second).first.first << " = " //portName << (q_it->second).first.second.value() << " / " << flush; //portValue jacky_os << "ST = " << (q_it->second).second.asString() << endl << flush; //schedule time } #endif // [2006-01-06] //The following condition is added to avoid offset results derived from external events //Change back & change further of the cell state is only allowed if no external event received at this time //Once an event is received: // if the event causes a state change -> change the state, and set flag=TRUE, thus no further change // if the event does not cause a change -> just set flag=TRUE, thus no further change as well // for ALL the message-passing rounds at this time. // When time changes, the flag will be reset to false. if( tranValueFlag == false ){ // if flag in T is FALSE, i.e. TF = FALSE //1> new state change happens if( ( ( UseQuantum().Active() || UseDynQuantum().Active() ) && ( valueWithQuantum(pvCursor->second, QuantumValue()) != valueWithQuantum(ltb, QuantumValue()) ) && //N != P ( valueWithQuantum(ltb, QuantumValue()) == valueWithQuantum(tranValue, QuantumValue()) ) //P == T ) || ( !UseQuantum().Active() && ( ltb != pvCursor->second ) && //N != P ( ltb == tranValue ) //P == T ) ) { #ifdef JACKY_DEBUG jacky_os << "\t\t\t 1> new state change " << endl << flush; #endif //a> set T = N if( isInputPort(pvCursor->first) ){ //Value change is derived from external event! //set the flag in the transient value to TRUE setTransientValue(out_port, pvCursor->second, true); } else { setTransientValue(out_port, pvCursor->second); } //end update [T] //b> Queue insertion TDCellState::Queue::iterator cursorAux; for ( cursorAux = queueVal().begin(); cursorAux != queueVal().end() && cursorAux->first <= valueTime; cursorAux++ ); //Jacky: Now cursorAux points to the 1st element with time > valueTime or NULL // the new element will be inserted before cursorAux //Jacky: create a new element with NEW value to be inserted onto the Queue TDCellState::QueueValue qv(out_port, pvCursor->second); //JACKY_TDCELL [2006-01-11] no flag in queue elements, but there is a schedule time //the schedule time is actualTime TDCellState::QueueValueWithScheduleTime qvst(qv, actualTime); //insert the qvst onto the queue at the place given by "cursorAux" //the output time is valueTime queueVal().insert( cursorAux, TDCellState::QueueElement(valueTime, qvst) ); holdIn( AtomicState::active, firstQueuedTime() - msgs.time() ); } //end if 1> [new state change] //2> change back else if( ( ( UseQuantum().Active() || UseDynQuantum().Active() ) && ( valueWithQuantum(pvCursor->second, QuantumValue()) == valueWithQuantum(ltb, QuantumValue()) ) && //N == P ( valueWithQuantum(ltb, QuantumValue()) != valueWithQuantum(tranValue, QuantumValue()) ) && //P != T ( valueWithQuantum(pvCursor->second, QuantumValue()) != valueWithQuantum(tranValue, QuantumValue()) ) //N != T ) || ( !UseQuantum().Active() && ( pvCursor->second == ltb ) && //N == P ( ltb != tranValue ) && //P != T ( pvCursor->second != tranValue ) //N != T ) ) { //[2006-01-11] [Change Back] reset T = P if( isInputPort(pvCursor->first) ){ //Value change is derived from external event! //set the flag in the transient value to TRUE setTransientValue(out_port, ltb, true); } else { setTransientValue(out_port, pvCursor->second); } //end update [T] //[2006-01-11] search scheduleTime //if this is within the process of multiple-round message passing, we need //to do Queue Removal; if it is not (i.e. getRecordTime() != msgs.time(), //msgTime has changed), we do nothing here! if( !timeChanged ){ //[2006-01-11] //Time has not changed, we are within the multiple rounds at the given time! //Do Queue removal! //b> Queue removal TDCellState::Queue::iterator cursorAux; #ifdef JACKY_DEBUG jacky_os << "[TD VARIABLE DELAY 3] MultipleRound! Change Back -> find element with [ST = " << actualTime.asString() << " & PORT = " << out_port << "] on the Queue" << endl << flush; #endif bool found = false; for ( cursorAux = queueVal().begin(); cursorAux != queueVal().end(); cursorAux++) { //scheduleTime = actualTime if( ( (cursorAux->second).second == actualTime ) && ( (cursorAux->second).first.first == out_port ) ) { //same schedule time & same port found = true; break; } } #ifdef JACKY_DEBUG if( found ){ jacky_os << "\t\t\t\t--> previous element with [ST = " << actualTime.asString() << " / port = " << out_port << "] found, remove from the Queue!" << endl << flush; } else { jacky_os << "\t\t\t\t--> No element with [ST = " << actualTime.asString() << " / port = " << out_port << "] is found, REMOVAL FAILED! [Variable Delays used? ]" << endl << flush; } #endif MASSERTMSG( found, "TDCell::externalFunction()->no element found, ChangeBack:Removal failed!"); queueVal().erase( cursorAux ); if( !queueVal().empty() ){ holdIn( AtomicState::active, firstQueuedTime() - msgs.time() ); } else { passivate(); } } //end if ( !timeChanged ) else { //The time has changed, it's NOT within the multiple rounds! //In this case, since N = P (i.e. No state change), no new element should be //added onto the Queue, nor do we need to remove some element from the Queue //leave the Queue along & no state change! #ifdef JACKY_DEBUG jacky_os << "[2006-01-11]TDCell:ChangeBack & timeChanged = TRUE -> Not in multiple rounds! NO REMOVAL!" << endl << flush; #endif } //end if ( timeChanged ) } //end if 2> [change back] //3> change further else if( ( ( UseQuantum().Active() || UseDynQuantum().Active() ) && ( valueWithQuantum(pvCursor->second, QuantumValue()) != valueWithQuantum(ltb, QuantumValue()) ) && //N != P ( valueWithQuantum(ltb, QuantumValue()) != valueWithQuantum(tranValue, QuantumValue()) ) && //P != T ( valueWithQuantum(pvCursor->second, QuantumValue()) != valueWithQuantum(tranValue, QuantumValue()) ) //N != T ) || ( !UseQuantum().Active() && ( pvCursor->second != ltb ) && //N != P ( ltb != tranValue ) && //P != T ( pvCursor->second != tranValue ) //N != T ) ) { //[2006-01-11] [Change Further] reset T = N if( isInputPort(pvCursor->first) ){ //Value change is derived from external event! //set the flag in the transient value to TRUE setTransientValue(out_port, pvCursor->second, true); } else { setTransientValue(out_port, pvCursor->second); } //end update [T] //[2006-01-11] //if this is within the process of multiple-round message passing, we need //to do Queue Replacement; if it is not (i.e. getRecordTime() != msgs.time(), //msgTime has changed), we do Queue Insertion here (i.e. a new state change //happened at a new time)! if( !timeChanged ){ //[2006-01-11] //Time has not changed, we are within the multiple rounds at the given time! //Do Queue replacement! #ifdef JACKY_DEBUG jacky_os << "[TD VARIABLE DELAY 4] Change Further! find element with [ST = " << actualTime.asString() << " / PORT = " << out_port << "] on the Queue" << endl << flush; #endif //b> Queue replacement TDCellState::Queue::iterator cursorAux; bool found = false; for ( cursorAux = queueVal().begin(); cursorAux != queueVal().end(); cursorAux++) { //scheduleTime = actualTime if( ( (cursorAux->second).second == actualTime ) && ( (cursorAux->second).first.first == out_port ) ) { //same schedule time & same port found = true; break; } } #ifdef JACKY_DEBUG if( found ){ jacky_os << "\t\t\t\t--> previous element with [ST = " << actualTime.asString() << " / port = " << out_port << "] found, replace it on the Queue!" << endl << flush; } else { jacky_os << "\t\t\t\t--> No element with [ST = " << actualTime.asString() << " / port = " << out_port << "] is found, REPLACEMENT FAILED! [Variable Delays used? ]" << endl << flush; } #endif MASSERTMSG( found, "TDCell::externalFunction()->no element found, ChangeFurther:Replacement failed!"); //replace the value on that port (cursorAux->second).first.second = pvCursor->second; holdIn( AtomicState::active, firstQueuedTime() - msgs.time() ); } //end if ( !timeChanged ) else { //The time has changed, it's NOT within the multiple rounds! //In this case, since N != P (i.e. state change), new element should be //added onto the Queue //insert element on the queue #ifdef JACKY_DEBUG jacky_os << "[2006-01-11]TDCell:ChangeFurther & timeChanged = TRUE -> Not in multiple rounds! Q INSERTION!!!" << endl << flush; #endif //c> Queue insertion TDCellState::Queue::iterator cursorAux; for ( cursorAux = queueVal().begin(); cursorAux != queueVal().end() && cursorAux->first <= valueTime; cursorAux++ ); //Jacky: Now cursorAux points to the 1st element with time > valueTime or NULL // the new element will be inserted before cursorAux //Jacky: create a new element with NEW value to be inserted onto the Queue TDCellState::QueueValue qv(out_port, pvCursor->second); //the schedule time is actualTime TDCellState::QueueValueWithScheduleTime qvst(qv, actualTime); //insert the qvst onto the queue at the place given by "cursorAux" //the output time is valueTime queueVal().insert( cursorAux, TDCellState::QueueElement(valueTime, qvst) ); holdIn( AtomicState::active, firstQueuedTime() - msgs.time() ); } //end if ( timeChanged ) } //end if 3> [change further] // [ ****************** 2006-01-06 *********************] // Note:If the external event does not cause cell's value changes, i.e. N = P // We still need to set the flag in the TransientValue to TRUE so that further messages // from neighbors will NOT cause new changes to this cell!!! // Ex: At time 04:000, cell's value is 1 (P), and an external event arrives at the cell // at the same time 04:000 with value 1. Thus, the cell's value at time 05:000 (after // a delay of 1000) should be 1 (the same as the external event based on Default-Port-In) // The resulting tv is , which is the same as the event value. In the following // rounds of message-passing, the cell gets values from its neighbors (all 1's), and the // resulting tv is based on Local-Transition. // Since in the 1st round, the event didn't cause state change, the flag in T is NOT set // to TRUE, the cell's value will be changed to 0 in the 2nd round!!! // This is NOT what we want! We need to set the flag in T to TRUE event when the external // event does not trigger a state change in the cell! // The following else clause will set the flag in T to TRUE (but do NOT change the value in T) // if the tv is derived from an event. else { // No state change, N = P if( isInputPort(pvCursor->first) ){ // set the flag in T to TRUE // In this case, external event's value is the same as the current cell's value // No value change! And we will NOT allow any potential urther changes derived // from neighbor's values in the later rounds of message-passing //portName = out_port //value is the current value, getTransientValue(out_port) //TF = true setTransientValue(out_port, getTransientValue(out_port), true); } } // end state change } //end tranValueFlag (TF) == false else { //[2006-01-06] // If TF = TRUE, i.e. the value of the cell has been changed (or is the same as the // external event) according to the external event, do NOTHING! #ifdef JACKY_DEBUG jacky_os << "[~~PORT~~] Scheduled change is derived from events! No further change is allowed!!! ~~~~~~~~~~~~~~" << endl << flush; #endif } //If using DynamicQuantum, calculate the new Quantum value. if ( UseDynQuantum().Active() ) { #ifdef JACKY_DEBUG jacky_os << "\t\t\t Using Dynamic Quantization, change Quantum Size -------" << endl << flush; #endif if ( valueWithQuantum(pvCursor->second, QuantumValue()) == valueWithQuantum(ltb, QuantumValue())) {//Jacky: N == P if ( UseDynQuantum().Strat() ) QuantumValue ( QuantumValue() * (1-UseDynQuantum().Ratio())); else QuantumValue ( QuantumValue() * (1+UseDynQuantum().Ratio())); } //GW // Esta es una nueva modificacion: si son distintos, lo reduzco. else { // Jacky: N != P if ( !UseDynQuantum().Strat() ) QuantumValue ( QuantumValue() * (1-UseDynQuantum().Ratio())); else QuantumValue ( QuantumValue() * (1+UseDynQuantum().Ratio())); } //cout << " q act = " << QuantumValue().value() << endl; } //end if } // for each N #ifdef JACKY_DEBUG jacky_os << "\t\tTDCell::externalFunction() before END Queue size = " << queueVal().size() << " ------------- " << endl << flush; list::iterator q_it; int q_count = 0; for (q_it = queueVal().begin(); q_it != queueVal().end(); q_it++){ jacky_os << "\t\t[" << ++q_count << "] " << (q_it->first).asString() //time << " / " << (q_it->second).first.first << " = " //portName << (q_it->second).first.second.value() << " / " << flush; //portValue if( (q_it->second).second == true ){ jacky_os << " flag = TRUE" << endl << flush; } else { jacky_os << " flag = FALSE" << endl << flush; } } jacky_os << "\t\tTDCell::externalFunction() queue End -------------------- " << endl << flush; #endif return *this ; } /****************************************************************** * Method: internalFunction * Jacky : This function will remove all elements on the Queue that have * the same time as the received * msg. ********************************************************************/ Model &TransportDelayCell::internalFunction( const InternalMessage &msg ) { MASSERT( !queueVal().empty() && firstQueuedTime() == msg.time() ) ; #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "\t------------->TDCell[" << asString() << "]::internalFunction() called" << endl << flush; #endif //Delete all messages that are scheduled for the current time while (!queueVal().empty() && firstQueuedTime() == msg.time() ){ #ifdef JACKY_DEBUG jacky_os << "\t\t TDCell[" << asString() << "]::internalFunction() erase first).asString() << " / " //output time << (queueVal().begin()->second).first.first << " = " //portName << (queueVal().begin()->second).first.second.value() //portValue << " / ST = " << (queueVal().begin()->second).second.asString() //schedule time << ">" << endl << flush; #endif //end JACKY_DEBUG queueVal().erase( queueVal().begin() ); } if( queueVal().empty() ) { passivate() ; #ifdef JACKY_DEBUG jacky_os << "\t\t TDCell[" << asString() << "]::internalFunction() passivate()!" << endl << flush; #endif } else { #ifdef JACKY_DEBUG jacky_os << "\t\t TDCell[" << asString() << "]::internalFunction() stay active for period = " << ( firstQueuedTime() - msg.time() ).asString() << endl << flush; #endif holdIn( AtomicState::active, ( firstQueuedTime() - msg.time() ) ); } return *this ; } /******************************************************************* * Method: outputFunction * Jacky : This function will send all elements on the Queue that have * the same time as the time of the received @ msg ********************************************************************/ Model &TransportDelayCell::outputFunction( const CollectMessage &msg ) { //Send all messages that are scheduled for the current time TDCellState::Queue::iterator cursor; #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "\t------------->TDCell[" << asString() << "]::outputFunction() called, cellState::QueueSize = " << queueVal().size() << endl << flush; #endif for( cursor = queueVal().begin() ; cursor != queueVal().end() && cursor->first == msg.time() ; cursor++ ) { #ifdef JACKY_DEBUG jacky_os << "\t\t\t TDCell[" << asString() << "] sends value=" << (cursor->second).first.second.value() << " to port=" << outputPort((cursor->second).first.first).name() << "@" << outputPort((cursor->second).first.first).model().asString() << endl << flush; #endif sendOutput( msg.time(), outputPort((cursor->second).first.first), (cursor->second).first.second.value() ) ; } return *this ; } /******************************************************************* * Function Name: firstQueuedTime ********************************************************************/ const VTime & TransportDelayCell::firstQueuedTime() const { return queueVal().begin()->first; } /******************************************************************* * Function Name: firstQueuedValue ********************************************************************/ const Real &TransportDelayCell::firstQueuedValue() const { TDCellState::QueueValue &QV = (queueVal().begin()->second).first; return QV.second; } /******************************************************************* * Function Name: firstQueuedPort ********************************************************************/ const string &TransportDelayCell::firstQueuedPort() const { TDCellState::QueueValue &QV = (queueVal().begin()->second).first; return QV.first; } /******************************************************************* * Function Name: updateRemainingTime * Description : this function is to update the output time for all elements on the Queue to reflect the elapse of time ********************************************************************/ TransportDelayCell & TransportDelayCell::updateRemainingTime( const VTime &elapsed ) { for( TDCellState::Queue::iterator cursor = queueVal().begin() ; cursor != queueVal().end() ; cursor++ ) cursor->first -= elapsed ; return *this; } /******************************************************************* * Function Name: getTransientValue * Description : function to get the transient value on a given port ********************************************************************/ const Real &TransportDelayCell::getTransientValue(const string &portName) const{ TDCellState::TransientQueue::iterator it; bool result = false; for( it = transientVal().begin(); it != transientVal().end() ; it++){ if( (it->first).first == portName){ result = true; break; } } MASSERTMSG( result, "TDCell::getTransientValue() -> no transient value on \"" + portName + "\" is found!" ); return (it->first).second; } //function to get the flag in the transient value const bool TransportDelayCell::getTransientValueFlag(const string &portName) const{ TDCellState::TransientQueue::iterator it; bool result = false; for( it = transientVal().begin(); it != transientVal().end() ; it++){ if( (it->first).first == portName){ result = true; break; } } MASSERTMSG(result, "TDCell::getTransientValueFlag() -> no transient value flag on \"" + portName + "\" is found!"); return it->second; } //No need to use this function since PORT_IN_FIRST is based on the flag in the transient value //rather than the flag in the Queue element [2006-01-06] // [2006-01-06] //function to reset all flags in the transient queue to FALSE, //values in the transient queue are not changed // TD -> list, //where QueueValueWithFlag -> pair, QueueValue -> pair void TransportDelayCell::resetTransientFlags( TDCellState::TransientQueue &tq ){ TDCellState::TransientQueue::iterator it; for(it = tq.begin(); it != tq.end(); it++){ it->second = false; } } /******************************************************************* * Function Name: setTransientValue * Description : function to set the transient value on a given port ********************************************************************/ void TransportDelayCell::setTransientValue(const string &portName, const Real &value, const bool &flag){ TDCellState::TransientQueue::iterator it; for( it = transientVal().begin(); it != transientVal().end() ; it++){ if( (it->first).first == portName ){ (it->first).second = value; it->second = flag; } } }