diff --git a/passes/cmds/icell_liberty.cc b/passes/cmds/icell_liberty.cc index 19692fa01..9b89c1125 100644 --- a/passes/cmds/icell_liberty.cc +++ b/passes/cmds/icell_liberty.cc @@ -18,19 +18,27 @@ */ #include "kernel/yosys.h" #include "kernel/celltypes.h" +#include "kernel/ff.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct LibertyStubber { CellTypes ct; - CellTypes ct_ff; LibertyStubber() { ct.setup(); ct.setup_internals_ff(); } void liberty_prefix(std::ostream& f) { + f << "/*\n"; + f << stringf("Models interfaces of select Yosys internal cell.\n"); + f << stringf("Likely contains INCORRECT POLARITIES.\n"); + f << stringf("Impractical for any simulation, synthesis, or timing.\n"); + f << stringf("Intended purely for SDC expansion.\n"); + f << stringf("Do not microwave or tumble dry.\n"); + f << stringf("Generated by %s\n", yosys_maybe_version()); + f << "*/\n"; f << "library (yosys) {\n"; f << "\tinput_threshold_pct_fall : 50;\n"; f << "\tinput_threshold_pct_rise : 50;\n"; @@ -45,6 +53,76 @@ struct LibertyStubber { { f << "}\n"; } + struct LibertyItemizer { + std::ostream& f; + int indent; + LibertyItemizer(std::ostream& f) : f(f), indent(0) {}; + void item(std::string key, std::string val) + { + f << std::string(indent, '\t') << key << " : \"" << val << "\";\n"; + } + }; + void liberty_flop(Module* base, Module* derived, std::ostream& f) + { + auto base_name = base->name.str().substr(1); + auto derived_name = derived->name.str().substr(1); + + FfTypeData ffType(base_name); + LibertyItemizer i(f); + + if (ffType.has_gclk) { + log_warning("Formal flip flop %s can't be modeled\n", base_name.c_str()); + return; + } + if (ffType.has_ce) { + log_warning("DFFE %s can't be modeled\n", base_name.c_str()); + return; + } + + f << "\tcell (\"" << derived_name << "\") {\n"; + auto& base_type = ct.cell_types[base_name]; + i.indent = 3; + for (auto x : derived->ports) { + bool is_input = base_type.inputs.count(x); + bool is_output = base_type.outputs.count(x); + f << "\t\tpin (" << RTLIL::unescape_id(x.str()) << ") {\n"; + if (is_input && !is_output) { + i.item("direction", "input"); + } else if (!is_input && is_output) { + i.item("direction", "output"); + } else { + i.item("direction", "inout"); + } + if (RTLIL::unescape_id(x) == "CLK" || RTLIL::unescape_id(x) == "C") + i.item("clock", "true"); + if (RTLIL::unescape_id(x) == "Q") + i.item("function", "IQ"); + f << "\t\t}\n"; + } + + f << "\t\tff (\"IQ\",\"IQ_N\") {\n"; + i.indent = 3; + // TODO polarities? + if (ffType.has_clk) { + auto pin = ffType.is_fine ? "C" : "CLK"; + i.item("clocked_on", pin); + } + if (ffType.has_arst) { + auto meaning = (ffType.val_arst == State::S1) ? "preset" : "clear"; + auto pin = ffType.is_fine ? "R" : "ARST"; + i.item(meaning, pin); + } + auto next_state = ffType.has_ce ? "D & EN" : "D"; + i.item("next_state", next_state); + f << "\t\t}\n"; + + + // bool has_aload; + // bool has_srst; + // bool has_arst; + // bool has_sr; + f << "\t}\n"; + } void liberty_cell(Module* base, Module* derived, std::ostream& f) { auto base_name = base->name.str().substr(1); @@ -53,6 +131,10 @@ struct LibertyStubber { log_debug("skip skeleton for %s\n", base_name.c_str()); return; } + + if (RTLIL::builtin_ff_cell_types().count(base_name)) + return liberty_flop(base, derived, f); + auto& base_type = ct.cell_types[base_name]; f << "\tcell (\"" << derived_name << "\") {\n"; for (auto x : derived->ports) { @@ -73,7 +155,7 @@ struct LibertyStubber { }; struct IcellLiberty : Pass { - IcellLiberty() : Pass("icell_liberty", "derive box modules") {} + IcellLiberty() : Pass("icell_liberty", "write Liberty interfaces for used internal cells") {} void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|