mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'master' of https://github.com/YosysHQ/yosys into abc_scratchpad_script
This commit is contained in:
commit
341fd872b5
|
@ -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
|
||||
----------------------
|
||||
|
|
42
Makefile
42
Makefile
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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).
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
@ -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).
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
@ -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); \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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--)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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),
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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)");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
Loading…
Reference in New Issue