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

This commit is contained in:
N. Engelhardt 2020-01-03 12:28:48 +01:00
commit 341fd872b5
122 changed files with 4391 additions and 713 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_ice40 -dsp" to infer DSP blocks
- Added latch support to synth_xilinx
- Added support for flip-flops with synchronous reset to synth_xilinx
- Added support for flip-flops with reset and enable to synth_xilinx
- Added "check -mapped"
- Added checking of SystemVerilog always block types (always_comb,
always_latch and always_ff)
- Added "xilinx_dffopt" pass
- Added "scratchpad" pass
Yosys 0.8 .. Yosys 0.9
----------------------

View File

@ -152,7 +152,15 @@ ifeq ($(ENABLE_PYOSYS),1)
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
PYTHON_PREFIX := $(shell $(PYTHON_EXECUTABLE)-config --prefix)
ENABLE_PYTHON_CONFIG_EMBED ?= $(shell $(PYTHON_EXECUTABLE)-config --embed --libs > /dev/null && echo 1)
ifeq ($(ENABLE_PYTHON_CONFIG_EMBED),1)
PYTHON_CONFIG := $(PYTHON_EXECUTABLE)-config --embed
else
PYTHON_CONFIG := $(PYTHON_EXECUTABLE)-config
endif
PYTHON_PREFIX := $(shell $(PYTHON_CONFIG) --prefix)
PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
# Reload Makefile.conf to override python specific variables if defined
@ -305,17 +313,17 @@ ifeq ($(ENABLE_PYOSYS),1)
#Detect name of boost_python library. Some distros usbe boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
ifeq ($(OS), Darwin)
BOOST_PYTHON_LIB ?= $(shell \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_CONFIG) --ldflags) -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_CONFIG) --ldflags) -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_CONFIG) --ldflags) -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_CONFIG) --ldflags) -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
echo ""; fi; fi; fi; fi;)
else
BOOST_PYTHON_LIB ?= $(shell \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_CONFIG) --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_CONFIG) --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_CONFIG) --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_CONFIG) --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
echo ""; fi; fi; fi; fi;)
endif
@ -325,19 +333,19 @@ endif
ifeq ($(OS), Darwin)
ifeq ($(PYTHON_MAJOR_VERSION),3)
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
LDLIBS += $(shell $(PYTHON_CONFIG) --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
else
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
LDLIBS += $(shell $(PYTHON_CONFIG) --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
endif
else
ifeq ($(PYTHON_MAJOR_VERSION),3)
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
LDLIBS += $(shell $(PYTHON_CONFIG) --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
else
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
LDLIBS += $(shell $(PYTHON_CONFIG) --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
endif
endif

View File

@ -454,10 +454,10 @@ Verilog Attributes and non-standard features
expressions over parameters and constant values are allowed). The intended
use for this is synthesis-time DRC.
- There is limited support for converting specify .. endspecify statements to
special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
functionality. (By default specify .. endspecify blocks are ignored.)
- There is limited support for converting ``specify`` .. ``endspecify``
statements to special ``$specify2``, ``$specify3``, and ``$specrule`` cells,
for use in blackboxes and whiteboxes. Use ``read_verilog -specify`` to
enable this functionality. (By default these blocks are ignored.)
Non-standard or SystemVerilog features for formal verification

View File

@ -81,8 +81,7 @@ struct XAigerWriter
pool<SigBit> input_bits, output_bits;
dict<SigBit, SigBit> not_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map;
vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
vector<SigBit> ci_bits, co_bits;
dict<SigBit, float> arrival_times;
vector<pair<int, int>> aig_gates;
@ -367,7 +366,6 @@ struct XAigerWriter
cell->setPort(port_name, rhs);
}
int offset = 0;
for (auto b : rhs.bits()) {
SigBit I = sigmap(b);
if (b == RTLIL::Sx)
@ -378,7 +376,7 @@ struct XAigerWriter
else
alias_map[b] = I;
}
co_bits.emplace_back(b, cell, port_name, offset++, 0);
co_bits.emplace_back(b);
unused_bits.erase(b);
}
}
@ -398,9 +396,8 @@ struct XAigerWriter
cell->setPort(port_name, rhs);
}
int offset = 0;
for (const auto &b : rhs.bits()) {
ci_bits.emplace_back(b, cell, port_name, offset++);
ci_bits.emplace_back(b);
SigBit O = sigmap(b);
if (O != b)
alias_map[O] = b;
@ -487,15 +484,13 @@ struct XAigerWriter
aig_map[bit] = 2*aig_m;
}
for (auto &c : ci_bits) {
RTLIL::SigBit bit = std::get<0>(c);
for (auto bit : ci_bits) {
aig_m++, aig_i++;
aig_map[bit] = 2*aig_m;
}
for (auto &c : co_bits) {
RTLIL::SigBit bit = std::get<0>(c);
std::get<4>(c) = ordered_outputs[bit] = aig_o++;
for (auto bit : co_bits) {
ordered_outputs[bit] = aig_o++;
aig_outputs.push_back(bit2aig(bit));
}
@ -508,7 +503,6 @@ struct XAigerWriter
ordered_outputs[bit] = aig_o++;
aig_outputs.push_back(bit2aig(bit));
}
}
void write_aiger(std::ostream &f, bool ascii_mode)
@ -605,25 +599,46 @@ struct XAigerWriter
RTLIL::Module *holes_module = module->design->addModule("$__holes__");
log_assert(holes_module);
dict<IdString, Cell*> cell_cache;
int port_id = 1;
int box_count = 0;
for (auto cell : box_list) {
RTLIL::Module* box_module = module->design->module(cell->type);
RTLIL::Module* orig_box_module = module->design->module(cell->type);
log_assert(orig_box_module);
IdString derived_name = orig_box_module->derive(module->design, cell->parameters);
RTLIL::Module* box_module = module->design->module(derived_name);
if (box_module->has_processes())
log_error("ABC9 box '%s' contains processes!\n", box_module->name.c_str());
int box_inputs = 0, box_outputs = 0;
Cell *holes_cell = nullptr;
if (box_module->get_bool_attribute("\\whitebox")) {
auto r = cell_cache.insert(std::make_pair(derived_name, nullptr));
Cell *holes_cell = r.first->second;
if (r.second && box_module->get_bool_attribute("\\whitebox")) {
holes_cell = holes_module->addCell(cell->name, cell->type);
holes_cell->parameters = cell->parameters;
r.first->second = holes_cell;
// Since Module::derive() will create a new module, there
// is a chance that the ports will be alphabetically ordered
// again, which is a problem when carry-chains are involved.
// Inherit the port ordering from the original module here...
// (and set the port_id below, when iterating through those)
log_assert(GetSize(box_module->ports) == GetSize(orig_box_module->ports));
box_module->ports = orig_box_module->ports;
}
// NB: Assume box_module->ports are sorted alphabetically
// (as RTLIL::Module::fixup_ports() would do)
int box_port_id = 1;
for (const auto &port_name : box_module->ports) {
RTLIL::Wire *w = box_module->wire(port_name);
log_assert(w);
if (r.second)
w->port_id = box_port_id++;
RTLIL::Wire *holes_wire;
RTLIL::SigSpec port_wire;
if (w->port_input) {
RTLIL::SigSpec port_sig;
if (w->port_input)
for (int i = 0; i < GetSize(w); i++) {
box_inputs++;
holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
@ -634,28 +649,29 @@ struct XAigerWriter
holes_module->ports.push_back(holes_wire->name);
}
if (holes_cell)
port_wire.append(holes_wire);
port_sig.append(holes_wire);
}
if (!port_wire.empty())
holes_cell->setPort(w->name, port_wire);
}
if (w->port_output) {
box_outputs += GetSize(w);
for (int i = 0; i < GetSize(w); i++) {
if (GetSize(w) == 1)
holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), w->name.c_str()));
holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), log_id(w->name)));
else
holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), w->name.c_str(), i));
holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), log_id(w->name), i));
holes_wire->port_output = true;
holes_wire->port_id = port_id++;
holes_module->ports.push_back(holes_wire->name);
if (holes_cell)
port_wire.append(holes_wire);
port_sig.append(holes_wire);
else
holes_module->connect(holes_wire, State::S0);
}
if (!port_wire.empty())
holes_cell->setPort(w->name, port_wire);
}
if (!port_sig.empty()) {
if (r.second)
holes_cell->setPort(w->name, port_sig);
else
holes_module->connect(holes_cell->getPort(w->name), port_sig);
}
}
@ -685,14 +701,11 @@ struct XAigerWriter
RTLIL::Selection& sel = holes_module->design->selection_stack.back();
sel.select(holes_module);
// TODO: Should not need to opt_merge if we only instantiate
// each box type once...
Pass::call(holes_module->design, "opt_merge -share_all");
Pass::call(holes_module->design, "flatten -wb");
// TODO: Should techmap/aigmap/check all lib_whitebox-es just once,
// instead of per write_xaiger call
// Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
// since boxes may contain parameters in which case `flatten` would have
// created a new $paramod ...
Pass::call(holes_module->design, "techmap");
Pass::call(holes_module->design, "aigmap");
for (auto cell : holes_module->cells())

View File

@ -1198,6 +1198,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf = new AstNode(AST_LOCALPARAM, varbuf);
varbuf->str = init_ast->children[0]->str;
auto resolved = current_scope.at(init_ast->children[0]->str);
if (resolved->range_valid) {
varbuf->range_left = resolved->range_left;
varbuf->range_right = resolved->range_right;
varbuf->range_swapped = resolved->range_swapped;
varbuf->range_valid = resolved->range_valid;
}
AstNode *backup_scope_varbuf = current_scope[varbuf->str];
current_scope[varbuf->str] = varbuf;
@ -2998,6 +3006,14 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
current_ast_mod->children.push_back(p);
str = p->str;
id2ast = p;
auto resolved = current_scope.at(index_var);
if (resolved->range_valid) {
p->range_left = resolved->range_left;
p->range_right = resolved->range_right;
p->range_swapped = resolved->range_swapped;
p->range_valid = resolved->range_valid;
}
}
}

View File

@ -1,7 +1,11 @@
This directory contains Verific bindings for Yosys.
See http://www.verific.com/ for details.
Use Symbiotic EDA Suite if you need Yosys+Verifc.
https://www.symbioticeda.com/seda-suite
Contact office@symbioticeda.com for free evaluation
binaries of Symbiotic EDA Suite.
Verific Features that should be enabled in your Verific library

View File

@ -2065,7 +2065,12 @@ struct VerificPass : public Pass {
log(" -d <dump_file>\n");
log(" Dump the Verific netlist as a verilog file.\n");
log("\n");
log("Visit http://verific.com/ for more information on Verific.\n");
log("\n");
log("Use Symbiotic EDA Suite if you need Yosys+Verifc.\n");
log("https://www.symbioticeda.com/seda-suite\n");
log("\n");
log("Contact office@symbioticeda.com for free evaluation\n");
log("binaries of Symbiotic EDA Suite.\n");
log("\n");
}
#ifdef YOSYS_ENABLE_VERIFIC
@ -2074,7 +2079,13 @@ struct VerificPass : public Pass {
static bool set_verific_global_flags = true;
if (check_noverific_env())
log_cmd_error("This version of Yosys is built without Verific support.\n");
log_cmd_error("This version of Yosys is built without Verific support.\n"
"\n"
"Use Symbiotic EDA Suite if you need Yosys+Verifc.\n"
"https://www.symbioticeda.com/seda-suite\n"
"\n"
"Contact office@symbioticeda.com for free evaluation\n"
"binaries of Symbiotic EDA Suite.\n");
log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n");
@ -2493,7 +2504,13 @@ struct VerificPass : public Pass {
}
#else /* YOSYS_ENABLE_VERIFIC */
void execute(std::vector<std::string>, RTLIL::Design *) YS_OVERRIDE {
log_cmd_error("This version of Yosys is built without Verific support.\n");
log_cmd_error("This version of Yosys is built without Verific support.\n"
"\n"
"Use Symbiotic EDA Suite if you need Yosys+Verifc.\n"
"https://www.symbioticeda.com/seda-suite\n"
"\n"
"Contact office@symbioticeda.com for free evaluation\n"
"binaries of Symbiotic EDA Suite.\n");
}
#endif
} VerificPass;

View File

@ -28,7 +28,7 @@
*
* Ad-hoc implementation of a Verilog preprocessor. The directives `define,
* `include, `ifdef, `ifndef, `else and `endif are handled here. All other
* directives are handled by the lexer (see lexer.l).
* directives are handled by the lexer (see verilog_lexer.l).
*
*/

View File

@ -28,7 +28,7 @@
*
* A simple lexer for Verilog code. Non-preprocessor compiler directives are
* handled here. The preprocessor stuff is handled in preproc.cc. Everything
* else is left to the bison parser (see parser.y).
* else is left to the bison parser (see verilog_parser.y).
*
*/

View File

@ -1893,10 +1893,6 @@ DEF_METHOD(And, max(sig_a.size(), sig_b.size()), ID($and))
DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), ID($or))
DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), ID($xor))
DEF_METHOD(Xnor, max(sig_a.size(), sig_b.size()), ID($xnor))
DEF_METHOD(Shl, sig_a.size(), ID($shl))
DEF_METHOD(Shr, sig_a.size(), ID($shr))
DEF_METHOD(Sshl, sig_a.size(), ID($sshl))
DEF_METHOD(Sshr, sig_a.size(), ID($sshr))
DEF_METHOD(Shift, sig_a.size(), ID($shift))
DEF_METHOD(Shiftx, sig_a.size(), ID($shiftx))
DEF_METHOD(Lt, 1, ID($lt))
@ -1916,6 +1912,31 @@ DEF_METHOD(LogicAnd, 1, ID($logic_and))
DEF_METHOD(LogicOr, 1, ID($logic_or))
#undef DEF_METHOD
#define DEF_METHOD(_func, _y_size, _type) \
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->parameters[ID(A_SIGNED)] = is_signed; \
cell->parameters[ID(B_SIGNED)] = false; \
cell->parameters[ID(A_WIDTH)] = sig_a.size(); \
cell->parameters[ID(B_WIDTH)] = sig_b.size(); \
cell->parameters[ID(Y_WIDTH)] = sig_y.size(); \
cell->setPort(ID::A, sig_a); \
cell->setPort(ID::B, sig_b); \
cell->setPort(ID::Y, sig_y); \
cell->set_src_attribute(src); \
return cell; \
} \
RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed, const std::string &src) { \
RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \
add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \
return sig_y; \
}
DEF_METHOD(Shl, sig_a.size(), ID($shl))
DEF_METHOD(Shr, sig_a.size(), ID($shr))
DEF_METHOD(Sshl, sig_a.size(), ID($sshl))
DEF_METHOD(Sshr, sig_a.size(), ID($sshr))
#undef DEF_METHOD
#define DEF_METHOD(_func, _type, _pmux) \
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \

View File

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

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
testing new synthesis algorithms it might be necessary to write a custom HDL
synthesis tool or add new features to an existing one. It this cases the
synthesis tool or add new features to an existing one. In these cases the
availability of a Free and Open Source (FOSS) synthesis tool that can be used
as basis for custom tools would be helpful.

View File

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

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

View File

@ -134,6 +134,7 @@ struct rules_t
dict<string, int> min_limits, max_limits;
bool or_next_if_better, make_transp, make_outreg;
char shuffle_enable;
vector<vector<std::tuple<bool,IdString,Const>>> attributes;
};
dict<IdString, vector<bram_t>> brams;
@ -327,6 +328,20 @@ struct rules_t
continue;
}
if (GetSize(tokens) >= 2 && tokens[0] == "attribute") {
data.attributes.emplace_back();
for (int idx = 1; idx < GetSize(tokens); idx++) {
size_t c1 = tokens[idx][0] == '!' ? 1 : 0;
size_t c2 = tokens[idx].find("=");
bool exists = (c1 == 0);
IdString key = RTLIL::escape_id(tokens[idx].substr(c1, c2));
Const val = c2 != std::string::npos ? tokens[idx].substr(c2+1) : RTLIL::Const(1);
data.attributes.back().emplace_back(exists, key, val);
}
continue;
}
syntax_error();
}
}
@ -724,7 +739,7 @@ grow_read_ports:;
if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true;
if (pi.clocks != 0) {
if (wr_ports == 1 && wr_clkdom != clkdom) {
if (wr_ports == 1 && wr_clkdom != clkdom) {
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
@ -813,6 +828,43 @@ grow_read_ports:;
return false;
}
for (const auto &sums : match.attributes) {
bool found = false;
for (const auto &term : sums) {
bool exists = std::get<0>(term);
IdString key = std::get<1>(term);
const Const &value = std::get<2>(term);
auto it = cell->attributes.find(key);
if (it == cell->attributes.end()) {
if (exists)
continue;
found = true;
break;
}
else if (!exists)
continue;
if (it->second != value)
continue;
found = true;
break;
}
if (!found) {
std::stringstream ss;
bool exists = std::get<0>(sums.front());
if (!exists)
ss << "!";
IdString key = std::get<1>(sums.front());
ss << log_id(key);
const Const &value = std::get<2>(sums.front());
if (exists && value != Const(1))
ss << "=\"" << value.decode_string() << "\"";
log(" Rule for bram type %s rejected: requirement 'attribute %s ...' not met.\n",
log_id(match.name), ss.str().c_str());
return false;
}
}
if (mode == 1)
return true;
}
@ -1100,6 +1152,43 @@ void handle_cell(Cell *cell, const rules_t &rules)
goto next_match_rule;
}
for (const auto &sums : match.attributes) {
bool found = false;
for (const auto &term : sums) {
bool exists = std::get<0>(term);
IdString key = std::get<1>(term);
const Const &value = std::get<2>(term);
auto it = cell->attributes.find(key);
if (it == cell->attributes.end()) {
if (exists)
continue;
found = true;
break;
}
else if (!exists)
continue;
if (it->second != value)
continue;
found = true;
break;
}
if (!found) {
std::stringstream ss;
bool exists = std::get<0>(sums.front());
if (!exists)
ss << "!";
IdString key = std::get<1>(sums.front());
ss << log_id(key);
const Const &value = std::get<2>(sums.front());
if (exists && value != Const(1))
ss << "=\"" << value.decode_string() << "\"";
log(" Rule for bram type %s (variant %d) rejected: requirement 'attribute %s ...' not met.\n",
log_id(bram.name), bram.variant, ss.str().c_str());
goto next_match_rule;
}
}
log(" Rule #%d for bram type %s (variant %d) accepted.\n", i+1, log_id(bram.name), bram.variant);
if (or_next_if_better || !best_rule_cache.empty())
@ -1225,6 +1314,13 @@ struct MemoryBramPass : public Pass {
log(" dcells ....... number of cells in 'data-direction'\n");
log(" cells ........ total number of cells (acells*dcells*dups)\n");
log("\n");
log("A match containing the command 'attribute' followed by a list of space\n");
log("separated 'name[=string_value]' values requires that the memory contains any\n");
log("one of the given attribute name and string values (where specified), or name\n");
log("and integer 1 value (if no string_value given, since Verilog will interpret\n");
log("'(* attr *)' as '(* attr=1 *)').\n");
log("A name prefixed with '!' indicates that the attribute must not exist.\n");
log("\n");
log("The interface for the created bram instances is derived from the bram\n");
log("description. Use 'techmap' to convert the created bram instances into\n");
log("instances of the actual bram cells of your target architecture.\n");

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());
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
log_id(module), cell->type == ID($eq) ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
cell->setPort(ID::A, cell->getPort(ID::B));

