13 const std::set<std::string> VerilogWriter::valid_types = {
"string",
"integer",
"floating_point",
"bit_value",
"bit_vector",
"bit_string"};
17 std::stringstream res_stream;
21 return ERR(
"could not write netlist to Verilog file '" + file_path.string() +
"': netlist is a 'nullptr'");
24 if (file_path.empty())
26 return ERR(
"could not write netlist to Verilog file '" + file_path.string() +
"': file path is empty");
30 std::vector<Module*> ordered_modules;
32 const std::vector<Module*> modules =
netlist->get_modules();
33 std::unordered_set<Module*> modules_set(modules.begin(), modules.end());
35 while (!modules_set.empty())
37 for (
auto it = modules_set.begin(); it != modules_set.end();)
39 std::vector<Module*> submodules = (*it)->get_submodules();
40 if (submodules.empty() || std::all_of(submodules.begin(), submodules.end(), [modules_set](
Module* submod) { return modules_set.find(submod) == modules_set.end(); }))
42 ordered_modules.push_back(*it);
43 it = modules_set.erase(it);
52 assert(ordered_modules.back()->is_top_module() ==
true);
55 std::unordered_map<const Module*, std::string> module_aliases;
56 std::unordered_map<std::string, u32> module_identifier_occurrences;
57 for (
Module* mod : ordered_modules)
59 if (
auto res = write_module_declaration(res_stream, mod, module_aliases, module_identifier_occurrences); res.is_error())
61 return ERR_APPEND(res.get_error(),
"could not write netlist to Verilog file '" + file_path.string() +
"': failed to write module declaration");
63 res_stream << std::endl;
68 file.open(file_path.string(), std::ofstream::out);
71 return ERR(
"could not write netlist to Verilog file '" + file_path.string() +
"': failed to open file");
73 file <<
"`timescale 1 ps/1 ps" << std::endl;
74 file << res_stream.str();
82 std::unordered_map<const Module*, std::string>& module_type_aliases,
83 std::unordered_map<std::string, u32>& module_type_occurrences)
const
93 if (module_type.empty())
98 module_type +=
"_type";
101 module_type_aliases[
module] = get_unique_alias(module_type_occurrences, module_type);
105 res_stream <<
"module " << escape(design_name);
109 res_stream <<
"module " << escape(module_type_aliases.at(
module));
112 std::unordered_map<const DataContainer*, std::string> aliases;
113 std::unordered_map<std::string, u32> identifier_occurrences;
115 bool first_port =
true;
116 std::stringstream tmp_stream;
121 Net*
net = pin->get_net();
131 aliases[
net] = escape(get_unique_alias(identifier_occurrences, pin->get_name()));
133 res_stream << aliases.at(
net);
134 tmp_stream <<
" " <<
enum_to_string(pin->get_direction()) <<
" " << aliases.at(
net) <<
";" << std::endl;
137 res_stream <<
");" << std::endl;
138 res_stream << tmp_stream.str();
142 const std::map<std::tuple<std::string, std::string>, std::tuple<std::string, std::string>>&
data =
module->
get_data_map();
144 for (
const auto& [first, second] : data)
146 const auto& [category, key] = first;
147 const auto& [
type, value] = second;
149 if (category !=
"generic" || valid_types.find(
type) == valid_types.end())
154 res_stream <<
" parameter " << escape(key) <<
" = ";
155 if (
auto res = write_parameter_value(res_stream,
type, value); res.is_error())
158 "could not write declaration of module '" +
module->
get_name() +
"' with ID " + std::to_string(
module->
get_id()) +
": failed to write parameter value");
160 res_stream <<
";" << std::endl;
166 port_nets.reserve(output_nets_tmp.size());
167 port_nets.insert(output_nets_tmp.begin(), output_nets_tmp.end());
171 if (port_nets.find(
net) != port_nets.end())
176 if (aliases.find(
net) == aliases.end())
178 auto net_alias = escape(get_unique_alias(identifier_occurrences,
net->get_name()));
179 aliases[
net] = net_alias;
181 res_stream <<
" wire " << net_alias;
183 if (
net->is_vcc_net() &&
net->get_num_of_sources() == 0)
185 res_stream <<
" = 1'b1";
187 else if (
net->is_gnd_net() &&
net->get_num_of_sources() == 0)
189 res_stream <<
" = 1'b0";
192 res_stream <<
";" << std::endl;
199 res_stream << std::endl;
200 if (
auto res = write_gate_instance(res_stream, gate, aliases, identifier_occurrences); res.is_error())
203 "could not write declaration of module '" +
module->
get_name() +
"' with ID " + std::to_string(
module->
get_id()) +
": failed to write gate '" + gate->get_name()
204 +
"' with ID " + std::to_string(gate->get_id()));
211 res_stream << std::endl;
212 if (
auto res = write_module_instance(res_stream, sub_module, aliases, identifier_occurrences, module_type_aliases); res.is_error())
215 "could not write declaration of module '" +
module->
get_name() +
"' with ID " + std::to_string(
module->
get_id()) +
": failed to write sub-module '"
216 + sub_module->get_name() +
"' with ID " + std::to_string(sub_module->get_id()));
220 res_stream <<
"endmodule" << std::endl;
225 Result<std::monostate> VerilogWriter::write_gate_instance(std::stringstream& res_stream,
227 std::unordered_map<const DataContainer*, std::string>& aliases,
228 std::unordered_map<std::string, u32>& identifier_occurrences)
const
230 const GateType* gate_type = gate->get_type();
232 res_stream <<
" " << escape(gate_type->get_name());
233 if (
auto res = write_parameter_assignments(res_stream, gate); res.is_error())
235 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");
237 aliases[gate] = escape(get_unique_alias(identifier_occurrences, gate->get_name()));
238 res_stream <<
" " << aliases.at(gate);
241 std::unordered_map<const GatePin*, const Net*> connections;
242 for (
const Endpoint* ep : gate->get_fan_in_endpoints())
244 connections[ep->get_pin()] = ep->get_net();
247 for (
const Endpoint* ep : gate->get_fan_out_endpoints())
249 connections[ep->get_pin()] = ep->get_net();
253 std::vector<std::pair<std::string, std::vector<const Net*>>> pin_assignments;
254 for (
const PinGroup<GatePin>* pin_group : gate_type->get_pin_groups())
256 std::vector<const Net*> nets;
257 for (
const GatePin* pin : pin_group->get_pins())
259 if (
const auto ep_it = connections.find(pin); ep_it != connections.end())
261 nets.push_back(ep_it->second);
265 nets.push_back(
nullptr);
270 if (std::any_of(nets.begin(), nets.end(), [](
const Net*
net) { return net != nullptr; }))
272 pin_assignments.push_back(std::make_pair(pin_group->get_name(), nets));
276 if (
auto res = write_pin_assignments(res_stream, pin_assignments, aliases); res.is_error())
278 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");
281 res_stream <<
";" << std::endl;
286 Result<std::monostate> VerilogWriter::write_module_instance(std::stringstream& res_stream,
288 std::unordered_map<const DataContainer*, std::string>& aliases,
289 std::unordered_map<std::string, u32>& identifier_occurrences,
290 std::unordered_map<const Module*, std::string>& module_type_aliases)
const
292 res_stream <<
" " << escape(module_type_aliases.at(
module));
293 if (
auto res = write_parameter_assignments(res_stream,
module); res.is_error())
295 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");
298 res_stream <<
" " << aliases.at(
module);
301 std::vector<std::pair<std::string, std::vector<const Net*>>> port_assignments;
305 port_assignments.push_back(std::make_pair(pin->get_name(), std::vector<const Net*>({pin->get_net()})));
308 if (
auto res = write_pin_assignments(res_stream, port_assignments, aliases); res.is_error())
310 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");
313 res_stream <<
";" << std::endl;
318 Result<std::monostate> VerilogWriter::write_parameter_assignments(std::stringstream& res_stream,
const DataContainer* container)
const
320 const std::map<std::tuple<std::string, std::string>, std::tuple<std::string, std::string>>&
data = container->get_data_map();
322 bool first_parameter =
true;
323 for (
const auto& [first, second] : data)
325 const auto& [category, key] = first;
326 const auto& [
type, value] = second;
328 if (category !=
"generic" || valid_types.find(
type) == valid_types.end())
335 res_stream <<
" #(" << std::endl;
336 first_parameter =
false;
340 res_stream <<
"," << std::endl;
343 res_stream <<
" ." << escape(key) <<
"(";
345 if (
auto res = write_parameter_value(res_stream,
type, value); res.is_error())
347 return ERR_APPEND(res.get_error(),
"could not write parameter assignments: failed to write parameter value '" + value +
"' of type '" +
type +
"'");
353 if (!first_parameter)
355 res_stream << std::endl <<
" )";
361 Result<std::monostate> VerilogWriter::write_pin_assignments(std::stringstream& res_stream,
362 const std::vector<std::pair<std::string, std::vector<const Net*>>>& pin_assignments,
363 std::unordered_map<const DataContainer*, std::string>& aliases)
const
365 static u32 unused_signal_counter = 0;
367 res_stream <<
" (" << std::endl;
368 bool first_pin =
true;
369 for (
const auto& [pin, nets] : pin_assignments)
377 res_stream <<
"," << std::endl;
380 res_stream <<
" ." << escape(pin) <<
"(";
383 res_stream <<
"{" << std::endl <<
" ";
386 bool first_net =
true;
387 for (
auto it = nets.begin(); it != nets.end(); it++)
393 res_stream <<
"," << std::endl <<
" ";
399 if (
const auto alias_it = aliases.find(
net); alias_it != aliases.end())
401 res_stream << alias_it->second;
405 return ERR(
"could not write pin assignments: no alias for net '" +
net->get_name() +
"' with ID " + std::to_string(
net->get_id()) +
" found");
411 res_stream <<
"HAL_UNUSED_SIGNAL_" + std::to_string(unused_signal_counter++);
417 res_stream << std::endl <<
" }";
423 res_stream << std::endl <<
" )";
428 Result<std::monostate> VerilogWriter::write_parameter_value(std::stringstream& res_stream,
const std::string&
type,
const std::string& value)
const
430 if (
type ==
"string")
432 res_stream <<
"\"" << value <<
"\"";
434 else if (
type ==
"integer" ||
type ==
"floating_point")
438 else if (
type ==
"bit_value")
440 res_stream <<
"1'b" << value;
442 else if (
type ==
"bit_vector")
444 u32 len = value.size() * 4;
457 res_stream << len <<
"'h" << value;
459 else if (
type ==
"bit_string")
461 u32 len = value.size();
474 res_stream << len <<
"'b" << value;
478 return ERR(
"could not write parameter value '" + value +
"' of type '" +
type +
"': invalid type");
484 std::string VerilogWriter::get_unique_alias(std::unordered_map<std::string, u32>& name_occurrences,
const std::string&
name)
const
486 name_occurrences[
name]++;
489 if (name_occurrences[
name] < 2)
495 return name +
"__[" + std::to_string(name_occurrences[
name]) +
"]__";
498 std::string VerilogWriter::escape(
const std::string& s)
const
505 const char first = s.at(0);
506 if (!(first >=
'a' && first <=
'z') && !(first >=
'A' && first <=
'Z') && first !=
'_')
508 return "\\" + s +
" ";
510 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 !=
'$'); }))
512 return "\\" + s +
" ";
then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file
const std::map< std::tuple< std::string, std::string >, std::tuple< std::string, std::string > > & get_data_map() 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::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)