HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
netlist_simulator.cpp
Go to the documentation of this file.
2 
9 
10 #include <algorithm>
11 #include <chrono>
12 #include <ctime>
13 #include <fstream>
14 #include <iomanip>
15 #include <sstream>
16 #include <unordered_map>
17 
18 namespace hal
19 {
20 #define measure_block_time(X)
21 
22  NetlistSimulator::NetlistSimulator(const std::string& nam) : SimulationEngineEventDriven(nam)
23  {
24  ;
25  }
26 
27  void NetlistSimulator::set_input(const Net* net, BooleanFunction::Value value)
28  {
29  if (net == nullptr)
30  {
31  log_error("hal_simulator", "net is a nullptr.");
32  return;
33  }
34 
35  if (auto it = m_simulation.m_events.find(net); it != m_simulation.m_events.end())
36  {
37  if (value == it->second.back().new_value)
38  {
39  return;
40  }
41  }
42 
43  WaveEvent e;
44  e.affected_net = net;
45  e.time = m_current_time;
46  e.new_value = value;
47  m_event_queue.push_back(e);
48  }
49 
50  void NetlistSimulator::initialize_sequential_gates(const std::function<bool(const Gate*)>& filter)
51  {
52  if (!m_is_initialized)
53  {
54  m_init_seq_gates.push_back(std::make_tuple(true, BooleanFunction::Value::X, filter));
55  }
56  else
57  {
58  log_error("hal_simulator", "cannot initialize sequential gates after the simulation was started.");
59  return;
60  }
61  }
62 
63  void NetlistSimulator::initialize_sequential_gates(BooleanFunction::Value value, const std::function<bool(const Gate*)>& filter)
64  {
65  if (!m_is_initialized)
66  {
67  m_init_seq_gates.push_back(std::make_tuple(false, value, filter));
68  }
69  else
70  {
71  log_error("hal_simulator", "cannot initialize sequential gates after the simulation was started.");
72  return;
73  }
74  }
75 
76  void NetlistSimulator::load_initial_values(BooleanFunction::Value value)
77  {
78  // has to work even if the simulation was not started, i.e., initialize was not called yet
79  // so we cannot use the SimulationGateFF type
80 
81  for (const Gate* gate : mSimulationInput->get_gates())
82  {
83  if (gate->get_type()->has_property(GateTypeProperty::ff))
84  {
85  GateType* gate_type = gate->get_type();
86 
88 
89  // generate events
90  for (Endpoint* ep : gate->get_fan_out_endpoints())
91  {
92  switch (ep->get_pin()->get_type())
93  {
94  case PinType::state: {
95  WaveEvent e;
96  e.affected_net = ep->get_net();
97  e.new_value = value;
98  e.time = m_current_time;
99  m_event_queue.push_back(e);
100  break;
101  }
102  case PinType::neg_state: {
103  WaveEvent e;
104  e.affected_net = ep->get_net();
105  e.new_value = inv_value;
106  e.time = m_current_time;
107  m_event_queue.push_back(e);
108  break;
109  }
110  default:
111  break;
112  }
113  }
114  }
115  }
116  }
117 
118  void NetlistSimulator::load_initial_values_from_netlist()
119  {
120  // has to work even if the simulation was not started, i.e., initialize was not called yet
121  // so we cannot use the SimulationGateFF type
122 
123  for (const Gate* gate : mSimulationInput->get_gates())
124  {
125  if (gate->get_type()->has_property(GateTypeProperty::ff))
126  {
127  GateType* gate_type = gate->get_type();
128 
129  // extract init string
130  const InitComponent* init_component =
131  gate->get_type()->get_component_as<InitComponent>([](const GateTypeComponent* component) { return component->get_type() == GateTypeComponent::ComponentType::init; });
132  if (init_component == nullptr)
133  {
134  continue;
135  }
136  const std::string& init_str = std::get<1>(gate->get_data(init_component->get_init_category(), init_component->get_init_identifiers().front()));
137 
138  if (!init_str.empty())
139  {
140  // parse init string
141 
142  BooleanFunction::Value value = BooleanFunction::Value::X;
143  if (init_str == "1")
144  {
145  value = BooleanFunction::Value::ONE;
146  }
147  else if (init_str == "0")
148  {
149  value = BooleanFunction::Value::ZERO;
150  }
151  else
152  {
153  log_error("hal_simulator", "init value of sequential gate '{}' (type '{}') is neither '1' or '0'.", gate->get_name(), gate_type->get_name());
154  }
155 
157 
158  // generate events
159  for (Endpoint* ep : gate->get_fan_out_endpoints())
160  {
161  switch (ep->get_pin()->get_type())
162  {
163  case PinType::state: {
164  WaveEvent e;
165  e.affected_net = ep->get_net();
166  e.new_value = value;
167  e.time = m_current_time;
168  m_event_queue.push_back(e);
169  break;
170  }
171  case PinType::neg_state: {
172  WaveEvent e;
173  e.affected_net = ep->get_net();
174  e.new_value = inv_value;
175  e.time = m_current_time;
176  m_event_queue.push_back(e);
177  break;
178  }
179  default:
180  break;
181  }
182  }
183  }
184  }
185  }
186  }
187 
188  void NetlistSimulator::simulate(u64 picoseconds)
189  {
190  if (!m_is_initialized)
191  {
192  initialize();
193  }
194 
195  prepare_clock_events(picoseconds);
196 
197  process_events(m_current_time + picoseconds);
198  }
199 
200  void NetlistSimulator::reset()
201  {
202  mSimulationInput->clear();
203  m_current_time = 0;
204  m_id_counter = 0;
205  m_simulation = Simulation();
206  m_event_queue.clear();
207  m_is_initialized = false;
208  }
209 
210  void NetlistSimulator::set_simulation_state(const Simulation& state)
211  {
212  m_simulation = state;
213  }
214 
215  const Simulation& NetlistSimulator::get_simulation_state() const
216  {
217  return m_simulation;
218  }
219 
220  void NetlistSimulator::set_iteration_timeout(u64 iterations)
221  {
222  m_timeout_iterations = iterations;
223  }
224 
225  u64 NetlistSimulator::get_simulation_timeout() const
226  {
227  return m_timeout_iterations;
228  }
229 
230  std::vector<WaveEvent> NetlistSimulator::get_simulation_events(u32 netId) const
231  {
232  return m_simulation.get_events_by_net_id(netId);
233  }
234 
235  bool NetlistSimulator::inputEvent(const SimulationInputNetEvent& netEv)
236  {
237  for (auto it = netEv.begin(); it != netEv.end(); ++it)
238  {
239  set_input(it->first, it->second);
240  }
241  simulate(netEv.get_simulation_duration());
242  return true;
243  }
244 
245  /*
246  * This function precomputes all the stuff that shall be cached for simulation.
247  */
249  {
250  measure_block_time("NetlistSimulator::initialize()");
251  m_successors.clear();
252  m_sim_gates.clear();
253  m_sim_gates_raw.clear();
254 
255  std::unordered_map<const Gate*, SimulationGate*> sim_gates_map;
256  std::unordered_set<const Net*> all_nets;
257  std::map<const Net*, BooleanFunction::Value> init_events;
258 
259  // precompute everything that is gate-related
260  for (const Gate* gate : mSimulationInput->get_gates())
261  {
262  SimulationGate* sim_gate_base = nullptr;
263 
264  if (gate->get_type()->has_property(GateTypeProperty::ff))
265  {
266  std::unique_ptr<SimulationGateFF> sim_gate_owner = std::make_unique<SimulationGateFF>(gate);
267  SimulationGateFF* sim_gate = sim_gate_owner.get();
268  sim_gate_base = sim_gate;
269  m_sim_gates.push_back(std::move(sim_gate_owner));
270 
271  for (const auto& [from_netlist, value, filter] : m_init_seq_gates)
272  {
273  if (!filter || filter(gate))
274  {
275  sim_gate->initialize(init_events, from_netlist, value);
276  }
277  }
278  }
279  else if (gate->get_type()->has_property(GateTypeProperty::ram))
280  {
281  std::unique_ptr<SimulationGateRAM> sim_gate_owner = std::make_unique<SimulationGateRAM>(gate);
282  SimulationGateRAM* sim_gate = sim_gate_owner.get();
283  sim_gate_base = sim_gate;
284  m_sim_gates.push_back(std::move(sim_gate_owner));
285 
286  for (const auto& [from_netlist, value, filter] : m_init_seq_gates)
287  {
288  if (!filter || filter(gate))
289  {
290  sim_gate->initialize(init_events, from_netlist, value);
291  }
292  }
293  }
294  else if (gate->get_type()->has_property(GateTypeProperty::combinational))
295  {
296  std::unique_ptr<SimulationGateCombinational> sim_gate_owner = std::make_unique<SimulationGateCombinational>(gate);
297  SimulationGateCombinational* sim_gate = sim_gate_owner.get();
298  sim_gate_base = sim_gate;
299  m_sim_gates.push_back(std::move(sim_gate_owner));
300  }
301  else
302  {
303  log_error("hal_simulator", "no support for gate type {} of gate {}.", gate->get_type()->get_name(), gate->get_name());
304  m_successors.clear();
305  m_sim_gates.clear();
306  return;
307  }
308 
309  sim_gates_map.emplace(gate, sim_gate_base);
310  m_sim_gates_raw.push_back(sim_gate_base);
311 
312  std::vector<Net*> out_nets = gate->get_fan_out_nets();
313  all_nets.insert(out_nets.begin(), out_nets.end());
314  }
315 
316  const std::unordered_set<const Net*>& inets = mSimulationInput->get_input_nets();
317  all_nets.insert(inets.begin(), inets.end());
318 
319  // find all successors of nets and transform them to their respective simulation gate instance
320  for (auto net : all_nets)
321  {
322  if (auto it = m_successors.find(net); it != m_successors.end())
323  {
324  continue;
325  }
326  auto endpoints = net->get_destinations();
327  std::unordered_map<Gate*, std::vector<const GatePin*>> affected_pins;
328  for (auto ep : endpoints)
329  {
330  auto gate = ep->get_gate();
331  affected_pins[gate].push_back(ep->get_pin());
332  }
333 
334  for (auto it : affected_pins)
335  {
336  auto gate = it.first;
337  auto& pins = it.second;
338  if (!mSimulationInput->contains_gate(gate))
339  {
340  continue;
341  }
342  auto sim_gate = sim_gates_map.at(gate);
343  m_successors[net].emplace_back(sim_gate, pins);
344  }
345  }
346 
347  // create one-time events for global gnd and vcc gates
348  for (auto g : mSimulationInput->get_gates())
349  {
350  if (g->is_gnd_gate())
351  {
352  for (auto n : g->get_fan_out_nets())
353  {
354  init_events[n] = BooleanFunction::Value::ZERO;
355  }
356  }
357  else if (g->is_vcc_gate())
358  {
359  for (auto n : g->get_fan_out_nets())
360  {
361  init_events[n] = BooleanFunction::Value::ONE;
362  }
363  }
364  }
365 
366  // set initial values
367  for (const auto& [net, value] : init_events)
368  {
369  WaveEvent e;
370  e.affected_net = net;
371  e.new_value = value;
372  e.time = m_current_time;
373  m_event_queue.push_back(e);
374  }
375 
376  // set initialization flag only if this point is reached
377  m_is_initialized = true;
378  }
379 
380  void NetlistSimulator::prepare_clock_events(u64 picoseconds)
381  {
382  for (const SimulationInput::Clock& c : mSimulationInput->get_clocks())
383  {
384  u64 base_time = m_current_time - (m_current_time % c.switch_time);
385  u64 time = 0;
386 
387  // determine next signal state
388  // works also if we are in the middle of a cycle
389  BooleanFunction::Value v = static_cast<BooleanFunction::Value>(base_time & 1);
390  if (!c.start_at_zero)
391  {
393  }
394 
395  // insert the required amount of clock signal switch events
396  while (time < picoseconds)
397  {
398  WaveEvent e;
399  e.affected_net = c.clock_net;
400  e.new_value = v;
401  e.time = base_time + time;
402  m_event_queue.push_back(e);
403 
405  time += c.switch_time;
406  }
407  }
408  }
409 
410  void NetlistSimulator::process_events(u64 timeout)
411  {
412  measure_block_time("NetlistSimulator::process_events(" + std::to_string(timeout) + ")");
413 
414  // iteration counter to catch infinite loops
415  u64 total_iterations_for_one_timeslot = 0;
416 
417  // strategy: propagate all signals at the current time
418  // THEN evaluate all FFs that were clocked by these signals
419  // hence we need to remember FFs that were clocked
420  std::vector<SimulationGateSequential*> clocked_gates;
421  bool clocked_gates_processed = false;
422 
423  while (!m_event_queue.empty() || !clocked_gates.empty())
424  {
425  std::map<std::pair<const Net*, u64>, BooleanFunction::Value> new_events;
426 
427  // sort events by time
428  std::sort(m_event_queue.begin(), m_event_queue.end());
429 
430  // queue empty or all events of the current point in time processed?
431  if (m_event_queue.empty() || m_current_time != m_event_queue[0].time)
432  {
433  // are there FFs that were clocked? process them now!
434  if (!clocked_gates.empty() && !clocked_gates_processed)
435  {
436  for (SimulationGateSequential* clocked_gate : clocked_gates)
437  {
438  clocked_gate->clock(m_current_time, new_events);
439  }
440  clocked_gates.clear();
441  clocked_gates_processed = true;
442  }
443  else if (m_event_queue.empty())
444  {
445  // no FFs and queue empty -> simulation is done
446  break;
447  }
448  else // no FFs but queue is not empty -> advance point in time
449  {
450  m_current_time = m_event_queue[0].time;
451  total_iterations_for_one_timeslot = 0;
452  clocked_gates_processed = false;
453  }
454  }
455 
456  // note: at this point not all events are processed necessarily!
457  // but they are processed when simulation is resumed, so no worries
458  if (m_current_time > timeout)
459  {
460  break;
461  }
462 
463  // process all events of the current point in time
464  u32 processed = 0;
465  for (; processed < m_event_queue.size() && m_event_queue[processed].time <= m_current_time; ++processed)
466  {
467  auto& event = m_event_queue[processed];
468 
469  // is there already a value recorded for the net?
470  if (auto it = m_simulation.m_events.find(event.affected_net); it != m_simulation.m_events.end())
471  {
472  // if the event does not change anything, skip it
473  if (it->second.back().new_value == event.new_value)
474  {
475  continue;
476  }
477  // if the event does change something, but there was already an event for this point in time, we simply update the value
478  else if (it->second.back().time == event.time)
479  {
480  it->second.back().new_value = event.new_value;
481  if (it->second.size() > 1 && it->second[it->second.size() - 2].new_value == event.new_value)
482  {
483  it->second.pop_back();
484  }
485  }
486  else // new event
487  {
488  m_simulation.m_events[event.affected_net].push_back(event);
489  }
490  }
491  else // no value recorded -> new event
492  {
493  m_simulation.m_events[event.affected_net].push_back(event);
494  }
495 
496  // simulate affected gates
497  // record all FFs that have to be clocked
498  if (auto suc_it = m_successors.find(event.affected_net); suc_it != m_successors.end())
499  {
500  for (auto& [gate, pins] : suc_it->second)
501  {
502  for (auto& pin : pins)
503  {
504  gate->m_input_values[pin->get_name()] = event.new_value;
505  }
506  if (!gate->simulate(m_simulation, event, new_events))
507  {
508  clocked_gates.push_back(static_cast<SimulationGateSequential*>(gate));
509  }
510  }
511  }
512  }
513 
514  // check for iteration limit
515  total_iterations_for_one_timeslot += processed;
516  if (m_timeout_iterations > 0 && total_iterations_for_one_timeslot > m_timeout_iterations)
517  {
518  log_error("hal_simulator", "reached iteration timeout of {} without advancing in time, aborting simulation. Please check for a combinational loop.", m_timeout_iterations);
519  return;
520  }
521 
522  // remove processed events
523  m_event_queue.erase(m_event_queue.begin(), m_event_queue.begin() + processed);
524 
525  // add new events
526  m_event_queue.reserve(m_event_queue.size() + new_events.size());
527  for (const auto& event_it : new_events)
528  {
529  WaveEvent e;
530  e.affected_net = event_it.first.first;
531  e.time = event_it.first.second;
532  e.new_value = event_it.second;
533  e.id = m_id_counter++;
534  m_event_queue.push_back(e);
535  }
536  }
537 
538  // adjust point in time
539  m_current_time = timeout;
540  }
541 
542  BooleanFunction::Value NetlistSimulator::process_clear_preset_behavior(AsyncSetResetBehavior behavior, BooleanFunction::Value previous_output)
543  {
544  if (behavior == AsyncSetResetBehavior::N)
545  {
546  return previous_output;
547  }
548  else if (behavior == AsyncSetResetBehavior::X)
549  {
550  return BooleanFunction::Value::X;
551  }
552  else if (behavior == AsyncSetResetBehavior::L)
553  {
554  return BooleanFunction::Value::ZERO;
555  }
556  else if (behavior == AsyncSetResetBehavior::H)
557  {
558  return BooleanFunction::Value::ONE;
559  }
560  else if (behavior == AsyncSetResetBehavior::T)
561  {
562  return simulation_utils::toggle(previous_output);
563  }
564  log_error("hal_simulator", "unsupported set/reset behavior {}.", enum_to_string(behavior));
565  return BooleanFunction::Value::X;
566  }
567 
568  bool NetlistSimulator::generate_vcd(const std::filesystem::path& path, u32 start_time, u32 end_time, std::set<const Net*> nets) const
569  {
570  if (mSimulationInput->get_gates().empty())
571  {
572  log_error("hal_simulator", "no gates have been added to the simulator.");
573  return false;
574  }
575 
576  if (m_simulation.get_events().empty())
577  {
578  log_error("hal_simulator", "nothing has been simulated, cannot generate VCD.");
579  return false;
580  }
581 
582  if (end_time > m_current_time)
583  {
584  log_error("hal_simulator", "cannot generate VCD for {} ps, only {} ps have been simulated thus far.", end_time, m_current_time);
585  return false;
586  }
587 
588  // write header
589  std::stringstream vcd;
590  auto t = std::time(nullptr);
591  auto tm = *std::localtime(&t);
592  vcd << "$version Generated by HAL $HAL" << std::endl;
593  vcd << "$date " << std::put_time(&tm, "%d-%m-%Y %H-%M-%S") << std::endl;
594  vcd << "$timescale 1ps $end" << std::endl;
595 
596  //declare variables
597  vcd << "$scope module TOP $end" << std::endl;
598 
599  std::unordered_map<const Net*, std::vector<WaveEvent>> events = m_simulation.get_events();
600  std::vector<const Net*> simulated_nets;
601 
602  for (auto net_changes : events)
603  {
604  const Net* net = net_changes.first;
605  if ((net != nullptr) && (nets.empty() || nets.find(net) != nets.end()))
606  {
607  // maping net ids to net names
608  vcd << "$var wire 1 n" << net->get_id() << " " << net->get_name() << " $end" << std::endl;
609 
610  // collect all simulated nets
611  simulated_nets.push_back(net);
612  }
613  }
614 
615  vcd << "$upscope $end" << std::endl;
616  vcd << "$enddefinitions $end" << std::endl;
617 
618  std::unordered_map<const Net*, BooleanFunction::Value> change_tracker;
619  vcd << "#" << 0 << std::endl;
620 
621  std::map<u32, std::map<const Net*, BooleanFunction::Value>> time_to_changes_map;
622 
623  std::unordered_map<const Net*, std::vector<WaveEvent>> event_tracker = m_simulation.get_events();
624 
625  for (const auto& simulated_net : simulated_nets)
626  {
627  std::vector<WaveEvent> net_events = event_tracker.at(simulated_net);
628  BooleanFunction::Value initial_value = BooleanFunction::Value::X;
629  u32 initial_time = 0;
630 
631  for (const auto& event_it : net_events)
632  {
633  u32 event_time = event_it.time;
634  if (initial_time == event_time || ((event_time > initial_time) && (event_time < start_time)))
635  {
636  initial_time = event_time;
637  initial_value = event_it.new_value;
638  }
639  if (event_time > start_time && event_time < end_time)
640  {
641  time_to_changes_map[event_it.time][simulated_net] = event_it.new_value;
642  }
643  }
644 
645  time_to_changes_map[start_time][simulated_net] = initial_value;
646  }
647 
648  u32 traces_count = 0;
649 
650  for (const auto& [event_time, changed_nets] : time_to_changes_map)
651  {
652  traces_count++;
653  vcd << "#" << event_time << std::endl;
654 
655  for (const auto& [net, value] : changed_nets)
656  {
657  // print signal value
658  if (value == BooleanFunction::Value::X)
659  {
660  vcd << "xn" << net->get_id() << std::endl;
661  }
662  else if (value == BooleanFunction::Value::ONE)
663  {
664  vcd << "1n" << net->get_id() << std::endl;
665  }
666  else if (value == BooleanFunction::Value::ZERO)
667  {
668  vcd << "0n" << net->get_id() << std::endl;
669  }
670  else if (value == BooleanFunction::Value::Z)
671  {
672  log_error("hal_simulator", "signal value of 'Z' for net with ID {} at {} ps is currently not supported.", net->get_id(), event_time);
673  return false;
674  }
675  else
676  {
677  log_error("hal_simulator", "signal value for net with ID {} at {} ps is unknown.", net->get_id(), event_time);
678  return false;
679  }
680  }
681  }
682  vcd << "#" << traces_count << std::endl;
683 
684  std::ofstream ofs(path);
685  if (!ofs.is_open())
686  {
687  log_error("hal_simulator", "could not open file '{}' for writing.", path.string());
688  return false;
689  }
690 
691  ofs << vcd.str();
692 
693  return true;
694  }
695 
696  SimulationEngine* NetlistSimulatorFactory::createEngine() const
697  {
698  return new NetlistSimulator(mName);
699  }
700 
701 } // namespace hal
Value
represents the type of the node
Definition: gate.h:58
const std::string & get_name() const
Definition: gate_type.cpp:64
const std::string & get_init_category() const
const std::vector< std::string > & get_init_identifiers() const
ComponentType get_type() const override
Definition: net.h:58
std::vector< WaveEvent > get_events_by_net_id(u32 netId, bool *found=nullptr) const
Definition: simulation.cpp:36
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
BooleanFunction::Value toggle(BooleanFunction::Value v)
BooleanFunction::Value process_clear_preset_behavior(AsyncSetResetBehavior behavior, BooleanFunction::Value previous_output)
Definition: defines.h:45
void initialize()
Definition: event_log.cpp:302
std::string enum_to_string(T e)
Definition: enums.h:53
std::vector< PinInformation > pins
Net * net
#define measure_block_time(X)
BooleanFunction::Value new_value
Definition: wave_event.h:46
const Net * affected_net
Definition: wave_event.h:41