mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			219 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  *  yosys -- Yosys Open SYnthesis Suite
 | |
|  *
 | |
|  *  Copyright (C) 2021  gatecat <gatecat@ds0.me>
 | |
|  *  Copyright (C) 2021  Cologne Chip AG <support@colognechip.com>
 | |
|  *
 | |
|  *  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.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "kernel/yosys.h"
 | |
| #include "kernel/sigtools.h"
 | |
| 
 | |
| USING_YOSYS_NAMESPACE
 | |
| PRIVATE_NAMESPACE_BEGIN
 | |
| 
 | |
| struct LUTPin {
 | |
|     int input_bit;
 | |
|     IdString init_param;
 | |
| };
 | |
| 
 | |
| struct LUTType {
 | |
|     dict<IdString, LUTPin> inputs;
 | |
|     IdString output_param;
 | |
| };
 | |
| 
 | |
| struct FoldInvWorker {
 | |
|     FoldInvWorker(Module *module) : module(module), sigmap(module) {};
 | |
|     Module *module;
 | |
|     SigMap sigmap;
 | |
| 
 | |
|     // Mapping from inverter output to inverter input
 | |
|     dict<SigBit, SigBit> inverted_bits;
 | |
|     // Mapping from inverter input to inverter
 | |
|     dict<SigBit, Cell*> inverter_input;
 | |
| 
 | |
|     const dict<IdString, LUTType> lut_types = {
 | |
|         {ID(CC_LUT2), {{
 | |
|                 {ID(I0), {0, ID(INIT)}},
 | |
|                 {ID(I1), {1, ID(INIT)}},
 | |
|             }, ID(INIT)}},
 | |
|         {ID(CC_L2T4), {{
 | |
|                 {ID(I0), {0, ID(INIT_L00)}},
 | |
|                 {ID(I1), {1, ID(INIT_L00)}},
 | |
|                 {ID(I2), {0, ID(INIT_L01)}},
 | |
|                 {ID(I3), {1, ID(INIT_L01)}},
 | |
|             }, ID(INIT_L10)}},
 | |
|         {ID(CC_L2T5), {{
 | |
|                 {ID(I0), {0, ID(INIT_L02)}},
 | |
|                 {ID(I1), {1, ID(INIT_L02)}},
 | |
|                 {ID(I2), {0, ID(INIT_L03)}},
 | |
|                 {ID(I3), {1, ID(INIT_L03)}},
 | |
|                 {ID(I4), {0, ID(INIT_L20)}},
 | |
|             }, ID(INIT_L20)}},
 | |
|     };
 | |
| 
 | |
| 
 | |
|     void find_inverted_bits()
 | |
|     {
 | |
|         for (auto cell : module->selected_cells()) {
 | |
|             if (cell->type != ID($__CC_NOT))
 | |
|                 continue;
 | |
|             SigBit a = sigmap(cell->getPort(ID::A)[0]);
 | |
|             SigBit y = sigmap(cell->getPort(ID::Y)[0]);
 | |
|             inverted_bits[y] = a;
 | |
|             inverter_input[a] = cell;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     Const invert_lut_input(Const lut, int bit)
 | |
|     {
 | |
|         Const result(State::S0, GetSize(lut));
 | |
|         for (int i = 0; i < GetSize(lut); i++) {
 | |
|             int j = i ^ (1 << bit);
 | |
|             result.set(j, lut[i]);
 | |
|         }
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     Const invert_lut_output(Const lut)
 | |
|     {
 | |
|         Const result(State::S0, GetSize(lut));
 | |
|         for (int i = 0; i < GetSize(lut); i++)
 | |
|             result.set(i, (lut[i] == State::S1) ? State::S0 : State::S1);
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     void fold_input_inverters()
 | |
|     {
 | |
|         for (auto cell : module->selected_cells()) {
 | |
|             auto found_type = lut_types.find(cell->type);
 | |
|             if (found_type == lut_types.end())
 | |
|                 continue;
 | |
|             const auto &type = found_type->second;
 | |
|             for (const auto &ipin : type.inputs) {
 | |
|                 if (!cell->hasPort(ipin.first))
 | |
|                     continue;
 | |
|                 auto sig = cell->getPort(ipin.first);
 | |
|                 if (GetSize(sig) == 0)
 | |
|                     continue;
 | |
|                 SigBit bit = sigmap(sig[0]);
 | |
|                 auto inv = inverted_bits.find(bit);
 | |
|                 if (inv == inverted_bits.end())
 | |
|                     continue; // not the output of an inverter
 | |
|                 // Rewire to inverter input
 | |
|                 cell->unsetPort(ipin.first);
 | |
|                 cell->setPort(ipin.first, inv->second);
 | |
|                 // Rewrite init
 | |
|                 cell->setParam(ipin.second.init_param,
 | |
|                     invert_lut_input(cell->getParam(ipin.second.init_param), ipin.second.input_bit));
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void fold_output_inverters()
 | |
|     {
 | |
|         pool<SigBit> used_bits;
 | |
|         // Find bits that are actually used
 | |
|         for (auto cell : module->selected_cells()) {
 | |
|             for (auto conn : cell->connections()) {
 | |
|                 if (cell->output(conn.first))
 | |
|                     continue;
 | |
|                 for (auto bit : sigmap(conn.second))
 | |
|                     used_bits.insert(bit);
 | |
|             }
 | |
|         }
 | |
|         // Find LUTs driving inverters
 | |
|         // (create a vector to avoid iterate-and-modify issues)
 | |
|         std::vector<std::pair<Cell *, Cell*>> lut_inv;
 | |
|         for (auto cell : module->selected_cells()) {
 | |
|             auto found_type = lut_types.find(cell->type);
 | |
|             if (found_type == lut_types.end())
 | |
|                 continue;
 | |
|             if (!cell->hasPort(ID::O))
 | |
|                 continue;
 | |
|             auto o_sig = cell->getPort(ID::O);
 | |
|             if (GetSize(o_sig) == 0)
 | |
|                 continue;
 | |
|             SigBit o = sigmap(o_sig[0]);
 | |
|             auto found_inv = inverter_input.find(o);
 | |
|             if (found_inv == inverter_input.end())
 | |
|                 continue; // doesn't drive an inverter
 | |
|             lut_inv.emplace_back(cell, found_inv->second);
 | |
|         }
 | |
|         for (auto pair : lut_inv) {
 | |
|             Cell *orig_lut = pair.first;
 | |
|             Cell *inv = pair.second;
 | |
|             // Find the inverter output
 | |
|             SigBit inv_y = sigmap(inv->getPort(ID::Y)[0]);
 | |
|             // Inverter output might not actually be used; if all users were folded into inputs already
 | |
|             if (!used_bits.count(inv_y))
 | |
|                 continue;
 | |
|             // Create a duplicate of the LUT with an inverted output
 | |
|             // (if the uninverted version becomes unused it will be swept away)
 | |
|             Cell *dup_lut = module->addCell(NEW_ID, orig_lut->type);
 | |
|             inv->unsetPort(ID::Y);
 | |
|             dup_lut->setPort(ID::O, inv_y);
 | |
|             for (auto conn : orig_lut->connections()) {
 | |
|                 if (conn.first == ID::O)
 | |
|                     continue;
 | |
|                 dup_lut->setPort(conn.first, conn.second);
 | |
|             }
 | |
|             for (auto param : orig_lut->parameters) {
 | |
|                 if (param.first == lut_types.at(orig_lut->type).output_param)
 | |
|                     dup_lut->parameters[param.first] = invert_lut_output(param.second);
 | |
|                 else
 | |
|                     dup_lut->parameters[param.first] = param.second;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void operator()()
 | |
|     {
 | |
|         find_inverted_bits();
 | |
|         fold_input_inverters();
 | |
|         fold_output_inverters();
 | |
|     }
 | |
| };
 | |
| 
 | |
| struct GatemateFoldInvPass : public Pass {
 | |
|     GatemateFoldInvPass() : Pass("gatemate_foldinv", "fold inverters into Gatemate LUT trees") { }
 | |
|     void help() override
 | |
|     {
 | |
|         //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | |
|         log("\n");
 | |
|         log("    gatemate_foldinv [selection]\n");
 | |
|         log("\n");
 | |
|         log("\n");
 | |
|         log("This pass searches for $__CC_NOT cells and folds them into CC_LUT2, CC_L2T4\n");
 | |
|         log("and CC_L2T5 cells as created by LUT tree mapping.\n");
 | |
|         log("\n");
 | |
|     }
 | |
| 
 | |
|     void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | |
|     {
 | |
|         log_header(design, "Executing GATEMATE_FOLDINV pass (folding LUT tree inverters).\n");
 | |
| 
 | |
|         size_t argidx = 1;
 | |
|         extra_args(args, argidx, design);
 | |
| 
 | |
|         for (Module *module : design->selected_modules()) {
 | |
|             FoldInvWorker worker(module);
 | |
|             worker();
 | |
|         }        
 | |
|     }
 | |
| } GatemateFoldInvPass;
 | |
| 
 | |
| PRIVATE_NAMESPACE_END
 | |
| 
 |