CGRA-ME
cgrame.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * The software programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 
11 // internal
12 #include <CGRA/dotparse.h>
13 #include <CGRA/Exception.h>
14 #include <CGRA/Mapper.h>
15 #include <CGRA/Mapping.h>
16 #include <CGRA/MappingProcedures.h>
17 #include <CGRA/MRRGProcedures.h>
18 #include <CGRA/OpGraphProcedures.h>
19 #include <CGRA/PerfEngine.h>
21 #include <CGRA/Util.h>
23 #include <CGRA/Visual.h>
24 #include <CGRA/cgrame.h>
25 
26 // thirdparty
27 #include <cxxopts.hpp>
28 #include <mini.hpp>
29 
30 // standard library
31 #include <fstream>
32 #include <iomanip>
33 #include <iostream>
34 #include <iterator>
35 #include <memory>
36 #include <sstream>
37 #include <streambuf>
38 #include <string>
39 
40 // Linux/Unix
41 #include <libgen.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <unistd.h>
45 
46 namespace {
47  const std::string default_config_file_name = "mapper_config.ini";
48 }
49 
50 int inner_main(int argc, char* argv[]);
51 
52 
53 int main(int argc, char* argv[])
54 {
55  try {
56  return inner_main(argc, argv);
57  } catch (...) {
58  printExceptionToOutAndErr(std::current_exception(), "!==>", "TERMINATING! An exception reached the top of the stack");
59  throw; // re-throw the top exception
60  }
61 }
62 
63 namespace cxxopts {
64 namespace values {
65  template <>
66  void parse_value(const std::string& text, VerilogType& value) {
67  try {
68  size_t end_pos = 0;
69  value = static_cast<VerilogType>(std::stoi(text, &end_pos));
70  if (end_pos != text.size()) {
71  throw 0;
72  }
73  } catch (...) {
74  throw std::logic_error("can't convert " + text + " to VerilogType");
75  }
76  }
77 }
78 }
79 
80 int inner_main(int argc, char* argv[]) {
81  int arg_count = argc;
82  PrintOnDestructionChronoSequence timing_seqence("CGRA-ME", &std::cout);
83 
84  std::cout << std::endl;
85  std::cout << "CGRA - Modelling and Exploration (http://cgra-me.ece.utoronto.ca/)" << std::endl;
86  std::cout << "Copyright (c) 2015-2023 University of Toronto. All Rights Reserved." << std::endl;
87  std::cout << "For research and academic purposes only. Commercial use is prohibited." << std::endl;
88  std::cout << "Please email questions to: Jason Anderson (janders@ece.utoronto.ca)" << std::endl;
89  std::cout << "Compiled: " << __DATE__ << " " << __TIME__ << std::endl;
90  std::cout << std::endl;
91 
92  //
93  // Argument Variables
94  // (alphabetically by type then name)
95  //
96 
97  struct {
98  bool exit_after_optimizing_dfg = false;
99  bool list_cpp_architectures = false;
100  bool make_testbench = false;
101  bool no_dfg_transformations = false;
102  bool no_reduce_mrrg = false;
103  bool print_mapper_help_and_exit = false;
104  bool print_mapper_list = false;
105  bool printarch = false;
106 
107  double timelimit = 7200.0;
108 
109  int II = 1;
110  int verbosity = 3;
111  std::string arch_opts = {};
112  std::string arch_opts_list_id = {};
113  std::string cpp_arch_id = {};
114  std::string dfg_filename = {};
115  std::string fix_port_filename = {};
116  std::string gen_config_file = {};
117  std::string load_mapping_filename = {};
118  std::string mapper_id = "BothSmallTimeThenHeurFullTime";
119  std::string mapper_opts = {};
120  std::string mapping_output_filename = {};
121  std::string print_final_dfg_filename = {};
122  std::string print_mrrg_filename = {};
123  std::string verilog_gen_output_path = {};
124  std::string verilog_opts = {};
125 
126  VerilogType verilog_gen_type = VerilogType::CoreIR;
127  } option_vals;
128 
129  //list of string arguments requiring validation
130  std::string *argument_list[14] = {
131  &option_vals.arch_opts,
132  &option_vals.arch_opts_list_id,
133  &option_vals.cpp_arch_id,
134  &option_vals.dfg_filename,
135  &option_vals.fix_port_filename,
136  &option_vals.gen_config_file,
137  &option_vals.load_mapping_filename,
138  &option_vals.mapper_id,
139  &option_vals.mapper_opts,
140  &option_vals.mapping_output_filename,
141  &option_vals.print_final_dfg_filename,
142  &option_vals.print_mrrg_filename,
143  &option_vals.verilog_gen_output_path,
144  &option_vals.verilog_opts
145  };
146  //
147  // Argument definitions
148  // (sorted by long option name)
149  //
150 
151  cxxopts::Options options("CGRA-ME", "CGRA - Modelling and Exploration");
152 
153  try {
154  options.add_options()
155  ("arch-list", "Show the List of Avaliable C++ Architectures with IDs",
156  cxxopts::value(option_vals.list_cpp_architectures))
157  ("arch-opts", "Override a C++ architecture's default parameters. Space-separated list of <Key>=<Value> pairs (must be a single arugment)",
158  cxxopts::value(option_vals.arch_opts), "<\"opts\">")
159  ("arch-opts-list", "Show the List of Avaliable Options for a C++ Architecture ID",
160  cxxopts::value(option_vals.arch_opts_list_id), "id")
161  ("c,cpp", "C++ architecture Identifier. See --arch-list for list.",
162  cxxopts::value(option_vals.cpp_arch_id), "id")
163  ("g,dfg", "The DFG file to map in dot format",
164  cxxopts::value(option_vals.dfg_filename))
165  ("exit-after-optimizing-dfg", "Only proceed as far as optimizing the DFG, then exit with success",
166  cxxopts::value(option_vals.exit_after_optimizing_dfg))
167  ("fixed-ports", "User can input fixed ports to mapper",
168  cxxopts::value(option_vals.fix_port_filename))
169  ("gen-testbench", "Generate testbench for use in a simulation of the DFG with configuration bitstream",
170  cxxopts::value(option_vals.make_testbench))
171  ("gen-config-file", "Create a config file at the given path, or the default name in the current directory if none is given. And do nothing else.",
172  cxxopts::value(option_vals.gen_config_file)->implicit_value(default_config_file_name))
173  ("gen-verilog", "Generate Verilog Implementation of Architecture and Dump to Specified Directory",
174  cxxopts::value(option_vals.verilog_gen_output_path), "<Directorypath>")
175  ("h,help", "Print Help")
176  ("i,II", "Architecture Contexts Used",
177  cxxopts::value(option_vals.II)->default_value(std::to_string(option_vals.II)), "<#>")
178  ("l,load-mapping", "Load the mapping from a dot file",
179  cxxopts::value(option_vals.load_mapping_filename))
180  ("m,mapper", "Which mapper to use. See --mapper-list for choices.",
181  cxxopts::value(option_vals.mapper_id)->default_value(option_vals.mapper_id), "<#>")
182  ("mapper-list", "List all available mappers",
183  cxxopts::value(option_vals.print_mapper_list), "<Name>")
184  ("mapper-opts", "Override default mapper settings",
185  cxxopts::value(option_vals.mapper_opts), "<Key>=<Value> ...")
186  ("mapper-help", "Show the list of options and defaults for the selected mapper, then exit",
187  cxxopts::value(option_vals.print_mapper_help_and_exit))
188  ("no-dfg-transformations", "Disable all DFG transformations and optimizations; pass the input DFG directly the mapper",
189  cxxopts::value(option_vals.no_dfg_transformations))
190  ("no-reduce-mrrg", "Don't reduce the mrrg prior to mapping",
191  cxxopts::value(option_vals.no_reduce_mrrg))
192  ("print-arch", "Print Architecture to stdout",
193  cxxopts::value(option_vals.printarch))
194  ("print-final-dfg", "Print the DFG that is sent to mapper to this file",
195  cxxopts::value(option_vals.print_final_dfg_filename))
196  ("print-mrrg", "Print Architecture MRRG to file",
197  cxxopts::value(option_vals.print_mrrg_filename),"<Filename>")
198  ("o,save-to-dot", "Save the mapping to a dot file",
199  cxxopts::value(option_vals.mapping_output_filename))
200  ("t,timelimit", "Mapper Timelimit",
201  cxxopts::value(option_vals.timelimit)->default_value(std::to_string(option_vals.timelimit)), "<#>")
202  ("verbose", "Output will contain extra information detailing steps taken by this tool",
203  cxxopts::value(option_vals.verbosity)->default_value(std::to_string(option_vals.verbosity))->implicit_value(std::to_string(option_vals.verbosity)), "level")
204  ("verilog-opts", "Verilog options with hybrid system and memory size. Space-separated list of <Key>=<Value> pairs (must be a single arugment)",
205  cxxopts::value(option_vals.verilog_opts), "<\"opts\">")
206  ;
207 
208  options.parse(argc, argv);
209  } catch (...) {
210  std::throw_with_nested(cgrame_error("Problem parsing command-line options"));
211  }
212  //verify arguments do not start with a dash
213  int arguments_size = sizeof(argument_list)/sizeof(argument_list[0]);
214  for(int i = 0; i< arguments_size; i++)
215  {
216  if(argument_list[i]->rfind("-",0)==0){
217  throw cgrame_error("An argument is missing. "+ *argument_list[i] +" cannot be accepted as an argument");
218  }
219  }
220  timing_seqence.tick("parse arguments", 0.01);
221 
222  char full_path[1024] = {0}; // initialize to zero, so we don't have to set the null char ourselves
223  ssize_t count = readlink("/proc/self/exe", full_path, sizeof(full_path)/sizeof(full_path[0]) - 1);
224  std::string exe_path;
225  if(count != -1) {
226  exe_path = std::string(dirname(full_path));
227  } else {
228  throw cgrame_error("Readlink is not able to get the executable path");
229  }
230 
231  UserArchs userarchs;
232  const auto mapper_registry = AutoRegisterMapper::getDefaultRegistry(); // make a copy to prevent any funny business
233 
234  //
235  // Handle mode flags that just print & exit
236  //
237 
238  if(options.count("help") || arg_count == 1) {
239  std::cout << options.help({""}) << std::endl;
240  return 0;
241  }
242 
243  if (not option_vals.gen_config_file.empty()) {
244  std::cout << "Writing a config file to " << option_vals.gen_config_file << '\n';
245  std::ofstream conf_file(option_vals.gen_config_file);
246  if (not conf_file) {
247  throw cgrame_error("Unable to open " + option_vals.gen_config_file + "for writing");
248  }
249  mapper_registry.printDefaultsAsINI(conf_file);
250  if (not conf_file) {
251  throw cgrame_error("Problem while writing " + option_vals.gen_config_file);
252  }
253  return 0;
254  }
255 
256  if(option_vals.list_cpp_architectures) {
257  std::cout << "List of C++ CGRA Architectures: [ID: description]" << std::endl;
258  for(const auto & id_and_arch_gen : userarchs)
259  std::cout << id_and_arch_gen.first << ": " << id_and_arch_gen.second.description << '\n';
260  return 0;
261  }
262 
263  if(not option_vals.arch_opts_list_id.empty()) {
264  const auto& arch_generator = userarchs.getGenerator(option_vals.arch_opts_list_id);
265  std::cout << "List of options and defaults for architecture `" << option_vals.arch_opts_list_id << "' - `" << arch_generator.description << "'\n" << arch_generator.args_and_defaults << '\n';
266  return 0;
267  }
268 
269  if (option_vals.print_mapper_list) {
270  std::cout << "The list of registered mappers follows. The currently selected mapper is " << option_vals.mapper_id << "\n";
271  mapper_registry.printMapperList(std::cout);
272  return 0;
273  }
274 
275  //
276  // Handle mode flags that just print & exit, but also need the inis
277  //
278  const std::string ini_full_path = exe_path + "/" + default_config_file_name;
279  std::ifstream ini_file(ini_full_path);
280  if(!ini_file) {
281  throw cgrame_error("Missing mapper_config.ini, Cannot Read Default Parameters for Mappers");
282  }
283 
284  const ConfigStore effective_inis = [&]() { // (immediately invoked)
285  try {
286  return parseMapperConfig(
287  {std::istreambuf_iterator<char>(ini_file), std::istreambuf_iterator<char>()},
288  option_vals.mapper_opts,
289  option_vals.cpp_arch_id,
290  option_vals.verbosity
291  );
292  } catch (...) {
293  std::throw_with_nested("Problem parsing config. INI file used was at " + ini_full_path);
294  }
295  }();
296 
297  if(option_vals.print_mapper_help_and_exit) {
298  if (option_vals.mapper_id.empty()) {
299  std::cout << "A mapper must be selected to print its options\n";
300  return 1;
301  }
302  std::cout << "Help for mapper `" << option_vals.mapper_id << "':\n\n";
303  mapper_registry.printHelpForMapper(option_vals.mapper_id, effective_inis, std::cout);
304  std::cout << '\n';
305  return 0;
306  }
307 
308  //
309  // Basic argument checking
310  //
311  if(option_vals.verilog_gen_output_path.empty() && option_vals.dfg_filename.empty()) {
312  if (!(option_vals.printarch || !option_vals.print_mrrg_filename.empty())){
313  throw cgrame_error("DFG File Path is Missing, Exiting...");
314  }
315  }
316 
317  if(!option_vals.fix_port_filename.empty() && !option_vals.make_testbench) {
318  throw cgrame_error("fix_port option need to be used for generating bitstream");
319  }
320 
321 
322  if (option_vals.timelimit < 0) {
323  throw make_from_stream<cgrame_error>([&](auto&& s) {
324  s << "Time limit must not be less than zero (" << option_vals.timelimit << " was given)";
325  });
326  }
327 
328  timing_seqence.tick("argument checking", 0.01);
329 
330  //
331  // Main CGRA-ME flows
332  //
333 
334  std::shared_ptr<CGRA> arch = nullptr;
335 
336  ConfigGraph parsed_mapping_dot;
337  //load mapping from file if provided
338  if (not option_vals.load_mapping_filename.empty()) {
339  parsed_mapping_dot = loadMapping(
340  option_vals.load_mapping_filename,
341  &option_vals.cpp_arch_id,
342  &option_vals.arch_opts,
343  &option_vals.II);
344  timing_seqence.tick("load mapping", 0.01);
345  }
346 
347  ConfigStore arch_attrs;
348  //create architecture
349  if(!option_vals.cpp_arch_id.empty()) // Use C++
350  {
351  createArchitectureCPP(&arch,option_vals.cpp_arch_id,option_vals.arch_opts,&arch_attrs,&userarchs, option_vals.II);
352  }
353  else // Use ADL
354  {
355  throw cgrame_error("ADL architecture not supported");
356  }
357 
358  timing_seqence.tick("create architecture", 0.01);
359 
360  // Print Architecture if requested
361  if(option_vals.printarch)
362  {
363  std::cout << std::endl << "[ARCHGRAPH]" << std::endl;
364  arch->getTopLevelModule().print();
365  arch->getTopLevelModule().print_dot();
366  }
367 
368  // print MRRG if requested
369  if (not option_vals.print_mrrg_filename.empty()) {
370  std::cout << "Dumping MRRG with option_vals.II = " << option_vals.II << " to file `" << option_vals.print_mrrg_filename << "'\n";
371  std::ofstream file_stream{option_vals.print_mrrg_filename};
372  arch->getMRRG(option_vals.II).printDot(file_stream);
373  }
374 
375  timing_seqence.tick("print arch and/or MRRG", 0.01);
376 
377  //Exit here if not generating verilog and no application provided
378  if(option_vals.verilog_gen_output_path.empty() && option_vals.dfg_filename.empty()){
379  return 0;
380  }
381 
382  // Generate Verilog implementation and exit
383  if(not option_vals.verilog_gen_output_path.empty()) {
384  generateVerilog(arch, option_vals.verilog_gen_output_path, option_vals.verilog_opts, option_vals.verilog_gen_type, option_vals.II);
385  return 0;
386  }
387 
388 
389  timing_seqence.tick("generate Verilog", 0.01);
390 
391  // Creating OpGraph
392  cgrame_msg("Parsing DFG...");
393  auto dfg_ifstream = std::ifstream(option_vals.dfg_filename);
394  const auto parsed_dfg_dot = parseDot(dfg_ifstream, option_vals.dfg_filename);
395  timing_seqence.tick("load DFG", 0.01);
396  std::shared_ptr<OpGraph> opgraph = std::make_shared<OpGraph>(createOpGraphFromConfig(parsed_dfg_dot));
397  if (not option_vals.no_dfg_transformations) {
398  *opgraph = removeBranchComputation(std::move(*opgraph));
399  if (option_vals.arch_opts.find("pred=1") == std::string::npos)
400  *opgraph = removePhiNodes(std::move(*opgraph));
401  *opgraph = removeCastNodes(std::move(*opgraph));
402  *opgraph = propagateConstants(std::move(*opgraph));
403  *opgraph = distributeConstants(std::move(*opgraph));
404  }
405  timing_seqence.tick("optimize DFG", 0.01);
406 
407  // Print OpGraph if requested, exit if requested
408  if(not option_vals.print_final_dfg_filename.empty()) {
409  cgrame_msg("Printing DFG to " + option_vals.print_final_dfg_filename);
410  auto final_dfg_ofstream = std::ofstream{option_vals.print_final_dfg_filename};
411  opgraph->serialize(final_dfg_ofstream);
412  if (not final_dfg_ofstream) {
413  cgrame_warn("DFG printing may not have been successful");
414  }
415  timing_seqence.tick("print DFG", 0.01);
416  }
417 
418  if (option_vals.exit_after_optimizing_dfg) {
419  return 0;
420  }
421 
422  std::cout << "[INFO] Creating MRRG..." << std::endl;
423  const auto& mrrg = arch->getMRRG(option_vals.II);
424  timing_seqence.tick("create MRRG", 0.01);
425 
426  //Parse fixed ports
427  std::unordered_map<std::string, std::string> fix_port;
428  if (!option_vals.fix_port_filename.empty()) {
429  std::ifstream infile(option_vals.fix_port_filename);
430  std::string line;
431  std::string first;
432  std::string second;
433  while (std::getline(infile, line)) {
434  std::string::size_type pos = line.find(':');
435  if(line.npos != pos) {
436  second = line.substr(pos + 1);
437  first = line.substr(0, pos);
438  fix_port[first] = second;
439  } else {
440  throw cgrame_error("Format for fix_port is not right, \":\" is used as delimiter");
441  }
442  }
443  }
444 
445  // Declaring mapping result
446  Mapping mapping_result = Mapping(arch, option_vals.II, opgraph);
447  CreateMappingGraphResult create_mapping_graph_result{};
448 
449  if (not option_vals.load_mapping_filename.empty()) {
450  std::cout << "[INFO] Mapping using information from DOT file: " << option_vals.load_mapping_filename << std::endl;
451  // Map the empty mapping `mapping_result` and create a Mapping Graph for it
452  create_mapping_graph_result = createMappingGraphFromConfig(mapping_result, parsed_mapping_dot, *opgraph, mrrg);
453 
454  mapping_result.outputMapping();
455  mapping_result.check();
456  timing_seqence.tick("created loaded mapping", 0.01);
457  }
458  else {
459  //************************ Start of Mapping ************************
460  std::cout << "[INFO] Creating Mapper '" << option_vals.mapper_id << "'..." << std::endl;
461 
462  auto mapper = mapper_registry.createMapper(option_vals.mapper_id, arch, option_vals.timelimit, effective_inis);
463 
464  timing_seqence.tick("mapper setup", 0.01);
465 
466  // common mapping routine
467  const auto map_given_mrrg = [&timing_seqence, &mapper, &option_vals, &opgraph, &fix_port](const MRRG& given_mrrg) {
468  std::cout << "[INFO] Mapping..." << std::endl;
469  auto mapping = mapper->mapOpGraph(opgraph, option_vals.II, given_mrrg, fix_port);
470  auto time = timing_seqence.tick("mapping");
471  return std::make_pair(mapping, time);
472  };
473 
474  ChronoSequence::TickResult mapping_tick;
475  std::tie(mapping_result, mapping_tick) = [&]() { // an immediately invoked lambda
476  // Reduce MRRG if requested
477  if (not option_vals.no_reduce_mrrg) {
478  std::cout << "[INFO] Reducing MRRG..." << std::endl;
479  const auto mrrg_reduction_result = reduceLosslessly(arch->getMRRG(option_vals.II), {});
480  timing_seqence.tick("reduce MRRG", 0.01);
481 
482  auto mapping_and_tick = map_given_mrrg(mrrg_reduction_result.transformed_mrrg);
483  auto untransformed_mapping = transformToOriginalMRRG(std::move(mapping_and_tick.first), mrrg_reduction_result);
484  timing_seqence.tick("transform mapping to original", 0.01);
485  return std::make_pair(std::move(untransformed_mapping), mapping_and_tick.second);
486  } else {
487  return map_given_mrrg(mrrg);
488  }
489  }();
490 
491  double solve_time = mapping_result.solve_time_in_seconds;
492  if (solve_time < 0) solve_time = mapping_result.solve_time_in_seconds; // fall back to the timing seq number
493  std::cout << "[INFO] Mapping Success: " << mapping_result.isMapped() << std::endl;
494  std::cout << "[INFO] Mapping Time: " << solve_time << std::endl;
495  std::cout << "[INFO] Mapping Timeout: " << mapping_result.isTimeout() << std::endl;
496 
497  if (not mapping_result.isMapped()) { return 1; }
498 
499  mapping_result.outputMapping();
500  mapping_result.check();
501 
502  create_mapping_graph_result = createMappingGraph(mrrg, mapping_result);
503  }
504 
505  const auto final_mapping_graph = removeIsolatedRoutingNodes(create_mapping_graph_result.mg, mrrg, create_mapping_graph_result.toMRRG);
506 
507  for (auto message : final_mapping_graph.verify(mrrg, create_mapping_graph_result.toMRRG)) {
508  std::cout << message.message;
509  }
510 
511  //const auto latency_check_result = latencyCheck(final_mapping_graph, mrrg, create_mapping_graph_result.toMRRG);
512  //if (not latency_check_result.first) {
513  // throw cgrame_error("Latencies of mapping are not balanced!");
514  //}
515  timing_seqence.tick("post mapping checks and transforms", 0.01);
516 
517  // Save the mapping result in an dot file if requested
518  if (not option_vals.mapping_output_filename.empty()) {
519  std::cout << "[INFO] Saving mapping result to '" << option_vals.mapping_output_filename << '\'' << std::endl;
520  std::ofstream mappingStream(option_vals.mapping_output_filename);
521  final_mapping_graph.printDot(mappingStream, mrrg, *opgraph, create_mapping_graph_result.toMRRG, arch_attrs);
522  if (not mappingStream) { std::cerr << "Problem writing mapping to '" << option_vals.mapping_output_filename << '\'' << std::endl; }
523  timing_seqence.tick("saving mapping", 0.01);
524  }
525 
526 
527  if (option_vals.make_testbench)
528  {
529  createTestbench(arch, mapping_result, option_vals.II);
530  timing_seqence.tick("generate testbench", 0.01);
531  }
532 
533  return 0;
534 }
535 
537  const std::string& ini_str,
538  const std::string& mapper_opts,
539  const std::string& cpp_arch_id,
540  const int verbosity
541 ) {
542  // parse command-line overrides
543  ConfigStore command_line_overrides;
544  std::stringstream ss_mapper_opts(mapper_opts);
545  for (;;) {
546  std::string opt_pair;
547  if (not (ss_mapper_opts >> opt_pair)) { break; }
548  auto assign_pos = opt_pair.find('=');
549 
550  if(assign_pos == opt_pair.npos) {
551  throw cgrame_error("Ill-formatted command-line override: " + opt_pair);
552  }
553 
554  command_line_overrides.addString(opt_pair.substr(0, assign_pos), opt_pair.substr(assign_pos + 1));
555  }
556 
557  // read ini file
558  mINI raw_inis;
559  if(not raw_inis.parse(ini_str)) {
560  throw cgrame_error("Error in INI Parser");
561  }
562 
563  // remove any leading dots & comments
564  ConfigStore parsed_inis;
565  for (const auto& ini_and_value : raw_inis) {
566  const auto& key = ini_and_value.first;
567  if (key.empty()) { continue; }
568  if (key.find_first_not_of("\t ") == key.npos) { continue; } // all whitespace
569  if (key.at(key.find_first_not_of("\t ")) == '#') { continue; } // comments
570  const auto dot_pos = key.find_first_of(".");
571  if (dot_pos != key.npos && key.at(key.find_first_not_of("\t ", dot_pos+1)) == '#') { continue; } // comments in sections
572  if (key.front() == '.') {
573  if (key.size() > 1) {
574  parsed_inis.setString(key.substr(1), ini_and_value.second);
575  }
576  } else {
577  parsed_inis.setString(key, ini_and_value.second);
578  }
579  }
580 
581  // add options from other flags
582  parsed_inis.setString("AllMappers.arch_id", cpp_arch_id);
583  parsed_inis.setInt("AllMappers.verbosity", verbosity);
584 
585  // set command-line overrides
586  const ConfigStore effective_inis = with_set(parsed_inis, command_line_overrides);
587  return effective_inis;
588 }
589 
590 void generateVerilog(std::shared_ptr<CGRA> arch,
591  std::string verilog_gen_output_path,
592  std::string verilog_opts,
593  VerilogType verilog_gen_type,
594  int contexts
595 ){
596  struct stat fs_info;
597  auto res = stat(verilog_gen_output_path.c_str(), &fs_info);
598  // Verify if directory exists
599  if (res != 0)
600  {
601  throw cgrame_error("Cannot open \"" + verilog_gen_output_path + "\"");
602  }
603  bool is_dir = fs_info.st_mode & S_IFDIR;
604  if (!is_dir) // make sure it is directory
605  {
606  throw cgrame_error("\"" + verilog_gen_output_path + "\" is not a directory");
607  }
608 
609  std::cout << "[INFO] Generating Verilog Implementation of Specified Architecture Using Generator "<< verilog_gen_type << std::endl;
610  if (verilog_gen_output_path.back() != '/')
611  verilog_gen_output_path = verilog_gen_output_path + "/";
612  arch->genVerilog(verilog_gen_type, verilog_gen_output_path, contexts);
613  ConfigStore verilog_attrs;
614  std::stringstream ss_verilog_opts(verilog_opts);
615  std::string opt_pair;
616  while(ss_verilog_opts >> opt_pair)
617  {
618  auto n = opt_pair.find('=');
619  if(n == std::string::npos) { make_and_throw<cgrame_error>([&](auto&& s) {
620  s << "Ill-formatted verilog option: " << opt_pair;
621  });}
622  auto key = opt_pair.substr(0, n);
623  auto value = opt_pair.substr(n + 1, std::string::npos);
624  if (verilog_attrs.hasKey(key)) {
625  std::cout << "[WARNING] duplicate key `" << key << "' verilog arguments. Overwriting with new value `" << value << "'\n";
626  }
627  verilog_attrs.setString(std::move(key), std::move(value));
628  }
629  if (verilog_attrs.hasKey("hybrid")) {
630  if(verilog_attrs.getString("hybrid").find("on") != std::string::npos) {
631  int mem_size = stoi(verilog_attrs.getStringOr("memSize", "22"));
632  arch->genHybrid(verilog_gen_type, verilog_gen_output_path, mem_size);
633  }
634  }
635 }
636 
637 
638 ConfigGraph loadMapping(std::string load_mapping_filename,
639  std::string* cpp_arch_id,
640  std::string* arch_opts,
641  int *II
642 ){
643  try{
644  ConfigGraph parsed_mapping_dot;
645  std::cout << "[INFO] Getting architecture information from DOT file: " << load_mapping_filename << std::endl;
646 
647  auto mapping_ifstream = std::ifstream(load_mapping_filename);
648  parsed_mapping_dot = parseDot(mapping_ifstream, load_mapping_filename);
649  const auto& mapping_attrs = parsed_mapping_dot.graphAttributes();
650 
651  if (mapping_attrs.hasKey("cpp_arch_id")) {
652  *cpp_arch_id = mapping_attrs.getString("cpp_arch_id");
653  *arch_opts = mapping_attrs.getStringOr("arch_opts", "");
654  }
655 
656  *II = mapping_attrs.getInt("II");
657  return parsed_mapping_dot;
658  } catch (...) {
659  std::throw_with_nested(cgrame_error("Problem parsing input mapping file `" + load_mapping_filename + "'"));
660  }
661 }
662 
664  std::shared_ptr<CGRA>* arch,
665  std::string cpp_arch_id,
666  std::string arch_opts,
667  ConfigStore* arch_attrs,
668  UserArchs* userarchs,
669  int II
670 ){
671  std::cout << "[INFO] Using C++ architecture ID " << cpp_arch_id << '\n';
672  auto& arch_generator = userarchs->getGenerator(cpp_arch_id);
673  std::cout << "[INFO] Architecture description: " << arch_generator.description << '\n';
674 
675  std::stringstream ss_arch_opts(arch_opts);
676  std::string opt_pair;
677  while(ss_arch_opts >> opt_pair)
678  {
679  auto n = opt_pair.find('=');
680  if(n == std::string::npos) { make_and_throw<cgrame_error>([&](auto&& s) {
681  s << "Ill-formatted C++ architecture option: " << opt_pair;
682  });}
683  auto key = opt_pair.substr(0, n);
684  auto value = opt_pair.substr(n + 1, std::string::npos);
685  if (arch_attrs->hasKey(key)) {
686  std::cout << "[WARNING] duplicate key `" << key << "' in C++ architecture arguments. Overwriting with new value `" << value << "'\n";
687  }
688  (*arch_attrs).setString(std::move(key), std::move(value));
689  }
690 
691  std::cout << "[INFO] Creating \"" << cpp_arch_id << "\" Architecture from C++..." << std::endl;
692  arch_attrs->setInt("II", II);
693  (*arch) = arch_generator(*arch_attrs);
694  arch_attrs->setString("cpp_arch_id", cpp_arch_id);
695  arch_attrs->setString("arch_opts", arch_opts);
696  if (arch_attrs->hasKey("rows")) {
697  (*arch)->setNumRows(arch_attrs->getInt("rows"));
698  }
699  if (arch_attrs->hasKey("cols")) {
700  (*arch)->setNumCols(arch_attrs->getInt("cols"));
701  }
702 }
703 
705  std::shared_ptr<CGRA> arch,
706  Mapping mapping_result,
707  int II
708 ){
709  std::ofstream tb_file("testbench.v");
710  auto bitstream = arch->genBitStream(mapping_result);
711  std::cout << bitstream;
712  bitstream.printTestbench(tb_file, II);
713 }
removeIsolatedRoutingNodes
MappingGraph removeIsolatedRoutingNodes(const MappingGraph &mapping, const MRRG &mrrg, const MappingGraph::ToMRRGVertexMap &toMRRG)
Definition: Mapping.cpp:504
Util.h
CodeProfiling.h
Mapping::II
int II
Definition: Mapping.h:105
Visual.h
cgrame.h
ChronoSequence::TickResult
Definition: CodeProfiling.h:31
ConfigStore::setString
void setString(std::string key, std::string value)
Definition: ConfigStore.h:128
MRRG
Definition: MRRG.h:216
dotparse.h
Mapping::check
void check() const
Definition: Mapping.cpp:284
removeBranchComputation
OpGraph removeBranchComputation(OpGraph opgraph)
Definition: OpGraphProcedures.cpp:305
VerilogType
VerilogType
Definition: Module.h:150
OpGraphProcedures.h
inner_main
int inner_main(int argc, char *argv[])
Definition: cgrame.cpp:80
propagateConstants
OpGraph propagateConstants(OpGraph og)
Definition: OpGraphProcedures.cpp:373
PerfEngine.h
loadMapping
ConfigGraph loadMapping(std::string load_mapping_filename, std::string *cpp_arch_id, std::string *arch_opts, int *II)
Definition: cgrame.cpp:638
Mapping::solve_time_in_seconds
double solve_time_in_seconds
Definition: Mapping.h:110
removeCastNodes
OpGraph removeCastNodes(OpGraph og)
Definition: OpGraphProcedures.cpp:313
removePhiNodes
OpGraph removePhiNodes(OpGraph opgraph)
Definition: OpGraphProcedures.cpp:334
ArchitectureGenerator::description
std::string description
Definition: UserArchs.h:26
ConfigStore::setInt
void setInt(std::string key, long long value)
Definition: ConfigStore.h:129
UserArchs.h
ConfigGraph
Definition: ConfigGraph.h:72
Mapping::outputMapping
void outputMapping(std::ostream &o=std::cout) const
Definition: Mapping.h:72
ConfigStore
Definition: ConfigStore.h:76
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
ConfigStore::getStringOr
const std::string & getStringOr(const std::string &key, const std::string &otherwise) const
Definition: ConfigStore.h:181
cxxopts::values::parse_value
void parse_value(const std::string &text, VerilogType &value)
Definition: cgrame.cpp:66
CreateMappingGraphResult
Definition: Mapping.h:246
Mapping
Definition: Mapping.h:31
Exception.h
VerilogType::CoreIR
@ CoreIR
ConfigStore::hasKey
bool hasKey(const std::string &key) const
Definition: ConfigStore.h:209
ConfigStore::addString
bool addString(std::string key, std::string value)
Definition: ConfigStore.h:120
main
int main(int argc, char *argv[])
Definition: cgrame.cpp:53
ConfigGraph::graphAttributes
const ConfigStore & graphAttributes() const &
Definition: ConfigGraph.h:109
createOpGraphFromConfig
OpGraph createOpGraphFromConfig(const ConfigGraph &config)
Definition: OpGraphProcedures.cpp:187
cgrame_msg
#define cgrame_msg(m)
Definition: Util.h:17
cgrame_warn
#define cgrame_warn(m)
Definition: Util.h:18
parseMapperConfig
ConfigStore parseMapperConfig(const std::string &ini_str, const std::string &mapper_opts, const std::string &cpp_arch_id, const int verbosity)
Definition: cgrame.cpp:536
PrintOnDestructionChronoSequence
Definition: CodeProfiling.h:121
ChronoSequence::tick
TickResult tick(std::string timepoint_name, double threshold=0.0, std::ostream *os=nullptr)
Definition: CodeProfiling.h:54
parseDot
ConfigGraph parseDot(std::istream &input, std::string file_name)
distributeConstants
OpGraph distributeConstants(OpGraph og)
Definition: OpGraphProcedures.cpp:455
createMappingGraphFromConfig
CreateMappingGraphResult createMappingGraphFromConfig(Mapping &m, const ConfigGraph &config, const OpGraph &opgraph, const MRRG &mrrg)
Definition: MappingProcedures.cpp:14
MappingProcedures.h
AutoRegisterMapper::getDefaultRegistry
static const MapperRegistry & getDefaultRegistry()
Public read-only access to the mapper registry that this class automatically adds mappers to.
Definition: Mapper.h:214
generateVerilog
void generateVerilog(std::shared_ptr< CGRA > arch, std::string verilog_gen_output_path, std::string verilog_opts, VerilogType verilog_gen_type, int contexts)
Definition: cgrame.cpp:590
transformToOriginalMRRG
Mapping transformToOriginalMRRG(const Mapping &map, const MRRGTransformationResult &transformation)
Definition: MRRGProcedures.cpp:607
reduceLosslessly
MRRGTransformationResult reduceLosslessly(const MRRG &src_mrrg, const MRRGTransformFlags &flags)
Definition: MRRGProcedures.cpp:420
createTestbench
void createTestbench(std::shared_ptr< CGRA > arch, Mapping mapping_result, int II)
Definition: cgrame.cpp:704
UserArchs::getGenerator
const ArchitectureGenerator & getGenerator(const std::string &identifer) const
Definition: UserArchs.h:154
ConfigStore::getString
const std::string & getString(const std::string &key) const
Definition: ConfigStore.h:136
with_set
ConfigStore with_set(ConfigStore into, const ConfigStore &from1, const CSes &... froms)
Definition: ConfigStore.h:279
UserArchs
Definition: UserArchs.h:43
Mapping.h
MRRGProcedures.h
Mapper.h
cxxopts
Definition: cgrame.cpp:63
Mapping::isMapped
bool isMapped() const
Definition: Mapping.h:37
createMappingGraph
CreateMappingGraphResult createMappingGraph(const MRRG &mrrg, const Mapping &m)
Definition: Mapping.cpp:468
createArchitectureCPP
void createArchitectureCPP(std::shared_ptr< CGRA > *arch, std::string cpp_arch_id, std::string arch_opts, ConfigStore *arch_attrs, UserArchs *userarchs, int II)
Definition: cgrame.cpp:663
ConfigStore::getInt
long long getInt(const std::string &key) const
Definition: ConfigStore.h:146
printExceptionToOutAndErr
void printExceptionToOutAndErr(std::exception_ptr eptr, const char *line_prefix, const char *message)
Definition: Exception.h:134
Mapping::isTimeout
bool isTimeout() const
Definition: Mapping.h:38
cgrame_error
Definition: Exception.h:20