scc  2024.06
SystemC components library
target.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_TARGET_H_
18 #define _BUS_AHB_PIN_TARGET_H_
19 
20 #include <interfaces/ahb/ahb_tlm.h>
21 #include <scc/peq.h>
22 #include <scc/report.h>
23 #include <scc/utilities.h>
24 #include <tlm/scc/initiator_mixin.h>
25 #include <tlm/scc/tlm_mm.h>
26 #include <tlm>
27 #include <tlm_utils/peq_with_get.h>
28 
30 namespace ahb {
32 namespace pin {
33 
34 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> class target : sc_core::sc_module {
35  static constexpr bool is_larger(unsigned x) { return x > 64U; }
36  using addr_t = typename std::conditional<is_larger(ADDR_WIDTH), sc_dt::sc_biguint<ADDR_WIDTH>, sc_dt::sc_uint<ADDR_WIDTH>>::type;
37  using data_t = typename std::conditional<is_larger(DATA_WIDTH), sc_dt::sc_biguint<DATA_WIDTH>, sc_dt::sc_uint<DATA_WIDTH>>::type;
38 
39 public:
40  sc_core::sc_in<bool> HCLK_i{"HCLK_i"};
41  sc_core::sc_in<bool> HRESETn_i{"HRESETn_i"};
42  sc_core::sc_in<addr_t> HADDR_i{"HADDR_i"};
43  sc_core::sc_in<sc_dt::sc_uint<3>> HBURST_i{"HBURST_i"};
44  sc_core::sc_in<bool> HMASTLOCK_i{"HMASTLOCK_i"};
45  sc_core::sc_in<sc_dt::sc_uint<4>> HPROT_i{"HPROT_i"};
46  sc_core::sc_in<sc_dt::sc_uint<3>> HSIZE_i{"HSIZE_i"};
47  sc_core::sc_in<sc_dt::sc_uint<2>> HTRANS_i{"HTRANS_i"};
48  sc_core::sc_in<data_t> HWDATA_i{"HWDATA_i"};
49  sc_core::sc_in<bool> HWRITE_i{"HWRITE_i"};
50  sc_core::sc_in<bool> HSEL_i{"HSEL_i"};
51  sc_core::sc_out<data_t> HRDATA_o{"HRDATA_o"};
52  sc_core::sc_out<bool> HREADY_o{"HREADY_o"};
53  sc_core::sc_out<bool> HRESP_o{"HRESP_o"};
54 
56 
57  target(const sc_core::sc_module_name& nm);
58  virtual ~target();
59 
60 private:
61  void bus_addr_task();
62  void bus_data_task();
63  static tlm::tlm_generic_payload* wait4tx(tlm_utils::peq_with_get<tlm::tlm_generic_payload>& que) {
64  tlm::tlm_generic_payload* ret = que.get_next_transaction();
65  while(!ret) {
66  ::sc_core::wait(que.get_event());
67  ret = que.get_next_transaction();
68  }
69  return ret;
70  }
71  sc_core::sc_event end_req_evt;
72  tlm_utils::peq_with_get<tlm::tlm_generic_payload> resp_que{"resp_que"};
73  tlm_utils::peq_with_get<tlm::tlm_generic_payload> tx_in_flight{"tx_in_flight"};
74  bool waiting4end_req{false};
75 };
76 
78 // implementations of functions
80 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH>
81 target<DATA_WIDTH, ADDR_WIDTH>::target(const sc_core::sc_module_name& nm)
82 : sc_module(nm) {
83  SC_HAS_PROCESS(target);
84  SC_THREAD(bus_addr_task);
85  SC_THREAD(bus_data_task);
86  isckt.register_nb_transport_bw([this](tlm::tlm_generic_payload& gp, tlm::tlm_phase& phase, sc_core::sc_time& delay) {
87  if(phase == tlm::END_REQ) {
88  end_req_evt.notify(delay);
89  waiting4end_req = false;
90  } else if(phase == tlm::BEGIN_RESP) {
91  if(waiting4end_req) {
92  end_req_evt.notify(delay);
93  waiting4end_req = false;
94  }
95  resp_que.notify(gp, delay);
96  }
97  return tlm::TLM_ACCEPTED;
98  });
99 }
100 
101 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> target<DATA_WIDTH, ADDR_WIDTH>::~target() = default;
102 
103 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> void target<DATA_WIDTH, ADDR_WIDTH>::bus_addr_task() {
104  auto const width_exp = scc::ilog2(DATA_WIDTH / 8);
105  wait(sc_core::SC_ZERO_TIME);
106  auto& htrans = HTRANS_i.read();
107  auto& hsel = HSEL_i.read();
108  auto& hready = HREADY_o.read();
109  auto& size = HSIZE_i.read();
110  while(true) {
111  if(!HRESETn_i.read()) {
112  wait(HRESETn_i.posedge_event());
113  } else {
114  wait(HCLK_i.posedge_event());
115  if(hsel && hready && htrans > 1) { // HTRANS/BUSY or IDLE check
116  unsigned sz = size;
117  if(sz > width_exp)
118  SCCERR(SCMOD) << "Access size (" << sz << ") is larger than bus wDWIDTH(" << width_exp << ")!";
119  unsigned length = (1 << sz);
121  gp->acquire();
122  gp->set_streaming_width(length);
123  gp->set_address(HADDR_i.read());
124  auto* ext = gp->get_extension<ahb_extension>();
125  ext->set_locked(HMASTLOCK_i.read());
126  ext->set_protection(HPROT_i.read());
127  ext->set_seq(htrans == 3);
128  ext->set_burst(static_cast<ahb::burst_e>(HBURST_i.read().to_uint()));
129  if(HWRITE_i.read()) {
130  gp->set_write();
131  } else {
132  gp->set_read();
133  }
134  tx_in_flight.notify(*gp);
135  }
136  }
137  }
138 }
139 
140 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> void target<DATA_WIDTH, ADDR_WIDTH>::bus_data_task() {
141  auto const width = DATA_WIDTH / 8;
142  auto& wdata = HWDATA_i.read();
143  wait(sc_core::SC_ZERO_TIME);
144  while(true) {
145  if(!HRESETn_i.read()) {
146  HREADY_o.write(false);
147  wait(HRESETn_i.posedge_event());
148  } else {
149  HREADY_o.write(true);
150  auto gp = wait4tx(tx_in_flight);
151  auto ext = gp->template get_extension<ahb::ahb_extension>();
152  auto start_offs = gp->get_address() & (width - 1);
153  sc_assert((start_offs + gp->get_data_length()) <= width);
154  auto len = gp->get_data_length();
155  HREADY_o.write(false);
156  if(gp->is_write()) {
157  wait(HCLK_i.negedge_event());
158  for(size_t i = start_offs * 8, j = 0; i < DATA_WIDTH; i += 8, ++j)
159  *(uint8_t*)(gp->get_data_ptr() + j) = wdata.range(i + 7, i).to_uint();
160  }
161  SCCDEBUG(SCMOD) << "Send beg req for " << (gp->is_write() ? "write to" : "read from") << " addr 0x" << std::hex
162  << gp->get_address();
163  sc_core::sc_time delay;
164  tlm::tlm_phase phase{tlm::BEGIN_REQ};
165  auto res = isckt->nb_transport_fw(*gp, phase, delay);
166  if(res == tlm::TLM_ACCEPTED) {
167  waiting4end_req = true;
168  wait(end_req_evt);
169  phase = tlm::END_REQ;
170  }
171  SCCDEBUG(SCMOD) << "Recv end req for " << (gp->is_write() ? "write to" : "read from") << " addr 0x" << std::hex
172  << gp->get_address();
173  if(phase != tlm::BEGIN_RESP) {
174  auto resp = wait4tx(resp_que);
175  sc_assert(gp == resp);
176  }
177  SCCDEBUG(SCMOD) << "Recv beg resp for " << (gp->is_write() ? "write to" : "read from") << " addr 0x" << std::hex
178  << gp->get_address();
179  if(gp->is_read()) {
180  data_t data{0};
181  for(size_t i = start_offs * 8, j = 0; j < len; i += 8, ++j)
182  data.range(i + 7, i) = *(uint8_t*)(gp->get_data_ptr() + j);
183  HRDATA_o.write(data);
184  }
185  delay = sc_core::SC_ZERO_TIME;
186  phase = tlm::END_RESP;
187  SCCDEBUG(SCMOD) << "Send end resp for " << (gp->is_write() ? "write to" : "read from") << " addr 0x" << std::hex
188  << gp->get_address();
189  res = isckt->nb_transport_fw(*gp, phase, delay);
190  gp->release();
191  HREADY_o.write(true);
192  wait(HCLK_i.posedge_event());
193  }
194  }
195 }
196 
197 } // namespace pin
198 } /* namespace ahb */
199 
200 #endif /* _BUS_AHB_PIN_TARGET_H_ */
initiator socket mixin
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
Definition: tlm_mm.h:185
TLM2.0 components modeling AHB.
Definition: ahb_tlm.cpp:19
static tlm_mm & get()
accessor function of the singleton
Definition: tlm_mm.h:293