mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-21 06:35:49 +00:00
Merge from upstream
This commit is contained in:
commit
e54fa487b8
29 changed files with 1314 additions and 793 deletions
|
|
@ -373,6 +373,12 @@ struct AbstractPass : public Pass {
|
|||
log(" abstractions performed by either mode. This option is not supported in\n");
|
||||
log(" the -init mode.\n");
|
||||
log("\n");
|
||||
log(" -initstates <n>\n");
|
||||
log(" Perform conditional abstraction for the first <n> time steps. See the\n");
|
||||
log(" description of the -state and -value modes for details on how the\n");
|
||||
log(" condition affects the abstractions performed by either mode. This option\n");
|
||||
log(" is not supported in the -init mode.\n");
|
||||
log("\n");
|
||||
log(" -slice <lhs>:<rhs>\n");
|
||||
log(" -slice <index>\n");
|
||||
log(" -rtlilslice <lhs>:<rhs>\n");
|
||||
|
|
@ -402,8 +408,10 @@ struct AbstractPass : public Pass {
|
|||
Always = -1,
|
||||
ActiveLow = false, // ensuring we can use bool(enable)
|
||||
ActiveHigh = true,
|
||||
Initstates = 2,
|
||||
};
|
||||
Enable enable = Enable::Always;
|
||||
int initstates = 0;
|
||||
std::string enable_name;
|
||||
std::vector<Slice> slices;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
|
@ -435,6 +443,13 @@ struct AbstractPass : public Pass {
|
|||
enable = Enable::ActiveLow;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-initstates" && argidx + 1 < args.size()) {
|
||||
if (enable != Enable::Always)
|
||||
log_cmd_error("Multiple enable condition are not supported\n");
|
||||
initstates = atoi(args[++argidx].c_str());
|
||||
enable = Enable::Initstates;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-slice" && argidx + 1 < args.size()) {
|
||||
slices.emplace_back(SliceIndices::HdlSlice, args[++argidx]);
|
||||
continue;
|
||||
|
|
@ -451,22 +466,50 @@ struct AbstractPass : public Pass {
|
|||
if (mode == Mode::Initial)
|
||||
log_cmd_error("Conditional initial value abstraction is not supported\n");
|
||||
|
||||
if (enable_name.empty())
|
||||
log_cmd_error("Unspecified enable wire\n");
|
||||
switch (enable) {
|
||||
case Enable::Always:
|
||||
log_assert(false);
|
||||
case Enable::ActiveLow:
|
||||
case Enable::ActiveHigh: {
|
||||
if (enable_name.empty())
|
||||
log_cmd_error("Unspecified enable wire\n");
|
||||
} break;
|
||||
case Enable::Initstates: {
|
||||
if (initstates <= 0)
|
||||
log_cmd_error("Number of initial time steps must be positive\n");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int changed = 0;
|
||||
if ((mode == State) || (mode == Value)) {
|
||||
for (auto mod : design->selected_modules()) {
|
||||
EnableLogic enable_logic = { State::S1, true };
|
||||
if (enable != Enable::Always) {
|
||||
Wire *enable_wire = mod->wire("\\" + enable_name);
|
||||
if (!enable_wire)
|
||||
log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str());
|
||||
if (GetSize(enable_wire) != 1)
|
||||
log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n",
|
||||
enable_name.c_str(), GetSize(enable_wire), mod->name.c_str());
|
||||
enable_logic = { enable_wire, enable == Enable::ActiveHigh };
|
||||
EnableLogic enable_logic;
|
||||
|
||||
switch (enable) {
|
||||
case Enable::Always: {
|
||||
enable_logic = { State::S1, true };
|
||||
} break;
|
||||
case Enable::ActiveLow:
|
||||
case Enable::ActiveHigh: {
|
||||
Wire *enable_wire = mod->wire("\\" + enable_name);
|
||||
if (!enable_wire)
|
||||
log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str());
|
||||
if (GetSize(enable_wire) != 1)
|
||||
log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n",
|
||||
enable_name.c_str(), GetSize(enable_wire), mod->name.c_str());
|
||||
enable_logic = { enable_wire, enable == Enable::ActiveHigh };
|
||||
} break;
|
||||
case Enable::Initstates: {
|
||||
SigBit in_init_states = mod->Initstate(NEW_ID);
|
||||
for (int i = 1; i < initstates; i++) {
|
||||
Wire *in_init_states_q = mod->addWire(NEW_ID);
|
||||
mod->addFf(NEW_ID, in_init_states, in_init_states_q);
|
||||
in_init_states_q->attributes[ID::init] = State::S1;
|
||||
in_init_states = in_init_states_q;
|
||||
}
|
||||
enable_logic = { in_init_states, true };
|
||||
} break;
|
||||
}
|
||||
if (mode == State)
|
||||
changed += abstract_state(mod, enable_logic, slices);
|
||||
|
|
|
|||
|
|
@ -195,16 +195,23 @@ struct CheckPass : public Pass {
|
|||
// in port widths are those for us to check.
|
||||
if (!cell->type.in(
|
||||
ID($add), ID($sub),
|
||||
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
|
||||
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
|
||||
ID($pmux), ID($bmux)))
|
||||
return false;
|
||||
|
||||
int in_widths = 0, out_widths = 0;
|
||||
|
||||
for (auto &conn : cell->connections()) {
|
||||
if (cell->input(conn.first))
|
||||
in_widths += conn.second.size();
|
||||
if (cell->output(conn.first))
|
||||
out_widths += conn.second.size();
|
||||
if (cell->type.in(ID($pmux), ID($bmux))) {
|
||||
// We're skipping inputs A and B, since each of their bits contributes only one edge
|
||||
in_widths = GetSize(cell->getPort(ID::S));
|
||||
out_widths = GetSize(cell->getPort(ID::Y));
|
||||
} else {
|
||||
for (auto &conn : cell->connections()) {
|
||||
if (cell->input(conn.first))
|
||||
in_widths += conn.second.size();
|
||||
if (cell->output(conn.first))
|
||||
out_widths += conn.second.size();
|
||||
}
|
||||
}
|
||||
|
||||
const int threshold = 1024;
|
||||
|
|
|
|||
|
|
@ -598,6 +598,8 @@ struct RenamePass : public Pass {
|
|||
|
||||
for (auto &it : new_cell_names)
|
||||
module->rename(it.first, it.second);
|
||||
|
||||
module->fixup_ports();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -44,20 +44,16 @@ struct OptMergeWorker
|
|||
CellTypes ct;
|
||||
int total_count;
|
||||
|
||||
static vector<pair<SigBit, SigSpec>> sorted_pmux_in(const dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
|
||||
static Hasher hash_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b, Hasher h)
|
||||
{
|
||||
SigSpec sig_s = conn.at(ID::S);
|
||||
SigSpec sig_b = conn.at(ID::B);
|
||||
|
||||
int s_width = GetSize(sig_s);
|
||||
int width = GetSize(sig_b) / s_width;
|
||||
|
||||
vector<pair<SigBit, SigSpec>> sb_pairs;
|
||||
hashlib::commutative_hash comm;
|
||||
for (int i = 0; i < s_width; i++)
|
||||
sb_pairs.push_back(pair<SigBit, SigSpec>(sig_s[i], sig_b.extract(i*width, width)));
|
||||
comm.eat(hash_ops<std::pair<SigBit, SigSpec>>::hash({sig_s[i], sig_b.extract(i*width, width)}));
|
||||
|
||||
std::sort(sb_pairs.begin(), sb_pairs.end());
|
||||
return sb_pairs;
|
||||
return comm.hash_into(h);
|
||||
}
|
||||
|
||||
static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
|
||||
|
|
@ -89,12 +85,10 @@ struct OptMergeWorker
|
|||
// (builtin || stdcell) && (unary || binary) && symmetrical
|
||||
if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul),
|
||||
ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) {
|
||||
std::array<RTLIL::SigSpec, 2> inputs = {
|
||||
assign_map(cell->getPort(ID::A)),
|
||||
assign_map(cell->getPort(ID::B))
|
||||
};
|
||||
std::sort(inputs.begin(), inputs.end());
|
||||
h = hash_ops<std::array<RTLIL::SigSpec, 2>>::hash_into(inputs, h);
|
||||
hashlib::commutative_hash comm;
|
||||
comm.eat(hash_ops<RTLIL::SigSpec>::hash(assign_map(cell->getPort(ID::A))));
|
||||
comm.eat(hash_ops<RTLIL::SigSpec>::hash(assign_map(cell->getPort(ID::B))));
|
||||
h = comm.hash_into(h);
|
||||
} else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) {
|
||||
SigSpec a = assign_map(cell->getPort(ID::A));
|
||||
a.sort();
|
||||
|
|
@ -104,44 +98,31 @@ struct OptMergeWorker
|
|||
a.sort_and_unify();
|
||||
h = a.hash_into(h);
|
||||
} else if (cell->type == ID($pmux)) {
|
||||
dict<RTLIL::IdString, RTLIL::SigSpec> conn = cell->connections();
|
||||
assign_map.apply(conn.at(ID::A));
|
||||
assign_map.apply(conn.at(ID::B));
|
||||
assign_map.apply(conn.at(ID::S));
|
||||
for (const auto& [s_bit, b_chunk] : sorted_pmux_in(conn)) {
|
||||
h = s_bit.hash_into(h);
|
||||
h = b_chunk.hash_into(h);
|
||||
}
|
||||
SigSpec sig_s = assign_map(cell->getPort(ID::S));
|
||||
SigSpec sig_b = assign_map(cell->getPort(ID::B));
|
||||
h = hash_pmux_in(sig_s, sig_b, h);
|
||||
h = assign_map(cell->getPort(ID::A)).hash_into(h);
|
||||
} else {
|
||||
std::vector<std::pair<IdString, SigSpec>> conns;
|
||||
for (const auto& conn : cell->connections()) {
|
||||
conns.push_back(conn);
|
||||
hashlib::commutative_hash comm;
|
||||
for (const auto& [port, sig] : cell->connections()) {
|
||||
if (cell->output(port))
|
||||
continue;
|
||||
comm.eat(hash_ops<std::pair<IdString, SigSpec>>::hash({port, assign_map(sig)}));
|
||||
}
|
||||
std::sort(conns.begin(), conns.end());
|
||||
for (const auto& [port, sig] : conns) {
|
||||
if (!cell->output(port)) {
|
||||
h = port.hash_into(h);
|
||||
h = assign_map(sig).hash_into(h);
|
||||
}
|
||||
}
|
||||
|
||||
h = comm.hash_into(h);
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type))
|
||||
h = initvals(cell->getPort(ID::Q)).hash_into(h);
|
||||
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static Hasher hash_cell_parameters(const RTLIL::Cell *cell, Hasher h)
|
||||
{
|
||||
using Paramvec = std::vector<std::pair<IdString, Const>>;
|
||||
Paramvec params;
|
||||
hashlib::commutative_hash comm;
|
||||
for (const auto& param : cell->parameters) {
|
||||
params.push_back(param);
|
||||
comm.eat(hash_ops<std::pair<IdString, Const>>::hash(param));
|
||||
}
|
||||
std::sort(params.begin(), params.end());
|
||||
return hash_ops<Paramvec>::hash_into(params, h);
|
||||
return comm.hash_into(h);
|
||||
}
|
||||
|
||||
Hasher hash_cell_function(const RTLIL::Cell *cell, Hasher h) const
|
||||
|
|
@ -227,7 +208,7 @@ struct OptMergeWorker
|
|||
}
|
||||
|
||||
OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all, bool mode_keepdc) :
|
||||
design(design), module(module), assign_map(module), mode_share_all(mode_share_all)
|
||||
design(design), module(module), mode_share_all(mode_share_all)
|
||||
{
|
||||
total_count = 0;
|
||||
ct.setup_internals();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "kernel/celltypes.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
|
@ -291,14 +293,14 @@ struct OptMuxtreeWorker
|
|||
// database of known inactive signals
|
||||
// the payload is a reference counter used to manage the
|
||||
// list. when it is non-zero the signal in known to be inactive
|
||||
vector<int> known_inactive;
|
||||
std::unordered_map<int, int> known_inactive;
|
||||
|
||||
// database of known active signals
|
||||
vector<int> known_active;
|
||||
std::unordered_map<int, int> known_active;
|
||||
|
||||
// this is just used to keep track of visited muxes in order to prohibit
|
||||
// endless recursion in mux loops
|
||||
vector<bool> visited_muxes;
|
||||
std::unordered_set<int> visited_muxes;
|
||||
};
|
||||
|
||||
void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
|
||||
|
|
@ -315,17 +317,18 @@ struct OptMuxtreeWorker
|
|||
if (i == port_idx)
|
||||
continue;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0)
|
||||
knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++;
|
||||
++knowledge.known_inactive[muxinfo.ports[i].ctrl_sig];
|
||||
}
|
||||
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
|
||||
knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++;
|
||||
++knowledge.known_active[muxinfo.ports[port_idx].ctrl_sig];
|
||||
|
||||
vector<int> parent_muxes;
|
||||
for (int m : muxinfo.ports[port_idx].input_muxes) {
|
||||
if (knowledge.visited_muxes[m])
|
||||
auto it = knowledge.visited_muxes.find(m);
|
||||
if (it != knowledge.visited_muxes.end())
|
||||
continue;
|
||||
knowledge.visited_muxes[m] = true;
|
||||
knowledge.visited_muxes.insert(it, m);
|
||||
parent_muxes.push_back(m);
|
||||
}
|
||||
for (int m : parent_muxes) {
|
||||
|
|
@ -344,16 +347,24 @@ struct OptMuxtreeWorker
|
|||
return;
|
||||
}
|
||||
for (int m : parent_muxes)
|
||||
knowledge.visited_muxes[m] = false;
|
||||
knowledge.visited_muxes.erase(m);
|
||||
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
|
||||
knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--;
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) {
|
||||
auto it = knowledge.known_active.find(muxinfo.ports[port_idx].ctrl_sig);
|
||||
if (it != knowledge.known_active.end())
|
||||
if (--it->second == 0)
|
||||
knowledge.known_active.erase(it);
|
||||
}
|
||||
|
||||
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
|
||||
if (i == port_idx)
|
||||
continue;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0)
|
||||
knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)--;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0) {
|
||||
auto it = knowledge.known_inactive.find(muxinfo.ports[i].ctrl_sig);
|
||||
if (it != knowledge.known_inactive.end())
|
||||
if (--it->second == 0)
|
||||
knowledge.known_inactive.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,11 +384,11 @@ struct OptMuxtreeWorker
|
|||
vector<int> bits = sig2bits(sig, false);
|
||||
for (int i = 0; i < GetSize(bits); i++) {
|
||||
if (bits[i] >= 0) {
|
||||
if (knowledge.known_inactive.at(bits[i])) {
|
||||
if (knowledge.known_inactive.count(bits[i]) > 0) {
|
||||
sig[i] = State::S0;
|
||||
did_something = true;
|
||||
} else
|
||||
if (knowledge.known_active.at(bits[i])) {
|
||||
if (knowledge.known_active.count(bits[i]) > 0) {
|
||||
sig[i] = State::S1;
|
||||
did_something = true;
|
||||
}
|
||||
|
|
@ -435,7 +446,7 @@ struct OptMuxtreeWorker
|
|||
portinfo_t &portinfo = muxinfo.ports[port_idx];
|
||||
if (portinfo.const_deactivated)
|
||||
continue;
|
||||
if (knowledge.known_active.at(portinfo.ctrl_sig)) {
|
||||
if (knowledge.known_active.count(portinfo.ctrl_sig) > 0) {
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
|
||||
return;
|
||||
}
|
||||
|
|
@ -449,7 +460,7 @@ struct OptMuxtreeWorker
|
|||
if (portinfo.const_deactivated)
|
||||
continue;
|
||||
if (port_idx < GetSize(muxinfo.ports)-1)
|
||||
if (knowledge.known_inactive.at(portinfo.ctrl_sig))
|
||||
if (knowledge.known_inactive.count(portinfo.ctrl_sig) > 0)
|
||||
continue;
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
|
||||
|
||||
|
|
@ -462,10 +473,7 @@ struct OptMuxtreeWorker
|
|||
{
|
||||
log_assert(glob_abort_cnt > 0);
|
||||
knowledge_t knowledge;
|
||||
knowledge.known_inactive.resize(GetSize(bit2info));
|
||||
knowledge.known_active.resize(GetSize(bit2info));
|
||||
knowledge.visited_muxes.resize(GetSize(mux2info));
|
||||
knowledge.visited_muxes[mux_idx] = true;
|
||||
knowledge.visited_muxes.insert(mux_idx);
|
||||
eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue