1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
/*
* 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[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[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
|