mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'main' of https://github.com/Silimate/yosys
This commit is contained in:
commit
1ce32209b4
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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('"');
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
/peepopt*.h
|
||||
|
|
@ -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 $<,$^)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
Loading…
Reference in New Issue