scc  2022.4.0
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 <numeric>
26 #include <scc/mt19937_rng.h>
27 #include <scc/report.h>
28 #include <scc/signal_opt_ports.h>
29 #include <scc/utilities.h>
30 #include <tlm.h>
31 #include <tlm/scc/target_mixin.h>
32 #include <util/sparse_array.h>
33 
34 namespace scc {
35 
48 template <unsigned long long SIZE, unsigned BUSWIDTH = LT> class memory : public sc_core::sc_module {
49 public:
59  memory(const sc_core::sc_module_name& nm);
65  constexpr unsigned long long getSize() const { return SIZE; }
72  void set_operation_callback(std::function<int(memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, sc_core::sc_time& delay)> cb) {
73  operation_cb = cb;
74  }
81  void set_dmi_callback(std::function<int(memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, tlm::tlm_dmi&)> cb) { dmi_cb = cb; }
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};
93  cci::cci_param<unsigned> rd_resp_clk_delay{"rd_resp_clk_delay", 0};
97  cci::cci_param<unsigned> wr_resp_clk_delay{"wr_resp_clk_delay", 0};
98 
99 protected:
102 
103 public:
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;
109  std::function<int(memory<SIZE, BUSWIDTH>&, tlm::tlm_generic_payload&, tlm::tlm_dmi&)> dmi_cb;
110 };
111 
112 template <unsigned long long SIZE, unsigned BUSWIDTH>
113 memory<SIZE, BUSWIDTH>::memory(const sc_core::sc_module_name& nm)
114 : sc_module(nm) {
115  // Register callback for incoming b_transport interface method call
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);
118  });
119  target.register_transport_dbg([this](tlm::tlm_generic_payload& gp) -> unsigned {
120  sc_core::sc_time z = sc_core::SC_ZERO_TIME;
121  return operation_cb ? operation_cb(*this, gp, z) : handle_operation(gp, z);
122  });
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);
125  });
126 }
127 
128 template <unsigned long long SIZE, unsigned BUSWIDTH>
129 int memory<SIZE, BUSWIDTH>::handle_operation(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) {
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();
135  // check address range and check for unsupported features,
136  // i.e. byte enables, streaming, and bursts
137  // Can ignore DMI hint and extensions
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);
141  return 0;
142  }
143  if(wid < len) {
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);
147  return 0;
148  }
149  if(byt) {
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);
154  return 0;
155  }
156  }
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);
169  } else {
170  std::copy(p.data() + offs, p.data() + offs + len, ptr);
171  }
172  } else {
173  // no allocated page so return randomized data
174  for(size_t i = 0; i < len; i++)
175  ptr[i] = scc::MT19937::uniform() % 256;
176  }
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());
186  } else {
187  std::copy(ptr, ptr + len, p.data() + offs);
188  }
189  }
190  trans.set_response_status(tlm::TLM_OK_RESPONSE);
191  trans.set_dmi_allowed(true);
192  return len;
193 }
194 
195 template <unsigned long long SIZE, unsigned BUSWIDTH>
196 inline bool memory<SIZE, BUSWIDTH>::handle_dmi(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) {
197  auto& p = mem(gp.get_address() / mem.page_size);
198  dmi_data.set_start_address(gp.get_address() & ~mem.page_addr_mask);
199  // TODO: fix to provide the correct end address
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);
205  return true;
206 }
207 
208 } // namespace scc
209 
210 #endif /* _SYSC_MEMORY_H_ */
static uint64_t uniform()
Definition: mt19937_rng.h:60
simple TLM2.0 LT memory model
Definition: memory.h:48
scc::sc_in_opt< sc_core::sc_time > clk_i
the optional clock pin to calculate clock based delays
Definition: memory.h:53
memory(const sc_core::sc_module_name &nm)
Definition: memory.h:113
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:129
constexpr unsigned long long getSize() const
return the size of the array
Definition: memory.h:65
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:81
bool handle_dmi(tlm::tlm_generic_payload &gp, tlm::tlm_dmi &dmi_data)
handle the dmi functionality
Definition: memory.h:196
util::sparse_array< uint8_t, SIZE > mem
the real memory structure
Definition: memory.h:101
cci::cci_param< sc_core::sc_time > rd_resp_delay
Definition: memory.h:85
cci::cci_param< unsigned > wr_resp_clk_delay
Definition: memory.h:97
cci::cci_param< unsigned > rd_resp_clk_delay
Definition: memory.h:93
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:72
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:89
SCC SystemC utilities.