View File

@ -22,8 +22,9 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
# --------------------------------------
OBJS += passes/pmgen/xilinx_dsp.o
passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp_CREG_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h
passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp48a_pm.h passes/pmgen/xilinx_dsp_CREG_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp48a_pm.h))
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_CREG_pm.h))
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))

View File

@ -26,6 +26,7 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
#include "passes/pmgen/xilinx_dsp_pm.h"
#include "passes/pmgen/xilinx_dsp48a_pm.h"
#include "passes/pmgen/xilinx_dsp_CREG_pm.h"
#include "passes/pmgen/xilinx_dsp_cascade_pm.h"
@ -487,6 +488,190 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
pm.blacklist(cell);
}
void xilinx_dsp48a_pack(xilinx_dsp48a_pm &pm)
{
auto &st = pm.st_xilinx_dsp48a_pack;
log("Analysing %s.%s for Xilinx DSP48A/DSP48A1 packing.\n", log_id(pm.module), log_id(st.dsp));
log_debug("preAdd: %s\n", log_id(st.preAdd, "--"));
log_debug("ffA1: %s %s %s\n", log_id(st.ffA1, "--"), log_id(st.ffA1cemux, "--"), log_id(st.ffA1rstmux, "--"));
log_debug("ffA0: %s %s %s\n", log_id(st.ffA0, "--"), log_id(st.ffA0cemux, "--"), log_id(st.ffA0rstmux, "--"));
log_debug("ffB1: %s %s %s\n", log_id(st.ffB1, "--"), log_id(st.ffB1cemux, "--"), log_id(st.ffB1rstmux, "--"));
log_debug("ffB0: %s %s %s\n", log_id(st.ffB0, "--"), log_id(st.ffB0cemux, "--"), log_id(st.ffB0rstmux, "--"));
log_debug("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--"));
log_debug("dsp: %s\n", log_id(st.dsp, "--"));
log_debug("ffM: %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), log_id(st.ffMrstmux, "--"));
log_debug("postAdd: %s\n", log_id(st.postAdd, "--"));
log_debug("postAddMux: %s\n", log_id(st.postAddMux, "--"));
log_debug("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--"));
Cell *cell = st.dsp;
SigSpec &opmode = cell->connections_.at(ID(OPMODE));
if (st.preAdd) {
log(" preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type));
bool D_SIGNED = st.preAdd->getParam(ID(A_SIGNED)).as_bool();
bool B_SIGNED = st.preAdd->getParam(ID(B_SIGNED)).as_bool();
st.sigB.extend_u0(18, B_SIGNED);
st.sigD.extend_u0(18, D_SIGNED);
cell->setPort(ID(B), st.sigB);
cell->setPort(ID(D), st.sigD);
opmode[4] = State::S1;
if (st.preAdd->type == ID($add))
opmode[6] = State::S0;
else if (st.preAdd->type == ID($sub))
opmode[6] = State::S1;
else
log_assert(!"strange pre-adder type");
pm.autoremove(st.preAdd);
}
if (st.postAdd) {
log(" postadder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type));
if (st.postAddMux) {
log_assert(st.ffP);
opmode[2] = st.postAddMux->getPort(ID(S));
pm.autoremove(st.postAddMux);
}
else if (st.ffP && st.sigC == st.sigP)
opmode[2] = State::S0;
else
opmode[2] = State::S1;
opmode[3] = State::S1;
if (opmode[2] != State::S0) {
if (st.postAddMuxAB == ID(A))
st.sigC.extend_u0(48, st.postAdd->getParam(ID(B_SIGNED)).as_bool());
else
st.sigC.extend_u0(48, st.postAdd->getParam(ID(A_SIGNED)).as_bool());
cell->setPort(ID(C), st.sigC);
}
pm.autoremove(st.postAdd);
}
if (st.clock != SigBit())
{
cell->setPort(ID(CLK), st.clock);
auto f = [&pm,cell](SigSpec &A, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) {
SigSpec D = ff->getPort(ID(D));
SigSpec Q = pm.sigmap(ff->getPort(ID(Q)));
if (!A.empty())
A.replace(Q, D);
if (rstmux) {
SigSpec Y = rstmux->getPort(ID(Y));
SigSpec AB = rstmux->getPort(rstpol ? ID(A) : ID(B));
if (!A.empty())
A.replace(Y, AB);
if (rstport != IdString()) {
SigSpec S = rstmux->getPort(ID(S));
cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S));
}
}
else if (rstport != IdString())
cell->setPort(rstport, State::S0);
if (cemux) {
SigSpec Y = cemux->getPort(ID(Y));
SigSpec BA = cemux->getPort(cepol ? ID(B) : ID(A));
SigSpec S = cemux->getPort(ID(S));
if (!A.empty())
A.replace(Y, BA);
cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S));
}
else
cell->setPort(ceport, State::S1);
for (auto c : Q.chunks()) {
auto it = c.wire->attributes.find(ID(init));
if (it == c.wire->attributes.end())
continue;
for (int i = c.offset; i < c.offset+c.width; i++) {
log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx);
it->second[i] = State::Sx;
}
}
};
if (st.ffA0 || st.ffA1) {
SigSpec A = cell->getPort(ID(A));
if (st.ffA1) {
f(A, st.ffA1, st.ffA1cemux, st.ffAcepol, ID(CEA), st.ffA1rstmux, st.ffArstpol, ID(RSTA));
cell->setParam(ID(A1REG), 1);
}
if (st.ffA0) {
f(A, st.ffA0, st.ffA0cemux, st.ffAcepol, ID(CEA), st.ffA0rstmux, st.ffArstpol, ID(RSTA));
cell->setParam(ID(A0REG), 1);
}
pm.add_siguser(A, cell);
cell->setPort(ID(A), A);
}
if (st.ffB0 || st.ffB1) {
SigSpec B = cell->getPort(ID(B));
if (st.ffB1) {
f(B, st.ffB1, st.ffB1cemux, st.ffBcepol, ID(CEB), st.ffB1rstmux, st.ffBrstpol, ID(RSTB));
cell->setParam(ID(B1REG), 1);
}
if (st.ffB0) {
f(B, st.ffB0, st.ffB0cemux, st.ffBcepol, ID(CEB), st.ffB0rstmux, st.ffBrstpol, ID(RSTB));
cell->setParam(ID(B0REG), 1);
}
pm.add_siguser(B, cell);
cell->setPort(ID(B), B);
}
if (st.ffD) {
SigSpec D = cell->getPort(ID(D));
f(D, st.ffD, st.ffDcemux, st.ffDcepol, ID(CED), st.ffDrstmux, st.ffDrstpol, ID(RSTD));
pm.add_siguser(D, cell);
cell->setPort(ID(D), D);
cell->setParam(ID(DREG), 1);
}
if (st.ffM) {
SigSpec M; // unused
f(M, st.ffM, st.ffMcemux, st.ffMcepol, ID(CEM), st.ffMrstmux, st.ffMrstpol, ID(RSTM));
st.ffM->connections_.at(ID(Q)).replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM)));
cell->setParam(ID(MREG), State::S1);
}
if (st.ffP) {
SigSpec P; // unused
f(P, st.ffP, st.ffPcemux, st.ffPcepol, ID(CEP), st.ffPrstmux, st.ffPrstpol, ID(RSTP));
st.ffP->connections_.at(ID(Q)).replace(st.sigP, pm.module->addWire(NEW_ID, GetSize(st.sigP)));
cell->setParam(ID(PREG), State::S1);
}
log(" clock: %s (%s)", log_signal(st.clock), "posedge");
if (st.ffA0)
log(" ffA0:%s", log_id(st.ffA0));
if (st.ffA1)
log(" ffA1:%s", log_id(st.ffA1));
if (st.ffB0)
log(" ffB0:%s", log_id(st.ffB0));
if (st.ffB1)
log(" ffB1:%s", log_id(st.ffB1));
if (st.ffD)
log(" ffD:%s", log_id(st.ffD));
if (st.ffM)
log(" ffM:%s", log_id(st.ffM));
if (st.ffP)
log(" ffP:%s", log_id(st.ffP));
}
log("\n");
SigSpec P = st.sigP;
if (GetSize(P) < 48)
P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
cell->setPort(ID(P), P);
pm.blacklist(cell);
}
void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm)
{
auto &st = pm.st_xilinx_dsp_packC;
@ -592,33 +777,48 @@ struct XilinxDspPass : public Pass {
log("P output implementing the operation \"(P >= <power-of-2>)\" will be transformed\n");
log("into using the DSP48E1's pattern detector feature for overflow detection.\n");
log("\n");
log(" -family {xcup|xcu|xc7|xc6v|xc5v|xc4v|xc6s|xc3sda}\n");
log(" select the family to target\n");
log(" default: xc7\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing XILINX_DSP pass (pack resources into DSPs).\n");
std::string family = "xc7";
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-singleton") {
// singleton_mode = true;
// continue;
// }
if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) {
family = args[++argidx];
continue;
}
break;
}
extra_args(args, argidx, design);
// Don't bother distinguishing between those.
if (family == "xc6v")
family = "xc7";
if (family == "xcup")
family = "xcu";
for (auto module : design->selected_modules()) {
// Experimental feature: pack $add/$sub cells with
// (* use_dsp48="simd" *) into DSP48E1's using its
// SIMD feature
xilinx_simd_pack(module, module->selected_cells());
if (family == "xc7")
xilinx_simd_pack(module, module->selected_cells());
// Match for all features ([ABDMP][12]?REG, pre-adder,
// post-adder, pattern detector, etc.) except for CREG
{
if (family == "xc7") {
xilinx_dsp_pm pm(module, module->selected_cells());
pm.run_xilinx_dsp_pack(xilinx_dsp_pack);
} else if (family == "xc6s" || family == "xc3sda") {
xilinx_dsp48a_pm pm(module, module->selected_cells());
pm.run_xilinx_dsp48a_pack(xilinx_dsp48a_pack);
}
// Separating out CREG packing is necessary since there
// is no guarantee that the cell ordering corresponds

View File

@ -0,0 +1,673 @@
// This file describes the main pattern matcher setup (of three total) that
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc - version for
// DSP48A/DSP48A1 (Spartan 3A DSP, Spartan 6).
// At a high level, it works as follows:
// ( 1) Starting from a DSP48A/DSP48A1 cell
// ( 2) Match the driver of the 'B' input to a possible $dff cell (B1REG)
// (attached to at most two $mux cells that implement clock-enable or
// reset functionality, using a subpattern discussed below)
// If B1REG matched, treat 'B' input as input of B1REG
// ( 3) Match the driver of the 'B' and 'D' inputs for a possible $add cell
// (pre-adder)
// ( 4) Match 'B' input for B0REG
// ( 5) Match 'A' input for A1REG
// If A1REG, then match 'A' input for A0REG
// ( 6) Match 'D' input for DREG
// ( 7) Match 'P' output that exclusively drives an MREG
// ( 8) Match 'P' output that exclusively drives one of two inputs to an $add
// cell (post-adder).
// The other input to the adder is assumed to come in from the 'C' input
// (note: 'P' -> 'C' connections that exist for accumulators are
// recognised in xilinx_dsp.cc).
// ( 9) Match 'P' output that exclusively drives a PREG
// (10) If post-adder and PREG both present, match for a $mux cell driving
// the 'C' input, where one of the $mux's inputs is the PREG output.
// This indicates an accumulator situation, and one where a $mux exists
// to override the accumulated value:
// +--------------------------------+
// | ____ |
// +--| \ |
// |$mux|-+ |
// 'C' ---|____/ | |
// | /-------\ +----+ |
// +----+ +-| post- |___|PREG|---+ 'P'
// |MREG|------ | adder | +----+
// +----+ \-------/
// Notes: see the notes in xilinx_dsp.pmg
pattern xilinx_dsp48a_pack
state <SigBit> clock
state <SigSpec> sigA sigB sigC sigD sigM sigP
state <IdString> postAddAB postAddMuxAB
state <bool> ffAcepol ffBcepol ffDcepol ffMcepol ffPcepol
state <bool> ffArstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol
state <Cell*> ffA0 ffA0cemux ffA0rstmux ffA1 ffA1cemux ffA1rstmux
state <Cell*> ffB0 ffB0cemux ffB0rstmux ffB1 ffB1cemux ffB1rstmux
state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux
// Variables used for subpatterns
state <SigSpec> argQ argD
state <bool> ffcepol ffrstpol
state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
udata <Cell*> dff dffcemux dffrstmux
udata <bool> dffcepol dffrstpol
// (1) Starting from a DSP48A/DSP48A1 cell
match dsp
select dsp->type.in(\DSP48A, \DSP48A1)
endmatch
code sigA sigB sigC sigD sigM clock
auto unextend = [](const SigSpec &sig) {
int i;
for (i = GetSize(sig)-1; i > 0; i--)
if (sig[i] != sig[i-1])
break;
// Do not remove non-const sign bit
if (sig[i].wire)
++i;
return sig.extract(0, i);
};
sigA = unextend(port(dsp, \A));
sigB = unextend(port(dsp, \B));
sigC = port(dsp, \C, SigSpec());
sigD = port(dsp, \D, SigSpec());
SigSpec P = port(dsp, \P);
// Only care about those bits that are used
int i;
for (i = GetSize(P)-1; i >= 0; i--)
if (nusers(P[i]) > 1)
break;
i++;
log_assert(nusers(P.extract_end(i)) <= 1);
// This sigM could have no users if downstream sinks (e.g. $add) is
// narrower than $mul result, for example
if (i == 0)
reject;
sigM = P.extract(0, i);
clock = port(dsp, \CLK, SigBit());
endcode
// (2) Match the driver of the 'B' input to a possible $dff cell (B1REG)
// (attached to at most two $mux cells that implement clock-enable or
// reset functionality, using a subpattern discussed above)
// If matched, treat 'B' input as input of B1REG
code argQ ffB1 ffB1cemux ffB1rstmux ffBcepol ffBrstpol sigB clock
if (param(dsp, \B1REG).as_int() == 0 && param(dsp, \B0REG).as_int() == 0 && port(dsp, \OPMODE, SigSpec()).extract(4, 1).is_fully_zero()) {
argQ = sigB;
subpattern(in_dffe);
if (dff) {
ffB1 = dff;
clock = dffclock;
if (dffrstmux) {
ffB1rstmux = dffrstmux;
ffBrstpol = dffrstpol;
}
if (dffcemux) {
ffB1cemux = dffcemux;
ffBcepol = dffcepol;
}
sigB = dffD;
}
}
endcode
// (3) Match the driver of the 'B' and 'D' inputs for a possible $add cell
// (pre-adder)
match preAdd
if sigD.empty() || sigD.is_fully_zero()
if param(dsp, \B0REG).as_int() == 0
// Ensure that preAdder not already used
if port(dsp, \OPMODE, SigSpec()).extract(4, 1).is_fully_zero()
select preAdd->type.in($add, $sub)
// Output has to be 18 bits or less
select GetSize(port(preAdd, \Y)) <= 18
select nusers(port(preAdd, \Y)) == 2
// D port has to be 18 bits or less
select GetSize(port(preAdd, \A)) <= 18
// B port has to be 18 bits or less
select GetSize(port(preAdd, \B)) <= 18
index <SigSpec> port(preAdd, \Y) === sigB
optional
endmatch
code sigB sigD
if (preAdd) {
sigD = port(preAdd, \A);
sigB = port(preAdd, \B);
}
endcode
// (4) Match 'B' input for B0REG
code argQ ffB0 ffB0cemux ffB0rstmux ffBcepol ffBrstpol sigB clock
if (param(dsp, \B0REG).as_int() == 0) {
argQ = sigB;
subpattern(in_dffe);
if (dff) {
if (ffB1) {
if ((ffB1rstmux != nullptr) ^ (dffrstmux != nullptr))
goto ffB0_end;
if ((ffB1cemux != nullptr) ^ (dffcemux != nullptr))
goto ffB0_end;
if (dffrstmux) {
if (ffBrstpol != dffrstpol)
goto ffB0_end;
if (port(ffB1rstmux, \S) != port(dffrstmux, \S))
goto ffB0_end;
ffB0rstmux = dffrstmux;
}
if (dffcemux) {
if (ffBcepol != dffcepol)
goto ffB0_end;
if (port(ffB1cemux, \S) != port(dffcemux, \S))
goto ffB0_end;
ffB0cemux = dffcemux;
}
}
ffB0 = dff;
clock = dffclock;
if (dffrstmux) {
ffB0rstmux = dffrstmux;
ffBrstpol = dffrstpol;
}
if (dffcemux) {
ffB0cemux = dffcemux;
ffBcepol = dffcepol;
}
sigB = dffD;
}
}
ffB0_end:
endcode
// (5) Match 'A' input for A1REG
// If A1REG, then match 'A' input for A0REG
code argQ ffA1 ffA1cemux ffA1rstmux ffAcepol ffArstpol sigA clock ffA0 ffA0cemux ffA0rstmux
if (param(dsp, \A0REG).as_int() == 0 && param(dsp, \A1REG).as_int() == 0) {
argQ = sigA;
subpattern(in_dffe);
if (dff) {
ffA1 = dff;
clock = dffclock;
if (dffrstmux) {
ffA1rstmux = dffrstmux;
ffArstpol = dffrstpol;
}
if (dffcemux) {
ffA1cemux = dffcemux;
ffAcepol = dffcepol;
}
sigA = dffD;
// Now attempt to match A0
if (ffA1) {
argQ = sigA;
subpattern(in_dffe);
if (dff) {
if ((ffA1rstmux != nullptr) ^ (dffrstmux != nullptr))
goto ffA0_end;
if ((ffA1cemux != nullptr) ^ (dffcemux != nullptr))
goto ffA0_end;
if (dffrstmux) {
if (ffArstpol != dffrstpol)
goto ffA0_end;
if (port(ffA1rstmux, \S) != port(dffrstmux, \S))
goto ffA0_end;
ffA0rstmux = dffrstmux;
}
if (dffcemux) {
if (ffAcepol != dffcepol)
goto ffA0_end;
if (port(ffA1cemux, \S) != port(dffcemux, \S))
goto ffA0_end;
ffA0cemux = dffcemux;
}
ffA0 = dff;
clock = dffclock;
if (dffcemux) {
ffA0cemux = dffcemux;
ffAcepol = dffcepol;
}
sigA = dffD;
ffA0_end: ;
}
}
}
}
endcode
// (6) Match 'D' input for DREG
code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock
if (param(dsp, \DREG).as_int() == 0) {
argQ = sigD;
subpattern(in_dffe);
if (dff) {
ffD = dff;
clock = dffclock;
if (dffrstmux) {
ffDrstmux = dffrstmux;
ffDrstpol = dffrstpol;
}
if (dffcemux) {
ffDcemux = dffcemux;
ffDcepol = dffcepol;
}
sigD = dffD;
}
}
endcode
// (7) Match 'P' output that exclusively drives an MREG
code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock
if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) {
argD = sigM;
subpattern(out_dffe);
if (dff) {
ffM = dff;
clock = dffclock;
if (dffrstmux) {
ffMrstmux = dffrstmux;
ffMrstpol = dffrstpol;
}
if (dffcemux) {
ffMcemux = dffcemux;
ffMcepol = dffcepol;
}
sigM = dffQ;
}
}
sigP = sigM;
endcode
// (8) Match 'P' output that exclusively drives one of two inputs to an $add
// cell (post-adder).
// The other input to the adder is assumed to come in from the 'C' input
// (note: 'P' -> 'C' connections that exist for accumulators are
// recognised in xilinx_dsp.cc).
match postAdd
// Ensure that Z mux is not already used
if port(dsp, \OPMODE, SigSpec()).extract(2,2).is_fully_zero()
select postAdd->type.in($add)
select GetSize(port(postAdd, \Y)) <= 48
choice <IdString> AB {\A, \B}
select nusers(port(postAdd, AB)) <= 3
filter ffMcemux || nusers(port(postAdd, AB)) == 2
filter !ffMcemux || nusers(port(postAdd, AB)) == 3
index <SigBit> port(postAdd, AB)[0] === sigP[0]
filter GetSize(port(postAdd, AB)) >= GetSize(sigP)
filter port(postAdd, AB).extract(0, GetSize(sigP)) == sigP
// Check that remainder of AB is a sign- or zero-extension
filter port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(sigP[GetSize(sigP)-1], GetSize(port(postAdd, AB))-GetSize(sigP)) || port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(State::S0, GetSize(port(postAdd, AB))-GetSize(sigP))
set postAddAB AB
optional
endmatch
code sigC sigP
if (postAdd) {
sigC = port(postAdd, postAddAB == \A ? \B : \A);
sigP = port(postAdd, \Y);
}
endcode
// (9) Match 'P' output that exclusively drives a PREG
code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock
if (param(dsp, \PREG).as_int() == 0) {
int users = 2;
// If ffMcemux and no postAdd new-value net must have three users: ffMcemux, ffM and ffPcemux
if (ffMcemux && !postAdd) users++;
if (nusers(sigP) == users) {
argD = sigP;
subpattern(out_dffe);
if (dff) {
ffP = dff;
clock = dffclock;
if (dffrstmux) {
ffPrstmux = dffrstmux;
ffPrstpol = dffrstpol;
}
if (dffcemux) {
ffPcemux = dffcemux;
ffPcepol = dffcepol;
}
sigP = dffQ;
}
}
}
endcode
// (10) If post-adder and PREG both present, match for a $mux cell driving
// the 'C' input, where one of the $mux's inputs is the PREG output.
// This indicates an accumulator situation, and one where a $mux exists
// to override the accumulated value:
// +--------------------------------+
// | ____ |
// +--| \ |
// |$mux|-+ |
// 'C' ---|____/ | |
// | /-------\ +----+ |
// +----+ +-| post- |___|PREG|---+ 'P'
// |MREG|------ | adder | +----+
// +----+ \-------/
match postAddMux
if postAdd
if ffP
select postAddMux->type.in($mux)
select nusers(port(postAddMux, \Y)) == 2
choice <IdString> AB {\A, \B}
index <SigSpec> port(postAddMux, AB) === sigP
index <SigSpec> port(postAddMux, \Y) === sigC
set postAddMuxAB AB
optional
endmatch
code sigC
if (postAddMux)
sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
endcode
code
accept;
endcode
// #######################
// Subpattern for matching against input registers, based on knowledge of the
// 'Q' input. Typically, identifying registers with clock-enable and reset
// capability would be a task would be handled by other Yosys passes such as
// dff2dffe, but since DSP inference happens much before this, these patterns
// have to be manually identified.
// At a high level:
// (1) Starting from a $dff cell that (partially or fully) drives the given
// 'Q' argument
// (2) Match for a $mux cell implementing synchronous reset semantics ---
// one that exclusively drives the 'D' input of the $dff, with one of its
// $mux inputs being fully zero
// (3) Match for a $mux cell implement clock enable semantics --- one that
// exclusively drives the 'D' input of the $dff (or the other input of
// the reset $mux) and where one of this $mux's inputs is connected to
// the 'Q' output of the $dff
subpattern in_dffe
arg argD argQ clock
code
dff = nullptr;
if (GetSize(argQ) == 0)
reject;
for (const auto &c : argQ.chunks()) {
// Abandon matches when 'Q' is a constant
if (!c.wire)
reject;
// Abandon matches when 'Q' has the keep attribute set
if (c.wire->get_bool_attribute(\keep))
reject;
// Abandon matches when 'Q' has a non-zero init attribute set
// (not supported by DSP48E1)
Const init = c.wire->attributes.at(\init, Const());
if (!init.empty())
for (auto b : init.extract(c.offset, c.width))
if (b != State::Sx && b != State::S0)
reject;
}
endcode
// (1) Starting from a $dff cell that (partially or fully) drives the given
// 'Q' argument
match ff
select ff->type.in($dff)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \Q)[offset] === argQ[0]
// Check that the rest of argQ is present
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
set ffoffset offset
endmatch
code argQ argD
SigSpec Q = port(ff, \Q);
dff = ff;
dffclock = port(ff, \CLK);
dffD = argQ;
argD = port(ff, \D);
argQ = Q;
dffD.replace(argQ, argD);
// Only search for ffrstmux if dffD only
// has two (ff, ffrstmux) users
if (nusers(dffD) > 2)
argD = SigSpec();
endcode
// (2) Match for a $mux cell implementing synchronous reset semantics ---
// exclusively drives the 'D' input of the $dff, with one of the $mux
// inputs being fully zero
match ffrstmux
if !argD.empty()
select ffrstmux->type.in($mux)
index <SigSpec> port(ffrstmux, \Y) === argD
choice <IdString> BA {\B, \A}
// DSP48E1 only supports reset to zero
select port(ffrstmux, BA).is_fully_zero()
define <bool> pol (BA == \B)
set ffrstpol pol
semioptional
endmatch
code argD
if (ffrstmux) {
dffrstmux = ffrstmux;
dffrstpol = ffrstpol;
argD = port(ffrstmux, ffrstpol ? \A : \B);
dffD.replace(port(ffrstmux, \Y), argD);
// Only search for ffcemux if argQ has at
// least 3 users (ff, <upstream>, ffrstmux) and
// dffD only has two (ff, ffrstmux)
if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
argD = SigSpec();
}
else
dffrstmux = nullptr;
endcode
// (3) Match for a $mux cell implement clock enable semantics --- one that
// exclusively drives the 'D' input of the $dff (or the other input of
// the reset $mux) and where one of this $mux's inputs is connected to
// the 'Q' output of the $dff
match ffcemux
if !argD.empty()
select ffcemux->type.in($mux)
index <SigSpec> port(ffcemux, \Y) === argD
choice <IdString> AB {\A, \B}
index <SigSpec> port(ffcemux, AB) === argQ
define <bool> pol (AB == \A)
set ffcepol pol
semioptional
endmatch
code argD
if (ffcemux) {
dffcemux = ffcemux;
dffcepol = ffcepol;
argD = port(ffcemux, ffcepol ? \B : \A);
dffD.replace(port(ffcemux, \Y), argD);
}
else
dffcemux = nullptr;
endcode
// #######################
// Subpattern for matching against output registers, based on knowledge of the
// 'D' input.
// At a high level:
// (1) Starting from an optional $mux cell that implements clock enable
// semantics --- one where the given 'D' argument (partially or fully)
// drives one of its two inputs
// (2) Starting from, or continuing onto, another optional $mux cell that
// implements synchronous reset semantics --- one where the given 'D'
// argument (or the clock enable $mux output) drives one of its two inputs
// and where the other input is fully zero
// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
// output of the previous clock enable or reset $mux cells)
subpattern out_dffe
arg argD argQ clock
code
dff = nullptr;
for (auto c : argD.chunks())
// Abandon matches when 'D' has the keep attribute set
if (c.wire->get_bool_attribute(\keep))
reject;
endcode
// (1) Starting from an optional $mux cell that implements clock enable
// semantics --- one where the given 'D' argument (partially or fully)
// drives one of its two inputs
match ffcemux
select ffcemux->type.in($mux)
// ffcemux output must have two users: ffcemux and ff.D
select nusers(port(ffcemux, \Y)) == 2
choice <IdString> AB {\A, \B}
// keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s)
select nusers(port(ffcemux, AB)) >= 3
slice offset GetSize(port(ffcemux, \Y))
define <IdString> BA (AB == \A ? \B : \A)
index <SigBit> port(ffcemux, BA)[offset] === argD[0]
// Check that the rest of argD is present
filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD)
filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD
set ffoffset offset
define <bool> pol (AB == \A)
set ffcepol pol
semioptional
endmatch
code argD argQ
dffcemux = ffcemux;
if (ffcemux) {
SigSpec BA = port(ffcemux, ffcepol ? \B : \A);
SigSpec Y = port(ffcemux, \Y);
argQ = argD;
argD.replace(BA, Y);
argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B));
dffcemux = ffcemux;
dffcepol = ffcepol;
}
endcode
// (2) Starting from, or continuing onto, another optional $mux cell that
// implements synchronous reset semantics --- one where the given 'D'
// argument (or the clock enable $mux output) drives one of its two inputs
// and where the other input is fully zero
match ffrstmux
select ffrstmux->type.in($mux)
// ffrstmux output must have two users: ffrstmux and ff.D
select nusers(port(ffrstmux, \Y)) == 2
choice <IdString> BA {\B, \A}
// DSP48E1 only supports reset to zero
select port(ffrstmux, BA).is_fully_zero()
slice offset GetSize(port(ffrstmux, \Y))
define <IdString> AB (BA == \B ? \A : \B)
index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
// Check that offset is consistent
filter !ffcemux || ffoffset == offset
// Check that the rest of argD is present
filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
set ffoffset offset
define <bool> pol (AB == \A)
set ffrstpol pol
semioptional
endmatch
code argD argQ
dffrstmux = ffrstmux;
if (ffrstmux) {
SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
SigSpec Y = port(ffrstmux, \Y);
argD.replace(AB, Y);
dffrstmux = ffrstmux;
dffrstpol = ffrstpol;
}
endcode
// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
// output of the previous clock enable or reset $mux cells)
match ff
select ff->type.in($dff)
// DSP48E1 does not support clock inversion
select param(ff, \CLK_POLARITY).as_bool()
slice offset GetSize(port(ff, \D))
index <SigBit> port(ff, \D)[offset] === argD[0]
// Check that offset is consistent
filter (!ffcemux && !ffrstmux) || ffoffset == offset
// Check that the rest of argD is present
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
// Check that FF.Q is connected to CE-mux
filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
filter clock == SigBit() || port(ff, \CLK) == clock
set ffoffset offset
endmatch
code argQ
SigSpec D = port(ff, \D);
SigSpec Q = port(ff, \Q);
if (!ffcemux) {
argQ = argD;
argQ.replace(D, Q);
}
// Abandon matches when 'Q' has a non-zero init attribute set
// (not supported by DSP48E1)
for (auto c : argQ.chunks()) {
Const init = c.wire->attributes.at(\init, Const());
if (!init.empty())
for (auto b : init.extract(c.offset, c.width))
if (b != State::Sx && b != State::S0)
reject;
}
dff = ff;
dffQ = argQ;
dffclock = port(ff, \CLK);
endcode

