Merge branch 'master' of github.com:YosysHQ/yosys

This commit is contained in:
Eddie Hung 2019-12-18 12:08:38 -08:00
commit d0afe4e10d
24 changed files with 1093 additions and 106 deletions

View File

@ -50,9 +50,12 @@ 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
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

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

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

@ -329,6 +329,41 @@ module FDSE (
endcase endgenerate endcase endgenerate
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
module FDCE ( module FDCE (
(* abc9_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,

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

@ -444,6 +444,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
@ -453,14 +463,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 else
techmap_args += " -map " + ff_map_file; techmap_args += " -map " + ff_map_file;
run("techmap " + techmap_args); run("techmap " + techmap_args);
run("xilinx_dffopt");
run("clean"); run("clean");
} }

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

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

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

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

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

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