This commit is contained in:
Alain Dargelas 2025-03-17 09:04:30 -07:00
commit 1ce32209b4
17 changed files with 631 additions and 19 deletions

2
.gitignore vendored
View File

@ -11,6 +11,7 @@
*.whl
*~
__pycache__
/.cache
/.cproject
/.project
/.settings
@ -19,6 +20,7 @@ __pycache__
/qtcreator.config
/qtcreator.creator
/qtcreator.creator.user
/compile_commands.json
/coverage.info
/coverage_html
/Makefile.conf

View File

@ -616,7 +616,7 @@ std::string escape_c_string(const std::string &input)
output.push_back('\\');
output.push_back(c);
} else {
char l = c & 0x3, m = (c >> 3) & 0x3, h = (c >> 6) & 0x3;
char l = c & 0x7, m = (c >> 3) & 0x7, h = (c >> 6) & 0x3;
output.append("\\");
output.push_back('0' + h);
output.push_back('0' + m);

View File

@ -3123,6 +3123,9 @@ std::string verific_import(Design *design, const std::map<std::string,std::strin
log(" Running post-elaboration for %s.\n", it->first.c_str());
nl->PostElaborationProcess();
log(" Running operator optimization for %s.\n", it->first.c_str());
nl->OperatorOptimization();
}
if (nl_done.count(it->first) == 0) {
@ -4494,7 +4497,7 @@ struct ReadPass : public Pass {
log("\n");
log(" read {-f|-F} <command-file>\n");
log("\n");
log("Load and execute the specified command file. (Requires Verific.)\n");
log("Load and execute the specified command file.\n");
log("Check verific command for more information about supported commands in file.\n");
log("\n");
log("\n");
@ -4608,10 +4611,14 @@ struct ReadPass : public Pass {
if (args[1] == "-f" || args[1] == "-F") {
if (use_verific) {
args[0] = "verific";
Pass::call(design, args);
} else {
cmd_error(args, 1, "This version of Yosys is built without Verific support.\n");
#if !defined(__wasm)
args[0] = "read_verilog_file_list";
#else
cmd_error(args, 1, "Command files are not supported on this platform.\n");
#endif
}
Pass::call(design, args);
return;
}

View File

@ -26,6 +26,10 @@
*
*/
#if !defined(__wasm)
#include <filesystem>
#endif
#include "verilog_frontend.h"
#include "preproc.h"
#include "kernel/yosys.h"
@ -672,6 +676,89 @@ struct VerilogDefines : public Pass {
}
} VerilogDefines;
#if !defined(__wasm)
static void parse_file_list(const std::string &file_list_path, RTLIL::Design *design, bool relative_to_file_list_path)
{
std::ifstream flist(file_list_path);
if (!flist.is_open()) {
log_error("Verilog file list file does not exist");
exit(1);
}
std::filesystem::path file_list_parent_dir = std::filesystem::path(file_list_path).parent_path();
std::string v_file_name;
while (std::getline(flist, v_file_name)) {
if (v_file_name.empty()) {
continue;
}
std::filesystem::path verilog_file_path;
if (relative_to_file_list_path) {
verilog_file_path = file_list_parent_dir / v_file_name;
} else {
verilog_file_path = std::filesystem::current_path() / v_file_name;
}
bool is_sv = (verilog_file_path.extension() == ".sv");
std::vector<std::string> read_verilog_cmd = {"read_verilog", "-defer"};
if (is_sv) {
read_verilog_cmd.push_back("-sv");
}
read_verilog_cmd.push_back(verilog_file_path.string());
Pass::call(design, read_verilog_cmd);
}
flist.close();
}
struct VerilogFileList : public Pass {
VerilogFileList() : Pass("read_verilog_file_list", "Parse a Verilog file list") {}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_verilog_file_list [options]\n");
log("\n");
log("Parse a Verilog file list, and pass the list of Verilog files to read_verilog\n");
log("command\n");
log("\n");
log(" -F file_list_path\n");
log(" File list file contains list of Verilog files to be parsed, any path is\n");
log(" treated relative to the file list file\n");
log("\n");
log(" -f file_list_path\n");
log(" File list file contains list of Verilog files to be parsed, any path is\n");
log(" treated relative to current working directroy\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-F" && argidx + 1 < args.size()) {
std::string file_list_path = args[++argidx];
parse_file_list(file_list_path, design, true);
continue;
}
if (arg == "-f" && argidx + 1 < args.size()) {
std::string file_list_path = args[++argidx];
parse_file_list(file_list_path, design, false);
continue;
}
break;
}
extra_args(args, argidx, design);
}
} VerilogFilelist;
#endif
YOSYS_NAMESPACE_END
// the yyerror function used by bison to report parser errors

View File

@ -634,10 +634,11 @@ std::string escape_cxx_string(const std::string &input)
output.push_back('\\');
output.push_back(c);
} else {
char l = c & 0xf, h = (c >> 4) & 0xf;
output.append("\\x");
output.push_back((h < 10 ? '0' + h : 'a' + h - 10));
output.push_back((l < 10 ? '0' + l : 'a' + l - 10));
char l = c & 0x7, m = (c >> 3) & 0x7, h = (c >> 6) & 0x3;
output.push_back('\\');
output.push_back('0' + h);
output.push_back('0' + m);
output.push_back('0' + l);
}
}
output.push_back('"');

