📄 at_interconnect.h
字号:
// Filename: at_interconnect.h
//----------------------------------------------------------------------
// Copyright (c) 2008 by Doulos Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//----------------------------------------------------------------------
// Version 1 09-Sep-2008
#ifndef __AT_INTERCONNECT_H__
#define __AT_INTERCONNECT_H__
#include "common_header.h"
struct AT_interconnect: sc_module
{
tlm_utils::multi_passthrough_target_socket <AT_interconnect, 32> targ_socket;
tlm_utils::multi_passthrough_initiator_socket<AT_interconnect, 32> init_socket;
SC_CTOR(AT_interconnect)
: targ_socket("targ_socket")
, init_socket("init_socket")
{
targ_socket.register_b_transport (this, &AT_interconnect::b_transport);
targ_socket.register_nb_transport_fw (this, &AT_interconnect::nb_transport_fw);
targ_socket.register_get_direct_mem_ptr (this, &AT_interconnect::get_direct_mem_ptr);
targ_socket.register_transport_dbg (this, &AT_interconnect::transport_dbg);
init_socket.register_nb_transport_bw (this, &AT_interconnect::nb_transport_bw);
init_socket.register_invalidate_direct_mem_ptr(this, &AT_interconnect::invalidate_direct_mem_ptr);
}
void end_of_elaboration()
{
n_targets = init_socket.size();
n_inits = targ_socket.size();
req_in_progress = new gp_ptr [n_targets];
rsp_in_progress = new gp_ptr [n_inits];
end_req_event = new sc_event[n_targets];
end_rsp_event = new sc_event[n_inits];
req_queue = new std::deque<Trans>[n_targets];
rsp_queue = new std::deque<Trans>[n_inits];
// Spawn one process per target, to wake up on receiving END_REQ
for (unsigned int i = 0; i < n_targets; i++)
{
sc_spawn_options* opt = new sc_spawn_options;
opt->spawn_method();
opt->dont_initialize();
opt->set_sensitivity( &end_req_event[i] );
ostringstream oss;
oss << "end_req_process" << i;
sc_spawn(sc_bind(&AT_interconnect::end_req_process, this, i), oss.str().c_str(), opt);
req_in_progress[i] = 0;
}
// Spawn one process per initiator, to wake up on receiving END_RESP
for (unsigned int i = 0; i < n_inits; i++)
{
sc_spawn_options* opt = new sc_spawn_options;
opt->spawn_method();
opt->dont_initialize();
opt->set_sensitivity( &end_rsp_event[i] );
ostringstream oss;
oss << "end_rsp_process" << i;
sc_spawn(sc_bind(&AT_interconnect::end_rsp_process, this, i), oss.str().c_str(), opt);
rsp_in_progress[i] = 0;
}
}
// Forward interface
virtual void b_transport( int id, tlm::tlm_generic_payload& trans, sc_time& delay )
{
sc_dt::uint64 masked_address;
unsigned int target = decode_address( trans.get_address(), masked_address );
trans.set_address( masked_address );
init_socket[target]->b_transport( trans, delay );
}
virtual tlm::tlm_sync_enum nb_transport_fw( int id, tlm::tlm_generic_payload& trans,
tlm::tlm_phase& phase, sc_time& delay )
{
unsigned int target;
// Sticky extension, survives the transaction pool
route_extension* ext;
accessor(trans).get_extension(ext);
bool is_request = (phase == tlm::BEGIN_REQ);
if (phase == tlm::BEGIN_REQ)
{
sc_dt::uint64 masked_address;
target = decode_address( trans.get_address(), masked_address );
trans.set_address( masked_address );
if (!ext)
{
ext = new route_extension;
accessor(trans).set_extension(ext);
}
ext->init = id;
ext->target = target;
ext->dont_propagate_fw = false;
if (req_in_progress[target])
{
// Queue the request to be sent forward later
trans.acquire();
Trans req;
req.trans = &trans;
req.time = sc_time_stamp() + delay;
req_queue[target].push_back( req );
return tlm::TLM_ACCEPTED;
}
req_in_progress[target] = &trans;
}
else if (phase == tlm::END_RESP)
{
assert(ext);
assert( ext->init == id );
target = ext->target;
assert( rsp_in_progress[ext->init] );
end_rsp_event[ext->init].notify();
if (ext->dont_propagate_fw)
return tlm::TLM_ACCEPTED;
}
tlm::tlm_sync_enum status;
status = init_socket[target]->nb_transport_fw( trans, phase, delay );
if (status == tlm::TLM_UPDATED)
{
if ((phase == tlm::END_REQ) || (phase == tlm::BEGIN_RESP))
{
assert( req_in_progress[target] );
end_req_event[target].notify();
}
// Need to check response exclusion rule here before passing BEGIN_RESP on return path!
if (phase == tlm::BEGIN_RESP)
{
if (rsp_in_progress[id])
{
queue_the_rsp_to_be_sent_bw_later( id, &trans, delay );
return tlm::TLM_ACCEPTED;
}
rsp_in_progress[id] = &trans;
}
}
else if (status == tlm::TLM_COMPLETED)
{
// Incoming phase could have been BEGIN_REQ or END_RESP
if ( is_request )
{
end_req_event[target].notify();
// Once target has returned TLM_COMPLETED, do not propagate transaction forward again
ext->dont_propagate_fw = true;
// Need to check response exclusion rule here before passing BEGIN_RESP on return path!
if (rsp_in_progress[id])
{
queue_the_rsp_to_be_sent_bw_later( id, &trans, delay );
return tlm::TLM_ACCEPTED;
}
}
// Cannot expect an END_RESP from the initiator after returning TLM_COMPLETED
}
return status;
}
virtual bool get_direct_mem_ptr( int id, tlm::tlm_generic_payload& trans,
tlm::tlm_dmi& dmi_data)
{
sc_dt::uint64 masked_address;
unsigned int target = decode_address( trans.get_address(), masked_address );
trans.set_address( masked_address );
bool status = init_socket[target]->get_direct_mem_ptr( trans, dmi_data );
dmi_data.set_start_address( reconstruct_address(dmi_data.get_start_address(), target) );
dmi_data.set_end_address( reconstruct_address(dmi_data.get_end_address(), target) );
return status;
}
virtual unsigned int transport_dbg( int id, tlm::tlm_generic_payload& trans )
{
sc_dt::uint64 masked_address;
unsigned int target = decode_address( trans.get_address(), masked_address );
trans.set_address( masked_address );
return init_socket[target]->transport_dbg( trans );
}
// Backward interface
virtual tlm::tlm_sync_enum nb_transport_bw( int id, tlm::tlm_generic_payload& trans,
tlm::tlm_phase& phase, sc_time& delay )
{
if (phase == tlm::END_REQ || (&trans == req_in_progress[id] && phase == tlm::BEGIN_RESP))
{
assert( req_in_progress[id] );
end_req_event[id].notify();
}
route_extension* ext;
accessor(trans).get_extension(ext);
assert(ext);
int init = ext->init;
if (phase == tlm::BEGIN_RESP)
{
if (rsp_in_progress[init])
{
queue_the_rsp_to_be_sent_bw_later( init, &trans, delay );
return tlm::TLM_ACCEPTED;
}
rsp_in_progress[init] = &trans;
// Set the delay so there are multiple responses pending
delay = delay + sc_time(1000, SC_PS);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -