diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index bb3fffff2..6efeefb3c 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -31,9 +31,8 @@ struct ExclusiveDatabase dict>> 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 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 &chain, bool make_excl) + void process_chain(vector &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 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 chain = create_chain(c); - process_chain(chain, make_excl); + vector 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 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); diff --git a/passes/techmap/bmuxmap.cc b/passes/techmap/bmuxmap.cc index 9e87efd58..7f4fd276a 100644 --- a/passes/techmap/bmuxmap.cc +++ b/passes/techmap/bmuxmap.cc @@ -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 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 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; } diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc index 7fc852105..1ad880be0 100644 --- a/passes/techmap/extract_reduce.cc +++ b/passes/techmap/extract_reduce.cc @@ -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 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 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 sources; - dict sels; int inner_cells = 0; - std::deque> bfs_queue = {{head_cell, State::S1}}; - std::set seen_set = {}; + std::deque 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); }