quic/qbox
Loading...
Searching...
No Matches
dmi_converter.h
1/*
2 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef _GREENSOCS_BASE_COMPONENTS_DMI_CONVERTER_H
8#define _GREENSOCS_BASE_COMPONENTS_DMI_CONVERTER_H
9
10#include <cci_configuration>
11#include <systemc>
12#include <tlm>
13#include <scp/report.h>
14
15#include <tlm_utils/simple_initiator_socket.h>
16#include <tlm_utils/simple_target_socket.h>
17#include <tlm_utils/multi_passthrough_initiator_socket.h>
18#include <tlm_utils/multi_passthrough_target_socket.h>
19#include <module_factory_registery.h>
20#include <tlm_sockets_buswidth.h>
21#include <map>
22#include <string>
23#include <memory>
24#include <cstring>
25
26namespace gs {
27
28template <unsigned int BUSWIDTH = DEFAULT_TLM_BUSWIDTH>
29class dmi_converter : public sc_core::sc_module
30{
31 SCP_LOGGER();
32
33public:
35 using tlm_initiator_socket_t = tlm_utils::simple_initiator_socket_b<MOD, BUSWIDTH, tlm::tlm_base_protocol_types,
36 sc_core::SC_ZERO_OR_MORE_BOUND>;
37 using tlm_target_socket_t = tlm_utils::simple_target_socket_tagged_b<MOD, BUSWIDTH, tlm::tlm_base_protocol_types,
38 sc_core::SC_ZERO_OR_MORE_BOUND>;
39 // These sockets are kept public for binding.
40 sc_core::sc_vector<tlm_initiator_socket_t> initiator_sockets;
41 sc_core::sc_vector<tlm_target_socket_t> target_sockets;
42 cci::cci_param<uint32_t> p_tlm_ports_num;
43
44public:
45 dmi_converter(const sc_core::sc_module_name& nm)
46 : sc_core::sc_module(nm)
47 , initiator_sockets("initiator_socket")
48 , target_sockets("target_socket")
49 , p_tlm_ports_num("dmic_tlm_ports_num", 1, "number of tlm ports")
50 {
51 SCP_DEBUG(()) << "dmi_converter constructor";
52 initiator_sockets.init(p_tlm_ports_num.get_value(),
53 [this](const char* n, int i) { return new tlm_initiator_socket_t(n); });
54 target_sockets.init(p_tlm_ports_num.get_value(),
55 [this](const char* n, int i) { return new tlm_target_socket_t(n); });
56 for (int i = 0; i < p_tlm_ports_num.get_value(); i++) {
57 target_sockets[i].register_b_transport(this, &dmi_converter::b_transport, i);
58 target_sockets[i].register_transport_dbg(this, &dmi_converter::transport_dbg, i);
59 target_sockets[i].register_get_direct_mem_ptr(this, &dmi_converter::get_direct_mem_ptr, i);
60 initiator_sockets[i].register_invalidate_direct_mem_ptr(this, &dmi_converter::invalidate_direct_mem_ptr);
61 }
62 }
63
65
66private:
67 void b_transport(int id, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay)
68 {
69 uint64_t addr = trans.get_address();
70 uint64_t len = trans.get_data_length();
71 tlm::tlm_command cmd = trans.get_command();
72 unsigned char* trans_data_ptr = trans.get_data_ptr();
73 unsigned char* ref_byt = trans.get_byte_enable_ptr();
74 unsigned int bel = trans.get_byte_enable_length();
75 if (ref_byt && (bel <= 0)) SCP_FATAL(()) << "byte enable ptr is not NULL but byte enable length <= 0!";
76 std::unique_ptr<unsigned char[]> byt;
77 if (ref_byt) {
78 byt = std::make_unique<unsigned char[]>(bel);
79 std::memcpy(byt.get(), ref_byt, bel);
80 } else {
81 byt = nullptr;
82 }
83 unsigned int bel_remaining_len = bel;
86 tlm::tlm_dmi* dmi_data;
87 bool is_cache_used = false;
88 while (remaining_len) {
89 dmi_data = in_cache(addr);
90 if (dmi_data && is_dmi_access_type_granted(*dmi_data, cmd)) {
91 sc_dt::uint64 start_addr = dmi_data->get_start_address();
92 sc_dt::uint64 end_addr = dmi_data->get_end_address();
93 unsigned char* dmi_ptr = dmi_data->get_dmi_ptr();
96 switch (cmd) {
97 case tlm::TLM_IGNORE_COMMAND:
98 return;
99 case tlm::TLM_WRITE_COMMAND:
100 SCP_DEBUG(()) << "(write request) cache is used to write " << std::hex << iter_len
101 << " bytes starting from: 0x" << std::hex << addr
102 << ", cache block used starts at: 0x" << std::hex << start_addr << " and ends at: 0x"
103 << std::hex << end_addr;
104 if (byt) {
105 for (unsigned int i = 0; i < iter_len; i++) {
106 if (byt[i % bel] == TLM_BYTE_ENABLED) {
108 }
109 }
110 } else {
111 memcpy(reinterpret_cast<unsigned char*>(&dmi_ptr[addr - start_addr]),
112 reinterpret_cast<unsigned char*>(trans_data_ptr), iter_len);
113 }
114 break;
115 case tlm::TLM_READ_COMMAND:
116 SCP_DEBUG(()) << "(read request) cache is used to read " << std::hex << iter_len
117 << " bytes starting from: 0x" << std::hex << addr
118 << ", cache block used starts at: 0x" << std::hex << start_addr << " and ends at: 0x"
119 << std::hex << end_addr;
120 if (byt) {
121 for (unsigned int i = 0; i < iter_len; i++) {
122 if (byt[i % bel] == TLM_BYTE_ENABLED) {
124 }
125 }
126 } else {
127 memcpy(reinterpret_cast<unsigned char*>(trans_data_ptr),
128 reinterpret_cast<unsigned char*>(&dmi_ptr[addr - start_addr]), iter_len);
129 }
130 break;
131 default:
132 SCP_FATAL(()) << "invalid tlm_command at address: 0x" << std::hex << addr;
133 break;
134 }
136 addr += iter_len;
139 unsigned char* mutated_byt = byt.get();
140 update_byte_enable(trans, &mutated_byt, &bel_remaining_len, iter_len);
141 if (remaining_len == 0) {
142 trans.set_dmi_allowed(true);
143 trans.set_response_status(tlm::TLM_OK_RESPONSE);
144 }
145 is_cache_used = true;
146 SCP_DEBUG(()) << "remaining_len: " << remaining_len;
147 } else {
148 tlm::tlm_dmi t_dmi_data;
149 tlm::tlm_generic_payload t_trans;
150 t_dmi_data.init();
151 if (is_cache_used) {
152 t_trans.deep_copy_from(trans);
153 t_trans.set_address(addr);
154 t_trans.set_data_length(len);
155 t_trans.set_data_ptr(trans_data_ptr);
156 t_trans.set_byte_enable_length(bel_remaining_len);
157 t_trans.set_byte_enable_ptr(byt.get());
158 }
159 bool dmi_ptr_valid = initiator_sockets[id]->get_direct_mem_ptr((is_cache_used ? t_trans : trans),
160 t_dmi_data);
161 if (dmi_ptr_valid && is_dmi_access_type_granted(t_dmi_data, cmd)) {
162 SCP_DEBUG(()) << get_access_type_str(cmd)
163 << " data is not in cache, DMI request is successful, granted start addr: "
164 "0x"
165 << std::hex << t_dmi_data.get_start_address() << " granted end addr: 0x" << std::hex
166 << t_dmi_data.get_end_address();
167 m_dmi_cache[t_dmi_data.get_start_address()] = t_dmi_data;
168 } else {
169 initiator_sockets[id]->b_transport((is_cache_used ? t_trans : trans), delay);
170 SCP_DEBUG(()) << get_access_type_str(cmd)
171 << " data is not in cache, DMI request failed, b_transport used, len: " << std::hex
172 << (is_cache_used ? t_trans.get_data_length() : trans.get_data_length())
173 << " addr: 0x" << std::hex
174 << (is_cache_used ? t_trans.get_address() : trans.get_address());
175 trans.set_dmi_allowed(false);
176 if (is_cache_used) trans.set_response_status(t_trans.get_response_status());
177 break;
178 }
179 }
180 }
181 }
182
183 unsigned int transport_dbg(int id, tlm::tlm_generic_payload& trans)
184 {
185 SCP_DEBUG(()) << "calling dbg_transport: ";
186 return initiator_sockets[id]->transport_dbg(trans);
187 }
188
189 bool get_direct_mem_ptr(int id, tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data)
190 {
191 SCP_DEBUG(()) << "DMI to " << trans.get_address() << " range " << std::hex << dmi_data.get_start_address()
192 << " - " << std::hex << dmi_data.get_end_address();
193 auto c_dmi_data = in_cache(trans.get_address());
194 if (c_dmi_data) {
195 dmi_data = *c_dmi_data;
196 return !(dmi_data.is_none_allowed());
197 } else {
198 auto dmi_ptr_valid = initiator_sockets[id]->get_direct_mem_ptr(trans, dmi_data);
199 if (dmi_ptr_valid) m_dmi_cache[dmi_data.get_start_address()] = dmi_data;
200 return dmi_ptr_valid;
201 }
202 }
203
204 void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end)
205 {
206 SCP_DEBUG(()) << " invalidate_direct_mem_ptr "
207 << " start address 0x" << std::hex << start << " end address 0x" << std::hex << end;
208
209 cache_clean(start, end);
210 for (int i = 0; i < target_sockets.size(); i++) {
211 target_sockets[i]->invalidate_direct_mem_ptr(start, end);
212 }
213 }
214
215 void update_byte_enable(tlm::tlm_generic_payload& trans, unsigned char** byt, unsigned int* bel_remaining_len,
217 {
218 if (!*byt) return;
219
220 unsigned int trans_dl = trans.get_data_length();
221 unsigned int trans_bel = trans.get_byte_enable_length();
222
223 if (trans_bel >= trans_dl) {
224 *byt += iter_len;
226 } else if (trans_bel < trans_dl) {
227 if (!(iter_len % trans_bel)) return; // nothing to do if the iter_len == (n * trans_bel)
228 std::rotate(*byt, *byt + (iter_len % trans_bel),
229 *byt + trans_bel); // keep trans_bel and adjust the position of bytes
231 }
232 }
233
234 bool is_dmi_access_type_granted(const tlm::tlm_dmi& dmi_data, const tlm::tlm_command& cmd)
235 {
236 switch (cmd) {
237 case tlm::TLM_WRITE_COMMAND:
238 return dmi_data.is_write_allowed();
239 case tlm::TLM_READ_COMMAND:
240 return dmi_data.is_read_allowed();
241 default:
242 return false;
243 }
244 }
245
246 std::string get_access_type_str(const tlm::tlm_command& cmd)
247 {
248 std::string ret_str;
249 switch (cmd) {
250 case tlm::TLM_WRITE_COMMAND:
251 ret_str = "(write request)";
252 break;
253 case tlm::TLM_READ_COMMAND:
254 ret_str = "(read request)";
255 break;
256 case tlm::TLM_IGNORE_COMMAND:
257 ret_str = "(ignore request)";
258 break;
259 default:
260 ret_str = "(invalid tlm_command)";
261 break;
262 }
263 return ret_str;
264 }
265
266 tlm::tlm_dmi* in_cache(uint64_t address)
267 {
268 if (m_dmi_cache.size() > 0) {
269 auto it = m_dmi_cache.upper_bound(address);
270 if (it != m_dmi_cache.begin()) {
271 it = std::prev(it);
272 if ((address >= it->second.get_start_address()) && (address <= it->second.get_end_address())) {
273 return &(it->second);
274 }
275 }
276 }
277 return nullptr;
278 }
279 void cache_clean(uint64_t start, uint64_t end)
280 {
281 auto it = m_dmi_cache.upper_bound(start);
282
283 if (it != m_dmi_cache.begin()) {
284 /*
285 * Start with the preceding region, as it may already cross the
286 * range we must invalidate.
287 */
288 it--;
289 }
290
291 while (it != m_dmi_cache.end()) {
292 tlm::tlm_dmi& r = it->second;
293
294 if (r.get_start_address() > end) {
295 /* We've got out of the invalidation range */
296 break;
297 }
298
299 if (r.get_end_address() < start) {
300 /* We are not in yet */
301 it++;
302 continue;
303 }
304 it = m_dmi_cache.erase(it);
305 }
306 }
307
308private:
309 std::map<uint64_t, tlm::tlm_dmi> m_dmi_cache;
310};
311} // namespace gs
312
313extern "C" void module_register();
314
315#endif
Definition target.h:160
Definition dmi_converter.h:30
Tool which reads a Lua configuration file and sets parameters.
Definition biflow.cc:10