3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-24 17:45:33 +00:00

Merge remote-tracking branch 'origin/master' into xc7mux

This commit is contained in:
Eddie Hung 2019-05-21 14:21:00 -07:00
commit fb09c6219b
56 changed files with 1811 additions and 487 deletions

View file

@ -281,6 +281,9 @@ struct BugpointPass : public Pass {
}
extra_args(args, argidx, design);
if (script.empty())
log_cmd_error("Missing -script option.\n");
if (!has_part)
{
modules = true;
@ -298,7 +301,7 @@ struct BugpointPass : public Pass {
if (!check_logfile(grep))
log_cmd_error("The provided grep string is not found in the log file!\n");
int seed = 0, crashing_seed = seed;
int seed = 0;
bool found_something = false, stage2 = false;
while (true)
{
@ -324,7 +327,6 @@ struct BugpointPass : public Pass {
if (crashing_design != design)
delete crashing_design;
crashing_design = simplified;
crashing_seed = seed;
found_something = true;
}
else

View file

@ -98,21 +98,23 @@ struct CoverPass : public Pass {
}
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
std::string filename = args[++argidx];
const std::string &filename = args[++argidx];
FILE *f = nullptr;
if (args[argidx-1] == "-d") {
#ifdef _WIN32
log_cmd_error("The 'cover -d' option is not supported on win32.\n");
#else
char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
filename = mkstemps(filename_buffer, 4);
f = fdopen(mkstemps(filename_buffer, 4), "w");
#endif
} else {
f = fopen(filename.c_str(), open_mode);
}
FILE *f = fopen(filename.c_str(), open_mode);
if (f == NULL) {
for (auto f : out_files)
fclose(f);
log_cmd_error("Can't create file %s.\n", args[argidx].c_str());
log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str());
}
out_files.push_back(f);
continue;

View file

@ -37,7 +37,9 @@ struct statdata_t
STAT_INT_MEMBERS
#undef X
double area;
string tech;
std::map<RTLIL::IdString, int> techinfo;
std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
std::set<RTLIL::IdString> unknown_cell_area;
@ -70,8 +72,10 @@ struct statdata_t
#undef X
}
statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area)
statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname)
{
tech = techname;
#define X(_name) _name = 0;
STAT_NUMERIC_MEMBERS
#undef X
@ -153,7 +157,8 @@ struct statdata_t
log(" Number of processes: %6d\n", num_processes);
log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type)
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
if (it.second)
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
if (!unknown_cell_area.empty()) {
log("\n");
@ -165,6 +170,59 @@ struct statdata_t
log("\n");
log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
}
if (tech == "xilinx")
{
int lut6_cnt = num_cells_by_type["\\LUT6"];
int lut5_cnt = num_cells_by_type["\\LUT5"];
int lut4_cnt = num_cells_by_type["\\LUT4"];
int lut3_cnt = num_cells_by_type["\\LUT3"];
int lut2_cnt = num_cells_by_type["\\LUT2"];
int lut1_cnt = num_cells_by_type["\\LUT1"];
int lc_cnt = 0;
lc_cnt += lut6_cnt;
lc_cnt += lut5_cnt;
if (lut1_cnt) {
int cnt = std::min(lut5_cnt, lut1_cnt);
lut5_cnt -= cnt;
lut1_cnt -= cnt;
}
lc_cnt += lut4_cnt;
if (lut1_cnt) {
int cnt = std::min(lut4_cnt, lut1_cnt);
lut4_cnt -= cnt;
lut1_cnt -= cnt;
}
if (lut2_cnt) {
int cnt = std::min(lut4_cnt, lut2_cnt);
lut4_cnt -= cnt;
lut2_cnt -= cnt;
}
lc_cnt += lut3_cnt;
if (lut1_cnt) {
int cnt = std::min(lut3_cnt, lut1_cnt);
lut3_cnt -= cnt;
lut1_cnt -= cnt;
}
if (lut2_cnt) {
int cnt = std::min(lut3_cnt, lut2_cnt);
lut3_cnt -= cnt;
lut2_cnt -= cnt;
}
if (lut3_cnt) {
int cnt = (lut3_cnt + 1) / 2;
lut3_cnt -= cnt;
}
lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2;
log("\n");
log(" Estimated number of LCs: %10d\n", lc_cnt);
}
}
};
@ -226,6 +284,10 @@ struct StatPass : public Pass {
log(" -liberty <liberty_file>\n");
log(" use cell area information from the provided liberty file\n");
log("\n");
log(" -tech <technology>\n");
log(" print area estemate for the specified technology. Corrently supported\n");
log(" calues for <technology>: xilinx\n");
log("\n");
log(" -width\n");
log(" annotate internal cell types with their word width.\n");
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
@ -239,6 +301,7 @@ struct StatPass : public Pass {
RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, double> cell_area;
string techname;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@ -253,6 +316,10 @@ struct StatPass : public Pass {
read_liberty_cellarea(cell_area, liberty_file);
continue;
}
if (args[argidx] == "-tech" && argidx+1 < args.size()) {
techname = args[++argidx];
continue;
}
if (args[argidx] == "-top" && argidx+1 < args.size()) {
if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
@ -263,6 +330,9 @@ struct StatPass : public Pass {
}
extra_args(args, argidx, design);
if (techname != "" && techname != "xilinx")
log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
for (auto mod : design->selected_modules())
{
if (!top_mod && design->full_selection())
@ -272,7 +342,7 @@ struct StatPass : public Pass {
if (mod->attributes.count("\\abc_box_id"))
continue;
statdata_t data(design, mod, width_mode, cell_area);
statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data;
log("\n");

View file

@ -570,7 +570,7 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -simcheck\n");
log(" like -check, but also throw an error if blackbox modules are\n");
log(" instantiated, and throw an error if the design has no top module\n");
log(" instantiated, and throw an error if the design has no top module.\n");
log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
@ -583,20 +583,20 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -keep_positionals\n");
log(" per default this pass also converts positional arguments in cells\n");
log(" to arguments using port names. this option disables this behavior.\n");
log(" to arguments using port names. This option disables this behavior.\n");
log("\n");
log(" -keep_portwidths\n");
log(" per default this pass adjusts the port width on cells that are\n");
log(" module instances when the width does not match the module port. this\n");
log(" module instances when the width does not match the module port. This\n");
log(" option disables this behavior.\n");
log("\n");
log(" -nokeep_asserts\n");
log(" per default this pass sets the \"keep\" attribute on all modules\n");
log(" that directly or indirectly contain one or more $assert cells. this\n");
log(" option disables this behavior.\n");
log(" that directly or indirectly contain one or more formal properties.\n");
log(" This option disables this behavior.\n");
log("\n");
log(" -top <module>\n");
log(" use the specified top module to built a design hierarchy. modules\n");
log(" use the specified top module to build the design hierarchy. Modules\n");
log(" outside this tree (unused modules) are removed.\n");
log("\n");
log(" when the -top option is used, the 'top' attribute will be set on the\n");
@ -606,6 +606,12 @@ struct HierarchyPass : public Pass {
log(" -auto-top\n");
log(" automatically determine the top of the design hierarchy and mark it.\n");
log("\n");
log(" -chparam name value \n");
log(" elaborate the top module using this parameter value. Modules on which\n");
log(" this parameter does not exist may cause a warning message to be output.\n");
log(" This option can be specified multiple times to override multiple\n");
log(" parameters. String values must be passed in double quotes (\").\n");
log("\n");
log("In -generate mode this pass generates blackbox modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n");
@ -641,6 +647,7 @@ struct HierarchyPass : public Pass {
bool nokeep_asserts = false;
std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports;
std::map<std::string, std::string> parameters;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@ -715,28 +722,61 @@ struct HierarchyPass : public Pass {
if (args[argidx] == "-top") {
if (++argidx >= args.size())
log_cmd_error("Option -top requires an additional argument!\n");
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
if (top_mod == NULL)
load_top_mod = args[argidx];
load_top_mod = args[argidx];
continue;
}
if (args[argidx] == "-auto-top") {
auto_top_mode = true;
continue;
}
if (args[argidx] == "-chparam" && argidx+2 < args.size()) {
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
auto r = parameters.emplace(key, value);
if (!r.second) {
log_warning("-chparam %s already specified: overwriting.\n", key.c_str());
r.first->second = value;
}
continue;
}
break;
}
extra_args(args, argidx, design, false);
if (!load_top_mod.empty()) {
if (!load_top_mod.empty())
{
IdString top_name = RTLIL::escape_id(load_top_mod);
IdString abstract_id = "$abstract" + RTLIL::escape_id(load_top_mod);
top_mod = design->module(top_name);
dict<RTLIL::IdString, RTLIL::Const> top_parameters;
for (auto &para : parameters) {
SigSpec sig_value;
if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
}
if (top_mod == nullptr && design->module(abstract_id))
top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters));
else if (top_mod != nullptr && !top_parameters.empty())
top_mod = design->module(top_mod->derive(design, top_parameters));
if (top_mod != nullptr && top_mod->name != top_name) {
Module *m = top_mod->clone();
m->name = top_name;
Module *old_mod = design->module(top_name);
if (old_mod)
design->remove(old_mod);
design->add(m);
top_mod = m;
}
}
if (top_mod == nullptr && !load_top_mod.empty()) {
#ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending) {
verific_import(design, load_top_mod);
verific_import(design, parameters, load_top_mod);
top_mod = design->module(RTLIL::escape_id(load_top_mod));
}
#endif
@ -745,7 +785,7 @@ struct HierarchyPass : public Pass {
} else {
#ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending)
verific_import(design);
verific_import(design, parameters);
#endif
}
@ -846,7 +886,7 @@ struct HierarchyPass : public Pass {
std::map<RTLIL::Module*, bool> cache;
for (auto mod : design->modules())
if (set_keep_assert(cache, mod)) {
log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod));
mod->set_bool_attribute("\\keep");
}
}

View file

@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell)
{
if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover"))
if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
return true;
if (cell->has_keep_attr())
@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose)
{
SigMap sigmap(module);
pool<Cell*> queue, unused;
pool<SigBit> used_raw_bits;
dict<SigBit, pool<Cell*>> wire2driver;
dict<SigBit, vector<string>> driver_driver_logs;
SigMap raw_sigmap;
for (auto &it : module->connections_) {
for (int i = 0; i < GetSize(it.second); i++) {
if (it.second[i].wire != nullptr)
raw_sigmap.add(it.first[i], it.second[i]);
}
}
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
for (auto raw_bit : it2.second) {
if (raw_bit.wire == nullptr)
continue;
auto bit = sigmap(raw_bit);
if (bit.wire == nullptr)
log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
}
if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
continue;
for (auto raw_bit : it2.second) {
if (raw_bit.wire == nullptr)
continue;
auto bit = sigmap(raw_bit);
if (bit.wire == nullptr)
driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
"for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
}
}
if (keep_cache.query(cell))
queue.insert(cell);
@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto bit : sigmap(wire))
for (auto c : wire2driver[bit])
queue.insert(c), unused.erase(c);
for (auto raw_bit : SigSpec(wire))
used_raw_bits.insert(raw_sigmap(raw_bit));
}
}
@ -142,6 +156,22 @@ void rmunused_module_cells(Module *module, bool verbose)
module->remove(cell);
count_rm_cells++;
}
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
continue;
for (auto raw_bit : raw_sigmap(it2.second))
used_raw_bits.insert(raw_bit);
}
}
for (auto it : driver_driver_logs) {
if (used_raw_bits.count(it.first))
for (auto msg : it.second)
log_warning("%s\n", msg.c_str());
}
}
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
@ -202,7 +232,7 @@ bool check_public_name(RTLIL::IdString id)
return true;
}
void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
{
SigPool register_signals;
SigPool connected_signals;
@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
module->connections_.clear();
SigPool used_signals;
SigPool raw_used_signals;
SigPool used_signals_nodrivers;
for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second);
raw_used_signals.add(it2.second);
used_signals.add(it2.second);
if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
@ -259,6 +291,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
raw_used_signals.add(sig);
assign_map.apply(sig);
used_signals.add(sig);
if (!wire->port_input)
@ -271,85 +304,102 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
}
}
std::vector<RTLIL::Wire*> maybe_del_wires;
pool<RTLIL::Wire*> del_wires_queue;
for (auto wire : module->wires())
{
if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) {
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
assign_map.apply(s2);
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
maybe_del_wires.push_back(wire);
} else {
log_assert(GetSize(s1) == GetSize(s2));
Const initval;
if (wire->attributes.count("\\init"))
initval = wire->attributes.at("\\init");
if (GetSize(initval) != GetSize(wire))
initval.bits.resize(GetSize(wire), State::Sx);
RTLIL::SigSig new_conn;
for (int i = 0; i < GetSize(s1); i++)
if (s1[i] != s2[i]) {
if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
s2[i] = initval[i];
initval[i] = State::Sx;
}
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
}
if (new_conn.first.size() > 0) {
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
else
wire->attributes.at("\\init") = initval;
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
module->connect(new_conn);
}
}
} else {
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
maybe_del_wires.push_back(wire);
SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
log_assert(GetSize(s1) == GetSize(s2));
Const initval;
if (wire->attributes.count("\\init"))
initval = wire->attributes.at("\\init");
if (GetSize(initval) != GetSize(wire))
initval.bits.resize(GetSize(wire), State::Sx);
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
if (GetSize(wire) == 0) {
// delete zero-width wires
goto delete_this_wire;
} else
if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
// do not delete anything with "keep" or module ports or initialized wires
} else
if (!purge_mode && check_public_name(wire->name)) {
// do not get rid of public names unless in purge mode
} else
if (!raw_used_signals.check_any(s1)) {
// delete wires that aren't used by anything directly
goto delete_this_wire;
} else
if (!used_signals.check_any(s2)) {
// delete wires that aren't used by anything indirectly, even though other wires may alias it
goto delete_this_wire;
}
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
if (!used_signals_nodrivers.check_any(sig)) {
std::string unused_bits;
for (int i = 0; i < GetSize(sig); i++) {
if (sig[i].wire == NULL)
continue;
if (!used_signals_nodrivers.check(sig[i])) {
if (!unused_bits.empty())
unused_bits += " ";
unused_bits += stringf("%d", i);
if (0)
{
delete_this_wire:
del_wires_queue.insert(wire);
}
else
{
RTLIL::SigSig new_conn;
for (int i = 0; i < GetSize(s1); i++)
if (s1[i] != s2[i]) {
if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
s2[i] = initval[i];
initval[i] = State::Sx;
}
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
}
if (new_conn.first.size() > 0) {
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
else
wire->attributes.at("\\init") = initval;
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
module->connect(new_conn);
}
if (unused_bits.empty() || wire->port_id != 0)
if (!used_signals_nodrivers.check_all(s2)) {
std::string unused_bits;
for (int i = 0; i < GetSize(s2); i++) {
if (s2[i].wire == NULL)
continue;
if (!used_signals_nodrivers.check(s2[i])) {
if (!unused_bits.empty())
unused_bits += " ";
unused_bits += stringf("%d", i);
}
}
if (unused_bits.empty() || wire->port_id != 0)
wire->attributes.erase("\\unused_bits");
else
wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
} else {
wire->attributes.erase("\\unused_bits");
else
wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
} else {
wire->attributes.erase("\\unused_bits");
}
}
}
int del_temp_wires_count = 0;
for (auto wire : del_wires_queue) {
if (ys_debug() || (check_public_name(wire->name) && verbose))
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
else
del_temp_wires_count++;
}
pool<RTLIL::Wire*> del_wires;
module->remove(del_wires_queue);
count_rm_wires += GetSize(del_wires_queue);
int del_wires_count = 0;
for (auto wire : maybe_del_wires)
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
}
del_wires.insert(wire);
del_wires_count++;
}
if (verbose && del_temp_wires_count)
log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
module->remove(del_wires);
count_rm_wires += del_wires.size();
if (verbose && del_wires_count > 0)
log_debug(" removed %d unused temporary wires.\n", del_wires_count);
return !del_wires_queue.empty();
}
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@ -447,10 +497,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
module->design->scratchpad_set_bool("opt.did_something", true);
rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose);
while (rmunused_module_signals(module, purge_mode, verbose)) { }
if (rminit && rmunused_module_init(module, purge_mode, verbose))
rmunused_module_signals(module, purge_mode, verbose);
while (rmunused_module_signals(module, purge_mode, verbose)) { }
}
struct OptCleanPass : public Pass {
@ -496,6 +546,9 @@ struct OptCleanPass : public Pass {
ct_all.setup(design);
count_rm_cells = 0;
count_rm_wires = 0;
for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn())
continue;
@ -561,7 +614,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) {
if (module->has_processes())
continue;
rmunused_module(module, purge_mode, false, false);
rmunused_module(module, purge_mode, ys_debug(), false);
}
log_suppressed();