View File

@ -1,7 +1,7 @@
// This file describes the second of three pattern matcher setups that
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc
// At a high level, it works as follows:
// (1) Starting from a DSP48E1 cell that (a) doesn't have a CREG already,
// (1) Starting from a DSP48* cell that (a) doesn't have a CREG already,
// and (b) uses the 'C' port
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
// (attached to at most two $mux cells that implement clock-enable or
@ -38,10 +38,10 @@ udata <SigBit> dffclock
udata <Cell*> dff dffcemux dffrstmux
udata <bool> dffcepol dffrstpol
// (1) Starting from a DSP48E1 cell that (a) doesn't have a CREG already,
// (1) Starting from a DSP48* cell that (a) doesn't have a CREG already,
// and (b) uses the 'C' port
match dsp
select dsp->type.in(\DSP48E1)
select dsp->type.in(\DSP48A, \DSP48A1, \DSP48E1)
select param(dsp, \CREG, 1).as_int() == 0
select nusers(port(dsp, \C, SigSpec())) > 1
endmatch
@ -60,7 +60,8 @@ code sigC sigP clock
sigC = unextend(port(dsp, \C, SigSpec()));
SigSpec P = port(dsp, \P);
if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
if (!dsp->type.in(\DSP48E1) ||
param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
// Only care about those bits that are used
int i;
for (i = GetSize(P)-1; i >= 0; i--)

View File

@ -62,12 +62,11 @@ code
#define MAX_DSP_CASCADE 20
endcode
// (1) Starting from a DSP48E1 cell that (a) has the Z multiplexer
// (controlled by OPMODE[6:4]) set to zero and (b) doesn't already
// use the 'PCOUT' port
// (1) Starting from a DSP48* cell that (a) has the Z multiplexer
// (controlled by OPMODE[3:2] for DSP48A*, by OPMODE[6:4] for DSP48E1)
// set to zero and (b) doesn't already use the 'PCOUT' port
match first
select first->type.in(\DSP48E1)
select port(first, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("000")
select (first->type.in(\DSP48A, \DSP48A1) && port(first, \OPMODE, Const(0, 8)).extract(2,2) == Const::from_string("00")) || (first->type.in(\DSP48E1) && port(first, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("000"))
select nusers(port(first, \PCOUT, SigSpec())) <= 1
endmatch
@ -100,14 +99,21 @@ finally
add_siguser(cascade, dsp);
SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7));
if (P == 17)
opmode[6] = State::S1;
else if (P == 0)
opmode[6] = State::S0;
else log_abort();
if (dsp->type.in(\DSP48A, \DSP48A1)) {
log_assert(P == 0);
opmode[3] = State::S0;
opmode[2] = State::S1;
}
else if (dsp->type.in(\DSP48E1)) {
if (P == 17)
opmode[6] = State::S1;
else if (P == 0)
opmode[6] = State::S0;
else log_abort();
opmode[5] = State::S0;
opmode[4] = State::S1;
opmode[5] = State::S0;
opmode[4] = State::S1;
}
dsp_pcin->setPort(\OPMODE, opmode);
log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
@ -120,21 +126,42 @@ finally
add_siguser(cascade, dsp_pcin);
add_siguser(cascade, dsp);
dsp->setParam(ID(ACASCREG), AREG);
if (dsp->type.in(\DSP48E1))
dsp->setParam(ID(ACASCREG), AREG);
dsp_pcin->setParam(ID(A_INPUT), Const("CASCADE"));
log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
}
if (BREG >= 0) {
Wire *cascade = module->addWire(NEW_ID, 18);
dsp_pcin->setPort(ID(B), Const(0, 18));
dsp_pcin->setPort(ID(BCIN), cascade);
if (dsp->type.in(\DSP48A, \DSP48A1)) {
// According to UG389 p9 [https://www.xilinx.com/support/documentation/user_guides/ug389.pdf]
// "The DSP48A1 component uses this input when cascading
// BCOUT from an adjacent DSP48A1 slice. The tools then
// translate BCOUT cascading to the dedicated BCIN input
// and set the B_INPUT attribute for implementation."
dsp_pcin->setPort(ID(B), cascade);
}
else {
dsp_pcin->setPort(ID(B), Const(0, 18));
dsp_pcin->setPort(ID(BCIN), cascade);
}
dsp->setPort(ID(BCOUT), cascade);
add_siguser(cascade, dsp_pcin);
add_siguser(cascade, dsp);
dsp->setParam(ID(BCASCREG), BREG);
dsp_pcin->setParam(ID(B_INPUT), Const("CASCADE"));
if (dsp->type.in(\DSP48E1)) {
dsp->setParam(ID(BCASCREG), BREG);
// According to UG389 p13 [https://www.xilinx.com/support/documentation/user_guides/ug389.pdf]
// "The attribute is only used by place and route tools and
// is not necessary for the users to set for synthesis. The
// attribute is determined by the connection to the B port
// of the DSP48A1 slice. If the B port is connected to the
// BCOUT of another DSP48A1 slice, then the tools automatically
// set the attribute to 'CASCADE', otherwise it is set to
// 'DIRECT'".
dsp_pcin->setParam(ID(B_INPUT), Const("CASCADE"));
}
log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
}
@ -156,22 +183,21 @@ subpattern tail
arg first
arg next
// (2.1) Match another DSP48E1 cell that (a) does not have the CREG enabled,
// (2.1) Match another DSP48* cell that (a) does not have the CREG enabled,
// (b) has its Z multiplexer output set to the 'C' port, which is
// driven by the 'P' output of the previous DSP cell, and (c) has its
// 'PCIN' port unused
match nextP
select nextP->type.in(\DSP48E1)
select !param(nextP, \CREG, State::S1).as_bool()
select port(nextP, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")
select (nextP->type.in(\DSP48A, \DSP48A1) && port(nextP, \OPMODE, Const(0, 8)).extract(2,2) == Const::from_string("11")) || (nextP->type.in(\DSP48E1) && port(nextP, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011"))
select nusers(port(nextP, \C, SigSpec())) > 1
select nusers(port(nextP, \PCIN, SigSpec())) == 0
index <SigBit> port(nextP, \C)[0] === port(std::get<0>(chain.back()), \P)[0]
semioptional
endmatch
// (2.2) Same as (2.1) but with the 'C' port driven by the 'P' output of the
// previous DSP cell right-shifted by 17 bits
// (2.2) For DSP48E1 only, same as (2.1) but with the 'C' port driven
// by the 'P' output of the previous DSP cell right-shifted by 17 bits
match nextP_shift17
if !nextP
select nextP_shift17->type.in(\DSP48E1)
@ -188,6 +214,8 @@ code next
if (!nextP)
next = nextP_shift17;
if (next) {
if (next->type != first->type)
reject;
unextend = [](const SigSpec &sig) {
int i;
for (i = GetSize(sig)-1; i > 0; i--)
@ -202,38 +230,50 @@ code next
endcode
// (3) For this subequent DSP48E1 match (i.e. PCOUT -> PCIN cascade exists)
// if (a) the previous DSP48E1 uses either the A2REG or A1REG, (b) this
// DSP48 does not use A2REG nor A1REG, (c) this DSP48E1 does not already
// have an ACOUT -> ACIN cascade, (d) the previous DSP does not already
// use its ACOUT port, then examine if an ACOUT -> ACIN cascade
// opportunity exists by matching for a $dff-with-optional-clock-enable-
// or-reset and checking that the 'D' input of this register is the same
// as the 'A' input of the previous DSP
// if (a) this DSP48E1 does not already have an ACOUT -> ACIN cascade,
// (b) the previous DSP does not already use its ACOUT port, then
// examine if an ACOUT -> ACIN cascade opportunity exists if
// (i) A ports are identical, or (ii) separated by a
// $dff-with-optional-clock-enable-or-reset and checking that the 'D' input
// of this register is the same as the 'A' input of the previous DSP
// TODO: Check for two levels of flops, instead of just one
code argQ clock AREG
AREG = -1;
if (next) {
if (next && next->type.in(\DSP48E1)) {
Cell *prev = std::get<0>(chain.back());
if (param(prev, \AREG, 2).as_int() > 0 &&
param(next, \AREG, 2).as_int() > 0 &&
param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
if (param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
port(next, \ACIN, SigSpec()).is_fully_zero() &&
nusers(port(prev, \ACOUT, SigSpec())) <= 1) {
argQ = unextend(port(next, \A));
clock = port(prev, \CLK);
subpattern(in_dffe);
if (dff) {
if (!dffrstmux && port(prev, \RSTA, State::S0) != State::S0)
goto reject_AREG;
if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTA, State::S0))
goto reject_AREG;
if (!dffcemux && port(prev, \CEA2, State::S0) != State::S0)
goto reject_AREG;
if (dffcemux && port(dffcemux, \S) != port(prev, \CEA2, State::S0))
goto reject_AREG;
if (dffD == unextend(port(prev, \A)))
AREG = 1;
reject_AREG: ;
if (param(prev, \AREG, 2) == 0) {
if (port(prev, \A) == port(next, \A))
AREG = 0;
}
else {
argQ = unextend(port(next, \A));
clock = port(prev, \CLK);
subpattern(in_dffe);
if (dff) {
if (!dffrstmux && port(prev, \RSTA, State::S0) != State::S0)
goto reject_AREG;
if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTA, State::S0))
goto reject_AREG;
IdString CEA;
if (param(prev, \AREG, 2) == 1)
CEA = \CEA2;
else if (param(prev, \AREG, 2) == 2)
CEA = \CEA1;
else log_abort();
if (!dffcemux && port(prev, CEA, State::S0) != State::S1)
goto reject_AREG;
if (dffcemux && port(dffcemux, \S) != port(prev, CEA, State::S0))
goto reject_AREG;
if (dffD == unextend(port(prev, \A)))
AREG = 1;
}
}
}
reject_AREG: ;
}
endcode
@ -242,28 +282,47 @@ code argQ clock BREG
BREG = -1;
if (next) {
Cell *prev = std::get<0>(chain.back());
if (param(prev, \BREG, 2).as_int() > 0 &&
param(next, \BREG, 2).as_int() > 0 &&
param(next, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
if (param(next, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
port(next, \BCIN, SigSpec()).is_fully_zero() &&
nusers(port(prev, \BCOUT, SigSpec())) <= 1) {
argQ = unextend(port(next, \B));
clock = port(prev, \CLK);
subpattern(in_dffe);
if (dff) {
if (!dffrstmux && port(prev, \RSTB, State::S0) != State::S0)
goto reject_BREG;
if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTB, State::S0))
goto reject_BREG;
if (!dffcemux && port(prev, \CEB2, State::S0) != State::S0)
goto reject_BREG;
if (dffcemux && port(dffcemux, \S) != port(prev, \CEB2, State::S0))
goto reject_BREG;
if (dffD == unextend(port(prev, \B)))
BREG = 1;
reject_BREG: ;
if ((next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG, 0) == 0 && param(prev, \B1REG, 1) == 0) ||
(next->type.in(\DSP48E1) && param(prev, \BREG, 2) == 0)) {
if (port(prev, \B) == port(next, \B))
BREG = 0;
}
else {
argQ = unextend(port(next, \B));
clock = port(prev, \CLK);
subpattern(in_dffe);
if (dff) {
if (!dffrstmux && port(prev, \RSTB, State::S0) != State::S0)
goto reject_BREG;
if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTB, State::S0))
goto reject_BREG;
IdString CEB;
if (next->type.in(\DSP48A, \DSP48A1))
CEB = \CEB;
else if (next->type.in(\DSP48E1)) {
if (param(prev, \BREG, 2) == 1)
CEB = \CEB2;
else if (param(prev, \BREG, 2) == 2)
CEB = \CEB1;
else log_abort();
}
else log_abort();
if (!dffcemux && port(prev, CEB, State::S0) != State::S1)
goto reject_BREG;
if (dffcemux && port(dffcemux, \S) != port(prev, CEB, State::S0))
goto reject_BREG;
if (dffD == unextend(port(prev, \B))) {
if (next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG, 0) != 0)
goto reject_BREG;
BREG = 1;
}
}
}
}
reject_BREG: ;
}
endcode

View File

@ -230,7 +230,7 @@ struct SimInstance
bool did_something = false;
sig = sigmap(sig);
log_assert(GetSize(sig) == GetSize(value));
log_assert(GetSize(sig) <= GetSize(value));
for (int i = 0; i < GetSize(sig); i++)
if (state_nets.at(sig[i]) != value[i]) {

View File

@ -29,17 +29,17 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; if; mfs2"
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; cover {I} {P}"
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_FAST_COMMAND_LIB "strash; dretime; retime {D}; map {D}"
#define ABC_FAST_COMMAND_CTR "strash; dretime; retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_FAST_COMMAND_LUT "strash; dretime; retime {D}; if"
#define ABC_FAST_COMMAND_SOP "strash; dretime; retime {D}; cover -I {I} -P {P}"
#define ABC_FAST_COMMAND_DFL "strash; dretime; retime {D}; map"
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@ -749,6 +749,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
if (script_file.empty() && !delay_target.empty())
for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
@ -1769,7 +1773,7 @@ struct AbcPass : public Pass {
extra_args(args, argidx, design);
if (!lut_costs.empty() && !liberty_file.empty())
log_cmd_error("Got -lut and -liberty! This two options are exclusive.\n");
log_cmd_error("Got -lut and -liberty! These two options are exclusive.\n");
if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n");

View File

@ -985,29 +985,28 @@ struct Abc9Pass : public Pass {
//}
if (arg == "-lut" && argidx+1 < args.size()) {
string arg = args[++argidx];
size_t pos = arg.find_first_of(':');
int lut_mode = 0, lut_mode2 = 0;
if (pos != string::npos) {
lut_mode = atoi(arg.substr(0, pos).c_str());
lut_mode2 = atoi(arg.substr(pos+1).c_str());
} else {
pos = arg.find_first_of('.');
if (arg.find_first_not_of("0123456789:") == std::string::npos) {
size_t pos = arg.find_first_of(':');
int lut_mode = 0, lut_mode2 = 0;
if (pos != string::npos) {
lut_file = arg;
rewrite_filename(lut_file);
if (!lut_file.empty() && !is_absolute_path(lut_file))
lut_file = std::string(pwd) + "/" + lut_file;
}
else {
lut_mode = atoi(arg.substr(0, pos).c_str());
lut_mode2 = atoi(arg.substr(pos+1).c_str());
} else {
lut_mode = atoi(arg.c_str());
lut_mode2 = lut_mode;
}
lut_costs.clear();
for (int i = 0; i < lut_mode; i++)
lut_costs.push_back(1);
for (int i = lut_mode; i < lut_mode2; i++)
lut_costs.push_back(2 << (i - lut_mode));
}
else {
lut_file = arg;
rewrite_filename(lut_file);
if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+')
lut_file = std::string(pwd) + "/" + lut_file;
}
lut_costs.clear();
for (int i = 0; i < lut_mode; i++)
lut_costs.push_back(1);
for (int i = lut_mode; i < lut_mode2; i++)
lut_costs.push_back(2 << (i - lut_mode));
continue;
}
if (arg == "-luts" && argidx+1 < args.size()) {
@ -1076,7 +1075,7 @@ struct Abc9Pass : public Pass {
box_file = "+/dummy.box";
rewrite_filename(box_file);
if (!box_file.empty() && !is_absolute_path(box_file))
if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+')
box_file = std::string(pwd) + "/" + box_file;
dict<int,IdString> box_lookup;

View File

@ -192,11 +192,28 @@ struct IopadmapPass : public Pass {
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
{
dict<SigBit, Cell *> tbuf_bits;
pool<SigBit> driven_bits;
// Gather tristate buffers and always-on drivers.
for (auto cell : module->cells())
if (cell->type == ID($_TBUF_)) {
SigBit bit = cell->getPort(ID::Y).as_bit();
tbuf_bits[bit] = cell;
} else {
for (auto port : cell->connections())
if (!cell->known() || cell->output(port.first))
for (auto bit : port.second)
driven_bits.insert(bit);
}
// If a wire is a target of an assignment, it is driven, unless the source is 'z.
for (auto &conn : module->connections())
for (int i = 0; i < GetSize(conn.first); i++) {
SigBit dstbit = conn.first[i];
SigBit srcbit = conn.second[i];
if (!srcbit.wire && srcbit.data == State::Sz)
continue;
driven_bits.insert(dstbit);
}
for (auto wire : module->selected_wires())
@ -204,41 +221,71 @@ struct IopadmapPass : public Pass {
if (!wire->port_output)
continue;
// Don't handle inout ports if we have no suitable buffer type.
if (wire->port_input && tinoutpad_celltype.empty())
continue;
// likewise for output ports.
if (!wire->port_input && toutpad_celltype.empty())
continue;
for (int i = 0; i < GetSize(wire); i++)
{
SigBit wire_bit(wire, i);
Cell *tbuf_cell = nullptr;
if (tbuf_bits.count(wire_bit) == 0)
if (skip_wire_bits.count(wire_bit))
continue;
Cell *tbuf_cell = tbuf_bits.at(wire_bit);
if (tbuf_bits.count(wire_bit))
tbuf_cell = tbuf_bits.at(wire_bit);
if (tbuf_cell == nullptr)
continue;
SigBit en_sig;
SigBit data_sig;
bool is_driven = driven_bits.count(wire_bit);
SigBit en_sig = tbuf_cell->getPort(ID(E)).as_bit();
SigBit data_sig = tbuf_cell->getPort(ID::A).as_bit();
if (tbuf_cell != nullptr) {
// Found a tristate buffer — use it.
en_sig = tbuf_cell->getPort(ID(E)).as_bit();
data_sig = tbuf_cell->getPort(ID::A).as_bit();
} else if (is_driven) {
// No tristate buffer, but an always-on driver is present.
// If this is an inout port, we're creating a tinoutpad
// anyway, just with a constant 1 as enable.
if (!wire->port_input)
continue;
en_sig = SigBit(State::S1);
data_sig = wire_bit;
} else {
// No driver on a wire. Create a tristate pad with always-0
// enable.
en_sig = SigBit(State::S0);
data_sig = SigBit(State::Sx);
}
if (wire->port_input && !tinoutpad_celltype.empty())
if (wire->port_input)
{
log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, tinoutpad_celltype.c_str());
Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(tinoutpad_celltype));
cell->setPort(RTLIL::escape_id(tinoutpad_portname_oe), en_sig);
cell->setPort(RTLIL::escape_id(tinoutpad_portname_o), wire_bit);
cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), data_sig);
cell->attributes[ID::keep] = RTLIL::Const(1);
module->remove(tbuf_cell);
if (tbuf_cell) {
module->remove(tbuf_cell);
cell->setPort(RTLIL::escape_id(tinoutpad_portname_o), wire_bit);
cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), data_sig);
} else if (is_driven) {
cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), wire_bit);
} else {
cell->setPort(RTLIL::escape_id(tinoutpad_portname_o), wire_bit);
cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), data_sig);
}
skip_wire_bits.insert(wire_bit);
if (!tinoutpad_portname_pad.empty())
rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(tinoutpad_portname_pad));
continue;
}
if (!wire->port_input && !toutpad_celltype.empty())
{
} else {
log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, toutpad_celltype.c_str());
Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(toutpad_celltype));
@ -247,12 +294,13 @@ struct IopadmapPass : public Pass {
cell->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig);
cell->attributes[ID::keep] = RTLIL::Const(1);
module->remove(tbuf_cell);
module->connect(wire_bit, data_sig);
if (tbuf_cell) {
module->remove(tbuf_cell);
module->connect(wire_bit, data_sig);
}
skip_wire_bits.insert(wire_bit);
if (!toutpad_portname_pad.empty())
rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(toutpad_portname_pad));
continue;
}
}
}

