-
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
Changes from all commits
b3ead7e
9e81db4
c2c9506
e4e32d7
bbf1e4b
0c4105d
7bed6ec
793594b
7bc88d5
9f07e21
cee3d0b
5acb77c
6846168
9a5465b
a5b6c3c
411fc14
85d2702
1edc32d
2eff366
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