17 #ifndef _SYSC_MEMORY_H_
18 #define _SYSC_MEMORY_H_
21 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
22 #define SC_INCLUDE_DYNAMIC_PROCESSES
25 #include "clock_if_mixins.h"
27 #include <scc/mt19937_rng.h>
28 #include <scc/report.h>
29 #include <scc/signal_opt_ports.h>
30 #include <scc/utilities.h>
32 #include <tlm/scc/target_mixin.h>
33 #include <util/sparse_array.h>
48 template <
unsigned long long SIZE,
unsigned BUSWIDTH = LT>
class memory :
public sc_core::sc_module {
57 memory(
const sc_core::sc_module_name& nm);
63 constexpr
unsigned long long getSize()
const {
return SIZE; }
83 cci::cci_param<sc_core::sc_time>
rd_resp_delay{
"rd_resp_delay", sc_core::SC_ZERO_TIME};
87 cci::cci_param<sc_core::sc_time>
wr_resp_delay{
"wr_resp_delay", sc_core::SC_ZERO_TIME};
101 void set_clock_period(sc_core::sc_time period) { clk_period = period; }
102 sc_core::sc_time clk_period;
106 int handle_operation(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay);
108 bool handle_dmi(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data);
109 std::function<int(
memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, sc_core::sc_time& delay)> operation_cb;
113 template <
unsigned long long SIZE,
unsigned BUSWIDTH = LT>
using memory_tl = tickless_clock<memory<SIZE, BUSWIDTH>>;
114 template <
unsigned long long SIZE,
unsigned BUSWIDTH = LT>
using memory_tc = ticking_clock<memory<SIZE, BUSWIDTH>>;
116 template <
unsigned long long SIZE,
unsigned BUSWIDTH>
120 target.register_b_transport([
this](tlm::tlm_generic_payload& gp, sc_core::sc_time& delay) ->
void {
121 operation_cb ? operation_cb(*
this, gp, delay) :
handle_operation(gp, delay);
123 target.register_transport_dbg([
this](tlm::tlm_generic_payload& gp) ->
unsigned {
124 sc_core::sc_time z = sc_core::SC_ZERO_TIME;
127 target.register_get_direct_mem_ptr([
this](tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) ->
bool {
128 return dmi_cb ? dmi_cb(*
this, gp, dmi_data) :
handle_dmi(gp, dmi_data);
132 template <
unsigned long long SIZE,
unsigned BUSWIDTH>
134 ::sc_dt::uint64 adr = trans.get_address();
135 uint8_t* ptr = trans.get_data_ptr();
136 unsigned len = trans.get_data_length();
137 uint8_t* byt = trans.get_byte_enable_ptr();
138 unsigned wid = trans.get_streaming_width();
142 if(adr + len > ::sc_dt::uint64(SIZE)) {
143 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction exceeeds memory size");
144 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
148 SCCERR(SCMOD) <<
"Streaming width: " << wid <<
", data length: " << len;
149 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction not supported");
150 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
154 auto res = std::accumulate(byt, byt + trans.get_byte_enable_length(), 0xff, [](uint8_t a, uint8_t b) { return a | b; });
155 if(trans.get_byte_enable_length() != len || res != 0xff) {
156 SC_REPORT_ERROR(
"TLM-2",
"generic payload transaction with scattered byte enable not supported");
157 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
161 tlm::tlm_command cmd = trans.get_command();
162 SCCTRACE(SCMOD) << (cmd == tlm::TLM_READ_COMMAND ?
"read" :
"write") <<
" access to addr 0x" << std::hex << adr;
163 if(cmd == tlm::TLM_READ_COMMAND) {
164 delay += clk_period.value() ? clk_period * rd_resp_clk_delay : rd_resp_delay;
165 if(mem.is_allocated(adr)) {
166 const auto& p = mem(adr / mem.page_size);
167 auto offs = adr & mem.page_addr_mask;
168 if((offs + len) > mem.page_size) {
169 auto first_part = mem.page_size - offs;
170 std::copy(p.data() + offs, p.data() + offs + first_part, ptr);
171 const auto& p2 = mem((adr / mem.page_size) + 1);
172 std::copy(p2.data(), p2.data() + len - first_part, ptr + first_part);
174 std::copy(p.data() + offs, p.data() + offs + len, ptr);
178 for(
size_t i = 0; i < len; i++)
181 }
else if(cmd == tlm::TLM_WRITE_COMMAND) {
182 delay += clk_period.value() ? clk_period * wr_resp_clk_delay : wr_resp_delay;
183 auto& p = mem(adr / mem.page_size);
184 auto offs = adr & mem.page_addr_mask;
185 if((offs + len) > mem.page_size) {
186 auto first_part = mem.page_size - offs;
187 std::copy(ptr, ptr + first_part, p.data() + offs);
188 auto& p2 = mem((adr / mem.page_size) + 1);
189 std::copy(ptr + first_part, ptr + len, p2.data());
191 std::copy(ptr, ptr + len, p.data() + offs);
194 trans.set_response_status(tlm::TLM_OK_RESPONSE);
195 trans.set_dmi_allowed(
true);
199 template <
unsigned long long SIZE,
unsigned BUSWIDTH>
201 auto& p = mem(gp.get_address() / mem.page_size);
202 dmi_data.set_start_address(gp.get_address() & ~mem.page_addr_mask);
204 dmi_data.set_end_address(dmi_data.get_start_address() + mem.page_size - 1);
205 dmi_data.set_dmi_ptr(p.data());
206 dmi_data.set_granted_access(tlm::tlm_dmi::DMI_ACCESS_READ_WRITE);
207 dmi_data.set_read_latency(clk_period.value() ? clk_period * rd_resp_clk_delay : rd_resp_delay);
208 dmi_data.set_write_latency(clk_period.value() ? clk_period * wr_resp_clk_delay : wr_resp_delay);
static uint64_t uniform()
simple TLM2.0 LT memory model
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