aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG4
-rw-r--r--frontends/verific/README8
-rw-r--r--frontends/verific/verific.cc23
-rw-r--r--frontends/verilog/preproc.cc2
-rw-r--r--frontends/verilog/verilog_lexer.l2
-rw-r--r--manual/CHAPTER_Verilog.tex4
-rw-r--r--manual/manual.tex2
-rw-r--r--passes/cmds/Makefile.inc1
-rw-r--r--passes/cmds/scratchpad.cc130
-rw-r--r--passes/equiv/equiv_opt.cc18
-rw-r--r--passes/memory/memory_bram.cc98
-rw-r--r--passes/opt/opt_expr.cc2
-rw-r--r--techlibs/ecp5/cells_map.v15
-rw-r--r--techlibs/ecp5/synth_ecp5.cc17
-rw-r--r--techlibs/xilinx/Makefile.inc1
-rw-r--r--techlibs/xilinx/cells_map.v27
-rw-r--r--techlibs/xilinx/cells_sim.v59
-rw-r--r--techlibs/xilinx/cells_xtra.py2
-rw-r--r--techlibs/xilinx/cells_xtra.v21
-rw-r--r--techlibs/xilinx/lutrams.txt107
-rw-r--r--techlibs/xilinx/lutrams_map.v182
-rw-r--r--techlibs/xilinx/synth_xilinx.cc16
-rw-r--r--techlibs/xilinx/xc6s_ff_map.v130
-rw-r--r--techlibs/xilinx/xc7_ff_map.v94
-rw-r--r--techlibs/xilinx/xc7_xcu_brams.txt54
-rw-r--r--techlibs/xilinx/xilinx_dffopt.cc351
-rw-r--r--tests/arch/anlogic/lutram.ys (renamed from tests/arch/anlogic/memory.ys)6
-rw-r--r--tests/arch/common/blockram.v45
-rw-r--r--tests/arch/common/lutram.v42
-rw-r--r--tests/arch/common/memory.v21
-rw-r--r--tests/arch/common/memory_attributes/attributes_test.v88
-rw-r--r--tests/arch/ecp5/lutram.ys (renamed from tests/arch/ecp5/memory.ys)6
-rw-r--r--tests/arch/efinix/lutram.ys (renamed from tests/arch/efinix/memory.ys)6
-rw-r--r--tests/arch/gowin/lutram.ys (renamed from tests/arch/gowin/memory.ys)6
-rw-r--r--tests/arch/ice40/lutram.ys (renamed from tests/arch/ice40/memory.ys)6
-rw-r--r--tests/arch/xilinx/adffs.ys9
-rw-r--r--tests/arch/xilinx/attributes_test.ys47
-rw-r--r--tests/arch/xilinx/blockram.ys97
-rw-r--r--tests/arch/xilinx/bug1460.ys34
-rw-r--r--tests/arch/xilinx/fsm.ys11
-rw-r--r--tests/arch/xilinx/lutram.ys137
-rw-r--r--tests/arch/xilinx/macc.ys3
-rw-r--r--tests/arch/xilinx/memory.ys17
-rw-r--r--tests/arch/xilinx/mux.ys6
-rw-r--r--tests/arch/xilinx/xilinx_dffopt.ys216
-rw-r--r--tests/arch/xilinx/xilinx_dffopt_blacklist.txt13
-rw-r--r--tests/various/scratchpad.ys5
47 files changed, 2030 insertions, 161 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a49c27b05..01ae17c2b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -50,9 +50,13 @@ Yosys 0.9 .. Yosys 0.9-dev
- "synth_ecp5" to now infer DSP blocks (-nodsp to disable, experimental)
- "synth_ice40 -dsp" to infer DSP blocks
- Added latch support to synth_xilinx
+ - Added support for flip-flops with synchronous reset to synth_xilinx
+ - Added support for flip-flops with reset and enable to synth_xilinx
- Added "check -mapped"
- Added checking of SystemVerilog always block types (always_comb,
always_latch and always_ff)
+ - Added "xilinx_dffopt" pass
+ - Added "scratchpad" pass
Yosys 0.8 .. Yosys 0.9
----------------------
diff --git a/frontends/verific/README b/frontends/verific/README
index 89584f2e8..c37d76343 100644
--- a/frontends/verific/README
+++ b/frontends/verific/README
@@ -1,7 +1,11 @@
-
This directory contains Verific bindings for Yosys.
-See http://www.verific.com/ for details.
+
+Use Symbiotic EDA Suite if you need Yosys+Verifc.
+https://www.symbioticeda.com/seda-suite
+
+Contact office@symbioticeda.com for free evaluation
+binaries of Symbiotic EDA Suite.
Verific Features that should be enabled in your Verific library
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 843e7b9b4..9274cf5ca 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -2065,7 +2065,12 @@ struct VerificPass : public Pass {
log(" -d <dump_file>\n");
log(" Dump the Verific netlist as a verilog file.\n");
log("\n");
- log("Visit http://verific.com/ for more information on Verific.\n");
+ log("\n");
+ log("Use Symbiotic EDA Suite if you need Yosys+Verifc.\n");
+ log("https://www.symbioticeda.com/seda-suite\n");
+ log("\n");
+ log("Contact office@symbioticeda.com for free evaluation\n");
+ log("binaries of Symbiotic EDA Suite.\n");
log("\n");
}
#ifdef YOSYS_ENABLE_VERIFIC
@@ -2074,7 +2079,13 @@ struct VerificPass : public Pass {
static bool set_verific_global_flags = true;
if (check_noverific_env())
- log_cmd_error("This version of Yosys is built without Verific support.\n");
+ log_cmd_error("This version of Yosys is built without Verific support.\n"
+ "\n"
+ "Use Symbiotic EDA Suite if you need Yosys+Verifc.\n"
+ "https://www.symbioticeda.com/seda-suite\n"
+ "\n"
+ "Contact office@symbioticeda.com for free evaluation\n"
+ "binaries of Symbiotic EDA Suite.\n");
log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n");
@@ -2493,7 +2504,13 @@ struct VerificPass : public Pass {
}
#else /* YOSYS_ENABLE_VERIFIC */
void execute(std::vector<std::string>, RTLIL::Design *) YS_OVERRIDE {
- log_cmd_error("This version of Yosys is built without Verific support.\n");
+ log_cmd_error("This version of Yosys is built without Verific support.\n"
+ "\n"
+ "Use Symbiotic EDA Suite if you need Yosys+Verifc.\n"
+ "https://www.symbioticeda.com/seda-suite\n"
+ "\n"
+ "Contact office@symbioticeda.com for free evaluation\n"
+ "binaries of Symbiotic EDA Suite.\n");
}
#endif
} VerificPass;
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index 7e107dc26..161253a99 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -28,7 +28,7 @@
*
* Ad-hoc implementation of a Verilog preprocessor. The directives `define,
* `include, `ifdef, `ifndef, `else and `endif are handled here. All other
- * directives are handled by the lexer (see lexer.l).
+ * directives are handled by the lexer (see verilog_lexer.l).
*
*/
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index c8984c2c4..ca23df3e8 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -28,7 +28,7 @@
*
* A simple lexer for Verilog code. Non-preprocessor compiler directives are
* handled here. The preprocessor stuff is handled in preproc.cc. Everything
- * else is left to the bison parser (see parser.y).
+ * else is left to the bison parser (see verilog_parser.y).
*
*/
diff --git a/manual/CHAPTER_Verilog.tex b/manual/CHAPTER_Verilog.tex
index e9ca6114e..d4cc55647 100644
--- a/manual/CHAPTER_Verilog.tex
+++ b/manual/CHAPTER_Verilog.tex
@@ -93,7 +93,7 @@ frontends/verilog/preproc.cc} in the Yosys source tree.
\begin{sloppypar}
The Verilog Lexer is written using the lexer generator {\it flex} \citeweblink{flex}. Its source code
-can be found in {\tt frontends/verilog/lexer.l} in the Yosys source tree.
+can be found in {\tt frontends/verilog/verilog\_lexer.l} in the Yosys source tree.
The lexer does little more than identifying all keywords and literals
recognised by the Yosys Verilog frontend.
\end{sloppypar}
@@ -115,7 +115,7 @@ whenever possible.)
\subsection{The Verilog Parser}
The Verilog Parser is written using the parser generator {\it bison} \citeweblink{bison}. Its source code
-can be found in {\tt frontends/verilog/parser.y} in the Yosys source tree.
+can be found in {\tt frontends/verilog/verilog\_parser.y} in the Yosys source tree.
It generates an AST using the \lstinline[language=C++]{AST::AstNode} data structure
defined in {\tt frontends/ast/ast.h}. An \lstinline[language=C++]{AST::AstNode} object has
diff --git a/manual/manual.tex b/manual/manual.tex
index 67982cbc8..75f087eca 100644
--- a/manual/manual.tex
+++ b/manual/manual.tex
@@ -146,7 +146,7 @@ with the help of HDL synthesis tools.
In special cases such as synthesis for coarse-grain cell libraries or when
testing new synthesis algorithms it might be necessary to write a custom HDL
-synthesis tool or add new features to an existing one. It this cases the
+synthesis tool or add new features to an existing one. In these cases the
availability of a Free and Open Source (FOSS) synthesis tool that can be used
as basis for custom tools would be helpful.
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index c7edc30fb..07a5d3ddc 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -32,3 +32,4 @@ OBJS += passes/cmds/chtype.o
OBJS += passes/cmds/blackbox.o
OBJS += passes/cmds/ltp.o
OBJS += passes/cmds/bugpoint.o
+OBJS += passes/cmds/scratchpad.o
diff --git a/passes/cmds/scratchpad.cc b/passes/cmds/scratchpad.cc
new file mode 100644
index 000000000..7ec55b78e
--- /dev/null
+++ b/passes/cmds/scratchpad.cc
@@ -0,0 +1,130 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Nina Engelhardt <nak@symbioticeda.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/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ScratchpadPass : public Pass {
+ ScratchpadPass() : Pass("scratchpad", "get/set values in the scratchpad") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" scratchpad [options]\n");
+ log("\n");
+ log("This pass allows to read and modify values from the scratchpad of the current\n");
+ log("design. Options:\n");
+ log("\n");
+ log(" -get <identifier>\n");
+ log(" print the value saved in the scratchpad under the given identifier.\n");
+ log("\n");
+ log(" -set <identifier> <value>\n");
+ log(" save the given value in the scratchpad under the given identifier.\n");
+ log("\n");
+ log(" -unset <identifier>\n");
+ log(" remove the entry for the given identifier from the scratchpad.\n");
+ log("\n");
+ log(" -copy <identifier_from> <identifier_to>\n");
+ log(" copy the value of the first identifier to the second identifier.\n");
+ log("\n");
+ log(" -assert <identifier> <value>\n");
+ log(" assert that the entry for the given identifier is set to the given value.\n");
+ log("\n");
+ log(" -assert-set <identifier>\n");
+ log(" assert that the entry for the given identifier exists.\n");
+ log("\n");
+ log(" -assert-unset <identifier>\n");
+ log(" assert that the entry for the given identifier does not exist.\n");
+ log("\n");
+ log("The identifier may not contain whitespace. By convention, it is usually prefixed\n");
+ log("by the name of the pass that uses it, e.g. 'opt.did_something'. If the value\n");
+ log("contains whitespace, it must be enclosed in double quotes.\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-get" && argidx+1 < args.size()) {
+ string identifier = args[++argidx];
+ if (design->scratchpad.count(identifier)){
+ log("%s\n", design->scratchpad_get_string(identifier).c_str());
+ } else {
+ log("\"%s\" not set\n", identifier.c_str());
+ }
+ continue;
+ }
+ if (args[argidx] == "-set" && argidx+2 < args.size()) {
+ string identifier = args[++argidx];
+ string value = args[++argidx];
+ if (value.front() == '\"' && value.back() == '\"') value = value.substr(1, value.size() - 2);
+ design->scratchpad_set_string(identifier, value);
+ continue;
+ }
+ if (args[argidx] == "-unset" && argidx+1 < args.size()) {
+ string identifier = args[++argidx];
+ design->scratchpad_unset(identifier);
+ continue;
+ }
+ if (args[argidx] == "-copy" && argidx+2 < args.size()) {
+ string identifier_from = args[++argidx];
+ string identifier_to = args[++argidx];
+ if (design->scratchpad.count(identifier_from) == 0) log_error("\"%s\" not set\n", identifier_from.c_str());
+ string value = design->scratchpad_get_string(identifier_from);
+ design->scratchpad_set_string(identifier_to, value);
+ continue;
+ }
+ if (args[argidx] == "-assert" && argidx+2 < args.size()) {
+ string identifier = args[++argidx];
+ string expected = args[++argidx];
+ if (expected.front() == '\"' && expected.back() == '\"') expected = expected.substr(1, expected.size() - 2);
+ if (design->scratchpad.count(identifier) == 0)
+ log_error("Assertion failed: scratchpad entry '%s' is not defined\n", identifier.c_str());
+ string value = design->scratchpad_get_string(identifier);
+ if (value != expected) {
+ log_error("Assertion failed: scratchpad entry '%s' is set to '%s' instead of the asserted '%s'\n",
+ identifier.c_str(), value.c_str(), expected.c_str());
+ }
+ continue;
+ }
+ if (args[argidx] == "-assert-set" && argidx+1 < args.size()) {
+ string identifier = args[++argidx];
+ if (design->scratchpad.count(identifier) == 0)
+ log_error("Assertion failed: scratchpad entry '%s' is not defined\n", identifier.c_str());
+ continue;
+ }
+ if (args[argidx] == "-assert-unset" && argidx+1 < args.size()) {
+ string identifier = args[++argidx];
+ if (design->scratchpad.count(identifier) > 0)
+ log_error("Assertion failed: scratchpad entry '%s' is defined\n", identifier.c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design, false);
+ }
+} ScratchpadPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
index c7e6d71a6..7c6c2e685 100644
--- a/passes/equiv/equiv_opt.cc
+++ b/passes/equiv/equiv_opt.cc
@@ -44,6 +44,10 @@ struct EquivOptPass:public ScriptPass
log(" expand the modules in this file before proving equivalence. this is\n");
log(" useful for handling architecture-specific primitives.\n");
log("\n");
+ log(" -blacklist <file>\n");
+ log(" Do not match cells or signals that match the names in the file\n");
+ log(" (passed to equiv_make).\n");
+ log("\n");
log(" -assert\n");
log(" produce an error if the circuits are not equivalent.\n");
log("\n");
@@ -61,13 +65,14 @@ struct EquivOptPass:public ScriptPass
log("\n");
}
- std::string command, techmap_opts;
+ std::string command, techmap_opts, make_opts;
bool assert, undef, multiclock, async2sync;
void clear_flags() YS_OVERRIDE
{
command = "";
techmap_opts = "";
+ make_opts = "";
assert = false;
undef = false;
multiclock = false;
@@ -93,6 +98,10 @@ struct EquivOptPass:public ScriptPass
techmap_opts += " -map " + args[++argidx];
continue;
}
+ if (args[argidx] == "-blacklist" && argidx + 1 < args.size()) {
+ make_opts += " -blacklist " + args[++argidx];
+ continue;
+ }
if (args[argidx] == "-assert") {
assert = true;
continue;
@@ -170,7 +179,12 @@ struct EquivOptPass:public ScriptPass
run("clk2fflogic", "(only with -multiclock)");
if (async2sync || help_mode)
run("async2sync", " (only with -async2sync)");
- run("equiv_make gold gate equiv");
+ string opts;
+ if (help_mode)
+ opts = " -blacklist <filename> ...";
+ else
+ opts = make_opts;
+ run("equiv_make" + opts + " gold gate equiv");
if (help_mode)
run("equiv_induct [-undef] equiv");
else if (undef)
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index aa8f94149..24478f2ee 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -134,6 +134,7 @@ struct rules_t
dict<string, int> min_limits, max_limits;
bool or_next_if_better, make_transp, make_outreg;
char shuffle_enable;
+ vector<vector<std::tuple<bool,IdString,Const>>> attributes;
};
dict<IdString, vector<bram_t>> brams;
@@ -327,6 +328,20 @@ struct rules_t
continue;
}
+ if (GetSize(tokens) >= 2 && tokens[0] == "attribute") {
+ data.attributes.emplace_back();
+ for (int idx = 1; idx < GetSize(tokens); idx++) {
+ size_t c1 = tokens[idx][0] == '!' ? 1 : 0;
+ size_t c2 = tokens[idx].find("=");
+ bool exists = (c1 == 0);
+ IdString key = RTLIL::escape_id(tokens[idx].substr(c1, c2));
+ Const val = c2 != std::string::npos ? tokens[idx].substr(c2+1) : RTLIL::Const(1);
+
+ data.attributes.back().emplace_back(exists, key, val);
+ }
+ continue;
+ }
+
syntax_error();
}
}
@@ -724,7 +739,7 @@ grow_read_ports:;
if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true;
if (pi.clocks != 0) {
- if (wr_ports == 1 && wr_clkdom != clkdom) {
+ if (wr_ports == 1 && wr_clkdom != clkdom) {
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
@@ -813,6 +828,43 @@ grow_read_ports:;
return false;
}
+ for (const auto &sums : match.attributes) {
+ bool found = false;
+ for (const auto &term : sums) {
+ bool exists = std::get<0>(term);
+ IdString key = std::get<1>(term);
+ const Const &value = std::get<2>(term);
+ auto it = cell->attributes.find(key);
+ if (it == cell->attributes.end()) {
+ if (exists)
+ continue;
+ found = true;
+ break;
+ }
+ else if (!exists)
+ continue;
+ if (it->second != value)
+ continue;
+ found = true;
+ break;
+ }
+ if (!found) {
+ std::stringstream ss;
+ bool exists = std::get<0>(sums.front());
+ if (!exists)
+ ss << "!";
+ IdString key = std::get<1>(sums.front());
+ ss << log_id(key);
+ const Const &value = std::get<2>(sums.front());
+ if (exists && value != Const(1))
+ ss << "=\"" << value.decode_string() << "\"";
+
+ log(" Rule for bram type %s rejected: requirement 'attribute %s ...' not met.\n",
+ log_id(match.name), ss.str().c_str());
+ return false;
+ }
+ }
+
if (mode == 1)
return true;
}
@@ -1100,6 +1152,43 @@ void handle_cell(Cell *cell, const rules_t &rules)
goto next_match_rule;
}
+ for (const auto &sums : match.attributes) {
+ bool found = false;
+ for (const auto &term : sums) {
+ bool exists = std::get<0>(term);
+ IdString key = std::get<1>(term);
+ const Const &value = std::get<2>(term);
+ auto it = cell->attributes.find(key);
+ if (it == cell->attributes.end()) {
+ if (exists)
+ continue;
+ found = true;
+ break;
+ }
+ else if (!exists)
+ continue;
+ if (it->second != value)
+ continue;
+ found = true;
+ break;
+ }
+ if (!found) {
+ std::stringstream ss;
+ bool exists = std::get<0>(sums.front());
+ if (!exists)
+ ss << "!";
+ IdString key = std::get<1>(sums.front());
+ ss << log_id(key);
+ const Const &value = std::get<2>(sums.front());
+ if (exists && value != Const(1))
+ ss << "=\"" << value.decode_string() << "\"";
+
+ log(" Rule for bram type %s (variant %d) rejected: requirement 'attribute %s ...' not met.\n",
+ log_id(bram.name), bram.variant, ss.str().c_str());
+ goto next_match_rule;
+ }
+ }
+
log(" Rule #%d for bram type %s (variant %d) accepted.\n", i+1, log_id(bram.name), bram.variant);
if (or_next_if_better || !best_rule_cache.empty())
@@ -1225,6 +1314,13 @@ struct MemoryBramPass : public Pass {
log(" dcells ....... number of cells in 'data-direction'\n");
log(" cells ........ total number of cells (acells*dcells*dups)\n");
log("\n");
+ log("A match containing the command 'attribute' followed by a list of space\n");
+ log("separated 'name[=string_value]' values requires that the memory contains any\n");
+ log("one of the given attribute name and string values (where specified), or name\n");
+ log("and integer 1 value (if no string_value given, since Verilog will interpret\n");
+ log("'(* attr *)' as '(* attr=1 *)').\n");
+ log("A name prefixed with '!' indicates that the attribute must not exist.\n");
+ log("\n");
log("The interface for the created bram instances is derived from the bram\n");
log("description. Use 'techmap' to convert the created bram instances into\n");
log("instances of the actual bram cells of your target architecture.\n");
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 6cf66fb95..4a2f170b8 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -978,7 +978,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
- log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
+ log_id(module), cell->type == ID($eq) ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
cell->setPort(ID::A, cell->getPort(ID::B));
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
index 71ae9237b..10e89a3e0 100644
--- a/techlibs/ecp5/cells_map.v
+++ b/techlibs/ecp5/cells_map.v
@@ -47,6 +47,21 @@ 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
+`ifdef ASYNC_PRLD
+module \$_DLATCH_N_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(!E), .DI(1'b0), .M(D), .Q(Q)); endmodule
+module \$_DLATCH_P_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(E), .DI(1'b0), .M(D), .Q(Q)); endmodule
+
+module \$_DFFSR_NNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule
+module \$_DFFSR_NNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule
+module \$_DFFSR_NPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule
+module \$_DFFSR_NPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule
+
+module \$_DFFSR_PNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule
+module \$_DFFSR_PNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule
+module \$_DFFSR_PPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule
+module \$_DFFSR_PPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule
+`endif
+
`include "cells_ff.vh"
`include "cells_io.vh"
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
index 4cbb56ea1..b71bb2395 100644
--- a/techlibs/ecp5/synth_ecp5.cc
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -79,6 +79,9 @@ struct SynthEcp5Pass : public ScriptPass
log(" -nowidelut\n");
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
log("\n");
+ log(" -asyncprld\n");
+ log(" use async PRLD mode to implement DLATCH and DFFSR (EXPERIMENTAL)\n");
+ log("\n");
log(" -abc2\n");
log(" run two passes of 'abc' for slightly improved logic density\n");
log("\n");
@@ -99,7 +102,7 @@ struct SynthEcp5Pass : public ScriptPass
}
string top_opt, blif_file, edif_file, json_file;
- bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, nodsp, vpr;
+ bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, retime, abc2, abc9, nodsp, vpr;
void clear_flags() YS_OVERRIDE
{
@@ -112,6 +115,7 @@ struct SynthEcp5Pass : public ScriptPass
nobram = false;
nolutram = false;
nowidelut = false;
+ asyncprld = false;
flatten = true;
retime = false;
abc2 = false;
@@ -176,6 +180,10 @@ struct SynthEcp5Pass : public ScriptPass
nobram = true;
continue;
}
+ if (args[argidx] == "-asyncprld") {
+ asyncprld = true;
+ continue;
+ }
if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
nolutram = true;
continue;
@@ -292,7 +300,7 @@ struct SynthEcp5Pass : public ScriptPass
run("opt_clean");
if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
- run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
+ run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : "")));
run("opt_expr -undriven -mux_undef");
run("simplemap");
run("ecp5_ffinit");
@@ -306,10 +314,11 @@ struct SynthEcp5Pass : public ScriptPass
if (abc2 || help_mode) {
run("abc", " (only if -abc2)");
}
- std::string techmap_args = "-map +/ecp5/latches_map.v";
+ std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v";
if (abc9)
techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1";
- run("techmap " + techmap_args);
+ if (!asyncprld || abc9)
+ run("techmap " + techmap_args);
if (abc9) {
run("read_verilog -icells -lib +/ecp5/abc9_model.v");
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 3ebc72fe8..3f2fbcc85 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -1,5 +1,6 @@
OBJS += techlibs/xilinx/synth_xilinx.o
+OBJS += techlibs/xilinx/xilinx_dffopt.o
GENFILES += techlibs/xilinx/brams_init_36.vh
GENFILES += techlibs/xilinx/brams_init_32.vh
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index de2068bc5..cc180f2b9 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -28,6 +28,33 @@ module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_ _TECHMAP_REPL
(* techmap_celltype = "$_DFF_PN1_" *)
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$__DFFE_NN0" *)
+module _90_dffe_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFE_PN0" *)
+module _90_dffe_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFE_NN1" *)
+module _90_dffe_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFE_PN1" *)
+module _90_dffe_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+
+(* techmap_celltype = "$__DFFS_NN0_" *)
+module _90_dffs_nn0_to_np0 (input D, C, R, output Q); \$__DFFS_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$__DFFS_PN0_" *)
+module _90_dffs_pn0_to_pp0 (input D, C, R, output Q); \$__DFFS_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$__DFFS_NN1_" *)
+module _90_dffs_nn1_to_np1 (input D, C, R, output Q); \$__DFFS_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$__DFFS_PN1_" *)
+module _90_dffs_pn1_to_pp1 (input D, C, R, output Q); \$__DFFS_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+
+(* techmap_celltype = "$__DFFSE_NN0" *)
+module _90_dffse_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFSE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFSE_PN0" *)
+module _90_dffse_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFSE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFSE_NN1" *)
+module _90_dffse_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFSE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+(* techmap_celltype = "$__DFFSE_PN1" *)
+module _90_dffse_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFSE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
+
module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0;
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index ef963793c..7941a94cd 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -320,6 +320,41 @@ module FDRE_1 (
always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D;
endmodule
+module FDRSE (
+ output reg Q,
+ (* clkbuf_sink *)
+ (* invertible_pin = "IS_C_INVERTED" *)
+ input C,
+ (* invertible_pin = "IS_CE_INVERTED" *)
+ input CE,
+ (* invertible_pin = "IS_D_INVERTED" *)
+ input D,
+ (* invertible_pin = "IS_R_INVERTED" *)
+ input R,
+ (* invertible_pin = "IS_S_INVERTED" *)
+ input S
+);
+ parameter [0:0] INIT = 1'b0;
+ parameter [0:0] IS_C_INVERTED = 1'b0;
+ parameter [0:0] IS_CE_INVERTED = 1'b0;
+ parameter [0:0] IS_D_INVERTED = 1'b0;
+ parameter [0:0] IS_R_INVERTED = 1'b0;
+ parameter [0:0] IS_S_INVERTED = 1'b0;
+ initial Q <= INIT;
+ wire c = C ^ IS_C_INVERTED;
+ wire ce = CE ^ IS_CE_INVERTED;
+ wire d = D ^ IS_D_INVERTED;
+ wire r = R ^ IS_R_INVERTED;
+ wire s = S ^ IS_S_INVERTED;
+ always @(posedge c)
+ if (r)
+ Q <= 0;
+ else if (s)
+ Q <= 1;
+ else if (ce)
+ Q <= d;
+endmodule
+
(* abc9_box_id=1003, lib_whitebox, abc9_flop *)
module FDCE (
(* abc9_arrival=303 *)
@@ -1193,10 +1228,10 @@ module RAM64M (
output DOB,
output DOC,
output DOD,
- input [4:0] ADDRA,
- input [4:0] ADDRB,
- input [4:0] ADDRC,
- input [4:0] ADDRD,
+ input [5:0] ADDRA,
+ input [5:0] ADDRB,
+ input [5:0] ADDRC,
+ input [5:0] ADDRD,
input DIA,
input DIB,
input DIC,
@@ -1238,14 +1273,14 @@ module RAM64M8 (
output DOF,
output DOG,
output DOH,
- input [4:0] ADDRA,
- input [4:0] ADDRB,
- input [4:0] ADDRC,
- input [4:0] ADDRD,
- input [4:0] ADDRE,
- input [4:0] ADDRF,
- input [4:0] ADDRG,
- input [4:0] ADDRH,
+ input [5:0] ADDRA,
+ input [5:0] ADDRB,
+ input [5:0] ADDRC,
+ input [5:0] ADDRD,
+ input [5:0] ADDRE,
+ input [5:0] ADDRF,
+ input [5:0] ADDRG,
+ input [5:0] ADDRH,
input DIA,
input DIB,
input DIC,
diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py
index e4c580b9d..6d5adf1aa 100644
--- a/techlibs/xilinx/cells_xtra.py
+++ b/techlibs/xilinx/cells_xtra.py
@@ -66,7 +66,7 @@ CELLS = [
# CLB -- registers/latches.
# Virtex 1/2/4/5, Spartan 3.
Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}),
- Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}),
+ # Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}),
Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}),
# Virtex 6, Spartan 6, Series 7, Ultrascale.
# Cell('FDCE'),
diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v
index 8ac596459..66b7c583f 100644
--- a/techlibs/xilinx/cells_xtra.v
+++ b/techlibs/xilinx/cells_xtra.v
@@ -17,27 +17,6 @@ module FDCPE (...);
input PRE;
endmodule
-module FDRSE (...);
- parameter [0:0] INIT = 1'b0;
- parameter [0:0] IS_C_INVERTED = 1'b0;
- parameter [0:0] IS_CE_INVERTED = 1'b0;
- parameter [0:0] IS_D_INVERTED = 1'b0;
- parameter [0:0] IS_R_INVERTED = 1'b0;
- parameter [0:0] IS_S_INVERTED = 1'b0;
- output Q;
- (* clkbuf_sink *)
- (* invertible_pin = "IS_C_INVERTED" *)
- input C;
- (* invertible_pin = "IS_CE_INVERTED" *)
- input CE;
- (* invertible_pin = "IS_D_INVERTED" *)
- input D;
- (* invertible_pin = "IS_R_INVERTED" *)
- input R;
- (* invertible_pin = "IS_S_INVERTED" *)
- input S;
-endmodule
-
module LDCPE (...);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_CLR_INVERTED = 1'b0;
diff --git a/techlibs/xilinx/lutrams.txt b/techlibs/xilinx/lutrams.txt
index 2613c206c..29f6b05cc 100644
--- a/techlibs/xilinx/lutrams.txt
+++ b/techlibs/xilinx/lutrams.txt
@@ -1,4 +1,17 @@
+bram $__XILINX_RAM16X1D
+ init 1
+ abits 4
+ dbits 1
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
bram $__XILINX_RAM32X1D
init 1
abits 5
@@ -38,6 +51,70 @@ bram $__XILINX_RAM128X1D
clkpol 0 2
endbram
+
+bram $__XILINX_RAM32X6SDP
+ init 1
+ abits 5
+ dbits 6
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
+bram $__XILINX_RAM64X3SDP
+ init 1
+ abits 6
+ dbits 3
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
+bram $__XILINX_RAM32X2Q
+ init 1
+ abits 5
+ dbits 2
+ groups 2
+ ports 3 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
+bram $__XILINX_RAM64X1Q
+ init 1
+ abits 6
+ dbits 1
+ groups 2
+ ports 3 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
+
+# Disabled for now, pending support for LUT4 arches
+# since on LUT6 arches this occupies same area as
+# a RAM32X1D
+#match $__XILINX_RAM16X1D
+# min bits 2
+# min wports 1
+# make_outreg
+# or_next_if_better
+#endmatch
+
match $__XILINX_RAM32X1D
min bits 3
min wports 1
@@ -56,5 +133,35 @@ match $__XILINX_RAM128X1D
min bits 9
min wports 1
make_outreg
+ or_next_if_better
+endmatch
+
+
+match $__XILINX_RAM32X6SDP
+ min bits 5
+ min wports 1
+ make_outreg
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAM64X3SDP
+ min bits 6
+ min wports 1
+ make_outreg
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAM32X2Q
+ min bits 5
+ min rports 3
+ min wports 1
+ make_outreg
+ or_next_if_better
endmatch
+match $__XILINX_RAM64X1Q
+ min bits 5
+ min rports 3
+ min wports 1
+ make_outreg
+endmatch
diff --git a/techlibs/xilinx/lutrams_map.v b/techlibs/xilinx/lutrams_map.v
index 77041ca86..3ac1143bb 100644
--- a/techlibs/xilinx/lutrams_map.v
+++ b/techlibs/xilinx/lutrams_map.v
@@ -1,4 +1,36 @@
+module \$__XILINX_RAM16X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter [15:0] INIT = 16'bx;
+ parameter CLKPOL2 = 1;
+ input CLK1;
+
+ input [3:0] A1ADDR;
+ output A1DATA;
+
+ input [3:0] B1ADDR;
+ input B1DATA;
+ input B1EN;
+
+ RAM16X1D #(
+ .INIT(INIT),
+ .IS_WCLK_INVERTED(!CLKPOL2)
+ ) _TECHMAP_REPLACE_ (
+ .DPRA0(A1ADDR[0]),
+ .DPRA1(A1ADDR[1]),
+ .DPRA2(A1ADDR[2]),
+ .DPRA3(A1ADDR[3]),
+ .DPO(A1DATA),
+
+ .A0(B1ADDR[0]),
+ .A1(B1ADDR[1]),
+ .A2(B1ADDR[2]),
+ .A3(B1ADDR[3]),
+ .D(B1DATA),
+ .WCLK(CLK1),
+ .WE(B1EN)
+ );
+endmodule
+
module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
parameter [31:0] INIT = 32'bx;
parameter CLKPOL2 = 1;
@@ -95,3 +127,153 @@ module \$__XILINX_RAM128X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
);
endmodule
+
+module \$__XILINX_RAM32X6SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter [32*6-1:0] INIT = {32*6{1'bx}};
+ parameter CLKPOL2 = 1;
+ input CLK1;
+
+ input [4:0] A1ADDR;
+ output [5:0] A1DATA;
+
+ input [4:0] B1ADDR;
+ input [5:0] B1DATA;
+ input B1EN;
+
+ wire [1:0] DOD_unused;
+
+ RAM32M #(
+ .INIT_A({INIT[187:186], INIT[181:180], INIT[175:174], INIT[169:168], INIT[163:162], INIT[157:156], INIT[151:150], INIT[145:144], INIT[139:138], INIT[133:132], INIT[127:126], INIT[121:120], INIT[115:114], INIT[109:108], INIT[103:102], INIT[ 97: 96], INIT[ 91: 90], INIT[ 85: 84], INIT[ 79: 78], INIT[ 73: 72], INIT[ 67: 66], INIT[ 61: 60], INIT[ 55: 54], INIT[ 49: 48], INIT[ 43: 42], INIT[ 37: 36], INIT[ 31: 30], INIT[ 25: 24], INIT[ 19: 18], INIT[ 13: 12], INIT[ 7: 6], INIT[ 1: 0]}),
+ .INIT_B({INIT[189:188], INIT[183:182], INIT[177:176], INIT[171:170], INIT[165:164], INIT[159:158], INIT[153:152], INIT[147:146], INIT[141:140], INIT[135:134], INIT[129:128], INIT[123:122], INIT[117:116], INIT[111:110], INIT[105:104], INIT[ 99: 98], INIT[ 93: 92], INIT[ 87: 86], INIT[ 81: 80], INIT[ 75: 74], INIT[ 69: 68], INIT[ 63: 62], INIT[ 57: 56], INIT[ 51: 50], INIT[ 45: 44], INIT[ 39: 38], INIT[ 33: 32], INIT[ 27: 26], INIT[ 21: 20], INIT[ 15: 14], INIT[ 9: 8], INIT[ 3: 2]}),
+ .INIT_C({INIT[191:190], INIT[185:184], INIT[179:178], INIT[173:172], INIT[167:166], INIT[161:160], INIT[155:154], INIT[149:148], INIT[143:142], INIT[137:136], INIT[131:130], INIT[125:124], INIT[119:118], INIT[113:112], INIT[107:106], INIT[101:100], INIT[ 95: 94], INIT[ 89: 88], INIT[ 83: 82], INIT[ 77: 76], INIT[ 71: 70], INIT[ 65: 64], INIT[ 59: 58], INIT[ 53: 52], INIT[ 47: 46], INIT[ 41: 40], INIT[ 35: 34], INIT[ 29: 28], INIT[ 23: 22], INIT[ 17: 16], INIT[ 11: 10], INIT[ 5: 4]}),
+ .INIT_D(64'bx),
+ .IS_WCLK_INVERTED(!CLKPOL2)
+ ) _TECHMAP_REPLACE_ (
+ .ADDRA(A1ADDR),
+ .ADDRB(A1ADDR),
+ .ADDRC(A1ADDR),
+ .DOA(A1DATA[1:0]),
+ .DOB(A1DATA[3:2]),
+ .DOC(A1DATA[5:4]),
+ .DOD(DOD_unused),
+
+ .ADDRD(B1ADDR),
+ .DIA(B1DATA[1:0]),
+ .DIB(B1DATA[3:2]),
+ .DIC(B1DATA[5:4]),
+ .DID(2'b00),
+ .WCLK(CLK1),
+ .WE(B1EN)
+ );
+endmodule
+
+module \$__XILINX_RAM64X3SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter [64*3-1:0] INIT = {64*3{1'bx}};
+ parameter CLKPOL2 = 1;
+ input CLK1;
+
+ input [5:0] A1ADDR;
+ output [2:0] A1DATA;
+
+ input [5:0] B1ADDR;
+ input [2:0] B1DATA;
+ input B1EN;
+
+ wire DOD_unused;
+
+ RAM64M #(
+ .INIT_A({INIT[189], INIT[186], INIT[183], INIT[180], INIT[177], INIT[174], INIT[171], INIT[168], INIT[165], INIT[162], INIT[159], INIT[156], INIT[153], INIT[150], INIT[147], INIT[144], INIT[141], INIT[138], INIT[135], INIT[132], INIT[129], INIT[126], INIT[123], INIT[120], INIT[117], INIT[114], INIT[111], INIT[108], INIT[105], INIT[102], INIT[ 99], INIT[ 96], INIT[ 93], INIT[ 90], INIT[ 87], INIT[ 84], INIT[ 81], INIT[ 78], INIT[ 75], INIT[ 72], INIT[ 69], INIT[ 66], INIT[ 63], INIT[ 60], INIT[ 57], INIT[ 54], INIT[ 51], INIT[ 48], INIT[ 45], INIT[ 42], INIT[ 39], INIT[ 36], INIT[ 33], INIT[ 30], INIT[ 27], INIT[ 24], INIT[ 21], INIT[ 18], INIT[ 15], INIT[ 12], INIT[ 9], INIT[ 6], INIT[ 3], INIT[ 0]}),
+ .INIT_B({INIT[190], INIT[187], INIT[184], INIT[181], INIT[178], INIT[175], INIT[172], INIT[169], INIT[166], INIT[163], INIT[160], INIT[157], INIT[154], INIT[151], INIT[148], INIT[145], INIT[142], INIT[139], INIT[136], INIT[133], INIT[130], INIT[127], INIT[124], INIT[121], INIT[118], INIT[115], INIT[112], INIT[109], INIT[106], INIT[103], INIT[100], INIT[ 97], INIT[ 94], INIT[ 91], INIT[ 88], INIT[ 85], INIT[ 82], INIT[ 79], INIT[ 76], INIT[ 73], INIT[ 70], INIT[ 67], INIT[ 64], INIT[ 61], INIT[ 58], INIT[ 55], INIT[ 52], INIT[ 49], INIT[ 46], INIT[ 43], INIT[ 40], INIT[ 37], INIT[ 34], INIT[ 31], INIT[ 28], INIT[ 25], INIT[ 22], INIT[ 19], INIT[ 16], INIT[ 13], INIT[ 10], INIT[ 7], INIT[ 4], INIT[ 1]}),
+ .INIT_C({INIT[191], INIT[188], INIT[185], INIT[182], INIT[179], INIT[176], INIT[173], INIT[170], INIT[167], INIT[164], INIT[161], INIT[158], INIT[155], INIT[152], INIT[149], INIT[146], INIT[143], INIT[140], INIT[137], INIT[134], INIT[131], INIT[128], INIT[125], INIT[122], INIT[119], INIT[116], INIT[113], INIT[110], INIT[107], INIT[104], INIT[101], INIT[ 98], INIT[ 95], INIT[ 92], INIT[ 89], INIT[ 86], INIT[ 83], INIT[ 80], INIT[ 77], INIT[ 74], INIT[ 71], INIT[ 68], INIT[ 65], INIT[ 62], INIT[ 59], INIT[ 56], INIT[ 53], INIT[ 50], INIT[ 47], INIT[ 44], INIT[ 41], INIT[ 38], INIT[ 35], INIT[ 32], INIT[ 29], INIT[ 26], INIT[ 23], INIT[ 20], INIT[ 17], INIT[ 14], INIT[ 11], INIT[ 8], INIT[ 5], INIT[ 2]}),
+ .INIT_D(64'bx),
+ .IS_WCLK_INVERTED(!CLKPOL2)
+ ) _TECHMAP_REPLACE_ (
+ .ADDRA(A1ADDR),
+ .ADDRB(A1ADDR),
+ .ADDRC(A1ADDR),
+ .DOA(A1DATA[0]),
+ .DOB(A1DATA[1]),
+ .DOC(A1DATA[2]),
+ .DOD(DOD_unused),
+
+ .ADDRD(B1ADDR),
+ .DIA(B1DATA[0]),
+ .DIB(B1DATA[1]),
+ .DIC(B1DATA[2]),
+ .DID(1'b0),
+ .WCLK(CLK1),
+ .WE(B1EN)
+ );
+endmodule
+
+module \$__XILINX_RAM32X2Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN);
+ parameter [63:0] INIT = 64'bx;
+ parameter CLKPOL2 = 1;
+ input CLK1;
+
+ input [4:0] A1ADDR, A2ADDR, A3ADDR;
+ output [1:0] A1DATA, A2DATA, A3DATA;
+
+ input [4:0] B1ADDR;
+ input [1:0] B1DATA;
+ input B1EN;
+
+ RAM32M #(
+ .INIT_A(INIT),
+ .INIT_B(INIT),
+ .INIT_C(INIT),
+ .INIT_D(INIT),
+ .IS_WCLK_INVERTED(!CLKPOL2)
+ ) _TECHMAP_REPLACE_ (
+ .ADDRA(A1ADDR),
+ .ADDRB(A2ADDR),
+ .ADDRC(A3ADDR),
+ .DOA(A1DATA),
+ .DOB(A2DATA),
+ .DOC(A3DATA),
+
+ .ADDRD(B1ADDR),
+ .DIA(B1DATA),
+ .DIB(B1DATA),
+ .DIC(B1DATA),
+ .DID(B1DATA),
+ .WCLK(CLK1),
+ .WE(B1EN)
+ );
+endmodule
+
+module \$__XILINX_RAM64X1Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN);
+ parameter [63:0] INIT = 64'bx;
+ parameter CLKPOL2 = 1;
+ input CLK1;
+
+ input [5:0] A1ADDR, A2ADDR, A3ADDR;
+ output A1DATA, A2DATA, A3DATA;
+
+ input [5:0] B1ADDR;
+ input B1DATA;
+ input B1EN;
+
+ RAM64M #(
+ .INIT_A(INIT),
+ .INIT_B(INIT),
+ .INIT_C(INIT),
+ .INIT_D(INIT),
+ .IS_WCLK_INVERTED(!CLKPOL2)
+ ) _TECHMAP_REPLACE_ (
+ .ADDRA(A1ADDR),
+ .ADDRB(A2ADDR),
+ .ADDRC(A3ADDR),
+ .DOA(A1DATA),
+ .DOB(A2DATA),
+ .DOC(A3DATA),
+
+ .ADDRD(B1ADDR),
+ .DIA(B1DATA),
+ .DIB(B1DATA),
+ .DIC(B1DATA),
+ .DID(B1DATA),
+ .WCLK(CLK1),
+ .WE(B1EN)
+ );
+endmodule
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index de262c8ad..ac6fedc58 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -445,6 +445,16 @@ struct SynthXilinxPass : public ScriptPass
}
if (check_label("map_ffram")) {
+ // Required for dffsr2dff to work.
+ run("simplemap t:$dff t:$adff t:$mux");
+ // Needs to be done before opt -mux_bool happens.
+ run("dffsr2dff");
+ if (help_mode)
+ run("dff2dffs [-match-init]", "(-match-init for xc6s only)");
+ else if (family == "xc6s")
+ run("dff2dffs -match-init");
+ else
+ run("dff2dffs");
if (widemux > 0)
run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
// performs less efficiently
@@ -454,14 +464,11 @@ struct SynthXilinxPass : public ScriptPass
}
if (check_label("fine")) {
- run("dffsr2dff");
- run("dff2dffe");
+ run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
if (help_mode) {
- run("simplemap t:$mux", " ('-widemux' only)");
run("muxcover <internal options>, ('-widemux' only)");
}
else if (widemux > 0) {
- run("simplemap t:$mux");
constexpr int cost_mux2 = 100;
std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
switch (widemux) {
@@ -563,6 +570,7 @@ struct SynthXilinxPass : public ScriptPass
else if (!abc9)
techmap_args += stringf(" -map %s", ff_map_file.c_str());
run("techmap " + techmap_args, "(option without '-abc9')");
+ run("xilinx_dffopt");
}
if (check_label("finalize")) {
diff --git a/techlibs/xilinx/xc6s_ff_map.v b/techlibs/xilinx/xc6s_ff_map.v
index bf35b09e5..c40f446e0 100644
--- a/techlibs/xilinx/xc6s_ff_map.v
+++ b/techlibs/xilinx/xc6s_ff_map.v
@@ -27,6 +27,8 @@
`ifndef _NO_FFS
+// No reset.
+
module \$_DFF_N_ (input D, C, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@@ -46,6 +48,8 @@ module \$_DFF_P_ (input D, C, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// No reset, enable.
+
module \$_DFFE_NP_ (input D, C, E, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@@ -65,80 +69,168 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NN0_ (input D, C, R, output Q);
+// Async reset.
+
+module \$_DFF_NP0_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
- FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
+ FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NP0_ (input D, C, R, output Q);
+module \$_DFF_PP0_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
- FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
+ FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PN0_ (input D, C, R, output Q);
+
+module \$_DFF_NP1_ (input D, C, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
+ $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
+ else
+ FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
+ $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
+ else
+ FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Async reset, enable.
+
+module \$__DFFE_NP0 (input D, C, E, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
- FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
+ FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PP0_ (input D, C, R, output Q);
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
- FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
+ FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NN1_ (input D, C, R, output Q);
+module \$__DFFE_NP1 (input D, C, E, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
$error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
else
- FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
+ FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NP1_ (input D, C, R, output Q);
+module \$__DFFE_PP1 (input D, C, E, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
$error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
else
- FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Sync reset.
+
+module \$__DFFS_NP0_ (input D, C, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
+ $error("Spartan 6 doesn't support FFs with reset initialized to 1");
+ else
+ FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PN1_ (input D, C, R, output Q);
+module \$__DFFS_PP0_ (input D, C, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
+ $error("Spartan 6 doesn't support FFs with reset initialized to 1");
+ else
+ FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+module \$__DFFS_NP1_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
- $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
+ $error("Spartan 6 doesn't support FFs with set initialized to 0");
else
- FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
+ FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PP1_ (input D, C, R, output Q);
+module \$__DFFS_PP1_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
- $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
+ $error("Spartan 6 doesn't support FFs with set initialized to 0");
else
- FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// Sync reset, enable.
+
+module \$__DFFSE_NP0 (input D, C, E, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
+ $error("Spartan 6 doesn't support FFs with reset initialized to 1");
+ else
+ FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFSE_PP0 (input D, C, E, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
+ $error("Spartan 6 doesn't support FFs with reset initialized to 1");
+ else
+ FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+module \$__DFFSE_NP1 (input D, C, E, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
+ $error("Spartan 6 doesn't support FFs with set initialized to 0");
+ else
+ FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFSE_PP1 (input D, C, E, R, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
+ $error("Spartan 6 doesn't support FFs with set initialized to 0");
+ else
+ FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
+ endgenerate
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Latches (no reset).
+
module \$_DLATCH_N_ (input E, D, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@@ -158,5 +250,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// Latches with reset (TODO).
+
`endif
diff --git a/techlibs/xilinx/xc7_ff_map.v b/techlibs/xilinx/xc7_ff_map.v
index 32ca9f560..2bd874457 100644
--- a/techlibs/xilinx/xc7_ff_map.v
+++ b/techlibs/xilinx/xc7_ff_map.v
@@ -37,6 +37,8 @@
`ifndef _NO_FFS
+// No reset.
+
module \$_DFF_N_ (input D, C, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0));
@@ -48,6 +50,8 @@ module \$_DFF_P_ (input D, C, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// No reset, enable.
+
module \$_DFFE_NP_ (input D, C, E, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0));
@@ -59,47 +63,103 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NN0_ (input D, C, R, output Q);
+// Async reset.
+
+module \$_DFF_NP0_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
+ FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NP0_ (input D, C, R, output Q);
+module \$_DFF_PP0_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
+ FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PN0_ (input D, C, R, output Q);
+
+module \$_DFF_NP1_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
+ FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PP0_ (input D, C, R, output Q);
+module \$_DFF_PP1_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
+ FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NN1_ (input D, C, R, output Q);
+// Async reset, enable.
+
+module \$__DFFE_NP0 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
+ FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_NP1_ (input D, C, R, output Q);
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PN1_ (input D, C, R, output Q);
+
+module \$__DFFE_NP1 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
+ FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
-module \$_DFF_PP1_ (input D, C, R, output Q);
+module \$__DFFE_PP1 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
- FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
+ FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Sync reset.
+
+module \$__DFFS_NP0_ (input D, C, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+module \$__DFFS_PP0_ (input D, C, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+module \$__DFFS_NP1_ (input D, C, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFS_PP1_ (input D, C, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Sync reset, enable.
+
+module \$__DFFSE_NP0 (input D, C, E, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFSE_PP0 (input D, C, E, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+module \$__DFFSE_NP1 (input D, C, E, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+module \$__DFFSE_PP1 (input D, C, E, R, output Q);
+ parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
+ FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
+ wire _TECHMAP_REMOVEINIT_Q_ = 1;
+endmodule
+
+// Latches (no reset).
module \$_DLATCH_N_ (input E, D, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
@@ -112,5 +172,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
+// Latches with reset (TODO).
+
`endif
diff --git a/techlibs/xilinx/xc7_xcu_brams.txt b/techlibs/xilinx/xc7_xcu_brams.txt
index f1161114e..c63218ae1 100644
--- a/techlibs/xilinx/xc7_xcu_brams.txt
+++ b/techlibs/xilinx/xc7_xcu_brams.txt
@@ -1,4 +1,3 @@
-
bram $__XILINX_RAMB36_SDP
init 1
abits 9
@@ -72,34 +71,79 @@ bram $__XILINX_RAMB18_TDP
clkpol 2 3
endbram
+# The "min bits" value were taken from:
+# [[CITE]] 7 Series FPGAs Memory Resources User Guide (UG473),
+# v1.14 ed., p 29-30, July, 2019.
+# https://www.xilinx.com/support/documentation/user_guides/ug473_7Series_Memory_Resources.pdf
+
match $__XILINX_RAMB36_SDP
- min bits 4096
+ attribute !ram_style
+ attribute !logic_block
+ min bits 1024
min efficiency 5
shuffle_enable B
make_transp
or_next_if_better
endmatch
+match $__XILINX_RAMB36_SDP
+ attribute ram_style=block ram_block
+ attribute !logic_block
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
match $__XILINX_RAMB18_SDP
- min bits 4096
+ attribute !ram_style
+ attribute !logic_block
+ min bits 1024
min efficiency 5
shuffle_enable B
make_transp
or_next_if_better
endmatch
+match $__XILINX_RAMB18_SDP
+ attribute ram_style=block ram_block
+ attribute !logic_block
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
match $__XILINX_RAMB36_TDP
- min bits 4096
+ attribute !ram_style
+ attribute !logic_block
+ min bits 1024
min efficiency 5
shuffle_enable B
make_transp
or_next_if_better
endmatch
+match $__XILINX_RAMB36_TDP
+ attribute ram_style=block ram_block
+ attribute !logic_block
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
match $__XILINX_RAMB18_TDP
- min bits 4096
+ attribute !ram_style
+ attribute !logic_block
+ min bits 1024
min efficiency 5
shuffle_enable B
make_transp
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAMB18_TDP
+ attribute ram_style=block ram_block
+ attribute !logic_block
+ shuffle_enable B
+ make_transp
endmatch
diff --git a/techlibs/xilinx/xilinx_dffopt.cc b/techlibs/xilinx/xilinx_dffopt.cc
new file mode 100644
index 000000000..1256a08cb
--- /dev/null
+++ b/techlibs/xilinx/xilinx_dffopt.cc
@@ -0,0 +1,351 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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
+
+typedef std::pair<Const, std::vector<SigBit>> LutData;
+
+// Compute a LUT implementing (select ^ select_inv) ? alt_data : data. Returns true if successful.
+bool merge_lut(LutData &result, const LutData &data, const LutData select, bool select_inv, SigBit alt_data, int max_lut_size) {
+ // First, gather input signals.
+ result.second = data.second;
+ int idx_alt = -1;
+ if (alt_data.wire) {
+ // Check if we already have it.
+ for (int i = 0; i < GetSize(result.second); i++)
+ if (result.second[i] == alt_data)
+ idx_alt = i;
+ // If not, add it.
+ if (idx_alt == -1) {
+ idx_alt = GetSize(result.second);
+ result.second.push_back(alt_data);
+ }
+ }
+ std::vector<int> idx_sel;
+ for (auto bit : select.second) {
+ int idx = -1;
+ for (int i = 0; i < GetSize(result.second); i++)
+ if (result.second[i] == bit)
+ idx = i;
+ if (idx == -1) {
+ idx = GetSize(result.second);
+ result.second.push_back(bit);
+ }
+ idx_sel.push_back(idx);
+ }
+
+ // If LUT would be too large, bail.
+ if (GetSize(result.second) > max_lut_size)
+ return false;
+
+ // Okay, we're doing it — compute the LUT mask.
+ result.first = Const(0, 1 << GetSize(result.second));
+ for (int i = 0; i < GetSize(result.first); i++) {
+ int sel_lut_idx = 0;
+ for (int j = 0; j < GetSize(select.second); j++)
+ if (i & 1 << idx_sel[j])
+ sel_lut_idx |= 1 << j;
+ bool select_val = (select.first.bits[sel_lut_idx] == State::S1);
+ bool new_bit;
+ if (select_val ^ select_inv) {
+ // Use alt_data.
+ if (alt_data.wire)
+ new_bit = (i & 1 << idx_alt) != 0;
+ else
+ new_bit = alt_data.data == State::S1;
+ } else {
+ // Use original LUT.
+ int lut_idx = i & ((1 << GetSize(data.second)) - 1);
+ new_bit = data.first.bits[lut_idx] == State::S1;
+ }
+ result.first.bits[i] = new_bit ? State::S1 : State::S0;
+ }
+ return true;
+}
+
+struct XilinxDffOptPass : public Pass {
+ XilinxDffOptPass() : Pass("xilinx_dffopt", "Xilinx: optimize FF control signal usage") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" xilinx_dffopt [options] [selection]\n");
+ log("\n");
+ log("Converts hardware clock enable and set/reset signals on FFs to emulation\n");
+ log("using LUTs, if doing so would improve area. Operates on post-techmap Xilinx\n");
+ log("cells (LUT*, FD*).\n");
+ log("\n");
+ log(" -lut4\n");
+ log(" Assume a LUT4-based device (instead of a LUT6-based device).\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing XILINX_DFFOPT pass (optimize FF control signal usage).\n");
+
+ size_t argidx;
+ int max_lut_size = 6;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-lut4") {
+ max_lut_size = 4;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ log("Optimizing FFs in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, pair<LutData, Cell *>> bit_to_lut;
+ dict<SigBit, int> bit_uses;
+
+ // Gather LUTs.
+ for (auto cell : module->selected_cells())
+ {
+ for (auto port : cell->connections())
+ for (auto bit : port.second)
+ bit_uses[sigmap(bit)]++;
+ if (cell->get_bool_attribute(ID::keep))
+ continue;
+ if (cell->type == ID(INV)) {
+ SigBit sigout = sigmap(cell->getPort(ID(O)));
+ SigBit sigin = sigmap(cell->getPort(ID(I)));
+ bit_to_lut[sigout] = make_pair(LutData(Const(1, 2), {sigin}), cell);
+ } else if (cell->type.in(ID(LUT1), ID(LUT2), ID(LUT3), ID(LUT4), ID(LUT5), ID(LUT6))) {
+ SigBit sigout = sigmap(cell->getPort(ID(O)));
+ const Const &init = cell->getParam(ID(INIT));
+ std::vector<SigBit> sigin;
+ sigin.push_back(sigmap(cell->getPort(ID(I0))));
+ if (cell->type == ID(LUT1))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I1))));
+ if (cell->type == ID(LUT2))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I2))));
+ if (cell->type == ID(LUT3))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I3))));
+ if (cell->type == ID(LUT4))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I4))));
+ if (cell->type == ID(LUT5))
+ goto lut_sigin_done;
+ sigin.push_back(sigmap(cell->getPort(ID(I5))));
+lut_sigin_done:
+ bit_to_lut[sigout] = make_pair(LutData(init, sigin), cell);
+ }
+ }
+ for (auto wire : module->wires())
+ if (wire->port_output || wire->port_input)
+ for (int i = 0; i < GetSize(wire); i++)
+ bit_uses[sigmap(SigBit(wire, i))]++;
+
+ // Iterate through FFs.
+ for (auto cell : module->selected_cells())
+ {
+ bool has_s = false, has_r = false;
+ if (cell->type.in(ID(FDCE), ID(FDPE), ID(FDCPE), ID(FDCE_1), ID(FDPE_1), ID(FDCPE_1))) {
+ // Async reset.
+ } else if (cell->type.in(ID(FDRE), ID(FDRE_1))) {
+ has_r = true;
+ } else if (cell->type.in(ID(FDSE), ID(FDSE_1))) {
+ has_s = true;
+ } else if (cell->type.in(ID(FDRSE), ID(FDRSE_1))) {
+ has_r = true;
+ has_s = true;
+ } else {
+ // Not a FF.
+ continue;
+ }
+ if (cell->get_bool_attribute(ID::keep))
+ continue;
+
+ // Don't bother if D has more than one use.
+ SigBit sig_D = sigmap(cell->getPort(ID(D)));
+ if (bit_uses[sig_D] > 2)
+ continue;
+
+ // Find the D LUT.
+ auto it_D = bit_to_lut.find(sig_D);
+ if (it_D == bit_to_lut.end())
+ continue;
+ LutData lut_d = it_D->second.first;
+ Cell *cell_d = it_D->second.second;
+ if (cell->hasParam(ID(IS_D_INVERTED)) && cell->getParam(ID(IS_D_INVERTED)).as_bool()) {
+ // Flip all bits in the LUT.
+ for (int i = 0; i < GetSize(lut_d.first); i++)
+ lut_d.first.bits[i] = (lut_d.first.bits[i] == State::S1) ? State::S0 : State::S1;
+ }
+
+ LutData lut_d_post_ce;
+ LutData lut_d_post_s;
+ LutData lut_d_post_r;
+ bool worthy_post_ce = false;
+ bool worthy_post_s = false;
+ bool worthy_post_r = false;
+
+ // First, unmap CE.
+ SigBit sig_Q = sigmap(cell->getPort(ID(Q)));
+ SigBit sig_CE = sigmap(cell->getPort(ID(CE)));
+ LutData lut_ce = LutData(Const(2, 2), {sig_CE});
+ auto it_CE = bit_to_lut.find(sig_CE);
+ if (it_CE != bit_to_lut.end())
+ lut_ce = it_CE->second.first;
+ if (sig_CE.wire) {
+ // Merge CE LUT and D LUT into one. If it cannot be done, nothing to do about this FF.
+ if (!merge_lut(lut_d_post_ce, lut_d, lut_ce, true, sig_Q, max_lut_size))
+ continue;
+
+ // If this gets rid of a CE LUT, it's worth it. If not, it still may be worth it, if we can remove set/reset as well.
+ if (it_CE != bit_to_lut.end())
+ worthy_post_ce = true;
+ } else if (sig_CE.data != State::S1) {
+ // Strange. Should not happen in a reasonable flow, so bail.
+ continue;
+ } else {
+ lut_d_post_ce = lut_d;
+ }
+
+ // Second, unmap S, if any.
+ lut_d_post_s = lut_d_post_ce;
+ if (has_s) {
+ SigBit sig_S = sigmap(cell->getPort(ID(S)));
+ LutData lut_s = LutData(Const(2, 2), {sig_S});
+ bool inv_s = cell->hasParam(ID(IS_S_INVERTED)) && cell->getParam(ID(IS_S_INVERTED)).as_bool();
+ auto it_S = bit_to_lut.find(sig_S);
+ if (it_S != bit_to_lut.end())
+ lut_s = it_S->second.first;
+ if (sig_S.wire) {
+ // Merge S LUT and D LUT into one. If it cannot be done, try to at least merge CE.
+ if (!merge_lut(lut_d_post_s, lut_d_post_ce, lut_s, inv_s, SigBit(State::S1), max_lut_size))
+ goto unmap;
+ // If this gets rid of an S LUT, it's worth it.
+ if (it_S != bit_to_lut.end())
+ worthy_post_s = true;
+ } else if (sig_S.data != (inv_s ? State::S1 : State::S0)) {
+ // Strange. Should not happen in a reasonable flow, so bail.
+ continue;
+ }
+ }
+
+ // Third, unmap R, if any.
+ lut_d_post_r = lut_d_post_s;
+ if (has_r) {
+ SigBit sig_R = sigmap(cell->getPort(ID(R)));
+ LutData lut_r = LutData(Const(2, 2), {sig_R});
+ bool inv_r = cell->hasParam(ID(IS_R_INVERTED)) && cell->getParam(ID(IS_R_INVERTED)).as_bool();
+ auto it_R = bit_to_lut.find(sig_R);
+ if (it_R != bit_to_lut.end())
+ lut_r = it_R->second.first;
+ if (sig_R.wire) {
+ // Merge R LUT and D LUT into one. If it cannot be done, try to at least merge CE/S.
+ if (!merge_lut(lut_d_post_r, lut_d_post_s, lut_r, inv_r, SigBit(State::S0), max_lut_size))
+ goto unmap;
+ // If this gets rid of an S LUT, it's worth it.
+ if (it_R != bit_to_lut.end())
+ worthy_post_r = true;
+ } else if (sig_R.data != (inv_r ? State::S1 : State::S0)) {
+ // Strange. Should not happen in a reasonable flow, so bail.
+ continue;
+ }
+ }
+
+unmap:
+ LutData final_lut;
+ if (worthy_post_r) {
+ final_lut = lut_d_post_r;
+ log(" Merging R LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
+ } else if (worthy_post_s) {
+ final_lut = lut_d_post_s;
+ log(" Merging S LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
+ } else if (worthy_post_ce) {
+ final_lut = lut_d_post_ce;
+ log(" Merging CE LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
+ } else {
+ // Nothing to do here.
+ continue;
+ }
+
+ // Okay, we're doing it. Unmap ports.
+ if (worthy_post_r) {
+ cell->unsetParam(ID(IS_R_INVERTED));
+ cell->setPort(ID(R), Const(0, 1));
+ }
+ if (has_s && (worthy_post_r || worthy_post_s)) {
+ cell->unsetParam(ID(IS_S_INVERTED));
+ cell->setPort(ID(S), Const(0, 1));
+ }
+ cell->setPort(ID(CE), Const(1, 1));
+ cell->unsetParam(ID(IS_D_INVERTED));
+
+ // Create the new LUT.
+ Cell *lut_cell = 0;
+ switch (GetSize(final_lut.second)) {
+ case 1:
+ lut_cell = module->addCell(NEW_ID, ID(LUT1));
+ break;
+ case 2:
+ lut_cell = module->addCell(NEW_ID, ID(LUT2));
+ break;
+ case 3:
+ lut_cell = module->addCell(NEW_ID, ID(LUT3));
+ break;
+ case 4:
+ lut_cell = module->addCell(NEW_ID, ID(LUT4));
+ break;
+ case 5:
+ lut_cell = module->addCell(NEW_ID, ID(LUT5));
+ break;
+ case 6:
+ lut_cell = module->addCell(NEW_ID, ID(LUT6));
+ break;
+ default:
+ log_assert(!"unknown lut size");
+ }
+ lut_cell->attributes = cell_d->attributes;
+ Wire *lut_out = module->addWire(NEW_ID);
+ lut_cell->setParam(ID(INIT), final_lut.first);
+ cell->setPort(ID(D), lut_out);
+ lut_cell->setPort(ID(O), lut_out);
+ lut_cell->setPort(ID(I0), final_lut.second[0]);
+ if (GetSize(final_lut.second) >= 2)
+ lut_cell->setPort(ID(I1), final_lut.second[1]);
+ if (GetSize(final_lut.second) >= 3)
+ lut_cell->setPort(ID(I2), final_lut.second[2]);
+ if (GetSize(final_lut.second) >= 4)
+ lut_cell->setPort(ID(I3), final_lut.second[3]);
+ if (GetSize(final_lut.second) >= 5)
+ lut_cell->setPort(ID(I4), final_lut.second[4]);
+ if (GetSize(final_lut.second) >= 6)
+ lut_cell->setPort(ID(I5), final_lut.second[5]);
+ }
+ }
+ }
+} XilinxDffOptPass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/tests/arch/anlogic/memory.ys b/tests/arch/anlogic/lutram.ys
index 87b93c2fe..9ebb75443 100644
--- a/tests/arch/anlogic/memory.ys
+++ b/tests/arch/anlogic/lutram.ys
@@ -1,5 +1,5 @@
-read_verilog ../common/memory.v
-hierarchy -top top
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r
proc
memory -nomap
equiv_opt -run :prove -map +/anlogic/cells_sim.v synth_anlogic
@@ -11,7 +11,7 @@ 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
+cd lutram_1w1r
select -assert-count 8 t:AL_MAP_LUT2
select -assert-count 8 t:AL_MAP_LUT4
diff --git a/tests/arch/common/blockram.v b/tests/arch/common/blockram.v
new file mode 100644
index 000000000..dbc6ca65c
--- /dev/null
+++ b/tests/arch/common/blockram.v
@@ -0,0 +1,45 @@
+`default_nettype none
+module sync_ram_sp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
+ (input wire write_enable, clk,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire [ADDRESS_WIDTH-1:0] address_in,
+ output wire [DATA_WIDTH-1:0] data_out);
+
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ reg [WORD:0] memory [0:DEPTH];
+
+ always @(posedge clk) begin
+ if (write_enable)
+ memory[address_in] <= data_in;
+ data_out_r <= memory[address_in];
+ end
+
+ assign data_out = data_out_r;
+endmodule // sync_ram_sp
+
+
+`default_nettype none
+module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
+ (input wire clk, write_enable,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire [ADDRESS_WIDTH-1:0] address_in_r, address_in_w,
+ output wire [DATA_WIDTH-1:0] data_out);
+
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ reg [WORD:0] memory [0:DEPTH];
+
+ always @(posedge clk) begin
+ if (write_enable)
+ memory[address_in_w] <= data_in;
+ data_out_r <= memory[address_in_r];
+ end
+
+ assign data_out = data_out_r;
+endmodule // sync_ram_sdp
+
diff --git a/tests/arch/common/lutram.v b/tests/arch/common/lutram.v
new file mode 100644
index 000000000..9534b7619
--- /dev/null
+++ b/tests/arch/common/lutram.v
@@ -0,0 +1,42 @@
+module lutram_1w1r
+#(parameter D_WIDTH=8, A_WIDTH=6)
+(
+ input [D_WIDTH-1:0] data_a,
+ input [A_WIDTH:1] addr_a,
+ input we_a, clk,
+ output reg [D_WIDTH-1:0] q_a
+);
+ // Declare the RAM variable
+ reg [D_WIDTH-1:0] ram[(2**A_WIDTH)-1:0];
+
+ // Port A
+ always @ (posedge clk)
+ begin
+ if (we_a)
+ ram[addr_a] <= data_a;
+ q_a <= ram[addr_a];
+ end
+endmodule
+
+
+module lutram_1w3r
+#(parameter D_WIDTH=8, A_WIDTH=5)
+(
+ input [D_WIDTH-1:0] data_a, data_b, data_c,
+ input [A_WIDTH:1] addr_a, addr_b, addr_c,
+ input we_a, clk,
+ output reg [D_WIDTH-1:0] q_a, q_b, q_c
+);
+ // Declare the RAM variable
+ reg [D_WIDTH-1:0] ram[(2**A_WIDTH)-1:0];
+
+ // Port A
+ always @ (posedge clk)
+ begin
+ if (we_a)
+ ram[addr_a] <= data_a;
+ q_a <= ram[addr_a];
+ q_b <= ram[addr_b];
+ q_c <= ram[addr_c];
+ end
+endmodule
diff --git a/tests/arch/common/memory.v b/tests/arch/common/memory.v
deleted file mode 100644
index cb7753f7b..000000000
--- a/tests/arch/common/memory.v
+++ /dev/null
@@ -1,21 +0,0 @@
-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/arch/common/memory_attributes/attributes_test.v b/tests/arch/common/memory_attributes/attributes_test.v
new file mode 100644
index 000000000..275800dd0
--- /dev/null
+++ b/tests/arch/common/memory_attributes/attributes_test.v
@@ -0,0 +1,88 @@
+`default_nettype none
+module block_ram #(parameter DATA_WIDTH=4, ADDRESS_WIDTH=10)
+ (input wire write_enable, clk,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire [ADDRESS_WIDTH-1:0] address_in,
+ output wire [DATA_WIDTH-1:0] data_out);
+
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ reg [WORD:0] memory [0:DEPTH];
+
+ always @(posedge clk) begin
+ if (write_enable)
+ memory[address_in] <= data_in;
+ data_out_r <= memory[address_in];
+ end
+
+ assign data_out = data_out_r;
+endmodule // block_ram
+
+`default_nettype none
+module distributed_ram #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=4)
+ (input wire write_enable, clk,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire [ADDRESS_WIDTH-1:0] address_in,
+ output wire [DATA_WIDTH-1:0] data_out);
+
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ reg [WORD:0] memory [0:DEPTH];
+
+ always @(posedge clk) begin
+ if (write_enable)
+ memory[address_in] <= data_in;
+ data_out_r <= memory[address_in];
+ end
+
+ assign data_out = data_out_r;
+endmodule // distributed_ram
+
+`default_nettype none
+module distributed_ram_manual #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=4)
+ (input wire write_enable, clk,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire [ADDRESS_WIDTH-1:0] address_in,
+ output wire [DATA_WIDTH-1:0] data_out);
+
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ (* ram_style = "block" *) reg [WORD:0] memory [0:DEPTH];
+
+ always @(posedge clk) begin
+ if (write_enable)
+ memory[address_in] <= data_in;
+ data_out_r <= memory[address_in];
+ end
+
+ assign data_out = data_out_r;
+endmodule // distributed_ram
+
+`default_nettype none
+module distributed_ram_manual_syn #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=4)
+ (input wire write_enable, clk,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire [ADDRESS_WIDTH-1:0] address_in,
+ output wire [DATA_WIDTH-1:0] data_out);
+
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ (* synthesis, ram_block *) reg [WORD:0] memory [0:DEPTH];
+
+ always @(posedge clk) begin
+ if (write_enable)
+ memory[address_in] <= data_in;
+ data_out_r <= memory[address_in];
+ end
+
+ assign data_out = data_out_r;
+endmodule // distributed_ram
+
diff --git a/tests/arch/ecp5/memory.ys b/tests/arch/ecp5/lutram.ys
index c82b7b405..e1ae7abd5 100644
--- a/tests/arch/ecp5/memory.ys
+++ b/tests/arch/ecp5/lutram.ys
@@ -1,5 +1,5 @@
-read_verilog ../common/memory.v
-hierarchy -top top
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r
proc
memory -nomap
equiv_opt -run :prove -map +/ecp5/cells_sim.v synth_ecp5
@@ -10,7 +10,7 @@ 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
+cd lutram_1w1r
select -assert-count 24 t:L6MUX21
select -assert-count 71 t:LUT4
select -assert-count 32 t:PFUMX
diff --git a/tests/arch/efinix/memory.ys b/tests/arch/efinix/lutram.ys
index 6f6acdcde..dcf647ce0 100644
--- a/tests/arch/efinix/memory.ys
+++ b/tests/arch/efinix/lutram.ys
@@ -1,5 +1,5 @@
-read_verilog ../common/memory.v
-hierarchy -top top
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r
proc
memory -nomap
equiv_opt -run :prove -map +/efinix/cells_sim.v synth_efinix
@@ -12,7 +12,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt
-cd top
+cd lutram_1w1r
select -assert-count 1 t:EFX_GBUFCE
select -assert-count 1 t:EFX_RAM_5K
select -assert-none t:EFX_GBUFCE t:EFX_RAM_5K %% t:* %D
diff --git a/tests/arch/gowin/memory.ys b/tests/arch/gowin/lutram.ys
index 8f88cdd7c..56f69e7c5 100644
--- a/tests/arch/gowin/memory.ys
+++ b/tests/arch/gowin/lutram.ys
@@ -1,5 +1,5 @@
-read_verilog ../common/memory.v
-hierarchy -top top
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r
proc
memory -nomap
equiv_opt -run :prove -map +/gowin/cells_sim.v synth_gowin
@@ -12,7 +12,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt
-cd top
+cd lutram_1w1r
select -assert-count 8 t:RAM16S4
# other logic present that is not simple
#select -assert-none t:RAM16S4 %% t:* %D
diff --git a/tests/arch/ice40/memory.ys b/tests/arch/ice40/lutram.ys
index c356e67fb..1ba40f8ec 100644
--- a/tests/arch/ice40/memory.ys
+++ b/tests/arch/ice40/lutram.ys
@@ -1,5 +1,5 @@
-read_verilog ../common/memory.v
-hierarchy -top top
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r
proc
memory -nomap
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
@@ -10,6 +10,6 @@ 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
+cd lutram_1w1r
select -assert-count 1 t:SB_RAM40_4K
select -assert-none t:SB_RAM40_4K %% t:* %D
diff --git a/tests/arch/xilinx/adffs.ys b/tests/arch/xilinx/adffs.ys
index e73bfe0b9..c0ff6a2e2 100644
--- a/tests/arch/xilinx/adffs.ys
+++ b/tests/arch/xilinx/adffs.ys
@@ -32,10 +32,9 @@ equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx # equivale
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd dffs # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
-select -assert-count 1 t:FDRE
-select -assert-count 1 t:LUT2
+select -assert-count 1 t:FDSE
-select -assert-none t:BUFG t:FDRE t:LUT2 %% t:* %D
+select -assert-none t:BUFG t:FDSE %% t:* %D
design -load read
@@ -46,6 +45,6 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd ndffnr # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
select -assert-count 1 t:FDRE_1
-select -assert-count 1 t:LUT2
+select -assert-count 1 t:INV
-select -assert-none t:BUFG t:FDRE_1 t:LUT2 %% t:* %D
+select -assert-none t:BUFG t:FDRE_1 t:INV %% t:* %D
diff --git a/tests/arch/xilinx/attributes_test.ys b/tests/arch/xilinx/attributes_test.ys
new file mode 100644
index 000000000..4c881b280
--- /dev/null
+++ b/tests/arch/xilinx/attributes_test.ys
@@ -0,0 +1,47 @@
+# Check that blockram memory without parameters is not modified
+read_verilog ../common/memory_attributes/attributes_test.v
+hierarchy -top block_ram
+synth_xilinx -top block_ram
+cd block_ram # Constrain all select calls below inside the top module
+select -assert-count 1 t:RAMB18E1
+
+# Check that distributed memory without parameters is not modified
+design -reset
+read_verilog ../common/memory_attributes/attributes_test.v
+hierarchy -top distributed_ram
+synth_xilinx -top distributed_ram
+cd distributed_ram # Constrain all select calls below inside the top module
+select -assert-count 8 t:RAM32X1D
+
+# Set ram_style distributed to blockram memory; will be implemented as distributed
+design -reset
+read_verilog ../common/memory_attributes/attributes_test.v
+prep
+setattr -mod -set ram_style "distributed" block_ram
+synth_xilinx -top block_ram
+cd block_ram # Constrain all select calls below inside the top module
+select -assert-count 32 t:RAM128X1D
+
+# Set synthesis, logic_block to blockram memory; will be implemented as distributed
+design -reset
+read_verilog ../common/memory_attributes/attributes_test.v
+prep
+setattr -mod -set logic_block 1 block_ram
+synth_xilinx -top block_ram
+cd block_ram # Constrain all select calls below inside the top module
+select -assert-count 0 t:RAMB18E1
+select -assert-count 32 t:RAM128X1D
+
+# Set ram_style block to a distributed memory; will be implemented as blockram
+design -reset
+read_verilog ../common/memory_attributes/attributes_test.v
+synth_xilinx -top distributed_ram_manual
+cd distributed_ram_manual # Constrain all select calls below inside the top module
+select -assert-count 1 t:RAMB18E1
+
+# Set synthesis, ram_block block to a distributed memory; will be implemented as blockram
+design -reset
+read_verilog ../common/memory_attributes/attributes_test.v
+synth_xilinx -top distributed_ram_manual_syn
+cd distributed_ram_manual_syn # Constrain all select calls below inside the top module
+select -assert-count 1 t:RAMB18E1
diff --git a/tests/arch/xilinx/blockram.ys b/tests/arch/xilinx/blockram.ys
new file mode 100644
index 000000000..bb908cbbf
--- /dev/null
+++ b/tests/arch/xilinx/blockram.ys
@@ -0,0 +1,97 @@
+### TODO: Not running equivalence checking because BRAM models does not exists
+### currently. Checking instance counts instead.
+# Memory bits <= 18K; Data width <= 36; Address width <= 14: -> RAMB18E1
+read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 1 sync_ram_sdp
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB18E1
+
+design -reset
+read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 8 -set DATA_WIDTH 18 sync_ram_sdp
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB18E1
+
+design -reset
+read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 14 -set DATA_WIDTH 1 sync_ram_sdp
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB18E1
+
+design -reset
+read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 36 sync_ram_sdp
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB18E1
+
+# Anything memory bits < 1024 -> LUTRAM
+design -reset
+read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 8 -set DATA_WIDTH 2 sync_ram_sdp
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 0 t:RAMB18E1
+select -assert-count 4 t:RAM128X1D
+
+# More than 18K bits, data width <= 36 (TDP), and address width from 10 to 15b (non-cascaded) -> RAMB36E1
+design -reset
+read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 36 sync_ram_sdp
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB36E1
+
+
+### With parameters
+
+design -reset
+read_verilog ../common/blockram.v
+hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1
+setattr -set ram_style "block" m:memory
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB18E1
+
+design -reset
+read_verilog ../common/blockram.v
+hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1
+setattr -set ram_block 1 m:memory
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB18E1
+
+design -reset
+read_verilog ../common/blockram.v
+hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1
+setattr -set ram_style "dont_infer_a_ram_pretty_please" m:memory
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 0 t:RAMB18E1
+
+design -reset
+read_verilog ../common/blockram.v
+hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1
+setattr -set logic_block 1 m:memory
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 0 t:RAMB18E1
+
+design -reset
+read_verilog ../common/blockram.v
+hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 8 -chparam DATA_WIDTH 1
+setattr -set ram_style "block" m:memory
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB18E1
+
+design -reset
+read_verilog ../common/blockram.v
+hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 8 -chparam DATA_WIDTH 1
+setattr -set ram_block 1 m:memory
+synth_xilinx -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:RAMB18E1
diff --git a/tests/arch/xilinx/bug1460.ys b/tests/arch/xilinx/bug1460.ys
new file mode 100644
index 000000000..2018071cc
--- /dev/null
+++ b/tests/arch/xilinx/bug1460.ys
@@ -0,0 +1,34 @@
+read_verilog <<EOT
+module register_file(
+ input wire clk,
+ input wire write_enable,
+ input wire [63:0] write_data,
+ input wire [4:0] write_reg,
+ input wire [4:0] read1_reg,
+ input wire [4:0] read2_reg,
+ input wire [4:0] read3_reg,
+ output reg [63:0] read1_data,
+ output reg [63:0] read2_data,
+ output reg [63:0] read3_data
+ );
+
+ reg [63:0] registers[0:31];
+
+ always @(posedge clk) begin
+ if (write_enable == 1'b1) begin
+ registers[write_reg] <= write_data;
+ end
+ end
+
+ always @(all) begin
+ read1_data <= registers[read1_reg];
+ read2_data <= registers[read2_reg];
+ read3_data <= registers[read3_reg];
+ end
+endmodule
+EOT
+
+synth_xilinx
+cd register_file
+select -assert-count 32 t:RAM32M
+select -assert-none t:* t:BUFG %d t:RAM32M %d
diff --git a/tests/arch/xilinx/fsm.ys b/tests/arch/xilinx/fsm.ys
index 2a72c34e8..f03400fe7 100644
--- a/tests/arch/xilinx/fsm.ys
+++ b/tests/arch/xilinx/fsm.ys
@@ -11,8 +11,9 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd fsm # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
-select -assert-count 5 t:FDRE
-select -assert-count 1 t:LUT3
-select -assert-count 2 t:LUT4
-select -assert-count 4 t:LUT6
-select -assert-none t:BUFG t:FDRE t:LUT3 t:LUT4 t:LUT6 %% t:* %D
+select -assert-count 4 t:FDRE
+select -assert-count 1 t:FDSE
+select -assert-count 1 t:LUT2
+select -assert-count 3 t:LUT5
+select -assert-count 1 t:LUT6
+select -assert-none t:BUFG t:FDRE t:FDSE t:LUT2 t:LUT5 t:LUT6 %% t:* %D
diff --git a/tests/arch/xilinx/lutram.ys b/tests/arch/xilinx/lutram.ys
new file mode 100644
index 000000000..6c9d1eae1
--- /dev/null
+++ b/tests/arch/xilinx/lutram.ys
@@ -0,0 +1,137 @@
+#read_verilog ../common/lutram.v
+#hierarchy -top lutram_1w1r -chparam A_WIDTH 4
+#proc
+#memory -nomap
+#equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
+#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 lutram_1w1r
+#select -assert-count 1 t:BUFG
+#select -assert-count 8 t:FDRE
+#select -assert-count 8 t:RAM16X1D
+#select -assert-none t:BUFG t:FDRE t:RAM16X1D %% t:* %D
+
+
+design -reset
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r -chparam A_WIDTH 5
+proc
+memory -nomap
+equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
+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 lutram_1w1r
+select -assert-count 1 t:BUFG
+select -assert-count 8 t:FDRE
+select -assert-count 8 t:RAM32X1D
+select -assert-none t:BUFG t:FDRE t:RAM32X1D %% t:* %D
+
+
+design -reset
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r
+proc
+memory -nomap
+equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
+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 lutram_1w1r
+select -assert-count 1 t:BUFG
+select -assert-count 8 t:FDRE
+select -assert-count 8 t:RAM64X1D
+select -assert-none t:BUFG t:FDRE t:RAM64X1D %% t:* %D
+
+
+design -reset
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w3r
+proc
+memory -nomap
+equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
+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 lutram_1w3r
+select -assert-count 1 t:BUFG
+select -assert-count 24 t:FDRE
+select -assert-count 4 t:RAM32M
+select -assert-none t:BUFG t:FDRE t:RAM32M %% t:* %D
+
+
+design -reset
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w3r -chparam A_WIDTH 6
+proc
+memory -nomap
+equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
+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 lutram_1w3r
+select -assert-count 1 t:BUFG
+select -assert-count 24 t:FDRE
+select -assert-count 8 t:RAM64M
+select -assert-none t:BUFG t:FDRE t:RAM64M %% t:* %D
+
+
+design -reset
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r -chparam A_WIDTH 5 -chparam D_WIDTH 6
+proc
+memory -nomap
+equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
+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 lutram_1w1r
+select -assert-count 1 t:BUFG
+select -assert-count 6 t:FDRE
+select -assert-count 1 t:RAM32M
+select -assert-none t:BUFG t:FDRE t:RAM32M %% t:* %D
+
+
+design -reset
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r -chparam A_WIDTH 6 -chparam D_WIDTH 6
+proc
+memory -nomap
+equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
+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 lutram_1w1r
+select -assert-count 1 t:BUFG
+select -assert-count 6 t:FDRE
+select -assert-count 2 t:RAM64M
+select -assert-none t:BUFG t:FDRE t:RAM64M %% t:* %D
diff --git a/tests/arch/xilinx/macc.ys b/tests/arch/xilinx/macc.ys
index 6e884b35a..11e959976 100644
--- a/tests/arch/xilinx/macc.ys
+++ b/tests/arch/xilinx/macc.ys
@@ -23,9 +23,10 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -seq 10 -show-inputs -show-outputs miter
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd macc2 # Constrain all select calls below inside the top module
+
select -assert-count 1 t:BUFG
select -assert-count 1 t:DSP48E1
select -assert-count 1 t:FDRE
select -assert-count 1 t:LUT2
-select -assert-count 41 t:LUT3
+select -assert-count 40 t:LUT3
select -assert-none t:BUFG t:DSP48E1 t:FDRE t:LUT2 t:LUT3 %% t:* %D
diff --git a/tests/arch/xilinx/memory.ys b/tests/arch/xilinx/memory.ys
deleted file mode 100644
index da1ed0e49..000000000
--- a/tests/arch/xilinx/memory.ys
+++ /dev/null
@@ -1,17 +0,0 @@
-read_verilog ../common/memory.v
-hierarchy -top top
-proc
-memory -nomap
-equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
-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:BUFG
-select -assert-count 8 t:FDRE
-select -assert-count 8 t:RAM64X1D
-select -assert-none t:BUFG t:FDRE t:RAM64X1D %% t:* %D
diff --git a/tests/arch/xilinx/mux.ys b/tests/arch/xilinx/mux.ys
index 821d0fab7..388272449 100644
--- a/tests/arch/xilinx/mux.ys
+++ b/tests/arch/xilinx/mux.ys
@@ -40,6 +40,8 @@ proc
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux16 # Constrain all select calls below inside the top module
-select -assert-count 5 t:LUT6
+select -assert-min 5 t:LUT6
+select -assert-max 7 t:LUT6
+select -assert-max 2 t:MUXF7
-select -assert-none t:LUT6 %% t:* %D
+select -assert-none t:LUT6 t:MUXF7 %% t:* %D
diff --git a/tests/arch/xilinx/xilinx_dffopt.ys b/tests/arch/xilinx/xilinx_dffopt.ys
new file mode 100644
index 000000000..dc036acfd
--- /dev/null
+++ b/tests/arch/xilinx/xilinx_dffopt.ys
@@ -0,0 +1,216 @@
+read_verilog << EOT
+
+// FDRE, mergeable CE and R.
+
+module t0 (...);
+input wire clk;
+input wire [7:0] i;
+output wire [7:0] o;
+
+wire [7:0] tmp ;
+
+LUT2 #(.INIT(4'h6)) lut0 (.I0(i[0]), .I1(i[1]), .O(tmp[0]));
+LUT2 #(.INIT(4'h6)) lut1 (.I0(i[1]), .I1(i[2]), .O(tmp[1]));
+LUT2 #(.INIT(4'h6)) lut2 (.I0(i[3]), .I1(i[4]), .O(tmp[2]));
+
+FDRE ff (.D(tmp[0]), .CE(tmp[1]), .R(tmp[2]), .Q(o[0]));
+
+endmodule
+
+EOT
+
+design -save t0
+
+equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt
+design -load postopt
+clean
+
+select -assert-count 1 t:FDRE
+select -assert-count 1 t:LUT6
+select -assert-count 3 t:LUT2
+select -assert-none t:FDRE t:LUT6 t:LUT2 %% t:* %D
+
+design -load t0
+
+equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt -lut4
+design -load postopt
+clean
+
+select -assert-count 1 t:FDRE
+select -assert-count 1 t:LUT4
+select -assert-count 3 t:LUT2
+select -assert-none t:FDRE t:LUT4 t:LUT2 %% t:* %D
+
+design -reset
+
+
+read_verilog << EOT
+
+// FDSE, mergeable CE and S, inversions.
+
+module t0 (...);
+input wire clk;
+input wire [7:0] i;
+output wire [7:0] o;
+
+wire [7:0] tmp ;
+
+LUT2 #(.INIT(4'h6)) lut0 (.I0(i[0]), .I1(i[1]), .O(tmp[0]));
+LUT2 #(.INIT(4'h6)) lut1 (.I0(i[1]), .I1(i[2]), .O(tmp[1]));
+LUT2 #(.INIT(4'h6)) lut2 (.I0(i[3]), .I1(i[4]), .O(tmp[2]));
+
+FDSE #(.IS_D_INVERTED(1'b1), .IS_S_INVERTED(1'b1)) ff (.D(tmp[0]), .CE(tmp[1]), .S(tmp[2]), .Q(o[0]));
+
+endmodule
+
+EOT
+
+design -save t0
+
+equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt
+design -load postopt
+clean
+
+select -assert-count 1 t:FDSE
+select -assert-count 1 t:LUT6
+select -assert-count 3 t:LUT2
+select -assert-none t:FDSE t:LUT6 t:LUT2 %% t:* %D
+
+design -load t0
+
+equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt -lut4
+design -load postopt
+clean
+
+select -assert-count 1 t:FDSE
+select -assert-count 1 t:LUT4
+select -assert-count 3 t:LUT2
+select -assert-none t:FDSE t:LUT4 t:LUT2 %% t:* %D
+
+design -reset
+
+
+read_verilog << EOT
+
+// FDCE, mergeable CE.
+
+module t0 (...);
+input wire clk;
+input wire [7:0] i;
+output wire [7:0] o;
+
+wire [7:0] tmp ;
+
+LUT2 #(.INIT(4'h6)) lut0 (.I0(i[0]), .I1(i[1]), .O(tmp[0]));
+LUT2 #(.INIT(4'h6)) lut1 (.I0(i[1]), .I1(i[2]), .O(tmp[1]));
+LUT2 #(.INIT(4'h6)) lut2 (.I0(i[3]), .I1(i[4]), .O(tmp[2]));
+
+FDCE ff (.D(tmp[0]), .CE(tmp[1]), .CLR(tmp[2]), .Q(o[0]));
+
+endmodule
+
+EOT
+
+design -save t0
+
+equiv_opt -async2sync -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt
+design -load postopt
+clean
+
+select -assert-count 1 t:FDCE
+select -assert-count 1 t:LUT4
+select -assert-count 3 t:LUT2
+select -assert-none t:FDCE t:LUT4 t:LUT2 %% t:* %D
+
+design -reset
+
+
+read_verilog << EOT
+
+// FDSE, mergeable CE and S, but CE only not worth it.
+
+module t0 (...);
+input wire clk;
+input wire [7:0] i;
+output wire [7:0] o;
+
+wire [7:0] tmp ;
+
+LUT2 #(.INIT(4'h6)) lut0 (.I0(i[0]), .I1(i[1]), .O(tmp[0]));
+LUT2 #(.INIT(4'h6)) lut1 (.I0(i[1]), .I1(i[2]), .O(tmp[1]));
+
+FDSE ff (.D(tmp[0]), .CE(i[7]), .S(tmp[1]), .Q(o[0]));
+
+endmodule
+
+EOT
+
+design -save t0
+
+equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt
+design -load postopt
+clean
+
+select -assert-count 1 t:FDSE
+select -assert-count 1 t:LUT5
+select -assert-count 2 t:LUT2
+select -assert-none t:FDSE t:LUT5 t:LUT2 %% t:* %D
+
+design -load t0
+
+equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt -lut4
+design -load postopt
+clean
+
+select -assert-count 1 t:FDSE
+select -assert-count 2 t:LUT2
+select -assert-none t:FDSE t:LUT2 %% t:* %D
+
+design -reset
+
+
+read_verilog << EOT
+
+// FDRSE, mergeable CE, S, R.
+
+module t0 (...);
+input wire clk;
+input wire [7:0] i;
+output wire [7:0] o;
+
+wire [7:0] tmp ;
+
+LUT2 #(.INIT(4'h6)) lut0 (.I0(i[0]), .I1(i[1]), .O(tmp[0]));
+LUT2 #(.INIT(4'h6)) lut1 (.I0(i[1]), .I1(i[2]), .O(tmp[1]));
+LUT2 #(.INIT(4'h8)) lut2 (.I0(i[2]), .I1(i[0]), .O(tmp[2]));
+LUT2 #(.INIT(4'h6)) lut3 (.I0(i[3]), .I1(i[4]), .O(tmp[3]));
+
+FDRSE ff (.D(tmp[0]), .CE(tmp[1]), .S(tmp[2]), .R(tmp[3]), .Q(o[0]));
+
+endmodule
+
+EOT
+
+design -save t0
+
+equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt
+design -load postopt
+clean
+
+select -assert-count 1 t:FDRSE
+select -assert-count 1 t:LUT6
+select -assert-count 4 t:LUT2
+select -assert-none t:FDRSE t:LUT6 t:LUT2 %% t:* %D
+
+design -load t0
+
+equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt -lut4
+design -load postopt
+clean
+
+select -assert-count 1 t:FDRSE
+select -assert-count 1 t:LUT4
+select -assert-count 4 t:LUT2
+select -assert-none t:FDRSE t:LUT4 t:LUT2 %% t:* %D
+
+design -reset
diff --git a/tests/arch/xilinx/xilinx_dffopt_blacklist.txt b/tests/arch/xilinx/xilinx_dffopt_blacklist.txt
new file mode 100644
index 000000000..6a31a0cd3
--- /dev/null
+++ b/tests/arch/xilinx/xilinx_dffopt_blacklist.txt
@@ -0,0 +1,13 @@
+lut0
+lut1
+lut2
+lut3
+ff
+ff.D
+ff.R
+ff.S
+ff.CE
+ff.d
+ff.r
+ff.s
+ff.ce
diff --git a/tests/various/scratchpad.ys b/tests/various/scratchpad.ys
new file mode 100644
index 000000000..dc94081ea
--- /dev/null
+++ b/tests/various/scratchpad.ys
@@ -0,0 +1,5 @@
+scratchpad -set foo "bar baz"
+scratchpad -copy foo oof
+scratchpad -unset foo
+scratchpad -assert oof "bar baz"
+scratchpad -assert-unset foo