tlm_noc_sim/src/router/router_cs.cpp

175 lines
6.4 KiB
C++
Raw Normal View History

/*******************************************************************************
* 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"
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(){
for(int link=0; link<NUM_LINKS; link++){
init_socket[link] = new rout_init_socket(("csnoc_"+router_name+
"_"+to_string(link)+"_init").c_str());
(*init_socket[link]).register_nb_transport_bw(this,
&TlmRouterCS::nb_transport_bw_cb, link);
target_socket[link] = new rout_targ_socket(("csnoc_"+router_name+
"_"+to_string(link)+"_targ").c_str());
(*target_socket[link]).register_nb_transport_fw(this,
&TlmRouterCS::nb_transport_fw_cb, link);
valid_links[link] = false;
//resp_in_progress[link] = false;
//nxt_resp_pend[link] = 0;
end_req_pend[link] = 0;
nxt_send_data_pend[link] = 0;
curr_req[link] = 0;
//send_data_in_prog_dest[link] = Direction::invalid;
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 TlmRouter::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]--;
// react to result
if(status == TLM_COMPLETED) {
log_error(link, "Request completed prematurely");
curr_req[dest_link] = 0;
check_transaction(link, *new_trans);
credit_counter[dest_link]++;
new_trans->release();
}
}
void configure_router(tlm_gp& trans){
// get link and destination
int* data = trans.get_data_ptr();
int link = data && 3;
int destination = data >> 2;
// set auto router map
set_auto_router_map(link, destination);
}
/******************* INIT SOCKET FUNCTIONS ********************/
tlm_sync_enum TlmRouter::nb_transport_bw_cb(int id, tlm_gp& trans,
tlm_phase& phase, sc_time& delay) {
log_info(id, "Backward transport callback start");
return TLM_ACCEPTED;
}
/******************* 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, "Target PEQ callback start");
log_info(link, "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(trans);
}
else{
log_error(link,
"Illegal transaction phase received by target");
}
break;
}
}
tlm_sync_enum TlmRouterCS::send_end_req(int link, tlm_gp& trans){
log_info(link, "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,"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
int type = get_type_from_extension(trans);
sc_phase phase = (type == TYPE_STREAM) ? INTERNAL_PROC_PHASE :
CONF_ROUT_PHASE;
target_peq.notify(trans, phase, delay);
return status;
}
void TlmRouterCS::switching(int link, tlm_gp& trans){
log_info(link, "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, "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,"Attempt to have pending data in same destination");
}
}