Merge remote-tracking branch 'origin/master' into xaig_dff

This commit is contained in:
Eddie Hung 2019-12-19 10:29:40 -08:00
commit 94f15f023c
47 changed files with 2053 additions and 184 deletions

View File

@ -50,9 +50,13 @@ Yosys 0.9 .. Yosys 0.9-dev
- "synth_ecp5" to now infer DSP blocks (-nodsp to disable, experimental) - "synth_ecp5" to now infer DSP blocks (-nodsp to disable, experimental)
- "synth_ice40 -dsp" to infer DSP blocks - "synth_ice40 -dsp" to infer DSP blocks
- Added latch support to synth_xilinx - 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 "check -mapped"
- Added checking of SystemVerilog always block types (always_comb, - Added checking of SystemVerilog always block types (always_comb,
always_latch and always_ff) always_latch and always_ff)
- Added "xilinx_dffopt" pass
- Added "scratchpad" pass
Yosys 0.8 .. Yosys 0.9 Yosys 0.8 .. Yosys 0.9
---------------------- ----------------------

View File

@ -1,7 +1,11 @@
This directory contains Verific bindings for Yosys. 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 Verific Features that should be enabled in your Verific library

View File

@ -2065,7 +2065,12 @@ struct VerificPass : public Pass {
log(" -d <dump_file>\n"); log(" -d <dump_file>\n");
log(" Dump the Verific netlist as a verilog file.\n"); log(" Dump the Verific netlist as a verilog file.\n");
log("\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"); log("\n");
} }
#ifdef YOSYS_ENABLE_VERIFIC #ifdef YOSYS_ENABLE_VERIFIC
@ -2074,7 +2079,13 @@ struct VerificPass : public Pass {
static bool set_verific_global_flags = true; static bool set_verific_global_flags = true;
if (check_noverific_env()) 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"); 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 */ #else /* YOSYS_ENABLE_VERIFIC */
void execute(std::vector<std::string>, RTLIL::Design *) YS_OVERRIDE { 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 #endif
} VerificPass; } VerificPass;

View File

@ -28,7 +28,7 @@
* *
* Ad-hoc implementation of a Verilog preprocessor. The directives `define, * Ad-hoc implementation of a Verilog preprocessor. The directives `define,
* `include, `ifdef, `ifndef, `else and `endif are handled here. All other * `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).
* *
*/ */

View File

@ -28,7 +28,7 @@
* *
* A simple lexer for Verilog code. Non-preprocessor compiler directives are * A simple lexer for Verilog code. Non-preprocessor compiler directives are
* handled here. The preprocessor stuff is handled in preproc.cc. Everything * 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).
* *
*/ */

View File

@ -93,7 +93,7 @@ frontends/verilog/preproc.cc} in the Yosys source tree.
\begin{sloppypar} \begin{sloppypar}
The Verilog Lexer is written using the lexer generator {\it flex} \citeweblink{flex}. Its source code 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 The lexer does little more than identifying all keywords and literals
recognised by the Yosys Verilog frontend. recognised by the Yosys Verilog frontend.
\end{sloppypar} \end{sloppypar}
@ -115,7 +115,7 @@ whenever possible.)
\subsection{The Verilog Parser} \subsection{The Verilog Parser}
The Verilog Parser is written using the parser generator {\it bison} \citeweblink{bison}. Its source code 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 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 defined in {\tt frontends/ast/ast.h}. An \lstinline[language=C++]{AST::AstNode} object has

View File

@ -146,7 +146,7 @@ with the help of HDL synthesis tools.
In special cases such as synthesis for coarse-grain cell libraries or when 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 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 availability of a Free and Open Source (FOSS) synthesis tool that can be used
as basis for custom tools would be helpful. as basis for custom tools would be helpful.

View File

@ -32,3 +32,4 @@ OBJS += passes/cmds/chtype.o
OBJS += passes/cmds/blackbox.o OBJS += passes/cmds/blackbox.o
OBJS += passes/cmds/ltp.o OBJS += passes/cmds/ltp.o
OBJS += passes/cmds/bugpoint.o OBJS += passes/cmds/bugpoint.o
OBJS += passes/cmds/scratchpad.o

130
passes/cmds/scratchpad.cc Normal file
View File

