17 #ifndef _SYSC_MEMORY_H_
18 #define _SYSC_MEMORY_H_
21 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
22 #define SC_INCLUDE_DYNAMIC_PROCESSES
26 #include <scc/mt19937_rng.h>
27 #include <scc/report.h>
28 #include <scc/signal_opt_ports.h>
29 #include <scc/utilities.h>
31 #include <tlm/scc/target_mixin.h>
32 #include <util/sparse_array.h>
48 template <
unsigned long long SIZE,
unsigned BUSWIDTH = LT>
class memory :
public sc_core::sc_module {
59 memory(
const sc_core::sc_module_name& nm);
65 constexpr
unsigned long long getSize()
const {
return SIZE; }
85 cci::cci_param<sc_core::sc_time>
rd_resp_delay{
"rd_resp_delay", sc_core::SC_ZERO_TIME};
89 cci::cci_param<sc_core::sc_time>
wr_resp_delay{
"wr_resp_delay", sc_core::SC_ZERO_TIME};
105 int handle_operation(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay);
107 bool handle_dmi(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data);
108 std::function<int(
memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, sc_core::sc_time& delay)> operation_cb;
112 template <
unsigned long long SIZE,
unsigned BUSWIDTH>
116 target.register_b_transport([
this](tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) ->
void {
117 operation_cb ? operation_cb(*
this, gp, delay) :
handle_operation(gp, delay);
119 target.register_transport_dbg([
this](tlm::tlm_generic_payload& gp) ->
unsigned {
120 sc_core::sc_time z = sc_core::SC_ZERO_TIME;
123 target.register_get_direct_mem_ptr([
this](tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) ->
bool {
124 return dmi_cb ? dmi_cb(*
this, gp, dmi_data) :
handle_dmi(gp, dmi_data);
128 template <
unsigned long long SIZE,
unsigned BUSWIDTH>
130 ::sc_dt::uint64 adr = trans.get_address();
131 uint8_t* ptr = trans.get_data_ptr();
132 unsigned len = trans.get_data_length();
133 uint8_t* byt = trans.get_byte_enable_ptr();
134 unsigned wid = trans.get_streaming_width();
138 if(adr + len > ::sc_dt::uint64(SIZE)) {
139 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction exceeeds memory size");
140 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
144 SCCERR(SCMOD) <<
"Streaming width: " << wid <<
", data length: " << len;
145 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction not supported");
146 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
150 auto res = std::accumulate(byt, byt + trans.get_byte_enable_length(), 0xff, [](uint8_t a, uint8_t b) { return a | b; });
151 if(trans.get_byte_enable_length() != len || res != 0xff) {
152 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction with scattered byte enable not supported");
153 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
157 tlm::tlm_command cmd = trans.get_command();
158 SCCTRACE(SCMOD) << (cmd == tlm::TLM_READ_COMMAND ?
"read" :
"write") <<
" access to addr 0x" << std::hex << adr;
159 if(cmd == tlm::TLM_READ_COMMAND) {
160 delay += clk_i.get_interface() ? clk_i->read() * rd_resp_clk_delay : rd_resp_delay;
161 if(mem.is_allocated(adr)) {
162 const auto& p = mem(adr / mem.page_size);
163 auto offs = adr & mem.page_addr_mask;
164 if((offs + len) > mem.page_size) {
165 auto first_part = mem.page_size - offs;
166 std::copy(p.data() + offs, p.data() + offs + first_part, ptr);
167 const auto& p2 = mem((adr / mem.page_size) + 1);
168 std::copy(p2.data(), p2.data() + len - first_part, ptr + first_part);
170 std::copy(p.data() + offs, p.data() + offs + len, ptr);
174 for(
size_t i = 0; i < len; i++)
177 }
else if(cmd == tlm::TLM_WRITE_COMMAND) {
178 delay += clk_i.get_interface() ? clk_i->read() * wr_resp_clk_delay : wr_resp_delay;
179 auto& p = mem(adr / mem.page_size);
180 auto offs = adr & mem.page_addr_mask;
181 if((offs + len) > mem.page_size) {
182 auto first_part = mem.page_size - offs;
183 std::copy(ptr, ptr + first_part, p.data() + offs);
184 auto& p2 = mem((adr / mem.page_size) + 1);
185 std::copy(ptr + first_part, ptr + len, p2.data());
187 std::copy(ptr, ptr + len, p.data() + offs);
190 trans.set_response_status(tlm::TLM_OK_RESPONSE);
191 trans.set_dmi_allowed(
true);
195 template <
unsigned long long SIZE,
unsigned BUSWIDTH>
197 auto& p = mem(gp.get_address() / mem.page_size);
198 dmi_data.set_start_address(gp.get_address() & ~mem.page_addr_mask);
200 dmi_data.set_end_address(dmi_data.get_start_address() + mem.page_size - 1);
201 dmi_data.set_dmi_ptr(p.data());
202 dmi_data.set_granted_access(tlm::tlm_dmi::DMI_ACCESS_READ_WRITE);
203 dmi_data.set_read_latency(clk_i.get_interface() ? clk_i->read() * rd_resp_clk_delay : rd_resp_delay);
204 dmi_data.set_write_latency(clk_i.get_interface() ? clk_i->read() * wr_resp_clk_delay : wr_resp_delay);
static uint64_t uniform()
simple TLM2.0 LT memory model
scc::sc_in_opt< sc_core::sc_time > clk_i
the optional clock pin to calculate clock based delays
memory(const sc_core::sc_module_name &nm)
int handle_operation(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay)
! handle the memory operation independent on interface function used
constexpr unsigned long long getSize() const
return the size of the array
void set_dmi_callback(std::function< int(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...
bool handle_dmi(tlm::tlm_generic_payload &gp, tlm::tlm_dmi &dmi_data)
handle the dmi functionality
util::sparse_array< uint8_t, SIZE > mem
the real memory structure
cci::cci_param< sc_core::sc_time > rd_resp_delay
cci::cci_param< unsigned > wr_resp_clk_delay
cci::cci_param< unsigned > rd_resp_clk_delay
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
tlm::scc::target_mixin< tlm::tlm_target_socket< BUSWIDTH > > target
the target socket to connect to TLM
cci::cci_param< sc_core::sc_time > wr_resp_delay