/******************************************************************************* * Copyright (C) 2024 Juan Neyra * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ******************************************************************************/ #include "router_cs.h" #include "ratatoskrUtils/utils/Structures.h" #include "traffic/PacketCS.h" TlmRouterCS::TlmRouterCS(sc_module_name name, uint8_t rout_pos[3], uint8_t max_pos[3]): TlmRouter(name, rout_pos, max_pos) { } TlmRouterCS::~TlmRouterCS(){ } void TlmRouterCS::initialize(){ TlmRouter::initialize(); cout<<"Inherited function called"; for(int link=0; linknb_transport_fw( *new_trans, phase, delay); curr_req[dest_link] = new_trans; credit_counter[dest_link]--; log_info(link, trans, "credits value updated: " + to_string(credit_counter[link])); // react to result if(status == TLM_COMPLETED) { log_error(link, trans, "Request completed prematurely"); curr_req[dest_link] = 0; check_transaction(link, *new_trans); credit_counter[dest_link]++; log_info(link, trans, "credits value updated: " + to_string(credit_counter[dest_link])); new_trans->release(); } } void TlmRouterCS::configure_router(int link, tlm_gp& trans){ log_info(link, trans, "Configure router"); // get link and destination unsigned char* data_ptr = trans.get_data_ptr(); Flit* rec_flit = reinterpret_cast(data_ptr); PacketCS* rec_packet = reinterpret_cast(rec_flit->packet); int config_link = rec_packet->msg.config_link; int destination = rec_packet->msg.dest_link; // set auto router map log_info(link, trans, "Set auto route of link "+DIR::toString(config_link) + " to "+DIR::toString(destination)); set_auto_router_map(config_link, Dir(destination)); } /******************* INIT SOCKET FUNCTIONS ********************/ tlm_sync_enum TlmRouterCS::nb_transport_bw_cb(int id, tlm_gp& trans, tlm_phase& phase, sc_time& delay) { log_info(id, trans, "Backward transport callback start CS"); init_peq.notify(trans, phase, delay); return TLM_ACCEPTED; } void TlmRouterCS::init_peq_cb(tlm_gp& trans, const tlm_phase& phase){ int link = get_link_from_extension(trans); log_info(link,trans, "Initiator PEQ callback start"); log_info(link,trans, "Phase "+string(phase.get_name())+" received"); if (phase != END_REQ){ log_error(link,trans,"Illegal transaction phase received by initiator"); } check_transaction(link, trans); } /******************* TARGET SOCKET FUNCTIONS ********************/ void TlmRouterCS::target_peq_cb(tlm_gp& trans, const tlm_phase& phase){ int link = DIR::getOppositeDir(get_link_from_extension(trans)); log_info(link, trans, "Target PEQ callback start CS"); log_info(link, trans, "Phase "+string(phase.get_name())+" received"); switch (phase) { case BEGIN_REQ: trans.acquire(); send_end_req(link, trans); break; default: if(phase == INTERNAL_PROC_PHASE){ switching(link, trans); } else if(phase == CONF_ROUT_PHASE){ configure_router(link, trans); } else{ log_error(link, trans, "Illegal transaction phase received by target"); } break; } } tlm_sync_enum TlmRouterCS::send_end_req(int link, tlm_gp& trans){ log_info(link, trans, "Send end request start"); // Queue the acceptance and the response with the appropriate latency sc_time delay = sc_time(REQ_END_DELAY, UNITS_DELAY); tlm_phase phase = END_REQ; tlm_sync_enum status = (*target_socket[link])->nb_transport_bw( trans, phase, delay); if (status == TLM_COMPLETED) { log_warn(link, trans, "Request completed, no response to be send"); trans.release(); return status; } delay = SC_ZERO_TIME; // no processing in circuit switching routers // Queue internal event to mark beginning of response string type_name = get_type_name(get_type_from_extension(trans)); phase = (type_name == TYPE_STREAM) ? INTERNAL_PROC_PHASE : CONF_ROUT_PHASE; log_info(link, trans, "Type of processed message: " + type_name); target_peq.notify(trans, phase, delay); return status; } void TlmRouterCS::switching(int link, tlm_gp& trans){ log_info(link, trans, "Switching start"); trans.set_response_status(TLM_OK_RESPONSE); // arbitration and send message to next router Dir destination = routing(link, trans); bool data_sent; if (destination == Dir::num_dirs) { data_sent = true; check_transaction(link, trans); // change to fatal? log_warn(link, trans, "Routing failed. Message couldn't be delivered"); } else{ data_sent = send_data(link, destination, trans); } // validate pending data sent if (!data_sent) { log_error(link, trans, "Attempt to have pending data in same destination"); } } int TlmRouterCS::get_type_from_extension(tlm_gp& trans){ link_extension* extension; trans.get_extension(extension); return extension->data_type; }