scc  2024.06
SystemC components library
memory.h
1 /*******************************************************************************
2  * Copyright 2016, 2018 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 
17 #ifndef _SYSC_MEMORY_H_
18 #define _SYSC_MEMORY_H_
19 
20 // Needed for the simple_target_socket
21 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
22 #define SC_INCLUDE_DYNAMIC_PROCESSES
23 #endif
24 
25 #include "clock_if_mixins.h"
26 #include <numeric>
27 #include <scc/mt19937_rng.h>
28 #include <scc/report.h>
29 #include <scc/signal_opt_ports.h>
30 #include <scc/utilities.h>
31 #include <tlm.h>
32 #include <tlm/scc/target_mixin.h>
33 #include <util/sparse_array.h>
34 
35 namespace scc {
48 template <unsigned long long SIZE, unsigned BUSWIDTH = LT> class memory : public sc_core::sc_module {
49 public:
57  memory(const sc_core::sc_module_name& nm);
63  constexpr unsigned long long getSize() const { return SIZE; }
70  void set_operation_callback(std::function<int(memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, sc_core::sc_time& delay)> cb) {
71  operation_cb = cb;
72  }
79  void set_dmi_callback(std::function<int(memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, tlm::tlm_dmi&)> cb) { dmi_cb = cb; }
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};
91  cci::cci_param<unsigned> rd_resp_clk_delay{"rd_resp_clk_delay", 0};
95  cci::cci_param<unsigned> wr_resp_clk_delay{"wr_resp_clk_delay", 0};
96 
97 protected:
100 
101  void set_clock_period(sc_core::sc_time period) { clk_period = period; }
102  sc_core::sc_time clk_period;
103 
104 public:
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;
110  std::function<int(memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, tlm::tlm_dmi&)> dmi_cb;
111 };
112 
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>>;
115 
116 template <unsigned long long SIZE, unsigned BUSWIDTH>
117 memory<SIZE, BUSWIDTH>::memory(const sc_core::sc_module_name& nm)
118 : sc_module(nm) {
119  // Register callback for incoming b_transport interface method call
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);
122  });
123  target.register_transport_dbg([this](tlm::tlm_generic_payload& gp) -> unsigned {
124  sc_core::sc_time z = sc_core::SC_ZERO_TIME;
125  return operation_cb ? operation_cb(*this, gp, z) : handle_operation(gp, z);
126  });
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);
129  });
130 }
131 
132 template <unsigned long long SIZE, unsigned BUSWIDTH>
133 int memory<SIZE, BUSWIDTH>::handle_operation(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) {
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();
139  // check address range and check for unsupported features,
140  // i.e. byte enables, streaming, and bursts
141  // Can ignore DMI hint and extensions
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);
145  return 0;
146  }
147  if(wid < len) {
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);
151  return 0;
152  }
153  if(byt) {
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);
158  return 0;
159  }
160  }
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);
173  } else {
174  std::copy(p.data() + offs, p.data() + offs + len, ptr);
175  }
176  } else {
177  // no allocated page so return randomized data
178  for(size_t i = 0; i < len; i++)
179  ptr[i] = scc::MT19937::uniform() % 256;
180  }
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());
190  } else {
191  std::copy(ptr, ptr + len, p.data() + offs);
192  }
193  }
194  trans.set_response_status(tlm::TLM_OK_RESPONSE);
195  trans.set_dmi_allowed(true);
196  return len;
197 }
198 
199 template <unsigned long long SIZE, unsigned BUSWIDTH>
200 inline bool memory<SIZE, BUSWIDTH>::handle_dmi(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) {
201  auto& p = mem(gp.get_address() / mem.page_size);
202  dmi_data.set_start_address(gp.get_address() & ~mem.page_addr_mask);
203  // TODO: fix to provide the correct end address
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);
209  return true;
210 }
211 
212 } // namespace scc
213 
214 #endif /* _SYSC_MEMORY_H_ */
static uint64_t uniform()
Definition: mt19937_rng.h:60
simple TLM2.0 LT memory model
Definition: memory.h:48
memory(const sc_core::sc_module_name &nm)
Definition: memory.h:117
int handle_operation(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay)
! handle the memory operation independent on interface function used
Definition: memory.h:133
constexpr unsigned long long getSize() const
return the size of the array
Definition: memory.h:63
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...
Definition: memory.h:79
bool handle_dmi(tlm::tlm_generic_payload &gp, tlm::tlm_dmi &dmi_data)
handle the dmi functionality
Definition: memory.h:200
util::sparse_array< uint8_t, SIZE > mem
the real memory structure
Definition: memory.h:99
cci::cci_param< sc_core::sc_time > rd_resp_delay
Definition: memory.h:83
cci::cci_param< unsigned > wr_resp_clk_delay
Definition: memory.h:95
cci::cci_param< unsigned > rd_resp_clk_delay
Definition: memory.h:91
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
Definition: memory.h:70
tlm::scc::target_mixin< tlm::tlm_target_socket< BUSWIDTH > > target
the target socket to connect to TLM
Definition: memory.h:51
cci::cci_param< sc_core::sc_time > wr_resp_delay
Definition: memory.h:87
SCC TLM utilities.