scc  2024.06
SystemC components library
initiator.h
1 /*******************************************************************************
2  * Copyright 2019-2024 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_AHB_PIN_INITIATOR_H_
18 #define _BUS_AHB_PIN_INITIATOR_H_
19 
20 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
21 #define SC_INCLUDE_DYNAMIC_PROCESSES
22 #endif
23 
24 #include <interfaces/ahb/ahb_tlm.h>
25 #include <scc/report.h>
26 #include <scc/utilities.h>
27 #include <tlm/scc/target_mixin.h>
28 #include <tlm>
29 #include <tlm_utils/peq_with_get.h>
30 #include <type_traits>
31 
32 namespace ahb {
33 namespace pin {
34 
35 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH = 32> class initiator : sc_core::sc_module {
36  static constexpr bool is_larger(unsigned x) { return x > 64U; }
37  using addr_t = sc_dt::sc_uint<ADDR_WIDTH>;
38  using data_t = typename std::conditional<is_larger(DATA_WIDTH), sc_dt::sc_biguint<DATA_WIDTH>, sc_dt::sc_uint<DATA_WIDTH>>::type;
39 
40 public:
41  sc_core::sc_in<bool> HCLK_i{"HCLK_i"};
42  sc_core::sc_in<bool> HRESETn_i{"HRESETn_i"};
43  sc_core::sc_out<addr_t> HADDR_o{"HADDR_o"};
44  sc_core::sc_out<sc_dt::sc_uint<3>> HBURST_o{"HBURST_o"};
45  sc_core::sc_out<bool> HMASTLOCK_o{"HMASTLOCK_o"};
46  sc_core::sc_out<sc_dt::sc_uint<4>> HPROT_o{"HPROT_o"};
47  sc_core::sc_out<sc_dt::sc_uint<3>> HSIZE_o{"HSIZE_o"};
48  sc_core::sc_out<sc_dt::sc_uint<2>> HTRANS_o{"HTRANS_o"};
49  sc_core::sc_out<data_t> HWDATA_o{"HWDATA_o"};
50  sc_core::sc_out<bool> HWRITE_o{"HWRITE_o"};
51  sc_core::sc_in<data_t> HRDATA_i{"HRDATA_i"};
52  sc_core::sc_in<bool> HREADY_i{"HREADY_i"};
53  sc_core::sc_in<bool> HRESP_i{"HRESP_i"};
54 
56 
57  initiator(const sc_core::sc_module_name& nm);
58  virtual ~initiator() = default;
59 
60 private:
61  struct data_phase_desc {
62  tlm::tlm_generic_payload* gp;
63  unsigned size;
64  unsigned length;
65  };
66  void bus_addr_task();
67  void bus_data_task();
68 
69  tlm_utils::peq_with_get<tlm::tlm_generic_payload> inqueue{"inqueue"};
70  tlm_utils::peq_with_get<tlm::tlm_generic_payload> tx_in_flight{"tx_in_flight"};
71 };
72 
74 // implementations of functions
76 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH>
77 initiator<DATA_WIDTH, ADDR_WIDTH>::initiator(const sc_core::sc_module_name& nm)
78 : sc_module(nm) {
79  SC_HAS_PROCESS(initiator);
80  SC_THREAD(bus_addr_task);
81  SC_THREAD(bus_data_task);
82 
84  [this](tlm::tlm_generic_payload& payload, tlm::tlm_phase& phase, sc_core::sc_time& delay) -> tlm::tlm_sync_enum {
85  if(phase == tlm::BEGIN_REQ) {
86  if(payload.has_mm())
87  payload.acquire();
88  auto* ext = payload.get_extension<ahb_extension>();
89  if(!ext) {
90  ext = new ahb_extension();
91  payload.set_extension(ext);
92  }
93  this->inqueue.notify(payload);
94  }
95  return tlm::TLM_ACCEPTED;
96  });
97 }
98 
99 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> inline void initiator<DATA_WIDTH, ADDR_WIDTH>::bus_addr_task() {
100  auto& hready = HREADY_i.read();
101  while(true) {
102  wait(inqueue.get_event());
103  while(auto trans = inqueue.get_next_transaction()) {
104  sc_assert(trans->get_data_length() * 8 <= DATA_WIDTH && "Transaction length larger than bus width, this is not supported");
105  SCCDEBUG(SCMOD) << "Recv beg req for read to addr 0x" << std::hex << trans->get_address();
106  auto bytes_exp = scc::ilog2(trans->get_data_length());
107  auto width_exp = scc::ilog2(DATA_WIDTH / 8);
108  size_t size = 0;
109  for(; size < bytes_exp; ++size)
110  if(trans->get_address() & (1 << size))
111  break; // i contains the first bit not being 0
112  auto* ext = trans->template get_extension<ahb_extension>();
113  HADDR_o.write(trans->get_address());
114  HWRITE_o.write(trans->is_write());
115  HMASTLOCK_o.write(ext->is_locked());
116  HPROT_o.write(ext->get_protection());
117  HBURST_o.write(static_cast<unsigned>(ext->get_burst()));
118  HSIZE_o.write(size);
119  HTRANS_o.write(static_cast<unsigned>(ext->is_seq() ? trans_e::SEQ : trans_e::NONSEQ));
120  do {
121  wait(HCLK_i.posedge_event());
122  } while(!hready);
123  SCCDEBUG(SCMOD) << "Send end req for read to addr 0x" << std::hex << trans->get_address();
124  tlm::tlm_phase phase{tlm::END_REQ};
125  sc_core::sc_time delay;
126  auto res = tsckt->nb_transport_bw(*trans, phase, delay);
127  tx_in_flight.notify(*trans);
128  HTRANS_o.write(static_cast<unsigned>(trans_e::IDLE));
129  }
130  }
131 }
132 
133 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> inline void initiator<DATA_WIDTH, ADDR_WIDTH>::bus_data_task() {
134  auto const width = DATA_WIDTH / 8;
135  auto& hready = HREADY_i.read();
136  auto& rdata = HRDATA_i.read();
137  while(true) {
138  wait(tx_in_flight.get_event());
139  while(auto trans = tx_in_flight.get_next_transaction()) {
140  auto bytes_exp = scc::ilog2(trans->get_data_length());
141  auto width_exp = scc::ilog2(DATA_WIDTH / 8);
142  size_t size = 0;
143  for(; size < width_exp; ++size)
144  if(trans->get_address() & (1 << size))
145  break; // i contains the first bit not being 0
146  auto beats = bytes_exp < size ? 1 : 1 << (bytes_exp - size);
147  auto start_offs = trans->get_address() & (width - 1);
148  auto len = trans->get_data_length();
149  if(trans->is_write()) {
150  data_t data{0};
151  for(size_t i = start_offs * 8, j = 0; i < DATA_WIDTH; i += 8, ++j)
152  data.range(i + 7, i) = *(uint8_t*)(trans->get_data_ptr() + j);
153  HWDATA_o.write(data);
154  trans->set_response_status(tlm::TLM_OK_RESPONSE);
155  tlm::tlm_phase phase{tlm::BEGIN_RESP};
156  sc_core::sc_time delay;
157  tsckt->nb_transport_bw(*trans, phase, delay);
158  }
159  do {
160  wait(HCLK_i.posedge_event());
161  } while(!hready);
162  if(trans->is_read()) {
163  for(size_t i = start_offs * 8, j = 0; i < DATA_WIDTH; i += 8, ++j)
164  *(uint8_t*)(trans->get_data_ptr() + j) = rdata.range(i + 7, i).to_uint();
165  trans->set_response_status(tlm::TLM_OK_RESPONSE);
166  tlm::tlm_phase phase{tlm::BEGIN_RESP};
167  sc_core::sc_time delay;
168  tsckt->nb_transport_bw(*trans, phase, delay);
169  }
170  if(trans->has_mm())
171  trans->release();
172  }
173  }
174 }
175 } // namespace pin
176 } /* namespace ahb */
177 
178 #endif /* _BUS_AHB_PIN_INITIATOR_H_ */
initiator ID recording TLM extension
void register_nb_transport_fw(std::function< sync_enum_type(transaction_type &, phase_type &, sc_core::sc_time &)> cb)
Definition: target_mixin.h:78
TLM2.0 components modeling AHB.
Definition: ahb_tlm.cpp:19