mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +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
 | 
						|
 |