View File

@ -52,7 +52,7 @@ struct SynthAchronixPass : public ScriptPass {
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
@ -152,12 +152,12 @@ struct SynthAchronixPass : public ScriptPass {
run("clean -purge");
run("setundef -undriven -zero");
if (retime || help_mode)
run("abc -markgroups -dff", "(only if -retime)");
run("abc -markgroups -dff -D 1", "(only if -retime)");
}
if (check_label("map_luts"))
{
run("abc -lut 4" + string(retime ? " -dff" : ""));
run("abc -lut 4" + string(retime ? " -dff -D 1" : ""));
run("clean");
}

View File

@ -7,6 +7,6 @@ $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_sim.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/eagle_bb.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams.txt))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams_map.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/dram_init_16x4.vh))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutrams.txt))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutrams_map.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutram_init_16x4.vh))

View File

@ -6,14 +6,14 @@ module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REG
module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
module \$_DLATCH_N_ (E, D, Q);
wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";

View File

@ -10,7 +10,7 @@ module \$__ANLOGIC_DRAM16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
input B1EN;
EG_LOGIC_DRAM16X4 #(
`include "dram_init_16x4.vh"
`include "lutram_init_16x4.vh"
) _TECHMAP_REPLACE_ (
.di(B1DATA),
.waddr(B1ADDR),

View File

@ -58,7 +58,10 @@ struct SynthAnlogicPass : public ScriptPass
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log(" -nolutram\n");
log(" do not use EG_LOGIC_DRAM16X4 cells in output netlist\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
@ -67,7 +70,7 @@ struct SynthAnlogicPass : public ScriptPass
}
string top_opt, edif_file, json_file;
bool flatten, retime;
bool flatten, retime, nolutram;
void clear_flags() YS_OVERRIDE
{
@ -76,6 +79,7 @@ struct SynthAnlogicPass : public ScriptPass
json_file = "";
flatten = true;
retime = false;
nolutram = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -110,6 +114,10 @@ struct SynthAnlogicPass : public ScriptPass
flatten = false;
continue;
}
if (args[argidx] == "-nolutram") {
nolutram = true;
continue;
}
if (args[argidx] == "-retime") {
retime = true;
continue;
@ -150,21 +158,25 @@ struct SynthAnlogicPass : public ScriptPass
run("synth -run coarse");
}
if (check_label("dram"))
if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
{
run("memory_bram -rules +/anlogic/drams.txt");
run("techmap -map +/anlogic/drams_map.v");
run("memory_bram -rules +/anlogic/lutrams.txt");
run("techmap -map +/anlogic/lutrams_map.v");
run("setundef -zero -params t:EG_LOGIC_DRAM16X4");
}
if (check_label("fine"))
if (check_label("map_ffram"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
}
if (check_label("map_gates"))
{
run("techmap -map +/techmap.v -map +/anlogic/arith_map.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
run("abc -dff -D 1", "(only if -retime)");
}
if (check_label("map_ffs"))
@ -187,7 +199,7 @@ struct SynthAnlogicPass : public ScriptPass
run("techmap -map +/anlogic/cells_map.v");
run("clean");
}
if (check_label("map_anlogic"))
{
run("anlogic_fixcarry");

View File

@ -55,7 +55,7 @@ struct SynthCoolrunner2Pass : public ScriptPass
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
@ -161,7 +161,7 @@ struct SynthCoolrunner2Pass : public ScriptPass
if (check_label("map_pla"))
{
run("abc -sop -I 40 -P 56");
run("abc -sop -I 40 -P 56" + string(retime ? " -dff -D 1" : ""));
run("clean");
}

View File

@ -56,7 +56,7 @@ struct SynthEasicPass : public ScriptPass
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
@ -158,7 +158,7 @@ struct SynthEasicPass : public ScriptPass
run("techmap");
run("opt -fast");
if (retime || help_mode) {
run("abc -dff", " (only if -retime)");
run("abc -dff -D 1", " (only if -retime)");
run("opt_clean", "(only if -retime)");
}
}

View File

@ -8,9 +8,9 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutram.txt))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams.txt))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams.txt))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v))

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_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
`ifdef ASYNC_PRLD
module \$_DLATCH_N_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(!E), .DI(1'b0), .M(D), .Q(Q)); endmodule
module \$_DLATCH_P_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(E), .DI(1'b0), .M(D), .Q(Q)); endmodule
module \$_DFFSR_NNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule
module \$_DFFSR_NNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule
module \$_DFFSR_NPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule
module \$_DFFSR_NPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule
module \$_DFFSR_PNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule
module \$_DFFSR_PNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule
module \$_DFFSR_PPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule
module \$_DFFSR_PPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule
`endif
`include "cells_ff.vh"
`include "cells_io.vh"

View File

