aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEddie Hung <eddie@fpgeh.com>2019-08-30 13:26:19 -0700
committerEddie Hung <eddie@fpgeh.com>2019-08-30 13:26:19 -0700
commit723815b384eee5669593c97442ed2d1055d2d167 (patch)
tree5e5cd2f7d23b2b7ed4b43fc58ca9982d529ce5fe
parent4e782f1509e74bbb69ac99fa3c443112327e4f39 (diff)
parent999fb33fd0e6d1714bc61f7e50a5c16e0da9d4ab (diff)
downloadyosys-723815b384eee5669593c97442ed2d1055d2d167.tar.gz
yosys-723815b384eee5669593c97442ed2d1055d2d167.tar.bz2
yosys-723815b384eee5669593c97442ed2d1055d2d167.zip
Merge remote-tracking branch 'origin/master' into xc7dsp
-rw-r--r--CHANGELOG2
-rw-r--r--Makefile1
-rw-r--r--README.md36
-rw-r--r--frontends/aiger/aigerparse.cc2
-rw-r--r--passes/pmgen/Makefile.inc6
-rw-r--r--passes/pmgen/test_pmgen.cc12
-rw-r--r--passes/pmgen/xilinx_srl.cc258
-rw-r--r--passes/pmgen/xilinx_srl.pmg326
-rw-r--r--passes/techmap/abc9.cc26
-rw-r--r--passes/techmap/shregmap.cc179
-rw-r--r--techlibs/ecp5/Makefile.inc2
-rw-r--r--techlibs/ecp5/cells_ff.vh40
-rw-r--r--techlibs/ecp5/cells_io.vh14
-rw-r--r--techlibs/ecp5/cells_map.v55
-rw-r--r--techlibs/ecp5/cells_sim.v59
-rw-r--r--techlibs/ecp5/tests/.gitignore1
-rw-r--r--techlibs/ecp5/tests/test_diamond_ffs.py82
-rw-r--r--techlibs/xilinx/synth_xilinx.cc37
-rw-r--r--tests/ice40/.gitignore4
-rw-r--r--tests/ice40/add_sub.v13
-rw-r--r--tests/ice40/add_sub.ys9
-rw-r--r--tests/ice40/adffs.v91
-rw-r--r--tests/ice40/adffs.ys12
-rw-r--r--tests/ice40/alu.v19
-rw-r--r--tests/ice40/alu.ys11
-rw-r--r--tests/ice40/counter.v17
-rw-r--r--tests/ice40/counter.ys11
-rw-r--r--tests/ice40/dffs.v37
-rw-r--r--tests/ice40/dffs.ys10
-rw-r--r--tests/ice40/div_mod.v13
-rw-r--r--tests/ice40/div_mod.ys9
-rw-r--r--tests/ice40/dpram.v23
-rw-r--r--tests/ice40/dpram.ys15
-rw-r--r--tests/ice40/fsm.v73
-rw-r--r--tests/ice40/fsm.ys13
-rw-r--r--tests/ice40/latches.v58
-rw-r--r--tests/ice40/latches.ys15
-rw-r--r--tests/ice40/logic.v18
-rw-r--r--tests/ice40/logic.ys7
-rw-r--r--tests/ice40/macc.v25
-rw-r--r--tests/ice40/macc.ys10
-rw-r--r--tests/ice40/memory.v21
-rw-r--r--tests/ice40/memory.ys15
-rw-r--r--tests/ice40/mul.v11
-rw-r--r--tests/ice40/mul.ys7
-rw-r--r--tests/ice40/mux.v100
-rw-r--r--tests/ice40/mux.ys8
-rw-r--r--tests/ice40/rom.v18
-rw-r--r--tests/ice40/rom.ys8
-rwxr-xr-xtests/ice40/run-test.sh2
-rw-r--r--tests/ice40/shifter.v22
-rw-r--r--tests/ice40/shifter.ys9
-rw-r--r--tests/ice40/tribuf.v23
-rw-r--r--tests/ice40/tribuf.ys9
-rwxr-xr-xtests/simple_abc9/run-test.sh8
-rw-r--r--tests/various/shregmap.ys33
-rw-r--r--tests/xilinx/.gitignore3
-rw-r--r--tests/xilinx/pmgen_xilinx_srl.ys57
-rwxr-xr-xtests/xilinx/run-test.sh20
-rw-r--r--tests/xilinx/xilinx_srl.v40
-rw-r--r--tests/xilinx/xilinx_srl.ys67
61 files changed, 1765 insertions, 367 deletions
diff --git a/CHANGELOG b/CHANGELOG
index f7774cb9e..c29429295 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -36,6 +36,8 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
- Removed "ice40_unlut"
- Improvements in pmgen: slices, choices, define, generate
+ - Added "xilinx_srl" for Xilinx shift register extraction
+ - Removed "shregmap -tech xilinx" (superseded by "xilinx_srl")
Yosys 0.8 .. Yosys 0.9
----------------------
diff --git a/Makefile b/Makefile
index 692b19826..2cac80f0f 100644
--- a/Makefile
+++ b/Makefile
@@ -709,6 +709,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/opt && bash run-test.sh
+cd tests/aiger && bash run-test.sh $(ABCOPT)
+cd tests/arch && bash run-test.sh
+ +cd tests/ice40 && bash run-test.sh $(SEEDOPT)
@echo ""
@echo " Passed \"make test\"."
@echo ""
diff --git a/README.md b/README.md
index 38ca77862..e0a95a9d5 100644
--- a/README.md
+++ b/README.md
@@ -330,7 +330,7 @@ Verilog Attributes and non-standard features
- The ``parameter`` and ``localparam`` attributes are used to mark wires
that represent module parameters or localparams (when the HDL front-end
- is run in -pwires mode).
+ is run in ``-pwires`` mode).
- The ``clkbuf_driver`` attribute can be set on an output port of a blackbox
module to mark it as a clock buffer output, and thus prevent ``clkbufmap``
@@ -347,6 +347,23 @@ Verilog Attributes and non-standard features
it as the external-facing pin of an I/O pad, and prevents ``iopadmap``
from inserting another pad cell on it.
+- The module attribute ``abc_box_id`` specifies a positive integer linking a
+ blackbox or whitebox definition to a corresponding entry in a `abc9`
+ box-file.
+
+- The port attribute ``abc_scc_break`` indicates a module input port that will
+ be treated as a primary output during `abc9` techmapping. Doing so eliminates
+ the possibility of a strongly-connected component (i.e. a combinatorial loop)
+ existing. Typically, this is specified for sequential inputs on otherwise
+ combinatorial boxes -- for example, applying ``abc_scc_break`` onto the `D`
+ port of a LUTRAM cell prevents `abc9` from interpreting any `Q` -> `D` paths
+ as a combinatorial loop.
+
+- The port attribute ``abc_carry`` marks the carry-in (if an input port) and
+ carry-out (if output port) ports of a box. This information is necessary for
+ `abc9` to preserve the integrity of carry-chains. Specifying this attribute
+ onto a bus port will affect only its most significant bit.
+
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
the non-standard ``{* ... *}`` attribute syntax to set default attributes
for everything that comes after the ``{* ... *}`` statement. (Reset
@@ -423,23 +440,6 @@ Verilog Attributes and non-standard features
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
functionality. (By default specify .. endspecify blocks are ignored.)
-- The module attribute ``abc_box_id`` specifies a positive integer linking a
- blackbox or whitebox definition to a corresponding entry in a `abc9`
- box-file.
-
-- The port attribute ``abc_scc_break`` indicates a module input port that will
- be treated as a primary output during `abc9` techmapping. Doing so eliminates
- the possibility of a strongly-connected component (i.e. a combinatorial loop)
- existing. Typically, this is specified for sequential inputs on otherwise
- combinatorial boxes -- for example, applying ``abc_scc_break`` onto the `D`
- port of a LUTRAM cell prevents `abc9` from interpreting any `Q` -> `D` paths
- as a combinatorial loop.
-
-- The port attribute ``abc_carry`` marks the carry-in (if an input port) and
- carry-out (if output port) ports of a box. This information is necessary for
- `abc9` to preserve the integrity of carry-chains. Specifying this attribute
- onto a bus port will affect only its most significant bit.
-
Non-standard or SystemVerilog features for formal verification
==============================================================
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index 06522939f..2e1fb8fad 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -974,7 +974,7 @@ void AigerReader::post_process()
// operate (and run checks on) this one module
RTLIL::Design *mapped_design = new RTLIL::Design;
mapped_design->add(module);
- Pass::call(mapped_design, "clean");
+ Pass::call(mapped_design, "clean -purge");
mapped_design->modules_.erase(module->name);
delete mapped_design;
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index 685024ec2..1c66f47c2 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -36,3 +36,9 @@ PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)
+
+# --------------------------------------
+
+OBJS += passes/pmgen/xilinx_srl.o
+passes/pmgen/xilinx_srl.o: passes/pmgen/xilinx_srl_pm.h
+$(eval $(call add_extra_objs,passes/pmgen/xilinx_srl_pm.h))
diff --git a/passes/pmgen/test_pmgen.cc b/passes/pmgen/test_pmgen.cc
index 0ad769dfd..4f3eec935 100644
--- a/passes/pmgen/test_pmgen.cc
+++ b/passes/pmgen/test_pmgen.cc
@@ -28,6 +28,7 @@ bool did_something;
#include "passes/pmgen/test_pmgen_pm.h"
#include "passes/pmgen/ice40_dsp_pm.h"
+#include "passes/pmgen/xilinx_srl_pm.h"
#include "passes/pmgen/peepopt_pm.h"
void reduce_chain(test_pmgen_pm &pm)
@@ -180,7 +181,7 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
{
if (timeout++ > 10000)
- log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n");
+ log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
pm matcher(mod, mod->cells());
@@ -216,7 +217,7 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
run(matcher, [](){});
}
- if (submodcnt)
+ if (submodcnt && maxsubcnt < (1 << 16))
maxsubcnt *= 2;
design->remove(mod);
@@ -349,13 +350,18 @@ struct TestPmgenPass : public Pass {
if (pattern == "ice40_dsp")
return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
+ if (pattern == "xilinx_srl.fixed")
+ return GENERATE_PATTERN(xilinx_srl_pm, fixed);
+ if (pattern == "xilinx_srl.variable")
+ return GENERATE_PATTERN(xilinx_srl_pm, variable);
+
if (pattern == "peepopt-muldiv")
return GENERATE_PATTERN(peepopt_pm, muldiv);
if (pattern == "peepopt-shiftmul")
return GENERATE_PATTERN(peepopt_pm, shiftmul);
- log_cmd_error("Unkown pattern: %s\n", pattern.c_str());
+ log_cmd_error("Unknown pattern: %s\n", pattern.c_str());
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/passes/pmgen/xilinx_srl.cc b/passes/pmgen/xilinx_srl.cc
new file mode 100644
index 000000000..3d264e8d4
--- /dev/null
+++ b/passes/pmgen/xilinx_srl.cc
@@ -0,0 +1,258 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * (C) 2019 Eddie Hung <eddie@fpgeh.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
+
+#include "passes/pmgen/xilinx_srl_pm.h"
+
+void run_fixed(xilinx_srl_pm &pm)
+{
+ auto &st = pm.st_fixed;
+ auto &ud = pm.ud_fixed;
+ log("Found fixed chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
+
+ SigSpec initval;
+ for (auto cell : ud.longest_chain) {
+ log_debug(" %s\n", log_id(cell));
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
+ SigBit Q = cell->getPort(ID(Q));
+ log_assert(Q.wire);
+ auto it = Q.wire->attributes.find(ID(init));
+ if (it != Q.wire->attributes.end()) {
+ auto &i = it->second[Q.offset];
+ initval.append(i);
+ i = State::Sx;
+ }
+ else
+ initval.append(State::Sx);
+ }
+ else if (cell->type.in(ID(FDRE), ID(FDRE_1))) {
+ if (cell->parameters.at(ID(INIT), State::S0).as_bool())
+ initval.append(State::S1);
+ else
+ initval.append(State::S0);
+ }
+ else
+ log_abort();
+ pm.autoremove(cell);
+ }
+
+ auto first_cell = ud.longest_chain.back();
+ auto last_cell = ud.longest_chain.front();
+ Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
+ pm.module->swap_names(c, first_cell);
+
+ if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID(FDRE), ID(FDRE_1))) {
+ c->setParam(ID(DEPTH), GetSize(ud.longest_chain));
+ c->setParam(ID(INIT), initval.as_const());
+ if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ c->setParam(ID(CLKPOL), 1);
+ else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1)))
+ c->setParam(ID(CLKPOL), 0);
+ else if (first_cell->type.in(ID(FDRE))) {
+ if (!first_cell->parameters.at(ID(IS_C_INVERTED), State::S0).as_bool())
+ c->setParam(ID(CLKPOL), 1);
+ else
+ c->setParam(ID(CLKPOL), 0);
+ }
+ else
+ log_abort();
+ if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
+ c->setParam(ID(ENPOL), 1);
+ else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
+ c->setParam(ID(ENPOL), 0);
+ else
+ c->setParam(ID(ENPOL), 2);
+
+ c->setPort(ID(C), first_cell->getPort(ID(C)));
+ c->setPort(ID(D), first_cell->getPort(ID(D)));
+ c->setPort(ID(Q), last_cell->getPort(ID(Q)));
+ c->setPort(ID(L), GetSize(ud.longest_chain)-1);
+ if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
+ c->setPort(ID(E), State::S1);
+ else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ c->setPort(ID(E), first_cell->getPort(ID(E)));
+ else if (first_cell->type.in(ID(FDRE), ID(FDRE_1)))
+ c->setPort(ID(E), first_cell->getPort(ID(CE)));
+ else
+ log_abort();
+ }
+ else
+ log_abort();
+
+ log(" -> %s (%s)\n", log_id(c), log_id(c->type));
+}
+
+void run_variable(xilinx_srl_pm &pm)
+{
+ auto &st = pm.st_variable;
+ auto &ud = pm.ud_variable;
+
+ log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type));
+
+ SigSpec initval;
+ for (const auto &i : ud.chain) {
+ auto cell = i.first;
+ auto slice = i.second;
+ log_debug(" %s\n", log_id(cell));
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) {
+ SigBit Q = cell->getPort(ID(Q))[slice];
+ log_assert(Q.wire);
+ auto it = Q.wire->attributes.find(ID(init));
+ if (it != Q.wire->attributes.end()) {
+ auto &i = it->second[Q.offset];
+ initval.append(i);
+ i = State::Sx;
+ }
+ else
+ initval.append(State::Sx);
+ }
+ else
+ log_abort();
+ }
+ pm.autoremove(st.shiftx);
+
+ auto first_cell = ud.chain.back().first;
+ auto first_slice = ud.chain.back().second;
+
+ Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
+ pm.module->swap_names(c, first_cell);
+
+ if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) {
+ c->setParam(ID(DEPTH), GetSize(ud.chain));
+ c->setParam(ID(INIT), initval.as_const());
+ Const clkpol, enpol;
+ if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ clkpol = 1;
+ else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_)))
+ clkpol = 0;
+ else if (first_cell->type.in(ID($dff), ID($dffe)))
+ clkpol = first_cell->getParam(ID(CLK_POLARITY));
+ else
+ log_abort();
+ if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
+ enpol = 1;
+ else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
+ enpol = 0;
+ else if (first_cell->type.in(ID($dffe)))
+ enpol = first_cell->getParam(ID(EN_POLARITY));
+ else
+ enpol = 2;
+ c->setParam(ID(CLKPOL), clkpol);
+ c->setParam(ID(ENPOL), enpol);
+
+ if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ c->setPort(ID(C), first_cell->getPort(ID(C)));
+ else if (first_cell->type.in(ID($dff), ID($dffe)))
+ c->setPort(ID(C), first_cell->getPort(ID(CLK)));
+ else
+ log_abort();
+ c->setPort(ID(D), first_cell->getPort(ID(D))[first_slice]);
+ c->setPort(ID(Q), st.shiftx->getPort(ID(Y)));
+ c->setPort(ID(L), st.shiftx->getPort(ID(B)));
+ if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($dff)))
+ c->setPort(ID(E), State::S1);
+ else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ c->setPort(ID(E), first_cell->getPort(ID(E)));
+ else if (first_cell->type.in(ID($dffe)))
+ c->setPort(ID(E), first_cell->getPort(ID(EN)));
+ else
+ log_abort();
+ }
+ else
+ log_abort();
+
+ log(" -> %s (%s)\n", log_id(c), log_id(c->type));
+}
+
+struct XilinxSrlPass : public Pass {
+ XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" xilinx_srl [options] [selection]\n");
+ log("\n");
+ log("This pass converts chains of built-in flops (bit-level: $_DFF_[NP]_, $_DFFE_*\n");
+ log("and word-level: $dff, $dffe) as well as Xilinx flops (FDRE, FDRE_1) into a\n");
+ log("$__XILINX_SHREG cell. Chains must be of the same cell type, clock, clock polarity,\n");
+ log("enable, and enable polarity (where relevant).\n");
+ log("Flops with resets cannot be mapped to Xilinx devices and will not be inferred.");
+ log("\n");
+ log(" -minlen N\n");
+ log(" min length of shift register (default = 3)\n");
+ log("\n");
+ log(" -fixed\n");
+ log(" infer fixed-length shift registers.\n");
+ log("\n");
+ log(" -variable\n");
+ log(" infer variable-length shift registers (i.e. fixed-length shifts where\n");
+ log(" each element also fans-out to a $shiftx cell).\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n");
+
+ bool fixed = false;
+ bool variable = false;
+ int minlen = 3;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
+ minlen = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-fixed") {
+ fixed = true;
+ continue;
+ }
+ if (args[argidx] == "-variable") {
+ variable = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!fixed && !variable)
+ log_cmd_error("'-fixed' and/or '-variable' must be specified.\n");
+
+ for (auto module : design->selected_modules()) {
+ auto pm = xilinx_srl_pm(module, module->selected_cells());
+ pm.ud_fixed.minlen = minlen;
+ pm.ud_variable.minlen = minlen;
+
+ if (fixed)
+ pm.run_fixed(run_fixed);
+ if (variable)
+ pm.run_variable(run_variable);
+ }
+ }
+} XilinxSrlPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/xilinx_srl.pmg b/passes/pmgen/xilinx_srl.pmg
new file mode 100644
index 000000000..b18119b87
--- /dev/null
+++ b/passes/pmgen/xilinx_srl.pmg
@@ -0,0 +1,326 @@
+pattern fixed
+
+state <IdString> clk_port en_port
+udata <vector<Cell*>> chain longest_chain
+udata <pool<Cell*>> non_first_cells
+udata <int> minlen
+
+code
+ non_first_cells.clear();
+ subpattern(setup);
+endcode
+
+match first
+ select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
+ select !first->has_keep_attr()
+ select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
+ select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
+ select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero()
+ filter !non_first_cells.count(first)
+generate
+ SigSpec C = module->addWire(NEW_ID);
+ SigSpec D = module->addWire(NEW_ID);
+ SigSpec Q = module->addWire(NEW_ID);
+ auto r = rng(8);
+ Cell* cell;
+ switch (r)
+ {
+ case 0:
+ case 1:
+ cell = module->addCell(NEW_ID, \FDRE);
+ cell->setPort(\C, C);
+ cell->setPort(\D, D);
+ cell->setPort(\Q, Q);
+ cell->setPort(\CE, module->addWire(NEW_ID));
+ if (r & 1)
+ cell->setPort(\R, module->addWire(NEW_ID));
+ else {
+ if (rng(2) == 0)
+ cell->setPort(\R, State::S0);
+ }
+ break;
+ case 2:
+ case 3:
+ cell = module->addDffGate(NEW_ID, C, D, Q, r & 1);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ cell = module->addDffeGate(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 2);
+ break;
+ default: log_abort();
+ }
+endmatch
+
+code clk_port en_port
+ if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1))
+ clk_port = \C;
+ else log_abort();
+ if (first->type.in($_DFF_N_, $_DFF_P_))
+ en_port = IdString();
+ else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
+ en_port = \E;
+ else if (first->type.in(\FDRE, \FDRE_1))
+ en_port = \CE;
+ else log_abort();
+
+ longest_chain.clear();
+ chain.push_back(first);
+ subpattern(tail);
+finally
+ chain.pop_back();
+ log_assert(chain.empty());
+ if (GetSize(longest_chain) >= minlen)
+ accept;
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern setup
+arg clk_port
+arg en_port
+
+match first
+ select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
+ select !first->has_keep_attr()
+ select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
+ select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
+ select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero()
+endmatch
+
+code clk_port en_port
+ if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1))
+ clk_port = \C;
+ else log_abort();
+ if (first->type.in($_DFF_N_, $_DFF_P_))
+ en_port = IdString();
+ else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
+ en_port = \E;
+ else if (first->type.in(\FDRE, \FDRE_1))
+ en_port = \CE;
+ else log_abort();
+endcode
+
+match next
+ select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
+ select !next->has_keep_attr()
+ select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
+ select nusers(port(next, \Q)) == 2
+ index <IdString> next->type === first->type
+ index <SigBit> port(next, \Q) === port(first, \D)
+ filter port(next, clk_port) == port(first, clk_port)
+ filter en_port == IdString() || port(next, en_port) == port(first, en_port)
+ filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool()
+ filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
+ filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
+ filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero()
+endmatch
+
+code
+ non_first_cells.insert(next);
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern tail
+arg first
+arg clk_port
+arg en_port
+
+match next
+ semioptional
+ select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
+ select !next->has_keep_attr()
+ select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
+ select nusers(port(next, \Q)) == 2
+ index <IdString> next->type === chain.back()->type
+ index <SigBit> port(next, \Q) === port(chain.back(), \D)
+ filter port(next, clk_port) == port(first, clk_port)
+ filter en_port == IdString() || port(next, en_port) == port(first, en_port)
+ filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool()
+ filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
+ filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
+ filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero()
+generate
+ Cell *cell = module->addCell(NEW_ID, chain.back()->type);
+ cell->setPort(\C, chain.back()->getPort(\C));
+ cell->setPort(\D, module->addWire(NEW_ID));
+ cell->setPort(\Q, chain.back()->getPort(\D));
+ if (cell->type == \FDRE) {
+ if (rng(2) == 0)
+ cell->setPort(\R, chain.back()->connections_.at(\R, State::S0));
+ cell->setPort(\CE, chain.back()->getPort(\CE));
+ }
+ else if (cell->type.begins_with("$_DFFE_"))
+ cell->setPort(\E, chain.back()->getPort(\E));
+endmatch
+
+code
+ if (next) {
+ chain.push_back(next);
+ subpattern(tail);
+ } else {
+ if (GetSize(chain) > GetSize(longest_chain))
+ longest_chain = chain;
+ }
+finally
+ if (next)
+ chain.pop_back();
+endcode
+
+// -----------
+
+pattern variable
+
+state <IdString> clk_port en_port
+state <int> shiftx_width
+state <int> slice
+udata <int> minlen
+udata <vector<pair<Cell*,int>>> chain
+udata <pool<SigBit>> chain_bits
+
+code
+ chain_bits.clear();
+endcode
+
+match shiftx
+ select shiftx->type.in($shiftx)
+ select !shiftx->has_keep_attr()
+ select param(shiftx, \Y_WIDTH).as_int() == 1
+ filter param(shiftx, \A_WIDTH).as_int() >= minlen
+generate
+ minlen = 3;
+ module->addShiftx(NEW_ID, module->addWire(NEW_ID, rng(6)+minlen), module->addWire(NEW_ID, 3), module->addWire(NEW_ID));
+endmatch
+
+code shiftx_width
+ shiftx_width = param(shiftx, \A_WIDTH).as_int();
+endcode
+
+match first
+ select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe)
+ select !first->has_keep_attr()
+ select port(first, \Q)[0].wire && !port(first, \Q)[0].wire->get_bool_attribute(\keep)
+ slice idx GetSize(port(first, \Q))
+ select nusers(port(first, \Q)[idx]) <= 2
+ index <SigBit> port(first, \Q)[idx] === port(shiftx, \A)[shiftx_width-1]
+ set slice idx
+generate
+ SigSpec C = module->addWire(NEW_ID);
+ auto WIDTH = rng(3)+1;
+ SigSpec D = module->addWire(NEW_ID, WIDTH);
+ SigSpec Q = module->addWire(NEW_ID, WIDTH);
+ auto r = rng(8);
+ Cell *cell = nullptr;
+ switch (r)
+ {
+ case 0:
+ case 1:
+ cell = module->addDff(NEW_ID, C, D, Q, r & 1);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ //cell = module->addDffe(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 4);
+ //break;
+ case 6:
+ case 7:
+ WIDTH = 1;
+ cell = module->addDffGate(NEW_ID, C, D[0], Q[0], r & 1);
+ break;
+ default: log_abort();
+ }
+ shiftx->connections_.at(\A)[shiftx_width-1] = port(cell, \Q)[rng(WIDTH)];
+endmatch
+
+code clk_port en_port
+ if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
+ clk_port = \C;
+ else if (first->type.in($dff, $dffe))
+ clk_port = \CLK;
+ else log_abort();
+ if (first->type.in($_DFF_N_, $_DFF_P_, $dff))
+ en_port = IdString();
+ else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
+ en_port = \E;
+ else if (first->type.in($dffe))
+ en_port = \EN;
+ else log_abort();
+
+ chain_bits.insert(port(first, \Q)[slice]);
+ chain.emplace_back(first, slice);
+ subpattern(tail);
+finally
+ if (GetSize(chain) == shiftx_width)
+ accept;
+ chain.clear();
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern tail
+arg first
+arg shiftx
+arg shiftx_width
+arg slice
+arg clk_port
+arg en_port
+
+match next
+ semioptional
+ select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe)
+ select !next->has_keep_attr()
+ select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
+ slice idx GetSize(port(next, \Q))
+ select nusers(port(next, \Q)[idx]) <= 3
+ index <IdString> next->type === chain.back().first->type
+ index <SigBit> port(next, \Q)[idx] === port(chain.back().first, \D)[chain.back().second]
+ index <SigBit> port(next, \Q)[idx] === port(shiftx, \A)[shiftx_width-1-GetSize(chain)]
+ filter port(next, clk_port) == port(first, clk_port)
+ filter en_port == IdString() || port(next, en_port) == port(first, en_port)
+ filter !next->type.in($dff, $dffe) || param(next, \CLK_POLARITY).as_bool() == param(first, \CLK_POLARITY).as_bool()
+ filter !next->type.in($dffe) || param(next, \EN_POLARITY).as_bool() == param(first, \EN_POLARITY).as_bool()
+ filter !chain_bits.count(port(next, \D)[idx])
+ set slice idx
+generate
+ if (GetSize(chain) < shiftx_width) {
+ auto back = chain.back().first;
+ auto slice = chain.back().second;
+ if (back->type.in($dff, $dffe)) {
+ auto WIDTH = GetSize(port(back, \D));
+ if (rng(2) == 0 && slice < WIDTH-1) {
+ auto new_slice = slice + rng(WIDTH-1-slice);
+ back->connections_.at(\D)[slice] = port(back, \Q)[new_slice];
+ }
+ else {
+ auto D = module->addWire(NEW_ID, WIDTH);
+ if (back->type == $dff)
+ module->addDff(NEW_ID, port(back, \CLK), D, port(back, \D), param(back, \CLK_POLARITY).as_bool());
+ else if (back->type == $dffe)
+ module->addDffe(NEW_ID, port(back, \CLK), port(back, \EN), D, port(back, \D), param(back, \CLK_POLARITY).as_bool(), param(back, \EN_POLARITY).as_bool());
+ else
+ log_abort();
+ }
+ }
+ else if (back->type.begins_with("$_DFF_")) {
+ Cell *cell = module->addCell(NEW_ID, back->type);
+ cell->setPort(\C, back->getPort(\C));
+ cell->setPort(\D, module->addWire(NEW_ID));
+ cell->setPort(\Q, back->getPort(\D));
+ }
+ else
+ log_abort();
+ shiftx->connections_.at(\A)[shiftx_width-1-GetSize(chain)] = port(back, \D)[slice];
+ }
+endmatch
+
+code
+ if (next) {
+ chain_bits.insert(port(next, \Q)[slice]);
+ chain.emplace_back(next, slice);
+ if (GetSize(chain) < shiftx_width)
+ subpattern(tail);
+ }
+endcode
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 84cb2c04f..6fdf987f0 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -694,30 +694,27 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
int in_wires = 0, out_wires = 0;
// Stitch in mapped_mod's inputs/outputs into module
- for (auto &it : mapped_mod->wires_) {
- RTLIL::Wire *w = it.second;
- if (!w->port_input && !w->port_output)
- continue;
- RTLIL::Wire *wire = module->wire(w->name);
+ for (auto port : mapped_mod->ports) {
+ RTLIL::Wire *w = mapped_mod->wire(port);
+ RTLIL::Wire *wire = module->wire(port);
log_assert(wire);
- RTLIL::Wire *remap_wire = module->wire(remap_name(w->name));
+ RTLIL::Wire *remap_wire = module->wire(remap_name(port));
RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
log_assert(GetSize(signal) >= GetSize(remap_wire));
- log_assert(w->port_input || w->port_output);
RTLIL::SigSig conn;
- if (w->port_input) {
- conn.first = remap_wire;
- conn.second = signal;
- in_wires++;
- module->connect(conn);
- }
if (w->port_output) {
conn.first = signal;
conn.second = remap_wire;
out_wires++;
module->connect(conn);
}
+ else if (w->port_input) {
+ conn.first = remap_wire;
+ conn.second = signal;
+ in_wires++;
+ module->connect(conn);
+ }
}
for (auto &it : bit_users)
@@ -1300,9 +1297,6 @@ struct Abc9Pass : public Pass {
assign_map.clear();
- // The "clean" pass also contains a design->check() call
- Pass::call(design, "clean");
-
log_pop();
}
} Abc9Pass;
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index 02cc27ae2..be00e5030 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -26,9 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ShregmapTech
{
virtual ~ShregmapTech() { }
- virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {}
- virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {}
- virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0;
+ virtual bool analyze(vector<int> &taps) = 0;
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
};
@@ -56,7 +54,7 @@ struct ShregmapOptions
struct ShregmapTechGreenpak4 : ShregmapTech
{
- bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/)
+ bool analyze(vector<int> &taps)
{
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
taps.clear();
@@ -93,155 +91,6 @@ struct ShregmapTechGreenpak4 : ShregmapTech
}
};
-struct ShregmapTechXilinx7 : ShregmapTech
-{
- dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
- const ShregmapOptions &opts;
-
- ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {}
-
- virtual void init(const Module* module, const SigMap &sigmap) override
- {
- for (const auto &i : module->cells_) {
- auto cell = i.second;
- if (cell->type == ID($shiftx)) {
- if (cell->getParam(ID(Y_WIDTH)) != 1) continue;
- int j = 0;
- for (auto bit : sigmap(cell->getPort(ID::A)))
- sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
- log_assert(j == cell->getParam(ID(A_WIDTH)).as_int());
- }
- else if (cell->type == ID($mux)) {
- int j = 0;
- for (auto bit : sigmap(cell->getPort(ID::A)))
- sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
- j = 0;
- for (auto bit : sigmap(cell->getPort(ID::B)))
- sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
- }
- }
- }
-
- virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override
- {
- auto it = sigbit_to_shiftx_offset.find(bit);
- if (it == sigbit_to_shiftx_offset.end())
- return;
- if (cell) {
- if (cell->type == ID($shiftx) && port == ID::A)
- return;
- if (cell->type == ID($mux) && port.in(ID::A, ID::B))
- return;
- }
- sigbit_to_shiftx_offset.erase(it);
- }
-
- virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override
- {
- if (GetSize(taps) == 1)
- return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]);
-
- if (taps.back() < opts.minlen-1)
- return false;
-
- Cell *shiftx = nullptr;
- int group = 0;
- for (int i = 0; i < GetSize(taps); ++i) {
- auto it = sigbit_to_shiftx_offset.find(qbits[i]);
- if (it == sigbit_to_shiftx_offset.end())
- return false;
-
- // Check taps are sequential
- if (i != taps[i])
- return false;
- // Check taps are not connected to a shift register,
- // or sequential to the same shift register
- if (i == 0) {
- int offset;
- std::tie(shiftx,offset,group) = it->second;
- if (offset != i)
- return false;
- }
- else {
- Cell *shiftx_ = std::get<0>(it->second);
- if (shiftx_ != shiftx)
- return false;
- int offset = std::get<1>(it->second);
- if (offset != i)
- return false;
- int group_ = std::get<2>(it->second);
- if (group_ != group)
- return false;
- }
- }
- log_assert(shiftx);
-
- // Only map if $shiftx exclusively covers the shift register
- if (shiftx->type == ID($shiftx)) {
- if (GetSize(taps) > shiftx->getParam(ID(A_WIDTH)).as_int())
- return false;
- // Due to padding the most significant bits of A may be 1'bx,
- // and if so, discount them
- if (GetSize(taps) < shiftx->getParam(ID(A_WIDTH)).as_int()) {
- const SigSpec A = shiftx->getPort(ID::A);
- const int A_width = shiftx->getParam(ID(A_WIDTH)).as_int();
- for (int i = GetSize(taps); i < A_width; ++i)
- if (A[i] != RTLIL::Sx) return false;
- }
- else if (GetSize(taps) != shiftx->getParam(ID(A_WIDTH)).as_int())
- return false;
- }
- else if (shiftx->type == ID($mux)) {
- if (GetSize(taps) != 2)
- return false;
- }
- else log_abort();
-
- return true;
- }
-
- virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override
- {
- const auto &tap = *taps.begin();
- auto bit = tap.second;
-
- auto it = sigbit_to_shiftx_offset.find(bit);
- log_assert(it != sigbit_to_shiftx_offset.end());
-
- auto newcell = cell->module->addCell(NEW_ID, ID($__XILINX_SHREG_));
- newcell->set_src_attribute(cell->get_src_attribute());
- newcell->setParam(ID(DEPTH), cell->getParam(ID(DEPTH)));
- newcell->setParam(ID(INIT), cell->getParam(ID(INIT)));
- newcell->setParam(ID(CLKPOL), cell->getParam(ID(CLKPOL)));
- newcell->setParam(ID(ENPOL), cell->getParam(ID(ENPOL)));
-
- newcell->setPort(ID(C), cell->getPort(ID(C)));
- newcell->setPort(ID(D), cell->getPort(ID(D)));
- if (cell->hasPort(ID(E)))
- newcell->setPort(ID(E), cell->getPort(ID(E)));
-
- Cell* shiftx = std::get<0>(it->second);
- RTLIL::SigSpec l_wire, q_wire;
- if (shiftx->type == ID($shiftx)) {
- l_wire = shiftx->getPort(ID::B);
- q_wire = shiftx->getPort(ID::Y);
- shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
- }
- else if (shiftx->type == ID($mux)) {
- l_wire = shiftx->getPort(ID(S));
- q_wire = shiftx->getPort(ID::Y);
- shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
- }
- else log_abort();
-
- newcell->setPort(ID(Q), q_wire);
- newcell->setPort(ID(L), l_wire);
-
- return false;
- }
-};
-
-
struct ShregmapWorker
{
Module *module;
@@ -264,10 +113,8 @@ struct ShregmapWorker
for (auto wire : module->wires())
{
if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
- for (auto bit : sigmap(wire)) {
+ for (auto bit : sigmap(wire))
sigbit_with_non_chain_users.insert(bit);
- if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
- }
}
if (wire->attributes.count(ID(init))) {
@@ -317,10 +164,8 @@ struct ShregmapWorker
for (auto conn : cell->connections())
if (cell->input(conn.first))
- for (auto bit : sigmap(conn.second)) {
+ for (auto bit : sigmap(conn.second))
sigbit_with_non_chain_users.insert(bit);
- if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first);
- }
}
}
@@ -425,7 +270,7 @@ struct ShregmapWorker
if (taps.empty() || taps.back() < depth-1)
taps.push_back(depth-1);
- if (opts.tech->analyze(taps, qbits))
+ if (opts.tech->analyze(taps))
break;
taps.pop_back();
@@ -544,9 +389,6 @@ struct ShregmapWorker
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
{
- if (opts.tech)
- opts.tech->init(module, sigmap);
-
make_sigbit_chain_next_prev();
find_chain_start_cells();
@@ -617,11 +459,6 @@ struct ShregmapPass : public Pass {
log("\n");
log(" -tech greenpak4\n");
log(" map to greenpak4 shift registers.\n");
- log(" this option also implies -clkpol pos -zinit\n");
- log("\n");
- log(" -tech xilinx\n");
- log(" map to xilinx dynamic-length shift registers.\n");
- log(" this option also implies -params -init\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -676,12 +513,6 @@ struct ShregmapPass : public Pass {
clkpol = "pos";
opts.zinit = true;
opts.tech = new ShregmapTechGreenpak4;
- }
- else if (tech == "xilinx") {
- opts.init = true;
- opts.params = true;
- enpol = "any_or_none";
- opts.tech = new ShregmapTechXilinx7(opts);
} else {
argidx--;
break;
diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc
index 96ca25075..a0c4e34e3 100644
--- a/techlibs/ecp5/Makefile.inc
+++ b/techlibs/ecp5/Makefile.inc
@@ -2,6 +2,8 @@
OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \
techlibs/ecp5/ecp5_gsr.o
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v))
diff --git a/techlibs/ecp5/cells_ff.vh b/techlibs/ecp5/cells_ff.vh
new file mode 100644
index 000000000..0c9689ebd
--- /dev/null
+++ b/techlibs/ecp5/cells_ff.vh
@@ -0,0 +1,40 @@
+// Diamond flip-flops
+module FD1P3AX(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .CE(SP), .DI(D), .Q(Q)); endmodule
+module FD1P3AY(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .CE(SP), .DI(D), .Q(Q)); endmodule
+module FD1P3BX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module FD1P3DX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module FD1P3IX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module FD1P3JX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module FD1S3AX(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .DI(D), .Q(Q)); endmodule
+module FD1S3AY(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .DI(D), .Q(Q)); endmodule
+module FD1S3BX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+module FD1S3DX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3IX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3JX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+
+// TODO: Diamond latches
+// module FL1P3AY(); endmodule
+// module FL1P3AZ(); endmodule
+// module FL1P3BX(); endmodule
+// module FL1P3DX(); endmodule
+// module FL1P3IY(); endmodule
+// module FL1P3JY(); endmodule
+// module FL1S3AX(); endmodule
+// module FL1S3AY(); endmodule
+
+// Diamond I/O registers
+module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+module OFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+// TODO: Diamond I/O latches
+// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
+// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
diff --git a/techlibs/ecp5/cells_io.vh b/techlibs/ecp5/cells_io.vh
new file mode 100644
index 000000000..02e66e8a5
--- /dev/null
+++ b/techlibs/ecp5/cells_io.vh
@@ -0,0 +1,14 @@
+// Diamond I/O buffers
+module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
+module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
+module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
+module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule
+module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
+module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
+module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
+module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
+module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
+module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
+module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
+module ILVDS(input A, AN, output Z ); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
+module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
index 0a92d906d..71ae9237b 100644
--- a/techlibs/ecp5/cells_map.v
+++ b/techlibs/ecp5/cells_map.v
@@ -47,59 +47,8 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .
module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
-// TODO: Diamond flip-flops
-// module FD1P3AX(); endmodule
-// module FD1P3AY(); endmodule
-// module FD1P3BX(); endmodule
-// module FD1P3DX(); endmodule
-// module FD1P3IX(); endmodule
-// module FD1P3JX(); endmodule
-// module FD1S3AX(); endmodule
-// module FD1S3AY(); endmodule
-module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
-module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
-module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
-module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
-// module FL1P3AY(); endmodule
-// module FL1P3AZ(); endmodule
-// module FL1P3BX(); endmodule
-// module FL1P3DX(); endmodule
-// module FL1P3IY(); endmodule
-// module FL1P3JY(); endmodule
-// module FL1S3AX(); endmodule
-// module FL1S3AY(); endmodule
-
-// Diamond I/O buffers
-module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
-module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
-module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
-module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule
-module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
-module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
-module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
-module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule
-module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
-module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
-module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
-module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
-module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
-
-// Diamond I/O registers
-module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
-
-module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
-
-// TODO: Diamond I/O latches
-// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
-// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
-// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
-// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
+`include "cells_ff.vh"
+`include "cells_io.vh"
`ifndef NO_LUT
module \$lut (A, Y);
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
index dc8334acb..75a1aad1f 100644
--- a/techlibs/ecp5/cells_sim.v
+++ b/techlibs/ecp5/cells_sim.v
@@ -693,56 +693,9 @@ module DP16KD(
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
endmodule
-// TODO: Diamond flip-flops
-// module FD1P3AX(); endmodule
-// module FD1P3AY(); endmodule
-// module FD1P3BX(); endmodule
-// module FD1P3DX(); endmodule
-// module FD1P3IX(); endmodule
-// module FD1P3JX(); endmodule
-// module FD1S3AX(); endmodule
-// module FD1S3AY(); endmodule
-module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
-module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
-module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
-module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
-// module FL1P3AY(); endmodule
-// module FL1P3AZ(); endmodule
-// module FL1P3BX(); endmodule
-// module FL1P3DX(); endmodule
-// module FL1P3IY(); endmodule
-// module FL1P3JY(); endmodule
-// module FL1S3AX(); endmodule
-// module FL1S3AY(); endmodule
-
-// Diamond I/O buffers
-module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
-module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
-module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
-module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule
-module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
-module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
-module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
-module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
-module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
-module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
-module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
-module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) tio (.B(A), .O(Z)); endmodule
-module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule
-
-// Diamond I/O registers
-module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
-
-module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
-module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
-
-// TODO: Diamond I/O latches
-// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
-// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
-// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
-// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
+`ifndef NO_INCLUDES
+
+`include "cells_ff.vh"
+`include "cells_io.vh"
+
+`endif
diff --git a/techlibs/ecp5/tests/.gitignore b/techlibs/ecp5/tests/.gitignore
new file mode 100644
index 000000000..0e18132cc
--- /dev/null
+++ b/techlibs/ecp5/tests/.gitignore
@@ -0,0 +1 @@
+work_*
diff --git a/techlibs/ecp5/tests/test_diamond_ffs.py b/techlibs/ecp5/tests/test_diamond_ffs.py
new file mode 100644
index 000000000..1ed85ce8b
--- /dev/null
+++ b/techlibs/ecp5/tests/test_diamond_ffs.py
@@ -0,0 +1,82 @@
+import os
+import subprocess
+
+if not os.path.exists("work_ff"):
+ os.mkdir("work_ff")
+
+modules = []
+
+with open("../cells_ff.vh", "r") as f:
+ with open("work_ff/cells_ff_gate.v", "w") as g:
+ for line in f:
+ if not line.startswith("module"):
+ g.write(line)
+ continue
+ else:
+ spidx = line.find(" ")
+ bridx = line.find("(")
+ modname = line[spidx+1 : bridx]
+ g.write("module %s_gate" % modname)
+ g.write(line[bridx:])
+ inpidx = line.find("input ")
+ outpidx = line.find(", output")
+ modules.append((modname, [x.strip() for x in line[inpidx+6:outpidx].split(",")]))
+
+with open("work_ff/testbench.v", "w") as f:
+ print("""
+`timescale 1ns/ 1ps
+
+module testbench;
+reg pur = 0, clk, rst, cen, d;
+
+// Needed for Diamond sim models
+GSR GSR_INST (.GSR(1'b1));
+PUR PUR_INST (.PUR(pur));
+
+
+initial begin
+ $dumpfile("work_ff/ffs.vcd");
+ $dumpvars(0, testbench);
+ #5;
+ pur = 1;
+ #95;
+ repeat (2500) begin
+ {clk, rst, cen, d} = $random;
+ #10;
+ check_outputs;
+ #1;
+ end
+ $finish;
+end
+ """, file=f)
+
+ for modname, inputs in modules:
+ print(" wire %s_gold_q, %s_gate_q;" % (modname, modname), file=f)
+ portconns = []
+ for inp in inputs:
+ if inp in ("SCLK", "CK"):
+ portconns.append(".%s(clk)" % inp)
+ elif inp in ("CD", "PD"):
+ portconns.append(".%s(rst)" % inp)
+ elif inp == "SP":
+ portconns.append(".%s(cen)" % inp)
+ elif inp == "D":
+ portconns.append(".%s(d)" % inp)
+ else:
+ assert False
+ portconns.append(".Q(%s_gold_q)" % modname)
+ print(" %s %s_gold_i (%s);" % (modname, modname, ", ".join(portconns)), file=f)
+ portconns[-1] = (".Q(%s_gate_q)" % modname)
+ print(" %s_gate %s_gate_i (%s);" % (modname, modname, ", ".join(portconns)), file=f)
+ print("", file=f)
+ print(" task check_outputs;", file=f)
+ print(" begin", file=f)
+ print(" if (%s_gold_q != %s_gate_q) $display(\"MISMATCH at %%1t: %s_gold_q=%%b, %s_gate_q=%%b\", $time, %s_gold_q, %s_gate_q);" %
+ (modname, modname, modname, modname, modname, modname), file=f)
+ print(" end", file=f)
+ print(" endtask", file=f)
+ print("endmodule", file=f)
+
+diamond_models = "/usr/local/diamond/3.10_x64/cae_library/simulation/verilog/ecp5u"
+subprocess.call(["iverilog", "-s", "testbench", "-o", "work_ff/testbench", "-Dmixed_hdl", "-DNO_INCLUDES", "-y", diamond_models, "work_ff/cells_ff_gate.v", "../cells_sim.v", "work_ff/testbench.v"])
+subprocess.call(["vvp", "work_ff/testbench"])
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 5e491b86b..5af27dea8 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -310,9 +310,8 @@ struct SynthXilinxPass : public ScriptPass
if (widemux > 0 || help_mode)
run("muxpack", " ('-widemux' only)");
- // shregmap -tech xilinx can cope with $shiftx and $mux
- // cells for identifying variable-length shift registers,
- // so attempt to convert $pmux-es to the former
+ // xilinx_srl looks for $shiftx cells for identifying variable-length
+ // shift registers, so attempt to convert $pmux-es to this
// Also: wide multiplexer inference benefits from this too
if (!(nosrl && widemux == 0) || help_mode) {
run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')");
@@ -408,13 +407,8 @@ struct SynthXilinxPass : public ScriptPass
}
run("opt -full");
- if (!nosrl || help_mode) {
- // shregmap operates on bit-level flops, not word-level,
- // so break those down here
- run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')");
- // shregmap with '-tech xilinx' infers variable length shift regs
- run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
- }
+ if (!nosrl || help_mode)
+ run("xilinx_srl -variable -minlen 3", "(skip if '-nosrl')");
std::string techmap_args = " -map +/techmap.v";
if (help_mode)
@@ -442,6 +436,14 @@ struct SynthXilinxPass : public ScriptPass
run("clean");
}
+ if (check_label("map_ffs")) {
+ if (abc9 || help_mode) {
+ run("techmap -map +/xilinx/ff_map.v", "('-abc9' only)");
+ run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
+ "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT", "('-abc9' only)");
+ }
+ }
+
if (check_label("map_luts")) {
run("opt_expr -mux_undef");
if (flatten_before_abc)
@@ -467,10 +469,17 @@ struct SynthXilinxPass : public ScriptPass
// This shregmap call infers fixed length shift registers after abc
// has performed any necessary retiming
if (!nosrl || help_mode)
- run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
- run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
- run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
- "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
+ run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
+
+ std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
+ if (help_mode)
+ techmap_args += " [-map +/xilinx/ff_map.v]";
+ else if (!abc9)
+ techmap_args += " -map +/xilinx/ff_map.v";
+ run("techmap " + techmap_args);
+ if (!abc9)
+ run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
+ "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT", "(without '-abc9' only)");
run("clean");
}
diff --git a/tests/ice40/.gitignore b/tests/ice40/.gitignore
new file mode 100644
index 000000000..9a71dca69
--- /dev/null
+++ b/tests/ice40/.gitignore
@@ -0,0 +1,4 @@
+*.log
+/run-test.mk
++*_synth.v
++*_testbench
diff --git a/tests/ice40/add_sub.v b/tests/ice40/add_sub.v
new file mode 100644
index 000000000..177c32e30
--- /dev/null
+++ b/tests/ice40/add_sub.v
@@ -0,0 +1,13 @@
+module top
+(
+ input [3:0] x,
+ input [3:0] y,
+
+ output [3:0] A,
+ output [3:0] B
+ );
+
+assign A = x + y;
+assign B = x - y;
+
+endmodule
diff --git a/tests/ice40/add_sub.ys b/tests/ice40/add_sub.ys
new file mode 100644
index 000000000..4a998d98d
--- /dev/null
+++ b/tests/ice40/add_sub.ys
@@ -0,0 +1,9 @@
+read_verilog add_sub.v
+hierarchy -top top
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 11 t:SB_LUT4
+select -assert-count 6 t:SB_CARRY
+select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D
+
diff --git a/tests/ice40/adffs.v b/tests/ice40/adffs.v
new file mode 100644
index 000000000..93c8bf52c
--- /dev/null
+++ b/tests/ice40/adffs.v
@@ -0,0 +1,91 @@
+module adff
+ ( input d, clk, clr, output reg q );
+ initial begin
+ q = 0;
+ end
+ always @( posedge clk, posedge clr )
+ if ( clr )
+ q <= 1'b0;
+ else
+ q <= d;
+endmodule
+
+module adffn
+ ( input d, clk, clr, output reg q );
+ initial begin
+ q = 0;
+ end
+ always @( posedge clk, negedge clr )
+ if ( !clr )
+ q <= 1'b0;
+ else
+ q <= d;
+endmodule
+
+module dffsr
+ ( input d, clk, pre, clr, output reg q );
+ initial begin
+ q = 0;
+ end
+ always @( posedge clk, posedge pre, posedge clr )
+ if ( clr )
+ q <= 1'b0;
+ else if ( pre )
+ q <= 1'b1;
+ else
+ q <= d;
+endmodule
+
+module ndffnsnr
+ ( input d, clk, pre, clr, output reg q );
+ initial begin
+ q = 0;
+ end
+ always @( negedge clk, negedge pre, negedge clr )
+ if ( !clr )
+ q <= 1'b0;
+ else if ( !pre )
+ q <= 1'b1;
+ else
+ q <= d;
+endmodule
+
+module top (
+input clk,
+input clr,
+input pre,
+input a,
+output b,b1,b2,b3
+);
+
+dffsr u_dffsr (
+ .clk (clk ),
+ .clr (clr),
+ .pre (pre),
+ .d (a ),
+ .q (b )
+ );
+
+ndffnsnr u_ndffnsnr (
+ .clk (clk ),
+ .clr (clr),
+ .pre (pre),
+ .d (a ),
+ .q (b1 )
+ );
+
+adff u_adff (
+ .clk (clk ),
+ .clr (clr),
+ .d (a ),
+ .q (b2 )
+ );
+
+adffn u_adffn (
+ .clk (clk ),
+ .clr (clr),
+ .d (a ),
+ .q (b3 )
+ );
+
+endmodule
diff --git a/tests/ice40/adffs.ys b/tests/ice40/adffs.ys
new file mode 100644
index 000000000..14b251c5c
--- /dev/null
+++ b/tests/ice40/adffs.ys
@@ -0,0 +1,12 @@
+read_verilog adffs.v
+proc
+async2sync # converts async flops to a 'sync' variant clocked by a 'super'-clock
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 1 t:SB_DFF
+select -assert-count 1 t:SB_DFFN
+select -assert-count 2 t:SB_DFFSR
+select -assert-count 7 t:SB_LUT4
+select -assert-none t:SB_DFF t:SB_DFFN t:SB_DFFSR t:SB_LUT4 %% t:* %D
diff --git a/tests/ice40/alu.v b/tests/ice40/alu.v
new file mode 100644
index 000000000..f82cc2e21
--- /dev/null
+++ b/tests/ice40/alu.v
@@ -0,0 +1,19 @@
+module top (
+ input clock,
+ input [31:0] dinA, dinB,
+ input [2:0] opcode,
+ output reg [31:0] dout
+);
+ always @(posedge clock) begin
+ case (opcode)
+ 0: dout <= dinA + dinB;
+ 1: dout <= dinA - dinB;
+ 2: dout <= dinA >> dinB;
+ 3: dout <= $signed(dinA) >>> dinB;
+ 4: dout <= dinA << dinB;
+ 5: dout <= dinA & dinB;
+ 6: dout <= dinA | dinB;
+ 7: dout <= dinA ^ dinB;
+ endcase
+ end
+endmodule
diff --git a/tests/ice40/alu.ys b/tests/ice40/alu.ys
new file mode 100644
index 000000000..bd859efc4
--- /dev/null
+++ b/tests/ice40/alu.ys
@@ -0,0 +1,11 @@
+read_verilog alu.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 62 t:SB_CARRY
+select -assert-count 32 t:SB_DFF
+select -assert-count 655 t:SB_LUT4
+select -assert-none t:SB_CARRY t:SB_DFF t:SB_LUT4 %% t:* %D
diff --git a/tests/ice40/counter.v b/tests/ice40/counter.v
new file mode 100644
index 000000000..52852f8ac
--- /dev/null
+++ b/tests/ice40/counter.v
@@ -0,0 +1,17 @@
+module top (
+out,
+clk,
+reset
+);
+ output [7:0] out;
+ input clk, reset;
+ reg [7:0] out;
+
+ always @(posedge clk, posedge reset)
+ if (reset) begin
+ out <= 8'b0 ;
+ end else
+ out <= out + 1;
+
+
+endmodule
diff --git a/tests/ice40/counter.ys b/tests/ice40/counter.ys
new file mode 100644
index 000000000..c65c21622
--- /dev/null
+++ b/tests/ice40/counter.ys
@@ -0,0 +1,11 @@
+read_verilog counter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 6 t:SB_CARRY
+select -assert-count 8 t:SB_DFFR
+select -assert-count 8 t:SB_LUT4
+select -assert-none t:SB_CARRY t:SB_DFFR t:SB_LUT4 %% t:* %D
diff --git a/tests/ice40/dffs.v b/tests/ice40/dffs.v
new file mode 100644
index 000000000..d97840c43
--- /dev/null
+++ b/tests/ice40/dffs.v
@@ -0,0 +1,37 @@
+module dff
+ ( input d, clk, output reg q );
+ always @( posedge clk )
+ q <= d;
+endmodule
+
+module dffe
+ ( input d, clk, en, output reg q );
+ initial begin
+ q = 0;
+ end
+ always @( posedge clk )
+ if ( en )
+ q <= d;
+endmodule
+
+module top (
+input clk,
+input en,
+input a,
+output b,b1,
+);
+
+dff u_dff (
+ .clk (clk ),
+ .d (a ),
+ .q (b )
+ );
+
+dffe u_ndffe (
+ .clk (clk ),
+ .en (en),
+ .d (a ),
+ .q (b1 )
+ );
+
+endmodule
diff --git a/tests/ice40/dffs.ys b/tests/ice40/dffs.ys
new file mode 100644
index 000000000..ee7f884b1
--- /dev/null
+++ b/tests/ice40/dffs.ys
@@ -0,0 +1,10 @@
+read_verilog dffs.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 1 t:SB_DFF
+select -assert-count 1 t:SB_DFFE
+select -assert-none t:SB_DFF t:SB_DFFE %% t:* %D
diff --git a/tests/ice40/div_mod.v b/tests/ice40/div_mod.v
new file mode 100644
index 000000000..64a36707d
--- /dev/null
+++ b/tests/ice40/div_mod.v
@@ -0,0 +1,13 @@
+module top
+(
+ input [3:0] x,
+ input [3:0] y,
+
+ output [3:0] A,
+ output [3:0] B
+ );
+
+assign A = x % y;
+assign B = x / y;
+
+endmodule
diff --git a/tests/ice40/div_mod.ys b/tests/ice40/div_mod.ys
new file mode 100644
index 000000000..21cac7144
--- /dev/null
+++ b/tests/ice40/div_mod.ys
@@ -0,0 +1,9 @@
+read_verilog div_mod.v
+hierarchy -top top
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 62 t:SB_LUT4
+select -assert-count 41 t:SB_CARRY
+select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D
diff --git a/tests/ice40/dpram.v b/tests/ice40/dpram.v
new file mode 100644
index 000000000..3ea4c1f27
--- /dev/null
+++ b/tests/ice40/dpram.v
@@ -0,0 +1,23 @@
+/*
+Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 72].
+*/
+module top (din, write_en, waddr, wclk, raddr, rclk, dout);
+parameter addr_width = 8;
+parameter data_width = 8;
+input [addr_width-1:0] waddr, raddr;
+input [data_width-1:0] din;
+input write_en, wclk, rclk;
+output [data_width-1:0] dout;
+reg [data_width-1:0] dout;
+reg [data_width-1:0] mem [(1<<addr_width)-1:0]
+/* synthesis syn_ramstyle = "no_rw_check" */ ;
+always @(posedge wclk) // Write memory.
+begin
+if (write_en)
+mem[waddr] <= din; // Using write address bus.
+end
+always @(posedge rclk) // Read memory.
+begin
+dout <= mem[raddr]; // Using read address bus.
+end
+endmodule
diff --git a/tests/ice40/dpram.ys b/tests/ice40/dpram.ys
new file mode 100644
index 000000000..4f6a253ea
--- /dev/null
+++ b/tests/ice40/dpram.ys
@@ -0,0 +1,15 @@
+read_verilog dpram.v
+hierarchy -top top
+proc
+memory -nomap
+equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
+memory
+opt -full
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
+
+design -load postopt
+cd top
+select -assert-count 1 t:SB_RAM40_4K
+select -assert-none t:SB_RAM40_4K %% t:* %D
diff --git a/tests/ice40/fsm.v b/tests/ice40/fsm.v
new file mode 100644
index 000000000..0605bd102
--- /dev/null
+++ b/tests/ice40/fsm.v
@@ -0,0 +1,73 @@
+ module fsm (
+ clock,
+ reset,
+ req_0,
+ req_1,
+ gnt_0,
+ gnt_1
+ );
+ input clock,reset,req_0,req_1;
+ output gnt_0,gnt_1;
+ wire clock,reset,req_0,req_1;
+ reg gnt_0,gnt_1;
+
+ parameter SIZE = 3 ;
+ parameter IDLE = 3'b001,GNT0 = 3'b010,GNT1 = 3'b100,GNT2 = 3'b101 ;
+
+ reg [SIZE-1:0] state;
+ reg [SIZE-1:0] next_state;
+
+ always @ (posedge clock)
+ begin : FSM
+ if (reset == 1'b1) begin
+ state <= #1 IDLE;
+ gnt_0 <= 0;
+ gnt_1 <= 0;
+ end else
+ case(state)
+ IDLE : if (req_0 == 1'b1) begin
+ state <= #1 GNT0;
+ gnt_0 <= 1;
+ end else if (req_1 == 1'b1) begin
+ gnt_1 <= 1;
+ state <= #1 GNT0;
+ end else begin
+ state <= #1 IDLE;
+ end
+ GNT0 : if (req_0 == 1'b1) begin
+ state <= #1 GNT0;
+ end else begin
+ gnt_0 <= 0;
+ state <= #1 IDLE;
+ end
+ GNT1 : if (req_1 == 1'b1) begin
+ state <= #1 GNT2;
+ gnt_1 <= req_0;
+ end
+ GNT2 : if (req_0 == 1'b1) begin
+ state <= #1 GNT1;
+ gnt_1 <= req_1;
+ end
+ default : state <= #1 IDLE;
+ endcase
+ end
+
+ endmodule
+
+ module top (
+input clk,
+input rst,
+input a,
+input b,
+output g0,
+output g1
+);
+
+fsm u_fsm ( .clock(clk),
+ .reset(rst),
+ .req_0(a),
+ .req_1(b),
+ .gnt_0(g0),
+ .gnt_1(g1));
+
+endmodule
diff --git a/tests/ice40/fsm.ys b/tests/ice40/fsm.ys
new file mode 100644
index 000000000..4cc8629d6
--- /dev/null
+++ b/tests/ice40/fsm.ys
@@ -0,0 +1,13 @@
+read_verilog fsm.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 2 t:SB_DFFESR
+select -assert-count 2 t:SB_DFFSR
+select -assert-count 1 t:SB_DFFSS
+select -assert-count 13 t:SB_LUT4
+select -assert-none t:SB_DFFESR t:SB_DFFSR t:SB_DFFSS t:SB_LUT4 %% t:* %D
diff --git a/tests/ice40/latches.v b/tests/ice40/latches.v
new file mode 100644
index 000000000..9dc43e4c2
--- /dev/null
+++ b/tests/ice40/latches.v
@@ -0,0 +1,58 @@
+module latchp
+ ( input d, clk, en, output reg q );
+ always @*
+ if ( en )
+ q <= d;
+endmodule
+
+module latchn
+ ( input d, clk, en, output reg q );
+ always @*
+ if ( !en )
+ q <= d;
+endmodule
+
+module latchsr
+ ( input d, clk, en, clr, pre, output reg q );
+ always @*
+ if ( clr )
+ q <= 1'b0;
+ else if ( pre )
+ q <= 1'b1;
+ else if ( en )
+ q <= d;
+endmodule
+
+
+module top (
+input clk,
+input clr,
+input pre,
+input a,
+output b,b1,b2
+);
+
+
+latchp u_latchp (
+ .en (clk ),
+ .d (a ),
+ .q (b )
+ );
+
+
+latchn u_latchn (
+ .en (clk ),
+ .d (a ),
+ .q (b1 )
+ );
+
+
+latchsr u_latchsr (
+ .en (clk ),
+ .clr (clr),
+ .pre (pre),
+ .d (a ),
+ .q (b2 )
+ );
+
+endmodule
diff --git a/tests/ice40/latches.ys b/tests/ice40/latches.ys
new file mode 100644
index 000000000..f3562559e
--- /dev/null
+++ b/tests/ice40/latches.ys
@@ -0,0 +1,15 @@
+read_verilog latches.v
+design -save read
+
+proc
+async2sync # converts latches to a 'sync' variant clocked by a 'super'-clock
+flatten
+synth_ice40
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+
+design -load read
+synth_ice40
+cd top
+select -assert-count 4 t:SB_LUT4
+select -assert-none t:SB_LUT4 %% t:* %D
diff --git a/tests/ice40/logic.v b/tests/ice40/logic.v
new file mode 100644
index 000000000..e5343cae0
--- /dev/null
+++ b/tests/ice40/logic.v
@@ -0,0 +1,18 @@
+module top
+(
+ input [0:7] in,
+ output B1,B2,B3,B4,B5,B6,B7,B8,B9,B10
+ );
+
+ assign B1 = in[0] & in[1];
+ assign B2 = in[0] | in[1];
+ assign B3 = in[0] ~& in[1];
+ assign B4 = in[0] ~| in[1];
+ assign B5 = in[0] ^ in[1];
+ assign B6 = in[0] ~^ in[1];
+ assign B7 = ~in[0];
+ assign B8 = in[0];
+ assign B9 = in[0:1] && in [2:3];
+ assign B10 = in[0:1] || in [2:3];
+
+endmodule
diff --git a/tests/ice40/logic.ys b/tests/ice40/logic.ys
new file mode 100644
index 000000000..fc5e5b1d8
--- /dev/null
+++ b/tests/ice40/logic.ys
@@ -0,0 +1,7 @@
+read_verilog logic.v
+hierarchy -top top
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 9 t:SB_LUT4
+select -assert-none t:SB_LUT4 %% t:* %D
diff --git a/tests/ice40/macc.v b/tests/ice40/macc.v
new file mode 100644
index 000000000..63a3d3a74
--- /dev/null
+++ b/tests/ice40/macc.v
@@ -0,0 +1,25 @@
+/*
+Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 77].
+*/
+module top(clk,a,b,c,set);
+parameter A_WIDTH = 4;
+parameter B_WIDTH = 3;
+input set;
+input clk;
+input signed [(A_WIDTH - 1):0] a;
+input signed [(B_WIDTH - 1):0] b;
+output signed [(A_WIDTH + B_WIDTH - 1):0] c;
+reg [(A_WIDTH + B_WIDTH - 1):0] reg_tmp_c;
+assign c = reg_tmp_c;
+always @(posedge clk)
+begin
+if(set)
+begin
+reg_tmp_c <= 0;
+end
+else
+begin
+reg_tmp_c <= a * b + c;
+end
+end
+endmodule
diff --git a/tests/ice40/macc.ys b/tests/ice40/macc.ys
new file mode 100644
index 000000000..fe5b5f662
--- /dev/null
+++ b/tests/ice40/macc.ys
@@ -0,0 +1,10 @@
+read_verilog macc.v
+proc
+hierarchy -top top
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 38 t:SB_LUT4
+select -assert-count 3 t:SB_CARRY
+select -assert-count 7 t:SB_DFFSR
+select -assert-none t:SB_LUT4 t:SB_CARRY t:SB_DFFSR %% t:* %D
diff --git a/tests/ice40/memory.v b/tests/ice40/memory.v
new file mode 100644
index 000000000..cb7753f7b
--- /dev/null
+++ b/tests/ice40/memory.v
@@ -0,0 +1,21 @@
+module top
+(
+ input [7:0] data_a,
+ input [6:1] addr_a,
+ input we_a, clk,
+ output reg [7:0] q_a
+);
+ // Declare the RAM variable
+ reg [7:0] ram[63:0];
+
+ // Port A
+ always @ (posedge clk)
+ begin
+ if (we_a)
+ begin
+ ram[addr_a] <= data_a;
+ q_a <= data_a;
+ end
+ q_a <= ram[addr_a];
+ end
+endmodule
diff --git a/tests/ice40/memory.ys b/tests/ice40/memory.ys
new file mode 100644
index 000000000..a66afbae6
--- /dev/null
+++ b/tests/ice40/memory.ys
@@ -0,0 +1,15 @@
+read_verilog memory.v
+hierarchy -top top
+proc
+memory -nomap
+equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
+memory
+opt -full
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
+
+design -load postopt
+cd top
+select -assert-count 1 t:SB_RAM40_4K
+select -assert-none t:SB_RAM40_4K %% t:* %D
diff --git a/tests/ice40/mul.v b/tests/ice40/mul.v
new file mode 100644
index 000000000..d5b48b1d7
--- /dev/null
+++ b/tests/ice40/mul.v
@@ -0,0 +1,11 @@
+module top
+(
+ input [5:0] x,
+ input [5:0] y,
+
+ output [11:0] A,
+ );
+
+assign A = x * y;
+
+endmodule
diff --git a/tests/ice40/mul.ys b/tests/ice40/mul.ys
new file mode 100644
index 000000000..8a0822a84
--- /dev/null
+++ b/tests/ice40/mul.ys
@@ -0,0 +1,7 @@
+read_verilog mul.v
+hierarchy -top top
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 1 t:SB_MAC16
+select -assert-none t:SB_MAC16 %% t:* %D
diff --git a/tests/ice40/mux.v b/tests/ice40/mux.v
new file mode 100644
index 000000000..0814b733e
--- /dev/null
+++ b/tests/ice40/mux.v
@@ -0,0 +1,100 @@
+module mux2 (S,A,B,Y);
+ input S;
+ input A,B;
+ output reg Y;
+
+ always @(*)
+ Y = (S)? B : A;
+endmodule
+
+module mux4 ( S, D, Y );
+
+input[1:0] S;
+input[3:0] D;
+output Y;
+
+reg Y;
+wire[1:0] S;
+wire[3:0] D;
+
+always @*
+begin
+ case( S )
+ 0 : Y = D[0];
+ 1 : Y = D[1];
+ 2 : Y = D[2];
+ 3 : Y = D[3];
+ endcase
+end
+
+endmodule
+
+module mux8 ( S, D, Y );
+
+input[2:0] S;
+input[7:0] D;
+output Y;
+
+reg Y;
+wire[2:0] S;
+wire[7:0] D;
+
+always @*
+begin
+ case( S )
+ 0 : Y = D[0];
+ 1 : Y = D[1];
+ 2 : Y = D[2];
+ 3 : Y = D[3];
+ 4 : Y = D[4];
+ 5 : Y = D[5];
+ 6 : Y = D[6];
+ 7 : Y = D[7];
+ endcase
+end
+
+endmodule
+
+module mux16 (D, S, Y);
+ input [15:0] D;
+ input [3:0] S;
+ output Y;
+
+assign Y = D[S];
+
+endmodule
+
+
+module top (
+input [3:0] S,
+input [15:0] D,
+output M2,M4,M8,M16
+);
+
+mux2 u_mux2 (
+ .S (S[0]),
+ .A (D[0]),
+ .B (D[1]),
+ .Y (M2)
+ );
+
+
+mux4 u_mux4 (
+ .S (S[1:0]),
+ .D (D[3:0]),
+ .Y (M4)
+ );
+
+mux8 u_mux8 (
+ .S (S[2:0]),
+ .D (D[7:0]),
+ .Y (M8)
+ );
+
+mux16 u_mux16 (
+ .S (S[3:0]),
+ .D (D[15:0]),
+ .Y (M16)
+ );
+
+endmodule
diff --git a/tests/ice40/mux.ys b/tests/ice40/mux.ys
new file mode 100644
index 000000000..182b49499
--- /dev/null
+++ b/tests/ice40/mux.ys
@@ -0,0 +1,8 @@
+read_verilog mux.v
+proc
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 19 t:SB_LUT4
+select -assert-none t:SB_LUT4 %% t:* %D
diff --git a/tests/ice40/rom.v b/tests/ice40/rom.v
new file mode 100644
index 000000000..0a0f41f37
--- /dev/null
+++ b/tests/ice40/rom.v
@@ -0,0 +1,18 @@
+/*
+Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 74].
+*/
+module top(data, addr);
+output [3:0] data;
+input [4:0] addr;
+always @(addr) begin
+case (addr)
+0 : data = 'h4;
+1 : data = 'h9;
+2 : data = 'h1;
+15 : data = 'h8;
+16 : data = 'h1;
+17 : data = 'h0;
+default : data = 'h0;
+endcase
+end
+endmodule
diff --git a/tests/ice40/rom.ys b/tests/ice40/rom.ys
new file mode 100644
index 000000000..41d214e2a
--- /dev/null
+++ b/tests/ice40/rom.ys
@@ -0,0 +1,8 @@
+read_verilog rom.v
+proc
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 5 t:SB_LUT4
+select -assert-none t:SB_LUT4 %% t:* %D
diff --git a/tests/ice40/run-test.sh b/tests/ice40/run-test.sh
index ea56b70f0..2c72ca3a9 100755
--- a/tests/ice40/run-test.sh
+++ b/tests/ice40/run-test.sh
@@ -6,7 +6,7 @@ for x in *.ys; do
echo "all:: run-$x"
echo "run-$x:"
echo " @echo 'Running $x..'"
- echo " @../../yosys -ql ${x%.ys}.log $x"
+ echo " @../../yosys -ql ${x%.ys}.log $x -w 'Yosys has only limited support for tri-state logic at the moment.'"
done
for s in *.sh; do
if [ "$s" != "run-test.sh" ]; then
diff --git a/tests/ice40/shifter.v b/tests/ice40/shifter.v
new file mode 100644
index 000000000..c55632552
--- /dev/null
+++ b/tests/ice40/shifter.v
@@ -0,0 +1,22 @@
+module top (
+out,
+clk,
+in
+);
+ output [7:0] out;
+ input signed clk, in;
+ reg signed [7:0] out = 0;
+
+ always @(posedge clk)
+ begin
+`ifndef BUG
+ out <= out >> 1;
+ out[7] <= in;
+`else
+
+ out <= out << 1;
+ out[7] <= in;
+`endif
+ end
+
+endmodule
diff --git a/tests/ice40/shifter.ys b/tests/ice40/shifter.ys
new file mode 100644
index 000000000..47d95d298
--- /dev/null
+++ b/tests/ice40/shifter.ys
@@ -0,0 +1,9 @@
+read_verilog shifter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 8 t:SB_DFF
+select -assert-none t:SB_DFF %% t:* %D
diff --git a/tests/ice40/tribuf.v b/tests/ice40/tribuf.v
new file mode 100644
index 000000000..870a02584
--- /dev/null
+++ b/tests/ice40/tribuf.v
@@ -0,0 +1,23 @@
+module tristate (en, i, o);
+ input en;
+ input i;
+ output o;
+
+ assign o = en ? i : 1'bz;
+
+endmodule
+
+
+module top (
+input en,
+input a,
+output b
+);
+
+tristate u_tri (
+ .en (en ),
+ .i (a ),
+ .o (b )
+ );
+
+endmodule
diff --git a/tests/ice40/tribuf.ys b/tests/ice40/tribuf.ys
new file mode 100644
index 000000000..d1e1b3108
--- /dev/null
+++ b/tests/ice40/tribuf.ys
@@ -0,0 +1,9 @@
+read_verilog tribuf.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -assert -map +/ice40/cells_sim.v -map +/simcells.v synth_ice40 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 1 t:$_TBUF_
+select -assert-none t:$_TBUF_ %% t:* %D
diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh
index 49ae23338..8df6994e3 100755
--- a/tests/simple_abc9/run-test.sh
+++ b/tests/simple_abc9/run-test.sh
@@ -20,4 +20,10 @@ fi
cp ../simple/*.v .
cp ../simple/*.sv .
DOLLAR='?'
-exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p 'hierarchy; synth -run coarse; opt -full; techmap; abc9 -lut 4 -box ../abc.box; stat; check -assert; select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
+exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p '\
+ hierarchy; \
+ synth -run coarse; \
+ opt -full; \
+ techmap; abc9 -lut 4 -box ../abc.box; \
+ check -assert; \
+ select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
diff --git a/tests/various/shregmap.ys b/tests/various/shregmap.ys
index 0e5fe882b..16e5f40e1 100644
--- a/tests/various/shregmap.ys
+++ b/tests/various/shregmap.ys
@@ -31,36 +31,3 @@ sat -verify -prove-asserts -show-ports -seq 5 miter
#design -load gate
#stat
-
-##########
-
-design -load read
-design -copy-to model $__XILINX_SHREG_
-hierarchy -top shregmap_variable_test
-prep
-design -save gold
-
-simplemap t:$dff t:$dffe
-shregmap -tech xilinx
-
-#stat
-# show -width
-# write_verilog -noexpr -norename
-select -assert-count 1 t:$_DFF_P_
-select -assert-count 2 t:$__XILINX_SHREG_
-
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
-prep
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -show-ports -seq 5 miter
-
-# design -load gold
-# stat
-
-# design -load gate
-# stat
diff --git a/tests/xilinx/.gitignore b/tests/xilinx/.gitignore
new file mode 100644
index 000000000..b48f808a1
--- /dev/null
+++ b/tests/xilinx/.gitignore
@@ -0,0 +1,3 @@
+/*.log
+/*.out
+/run-test.mk
diff --git a/tests/xilinx/pmgen_xilinx_srl.ys b/tests/xilinx/pmgen_xilinx_srl.ys
new file mode 100644
index 000000000..ea2f20487
--- /dev/null
+++ b/tests/xilinx/pmgen_xilinx_srl.ys
@@ -0,0 +1,57 @@
+read_verilog -icells <<EOT
+module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO);
+ parameter DEPTH = 1;
+ parameter [DEPTH-1:0] INIT = 0;
+ parameter CLKPOL = 1;
+ parameter ENPOL = 2;
+
+ wire pos_clk = C == CLKPOL;
+ reg pos_en;
+ always @(E)
+ if (ENPOL == 2) pos_en = 1'b1;
+ else pos_en = (E == ENPOL[0]);
+
+ reg [DEPTH-1:0] r;
+ always @(posedge pos_clk)
+ if (pos_en)
+ r <= {r[DEPTH-2:0], D};
+
+ assign Q = r[L];
+ assign SO = r[DEPTH-1];
+endmodule
+EOT
+read_verilog +/xilinx/cells_sim.v
+proc
+design -save model
+
+test_pmgen -generate xilinx_srl.fixed
+hierarchy -top pmtest_xilinx_srl_pm_fixed
+flatten; opt_clean
+
+design -save gold
+xilinx_srl -fixed
+techmap -autoproc -map %model
+design -stash gate
+
+design -copy-from gold -as gold pmtest_xilinx_srl_pm_fixed
+design -copy-from gate -as gate pmtest_xilinx_srl_pm_fixed
+dff2dffe -unmap # sat does not support flops-with-enable yet
+miter -equiv -flatten -make_assert gold gate miter
+sat -set-init-zero -seq 5 -verify -prove-asserts miter
+
+design -load model
+
+test_pmgen -generate xilinx_srl.variable
+hierarchy -top pmtest_xilinx_srl_pm_variable
+flatten; opt_clean
+
+design -save gold
+xilinx_srl -variable
+techmap -autoproc -map %model
+design -stash gate
+
+design -copy-from gold -as gold pmtest_xilinx_srl_pm_variable
+design -copy-from gate -as gate pmtest_xilinx_srl_pm_variable
+dff2dffe -unmap # sat does not support flops-with-enable yet
+miter -equiv -flatten -make_assert gold gate miter
+sat -set-init-zero -seq 5 -verify -prove-asserts miter
diff --git a/tests/xilinx/run-test.sh b/tests/xilinx/run-test.sh
new file mode 100755
index 000000000..ea56b70f0
--- /dev/null
+++ b/tests/xilinx/run-test.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -e
+{
+echo "all::"
+for x in *.ys; do
+ echo "all:: run-$x"
+ echo "run-$x:"
+ echo " @echo 'Running $x..'"
+ echo " @../../yosys -ql ${x%.ys}.log $x"
+done
+for s in *.sh; do
+ if [ "$s" != "run-test.sh" ]; then
+ echo "all:: run-$s"
+ echo "run-$s:"
+ echo " @echo 'Running $s..'"
+ echo " @bash $s"
+ fi
+done
+} > run-test.mk
+exec ${MAKE:-make} -f run-test.mk
diff --git a/tests/xilinx/xilinx_srl.v b/tests/xilinx/xilinx_srl.v
new file mode 100644
index 000000000..bc2a15ab2
--- /dev/null
+++ b/tests/xilinx/xilinx_srl.v
@@ -0,0 +1,40 @@
+module xilinx_srl_static_test(input i, clk, output [1:0] q);
+reg head = 1'b0;
+reg [3:0] shift1 = 4'b0000;
+reg [3:0] shift2 = 4'b0000;
+
+always @(posedge clk) begin
+ head <= i;
+ shift1 <= {shift1[2:0], head};
+ shift2 <= {shift2[2:0], head};
+end
+
+assign q = {shift2[3], shift1[3]};
+endmodule
+
+module xilinx_srl_variable_test(input i, clk, input [1:0] l1, l2, output [1:0] q);
+reg head = 1'b0;
+reg [3:0] shift1 = 4'b0000;
+reg [3:0] shift2 = 4'b0000;
+
+always @(posedge clk) begin
+ head <= i;
+ shift1 <= {shift1[2:0], head};
+ shift2 <= {shift2[2:0], head};
+end
+
+assign q = {shift2[l2], shift1[l1]};
+endmodule
+
+module $__XILINX_SHREG_(input C, D, E, input [1:0] L, output Q);
+parameter CLKPOL = 1;
+parameter ENPOL = 1;
+parameter DEPTH = 1;
+parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
+reg [DEPTH-1:0] r = INIT;
+wire clk = C ^ CLKPOL;
+always @(posedge C)
+ if (E)
+ r <= { r[DEPTH-2:0], D };
+assign Q = r[L];
+endmodule
diff --git a/tests/xilinx/xilinx_srl.ys b/tests/xilinx/xilinx_srl.ys
new file mode 100644
index 000000000..b8df0e55a
--- /dev/null
+++ b/tests/xilinx/xilinx_srl.ys
@@ -0,0 +1,67 @@
+read_verilog xilinx_srl.v
+design -save read
+
+design -copy-to model $__XILINX_SHREG_
+hierarchy -top xilinx_srl_static_test
+prep
+design -save gold
+
+techmap
+xilinx_srl -fixed
+opt
+
+# stat
+# show -width
+select -assert-count 1 t:$_DFF_P_
+select -assert-count 2 t:$__XILINX_SHREG_
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
+prep
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+dump gate
+sat -verify -prove-asserts -show-ports -seq 5 miter
+
+#design -load gold
+#stat
+
+#design -load gate
+#stat
+
+##########
+
+design -load read
+design -copy-to model $__XILINX_SHREG_
+hierarchy -top xilinx_srl_variable_test
+prep
+design -save gold
+
+xilinx_srl -variable
+opt
+
+#stat
+# show -width
+# write_verilog -noexpr -norename
+select -assert-count 1 t:$dff
+select -assert-count 1 t:$dff r:WIDTH=1 %i
+select -assert-count 2 t:$__XILINX_SHREG_
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
+prep
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports -seq 5 miter
+
+# design -load gold
+# stat
+
+# design -load gate
+# stat