HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
simulation_gate_ram.cpp
Go to the documentation of this file.
5 
6 namespace hal
7 {
8  namespace
9  {
10  u32 get_data_word(const std::vector<u64>& data, u32 address, u32 width)
11  {
12  u32 start_pos = address * width;
13  u32 row = start_pos >> 6;
14  u32 start_bit = start_pos & 0x3F;
15 
16  if (row >= data.size() || 64 % width != 0 || width > 32)
17  {
18  log_error("hal_simulator", "cannot read data word of width {} at address {0:x}.", width, address);
19  return 0;
20  }
21 
22  // reads right to left
23  return (u32)((data.at(row) >> start_bit) & ((1 << width) - 1));
24  }
25 
26  void set_data_word(std::vector<u64>& data, u32 in_data, u32 address, u32 width)
27  {
28  u32 start_pos = address * width;
29  u32 row = start_pos >> 6;
30  u32 start_bit = start_pos & 0x3F;
31 
32  if (row >= data.size() || 64 % width != 0 || width > 32)
33  {
34  log_error("hal_simulator", "cannot write data word {0:x} of width {} to address {0:x}.", in_data, width, address);
35  return;
36  }
37 
38  // reads right to left
39  u64 mask = ~((((u64)1 << width) - 1) << start_bit);
40  data.at(row) = (data.at(row) & mask) ^ ((u64)in_data << start_bit);
41  }
42  } // namespace
43 
44  NetlistSimulator::SimulationGateRAM::SimulationGateRAM(const Gate* gate) : SimulationGateSequential(gate)
45  {
46  const GateType* gate_type = gate->get_type();
47  const RAMComponent* ram_component = gate_type->get_component_as<RAMComponent>([](const GateTypeComponent* c) { return RAMComponent::is_class_of(c); });
48  assert(ram_component != nullptr);
49 
50  m_bit_size = ram_component->get_bit_size();
51 
52  for (const GateTypeComponent* component : ram_component->get_components([](const GateTypeComponent* c) { return RAMPortComponent::is_class_of(c); }))
53  {
54  const RAMPortComponent* port_component = component->convert_to<RAMPortComponent>();
55 
56  Port simulation_port;
57  simulation_port.clock_func = port_component->get_clock_function();
58  simulation_port.enable_func = port_component->get_enable_function();
59  simulation_port.is_write = port_component->is_write_port();
60 
61  for (GatePin* pin : gate_type->get_pin_group_by_name(port_component->get_data_group())->get_pins())
62  {
63  simulation_port.data_pins.push_back(pin);
64  }
65 
66  for (GatePin* pin : gate_type->get_pin_group_by_name(port_component->get_address_group())->get_pins())
67  {
68  simulation_port.address_pins.push_back(pin);
69  }
70 
71  // determine clock net
72  for (const std::string& var : simulation_port.clock_func.get_variable_names())
73  {
74  if (const GatePin* pin = gate_type->get_pin_by_name(var); pin != nullptr && pin->get_type() == PinType::clock)
75  {
76  simulation_port.clock_net = gate->get_fan_in_net(pin);
77  }
78  }
79 
80  assert(simulation_port.clock_net != nullptr);
81 
82  m_ports.push_back(simulation_port);
83  }
84  }
85 
86  void NetlistSimulator::SimulationGateRAM::initialize(std::map<const Net*, BooleanFunction::Value>& new_events, bool from_netlist, BooleanFunction::Value value)
87  {
88  GateType* gate_type = m_gate->get_type();
89 
90  const RAMComponent* ram_component = gate_type->get_component_as<RAMComponent>([](const GateTypeComponent* c) { return RAMComponent::is_class_of(c); });
91  if (ram_component == nullptr)
92  {
93  log_error("hal_simulator", "cannot find RAM properties for RAM gate '{}' with ID {} of type '{}'.", m_gate->get_name(), m_gate->get_id(), gate_type->get_name());
94  return;
95  }
96 
97  if (from_netlist)
98  {
99  const std::vector<std::string>& init_ids = ram_component->get_init_identifiers();
100 
101  if (init_ids.empty())
102  {
103  log_error("hal_simulator", "no initialization identifiers for RAM gate '{}' with ID {} of type '{}'.", m_gate->get_name(), m_gate->get_id(), gate_type->get_name());
104  return;
105  }
106 
107  for (const std::string& identifier : init_ids)
108  {
109  auto param_res = m_gate->get_parameter_value(identifier);
110  if (param_res.is_error())
111  {
112  log_error("hal_simulator",
113  "could not read initialization parameter '{}' for RAM gate '{}' with ID {}: {}",
114  identifier,
115  m_gate->get_name(),
116  m_gate->get_id(),
117  param_res.get_error().get());
118  return;
119  }
120  const std::string& pv = param_res.get();
121  const std::string& data = (pv.size() >= 2 && pv[0] == '0' && pv[1] == 'x') ? pv.substr(2) : pv;
122 
123  u32 data_len = static_cast<u32>(data.size());
124  if (data_len == 0 || data_len % 16 != 0)
125  {
126  log_error("hal_simulator", "initialization data for '{}' in RAM gate '{}' must be a multiple of 64 bits.", identifier, m_gate->get_name());
127  return;
128  }
129 
130  for (u32 i = 0; i < data_len; i += 16)
131  {
132  m_data.push_back(strtoull(data.substr(data_len - i - 16, 16).c_str(), nullptr, 16));
133  }
134  }
135 
136  if (ram_component->get_bit_size() != m_data.size() * 64)
137  {
138  log_error("hal_simulator", "initialization data does not fit memory size for RAM gate '{}' with ID {} of type '{}'.", m_gate->get_name(), m_gate->get_id(), gate_type->get_name());
139  m_data.clear();
140  return;
141  }
142  }
143  else
144  {
145  u64 init_val;
146 
147  switch (value)
148  {
149  case BooleanFunction::Value::ONE:
150  init_val = 0xFFFFFFFFFFFFFFFF;
151  break;
152  case BooleanFunction::Value::ZERO:
153  init_val = 0x0;
154  break;
155  case BooleanFunction::Value::X:
156  case BooleanFunction::Value::Z:
157  log_error("hal_simulator", "RAM gate '{}' with ID {} of type {} cannot be initialized with value '{}'.", m_gate->get_name(), m_gate->get_id(), gate_type->get_name(), BooleanFunction::to_string(value));
158  return;
159  }
160 
161  assert(ram_component->get_bit_size() % 64 == 0);
162  u32 num_words = ram_component->get_bit_size() / 64;
163 
164  for (u32 i = 0; i < num_words; i++)
165  {
166  m_data.push_back(init_val);
167  }
168  }
169 
170  // generate initial output events (all zero)
171  for (const Port& port : m_ports)
172  {
173  if (!port.is_write)
174  {
175  u32 data_size = port.data_pins.size();
176  for (u32 j = 0; j < data_size; j++)
177  {
178  const Net* out_net = m_gate->get_fan_out_net(port.data_pins.at(j));
179  new_events[out_net] = BooleanFunction::Value::ZERO;
180  }
181  }
182  }
183  }
184 
185  bool NetlistSimulator::SimulationGateRAM::simulate(const Simulation& simulation, const WaveEvent& event, std::map<std::pair<const Net*, u64>, BooleanFunction::Value>& new_events)
186  {
187  UNUSED(simulation);
188  UNUSED(new_events);
189 
190  // is the event triggering a clock pin? if so, remember the clocked port and process later
191  for (size_t i = 0; i < m_ports.size(); i++)
192  {
193  Port& port = m_ports.at(i);
194  if (event.affected_net == port.clock_net && port.clock_func.evaluate(m_input_values).get() == BooleanFunction::ONE)
195  {
196  if (port.enable_func.evaluate(m_input_values).get() == BooleanFunction::Value::ONE)
197  {
198  if (port.is_write)
199  {
200  m_clocked_write_ports.push_back(i);
201  }
202  else
203  {
204  m_clocked_read_ports.push_back(i);
205  }
206  }
207  }
208  }
209 
210  if (!m_clocked_read_ports.empty() || !m_clocked_write_ports.empty())
211  {
212  return false;
213  }
214 
215  // gate fully handled
216  return true;
217  }
218 
219  void NetlistSimulator::SimulationGateRAM::clock(const u64 current_time, std::map<std::pair<const Net*, u64>, BooleanFunction::Value>& new_events)
220  {
221  // compute delay, currently just a placeholder
222  u64 delay = 0;
223 
224  std::unordered_map<std::string, BooleanFunction> functions = m_gate->get_boolean_functions();
225 
226  for (size_t index : m_clocked_read_ports)
227  {
228  Port port = m_ports.at(index);
229 
230  std::vector<BooleanFunction::Value> address_values;
231  for (const GatePin* pin : port.address_pins)
232  {
233  address_values.push_back(m_input_values.at(pin->get_name()));
234  }
235 
236  u32 address = simulation_utils::values_to_int(address_values);
237  u32 data_size = port.data_pins.size();
238 
239  // read data from internal memory
240  u32 read_data = get_data_word(m_data, address, data_size);
241  std::vector<BooleanFunction::Value> data_values = simulation_utils::int_to_values(read_data, data_size);
242 
243  assert(data_values.size() == data_size);
244 
245  // generate events
246  for (u32 i = 0; i < data_size; i++)
247  {
248  const Net* out_net = m_gate->get_fan_out_net(port.data_pins.at(i));
249  new_events[std::make_pair(out_net, current_time + delay)] = data_values.at(i);
250  }
251  }
252 
253  for (size_t index : m_clocked_write_ports)
254  {
255  Port port = m_ports.at(index);
256  u32 address = simulation_utils::get_int_bus_value(m_input_values, port.address_pins);
257  u32 data_size = port.data_pins.size();
258 
259  // write data to internal memory
260  std::vector<BooleanFunction::Value> data_values = simulation_utils::int_to_values(get_data_word(m_data, address, data_size), data_size);
261 
262  for (u32 i = 0; i < data_size; i++)
263  {
264  const GatePin* pin = port.data_pins.at(i);
265 
266  // do not change memory content of masking function specified and not evaluating to 1
267  if (auto func_it = functions.find(pin->get_name()); func_it != functions.end() && func_it->second.evaluate(m_input_values).get() != BooleanFunction::Value::ONE)
268  {
269  continue;
270  }
271 
272  data_values[i] = m_input_values.at(pin->get_name());
273  }
274  u32 write_data = simulation_utils::values_to_int(data_values);
275  set_data_word(m_data, write_data, address, data_size);
276  }
277 
278  m_clocked_read_ports.clear();
279  m_clocked_write_ports.clear();
280  }
281 } // namespace hal
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
#define UNUSED(expr)
Definition: defines.h:49
#define log_error(channel,...)
Definition: log.h:78
u32 get_int_bus_value(const std::unordered_map< std::string, BooleanFunction::Value > &signal_values, const std::vector< GatePin * > &ordered_pins)
std::vector< BooleanFunction::Value > int_to_values(u32 integer, u32 len)
u32 values_to_int(const std::vector< BooleanFunction::Value > &values)
Definition: defines.h:45
void initialize()
Definition: event_log.cpp:302
std::string identifier