scc 2025.09
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
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
108protected:
109 util::range_lut<std::pair<resource_access_if*, uint64_t>> socket_map;
110};
111
114template <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};
119
122template <unsigned BUSWIDTH = LT> struct target_name_map_entry {
123 std::string name;
124 ::sc_dt::uint64 start;
125 ::sc_dt::uint64 size;
126};
127template <unsigned int BUSWIDTH = LT, unsigned int ADDR_UNIT_BITWIDTH = 8>
128struct tlm_target_mod : sc_core::sc_module, public tlm_target<BUSWIDTH, ADDR_UNIT_BITWIDTH> {
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
136template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_BITWIDTH>
137inline scc::tlm_target<BUSWIDTH, ADDR_UNIT_BITWIDTH>::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([this](tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) -> void { this->b_tranport_cb(gp, delay); });
142 socket.register_transport_dbg([this](tlm::tlm_generic_payload& gp) -> unsigned { return this->tranport_dbg_cb(gp); });
143}
144
145template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_BITWIDTH>
146void scc::tlm_target<BUSWIDTH, ADDR_UNIT_BITWIDTH>::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
212template <unsigned int BUSWIDTH, unsigned int ADDR_UNIT_BITWIDTH>
213unsigned int scc::tlm_target<BUSWIDTH, ADDR_UNIT_BITWIDTH>::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
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
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:213
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:137
SCC TLM utilities.
struct representing address range
Definition tlm_target.h:34
Definition tlm_target.h:114
Definition tlm_target.h:122