70class memory :
public sc_core::sc_module {
81 memory(
const sc_core::sc_module_name& nm);
87 static constexpr unsigned long long getPageSize() {
return 1 << PAGE_ADDR_BITS; }
93 static constexpr unsigned long long getSize() {
return SIZE; }
114 cci::cci_param<bool>
allow_dmi{
"allow_dmi",
true,
"Allow DMI accesses to this memory if set"};
133 host_mem_lut.addEntry(
host_map_entry{ptr, base, size}, base, size);
134 }
catch(std::runtime_error& e) {
135 SCCERR(SCMOD) <<
"Cannot map memory to address=0x" << std::hex << base <<
" with size=0x" << size <<
" because: " << e.what();
146 if(!host_mem_lut.removeEntry(
host_map_entry{nullptr, base, size})) {
147 SCCERR(SCMOD) <<
"Cannot unmap memory at address=0x" << std::hex << base <<
" with size=0x" << size;
158 bool operator==(
host_map_entry const& o) {
return base == o.base && size == o.size; }
159 bool operator!=(
host_map_entry const& o) {
return !operator==(o); }
163 void set_clock_period(sc_core::sc_time period) { clk_period = period; }
164 sc_core::sc_time clk_period;
168 int handle_operation(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay);
170 bool handle_dmi(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data);
171 std::function<int(
memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, sc_core::sc_time& delay)> operation_cb;
183struct host_mem_map_extension :
public tlm::tlm_extension<host_mem_map_extension> {
184 tlm_extension_base* clone()
const override {
return nullptr; }
185 void copy_from(tlm_extension_base
const& ext)
override {}
186 host_mem_map_extension(uint8_t* ptr)
188 host_mem_map_extension() =
default;
189 ~host_mem_map_extension() {}
190 uint8_t* ptr{
nullptr};
200 target.register_b_transport([
this](tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) ->
void {
201 operation_cb ? operation_cb(*
this, gp, delay) :
handle_operation(gp, delay);
203 target.register_transport_dbg([
this](tlm::tlm_generic_payload& gp) ->
unsigned {
204 sc_core::sc_time z = sc_core::SC_ZERO_TIME;
210 if(gp.get_command() == tlm::TLM_IGNORE_COMMAND)
215 target.register_get_direct_mem_ptr([
this](tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) ->
bool {
216 return dmi_cb ? dmi_cb(*
this, gp, dmi_data) :
handle_dmi(gp, dmi_data);
222 uint64_t adr = trans.get_address();
223 uint8_t* ptr = trans.get_data_ptr();
224 unsigned len = trans.get_data_length();
225 uint8_t* byt = trans.get_byte_enable_ptr();
226 unsigned wid = trans.get_streaming_width();
230 if(adr + len > ::sc_dt::uint64(SIZE)) {
231 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction exceeeds memory size");
232 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
236 SCCERR(SCMOD) <<
"Streaming width: " << wid <<
", data length: " << len;
237 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction not supported");
238 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
242 auto res = std::accumulate(byt, byt + trans.get_byte_enable_length(), 0xff, [](uint8_t a, uint8_t b) { return a | b; });
243 if(trans.get_byte_enable_length() != len || res != 0xff) {
244 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction with scattered byte enable not supported");
245 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
249 tlm::tlm_command cmd = trans.get_command();
250 SCCTRACE(SCMOD) << (cmd == tlm::TLM_READ_COMMAND ?
"read" :
"write") <<
" access to addr 0x" << std::hex << adr;
251 trans.set_response_status(tlm::TLM_OK_RESPONSE);
252 auto hm_entry = host_mem_lut.getEntry(adr);
253 if(cmd == tlm::TLM_READ_COMMAND) {
256 auto hm_start_offs = adr - hm_entry.base;
257 auto hm_end_offs = hm_start_offs + len;
258 auto hm_ptr = hm_entry.ptr + hm_start_offs;
259 if(hm_end_offs < hm_entry.size) {
260 std::copy(hm_ptr, hm_ptr + len, ptr);
262 auto transfer_length = hm_end_offs - hm_start_offs;
263 std::copy(hm_ptr, hm_ptr + transfer_length, ptr);
264 for(
size_t i = transfer_length; i < len; i++)
268 if(
mem.is_allocated(adr)) {
269 const auto& p =
mem(adr /
mem.page_size);
270 auto offs = adr &
mem.page_addr_mask;
271 if((offs + len) >
mem.page_size) {
272 auto first_part =
mem.page_size - offs;
273 std::copy(p.data() + offs, p.data() + offs + first_part, ptr);
274 const auto& p2 =
mem((adr /
mem.page_size) + 1);
275 auto second_part = len - first_part;
276 std::copy(p2.data(), p2.data() + second_part, ptr + first_part);
278 std::copy(p.data() + offs, p.data() + offs + len, ptr);
282 for(
size_t i = 0; i < len; i++)
286 }
else if(cmd == tlm::TLM_WRITE_COMMAND) {
289 auto hm_start_offs = adr - hm_entry.base;
290 auto hm_end_offs = adr + len - hm_entry.base;
291 auto hm_ptr = hm_entry.ptr + hm_start_offs;
292 auto transfer_length = hm_end_offs < hm_entry.size ? len : hm_end_offs - hm_start_offs;
293 std::copy(ptr, ptr + transfer_length, hm_ptr);
295 auto& p =
mem(adr /
mem.page_size);
296 auto offs = adr &
mem.page_addr_mask;
297 if((offs + len) >
mem.page_size) {
298 auto first_part =
mem.page_size - offs;
299 std::copy(ptr, ptr + first_part, p.data() + offs);
300 auto& p2 =
mem((adr /
mem.page_size) + 1);
301 std::copy(ptr + first_part, ptr + len, p2.data());
303 std::copy(ptr, ptr + len, p.data() + offs);
307 trans.set_dmi_allowed(
allow_dmi.get_value());
314 auto hm_entry = host_mem_lut.getEntry(gp.get_address());
316 dmi_data.set_start_address(hm_entry.base);
317 dmi_data.set_end_address(hm_entry.base + hm_entry.size - 1);
318 dmi_data.set_dmi_ptr(hm_entry.ptr);
320 auto& p =
mem(gp.get_address() /
mem.page_size);
321 auto start_address = gp.get_address() &
~mem.page_addr_mask;
322 auto end_address = std::min<uint64_t>(start_address +
mem.page_size, SIZE);
323 dmi_data.set_start_address(start_address);
324 dmi_data.set_end_address(end_address - 1);
325 dmi_data.set_dmi_ptr(p.data());
327 dmi_data.set_granted_access(tlm::tlm_dmi::DMI_ACCESS_READ_WRITE);
void set_dmi_callback(std::function< bool(memory< SIZE, BUSWIDTH > &, tlm::tlm_generic_payload &, tlm::tlm_dmi &)> cb)
allows to register a callback or functor being invoked upon a direct memory access (DMI) to the memor...
void set_operation_callback(std::function< int(memory< SIZE, BUSWIDTH > &, tlm::tlm_generic_payload &, sc_core::sc_time &delay)> cb)
allows to register a callback or functor being invoked upon an access to the memory