mirror of https://github.com/YosysHQ/yosys.git
Merged with main
This commit is contained in:
commit
8d22f6d7e1
23
CHANGELOG
23
CHANGELOG
|
|
@ -2,9 +2,30 @@
|
|||
List of major changes and improvements between releases
|
||||
=======================================================
|
||||
|
||||
Yosys 0.61 .. Yosys 0.62-dev
|
||||
Yosys 0.62 .. Yosys 0.63-dev
|
||||
--------------------------
|
||||
|
||||
Yosys 0.61 .. Yosys 0.62
|
||||
--------------------------
|
||||
* Various
|
||||
- verific: Added "-sv2017" flag option to support System
|
||||
Verilog 2017.
|
||||
- verific: Added VHDL related flags to "-f" and "-F" and
|
||||
support reading VHDL file from file lists.
|
||||
- Updated cell libs with proper module declaration where
|
||||
non standard (...) style was used.
|
||||
|
||||
* New commands and options
|
||||
- Added "-word" option to "lut2mux" pass to enable emitting
|
||||
word level cells.
|
||||
- Added experimental "opt_balance_tree" pass to convert
|
||||
cascaded cells into tree of cells to improve timing.
|
||||
- Added "-gatesi" option to "write_blif" pass to init gates
|
||||
under gates_mode in BLIF format.
|
||||
- Added "-on" and "-off" options to "debug" pass for
|
||||
persistent debug logging.
|
||||
- Added "linux_perf" pass to control performance recording.
|
||||
|
||||
Yosys 0.60 .. Yosys 0.61
|
||||
--------------------------
|
||||
* Various
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -177,7 +177,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.61+112
|
||||
YOSYS_VER := 0.62+0
|
||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2)
|
||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'.' -f3)
|
||||
|
|
@ -202,7 +202,7 @@ endif
|
|||
OBJS = kernel/version_$(GIT_REV).o
|
||||
|
||||
bumpversion:
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5ae48ee.. | wc -l`/;" Makefile
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 7326bb7.. | wc -l`/;" Makefile
|
||||
|
||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) OPTFLAGS="-g -O3"
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import os
|
|||
project = 'YosysHQ Yosys'
|
||||
author = 'YosysHQ GmbH'
|
||||
copyright ='2026 YosysHQ GmbH'
|
||||
yosys_ver = "0.61"
|
||||
yosys_ver = "0.62"
|
||||
|
||||
# select HTML theme
|
||||
html_theme = 'furo-ys'
|
||||
|
|
|
|||
|
|
@ -3143,9 +3143,6 @@ std::string verific_import(Design *design, const std::map<std::string,std::strin
|
|||
if (verific_opt) {
|
||||
log(" Optimizing netlist for %s.\n", it->first.c_str());
|
||||
|
||||
// log(" Inferring clock enable muxes for %s.\n", it->first.c_str());
|
||||
// nl->InferClockEnableMux();
|
||||
|
||||
log(" Running post-elaboration for %s.\n", it->first.c_str());
|
||||
nl->PostElaborationProcess();
|
||||
|
||||
|
|
@ -3864,14 +3861,17 @@ struct VerificPass : public Pass {
|
|||
{
|
||||
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
||||
unsigned verilog_mode = veri_file::UNDEFINED;
|
||||
#ifdef VERIFIC_VHDL_SUPPORT
|
||||
unsigned vhdl_mode = vhdl_file::UNDEFINED;
|
||||
bool is_formal = false;
|
||||
#endif
|
||||
bool is_formal = false;
|
||||
#else
|
||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||
unsigned verilog_mode = veri_file::SYSTEM_VERILOG;
|
||||
#endif
|
||||
#ifdef VERIFIC_VHDL_SUPPORT
|
||||
unsigned vhdl_mode = vhdl_file::UNDEFINED;
|
||||
#endif
|
||||
#endif
|
||||
const char* filename = nullptr;
|
||||
|
||||
|
|
|
|||
|
|
@ -1612,12 +1612,6 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules(RTLIL::SelectPartial
|
|||
return result;
|
||||
}
|
||||
|
||||
void RTLIL::Design::run_pass(std::string command) {
|
||||
log("\n-- Running command `%s' --\n", command.c_str());
|
||||
Pass::call(this, command);
|
||||
log_flush();
|
||||
}
|
||||
|
||||
RTLIL::Module::Module()
|
||||
{
|
||||
static unsigned int hashidx_count = 123456789;
|
||||
|
|
|
|||
|
|
@ -2039,9 +2039,6 @@ struct RTLIL::Design
|
|||
// partially selected or boxed modules have been ignored
|
||||
std::vector<RTLIL::Module*> selected_unboxed_whole_modules_warn() const { return selected_modules(SELECT_WHOLE_WARN, SB_UNBOXED_WARN); }
|
||||
|
||||
// SILIMATE ADDED TO IMPROVE PYOSYS API
|
||||
void run_pass(std::string command);
|
||||
|
||||
static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);
|
||||
|
||||
std::string to_rtlil_str(bool only_selected = true) const;
|
||||
|
|
|
|||
|
|
@ -258,9 +258,13 @@ struct SimInstance
|
|||
if ((shared->fst) && !(shared->hide_internal && wire->name[0] == '$')) {
|
||||
fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
|
||||
if (id==0 && wire->name.isPublic()) {
|
||||
log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
|
||||
if (shared->debug) {
|
||||
log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
|
||||
}
|
||||
} else {
|
||||
log("Found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
|
||||
if (shared->debug) {
|
||||
log("Found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
|
||||
}
|
||||
}
|
||||
fst_handles[wire] = id;
|
||||
}
|
||||
|
|
@ -2504,16 +2508,11 @@ struct AnnotateActivity : public OutputWriter {
|
|||
}
|
||||
}
|
||||
|
||||
// Retrieve VCD timescale
|
||||
std::string timescale = worker->timescale;
|
||||
double real_timescale = 1e-12; // ps
|
||||
if (timescale == "ns")
|
||||
real_timescale = 1e-9;
|
||||
if (timescale == "fs")
|
||||
real_timescale = 1e-15;
|
||||
|
||||
// TODO: remove all debug sections when dev is completed
|
||||
bool debug = false;
|
||||
// Retrieve timescale from converted VCD file
|
||||
double real_timescale = worker->fst->getTimescale();
|
||||
if (worker->debug) {
|
||||
log_debug("Timescale %e seconds extracted from converted VCD file", real_timescale);
|
||||
}
|
||||
|
||||
// Compute clock period, find the highest toggling signal and compute its average period
|
||||
SignalActivityDataMap::iterator itr = dataMap.find(clk);
|
||||
|
|
@ -2527,31 +2526,32 @@ struct AnnotateActivity : public OutputWriter {
|
|||
std::stringstream ss;
|
||||
ss << std::setprecision(4) << real_timescale;
|
||||
worker->top->module->set_string_attribute("$TIMESCALE", ss.str());
|
||||
if (debug) {
|
||||
std::cout << "Clock toggle count: " << clktoggleCounts[0] << "\n";
|
||||
std::cout << "Max time: " << max_time << "\n";
|
||||
std::cout << "Clock period: " << clk_period << "\n";
|
||||
std::cout << "Frequency: " << frequency << "\n";
|
||||
if (worker->debug) {
|
||||
log_debug("Clock toggle count: %f", clktoggleCounts[0]);
|
||||
log_debug("Max time: %d", max_time);
|
||||
log_debug("Clock period: %f", clk_period);
|
||||
log_debug("Frequency: %f", frequency);
|
||||
}
|
||||
double totalActivity = 0.0f;
|
||||
double totalDuty = 0.0f;
|
||||
|
||||
// TODO make this debug code less messy and more readable.
|
||||
worker->top->write_output_header(
|
||||
[debug](IdString name) {
|
||||
if (debug)
|
||||
std::cout << stringf("module %s\n", log_id(name));
|
||||
[&](IdString name) {
|
||||
if (worker->debug)
|
||||
log_debug("module %s", log_id(name));
|
||||
},
|
||||
[debug]() {
|
||||
if (debug)
|
||||
std::cout << "endmodule\n";
|
||||
[&]() {
|
||||
if (worker->debug)
|
||||
log_debug("endmodule");
|
||||
},
|
||||
[&use_signal, &dataMap, max_time, real_timescale, clk_period, debug, &totalActivity, &totalDuty]
|
||||
(const char *name, int size, Wire *w, int id, bool) {
|
||||
[&](const char *name, int size, Wire *w, int id, bool) {
|
||||
if (!use_signal.at(id) || (w == nullptr))
|
||||
return;
|
||||
SignalActivityDataMap::const_iterator itr = dataMap.find(id);
|
||||
const std::vector<double_t> &toggleCounts = itr->second.toggleCounts;
|
||||
const std::vector<uint64_t> &highTimes = itr->second.highTimes;
|
||||
if (debug) {
|
||||
if (worker->debug) {
|
||||
std::string full_name = form_vcd_name(name, size, w);
|
||||
std::cout << full_name << " " << id << ":\n";
|
||||
std::cout << " TC: ";
|
||||
|
|
@ -2577,10 +2577,8 @@ struct AnnotateActivity : public OutputWriter {
|
|||
totalActivity += activity;
|
||||
activity_str += std::to_string(activity) + " ";
|
||||
}
|
||||
if (debug) {
|
||||
std::cout << activity_str;
|
||||
std::cout << "\n";
|
||||
std::cout << " DUTY: ";
|
||||
if (worker->debug) {
|
||||
log_debug(" ACKT: %s", activity_str.c_str());
|
||||
}
|
||||
std::string duty_str;
|
||||
for (uint32_t i = 0; i < (uint32_t)size; i++) {
|
||||
|
|
@ -2589,9 +2587,8 @@ struct AnnotateActivity : public OutputWriter {
|
|||
totalDuty += duty;
|
||||
duty_str += std::to_string(duty) + " ";
|
||||
}
|
||||
if (debug) {
|
||||
std::cout << duty_str;
|
||||
std::cout << "\n";
|
||||
if (worker->debug) {
|
||||
log_debug(" DUTY: %s", duty_str.c_str());
|
||||
}
|
||||
w->set_string_attribute("$ACKT", activity_str);
|
||||
w->set_string_attribute("$DUTY", duty_str);
|
||||
|
|
|
|||
|
|
@ -33,3 +33,20 @@ PEEPOPT_PATTERN += passes/silimate/peepopt_muxinvprop.pmg
|
|||
|
||||
passes/silimate/peepopt_muxmode.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
||||
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
|
||||
|
||||
OBJS += passes/silimate/negopt.o
|
||||
GENFILES += passes/silimate/peepopt_negopt.h
|
||||
passes/silimate/negopt.o: passes/silimate/peepopt_negopt.h
|
||||
$(eval $(call add_extra_objs,passes/silimate/peepopt_negopt.h))
|
||||
|
||||
PEEPOPT_PATTERN = passes/silimate/peepopt_manual2sub.pmg
|
||||
PEEPOPT_PATTERN += passes/silimate/peepopt_sub2neg.pmg
|
||||
PEEPOPT_PATTERN += passes/silimate/peepopt_negexpand.pmg
|
||||
PEEPOPT_PATTERN += passes/silimate/peepopt_negneg.pmg
|
||||
PEEPOPT_PATTERN += passes/silimate/peepopt_negmux.pmg
|
||||
PEEPOPT_PATTERN += passes/silimate/peepopt_negrebuild.pmg
|
||||
PEEPOPT_PATTERN += passes/silimate/peepopt_muxneg.pmg
|
||||
PEEPOPT_PATTERN += passes/silimate/peepopt_neg2sub.pmg
|
||||
|
||||
passes/silimate/peepopt_negopt.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
||||
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (C) 2025 Silimate, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc.
|
||||
//
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
bool did_something;
|
||||
|
||||
#include "passes/silimate/peepopt_negopt.h"
|
||||
|
||||
struct NegoptPass : public Pass {
|
||||
NegoptPass() : Pass("negopt", "optimize negation patterns in arithmetic") { }
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" negopt [options] [selection]\n");
|
||||
log("\n");
|
||||
log("This pass optimizes negation patterns in arithmetic expressions.\n");
|
||||
log("\n");
|
||||
log(" -pre\n");
|
||||
log(" Run pre-optimization transformations:\n" );
|
||||
log(" - manual2sub: a + ~b + 1 => a - b\n" );
|
||||
log(" - sub2neg: a - b => a + (-b)\n" );
|
||||
log(" - negexpand: -(a + b) => (-a) + (-b)\n");
|
||||
log(" - negneg: -(-a) => a\n" );
|
||||
log(" - negmux: -(s?a:b) => s?(-a):(-b)\n");
|
||||
log("\n");
|
||||
log(" -post\n");
|
||||
log(" Run post-optimization transformations:\n" );
|
||||
log(" - negrebuild: (-a)+(-b) => -(a + b)\n");
|
||||
log(" - muxneg: s?(-a):(-b) => -(s?a:b)\n");
|
||||
log(" - neg2sub: a + (-b) => a - b\n" );
|
||||
log("\n");
|
||||
log("When called without options, both -pre and -post are executed.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
bool run_pre = false;
|
||||
bool run_post = false;
|
||||
|
||||
log_header(design, "Executing NEGOPT pass (optimize negation patterns).\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-pre") {
|
||||
run_pre = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-post") {
|
||||
run_post = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (!run_pre && !run_post) {
|
||||
run_pre = true;
|
||||
run_post = true;
|
||||
}
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
if (run_pre) {
|
||||
did_something = true;
|
||||
while (did_something) {
|
||||
did_something = false;
|
||||
peepopt_pm pm(module);
|
||||
pm.setup(module->selected_cells());
|
||||
|
||||
pm.run_manual2sub(); // Reduce manual 2's complement to subtraction first
|
||||
pm.run_sub2neg();
|
||||
pm.run_negexpand();
|
||||
pm.run_negneg();
|
||||
pm.run_negmux();
|
||||
}
|
||||
}
|
||||
|
||||
if (run_post) {
|
||||
did_something = true;
|
||||
while (did_something) {
|
||||
did_something = false;
|
||||
peepopt_pm pm(module);
|
||||
pm.setup(module->selected_cells());
|
||||
|
||||
pm.run_negrebuild();
|
||||
pm.run_muxneg();
|
||||
pm.run_neg2sub();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} NegoptPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
pattern manual2sub
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
|
||||
//
|
||||
// Canonicalize manual 2's complement subtraction:
|
||||
// Case A: (a + ~b) + 1 ===> a - b
|
||||
// Case B: a + (~b + 1) ===> a - b
|
||||
//
|
||||
// Note: Fanout checking includes module connections to avoid breaking
|
||||
// designs where intermediate results are used by output assignments.
|
||||
//
|
||||
|
||||
state <SigSpec> minuend subtrahend result_sig
|
||||
state <bool> is_signed
|
||||
state <SigSpec> inner_y
|
||||
|
||||
// 1. Match the "root" add (the one that produces the final result)
|
||||
match root_add
|
||||
select root_add->type == $add
|
||||
set result_sig port(root_add, \Y)
|
||||
set is_signed root_add->getParam(ID::A_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
// 2. Case A: (a + ~b) + 1
|
||||
// Check if root_add has a constant 1
|
||||
code root_add inner_y
|
||||
{
|
||||
SigSpec pa = root_add->getPort(ID::A);
|
||||
SigSpec pb = root_add->getPort(ID::B);
|
||||
|
||||
auto is_one = [](SigSpec s) {
|
||||
if (!s.is_fully_const()) return false;
|
||||
Const c = s.as_const();
|
||||
for (int i = 0; i < c.size(); i++) {
|
||||
if (i == 0 && c[i] != State::S1) return false;
|
||||
if (i > 0 && c[i] != State::S0) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (is_one(pa)) {
|
||||
inner_y = pb;
|
||||
} else if (is_one(pb)) {
|
||||
inner_y = pa;
|
||||
} else {
|
||||
branch;
|
||||
reject;
|
||||
}
|
||||
}
|
||||
endcode
|
||||
|
||||
// Find the inner add
|
||||
match inner_add_A
|
||||
select inner_add_A->type == $add
|
||||
index <SigSpec> port(inner_add_A, \Y) === inner_y
|
||||
select nusers(port(inner_add_A, \Y)) == 2
|
||||
endmatch
|
||||
|
||||
// Find the NOT gate on one of the ports of inner_add_A
|
||||
match not_gate_A
|
||||
select not_gate_A->type == $not
|
||||
filter not_gate_A->getPort(ID::Y) == inner_add_A->getPort(ID::A) || not_gate_A->getPort(ID::Y) == inner_add_A->getPort(ID::B)
|
||||
set subtrahend port(not_gate_A, \A)
|
||||
endmatch
|
||||
|
||||
code root_add inner_add_A not_gate_A subtrahend minuend result_sig is_signed
|
||||
{
|
||||
|
||||
// Require consistent signedness on the root add.
|
||||
if (root_add->getParam(ID::B_SIGNED).as_bool() != is_signed)
|
||||
reject;
|
||||
|
||||
if (inner_add_A->getParam(ID::A_SIGNED).as_bool() != is_signed)
|
||||
reject;
|
||||
if (inner_add_A->getParam(ID::B_SIGNED).as_bool() != is_signed)
|
||||
reject;
|
||||
|
||||
if (not_gate_A->getPort(ID::Y) == inner_add_A->getPort(ID::A))
|
||||
minuend = inner_add_A->getPort(ID::B);
|
||||
else
|
||||
minuend = inner_add_A->getPort(ID::A);
|
||||
|
||||
// Create the subtraction cell
|
||||
log("manual2sub in %s: Found (a + ~b) + 1 pattern, creating $sub for %s\n", log_id(module), log_signal(result_sig));
|
||||
Cell *sub = module->addSub(NEW_ID, minuend, subtrahend, result_sig, is_signed);
|
||||
|
||||
// Let fixup_parameters handle width adjustments
|
||||
sub->fixup_parameters();
|
||||
|
||||
// Remove old cells
|
||||
autoremove(root_add);
|
||||
autoremove(inner_add_A);
|
||||
autoremove(not_gate_A);
|
||||
|
||||
did_something = true;
|
||||
accept;
|
||||
}
|
||||
endcode
|
||||
|
||||
// 3. Case B: a + (~b + 1)
|
||||
code root_add
|
||||
// Just fall through to the next match
|
||||
endcode
|
||||
|
||||
// Find the inner add on either port of root_add
|
||||
match inner_add_B
|
||||
select inner_add_B->type == $add
|
||||
filter inner_add_B->getPort(ID::Y) == root_add->getPort(ID::A) || inner_add_B->getPort(ID::Y) == root_add->getPort(ID::B)
|
||||
select nusers(port(inner_add_B, \Y)) == 2
|
||||
endmatch
|
||||
|
||||
// Check if inner_add_B has a constant 1 and a NOT gate
|
||||
match not_gate_B
|
||||
select not_gate_B->type == $not
|
||||
filter not_gate_B->getPort(ID::Y) == inner_add_B->getPort(ID::A) || not_gate_B->getPort(ID::Y) == inner_add_B->getPort(ID::B)
|
||||
endmatch
|
||||
|
||||
code root_add inner_add_B not_gate_B minuend subtrahend result_sig is_signed
|
||||
{
|
||||
|
||||
// Require consistent signedness on the root add.
|
||||
if (root_add->getParam(ID::B_SIGNED).as_bool() != is_signed)
|
||||
reject;
|
||||
|
||||
if (inner_add_B->getParam(ID::A_SIGNED).as_bool() != is_signed)
|
||||
reject;
|
||||
if (inner_add_B->getParam(ID::B_SIGNED).as_bool() != is_signed)
|
||||
reject;
|
||||
|
||||
SigSpec pa = inner_add_B->getPort(ID::A);
|
||||
SigSpec pb = inner_add_B->getPort(ID::B);
|
||||
SigSpec not_y = not_gate_B->getPort(ID::Y);
|
||||
|
||||
auto is_one = [](SigSpec s) {
|
||||
if (!s.is_fully_const()) return false;
|
||||
Const c = s.as_const();
|
||||
for (int i = 0; i < c.size(); i++) {
|
||||
if (i == 0 && c[i] != State::S1) return false;
|
||||
if (i > 0 && c[i] != State::S0) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
bool valid = false;
|
||||
if (is_one(pa) && pb == not_y) valid = true;
|
||||
if (is_one(pb) && pa == not_y) valid = true;
|
||||
|
||||
if (!valid) reject;
|
||||
|
||||
subtrahend = not_gate_B->getPort(ID::A);
|
||||
if (inner_add_B->getPort(ID::Y) == root_add->getPort(ID::A))
|
||||
minuend = root_add->getPort(ID::B);
|
||||
else
|
||||
minuend = root_add->getPort(ID::A);
|
||||
|
||||
// Create the subtraction cell
|
||||
log("manual2sub in %s: Found a + (~b + 1) pattern, creating $sub for %s\n", log_id(module), log_signal(result_sig));
|
||||
Cell *sub = module->addSub(NEW_ID, minuend, subtrahend, result_sig, is_signed);
|
||||
|
||||
// Let fixup_parameters handle width adjustments
|
||||
sub->fixup_parameters();
|
||||
|
||||
// Remove old cells
|
||||
autoremove(root_add);
|
||||
autoremove(inner_add_B);
|
||||
autoremove(not_gate_B);
|
||||
|
||||
did_something = true;
|
||||
accept;
|
||||
}
|
||||
endcode
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
pattern muxneg
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
|
||||
//
|
||||
// Factor negation out of mux
|
||||
//
|
||||
// s ? (-a) : (-b) ===> -(s ? a : b)
|
||||
//
|
||||
|
||||
state <SigSpec> mux_a mux_b mux_s mux_y neg_a_in neg_b_in
|
||||
state <bool> neg_a_signed neg_b_signed
|
||||
|
||||
match mux
|
||||
select mux->type == $mux
|
||||
set mux_a port(mux, \A)
|
||||
set mux_b port(mux, \B)
|
||||
set mux_s port(mux, \S)
|
||||
set mux_y port(mux, \Y)
|
||||
endmatch
|
||||
|
||||
match neg_a
|
||||
select neg_a->type == $neg
|
||||
select nusers(port(neg_a, \Y)) == 2
|
||||
index <SigSpec> port(neg_a, \Y) === mux_a
|
||||
set neg_a_in port(neg_a, \A)
|
||||
set neg_a_signed neg_a->getParam(\A_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
match neg_b
|
||||
select neg_b->type == $neg
|
||||
select nusers(port(neg_b, \Y)) == 2
|
||||
index <SigSpec> port(neg_b, \Y) === mux_b
|
||||
set neg_b_in port(neg_b, \A)
|
||||
set neg_b_signed neg_b->getParam(\A_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
code mux_a mux_b mux_s mux_y neg_a_in neg_b_in neg_a_signed neg_b_signed
|
||||
if (neg_a_signed != neg_b_signed)
|
||||
reject;
|
||||
|
||||
{
|
||||
int width = GetSize(mux_y);
|
||||
|
||||
SigSpec mux_out = module->addWire(NEW_ID, width);
|
||||
Cell *new_mux = module->addMux(NEW_ID, neg_a_in, neg_b_in, mux_s, mux_out);
|
||||
Cell *new_neg = module->addNeg(NEW_ID, mux_out, mux_y, neg_a_signed);
|
||||
|
||||
log("muxneg pattern in %s: mux=%s, neg_a=%s, neg_b=%s\n",
|
||||
log_id(module), log_id(mux), log_id(neg_a), log_id(neg_b));
|
||||
|
||||
new_mux->fixup_parameters();
|
||||
new_neg->fixup_parameters();
|
||||
autoremove(mux);
|
||||
autoremove(neg_a);
|
||||
autoremove(neg_b);
|
||||
did_something = true;
|
||||
}
|
||||
accept;
|
||||
endcode
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
pattern neg2sub
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
|
||||
//
|
||||
// Convert addition with negation back to subtraction
|
||||
//
|
||||
// a + (-b) ===> a - b
|
||||
//
|
||||
|
||||
state <SigSpec> add_a add_b add_y neg_a
|
||||
state <bool> add_a_signed add_b_signed neg_signed
|
||||
state <bool> neg_on_a
|
||||
|
||||
match add
|
||||
select add->type == $add
|
||||
set add_a port(add, \A)
|
||||
set add_b port(add, \B)
|
||||
set add_y port(add, \Y)
|
||||
set add_a_signed add->getParam(\A_SIGNED).as_bool()
|
||||
set add_b_signed add->getParam(\B_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
code neg_on_a
|
||||
neg_on_a = true;
|
||||
branch;
|
||||
neg_on_a = false;
|
||||
endcode
|
||||
|
||||
match neg
|
||||
select neg->type == $neg
|
||||
select nusers(port(neg, \Y)) == 2
|
||||
index <SigSpec> port(neg, \Y) === (neg_on_a ? add_a : add_b)
|
||||
set neg_a port(neg, \A)
|
||||
set neg_signed neg->getParam(\A_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
code add_a add_b add_y neg_a neg_on_a add_a_signed add_b_signed neg_signed
|
||||
if (add_a_signed != add_b_signed)
|
||||
reject;
|
||||
|
||||
if (neg_signed != (neg_on_a ? add_a_signed : add_b_signed))
|
||||
reject;
|
||||
|
||||
{
|
||||
Cell *new_sub;
|
||||
if (neg_on_a)
|
||||
new_sub = module->addSub(NEW_ID, add_b, neg_a, add_y, add_b_signed);
|
||||
else
|
||||
new_sub = module->addSub(NEW_ID, add_a, neg_a, add_y, add_a_signed);
|
||||
|
||||
log("neg2sub pattern in %s: add=%s, neg=%s\n",
|
||||
log_id(module), log_id(add), log_id(neg));
|
||||
|
||||
new_sub->fixup_parameters();
|
||||
autoremove(add);
|
||||
autoremove(neg);
|
||||
did_something = true;
|
||||
}
|
||||
accept;
|
||||
endcode
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
pattern negexpand
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
|
||||
//
|
||||
// Expand negation over addition
|
||||
//
|
||||
// -(a + b) ===> (-a) + (-b)
|
||||
//
|
||||
|
||||
state <SigSpec> neg_a neg_y add_a add_b
|
||||
state <bool> a_signed
|
||||
|
||||
match neg
|
||||
select neg->type == $neg
|
||||
set neg_a port(neg, \A)
|
||||
set neg_y port(neg, \Y)
|
||||
set a_signed neg->getParam(\A_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
match add
|
||||
select add->type == $add
|
||||
index <SigSpec> port(add, \Y) === neg_a
|
||||
select nusers(port(add, \Y)) == 2
|
||||
set add_a port(add, \A)
|
||||
set add_b port(add, \B)
|
||||
endmatch
|
||||
|
||||
code neg_a neg_y add_a add_b a_signed
|
||||
if (add->getParam(\A_SIGNED).as_bool() != a_signed)
|
||||
reject;
|
||||
if (add->getParam(\B_SIGNED).as_bool() != a_signed)
|
||||
reject;
|
||||
|
||||
{
|
||||
// Use output width for negations to handle overflow correctly
|
||||
int width = GetSize(neg_y);
|
||||
SigSpec neg_add_a = module->addWire(NEW_ID, width);
|
||||
Cell *neg_a_cell = module->addNeg(NEW_ID, add_a, neg_add_a, a_signed);
|
||||
|
||||
SigSpec neg_add_b = module->addWire(NEW_ID, width);
|
||||
Cell *neg_b_cell = module->addNeg(NEW_ID, add_b, neg_add_b, a_signed);
|
||||
|
||||
Cell *new_add = module->addAdd(NEW_ID, neg_add_a, neg_add_b, neg_y, a_signed);
|
||||
|
||||
log("negexpand pattern in %s: neg=%s, add=%s\n",
|
||||
log_id(module), log_id(neg), log_id(add));
|
||||
|
||||
neg_a_cell->fixup_parameters();
|
||||
neg_b_cell->fixup_parameters();
|
||||
new_add->fixup_parameters();
|
||||
autoremove(neg);
|
||||
autoremove(add);
|
||||
did_something = true;
|
||||
}
|
||||
accept;
|
||||
endcode
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
pattern negmux
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
|
||||
//
|
||||
// Distribute negation over mux
|
||||
//
|
||||
// -(s ? a : b) ===> s ? (-a) : (-b)
|
||||
//
|
||||
|
||||
state <SigSpec> neg_a neg_y mux_a mux_b mux_s
|
||||
state <bool> a_signed
|
||||
|
||||
match neg
|
||||
select neg->type == $neg
|
||||
set neg_a port(neg, \A)
|
||||
set neg_y port(neg, \Y)
|
||||
set a_signed neg->getParam(\A_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
match mux
|
||||
select mux->type == $mux
|
||||
index <SigSpec> port(mux, \Y) === neg_a
|
||||
select nusers(port(mux, \Y)) == 2
|
||||
set mux_a port(mux, \A)
|
||||
set mux_b port(mux, \B)
|
||||
set mux_s port(mux, \S)
|
||||
endmatch
|
||||
|
||||
code neg_a neg_y mux_a mux_b mux_s a_signed
|
||||
{
|
||||
int width = GetSize(neg_y);
|
||||
|
||||
SigSpec neg_mux_a = module->addWire(NEW_ID, width);
|
||||
Cell *neg_a_cell = module->addNeg(NEW_ID, mux_a, neg_mux_a, a_signed);
|
||||
|
||||
SigSpec neg_mux_b = module->addWire(NEW_ID, width);
|
||||
Cell *neg_b_cell = module->addNeg(NEW_ID, mux_b, neg_mux_b, a_signed);
|
||||
|
||||
Cell *new_mux = module->addMux(NEW_ID, neg_mux_a, neg_mux_b, mux_s, neg_y);
|
||||
|
||||
log("negmux pattern in %s: neg=%s, mux=%s\n",
|
||||
log_id(module), log_id(neg), log_id(mux));
|
||||
|
||||
neg_a_cell->fixup_parameters();
|
||||
neg_b_cell->fixup_parameters();
|
||||
new_mux->fixup_parameters();
|
||||
autoremove(neg);
|
||||
autoremove(mux);
|
||||
did_something = true;
|
||||
}
|
||||
accept;
|
||||
endcode
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
pattern negneg
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
|
||||
//
|
||||
// Simplify double negation
|
||||
//
|
||||
// -(-a) ===> a
|
||||
//
|
||||
|
||||
state <SigSpec> neg1_a neg1_y neg2_a
|
||||
|
||||
match neg1
|
||||
select neg1->type == $neg
|
||||
set neg1_a port(neg1, \A)
|
||||
set neg1_y port(neg1, \Y)
|
||||
endmatch
|
||||
|
||||
match neg2
|
||||
select neg2->type == $neg
|
||||
index <SigSpec> port(neg2, \Y) === neg1_a
|
||||
select nusers(port(neg2, \Y)) == 2
|
||||
set neg2_a port(neg2, \A)
|
||||
endmatch
|
||||
|
||||
code neg1_a neg1_y neg2_a
|
||||
module->connect(neg1_y, neg2_a);
|
||||
|
||||
log("negneg pattern in %s: neg1=%s, neg2=%s\n",
|
||||
log_id(module), log_id(neg1), log_id(neg2));
|
||||
|
||||
autoremove(neg1);
|
||||
autoremove(neg2);
|
||||
did_something = true;
|
||||
accept;
|
||||
endcode
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
pattern negrebuild
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
|
||||
//
|
||||
// Rebuild addition of negations into negation of addition
|
||||
//
|
||||
// (-a) + (-b) ===> -(a + b)
|
||||
//
|
||||
|
||||
state <SigSpec> add_a add_b add_y neg1_a neg2_a
|
||||
state <bool> add_signed add_b_signed neg1_signed neg2_signed
|
||||
|
||||
match add
|
||||
select add->type == $add
|
||||
set add_a port(add, \A)
|
||||
set add_b port(add, \B)
|
||||
set add_y port(add, \Y)
|
||||
set add_signed add->getParam(\A_SIGNED).as_bool()
|
||||
set add_b_signed add->getParam(\B_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
match neg1
|
||||
select neg1->type == $neg
|
||||
select nusers(port(neg1, \Y)) == 2
|
||||
index <SigSpec> port(neg1, \Y) === add_a
|
||||
set neg1_a port(neg1, \A)
|
||||
set neg1_signed neg1->getParam(\A_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
match neg2
|
||||
select neg2->type == $neg
|
||||
select nusers(port(neg2, \Y)) == 2
|
||||
index <SigSpec> port(neg2, \Y) === add_b
|
||||
set neg2_a port(neg2, \A)
|
||||
set neg2_signed neg2->getParam(\A_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
code add_a add_b add_y neg1_a neg2_a add_signed add_b_signed neg1_signed neg2_signed
|
||||
if (add_signed != add_b_signed)
|
||||
reject;
|
||||
|
||||
if (neg1_signed != add_signed || neg2_signed != add_signed)
|
||||
reject;
|
||||
|
||||
{
|
||||
int width = GetSize(add_y);
|
||||
|
||||
SigSpec sum = module->addWire(NEW_ID, width);
|
||||
Cell *new_add = module->addAdd(NEW_ID, neg1_a, neg2_a, sum, add_signed);
|
||||
Cell *new_neg = module->addNeg(NEW_ID, sum, add_y, add_signed);
|
||||
|
||||
log("negrebuild pattern in %s: add=%s, neg1=%s, neg2=%s\n",
|
||||
log_id(module), log_id(add), log_id(neg1), log_id(neg2));
|
||||
|
||||
new_add->fixup_parameters();
|
||||
new_neg->fixup_parameters();
|
||||
autoremove(add);
|
||||
autoremove(neg1);
|
||||
autoremove(neg2);
|
||||
did_something = true;
|
||||
}
|
||||
accept;
|
||||
endcode
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
pattern sub2neg
|
||||
//
|
||||
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
|
||||
//
|
||||
// Convert subtraction to addition with negation
|
||||
//
|
||||
// a - b ===> a + (-b)
|
||||
//
|
||||
|
||||
state <SigSpec> sub_a sub_b sub_y
|
||||
state <bool> a_signed b_signed
|
||||
|
||||
match sub
|
||||
select sub->type == $sub
|
||||
filter !sub->getPort(\B).is_fully_const()
|
||||
set sub_a port(sub, \A)
|
||||
set sub_b port(sub, \B)
|
||||
set sub_y port(sub, \Y)
|
||||
set a_signed sub->getParam(\A_SIGNED).as_bool()
|
||||
set b_signed sub->getParam(\B_SIGNED).as_bool()
|
||||
endmatch
|
||||
|
||||
code sub_a sub_b sub_y a_signed b_signed
|
||||
if (a_signed != b_signed)
|
||||
reject;
|
||||
|
||||
{
|
||||
int width = GetSize(sub_y);
|
||||
SigSpec neg_y = module->addWire(NEW_ID, width);
|
||||
Cell *neg = module->addNeg(NEW_ID, sub_b, neg_y, b_signed);
|
||||
Cell *add = module->addAdd(NEW_ID, sub_a, neg_y, sub_y, a_signed);
|
||||
|
||||
log("sub2neg pattern in %s: sub=%s -> neg=%s, add=%s\n",
|
||||
log_id(module), log_id(sub), log_id(neg), log_id(add));
|
||||
|
||||
neg->fixup_parameters();
|
||||
add->fixup_parameters();
|
||||
autoremove(sub);
|
||||
did_something = true;
|
||||
}
|
||||
accept;
|
||||
endcode
|
||||
|
|
@ -2873,4 +2873,4 @@ struct AbcPass : public Pass {
|
|||
}
|
||||
} AbcPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
@ -708,6 +708,16 @@ class PyosysWrapperGenerator(object):
|
|||
|
||||
self.process_class_members(metadata, metadata, cls, basename)
|
||||
|
||||
if basename == "Design":
|
||||
print(
|
||||
'\t\t\t.def("run_pass", [](Design &s, std::vector<std::string> cmd) { Pass::call(&s, cmd); })',
|
||||
file=self.f,
|
||||
)
|
||||
print(
|
||||
'\t\t\t.def("run_pass", [](Design &s, std::string cmd) { Pass::call(&s, cmd); })',
|
||||
file=self.f,
|
||||
)
|
||||
|
||||
if expr := metadata.string_expr:
|
||||
print(
|
||||
f'\t\t.def("__str__", [](const {basename} &s) {{ return {expr}; }})',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
from pathlib import Path
|
||||
from pyosys import libyosys as ys
|
||||
|
||||
__file_dir__ = Path(__file__).absolute().parent
|
||||
add_sub = __file_dir__.parent / "arch" / "common" / "add_sub.v"
|
||||
|
||||
base = ys.Design()
|
||||
base.run_pass(["read_verilog", str(add_sub)])
|
||||
base.run_pass("hierarchy -top top")
|
||||
base.run_pass(["proc"])
|
||||
base.run_pass("equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5")
|
||||
|
||||
postopt = ys.Design()
|
||||
postopt.run_pass("design -load postopt")
|
||||
postopt.run_pass(["cd", "top"])
|
||||
postopt.run_pass("select -assert-min 25 t:LUT4")
|
||||
postopt.run_pass("select -assert-max 26 t:LUT4")
|
||||
postopt.run_pass(["select", "-assert-count", "10", "t:PFUMX"])
|
||||
postopt.run_pass(["select", "-assert-count", "6", "t:L6MUX21"])
|
||||
postopt.run_pass("select -assert-none t:LUT4 t:PFUMX t:L6MUX21 %% t:* %D")
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
log -header "Positive case: (a + ~b) + 1 => a - b => a + (-b)"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
input wire [7:0] a;
|
||||
input wire [7:0] b;
|
||||
output wire [7:0] y;
|
||||
|
||||
assign y = (a + ~b) + 1;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$add
|
||||
select -assert-count 1 t:$neg
|
||||
select -assert-none t:$not
|
||||
select -assert-none t:$sub
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Positive case B: 1 + (a + ~b) => a - b => a + (-b)"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
input wire [7:0] a;
|
||||
input wire [7:0] b;
|
||||
output wire [7:0] y;
|
||||
|
||||
assign y = 1 + (a + ~b);
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$add
|
||||
select -assert-count 1 t:$neg
|
||||
select -assert-none t:$not
|
||||
select -assert-none t:$sub
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Negative case: fanout on inner add output"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y, z);
|
||||
input wire [7:0] a;
|
||||
input wire [7:0] b;
|
||||
output wire [7:0] y;
|
||||
output wire [7:0] z;
|
||||
(* keep *) wire [7:0] s;
|
||||
assign s = a + ~b;
|
||||
assign y = s + 1;
|
||||
assign z = s + a;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
# Should NOT transform due to fanout on inner add output (marked with keep)
|
||||
select -assert-count 3 t:$add
|
||||
select -assert-count 1 t:$not
|
||||
select -assert-none t:$sub
|
||||
select -assert-none t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
log -header "Simple positive case"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, s, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
input wire s;
|
||||
output wire signed [7:0] y;
|
||||
assign y = s ? (-a) : (-b);
|
||||
endmodule
|
||||
EOF
|
||||
check -assert
|
||||
equiv_opt -assert negopt -post
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$mux
|
||||
select -assert-count 1 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "With intermediate signals"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, s, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
input wire s;
|
||||
output wire signed [7:0] y;
|
||||
wire signed [7:0] neg_a;
|
||||
wire signed [7:0] neg_b;
|
||||
assign neg_a = -a;
|
||||
assign neg_b = -b;
|
||||
assign y = s ? neg_a : neg_b;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -post
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$mux
|
||||
select -assert-count 1 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
log -header "Simple positive case (negation on port B)"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
output wire signed [8:0] y;
|
||||
assign y = a + (-b);
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -post
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$sub
|
||||
select -assert-none t:$add
|
||||
select -assert-none t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Positive case (negation on port A)"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
output wire signed [8:0] y;
|
||||
assign y = (-a) + b;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -post
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$sub
|
||||
select -assert-none t:$add
|
||||
select -assert-none t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
log -header "Simple positive case (same width)"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
output wire signed [7:0] y;
|
||||
assign y = -(a + b);
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$add
|
||||
select -assert-count 2 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Width extension case (output wider than inputs)"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
output wire signed [9:0] y;
|
||||
assign y = -(a + b);
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
# Negations should use output width (9 bits) not input width (8 bits)
|
||||
select -assert-count 1 t:$add
|
||||
select -assert-count 2 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Negative case: fanout on add output"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y, z);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
output wire signed [7:0] y;
|
||||
output wire signed [7:0] z;
|
||||
(* keep *) wire signed [7:0] sum;
|
||||
assign sum = a + b;
|
||||
assign y = -sum;
|
||||
assign z = sum;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
# Should NOT transform due to extra fanout on add output
|
||||
select -assert-count 1 t:$add
|
||||
select -assert-count 1 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
log -header "Simple positive case"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, s, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
input wire s;
|
||||
output wire signed [7:0] y;
|
||||
assign y = -(s ? a : b);
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$mux
|
||||
select -assert-count 2 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "With intermediate signal"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, s, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
input wire s;
|
||||
output wire signed [7:0] y;
|
||||
wire signed [7:0] m;
|
||||
assign m = s ? a : b;
|
||||
assign y = -m;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$mux
|
||||
select -assert-count 2 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Negative case: mux output has extra fanout"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, s, y, z);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
input wire s;
|
||||
output wire signed [7:0] y;
|
||||
output wire signed [7:0] z;
|
||||
(* keep *) wire signed [7:0] m;
|
||||
assign m = s ? a : b;
|
||||
assign y = -m;
|
||||
assign z = m;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
# Should NOT transform due to extra fanout on mux output
|
||||
select -assert-count 1 t:$mux
|
||||
select -assert-count 1 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
log -header "Simple positive case"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, y);
|
||||
input wire signed [7:0] a;
|
||||
output wire signed [7:0] y;
|
||||
assign y = -(-a);
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
select -assert-none t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "With intermediate signal"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, y);
|
||||
input wire signed [7:0] a;
|
||||
output wire signed [7:0] y;
|
||||
wire signed [7:0] neg_a;
|
||||
assign neg_a = -a;
|
||||
assign y = -neg_a;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
select -assert-none t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Negative case: extra fanout on inner neg"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, y, z);
|
||||
input wire signed [7:0] a;
|
||||
output wire signed [7:0] y;
|
||||
output wire signed [7:0] z;
|
||||
(* keep *) wire signed [7:0] neg_a;
|
||||
assign neg_a = -a;
|
||||
assign y = -neg_a;
|
||||
assign z = neg_a;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
# Should NOT transform due to extra fanout on inner neg output
|
||||
select -assert-count 2 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
log -header "Simple positive case (same width)"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
output wire signed [7:0] y;
|
||||
assign y = (-a) + (-b);
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -post
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$add
|
||||
select -assert-count 1 t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
log -header "Simple positive case"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, y);
|
||||
input wire signed [7:0] a;
|
||||
input wire signed [7:0] b;
|
||||
output wire signed [7:0] y;
|
||||
assign y = a - b;
|
||||
endmodule
|
||||
EOF
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$add
|
||||
select -assert-count 1 t:$neg
|
||||
select -assert-none t:$sub
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Negative case: constant subtrahend"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, y);
|
||||
input wire signed [7:0] a;
|
||||
output wire signed [7:0] y;
|
||||
assign y = a - 8'd5;
|
||||
endmodule
|
||||
EOF
|
||||
check -assert
|
||||
equiv_opt -assert negopt -pre
|
||||
design -load postopt
|
||||
# Should NOT transform because constant subtraction is kept as $sub
|
||||
select -assert-count 1 t:$sub
|
||||
select -assert-none t:$add
|
||||
select -assert-none t:$neg
|
||||
design -reset
|
||||
log -pop
|
||||
Loading…
Reference in New Issue