diff options
author | gatecat <gatecat@ds0.me> | 2021-12-07 13:41:39 +0000 |
---|---|---|
committer | myrtle <gatecat@ds0.me> | 2022-06-27 10:09:48 +0100 |
commit | 38a24ec5cc3ae25d46a306bceb94244fad787a19 (patch) | |
tree | 2fcc77f43fe2103fbe476217fce4d9329fe5b99a /techlibs/gatemate | |
parent | 7c756c9959b61160ea62b56c13c58371cb2b401c (diff) | |
download | yosys-38a24ec5cc3ae25d46a306bceb94244fad787a19.tar.gz yosys-38a24ec5cc3ae25d46a306bceb94244fad787a19.tar.bz2 yosys-38a24ec5cc3ae25d46a306bceb94244fad787a19.zip |
gatemate: Add LUT tree library script
Co-authored-by: Claire Xenia Wolf <claire@clairexen.net>
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'techlibs/gatemate')
-rw-r--r-- | techlibs/gatemate/.gitignore | 4 | ||||
-rw-r--r-- | techlibs/gatemate/Makefile.inc | 16 | ||||
-rw-r--r-- | techlibs/gatemate/gatemate_foldinv.cc | 218 | ||||
-rw-r--r-- | techlibs/gatemate/inv_map.v | 4 | ||||
-rw-r--r-- | techlibs/gatemate/make_lut_tree_lib.py | 323 | ||||
-rw-r--r-- | techlibs/gatemate/synth_gatemate.cc | 32 |
6 files changed, 591 insertions, 6 deletions
diff --git a/techlibs/gatemate/.gitignore b/techlibs/gatemate/.gitignore new file mode 100644 index 000000000..f260d6e9d --- /dev/null +++ b/techlibs/gatemate/.gitignore @@ -0,0 +1,4 @@ +lut_tree_cells.genlib +lut_tree_map.v +lut_tree_lib.mk + diff --git a/techlibs/gatemate/Makefile.inc b/techlibs/gatemate/Makefile.inc index d1341d7bb..aeb318cc9 100644 --- a/techlibs/gatemate/Makefile.inc +++ b/techlibs/gatemate/Makefile.inc @@ -1,5 +1,6 @@ OBJS += techlibs/gatemate/synth_gatemate.o
+OBJS += techlibs/gatemate/gatemate_foldinv.o
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/reg_map.v))
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/mux_map.v))
@@ -12,3 +13,18 @@ $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_map.v)) $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams.txt))
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_init_20.vh))
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_init_40.vh))
+$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/inv_map.v))
+
+EXTRA_OBJS += techlibs/gatemate/lut_tree_lib.mk
+.SECONDARY: techlibs/gatemate/lut_tree_lib.mk
+
+techlibs/gatemate/lut_tree_lib.mk: techlibs/gatemate/make_lut_tree_lib.py
+ $(Q) mkdir -p techlibs/gatemate
+ $(P) $(PYTHON_EXECUTABLE) $<
+ $(Q) touch $@
+
+techlibs/gatemate/lut_tree_cells.genlib: techlibs/gatemate/lut_tree_lib.mk
+techlibs/gatemate/lut_tree_map.v: techlibs/gatemate/lut_tree_lib.mk
+
+$(eval $(call add_gen_share_file,share/gatemate,techlibs/gatemate/lut_tree_cells.genlib))
+$(eval $(call add_gen_share_file,share/gatemate,techlibs/gatemate/lut_tree_map.v))
diff --git a/techlibs/gatemate/gatemate_foldinv.cc b/techlibs/gatemate/gatemate_foldinv.cc new file mode 100644 index 000000000..20fbbf8a3 --- /dev/null +++ b/techlibs/gatemate/gatemate_foldinv.cc @@ -0,0 +1,218 @@ +/* + * 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; +}; + +static 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)}}, +}; + +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; + + 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 + diff --git a/techlibs/gatemate/inv_map.v b/techlibs/gatemate/inv_map.v new file mode 100644 index 000000000..8a5051747 --- /dev/null +++ b/techlibs/gatemate/inv_map.v @@ -0,0 +1,4 @@ +// Any inverters not folded into LUTs are mapped to a LUT of their own +module \$__CC_NOT (input A, output Y); + CC_LUT1 #(.INIT(2'b01)) _TECHMAP_REPLACE_ (.I0(A), .O(Y)); +endmodule diff --git a/techlibs/gatemate/make_lut_tree_lib.py b/techlibs/gatemate/make_lut_tree_lib.py new file mode 100644 index 000000000..25ca88882 --- /dev/null +++ b/techlibs/gatemate/make_lut_tree_lib.py @@ -0,0 +1,323 @@ +#!/usr/bin/env python3 + +class FNode: + def __init__(self, fun, *args): + self.fun = fun + self.args = args + + if len(self.args) == 0: + assert fun not in ("BUF", "NOT", "AND", "OR", "XOR", "MUX") + + if len(self.args) == 1: + assert fun in ("BUF", "NOT") + + if len(self.args) == 2: + assert fun in ("AND", "OR", "XOR") + + if len(self.args) == 3: + assert fun in ("MUX") + + def __str__(self): + if len(self.args) == 0: + return self.fun + if self.fun == "NOT" and len(self.args[0].args) == 0: + return "!" + self.args[0].fun + return self.fun + "(" + ",".join([str(a) for a in self.args]) + ")" + + def as_genlib_term(self): + if len(self.args) == 0: + return self.fun + if self.fun == "NOT": + assert len(self.args[0].args) == 0 + return "!" + self.args[0].fun + if self.fun == "AND": + return "(" + self.args[0].as_genlib_term() + "*" + self.args[1].as_genlib_term() + ")" + if self.fun == "OR": + return "(" + self.args[0].as_genlib_term() + "+" + self.args[1].as_genlib_term() + ")" + assert False + + def mapMux(self): + if self.fun == "MUX": + A, B, C = self.args + return OR(AND(A, NOT(C)), AND(B, C)).mapMux() + return FNode(self.fun, *[a.mapMux() for a in self.args]) + + def mapXor(self): + if self.fun == "XOR": + A, B = self.args + return OR(AND(A, NOT(B)), AND(NOT(A), B)).mapXor() + return FNode(self.fun, *[a.mapXor() for a in self.args]) + + def mapNot(self): + if self.fun == "BUF": + return self.arg1.mapNot() + if self.fun == "NOT": + if self.args[0].fun == "AND": + return OR(NOT(self.args[0].args[0]),NOT(self.args[0].args[1])).mapNot() + if self.args[0].fun == "OR": + return AND(NOT(self.args[0].args[0]),NOT(self.args[0].args[1])).mapNot() + if self.args[0].fun == "NOT": + return self.args[0].args[0].mapNot() + return FNode(self.fun, *[a.mapNot() for a in self.args]) + + def map(self): + n = self + n = n.mapMux() + n = n.mapXor() + n = n.mapNot() + return n + + def isInv(self): + if len(self.args) == 0: + return False + if self.fun == "XOR": + return False + if self.fun == "NOT": + return self.args[0].isNonInv() + for a in self.args: + if not a.isInv(): + return False + return True + + def isNonInv(self): + if len(self.args) == 0: + return True + if self.fun == "XOR": + return False + if self.fun == "NOT": + return self.args[0].isInv() + for a in self.args: + if not a.isNonInv(): + return False + return True + +A = FNode("A") +B = FNode("B") +C = FNode("C") +D = FNode("D") +E = FNode("E") + +def BUF(arg): return FNode("BUF", arg) +def NOT(arg): return FNode("NOT", arg) +def AND(arg1, arg2): return FNode("AND", arg1, arg2) +def OR(arg1, arg2): return FNode( "OR", arg1, arg2) +def XOR(arg1, arg2): return FNode("XOR", arg1, arg2) +def MUX(arg1, arg2, arg3): return FNode("MUX", arg1, arg2, arg3) + +# Genlib Format: +# +# GATE <cell-name> <cell-area> <cell-logic-function> +# +# PIN <pin-name> <phase> <input-load> <max-load> +# <rise-block-delay> <rise-fanout-delay> +# <fall-block-delay> <fall-fanout-delay> +# +# phase: +# INV, NONINV, or UNKNOWN +# +# cell-logic-function: +# <output> = <term with *(AND), +(OR), !(NOT)> + + +cells = [ + ["$__CC_BUF", 5, A], + ["$__CC_NOT", 0, NOT(A)], + ["$__CC_MUX", 5, MUX(A, B, C)], +] + +base_cells = [ + ["$__CC2_A", AND(A, B)], + ["$__CC2_O", OR(A, B)], + ["$__CC2_X", XOR(A, B)], + + ["$__CC3_AA", AND(AND(A, B), C)], + ["$__CC3_OO", OR( OR(A, B), C)], + ["$__CC3_XX", XOR(XOR(A, B), C)], + ["$__CC3_AO", OR(AND(A, B), C)], + ["$__CC3_OA", AND( OR(A, B), C)], + ["$__CC3_AX", XOR(AND(A, B), C)], + ["$__CC3_XA", AND(XOR(A, B), C)], + +# ["$__CC3_AAA", AND(AND(A,B),AND(A,C))], +# ["$__CC3_AXA", XOR(AND(A,B),AND(A,C))], +# ["$__CC3_XAX", AND(XOR(A,B),XOR(A,C))], +# ["$__CC3_AAX", AND(AND(A,B),XOR(A,C))], +# ["$__CC3_AXX", XOR(AND(A,B),XOR(A,C))], +# ["$__CC3_XXX", XOR(XOR(A,B),XOR(A,C))], +# ["$__CC3_AAO", AND(AND(A,B), OR(A,C))], +# ["$__CC3_AOA", OR(AND(A,B),AND(A,C))], +# ["$__CC3_AOX", OR(AND(A,B),XOR(A,C))], + +# ["$__CC3_AAA_N", AND(AND(A,B),AND(NOT(A),C))], +# ["$__CC3_AXA_N", XOR(AND(A,B),AND(NOT(A),C))], +# ["$__CC3_XAX_N", AND(XOR(A,B),XOR(NOT(A),C))], +# ["$__CC3_AAX_N", AND(AND(A,B),XOR(NOT(A),C))], +# ["$__CC3_AXX_N", XOR(AND(A,B),XOR(NOT(A),C))], +# ["$__CC3_XXX_N", XOR(XOR(A,B),XOR(NOT(A),C))], +# ["$__CC3_AAO_N", AND(AND(A,B), OR(NOT(A),C))], +# ["$__CC3_AOA_N", OR(AND(A,B),AND(NOT(A),C))], +# ["$__CC3_AOX_N", OR(AND(A,B),XOR(NOT(A),C))], + + ["$__CC4_AAA", AND(AND(A,B),AND(C,D))], + ["$__CC4_AXA", XOR(AND(A,B),AND(C,D))], + ["$__CC4_XAX", AND(XOR(A,B),XOR(C,D))], + ["$__CC4_AAX", AND(AND(A,B),XOR(C,D))], + ["$__CC4_AXX", XOR(AND(A,B),XOR(C,D))], + ["$__CC4_XXX", XOR(XOR(A,B),XOR(C,D))], + ["$__CC4_AAO", AND(AND(A,B), OR(C,D))], + ["$__CC4_AOA", OR(AND(A,B),AND(C,D))], + ["$__CC4_AOX", OR(AND(A,B),XOR(C,D))], +] + +for name, expr in base_cells: + cells.append([name, 10, expr]) + + name = (name + .replace("$__CC4_", "$__CC5_") + .replace("$__CC3_", "$__CC4_") + .replace("$__CC2_", "$__CC3_")) + + # Cells such as $__CC4_AA_A are redundant, as $__CC4_AAA is equivalent + if name not in ("$__CC4_AA", "$__CC3_A"): + cells.append([name + "_A", 12, AND(E, expr)]) + if name not in ("$__CC4_OO", "$__CC3_O"): + cells.append([name + "_O", 12, OR(E, expr)]) + if name not in ("$__CC4_XX", "$__CC3_X"): + cells.append([name + "_X", 12, XOR(E, expr)]) + +with open("techlibs/gatemate/lut_tree_cells.genlib", "w") as glf: + def mkGate(name, cost, expr, max_load=9999, block_delay = 10, fanout_delay = 5): + name = name.replace(" ", "") + expr = expr.map() + + phase = "UNKNOWN" + if expr.isInv(): phase = "INV" + if expr.isNonInv(): phase = "NONINV" + + print("", file=glf) + print("GATE %s %d Y=%s;" % (name, cost, expr.as_genlib_term()), file=glf) + print("PIN * %s 1 %d %d %d %d %d" % (phase, max_load, block_delay, fanout_delay, block_delay, fanout_delay), file=glf) + print("GATE $__ZERO 0 Y=CONST0;", file=glf) + print("GATE $__ONE 0 Y=CONST1;", file=glf) + for name, cost, expr in cells: + mkGate(name, cost, expr) + +class LUTTreeNode: + def __init__(self, name, width, inputs=None): + self.name = name + self.width = width + self.inputs = inputs + def is_input(self): + return self.width == 0 + def map(self, expr, params, ports): + if self.is_input(): + # Input to LUT tree + if expr is None: + ports[self.name] = "" # disconnected input + else: + assert(len(expr.args) == 0) + ports[self.name] = expr.fun + return + if expr is None: + # Unused part of tree + params[self.name] = "4'b0000" + for i in self.inputs: + i.map(None, params, ports) + return + elif len(expr.args) == 0: + # Input to the expression; but not LUT tree + # Insert a route through + params[self.name] = "4'b1010" + self.inputs[0].map(expr, params, ports) + for i in self.inputs[1:]: + i.map(None, params, ports) + return + # Map uphill LUTs; uninverting arguments and keeping track of that if needed + arg_inv = [] + for (i, arg) in zip(self.inputs, expr.args): + if arg.fun == "NOT": + i.map(arg.args[0], params, ports) + arg_inv.append(True) + else: + i.map(arg, params, ports) + arg_inv.append(False) + # Determine base init value + assert self.width == 2 + if expr.fun == "AND": + init = 0b1000 + elif expr.fun == "OR": + init = 0b1110 + elif expr.fun == "XOR": + init = 0b0110 + else: + assert False, expr.fun + # Swap bits if init inverted + swapped_init = 0b0000 + for b in range(4): + if ((init >> b) & 0x1) == 0: continue + for i in range(2): + if arg_inv[i]: + b ^= (1 << i) + swapped_init |= (1 << b) + # Set init param + params[self.name] = "4'b{:04b}".format(swapped_init) + +def LUT2(name, i0, i1): return LUTTreeNode(name, 2, [i0, i1]) +def I(name): return LUTTreeNode(name, 0) + +lut_prims = { + "CC_LUT2": LUT2("INIT", I("I0"), I("I1")), + "CC_L2T4": LUT2( + "INIT_L10", + LUT2("INIT_L00", I("I0"), I("I1")), + LUT2("INIT_L01", I("I2"), I("I3")), + ), + "CC_L2T5": LUT2( + "INIT_L20", I("I4"), LUT2("INIT_L11", + LUT2("INIT_L02", I("I0"), I("I1")), + LUT2("INIT_L03", I("I2"), I("I3")), + ) + ) +} + +with open("techlibs/gatemate/lut_tree_map.v", "w") as vf: + # Non-automatic rules + print(""" +module \\$__ZERO (output Y); assign Y = 1'b0; endmodule +module \\$__ONE (output Y); assign Y = 1'b1; endmodule + +module \\$__CC_BUF (input A, output Y); assign Y = A; endmodule + +module \\$__CC_MUX (input A, B, C, output Y); + CC_MX2 _TECHMAP_REPLACE_ ( + .D0(A), .D1(B), .S0(C), + .Y(Y) + ); +endmodule +""", file=vf) + for name, cost, expr in cells: + expr = expr.mapMux().mapNot() # Don't map XOR + if name in ("$__CC_BUF", "$__CC_NOT", "$__CC_MUX"): + # Special cases + continue + if name.startswith("$__CC2_"): + prim = "CC_LUT2" + elif name.startswith("$__CC5_") or (name.startswith("$__CC4_") and cost == 12): + prim = "CC_L2T5" + else: + prim = "CC_L2T4" + ports = {} + params = {} + lut_prims[prim].map(expr, params, ports) + print("", file=vf) + print("module \\%s (input %s, output Y);" % (name, + ", ".join(sorted(set(x for x in ports.values() if x)))), file=vf) + print(" %s #(" % prim, file=vf) + for k, v in sorted(params.items(), key=lambda x: x[0]): + print(" .%s(%s)," % (k, v), file=vf) + print(" ) _TECHMAP_REPLACE_ (", file=vf) + print(" %s," % ", ".join(".%s(%s)" % (k, v) for k, v in sorted(ports.items(), key=lambda x:x[0])), + file=vf) + print(" .O(Y)", file=vf) + print(" );", file=vf) + print("endmodule", file=vf) diff --git a/techlibs/gatemate/synth_gatemate.cc b/techlibs/gatemate/synth_gatemate.cc index 93b16b2e0..dd4fde643 100644 --- a/techlibs/gatemate/synth_gatemate.cc +++ b/techlibs/gatemate/synth_gatemate.cc @@ -67,7 +67,10 @@ struct SynthGateMatePass : public ScriptPass log("\n");
log(" -nomx8, -nomx4\n");
log(" do not use CC_MX{8,4} multiplexer cells in output netlist.\n");
- log("\n");;
+ log("\n");
+ log(" -luttree\n");
+ log(" use new LUT tree mapping approach (EXPERIMENTAL).\n");
+ log("\n");
log(" -dff\n");
log(" run 'abc' with -dff option\n");
log("\n");
@@ -87,7 +90,7 @@ struct SynthGateMatePass : public ScriptPass }
string top_opt, vlog_file, json_file;
- bool noflatten, nobram, noaddf, nomult, nomx4, nomx8, dff, retime, noiopad, noclkbuf;
+ bool noflatten, nobram, noaddf, nomult, nomx4, nomx8, luttree, dff, retime, noiopad, noclkbuf;
void clear_flags() override
{
@@ -100,6 +103,7 @@ struct SynthGateMatePass : public ScriptPass nomult = false;
nomx4 = false;
nomx8 = false;
+ luttree = false;
dff = false;
retime = false;
noiopad = false;
@@ -158,6 +162,10 @@ struct SynthGateMatePass : public ScriptPass nomx8 = true;
continue;
}
+ if (args[argidx] == "-luttree") {
+ luttree = true;
+ continue;
+ }
if (args[argidx] == "-dff") {
dff = true;
continue;
@@ -298,11 +306,23 @@ struct SynthGateMatePass : public ScriptPass if (check_label("map_luts"))
{
- std::string abc_args = " -dress -lut 4";
- if (dff) {
- abc_args += " -dff";
+ if (luttree || help_mode) {
+ std::string abc_args = " -genlib +/gatemate/lut_tree_cells.genlib";
+ if (dff) {
+ abc_args += " -dff";
+ }
+ run("abc " + abc_args, "(with -luttree)");
+ run("techmap -map +/gatemate/lut_tree_map.v", "(with -luttree)");
+ run("gatemate_foldinv", "(with -luttree)");
+ run("techmap -map +/gatemate/inv_map.v", "(with -luttree)");
+ }
+ if (!luttree || help_mode) {
+ std::string abc_args = " -dress -lut 4";
+ if (dff) {
+ abc_args += " -dff";
+ }
+ run("abc " + abc_args, "(without -luttree)");
}
- run("abc " + abc_args);
run("clean");
}
|