@ -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

View File

@ -44,6 +44,10 @@ struct EquivOptPass:public ScriptPass
log(" expand the modules in this file before proving equivalence. this is\n"); log(" expand the modules in this file before proving equivalence. this is\n");
log(" useful for handling architecture-specific primitives.\n"); log(" useful for handling architecture-specific primitives.\n");
log("\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(" -assert\n");
log(" produce an error if the circuits are not equivalent.\n"); log(" produce an error if the circuits are not equivalent.\n");
log("\n"); log("\n");
@ -61,13 +65,14 @@ struct EquivOptPass:public ScriptPass
log("\n"); log("\n");
} }
std::string command, techmap_opts; std::string command, techmap_opts, make_opts;
bool assert, undef, multiclock, async2sync; bool assert, undef, multiclock, async2sync;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
command = ""; command = "";
techmap_opts = ""; techmap_opts = "";
make_opts = "";
assert = false; assert = false;
undef = false; undef = false;
multiclock = false; multiclock = false;
@ -93,6 +98,10 @@ struct EquivOptPass:public ScriptPass
techmap_opts += " -map " + args[++argidx]; techmap_opts += " -map " + args[++argidx];
continue; continue;
} }
if (args[argidx] == "-blacklist" && argidx + 1 < args.size()) {
make_opts += " -blacklist " + args[++argidx];
continue;
}
if (args[argidx] == "-assert") { if (args[argidx] == "-assert") {
assert = true; assert = true;
continue; continue;
@ -170,7 +179,12 @@ struct EquivOptPass:public ScriptPass
run("clk2fflogic", "(only with -multiclock)"); run("clk2fflogic", "(only with -multiclock)");
if (async2sync || help_mode) if (async2sync || help_mode)
run("async2sync", " (only with -async2sync)"); 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) if (help_mode)
run("equiv_induct [-undef] equiv"); run("equiv_induct [-undef] equiv");
else if (undef) else if (undef)

View File

@ -134,6 +134,7 @@ struct rules_t
dict<string, int> min_limits, max_limits; dict<string, int> min_limits, max_limits;
bool or_next_if_better, make_transp, make_outreg; bool or_next_if_better, make_transp, make_outreg;
char shuffle_enable; char shuffle_enable;
vector<vector<std::tuple<bool,IdString,Const>>> attributes;
}; };
dict<IdString, vector<bram_t>> brams; dict<IdString, vector<bram_t>> brams;
@ -327,6 +328,20 @@ struct rules_t
continue; 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(); syntax_error();
} }
} }
@ -724,7 +739,7 @@ grow_read_ports:;
if (match.make_transp && wr_ports <= 1) { if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true; pi.make_transp = true;
if (pi.clocks != 0) { 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); 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; goto skip_bram_rport;
} }
@ -813,6 +828,43 @@ grow_read_ports:;
return false; 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) if (mode == 1)
return true; return true;
} }
@ -1100,6 +1152,43 @@ void handle_cell(Cell *cell, const rules_t &rules)
goto next_match_rule; 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); 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()) 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(" dcells ....... number of cells in 'data-direction'\n");
log(" cells ........ total number of cells (acells*dcells*dups)\n"); log(" cells ........ total number of cells (acells*dcells*dups)\n");
log("\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("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("description. Use 'techmap' to convert the created bram instances into\n");
log("instances of the actual bram cells of your target architecture.\n"); log("instances of the actual bram cells of your target architecture.\n");

View File

@ -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()); 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_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); cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
if (assign_map(cell->getPort(ID::A)).is_fully_zero()) { if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
cell->setPort(ID::A, cell->getPort(ID::B)); cell->setPort(ID::A, cell->getPort(ID::B));

View File

@ -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_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 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_ff.vh"
`include "cells_io.vh" `include "cells_io.vh"

View File

@ -79,6 +79,9 @@ struct SynthEcp5Pass : public ScriptPass
log(" -nowidelut\n"); log(" -nowidelut\n");
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n"); log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
log("\n"); log("\n");
log(" -asyncprld\n");
log(" use async PRLD mode to implement DLATCH and DFFSR (EXPERIMENTAL)\n");
log("\n");
log(" -abc2\n"); log(" -abc2\n");
log(" run two passes of 'abc' for slightly improved logic density\n"); log(" run two passes of 'abc' for slightly improved logic density\n");
log("\n"); log("\n");
@ -99,7 +102,7 @@ struct SynthEcp5Pass : public ScriptPass
} }
string top_opt, blif_file, edif_file, json_file; 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 void clear_flags() YS_OVERRIDE
{ {
@ -112,6 +115,7 @@ struct SynthEcp5Pass : public ScriptPass
nobram = false; nobram = false;
nolutram = false; nolutram = false;
nowidelut = false; nowidelut = false;
asyncprld = false;
flatten = true; flatten = true;
retime = false; retime = false;
abc2 = false; abc2 = false;
@ -176,6 +180,10 @@ struct SynthEcp5Pass : public ScriptPass
nobram = true; nobram = true;
continue; continue;
} }
if (args[argidx] == "-asyncprld") {
asyncprld = true;
continue;
}
if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") { if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
nolutram = true; nolutram = true;
continue; continue;
@ -292,7 +300,7 @@ struct SynthEcp5Pass : public ScriptPass
run("opt_clean"); run("opt_clean");
if (!nodffe) if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); 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("opt_expr -undriven -mux_undef");
run("simplemap"); run("simplemap");
run("ecp5_ffinit"); run("ecp5_ffinit");
@ -306,10 +314,11 @@ struct SynthEcp5Pass : public ScriptPass
if (abc2 || help_mode) { if (abc2 || help_mode) {
run("abc", " (only if -abc2)"); 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) if (abc9)
techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1"; techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1";
run("techmap " + techmap_args); if (!asyncprld || abc9)
run("techmap " + techmap_args);
if (abc9) { if (abc9) {
run("read_verilog -icells -lib +/ecp5/abc9_model.v"); run("read_verilog -icells -lib +/ecp5/abc9_model.v");

View File

@ -1,5 +1,6 @@
OBJS += techlibs/xilinx/synth_xilinx.o OBJS += techlibs/xilinx/synth_xilinx.o
OBJS += techlibs/xilinx/xilinx_dffopt.o
GENFILES += techlibs/xilinx/brams_init_36.vh GENFILES += techlibs/xilinx/brams_init_36.vh
GENFILES += techlibs/xilinx/brams_init_32.vh GENFILES += techlibs/xilinx/brams_init_32.vh

View File

@ -28,6 +28,33 @@ module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_ _TECHMAP_REPL
(* techmap_celltype = "$_DFF_PN1_" *) (* 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 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); module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0; parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0; parameter [DEPTH-1:0] INIT = 0;

View File

@ -320,6 +320,41 @@ module FDRE_1 (
always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D; always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D;
endmodule 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 *) (* abc9_box_id=1003, lib_whitebox, abc9_flop *)
module FDCE ( module FDCE (
(* abc9_arrival=303 *) (* abc9_arrival=303 *)
@ -1193,10 +1228,10 @@ module RAM64M (
output DOB, output DOB,
output DOC, output DOC,
output DOD, output DOD,
input [4:0] ADDRA, input [5:0] ADDRA,
input [4:0] ADDRB, input [5:0] ADDRB,
input [4:0] ADDRC, input [5:0] ADDRC,
input [4:0] ADDRD, input [5:0] ADDRD,
input DIA, input DIA,
input DIB, input DIB,
input DIC, input DIC,
@ -1238,14 +1273,14 @@ module RAM64M8 (
output DOF, output DOF,
output DOG, output DOG,
output DOH, output DOH,
input [4:0] ADDRA, input [5:0] ADDRA,
input [4:0] ADDRB, input [5:0] ADDRB,
input [4:0] ADDRC, input [5:0] ADDRC,
input [4:0] ADDRD, input [5:0] ADDRD,
input [4:0] ADDRE, input [5:0] ADDRE,
input [4:0] ADDRF, input [5:0] ADDRF,
input [4:0] ADDRG, input [5:0] ADDRG,
input [4:0] ADDRH, input [5:0] ADDRH,
input DIA, input DIA,
input DIB, input DIB,
input DIC, input DIC,

View File

@ -66,7 +66,7 @@ CELLS = [
# CLB -- registers/latches. # CLB -- registers/latches.
# Virtex 1/2/4/5, Spartan 3. # Virtex 1/2/4/5, Spartan 3.
Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}), 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']}), Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}),
# Virtex 6, Spartan 6, Series 7, Ultrascale. # Virtex 6, Spartan 6, Series 7, Ultrascale.
# Cell('FDCE'), # Cell('FDCE'),

View File

@ -17,27 +17,6 @@ module FDCPE (...);
input PRE; input PRE;
endmodule 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 (...); module LDCPE (...);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_CLR_INVERTED = 1'b0; parameter [0:0] IS_CLR_INVERTED = 1'b0;

View File

@ -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 bram $__XILINX_RAM32X1D
init 1 init 1
abits 5 abits 5
@ -38,6 +51,70 @@ bram $__XILINX_RAM128X1D
clkpol 0 2 clkpol 0 2
endbram 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 match $__XILINX_RAM32X1D
min bits 3 min bits 3
min wports 1 min wports 1
@ -56,5 +133,35 @@ match $__XILINX_RAM128X1D
min bits 9 min bits 9
min wports 1 min wports 1
make_outreg make_outreg
or_next_if_better
endmatch 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

View File

@ -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); module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
parameter [31:0] INIT = 32'bx; parameter [31:0] INIT = 32'bx;
parameter CLKPOL2 = 1; parameter CLKPOL2 = 1;
@ -95,3 +127,153 @@ module \$__XILINX_RAM128X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
); );
endmodule 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

View File

@ -445,6 +445,16 @@ struct SynthXilinxPass : public ScriptPass
} }
if (check_label("map_ffram")) { 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) if (widemux > 0)
run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
// performs less efficiently // performs less efficiently
@ -454,14 +464,11 @@ struct SynthXilinxPass : public ScriptPass
} }
if (check_label("fine")) { if (check_label("fine")) {
run("dffsr2dff"); run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
run("dff2dffe");
if (help_mode) { if (help_mode) {
run("simplemap t:$mux", " ('-widemux' only)");
run("muxcover <internal options>, ('-widemux' only)"); run("muxcover <internal options>, ('-widemux' only)");
} }
else if (widemux > 0) { else if (widemux > 0) {
run("simplemap t:$mux");
constexpr int cost_mux2 = 100; constexpr int cost_mux2 = 100;
std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2); std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
switch (widemux) { switch (widemux) {
@ -563,6 +570,7 @@ struct SynthXilinxPass : public ScriptPass
else if (!abc9) else if (!abc9)
techmap_args += stringf(" -map %s", ff_map_file.c_str()); techmap_args += stringf(" -map %s", ff_map_file.c_str());
run("techmap " + techmap_args, "(option without '-abc9')"); run("techmap " + techmap_args, "(option without '-abc9')");
run("xilinx_dffopt");
} }
if (check_label("finalize")) { if (check_label("finalize")) {

View File

@ -27,6 +27,8 @@
`ifndef _NO_FFS `ifndef _NO_FFS
// No reset.
module \$_DFF_N_ (input D, C, output Q); module \$_DFF_N_ (input D, C, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -46,6 +48,8 @@ module \$_DFF_P_ (input D, C, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
// No reset, enable.
module \$_DFFE_NP_ (input D, C, E, output Q); module \$_DFFE_NP_ (input D, C, E, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -65,15 +69,8 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); // Async reset.
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));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); module \$_DFF_NP0_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -83,15 +80,6 @@ module \$_DFF_NP0_ (input D, C, R, output Q);
endgenerate endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
module \$_DFF_PN0_ (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 #(.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_PP0_ (input D, C, R, output Q); module \$_DFF_PP0_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -102,15 +90,6 @@ module \$_DFF_PP0_ (input D, C, R, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
module \$_DFF_NN1_ (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_NP1_ (input D, C, R, output Q); module \$_DFF_NP1_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
@ -120,15 +99,6 @@ module \$_DFF_NP1_ (input D, C, R, output Q);
endgenerate endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
module \$_DFF_PN1_ (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
module \$_DFF_PP1_ (input D, C, R, output Q); module \$_DFF_PP1_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
@ -139,6 +109,128 @@ module \$_DFF_PP1_ (input D, C, R, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule 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_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 \$__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(E), .CLR( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
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(E), .PRE( R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
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 #(.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 \$__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 set initialized to 0");
else
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 \$__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 set initialized to 0");
else
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); module \$_DLATCH_N_ (input E, D, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx; parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -158,5 +250,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
// Latches with reset (TODO).
`endif `endif

View File

@ -37,6 +37,8 @@
`ifndef _NO_FFS `ifndef _NO_FFS
// No reset.
module \$_DFF_N_ (input D, C, output Q); module \$_DFF_N_ (input D, C, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx; 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)); 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; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
// No reset, enable.
module \$_DFFE_NP_ (input D, C, E, output Q); module \$_DFFE_NP_ (input D, C, E, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx; 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)); FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0));
@ -59,48 +63,104 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); // Async reset.
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));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); module \$_DFF_NP0_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx; 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; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
module \$_DFF_PN0_ (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));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); module \$_DFF_PP0_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx; parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
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(1'b1), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
module \$_DFF_NN1_ (input D, C, 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));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); module \$_DFF_NP1_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx; 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)); FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
module \$_DFF_PN1_ (input D, C, 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));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); module \$_DFF_PP1_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx; 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(1'b1), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
// Async reset, enable.
module \$__DFFE_NP0 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
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 \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
module \$__DFFE_NP1 (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(E), .PRE( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
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(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); module \$_DLATCH_N_ (input E, D, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx; parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
LDCE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(1'b0)); LDCE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(1'b0));
@ -112,5 +172,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1; wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule endmodule
// Latches with reset (TODO).
`endif `endif

View File

@ -1,4 +1,3 @@
bram $__XILINX_RAMB36_SDP bram $__XILINX_RAMB36_SDP
init 1 init 1
abits 9 abits 9
@ -72,8 +71,33 @@ bram $__XILINX_RAMB18_TDP
clkpol 2 3 clkpol 2 3
endbram 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 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
attribute !ram_style
attribute !logic_block
min bits 1024
min efficiency 5 min efficiency 5
shuffle_enable B shuffle_enable B
make_transp make_transp
@ -81,7 +105,17 @@ match $__XILINX_RAMB36_SDP
endmatch endmatch
match $__XILINX_RAMB18_SDP match $__XILINX_RAMB18_SDP
min bits 4096 attribute ram_style=block ram_block
attribute !logic_block
shuffle_enable B
make_transp
or_next_if_better
endmatch
match $__XILINX_RAMB36_TDP
attribute !ram_style
attribute !logic_block
min bits 1024
min efficiency 5 min efficiency 5
shuffle_enable B shuffle_enable B
make_transp make_transp
@ -89,7 +123,17 @@ match $__XILINX_RAMB18_SDP
endmatch endmatch
match $__XILINX_RAMB36_TDP match $__XILINX_RAMB36_TDP
min bits 4096 attribute ram_style=block ram_block
attribute !logic_block
shuffle_enable B
make_transp
or_next_if_better
endmatch
match $__XILINX_RAMB18_TDP
attribute !ram_style
attribute !logic_block
min bits 1024
min efficiency 5 min efficiency 5
shuffle_enable B shuffle_enable B
make_transp make_transp
@ -97,8 +141,8 @@ match $__XILINX_RAMB36_TDP
endmatch endmatch
match $__XILINX_RAMB18_TDP match $__XILINX_RAMB18_TDP
min bits 4096 attribute ram_style=block ram_block
min efficiency 5 attribute !logic_block
shuffle_enable B shuffle_enable B
make_transp make_transp
endmatch endmatch

View File

@ -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

View File

@ -1,5 +1,5 @@
read_verilog ../common/memory.v read_verilog ../common/lutram.v
hierarchy -top top hierarchy -top lutram_1w1r
proc proc
memory -nomap memory -nomap
equiv_opt -run :prove -map +/anlogic/cells_sim.v synth_anlogic 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 #sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
design -load postopt design -load postopt
cd top cd lutram_1w1r
select -assert-count 8 t:AL_MAP_LUT2 select -assert-count 8 t:AL_MAP_LUT2
select -assert-count 8 t:AL_MAP_LUT4 select -assert-count 8 t:AL_MAP_LUT4

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
read_verilog ../common/memory.v read_verilog ../common/lutram.v
hierarchy -top top hierarchy -top lutram_1w1r
proc proc
memory -nomap memory -nomap
equiv_opt -run :prove -map +/ecp5/cells_sim.v synth_ecp5 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 sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt design -load postopt
cd top cd lutram_1w1r
select -assert-count 24 t:L6MUX21 select -assert-count 24 t:L6MUX21
select -assert-count 71 t:LUT4 select -assert-count 71 t:LUT4
select -assert-count 32 t:PFUMX select -assert-count 32 t:PFUMX

View File

@ -1,5 +1,5 @@
read_verilog ../common/memory.v read_verilog ../common/lutram.v
hierarchy -top top hierarchy -top lutram_1w1r
proc proc
memory -nomap memory -nomap
equiv_opt -run :prove -map +/efinix/cells_sim.v synth_efinix 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 sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt design -load postopt
cd top cd lutram_1w1r
select -assert-count 1 t:EFX_GBUFCE select -assert-count 1 t:EFX_GBUFCE
select -assert-count 1 t:EFX_RAM_5K select -assert-count 1 t:EFX_RAM_5K
select -assert-none t:EFX_GBUFCE t:EFX_RAM_5K %% t:* %D select -assert-none t:EFX_GBUFCE t:EFX_RAM_5K %% t:* %D

View File

@ -1,5 +1,5 @@
read_verilog ../common/memory.v read_verilog ../common/lutram.v
hierarchy -top top hierarchy -top lutram_1w1r
proc proc
memory -nomap memory -nomap
equiv_opt -run :prove -map +/gowin/cells_sim.v synth_gowin 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 sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt design -load postopt
cd top cd lutram_1w1r
select -assert-count 8 t:RAM16S4 select -assert-count 8 t:RAM16S4
# other logic present that is not simple # other logic present that is not simple
#select -assert-none t:RAM16S4 %% t:* %D #select -assert-none t:RAM16S4 %% t:* %D

View File

@ -1,5 +1,5 @@
read_verilog ../common/memory.v read_verilog ../common/lutram.v
hierarchy -top top hierarchy -top lutram_1w1r
proc proc
memory -nomap memory -nomap
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40 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 sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt design -load postopt
cd top cd lutram_1w1r
select -assert-count 1 t:SB_RAM40_4K select -assert-count 1 t:SB_RAM40_4K
select -assert-none t:SB_RAM40_4K %% t:* %D select -assert-none t:SB_RAM40_4K %% t:* %D

View File

@ -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) 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 cd dffs # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG select -assert-count 1 t:BUFG
select -assert-count 1 t:FDRE select -assert-count 1 t:FDSE
select -assert-count 1 t:LUT2
select -assert-none t:BUFG t:FDRE t:LUT2 %% t:* %D select -assert-none t:BUFG t:FDSE %% t:* %D
design -load read 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 cd ndffnr # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG select -assert-count 1 t:BUFG
select -assert-count 1 t:FDRE_1 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 cd fsm # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG select -assert-count 1 t:BUFG
select -assert-count 5 t:FDRE select -assert-count 4 t:FDRE
select -assert-count 1 t:LUT3 select -assert-count 1 t:FDSE
select -assert-count 2 t:LUT4 select -assert-count 1 t:LUT2
select -assert-count 4 t:LUT6 select -assert-count 3 t:LUT5
select -assert-none t:BUFG t:FDRE t:LUT3 t:LUT4 t:LUT6 %% t:* %D select -assert-count 1 t:LUT6
select -assert-none t:BUFG t:FDRE t:FDSE t:LUT2 t:LUT5 t:LUT6 %% t:* %D

137
tests/arch/xilinx/lutram.ys Normal file
View File

@ -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

View File

@ -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 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) 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 cd macc2 # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG select -assert-count 1 t:BUFG
select -assert-count 1 t:DSP48E1 select -assert-count 1 t:DSP48E1
select -assert-count 1 t:FDRE select -assert-count 1 t:FDRE
select -assert-count 1 t:LUT2 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 select -assert-none t:BUFG t:DSP48E1 t:FDRE t:LUT2 t:LUT3 %% t:* %D

View File

@ -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

View File

@ -40,6 +40,8 @@ proc
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check 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) 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 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

View File

@ -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

View File

@ -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

View File

@ -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