View file

@ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
if (wire->port_input)
driven_signals.add(sigmap(wire));
if (wire->port_output)
if (wire->port_output || wire->get_bool_attribute("\\keep"))
used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire));
}
@ -88,7 +88,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
}
log_debug("Setting undriven signal in %s to constant: %s = %s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(val));
log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val));
module->connect(sig, val);
did_something = true;
}
@ -104,10 +104,15 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (SigBit(initval[i]) == sig[i])
initval[i] = State::Sx;
}
if (initval.is_fully_undef())
if (initval.is_fully_undef()) {
log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
wire->attributes.erase("\\init");
else
did_something = true;
} else if (initval != wire->attributes.at("\\init")) {
log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
wire->attributes["\\init"] = initval;
did_something = true;
}
}
}
}

View file

@ -184,6 +184,10 @@ struct OptMuxtreeWorker
log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
return;
}
}
while (!root_mux_rerun.empty()) {
@ -192,9 +196,14 @@ struct OptMuxtreeWorker
log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
return;
}
}
log(" Analyzing evaluation results.\n");
log_assert(glob_abort_cnt > 0);
for (auto &mi : mux2info)
{
@ -397,10 +406,8 @@ struct OptMuxtreeWorker
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
if (glob_abort_cnt == 0)
return;
}
glob_abort_cnt--;
muxinfo_t &muxinfo = mux2info[mux_idx];
@ -454,6 +461,7 @@ struct OptMuxtreeWorker
void eval_root_mux(int mux_idx)
{
log_assert(glob_abort_cnt > 0);
knowledge_t knowledge;
knowledge.known_inactive.resize(GetSize(bit2info));
knowledge.known_active.resize(GetSize(bit2info));

View file

@ -29,19 +29,25 @@ up in any future matches:
pm.blacklist(some_cell);
The `.run(callback_function)` method searches for all matches and calls the
callback function for each found match:
The `.run_<pattern_name>(callback_function)` method searches for all matches
for the pattern`<pattern_name>` and calls the callback function for each found
match:
pm.run([&](){
pm.run_foobar([&](){
log("found matching 'foo' cell: %s\n", log_id(pm.st.foo));
log(" with 'bar' cell: %s\n", log_id(pm.st.bar));
});
The `.pmg` file declares matcher state variables that are accessible via the
`.st.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.)
`.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is
of type `foobar_pm::state_<pattern_name>_t`.)
Similarly the `.pmg` file declares user data variables that become members of
`.ud`, a struct of type `foobar_pm::udata_t`.
`.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`.
There are four versions of the `run_<pattern_name>()` method: Without callback,
callback without arguments, callback with reference to `pm`, and callback with
reference to `pm.st_<pattern_name>`.
The .pmg File Format
@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens.
Lines in `.pmg` files starting with `//` are comments.
Declaring a pattern
-------------------
A `.pmg` file contains one or more patterns. Each pattern starts with a line
with the `pattern` keyword followed by the name of the pattern.
Declaring state variables
-------------------------
@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith
and saved and restored as needed.
They are automatically initialized to the default constructed value of their type
when `.run(callback_function)` is called.
when `.run_<pattern_name>(callback_function)` is called.
Declaring udata variables
-------------------------

View file

@ -40,7 +40,7 @@ struct PeepoptPass : public Pass {
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PEEOPOPT pass (run peephole optimizers).\n");
log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)

View file

@ -8,9 +8,13 @@ endmatch
code shamt
shamt = port(shift, \B);
if (shamt.empty())
reject;
if (shamt[GetSize(shamt)-1] == State::S0) {
do {
shamt.remove(GetSize(shamt)-1);
if (shamt.empty())
reject;
} while (shamt[GetSize(shamt)-1] == State::S0);
} else
if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) {

View file

@ -508,7 +508,7 @@ struct ExposePass : public Pass {
}
for (auto &conn : module->connections_)
conn.first = out_to_in_map(sigmap(conn.first));
conn.first = out_to_in_map(conn.first);
}
if (flag_cut)

View file

@ -26,6 +26,8 @@ PRIVATE_NAMESPACE_BEGIN
struct opts_t
{
bool initeq = false;
bool anyeq = false;
bool fwd = false;
bool bwd = false;
bool nop = false;
@ -56,7 +58,7 @@ struct FmcombineWorker
return newsig;
}
void import_prim_cell(Cell *cell, const string &suffix)
Cell *import_prim_cell(Cell *cell, const string &suffix)
{
Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
c->parameters = cell->parameters;
@ -64,6 +66,8 @@ struct FmcombineWorker
for (auto &conn : cell->connections())
c->setPort(conn.first, import_sig(conn.second, suffix));
return c;
}
void import_hier_cell(Cell *cell)
@ -102,8 +106,24 @@ struct FmcombineWorker
for (auto cell : original->cells()) {
if (design->module(cell->type) == nullptr) {
import_prim_cell(cell, "_gold");
import_prim_cell(cell, "_gate");
if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) {
Cell *gold = import_prim_cell(cell, "_gold");
for (auto &conn : cell->connections())
module->connect(import_sig(conn.second, "_gate"), gold->getPort(conn.first));
} else {
Cell *gold = import_prim_cell(cell, "_gold");
Cell *gate = import_prim_cell(cell, "_gate");
if (opts.initeq) {
if (cell->type.in("$ff", "$dff", "$dffe",
"$dffsr", "$adff", "$dlatch", "$dlatchsr")) {
SigSpec gold_q = gold->getPort("\\Q");
SigSpec gate_q = gate->getPort("\\Q");
SigSpec en = module->Initstate(NEW_ID);
SigSpec eq = module->Eq(NEW_ID, gold_q, gate_q);
module->addAssume(NEW_ID, eq, en);
}
}
}
} else {
import_hier_cell(cell);
}
@ -229,6 +249,13 @@ struct FmcombinePass : public Pass {
log("This is useful for formal test benches that check what differences in behavior\n");
log("a slight difference in input causes in a module.\n");
log("\n");
log(" -initeq\n");
log(" Insert assumptions that initially all FFs in both circuits have the\n");
log(" same initial values.\n");
log("\n");
log(" -anyeq\n");
log(" Do not duplicate $anyseq/$anyconst cells.\n");
log("\n");
log(" -fwd\n");
log(" Insert forward hint assumptions into the combined module.\n");
log("\n");
@ -261,6 +288,14 @@ struct FmcombinePass : public Pass {
// filename = args[++argidx];
// continue;
// }
if (args[argidx] == "-initeq") {
opts.initeq = true;
continue;
}
if (args[argidx] == "-anyeq") {
opts.anyeq = true;
continue;
}
if (args[argidx] == "-fwd") {
opts.fwd = true;
continue;

View file

@ -330,20 +330,33 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr)
{
std::string abc_sname = abc_name.substr(1);
if (abc_sname.substr(0, 5) == "ys__n") {
bool inv = abc_sname.back() == 'v';
if (inv) abc_sname.pop_back();
bool isnew = false;
if (abc_sname.substr(0, 4) == "new_")
{
abc_sname.erase(0, 4);
isnew = true;
}
if (abc_sname.substr(0, 5) == "ys__n")
{
abc_sname.erase(0, 5);
if (abc_sname.find_last_not_of("012345689") == std::string::npos) {
if (std::isdigit(abc_sname.at(0)))
{
int sid = std::stoi(abc_sname);
for (auto sig : signal_list) {
if (sig.id == sid && sig.bit.wire != nullptr) {
size_t postfix_start = abc_sname.find_first_not_of("0123456789");
std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : "";
if (sid < GetSize(signal_list))
{
auto sig = signal_list.at(sid);
if (sig.bit.wire != nullptr)
{
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
if (sig.bit.wire->width != 1)
sstr << "[" << sig.bit.offset << "]";
if (inv)
sstr << "_inv";
if (isnew)
sstr << "_new";
sstr << postfix;
if (orig_wire != nullptr)
*orig_wire = sig.bit.wire;
return sstr.str();

View file

@ -102,7 +102,8 @@ struct DffinitPass : public Pass {
if (wire->attributes.count("\\init")) {
Const value = wire->attributes.at("\\init");
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
init_bits[sigmap(SigBit(wire, i))] = value[i];
if (value[i] != State::Sx)
init_bits[sigmap(SigBit(wire, i))] = value[i];
}
if (wire->port_output)
for (auto bit : sigmap(wire))

View file

@ -397,7 +397,6 @@ struct FlowGraph
pool<RTLIL::SigBit> x, xi;
NodePrime source_prime = {source, true};
NodePrime sink_prime = {sink, false};
pool<NodePrime> visited;
vector<NodePrime> worklist = {source_prime};
while (!worklist.empty())
@ -1382,7 +1381,8 @@ struct FlowmapWorker
vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end());
RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut));
for (unsigned i = 0; i < (1 << input_nodes.size()); i++)
unsigned const mask = 1 << input_nodes.size();
for (unsigned i = 0; i < mask; i++)
{
ce.push();
for (size_t n = 0; n < input_nodes.size(); n++)

View file

@ -94,7 +94,7 @@ int LibertyParser::lexer(std::string &str)
// search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c;
str = static_cast<char>(c);
while (1) {
c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')

View file

@ -46,7 +46,7 @@ struct ZinitPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-singleton") {
if (args[argidx] == "-all") {
all_mode = true;
continue;
}