-
Notifications
You must be signed in to change notification settings - Fork 1k
SDC expansion with OpenSTA #5237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
225a45c
aec8c98
764ccc8
9437941
c9ef434
f284751
36c30dc
8993ba2
f027cfb
b2ed772
8179ba1
8f17822
ab03d33
838732e
526c5e9
3651eec
db6d50e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,207 @@ | ||
| #include "kernel/yosys.h" | ||
| #include "kernel/celltypes.h" | ||
| #include "kernel/ff.h" | ||
|
|
||
| USING_YOSYS_NAMESPACE | ||
| PRIVATE_NAMESPACE_BEGIN | ||
|
|
||
| struct LibertyStubber { | ||
| CellTypes ct; | ||
| LibertyStubber() { | ||
| ct.setup(); | ||
| ct.setup_internals_ff(); | ||
| } | ||
| void liberty_prefix(std::ostream& f) | ||
| { | ||
| f << "/*\n"; | ||
| f << stringf("\tModels interfaces of select Yosys internal cell.\n"); | ||
| f << stringf("\tLikely contains INCORRECT POLARITIES.\n"); | ||
| f << stringf("\tImpractical for any simulation, synthesis, or timing.\n"); | ||
| f << stringf("\tIntended purely for SDC expansion.\n"); | ||
| f << stringf("\tDo not microwave or tumble dry.\n"); | ||
| f << stringf("\tGenerated 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"; | ||
| f << "\toutput_threshold_pct_fall : 50;\n"; | ||
| f << "\toutput_threshold_pct_rise : 50;\n"; | ||
| f << "\tslew_lower_threshold_pct_fall : 1;\n"; | ||
| f << "\tslew_lower_threshold_pct_rise : 1;\n"; | ||
| f << "\tslew_upper_threshold_pct_fall : 99;\n"; | ||
| f << "\tslew_upper_threshold_pct_rise : 99;\n"; | ||
| } | ||
| void liberty_suffix(std::ostream& f) | ||
| { | ||
| 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; | ||
| auto sorted_ports = derived->ports; | ||
| // Hack for CLK and C coming before Q does | ||
| auto cmp = [](IdString l, IdString r) { return l.str() < r.str(); }; | ||
| std::sort(sorted_ports.begin(), sorted_ports.end(), cmp); | ||
| std::string clock_pin_name = ""; | ||
| for (auto x : sorted_ports) { | ||
| std::string port_name = RTLIL::unescape_id(x); | ||
| 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 (port_name == "CLK" || port_name == "C") { | ||
| i.item("clock", "true"); | ||
| clock_pin_name = port_name; | ||
| } | ||
| if (port_name == "Q") { | ||
| i.item("function", "IQ"); | ||
| f << "\t\t\ttiming () {\n"; | ||
| i.indent++; | ||
| log_assert(clock_pin_name.size()); | ||
| i.item("related_pin", clock_pin_name); | ||
| i.indent--; | ||
| f << "\t\t\t}\n"; | ||
| } | ||
| 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"; | ||
| f << "\t}\n"; | ||
| } | ||
| void liberty_cell(Module* base, Module* derived, std::ostream& f) | ||
| { | ||
| auto base_name = base->name.str().substr(1); | ||
| auto derived_name = derived->name.str().substr(1); | ||
| if (!ct.cell_types.count(base_name)) { | ||
| 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) { | ||
| 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) { | ||
| f << "\t\t\tdirection : input;\n"; | ||
| } else if (!is_input && is_output) { | ||
| f << "\t\t\tdirection : output;\n"; | ||
| } else { | ||
| f << "\t\t\tdirection : inout;\n"; | ||
| } | ||
| f << "\t\t}\n"; | ||
| } | ||
| f << "\t}\n"; | ||
| } | ||
| }; | ||
|
|
||
| struct IcellLiberty : Pass { | ||
widlarizer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| IcellLiberty() : Pass("icell_liberty", "write Liberty interfaces for used internal cells") {} | ||
| void help() override | ||
| { | ||
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | ||
| log("\n"); | ||
| log(" icell_liberty <liberty_file>\n"); | ||
| log("\n"); | ||
| log("Write Liberty files modeling the interfaces of used internal cells.\n"); | ||
| log("\n"); | ||
| log("Models are not guaranteed to be logically sound.\n"); | ||
| log("\n"); | ||
| } | ||
| void execute(std::vector<std::string> args, RTLIL::Design *d) override | ||
| { | ||
| log_header(d, "Executing ICELL_LIBERTY pass.\n"); | ||
|
|
||
| size_t argidx; | ||
| IdString naming_attr; | ||
|
Check warning on line 166 in passes/cmds/icell_liberty.cc
|
||
| std::string liberty_filename; | ||
| auto liberty_file = std::make_unique<std::ofstream>(); | ||
|
|
||
| for (argidx = 1; argidx < args.size(); argidx++) { | ||
| break; | ||
| } | ||
| if (argidx < args.size()) | ||
| liberty_filename = args[argidx++]; | ||
| else | ||
| log_cmd_error("no Liberty filename specified\n"); | ||
|
|
||
| if (liberty_filename.size()) { | ||
| liberty_file->open(liberty_filename.c_str()); | ||
| if (liberty_file->fail()) { | ||
| log_cmd_error("Can't open file `%s' for writing: %s\n", liberty_filename.c_str(), strerror(errno)); | ||
| } | ||
| } | ||
|
|
||
| pool<RTLIL::IdString> done; | ||
| LibertyStubber stubber = {}; | ||
|
|
||
| stubber.liberty_prefix(*liberty_file); | ||
|
|
||
| for (auto module : d->selected_modules()) { | ||
| for (auto cell : module->selected_cells()) { | ||
| Module *inst_module = d->module(cell->type); | ||
| if (!inst_module || !inst_module->get_blackbox_attribute()) | ||
| continue; | ||
| Module *base = inst_module; | ||
| if (!done.count(base->name)) { | ||
| stubber.liberty_cell(base, base, *liberty_file); | ||
| done.insert(base->name); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| stubber.liberty_suffix(*liberty_file); | ||
| } | ||
| } IcellLiberty; | ||
|
|
||
| PRIVATE_NAMESPACE_END | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask why this is being un-deprecated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is left over from having changed the function entirely for some reason but apparently I no longer needed it afterwards
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, no, I do need this undeprecated. I need a function that takes the name. In
icell_libertyI call this on type IdStrings for cells I don't have instantiated in any design, andCell::is_builtin_fflooks at the type member so it's not static