19 #include <interfaces/obi/obi_tlm.h>
20 #include <scc/mt19937_rng.h>
22 #include <scc/report.h>
23 #include <scc/signal_opt_ports.h>
25 #include <tlm/scc/initiator_mixin.h>
26 #include <tlm/scc/scv/tlm_rec_initiator_socket.h>
27 #include <tlm/scc/tlm_gp_shared.h>
28 #include <tlm/scc/tlm_id.h>
29 #include <tlm/scc/tlm_mm.h>
35 #include <unordered_map>
40 template <
unsigned int DATA_WIDTH = 32,
unsigned int ADDR_WIDTH = 32,
unsigned int ID_WIDTH = 0,
unsigned int USER_WIDTH = 0>
41 class target :
public sc_core::sc_module {
43 using payload_type = tlm::tlm_base_protocol_types::tlm_payload_type;
44 using phase_type = tlm::tlm_base_protocol_types::tlm_phase_type;
48 target(sc_core::sc_module_name nm);
52 sc_core::sc_in<bool> clk_i{
"clk_i"};
53 sc_core::sc_in<bool> resetn_i{
"resetn_i"};
55 sc_core::sc_in<bool> req_i{
"req_i"};
56 sc_core::sc_out<bool> gnt_o{
"gnt_o"};
57 sc_core::sc_in<sc_dt::sc_uint<ADDR_WIDTH>> addr_i{
"addr_i"};
58 sc_core::sc_in<bool> we_i{
"we_i"};
59 sc_core::sc_in<sc_dt::sc_uint<DATA_WIDTH / 8>> be_i{
"be_i"};
60 sc_core::sc_in<sc_dt::sc_uint<DATA_WIDTH>> wdata_i{
"wdata_i"};
65 sc_core::sc_out<bool> rvalid_o{
"rvalid_o"};
66 sc_core::sc_in<bool> rready_i{
"rready_i"};
67 sc_core::sc_out<sc_dt::sc_uint<DATA_WIDTH>> rdata_o{
"rdata_o"};
68 sc_core::sc_out<bool> err_o{
"err_o"};
72 tlm::tlm_sync_enum nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t);
74 cci::cci_param<sc_core::sc_time> sample_delay{
"sample_delay", 0_ns};
75 cci::cci_param<int> req2gnt_delay{
"req2gnt_delay", 0};
76 cci::cci_param<int> addr2data_delay{
"addr2data_delay", 0};
80 void achannel_req_t();
81 void rchannel_rsp_t();
84 if(sc_core::sc_delta_count_at_current_time() < 5) {
85 clk_self.notify(sc_core::SC_ZERO_TIME);
86 next_trigger(clk_self);
88 clk_delayed.notify(sc_core::SC_ZERO_TIME );
90 sc_core::sc_event clk_delayed, clk_self;
92 std::deque<std::tuple<tlm::scc::tlm_gp_shared_ptr, unsigned>> rchannel_pending_rsp;
95 bool addrPhaseFinished;
96 tlm::tlm_phase last_phase;
99 std::unordered_map<payload_type*, tx_state> states;
105 template <
unsigned int DATA_WIDTH,
unsigned int ADDR_WIDTH,
unsigned int ID_WIDTH,
unsigned int USER_WIDTH>
108 isckt.
register_nb_transport_bw([
this](payload_type& trans, phase_type& phase, sc_core::sc_time& t) -> tlm::tlm_sync_enum {
109 return nb_transport_bw(trans, phase, t);
112 sensitive << clk_i.pos() << resetn_i.neg();
113 SC_METHOD(clk_delay);
114 sensitive << clk_i.pos();
115 SC_THREAD(achannel_req_t)
116 SC_THREAD(rchannel_rsp_t);
119 template <
unsigned int DATA_WIDTH,
unsigned int ADDR_WIDTH,
unsigned int ID_WIDTH,
unsigned int USER_WIDTH>
120 inline void target<DATA_WIDTH, ADDR_WIDTH, ID_WIDTH, USER_WIDTH>::target::clk_cb() {
121 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
123 if(rchannel_pending_rsp.size()) {
124 auto& head = rchannel_pending_rsp.front();
125 if(std::get<1>(head) == 0) {
126 rchannel_rsp.notify(std::get<0>(head));
127 rchannel_pending_rsp.pop_front();
129 for(
auto& e : rchannel_pending_rsp) {
137 template <
unsigned int DATA_WIDTH,
unsigned int ADDR_WIDTH,
unsigned int ID_WIDTH,
unsigned int USER_WIDTH>
138 inline tlm::tlm_sync_enum
139 target<DATA_WIDTH, ADDR_WIDTH, ID_WIDTH, USER_WIDTH>::target::nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) {
140 auto id = obi::get_obi_id(trans);
142 sc_assert(ext &&
"obi_extension missing");
145 auto it = states.find(&trans);
146 sc_assert(it != states.end());
147 it->second.last_phase = tlm::END_REQ;
148 achannel_rsp.notify(&trans, t);
149 return tlm::TLM_ACCEPTED;
151 case tlm::BEGIN_RESP: {
152 auto it = states.find(&trans);
153 sc_assert(it != states.end());
154 auto& state = it->second;
155 if(state.pending_tx) {
156 unsigned resp_delay = addr2data_delay < 0 ?
scc::MT19937::uniform(0, -addr2data_delay) : addr2data_delay;
158 rchannel_pending_rsp.push_back({state.pending_tx, resp_delay - 1});
160 rchannel_pending_rsp.push_back({state.pending_tx, 0});
162 state.last_phase = tlm::BEGIN_RESP;
163 return tlm::TLM_ACCEPTED;
166 SCCWARN(SCMOD) << phase <<
" is unsupported phase transaction combination";
167 return tlm::TLM_ACCEPTED;
171 template <
unsigned int DATA_WIDTH,
unsigned int ADDR_WIDTH,
unsigned int ID_WIDTH,
unsigned int USER_WIDTH>
172 inline void target<DATA_WIDTH, ADDR_WIDTH, ID_WIDTH, USER_WIDTH>::achannel_req_t() {
174 wait(clk_i.posedge_event());
176 while(resetn_i.read() ==
false)
177 wait(clk_i.posedge_event());
178 while(resetn_i.read() ==
true) {
179 gnt_o.write(req2gnt_delay == 0);
181 wait(this->req_i.posedge_event() | clk_delayed);
182 }
while(this->req_i.read() ==
false);
183 auto data_len = DATA_WIDTH / 8;
185 gp->set_streaming_width(data_len);
186 gp->set_address(addr_i.read());
187 gp->set_command(we_i.read() ? tlm::TLM_WRITE_COMMAND : tlm::TLM_READ_COMMAND);
188 auto be =
static_cast<unsigned>(be_i.read());
189 auto cnt = util::bit_count(be);
190 gp->set_streaming_width(cnt);
191 gp->set_data_length(cnt);
193 auto bus_data = wdata_i.read();
194 auto tx_byte_idx = 0;
195 for(
auto i = 0U, be_idx = 0U; i < DATA_WIDTH; i += 8, ++be_idx) {
196 if(be & (1U << be_idx)) {
197 *(gp->get_data_ptr() + tx_byte_idx) = bus_data.range(i + 7, i).to_uint();
201 SCCTRACE(SCMOD) <<
"Got write request to address 0x" << std::hex << gp->get_address();
203 SCCTRACE(SCMOD) <<
"Got read request to address 0x" << std::hex << gp->get_address();
205 if(ID_WIDTH && aid_i.get_interface())
206 ext->set_id(aid_i->read());
208 if(auser_i.get_interface())
209 ext->set_auser(auser_i->read());
210 if(wuser_i.get_interface() && we_i.read())
211 ext->set_duser(wuser_i->read());
213 auto& state = states[gp.
get()];
214 phase_type phase = tlm::BEGIN_REQ;
215 auto delay = sc_core::SC_ZERO_TIME;
216 auto ret = isckt->nb_transport_fw(*gp, phase, delay);
217 auto startResp =
false;
218 state.last_phase = phase;
219 if(ret == tlm::TLM_ACCEPTED) {
220 SCCTRACE(SCMOD) <<
"waiting for TLM reponse";
221 auto resp = achannel_rsp.get();
222 sc_assert(resp.get() == gp.
get());
225 for(
unsigned i = 0U; i < gnt_delay; ++i)
226 wait(clk_i.posedge_event());
228 wait(clk_i.posedge_event());
229 state.addrPhaseFinished =
true;
230 if(state.last_phase == tlm::BEGIN_RESP) {
231 unsigned resp_delay = addr2data_delay < 0 ?
scc::MT19937::uniform(0, -addr2data_delay) : addr2data_delay;
233 rchannel_pending_rsp.push_back({gp, resp_delay - 1});
235 rchannel_rsp.notify(gp);
237 state.pending_tx = gp;
243 template <
unsigned int DATA_WIDTH,
unsigned int ADDR_WIDTH,
unsigned int ID_WIDTH,
unsigned int USER_WIDTH>
244 inline void target<DATA_WIDTH, ADDR_WIDTH, ID_WIDTH, USER_WIDTH>::rchannel_rsp_t() {
247 if(ID_WIDTH && r_id_o.get_interface())
249 if(USER_WIDTH && ruser_o.get_interface())
252 rvalid_o.write(
false);
254 if(tx->get_command() == tlm::TLM_READ_COMMAND) {
255 auto offset = tx->get_address() % (DATA_WIDTH / 8);
256 auto rx_data{sc_dt::sc_uint<DATA_WIDTH>(0)};
257 for(
unsigned i = 0U, j = offset * 8; i < tx->get_data_length(); ++i, j += 8) {
258 rx_data.range(j + 7, j) = *(tx->get_data_ptr() + i);
260 rdata_o.write(rx_data);
261 SCCTRACE(SCMOD) <<
"responding to read request to address 0x" << std::hex << tx->get_address();
263 SCCTRACE(SCMOD) <<
"responding to write request to address 0x" << std::hex << tx->get_address();
264 err_o.write(tx->get_response_status() != tlm::TLM_OK_RESPONSE);
265 if(ID_WIDTH || USER_WIDTH) {
267 if(ID_WIDTH && r_id_o.get_interface())
268 r_id_o->write(ext->get_id());
269 if(USER_WIDTH && ruser_o.get_interface())
270 ruser_o->write(ext->get_duser());
272 rvalid_o.write(
true);
274 while(!rready_i.read())
275 wait(rready_i.value_changed_event());
276 phase_type phase = tlm::END_RESP;
277 auto delay = sc_core::SC_ZERO_TIME;
278 auto ret = isckt->nb_transport_fw(*tx, phase, delay);
279 auto it = states.find(tx.
get());
280 sc_assert(it != states.end());
282 wait(clk_i.posedge_event());
static uint64_t uniform()
void register_nb_transport_bw(std::function< sync_enum_type(transaction_type &, phase_type &, sc_core::sc_time &)> cb)
payload_type * allocate()
get a plain tlm_payload_type without extensions
T * get() const noexcept
Return the stored pointer.
TLM2.0 components modeling OBI.
static tlm_mm & get()
accessor function of the singleton