189 lines
7.1 KiB
C++
Executable file
189 lines
7.1 KiB
C++
Executable file
/*******************************************************************************
|
|
* 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; link<NUM_LINKS; link++){
|
|
credit_counter[link] = NUM_CREDITS_CS;
|
|
auto_rout_map[link] = Direction::invalid;
|
|
}
|
|
}
|
|
|
|
Dir TlmRouterCS::routing(int link, tlm_gp& trans){
|
|
return auto_rout_map[link];
|
|
}
|
|
|
|
void TlmRouterCS::set_auto_router_map(int link, Dir dir){
|
|
auto_rout_map[link] = dir;
|
|
}
|
|
|
|
Dir TlmRouterCS::get_auto_router_map(int link){
|
|
return auto_rout_map[link];
|
|
}
|
|
|
|
void TlmRouterCS::send_begin_req(int link, tlm_gp& trans, int dest_link){
|
|
tlm_gp* new_trans = build_transaction(trans, dest_link);
|
|
|
|
// send transaction in socket
|
|
tlm_phase phase = BEGIN_REQ;
|
|
sc_time delay = sc_time(REQ_INIT_DELAY, UNITS_DELAY);
|
|
|
|
tlm_sync_enum status;
|
|
status = (*init_socket[dest_link])->nb_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<Flit*>(data_ptr);
|
|
PacketCS* rec_packet = reinterpret_cast<PacketCS*>(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<link_extension>(extension);
|
|
return extension->data_type;
|
|
}
|