Revert three passes

This commit is contained in:
Akash Levy 2025-09-29 00:18:34 -07:00
parent a0d1c8b30f
commit b5f3d7ee9c
3 changed files with 45 additions and 247 deletions

View File

@ -31,9 +31,8 @@ struct ExclusiveDatabase
dict<SigBit, std::pair<SigSpec,std::vector<Const>>> sig_cmp_prev;
ExclusiveDatabase(Module *module, const SigMap &sigmap, bool assume_excl, bool make_excl) : module(module), sigmap(sigmap)
ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap)
{
if (assume_excl || make_excl) return;
SigSpec const_sig, nonconst_sig;
SigBit y_port;
pool<Cell*> reduce_or;
@ -181,7 +180,7 @@ struct MuxpackWorker
}
}
void find_chain_start_cells(bool assume_excl)
void find_chain_start_cells()
{
for (auto cell : candidate_cells)
{
@ -211,7 +210,7 @@ struct MuxpackWorker
log_assert(prev_cell);
SigSpec s_sig = sigmap(cell->getPort(ID::S));
s_sig.append(sigmap(prev_cell->getPort(ID::S)));
if (!assume_excl && !excl_db.query(s_sig))
if (!excl_db.query(s_sig))
goto start_cell;
}
@ -244,7 +243,7 @@ struct MuxpackWorker
return chain;
}
void process_chain(vector<Cell*> &chain, bool make_excl)
void process_chain(vector<Cell*> &chain)
{
if (GetSize(chain) < 2)
return;
@ -277,7 +276,6 @@ struct MuxpackWorker
for (int i = 1; i < cases; i++) {
Cell* prev_cell = chain[cursor+i-1];
Cell* cursor_cell = chain[cursor+i];
Cell* cell = cursor_cell; // SILIMATE: Set cell to cursor cell for better naming
if (sigmap(prev_cell->getPort(ID::Y)) == sigmap(cursor_cell->getPort(ID::A))) {
b_sig.append(cursor_cell->getPort(ID::B));
s_sig.append(cursor_cell->getPort(ID::S));
@ -285,72 +283,13 @@ struct MuxpackWorker
else {
log_assert(cursor_cell->type == ID($mux));
b_sig.append(cursor_cell->getPort(ID::A));
s_sig.append(module->LogicNot(NEW_ID2_SUFFIX("sel"), cursor_cell->getPort(ID::S), false, cell->get_src_attribute())); // SILIMATE: Improve the naming
s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort(ID::S)));
}
remove_cells.insert(cursor_cell);
first_cell->add_strpool_attribute(ID::src, cursor_cell->get_strpool_attribute(ID::src)); // SILIMATE: Improve src attribution
}
if (make_excl) {
/* Create the following one-hot select line decoder:
S0 S1 S2 S3 ...
| | | |
+--------+ +----------+ +-------------+ |
| _|_ | _|_ | _|_ |
| \_/ | \_/ | \_/ |
| o | o | o |
| | | | | ___ | |
| +----------+ | | / | | |
| | | |___| | / |___| |
| |___| | & | / / | & | / ...
| | & | \___/ / / \___/ / /
| \___/ | | / | | /
| | +------+ +-------+
| | | | | |
| | |___| |___|
| | | & | | & |
| | \___/ \___/
| | | |
S0 S0'S1 S0'S1'S2 S0'S1'S2'S3 ...
*/
SigSpec decodedSelect;
Cell *cell = last_cell;
std::vector<RTLIL::SigBit> select_bits = s_sig.bits();
RTLIL::SigBit prevSigNot = RTLIL::State::S1;
RTLIL::SigBit prevSigAnd = RTLIL::State::S1;
for (int i = (int) (select_bits.size() -1); i >= 0; i--) {
Yosys::RTLIL::SigBit sigbit = select_bits[i];
if (i == (int) (select_bits.size() -1)) {
decodedSelect.append(sigbit);
Wire *not_y = module->addWire(NEW_ID2_SUFFIX("not_y"), 1);
module->addNot(NEW_ID2_SUFFIX("not"), sigbit, not_y, false, last_cell->get_src_attribute());
prevSigNot = not_y;
} else if (i == (int) (select_bits.size() -2)) {
Wire *and_y = module->addWire(NEW_ID2_SUFFIX("and_y"), 1);
module->addAnd(NEW_ID2_SUFFIX("sel"), sigbit, prevSigNot, and_y, false, last_cell->get_src_attribute());
decodedSelect.append(and_y);
Wire *not_y = module->addWire(NEW_ID2_SUFFIX("not_y"), 1);
module->addNot(NEW_ID2_SUFFIX("not"), sigbit, not_y, false, last_cell->get_src_attribute());
prevSigAnd = prevSigNot;
prevSigNot = not_y;
} else {
Wire *and_y1 = module->addWire(NEW_ID2_SUFFIX("and_y1"), 1);
module->addAnd(NEW_ID2_SUFFIX("sel"), prevSigAnd, prevSigNot, and_y1, false, last_cell->get_src_attribute());
Wire *and_y2 = module->addWire(NEW_ID2_SUFFIX("and_y2"), 1);
module->addAnd(NEW_ID2_SUFFIX("sel"), sigbit, and_y1, and_y2, false, last_cell->get_src_attribute());
decodedSelect.append(and_y2);
Wire *not_y = module->addWire(NEW_ID2_SUFFIX("not_y"), 1);
module->addNot(NEW_ID2_SUFFIX("not"), sigbit, not_y, false, last_cell->get_src_attribute());
prevSigAnd = and_y1;
prevSigNot = not_y;
}
}
decodedSelect.reverse();
first_cell->setPort(ID::S, decodedSelect);
} else {
first_cell->setPort(ID::S, s_sig);
}
first_cell->setPort(ID::B, b_sig);
first_cell->setPort(ID::S, s_sig);
first_cell->setParam(ID::S_WIDTH, GetSize(s_sig));
first_cell->setPort(ID::Y, last_cell->getPort(ID::Y));
@ -370,18 +309,17 @@ struct MuxpackWorker
candidate_cells.clear();
}
MuxpackWorker(Module *module, bool assume_excl, bool make_excl) :
module(module), sigmap(module), mux_count(0), pmux_count(0), excl_db(module, sigmap, assume_excl, make_excl)
MuxpackWorker(Module *module) :
module(module), sigmap(module), mux_count(0), pmux_count(0), excl_db(module, sigmap)
{
make_sig_chain_next_prev();
find_chain_start_cells(assume_excl);
find_chain_start_cells();
// Make the actual transform
for (auto c : chain_start_cells) {
vector<Cell *> chain = create_chain(c);
process_chain(chain, make_excl);
vector<Cell*> chain = create_chain(c);
process_chain(chain);
}
// Clean up
cleanup();
}
};
@ -392,7 +330,7 @@ struct MuxpackPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" muxpack [options] [selection]\n");
log(" muxpack [selection]\n");
log("\n");
log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n");
log("constructs) and $mux cells (e.g. those created by if-else constructs) into\n");
@ -402,32 +340,14 @@ struct MuxpackPass : public Pass {
log("whose select lines are driven by '$eq' cells with other such cells if it can be\n");
log("certain that their select inputs are mutually exclusive.\n");
log("\n");
log(" -assume_excl\n");
log(" assume mutually exclusive constraint when packing (may result in inequivalence)\n");
log("\n");
log(" -make_excl\n");
log(" Adds a one-hot decoder on the control signals\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool assume_excl = false;
bool make_excl = false;
log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-assume_excl") {
assume_excl = true;
continue;
}
if (args[argidx] == "-make_excl") {
make_excl = true;
assume_excl = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -436,15 +356,9 @@ struct MuxpackPass : public Pass {
int pmux_count = 0;
for (auto module : design->selected_modules()) {
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);
MuxpackWorker worker(module);
mux_count += worker.mux_count;
pmux_count += worker.pmux_count;
}
log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count);

View File

@ -36,14 +36,10 @@ struct BmuxmapPass : public Pass {
log(" -pmux\n");
log(" transform to $pmux instead of $mux cells.\n");
log("\n");
log(" -fewunq\n");
log(" only transform $bmux cells that have few unique A bits.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool pmux_mode = false;
bool fewunq_mode = false;
log_header(design, "Executing BMUXMAP pass.\n");
@ -53,10 +49,6 @@ struct BmuxmapPass : public Pass {
pmux_mode = true;
continue;
}
if (args[argidx] == "-fewunq") {
fewunq_mode = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -66,17 +58,6 @@ struct BmuxmapPass : public Pass {
{
if (cell->type != ID($bmux))
continue;
if (fewunq_mode) {
SigSpec data = cell->getPort(ID::A);
SigMap sigmap(module);
pool<SigBit> unqbits;
for (auto bit : data)
if (bit.wire != nullptr)
unqbits.insert(sigmap(bit));
if (GetSize(unqbits) > GetSize(data)/2)
continue;
}
SigSpec sel = cell->getPort(ID::S);
SigSpec data = cell->getPort(ID::A);
@ -89,16 +70,14 @@ struct BmuxmapPass : public Pass {
SigSpec new_a = SigSpec(State::Sx, width);
SigSpec new_s = module->addWire(NEW_ID2_SUFFIX("sel"), num_cases); // SILIMATE: Improve the naming
SigSpec new_data = module->addWire(NEW_ID2_SUFFIX("data"), width); // SILIMATE: Improve the naming
for (int val = 0; val < num_cases; val++) {
RTLIL::Cell *eq = module->addEq(NEW_ID2_SUFFIX("eq"), sel, SigSpec(val, GetSize(sel)), new_s[val]); // SILIMATE: Improve the naming
for (auto attr : cell->attributes) // SILIMATE: Copy all attributes from original cell to new cell
eq->attributes[attr.first] = attr.second;
for (int val = 0; val < num_cases; val++)
{
module->addEq(NEW_ID2_SUFFIX("eq"), sel, SigSpec(val, GetSize(sel)), new_s[val], false, cell->get_src_attribute()); // SILIMATE: Improve the naming
}
IdString cell_name = cell->name; // SILIMATE: Save the original cell name
module->rename(cell_name, NEW_ID); // SILIMATE: Rename the original cell, which will be deleted
RTLIL::Cell *pmux = module->addPmux(cell_name, new_a, data, new_s, new_data); // SILIMATE: Improve the naming
pmux->attributes = cell->attributes; // SILIMATE: Copy all attributes from original cell to new cell
RTLIL::Cell *pmux = module->addPmux(NEW_ID, new_a, data, new_s, new_data);
pmux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
data = new_data;
module->swap_names(cell, pmux); // SILIMATE: Improve the naming
}
else
{
@ -110,7 +89,7 @@ struct BmuxmapPass : public Pass {
data.extract(i*2+width, width),
sel[idx],
new_data.extract(i, width));
mux->attributes = cell->attributes; // SILIMATE: Copy all attributes from original cell to new cell
mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
}
data = new_data;
}

View File

@ -29,11 +29,10 @@ struct ExtractReducePass : public Pass
enum GateType {
And,
Or,
Xor,
Mux
Xor
};
ExtractReducePass() : Pass("extract_reduce", "converts gate chains into $reduce_*/$pmux cells") { }
ExtractReducePass() : Pass("extract_reduce", "converts gate chains into $reduce_* cells") { }
void help() override
{
@ -50,46 +49,18 @@ struct ExtractReducePass : public Pass
log("to map the design to only $_AND_ cells, run extract_reduce, map the remaining\n");
log("parts of the design to AND/OR/XOR cells, and run extract_reduce a second time.\n");
log("\n");
log("Silimate has modified this pass to support word-level cells ($and, $or, \n");
log("and $xor) as well as the single-bit cells ($_AND_, $_OR_, and $_XOR_).\n");
log("Mux cells ($mux, $_MUX_) can also be reduced to $pmux cells with the mods.\n");
log("\n");
log(" -allow-off-chain\n");
log(" Allows matching of cells that have loads outside the chain. These cells\n");
log(" will be replicated and folded into the $reduce_* cell, but the original\n");
log(" cell will remain, driving its original loads.\n");
log("\n");
log(" -mux-only\n");
log(" Only reduce $mux cells to $pmux cells, ignore other cell types.\n");
log("\n");
log(" -no-mux\n");
log(" Do not reduce $mux cells to $pmux cells, only reduce other cell types.\n");
log("\n");
log(" -assume-excl\n");
log(" Assume that $mux select signals are exclusive. Will result in logical\n");
log(" inequivalence if this assumption is incorrect.\n");
log("\n");
}
inline bool IsSingleBit(Cell* cell)
{
return (cell->hasParam(ID::WIDTH) && cell->getParam(ID::WIDTH).as_int() == 1) ||
(cell->hasParam(ID::A_WIDTH) &&
cell->getParam(ID::A_WIDTH).as_int() == 1 &&
cell->getParam(ID::B_WIDTH).as_int() == 1 &&
cell->getParam(ID::Y_WIDTH).as_int() == 1);
}
inline bool IsRightType(Cell* cell, GateType gt)
{
return (cell->type == ID($_AND_) && gt == GateType::And) ||
(cell->type == ID($_OR_) && gt == GateType::Or) ||
(cell->type == ID($_XOR_) && gt == GateType::Xor) ||
(cell->type == ID($_MUX_) && gt == GateType::Mux) ||
(cell->type == ID($and) && IsSingleBit(cell) && gt == GateType::And) ||
(cell->type == ID($or) && IsSingleBit(cell) && gt == GateType::Or) ||
(cell->type == ID($xor) && IsSingleBit(cell) && gt == GateType::Xor) ||
(cell->type == ID($mux) && IsSingleBit(cell) && gt == GateType::Mux);
(cell->type == ID($_XOR_) && gt == GateType::Xor);
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
@ -98,7 +69,7 @@ struct ExtractReducePass : public Pass
log_push();
size_t argidx;
bool allow_off_chain = false, mux_only = false, no_mux = false, assume_excl = false;
bool allow_off_chain = false;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-allow-off-chain")
@ -106,21 +77,6 @@ struct ExtractReducePass : public Pass
allow_off_chain = true;
continue;
}
if (args[argidx] == "-mux-only")
{
mux_only = true;
continue;
}
if (args[argidx] == "-no-mux")
{
no_mux = true;
continue;
}
if (args[argidx] == "-assume-excl")
{
assume_excl = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -174,26 +130,10 @@ struct ExtractReducePass : public Pass
gt = GateType::Or;
else if (cell->type == ID($_XOR_))
gt = GateType::Xor;
else if (cell->type == ID($_MUX_))
gt = GateType::Mux;
else if (cell->type == ID($and) && IsSingleBit(cell))
gt = GateType::And;
else if (cell->type == ID($or) && IsSingleBit(cell))
gt = GateType::Or;
else if (cell->type == ID($xor) && IsSingleBit(cell))
gt = GateType::Xor;
else if (cell->type == ID($mux) && IsSingleBit(cell))
gt = GateType::Mux;
else
continue;
if (mux_only && gt != GateType::Mux)
continue;
if (no_mux && gt == GateType::Mux)
continue;
log_debug("Working on cell %s...\n", cell->name);
log("Working on cell %s...\n", cell->name);
// If looking for a single chain, follow linearly to the sink
pool<Cell*> sinks;
@ -280,60 +220,33 @@ struct ExtractReducePass : public Pass
//We have our list, go act on it
for(auto head_cell : sinks)
{
log_debug(" Head cell is %s\n", head_cell->name);
log(" Head cell is %s\n", head_cell->name);
//Avoid duplication if we already were covered
if(consumed_cells.count(head_cell))
continue;
dict<SigBit, int> sources;
dict<SigBit, int> sels;
int inner_cells = 0;
std::deque<std::pair<Cell*, SigBit>> bfs_queue = {{head_cell, State::S1}};
std::set<Cell*> seen_set = {};
std::deque<Cell*> bfs_queue = {head_cell};
while (bfs_queue.size())
{
auto bfs_item = bfs_queue.front();
Cell* x = bfs_queue.front();
bfs_queue.pop_front();
Cell* x = bfs_item.first;
SigBit excl = bfs_item.second;
for (IdString port: {ID::B, ID::A}) {
for (auto port: {ID::A, ID::B}) {
auto bit = sigmap(x->getPort(port)[0]);
bool sink_single = sig_to_sink[bit].size() == 1 && !port_sigs.count(bit);
Cell* drv = sig_to_driver[bit];
bool drv_ok = drv && IsRightType(drv, gt) && !consumed_cells.count(drv) && !seen_set.count(drv);
seen_set.insert(drv);
SigBit s_port;
SigBit sel_sig;
if (gt == GateType::Mux) {
s_port = sigmap(x->getPort(ID::S)[0]);
if (port == ID::A)
sel_sig = module->Not(NEW_ID2_SUFFIX("not"), s_port, false, x->get_src_attribute());
else
sel_sig = module->Buf(NEW_ID2_SUFFIX("buf"), s_port, false, x->get_src_attribute());
}
bool drv_ok = drv && drv->type == head_cell->type;
if (drv_ok && (allow_off_chain || sink_single)) {
inner_cells++;
if (gt == GateType::Mux && !assume_excl) { // if not assuming exclusivity, add to excl signal
SigBit sel_sig_inv = (port == ID::A) ? module->Not(NEW_ID2_SUFFIX("not"), s_port, false, x->get_src_attribute())[0] : s_port;
bfs_queue.push_back({drv, module->And(NEW_ID2_SUFFIX("excl_and"), sel_sig_inv, excl, false, x->get_src_attribute())});
} else { // otherwise, just use the drv signal and don't worry about exclusivity
bfs_queue.push_back({drv, excl});
}
bfs_queue.push_back(drv);
} else {
sources[module->Buf(NEW_ID2_SUFFIX("buf"), bit, false, x->get_src_attribute())]++;
if (gt == GateType::Mux) {
if (assume_excl) // if assuming exclusivity, just use select signal
sels[sel_sig]++;
else // enforce exclusivity by ANDing with excl signal
sels[module->And(NEW_ID2_SUFFIX("selex_and"), sel_sig, excl)]++;
}
sources[bit]++;
}
}
}
@ -341,35 +254,27 @@ struct ExtractReducePass : public Pass
if (inner_cells)
{
// Worth it to create reduce cell
log_debug("Creating reduce_* cell for %s (%s) in %s\n", head_cell->name.c_str(), head_cell->type.c_str(), module->name.c_str());
log(" Creating $reduce_* cell!\n");
SigBit output = sigmap(head_cell->getPort(ID::Y)[0]);
SigSpec input, sel;
SigSpec input;
for (auto it : sources) {
bool cond;
if (head_cell->type == ID($_XOR_) || head_cell->type == ID($xor))
if (head_cell->type == ID($_XOR_))
cond = it.second & 1;
else
cond = it.second != 0;
if (cond || head_cell->hasPort(ID::S))
if (cond)
input.append(it.first);
}
if (head_cell->hasPort(ID::S)) {
for (auto it : sels)
sel.append(it.first);
input.reverse();
sel.reverse();
}
if (head_cell->type == ID($_AND_) || head_cell->type == ID($and)) {
module->addReduceAnd(NEW_ID2_SUFFIX("reduce_and"), input, output, false, cell->get_src_attribute()); // SILIMATE: Improve the naming
} else if (head_cell->type == ID($_OR_) || head_cell->type == ID($or)) {
module->addReduceOr(NEW_ID2_SUFFIX("reduce_or"), input, output, false, cell->get_src_attribute()); // SILIMATE: Improve the naming
} else if (head_cell->type == ID($_XOR_) || head_cell->type == ID($xor)) {
module->addReduceXor(NEW_ID2_SUFFIX("reduce_xor"), input, output, false, cell->get_src_attribute()); // SILIMATE: Improve the naming
} else if (head_cell->type == ID($_MUX_) || head_cell->type == ID($mux)) {
module->addPmux(NEW_ID2_SUFFIX("pmux"), State::Sx, input, sel, output, cell->get_src_attribute()); // SILIMATE: Improve the naming
if (head_cell->type == ID($_AND_)) {
module->addReduceAnd(NEW_ID, input, output);
} else if (head_cell->type == ID($_OR_)) {
module->addReduceOr(NEW_ID, input, output);
} else if (head_cell->type == ID($_XOR_)) {
module->addReduceXor(NEW_ID, input, output);
} else {
log_assert(false);
}