scc 2026.07
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 <scc/utilities.h>
22#include <tlm/scc/memory_map_collector.h>
23#include <tlm/scc/scv/tlm_rec_target_socket.h>
24#include <tlm/scc/target_mixin.h>
25#include <tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h>
26#include <util/range_lut.h>
27
28namespace scc {
34struct addr_range {
35 uint64_t base, size;
36};
37
44template <unsigned int BUSWIDTH = LT, unsigned int ADDR_UNIT_BITWIDTH = 8> class tlm_target {
45public:
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_BITWIDTH / 8)));
82 }
83
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_BITWIDTH / 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
105private:
106 sc_core::sc_time& clk;
107 tlm::tlm_generic_payload* current_payload{nullptr};
108
109protected:
110 using resource_access_t = std::pair<resource_access_if*, uint64_t>;
111 util::range_lut<resource_access_t> socket_map;
112 template <typename T> T* get_payload_extension() {
113 if(current_payload)
114 return current_payload->get_extension<T>();
115 return nullptr;
116 }
117};
118
121template <unsigned BUSWIDTH = LT> struct target_memory_map_entry {
122 tlm::tlm_target_socket<BUSWIDTH>& target;
123 ::sc_dt::uint64 start;
124 ::sc_dt::uint64 size;
125};
126
129template <unsigned BUSWIDTH = LT> struct target_name_map_entry {
130 std::string name;
131 ::sc_dt::uint64 start;
132 ::sc_dt::uint64 size;
133};
134template <unsigned int BUSWIDTH = LT, unsigned int ADDR_UNIT_BITWIDTH = 8>
135struct tlm_target_mod : sc_core::sc_module, public tlm_target<BUSWIDTH, ADDR_UNIT_BITWIDTH> {
136 tlm_target_mod(sc_core::sc_module_name nm, sc_core::sc_time& clk_period)
137 : sc_module(nm)
139};
140
141} /* namespace scc */
142
143template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_BITWIDTH>
144inline scc::tlm_target<BUSWIDTH, ADDR_UNIT_BITWIDTH>::tlm_target(sc_core::sc_time& clock, const char* socket_name)
145: socket(socket_name)
146, clk(clock)
147, socket_map(std::make_pair(nullptr, 0)) {
148 socket.register_b_transport([this](tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) -> void { this->b_tranport_cb(gp, delay); });
149 socket.register_transport_dbg([this](tlm::tlm_generic_payload& gp) -> unsigned { return this->tranport_dbg_cb(gp); });
150}
151
152template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_BITWIDTH>
153void scc::tlm_target<BUSWIDTH, ADDR_UNIT_BITWIDTH>::b_tranport_cb(tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) {
154 resource_access_if* ra = nullptr;
155 uint64_t base = 0;
156 std::tie(ra, base) = socket_map.getEntry(gp.get_address());
157 if(ra) {
158 auto offset = 0;
159 auto len = gp.get_data_length();
160 auto contigous = true;
161 if(gp.get_byte_enable_ptr()) {
162 auto lower = std::numeric_limits<unsigned>::max();
163 auto upper = std::numeric_limits<unsigned>::max();
164 auto en = false;
165 auto p = gp.get_byte_enable_ptr();
166 auto i = 0u;
167 for(; i < gp.get_byte_enable_length(); ++i, ++p) {
168 if(*p && !en) {
169 if(lower != std::numeric_limits<unsigned>::max()) {
170 contigous = false;
171 break;
172 } else {
173 lower = i;
174 en = true;
175 }
176 }
177 if(!*p && en) {
178 if(upper != std::numeric_limits<unsigned>::max()) {
179 contigous = false;
180 break;
181 } else {
182 upper = i;
183 en = false;
184 }
185 }
186 }
187 if(i == gp.get_byte_enable_length() && upper == std::numeric_limits<unsigned>::max())
188 upper = i;
189 if(contigous) {
190 offset = lower;
191 len = upper - lower;
192 }
193 }
194 if(gp.get_data_length() > ra->size()) {
195 gp.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
196 } else if(gp.get_data_length() != gp.get_streaming_width()) {
197 gp.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
198 } else if(gp.get_byte_enable_ptr() != nullptr && !(contigous && gp.get_byte_enable_length() == gp.get_data_length())) {
199 gp.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE);
200 } else {
201 gp.set_response_status(tlm::TLM_COMMAND_ERROR_RESPONSE);
202 current_payload = &gp;
203 switch(gp.get_command()) {
204 case tlm::TLM_READ_COMMAND:
205 if(ra->read(gp.get_data_ptr() + offset, len, (gp.get_address() - base + offset), delay))
206 gp.set_response_status(tlm::TLM_OK_RESPONSE);
207 break;
208 case tlm::TLM_WRITE_COMMAND:
209 if(ra->write(gp.get_data_ptr() + offset, len, (gp.get_address() - base + offset), delay))
210 gp.set_response_status(tlm::TLM_OK_RESPONSE);
211 break;
212 case tlm::TLM_IGNORE_COMMAND:
213 break;
214 }
215 current_payload = nullptr;
216 }
217 } else {
218 gp.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
219 }
220 delay += clk;
221}
222
223template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_BITWIDTH>
224unsigned int scc::tlm_target<BUSWIDTH, ADDR_UNIT_BITWIDTH>::tranport_dbg_cb(tlm::tlm_generic_payload& gp) {
225 if(gp.get_command() == tlm::TLM_IGNORE_COMMAND)
226 if(auto ext = gp.get_extension<tlm::scc::memory_map_extension>()) {
227 std::string name = socket.name();
228 ext->node.name = name.substr(0, name.length() - strlen(socket.basename()) - 1);
229 auto start_addr = ext->node.start;
230 for(auto e : socket_map) {
231 auto addr = ext->offset + e.first;
232 auto entry = e.second;
233 switch(entry.type) {
234 case util::range_lut<resource_access_t>::BEGIN_RANGE:
235 start_addr = addr;
236 break;
237 case util::range_lut<resource_access_t>::SINGLE_BYTE_RANGE:
238 start_addr = addr;
239 case util::range_lut<resource_access_t>::END_RANGE: {
240 ext->node.elemets.emplace_back(start_addr, ext->offset + addr);
241 ext->node.elemets.back().name = entry.index.first->full_name();
242 break;
243 }
244 }
245 }
246 return 0;
247 }
248 resource_access_if* ra = nullptr;
249 uint64_t base = 0;
250 std::tie(ra, base) = socket_map.getEntry(gp.get_address());
251 if(ra) {
252 if(gp.get_data_length() == ra->size() && gp.get_byte_enable_ptr() == nullptr && gp.get_data_length() == gp.get_streaming_width()) {
253 current_payload = &gp;
254 if(gp.get_command() == tlm::TLM_READ_COMMAND) {
255 if(ra->read_dbg(gp.get_data_ptr(), gp.get_data_length(), (gp.get_address() - base) / ra->size()))
256 return gp.get_data_length();
257 } else if(gp.get_command() == tlm::TLM_WRITE_COMMAND) {
258 if(ra->write_dbg(gp.get_data_ptr(), gp.get_data_length(), (gp.get_address() - base) / ra->size()))
259 return gp.get_data_length();
260 }
261 current_payload = nullptr;
262 }
263 }
264 return 0;
265}
266
267#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
void b_tranport_cb(tlm::tlm_generic_payload &gp, sc_core::sc_time &d)
the blocking transport callback
Definition tlm_target.h:153
tlm::scc::target_mixin< tlm::scc::scv::tlm_rec_target_socket< BUSWIDTH > > socket
Definition tlm_target.h:56
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
unsigned int tranport_dbg_cb(tlm::tlm_generic_payload &gp)
the debug transport callback
Definition tlm_target.h:224
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
tlm_target(sc_core::sc_time &clock, const char *socket_name="socket")
the constructor
Definition tlm_target.h:144
SCC TLM utilities.
struct representing address range
Definition tlm_target.h:34
Definition tlm_target.h:121
Definition tlm_target.h:129