18 std::stringstream res_stream;
20 if (netlist ==
nullptr)
22 return ERR(
"could not write netlist to Verilog file '" + file_path.string() +
"': netlist is a 'nullptr'");
25 if (file_path.empty())
27 return ERR(
"could not write netlist to Verilog file '" + file_path.string() +
"': file path is empty");
31 std::vector<Module*> ordered_modules;
33 const std::vector<Module*> modules = netlist->
get_modules();
34 std::unordered_set<Module*> modules_set(modules.begin(), modules.end());
36 while (!modules_set.empty())
38 for (
auto it = modules_set.begin(); it != modules_set.end();)
40 std::vector<Module*> submodules = (*it)->get_submodules();
41 if (submodules.empty() || std::all_of(submodules.begin(), submodules.end(), [modules_set](
Module* submod) { return modules_set.find(submod) == modules_set.end(); }))
43 ordered_modules.push_back(*it);
44 it = modules_set.erase(it);
53 assert(ordered_modules.back()->is_top_module() ==
true);
56 std::unordered_map<const Module*, std::string> module_aliases;
57 std::unordered_map<std::string, u32> module_identifier_occurrences;
58 for (
Module* mod : ordered_modules)
60 if (
auto res = write_module_declaration(res_stream, mod, module_aliases, module_identifier_occurrences); res.is_error())
62 return ERR_APPEND(res.get_error(),
"could not write netlist to Verilog file '" + file_path.string() +
"': failed to write module declaration");
64 res_stream << std::endl;
69 file.open(file_path.string(), std::ofstream::out);
72 return ERR(
"could not write netlist to Verilog file '" + file_path.string() +
"': failed to open file");
74 file <<
"`timescale 1 ps/1 ps" << std::endl;
75 file << res_stream.str();
83 std::unordered_map<const Module*, std::string>& module_type_aliases,
84 std::unordered_map<std::string, u32>& module_type_occurrences)
const
94 if (module_type.empty())
99 module_type +=
"_type";
102 module_type_aliases[
module] = get_unique_alias(module_type_occurrences, module_type);
106 res_stream <<
"module " << escape(design_name);
110 res_stream <<
"module " << escape(module_type_aliases.at(
module));
113 std::unordered_map<const DataContainer*, std::string> aliases;
114 std::unordered_map<std::string, u32> identifier_occurrences;
116 bool first_port =
true;
117 std::stringstream tmp_stream;
122 Net*
net = pin->get_net();
132 aliases[
net] = escape(get_unique_alias(identifier_occurrences, pin->get_name()));
134 res_stream << aliases.at(
net);
135 tmp_stream <<
" " <<
enum_to_string(pin->get_direction()) <<
" " << aliases.at(
net) <<
";" << std::endl;
138 res_stream <<
");" << std::endl;
139 res_stream << tmp_stream.str();
145 const auto& [decl, value] = decl_and_value;
146 res_stream <<
" parameter " << escape(
name) <<
" = ";
147 if (
auto res = write_typed_parameter_value(res_stream, decl, value); res.is_error())
150 "could not write declaration of module '" +
module->
get_name() +
"' with ID " + std::to_string(
module->
get_id()) +
": failed to write parameter value");
152 res_stream <<
";" << std::endl;
158 port_nets.reserve(output_nets_tmp.size());
159 port_nets.insert(output_nets_tmp.begin(), output_nets_tmp.end());
163 if (port_nets.find(
net) != port_nets.end())
168 if (aliases.find(
net) == aliases.end())
170 auto net_alias = escape(get_unique_alias(identifier_occurrences,
net->get_name()));
171 aliases[
net] = net_alias;
173 res_stream <<
" wire " << net_alias;
175 if (
net->is_vcc_net() &&
net->get_num_of_sources() == 0)
177 res_stream <<
" = 1'b1";
179 else if (
net->is_gnd_net() &&
net->get_num_of_sources() == 0)
181 res_stream <<
" = 1'b0";
184 res_stream <<
";" << std::endl;
191 res_stream << std::endl;
192 if (
auto res = write_gate_instance(res_stream, gate, aliases, identifier_occurrences); res.is_error())
195 "could not write declaration of module '" +
module->
get_name() +
"' with ID " + std::to_string(
module->
get_id()) +
": failed to write gate '" + gate->get_name()
196 +
"' with ID " + std::to_string(gate->get_id()));
203 res_stream << std::endl;
204 if (
auto res = write_module_instance(res_stream, sub_module, aliases, identifier_occurrences, module_type_aliases); res.is_error())
207 "could not write declaration of module '" +
module->
get_name() +
"' with ID " + std::to_string(
module->
get_id()) +
": failed to write sub-module '"
208 + sub_module->get_name() +
"' with ID " + std::to_string(sub_module->get_id()));
212 res_stream <<
"endmodule" << std::endl;
217 Result<std::monostate> VerilogWriter::write_gate_instance(std::stringstream& res_stream,
219 std::unordered_map<const DataContainer*, std::string>& aliases,
220 std::unordered_map<std::string, u32>& identifier_occurrences)
const
222 const GateType* gate_type = gate->get_type();
224 res_stream <<
" " << escape(gate_type->get_name());
225 if (
auto res = write_parameter_assignments(res_stream, gate); res.is_error())
227 return ERR_APPEND(res.get_error(),
"could not write gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()) +
": failed to write parameter assignments");
229 aliases[gate] = escape(get_unique_alias(identifier_occurrences, gate->get_name()));
230 res_stream <<
" " << aliases.at(gate);
233 std::unordered_map<const GatePin*, const Net*> connections;
234 for (
const Endpoint* ep : gate->get_fan_in_endpoints())
236 connections[ep->get_pin()] = ep->get_net();
239 for (
const Endpoint* ep : gate->get_fan_out_endpoints())
241 connections[ep->get_pin()] = ep->get_net();
245 std::vector<std::pair<std::string, std::vector<const Net*>>> pin_assignments;
246 for (
const PinGroup<GatePin>* pin_group : gate_type->get_pin_groups())
248 std::vector<const Net*> nets;
249 for (
const GatePin* pin : pin_group->get_pins())
251 if (
const auto ep_it = connections.find(pin); ep_it != connections.end())
253 nets.push_back(ep_it->second);
257 nets.push_back(
nullptr);
262 if (std::any_of(nets.begin(), nets.end(), [](
const Net*
net) { return net != nullptr; }))
264 pin_assignments.push_back(std::make_pair(pin_group->get_name(), nets));
268 if (
auto res = write_pin_assignments(res_stream, pin_assignments, aliases); res.is_error())
270 return ERR_APPEND(res.get_error(),
"could not write gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()) +
": failed to write pin assignments");
273 res_stream <<
";" << std::endl;
278 Result<std::monostate> VerilogWriter::write_module_instance(std::stringstream& res_stream,
280 std::unordered_map<const DataContainer*, std::string>& aliases,
281 std::unordered_map<std::string, u32>& identifier_occurrences,
282 std::unordered_map<const Module*, std::string>& module_type_aliases)
const
284 res_stream <<
" " << escape(module_type_aliases.at(
module));
285 if (
auto res = write_parameter_assignments(res_stream,
module); res.is_error())
287 return ERR_APPEND(res.get_error(),
"could not write sub-module '" +
module->
get_name() +
"' with ID " + std::to_string(
module->
get_id()) +
": failed to write parameter assignments");
290 res_stream <<
" " << aliases.at(
module);
293 std::vector<std::pair<std::string, std::vector<const Net*>>> port_assignments;
297 port_assignments.push_back(std::make_pair(pin->get_name(), std::vector<const Net*>({pin->get_net()})));
300 if (
auto res = write_pin_assignments(res_stream, port_assignments, aliases); res.is_error())
302 return ERR_APPEND(res.get_error(),
"could not write sub-module '" +
module->
get_name() +
"' with ID " + std::to_string(
module->
get_id()) +
": failed to write pin assignments");
305 res_stream <<
";" << std::endl;
310 Result<std::monostate> VerilogWriter::write_parameter_assignments(std::stringstream& res_stream,
const DataContainer* container)
const
312 bool first_parameter =
true;
313 const auto open_or_separator = [&]() {
316 res_stream <<
" #(" << std::endl;
317 first_parameter =
false;
321 res_stream <<
"," << std::endl;
325 for (
const auto& [
name, decl_and_value] : container->get_parameters())
327 const auto& [decl, value] = decl_and_value;
329 res_stream <<
" ." << escape(
name) <<
"(";
330 if (
auto res = write_typed_parameter_value(res_stream, decl, value); res.is_error())
332 return ERR_APPEND(res.get_error(),
"could not write parameter assignments for '" +
name +
"'");
337 if (!first_parameter)
339 res_stream << std::endl <<
" )";
345 Result<std::monostate> VerilogWriter::write_pin_assignments(std::stringstream& res_stream,
346 const std::vector<std::pair<std::string, std::vector<const Net*>>>& pin_assignments,
347 std::unordered_map<const DataContainer*, std::string>& aliases)
const
349 static u32 unused_signal_counter = 0;
351 res_stream <<
" (" << std::endl;
352 bool first_pin =
true;
353 for (
const auto& [pin, nets] : pin_assignments)
361 res_stream <<
"," << std::endl;
364 res_stream <<
" ." << escape(pin) <<
"(";
367 res_stream <<
"{" << std::endl <<
" ";
370 bool first_net =
true;
371 for (
auto it = nets.begin(); it != nets.end(); it++)
377 res_stream <<
"," << std::endl <<
" ";
383 if (
const auto alias_it = aliases.find(
net); alias_it != aliases.end())
385 res_stream << alias_it->second;
389 return ERR(
"could not write pin assignments: no alias for net '" +
net->get_name() +
"' with ID " + std::to_string(
net->get_id()) +
" found");
395 res_stream <<
"HAL_UNUSED_SIGNAL_" + std::to_string(unused_signal_counter++);
401 res_stream << std::endl <<
" }";
407 res_stream << std::endl <<
" )";
412 Result<std::monostate> VerilogWriter::write_typed_parameter_value(std::stringstream& res_stream,
const Parameter& decl,
const std::string& value)
const
414 switch (decl.get_type())
424 res_stream <<
"\"" << value <<
"\"";
428 res_stream << (value ==
"true" ?
"1'b1" :
"1'b0");
434 if (value.size() < 3 || value[0] !=
'0')
436 return ERR(
"could not write parameter '" + decl.get_name() +
"': unexpected value format '" + value +
"'");
438 const char base =
static_cast<char>(std::tolower(
static_cast<unsigned char>(value[1])));
439 const auto digits = value.substr(2);
443 case 'b': verilog_base =
'b';
break;
444 case 'o': verilog_base =
'o';
break;
445 case 'x': verilog_base =
'h';
break;
447 return ERR(
"could not write parameter '" + decl.get_name() +
"': unknown base '" + std::string(1, base) +
"' in value '" + value +
"'");
449 res_stream << decl.get_size() <<
"'" << verilog_base << digits;
457 std::string VerilogWriter::get_unique_alias(std::unordered_map<std::string, u32>& name_occurrences,
const std::string&
name)
const
459 name_occurrences[
name]++;
462 if (name_occurrences[
name] < 2)
468 return name +
"__[" + std::to_string(name_occurrences[
name]) +
"]__";
471 std::string VerilogWriter::escape(
const std::string& s)
const
478 const char first = s.at(0);
479 if (!(first >=
'a' && first <=
'z') && !(first >=
'A' && first <=
'Z') && first !=
'_')
481 return "\\" + s +
" ";
483 else if (std::any_of(s.begin(), s.end(), [](
const char c) { return (!(c >=
'a' && c <=
'z') && !(c >=
'A' && c <=
'Z') && !(c >=
'0' && c <=
'9') && c !=
'_' && c !=
'$'); }))
485 return "\\" + s +
" ";
const std::unordered_map< std::string, std::pair< Parameter, std::string > > & get_parameters() const
const std::unordered_set< Net * > & get_nets() const
std::vector< ModulePin * > get_pins(const std::function< bool(ModulePin *)> &filter=nullptr) const
bool is_top_module() const
const std::vector< Gate * > & get_gates() const
std::string get_name() const
const std::unordered_set< Net * > & get_input_nets() const
Netlist * get_netlist() const
std::vector< Module * > get_submodules(const std::function< bool(Module *)> &filter=nullptr, bool recursive=false) const
std::string get_type() const
const std::unordered_set< Net * > & get_output_nets() const
const std::vector< Module * > & get_modules() const
const std::string & get_design_name() const
Result< std::monostate > write(Netlist *netlist, const std::filesystem::path &file_path) override
#define ERR_APPEND(prev_error, message)
const Module * module(const Gate *g, const NodeBoxes &boxes)
std::string enum_to_string(T e)