@ -1,5 +1,6 @@
// ---------------------------------------
(* lib_whitebox *)
module LUT4(input A, B, C, D, output Z);
parameter [15:0] INIT = 16'h0000;
wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0];
@ -31,13 +32,8 @@ module CCU2C(
// First half
wire LUT4_0, LUT2_0;
`ifdef _ABC
assign LUT4_0 = INIT0[{D0, C0, B0, A0}];
assign LUT2_0 = INIT0[{2'b00, B0, A0}];
`else
LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0));
LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0));
`endif
wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN;
assign S0 = LUT4_0 ^ gated_cin_0;
@ -46,13 +42,8 @@ module CCU2C(
// Second half
wire LUT4_1, LUT2_1;
`ifdef _ABC
assign LUT4_1 = INIT1[{D1, C1, B1, A1}];
assign LUT2_1 = INIT1[{2'b00, B1, A1}];
`else
LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1));
LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1));
`endif
wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0;
assign S1 = LUT4_1 ^ gated_cin_1;
@ -209,6 +200,7 @@ endmodule
// ---------------------------------------
(* lib_whitebox *)
module LUT2(input A, B, output Z);
parameter [3:0] INIT = 4'h0;
wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0];

View File

@ -62,7 +62,7 @@ struct SynthEcp5Pass : public ScriptPass
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log(" -noccu2\n");
log(" do not use CCU2 cells in output netlist\n");
@ -79,6 +79,9 @@ struct SynthEcp5Pass : public ScriptPass
log(" -nowidelut\n");
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
log("\n");
log(" -asyncprld\n");
log(" use async PRLD mode to implement DLATCH and DFFSR (EXPERIMENTAL)\n");
log("\n");
log(" -abc2\n");
log(" run two passes of 'abc' for slightly improved logic density\n");
log("\n");
@ -99,7 +102,7 @@ struct SynthEcp5Pass : public ScriptPass
}
string top_opt, blif_file, edif_file, json_file;
bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, nodsp, vpr;
bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, retime, abc2, abc9, nodsp, vpr;
void clear_flags() YS_OVERRIDE
{
@ -112,6 +115,7 @@ struct SynthEcp5Pass : public ScriptPass
nobram = false;
nolutram = false;
nowidelut = false;
asyncprld = false;
flatten = true;
retime = false;
abc2 = false;
@ -176,6 +180,10 @@ struct SynthEcp5Pass : public ScriptPass
nobram = true;
continue;
}
if (args[argidx] == "-asyncprld") {
asyncprld = true;
continue;
}
if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
nolutram = true;
continue;
@ -222,7 +230,7 @@ struct SynthEcp5Pass : public ScriptPass
{
if (check_label("begin"))
{
run("read_verilog -D_ABC -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v");
run("read_verilog -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
@ -258,13 +266,13 @@ struct SynthEcp5Pass : public ScriptPass
if (!nobram && check_label("map_bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/ecp5/bram.txt");
run("memory_bram -rules +/ecp5/brams.txt");
run("techmap -map +/ecp5/brams_map.v");
}
if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
{
run("memory_bram -rules +/ecp5/lutram.txt");
run("memory_bram -rules +/ecp5/lutrams.txt");
run("techmap -map +/ecp5/lutrams_map.v");
}
@ -282,7 +290,7 @@ struct SynthEcp5Pass : public ScriptPass
else
run("techmap -map +/techmap.v -map +/ecp5/arith_map.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
run("abc -dff -D 1", "(only if -retime)");
}
if (check_label("map_ffs"))
@ -292,7 +300,7 @@ struct SynthEcp5Pass : public ScriptPass
run("opt_clean");
if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : "")));
run("opt_expr -undriven -mux_undef");
run("simplemap");
run("ecp5_ffinit");
@ -306,10 +314,11 @@ struct SynthEcp5Pass : public ScriptPass
if (abc2 || help_mode) {
run("abc", " (only if -abc2)");
}
std::string techmap_args = "-map +/ecp5/latches_map.v";
std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v";
if (abc9)
techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1";
run("techmap " + techmap_args);
if (!asyncprld || abc9)
run("techmap " + techmap_args);
if (abc9) {
run("read_verilog -icells -lib +/ecp5/abc9_model.v");

View File

@ -7,4 +7,4 @@ $(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/arith_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/brams_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/bram.txt))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/brams.txt))

View File

@ -58,7 +58,10 @@ struct SynthEfinixPass : public ScriptPass
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log(" -nobram\n");
log(" do not use EFX_RAM_5K cells in output netlist\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
@ -67,7 +70,7 @@ struct SynthEfinixPass : public ScriptPass
}
string top_opt, edif_file, json_file;
bool flatten, retime;
bool flatten, retime, nobram;
void clear_flags() YS_OVERRIDE
{
@ -76,6 +79,7 @@ struct SynthEfinixPass : public ScriptPass
json_file = "";
flatten = true;
retime = false;
nobram = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -114,6 +118,10 @@ struct SynthEfinixPass : public ScriptPass
retime = true;
continue;
}
if (args[argidx] == "-nobram") {
nobram = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -150,21 +158,25 @@ struct SynthEfinixPass : public ScriptPass
run("synth -run coarse");
}
if (check_label("map_bram", "(skip if -nobram)"))
if (!nobram || check_label("map_bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/efinix/bram.txt");
run("memory_bram -rules +/efinix/brams.txt");
run("techmap -map +/efinix/brams_map.v");
run("setundef -zero -params t:EFX_RAM_5K");
}
if (check_label("fine"))
if (check_label("map_ffram"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
}
if (check_label("map_gates"))
{
run("techmap -map +/techmap.v -map +/efinix/arith_map.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
run("abc -dff -D 1", "(only if -retime)");
}
if (check_label("map_ffs"))
@ -194,7 +206,7 @@ struct SynthEfinixPass : public ScriptPass
run("efinix_fixcarry");
run("clean");
}
if (check_label("check"))
{
run("hierarchy -check");

View File

@ -7,9 +7,9 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt))

View File

@ -55,23 +55,23 @@ struct SynthGowinPass : public ScriptPass
log(" -nobram\n");
log(" do not use BRAM cells in output netlist\n");
log("\n");
log(" -nodram\n");
log(" -nolutram\n");
log(" do not use distributed RAM cells in output netlist\n");
log("\n");
log(" -noflatten\n");
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log(" -nowidelut\n");
log(" do not use muxes to implement LUTs larger than LUT4s\n");
log("\n");
log(" -noiopads\n");
log(" do not emit IOB at top level ports\n");
log("\n");
log(" -abc9\n");
log(" use new ABC9 flow (EXPERIMENTAL)\n");
//log("\n");
//log(" -abc9\n");
//log(" use new ABC9 flow (EXPERIMENTAL)\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
@ -80,7 +80,7 @@ struct SynthGowinPass : public ScriptPass
}
string top_opt, vout_file;
bool retime, nobram, nodram, flatten, nodffe, nowidelut, abc9, noiopads;
bool retime, nobram, nolutram, flatten, nodffe, nowidelut, abc9, noiopads;
void clear_flags() YS_OVERRIDE
{
@ -90,7 +90,7 @@ struct SynthGowinPass : public ScriptPass
flatten = true;
nobram = false;
nodffe = false;
nodram = false;
nolutram = false;
nowidelut = false;
abc9 = false;
noiopads = false;
@ -128,8 +128,8 @@ struct SynthGowinPass : public ScriptPass
nobram = true;
continue;
}
if (args[argidx] == "-nodram") {
nodram = true;
if (args[argidx] == "-nolutram" || /*deprecated*/args[argidx] == "-nodram") {
nolutram = true;
continue;
}
if (args[argidx] == "-nodffe") {
@ -144,10 +144,10 @@ struct SynthGowinPass : public ScriptPass
nowidelut = true;
continue;
}
if (args[argidx] == "-abc9") {
abc9 = true;
continue;
}
//if (args[argidx] == "-abc9") {
// abc9 = true;
// continue;
//}
if (args[argidx] == "-noiopads") {
noiopads = true;
continue;
@ -188,28 +188,32 @@ struct SynthGowinPass : public ScriptPass
run("synth -run coarse");
}
if (!nobram && check_label("bram", "(skip if -nobram)"))
if (!nobram && check_label("map_bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/gowin/bram.txt");
run("memory_bram -rules +/gowin/brams.txt");
run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v");
}
if (!nodram && check_label("dram", "(skip if -nodram)"))
if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
{
run("memory_bram -rules +/gowin/dram.txt");
run("techmap -map +/gowin/drams_map.v");
run("memory_bram -rules +/gowin/lutrams.txt");
run("techmap -map +/gowin/lutrams_map.v");
run("determine_init");
}
if (check_label("fine"))
if (check_label("map_ffram"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
}
if (check_label("map_gates"))
{
run("techmap -map +/techmap.v -map +/gowin/arith_map.v");
run("techmap -map +/techmap.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
run("abc -dff -D 1", "(only if -retime)");
run("splitnets");
}
@ -227,13 +231,13 @@ struct SynthGowinPass : public ScriptPass
if (check_label("map_luts"))
{
if (nowidelut && abc9) {
/*if (nowidelut && abc9) {
run("abc9 -lut 4");
} else if (nowidelut && !abc9) {
} else*/ if (nowidelut && !abc9) {
run("abc -lut 4");
} else if (!nowidelut && abc9) {
} else /*if (!nowidelut && abc9) {
run("abc9 -lut 4:8");
} else if (!nowidelut && !abc9) {
} else*/ if (!nowidelut && !abc9) {
run("abc -lut 4:8");
}
run("clean");
@ -248,7 +252,6 @@ struct SynthGowinPass : public ScriptPass
run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O "
"-toutpad TBUF OEN:I:O -tinoutpad IOBUF OEN:O:I:IO", "(unless -noiopads)");
run("clean");
}
if (check_label("check"))

View File

@ -59,7 +59,7 @@ struct SynthGreenPAK4Pass : public ScriptPass
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
@ -165,7 +165,7 @@ struct SynthGreenPAK4Pass : public ScriptPass
run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib");
run("opt -fast");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
run("abc -dff -D 1", "(only if -retime)");
}
if (check_label("map_luts"))

View File

@ -65,7 +65,7 @@ struct SynthIce40Pass : public ScriptPass
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log(" -nocarry\n");
log(" do not use SB_CARRY cells in output netlist\n");
@ -316,7 +316,7 @@ struct SynthIce40Pass : public ScriptPass
run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
}
if (retime || help_mode)
run(abc + " -dff", "(only if -retime)");
run(abc + " -dff -D 1", "(only if -retime)");
run("ice40_opt");
}

View File

