scc  2024.06
SystemC components library
tlm_target.h
1 /*******************************************************************************
2  * Copyright 2016, 2018 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 _SYSC_TLM_TARGET_H_
18 #define _SYSC_TLM_TARGET_H_
19 
20 #include "resource_access_if.h"
21 #include <array>
22 #include <numeric>
23 #include <scc/utilities.h>
24 #include <tlm/scc/scv/tlm_rec_target_socket.h>
25 #include <tlm/scc/target_mixin.h>
26 #include <util/range_lut.h>
27 
28 namespace scc {
34 struct addr_range {
35  uint64_t base, size;
36 };
44 template <unsigned int BUSWIDTH = LT, unsigned int ADDR_UNIT_WIDTH = 8> class tlm_target {
45 public:
54  tlm_target(sc_core::sc_time& clock, const char* socket_name = "socket");
64  void b_tranport_cb(tlm::tlm_generic_payload& gp, sc_core::sc_time& d);
72  unsigned int tranport_dbg_cb(tlm::tlm_generic_payload& gp);
80  void addResource(resource_access_if& rai, uint64_t base_addr) {
81  socket_map.addEntry(std::make_pair(&rai, base_addr), base_addr, std::max<size_t>(1, rai.size() / (ADDR_UNIT_WIDTH / 8)));
82  }
89  void addResource(indexed_resource_access_if& irai, uint64_t base_addr) {
90  for(size_t idx = 0; idx < irai.size(); ++idx) {
91  auto irai_size = std::max<size_t>(1, irai[idx].size() / (ADDR_UNIT_WIDTH / 8));
92  socket_map.addEntry(std::make_pair(&irai[idx], base_addr), base_addr, irai_size);
93  base_addr += irai_size;
94  }
95  }
96 
97  size_t get_size() {
98  size_t res = 0;
99  for(auto& e : socket_map) {
100  res = std::max<size_t>(res, e.first + e.second.index.second);
101  }
102  return res;
103  }
104 
105 private:
106  sc_core::sc_time& clk;
107 
108 protected:
110 };
114 template <unsigned BUSWIDTH = LT> struct target_memory_map_entry {
115  tlm::tlm_target_socket<BUSWIDTH>& target;
116  ::sc_dt::uint64 start;
117  ::sc_dt::uint64 size;
118 };
122 template <unsigned BUSWIDTH = LT> struct target_name_map_entry {
123  std::string name;
124  ::sc_dt::uint64 start;
125  ::sc_dt::uint64 size;
126 };
127 template <unsigned int BUSWIDTH = LT, unsigned int ADDR_UNIT_WIDTH = 8>
128 struct tlm_target_mod : sc_core::sc_module, public tlm_target<BUSWIDTH, ADDR_UNIT_WIDTH> {
129  tlm_target_mod(sc_core::sc_module_name nm, sc_core::sc_time& clk_period)
130  : sc_module(nm)
132 };
133 
134 } /* namespace scc */
135 
136 template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_WIDTH>
137 inline scc::tlm_target<BUSWIDTH, ADDR_UNIT_WIDTH>::tlm_target(sc_core::sc_time& clock, const char* socket_name)
138 : socket(socket_name)
139 , clk(clock)
140 , socket_map(std::make_pair(nullptr, 0)) {
141  socket.register_b_transport([=](tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) -> void { this->b_tranport_cb(gp, delay); });
142  socket.register_transport_dbg([=](tlm::tlm_generic_payload& gp) -> unsigned { return this->tranport_dbg_cb(gp); });
143 }
144 
145 template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_WIDTH>
146 void scc::tlm_target<BUSWIDTH, ADDR_UNIT_WIDTH>::b_tranport_cb(tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) {
147  resource_access_if* ra = nullptr;
148  uint64_t base = 0;
149  std::tie(ra, base) = socket_map.getEntry(gp.get_address());
150  if(ra) {
151  auto offset = 0;
152  auto len = gp.get_data_length();
153  auto contigous = true;
154  if(gp.get_byte_enable_ptr()) {
155  auto lower = std::numeric_limits<unsigned>::max();
156  auto upper = std::numeric_limits<unsigned>::max();
157  auto en = false;
158  auto p = gp.get_byte_enable_ptr();
159  auto i = 0u;
160  for(; i < gp.get_byte_enable_length(); ++i, ++p) {
161  if(*p && !en) {
162  if(lower != std::numeric_limits<unsigned>::max()) {
163  contigous = false;
164  break;
165  } else {
166  lower = i;
167  en = true;
168  }
169  }
170  if(!*p && en) {
171  if(upper != std::numeric_limits<unsigned>::max()) {
172  contigous = false;
173  break;
174  } else {
175  upper = i;
176  en = false;
177  }
178  }
179  }
180  if(i == gp.get_byte_enable_length() && upper == std::numeric_limits<unsigned>::max())
181  upper = i;
182  if(contigous) {
183  offset = lower;
184  len = upper - lower;
185  }
186  }
187  if(gp.get_data_length() > ra->size()) {
188  gp.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
189  } else if(gp.get_data_length() != gp.get_streaming_width()) {
190  gp.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
191  } else if(gp.get_byte_enable_ptr() != nullptr && !(contigous && gp.get_byte_enable_length() == gp.get_data_length())) {
192  gp.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE);
193  } else {
194  gp.set_response_status(tlm::TLM_COMMAND_ERROR_RESPONSE);
195  switch(gp.get_command()) {
196  case tlm::TLM_READ_COMMAND:
197  if(ra->read(gp.get_data_ptr() + offset, len, (gp.get_address() - base + offset), delay))
198  gp.set_response_status(tlm::TLM_OK_RESPONSE);
199  break;
200  case tlm::TLM_WRITE_COMMAND:
201  if(ra->write(gp.get_data_ptr() + offset, len, (gp.get_address() - base + offset), delay))
202  gp.set_response_status(tlm::TLM_OK_RESPONSE);
203  break;
204  }
205  }
206  } else {
207  gp.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
208  }
209  delay += clk;
210 }
211 
212 template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_WIDTH>
213 unsigned int scc::tlm_target<BUSWIDTH, ADDR_UNIT_WIDTH>::tranport_dbg_cb(tlm::tlm_generic_payload& gp) {
214  resource_access_if* ra = nullptr;
215  uint64_t base = 0;
216  std::tie(ra, base) = socket_map.getEntry(gp.get_address());
217  if(ra) {
218  if(gp.get_data_length() == ra->size() && gp.get_byte_enable_ptr() == nullptr && gp.get_data_length() == gp.get_streaming_width()) {
219  if(gp.get_command() == tlm::TLM_READ_COMMAND) {
220  if(ra->read_dbg(gp.get_data_ptr(), gp.get_data_length(), (gp.get_address() - base) / ra->size()))
221  return gp.get_data_length();
222  } else if(gp.get_command() == tlm::TLM_WRITE_COMMAND) {
223  if(ra->write_dbg(gp.get_data_ptr(), gp.get_data_length(), (gp.get_address() - base) / ra->size()))
224  return gp.get_data_length();
225  }
226  }
227  }
228  return 0;
229 }
230 
231 #endif /* _SYSC_TLM_TARGET_H_ */
interface defining access to an indexed resource e.g. register file
virtual std::size_t size()=0
get the size of the resource
interface defining access to a resource e.g. a register
virtual std::size_t size() const =0
return the size of the resource
virtual bool read_dbg(uint8_t *data, std::size_t length, uint64_t offset=0) const =0
debug read the data from the resource
virtual bool write_dbg(const uint8_t *data, std::size_t length, uint64_t offset=0)=0
debug write to the resource
a simple access-width based bus interface (no DMI support)
Definition: tlm_target.h:44
void addResource(resource_access_if &rai, uint64_t base_addr)
add a resource to this target at a certain address within the socket address range
Definition: tlm_target.h:80
tlm_target(sc_core::sc_time &clock, const char *socket_name="socket")
the constructor
Definition: tlm_target.h:137
unsigned int tranport_dbg_cb(tlm::tlm_generic_payload &gp)
the debug transport callback
Definition: tlm_target.h:213
void b_tranport_cb(tlm::tlm_generic_payload &gp, sc_core::sc_time &d)
the blocking transport callback
Definition: tlm_target.h:146
tlm::scc::target_mixin< tlm::scc::scv::tlm_rec_target_socket< BUSWIDTH > > socket
the target socket
Definition: tlm_target.h:56
void addResource(indexed_resource_access_if &irai, uint64_t base_addr)
add an indexed resource to this target at a certain address within the socket address range
Definition: tlm_target.h:89
range based lookup table
Definition: range_lut.h:37
SCC TLM utilities.
struct representing address range
Definition: tlm_target.h:34
Definition: tlm_target.h:114
Definition: tlm_target.h:122