Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
501 changes: 286 additions & 215 deletions kernel/ff.cc

Large diffs are not rendered by default.

78 changes: 43 additions & 35 deletions kernel/ff.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,20 @@ YOSYS_NAMESPACE_BEGIN
// - has_arst [does not correspond to a native cell, represented as dlatch with const D input]
// - empty set [not a cell — will be emitted as a simple direct connection]

struct FfData {
Module *module;
FfInitVals *initvals;
Cell *cell;
IdString name;
// The FF output.
SigSpec sig_q;
// The sync data input, present if has_clk or has_gclk.
SigSpec sig_d;
// The async data input, present if has_aload.
SigSpec sig_ad;
// The sync clock, present if has_clk.
SigSpec sig_clk;
// The clock enable, present if has_ce.
SigSpec sig_ce;
// The async load enable, present if has_aload.
SigSpec sig_aload;
// The async reset, preset if has_arst.
SigSpec sig_arst;
// The sync reset, preset if has_srst.
SigSpec sig_srst;
// The async clear (per-lane), present if has_sr.
SigSpec sig_clr;
// The async set (per-lane), present if has_sr.
SigSpec sig_set;
struct FfTypeData {
FfTypeData(IdString type);
FfTypeData() {
has_clk = false;
has_gclk = false;
has_ce = false;
has_aload = false;
has_srst = false;
has_arst = false;
has_sr = false;
ce_over_srst = false;
is_fine = false;
is_anyinit = false;
}
// True if this is a clocked (edge-sensitive) flip-flop.
bool has_clk;
// True if this is a $ff, exclusive with every other has_*.
Expand Down Expand Up @@ -143,9 +132,38 @@ struct FfData {
bool pol_clr;
bool pol_set;
// The value loaded by sig_arst.
// Zero length if unknowable from just type
Const val_arst;
// The value loaded by sig_srst.
// Zero length if unknowable from just type
Const val_srst;
};

struct FfData : FfTypeData {
Module *module;
FfInitVals *initvals;
Cell *cell;
IdString name;
// The FF output.
SigSpec sig_q;
// The sync data input, present if has_clk or has_gclk.
SigSpec sig_d;
// The async data input, present if has_aload.
SigSpec sig_ad;
// The sync clock, present if has_clk.
SigSpec sig_clk;
// The clock enable, present if has_ce.
SigSpec sig_ce;
// The async load enable, present if has_aload.
SigSpec sig_aload;
// The async reset, preset if has_arst.
SigSpec sig_arst;
// The sync reset, preset if has_srst.
SigSpec sig_srst;
// The async clear (per-lane), present if has_sr.
SigSpec sig_clr;
// The async set (per-lane), present if has_sr.
SigSpec sig_set;
// The initial value at power-up.
Const val_init;
// The FF data width in bits.
Expand All @@ -154,16 +172,6 @@ struct FfData {

FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) {
width = 0;
has_clk = false;
has_gclk = false;
has_ce = false;
has_aload = false;
has_srst = false;
has_arst = false;
has_sr = false;
ce_over_srst = false;
is_fine = false;
is_anyinit = false;
pol_clk = false;
pol_aload = false;
pol_ce = false;
Expand Down
1 change: 0 additions & 1 deletion kernel/rtlil.h
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,6 @@
namespace RTLIL {
extern dict<std::string, std::string> constpad;

[[deprecated("Call cell->is_builtin_ff() instead")]]
Copy link
Collaborator

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?

Copy link
Collaborator Author

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

Copy link
Collaborator Author

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_liberty I call this on type IdStrings for cells I don't have instantiated in any design, and Cell::is_builtin_ff looks at the type member so it's not static

const pool<IdString> &builtin_ff_cell_types();

static inline std::string escape_id(const std::string &str) {
Expand Down Expand Up @@ -1272,7 +1271,7 @@
RTLIL::IdString name;
};

struct RTLIL::SigChunk

Check warning on line 1274 in kernel/rtlil.h

View workflow job for this annotation

GitHub Actions / test-compile (ubuntu-latest, gcc-14)

‘((__vector(2) int*)((char*)&<unnamed> + offsetof(Yosys::RTLIL::SigSpec, Yosys::RTLIL::SigSpec::<unnamed>)))[4]’ may be used uninitialized [-Wmaybe-uninitialized]

Check warning on line 1274 in kernel/rtlil.h

View workflow job for this annotation

GitHub Actions / test-compile (ubuntu-latest, gcc-14)

‘((__vector(2) int*)((char*)&<unnamed> + offsetof(Yosys::RTLIL::SigSpec, Yosys::RTLIL::SigSpec::<unnamed>)))[4]’ may be used uninitialized [-Wmaybe-uninitialized]

Check warning on line 1274 in kernel/rtlil.h

View workflow job for this annotation

GitHub Actions / test-compile (ubuntu-latest, gcc-14)

‘((__vector(2) int*)((char*)&<unnamed> + offsetof(Yosys::RTLIL::SigSpec, Yosys::RTLIL::SigSpec::<unnamed>)))[4]’ may be used uninitialized [-Wmaybe-uninitialized]
{
RTLIL::Wire *wire;
std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
Expand Down
1 change: 1 addition & 0 deletions passes/cmds/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,4 @@ OBJS += passes/cmds/test_select.o
OBJS += passes/cmds/timeest.o
OBJS += passes/cmds/linecoverage.o
OBJS += passes/cmds/sort.o
OBJS += passes/cmds/icell_liberty.o
207 changes: 207 additions & 0 deletions passes/cmds/icell_liberty.cc
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 {
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

View workflow job for this annotation

GitHub Actions / test-compile (ubuntu-latest, clang-10)

unused variable 'naming_attr' [-Wunused-variable]

Check warning on line 166 in passes/cmds/icell_liberty.cc

View workflow job for this annotation

GitHub Actions / test-compile (ubuntu-latest, clang-19)

unused variable 'naming_attr' [-Wunused-variable]

Check warning on line 166 in passes/cmds/icell_liberty.cc

View workflow job for this annotation

GitHub Actions / test-compile (macos-latest, clang-19)

unused variable 'naming_attr' [-Wunused-variable]

Check warning on line 166 in passes/cmds/icell_liberty.cc

View workflow job for this annotation

GitHub Actions / test-compile (macos-15-intel, clang-19)

unused variable 'naming_attr' [-Wunused-variable]
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
2 changes: 2 additions & 0 deletions techlibs/common/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
ifneq ($(SMALL),1)
OBJS += techlibs/common/synth.o
OBJS += techlibs/common/prep.o
OBJS += techlibs/common/opensta.o
OBJS += techlibs/common/sdc_expand.o
endif

GENFILES += techlibs/common/simlib_help.inc
Expand Down
Loading
Loading