scc  2022.4.0
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 private:
98  sc_core::sc_time& clk;
99 
100 protected:
102 };
106 template <unsigned BUSWIDTH = LT> struct target_memory_map_entry {
107  tlm::tlm_target_socket<BUSWIDTH>& target;
108  ::sc_dt::uint64 start;
109  ::sc_dt::uint64 size;
110 };
114 template <unsigned BUSWIDTH = LT> struct target_name_map_entry {
115  std::string name;
116  ::sc_dt::uint64 start;
117  ::sc_dt::uint64 size;
118 };
119 template <unsigned int BUSWIDTH = LT, unsigned int ADDR_UNIT_WIDTH = 8>
120 struct tlm_target_mod : sc_core::sc_module, public tlm_target<BUSWIDTH, ADDR_UNIT_WIDTH> {
121  tlm_target_mod(sc_core::sc_module_name nm, sc_core::sc_time& clk_period)
122  : sc_module(nm)
124 };
125 
126 } /* namespace scc */
127 
128 template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_WIDTH>
129 inline scc::tlm_target<BUSWIDTH, ADDR_UNIT_WIDTH>::tlm_target(sc_core::sc_time& clock, const char* socket_name)
130 : socket(socket_name)
131 , clk(clock)
132 , socket_map(std::make_pair(nullptr, 0)) {
133  socket.register_b_transport([=](tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) -> void { this->b_tranport_cb(gp, delay); });
134  socket.register_transport_dbg([=](tlm::tlm_generic_payload& gp) -> unsigned { return this->tranport_dbg_cb(gp); });
135 }
136 
137 template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_WIDTH>
138 void scc::tlm_target<BUSWIDTH, ADDR_UNIT_WIDTH>::b_tranport_cb(tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) {
139  resource_access_if* ra = nullptr;
140  uint64_t base = 0;
141  std::tie(ra, base) = socket_map.getEntry(gp.get_address());
142  if(ra) {
143  auto offset = 0;
144  auto len = gp.get_data_length();
145  auto contigous = true;
146  if(gp.get_byte_enable_ptr()) {
147  auto lower = std::numeric_limits<unsigned>::max();
148  auto upper = std::numeric_limits<unsigned>::max();
149  auto en = false;
150  auto p = gp.get_byte_enable_ptr();
151  auto i = 0u;
152  for(; i < gp.get_byte_enable_length(); ++i, ++p) {
153  if(*p && !en) {
154  if(lower != std::numeric_limits<unsigned>::max()) {
155  contigous = false;
156  break;
157  } else {
158  lower = i;
159  en = true;
160  }
161  }
162  if(!*p && en) {
163  if(upper != std::numeric_limits<unsigned>::max()) {
164  contigous = false;
165  break;
166  } else {
167  upper = i;
168  en = false;
169  }
170  }
171  }
172  if(i == gp.get_byte_enable_length() && upper == std::numeric_limits<unsigned>::max())
173  upper = i;
174  if(contigous) {
175  offset = lower;
176  len = upper - lower;
177  }
178  }
179  if(gp.get_data_length() > ra->size()) {
180  gp.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
181  } else if(gp.get_data_length() != gp.get_streaming_width()) {
182  gp.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
183  } else if(gp.get_byte_enable_ptr() != nullptr && !(contigous && gp.get_byte_enable_length() == gp.get_data_length())) {
184  gp.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE);
185  } else {
186  gp.set_response_status(tlm::TLM_COMMAND_ERROR_RESPONSE);
187  switch(gp.get_command()) {
188  case tlm::TLM_READ_COMMAND:
189  if(ra->read(gp.get_data_ptr() + offset, len, (gp.get_address() - base + offset), delay))
190  gp.set_response_status(tlm::TLM_OK_RESPONSE);
191  break;
192  case tlm::TLM_WRITE_COMMAND:
193  if(ra->write(gp.get_data_ptr() + offset, len, (gp.get_address() - base + offset), delay))
194  gp.set_response_status(tlm::TLM_OK_RESPONSE);
195  break;
196  }
197  }
198  } else {
199  gp.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
200  }
201  delay += clk;
202 }
203 
204 template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_WIDTH>
205 unsigned int scc::tlm_target<BUSWIDTH, ADDR_UNIT_WIDTH>::tranport_dbg_cb(tlm::tlm_generic_payload& gp) {
206  resource_access_if* ra = nullptr;
207  uint64_t base = 0;
208  std::tie(ra, base) = socket_map.getEntry(gp.get_address());
209  if(ra) {
210  if(gp.get_data_length() == ra->size() && gp.get_byte_enable_ptr() == nullptr && gp.get_data_length() == gp.get_streaming_width()) {
211  if(gp.get_command() == tlm::TLM_READ_COMMAND) {
212  if(ra->read_dbg(gp.get_data_ptr(), gp.get_data_length(), (gp.get_address() - base) / ra->size()))
213  return gp.get_data_length();
214  } else if(gp.get_command() == tlm::TLM_WRITE_COMMAND) {
215  if(ra->write_dbg(gp.get_data_ptr(), gp.get_data_length(), (gp.get_address() - base) / ra->size()))
216  return gp.get_data_length();
217  }
218  }
219  }
220  return 0;
221 }
222 
223 #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:129
unsigned int tranport_dbg_cb(tlm::tlm_generic_payload &gp)
the debug transport callback
Definition: tlm_target.h:205
void b_tranport_cb(tlm::tlm_generic_payload &gp, sc_core::sc_time &d)
the blocking transport callback
Definition: tlm_target.h:138
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 SystemC utilities.
struct representing address range
Definition: tlm_target.h:34
Definition: tlm_target.h:106
Definition: tlm_target.h:114