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_APB_PIN_TARGET_H_
18 #define _BUS_APB_PIN_TARGET_H_
19 
20 #include <interfaces/apb/apb_tlm.h>
21 #include <scc/peq.h>
22 #include <scc/report.h>
23 #include <scc/signal_opt_ports.h>
24 #include <scc/utilities.h>
25 #include <tlm/scc/initiator_mixin.h>
26 #include <tlm/scc/tlm_mm.h>
27 #include <tlm>
28 #include <tlm_utils/peq_with_get.h>
29 
31 namespace apb {
33 namespace pin {
34 
35 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH> class target : sc_core::sc_module {
36  static constexpr bool is_larger(unsigned x) { return x > 64U; }
37 
38 public:
39  using addr_t = typename std::conditional<is_larger(ADDR_WIDTH), sc_dt::sc_biguint<ADDR_WIDTH>, sc_dt::sc_uint<ADDR_WIDTH>>::type;
40  using data_t = typename std::conditional<is_larger(DATA_WIDTH), sc_dt::sc_biguint<DATA_WIDTH>, sc_dt::sc_uint<DATA_WIDTH>>::type;
41  using strb_t = sc_dt::sc_uint<DATA_WIDTH / 8>;
42 
43  sc_core::sc_in<bool> PCLK_i{"PCLK_i"};
44  sc_core::sc_in<bool> PRESETn_i{"PRESETn_i"};
45  sc_core::sc_in<addr_t> PADDR_i{"PADDR_i"};
46  scc::sc_in_opt<sc_dt::sc_uint<3>> PPROT_i{"PPROT_i"};
47  scc::sc_in_opt<bool> PNSE_i{"PNSE_i"};
48  sc_core::sc_in<bool> PSELx_i{"PSELx_i"};
49  sc_core::sc_in<bool> PENABLE_i{"PENABLE_i"};
50  sc_core::sc_in<bool> PWRITE_i{"PWRITE_i"};
51  sc_core::sc_in<data_t> PWDATA_i{"PWDATA_i"};
52  scc::sc_in_opt<strb_t> PSTRB_i{"PSTRB_i"};
53  sc_core::sc_out<bool> PREADY_o{"PREADY_o"};
54  sc_core::sc_out<data_t> PRDATA_o{"PRDATA_o"};
55  sc_core::sc_out<bool> PSLVERR_o{"PSLVERR_o"};
56  scc::sc_in_opt<bool> PWAKEUP_i{"PWAKEUP_i"};
57 
59 
60  target(const sc_core::sc_module_name& nm);
61  virtual ~target();
62 
63 private:
64  void bus_task();
65  static tlm::tlm_generic_payload* wait4tx(tlm_utils::peq_with_get<tlm::tlm_generic_payload>& que) {
66  tlm::tlm_generic_payload* ret = que.get_next_transaction();
67  while(!ret) {
68  ::sc_core::wait(que.get_event());
69  ret = que.get_next_transaction();
70  }
71  return ret;
72  }
73  sc_core::sc_event end_req_evt;
74  tlm_utils::peq_with_get<tlm::tlm_generic_payload> resp_que{"resp_que"};
75  bool waiting4end_req{false};
76 };
77 
79 // implementations of functions
81 template <unsigned DATA_WIDTH, unsigned ADDR_WIDTH>
82 target<DATA_WIDTH, ADDR_WIDTH>::target(const sc_core::sc_module_name& nm)
83 : sc_module(nm) {
84  SC_HAS_PROCESS(target);
85  SC_THREAD(bus_task);
86  isckt.register_nb_transport_bw([this](tlm::tlm_generic_payload& trans, 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(trans, 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_task() {
104  auto const width_exp = scc::ilog2(DATA_WIDTH / 8);
105  wait(sc_core::SC_ZERO_TIME);
106  auto& psel = PSELx_i.read();
107  auto& penable = PENABLE_i.read();
108  wait(PCLK_i.posedge_event());
109  while(true) {
110  if(!PRESETn_i.read()) {
111  wait(PRESETn_i.posedge_event());
112  wait(PCLK_i.posedge_event());
113  } else {
114  PREADY_o.write(false);
115  wait(1_ps);
116  if(psel) { // HTRANS/BUSY or IDLE check
117  PREADY_o.write(false);
118  SCCDEBUG(SCMOD) << "Starting APB setup phase";
119  unsigned length = DATA_WIDTH / 8;
120  auto trans = tlm::scc::tlm_mm<>::get().allocate<apb::apb_extension>(length);
121  trans->acquire();
122  trans->set_streaming_width(length);
123  trans->set_address(PADDR_i.read());
124  auto* ext = trans->get_extension<apb_extension>();
125  if(PPROT_i.get_interface())
126  ext->set_protection(PPROT_i.read().to_uint());
127  if(PNSE_i.get_interface())
128  ext->set_nse(PNSE_i.read());
129  auto start_offs = trans->get_address() & (length - 1);
130  if(PWRITE_i.read()) {
131  trans->set_write();
132  auto data = PWDATA_i.read();
133  if(PSTRB_i.get_interface()) {
134  auto strb = PSTRB_i.read();
135  auto dptr_begin = std::numeric_limits<unsigned>::max();
136  auto dptr_end = 0;
137  for(size_t j = 0; j < DATA_WIDTH / 8; ++j) {
138  if(strb[j]) {
139  if(j < dptr_begin)
140  dptr_begin = j;
141  *(trans->get_data_ptr() + dptr_end) = data(8 * j + 7, 8 * j).to_uint();
142  dptr_end++;
143  }
144  }
145  trans->set_address((trans->get_address() & ~(DATA_WIDTH / 8 - 1)) + dptr_begin);
146  trans->set_data_length(dptr_end);
147  } else
148  for(size_t j = 0; j < DATA_WIDTH / 8; ++j)
149  *(trans->get_data_ptr() + j) = data(8 * j + 7, 8 * j).to_uint();
150  } else {
151  trans->set_read();
152  }
153  sc_core::sc_time delay;
154  tlm::tlm_phase phase{tlm::BEGIN_REQ};
155  SCCDEBUG(SCMOD) << "Recv beg req for read to addr 0x" << std::hex << trans->get_address();
156  auto res = isckt->nb_transport_fw(*trans, phase, delay);
157  if(res == tlm::TLM_ACCEPTED) {
158  waiting4end_req = true;
159  wait(end_req_evt);
160  phase = tlm::END_REQ;
161  }
162  SCCDEBUG(SCMOD) << "Recv end req for " << (trans->is_write() ? "write to" : "read from") << " addr 0x" << std::hex
163  << trans->get_address();
164  SCCDEBUG(SCMOD) << "APB setup phase, finished";
165  wait(PENABLE_i.posedge_event());
166  if(phase != tlm::BEGIN_RESP) {
167  auto resp = wait4tx(resp_que);
168  sc_assert(trans == resp);
169  }
170  SCCDEBUG(SCMOD) << "Recv beg resp for " << (trans->is_write() ? "write to" : "read from") << " addr 0x" << std::hex
171  << trans->get_address() << ", starting access phase";
172  delay = sc_core::SC_ZERO_TIME;
173  phase = tlm::END_RESP;
174  res = isckt->nb_transport_fw(*trans, phase, delay);
175  if(trans->is_read()) {
176  data_t data{0};
177  for(size_t j = 0; j < DATA_WIDTH / 8; ++j)
178  data.range(j * 8 + 7, j * 8) = *(trans->get_data_ptr() + j);
179  PRDATA_o.write(data);
180  }
181  PREADY_o.write(true);
182  PSLVERR_o.write(trans->get_response_status() != tlm::TLM_OK_RESPONSE);
183  wait(PCLK_i.posedge_event());
184  SCCDEBUG(SCMOD) << "APB access phase finished";
185  }
186  }
187  }
188 }
189 } // namespace pin
190 } /* namespace apb */
191 
192 #endif /* _BUS_APB_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 APB.
Definition: apb_tlm.cpp:21
static tlm_mm & get()
accessor function of the singleton
Definition: tlm_mm.h:293