73class memory :
public sc_core::sc_module {
85 memory(
const sc_core::sc_module_name& nm);
91 static constexpr unsigned long long getPageSize() {
return 1 << PAGE_ADDR_BITS; }
97 static constexpr unsigned long long getSize() {
return SIZE; }
118 cci::cci_param<bool>
allow_dmi{
"allow_dmi",
true,
"Allow DMI accesses to this memory if set"};
137 host_mem_lut.addEntry(host_map_entry{ptr, base, size}, base, size);
138 }
catch(std::runtime_error& e) {
139 SCCERR(SCMOD) <<
"Cannot map memory to address=0x" << std::hex << base <<
" with size=0x" << size <<
" because: " << e.what();
150 if(!host_mem_lut.removeEntry(host_map_entry{nullptr, base, size})) {
151 SCCERR(SCMOD) <<
"Cannot unmap memory at address=0x" << std::hex << base <<
" with size=0x" << size;
162 bool operator==(
host_map_entry const& o) {
return base == o.base && size == o.size; }
163 bool operator!=(
host_map_entry const& o) {
return !operator==(o); }
167 void set_clock_period(sc_core::sc_time period) { clk_period = period; }
168 sc_core::sc_time clk_period;
174 bool handle_dmi(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data);
175 std::function<int(this_class&, tlm::tlm_generic_payload&, sc_core::sc_time& delay)> operation_cb;
176 std::function<bool(this_class&, tlm::tlm_generic_payload&, tlm::tlm_dmi&)> dmi_cb;
187struct host_mem_map_extension :
public tlm::tlm_extension<host_mem_map_extension> {
188 tlm_extension_base* clone()
const override {
return nullptr; }
189 void copy_from(tlm_extension_base
const& ext)
override {}
190 host_mem_map_extension(uint8_t* data,
size_t size)
191 : range(data, data + size) {}
192 host_mem_map_extension(
size_t size)
193 : range(
nullptr, size) {}
194 host_mem_map_extension() =
default;
195 ~host_mem_map_extension() {}
196 nonstd::span<uint8_t> range;
206 target.register_b_transport([
this](tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) ->
void {
207 operation_cb ? operation_cb(*
this, gp, delay) :
handle_operation(gp, delay);
209 target.register_transport_dbg([
this](tlm::tlm_generic_payload& gp) ->
unsigned {
210 if(gp.get_command() == tlm::TLM_IGNORE_COMMAND)
212 ext->node.name = name();
215 sc_core::sc_time z = sc_core::SC_ZERO_TIME;
217 if(ext->range.data())
218 map_host_memory(gp.get_address(), ext->range.size(), ext->range.data());
221 if(gp.get_command() == tlm::TLM_IGNORE_COMMAND)
226 target.register_get_direct_mem_ptr([
this](tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) ->
bool {
227 return dmi_cb ? dmi_cb(*
this, gp, dmi_data) :
handle_dmi(gp, dmi_data);
233 uint64_t adr = trans.get_address();
234 uint8_t* ptr = trans.get_data_ptr();
235 unsigned len = trans.get_data_length();
236 uint8_t* byt = trans.get_byte_enable_ptr();
237 unsigned wid = trans.get_streaming_width();
241 if(adr + len > ::sc_dt::uint64(SIZE)) {
242 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction exceeeds memory size");
243 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
247 SCCERR(SCMOD) <<
"Streaming width: " << wid <<
", data length: " << len;
248 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction not supported");
249 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
253 byt ? std::accumulate(byt, byt + trans.get_byte_enable_length(), 0xff, [](uint8_t a, uint8_t b) { return a & b; }) != 0xff :
false;
254 tlm::tlm_command cmd = trans.get_command();
255 SCCTRACE(SCMOD) << (cmd == tlm::TLM_READ_COMMAND ?
"read" :
"write") <<
" access to addr 0x" << std::hex << adr;
256 trans.set_dmi_allowed(
allow_dmi.get_value());
257 trans.set_response_status(tlm::TLM_OK_RESPONSE);
258 auto hm_entry = host_mem_lut.getEntry(adr);
259 if(cmd == tlm::TLM_READ_COMMAND) {
262 auto hm_start_offs = adr - hm_entry.base;
263 auto hm_end_offs = hm_start_offs + len;
264 auto hm_ptr = hm_entry.ptr + hm_start_offs;
265 if(hm_end_offs < hm_entry.size) {
266 std::copy(hm_ptr, hm_ptr + len, ptr);
268 auto transfer_length = hm_end_offs - hm_start_offs;
269 std::copy(hm_ptr, hm_ptr + transfer_length, ptr);
270 for(
size_t i = transfer_length; i < len; i++)
274 if(
mem.is_allocated(adr)) {
275 const auto& p =
mem(adr /
mem.page_size);
276 auto offs = adr &
mem.page_addr_mask;
277 if((offs + len) >
mem.page_size) {
278 auto first_part =
mem.page_size - offs;
279 std::copy(p.data() + offs, p.data() + offs + first_part, ptr);
280 const auto& p2 =
mem((adr /
mem.page_size) + 1);
281 auto second_part = len - first_part;
282 std::copy(p2.data(), p2.data() + second_part, ptr + first_part);
284 std::copy(p.data() + offs, p.data() + offs + len, ptr);
288 for(
size_t i = 0; i < len; i++)
292 }
else if(cmd == tlm::TLM_WRITE_COMMAND) {
294 if(UNLIKELY(hm_entry.ptr)) {
295 auto hm_start_offs = adr - hm_entry.base;
296 auto hm_end_offs = adr + len - hm_entry.base;
297 auto hm_ptr = hm_entry.ptr + hm_start_offs;
298 auto transfer_length = hm_end_offs < hm_entry.size ? len : hm_end_offs - hm_start_offs;
300 for(
size_t i = 0; i < transfer_length; ++i)
302 *(hm_ptr + i) = *(ptr + i);
304 std::copy(ptr, ptr + transfer_length, hm_ptr);
306 auto& p =
mem(adr /
mem.page_size);
307 auto offs = adr &
mem.page_addr_mask;
308 if(UNLIKELY((offs + len) >
mem.page_size)) {
309 auto first_part =
mem.page_size - offs;
311 for(
size_t i = 0; i < first_part; ++i)
313 *(p.data() + offs + i) = *(ptr + i);
315 std::copy(ptr, ptr + first_part, p.data() + offs);
316 auto& p2 =
mem((adr /
mem.page_size) + 1);
318 for(
size_t i = 0, j = first_part; j < len; ++i, ++j)
320 *(p2.data() + i) = *(ptr + j);
322 std::copy(ptr + first_part, ptr + len, p2.data());
325 for(
size_t i = 0; i < len; ++i)
327 *(p.data() + offs + i) = *(ptr + i);
329 std::copy(ptr, ptr + len, p.data() + offs);
339 auto hm_entry = host_mem_lut.getEntry(gp.get_address());
341 dmi_data.set_start_address(hm_entry.base);
342 dmi_data.set_end_address(hm_entry.base + hm_entry.size - 1);
343 dmi_data.set_dmi_ptr(hm_entry.ptr);
345 auto& p =
mem(gp.get_address() /
mem.page_size);
346 auto start_address = gp.get_address() &
~mem.page_addr_mask;
347 auto end_address = std::min<uint64_t>(start_address +
mem.page_size, SIZE);
348 dmi_data.set_start_address(start_address);
349 dmi_data.set_end_address(end_address - 1);
350 dmi_data.set_dmi_ptr(p.data());
352 dmi_data.set_granted_access(tlm::tlm_dmi::DMI_ACCESS_READ_WRITE);