@ -71,7 +71,7 @@ struct SynthIntelPass : public ScriptPass {
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
@ -187,10 +187,10 @@ struct SynthIntelPass : public ScriptPass {
}
if (!nobram && check_label("map_bram", "(skip if -nobram)")) {
if (family_opt == "cycloneiv" ||
family_opt == "cycloneive" ||
family_opt == "max10" ||
help_mode) {
if (family_opt == "cycloneiv" ||
family_opt == "cycloneive" ||
family_opt == "max10" ||
help_mode) {
run("memory_bram -rules +/intel/common/brams_m9k.txt", "(if applicable for family)");
run("techmap -map +/intel/common/brams_map_m9k.v", "(if applicable for family)");
} else {
@ -210,7 +210,7 @@ struct SynthIntelPass : public ScriptPass {
run("clean -purge");
run("setundef -undriven -zero");
if (retime || help_mode)
run("abc -markgroups -dff", "(only if -retime)");
run("abc -markgroups -dff -D 1", "(only if -retime)");
}
if (check_label("map_luts")) {
@ -224,7 +224,7 @@ struct SynthIntelPass : public ScriptPass {
if (check_label("map_cells")) {
if (iopads || help_mode)
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(if -iopads)");
run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str()));
run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str()));
run("dffinit -highlow -ff dffeas q power_up");
run("clean -purge");
}

View File

@ -67,7 +67,7 @@ struct SynthSf2Pass : public ScriptPass
log(" insert direct PAD->global_net buffers\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
@ -181,7 +181,7 @@ struct SynthSf2Pass : public ScriptPass
run("opt -undriven -fine");
run("techmap -map +/techmap.v -map +/sf2/arith_map.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
run("abc -dff -D 1", "(only if -retime)");
}
if (check_label("map_ffs"))

View File

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

View File

@ -88,6 +88,84 @@ module RAM128X1D (
\$__ABC9_LUT7 dpo (.A(\$DPO ), .S(DPRA), .Y(DPO));
endmodule
module RAM32M (
output [1:0] DOA,
output [1:0] DOB,
output [1:0] DOC,
output [1:0] DOD,
(* techmap_autopurge *) input [4:0] ADDRA,
(* techmap_autopurge *) input [4:0] ADDRB,
(* techmap_autopurge *) input [4:0] ADDRC,
(* techmap_autopurge *) input [4:0] ADDRD,
(* techmap_autopurge *) input [1:0] DIA,
(* techmap_autopurge *) input [1:0] DIB,
(* techmap_autopurge *) input [1:0] DIC,
(* techmap_autopurge *) input [1:0] DID,
(* techmap_autopurge *) input WCLK,
(* techmap_autopurge *) input WE
);
parameter [63:0] INIT_A = 64'h0000000000000000;
parameter [63:0] INIT_B = 64'h0000000000000000;
parameter [63:0] INIT_C = 64'h0000000000000000;
parameter [63:0] INIT_D = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
wire [1:0] \$DOA , \$DOB , \$DOC , \$DOD ;
RAM32M #(
.INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D),
.IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ (
.DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ),
.WCLK(WCLK), .WE(WE),
.ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD),
.DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID)
);
\$__ABC9_LUT6 doa0 (.A(\$DOA [0]), .S({1'b1, ADDRA}), .Y(DOA[0]));
\$__ABC9_LUT6 doa1 (.A(\$DOA [1]), .S({1'b1, ADDRA}), .Y(DOA[1]));
\$__ABC9_LUT6 dob0 (.A(\$DOB [0]), .S({1'b1, ADDRB}), .Y(DOB[0]));
\$__ABC9_LUT6 dob1 (.A(\$DOB [1]), .S({1'b1, ADDRB}), .Y(DOB[1]));
\$__ABC9_LUT6 doc0 (.A(\$DOC [0]), .S({1'b1, ADDRC}), .Y(DOC[0]));
\$__ABC9_LUT6 doc1 (.A(\$DOC [1]), .S({1'b1, ADDRC}), .Y(DOC[1]));
\$__ABC9_LUT6 dod0 (.A(\$DOD [0]), .S({1'b1, ADDRD}), .Y(DOD[0]));
\$__ABC9_LUT6 dod1 (.A(\$DOD [1]), .S({1'b1, ADDRD}), .Y(DOD[1]));
endmodule
module RAM64M (
output DOA,
output DOB,
output DOC,
output DOD,
(* techmap_autopurge *) input [5:0] ADDRA,
(* techmap_autopurge *) input [5:0] ADDRB,
(* techmap_autopurge *) input [5:0] ADDRC,
(* techmap_autopurge *) input [5:0] ADDRD,
(* techmap_autopurge *) input DIA,
(* techmap_autopurge *) input DIB,
(* techmap_autopurge *) input DIC,
(* techmap_autopurge *) input DID,
(* techmap_autopurge *) input WCLK,
(* techmap_autopurge *) input WE
);
parameter [63:0] INIT_A = 64'h0000000000000000;
parameter [63:0] INIT_B = 64'h0000000000000000;
parameter [63:0] INIT_C = 64'h0000000000000000;
parameter [63:0] INIT_D = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
wire \$DOA , \$DOB , \$DOC , \$DOD ;
RAM64M #(
.INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D),
.IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ (
.DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ),
.WCLK(WCLK), .WE(WE),
.ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD),
.DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID)
);
\$__ABC9_LUT6 doa (.A(\$DOA ), .S(ADDRA), .Y(DOA));
\$__ABC9_LUT6 dob (.A(\$DOB ), .S(ADDRB), .Y(DOB));
\$__ABC9_LUT6 doc (.A(\$DOC ), .S(ADDRC), .Y(DOC));
\$__ABC9_LUT6 dod (.A(\$DOD ), .S(ADDRD), .Y(DOD));
endmodule
module SRL16E (
output Q,
(* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D

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_" *)
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$__DFFE_NN0" *)
module _90_dffe_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
(* techmap_celltype = "$__DFFE_PN0" *)
module _90_dffe_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
(* techmap_celltype = "$__DFFE_NN1" *)
module _90_dffe_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
(* techmap_celltype = "$__DFFE_PN1" *)
module _90_dffe_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
(* techmap_celltype = "$__DFFS_NN0_" *)
module _90_dffs_nn0_to_np0 (input D, C, R, output Q); \$__DFFS_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$__DFFS_PN0_" *)
module _90_dffs_pn0_to_pp0 (input D, C, R, output Q); \$__DFFS_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$__DFFS_NN1_" *)
module _90_dffs_nn1_to_np1 (input D, C, R, output Q); \$__DFFS_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$__DFFS_PN1_" *)
module _90_dffs_pn1_to_pp1 (input D, C, R, output Q); \$__DFFS_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$__DFFSE_NN0" *)
module _90_dffse_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFSE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
(* techmap_celltype = "$__DFFSE_PN0" *)
module _90_dffse_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFSE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
(* techmap_celltype = "$__DFFSE_NN1" *)
module _90_dffse_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFSE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
(* techmap_celltype = "$__DFFSE_PN1" *)
module _90_dffse_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFSE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0;

View File

@ -227,6 +227,14 @@ module MUXCY(output O, input CI, DI, S);
assign O = S ? CI : DI;
endmodule
module MUXF5(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
module MUXF6(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
(* abc9_box_id = 1, lib_whitebox *)
module MUXF7(output O, input I0, I1, S);
assign O = S ? I1 : I0;
@ -237,6 +245,10 @@ module MUXF8(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
module MUXF9(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
module XORCY(output O, input CI, LI);
assign O = CI ^ LI;
endmodule
@ -258,6 +270,26 @@ module CARRY4(
assign CO[3] = S[3] ? CO[2] : DI[3];
endmodule
module CARRY8(
output [7:0] CO,
output [7:0] O,
input CI,
input CI_TOP,
input [7:0] DI, S
);
parameter CARRY_TYPE = "SINGLE_CY8";
wire CI4 = (CARRY_TYPE == "DUAL_CY4" ? CI_TOP : CO[3]);
assign O = S ^ {CO[6:4], CI4, CO[2:0], CI};
assign CO[0] = S[0] ? CI : DI[0];
assign CO[1] = S[1] ? CO[0] : DI[1];
assign CO[2] = S[2] ? CO[1] : DI[2];
assign CO[3] = S[3] ? CO[2] : DI[3];
assign CO[4] = S[4] ? CI4 : DI[4];
assign CO[5] = S[5] ? CO[4] : DI[5];
assign CO[6] = S[6] ? CO[5] : DI[6];
assign CO[7] = S[7] ? CO[6] : DI[7];
endmodule
`ifdef _EXPLICIT_CARRY
module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
@ -281,6 +313,16 @@ endmodule
`endif
module ORCY (output O, input CI, I);
assign O = CI | I;
endmodule
module MULT_AND (output LO, input I0, I1);
assign LO = I0 & I1;
endmodule
// Flip-flops and latches.
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
module FDRE (
@ -329,6 +371,41 @@ module FDSE (
endcase endgenerate
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 (
(* abc9_arrival=303 *)
output reg Q,
@ -379,6 +456,51 @@ module FDPE (
endcase endgenerate
endmodule
module FDCPE (
output wire Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
input CE,
(* invertible_pin = "IS_CLR_INVERTED" *)
input CLR,
input D,
(* invertible_pin = "IS_PRE_INVERTED" *)
input PRE
);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_CLR_INVERTED = 1'b0;
parameter [0:0] IS_PRE_INVERTED = 1'b0;
wire c = C ^ IS_C_INVERTED;
wire clr = CLR ^ IS_CLR_INVERTED;
wire pre = PRE ^ IS_PRE_INVERTED;
// Hacky model to avoid simulation-synthesis mismatches.
reg qc, qp, qs;
initial qc = INIT;
initial qp = INIT;
initial qs = 0;
always @(posedge c, posedge clr) begin
if (clr)
qc <= 0;
else if (CE)
qc <= D;
end
always @(posedge c, posedge pre) begin
if (pre)
qp <= 1;
else if (CE)
qp <= D;
end
always @* begin
if (clr)
qs <= 0;
else if (pre)
qs <= 1;
end
assign Q = qs ? qp : qc;
endmodule
module FDRE_1 (
(* abc9_arrival=303 *)
output reg Q,
@ -445,8 +567,8 @@ module LDCE (
wire clr = CLR ^ IS_CLR_INVERTED;
wire g = G ^ IS_G_INVERTED;
always @*
if (clr) Q = 1'b0;
else if (GE && g) Q = D;
if (clr) Q <= 1'b0;
else if (GE && g) Q <= D;
endmodule
module LDPE (
@ -467,8 +589,59 @@ module LDPE (
wire g = G ^ IS_G_INVERTED;
wire pre = PRE ^ IS_PRE_INVERTED;
always @*
if (pre) Q = 1'b1;
else if (GE && g) Q = D;
if (pre) Q <= 1'b1;
else if (GE && g) Q <= D;
endmodule
module LDCPE (
output reg Q,
(* invertible_pin = "IS_CLR_INVERTED" *)
input CLR,
(* invertible_pin = "IS_D_INVERTED" *)
input D,
(* invertible_pin = "IS_G_INVERTED" *)
input G,
(* invertible_pin = "IS_GE_INVERTED" *)
input GE,
(* invertible_pin = "IS_PRE_INVERTED" *)
input PRE
);
parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_CLR_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_G_INVERTED = 1'b0;
parameter [0:0] IS_GE_INVERTED = 1'b0;
parameter [0:0] IS_PRE_INVERTED = 1'b0;
initial Q = INIT;
wire d = D ^ IS_D_INVERTED;
wire g = G ^ IS_G_INVERTED;
wire ge = GE ^ IS_GE_INVERTED;
wire clr = CLR ^ IS_CLR_INVERTED;
wire pre = PRE ^ IS_PRE_INVERTED;
always @*
if (clr) Q <= 1'b0;
else if (pre) Q <= 1'b1;
else if (ge && g) Q <= d;
endmodule
module AND2B1L (
output O,
input DI,
(* invertible_pin = "IS_SRI_INVERTED" *)
input SRI
);
parameter [0:0] IS_SRI_INVERTED = 1'b0;
assign O = DI & ~(SRI ^ IS_SRI_INVERTED);
endmodule
module OR2L (
output O,
input DI,
(* invertible_pin = "IS_SRI_INVERTED" *)
input SRI
);
parameter [0:0] IS_SRI_INVERTED = 1'b0;
assign O = DI | (SRI ^ IS_SRI_INVERTED);
endmodule
// LUTRAM.
@ -939,8 +1112,8 @@ module RAM16X1D_1 (
endmodule
module RAM32X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc9_arrival=1153 *)
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
(* abc9_arrival=1188 *)
output DPO, SPO,
input D,
(* clkbuf_sink *)
@ -962,8 +1135,8 @@ module RAM32X1D (
endmodule
module RAM32X1D_1 (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc9_arrival=1153 *)
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
(* abc9_arrival=1188 *)
output DPO, SPO,
input D,
(* clkbuf_sink *)
@ -985,7 +1158,7 @@ module RAM32X1D_1 (
endmodule
module RAM64X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
(* abc9_arrival=1153 *)
output DPO, SPO,
input D,
@ -1008,7 +1181,7 @@ module RAM64X1D (
endmodule
module RAM64X1D_1 (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
(* abc9_arrival=1153 *)
output DPO, SPO,
input D,
@ -1031,8 +1204,9 @@ module RAM64X1D_1 (
endmodule
module RAM128X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc9_arrival=1153 *)
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
// plus 204ps to cross MUXF7
(* abc9_arrival=1357 *)
output DPO, SPO,
input D,
(* clkbuf_sink *)
@ -1071,18 +1245,20 @@ endmodule
// Multi port.
module RAM32M (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
(* abc9_arrival=1188 *)
output [1:0] DOA,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925
(* abc9_arrival=1187 *)
output [1:0] DOB,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993
(* abc9_arrival=1180 *)
output [1:0] DOC,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061
(* abc9_arrival=1190 *)
output [1:0] DOD,
input [4:0] ADDRA,
input [4:0] ADDRB,
input [4:0] ADDRC,
input [4:0] ADDRD,
input [1:0] DIA,
input [1:0] DIB,
input [1:0] DIC,
input [1:0] DID,
input [4:0] ADDRA, ADDRB, ADDRC, ADDRD,
input [1:0] DIA, DIB, DIC, DID,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK,
@ -1181,18 +1357,20 @@ module RAM32M16 (
endmodule
module RAM64M (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
(* abc9_arrival=1153 *)
output DOA,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc9_arrival=1161 *)
output DOB,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
(* abc9_arrival=1158 *)
output DOC,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
(* abc9_arrival=1163 *)
output DOD,
input [4:0] ADDRA,
input [4:0] ADDRB,
input [4:0] ADDRC,
input [4:0] ADDRD,
input DIA,
input DIB,
input DIC,
input DID,
input [5:0] ADDRA, ADDRB, ADDRC, ADDRD,
input DIA, DIB, DIC, DID,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK,
@ -1230,14 +1408,14 @@ module RAM64M8 (
output DOF,
output DOG,
output DOH,
input [4:0] ADDRA,
input [4:0] ADDRB,
input [4:0] ADDRC,
input [4:0] ADDRD,
input [4:0] ADDRE,
input [4:0] ADDRF,
input [4:0] ADDRG,
input [4:0] ADDRH,
input [5:0] ADDRA,
input [5:0] ADDRB,
input [5:0] ADDRC,
input [5:0] ADDRD,
input [5:0] ADDRE,
input [5:0] ADDRF,
input [5:0] ADDRG,
input [5:0] ADDRH,
input DIA,
input DIB,
input DIC,
@ -1334,8 +1512,22 @@ endmodule
// Shift registers.
module SRL16 (
output Q,
input A0, A1, A2, A3,
(* clkbuf_sink *)
input CLK,
input D
);
parameter [15:0] INIT = 16'h0000;
reg [15:0] r = INIT;
assign Q = r[{A3,A2,A1,A0}];
always @(posedge CLK) r <= { r[14:0], D };
endmodule
module SRL16E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905
(* abc9_arrival=1472 *)
output Q,
input A0, A1, A2, A3, CE,
@ -1358,6 +1550,22 @@ module SRL16E (
endgenerate
endmodule
module SRLC16 (
output Q,
output Q15,
input A0, A1, A2, A3,
(* clkbuf_sink *)
input CLK,
input D
);
parameter [15:0] INIT = 16'h0000;
reg [15:0] r = INIT;
assign Q15 = r[15];
assign Q = r[{A3,A2,A1,A0}];
always @(posedge CLK) r <= { r[14:0], D };
endmodule
module SRLC16E (
output Q,
output Q15,
@ -1383,9 +1591,10 @@ module SRLC16E (
endmodule
module SRLC32E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905
(* abc9_arrival=1472 *)
output Q,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904
(* abc9_arrival=1114 *)
output Q31,
input [4:0] A,
@ -1410,6 +1619,31 @@ module SRLC32E (
endgenerate
endmodule
module CFGLUT5 (
output CDO,
output O5,
output O6,
input I4,
input I3,
input I2,
input I1,
input I0,
input CDI,
input CE,
(* clkbuf_sink *)
(* invertible_pin = "IS_CLK_INVERTED" *)
input CLK
);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
wire clk = CLK ^ IS_CLK_INVERTED;
reg [31:0] r = INIT;
assign CDO = r[31];
assign O5 = r[{1'b0, I3, I2, I1, I0}];
assign O6 = r[{I4, I3, I2, I1, I0}];
always @(posedge clk) if (CE) r <= {r[30:0], CDI};
endmodule
// DSP
// Virtex 2, Virtex 2 Pro, Spartan 3.
@ -1885,7 +2119,7 @@ always @* begin
2'b00: XMUX <= 0;
2'b01: XMUX <= M;
2'b10: XMUX <= P;
2'b11: XMUX <= {D_OUT[11:0], B1_OUT, A1_OUT};
2'b11: XMUX <= {D_OUT[11:0], A1_OUT, B1_OUT};
default: XMUX <= 48'hxxxxxxxxxxxx;
endcase
end
@ -1903,8 +2137,8 @@ end
// The post-adder.
wire signed [48:0] X_EXT;
wire signed [48:0] Z_EXT;
assign X_EXT = XMUX;
assign Z_EXT = ZMUX;
assign X_EXT = {1'b0, XMUX};
assign Z_EXT = {1'b0, ZMUX};
assign {CARRYOUT_IN, P_IN} = OPMODE_OUT[7] ? (Z_EXT - (X_EXT + CARRYIN_OUT)) : (Z_EXT + X_EXT + CARRYIN_OUT);
// Cascade outputs.
@ -2002,7 +2236,7 @@ module DSP48E1 (
parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
initial begin
`ifdef __ICARUS__
`ifndef YOSYS
if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value");
if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
@ -2165,12 +2399,12 @@ module DSP48E1 (
case (OPMODEr[1:0])
2'b00: X = 48'b0;
2'b01: begin X = $signed(Mrx);
`ifdef __ICARUS__
`ifndef YOSYS
if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
`endif
end
2'b10: begin X = P;
`ifdef __ICARUS__
`ifndef YOSYS
if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
`endif
end
@ -2182,7 +2416,7 @@ module DSP48E1 (
case (OPMODEr[3:2])
2'b00: Y = 48'b0;
2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling?
`ifdef __ICARUS__
`ifndef YOSYS
if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
`endif
end
@ -2196,13 +2430,13 @@ module DSP48E1 (
3'b000: Z = 48'b0;
3'b001: Z = PCIN;
3'b010: begin Z = P;
`ifdef __ICARUS__
`ifndef YOSYS
if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
`endif
end
3'b011: Z = Cr;
3'b100: begin Z = P;
`ifdef __ICARUS__
`ifndef YOSYS
if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100");
if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
`endif

View File

@ -65,9 +65,9 @@ CELLS = [
# CLB -- registers/latches.
# Virtex 1/2/4/5, Spartan 3.
Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}),
Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}),
Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}),
# Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}),
# Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}),
# Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}),
# Virtex 6, Spartan 6, Series 7, Ultrascale.
# Cell('FDCE'),
# Cell('FDPE'),
@ -75,8 +75,8 @@ CELLS = [
# Cell('FDSE'),
# Cell('LDCE'),
# Cell('LDPE'),
Cell('AND2B1L'),
Cell('OR2L'),
# Cell('AND2B1L'),
# Cell('OR2L'),
# CLB -- other.
# Cell('LUT1'),
@ -86,23 +86,23 @@ CELLS = [
# Cell('LUT5'),
# Cell('LUT6'),
# Cell('LUT6_2'),
Cell('MUXF5'),
Cell('MUXF6'),
# Cell('MUXF5'),
# Cell('MUXF6'),
# Cell('MUXF7'),
# Cell('MUXF8'),
Cell('MUXF9'),
# Cell('MUXF9'),
# Cell('CARRY4'),
Cell('CARRY8'),
# Cell('CARRY8'),
# Cell('MUXCY'),
# Cell('XORCY'),
Cell('ORCY'),
Cell('MULT_AND'),
Cell('SRL16', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('ORCY'),
# Cell('MULT_AND'),
# Cell('SRL16', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}),
Cell('SRLC16', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('SRLC16', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('SRLC16E', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}),
Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}),
# Block RAM.
# Virtex.

View File

@ -1,165 +1,5 @@
// Created by cells_xtra.py from Xilinx models
module FDCPE (...);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_CLR_INVERTED = 1'b0;
parameter [0:0] IS_PRE_INVERTED = 1'b0;
output Q;
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C;
input CE;
(* invertible_pin = "IS_CLR_INVERTED" *)
input CLR;
input D;
(* invertible_pin = "IS_PRE_INVERTED" *)
input PRE;
endmodule
module FDRSE (...);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_CE_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_R_INVERTED = 1'b0;
parameter [0:0] IS_S_INVERTED = 1'b0;
output Q;
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C;
(* invertible_pin = "IS_CE_INVERTED" *)
input CE;
(* invertible_pin = "IS_D_INVERTED" *)
input D;
(* invertible_pin = "IS_R_INVERTED" *)
input R;
(* invertible_pin = "IS_S_INVERTED" *)
input S;
endmodule
module LDCPE (...);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_CLR_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_G_INVERTED = 1'b0;
parameter [0:0] IS_GE_INVERTED = 1'b0;
parameter [0:0] IS_PRE_INVERTED = 1'b0;
output Q;
(* invertible_pin = "IS_CLR_INVERTED" *)
input CLR;
(* invertible_pin = "IS_D_INVERTED" *)
input D;
(* invertible_pin = "IS_G_INVERTED" *)
input G;
(* invertible_pin = "IS_GE_INVERTED" *)
input GE;
(* invertible_pin = "IS_PRE_INVERTED" *)
input PRE;
endmodule
module AND2B1L (...);
parameter [0:0] IS_SRI_INVERTED = 1'b0;
output O;
input DI;
(* invertible_pin = "IS_SRI_INVERTED" *)
input SRI;
endmodule
module OR2L (...);
parameter [0:0] IS_SRI_INVERTED = 1'b0;
output O;
input DI;
(* invertible_pin = "IS_SRI_INVERTED" *)
input SRI;
endmodule
module MUXF5 (...);
output O;
input I0;
input I1;
input S;
endmodule
module MUXF6 (...);
output O;
input I0;
input I1;
input S;
endmodule
module MUXF9 (...);
output O;
input I0;
input I1;
input S;
endmodule
module CARRY8 (...);
parameter CARRY_TYPE = "SINGLE_CY8";
output [7:0] CO;
output [7:0] O;
input CI;
input CI_TOP;
input [7:0] DI;
input [7:0] S;
endmodule
module ORCY (...);
output O;
input CI;
input I;
endmodule
module MULT_AND (...);
output LO;
input I0;
input I1;
endmodule
module SRL16 (...);
parameter [15:0] INIT = 16'h0000;
output Q;
input A0;
input A1;
input A2;
input A3;
(* clkbuf_sink *)
input CLK;
input D;
endmodule
module SRLC16 (...);
parameter [15:0] INIT = 16'h0000;
output Q;
output Q15;
input A0;
input A1;
input A2;
input A3;
(* clkbuf_sink *)
input CLK;
input D;
endmodule
module CFGLUT5 (...);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
output CDO;
output O5;
output O6;
input I4;
input I3;
input I2;
input I1;
input I0;
input CDI;
input CE;
(* clkbuf_sink *)
(* invertible_pin = "IS_CLK_INVERTED" *)
input CLK;
endmodule
module RAMB16_S1 (...);
parameter [0:0] INIT = 1'h0;
parameter [0:0] SRVAL = 1'h0;

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
init 1
abits 5
@ -38,6 +51,70 @@ bram $__XILINX_RAM128X1D
clkpol 0 2
endbram
bram $__XILINX_RAM32X6SDP
init 1
abits 5
dbits 6
groups 2
ports 1 1
wrmode 0 1
enable 0 1
transp 0 0
clocks 0 1
clkpol 0 2
endbram
bram $__XILINX_RAM64X3SDP
init 1
abits 6
dbits 3
groups 2
ports 1 1
wrmode 0 1
enable 0 1
transp 0 0
clocks 0 1
clkpol 0 2
endbram
bram $__XILINX_RAM32X2Q
init 1
abits 5
dbits 2
groups 2
ports 3 1
wrmode 0 1
enable 0 1
transp 0 0
clocks 0 1
clkpol 0 2
endbram
bram $__XILINX_RAM64X1Q
init 1
abits 6
dbits 1
groups 2
ports 3 1
wrmode 0 1
enable 0 1
transp 0 0
clocks 0 1
clkpol 0 2
endbram
# Disabled for now, pending support for LUT4 arches
# since on LUT6 arches this occupies same area as
# a RAM32X1D
#match $__XILINX_RAM16X1D
# min bits 2
# min wports 1
# make_outreg
# or_next_if_better
#endmatch
match $__XILINX_RAM32X1D
min bits 3
min wports 1
@ -56,5 +133,35 @@ match $__XILINX_RAM128X1D
min bits 9
min wports 1
make_outreg
or_next_if_better
endmatch
match $__XILINX_RAM32X6SDP
min bits 5
min wports 1
make_outreg
or_next_if_better
endmatch
match $__XILINX_RAM64X3SDP
min bits 6
min wports 1
make_outreg
or_next_if_better
endmatch
match $__XILINX_RAM32X2Q
min bits 5
min rports 3
min wports 1
make_outreg
or_next_if_better
endmatch
match $__XILINX_RAM64X1Q
min bits 5
min rports 3
min wports 1
make_outreg
endmatch

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);
parameter [31:0] INIT = 32'bx;
parameter CLKPOL2 = 1;
@ -95,3 +127,153 @@ module \$__XILINX_RAM128X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
);
endmodule
module \$__XILINX_RAM32X6SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
parameter [32*6-1:0] INIT = {32*6{1'bx}};
parameter CLKPOL2 = 1;
input CLK1;
input [4:0] A1ADDR;
output [5:0] A1DATA;
input [4:0] B1ADDR;
input [5:0] B1DATA;
input B1EN;
wire [1:0] DOD_unused;
RAM32M #(
.INIT_A({INIT[187:186], INIT[181:180], INIT[175:174], INIT[169:168], INIT[163:162], INIT[157:156], INIT[151:150], INIT[145:144], INIT[139:138], INIT[133:132], INIT[127:126], INIT[121:120], INIT[115:114], INIT[109:108], INIT[103:102], INIT[ 97: 96], INIT[ 91: 90], INIT[ 85: 84], INIT[ 79: 78], INIT[ 73: 72], INIT[ 67: 66], INIT[ 61: 60], INIT[ 55: 54], INIT[ 49: 48], INIT[ 43: 42], INIT[ 37: 36], INIT[ 31: 30], INIT[ 25: 24], INIT[ 19: 18], INIT[ 13: 12], INIT[ 7: 6], INIT[ 1: 0]}),
.INIT_B({INIT[189:188], INIT[183:182], INIT[177:176], INIT[171:170], INIT[165:164], INIT[159:158], INIT[153:152], INIT[147:146], INIT[141:140], INIT[135:134], INIT[129:128], INIT[123:122], INIT[117:116], INIT[111:110], INIT[105:104], INIT[ 99: 98], INIT[ 93: 92], INIT[ 87: 86], INIT[ 81: 80], INIT[ 75: 74], INIT[ 69: 68], INIT[ 63: 62], INIT[ 57: 56], INIT[ 51: 50], INIT[ 45: 44], INIT[ 39: 38], INIT[ 33: 32], INIT[ 27: 26], INIT[ 21: 20], INIT[ 15: 14], INIT[ 9: 8], INIT[ 3: 2]}),
.INIT_C({INIT[191:190], INIT[185:184], INIT[179:178], INIT[173:172], INIT[167:166], INIT[161:160], INIT[155:154], INIT[149:148], INIT[143:142], INIT[137:136], INIT[131:130], INIT[125:124], INIT[119:118], INIT[113:112], INIT[107:106], INIT[101:100], INIT[ 95: 94], INIT[ 89: 88], INIT[ 83: 82], INIT[ 77: 76], INIT[ 71: 70], INIT[ 65: 64], INIT[ 59: 58], INIT[ 53: 52], INIT[ 47: 46], INIT[ 41: 40], INIT[ 35: 34], INIT[ 29: 28], INIT[ 23: 22], INIT[ 17: 16], INIT[ 11: 10], INIT[ 5: 4]}),
.INIT_D(64'bx),
.IS_WCLK_INVERTED(!CLKPOL2)
) _TECHMAP_REPLACE_ (
.ADDRA(A1ADDR),
.ADDRB(A1ADDR),
.ADDRC(A1ADDR),
.DOA(A1DATA[1:0]),
.DOB(A1DATA[3:2]),
.DOC(A1DATA[5:4]),
.DOD(DOD_unused),
.ADDRD(B1ADDR),
.DIA(B1DATA[1:0]),
.DIB(B1DATA[3:2]),
.DIC(B1DATA[5:4]),
.DID(2'b00),
.WCLK(CLK1),
.WE(B1EN)
);
endmodule
module \$__XILINX_RAM64X3SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
parameter [64*3-1:0] INIT = {64*3{1'bx}};
parameter CLKPOL2 = 1;
input CLK1;
input [5:0] A1ADDR;
output [2:0] A1DATA;
input [5:0] B1ADDR;
input [2:0] B1DATA;
input B1EN;
wire DOD_unused;
RAM64M #(
.INIT_A({INIT[189], INIT[186], INIT[183], INIT[180], INIT[177], INIT[174], INIT[171], INIT[168], INIT[165], INIT[162], INIT[159], INIT[156], INIT[153], INIT[150], INIT[147], INIT[144], INIT[141], INIT[138], INIT[135], INIT[132], INIT[129], INIT[126], INIT[123], INIT[120], INIT[117], INIT[114], INIT[111], INIT[108], INIT[105], INIT[102], INIT[ 99], INIT[ 96], INIT[ 93], INIT[ 90], INIT[ 87], INIT[ 84], INIT[ 81], INIT[ 78], INIT[ 75], INIT[ 72], INIT[ 69], INIT[ 66], INIT[ 63], INIT[ 60], INIT[ 57], INIT[ 54], INIT[ 51], INIT[ 48], INIT[ 45], INIT[ 42], INIT[ 39], INIT[ 36], INIT[ 33], INIT[ 30], INIT[ 27], INIT[ 24], INIT[ 21], INIT[ 18], INIT[ 15], INIT[ 12], INIT[ 9], INIT[ 6], INIT[ 3], INIT[ 0]}),
.INIT_B({INIT[190], INIT[187], INIT[184], INIT[181], INIT[178], INIT[175], INIT[172], INIT[169], INIT[166], INIT[163], INIT[160], INIT[157], INIT[154], INIT[151], INIT[148], INIT[145], INIT[142], INIT[139], INIT[136], INIT[133], INIT[130], INIT[127], INIT[124], INIT[121], INIT[118], INIT[115], INIT[112], INIT[109], INIT[106], INIT[103], INIT[100], INIT[ 97], INIT[ 94], INIT[ 91], INIT[ 88], INIT[ 85], INIT[ 82], INIT[ 79], INIT[ 76], INIT[ 73], INIT[ 70], INIT[ 67], INIT[ 64], INIT[ 61], INIT[ 58], INIT[ 55], INIT[ 52], INIT[ 49], INIT[ 46], INIT[ 43], INIT[ 40], INIT[ 37], INIT[ 34], INIT[ 31], INIT[ 28], INIT[ 25], INIT[ 22], INIT[ 19], INIT[ 16], INIT[ 13], INIT[ 10], INIT[ 7], INIT[ 4], INIT[ 1]}),
.INIT_C({INIT[191], INIT[188], INIT[185], INIT[182], INIT[179], INIT[176], INIT[173], INIT[170], INIT[167], INIT[164], INIT[161], INIT[158], INIT[155], INIT[152], INIT[149], INIT[146], INIT[143], INIT[140], INIT[137], INIT[134], INIT[131], INIT[128], INIT[125], INIT[122], INIT[119], INIT[116], INIT[113], INIT[110], INIT[107], INIT[104], INIT[101], INIT[ 98], INIT[ 95], INIT[ 92], INIT[ 89], INIT[ 86], INIT[ 83], INIT[ 80], INIT[ 77], INIT[ 74], INIT[ 71], INIT[ 68], INIT[ 65], INIT[ 62], INIT[ 59], INIT[ 56], INIT[ 53], INIT[ 50], INIT[ 47], INIT[ 44], INIT[ 41], INIT[ 38], INIT[ 35], INIT[ 32], INIT[ 29], INIT[ 26], INIT[ 23], INIT[ 20], INIT[ 17], INIT[ 14], INIT[ 11], INIT[ 8], INIT[ 5], INIT[ 2]}),
.INIT_D(64'bx),
.IS_WCLK_INVERTED(!CLKPOL2)
) _TECHMAP_REPLACE_ (
.ADDRA(A1ADDR),
.ADDRB(A1ADDR),
.ADDRC(A1ADDR),
.DOA(A1DATA[0]),
.DOB(A1DATA[1]),
.DOC(A1DATA[2]),
.DOD(DOD_unused),
.ADDRD(B1ADDR),
.DIA(B1DATA[0]),
.DIB(B1DATA[1]),
.DIC(B1DATA[2]),
.DID(1'b0),
.WCLK(CLK1),
.WE(B1EN)
);
endmodule
module \$__XILINX_RAM32X2Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN);
parameter [63:0] INIT = 64'bx;
parameter CLKPOL2 = 1;
input CLK1;
input [4:0] A1ADDR, A2ADDR, A3ADDR;
output [1:0] A1DATA, A2DATA, A3DATA;
input [4:0] B1ADDR;
input [1:0] B1DATA;
input B1EN;
RAM32M #(
.INIT_A(INIT),
.INIT_B(INIT),
.INIT_C(INIT),
.INIT_D(INIT),
.IS_WCLK_INVERTED(!CLKPOL2)
) _TECHMAP_REPLACE_ (
.ADDRA(A1ADDR),
.ADDRB(A2ADDR),
.ADDRC(A3ADDR),
.DOA(A1DATA),
.DOB(A2DATA),
.DOC(A3DATA),
.ADDRD(B1ADDR),
.DIA(B1DATA),
.DIB(B1DATA),
.DIC(B1DATA),
.DID(B1DATA),
.WCLK(CLK1),
.WE(B1EN)
);
endmodule
module \$__XILINX_RAM64X1Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN);
parameter [63:0] INIT = 64'bx;
parameter CLKPOL2 = 1;
input CLK1;
input [5:0] A1ADDR, A2ADDR, A3ADDR;
output A1DATA, A2DATA, A3DATA;
input [5:0] B1ADDR;
input B1DATA;
input B1EN;
RAM64M #(
.INIT_A(INIT),
.INIT_B(INIT),
.INIT_C(INIT),
.INIT_D(INIT),
.IS_WCLK_INVERTED(!CLKPOL2)
) _TECHMAP_REPLACE_ (
.ADDRA(A1ADDR),
.ADDRB(A2ADDR),
.ADDRC(A3ADDR),
.DOA(A1DATA),
.DOB(A2DATA),
.DOC(A3DATA),
.ADDRD(B1ADDR),
.DIA(B1DATA),
.DIB(B1DATA),
.DIC(B1DATA),
.DID(B1DATA),
.WCLK(CLK1),
.WE(B1EN)
);
endmodule

View File

@ -64,7 +64,7 @@ struct SynthXilinxPass : public ScriptPass
log(" (this feature is experimental and incomplete)\n");
log("\n");
log(" -ise\n");
log(" generate an output netlist suitable for ISE (enables -iopad)\n");
log(" generate an output netlist suitable for ISE\n");
log("\n");
log(" -nobram\n");
log(" do not use block RAM cells in output netlist\n");
@ -84,11 +84,9 @@ struct SynthXilinxPass : public ScriptPass
log(" -nodsp\n");
log(" do not use DSP48E1s to implement multipliers and associated logic\n");
log("\n");
log(" -iopad\n");
log(" enable I/O buffer insertion (selected automatically by -ise)\n");
log("\n");
log(" -noiopad\n");
log(" disable I/O buffer insertion (only useful with -ise)\n");
log(" disable I/O buffer insertion (useful for hierarchical or \n");
log(" out-of-context flows)\n");
log("\n");
log(" -noclkbuf\n");
log(" disable automatic clock buffer insertion\n");
@ -110,7 +108,7 @@ struct SynthXilinxPass : public ScriptPass
log(" flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log(" run 'abc' with '-dff -D 1' options\n");
log("\n");
log(" -abc9\n");
log(" use new ABC9 flow (EXPERIMENTAL)\n");
@ -122,7 +120,7 @@ struct SynthXilinxPass : public ScriptPass
}
std::string top_opt, edif_file, blif_file, family;
bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram, abc9;
bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram, abc9;
bool flatten_before_abc;
int widemux;
@ -136,7 +134,6 @@ struct SynthXilinxPass : public ScriptPass
retime = false;
vpr = false;
ise = false;
iopad = false;
noiopad = false;
noclkbuf = false;
nocarry = false;
@ -213,7 +210,6 @@ struct SynthXilinxPass : public ScriptPass
continue;
}
if (args[argidx] == "-iopad") {
iopad = true;
continue;
}
if (args[argidx] == "-noiopad") {
@ -282,7 +278,6 @@ struct SynthXilinxPass : public ScriptPass
void script() YS_OVERRIDE
{
bool do_iopad = iopad || (ise && !noiopad);
std::string ff_map_file;
if (help_mode)
ff_map_file = "+/xilinx/{family}_ff_map.v";
@ -387,7 +382,10 @@ struct SynthXilinxPass : public ScriptPass
run("opt_expr -fine");
run("wreduce");
run("select -clear");
run("xilinx_dsp");
if (help_mode)
run("xilinx_dsp -family <family>");
else
run("xilinx_dsp -family " + family);
run("chtype -set $mul t:$__soft_mul");
}
}
@ -444,6 +442,16 @@ struct SynthXilinxPass : public ScriptPass
}
if (check_label("map_ffram")) {
// Required for dffsr2dff to work.
run("simplemap t:$dff t:$adff t:$mux");
// Needs to be done before opt -mux_bool happens.
run("dffsr2dff");
if (help_mode)
run("dff2dffs [-match-init]", "(-match-init for xc6s only)");
else if (family == "xc6s")
run("dff2dffs -match-init");
else
run("dff2dffs");
if (widemux > 0)
run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
// performs less efficiently
@ -453,14 +461,11 @@ struct SynthXilinxPass : public ScriptPass
}
if (check_label("fine")) {
run("dffsr2dff");
run("dff2dffe");
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
if (help_mode) {
run("simplemap t:$mux", " ('-widemux' only)");
run("muxcover <internal options>, ('-widemux' only)");
}
else if (widemux > 0) {
run("simplemap t:$mux");
constexpr int cost_mux2 = 100;
std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
switch (widemux) {
@ -507,8 +512,8 @@ struct SynthXilinxPass : public ScriptPass
if (check_label("map_cells")) {
// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
if (help_mode || do_iopad)
run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(only if '-iopad' or '-ise' and not '-noiopad')");
if (help_mode || !noiopad)
run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(only if not '-noiopad')");
std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v";
if (widemux > 0)
techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
@ -545,9 +550,9 @@ struct SynthXilinxPass : public ScriptPass
}
else {
if (nowidelut)
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff -D 1" : ""));
else
run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff -D 1" : ""));
}
run("clean");
@ -563,6 +568,7 @@ struct SynthXilinxPass : public ScriptPass
else
techmap_args += " -map " + ff_map_file;
run("techmap " + techmap_args);
run("xilinx_dffopt");
run("clean");
}

View File

@ -8,4 +8,8 @@ dsp_work*/
test_dsp_model_ref.v
test_dsp_model_uut.v
test_dsp_model
test_dsp48a_model_ref.v
test_dsp48a1_model_ref.v
test_dsp48a1_model_uut.v
test_dsp48a1_model
*.vcd

View File

@ -0,0 +1,17 @@
#!/bin/bash
set -ex
if [ -z $ISE_DIR ]; then
ISE_DIR=/opt/Xilinx/ISE/14.7
fi
sed 's/DSP48A1/MARKER1/; s/DSP48A/DSP48A_UUT/; s/MARKER1/DSP48A1_UUT/; /module DSP48A_UUT/,/endmodule/ p; /module DSP48A1_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp48a1_model_uut.v
if [ ! -f "test_dsp48a1_model_ref.v" ]; then
cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48A1.v test_dsp48a1_model_ref.v
fi
if [ ! -f "test_dsp48a_model_ref.v" ]; then
cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48A.v test_dsp48a_model_ref.v
fi
for tb in mult_allreg mult_noreg mult_inreg
do
iverilog -s $tb -s glbl -o test_dsp48a1_model test_dsp48a1_model.v test_dsp48a1_model_uut.v test_dsp48a1_model_ref.v test_dsp48a_model_ref.v $ISE_DIR/ISE_DS/ISE/verilog/src/glbl.v
vvp -N ./test_dsp48a1_model
done

View File

@ -0,0 +1,331 @@
`timescale 1ns / 1ps
module testbench;
parameter integer A0REG = 1;
parameter integer A1REG = 1;
parameter integer B0REG = 1;
parameter integer B1REG = 1;
parameter integer CREG = 1;
parameter integer DREG = 1;
parameter integer MREG = 1;
parameter integer PREG = 1;
parameter integer CARRYINREG = 1;
parameter integer CARRYOUTREG = 1;
parameter integer OPMODEREG = 1;
parameter CARRYINSEL = "OPMODE5";
parameter RSTTYPE = "SYNC";
reg CLK;
reg CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE;
reg RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE;
reg [17:0] A;
reg [17:0] B;
reg [47:0] C;
reg [17:0] D;
reg [47:0] PCIN;
reg [7:0] OPMODE;
reg CARRYIN;
output CARRYOUTF, REF_CARRYOUTF;
output CARRYOUT, REF_CARRYOUT, REF_OLD_CARRYOUT;
output [35:0] M, REF_M;
output [47:0] P, REF_P, REF_OLD_P;
output [17:0] BCOUT, REF_BCOUT, REF_OLD_BCOUT;
output [47:0] PCOUT, REF_PCOUT, REF_OLD_PCOUT;
integer errcount = 0;
reg ERROR_FLAG = 0;
task clkcycle;
begin
#5;
CLK = ~CLK;
#10;
CLK = ~CLK;
#2;
ERROR_FLAG = 0;
if (REF_BCOUT !== BCOUT || REF_OLD_BCOUT != BCOUT) begin
$display("ERROR at %1t: REF_BCOUT=%b REF_OLD_BCOUT=%b UUT_BCOUT=%b DIFF=%b", $time, REF_BCOUT, REF_OLD_BCOUT, BCOUT, REF_BCOUT ^ BCOUT);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_M !== M) begin
$display("ERROR at %1t: REF_M=%b UUT_M=%b DIFF=%b", $time, REF_M, M, REF_M ^ M);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_P !== P || REF_OLD_P != P) begin
$display("ERROR at %1t: REF_P=%b REF_OLD_P=%b UUT_P=%b DIFF=%b", $time, REF_P, REF_OLD_P, P, REF_P ^ P);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_PCOUT !== PCOUT || REF_OLD_PCOUT != PCOUT) begin
$display("ERROR at %1t: REF_PCOUT=%b REF_OLD_PCOUT=%b UUT_PCOUT=%b DIFF=%b", $time, REF_PCOUT, REF_OLD_PCOUT, PCOUT, REF_PCOUT ^ PCOUT);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_CARRYOUT !== CARRYOUT || (REF_OLD_CARRYOUT != CARRYOUT && !CARRYOUTREG)) begin
$display("ERROR at %1t: REF_CARRYOUT=%b REF_OLD_CARRYOUT=%b UUT_CARRYOUT=%b DIFF=%b", $time, REF_CARRYOUT, REF_OLD_CARRYOUT, CARRYOUT, REF_CARRYOUT ^ CARRYOUT);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_CARRYOUTF !== CARRYOUTF) begin
$display("ERROR at %1t: REF_CARRYOUTF=%b UUT_CARRYOUTF=%b", $time, REF_CARRYOUTF, CARRYOUTF);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
#3;
end
endtask
reg config_valid = 0;
task drc;
begin
config_valid = 1;
if (OPMODE[1:0] == 2'b10 && PREG != 1) config_valid = 0;
if (OPMODE[3:2] == 2'b10 && PREG != 1) config_valid = 0;
end
endtask
initial begin
$dumpfile("test_dsp48a1_model.vcd");
$dumpvars(0, testbench);
#2;
CLK = 1'b0;
{CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE} = 8'b11111111;
{A, B, C, D, PCIN, OPMODE, CARRYIN} = 0;
{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = 8'b11111111;
repeat (10) begin
#10;
CLK = 1'b1;
#10;
CLK = 1'b0;
#10;
CLK = 1'b1;
#10;
CLK = 1'b0;
end
{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = 0;
repeat (10000) begin
clkcycle;
config_valid = 0;
while (!config_valid) begin
A = $urandom;
B = $urandom;
C = {$urandom, $urandom};
D = $urandom;
PCIN = {$urandom, $urandom};
{CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE} = $urandom | $urandom | $urandom;
{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom;
{CARRYIN, OPMODE} = $urandom;
drc;
end
end
if (errcount == 0) begin
$display("All tests passed.");
$finish;
end else begin
$display("Caught %1d errors.", errcount);
$stop;
end
end
DSP48A #(
.A0REG (A0REG),
.A1REG (A1REG),
.B0REG (B0REG),
.B1REG (B1REG),
.CREG (CREG),
.DREG (DREG),
.MREG (MREG),
.PREG (PREG),
.CARRYINREG (CARRYINREG),
.OPMODEREG (OPMODEREG),
.CARRYINSEL (CARRYINSEL),
.RSTTYPE (RSTTYPE)
) ref_old (
.A (A),
.B (B),
.C (C),
.D (D),
.PCIN (PCIN),
.CARRYIN (CARRYIN),
.OPMODE (OPMODE),
.BCOUT (REF_OLD_BCOUT),
.CARRYOUT (REF_OLD_CARRYOUT),
.P (REF_OLD_P),
.PCOUT (REF_OLD_PCOUT),
.CEA (CEA),
.CEB (CEB),
.CEC (CEC),
.CED (CED),
.CEM (CEM),
.CEP (CEP),
.CECARRYIN (CECARRYIN),
.CEOPMODE (CEOPMODE),
.CLK (CLK),
.RSTA (RSTA),
.RSTB (RSTB),
.RSTC (RSTC),
.RSTD (RSTD),
.RSTM (RSTM),
.RSTP (RSTP),
.RSTCARRYIN (RSTCARRYIN),
.RSTOPMODE (RSTOPMODE)
);
DSP48A1 #(
.A0REG (A0REG),
.A1REG (A1REG),
.B0REG (B0REG),
.B1REG (B1REG),
.CREG (CREG),
.DREG (DREG),
.MREG (MREG),
.PREG (PREG),
.CARRYINREG (CARRYINREG),
.CARRYOUTREG (CARRYOUTREG),
.OPMODEREG (OPMODEREG),
.CARRYINSEL (CARRYINSEL),
.RSTTYPE (RSTTYPE)
) ref (
.A (A),
.B (B),
.C (C),
.D (D),
.PCIN (PCIN),
.CARRYIN (CARRYIN),
.OPMODE (OPMODE),
.BCOUT (REF_BCOUT),
.CARRYOUTF (REF_CARRYOUTF),
.CARRYOUT (REF_CARRYOUT),
.P (REF_P),
.M (REF_M),
.PCOUT (REF_PCOUT),
.CEA (CEA),
.CEB (CEB),
.CEC (CEC),
.CED (CED),
.CEM (CEM),
.CEP (CEP),
.CECARRYIN (CECARRYIN),
.CEOPMODE (CEOPMODE),
.CLK (CLK),
.RSTA (RSTA),
.RSTB (RSTB),
.RSTC (RSTC),
.RSTD (RSTD),
.RSTM (RSTM),
.RSTP (RSTP),
.RSTCARRYIN (RSTCARRYIN),
.RSTOPMODE (RSTOPMODE)
);
DSP48A1_UUT #(
.A0REG (A0REG),
.A1REG (A1REG),
.B0REG (B0REG),
.B1REG (B1REG),
.CREG (CREG),
.DREG (DREG),
.MREG (MREG),
.PREG (PREG),
.CARRYINREG (CARRYINREG),
.CARRYOUTREG (CARRYOUTREG),
.OPMODEREG (OPMODEREG),
.CARRYINSEL (CARRYINSEL),
.RSTTYPE (RSTTYPE)
) uut (
.A (A),
.B (B),
.C (C),
.D (D),
.PCIN (PCIN),
.CARRYIN (CARRYIN),
.OPMODE (OPMODE),
.BCOUT (BCOUT),
.CARRYOUTF (CARRYOUTF),
.CARRYOUT (CARRYOUT),
.P (P),
.M (M),
.PCOUT (PCOUT),
.CEA (CEA),
.CEB (CEB),
.CEC (CEC),
.CED (CED),
.CEM (CEM),
.CEP (CEP),
.CECARRYIN (CECARRYIN),
.CEOPMODE (CEOPMODE),
.CLK (CLK),
.RSTA (RSTA),
.RSTB (RSTB),
.RSTC (RSTC),
.RSTD (RSTD),
.RSTM (RSTM),
.RSTP (RSTP),
.RSTCARRYIN (RSTCARRYIN),
.RSTOPMODE (RSTOPMODE)
);
endmodule
module mult_noreg;
testbench #(
.A0REG (0),
.A1REG (0),
.B0REG (0),
.B1REG (0),
.CREG (0),
.DREG (0),
.MREG (0),
.PREG (0),
.CARRYINREG (0),
.CARRYOUTREG (0),
.OPMODEREG (0),
.CARRYINSEL ("CARRYIN"),
.RSTTYPE ("SYNC")
) testbench ();
endmodule
module mult_allreg;
testbench #(
.A0REG (1),
.A1REG (1),
.B0REG (1),
.B1REG (1),
.CREG (1),
.DREG (1),
.MREG (1),
.PREG (1),
.CARRYINREG (1),
.CARRYOUTREG (1),
.OPMODEREG (1),
.CARRYINSEL ("OPMODE5"),
.RSTTYPE ("SYNC")
) testbench ();
endmodule
module mult_inreg;
testbench #(
.A0REG (1),
.A1REG (1),
.B0REG (1),
.B1REG (1),
.CREG (1),
.DREG (1),
.MREG (0),
.PREG (0),
.CARRYINREG (1),
.CARRYOUTREG (0),
.OPMODEREG (0),
.CARRYINSEL ("CARRYIN"),
.RSTTYPE ("SYNC")
) testbench ();
endmodule

View File

@ -1,14 +1,17 @@
#!/bin/bash
set -ex
if [ -z $VIVADO_DIR ]; then
VIVADO_DIR=/opt/Xilinx/Vivado/2019.1
fi
sed 's/DSP48E1/DSP48E1_UUT/; /DSP48E1_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v
if [ ! -f "test_dsp_model_ref.v" ]; then
cat /opt/Xilinx/Vivado/2019.1/data/verilog/src/unisims/DSP48E1.v > test_dsp_model_ref.v
cp $VIVADO_DIR/data/verilog/src/unisims/DSP48E1.v test_dsp_model_ref.v
fi
for tb in macc_overflow_underflow \
simd24_preadd_noreg_nocasc simd12_preadd_noreg_nocasc \
mult_allreg_nopreadd_nocasc mult_noreg_nopreadd_nocasc \
simd24_preadd_noreg_nocasc simd12_preadd_noreg_nocasc \
mult_allreg_nopreadd_nocasc mult_noreg_nopreadd_nocasc \
mult_allreg_preadd_nocasc mult_noreg_preadd_nocasc mult_inreg_preadd_nocasc
do
iverilog -s $tb -s glbl -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v /opt/Xilinx/Vivado/2019.1/data/verilog/src/glbl.v
iverilog -s $tb -s glbl -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v $VIVADO_DIR/data/verilog/src/glbl.v
vvp -N ./test_dsp_model
done

View File

@ -27,7 +27,7 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
.D(18'b0),
.P(P_48),
.OPMODE(8'b0000010)
.OPMODE(8'b0000001)
);
assign Y = P_48;
endmodule

View File

@ -27,7 +27,7 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
.D(18'b0),
.P(P_48),
.OPMODE(8'b0000010)
.OPMODE(8'b0000001)
);
assign Y = P_48;
endmodule

View File

@ -27,6 +27,8 @@
`ifndef _NO_FFS
// No reset.
module \$_DFF_N_ (input D, C, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -46,6 +48,8 @@ module \$_DFF_P_ (input D, C, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
// No reset, enable.
module \$_DFFE_NP_ (input D, C, E, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -65,15 +69,8 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
module \$_DFF_NN0_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
else
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
// Async reset.
module \$_DFF_NP0_ (input D, C, R, output Q);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -83,15 +80,6 @@ module \$_DFF_NP0_ (input D, C, R, output Q);
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
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);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
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;
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);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
@ -120,15 +99,6 @@ module \$_DFF_NP1_ (input D, C, R, output Q);
endgenerate
wire _TECHMAP_REMOVEINIT_Q_ = 1;
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);
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
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;
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);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
@ -158,5 +250,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
// Latches with reset (TODO).
`endif

View File

@ -37,6 +37,8 @@
`ifndef _NO_FFS
// No reset.
module \$_DFF_N_ (input D, C, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0));
@ -48,6 +50,8 @@ module \$_DFF_P_ (input D, C, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
// No reset, enable.
module \$_DFFE_NP_ (input D, C, E, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0));
@ -59,48 +63,104 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
module \$_DFF_NN0_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
// Async reset.
module \$_DFF_NP0_ (input D, C, R, output Q);
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
wire _TECHMAP_REMOVEINIT_Q_ = 1;
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);
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_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);
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_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);
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
// 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);
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));
@ -112,5 +172,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
wire _TECHMAP_REMOVEINIT_Q_ = 1;
endmodule
// Latches with reset (TODO).
`endif

View File

@ -1,4 +1,3 @@
bram $__XILINX_RAMB36_SDP
init 1
abits 9
@ -72,8 +71,33 @@ bram $__XILINX_RAMB18_TDP
clkpol 2 3
endbram
# The "min bits" value were taken from:
# [[CITE]] 7 Series FPGAs Memory Resources User Guide (UG473),
# v1.14 ed., p 29-30, July, 2019.
# https://www.xilinx.com/support/documentation/user_guides/ug473_7Series_Memory_Resources.pdf
match $__XILINX_RAMB36_SDP
min bits 4096
attribute !ram_style
attribute !logic_block
min bits 1024
min efficiency 5
shuffle_enable B
make_transp
or_next_if_better
endmatch
match $__XILINX_RAMB36_SDP
attribute ram_style=block ram_block
attribute !logic_block
shuffle_enable B
make_transp
or_next_if_better
endmatch
match $__XILINX_RAMB18_SDP
attribute !ram_style
attribute !logic_block
min bits 1024
min efficiency 5
shuffle_enable B
make_transp
@ -81,7 +105,17 @@ match $__XILINX_RAMB36_SDP
endmatch
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
shuffle_enable B
make_transp
@ -89,7 +123,17 @@ match $__XILINX_RAMB18_SDP
endmatch
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
shuffle_enable B
make_transp
@ -97,8 +141,8 @@ match $__XILINX_RAMB36_TDP
endmatch
match $__XILINX_RAMB18_TDP
min bits 4096
min efficiency 5
attribute ram_style=block ram_block
attribute !logic_block
shuffle_enable B
make_transp
endmatch

View File

@ -0,0 +1,365 @@
/*
* 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 -- insert new signals at the beginning
// of the vector, so they don't disturb the likely-critical D LUT input
// timings.
result.second = data.second;
// D lut inputs initially start at 0.
int idx_data = 0;
// Now add the control input LUT inputs.
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 = 0;
// Insert new signal at the beginning and bump all indices.
result.second.insert(result.second.begin(), bit);
idx_data++;
for (int &sidx : idx_sel)
sidx++;
}
idx_sel.push_back(idx);
}
// Insert the Q signal, if any, to the slowest input -- it will have
// no problem meeting timing.
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 = 0;
result.second.insert(result.second.begin(), alt_data);
idx_data++;
for (int &sidx : idx_sel)
sidx++;
}
}
// 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 >> idx_data & ((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

@ -2,7 +2,7 @@ read_verilog ../common/counter.v
hierarchy -top top
proc
flatten
equiv_opt -map +/anlogic/cells_sim.v synth_anlogic # equivalency check
equiv_opt -assert -multiclock -map +/anlogic/cells_sim.v synth_anlogic # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module

View File

@ -1,5 +1,5 @@
read_verilog ../common/memory.v
hierarchy -top top
read_verilog ../common/lutram.v
hierarchy -top lutram_1w1r
proc
memory -nomap
equiv_opt -run :prove -map +/anlogic/cells_sim.v synth_anlogic
@ -11,7 +11,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
#sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
design -load postopt
cd top
cd lutram_1w1r
select -assert-count 8 t:AL_MAP_LUT2
select -assert-count 8 t:AL_MAP_LUT4

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

@ -0,0 +1,16 @@
read_verilog <<EOT
module led_blink (
input clk,
output ledc
);
reg [6:0] led_counter = 0;
always @( posedge clk ) begin
led_counter <= led_counter + 1;
end
assign ledc = !led_counter[ 6:3 ];
endmodule
EOT
proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 -abc9

View File

@ -2,7 +2,7 @@ read_verilog ../common/counter.v
hierarchy -top top
proc
flatten
equiv_opt -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
equiv_opt -assert -multiclock -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 4 t:CCU2C

View File

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

View File

@ -3,8 +3,8 @@ hierarchy -top top
proc
# Blocked by issue #1358 (Missing ECP5 simulation models)
#equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
equiv_opt -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
synth_ecp5
#design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:MULT18X18D
select -assert-count 4 t:CCU2C

View File

@ -3,9 +3,9 @@ hierarchy -top top
proc
# Blocked by issue #1358 (Missing ECP5 simulation models)
#equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
equiv_opt -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
synth_ecp5
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 top # Constrain all select calls below inside the top module
select -assert-count 1 t:MULT18X18D
select -assert-none t:MULT18X18D %% t:* %D

View File

@ -39,8 +39,8 @@ proc
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux16 # Constrain all select calls below inside the top module
select -assert-count 8 t:L6MUX21
select -assert-count 26 t:LUT4
select -assert-count 12 t:PFUMX
select -assert-count 12 t:L6MUX21
select -assert-count 34 t:LUT4
select -assert-count 17 t:PFUMX
select -assert-none t:LUT4 t:L6MUX21 t:PFUMX %% t:* %D

View File

@ -2,7 +2,7 @@ read_verilog ../common/counter.v
hierarchy -top top
proc
flatten
equiv_opt -map +/efinix/cells_sim.v synth_efinix # equivalency check
equiv_opt -assert -multiclock -map +/efinix/cells_sim.v synth_efinix # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module

View File

@ -1,5 +1,5 @@
read_verilog ../common/memory.v
hierarchy -top top
read_verilog ../common/lutram.v
hierarchy -top lutram_1w1r
proc
memory -nomap
equiv_opt -run :prove -map +/efinix/cells_sim.v synth_efinix
@ -12,7 +12,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt
cd top
cd lutram_1w1r
select -assert-count 1 t:EFX_GBUFCE
select -assert-count 1 t:EFX_RAM_5K
select -assert-none t:EFX_GBUFCE t:EFX_RAM_5K %% t:* %D

View File

@ -2,7 +2,7 @@ read_verilog ../common/counter.v
hierarchy -top top
proc
flatten
equiv_opt -map +/gowin/cells_sim.v synth_gowin # equivalency check
equiv_opt -assert -multiclock -map +/gowin/cells_sim.v synth_gowin # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module

View File

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

View File

@ -0,0 +1,16 @@
read_verilog <<EOT
module led_blink (
input clk,
output ledc
);
reg [6:0] led_counter = 0;
always @( posedge clk ) begin
led_counter <= led_counter + 1;
end
assign ledc = !led_counter[ 6:3 ];
endmodule
EOT
proc
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -abc9

View File

@ -2,7 +2,7 @@ read_verilog ../common/counter.v
hierarchy -top top
proc
flatten
equiv_opt -map +/ice40/cells_sim.v synth_ice40 # equivalency check
equiv_opt -assert -multiclock -map +/ice40/cells_sim.v synth_ice40 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 6 t:SB_CARRY

View File

@ -1,5 +1,5 @@
read_verilog ../common/memory.v
hierarchy -top top
read_verilog ../common/lutram.v
hierarchy -top lutram_1w1r
proc
memory -nomap
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
@ -10,6 +10,6 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt
cd top
cd lutram_1w1r
select -assert-count 1 t:SB_RAM40_4K
select -assert-none t:SB_RAM40_4K %% t:* %D

View File

@ -1,6 +1,6 @@
read_verilog ../common/mul.v
hierarchy -top top
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
equiv_opt -assert -multiclock -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:SB_MAC16

View File

@ -2,7 +2,8 @@
Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 74].
*/
module top(data, addr);
output [3:0] data;
output [3:0] data; // Note: this prompts a Yosys warning, but
// vendor doc does not contain 'reg'
input [4:0] addr;
always @(addr) begin
case (addr)

View File

@ -1,7 +1,7 @@
read_verilog ../common/add_sub.v
hierarchy -top top
proc
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 14 t:LUT2

View File

@ -3,7 +3,7 @@ design -save read
hierarchy -top adff
proc
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd adff # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
@ -15,7 +15,7 @@ select -assert-none t:BUFG t:FDCE %% t:* %D
design -load read
hierarchy -top adffn
proc
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd adffn # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
@ -28,24 +28,23 @@ select -assert-none t:BUFG t:FDCE t:INV %% t:* %D
design -load read
hierarchy -top dffs
proc
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd dffs # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
select -assert-count 1 t:FDRE
select -assert-count 1 t:LUT2
select -assert-count 1 t:FDSE
select -assert-none t:BUFG t:FDRE t:LUT2 %% t:* %D
select -assert-none t:BUFG t:FDSE %% t:* %D
design -load read
hierarchy -top ndffnr
proc
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd ndffnr # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
select -assert-count 1 t:FDRE_1
select -assert-count 1 t:LUT2
select -assert-count 1 t:INV
select -assert-none t:BUFG t:FDRE_1 t:LUT2 %% t:* %D
select -assert-none t:BUFG t:FDRE_1 t:INV %% t:* %D

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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
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 -noiopad
cd register_file
select -assert-count 32 t:RAM32M
select -assert-none t:* t:BUFG %d t:RAM32M %d

View File

@ -0,0 +1,16 @@
read_verilog <<EOT
module led_blink (
input clk,
output ledc
);
reg [6:0] led_counter = 0;
always @( posedge clk ) begin
led_counter <= led_counter + 1;
end
assign ledc = !led_counter[ 6:3 ];
endmodule
EOT
proc
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -abc9

View File

@ -0,0 +1,19 @@
read_verilog <<EOT
module top(inout io);
wire in;
wire t;
wire o;
IOBUF IOBUF(
.I(in),
.T(t),
.IO(io),
.O(o)
);
endmodule
EOT
synth_xilinx
cd top
select -assert-count 1 t:IOBUF
select -assert-none t:* t:IOBUF %d

Some files were not shown because too many files have changed in this diff Show More