HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
plugin_perf_test.cpp
Go to the documentation of this file.
2 
5 #include "hal_core/netlist/net.h"
11 #include "hal_core/utilities/log.h"
17 
18 #include <thread>
19 
20 namespace hal
21 {
22  extern std::unique_ptr<BasePluginInterface> create_plugin_instance()
23  {
24  return std::make_unique<PerfTestPlugin>();
25  }
26 
28  {
29  m_extensions.push_back(new CliExtensionsPerfTest(this));
30  }
31 
32  std::string PerfTestPlugin::get_name() const
33  {
34  return std::string("perf_test");
35  }
36 
37  std::string PerfTestPlugin::get_version() const
38  {
39  return std::string("0.1");
40  }
41 
43  {
44  }
45 
47  {
48  ProgramOptions description;
49 
50  description.add("--perf_test", "executes the plugin perf_test");
51  description.add("--base_path", "set base path of HAL install", {""});
52 
53  return description;
54  }
55 
56  bool PerfTestPlugin::cmp_sim_data(NetlistSimulatorController* reference_simulation_ctrl, NetlistSimulatorController* simulation_ctrl, int tolerance)
57  {
58  bool no_errors = true;
59  WaveDataList* reference_simulation = reference_simulation_ctrl->get_waves();
60  WaveDataList* engine_simulation = simulation_ctrl->get_waves();
61  std::cout << "comparing outputs..." << std::endl;
62  std::cout << "reference has " << reference_simulation->size() << " and engine simulation " << engine_simulation->size() << " nets" << std::endl;
63 
64  // TODO @ Jörn: remove GND and VCC from simulation_ctrl
65  // for (auto it = b_events.begin(); it != b_events.end();)
66  // {
67  // auto srcs = it->first->get_sources();
68  // if (srcs.size() == 1 && (srcs[0]->get_gate()->is_gnd_gate() || srcs[0]->get_gate()->is_vcc_gate()) && a_events.find(it->first) == a_events.end())
69  // {
70  // it = b_events.erase(it);
71  // }
72  // else
73  // {
74  // ++it;
75  // }
76  // }
77 
78  auto signal_to_string = [](auto v) -> std::string {
79  if (v >= 0)
80  return std::to_string(v);
81  return "X";
82  };
83 
84  // get all reference simulation net ids
85  std::set<u32> reference_simulation_nets;
86  for (auto it : *reference_simulation)
87  {
88  reference_simulation_nets.insert(it->id());
89  }
90 
91  // get all simulation net ids
92  std::set<u32> engine_simulation_nets;
93  for (auto it : *engine_simulation)
94  {
95  engine_simulation_nets.insert(it->id());
96  }
97 
98  // identify missmatches
99  std::cout << "searching for mismatches..." << std::endl;
100 
101  std::set<u32> unmatching_nets;
102 
103  for (auto it_ref : *reference_simulation)
104  {
105  int iwave_sim = engine_simulation->waveIndexByNetId(it_ref->id());
106  if (iwave_sim < 0)
107  {
108  no_errors = false;
109  std::cout << "error: net: " << it_ref->name().toStdString() << " (" << it_ref->id() << ") in reference, but not in simulated output" << std::endl;
110  }
111  else
112  {
113  if (!it_ref->isEqual(*engine_simulation->at(iwave_sim), tolerance))
114  {
115  no_errors = false;
116  unmatching_nets.insert(it_ref->id());
117  }
118  }
119  }
120 
121  if (unmatching_nets.size() != 0)
122  {
123  no_errors = false;
124  std::cout << "error: found " << unmatching_nets.size() << " unmatching nets..." << std::endl;
125  }
126 
127  std::cout << "printing mismatches (if any)..." << std::endl;
128 
129  u64 earliest_mismatch = -1;
130  std::vector<u32> earliest_mismatch_nets;
131  auto update_mismatch = [&](u64 time, u32 net) {
132  if (time < earliest_mismatch)
133  {
134  earliest_mismatch = time;
135  earliest_mismatch_nets = {net};
136  }
137  else if (time == earliest_mismatch)
138  {
139  earliest_mismatch_nets.push_back(net);
140  }
141  };
142 
143  for (auto net_id : unmatching_nets)
144  {
145  std::vector<std::pair<u64, int>> events_a;
146  WaveData* wave_data_a;
147  for (auto it_sim : *reference_simulation)
148  {
149  if (it_sim->id() == net_id)
150  {
151  wave_data_a = it_sim;
152  events_a = it_sim->get_events();
153  }
154  }
155 
156  std::vector<std::pair<u64, int>> events_b;
157  WaveData* wave_data_b;
158  for (auto it_sim : *engine_simulation)
159  {
160  if (it_sim->id() == net_id)
161  {
162  wave_data_b = it_sim;
163  events_b = it_sim->get_events();
164  }
165  }
166 
167  u32 max_number_length = 0;
168  if (!events_a.empty() && !events_b.empty())
169  {
170  max_number_length = std::to_string(std::max(events_a.back().first, events_b.back().first)).size();
171  }
172 
173  std::cout << "difference in net " << wave_data_a->name().toStdString() << " id=" << net_id << ":" << std::endl;
174  std::cout << "reference:" << std::setfill(' ') << std::setw(max_number_length + 5) << ""
175  << "engine:" << std::endl;
176 
177  for (u32 i = 0, j = 0; i < events_a.size() || j < events_b.size();)
178  {
179  if (i < events_a.size() && j < events_b.size())
180  {
181  if (abs((int)(events_a[i].first - events_b[j].first)) < tolerance)
182  {
183  if (events_a[i].second == events_b[j].second)
184  {
185  std::cout << signal_to_string(events_a[i].second) << " @ " << std::setfill(' ') << std::setw(max_number_length) << events_a[i].first << "ns";
186  std::cout << " | ";
187  std::cout << signal_to_string(events_b[j].second) << " @ " << std::setfill(' ') << std::setw(max_number_length) << events_b[j].first << "ns";
188  std::cout << std::endl;
189  i++;
190  j++;
191  }
192  else
193  {
194  update_mismatch(events_a[i].first, net_id);
195  std::cout << signal_to_string(events_a[i].second) << " @ " << std::setfill(' ') << std::setw(max_number_length) << events_a[i].first << "ns";
196  std::cout << " | ";
197  std::cout << signal_to_string(events_b[j].second) << " @ " << std::setfill(' ') << std::setw(max_number_length) << events_b[j].first << "ns";
198  std::cout << " <--" << std::endl;
199  i++;
200  j++;
201  }
202  }
203  else
204  {
205  if (events_a[i].first < events_b[j].first)
206  {
207  update_mismatch(events_a[i].first, net_id);
208  std::cout << signal_to_string(events_a[i].second) << " @ " << std::setfill(' ') << std::setw(max_number_length) << events_a[i].first << "ns";
209  std::cout << " | ";
210  std::cout << std::endl;
211  i++;
212  }
213  else
214  {
215  update_mismatch(events_b[j].first, net_id);
216  std::cout << " " << std::setfill(' ') << std::setw(max_number_length) << ""
217  << " ";
218  std::cout << " | ";
219  std::cout << signal_to_string(events_b[j].second) << " @ " << std::setfill(' ') << std::setw(max_number_length) << events_b[j].first << "ns";
220  std::cout << std::endl;
221  j++;
222  }
223  }
224  }
225  else if (i < events_a.size())
226  {
227  update_mismatch(events_a[i].first, net_id);
228  std::cout << signal_to_string(events_a[i].second) << " @ " << std::setfill(' ') << std::setw(max_number_length) << events_a[i].first << "ns";
229  std::cout << " | ";
230  std::cout << std::endl;
231  i++;
232  }
233  else
234  {
235  update_mismatch(events_b[j].first, net_id);
236  std::cout << " " << std::setfill(' ') << std::setw(max_number_length) << ""
237  << " ";
238  std::cout << " | ";
239  std::cout << signal_to_string(events_b[j].second) << " @ " << std::setfill(' ') << std::setw(max_number_length) << events_b[j].first << "ns";
240  std::cout << std::endl;
241  j++;
242  }
243  }
244  std::cout << std::endl;
245  }
246 
247  if (reference_simulation->size() != engine_simulation->size())
248  {
249  std::cout << "WARNING SIZE MISMATCH" << std::endl;
250  if (reference_simulation->size() > engine_simulation->size())
251  {
252  no_errors = false;
253  std::cout << "more nets are captured in the reference vcd file:" << std::endl;
254  std::vector<u32> mismatch;
255  std::set_difference(reference_simulation_nets.begin(), reference_simulation_nets.end(), engine_simulation_nets.begin(), engine_simulation_nets.end(), std::back_inserter(mismatch));
256  for (auto x : mismatch)
257  {
258  int iwave = reference_simulation->waveIndexByNetId(x);
259  std::cout << " " << x << " " << (iwave < 0 ? "" : reference_simulation->at(iwave)->name().toUtf8().data()) << std::endl;
260  }
261  }
262  else
263  {
264  std::cout << "more nets are captured in the engine_simulation output:" << std::endl;
265  std::vector<u32> mismatch;
266  std::set_difference(engine_simulation_nets.begin(), engine_simulation_nets.end(), reference_simulation_nets.begin(), reference_simulation_nets.end(), std::back_inserter(mismatch));
267  const char* artifical_added[] = {"'0'", "'1'", nullptr};
268  for (auto x : mismatch)
269  {
270  int iwave = engine_simulation->waveIndexByNetId(x);
271  std::string waveName(iwave < 0 ? "" : engine_simulation->at(iwave)->name().toUtf8().data());
272  if (!waveName.empty())
273  {
274  bool take_it_easy = false;
275  for (int i = 0; artifical_added[i]; i++)
276  {
277  if (waveName == artifical_added[i])
278  {
279  take_it_easy = true;
280  break;
281  }
282  }
283  if (!take_it_easy)
284  no_errors = false;
285  }
286  std::cout << " " << x << " " << (iwave < 0 ? "" : engine_simulation->at(iwave)->name().toUtf8().data()) << std::endl;
287  }
288  }
289 
290  if (unmatching_nets.empty())
291  {
292  std::cout << "everything that could be compared was correct, though!" << std::endl;
293  }
294  }
295 
296  if (no_errors)
297  {
298  std::cout << "simulation correct!" << std::endl;
299  }
300  else
301  {
302  std::cout << "simulation incorrect, have fun debugging!" << std::endl;
303  }
304 
305  return no_errors;
306  }
307 
309  {
310  std::string base_path;
311 
312  if (args.is_option_set("--base_path"))
313  {
314  if (args.get_parameter("--base_path").back() == '/')
315  base_path = args.get_parameter("--base_path");
316  else
317  base_path = args.get_parameter("--base_path");
318  }
319  else
320  {
321  log_error("perf_test", "base_path parameter not set");
322  }
323 
324  auto plugin = plugin_manager::get_plugin_instance<NetlistSimulatorControllerPlugin>("netlist_simulator_controller");
325 
326  auto sim_ctrl_verilator = plugin->create_simulator_controller("tocipher_simulator");
327  auto verilator_engine = sim_ctrl_verilator->create_simulation_engine("verilator");
328  //EXPECT_TRUE(sim_ctrl_verilator->get_state() == NetlistSimulatorController::SimulationState::NoGatesSelected);
329  //EXPECT_TRUE(verilator_engine->get_state() == SimulationEngine::State::Preparing);
330 
331  auto sim_ctrl_reference = plugin->create_simulator_controller("tocipher_reference");
332 
333  //path to netlist
334  std::string path_netlist = base_path + "/bin/hal_plugins/test-files/toycipher/cipher_flat.vhd";
335  //FAIL() << "netlist for toycipher-test not found: " << path_netlist;
336 
337  //create netlist from path
338  auto lib = nl->get_gate_library();
339  if (lib == nullptr)
340  {
341  log_error("perf_test", "lib empty");
342  return -1;
343  }
344 
345  //path to vcd
346  std::string path_vcd = base_path + "/bin/hal_plugins/test-files/toycipher/dump.vcd";
347  if (!utils::file_exists(path_vcd))
348  {
349  log_error("perf_test", "ref vcd not found");
350  return -1;
351  }
352  //FAIL() << "dump for toycipher-test not found: " << path_vcd;
353 
354  sim_ctrl_reference->add_gates(nl->get_gates());
355  sim_ctrl_reference->initialize();
356  sim_ctrl_reference->import_vcd(path_vcd, NetlistSimulatorController::FilterInputFlag::CompleteNetlist);
357 
358  //prepare simulation
359  sim_ctrl_verilator->add_gates(nl->get_gates());
360  //EXPECT_TRUE(sim_ctrl_verilator->get_state() == NetlistSimulatorController::SimulationState::ParameterSetup);
361  sim_ctrl_verilator->initialize();
362 
363  // retrieve nets
364  auto clk = *(nl->get_nets([](auto net) { return net->get_name() == "CLK"; }).begin());
365  sim_ctrl_verilator->add_clock_period(clk, 10000);
366 
367  std::set<const Net*> key_set, plaintext_set;
368  auto start = *(nl->get_nets([](auto net) { return net->get_name() == "START"; }).begin());
369 
370  for (int i = 0; i < 16; i++)
371  {
372  std::string name = "KEY_" + std::to_string(i);
373  key_set.insert(*(nl->get_nets([name](auto net) { return net->get_name() == name; }).begin()));
374  }
375 
376  for (int i = 0; i < 16; i++)
377  {
378  std::string name = "PLAINTEXT_" + std::to_string(i);
379  plaintext_set.insert(*(nl->get_nets([name](auto net) { return net->get_name() == name; }).begin()));
380  }
381 
382  int input_nets_amount = key_set.size() + plaintext_set.size();
383 
384  if (clk != nullptr)
385  input_nets_amount++;
386 
387  if (start != nullptr)
388  input_nets_amount++;
389 
390  //FAIL() << "not all input nets set: actual " << input_nets_amount << " vs. " << sim_ctrl_verilator->get_input_nets().size();
391 
392  // set GND and VCC
393  Net* GND = *(nl->get_nets([](auto net) { return net->is_gnd_net(); }).begin());
394  if (GND != nullptr)
395  {
396  sim_ctrl_verilator->set_input(GND, BooleanFunction::Value::ZERO); // set GND to zero
397  }
398 
399  Net* VCC = *(nl->get_nets([](auto net) { return net->is_vcc_net(); }).begin());
400  if (VCC != nullptr)
401  {
402  sim_ctrl_verilator->set_input(VCC, BooleanFunction::Value::ONE); // set VCC to zero
403  }
404 
405  //start simulation
406  {
407  //testbench
408 
409  for (auto net : plaintext_set) //PLAINTEXT <= (OTHERS => '0');
410  sim_ctrl_verilator->set_input(net, BooleanFunction::Value::ZERO);
411 
412  for (auto net : key_set) //KEY <= (OTHERS => '0');
413  sim_ctrl_verilator->set_input(net, BooleanFunction::Value::ZERO);
414 
415  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ZERO); //START <= '0';
416  sim_ctrl_verilator->simulate(10 * 1000); //WAIT FOR 10 NS;
417 
418  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ONE); //START <= '1';
419  sim_ctrl_verilator->simulate(10 * 1000); //WAIT FOR 10 NS;
420 
421  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ZERO); //START <= '0';
422  sim_ctrl_verilator->simulate(100 * 1000); //WAIT FOR 100 NS;
423 
424  for (auto net : plaintext_set) //PLAINTEXT <= (OTHERS => '1');
425  sim_ctrl_verilator->set_input(net, BooleanFunction::Value::ONE);
426 
427  for (auto net : key_set) //KEY <= (OTHERS => '1');
428  sim_ctrl_verilator->set_input(net, BooleanFunction::Value::ONE);
429 
430  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ZERO); //START <= '0';
431  sim_ctrl_verilator->simulate(10 * 1000); //WAIT FOR 10 NS;
432 
433  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ONE); //START <= '1';
434  sim_ctrl_verilator->simulate(10 * 1000); //WAIT FOR 10 NS;
435 
436  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ZERO); //START <= '0';
437  sim_ctrl_verilator->simulate(100 * 1000); //WAIT FOR 100 NS;
438 
439  for (auto net : plaintext_set) //PLAINTEXT <= (OTHERS => '0');
440  sim_ctrl_verilator->set_input(net, BooleanFunction::Value::ZERO);
441 
442  for (auto net : key_set) //KEY <= (OTHERS => '0');
443  sim_ctrl_verilator->set_input(net, BooleanFunction::Value::ZERO);
444 
445  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ZERO); //START <= '0';
446 
447  sim_ctrl_verilator->simulate(10 * 1000);
448  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ONE); //START <= '1';
449 
450  sim_ctrl_verilator->simulate(10 * 1000);
451  sim_ctrl_verilator->set_input(start, BooleanFunction::Value::ZERO); //START <= '0';
452 
453  sim_ctrl_verilator->simulate(25 * 1000);
454 
455  sim_ctrl_verilator->initialize();
456  sim_ctrl_verilator->run_simulation();
457 
458  //EXPECT_FALSE(verilator_engine->get_state() == SimulationEngine::State::Failed);
459 
460  while (verilator_engine->get_state() == SimulationEngine::State::Running)
461  {
462  std::this_thread::sleep_for(std::chrono::milliseconds(1000));
463  }
464  }
465 
466  if (verilator_engine->get_state() == SimulationEngine::State::Failed)
467  {
468  //FAIL() << "engine failed";
469  }
470 
471  //EXPECT_TRUE(verilator_engine->get_state() == SimulationEngine::State::Done);
472  //EXPECT_FALSE(sim_ctrl_verilator->get_state() == NetlistSimulatorController::SimulationState::EngineFailed);
473 
474  sim_ctrl_verilator->get_results();
475 
476  for (Net* n : nl->get_nets())
477  {
478  sim_ctrl_verilator->get_waveform_by_net(n);
479  sim_ctrl_reference->get_waveform_by_net(n);
480  }
481 
482  // TODO @ Jörn: LOAD ALL WAVES TO MEMORY
483  //EXPECT_TRUE(sim_ctrl_verilator->get_waves()->size() == (int)nl->get_nets().size());
484  //EXPECT_TRUE(sim_ctrl_reference->get_waves()->size() <= (int)nl->get_nets().size()); // net might have additional '0' and '1'
485 
486  //Test if maps are equal
487  bool equal = mParent->cmp_sim_data(sim_ctrl_reference.get(), sim_ctrl_verilator.get());
488  return true;
489  }
490 } // namespace hal
std::vector< AbstractExtensionInterface * > m_extensions
ProgramOptions get_cli_options() const override
bool handle_cli_call(hal::Netlist *nl, hal::ProgramArguments &args) override
Definition: net.h:58
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:204
const std::vector< Net * > & get_nets() const
Definition: netlist.cpp:364
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:132
std::string get_version() const override
void initialize() override
std::string get_name() const override
bool cmp_sim_data(hal::NetlistSimulatorController *reference_simulation_ctrl, hal::NetlistSimulatorController *simulation_ctrl, int tolerance=200)
std::string get_parameter(const std::string &flag) const
bool is_option_set(const std::string &flag) const
bool add(const std::string &flag, const std::string &description, const std::initializer_list< std::string > &parameters={})
std::vector< std::pair< u64, int > > get_events(u64 t0=0) const
Definition: wave_data.cpp:194
QString name() const
Definition: wave_data.h:104
int waveIndexByNetId(u32 id) const
Definition: wave_data.h:227
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
bool file_exists(const std::string &filename)
Definition: utils.cpp:31
Definition: defines.h:45
std::unique_ptr< BasePluginInterface > create_plugin_instance()
Net * net
std::string name
This file contains various functions to create and load netlists.
const T & at(int i) const const
int size() const const
std::string toStdString() const const