View File

@ -334,7 +334,19 @@ RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std:
#define NEW_ID_SUFFIX(suffix) \
YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
#define NEW_ID2 module->uniquify(cell->name.str())
inline std::string removeNumericSuffix(const std::string& str) {
size_t pos = str.rfind('_'); // Find the last underscore
if (pos != std::string::npos && pos + 1 < str.size()) {
// Check if everything after the underscore is a digit
if (std::all_of(str.begin() + pos + 1, str.end(), ::isdigit)) {
return str.substr(0, pos); // Return the string without the suffix
}
}
return str; // Return unchanged if no numeric suffix found
}
#define NEW_ID2 module->uniquify(removeNumericSuffix(cell->name.str()))
#define NEW_ID2_SUFFIX(suffix) module->uniquify(cell->name.str() + "_" + suffix)
#define NEW_ID3 module->uniquify(cell_name.str())
#define NEW_ID3_SUFFIX(suffix) module->uniquify(cell_name.str() + "_" + suffix)

View File

@ -88,7 +88,7 @@ struct SplitcellsWorker
}
if (GetSize(slices) <= 1) return 0;
if (limit != -1 && GetSize(slices) > limit) { // skip if number of slices is above limit
log("Skipping %s cell %s/%s with high slice count %d.\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(slices));
log_debug("Skipping %s cell %s/%s with high slice count %d.\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(slices));
return 0;
}
slices.push_back(GetSize(outsig));
@ -107,8 +107,7 @@ struct SplitcellsWorker
auto slice_signal = [&](SigSpec old_sig) -> SigSpec {
SigSpec new_sig;
for (int i = 0; i < GetSize(old_sig); i += GetSize(outsig)) {
int offset = i+slice_lsb;
for (int offset = slice_lsb; offset < GetSize(old_sig); offset += GetSize(outsig)) {
int length = std::min(GetSize(old_sig)-offset, slice_msb-slice_lsb+1);
new_sig.append(old_sig.extract(offset, length));
}
@ -159,7 +158,7 @@ struct SplitcellsWorker
if (GetSize(slices) <= 1) return 0;
if (limit != -1 && GetSize(slices) > limit) { // skip if number of slices is above limit
log("Skipping %s cell %s/%s with high slice count %d.\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(slices));
log_debug("Skipping %s cell %s/%s with high slice count %d.\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(slices));
return 0;
}
slices.push_back(GetSize(outsig));

View File

@ -436,9 +436,15 @@ struct MuxpackPass : public Pass {
int pmux_count = 0;
for (auto module : design->selected_modules()) {
MuxpackWorker worker(module, assume_excl, make_excl);
mux_count += worker.mux_count;
pmux_count += worker.pmux_count;
int worker_mux_count = 0;
int worker_pmux_count = 0;
do {
MuxpackWorker worker(module, assume_excl, make_excl);
mux_count += worker.mux_count;
pmux_count += worker.pmux_count;
worker_mux_count = worker.mux_count;
worker_pmux_count = worker.pmux_count;
} while (worker_mux_count + worker_pmux_count > 0);
}
log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count);

View File

@ -1520,6 +1520,27 @@ skip_identity:
goto next_cell;
}
if (consume_x && mux_bool && (cell->type == ID($_MUX_) || (cell->type == ID($mux) && cell->parameters[ID::WIDTH] == 1)) && cell->getPort(ID::A) == State::S1) {
cover_list("opt.opt_expr.mux_ornot", "$mux", "$_MUX_", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with or-gate and not-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort(ID::A, module->Not(NEW_ID2_SUFFIX("not"), cell->getPort(ID::S), false, cell->get_src_attribute()));
cell->unsetPort(ID::S);
if (cell->type == ID($mux)) {
Const width = cell->parameters[ID::WIDTH];
cell->parameters[ID::A_WIDTH] = width;
cell->parameters[ID::B_WIDTH] = width;
cell->parameters[ID::Y_WIDTH] = width;
cell->parameters[ID::A_SIGNED] = 0;
cell->parameters[ID::B_SIGNED] = 0;
cell->parameters.erase(ID::WIDTH);
cell->type = ID($or);
} else
cell->type = ID($_OR_);
module->rename(cell, NEW_ID2_SUFFIX("ornot"));
did_something = true;
goto next_cell;
}
if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S1) {
cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
@ -1540,6 +1561,27 @@ skip_identity:
goto next_cell;
}
if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S0) {
cover_list("opt.opt_expr.mux_andnot", "$mux", "$_MUX_", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with and-gate and not-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort(ID::B, module->Not(NEW_ID2_SUFFIX("not"), cell->getPort(ID::S), false, cell->get_src_attribute()));
cell->unsetPort(ID::S);
if (cell->type == ID($mux)) {
Const width = cell->parameters[ID::WIDTH];
cell->parameters[ID::A_WIDTH] = width;
cell->parameters[ID::B_WIDTH] = width;
cell->parameters[ID::Y_WIDTH] = width;
cell->parameters[ID::A_SIGNED] = 0;
cell->parameters[ID::B_SIGNED] = 0;
cell->parameters.erase(ID::WIDTH);
cell->type = ID($and);
} else
cell->type = ID($_AND_);
module->rename(cell, NEW_ID2_SUFFIX("andnot"));
did_something = true;
goto next_cell;
}
if (mux_undef && cell->type.in(ID($mux), ID($pmux))) {
RTLIL::SigSpec new_a, new_b, new_s;
int width = GetSize(cell->getPort(ID::A));

1
passes/silimate/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/peepopt*.h

View File

@ -2,6 +2,7 @@
OBJS += passes/silimate/activity.o
OBJS += passes/silimate/annotate_cell_fanout.o
OBJS += passes/silimate/annotate_logic_depth.o
OBJS += passes/silimate/breakreduce.o
OBJS += passes/silimate/breaksop.o
OBJS += passes/silimate/bus_rebuild.o
OBJS += passes/silimate/longloop_select.o
@ -11,3 +12,13 @@ OBJS += passes/silimate/segv.o
OBJS += passes/silimate/selectconst.o
OBJS += passes/silimate/splitfanout.o
OBJS += passes/silimate/splitnetlist.o
OBJS += passes/silimate/opt_expand.o
GENFILES += passes/silimate/peepopt_expand.h
passes/silimate/opt_expand.o: passes/silimate/peepopt_expand.h
$(eval $(call add_extra_objs,passes/silimate/peepopt_expand.h))
PEEPOPT_PATTERN = passes/silimate/peepopt_expand.pmg
passes/silimate/peepopt_expand.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)

View File

@ -0,0 +1,241 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
* Copyright (C) 2025 Akash Levy <akash@silimate.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell *cell)
{
while (sig.size() > 1)
{
RTLIL::SigSpec sig_t = module->addWire(NEW_ID2_SUFFIX("t"), sig.size() / 2); // SILIMATE: Improve the naming
for (int i = 0; i < sig.size(); i += 2)
{
if (i+1 == sig.size()) {
sig_t.append(sig[i]);
continue;
}
RTLIL::Cell *gate = module->addCell(NEW_ID2, ID($or)); // SILIMATE: Improve the naming
gate->attributes = cell->attributes;
gate->setPort(ID::A, sig[i]);
gate->setPort(ID::B, sig[i+1]);
gate->setPort(ID::Y, sig_t[i/2]);
gate->fixup_parameters();
}
sig = sig_t;
}
if (sig.size() == 0)
sig = State::S0;
}
void breakreduce(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
if (sig_y.size() == 0)
return;
if (sig_a.size() == 0) {
if (cell->type == ID($reduce_and)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
if (cell->type == ID($reduce_or)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
if (cell->type == ID($reduce_xor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
if (cell->type == ID($reduce_xnor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
if (cell->type == ID($reduce_bool)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
return;
}
if (sig_y.size() > 1) {
module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
IdString gate_type;
if (cell->type == ID($reduce_and)) gate_type = ID($and);
if (cell->type == ID($reduce_or)) gate_type = ID($or);
if (cell->type == ID($reduce_xor)) gate_type = ID($xor);
if (cell->type == ID($reduce_xnor)) gate_type = ID($xor);
if (cell->type == ID($reduce_bool)) gate_type = ID($or);
log_assert(!gate_type.empty());
RTLIL::Cell *last_output_cell = NULL;
while (sig_a.size() > 1)
{
RTLIL::SigSpec sig_t = module->addWire(NEW_ID2_SUFFIX("t"), sig_a.size() / 2); // SILIMATE: Improve the naming
for (int i = 0; i < sig_a.size(); i += 2)
{
if (i+1 == sig_a.size()) {
sig_t.append(sig_a[i]);
continue;
}
RTLIL::Cell *gate = module->addCell(NEW_ID2, gate_type); // SILIMATE: Improve the naming
gate->attributes = cell->attributes;
gate->setPort(ID::A, sig_a[i]);
gate->setPort(ID::B, sig_a[i+1]);
gate->setPort(ID::Y, sig_t[i/2]);
gate->fixup_parameters();
last_output_cell = gate;
}
sig_a = sig_t;
}
if (cell->type == ID($reduce_xnor)) {
RTLIL::SigSpec sig_t = module->addWire(NEW_ID2_SUFFIX("t")); // SILIMATE: Improve the naming
RTLIL::Cell *gate = module->addCell(NEW_ID2, ID($not)); // SILIMATE: Improve the naming
gate->attributes = cell->attributes;
gate->setPort(ID::A, sig_a);
gate->setPort(ID::Y, sig_t);
gate->fixup_parameters();
last_output_cell = gate;
sig_a = sig_t;
}
if (last_output_cell == NULL) {
module->connect(RTLIL::SigSig(sig_y, sig_a));
} else {
last_output_cell->setPort(ID::Y, sig_y);
}
module->remove(cell);
}
void breaklognot(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
logic_reduce(module, sig_a, cell);
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
if (sig_y.size() == 0)
return;
if (sig_y.size() > 1) {
module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
RTLIL::Cell *gate = module->addCell(NEW_ID2, ID($not)); // SILIMATE: Improve the naming
gate->attributes = cell->attributes;
gate->setPort(ID::A, sig_a);
gate->setPort(ID::Y, sig_y);
gate->fixup_parameters();
module->remove(cell);
}
void breaklogbin(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
logic_reduce(module, sig_a, cell);
RTLIL::SigSpec sig_b = cell->getPort(ID::B);
logic_reduce(module, sig_b, cell);
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
if (sig_y.size() == 0)
return;
if (sig_y.size() > 1) {
module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
IdString gate_type;
if (cell->type == ID($logic_and)) gate_type = ID($and);
if (cell->type == ID($logic_or)) gate_type = ID($or);
log_assert(!gate_type.empty());
RTLIL::Cell *gate = module->addCell(NEW_ID2, gate_type); // SILIMATE: Improve the naming
gate->attributes = cell->attributes;
gate->setPort(ID::A, sig_a);
gate->setPort(ID::B, sig_b);
gate->setPort(ID::Y, sig_y);
gate->fixup_parameters();
module->remove(cell);
}
void breakeqne(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
RTLIL::SigSpec sig_b = cell->getPort(ID::B);
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
bool is_signed = cell->parameters.at(ID::A_SIGNED).as_bool();
bool is_ne = cell->type.in(ID($ne), ID($nex));
RTLIL::SigSpec xor_out = module->addWire(NEW_ID2_SUFFIX("xor"), max(GetSize(sig_a), GetSize(sig_b))); // SILIMATE: Improve the naming
RTLIL::Cell *xor_cell = module->addXor(NEW_ID2, sig_a, sig_b, xor_out, is_signed, cell->get_src_attribute()); // SILIMATE: Improve the naming
xor_cell->attributes = cell->attributes;
RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID2_SUFFIX("reduce_out")); // SILIMATE: Improve the naming
RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID2_SUFFIX("reduce_or"), xor_out, reduce_out, false, cell->get_src_attribute()); // SILIMATE: Improve the naming
reduce_cell->attributes = cell->attributes;
breakreduce(module, reduce_cell);
if (!is_ne) {
RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID2_SUFFIX("not"), reduce_out, sig_y, false, cell->get_src_attribute()); // SILIMATE: Improve the naming
not_cell->attributes = cell->attributes;
breaklognot(module, not_cell);
}
module->remove(cell);
}
struct BreakReducePass : public Pass {
BreakReducePass() : Pass("breakreduce", "break reduce-style cells into trees of primitives") { }
void help() override
{
log("\n");
log(" breakreduce [selection]\n");
log("\n");
log("Break reduce-style ($reduce_*/$logic_*/$*eq*) cells into trees of primitives.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing BREAKREDUCE pass (break reduce-style cells into trees of primitives).\n");
extra_args(args, 1, design);
for (auto module : design->selected_modules())
for (auto cell : module->selected_cells())
if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool"))
breakreduce(module, cell);
else if (cell->type.in("$logic_and", "$logic_or"))
breaklogbin(module, cell);
else if (cell->type.in("$logic_not"))
breaklognot(module, cell);
else if (cell->type.in("$eq", "$ne", "$eqx", "$nex"))
breakeqne(module, cell);
}
} BreakReducePass;
PRIVATE_NAMESPACE_END

View File

@ -444,7 +444,9 @@ struct OptBalanceTreePass : public Pass {
log(" will be replicated and balanced into a tree, but the original\n");
log(" cell will remain, driving its original loads.\n");
log(" -fanout_limit n\n");
log(" max fanout to split.\n");
log(" Max fanout to split.\n");
log(" -arith_only\n");
log(" Only balance arithmetic cells.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
@ -452,6 +454,7 @@ struct OptBalanceTreePass : public Pass {
log_header(design, "Executing OPT_BALANCE_TREE pass (cell cascades to trees).\n");
bool allow_off_chain = false;
bool arith_only = false;
size_t argidx;
int limit = -1;
for (argidx = 1; argidx < args.size(); argidx++) {
@ -463,13 +466,18 @@ struct OptBalanceTreePass : public Pass {
limit = std::stoi(args[++argidx]);
continue;
}
if (args[argidx] == "-arith_only") {
arith_only = true;
continue;
}
break;
}
extra_args(args, argidx, design);
// Count of all cells that were packed
dict<IdString, int> cell_count;
const vector<IdString> cell_types = {ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul)};
vector<IdString> cell_types = {ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul)};
if (arith_only) cell_types = {ID($add), ID($mul)};
for (auto module : design->selected_modules()) {
OptBalanceTreeWorker worker(design, module, cell_types, allow_off_chain, limit);
for (auto cell : worker.cell_count) {

View File

@ -0,0 +1,76 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
* Akash Levy <akash@silimate.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool did_something;
#include "passes/silimate/peepopt_expand.h"
struct OptExpandPass : public Pass {
OptExpandPass() : Pass("opt_expand", "expand conjunction") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" opt_expand [selection]\n");
log("\n");
log("This pass expands conjunction (AND) operations into disjunction (OR).\n");
log("\n");
log("y = (a | b) & c ===> y = (a & c) | (b & c)\n");
log("\n");
log(" -max_iters n\n");
log(" max number of pass iterations to run.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing OPT_EXPAND pass (expand conjunction into disjunction).\n");
size_t argidx;
int max_iters = 10000;
for (argidx = 1; argidx < args.size(); argidx++) {
// No extra arguments
if (args[argidx] == "-max_iters" && argidx + 1 < args.size()) {
max_iters = std::stoi(args[++argidx]);
continue;
}
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
did_something = true;
for (int i = 0; did_something && i < max_iters; i++)
{
log("ITERATION OF OPT_EXPAND\n");
did_something = false;
peepopt_pm pm(module);
pm.setup(module->selected_cells());
pm.run_expand();
}
}
}
} PeepoptPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,75 @@
pattern expand
//
// Authored by Akash Levy of Silimate, Inc. under ISC license.
//
// Expand logical conjunction (&) across (|)
//
// y = (a | b) & c ===> y = (a & c) | (b & c)
//
state <SigSpec> and_a and_b and_y or_a or_b or_y
match or_gate
// Select OR gate
select or_gate->type.in($or, $_OR_)
set or_a port(or_gate, \A)
set or_b port(or_gate, \B)
set or_y port(or_gate, \Y)
endmatch
code
// Fanout of each OR gate Y bit should be 1 (no bit-split)
if (nusers(or_y) != 2)
reject;
endcode
match and_gate
// Select AND gate
select and_gate->type.in($and, $_AND_)
// Set ports, allowing A and B to be swapped
choice <IdString> A {\A, \B}
define <IdString> B (A == \A ? \B : \A)
set and_a port(and_gate, A)
set and_b port(and_gate, B)
set and_y port(and_gate, \Y)
// Connection
index <SigSpec> port(and_gate, A) === or_y
endmatch
code and_a and_b and_y or_a or_b or_y
// Unset all ports
and_gate->unsetPort(\A);
and_gate->unsetPort(\B);
and_gate->unsetPort(\Y);
or_gate->unsetPort(\A);
or_gate->unsetPort(\B);
or_gate->unsetPort(\Y);
// Create new intermediate wires
Cell *cell = and_gate;
Wire *new_or_a = module->addWire(NEW_ID2, GetSize(and_y));
Wire *new_or_b = module->addWire(NEW_ID2, GetSize(and_y));
// Create new AND gates connected to the OR gate
module->addAnd(NEW_ID2, or_a, and_b, new_or_a, false, cell->get_src_attribute());
module->addAnd(NEW_ID2, or_b, and_b, new_or_b, false, cell->get_src_attribute());
// Update OR gate ports
or_gate->setPort(\A, new_or_a);
or_gate->setPort(\B, new_or_b);
or_gate->setPort(\Y, and_y);
// Rename OR gate for formal
cell = or_gate;
module->rename(or_gate, NEW_ID2);
// Remove AND gate
autoremove(and_gate);
// Log, fixup, accept
log("expand pattern in %s: and=%s, or=%s\n", log_id(module), log_id(and_gate), log_id(or_gate));
did_something = true;
accept;
endcode

View File

@ -245,7 +245,7 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
bool is_signed = cell->parameters.at(ID::A_SIGNED).as_bool();
bool is_ne = cell->type.in(ID($ne), ID($nex));
RTLIL::SigSpec xor_out = module->addWire(NEW_ID2_SUFFIX("xor_out"), max(GetSize(sig_a), GetSize(sig_b))); // SILIMATE: Improve the naming
RTLIL::SigSpec xor_out = module->addWire(NEW_ID2_SUFFIX("xor"), max(GetSize(sig_a), GetSize(sig_b))); // SILIMATE: Improve the naming
RTLIL::Cell *xor_cell = module->addXor(NEW_ID2, sig_a, sig_b, xor_out, is_signed, cell->get_src_attribute()); // SILIMATE: Improve the naming
xor_cell->attributes = cell->attributes;
simplemap_bitop(module, xor_cell);

44
tests/various/bug4909.ys Normal file
View File

@ -0,0 +1,44 @@
read_rtlil << EOF
autoidx 20
attribute \src "3510.v:2.1-26.10"
attribute \cells_not_processed 1
attribute \tamara_triplicate 1
module \top
attribute \src "3510.v:14.3-17.8"
wire width 4 $0\reg5[3:0]
attribute $bugpoint 1
wire width 4 $auto$bugpoint.cc:258:simplify_something$12
wire $delete_wire$14
attribute \src "3510.v:13.19-13.59"
wire width 4 $xnor$3510.v:13$1_Y
attribute \src "3510.v:11.23-11.27"
wire width 4 \reg5
attribute \src "3510.v:8.24-8.29"
wire width 3 \wire4
attribute \src "3510.v:3.33-3.34"
wire width 12 output 1 \y
attribute \src "3510.v:13.19-13.59"
cell $xnor $xnor$3510.v:13$1
parameter \A_SIGNED 0
parameter \A_WIDTH 3
parameter \B_SIGNED 0
parameter \B_WIDTH 4
parameter \Y_WIDTH 4
connect \A 3'x
connect \B $auto$bugpoint.cc:258:simplify_something$12
connect \Y $xnor$3510.v:13$1_Y
end
attribute \src "3510.v:14.3-17.8"
process $proc$3510.v:14$2
assign $0\reg5[3:0] { \wire4 [2] \wire4 }
sync posedge $delete_wire$14
update \reg5 $0\reg5[3:0]
end
connect \y [4:0] { \reg5 1'0 }
connect \wire4 $xnor$3510.v:13$1_Y [2:0]
end
EOF
prep
splitcells