From 379dcda1398ea7a1325f82340148359ffe2bf548 Mon Sep 17 00:00:00 2001 From: Niklas Nisbeth Date: Tue, 31 Dec 2019 02:38:10 +0100 Subject: [PATCH 01/33] ice40: Demote conflicting FF init values to a warning --- techlibs/ice40/ice40_ffinit.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc index 3089d8932..c098736e9 100644 --- a/techlibs/ice40/ice40_ffinit.cc +++ b/techlibs/ice40/ice40_ffinit.cc @@ -78,10 +78,12 @@ struct Ice40FfinitPass : public Pass { continue; if (initbits.count(bit)) { - if (initbits.at(bit) != val) - log_error("Conflicting init values for signal %s (%s = %s, %s = %s).\n", + if (initbits.at(bit) != val) { + log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n", log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); + initbits.at(bit) = State::Sx; + } continue; } @@ -114,6 +116,10 @@ struct Ice40FfinitPass : public Pass { continue; State val = initbits.at(bit_q); + + if (val == State::Sx) + continue; + handled_initbits.insert(bit_q); log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type), From 3fa374a69886c3a7ef8d52a2bbb67ea740e130dd Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 9 Jan 2020 21:22:54 +0100 Subject: [PATCH 02/33] Add fminit pass Signed-off-by: Clifford Wolf --- passes/sat/Makefile.inc | 1 + passes/sat/fminit.cc | 197 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 passes/sat/fminit.cc diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index fc3ac879e..4bb4b0edc 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -12,4 +12,5 @@ OBJS += passes/sat/supercover.o OBJS += passes/sat/fmcombine.o OBJS += passes/sat/mutate.o OBJS += passes/sat/cutpoint.o +OBJS += passes/sat/fminit.o diff --git a/passes/sat/fminit.cc b/passes/sat/fminit.cc new file mode 100644 index 000000000..f3f00b382 --- /dev/null +++ b/passes/sat/fminit.cc @@ -0,0 +1,197 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 FminitPass : public Pass { + FminitPass() : Pass("fminit", "set init values/sequences for formal") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" fminit [options] \n"); + log("\n"); + log("This pass creates init constraints (for example for reset sequences) in a formal\n"); + log("model.\n"); + log("\n"); + log(" -seq \n"); + log(" Set sequence using comma-separated list of values, use 'z for\n"); + log(" unconstrained bits. The last value is used for the remainder of the\n"); + log(" trace.\n"); + log("\n"); + log(" -set \n"); + log(" Add constant value constraint\n"); + log("\n"); + log(" -posedge \n"); + log(" -negedge \n"); + log(" Set clock for init sequences\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + vector>> initdata; + vector> setdata; + string clocksignal; + bool clockedge; + + log_header(design, "Executing FMINIT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-o" && argidx+1 < args.size()) { + // filename = args[++argidx]; + // continue; + // } + if (args[argidx] == "-seq" && argidx+2 < args.size()) { + string lhs = args[++argidx]; + string rhs = args[++argidx]; + initdata.push_back(make_pair(lhs, split_tokens(rhs, ","))); + continue; + } + if (args[argidx] == "-set" && argidx+2 < args.size()) { + string lhs = args[++argidx]; + string rhs = args[++argidx]; + setdata.push_back(make_pair(lhs, rhs)); + continue; + } + if (args[argidx] == "-posedge" && argidx+1 < args.size()) { + clocksignal = args[++argidx]; + clockedge = true; + continue; + } + if (args[argidx] == "-negedge" && argidx+1 < args.size()) { + clocksignal = args[++argidx]; + clockedge = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + Module *module = nullptr; + + for (auto mod : design->selected_modules()) { + if (module != nullptr) + log_error("'fminit' requires exactly one module to be selected.\n"); + module = mod; + } + + if (module == nullptr) + log_error("'fminit' requires exactly one module to be selected.\n"); + + SigSpec clksig; + if (!clocksignal.empty()) { + if (!SigSpec::parse(clksig, module, clocksignal)) + log_error("Error parsing expression '%s'.\n", clocksignal.c_str()); + } + + for (auto &it : setdata) + { + SigSpec lhs, rhs; + + if (!SigSpec::parse(lhs, module, it.first)) + log_error("Error parsing expression '%s'.\n", it.first.c_str()); + + if (!SigSpec::parse_rhs(lhs, rhs, module, it.second)) + log_error("Error parsing expression '%s'.\n", it.second.c_str()); + + SigSpec final_lhs, final_rhs; + + for (int i = 0; i < GetSize(rhs); i++) + if (rhs[i] != State::Sz) { + final_lhs.append(lhs[i]); + final_rhs.append(rhs[i]); + } + + if (!final_lhs.empty()) { + SigSpec eq = module->Eq(NEW_ID, final_lhs, final_rhs); + module->addAssume(NEW_ID, eq, State::S1); + } + } + + vector ctrlsig; + vector ctrlsig_latched; + + for (auto &it : initdata) + { + SigSpec lhs, rhs; + + if (!SigSpec::parse(lhs, module, it.first)) + log_error("Error parsing expression '%s'.\n", it.first.c_str()); + + for (int i = 0; i < GetSize(it.second); i++) + { + if (i >= GetSize(ctrlsig)) + { + SigSpec insig = i > 0 ? ctrlsig.at(i-1) : State::S0; + + Wire *outwire = module->addWire(NEW_ID); + outwire->attributes[ID(init)] = i > 0 ? State::S0 : State::S1; + + if (clksig.empty()) + module->addFf(NEW_ID, insig, outwire); + else + module->addDff(NEW_ID, clksig, insig, outwire, clockedge); + + ctrlsig.push_back(outwire); + ctrlsig_latched.push_back(SigSpec()); + } + + if (i+1 == GetSize(it.second) && ctrlsig_latched[i].empty()) + { + Wire *ffwire = module->addWire(NEW_ID); + ffwire->attributes[ID(init)] = State::S0; + SigSpec outsig = module->Or(NEW_ID, ffwire, ctrlsig[i]); + + if (clksig.empty()) + module->addFf(NEW_ID, outsig, ffwire); + else + module->addDff(NEW_ID, clksig, outsig, ffwire, clockedge); + + ctrlsig_latched[i] = outsig; + } + + SigSpec ctrl = i+1 == GetSize(it.second) ? ctrlsig_latched[i] : ctrlsig[i]; + + SigSpec final_lhs, final_rhs; + + if (!SigSpec::parse_rhs(lhs, rhs, module, it.second[i])) + log_error("Error parsing expression '%s'.\n", it.second[i].c_str()); + + for (int i = 0; i < GetSize(rhs); i++) + if (rhs[i] != State::Sz) { + final_lhs.append(lhs[i]); + final_rhs.append(rhs[i]); + } + + if (!final_lhs.empty()) { + SigSpec eq = module->Eq(NEW_ID, final_lhs, final_rhs); + module->addAssume(NEW_ID, eq, ctrl); + } + } + } + } +} FminitPass; + +PRIVATE_NAMESPACE_END From 55f86eda36ed9288528c2216972d5b49acfca54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Mon, 13 Jan 2020 14:49:31 +0100 Subject: [PATCH 03/33] edif: Just ignore connections to 'z Connecting a const 'z to a net should be equivalent to not connecting it at all, so let's just ignore such connections on output. --- backends/edif/edif.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index 6d9469538..e9beace83 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -404,6 +404,8 @@ struct EdifBackend : public Backend { for (auto &ref : it.second) log_warning("Exporting x-bit on %s as zero bit.\n", ref.c_str()); sig = RTLIL::State::S0; + } else if (sig == RTLIL::State::Sz) { + continue; } else { for (auto &ref : it.second) log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.c_str()); From a5d2358a60084361902583f4fa024d2d53ce6c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Tue, 14 Jan 2020 22:48:40 +0100 Subject: [PATCH 04/33] fsm_detect: Add a cache to avoid excessive CPU usage for big mux networks. Fixes #1634. --- passes/fsm/fsm_detect.cc | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc index fb3896669..a1c8067b4 100644 --- a/passes/fsm/fsm_detect.cc +++ b/passes/fsm/fsm_detect.cc @@ -34,13 +34,20 @@ static SigSet sig2driver, sig2user; static std::set muxtree_cells; static SigPool sig_at_port; -static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool &recursion_monitor) +static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool &recursion_monitor, dict &mux_tree_cache) { + if (mux_tree_cache.find(sig) != mux_tree_cache.end()) + return mux_tree_cache.at(sig); + if (sig.is_fully_const() || old_sig == sig) { +ret_true: + mux_tree_cache[sig] = true; return true; } if (sig_at_port.check_any(assign_map(sig))) { +ret_false: + mux_tree_cache[sig] = false; return false; } @@ -49,13 +56,13 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, poo for (auto &cellport : cellport_list) { if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") { - return false; + goto ret_false; } if (recursion_monitor.count(cellport.first)) { log_warning("logic loop in mux tree at signal %s in module %s.\n", log_signal(sig), RTLIL::id2cstr(module->name)); - return false; + goto ret_false; } recursion_monitor.insert(cellport.first); @@ -63,22 +70,22 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, poo RTLIL::SigSpec sig_a = assign_map(cellport.first->getPort("\\A")); RTLIL::SigSpec sig_b = assign_map(cellport.first->getPort("\\B")); - if (!check_state_mux_tree(old_sig, sig_a, recursion_monitor)) { + if (!check_state_mux_tree(old_sig, sig_a, recursion_monitor, mux_tree_cache)) { recursion_monitor.erase(cellport.first); - return false; + goto ret_false; } for (int i = 0; i < sig_b.size(); i += sig_a.size()) - if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.size()), recursion_monitor)) { + if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.size()), recursion_monitor, mux_tree_cache)) { recursion_monitor.erase(cellport.first); - return false; + goto ret_false; } recursion_monitor.erase(cellport.first); muxtree_cells.insert(cellport.first); } - return true; + goto ret_true; } static bool check_state_users(RTLIL::SigSpec sig) @@ -143,11 +150,12 @@ static void detect_fsm(RTLIL::Wire *wire) pool recursion_monitor; RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q")); RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D")); + dict mux_tree_cache; if (sig_q != assign_map(wire)) continue; - looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor); + looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor, mux_tree_cache); looks_like_good_state_reg = check_state_users(sig_q); if (!looks_like_state_reg) From 1e6d56dca11c7a632b74ba51361f879dc706110a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 11:14:19 -0800 Subject: [PATCH 05/33] +/xilinx/arith_map.v fix $lcu rule --- techlibs/xilinx/arith_map.v | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v index 5c848d4e6..c345a3da3 100644 --- a/techlibs/xilinx/arith_map.v +++ b/techlibs/xilinx/arith_map.v @@ -53,9 +53,9 @@ module _80_xilinx_lcu (P, G, CI, CO); ( .CYINIT(CI), .CI (1'd0), - .DI (G [(Y_WIDTH - 1):i*4]), - .S (S [(Y_WIDTH - 1):i*4]), - .CO (CO[(Y_WIDTH - 1):i*4]), + .DI (G [(WIDTH - 1):i*4]), + .S (S [(WIDTH - 1):i*4]), + .CO (CO[(WIDTH - 1):i*4]), ); // Another one end else begin @@ -63,9 +63,9 @@ module _80_xilinx_lcu (P, G, CI, CO); ( .CYINIT(1'd0), .CI (C [i*4 - 1]), - .DI (G [(Y_WIDTH - 1):i*4]), - .S (S [(Y_WIDTH - 1):i*4]), - .CO (CO[(Y_WIDTH - 1):i*4]), + .DI (G [(WIDTH - 1):i*4]), + .S (S [(WIDTH - 1):i*4]), + .CO (CO[(WIDTH - 1):i*4]), ); end From d4e188299ba729756ee689d14c81aab68a7ca1b7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 12:00:14 -0800 Subject: [PATCH 06/33] abc9: add some log_{push,pop}() as per @nakengelhardt --- passes/techmap/abc9.cc | 5 +++++ passes/techmap/alumacc.cc | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 6a296bfe7..f4a89efff 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -235,8 +235,11 @@ struct Abc9Pass : public ScriptPass extra_args(args, argidx, design); log_header(design, "Executing ABC9 pass.\n"); + log_push(); run_script(design, run_from, run_to); + + log_pop(); } void script() YS_OVERRIDE @@ -276,6 +279,7 @@ struct Abc9Pass : public ScriptPass } log_assert(!mod->attributes.count(ID(abc9_box_id))); + log_push(); active_design->selection().select(mod); if (!active_design->selected_whole_module(mod)) @@ -310,6 +314,7 @@ struct Abc9Pass : public ScriptPass } active_design->selection().selected_modules.clear(); + log_pop(); } active_design->selection_stack.pop_back(); diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 034731b87..cf2ac16c9 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -397,18 +397,21 @@ struct AlumaccWorker { log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type)); - bool cmp_less = cell->type.in(ID($lt), ID($le)); - bool cmp_equal = cell->type.in(ID($le), ID($ge)); + bool cmp_less = false; //cell->type.in(ID($lt), ID($le)); + bool cmp_equal = false; //cell->type.in(ID($le), ID($ge)); bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); - if (B < A && GetSize(B)) { - cmp_less = !cmp_less; + if (cell->type.in(ID($lt), ID($ge))) std::swap(A, B); - } + + //if (B < A && GetSize(B)) { + // cmp_less = !cmp_less; + // std::swap(A, B); + //} alunode_t *n = nullptr; @@ -432,6 +435,12 @@ struct AlumaccWorker log(" merged with %s.\n", log_id(n->cells.front())); } + if (cell->type.in(ID($le), ID($ge))) { + SigSpec YY = module->addWire(NEW_ID, GetSize(Y)); + module->addNot(NEW_ID, YY, Y); + Y = YY; + } + n->cells.push_back(cell); n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, Y)); } From 5c589244df2ec4fc5fde0bcdc69dee727f4b8e79 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 12:02:46 -0800 Subject: [PATCH 07/33] Deprecate `_CLB_CARRY from +/xilinx/arith_map.v since #1623 --- techlibs/xilinx/arith_map.v | 199 +++++++++++++------------------- techlibs/xilinx/synth_xilinx.cc | 2 - 2 files changed, 82 insertions(+), 119 deletions(-) diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v index c345a3da3..40c378d16 100644 --- a/techlibs/xilinx/arith_map.v +++ b/techlibs/xilinx/arith_map.v @@ -33,7 +33,21 @@ module _80_xilinx_lcu (P, G, CI, CO); genvar i; -`ifdef _CLB_CARRY +`ifdef _EXPLICIT_CARRY + + wire [WIDTH-1:0] C = {CO, CI}; + wire [WIDTH-1:0] S = P & ~G; + + generate for (i = 0; i < WIDTH; i = i + 1) begin:slice + MUXCY muxcy ( + .CI(C[i]), + .DI(G[i]), + .S(S[i]), + .O(CO[i]) + ); + end endgenerate + +`else localparam CARRY4_COUNT = (WIDTH + 3) / 4; localparam MAX_WIDTH = CARRY4_COUNT * 4; @@ -97,34 +111,6 @@ module _80_xilinx_lcu (P, G, CI, CO); end end endgenerate - -`elsif _EXPLICIT_CARRY - - wire [WIDTH-1:0] C = {CO, CI}; - wire [WIDTH-1:0] S = P & ~G; - - generate for (i = 0; i < WIDTH; i = i + 1) begin:slice - MUXCY muxcy ( - .CI(C[i]), - .DI(G[i]), - .S(S[i]), - .O(CO[i]) - ); - end endgenerate - -`else - - wire [WIDTH-1:0] C = {CO, CI}; - wire [WIDTH-1:0] S = P & ~G; - - generate for (i = 0; i < WIDTH; i = i + 1) begin:slice - MUXCY muxcy ( - .CI(C[i]), - .DI(G[i]), - .S(S[i]), - .O(CO[i]) - ); - end endgenerate `endif endmodule @@ -161,79 +147,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); genvar i; -`ifdef _CLB_CARRY - - localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4; - localparam MAX_WIDTH = CARRY4_COUNT * 4; - localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH; - - wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB}; - wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB}; - - wire [MAX_WIDTH-1:0] C = CO; - - genvar i; - generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice - - // Partially occupied CARRY4 - if ((i+1)*4 > Y_WIDTH) begin - - // First one - if (i == 0) begin - CARRY4 carry4_1st_part - ( - .CYINIT(CI), - .CI (1'd0), - .DI (DI[(Y_WIDTH - 1):i*4]), - .S (S [(Y_WIDTH - 1):i*4]), - .O (Y [(Y_WIDTH - 1):i*4]), - .CO (CO[(Y_WIDTH - 1):i*4]) - ); - // Another one - end else begin - CARRY4 carry4_part - ( - .CYINIT(1'd0), - .CI (C [i*4 - 1]), - .DI (DI[(Y_WIDTH - 1):i*4]), - .S (S [(Y_WIDTH - 1):i*4]), - .O (Y [(Y_WIDTH - 1):i*4]), - .CO (CO[(Y_WIDTH - 1):i*4]) - ); - end - - // Fully occupied CARRY4 - end else begin - - // First one - if (i == 0) begin - CARRY4 carry4_1st_full - ( - .CYINIT(CI), - .CI (1'd0), - .DI (DI[((i+1)*4 - 1):i*4]), - .S (S [((i+1)*4 - 1):i*4]), - .O (Y [((i+1)*4 - 1):i*4]), - .CO (CO[((i+1)*4 - 1):i*4]) - ); - // Another one - end else begin - CARRY4 carry4_full - ( - .CYINIT(1'd0), - .CI (C [i*4 - 1]), - .DI (DI[((i+1)*4 - 1):i*4]), - .S (S [((i+1)*4 - 1):i*4]), - .O (Y [((i+1)*4 - 1):i*4]), - .CO (CO[((i+1)*4 - 1):i*4]) - ); - end - - end - - end endgenerate - -`elsif _EXPLICIT_CARRY +`ifdef _EXPLICIT_CARRY wire [Y_WIDTH-1:0] S = AA ^ BB; wire [Y_WIDTH-1:0] DI = AA & BB; @@ -333,23 +247,74 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); `else - wire [Y_WIDTH-1:0] S = AA ^ BB; - wire [Y_WIDTH-1:0] DI = AA & BB; + localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4; + localparam MAX_WIDTH = CARRY4_COUNT * 4; + localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH; - wire [Y_WIDTH-1:0] C = {CO, CI}; + wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB}; + wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB}; + + wire [MAX_WIDTH-1:0] C = CO; + + genvar i; + generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice + + // Partially occupied CARRY4 + if ((i+1)*4 > Y_WIDTH) begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_part + ( + .CYINIT(CI), + .CI (1'd0), + .DI (DI[(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .O (Y [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]) + ); + // Another one + end else begin + CARRY4 carry4_part + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (DI[(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .O (Y [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]) + ); + end + + // Fully occupied CARRY4 + end else begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_full + ( + .CYINIT(CI), + .CI (1'd0), + .DI (DI[((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .O (Y [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]) + ); + // Another one + end else begin + CARRY4 carry4_full + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (DI[((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .O (Y [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]) + ); + end + + end - generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice - MUXCY muxcy ( - .CI(C[i]), - .DI(DI[i]), - .S(S[i]), - .O(CO[i]) - ); - XORCY xorcy ( - .CI(C[i]), - .LI(S[i]), - .O(Y[i]) - ); end endgenerate `endif diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 3dc05cd10..5c3b5179d 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -518,8 +518,6 @@ struct SynthXilinxPass : public ScriptPass techmap_args += " -map +/xilinx/arith_map.v"; if (vpr) techmap_args += " -D _EXPLICIT_CARRY"; - else - techmap_args += " -D _CLB_CARRY"; } run("techmap " + techmap_args); run("opt -fast"); From 6692e5d558e7c7277153b7a3bd1623af0e57405d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 15:28:02 -0800 Subject: [PATCH 08/33] ice40_dsp: tolerant of fanout-less outputs, as well as all-zero inputs --- passes/pmgen/ice40_dsp.pmg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 6b6d2b56f..9514e65d9 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -57,6 +57,9 @@ code sigA sigB sigH sigH.append(O[i]); } log_assert(nusers(O.extract_end(i)) <= 1); + + if (sigH.empty()) + reject; endcode code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol @@ -328,6 +331,8 @@ arg argD argQ clock clock_pol code dff = nullptr; + if (argQ.empty()) + reject; for (auto c : argQ.chunks()) { if (!c.wire) reject; From 4985318263a8113563c9c62c60a9d4d6ee0a4f4e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 15:37:52 -0800 Subject: [PATCH 09/33] ice40_dsp: add default values for parameters --- passes/pmgen/ice40_dsp.cc | 8 ++++---- passes/pmgen/ice40_dsp.pmg | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index f60e67158..202a43f0c 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -73,11 +73,11 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Input Interface SigSpec A = st.sigA; - A.extend_u0(16, st.mul->getParam(ID(A_SIGNED)).as_bool()); + A.extend_u0(16, st.mul->connections_.at(ID(A_SIGNED), State::S0).as_bool()); log_assert(GetSize(A) == 16); SigSpec B = st.sigB; - B.extend_u0(16, st.mul->getParam(ID(B_SIGNED)).as_bool()); + B.extend_u0(16, st.mul->connections_.at(ID(B_SIGNED), State::S0).as_bool()); log_assert(GetSize(B) == 16); SigSpec CD = st.sigCD; @@ -248,8 +248,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam(ID(BOTADDSUB_CARRYSELECT), Const(0, 2)); cell->setParam(ID(MODE_8x8), State::S0); - cell->setParam(ID(A_SIGNED), st.mul->getParam(ID(A_SIGNED)).as_bool()); - cell->setParam(ID(B_SIGNED), st.mul->getParam(ID(B_SIGNED)).as_bool()); + cell->setParam(ID(A_SIGNED), st.mul->parameters.at(ID(A_SIGNED), State::S0).as_bool()); + cell->setParam(ID(B_SIGNED), st.mul->parameters.at(ID(B_SIGNED), State::S0).as_bool()); if (st.ffO) { if (st.o_lo) diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 9514e65d9..fca307453 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -63,7 +63,7 @@ code sigA sigB sigH endcode code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol - if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) { + if (mul->type != \SB_MAC16 || !param(mul, \A_REG, State::S0).as_bool()) { argQ = sigA; subpattern(in_dffe); if (dff) { @@ -84,7 +84,7 @@ code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol endcode code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol - if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) { + if (mul->type != \SB_MAC16 || !param(mul, \B_REG, State::S0).as_bool()) { argQ = sigB; subpattern(in_dffe); if (dff) { @@ -107,7 +107,7 @@ endcode code argD ffFJKG sigH clock clock_pol if (nusers(sigH) == 2 && (mul->type != \SB_MAC16 || - (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) { + (!param(mul, \TOP_8x8_MULT_REG, State::S0).as_bool() && !param(mul, \BOT_8x8_MULT_REG, State::S0).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1, State::S0).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1, State::S0).as_bool()))) { argD = sigH; subpattern(out_dffe); if (dff) { @@ -146,7 +146,7 @@ endcode code argD ffH sigH sigO clock clock_pol if (ffFJKG && nusers(sigH) == 2 && - (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) { + (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2, State::S0).as_bool())) { argD = sigH; subpattern(out_dffe); if (dff) { @@ -177,7 +177,7 @@ reject_ffH: ; endcode match add - if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3) + if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT, State::S0).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT, State::S0).as_int() == 3) select add->type.in($add) choice AB {\A, \B} @@ -203,7 +203,7 @@ code sigCD sigO cd_signed if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; // If accumulator, check adder width and signedness - if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(add, \A_SIGNED).as_bool())) + if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED, State::S0).as_bool() != param(add, \A_SIGNED).as_bool())) reject; sigO = port(add, \Y); @@ -278,7 +278,7 @@ endcode code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol if (!sigCD.empty() && sigCD != sigO && - (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) { + (mul->type != \SB_MAC16 || (!param(mul, \C_REG, State::S0).as_bool() && !param(mul, \D_REG, State::S0).as_bool()))) { argQ = sigCD; subpattern(in_dffe); if (dff) { From ad6c49fff12e27d99c1fc15850857e5129dd76ee Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 15:38:26 -0800 Subject: [PATCH 10/33] ice40_dsp: add test --- tests/arch/ice40/ice40_dsp.ys | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/arch/ice40/ice40_dsp.ys diff --git a/tests/arch/ice40/ice40_dsp.ys b/tests/arch/ice40/ice40_dsp.ys new file mode 100644 index 000000000..250273859 --- /dev/null +++ b/tests/arch/ice40/ice40_dsp.ys @@ -0,0 +1,11 @@ +read_verilog < Date: Fri, 17 Jan 2020 15:41:55 -0800 Subject: [PATCH 11/33] synth_ice40: call wreduce before mul2dsp --- techlibs/ice40/synth_ice40.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 121bcff1f..d92e40726 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -273,7 +273,8 @@ struct SynthIce40Pass : public ScriptPass run("opt_expr"); run("opt_clean"); if (help_mode || dsp) { - run("memory_dff"); + run("memory_dff"); // ice40_dsp will merge registers, reserve memory port registers first + run("wreduce t:$mul"); run("techmap -map +/mul2dsp.v -map +/ice40/dsp_map.v -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=16 " "-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_Y_MINWIDTH=11 " "-D DSP_NAME=$__MUL16X16", "(if -dsp)"); From 5507c328fff7b534abcba4186b2e5b1e26c4ad5e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 15:57:52 -0800 Subject: [PATCH 12/33] Add #1644 testcase --- tests/arch/ice40/bug1644.il.gz | Bin 0 -> 25669 bytes tests/arch/ice40/bug1644.ys | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 tests/arch/ice40/bug1644.il.gz create mode 100644 tests/arch/ice40/bug1644.ys diff --git a/tests/arch/ice40/bug1644.il.gz b/tests/arch/ice40/bug1644.il.gz new file mode 100644 index 0000000000000000000000000000000000000000..363c510efe8028d2593da0ec83e4caea16a30ca8 GIT binary patch literal 25669 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 Z-?M84_Ggu%{#;x6{{qE6g`vMe0{|QxOz8js literal 0 HcmV?d00001 diff --git a/tests/arch/ice40/bug1644.ys b/tests/arch/ice40/bug1644.ys new file mode 100644 index 000000000..5950f0e3c --- /dev/null +++ b/tests/arch/ice40/bug1644.ys @@ -0,0 +1,2 @@ +read_ilang bug1644.il.gz +synth_ice40 -top top -dsp -json adc_dac_pass_through.json -run :map_bram From ee500b6d8e7a6cd10a8187a3fc69b46f3d155a91 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 16:05:10 -0800 Subject: [PATCH 13/33] xilinx_dsp: add parameter defaults --- passes/pmgen/xilinx_dsp.pmg | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 5d3b9c2eb..b9a4b0864 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -120,7 +120,7 @@ endcode // reset functionality, using a subpattern discussed above) // If matched, treat 'A' input as input of ADREG code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock - if (param(dsp, \ADREG).as_int() == 0) { + if (param(dsp, \ADREG, 1).as_int() == 0) { argQ = sigA; subpattern(in_dffe); if (dff) { @@ -176,7 +176,7 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cem // Only search for ffA2 if there was a pre-adder // (otherwise ffA2 would have been matched as ffAD) if (preAdd) { - if (param(dsp, \AREG).as_int() == 0) { + if (param(dsp, \AREG, 1).as_int() == 0) { argQ = sigA; subpattern(in_dffe); if (dff) { @@ -237,7 +237,7 @@ endcode // (5) Match 'B' input for B2REG // If B2REG, then match 'B' input for B1REG code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffB1 ffB1cemux ffB1rstmux ffB1cepol - if (param(dsp, \BREG).as_int() == 0) { + if (param(dsp, \BREG, 1).as_int() == 0) { argQ = sigB; subpattern(in_dffe); if (dff) { @@ -287,7 +287,7 @@ endcode // (6) Match 'D' input for DREG code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock - if (param(dsp, \DREG).as_int() == 0) { + if (param(dsp, \DREG, 1).as_int() == 0) { argQ = sigD; subpattern(in_dffe); if (dff) { @@ -308,7 +308,7 @@ endcode // (7) Match 'P' output that exclusively drives an MREG code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock - if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) { + if (param(dsp, \MREG, 1).as_int() == 0 && nusers(sigM) == 2) { argD = sigM; subpattern(out_dffe); if (dff) { @@ -335,7 +335,7 @@ endcode // recognised in xilinx_dsp.cc). match postAdd // Ensure that Z mux is not already used - if port(dsp, \OPMODE, SigSpec()).extract(4,3).is_fully_zero() + if port(dsp, \OPMODE, SigSpec(0, 7)).extract(4,3).is_fully_zero() select postAdd->type.in($add) select GetSize(port(postAdd, \Y)) <= 48 @@ -363,7 +363,7 @@ endcode // (9) Match 'P' output that exclusively drives a PREG code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock - if (param(dsp, \PREG).as_int() == 0) { + if (param(dsp, \PREG, 1).as_int() == 0) { int users = 2; // If ffMcemux and no postAdd new-value net must have three users: ffMcemux, ffM and ffPcemux if (ffMcemux && !postAdd) users++; From e17f3f8c63603746ad3aa33e9900d91e9b86db39 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 16:06:20 -0800 Subject: [PATCH 14/33] Consistency --- passes/pmgen/ice40_dsp.pmg | 8 +++++--- passes/pmgen/xilinx_dsp.pmg | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index fca307453..9d649cb98 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -56,10 +56,12 @@ code sigA sigB sigH break; sigH.append(O[i]); } - log_assert(nusers(O.extract_end(i)) <= 1); - - if (sigH.empty()) + // This sigM could have no users if downstream sinks (e.g. $add) is + // narrower than $mul result, for example + if (i == 0) reject; + + log_assert(nusers(O.extract_end(i)) <= 1); endcode code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index b9a4b0864..20925c0dc 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -460,7 +460,7 @@ arg argD argQ clock code dff = nullptr; - if (GetSize(argQ) == 0) + if (argQ.empty() == 0) reject; for (const auto &c : argQ.chunks()) { // Abandon matches when 'Q' is a constant From db68e4c2a7a39eda46863fba8b8c8313a831f606 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Jan 2020 16:08:04 -0800 Subject: [PATCH 15/33] ice40_dsp: fix typo --- passes/pmgen/ice40_dsp.cc | 4 ++-- tests/arch/xilinx/xilinx_dsp.ys | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/arch/xilinx/xilinx_dsp.ys diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 202a43f0c..c364cd91a 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -73,11 +73,11 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Input Interface SigSpec A = st.sigA; - A.extend_u0(16, st.mul->connections_.at(ID(A_SIGNED), State::S0).as_bool()); + A.extend_u0(16, st.mul->parameters.at(ID(A_SIGNED), State::S0).as_bool()); log_assert(GetSize(A) == 16); SigSpec B = st.sigB; - B.extend_u0(16, st.mul->connections_.at(ID(B_SIGNED), State::S0).as_bool()); + B.extend_u0(16, st.mul->parameters.at(ID(B_SIGNED), State::S0).as_bool()); log_assert(GetSize(B) == 16); SigSpec CD = st.sigCD; diff --git a/tests/arch/xilinx/xilinx_dsp.ys b/tests/arch/xilinx/xilinx_dsp.ys new file mode 100644 index 000000000..3b9f52930 --- /dev/null +++ b/tests/arch/xilinx/xilinx_dsp.ys @@ -0,0 +1,11 @@ +read_verilog < Date: Fri, 17 Jan 2020 17:07:03 -0800 Subject: [PATCH 16/33] xilinx_dsp: another typo; move xilinx specific test --- passes/pmgen/xilinx_dsp.pmg | 2 +- tests/{various => arch/xilinx}/bug1462.ys | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/{various => arch/xilinx}/bug1462.ys (100%) diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 20925c0dc..af47ab111 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -460,7 +460,7 @@ arg argD argQ clock code dff = nullptr; - if (argQ.empty() == 0) + if (argQ.empty()) reject; for (const auto &c : argQ.chunks()) { // Abandon matches when 'Q' is a constant diff --git a/tests/various/bug1462.ys b/tests/arch/xilinx/bug1462.ys similarity index 100% rename from tests/various/bug1462.ys rename to tests/arch/xilinx/bug1462.ys From cd8f55a91100b8dcf8b4775803cbacf70f5a998c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Jan 2020 09:43:04 -0800 Subject: [PATCH 17/33] write_xaiger: fix for (* keep *) on flop output --- backends/aiger/xaiger.cc | 6 +++--- tests/various/abc9.ys | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index a9b75ecc7..b72dd6890 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -222,6 +222,8 @@ struct XAigerWriter alias_map[Q] = D; auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell)); log_assert(r.second); + if (input_bits.erase(Q)) + log_assert(Q.wire->attributes.count(ID::keep)); continue; } @@ -568,9 +570,6 @@ struct XAigerWriter // write_o_buffer(0); if (!box_list.empty() || !ff_bits.empty()) { - RTLIL::Module *holes_module = module->design->module(stringf("%s$holes", module->name.c_str())); - log_assert(holes_module); - dict> cell_cache; int box_count = 0; @@ -653,6 +652,7 @@ struct XAigerWriter f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); f.write(buffer_str.data(), buffer_str.size()); + RTLIL::Module *holes_module = module->design->module(stringf("%s$holes", module->name.c_str())); if (holes_module) { std::stringstream a_buffer; XAigerWriter writer(holes_module, true /* holes_mode */); diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys index 81d0afd1b..0c7695089 100644 --- a/tests/various/abc9.ys +++ b/tests/various/abc9.ys @@ -14,6 +14,7 @@ design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + design -load read hierarchy -top abc9_test028 proc @@ -23,6 +24,7 @@ select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i select -assert-count 1 t:unknown select -assert-none t:$lut t:unknown %% t: %D + design -load read hierarchy -top abc9_test032 proc @@ -38,3 +40,16 @@ design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -seq 10 -verify -prove-asserts -show-ports miter + + +design -reset +read_verilog -icells < Date: Tue, 21 Jan 2020 11:16:50 -0800 Subject: [PATCH 18/33] read_aiger: ignore constant inputs on LUTs --- frontends/aiger/aigerparse.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index b5c861936..52bcfa0b6 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -414,6 +414,10 @@ void AigerReader::parse_xaiger() for (unsigned j = 0; j < cutLeavesM; ++j) { nodeID = parse_xaiger_literal(f); log_debug2("\t%u\n", nodeID); + if (nodeID < 2) { + log_debug("\tLUT '$lut$aiger%d$%d' input %d is constant!\n", aiger_autoidx, rootNodeID, cutLeavesM); + continue; + } RTLIL::Wire *wire = module->wire(stringf("$aiger%d$%d", aiger_autoidx, nodeID)); log_assert(wire); input_sig.append(wire); @@ -421,10 +425,10 @@ void AigerReader::parse_xaiger() // TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size()) ce.clear(); ce.compute_deps(output_sig, input_sig.to_sigbit_pool()); - RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size()); - for (int j = 0; j < (1 << cutLeavesM); ++j) { + RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << GetSize(input_sig)); + for (int j = 0; j < GetSize(lut_mask); ++j) { int gray = j ^ (j >> 1); - ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast(cutLeavesM)}); + ce.set_incremental(input_sig, RTLIL::Const{gray, GetSize(input_sig)}); RTLIL::SigBit o(output_sig); bool success YS_ATTRIBUTE(unused) = ce.eval(o); log_assert(success); From cd093c00f84b44662a09d469c2b0d8ba6ecf6f6e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Jan 2020 11:56:01 -0800 Subject: [PATCH 19/33] read_aiger: discard LUT inputs with nodeID == 0; not < 2 --- frontends/aiger/aigerparse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 52bcfa0b6..e7478c316 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -414,7 +414,7 @@ void AigerReader::parse_xaiger() for (unsigned j = 0; j < cutLeavesM; ++j) { nodeID = parse_xaiger_literal(f); log_debug2("\t%u\n", nodeID); - if (nodeID < 2) { + if (nodeID == 0) { log_debug("\tLUT '$lut$aiger%d$%d' input %d is constant!\n", aiger_autoidx, rootNodeID, cutLeavesM); continue; } From 3b44b53e946780ac25581f236be7c836fa6927bf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Jan 2020 09:36:54 -0800 Subject: [PATCH 20/33] abc9: fix scratchpad entry abc9.verify --- passes/techmap/abc9.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 1f6cdaa22..b0e2c7697 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -304,14 +304,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip for (size_t pos = abc9_script.find("{R}"); pos != std::string::npos; pos = abc9_script.find("{R}", pos)) abc9_script = abc9_script.substr(0, pos) + R + abc9_script.substr(pos+3); - abc9_script += stringf("; &ps -l; &write -n %s/output.aig;", tempdir_name.c_str()); + abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name.c_str()); if (design->scratchpad_get_bool("abc9.verify")) { if (dff_mode) - abc9_script += "verify -s;"; + abc9_script += "; &verify -s"; else - abc9_script += "verify;"; + abc9_script += "; &verify"; } - abc9_script += "time"; + abc9_script += "; time"; abc9_script = add_echos_to_abc9_cmd(abc9_script); for (size_t i = 0; i+1 < abc9_script.size(); i++) From a94b41011d5ec9514739c52b963e0bd96890973f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Jan 2020 10:08:48 -0800 Subject: [PATCH 21/33] abc9: error out if flip-flop init is 1'b1 for '-dff' Due to ABC sequential synthesis restriction --- passes/techmap/abc9.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index b0e2c7697..2568a6cd1 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -1069,6 +1069,8 @@ struct Abc9Pass : public Pass { SigSpec abc9_init = assign_map(abc9_init_wire); if (!abc9_init.is_fully_const()) log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + if (abc9_init == State::S1) + log_error("'%s.init' in module '%s' has value 1'b1 which is not supported by 'abc9 -dff'.\n", cell->name.c_str(), log_id(module)); r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); log_assert(r2.second); } From 73526a6f103c927dd0d1504281659a87e7943688 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Jan 2020 14:21:25 -0800 Subject: [PATCH 22/33] read_aiger: also parse abc9_mergeability --- frontends/aiger/aigerparse.cc | 7 +++++-- frontends/aiger/aigerparse.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index e7478c316..b9c648afd 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -442,11 +442,13 @@ void AigerReader::parse_xaiger() } } else if (c == 'r') { - uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + uint32_t dataSize = parse_xaiger_literal(f); flopNum = parse_xaiger_literal(f); log_debug("flopNum = %u\n", flopNum); log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); - f.ignore(flopNum * sizeof(uint32_t)); + mergeability.reserve(flopNum); + for (unsigned i = 0; i < flopNum; i++) + mergeability.emplace_back(parse_xaiger_literal(f)); } else if (c == 'n') { parse_xaiger_literal(f); @@ -774,6 +776,7 @@ void AigerReader::post_process() auto ff = module->addCell(NEW_ID, "$__ABC9_FF_"); ff->setPort("\\D", d); ff->setPort("\\Q", q); + ff->attributes["\\abc9_mergeability"] = mergeability[i]; } dict wideports_cache; diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h index 722f1e472..46ac81212 100644 --- a/frontends/aiger/aigerparse.h +++ b/frontends/aiger/aigerparse.h @@ -45,6 +45,7 @@ struct AigerReader std::vector outputs; std::vector bad_properties; std::vector boxes; + std::vector mergeability; AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); void parse_aiger(); From da134701cd86e3958490b97fd6d840ce24586080 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Jan 2020 14:22:03 -0800 Subject: [PATCH 23/33] Fix $__ABC9_ASYNC1 to output 1'b1 not 1'b0 --- techlibs/xilinx/abc9_model.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/abc9_model.v b/techlibs/xilinx/abc9_model.v index 204fa883f..15d12c89f 100644 --- a/techlibs/xilinx/abc9_model.v +++ b/techlibs/xilinx/abc9_model.v @@ -42,7 +42,7 @@ endmodule // Box to emulate async behaviour of FDP* (* abc9_box_id = 1001, lib_whitebox *) module \$__ABC9_ASYNC1 (input A, S, output Y); - assign Y = S ? 1'b0 : A; + assign Y = S ? 1'b1 : A; endmodule // Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32} From af0e7637a28f08978bc4dfb77089261f9fe18a5d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Jan 2020 20:54:03 -0800 Subject: [PATCH 24/33] alumacc: undo accidental commit --- passes/techmap/alumacc.cc | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index cf2ac16c9..034731b87 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -397,21 +397,18 @@ struct AlumaccWorker { log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type)); - bool cmp_less = false; //cell->type.in(ID($lt), ID($le)); - bool cmp_equal = false; //cell->type.in(ID($le), ID($ge)); + bool cmp_less = cell->type.in(ID($lt), ID($le)); + bool cmp_equal = cell->type.in(ID($le), ID($ge)); bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); - if (cell->type.in(ID($lt), ID($ge))) + if (B < A && GetSize(B)) { + cmp_less = !cmp_less; std::swap(A, B); - - //if (B < A && GetSize(B)) { - // cmp_less = !cmp_less; - // std::swap(A, B); - //} + } alunode_t *n = nullptr; @@ -435,12 +432,6 @@ struct AlumaccWorker log(" merged with %s.\n", log_id(n->cells.front())); } - if (cell->type.in(ID($le), ID($ge))) { - SigSpec YY = module->addWire(NEW_ID, GetSize(Y)); - module->addNot(NEW_ID, YY, Y); - Y = YY; - } - n->cells.push_back(cell); n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, Y)); } From 1d4314d88853feb1fa6af13fe56274d53d81d853 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 14:58:56 -0800 Subject: [PATCH 25/33] abc9_ops -prep_dff: insert async s/r mux in holes when replacing $_DFF_* --- passes/techmap/abc9_ops.cc | 68 +++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 5091ac0f2..750f36ceb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -106,38 +106,44 @@ void prep_dff(RTLIL::Module *module) SigMap sigmap(holes_module); dict replace; - for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { - auto cell = it->second; - if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { - SigBit D = cell->getPort("\\D"); - SigBit Q = cell->getPort("\\Q"); - // Remove the $_DFF_* cell from what needs to be a combinatorial box - it = holes_module->cells_.erase(it); - Wire *port; - if (GetSize(Q.wire) == 1) - port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); - else - port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); - log_assert(port); - // Prepare to replace "assign = $_DFF_*.Q;" with "assign = $_DFF_*.D;" - // in order to extract just the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(Q,D)); - // Since `flatten` above would have created wires named ".Q", - // extract the pre-techmap cell name - auto pos = Q.wire->name.str().rfind("."); - log_assert(pos != std::string::npos); - IdString driver = Q.wire->name.substr(0, pos); - // And drive the signal that was previously driven by "DFF.Q" (typically - // used to implement clock-enable functionality) with the ".$abc9_currQ" - // wire (which itself is driven an by input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); - } + for (auto cell : holes_module->cells().to_vector()) { + if (!cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) + continue; + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Emulate async control embedded inside $_DFF_* cell with mux in front of D + if (cell->type.in("$_DFF_NN0_", "$_DFF_PN0_")) + D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NN1_", "$_DFF_PN1_")) + D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NP0_", "$_DFF_PP0_")) + D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NP1_", "$_DFF_PP1_")) + D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort("\\R")); + // Remove the $_DFF_* cell from what needs to be a combinatorial box + holes_module->remove(cell); + Wire *port; + if (GetSize(Q.wire) == 1) + port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); else - ++it; + port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); + log_assert(port); + // Prepare to replace "assign = $_DFF_*.Q;" with "assign = $_DFF_*.D;" + // in order to extract just the combinatorial control logic that feeds the box + // (i.e. clock enable, synchronous reset, etc.) + replace.insert(std::make_pair(Q,D)); + // Since `flatten` above would have created wires named ".Q", + // extract the pre-techmap cell name + auto pos = Q.wire->name.str().rfind("."); + log_assert(pos != std::string::npos); + IdString driver = Q.wire->name.substr(0, pos); + // And drive the signal that was previously driven by "DFF.Q" (typically + // used to implement clock-enable functionality) with the ".$abc9_currQ" + // wire (which itself is driven an by input port) we inserted above + Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str())); + log_assert(currQ); + holes_module->connect(Q, currQ); } for (auto &conn : holes_module->connections_) From 48aec34e0dbb6918e38ef2b80cdbbd8bb992d0f5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 18:53:14 -0800 Subject: [PATCH 26/33] abc_box_id -> abc9_box_id in test --- tests/simple_abc9/abc9.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v index 8afd0ce96..ee01ab5dc 100644 --- a/tests/simple_abc9/abc9.v +++ b/tests/simple_abc9/abc9.v @@ -213,7 +213,7 @@ module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encode input rst; endmodule -(* abc_box_id=1 *) +(* abc9_box_id=1 *) module MUXF8(input I0, I1, S, output O); endmodule From f180dba753c9f4bfb3b89575b0d224c73a1e8897 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 18:56:06 -0800 Subject: [PATCH 27/33] abc9_ops: -prep_xaiger to skip (* keep *) cells --- passes/techmap/abc9_ops.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 750f36ceb..40622ece7 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -165,6 +165,8 @@ void prep_xaiger(RTLIL::Module *module, bool dff) for (auto cell : module->cells()) { if (cell->type == "$__ABC9_FF_") continue; + if (cell->has_keep_attr()) + continue; auto inst_module = module->design->module(cell->type); bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id"); From 11e50c0e9ecec6439d44064a0e1a016dc2b3188b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 18:56:25 -0800 Subject: [PATCH 28/33] Test for (* keep *)-ed abc9_box_id --- tests/simple_abc9/abc9.v | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v index ee01ab5dc..52ccb3e1d 100644 --- a/tests/simple_abc9/abc9.v +++ b/tests/simple_abc9/abc9.v @@ -291,3 +291,19 @@ module abc9_test035(input clk, d, output reg [1:0] q); always @(posedge clk) q[0] <= d; always @(negedge clk) q[1] <= q[0]; endmodule + +module abc9_test036(input A, B, S, output [1:0] O); + (* keep *) + MUXF8 m ( + .I0(I0), + .I1(I1), + .O(O[0]), + .S(S) + ); + MUXF8 m2 ( + .I0(I0), + .I1(I1), + .O(O[1]), + .S(S) + ); +endmodule From 245873d42d7975b6c303c2d04b75f3cafc6c5697 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 19:08:51 -0800 Subject: [PATCH 29/33] abc9: warning message if no modules selected --- passes/techmap/abc9.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index f4a89efff..2aeda16d6 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -234,6 +234,12 @@ struct Abc9Pass : public ScriptPass } extra_args(args, argidx, design); + log_assert(design); + if (design->selected_modules().empty()) { + log_warning("No modules selected for ABC9 techmapping.\n"); + return; + } + log_header(design, "Executing ABC9 pass.\n"); log_push(); From dca1c806eca0219fb609acfd111fbf9073c6908f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 19:55:11 -0800 Subject: [PATCH 30/33] simple_abc9 tests to discard whitebox before write for sim --- tests/simple_abc9/abc9.v | 2 +- tests/simple_abc9/run-test.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v index 52ccb3e1d..e5837d480 100644 --- a/tests/simple_abc9/abc9.v +++ b/tests/simple_abc9/abc9.v @@ -213,7 +213,7 @@ module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encode input rst; endmodule -(* abc9_box_id=1 *) +(* abc9_box_id=1, whitebox *) module MUXF8(input I0, I1, S, output O); endmodule diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh index bc921daa9..32d7a80ca 100755 --- a/tests/simple_abc9/run-test.sh +++ b/tests/simple_abc9/run-test.sh @@ -28,4 +28,5 @@ exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p abc9 -lut 4 -box ../abc.box; \ clean; \ check -assert; \ - select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'" + select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%; \ + setattr -mod -unset whitebox'" From dbf351390e68a9d7c453e893de8fa9d09eb24f62 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 22:45:34 -0800 Subject: [PATCH 31/33] abc9: -reintegrate recover type from existing cell, check against boxid --- passes/techmap/abc9_ops.cc | 49 +++++++++++++++----------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 40622ece7..d238ce0ad 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -356,24 +356,14 @@ void reintegrate(RTLIL::Module *module) for (auto w : mapped_mod->wires()) module->addWire(remap_name(w->name), GetSize(w)); - dict box_lookup; dict> box_ports; for (auto m : design->modules()) { - auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) + if (!m->attributes.count(ID(abc9_box_id))) continue; - if (m->name.begins_with("$paramod")) - continue; - auto id = it->second.as_int(); - auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); - if (!r.second) - log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", - log_id(m), id, log_id(r.first->second)); - log_assert(r.second); - auto r2 = box_ports.insert(m->name); - if (r2.second) { + auto r = box_ports.insert(m->name); + if (r.second) { // Make carry in the last PI, and carry out the last PO // since ABC requires it this way IdString carry_in, carry_out; @@ -393,7 +383,7 @@ void reintegrate(RTLIL::Module *module) } } else - r2.first->second.push_back(port_name); + r.first->second.push_back(port_name); } if (carry_in != IdString() && carry_out == IdString()) @@ -401,8 +391,8 @@ void reintegrate(RTLIL::Module *module) if (carry_in == IdString() && carry_out != IdString()) log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); if (carry_in != IdString()) { - r2.first->second.push_back(carry_in); - r2.first->second.push_back(carry_out); + r.first->second.push_back(carry_in); + r.first->second.push_back(carry_out); } } } @@ -516,28 +506,27 @@ void reintegrate(RTLIL::Module *module) else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); - log_assert(mapped_cell->type.begins_with("$__boxid")); - auto type = box_lookup.at(mapped_cell->type, IdString()); - if (type == IdString()) - log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); - mapped_cell->type = type; + RTLIL::Module* box_module = design->module(existing_cell->type); + auto it = box_module->attributes.find(ID(abc9_box_id)); + log_assert(it != box_module->attributes.end()); + log_assert(mapped_cell->type == stringf("$__boxid%d", it->second.as_int())); + mapped_cell->type = existing_cell->type; RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; module->swap_names(cell, existing_cell); - auto it = mapped_cell->connections_.find("\\i"); - log_assert(it != mapped_cell->connections_.end()); - SigSpec inputs = std::move(it->second); - mapped_cell->connections_.erase(it); - it = mapped_cell->connections_.find("\\o"); - log_assert(it != mapped_cell->connections_.end()); - SigSpec outputs = std::move(it->second); - mapped_cell->connections_.erase(it); + auto jt = mapped_cell->connections_.find("\\i"); + log_assert(jt != mapped_cell->connections_.end()); + SigSpec inputs = std::move(jt->second); + mapped_cell->connections_.erase(jt); + jt = mapped_cell->connections_.find("\\o"); + log_assert(jt != mapped_cell->connections_.end()); + SigSpec outputs = std::move(jt->second); + mapped_cell->connections_.erase(jt); - RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module->attributes.count("\\abc9_flop"); if (!abc9_flop) { for (const auto &i : inputs) From c7fbe13db5144cf87c56d3f7a620a295029606b3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 24 Jan 2020 13:11:43 -0800 Subject: [PATCH 32/33] read_aiger: set abc9_box_seq attr --- frontends/aiger/aigerparse.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index b9c648afd..418fd722c 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -478,6 +478,7 @@ void AigerReader::parse_xaiger() RTLIL::Cell* cell = module->addCell(stringf("$box%u", oldBoxNum), stringf("$__boxid%u", boxUniqueId)); cell->setPort("\\i", SigSpec(State::S0, boxInputs)); cell->setPort("\\o", SigSpec(State::S0, boxOutputs)); + cell->attributes["\\abc9_box_seq"] = oldBoxNum; boxes.emplace_back(cell); } } From 9009b76a69b9e867f69295a8e555305925e83aeb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 27 Jan 2020 11:18:21 -0800 Subject: [PATCH 33/33] abc9_ops: add comments --- passes/techmap/abc9_ops.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d238ce0ad..9ad29a8f6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -213,6 +213,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) else if (!yosys_celltypes.cell_known(cell->type)) continue; + // TODO: Speed up toposort -- we care about box ordering only for (auto conn : cell->connections()) { if (cell->input(conn.first)) for (auto bit : sigmap(conn.second)) @@ -222,7 +223,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) for (auto bit : sigmap(conn.second)) bit_drivers[bit].insert(cell->name); } - toposort.node(cell->name); } @@ -415,6 +415,7 @@ void reintegrate(RTLIL::Module *module) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { + // TODO: Speed up toposort -- we care about NOT ordering only toposort.node(mapped_cell->name); if (mapped_cell->type == ID($_NOT_)) { @@ -625,6 +626,17 @@ void reintegrate(RTLIL::Module *module) } } + // ABC9 will return $_NOT_ gates in its mapping (since they are + // treated as being "free"), in particular driving primary + // outputs (real primary outputs, or cells treated as blackboxes) + // or driving box inputs. + // Instead of just mapping those $_NOT_ gates into 2-input $lut-s + // at an area and delay cost, see if it is possible to push + // this $_NOT_ into the driving LUT, or into all sink LUTs. + // When this is not possible, (i.e. this signal drives two primary + // outputs, only one of which is complemented) and when the driver + // is a LUT, then clone the LUT so that it can be inverted without + // increasing depth/delay. for (auto &it : bit_users) if (bit_drivers.count(it.first)) for (auto driver_cell : bit_drivers.at(it.first))