mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'main' into remove_filter_non_trigger_outputs
This commit is contained in:
commit
60d5e40897
|
|
@ -1593,6 +1593,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
Instance *inst;
|
||||
PortRef *pr;
|
||||
Att *attr;
|
||||
pool<Net*> empty_port_nets;
|
||||
|
||||
FOREACH_ATTRIBUTE(nl, mi, attr) {
|
||||
if (!strcmp(attr->Key(), "noblackbox"))
|
||||
|
|
@ -1604,6 +1605,12 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
if (port->Bus())
|
||||
continue;
|
||||
|
||||
if (port->GetAtt(" empty_port")) {
|
||||
if (port->GetNet())
|
||||
empty_port_nets.insert(port->GetNet());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verific_verbose)
|
||||
log(" importing port %s.\n", port->Name());
|
||||
|
||||
|
|
@ -1687,6 +1694,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
|
||||
FOREACH_NET_OF_NETLIST(nl, mi, net)
|
||||
{
|
||||
if (empty_port_nets.count(net))
|
||||
continue;
|
||||
|
||||
if (net->IsRamNet())
|
||||
{
|
||||
RTLIL::Memory *memory = new RTLIL::Memory;
|
||||
|
|
@ -2291,6 +2301,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
}
|
||||
|
||||
FOREACH_PORTREF_OF_INST(inst, mi2, pr) {
|
||||
if (pr->GetPort()->GetAtt(" empty_port"))
|
||||
continue;
|
||||
if (verific_verbose)
|
||||
log(" .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name());
|
||||
const char *port_name = pr->GetPort()->Name();
|
||||
|
|
|
|||
|
|
@ -96,10 +96,17 @@ fstHandle FstData::getHandle(std::string name) {
|
|||
return 0;
|
||||
};
|
||||
|
||||
dict<int,fstHandle> FstData::getMemoryHandles(std::string name) {
|
||||
dict<int,fstHandle> FstData::getMemoryHandles(std::string name) {
|
||||
if (memory_to_handle.find(name) != memory_to_handle.end())
|
||||
return memory_to_handle[name];
|
||||
else
|
||||
else
|
||||
return dict<int,fstHandle>();
|
||||
};
|
||||
|
||||
dict<int,fstHandle> FstData::getArrayHandles(std::string name) {
|
||||
if (array_to_handle.find(name) != array_to_handle.end())
|
||||
return array_to_handle[name];
|
||||
else
|
||||
return dict<int,fstHandle>();
|
||||
};
|
||||
|
||||
|
|
@ -195,13 +202,38 @@ void FstData::extractVarNames()
|
|||
}
|
||||
if (clean_name[0]=='\\')
|
||||
clean_name = clean_name.substr(1);
|
||||
|
||||
// Strip bit ranges like [4:0] from the end (only if no space)
|
||||
if (!has_space) {
|
||||
size_t pos = clean_name.find_last_of("[");
|
||||
std::string index_or_range = clean_name.substr(pos+1);
|
||||
if (index_or_range.find(":") != std::string::npos) {
|
||||
clean_name = clean_name.substr(0,pos);
|
||||
if (pos != std::string::npos) {
|
||||
std::string index_or_range = clean_name.substr(pos+1);
|
||||
if (index_or_range.find(":") != std::string::npos) {
|
||||
clean_name = clean_name.substr(0,pos);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Handle "signal [index][bitrange]" format
|
||||
std::string full_name = h->u.var.name;
|
||||
size_t space_pos = full_name.find(' ');
|
||||
if (space_pos != std::string::npos) {
|
||||
std::string suffix = full_name.substr(space_pos + 1);
|
||||
// Parse first bracket pair for array index
|
||||
if (!suffix.empty() && suffix[0] == '[') {
|
||||
size_t close_bracket = suffix.find(']');
|
||||
if (close_bracket != std::string::npos) {
|
||||
std::string index_str = suffix.substr(1, close_bracket - 1);
|
||||
// Check it's an array index (no colon), not a bit range
|
||||
if (index_str.find(':') == std::string::npos) {
|
||||
int array_index = std::stoi(index_str);
|
||||
array_to_handle[var.scope+"."+clean_name][array_index] = var.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle memory addresses
|
||||
size_t pos = clean_name.find_last_of("<");
|
||||
if (pos != std::string::npos && clean_name.back() == '>') {
|
||||
std::string mem_cell = clean_name.substr(0, pos);
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class FstData
|
|||
std::string valueOf(fstHandle signal);
|
||||
fstHandle getHandle(std::string name);
|
||||
dict<int,fstHandle> getMemoryHandles(std::string name);
|
||||
dict<int,fstHandle> getArrayHandles(std::string name);
|
||||
double getTimescale() { return timescale; }
|
||||
const char *getTimescaleString() { return timescale_str.c_str(); }
|
||||
int getWidth(fstHandle signal);
|
||||
|
|
@ -67,6 +68,7 @@ private:
|
|||
std::map<fstHandle, FstVar> handle_to_var;
|
||||
std::map<std::string, fstHandle> name_to_handle;
|
||||
std::map<std::string, dict<int, fstHandle>> memory_to_handle;
|
||||
std::map<std::string, dict<int, fstHandle>> array_to_handle;
|
||||
std::map<fstHandle, std::string> last_data;
|
||||
uint64_t last_time;
|
||||
std::map<fstHandle, std::string> past_data;
|
||||
|
|
|
|||
|
|
@ -224,6 +224,53 @@ struct SimInstance
|
|||
dict<Wire*, fstHandle> fst_inputs;
|
||||
dict<IdString, dict<int,fstHandle>> fst_memories;
|
||||
|
||||
// For multi-dimensional arrays
|
||||
dict<Wire*, dict<int,fstHandle>> fst_array_handles;
|
||||
dict<Wire*, dict<int,fstHandle>> fst_array_inputs;
|
||||
|
||||
// Helper function to detect and retrieve array element handles
|
||||
// Returns non-empty dict if wire is a multi-dimensional array split in VCD
|
||||
dict<int, fstHandle> tryGetArrayHandles(FstData* fst, const std::string& scope, Wire* wire)
|
||||
{
|
||||
std::string wire_name = scope + "." + RTLIL::unescape_id(wire->name);
|
||||
dict<int, fstHandle> array_handles = fst->getArrayHandles(wire_name);
|
||||
|
||||
if (!array_handles.empty()) {
|
||||
int total_width = 0;
|
||||
for (auto &pair : array_handles) {
|
||||
total_width += fst->getWidth(pair.second);
|
||||
}
|
||||
if (total_width == wire->width) {
|
||||
if (shared->debug) {
|
||||
log("Found %zu array elements for wire %s, total width: %d\n",
|
||||
array_handles.size(), wire_name.c_str(), total_width);
|
||||
}
|
||||
return array_handles;
|
||||
}
|
||||
log_warning("Array wire '%s' found in VCD (total width %d) but does not match Yosys wire width %d; skipping.\n",
|
||||
wire_name.c_str(), total_width, wire->width);
|
||||
}
|
||||
return dict<int, fstHandle>();
|
||||
}
|
||||
|
||||
// Helper function to set wire state from array element handles
|
||||
// Concatenates values from array elements in descending index order
|
||||
bool setStateFromArrayHandles(Wire* wire, dict<int, fstHandle>& handles)
|
||||
{
|
||||
// Collect and sort indices in descending order (MSB = highest index)
|
||||
std::vector<int> indices;
|
||||
for (auto &kv : handles)
|
||||
indices.push_back(kv.first);
|
||||
std::sort(indices.begin(), indices.end(), std::greater<int>());
|
||||
|
||||
// Concatenate values in descending index order
|
||||
std::string concatenated = "";
|
||||
for (int idx : indices) {
|
||||
concatenated += shared->fst->valueOf(handles[idx]);
|
||||
}
|
||||
return set_state(wire, Const::from_string(concatenated));
|
||||
}
|
||||
|
||||
SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
|
||||
shared(shared), scope(scope), module(module), instance(instance), parent(parent), sigmap(module)
|
||||
{
|
||||
|
|
@ -255,18 +302,25 @@ struct SimInstance
|
|||
}
|
||||
}
|
||||
|
||||
// Populate fst_handles and fst_array_handles for signal lookups
|
||||
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()) {
|
||||
if (shared->debug) {
|
||||
log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
|
||||
}
|
||||
} else {
|
||||
|
||||
// Try to get array element handles if this is a multi-dimensional array
|
||||
dict<int, fstHandle> array_handles = tryGetArrayHandles(shared->fst, scope, wire);
|
||||
if (!array_handles.empty()) {
|
||||
// Must be an array, store in fst_array_handles
|
||||
fst_array_handles[wire] = array_handles;
|
||||
} else if (id != 0) {
|
||||
// Case of a regular wire/reg
|
||||
fst_handles[wire] = id;
|
||||
if (shared->debug) {
|
||||
log("Found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
|
||||
}
|
||||
} else if (wire->name.isPublic() && shared->debug) {
|
||||
// Not found
|
||||
log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
|
||||
}
|
||||
fst_handles[wire] = id;
|
||||
}
|
||||
|
||||
if (wire->attributes.count(ID::init)) {
|
||||
|
|
@ -1178,6 +1232,10 @@ struct SimInstance
|
|||
std::string v = shared->fst->valueOf(item.second);
|
||||
did_something |= set_state(item.first, Const::from_string(v));
|
||||
}
|
||||
// Handle multi-dimensional arrays by concatenating array elements
|
||||
for(auto &item : fst_array_handles) {
|
||||
did_something |= setStateFromArrayHandles(item.first, item.second);
|
||||
}
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
if (cell->is_mem_cell()) {
|
||||
|
|
@ -1227,7 +1285,10 @@ struct SimInstance
|
|||
std::string v = shared->fst->valueOf(item.second);
|
||||
did_something |= set_state(item.first, Const::from_string(v));
|
||||
}
|
||||
|
||||
// Handle multi-dimensional array inputs by concatenating array elements
|
||||
for(auto &item : fst_array_inputs) {
|
||||
did_something |= setStateFromArrayHandles(item.first, item.second);
|
||||
}
|
||||
for (auto child : children)
|
||||
did_something |= child.second->setInputs();
|
||||
|
||||
|
|
@ -1523,11 +1584,23 @@ struct SimWorker : SimShared
|
|||
SigMap sigmap(topmod);
|
||||
|
||||
for (auto wire : topmod->wires()) {
|
||||
|
||||
// Populate fst_inputs and fst_array_inputs for input ports
|
||||
if (wire->port_input) {
|
||||
fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
|
||||
if (id==0)
|
||||
|
||||
// Try to get array element handles if this is a multi-dimensional array
|
||||
dict<int, fstHandle> array_handles = top->tryGetArrayHandles(fst, scope, wire);
|
||||
if (!array_handles.empty()) {
|
||||
// Must be an array, store in fst_array_inputs
|
||||
top->fst_array_inputs[wire] = array_handles;
|
||||
} else if (id != 0) {
|
||||
// Case of a regular wire/reg
|
||||
top->fst_inputs[wire] = id;
|
||||
} else {
|
||||
// Not found
|
||||
log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name)));
|
||||
top->fst_inputs[wire] = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,33 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
bool did_something;
|
||||
|
||||
// Normalize top-end sign/zero extension for PMG prefiltering.
|
||||
// Strips any redundant high bits so that a sign- or zero-extended SigSpec
|
||||
// and its narrower original compare equal under index lookups.
|
||||
// - top == prev: sign extension (MSB replicated)
|
||||
// - top == SigBit(State::S0): zero extension (constant-zero padding)
|
||||
// Only the prefilter key is stripped; exact legality is re-checked in the
|
||||
// code block, so false-positive index hits are safe.
|
||||
static SigSpec strip_ext_for_match(SigSpec sig)
|
||||
{
|
||||
int n = GetSize(sig);
|
||||
if (n <= 1)
|
||||
return sig;
|
||||
|
||||
while (n > 1) {
|
||||
SigBit top = sig[n-1];
|
||||
SigBit prev = sig[n-2];
|
||||
// Strip sign-extended (repeated MSB) or zero-extended (S0) bits
|
||||
if (top == prev || top == SigBit(State::S0)) {
|
||||
n--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return sig.extract(0, n);
|
||||
}
|
||||
|
||||
#include "passes/silimate/peepopt_negopt.h"
|
||||
|
||||
struct NegoptPass : public Pass {
|
||||
|
|
@ -51,7 +78,7 @@ struct NegoptPass : public Pass {
|
|||
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("Specify exactly one of -pre or -post.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,8 +169,8 @@ code root_add inner_add_B not_gate_B minuend subtrahend result_sig is_signed
|
|||
|
||||
// Verify inner_add_B has the form (~b + 1): one port is constant 1,
|
||||
// the other is the NOT output
|
||||
SigSpec pa = inner_add_B->getPort(ID::A);
|
||||
SigSpec pb = inner_add_B->getPort(ID::B);
|
||||
SigSpec pa = port(inner_add_B, \A);
|
||||
SigSpec pb = port(inner_add_B, \B);
|
||||
SigSpec not_y = port(not_gate_B, \Y);
|
||||
|
||||
auto is_one = [](SigSpec s) {
|
||||
|
|
@ -191,7 +191,7 @@ code root_add inner_add_B not_gate_B minuend subtrahend result_sig is_signed
|
|||
|
||||
// The minuend is whichever root_add port is NOT the inner_add_B output
|
||||
subtrahend = port(not_gate_B, \A);
|
||||
if (inner_add_B->getPort(ID::Y) == root_add->getPort(ID::A))
|
||||
if (port(inner_add_B, \Y) == port(root_add, \A))
|
||||
minuend = root_b;
|
||||
else
|
||||
minuend = root_a;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ code mux_a mux_b mux_s mux_y neg_a_in neg_a_y neg_b_in neg_b_y neg_a_signed neg_
|
|||
SigSpec neg_a_rs = neg_a_in;
|
||||
SigSpec neg_b_rs = neg_b_in;
|
||||
neg_a_rs.extend_u0(width, neg_a_signed);
|
||||
neg_b_rs.extend_u0(width, neg_a_signed);
|
||||
neg_b_rs.extend_u0(width, neg_b_signed);
|
||||
|
||||
SigSpec mux_out = module->addWire(NEW_ID2_SUFFIX("y"), width);
|
||||
Cell *new_mux = module->addMux(NEW_ID2_SUFFIX("mux"), neg_a_rs, neg_b_rs, mux_s, mux_out);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ pattern negmux
|
|||
// -(s ? a : b) ===> s ? (-a) : (-b)
|
||||
//
|
||||
|
||||
state <SigSpec> neg_a neg_y mux_a mux_b mux_s mux_y
|
||||
state <SigSpec> neg_a neg_y neg_a_norm mux_a mux_b mux_s mux_y
|
||||
state <bool> a_signed
|
||||
|
||||
match neg
|
||||
|
|
@ -15,11 +15,13 @@ match neg
|
|||
set neg_a port(neg, \A)
|
||||
set neg_y port(neg, \Y)
|
||||
set a_signed neg->getParam(\A_SIGNED).as_bool()
|
||||
set neg_a_norm strip_ext_for_match(neg_a)
|
||||
endmatch
|
||||
|
||||
match mux
|
||||
select mux->type == $mux
|
||||
select nusers(port(mux, \Y)) == 2
|
||||
index <SigSpec> strip_ext_for_match(port(mux, \Y)) === neg_a_norm
|
||||
filter nusers(port(mux, \Y)) == 2
|
||||
set mux_a port(mux, \A)
|
||||
set mux_b port(mux, \B)
|
||||
set mux_s port(mux, \S)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ match neg2
|
|||
endmatch
|
||||
|
||||
code neg1_a neg1_y neg2_a
|
||||
// Reject if inner negation truncates
|
||||
// Reject if the inner negation widens its output
|
||||
if (GetSize(neg1_a) > GetSize(neg2_a))
|
||||
reject;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ pattern negrebuild
|
|||
// (-a) + (-b) ===> -(a + b)
|
||||
//
|
||||
|
||||
state <SigSpec> add_a add_b add_y neg1_a neg1_y neg2_a neg2_y
|
||||
state <bool> add_signed add_b_signed neg1_signed neg2_signed
|
||||
state <SigSpec> add_a add_b add_y add_a_norm add_b_norm neg1_a neg1_y neg2_a neg2_y
|
||||
state <bool> add_signed add_b_signed neg1_signed neg2_signed neg1_on_a
|
||||
|
||||
match add
|
||||
select add->type == $add
|
||||
|
|
@ -17,11 +17,20 @@ match add
|
|||
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()
|
||||
set add_a_norm strip_ext_for_match(add_a)
|
||||
set add_b_norm strip_ext_for_match(add_b)
|
||||
endmatch
|
||||
|
||||
code neg1_on_a
|
||||
neg1_on_a = true;
|
||||
branch;
|
||||
neg1_on_a = false;
|
||||
endcode
|
||||
|
||||
match neg1
|
||||
select neg1->type == $neg
|
||||
select nusers(port(neg1, \Y)) == 2
|
||||
index <SigSpec> strip_ext_for_match(port(neg1, \Y)) === (neg1_on_a ? add_a_norm : add_b_norm)
|
||||
filter nusers(port(neg1, \Y)) == 2
|
||||
set neg1_a port(neg1, \A)
|
||||
set neg1_y port(neg1, \Y)
|
||||
set neg1_signed neg1->getParam(\A_SIGNED).as_bool()
|
||||
|
|
@ -29,7 +38,8 @@ endmatch
|
|||
|
||||
match neg2
|
||||
select neg2->type == $neg
|
||||
select nusers(port(neg2, \Y)) == 2
|
||||
index <SigSpec> strip_ext_for_match(port(neg2, \Y)) === (neg1_on_a ? add_b_norm : add_a_norm)
|
||||
filter nusers(port(neg2, \Y)) == 2
|
||||
set neg2_a port(neg2, \A)
|
||||
set neg2_y port(neg2, \Y)
|
||||
set neg2_signed neg2->getParam(\A_SIGNED).as_bool()
|
||||
|
|
|
|||
|
|
@ -113,12 +113,18 @@ struct RegRenameInstance {
|
|||
newWire = module->addWire(RTLIL::escape_id(baseName), origRegWidth);
|
||||
}
|
||||
|
||||
// Check if the bit index exceeds the actual wire width before creating SigSpec
|
||||
if (index >= newWire->width) {
|
||||
log_warning("Register bit index %d exceeds wire width %d for '%s' in scope '%s'. Skipping.\n",
|
||||
index, newWire->width, baseName.c_str(), vcd_scope.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Log the connection of the new wire to the register
|
||||
log_debug("Connecting register wire %s[%d] to bit %d of %s in module %s\n",
|
||||
newWire->name.c_str(), index, index, log_id(newWire), log_id(module));
|
||||
|
||||
// Replace old connection with a new one even at the input ports of subsequent cells from the register
|
||||
// output
|
||||
// Replace old connection with a new one even at the input ports of subsequent cells from the register output
|
||||
auto rewriter = [&](SigSpec &sig) { sig.replace(SigBit(oldWire), SigSpec(newWire, index, 1)); };
|
||||
module->rewrite_sigspecs(rewriter);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,56 @@ select -assert-count 2 t:$neg
|
|||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Positive case: neg input is sign extension of mux output"
|
||||
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 [11:0] y;
|
||||
wire signed [7:0] m;
|
||||
wire signed [11:0] m_ext;
|
||||
assign m = s ? a : b;
|
||||
assign m_ext = m;
|
||||
assign y = -m_ext;
|
||||
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 "Positive case: neg input is zero extension of mux output"
|
||||
log -push
|
||||
design -reset
|
||||
read_verilog <<EOF
|
||||
module top(a, b, s, y);
|
||||
input wire [7:0] a;
|
||||
input wire [7:0] b;
|
||||
input wire s;
|
||||
output wire [11:0] y;
|
||||
wire [7:0] m;
|
||||
wire [11:0] m_ext;
|
||||
assign m = s ? a : b;
|
||||
assign m_ext = m;
|
||||
assign y = -m_ext;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -40,6 +40,35 @@ select -assert-none t:$sub
|
|||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Negative case: add inputs are sign-extended neg outputs"
|
||||
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 [11:0] y;
|
||||
wire signed [7:0] na;
|
||||
wire signed [7:0] nb;
|
||||
wire signed [11:0] na_ext;
|
||||
wire signed [11:0] nb_ext;
|
||||
assign na = -a;
|
||||
assign nb = -b;
|
||||
assign na_ext = na;
|
||||
assign nb_ext = nb;
|
||||
assign y = na_ext + nb_ext;
|
||||
endmodule
|
||||
EOF
|
||||
proc; opt
|
||||
check -assert
|
||||
equiv_opt -assert negopt -post
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$add
|
||||
select -assert-count 2 t:$neg
|
||||
select -assert-none t:$sub
|
||||
design -reset
|
||||
log -pop
|
||||
|
||||
log -header "Anchor case: neg branches with different widths"
|
||||
log -push
|
||||
design -reset
|
||||
|
|
|
|||
Loading…
Reference in New Issue