scc  2024.06
SystemC components library
target.h
1 /*******************************************************************************
2  * Copyright 2021-2022 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 
17 #ifndef _BUS_TLM_PIN_OCP_TARGET_H_
18 #define _BUS_TLM_PIN_OCP_TARGET_H_
19 
20 #include <interfaces/ocp/ocp_tlm.h>
21 #include <scc/peq.h>
22 #include <scc/report.h>
23 #include <scc/utilities.h>
24 #include <systemc>
25 #include <tlm/scc/tlm_gp_shared.h>
26 #include <tlm/scc/tlm_mm.h>
27 #include <util/ities.h>
28 
30 namespace ocp {
32 namespace pin {
33 
34 #define OCP_CLK_DELAY 1_ps
35 
36 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH = DATA_WIDTH>
37 struct target : public sc_core::sc_module, public tlm::tlm_bw_transport_if<tlm::tlm_base_protocol_types> {
38  SC_HAS_PROCESS(target);
39 
40  using payload_type = tlm::tlm_base_protocol_types::tlm_payload_type;
41  using phase_type = tlm::tlm_base_protocol_types::tlm_phase_type;
42 
43  sc_core::sc_in<bool> clk_i{"clk_i"};
44  sc_core::sc_in<bool> reset{""};
45 
46  sc_core::sc_in<sc_uint<3>> MCmd{"MCmd"};
47  sc_core::sc_in<sc_uint<ADDR_WIDTH>> MAddr{"MAddr"};
48  sc_core::sc_in<sc_uint<DATA_WIDTH>> MData{"MData"};
49  sc_core::sc_in<sc_uint<DATA_WIDTH / 8>> MByteEn{"MByteEn"};
50  sc_core::sc_out<bool> SCmdAccept{"SCmdAccept"};
51 
52  sc_core::sc_out<sc_uint<2>> SResp{"SResp"};
53  sc_core::sc_out<sc_uint<DATA_WIDTH>> SData{"SData"};
54  sc_core::sc_in<bool> MRespAccept{"MRespAccept"};
55 
56  tlm::tlm_initiator_socket<BUSWIDTH> isckt{"isckt"};
57 
58  target(sc_core::sc_module_name const& nm)
59  : sc_core::sc_module(nm) {
60  isckt.bind(*this);
61  SC_METHOD(clk_delay);
62  sensitive << clk_i.pos();
63  dont_initialize();
64  SC_THREAD(req);
65  SC_THREAD(resp);
66  }
67 
68 private:
69  tlm::tlm_sync_enum nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) override;
70 
71  void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) override;
72 
73  void end_of_elaboration() override { clk_if = dynamic_cast<sc_core::sc_clock*>(clk_i.get_interface()); }
74 
75  void clk_delay() { clk_delayed.notify(OCP_CLK_DELAY); }
76  void req();
77  void resp();
78  sc_core::sc_clock* clk_if{nullptr};
79  sc_core::sc_event clk_delayed, end_req_received_evt, wdata_end_req_evt;
81 };
82 
83 } // namespace pin
84 } // namespace ocp
85 
86 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH>
87 inline tlm::tlm_sync_enum ocp::pin::target<DATA_WIDTH, ADDR_WIDTH, BUSWIDTH>::nb_transport_bw(payload_type& trans, phase_type& phase,
88  sc_core::sc_time& t) {
89  if(phase == tlm::END_REQ) {
90  end_req_received_evt.notify(sc_core::SC_ZERO_TIME);
91  } else if(phase == tlm::BEGIN_RESP) {
92  resp_queue.notify(tlm::scc::tlm_gp_shared_ptr(&trans), t);
93  t += clk_if->period().value() ? clk_if->period() : sc_core::SC_ZERO_TIME;
94  }
95  return tlm::TLM_ACCEPTED;
96  ;
97 }
98 
99 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH>
101  sc_dt::uint64 end_range) {}
102 
103 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH>
105  this->SCmdAccept.write(false);
106  wait(sc_core::SC_ZERO_TIME);
107  while(true) {
108  wait(clk_delayed);
109  this->SCmdAccept.write(false);
110  while(!this->MCmd.read()) {
111  wait(this->MCmd.default_event());
112  }
113  auto cmd = static_cast<ocp::cmd_e>(this->MCmd.read().to_uint());
114  auto gp = tlm::scc::tlm_mm<>::get().allocate<ocp::ocp_extension>(DATA_WIDTH / 8);
115  gp->set_streaming_width(DATA_WIDTH / 8);
116  gp->set_data_length(DATA_WIDTH / 8);
117  auto addr = this->MAddr.read().to_uint64();
118  gp->set_address(addr);
119  switch(cmd) {
120  case cmd_e::WRITE:
121  case cmd_e::WRITE_CONDITIONAL:
122  case cmd_e::WRITE_NON_POSTED: {
123  gp->set_command(tlm::TLM_WRITE_COMMAND);
124  auto data = this->MData.read();
125  auto strb = this->MByteEn.read();
126  auto dptr = gp->get_data_ptr();
127  auto len = 0;
128  for(size_t i = 0; i < DATA_WIDTH / 8; ++i) {
129  auto be = strb[i] ? 0xff : 0;
130  if(!len && !be) {
131  addr++;
132  } else if(be) {
133  *dptr = data((i << 3) + 7, i << 3).to_uint();
134  ++dptr;
135  ++len;
136  }
137  }
138  gp->set_address(addr);
139  gp->set_streaming_width(len);
140  gp->set_data_length(len);
141  } break;
142  case cmd_e::READ:
143  case cmd_e::READEX:
144  case cmd_e::READ_LINKED:
145  gp->set_command(tlm::TLM_READ_COMMAND);
146  break;
147  default:
148  SCCFATAL(SCMOD) << "not supported";
149  }
150  auto ext = gp->get_extension<ocp::ocp_extension>();
151  ext->set_mcmd(cmd);
152  SCCDEBUG(SCMOD) << "received OCP bus transaction req " << *gp;
153  tlm::tlm_phase ph = tlm::BEGIN_REQ;
154  auto t{sc_core::SC_ZERO_TIME};
155  auto status = isckt->nb_transport_fw(*gp, ph, t);
156  if(status == tlm::TLM_ACCEPTED) {
157  wait(end_req_received_evt);
158  }
159  this->SCmdAccept.write(true);
160  wait(clk_i.posedge_event());
161  }
162 }
163 
164 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH, unsigned BUSWIDTH>
166  this->SResp.write(static_cast<unsigned>(ocp::resp_e::NULL_));
167  wait(sc_core::SC_ZERO_TIME);
168  uint8_t val;
169  while(true) {
170  wait(clk_i.posedge_event());
171  this->SResp.write(static_cast<unsigned>(ocp::resp_e::NULL_));
172  if(resp_queue.has_next()) {
173  auto gp = resp_queue.get();
174  SCCDEBUG(SCMOD) << "received OCP bus transaction resp " << *gp;
175  this->SResp.write(static_cast<unsigned>(ocp::resp_e::DVA));
176  if(gp->is_read()) {
177  auto d = gp->get_data_ptr();
178  this->SData.write(bit_comb<uint32_t>(d[0], d[1], d[2], d[3]));
179  }
180  do {
181  wait(this->MRespAccept.default_event() | clk_delayed);
182  } while(!this->MRespAccept.read());
183  tlm::tlm_phase ph = tlm::END_RESP;
184  auto t{sc_core::SC_ZERO_TIME};
185  auto status = isckt->nb_transport_fw(*gp, ph, t);
186  }
187  }
188 }
189 
190 #endif /* _BUS_TLM_PIN_OCP_TARGET_H_ */
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition: tlm_mm.h:185
TLM2.0 components modeling OCP.
Definition: ocp_tlm.cpp:20
priority event queue
Definition: peq.h:41
static tlm_mm & get()
accessor function of the singleton
Definition: tlm_mm.h:293