mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-12 20:18:20 +00:00
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_ecp5" to now infer DSP blocks (-nodsp to disable, experimental)
|
||||||
- "synth_ice40 -dsp" to infer DSP blocks
|
- "synth_ice40 -dsp" to infer DSP blocks
|
||||||
- Added latch support to synth_xilinx
|
- Added latch support to synth_xilinx
|
||||||
|
- Added support for flip-flops with synchronous reset to synth_xilinx
|
||||||
|
- Added support for flip-flops with reset and enable to synth_xilinx
|
||||||
- Added "check -mapped"
|
- Added "check -mapped"
|
||||||
- Added checking of SystemVerilog always block types (always_comb,
|
- Added checking of SystemVerilog always block types (always_comb,
|
||||||
always_latch and always_ff)
|
always_latch and always_ff)
|
||||||
|
- Added "xilinx_dffopt" pass
|
||||||
|
- Added "scratchpad" pass
|
||||||
|
|
||||||
Yosys 0.8 .. Yosys 0.9
|
Yosys 0.8 .. Yosys 0.9
|
||||||
----------------------
|
----------------------
|
||||||
|
|
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_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_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
|
||||||
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
|
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
|
PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
|
||||||
|
|
||||||
# Reload Makefile.conf to override python specific variables if defined
|
# 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
|
#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)
|
ifeq ($(OS), Darwin)
|
||||||
BOOST_PYTHON_LIB ?= $(shell \
|
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_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_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_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$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
|
||||||
echo ""; fi; fi; fi; fi;)
|
echo ""; fi; fi; fi; fi;)
|
||||||
else
|
else
|
||||||
BOOST_PYTHON_LIB ?= $(shell \
|
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_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_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_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$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
|
||||||
echo ""; fi; fi; fi; fi;)
|
echo ""; fi; fi; fi; fi;)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -325,19 +333,19 @@ endif
|
||||||
|
|
||||||
ifeq ($(OS), Darwin)
|
ifeq ($(OS), Darwin)
|
||||||
ifeq ($(PYTHON_MAJOR_VERSION),3)
|
ifeq ($(PYTHON_MAJOR_VERSION),3)
|
||||||
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
LDLIBS += $(shell $(PYTHON_CONFIG) --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||||
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
|
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
|
||||||
else
|
else
|
||||||
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
LDLIBS += $(shell $(PYTHON_CONFIG) --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||||
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
|
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
ifeq ($(PYTHON_MAJOR_VERSION),3)
|
ifeq ($(PYTHON_MAJOR_VERSION),3)
|
||||||
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
LDLIBS += $(shell $(PYTHON_CONFIG) --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||||
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
|
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
|
||||||
else
|
else
|
||||||
LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
LDLIBS += $(shell $(PYTHON_CONFIG) --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||||
CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
|
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -454,10 +454,10 @@ Verilog Attributes and non-standard features
|
||||||
expressions over parameters and constant values are allowed). The intended
|
expressions over parameters and constant values are allowed). The intended
|
||||||
use for this is synthesis-time DRC.
|
use for this is synthesis-time DRC.
|
||||||
|
|
||||||
- There is limited support for converting specify .. endspecify statements to
|
- There is limited support for converting ``specify`` .. ``endspecify``
|
||||||
special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in
|
statements to special ``$specify2``, ``$specify3``, and ``$specrule`` cells,
|
||||||
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
|
for use in blackboxes and whiteboxes. Use ``read_verilog -specify`` to
|
||||||
functionality. (By default specify .. endspecify blocks are ignored.)
|
enable this functionality. (By default these blocks are ignored.)
|
||||||
|
|
||||||
|
|
||||||
Non-standard or SystemVerilog features for formal verification
|
Non-standard or SystemVerilog features for formal verification
|
||||||
|
|
|
@ -81,8 +81,7 @@ struct XAigerWriter
|
||||||
pool<SigBit> input_bits, output_bits;
|
pool<SigBit> input_bits, output_bits;
|
||||||
dict<SigBit, SigBit> not_map, alias_map;
|
dict<SigBit, SigBit> not_map, alias_map;
|
||||||
dict<SigBit, pair<SigBit, SigBit>> and_map;
|
dict<SigBit, pair<SigBit, SigBit>> and_map;
|
||||||
vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
|
vector<SigBit> ci_bits, co_bits;
|
||||||
vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
|
|
||||||
dict<SigBit, float> arrival_times;
|
dict<SigBit, float> arrival_times;
|
||||||
|
|
||||||
vector<pair<int, int>> aig_gates;
|
vector<pair<int, int>> aig_gates;
|
||||||
|
@ -367,7 +366,6 @@ struct XAigerWriter
|
||||||
cell->setPort(port_name, rhs);
|
cell->setPort(port_name, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
for (auto b : rhs.bits()) {
|
for (auto b : rhs.bits()) {
|
||||||
SigBit I = sigmap(b);
|
SigBit I = sigmap(b);
|
||||||
if (b == RTLIL::Sx)
|
if (b == RTLIL::Sx)
|
||||||
|
@ -378,7 +376,7 @@ struct XAigerWriter
|
||||||
else
|
else
|
||||||
alias_map[b] = I;
|
alias_map[b] = I;
|
||||||
}
|
}
|
||||||
co_bits.emplace_back(b, cell, port_name, offset++, 0);
|
co_bits.emplace_back(b);
|
||||||
unused_bits.erase(b);
|
unused_bits.erase(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,9 +396,8 @@ struct XAigerWriter
|
||||||
cell->setPort(port_name, rhs);
|
cell->setPort(port_name, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
for (const auto &b : rhs.bits()) {
|
for (const auto &b : rhs.bits()) {
|
||||||
ci_bits.emplace_back(b, cell, port_name, offset++);
|
ci_bits.emplace_back(b);
|
||||||
SigBit O = sigmap(b);
|
SigBit O = sigmap(b);
|
||||||
if (O != b)
|
if (O != b)
|
||||||
alias_map[O] = b;
|
alias_map[O] = b;
|
||||||
|
@ -487,15 +484,13 @@ struct XAigerWriter
|
||||||
aig_map[bit] = 2*aig_m;
|
aig_map[bit] = 2*aig_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &c : ci_bits) {
|
for (auto bit : ci_bits) {
|
||||||
RTLIL::SigBit bit = std::get<0>(c);
|
|
||||||
aig_m++, aig_i++;
|
aig_m++, aig_i++;
|
||||||
aig_map[bit] = 2*aig_m;
|
aig_map[bit] = 2*aig_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &c : co_bits) {
|
for (auto bit : co_bits) {
|
||||||
RTLIL::SigBit bit = std::get<0>(c);
|
ordered_outputs[bit] = aig_o++;
|
||||||
std::get<4>(c) = ordered_outputs[bit] = aig_o++;
|
|
||||||
aig_outputs.push_back(bit2aig(bit));
|
aig_outputs.push_back(bit2aig(bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +503,6 @@ struct XAigerWriter
|
||||||
ordered_outputs[bit] = aig_o++;
|
ordered_outputs[bit] = aig_o++;
|
||||||
aig_outputs.push_back(bit2aig(bit));
|
aig_outputs.push_back(bit2aig(bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_aiger(std::ostream &f, bool ascii_mode)
|
void write_aiger(std::ostream &f, bool ascii_mode)
|
||||||
|
@ -605,25 +599,46 @@ struct XAigerWriter
|
||||||
RTLIL::Module *holes_module = module->design->addModule("$__holes__");
|
RTLIL::Module *holes_module = module->design->addModule("$__holes__");
|
||||||
log_assert(holes_module);
|
log_assert(holes_module);
|
||||||
|
|
||||||
|
dict<IdString, Cell*> cell_cache;
|
||||||
|
|
||||||
int port_id = 1;
|
int port_id = 1;
|
||||||
int box_count = 0;
|
int box_count = 0;
|
||||||
for (auto cell : box_list) {
|
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;
|
int box_inputs = 0, box_outputs = 0;
|
||||||
Cell *holes_cell = nullptr;
|
auto r = cell_cache.insert(std::make_pair(derived_name, nullptr));
|
||||||
if (box_module->get_bool_attribute("\\whitebox")) {
|
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 = holes_module->addCell(cell->name, cell->type);
|
||||||
holes_cell->parameters = cell->parameters;
|
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
|
// NB: Assume box_module->ports are sorted alphabetically
|
||||||
// (as RTLIL::Module::fixup_ports() would do)
|
// (as RTLIL::Module::fixup_ports() would do)
|
||||||
|
int box_port_id = 1;
|
||||||
for (const auto &port_name : box_module->ports) {
|
for (const auto &port_name : box_module->ports) {
|
||||||
RTLIL::Wire *w = box_module->wire(port_name);
|
RTLIL::Wire *w = box_module->wire(port_name);
|
||||||
log_assert(w);
|
log_assert(w);
|
||||||
|
if (r.second)
|
||||||
|
w->port_id = box_port_id++;
|
||||||
RTLIL::Wire *holes_wire;
|
RTLIL::Wire *holes_wire;
|
||||||
RTLIL::SigSpec port_wire;
|
RTLIL::SigSpec port_sig;
|
||||||
if (w->port_input) {
|
if (w->port_input)
|
||||||
for (int i = 0; i < GetSize(w); i++) {
|
for (int i = 0; i < GetSize(w); i++) {
|
||||||
box_inputs++;
|
box_inputs++;
|
||||||
holes_wire = holes_module->wire(stringf("\\i%d", 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);
|
holes_module->ports.push_back(holes_wire->name);
|
||||||
}
|
}
|
||||||
if (holes_cell)
|
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) {
|
if (w->port_output) {
|
||||||
box_outputs += GetSize(w);
|
box_outputs += GetSize(w);
|
||||||
for (int i = 0; i < GetSize(w); i++) {
|
for (int i = 0; i < GetSize(w); i++) {
|
||||||
if (GetSize(w) == 1)
|
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
|
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_output = true;
|
||||||
holes_wire->port_id = port_id++;
|
holes_wire->port_id = port_id++;
|
||||||
holes_module->ports.push_back(holes_wire->name);
|
holes_module->ports.push_back(holes_wire->name);
|
||||||
if (holes_cell)
|
if (holes_cell)
|
||||||
port_wire.append(holes_wire);
|
port_sig.append(holes_wire);
|
||||||
else
|
else
|
||||||
holes_module->connect(holes_wire, State::S0);
|
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();
|
RTLIL::Selection& sel = holes_module->design->selection_stack.back();
|
||||||
sel.select(holes_module);
|
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");
|
Pass::call(holes_module->design, "flatten -wb");
|
||||||
|
|
||||||
// TODO: Should techmap/aigmap/check all lib_whitebox-es just once,
|
// Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
|
||||||
// instead of per write_xaiger call
|
// 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, "techmap");
|
||||||
Pass::call(holes_module->design, "aigmap");
|
Pass::call(holes_module->design, "aigmap");
|
||||||
for (auto cell : holes_module->cells())
|
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 = new AstNode(AST_LOCALPARAM, varbuf);
|
||||||
varbuf->str = init_ast->children[0]->str;
|
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];
|
AstNode *backup_scope_varbuf = current_scope[varbuf->str];
|
||||||
current_scope[varbuf->str] = varbuf;
|
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);
|
current_ast_mod->children.push_back(p);
|
||||||
str = p->str;
|
str = p->str;
|
||||||
id2ast = p;
|
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.
|
This directory contains Verific bindings for Yosys.
|
||||||
See http://www.verific.com/ for details.
|
|
||||||
|
Use Symbiotic EDA Suite if you need Yosys+Verifc.
|
||||||
|
https://www.symbioticeda.com/seda-suite
|
||||||
|
|
||||||
|
Contact office@symbioticeda.com for free evaluation
|
||||||
|
binaries of Symbiotic EDA Suite.
|
||||||
|
|
||||||
|
|
||||||
Verific Features that should be enabled in your Verific library
|
Verific Features that should be enabled in your Verific library
|
||||||
|
|
|
@ -2065,7 +2065,12 @@ struct VerificPass : public Pass {
|
||||||
log(" -d <dump_file>\n");
|
log(" -d <dump_file>\n");
|
||||||
log(" Dump the Verific netlist as a verilog file.\n");
|
log(" Dump the Verific netlist as a verilog file.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Visit http://verific.com/ for more information on Verific.\n");
|
log("\n");
|
||||||
|
log("Use Symbiotic EDA Suite if you need Yosys+Verifc.\n");
|
||||||
|
log("https://www.symbioticeda.com/seda-suite\n");
|
||||||
|
log("\n");
|
||||||
|
log("Contact office@symbioticeda.com for free evaluation\n");
|
||||||
|
log("binaries of Symbiotic EDA Suite.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
#ifdef YOSYS_ENABLE_VERIFIC
|
#ifdef YOSYS_ENABLE_VERIFIC
|
||||||
|
@ -2074,7 +2079,13 @@ struct VerificPass : public Pass {
|
||||||
static bool set_verific_global_flags = true;
|
static bool set_verific_global_flags = true;
|
||||||
|
|
||||||
if (check_noverific_env())
|
if (check_noverific_env())
|
||||||
log_cmd_error("This version of Yosys is built without Verific support.\n");
|
log_cmd_error("This version of Yosys is built without Verific support.\n"
|
||||||
|
"\n"
|
||||||
|
"Use Symbiotic EDA Suite if you need Yosys+Verifc.\n"
|
||||||
|
"https://www.symbioticeda.com/seda-suite\n"
|
||||||
|
"\n"
|
||||||
|
"Contact office@symbioticeda.com for free evaluation\n"
|
||||||
|
"binaries of Symbiotic EDA Suite.\n");
|
||||||
|
|
||||||
log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n");
|
log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n");
|
||||||
|
|
||||||
|
@ -2493,7 +2504,13 @@ struct VerificPass : public Pass {
|
||||||
}
|
}
|
||||||
#else /* YOSYS_ENABLE_VERIFIC */
|
#else /* YOSYS_ENABLE_VERIFIC */
|
||||||
void execute(std::vector<std::string>, RTLIL::Design *) YS_OVERRIDE {
|
void execute(std::vector<std::string>, RTLIL::Design *) YS_OVERRIDE {
|
||||||
log_cmd_error("This version of Yosys is built without Verific support.\n");
|
log_cmd_error("This version of Yosys is built without Verific support.\n"
|
||||||
|
"\n"
|
||||||
|
"Use Symbiotic EDA Suite if you need Yosys+Verifc.\n"
|
||||||
|
"https://www.symbioticeda.com/seda-suite\n"
|
||||||
|
"\n"
|
||||||
|
"Contact office@symbioticeda.com for free evaluation\n"
|
||||||
|
"binaries of Symbiotic EDA Suite.\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} VerificPass;
|
} VerificPass;
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
*
|
*
|
||||||
* Ad-hoc implementation of a Verilog preprocessor. The directives `define,
|
* Ad-hoc implementation of a Verilog preprocessor. The directives `define,
|
||||||
* `include, `ifdef, `ifndef, `else and `endif are handled here. All other
|
* `include, `ifdef, `ifndef, `else and `endif are handled here. All other
|
||||||
* directives are handled by the lexer (see lexer.l).
|
* directives are handled by the lexer (see verilog_lexer.l).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
*
|
*
|
||||||
* A simple lexer for Verilog code. Non-preprocessor compiler directives are
|
* A simple lexer for Verilog code. Non-preprocessor compiler directives are
|
||||||
* handled here. The preprocessor stuff is handled in preproc.cc. Everything
|
* handled here. The preprocessor stuff is handled in preproc.cc. Everything
|
||||||
* else is left to the bison parser (see parser.y).
|
* else is left to the bison parser (see verilog_parser.y).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -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(Or, max(sig_a.size(), sig_b.size()), ID($or))
|
||||||
DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), ID($xor))
|
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(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(Shift, sig_a.size(), ID($shift))
|
||||||
DEF_METHOD(Shiftx, sig_a.size(), ID($shiftx))
|
DEF_METHOD(Shiftx, sig_a.size(), ID($shiftx))
|
||||||
DEF_METHOD(Lt, 1, ID($lt))
|
DEF_METHOD(Lt, 1, ID($lt))
|
||||||
|
@ -1916,6 +1912,31 @@ DEF_METHOD(LogicAnd, 1, ID($logic_and))
|
||||||
DEF_METHOD(LogicOr, 1, ID($logic_or))
|
DEF_METHOD(LogicOr, 1, ID($logic_or))
|
||||||
#undef DEF_METHOD
|
#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) \
|
#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* 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); \
|
RTLIL::Cell *cell = addCell(name, _type); \
|
||||||
|
|
|
@ -93,7 +93,7 @@ frontends/verilog/preproc.cc} in the Yosys source tree.
|
||||||
|
|
||||||
\begin{sloppypar}
|
\begin{sloppypar}
|
||||||
The Verilog Lexer is written using the lexer generator {\it flex} \citeweblink{flex}. Its source code
|
The Verilog Lexer is written using the lexer generator {\it flex} \citeweblink{flex}. Its source code
|
||||||
can be found in {\tt frontends/verilog/lexer.l} in the Yosys source tree.
|
can be found in {\tt frontends/verilog/verilog\_lexer.l} in the Yosys source tree.
|
||||||
The lexer does little more than identifying all keywords and literals
|
The lexer does little more than identifying all keywords and literals
|
||||||
recognised by the Yosys Verilog frontend.
|
recognised by the Yosys Verilog frontend.
|
||||||
\end{sloppypar}
|
\end{sloppypar}
|
||||||
|
@ -115,7 +115,7 @@ whenever possible.)
|
||||||
\subsection{The Verilog Parser}
|
\subsection{The Verilog Parser}
|
||||||
|
|
||||||
The Verilog Parser is written using the parser generator {\it bison} \citeweblink{bison}. Its source code
|
The Verilog Parser is written using the parser generator {\it bison} \citeweblink{bison}. Its source code
|
||||||
can be found in {\tt frontends/verilog/parser.y} in the Yosys source tree.
|
can be found in {\tt frontends/verilog/verilog\_parser.y} in the Yosys source tree.
|
||||||
|
|
||||||
It generates an AST using the \lstinline[language=C++]{AST::AstNode} data structure
|
It generates an AST using the \lstinline[language=C++]{AST::AstNode} data structure
|
||||||
defined in {\tt frontends/ast/ast.h}. An \lstinline[language=C++]{AST::AstNode} object has
|
defined in {\tt frontends/ast/ast.h}. An \lstinline[language=C++]{AST::AstNode} object has
|
||||||
|
|
|
@ -146,7 +146,7 @@ with the help of HDL synthesis tools.
|
||||||
|
|
||||||
In special cases such as synthesis for coarse-grain cell libraries or when
|
In special cases such as synthesis for coarse-grain cell libraries or when
|
||||||
testing new synthesis algorithms it might be necessary to write a custom HDL
|
testing new synthesis algorithms it might be necessary to write a custom HDL
|
||||||
synthesis tool or add new features to an existing one. It this cases the
|
synthesis tool or add new features to an existing one. In these cases the
|
||||||
availability of a Free and Open Source (FOSS) synthesis tool that can be used
|
availability of a Free and Open Source (FOSS) synthesis tool that can be used
|
||||||
as basis for custom tools would be helpful.
|
as basis for custom tools would be helpful.
|
||||||
|
|
||||||
|
|
|
@ -32,3 +32,4 @@ OBJS += passes/cmds/chtype.o
|
||||||
OBJS += passes/cmds/blackbox.o
|
OBJS += passes/cmds/blackbox.o
|
||||||
OBJS += passes/cmds/ltp.o
|
OBJS += passes/cmds/ltp.o
|
||||||
OBJS += passes/cmds/bugpoint.o
|
OBJS += passes/cmds/bugpoint.o
|
||||||
|
OBJS += passes/cmds/scratchpad.o
|
||||||
|
|
130
passes/cmds/scratchpad.cc
Normal file
130
passes/cmds/scratchpad.cc
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* 2019 Nina Engelhardt <nak@symbioticeda.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/register.h"
|
||||||
|
#include "kernel/rtlil.h"
|
||||||
|
#include "kernel/log.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct ScratchpadPass : public Pass {
|
||||||
|
ScratchpadPass() : Pass("scratchpad", "get/set values in the scratchpad") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" scratchpad [options]\n");
|
||||||
|
log("\n");
|
||||||
|
log("This pass allows to read and modify values from the scratchpad of the current\n");
|
||||||
|
log("design. Options:\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -get <identifier>\n");
|
||||||
|
log(" print the value saved in the scratchpad under the given identifier.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -set <identifier> <value>\n");
|
||||||
|
log(" save the given value in the scratchpad under the given identifier.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -unset <identifier>\n");
|
||||||
|
log(" remove the entry for the given identifier from the scratchpad.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -copy <identifier_from> <identifier_to>\n");
|
||||||
|
log(" copy the value of the first identifier to the second identifier.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -assert <identifier> <value>\n");
|
||||||
|
log(" assert that the entry for the given identifier is set to the given value.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -assert-set <identifier>\n");
|
||||||
|
log(" assert that the entry for the given identifier exists.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -assert-unset <identifier>\n");
|
||||||
|
log(" assert that the entry for the given identifier does not exist.\n");
|
||||||
|
log("\n");
|
||||||
|
log("The identifier may not contain whitespace. By convention, it is usually prefixed\n");
|
||||||
|
log("by the name of the pass that uses it, e.g. 'opt.did_something'. If the value\n");
|
||||||
|
log("contains whitespace, it must be enclosed in double quotes.\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
if (args[argidx] == "-get" && argidx+1 < args.size()) {
|
||||||
|
string identifier = args[++argidx];
|
||||||
|
if (design->scratchpad.count(identifier)){
|
||||||
|
log("%s\n", design->scratchpad_get_string(identifier).c_str());
|
||||||
|
} else {
|
||||||
|
log("\"%s\" not set\n", identifier.c_str());
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-set" && argidx+2 < args.size()) {
|
||||||
|
string identifier = args[++argidx];
|
||||||
|
string value = args[++argidx];
|
||||||
|
if (value.front() == '\"' && value.back() == '\"') value = value.substr(1, value.size() - 2);
|
||||||
|
design->scratchpad_set_string(identifier, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-unset" && argidx+1 < args.size()) {
|
||||||
|
string identifier = args[++argidx];
|
||||||
|
design->scratchpad_unset(identifier);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-copy" && argidx+2 < args.size()) {
|
||||||
|
string identifier_from = args[++argidx];
|
||||||
|
string identifier_to = args[++argidx];
|
||||||
|
if (design->scratchpad.count(identifier_from) == 0) log_error("\"%s\" not set\n", identifier_from.c_str());
|
||||||
|
string value = design->scratchpad_get_string(identifier_from);
|
||||||
|
design->scratchpad_set_string(identifier_to, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-assert" && argidx+2 < args.size()) {
|
||||||
|
string identifier = args[++argidx];
|
||||||
|
string expected = args[++argidx];
|
||||||
|
if (expected.front() == '\"' && expected.back() == '\"') expected = expected.substr(1, expected.size() - 2);
|
||||||
|
if (design->scratchpad.count(identifier) == 0)
|
||||||
|
log_error("Assertion failed: scratchpad entry '%s' is not defined\n", identifier.c_str());
|
||||||
|
string value = design->scratchpad_get_string(identifier);
|
||||||
|
if (value != expected) {
|
||||||
|
log_error("Assertion failed: scratchpad entry '%s' is set to '%s' instead of the asserted '%s'\n",
|
||||||
|
identifier.c_str(), value.c_str(), expected.c_str());
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-assert-set" && argidx+1 < args.size()) {
|
||||||
|
string identifier = args[++argidx];
|
||||||
|
if (design->scratchpad.count(identifier) == 0)
|
||||||
|
log_error("Assertion failed: scratchpad entry '%s' is not defined\n", identifier.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-assert-unset" && argidx+1 < args.size()) {
|
||||||
|
string identifier = args[++argidx];
|
||||||
|
if (design->scratchpad.count(identifier) > 0)
|
||||||
|
log_error("Assertion failed: scratchpad entry '%s' is defined\n", identifier.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design, false);
|
||||||
|
}
|
||||||
|
} ScratchpadPass;
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -44,6 +44,10 @@ struct EquivOptPass:public ScriptPass
|
||||||
log(" expand the modules in this file before proving equivalence. this is\n");
|
log(" expand the modules in this file before proving equivalence. this is\n");
|
||||||
log(" useful for handling architecture-specific primitives.\n");
|
log(" useful for handling architecture-specific primitives.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -blacklist <file>\n");
|
||||||
|
log(" Do not match cells or signals that match the names in the file\n");
|
||||||
|
log(" (passed to equiv_make).\n");
|
||||||
|
log("\n");
|
||||||
log(" -assert\n");
|
log(" -assert\n");
|
||||||
log(" produce an error if the circuits are not equivalent.\n");
|
log(" produce an error if the circuits are not equivalent.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -61,13 +65,14 @@ struct EquivOptPass:public ScriptPass
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string command, techmap_opts;
|
std::string command, techmap_opts, make_opts;
|
||||||
bool assert, undef, multiclock, async2sync;
|
bool assert, undef, multiclock, async2sync;
|
||||||
|
|
||||||
void clear_flags() YS_OVERRIDE
|
void clear_flags() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
command = "";
|
command = "";
|
||||||
techmap_opts = "";
|
techmap_opts = "";
|
||||||
|
make_opts = "";
|
||||||
assert = false;
|
assert = false;
|
||||||
undef = false;
|
undef = false;
|
||||||
multiclock = false;
|
multiclock = false;
|
||||||
|
@ -93,6 +98,10 @@ struct EquivOptPass:public ScriptPass
|
||||||
techmap_opts += " -map " + args[++argidx];
|
techmap_opts += " -map " + args[++argidx];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-blacklist" && argidx + 1 < args.size()) {
|
||||||
|
make_opts += " -blacklist " + args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-assert") {
|
if (args[argidx] == "-assert") {
|
||||||
assert = true;
|
assert = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -170,7 +179,12 @@ struct EquivOptPass:public ScriptPass
|
||||||
run("clk2fflogic", "(only with -multiclock)");
|
run("clk2fflogic", "(only with -multiclock)");
|
||||||
if (async2sync || help_mode)
|
if (async2sync || help_mode)
|
||||||
run("async2sync", " (only with -async2sync)");
|
run("async2sync", " (only with -async2sync)");
|
||||||
run("equiv_make gold gate equiv");
|
string opts;
|
||||||
|
if (help_mode)
|
||||||
|
opts = " -blacklist <filename> ...";
|
||||||
|
else
|
||||||
|
opts = make_opts;
|
||||||
|
run("equiv_make" + opts + " gold gate equiv");
|
||||||
if (help_mode)
|
if (help_mode)
|
||||||
run("equiv_induct [-undef] equiv");
|
run("equiv_induct [-undef] equiv");
|
||||||
else if (undef)
|
else if (undef)
|
||||||
|
|
|
@ -134,6 +134,7 @@ struct rules_t
|
||||||
dict<string, int> min_limits, max_limits;
|
dict<string, int> min_limits, max_limits;
|
||||||
bool or_next_if_better, make_transp, make_outreg;
|
bool or_next_if_better, make_transp, make_outreg;
|
||||||
char shuffle_enable;
|
char shuffle_enable;
|
||||||
|
vector<vector<std::tuple<bool,IdString,Const>>> attributes;
|
||||||
};
|
};
|
||||||
|
|
||||||
dict<IdString, vector<bram_t>> brams;
|
dict<IdString, vector<bram_t>> brams;
|
||||||
|
@ -327,6 +328,20 @@ struct rules_t
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GetSize(tokens) >= 2 && tokens[0] == "attribute") {
|
||||||
|
data.attributes.emplace_back();
|
||||||
|
for (int idx = 1; idx < GetSize(tokens); idx++) {
|
||||||
|
size_t c1 = tokens[idx][0] == '!' ? 1 : 0;
|
||||||
|
size_t c2 = tokens[idx].find("=");
|
||||||
|
bool exists = (c1 == 0);
|
||||||
|
IdString key = RTLIL::escape_id(tokens[idx].substr(c1, c2));
|
||||||
|
Const val = c2 != std::string::npos ? tokens[idx].substr(c2+1) : RTLIL::Const(1);
|
||||||
|
|
||||||
|
data.attributes.back().emplace_back(exists, key, val);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
syntax_error();
|
syntax_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -724,7 +739,7 @@ grow_read_ports:;
|
||||||
if (match.make_transp && wr_ports <= 1) {
|
if (match.make_transp && wr_ports <= 1) {
|
||||||
pi.make_transp = true;
|
pi.make_transp = true;
|
||||||
if (pi.clocks != 0) {
|
if (pi.clocks != 0) {
|
||||||
if (wr_ports == 1 && wr_clkdom != clkdom) {
|
if (wr_ports == 1 && wr_clkdom != clkdom) {
|
||||||
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
|
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
|
||||||
goto skip_bram_rport;
|
goto skip_bram_rport;
|
||||||
}
|
}
|
||||||
|
@ -813,6 +828,43 @@ grow_read_ports:;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &sums : match.attributes) {
|
||||||
|
bool found = false;
|
||||||
|
for (const auto &term : sums) {
|
||||||
|
bool exists = std::get<0>(term);
|
||||||
|
IdString key = std::get<1>(term);
|
||||||
|
const Const &value = std::get<2>(term);
|
||||||
|
auto it = cell->attributes.find(key);
|
||||||
|
if (it == cell->attributes.end()) {
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!exists)
|
||||||
|
continue;
|
||||||
|
if (it->second != value)
|
||||||
|
continue;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
std::stringstream ss;
|
||||||
|
bool exists = std::get<0>(sums.front());
|
||||||
|
if (!exists)
|
||||||
|
ss << "!";
|
||||||
|
IdString key = std::get<1>(sums.front());
|
||||||
|
ss << log_id(key);
|
||||||
|
const Const &value = std::get<2>(sums.front());
|
||||||
|
if (exists && value != Const(1))
|
||||||
|
ss << "=\"" << value.decode_string() << "\"";
|
||||||
|
|
||||||
|
log(" Rule for bram type %s rejected: requirement 'attribute %s ...' not met.\n",
|
||||||
|
log_id(match.name), ss.str().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == 1)
|
if (mode == 1)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1100,6 +1152,43 @@ void handle_cell(Cell *cell, const rules_t &rules)
|
||||||
goto next_match_rule;
|
goto next_match_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &sums : match.attributes) {
|
||||||
|
bool found = false;
|
||||||
|
for (const auto &term : sums) {
|
||||||
|
bool exists = std::get<0>(term);
|
||||||
|
IdString key = std::get<1>(term);
|
||||||
|
const Const &value = std::get<2>(term);
|
||||||
|
auto it = cell->attributes.find(key);
|
||||||
|
if (it == cell->attributes.end()) {
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!exists)
|
||||||
|
continue;
|
||||||
|
if (it->second != value)
|
||||||
|
continue;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
std::stringstream ss;
|
||||||
|
bool exists = std::get<0>(sums.front());
|
||||||
|
if (!exists)
|
||||||
|
ss << "!";
|
||||||
|
IdString key = std::get<1>(sums.front());
|
||||||
|
ss << log_id(key);
|
||||||
|
const Const &value = std::get<2>(sums.front());
|
||||||
|
if (exists && value != Const(1))
|
||||||
|
ss << "=\"" << value.decode_string() << "\"";
|
||||||
|
|
||||||
|
log(" Rule for bram type %s (variant %d) rejected: requirement 'attribute %s ...' not met.\n",
|
||||||
|
log_id(bram.name), bram.variant, ss.str().c_str());
|
||||||
|
goto next_match_rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log(" Rule #%d for bram type %s (variant %d) accepted.\n", i+1, log_id(bram.name), bram.variant);
|
log(" Rule #%d for bram type %s (variant %d) accepted.\n", i+1, log_id(bram.name), bram.variant);
|
||||||
|
|
||||||
if (or_next_if_better || !best_rule_cache.empty())
|
if (or_next_if_better || !best_rule_cache.empty())
|
||||||
|
@ -1225,6 +1314,13 @@ struct MemoryBramPass : public Pass {
|
||||||
log(" dcells ....... number of cells in 'data-direction'\n");
|
log(" dcells ....... number of cells in 'data-direction'\n");
|
||||||
log(" cells ........ total number of cells (acells*dcells*dups)\n");
|
log(" cells ........ total number of cells (acells*dcells*dups)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("A match containing the command 'attribute' followed by a list of space\n");
|
||||||
|
log("separated 'name[=string_value]' values requires that the memory contains any\n");
|
||||||
|
log("one of the given attribute name and string values (where specified), or name\n");
|
||||||
|
log("and integer 1 value (if no string_value given, since Verilog will interpret\n");
|
||||||
|
log("'(* attr *)' as '(* attr=1 *)').\n");
|
||||||
|
log("A name prefixed with '!' indicates that the attribute must not exist.\n");
|
||||||
|
log("\n");
|
||||||
log("The interface for the created bram instances is derived from the bram\n");
|
log("The interface for the created bram instances is derived from the bram\n");
|
||||||
log("description. Use 'techmap' to convert the created bram instances into\n");
|
log("description. Use 'techmap' to convert the created bram instances into\n");
|
||||||
log("instances of the actual bram cells of your target architecture.\n");
|
log("instances of the actual bram cells of your target architecture.\n");
|
||||||
|
|
|
@ -978,7 +978,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
|
||||||
{
|
{
|
||||||
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
|
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
|
||||||
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
|
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
|
||||||
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
|
log_id(module), cell->type == ID($eq) ? "$logic_not" : "$reduce_bool");
|
||||||
cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
|
cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
|
||||||
if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
|
if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
|
||||||
cell->setPort(ID::A, cell->getPort(ID::B));
|
cell->setPort(ID::A, cell->getPort(ID::B));
|
||||||
|
|
|
@ -22,8 +22,9 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
|
||||||
OBJS += passes/pmgen/xilinx_dsp.o
|
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_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_CREG_pm.h))
|
||||||
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
|
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
#include "passes/pmgen/xilinx_dsp_pm.h"
|
#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_CREG_pm.h"
|
||||||
#include "passes/pmgen/xilinx_dsp_cascade_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);
|
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)
|
void xilinx_dsp_packC(xilinx_dsp_CREG_pm &pm)
|
||||||
{
|
{
|
||||||
auto &st = pm.st_xilinx_dsp_packC;
|
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("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("into using the DSP48E1's pattern detector feature for overflow detection.\n");
|
||||||
log("\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
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
{
|
{
|
||||||
log_header(design, "Executing XILINX_DSP pass (pack resources into DSPs).\n");
|
log_header(design, "Executing XILINX_DSP pass (pack resources into DSPs).\n");
|
||||||
|
|
||||||
|
std::string family = "xc7";
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
{
|
{
|
||||||
// if (args[argidx] == "-singleton") {
|
if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) {
|
||||||
// singleton_mode = true;
|
family = args[++argidx];
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
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()) {
|
for (auto module : design->selected_modules()) {
|
||||||
// Experimental feature: pack $add/$sub cells with
|
// Experimental feature: pack $add/$sub cells with
|
||||||
// (* use_dsp48="simd" *) into DSP48E1's using its
|
// (* use_dsp48="simd" *) into DSP48E1's using its
|
||||||
// SIMD feature
|
// 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,
|
// Match for all features ([ABDMP][12]?REG, pre-adder,
|
||||||
// post-adder, pattern detector, etc.) except for CREG
|
// post-adder, pattern detector, etc.) except for CREG
|
||||||
{
|
if (family == "xc7") {
|
||||||
xilinx_dsp_pm pm(module, module->selected_cells());
|
xilinx_dsp_pm pm(module, module->selected_cells());
|
||||||
pm.run_xilinx_dsp_pack(xilinx_dsp_pack);
|
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
|
// Separating out CREG packing is necessary since there
|
||||||
// is no guarantee that the cell ordering corresponds
|
// is no guarantee that the cell ordering corresponds
|
||||||
|
|
673
passes/pmgen/xilinx_dsp48a.pmg
Normal file
673
passes/pmgen/xilinx_dsp48a.pmg
Normal file
|
@ -0,0 +1,673 @@
|
||||||
|
// This file describes the main pattern matcher setup (of three total) that
|
||||||
|
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc - version for
|
||||||
|
// DSP48A/DSP48A1 (Spartan 3A DSP, Spartan 6).
|
||||||
|
// At a high level, it works as follows:
|
||||||
|
// ( 1) Starting from a DSP48A/DSP48A1 cell
|
||||||
|
// ( 2) Match the driver of the 'B' input to a possible $dff cell (B1REG)
|
||||||
|
// (attached to at most two $mux cells that implement clock-enable or
|
||||||
|
// reset functionality, using a subpattern discussed below)
|
||||||
|
// If B1REG matched, treat 'B' input as input of B1REG
|
||||||
|
// ( 3) Match the driver of the 'B' and 'D' inputs for a possible $add cell
|
||||||
|
// (pre-adder)
|
||||||
|
// ( 4) Match 'B' input for B0REG
|
||||||
|
// ( 5) Match 'A' input for A1REG
|
||||||
|
// If A1REG, then match 'A' input for A0REG
|
||||||
|
// ( 6) Match 'D' input for DREG
|
||||||
|
// ( 7) Match 'P' output that exclusively drives an MREG
|
||||||
|
// ( 8) Match 'P' output that exclusively drives one of two inputs to an $add
|
||||||
|
// cell (post-adder).
|
||||||
|
// The other input to the adder is assumed to come in from the 'C' input
|
||||||
|
// (note: 'P' -> 'C' connections that exist for accumulators are
|
||||||
|
// recognised in xilinx_dsp.cc).
|
||||||
|
// ( 9) Match 'P' output that exclusively drives a PREG
|
||||||
|
// (10) If post-adder and PREG both present, match for a $mux cell driving
|
||||||
|
// the 'C' input, where one of the $mux's inputs is the PREG output.
|
||||||
|
// This indicates an accumulator situation, and one where a $mux exists
|
||||||
|
// to override the accumulated value:
|
||||||
|
// +--------------------------------+
|
||||||
|
// | ____ |
|
||||||
|
// +--| \ |
|
||||||
|
// |$mux|-+ |
|
||||||
|
// 'C' ---|____/ | |
|
||||||
|
// | /-------\ +----+ |
|
||||||
|
// +----+ +-| post- |___|PREG|---+ 'P'
|
||||||
|
// |MREG|------ | adder | +----+
|
||||||
|
// +----+ \-------/
|
||||||
|
// Notes: see the notes in xilinx_dsp.pmg
|
||||||
|
|
||||||
|
pattern xilinx_dsp48a_pack
|
||||||
|
|
||||||
|
state <SigBit> clock
|
||||||
|
state <SigSpec> sigA sigB sigC sigD sigM sigP
|
||||||
|
state <IdString> postAddAB postAddMuxAB
|
||||||
|
state <bool> ffAcepol ffBcepol ffDcepol ffMcepol ffPcepol
|
||||||
|
state <bool> ffArstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol
|
||||||
|
state <Cell*> ffA0 ffA0cemux ffA0rstmux ffA1 ffA1cemux ffA1rstmux
|
||||||
|
state <Cell*> ffB0 ffB0cemux ffB0rstmux ffB1 ffB1cemux ffB1rstmux
|
||||||
|
state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux
|
||||||
|
|
||||||
|
// Variables used for subpatterns
|
||||||
|
state <SigSpec> argQ argD
|
||||||
|
state <bool> ffcepol ffrstpol
|
||||||
|
state <int> ffoffset
|
||||||
|
udata <SigSpec> dffD dffQ
|
||||||
|
udata <SigBit> dffclock
|
||||||
|
udata <Cell*> dff dffcemux dffrstmux
|
||||||
|
udata <bool> dffcepol dffrstpol
|
||||||
|
|
||||||
|
// (1) Starting from a DSP48A/DSP48A1 cell
|
||||||
|
match dsp
|
||||||
|
select dsp->type.in(\DSP48A, \DSP48A1)
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code sigA sigB sigC sigD sigM clock
|
||||||
|
auto unextend = [](const SigSpec &sig) {
|
||||||
|
int i;
|
||||||
|
for (i = GetSize(sig)-1; i > 0; i--)
|
||||||
|
if (sig[i] != sig[i-1])
|
||||||
|
break;
|
||||||
|
// Do not remove non-const sign bit
|
||||||
|
if (sig[i].wire)
|
||||||
|
++i;
|
||||||
|
return sig.extract(0, i);
|
||||||
|
};
|
||||||
|
sigA = unextend(port(dsp, \A));
|
||||||
|
sigB = unextend(port(dsp, \B));
|
||||||
|
|
||||||
|
sigC = port(dsp, \C, SigSpec());
|
||||||
|
sigD = port(dsp, \D, SigSpec());
|
||||||
|
|
||||||
|
SigSpec P = port(dsp, \P);
|
||||||
|
// Only care about those bits that are used
|
||||||
|
int i;
|
||||||
|
for (i = GetSize(P)-1; i >= 0; i--)
|
||||||
|
if (nusers(P[i]) > 1)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
log_assert(nusers(P.extract_end(i)) <= 1);
|
||||||
|
// This sigM could have no users if downstream sinks (e.g. $add) is
|
||||||
|
// narrower than $mul result, for example
|
||||||
|
if (i == 0)
|
||||||
|
reject;
|
||||||
|
sigM = P.extract(0, i);
|
||||||
|
|
||||||
|
clock = port(dsp, \CLK, SigBit());
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (2) Match the driver of the 'B' input to a possible $dff cell (B1REG)
|
||||||
|
// (attached to at most two $mux cells that implement clock-enable or
|
||||||
|
// reset functionality, using a subpattern discussed above)
|
||||||
|
// If matched, treat 'B' input as input of B1REG
|
||||||
|
code argQ ffB1 ffB1cemux ffB1rstmux ffBcepol ffBrstpol sigB clock
|
||||||
|
if (param(dsp, \B1REG).as_int() == 0 && param(dsp, \B0REG).as_int() == 0 && port(dsp, \OPMODE, SigSpec()).extract(4, 1).is_fully_zero()) {
|
||||||
|
argQ = sigB;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffB1 = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
if (dffrstmux) {
|
||||||
|
ffB1rstmux = dffrstmux;
|
||||||
|
ffBrstpol = dffrstpol;
|
||||||
|
}
|
||||||
|
if (dffcemux) {
|
||||||
|
ffB1cemux = dffcemux;
|
||||||
|
ffBcepol = dffcepol;
|
||||||
|
}
|
||||||
|
sigB = dffD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (3) Match the driver of the 'B' and 'D' inputs for a possible $add cell
|
||||||
|
// (pre-adder)
|
||||||
|
match preAdd
|
||||||
|
if sigD.empty() || sigD.is_fully_zero()
|
||||||
|
if param(dsp, \B0REG).as_int() == 0
|
||||||
|
// Ensure that preAdder not already used
|
||||||
|
if port(dsp, \OPMODE, SigSpec()).extract(4, 1).is_fully_zero()
|
||||||
|
|
||||||
|
select preAdd->type.in($add, $sub)
|
||||||
|
// Output has to be 18 bits or less
|
||||||
|
select GetSize(port(preAdd, \Y)) <= 18
|
||||||
|
select nusers(port(preAdd, \Y)) == 2
|
||||||
|
// D port has to be 18 bits or less
|
||||||
|
select GetSize(port(preAdd, \A)) <= 18
|
||||||
|
// B port has to be 18 bits or less
|
||||||
|
select GetSize(port(preAdd, \B)) <= 18
|
||||||
|
index <SigSpec> port(preAdd, \Y) === sigB
|
||||||
|
|
||||||
|
optional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code sigB sigD
|
||||||
|
if (preAdd) {
|
||||||
|
sigD = port(preAdd, \A);
|
||||||
|
sigB = port(preAdd, \B);
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (4) Match 'B' input for B0REG
|
||||||
|
code argQ ffB0 ffB0cemux ffB0rstmux ffBcepol ffBrstpol sigB clock
|
||||||
|
if (param(dsp, \B0REG).as_int() == 0) {
|
||||||
|
argQ = sigB;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
if (ffB1) {
|
||||||
|
if ((ffB1rstmux != nullptr) ^ (dffrstmux != nullptr))
|
||||||
|
goto ffB0_end;
|
||||||
|
if ((ffB1cemux != nullptr) ^ (dffcemux != nullptr))
|
||||||
|
goto ffB0_end;
|
||||||
|
if (dffrstmux) {
|
||||||
|
if (ffBrstpol != dffrstpol)
|
||||||
|
goto ffB0_end;
|
||||||
|
if (port(ffB1rstmux, \S) != port(dffrstmux, \S))
|
||||||
|
goto ffB0_end;
|
||||||
|
ffB0rstmux = dffrstmux;
|
||||||
|
}
|
||||||
|
if (dffcemux) {
|
||||||
|
if (ffBcepol != dffcepol)
|
||||||
|
goto ffB0_end;
|
||||||
|
if (port(ffB1cemux, \S) != port(dffcemux, \S))
|
||||||
|
goto ffB0_end;
|
||||||
|
ffB0cemux = dffcemux;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ffB0 = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
if (dffrstmux) {
|
||||||
|
ffB0rstmux = dffrstmux;
|
||||||
|
ffBrstpol = dffrstpol;
|
||||||
|
}
|
||||||
|
if (dffcemux) {
|
||||||
|
ffB0cemux = dffcemux;
|
||||||
|
ffBcepol = dffcepol;
|
||||||
|
}
|
||||||
|
sigB = dffD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ffB0_end:
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (5) Match 'A' input for A1REG
|
||||||
|
// If A1REG, then match 'A' input for A0REG
|
||||||
|
code argQ ffA1 ffA1cemux ffA1rstmux ffAcepol ffArstpol sigA clock ffA0 ffA0cemux ffA0rstmux
|
||||||
|
if (param(dsp, \A0REG).as_int() == 0 && param(dsp, \A1REG).as_int() == 0) {
|
||||||
|
argQ = sigA;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffA1 = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
if (dffrstmux) {
|
||||||
|
ffA1rstmux = dffrstmux;
|
||||||
|
ffArstpol = dffrstpol;
|
||||||
|
}
|
||||||
|
if (dffcemux) {
|
||||||
|
ffA1cemux = dffcemux;
|
||||||
|
ffAcepol = dffcepol;
|
||||||
|
}
|
||||||
|
sigA = dffD;
|
||||||
|
|
||||||
|
// Now attempt to match A0
|
||||||
|
if (ffA1) {
|
||||||
|
argQ = sigA;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
if ((ffA1rstmux != nullptr) ^ (dffrstmux != nullptr))
|
||||||
|
goto ffA0_end;
|
||||||
|
if ((ffA1cemux != nullptr) ^ (dffcemux != nullptr))
|
||||||
|
goto ffA0_end;
|
||||||
|
if (dffrstmux) {
|
||||||
|
if (ffArstpol != dffrstpol)
|
||||||
|
goto ffA0_end;
|
||||||
|
if (port(ffA1rstmux, \S) != port(dffrstmux, \S))
|
||||||
|
goto ffA0_end;
|
||||||
|
ffA0rstmux = dffrstmux;
|
||||||
|
}
|
||||||
|
if (dffcemux) {
|
||||||
|
if (ffAcepol != dffcepol)
|
||||||
|
goto ffA0_end;
|
||||||
|
if (port(ffA1cemux, \S) != port(dffcemux, \S))
|
||||||
|
goto ffA0_end;
|
||||||
|
ffA0cemux = dffcemux;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffA0 = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
|
||||||
|
if (dffcemux) {
|
||||||
|
ffA0cemux = dffcemux;
|
||||||
|
ffAcepol = dffcepol;
|
||||||
|
}
|
||||||
|
sigA = dffD;
|
||||||
|
|
||||||
|
ffA0_end: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (6) Match 'D' input for DREG
|
||||||
|
code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock
|
||||||
|
if (param(dsp, \DREG).as_int() == 0) {
|
||||||
|
argQ = sigD;
|
||||||
|
subpattern(in_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffD = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
if (dffrstmux) {
|
||||||
|
ffDrstmux = dffrstmux;
|
||||||
|
ffDrstpol = dffrstpol;
|
||||||
|
}
|
||||||
|
if (dffcemux) {
|
||||||
|
ffDcemux = dffcemux;
|
||||||
|
ffDcepol = dffcepol;
|
||||||
|
}
|
||||||
|
sigD = dffD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (7) Match 'P' output that exclusively drives an MREG
|
||||||
|
code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock
|
||||||
|
if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) {
|
||||||
|
argD = sigM;
|
||||||
|
subpattern(out_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffM = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
if (dffrstmux) {
|
||||||
|
ffMrstmux = dffrstmux;
|
||||||
|
ffMrstpol = dffrstpol;
|
||||||
|
}
|
||||||
|
if (dffcemux) {
|
||||||
|
ffMcemux = dffcemux;
|
||||||
|
ffMcepol = dffcepol;
|
||||||
|
}
|
||||||
|
sigM = dffQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sigP = sigM;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (8) Match 'P' output that exclusively drives one of two inputs to an $add
|
||||||
|
// cell (post-adder).
|
||||||
|
// The other input to the adder is assumed to come in from the 'C' input
|
||||||
|
// (note: 'P' -> 'C' connections that exist for accumulators are
|
||||||
|
// recognised in xilinx_dsp.cc).
|
||||||
|
match postAdd
|
||||||
|
// Ensure that Z mux is not already used
|
||||||
|
if port(dsp, \OPMODE, SigSpec()).extract(2,2).is_fully_zero()
|
||||||
|
|
||||||
|
select postAdd->type.in($add)
|
||||||
|
select GetSize(port(postAdd, \Y)) <= 48
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
select nusers(port(postAdd, AB)) <= 3
|
||||||
|
filter ffMcemux || nusers(port(postAdd, AB)) == 2
|
||||||
|
filter !ffMcemux || nusers(port(postAdd, AB)) == 3
|
||||||
|
|
||||||
|
index <SigBit> port(postAdd, AB)[0] === sigP[0]
|
||||||
|
filter GetSize(port(postAdd, AB)) >= GetSize(sigP)
|
||||||
|
filter port(postAdd, AB).extract(0, GetSize(sigP)) == sigP
|
||||||
|
// Check that remainder of AB is a sign- or zero-extension
|
||||||
|
filter port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(sigP[GetSize(sigP)-1], GetSize(port(postAdd, AB))-GetSize(sigP)) || port(postAdd, AB).extract_end(GetSize(sigP)) == SigSpec(State::S0, GetSize(port(postAdd, AB))-GetSize(sigP))
|
||||||
|
|
||||||
|
set postAddAB AB
|
||||||
|
optional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code sigC sigP
|
||||||
|
if (postAdd) {
|
||||||
|
sigC = port(postAdd, postAddAB == \A ? \B : \A);
|
||||||
|
sigP = port(postAdd, \Y);
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (9) Match 'P' output that exclusively drives a PREG
|
||||||
|
code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock
|
||||||
|
if (param(dsp, \PREG).as_int() == 0) {
|
||||||
|
int users = 2;
|
||||||
|
// If ffMcemux and no postAdd new-value net must have three users: ffMcemux, ffM and ffPcemux
|
||||||
|
if (ffMcemux && !postAdd) users++;
|
||||||
|
if (nusers(sigP) == users) {
|
||||||
|
argD = sigP;
|
||||||
|
subpattern(out_dffe);
|
||||||
|
if (dff) {
|
||||||
|
ffP = dff;
|
||||||
|
clock = dffclock;
|
||||||
|
if (dffrstmux) {
|
||||||
|
ffPrstmux = dffrstmux;
|
||||||
|
ffPrstpol = dffrstpol;
|
||||||
|
}
|
||||||
|
if (dffcemux) {
|
||||||
|
ffPcemux = dffcemux;
|
||||||
|
ffPcepol = dffcepol;
|
||||||
|
}
|
||||||
|
sigP = dffQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (10) If post-adder and PREG both present, match for a $mux cell driving
|
||||||
|
// the 'C' input, where one of the $mux's inputs is the PREG output.
|
||||||
|
// This indicates an accumulator situation, and one where a $mux exists
|
||||||
|
// to override the accumulated value:
|
||||||
|
// +--------------------------------+
|
||||||
|
// | ____ |
|
||||||
|
// +--| \ |
|
||||||
|
// |$mux|-+ |
|
||||||
|
// 'C' ---|____/ | |
|
||||||
|
// | /-------\ +----+ |
|
||||||
|
// +----+ +-| post- |___|PREG|---+ 'P'
|
||||||
|
// |MREG|------ | adder | +----+
|
||||||
|
// +----+ \-------/
|
||||||
|
match postAddMux
|
||||||
|
if postAdd
|
||||||
|
if ffP
|
||||||
|
select postAddMux->type.in($mux)
|
||||||
|
select nusers(port(postAddMux, \Y)) == 2
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
index <SigSpec> port(postAddMux, AB) === sigP
|
||||||
|
index <SigSpec> port(postAddMux, \Y) === sigC
|
||||||
|
set postAddMuxAB AB
|
||||||
|
optional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code sigC
|
||||||
|
if (postAddMux)
|
||||||
|
sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
|
||||||
|
endcode
|
||||||
|
|
||||||
|
code
|
||||||
|
accept;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// #######################
|
||||||
|
|
||||||
|
// Subpattern for matching against input registers, based on knowledge of the
|
||||||
|
// 'Q' input. Typically, identifying registers with clock-enable and reset
|
||||||
|
// capability would be a task would be handled by other Yosys passes such as
|
||||||
|
// dff2dffe, but since DSP inference happens much before this, these patterns
|
||||||
|
// have to be manually identified.
|
||||||
|
// At a high level:
|
||||||
|
// (1) Starting from a $dff cell that (partially or fully) drives the given
|
||||||
|
// 'Q' argument
|
||||||
|
// (2) Match for a $mux cell implementing synchronous reset semantics ---
|
||||||
|
// one that exclusively drives the 'D' input of the $dff, with one of its
|
||||||
|
// $mux inputs being fully zero
|
||||||
|
// (3) Match for a $mux cell implement clock enable semantics --- one that
|
||||||
|
// exclusively drives the 'D' input of the $dff (or the other input of
|
||||||
|
// the reset $mux) and where one of this $mux's inputs is connected to
|
||||||
|
// the 'Q' output of the $dff
|
||||||
|
subpattern in_dffe
|
||||||
|
arg argD argQ clock
|
||||||
|
|
||||||
|
code
|
||||||
|
dff = nullptr;
|
||||||
|
if (GetSize(argQ) == 0)
|
||||||
|
reject;
|
||||||
|
for (const auto &c : argQ.chunks()) {
|
||||||
|
// Abandon matches when 'Q' is a constant
|
||||||
|
if (!c.wire)
|
||||||
|
reject;
|
||||||
|
// Abandon matches when 'Q' has the keep attribute set
|
||||||
|
if (c.wire->get_bool_attribute(\keep))
|
||||||
|
reject;
|
||||||
|
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||||
|
// (not supported by DSP48E1)
|
||||||
|
Const init = c.wire->attributes.at(\init, Const());
|
||||||
|
if (!init.empty())
|
||||||
|
for (auto b : init.extract(c.offset, c.width))
|
||||||
|
if (b != State::Sx && b != State::S0)
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (1) Starting from a $dff cell that (partially or fully) drives the given
|
||||||
|
// 'Q' argument
|
||||||
|
match ff
|
||||||
|
select ff->type.in($dff)
|
||||||
|
// DSP48E1 does not support clock inversion
|
||||||
|
select param(ff, \CLK_POLARITY).as_bool()
|
||||||
|
|
||||||
|
slice offset GetSize(port(ff, \D))
|
||||||
|
index <SigBit> port(ff, \Q)[offset] === argQ[0]
|
||||||
|
|
||||||
|
// Check that the rest of argQ is present
|
||||||
|
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
||||||
|
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||||
|
|
||||||
|
filter clock == SigBit() || port(ff, \CLK) == clock
|
||||||
|
|
||||||
|
set ffoffset offset
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argQ argD
|
||||||
|
SigSpec Q = port(ff, \Q);
|
||||||
|
dff = ff;
|
||||||
|
dffclock = port(ff, \CLK);
|
||||||
|
dffD = argQ;
|
||||||
|
argD = port(ff, \D);
|
||||||
|
argQ = Q;
|
||||||
|
dffD.replace(argQ, argD);
|
||||||
|
// Only search for ffrstmux if dffD only
|
||||||
|
// has two (ff, ffrstmux) users
|
||||||
|
if (nusers(dffD) > 2)
|
||||||
|
argD = SigSpec();
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (2) Match for a $mux cell implementing synchronous reset semantics ---
|
||||||
|
// exclusively drives the 'D' input of the $dff, with one of the $mux
|
||||||
|
// inputs being fully zero
|
||||||
|
match ffrstmux
|
||||||
|
if !argD.empty()
|
||||||
|
select ffrstmux->type.in($mux)
|
||||||
|
index <SigSpec> port(ffrstmux, \Y) === argD
|
||||||
|
|
||||||
|
choice <IdString> BA {\B, \A}
|
||||||
|
// DSP48E1 only supports reset to zero
|
||||||
|
select port(ffrstmux, BA).is_fully_zero()
|
||||||
|
|
||||||
|
define <bool> pol (BA == \B)
|
||||||
|
set ffrstpol pol
|
||||||
|
semioptional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argD
|
||||||
|
if (ffrstmux) {
|
||||||
|
dffrstmux = ffrstmux;
|
||||||
|
dffrstpol = ffrstpol;
|
||||||
|
argD = port(ffrstmux, ffrstpol ? \A : \B);
|
||||||
|
dffD.replace(port(ffrstmux, \Y), argD);
|
||||||
|
|
||||||
|
// Only search for ffcemux if argQ has at
|
||||||
|
// least 3 users (ff, <upstream>, ffrstmux) and
|
||||||
|
// dffD only has two (ff, ffrstmux)
|
||||||
|
if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
|
||||||
|
argD = SigSpec();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dffrstmux = nullptr;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (3) Match for a $mux cell implement clock enable semantics --- one that
|
||||||
|
// exclusively drives the 'D' input of the $dff (or the other input of
|
||||||
|
// the reset $mux) and where one of this $mux's inputs is connected to
|
||||||
|
// the 'Q' output of the $dff
|
||||||
|
match ffcemux
|
||||||
|
if !argD.empty()
|
||||||
|
select ffcemux->type.in($mux)
|
||||||
|
index <SigSpec> port(ffcemux, \Y) === argD
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
index <SigSpec> port(ffcemux, AB) === argQ
|
||||||
|
define <bool> pol (AB == \A)
|
||||||
|
set ffcepol pol
|
||||||
|
semioptional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argD
|
||||||
|
if (ffcemux) {
|
||||||
|
dffcemux = ffcemux;
|
||||||
|
dffcepol = ffcepol;
|
||||||
|
argD = port(ffcemux, ffcepol ? \B : \A);
|
||||||
|
dffD.replace(port(ffcemux, \Y), argD);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dffcemux = nullptr;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// #######################
|
||||||
|
|
||||||
|
// Subpattern for matching against output registers, based on knowledge of the
|
||||||
|
// 'D' input.
|
||||||
|
// At a high level:
|
||||||
|
// (1) Starting from an optional $mux cell that implements clock enable
|
||||||
|
// semantics --- one where the given 'D' argument (partially or fully)
|
||||||
|
// drives one of its two inputs
|
||||||
|
// (2) Starting from, or continuing onto, another optional $mux cell that
|
||||||
|
// implements synchronous reset semantics --- one where the given 'D'
|
||||||
|
// argument (or the clock enable $mux output) drives one of its two inputs
|
||||||
|
// and where the other input is fully zero
|
||||||
|
// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
|
||||||
|
// output of the previous clock enable or reset $mux cells)
|
||||||
|
subpattern out_dffe
|
||||||
|
arg argD argQ clock
|
||||||
|
|
||||||
|
code
|
||||||
|
dff = nullptr;
|
||||||
|
for (auto c : argD.chunks())
|
||||||
|
// Abandon matches when 'D' has the keep attribute set
|
||||||
|
if (c.wire->get_bool_attribute(\keep))
|
||||||
|
reject;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (1) Starting from an optional $mux cell that implements clock enable
|
||||||
|
// semantics --- one where the given 'D' argument (partially or fully)
|
||||||
|
// drives one of its two inputs
|
||||||
|
match ffcemux
|
||||||
|
select ffcemux->type.in($mux)
|
||||||
|
// ffcemux output must have two users: ffcemux and ff.D
|
||||||
|
select nusers(port(ffcemux, \Y)) == 2
|
||||||
|
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
// keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s)
|
||||||
|
select nusers(port(ffcemux, AB)) >= 3
|
||||||
|
|
||||||
|
slice offset GetSize(port(ffcemux, \Y))
|
||||||
|
define <IdString> BA (AB == \A ? \B : \A)
|
||||||
|
index <SigBit> port(ffcemux, BA)[offset] === argD[0]
|
||||||
|
|
||||||
|
// Check that the rest of argD is present
|
||||||
|
filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD)
|
||||||
|
filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD
|
||||||
|
|
||||||
|
set ffoffset offset
|
||||||
|
define <bool> pol (AB == \A)
|
||||||
|
set ffcepol pol
|
||||||
|
|
||||||
|
semioptional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argD argQ
|
||||||
|
dffcemux = ffcemux;
|
||||||
|
if (ffcemux) {
|
||||||
|
SigSpec BA = port(ffcemux, ffcepol ? \B : \A);
|
||||||
|
SigSpec Y = port(ffcemux, \Y);
|
||||||
|
argQ = argD;
|
||||||
|
argD.replace(BA, Y);
|
||||||
|
argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B));
|
||||||
|
|
||||||
|
dffcemux = ffcemux;
|
||||||
|
dffcepol = ffcepol;
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (2) Starting from, or continuing onto, another optional $mux cell that
|
||||||
|
// implements synchronous reset semantics --- one where the given 'D'
|
||||||
|
// argument (or the clock enable $mux output) drives one of its two inputs
|
||||||
|
// and where the other input is fully zero
|
||||||
|
match ffrstmux
|
||||||
|
select ffrstmux->type.in($mux)
|
||||||
|
// ffrstmux output must have two users: ffrstmux and ff.D
|
||||||
|
select nusers(port(ffrstmux, \Y)) == 2
|
||||||
|
|
||||||
|
choice <IdString> BA {\B, \A}
|
||||||
|
// DSP48E1 only supports reset to zero
|
||||||
|
select port(ffrstmux, BA).is_fully_zero()
|
||||||
|
|
||||||
|
slice offset GetSize(port(ffrstmux, \Y))
|
||||||
|
define <IdString> AB (BA == \B ? \A : \B)
|
||||||
|
index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
|
||||||
|
|
||||||
|
// Check that offset is consistent
|
||||||
|
filter !ffcemux || ffoffset == offset
|
||||||
|
// Check that the rest of argD is present
|
||||||
|
filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
|
||||||
|
filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
|
||||||
|
|
||||||
|
set ffoffset offset
|
||||||
|
define <bool> pol (AB == \A)
|
||||||
|
set ffrstpol pol
|
||||||
|
|
||||||
|
semioptional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argD argQ
|
||||||
|
dffrstmux = ffrstmux;
|
||||||
|
if (ffrstmux) {
|
||||||
|
SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
|
||||||
|
SigSpec Y = port(ffrstmux, \Y);
|
||||||
|
argD.replace(AB, Y);
|
||||||
|
|
||||||
|
dffrstmux = ffrstmux;
|
||||||
|
dffrstpol = ffrstpol;
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
|
||||||
|
// output of the previous clock enable or reset $mux cells)
|
||||||
|
match ff
|
||||||
|
select ff->type.in($dff)
|
||||||
|
// DSP48E1 does not support clock inversion
|
||||||
|
select param(ff, \CLK_POLARITY).as_bool()
|
||||||
|
|
||||||
|
slice offset GetSize(port(ff, \D))
|
||||||
|
index <SigBit> port(ff, \D)[offset] === argD[0]
|
||||||
|
|
||||||
|
// Check that offset is consistent
|
||||||
|
filter (!ffcemux && !ffrstmux) || ffoffset == offset
|
||||||
|
// Check that the rest of argD is present
|
||||||
|
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
|
||||||
|
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
|
||||||
|
// Check that FF.Q is connected to CE-mux
|
||||||
|
filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||||
|
|
||||||
|
filter clock == SigBit() || port(ff, \CLK) == clock
|
||||||
|
|
||||||
|
set ffoffset offset
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code argQ
|
||||||
|
SigSpec D = port(ff, \D);
|
||||||
|
SigSpec Q = port(ff, \Q);
|
||||||
|
if (!ffcemux) {
|
||||||
|
argQ = argD;
|
||||||
|
argQ.replace(D, Q);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abandon matches when 'Q' has a non-zero init attribute set
|
||||||
|
// (not supported by DSP48E1)
|
||||||
|
for (auto c : argQ.chunks()) {
|
||||||
|
Const init = c.wire->attributes.at(\init, Const());
|
||||||
|
if (!init.empty())
|
||||||
|
for (auto b : init.extract(c.offset, c.width))
|
||||||
|
if (b != State::Sx && b != State::S0)
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
dff = ff;
|
||||||
|
dffQ = argQ;
|
||||||
|
dffclock = port(ff, \CLK);
|
||||||
|
endcode
|
|
@ -1,7 +1,7 @@
|
||||||
// This file describes the second of three pattern matcher setups that
|
// This file describes the second of three pattern matcher setups that
|
||||||
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc
|
// forms the `xilinx_dsp` pass described in xilinx_dsp.cc
|
||||||
// At a high level, it works as follows:
|
// 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
|
// and (b) uses the 'C' port
|
||||||
// (2) Match the driver of the 'C' input to a possible $dff cell (CREG)
|
// (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
|
// (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 <Cell*> dff dffcemux dffrstmux
|
||||||
udata <bool> dffcepol dffrstpol
|
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
|
// and (b) uses the 'C' port
|
||||||
match dsp
|
match dsp
|
||||||
select dsp->type.in(\DSP48E1)
|
select dsp->type.in(\DSP48A, \DSP48A1, \DSP48E1)
|
||||||
select param(dsp, \CREG, 1).as_int() == 0
|
select param(dsp, \CREG, 1).as_int() == 0
|
||||||
select nusers(port(dsp, \C, SigSpec())) > 1
|
select nusers(port(dsp, \C, SigSpec())) > 1
|
||||||
endmatch
|
endmatch
|
||||||
|
@ -60,7 +60,8 @@ code sigC sigP clock
|
||||||
sigC = unextend(port(dsp, \C, SigSpec()));
|
sigC = unextend(port(dsp, \C, SigSpec()));
|
||||||
|
|
||||||
SigSpec P = port(dsp, \P);
|
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
|
// Only care about those bits that are used
|
||||||
int i;
|
int i;
|
||||||
for (i = GetSize(P)-1; i >= 0; i--)
|
for (i = GetSize(P)-1; i >= 0; i--)
|
||||||
|
|
|
@ -62,12 +62,11 @@ code
|
||||||
#define MAX_DSP_CASCADE 20
|
#define MAX_DSP_CASCADE 20
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
// (1) Starting from a DSP48E1 cell that (a) has the Z multiplexer
|
// (1) Starting from a DSP48* cell that (a) has the Z multiplexer
|
||||||
// (controlled by OPMODE[6:4]) set to zero and (b) doesn't already
|
// (controlled by OPMODE[3:2] for DSP48A*, by OPMODE[6:4] for DSP48E1)
|
||||||
// use the 'PCOUT' port
|
// set to zero and (b) doesn't already use the 'PCOUT' port
|
||||||
match first
|
match first
|
||||||
select first->type.in(\DSP48E1)
|
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 port(first, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("000")
|
|
||||||
select nusers(port(first, \PCOUT, SigSpec())) <= 1
|
select nusers(port(first, \PCOUT, SigSpec())) <= 1
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
|
@ -100,14 +99,21 @@ finally
|
||||||
add_siguser(cascade, dsp);
|
add_siguser(cascade, dsp);
|
||||||
|
|
||||||
SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7));
|
SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7));
|
||||||
if (P == 17)
|
if (dsp->type.in(\DSP48A, \DSP48A1)) {
|
||||||
opmode[6] = State::S1;
|
log_assert(P == 0);
|
||||||
else if (P == 0)
|
opmode[3] = State::S0;
|
||||||
opmode[6] = State::S0;
|
opmode[2] = State::S1;
|
||||||
else log_abort();
|
}
|
||||||
|
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[5] = State::S0;
|
||||||
opmode[4] = State::S1;
|
opmode[4] = State::S1;
|
||||||
|
}
|
||||||
dsp_pcin->setPort(\OPMODE, opmode);
|
dsp_pcin->setPort(\OPMODE, opmode);
|
||||||
|
|
||||||
log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
|
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_pcin);
|
||||||
add_siguser(cascade, dsp);
|
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"));
|
dsp_pcin->setParam(ID(A_INPUT), Const("CASCADE"));
|
||||||
|
|
||||||
log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
|
log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
|
||||||
}
|
}
|
||||||
if (BREG >= 0) {
|
if (BREG >= 0) {
|
||||||
Wire *cascade = module->addWire(NEW_ID, 18);
|
Wire *cascade = module->addWire(NEW_ID, 18);
|
||||||
dsp_pcin->setPort(ID(B), Const(0, 18));
|
if (dsp->type.in(\DSP48A, \DSP48A1)) {
|
||||||
dsp_pcin->setPort(ID(BCIN), cascade);
|
// 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);
|
dsp->setPort(ID(BCOUT), cascade);
|
||||||
add_siguser(cascade, dsp_pcin);
|
add_siguser(cascade, dsp_pcin);
|
||||||
add_siguser(cascade, dsp);
|
add_siguser(cascade, dsp);
|
||||||
|
|
||||||
dsp->setParam(ID(BCASCREG), BREG);
|
if (dsp->type.in(\DSP48E1)) {
|
||||||
dsp_pcin->setParam(ID(B_INPUT), Const("CASCADE"));
|
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));
|
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 first
|
||||||
arg next
|
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
|
// (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
|
// driven by the 'P' output of the previous DSP cell, and (c) has its
|
||||||
// 'PCIN' port unused
|
// 'PCIN' port unused
|
||||||
match nextP
|
match nextP
|
||||||
select nextP->type.in(\DSP48E1)
|
|
||||||
select !param(nextP, \CREG, State::S1).as_bool()
|
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, \C, SigSpec())) > 1
|
||||||
select nusers(port(nextP, \PCIN, SigSpec())) == 0
|
select nusers(port(nextP, \PCIN, SigSpec())) == 0
|
||||||
index <SigBit> port(nextP, \C)[0] === port(std::get<0>(chain.back()), \P)[0]
|
index <SigBit> port(nextP, \C)[0] === port(std::get<0>(chain.back()), \P)[0]
|
||||||
semioptional
|
semioptional
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
// (2.2) Same as (2.1) but with the 'C' port driven by the 'P' output of the
|
// (2.2) For DSP48E1 only, same as (2.1) but with the 'C' port driven
|
||||||
// previous DSP cell right-shifted by 17 bits
|
// by the 'P' output of the previous DSP cell right-shifted by 17 bits
|
||||||
match nextP_shift17
|
match nextP_shift17
|
||||||
if !nextP
|
if !nextP
|
||||||
select nextP_shift17->type.in(\DSP48E1)
|
select nextP_shift17->type.in(\DSP48E1)
|
||||||
|
@ -188,6 +214,8 @@ code next
|
||||||
if (!nextP)
|
if (!nextP)
|
||||||
next = nextP_shift17;
|
next = nextP_shift17;
|
||||||
if (next) {
|
if (next) {
|
||||||
|
if (next->type != first->type)
|
||||||
|
reject;
|
||||||
unextend = [](const SigSpec &sig) {
|
unextend = [](const SigSpec &sig) {
|
||||||
int i;
|
int i;
|
||||||
for (i = GetSize(sig)-1; i > 0; i--)
|
for (i = GetSize(sig)-1; i > 0; i--)
|
||||||
|
@ -202,38 +230,50 @@ code next
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
// (3) For this subequent DSP48E1 match (i.e. PCOUT -> PCIN cascade exists)
|
// (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
|
// if (a) this DSP48E1 does not already have an ACOUT -> ACIN cascade,
|
||||||
// DSP48 does not use A2REG nor A1REG, (c) this DSP48E1 does not already
|
// (b) the previous DSP does not already use its ACOUT port, then
|
||||||
// have an ACOUT -> ACIN cascade, (d) the previous DSP does not already
|
// examine if an ACOUT -> ACIN cascade opportunity exists if
|
||||||
// use its ACOUT port, then examine if an ACOUT -> ACIN cascade
|
// (i) A ports are identical, or (ii) separated by a
|
||||||
// opportunity exists by matching for a $dff-with-optional-clock-enable-
|
// $dff-with-optional-clock-enable-or-reset and checking that the 'D' input
|
||||||
// or-reset and checking that the 'D' input of this register is the same
|
// of this register is the same as the 'A' input of the previous DSP
|
||||||
// as the 'A' input of the previous DSP
|
// TODO: Check for two levels of flops, instead of just one
|
||||||
code argQ clock AREG
|
code argQ clock AREG
|
||||||
AREG = -1;
|
AREG = -1;
|
||||||
if (next) {
|
if (next && next->type.in(\DSP48E1)) {
|
||||||
Cell *prev = std::get<0>(chain.back());
|
Cell *prev = std::get<0>(chain.back());
|
||||||
if (param(prev, \AREG, 2).as_int() > 0 &&
|
|
||||||
param(next, \AREG, 2).as_int() > 0 &&
|
if (param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
|
||||||
param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
|
port(next, \ACIN, SigSpec()).is_fully_zero() &&
|
||||||
nusers(port(prev, \ACOUT, SigSpec())) <= 1) {
|
nusers(port(prev, \ACOUT, SigSpec())) <= 1) {
|
||||||
argQ = unextend(port(next, \A));
|
if (param(prev, \AREG, 2) == 0) {
|
||||||
clock = port(prev, \CLK);
|
if (port(prev, \A) == port(next, \A))
|
||||||
subpattern(in_dffe);
|
AREG = 0;
|
||||||
if (dff) {
|
}
|
||||||
if (!dffrstmux && port(prev, \RSTA, State::S0) != State::S0)
|
else {
|
||||||
goto reject_AREG;
|
argQ = unextend(port(next, \A));
|
||||||
if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTA, State::S0))
|
clock = port(prev, \CLK);
|
||||||
goto reject_AREG;
|
subpattern(in_dffe);
|
||||||
if (!dffcemux && port(prev, \CEA2, State::S0) != State::S0)
|
if (dff) {
|
||||||
goto reject_AREG;
|
if (!dffrstmux && port(prev, \RSTA, State::S0) != State::S0)
|
||||||
if (dffcemux && port(dffcemux, \S) != port(prev, \CEA2, State::S0))
|
goto reject_AREG;
|
||||||
goto reject_AREG;
|
if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTA, State::S0))
|
||||||
if (dffD == unextend(port(prev, \A)))
|
goto reject_AREG;
|
||||||
AREG = 1;
|
IdString CEA;
|
||||||
reject_AREG: ;
|
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
|
endcode
|
||||||
|
|
||||||
|
@ -242,28 +282,47 @@ code argQ clock BREG
|
||||||
BREG = -1;
|
BREG = -1;
|
||||||
if (next) {
|
if (next) {
|
||||||
Cell *prev = std::get<0>(chain.back());
|
Cell *prev = std::get<0>(chain.back());
|
||||||
if (param(prev, \BREG, 2).as_int() > 0 &&
|
if (param(next, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
|
||||||
param(next, \BREG, 2).as_int() > 0 &&
|
|
||||||
param(next, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
|
|
||||||
port(next, \BCIN, SigSpec()).is_fully_zero() &&
|
port(next, \BCIN, SigSpec()).is_fully_zero() &&
|
||||||
nusers(port(prev, \BCOUT, SigSpec())) <= 1) {
|
nusers(port(prev, \BCOUT, SigSpec())) <= 1) {
|
||||||
argQ = unextend(port(next, \B));
|
if ((next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG, 0) == 0 && param(prev, \B1REG, 1) == 0) ||
|
||||||
clock = port(prev, \CLK);
|
(next->type.in(\DSP48E1) && param(prev, \BREG, 2) == 0)) {
|
||||||
subpattern(in_dffe);
|
if (port(prev, \B) == port(next, \B))
|
||||||
if (dff) {
|
BREG = 0;
|
||||||
if (!dffrstmux && port(prev, \RSTB, State::S0) != State::S0)
|
}
|
||||||
goto reject_BREG;
|
else {
|
||||||
if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTB, State::S0))
|
argQ = unextend(port(next, \B));
|
||||||
goto reject_BREG;
|
clock = port(prev, \CLK);
|
||||||
if (!dffcemux && port(prev, \CEB2, State::S0) != State::S0)
|
subpattern(in_dffe);
|
||||||
goto reject_BREG;
|
if (dff) {
|
||||||
if (dffcemux && port(dffcemux, \S) != port(prev, \CEB2, State::S0))
|
if (!dffrstmux && port(prev, \RSTB, State::S0) != State::S0)
|
||||||
goto reject_BREG;
|
goto reject_BREG;
|
||||||
if (dffD == unextend(port(prev, \B)))
|
if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTB, State::S0))
|
||||||
BREG = 1;
|
goto reject_BREG;
|
||||||
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
|
endcode
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,7 @@ struct SimInstance
|
||||||
bool did_something = false;
|
bool did_something = false;
|
||||||
|
|
||||||
sig = sigmap(sig);
|
sig = sigmap(sig);
|
||||||
log_assert(GetSize(sig) == GetSize(value));
|
log_assert(GetSize(sig) <= GetSize(value));
|
||||||
|
|
||||||
for (int i = 0; i < GetSize(sig); i++)
|
for (int i = 0; i < GetSize(sig); i++)
|
||||||
if (state_nets.at(sig[i]) != value[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
|
// 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
|
// 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_LIB "strash; ifraig; scorr; dc2; dretime; 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_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; retime {D}; strash; dch -f; if; mfs2"
|
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; 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_SOP "strash; ifraig; scorr; dc2; dretime; 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_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_LIB "strash; dretime; map {D}"
|
||||||
#define ABC_FAST_COMMAND_CTR "strash; dretime; retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
||||||
#define ABC_FAST_COMMAND_LUT "strash; dretime; retime {D}; if"
|
#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
|
||||||
#define ABC_FAST_COMMAND_SOP "strash; dretime; retime {D}; cover -I {I} -P {P}"
|
#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
|
||||||
#define ABC_FAST_COMMAND_DFL "strash; dretime; retime {D}; map"
|
#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
|
||||||
|
|
||||||
#include "kernel/register.h"
|
#include "kernel/register.h"
|
||||||
#include "kernel/sigtools.h"
|
#include "kernel/sigtools.h"
|
||||||
|
@ -749,6 +749,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
else
|
else
|
||||||
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
|
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))
|
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);
|
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);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
if (!lut_costs.empty() && !liberty_file.empty())
|
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())
|
if (!constr_file.empty() && liberty_file.empty())
|
||||||
log_cmd_error("Got -constr but no -liberty!\n");
|
log_cmd_error("Got -constr but no -liberty!\n");
|
||||||
|
|
||||||
|
|
|
@ -985,29 +985,28 @@ struct Abc9Pass : public Pass {
|
||||||
//}
|
//}
|
||||||
if (arg == "-lut" && argidx+1 < args.size()) {
|
if (arg == "-lut" && argidx+1 < args.size()) {
|
||||||
string arg = args[++argidx];
|
string arg = args[++argidx];
|
||||||
size_t pos = arg.find_first_of(':');
|
if (arg.find_first_not_of("0123456789:") == std::string::npos) {
|
||||||
int lut_mode = 0, lut_mode2 = 0;
|
size_t pos = arg.find_first_of(':');
|
||||||
if (pos != string::npos) {
|
int lut_mode = 0, lut_mode2 = 0;
|
||||||
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 (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
lut_file = arg;
|
lut_mode = atoi(arg.substr(0, pos).c_str());
|
||||||
rewrite_filename(lut_file);
|
lut_mode2 = atoi(arg.substr(pos+1).c_str());
|
||||||
if (!lut_file.empty() && !is_absolute_path(lut_file))
|
} else {
|
||||||
lut_file = std::string(pwd) + "/" + lut_file;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lut_mode = atoi(arg.c_str());
|
lut_mode = atoi(arg.c_str());
|
||||||
lut_mode2 = lut_mode;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
if (arg == "-luts" && argidx+1 < args.size()) {
|
if (arg == "-luts" && argidx+1 < args.size()) {
|
||||||
|
@ -1076,7 +1075,7 @@ struct Abc9Pass : public Pass {
|
||||||
box_file = "+/dummy.box";
|
box_file = "+/dummy.box";
|
||||||
|
|
||||||
rewrite_filename(box_file);
|
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;
|
box_file = std::string(pwd) + "/" + box_file;
|
||||||
|
|
||||||
dict<int,IdString> box_lookup;
|
dict<int,IdString> box_lookup;
|
||||||
|
|
|
@ -192,11 +192,28 @@ struct IopadmapPass : public Pass {
|
||||||
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
|
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
|
||||||
{
|
{
|
||||||
dict<SigBit, Cell *> tbuf_bits;
|
dict<SigBit, Cell *> tbuf_bits;
|
||||||
|
pool<SigBit> driven_bits;
|
||||||
|
|
||||||
|
// Gather tristate buffers and always-on drivers.
|
||||||
for (auto cell : module->cells())
|
for (auto cell : module->cells())
|
||||||
if (cell->type == ID($_TBUF_)) {
|
if (cell->type == ID($_TBUF_)) {
|
||||||
SigBit bit = cell->getPort(ID::Y).as_bit();
|
SigBit bit = cell->getPort(ID::Y).as_bit();
|
||||||
tbuf_bits[bit] = cell;
|
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())
|
for (auto wire : module->selected_wires())
|
||||||
|
@ -204,41 +221,71 @@ struct IopadmapPass : public Pass {
|
||||||
if (!wire->port_output)
|
if (!wire->port_output)
|
||||||
continue;
|
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++)
|
for (int i = 0; i < GetSize(wire); i++)
|
||||||
{
|
{
|
||||||
SigBit wire_bit(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;
|
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)
|
SigBit en_sig;
|
||||||
continue;
|
SigBit data_sig;
|
||||||
|
bool is_driven = driven_bits.count(wire_bit);
|
||||||
|
|
||||||
SigBit en_sig = tbuf_cell->getPort(ID(E)).as_bit();
|
if (tbuf_cell != nullptr) {
|
||||||
SigBit data_sig = tbuf_cell->getPort(ID::A).as_bit();
|
// 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());
|
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 *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_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);
|
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);
|
skip_wire_bits.insert(wire_bit);
|
||||||
if (!tinoutpad_portname_pad.empty())
|
if (!tinoutpad_portname_pad.empty())
|
||||||
rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(tinoutpad_portname_pad));
|
rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(tinoutpad_portname_pad));
|
||||||
continue;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
if (!wire->port_input && !toutpad_celltype.empty())
|
|
||||||
{
|
|
||||||
log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, toutpad_celltype.c_str());
|
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));
|
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->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig);
|
||||||
cell->attributes[ID::keep] = RTLIL::Const(1);
|
cell->attributes[ID::keep] = RTLIL::Const(1);
|
||||||
|
|
||||||
module->remove(tbuf_cell);
|
if (tbuf_cell) {
|
||||||
module->connect(wire_bit, data_sig);
|
module->remove(tbuf_cell);
|
||||||
|
module->connect(wire_bit, data_sig);
|
||||||
|
}
|
||||||
skip_wire_bits.insert(wire_bit);
|
skip_wire_bits.insert(wire_bit);
|
||||||
if (!toutpad_portname_pad.empty())
|
if (!toutpad_portname_pad.empty())
|
||||||
rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(toutpad_portname_pad));
|
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(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\n");
|
log("The following commands are executed by this synthesis command:\n");
|
||||||
|
@ -152,12 +152,12 @@ struct SynthAchronixPass : public ScriptPass {
|
||||||
run("clean -purge");
|
run("clean -purge");
|
||||||
run("setundef -undriven -zero");
|
run("setundef -undriven -zero");
|
||||||
if (retime || help_mode)
|
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"))
|
if (check_label("map_luts"))
|
||||||
{
|
{
|
||||||
run("abc -lut 4" + string(retime ? " -dff" : ""));
|
run("abc -lut 4" + string(retime ? " -dff -D 1" : ""));
|
||||||
run("clean");
|
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/arith_map.v))
|
||||||
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_sim.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/eagle_bb.v))
|
||||||
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams.txt))
|
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutrams.txt))
|
||||||
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams_map.v))
|
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutrams_map.v))
|
||||||
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/dram_init_16x4.vh))
|
$(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_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 \$_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_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("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("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("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("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("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("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("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("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("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("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("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("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("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("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
|
||||||
|
|
||||||
module \$_DLATCH_N_ (E, D, Q);
|
module \$_DLATCH_N_ (E, D, Q);
|
||||||
wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";
|
wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";
|
||||||
|
|
|
@ -10,7 +10,7 @@ module \$__ANLOGIC_DRAM16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
||||||
input B1EN;
|
input B1EN;
|
||||||
|
|
||||||
EG_LOGIC_DRAM16X4 #(
|
EG_LOGIC_DRAM16X4 #(
|
||||||
`include "dram_init_16x4.vh"
|
`include "lutram_init_16x4.vh"
|
||||||
) _TECHMAP_REPLACE_ (
|
) _TECHMAP_REPLACE_ (
|
||||||
.di(B1DATA),
|
.di(B1DATA),
|
||||||
.waddr(B1ADDR),
|
.waddr(B1ADDR),
|
|
@ -58,7 +58,10 @@ struct SynthAnlogicPass : public ScriptPass
|
||||||
log(" do not flatten design before synthesis\n");
|
log(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\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;
|
string top_opt, edif_file, json_file;
|
||||||
bool flatten, retime;
|
bool flatten, retime, nolutram;
|
||||||
|
|
||||||
void clear_flags() YS_OVERRIDE
|
void clear_flags() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -76,6 +79,7 @@ struct SynthAnlogicPass : public ScriptPass
|
||||||
json_file = "";
|
json_file = "";
|
||||||
flatten = true;
|
flatten = true;
|
||||||
retime = false;
|
retime = false;
|
||||||
|
nolutram = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
@ -110,6 +114,10 @@ struct SynthAnlogicPass : public ScriptPass
|
||||||
flatten = false;
|
flatten = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-nolutram") {
|
||||||
|
nolutram = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-retime") {
|
if (args[argidx] == "-retime") {
|
||||||
retime = true;
|
retime = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -150,21 +158,25 @@ struct SynthAnlogicPass : public ScriptPass
|
||||||
run("synth -run coarse");
|
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("memory_bram -rules +/anlogic/lutrams.txt");
|
||||||
run("techmap -map +/anlogic/drams_map.v");
|
run("techmap -map +/anlogic/lutrams_map.v");
|
||||||
run("setundef -zero -params t:EG_LOGIC_DRAM16X4");
|
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("opt -fast -mux_undef -undriven -fine");
|
||||||
run("memory_map");
|
run("memory_map");
|
||||||
run("opt -undriven -fine");
|
run("opt -undriven -fine");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_gates"))
|
||||||
|
{
|
||||||
run("techmap -map +/techmap.v -map +/anlogic/arith_map.v");
|
run("techmap -map +/techmap.v -map +/anlogic/arith_map.v");
|
||||||
if (retime || help_mode)
|
if (retime || help_mode)
|
||||||
run("abc -dff", "(only if -retime)");
|
run("abc -dff -D 1", "(only if -retime)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_ffs"))
|
if (check_label("map_ffs"))
|
||||||
|
@ -187,7 +199,7 @@ struct SynthAnlogicPass : public ScriptPass
|
||||||
run("techmap -map +/anlogic/cells_map.v");
|
run("techmap -map +/anlogic/cells_map.v");
|
||||||
run("clean");
|
run("clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_anlogic"))
|
if (check_label("map_anlogic"))
|
||||||
{
|
{
|
||||||
run("anlogic_fixcarry");
|
run("anlogic_fixcarry");
|
||||||
|
|
|
@ -55,7 +55,7 @@ struct SynthCoolrunner2Pass : public ScriptPass
|
||||||
log(" do not flatten design before synthesis\n");
|
log(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\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"))
|
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");
|
run("clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ struct SynthEasicPass : public ScriptPass
|
||||||
log(" do not flatten design before synthesis\n");
|
log(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\n");
|
log("The following commands are executed by this synthesis command:\n");
|
||||||
|
@ -158,7 +158,7 @@ struct SynthEasicPass : public ScriptPass
|
||||||
run("techmap");
|
run("techmap");
|
||||||
run("opt -fast");
|
run("opt -fast");
|
||||||
if (retime || help_mode) {
|
if (retime || help_mode) {
|
||||||
run("abc -dff", " (only if -retime)");
|
run("abc -dff -D 1", " (only if -retime)");
|
||||||
run("opt_clean", "(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_sim.v))
|
||||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.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/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/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/arith_map.v))
|
||||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_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))
|
$(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_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
|
||||||
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
|
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
`ifdef ASYNC_PRLD
|
||||||
|
module \$_DLATCH_N_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(!E), .DI(1'b0), .M(D), .Q(Q)); endmodule
|
||||||
|
module \$_DLATCH_P_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(E), .DI(1'b0), .M(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
module \$_DFFSR_NNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule
|
||||||
|
module \$_DFFSR_NNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule
|
||||||
|
module \$_DFFSR_NPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule
|
||||||
|
module \$_DFFSR_NPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
module \$_DFFSR_PNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule
|
||||||
|
module \$_DFFSR_PNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule
|
||||||
|
module \$_DFFSR_PPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule
|
||||||
|
module \$_DFFSR_PPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule
|
||||||
|
`endif
|
||||||
|
|
||||||
`include "cells_ff.vh"
|
`include "cells_ff.vh"
|
||||||
`include "cells_io.vh"
|
`include "cells_io.vh"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
|
||||||
|
(* lib_whitebox *)
|
||||||
module LUT4(input A, B, C, D, output Z);
|
module LUT4(input A, B, C, D, output Z);
|
||||||
parameter [15:0] INIT = 16'h0000;
|
parameter [15:0] INIT = 16'h0000;
|
||||||
wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0];
|
wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0];
|
||||||
|
@ -31,13 +32,8 @@ module CCU2C(
|
||||||
|
|
||||||
// First half
|
// First half
|
||||||
wire LUT4_0, LUT2_0;
|
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));
|
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));
|
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;
|
wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN;
|
||||||
assign S0 = LUT4_0 ^ gated_cin_0;
|
assign S0 = LUT4_0 ^ gated_cin_0;
|
||||||
|
|
||||||
|
@ -46,13 +42,8 @@ module CCU2C(
|
||||||
|
|
||||||
// Second half
|
// Second half
|
||||||
wire LUT4_1, LUT2_1;
|
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));
|
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));
|
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;
|
wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0;
|
||||||
assign S1 = LUT4_1 ^ gated_cin_1;
|
assign S1 = LUT4_1 ^ gated_cin_1;
|
||||||
|
|
||||||
|
@ -209,6 +200,7 @@ endmodule
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
|
||||||
|
(* lib_whitebox *)
|
||||||
module LUT2(input A, B, output Z);
|
module LUT2(input A, B, output Z);
|
||||||
parameter [3:0] INIT = 4'h0;
|
parameter [3:0] INIT = 4'h0;
|
||||||
wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0];
|
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(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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(" -noccu2\n");
|
log(" -noccu2\n");
|
||||||
log(" do not use CCU2 cells in output netlist\n");
|
log(" do not use CCU2 cells in output netlist\n");
|
||||||
|
@ -79,6 +79,9 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
log(" -nowidelut\n");
|
log(" -nowidelut\n");
|
||||||
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
|
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -asyncprld\n");
|
||||||
|
log(" use async PRLD mode to implement DLATCH and DFFSR (EXPERIMENTAL)\n");
|
||||||
|
log("\n");
|
||||||
log(" -abc2\n");
|
log(" -abc2\n");
|
||||||
log(" run two passes of 'abc' for slightly improved logic density\n");
|
log(" run two passes of 'abc' for slightly improved logic density\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -99,7 +102,7 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
}
|
}
|
||||||
|
|
||||||
string top_opt, blif_file, edif_file, json_file;
|
string top_opt, blif_file, edif_file, json_file;
|
||||||
bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, nodsp, vpr;
|
bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, retime, abc2, abc9, nodsp, vpr;
|
||||||
|
|
||||||
void clear_flags() YS_OVERRIDE
|
void clear_flags() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -112,6 +115,7 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
nobram = false;
|
nobram = false;
|
||||||
nolutram = false;
|
nolutram = false;
|
||||||
nowidelut = false;
|
nowidelut = false;
|
||||||
|
asyncprld = false;
|
||||||
flatten = true;
|
flatten = true;
|
||||||
retime = false;
|
retime = false;
|
||||||
abc2 = false;
|
abc2 = false;
|
||||||
|
@ -176,6 +180,10 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
nobram = true;
|
nobram = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-asyncprld") {
|
||||||
|
asyncprld = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
|
if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
|
||||||
nolutram = true;
|
nolutram = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -222,7 +230,7 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
{
|
{
|
||||||
if (check_label("begin"))
|
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()));
|
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)"))
|
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");
|
run("techmap -map +/ecp5/brams_map.v");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
|
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");
|
run("techmap -map +/ecp5/lutrams_map.v");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +290,7 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
else
|
else
|
||||||
run("techmap -map +/techmap.v -map +/ecp5/arith_map.v");
|
run("techmap -map +/techmap.v -map +/ecp5/arith_map.v");
|
||||||
if (retime || help_mode)
|
if (retime || help_mode)
|
||||||
run("abc -dff", "(only if -retime)");
|
run("abc -dff -D 1", "(only if -retime)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_ffs"))
|
if (check_label("map_ffs"))
|
||||||
|
@ -292,7 +300,7 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
run("opt_clean");
|
run("opt_clean");
|
||||||
if (!nodffe)
|
if (!nodffe)
|
||||||
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
|
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
|
||||||
run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
|
run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : "")));
|
||||||
run("opt_expr -undriven -mux_undef");
|
run("opt_expr -undriven -mux_undef");
|
||||||
run("simplemap");
|
run("simplemap");
|
||||||
run("ecp5_ffinit");
|
run("ecp5_ffinit");
|
||||||
|
@ -306,10 +314,11 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
if (abc2 || help_mode) {
|
if (abc2 || help_mode) {
|
||||||
run("abc", " (only if -abc2)");
|
run("abc", " (only if -abc2)");
|
||||||
}
|
}
|
||||||
std::string techmap_args = "-map +/ecp5/latches_map.v";
|
std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v";
|
||||||
if (abc9)
|
if (abc9)
|
||||||
techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1";
|
techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1";
|
||||||
run("techmap " + techmap_args);
|
if (!asyncprld || abc9)
|
||||||
|
run("techmap " + techmap_args);
|
||||||
|
|
||||||
if (abc9) {
|
if (abc9) {
|
||||||
run("read_verilog -icells -lib +/ecp5/abc9_model.v");
|
run("read_verilog -icells -lib +/ecp5/abc9_model.v");
|
||||||
|
|
|
@ -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/arith_map.v))
|
||||||
$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.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/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(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\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;
|
string top_opt, edif_file, json_file;
|
||||||
bool flatten, retime;
|
bool flatten, retime, nobram;
|
||||||
|
|
||||||
void clear_flags() YS_OVERRIDE
|
void clear_flags() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -76,6 +79,7 @@ struct SynthEfinixPass : public ScriptPass
|
||||||
json_file = "";
|
json_file = "";
|
||||||
flatten = true;
|
flatten = true;
|
||||||
retime = false;
|
retime = false;
|
||||||
|
nobram = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
@ -114,6 +118,10 @@ struct SynthEfinixPass : public ScriptPass
|
||||||
retime = true;
|
retime = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-nobram") {
|
||||||
|
nobram = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
@ -150,21 +158,25 @@ struct SynthEfinixPass : public ScriptPass
|
||||||
run("synth -run coarse");
|
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("techmap -map +/efinix/brams_map.v");
|
||||||
run("setundef -zero -params t:EFX_RAM_5K");
|
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("opt -fast -mux_undef -undriven -fine");
|
||||||
run("memory_map");
|
run("memory_map");
|
||||||
run("opt -undriven -fine");
|
run("opt -undriven -fine");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_gates"))
|
||||||
|
{
|
||||||
run("techmap -map +/techmap.v -map +/efinix/arith_map.v");
|
run("techmap -map +/techmap.v -map +/efinix/arith_map.v");
|
||||||
if (retime || help_mode)
|
if (retime || help_mode)
|
||||||
run("abc -dff", "(only if -retime)");
|
run("abc -dff -D 1", "(only if -retime)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_ffs"))
|
if (check_label("map_ffs"))
|
||||||
|
@ -194,7 +206,7 @@ struct SynthEfinixPass : public ScriptPass
|
||||||
run("efinix_fixcarry");
|
run("efinix_fixcarry");
|
||||||
run("clean");
|
run("clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("check"))
|
if (check_label("check"))
|
||||||
{
|
{
|
||||||
run("hierarchy -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/cells_sim.v))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.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/brams_map.v))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,23 +55,23 @@ struct SynthGowinPass : public ScriptPass
|
||||||
log(" -nobram\n");
|
log(" -nobram\n");
|
||||||
log(" do not use BRAM cells in output netlist\n");
|
log(" do not use BRAM cells in output netlist\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -nodram\n");
|
log(" -nolutram\n");
|
||||||
log(" do not use distributed RAM cells in output netlist\n");
|
log(" do not use distributed RAM cells in output netlist\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -noflatten\n");
|
log(" -noflatten\n");
|
||||||
log(" do not flatten design before synthesis\n");
|
log(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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(" -nowidelut\n");
|
log(" -nowidelut\n");
|
||||||
log(" do not use muxes to implement LUTs larger than LUT4s\n");
|
log(" do not use muxes to implement LUTs larger than LUT4s\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -noiopads\n");
|
log(" -noiopads\n");
|
||||||
log(" do not emit IOB at top level ports\n");
|
log(" do not emit IOB at top level ports\n");
|
||||||
log("\n");
|
//log("\n");
|
||||||
log(" -abc9\n");
|
//log(" -abc9\n");
|
||||||
log(" use new ABC9 flow (EXPERIMENTAL)\n");
|
//log(" use new ABC9 flow (EXPERIMENTAL)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\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;
|
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
|
void clear_flags() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -90,7 +90,7 @@ struct SynthGowinPass : public ScriptPass
|
||||||
flatten = true;
|
flatten = true;
|
||||||
nobram = false;
|
nobram = false;
|
||||||
nodffe = false;
|
nodffe = false;
|
||||||
nodram = false;
|
nolutram = false;
|
||||||
nowidelut = false;
|
nowidelut = false;
|
||||||
abc9 = false;
|
abc9 = false;
|
||||||
noiopads = false;
|
noiopads = false;
|
||||||
|
@ -128,8 +128,8 @@ struct SynthGowinPass : public ScriptPass
|
||||||
nobram = true;
|
nobram = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-nodram") {
|
if (args[argidx] == "-nolutram" || /*deprecated*/args[argidx] == "-nodram") {
|
||||||
nodram = true;
|
nolutram = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-nodffe") {
|
if (args[argidx] == "-nodffe") {
|
||||||
|
@ -144,10 +144,10 @@ struct SynthGowinPass : public ScriptPass
|
||||||
nowidelut = true;
|
nowidelut = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-abc9") {
|
//if (args[argidx] == "-abc9") {
|
||||||
abc9 = true;
|
// abc9 = true;
|
||||||
continue;
|
// continue;
|
||||||
}
|
//}
|
||||||
if (args[argidx] == "-noiopads") {
|
if (args[argidx] == "-noiopads") {
|
||||||
noiopads = true;
|
noiopads = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -188,28 +188,32 @@ struct SynthGowinPass : public ScriptPass
|
||||||
run("synth -run coarse");
|
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");
|
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("memory_bram -rules +/gowin/lutrams.txt");
|
||||||
run("techmap -map +/gowin/drams_map.v");
|
run("techmap -map +/gowin/lutrams_map.v");
|
||||||
run("determine_init");
|
run("determine_init");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("fine"))
|
if (check_label("map_ffram"))
|
||||||
{
|
{
|
||||||
run("opt -fast -mux_undef -undriven -fine");
|
run("opt -fast -mux_undef -undriven -fine");
|
||||||
run("memory_map");
|
run("memory_map");
|
||||||
run("opt -undriven -fine");
|
run("opt -undriven -fine");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_label("map_gates"))
|
||||||
|
{
|
||||||
run("techmap -map +/techmap.v -map +/gowin/arith_map.v");
|
run("techmap -map +/techmap.v -map +/gowin/arith_map.v");
|
||||||
run("techmap -map +/techmap.v");
|
run("techmap -map +/techmap.v");
|
||||||
if (retime || help_mode)
|
if (retime || help_mode)
|
||||||
run("abc -dff", "(only if -retime)");
|
run("abc -dff -D 1", "(only if -retime)");
|
||||||
run("splitnets");
|
run("splitnets");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,13 +231,13 @@ struct SynthGowinPass : public ScriptPass
|
||||||
|
|
||||||
if (check_label("map_luts"))
|
if (check_label("map_luts"))
|
||||||
{
|
{
|
||||||
if (nowidelut && abc9) {
|
/*if (nowidelut && abc9) {
|
||||||
run("abc9 -lut 4");
|
run("abc9 -lut 4");
|
||||||
} else if (nowidelut && !abc9) {
|
} else*/ if (nowidelut && !abc9) {
|
||||||
run("abc -lut 4");
|
run("abc -lut 4");
|
||||||
} else if (!nowidelut && abc9) {
|
} else /*if (!nowidelut && abc9) {
|
||||||
run("abc9 -lut 4:8");
|
run("abc9 -lut 4:8");
|
||||||
} else if (!nowidelut && !abc9) {
|
} else*/ if (!nowidelut && !abc9) {
|
||||||
run("abc -lut 4:8");
|
run("abc -lut 4:8");
|
||||||
}
|
}
|
||||||
run("clean");
|
run("clean");
|
||||||
|
@ -248,7 +252,6 @@ struct SynthGowinPass : public ScriptPass
|
||||||
run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O "
|
run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O "
|
||||||
"-toutpad TBUF OEN:I:O -tinoutpad IOBUF OEN:O:I:IO", "(unless -noiopads)");
|
"-toutpad TBUF OEN:I:O -tinoutpad IOBUF OEN:O:I:IO", "(unless -noiopads)");
|
||||||
run("clean");
|
run("clean");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("check"))
|
if (check_label("check"))
|
||||||
|
|
|
@ -59,7 +59,7 @@ struct SynthGreenPAK4Pass : public ScriptPass
|
||||||
log(" do not flatten design before synthesis\n");
|
log(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\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("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib");
|
||||||
run("opt -fast");
|
run("opt -fast");
|
||||||
if (retime || help_mode)
|
if (retime || help_mode)
|
||||||
run("abc -dff", "(only if -retime)");
|
run("abc -dff -D 1", "(only if -retime)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_luts"))
|
if (check_label("map_luts"))
|
||||||
|
|
|
@ -65,7 +65,7 @@ struct SynthIce40Pass : public ScriptPass
|
||||||
log(" do not flatten design before synthesis\n");
|
log(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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(" -nocarry\n");
|
log(" -nocarry\n");
|
||||||
log(" do not use SB_CARRY cells in output netlist\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");
|
run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
|
||||||
}
|
}
|
||||||
if (retime || help_mode)
|
if (retime || help_mode)
|
||||||
run(abc + " -dff", "(only if -retime)");
|
run(abc + " -dff -D 1", "(only if -retime)");
|
||||||
run("ice40_opt");
|
run("ice40_opt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ struct SynthIntelPass : public ScriptPass {
|
||||||
log(" do not flatten design before synthesis\n");
|
log(" do not flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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");
|
log("The following commands are executed by this synthesis command:\n");
|
||||||
help_script();
|
help_script();
|
||||||
|
@ -187,10 +187,10 @@ struct SynthIntelPass : public ScriptPass {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nobram && check_label("map_bram", "(skip if -nobram)")) {
|
if (!nobram && check_label("map_bram", "(skip if -nobram)")) {
|
||||||
if (family_opt == "cycloneiv" ||
|
if (family_opt == "cycloneiv" ||
|
||||||
family_opt == "cycloneive" ||
|
family_opt == "cycloneive" ||
|
||||||
family_opt == "max10" ||
|
family_opt == "max10" ||
|
||||||
help_mode) {
|
help_mode) {
|
||||||
run("memory_bram -rules +/intel/common/brams_m9k.txt", "(if applicable for family)");
|
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)");
|
run("techmap -map +/intel/common/brams_map_m9k.v", "(if applicable for family)");
|
||||||
} else {
|
} else {
|
||||||
|
@ -210,7 +210,7 @@ struct SynthIntelPass : public ScriptPass {
|
||||||
run("clean -purge");
|
run("clean -purge");
|
||||||
run("setundef -undriven -zero");
|
run("setundef -undriven -zero");
|
||||||
if (retime || help_mode)
|
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")) {
|
if (check_label("map_luts")) {
|
||||||
|
@ -224,7 +224,7 @@ struct SynthIntelPass : public ScriptPass {
|
||||||
if (check_label("map_cells")) {
|
if (check_label("map_cells")) {
|
||||||
if (iopads || help_mode)
|
if (iopads || help_mode)
|
||||||
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(if -iopads)");
|
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("dffinit -highlow -ff dffeas q power_up");
|
||||||
run("clean -purge");
|
run("clean -purge");
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ struct SynthSf2Pass : public ScriptPass
|
||||||
log(" insert direct PAD->global_net buffers\n");
|
log(" insert direct PAD->global_net buffers\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\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("opt -undriven -fine");
|
||||||
run("techmap -map +/techmap.v -map +/sf2/arith_map.v");
|
run("techmap -map +/techmap.v -map +/sf2/arith_map.v");
|
||||||
if (retime || help_mode)
|
if (retime || help_mode)
|
||||||
run("abc -dff", "(only if -retime)");
|
run("abc -dff -D 1", "(only if -retime)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_ffs"))
|
if (check_label("map_ffs"))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
OBJS += techlibs/xilinx/synth_xilinx.o
|
OBJS += techlibs/xilinx/synth_xilinx.o
|
||||||
|
OBJS += techlibs/xilinx/xilinx_dffopt.o
|
||||||
|
|
||||||
GENFILES += techlibs/xilinx/brams_init_36.vh
|
GENFILES += techlibs/xilinx/brams_init_36.vh
|
||||||
GENFILES += techlibs/xilinx/brams_init_32.vh
|
GENFILES += techlibs/xilinx/brams_init_32.vh
|
||||||
|
|
|
@ -88,6 +88,84 @@ module RAM128X1D (
|
||||||
\$__ABC9_LUT7 dpo (.A(\$DPO ), .S(DPRA), .Y(DPO));
|
\$__ABC9_LUT7 dpo (.A(\$DPO ), .S(DPRA), .Y(DPO));
|
||||||
endmodule
|
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 (
|
module SRL16E (
|
||||||
output Q,
|
output Q,
|
||||||
(* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D
|
(* 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_" *)
|
(* techmap_celltype = "$_DFF_PN1_" *)
|
||||||
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
|
|
||||||
|
(* techmap_celltype = "$__DFFE_NN0" *)
|
||||||
|
module _90_dffe_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFE_PN0" *)
|
||||||
|
module _90_dffe_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFE_NN1" *)
|
||||||
|
module _90_dffe_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFE_PN1" *)
|
||||||
|
module _90_dffe_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
|
||||||
|
|
||||||
|
(* techmap_celltype = "$__DFFS_NN0_" *)
|
||||||
|
module _90_dffs_nn0_to_np0 (input D, C, R, output Q); \$__DFFS_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFS_PN0_" *)
|
||||||
|
module _90_dffs_pn0_to_pp0 (input D, C, R, output Q); \$__DFFS_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFS_NN1_" *)
|
||||||
|
module _90_dffs_nn1_to_np1 (input D, C, R, output Q); \$__DFFS_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFS_PN1_" *)
|
||||||
|
module _90_dffs_pn1_to_pp1 (input D, C, R, output Q); \$__DFFS_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||||
|
|
||||||
|
(* techmap_celltype = "$__DFFSE_NN0" *)
|
||||||
|
module _90_dffse_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFSE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFSE_PN0" *)
|
||||||
|
module _90_dffse_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFSE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFSE_NN1" *)
|
||||||
|
module _90_dffse_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFSE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
|
||||||
|
(* techmap_celltype = "$__DFFSE_PN1" *)
|
||||||
|
module _90_dffse_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFSE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule
|
||||||
|
|
||||||
module \$__SHREG_ (input C, input D, input E, output Q);
|
module \$__SHREG_ (input C, input D, input E, output Q);
|
||||||
parameter DEPTH = 0;
|
parameter DEPTH = 0;
|
||||||
parameter [DEPTH-1:0] INIT = 0;
|
parameter [DEPTH-1:0] INIT = 0;
|
||||||
|
|
|
@ -227,6 +227,14 @@ module MUXCY(output O, input CI, DI, S);
|
||||||
assign O = S ? CI : DI;
|
assign O = S ? CI : DI;
|
||||||
endmodule
|
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 *)
|
(* abc9_box_id = 1, lib_whitebox *)
|
||||||
module MUXF7(output O, input I0, I1, S);
|
module MUXF7(output O, input I0, I1, S);
|
||||||
assign O = S ? I1 : I0;
|
assign O = S ? I1 : I0;
|
||||||
|
@ -237,6 +245,10 @@ module MUXF8(output O, input I0, I1, S);
|
||||||
assign O = S ? I1 : I0;
|
assign O = S ? I1 : I0;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module MUXF9(output O, input I0, I1, S);
|
||||||
|
assign O = S ? I1 : I0;
|
||||||
|
endmodule
|
||||||
|
|
||||||
module XORCY(output O, input CI, LI);
|
module XORCY(output O, input CI, LI);
|
||||||
assign O = CI ^ LI;
|
assign O = CI ^ LI;
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -258,6 +270,26 @@ module CARRY4(
|
||||||
assign CO[3] = S[3] ? CO[2] : DI[3];
|
assign CO[3] = S[3] ? CO[2] : DI[3];
|
||||||
endmodule
|
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
|
`ifdef _EXPLICIT_CARRY
|
||||||
|
|
||||||
module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
|
module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
|
||||||
|
@ -281,6 +313,16 @@ endmodule
|
||||||
|
|
||||||
`endif
|
`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
|
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
|
||||||
|
|
||||||
module FDRE (
|
module FDRE (
|
||||||
|
@ -329,6 +371,41 @@ module FDSE (
|
||||||
endcase endgenerate
|
endcase endgenerate
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module FDRSE (
|
||||||
|
output reg Q,
|
||||||
|
(* clkbuf_sink *)
|
||||||
|
(* invertible_pin = "IS_C_INVERTED" *)
|
||||||
|
input C,
|
||||||
|
(* invertible_pin = "IS_CE_INVERTED" *)
|
||||||
|
input CE,
|
||||||
|
(* invertible_pin = "IS_D_INVERTED" *)
|
||||||
|
input D,
|
||||||
|
(* invertible_pin = "IS_R_INVERTED" *)
|
||||||
|
input R,
|
||||||
|
(* invertible_pin = "IS_S_INVERTED" *)
|
||||||
|
input S
|
||||||
|
);
|
||||||
|
parameter [0:0] INIT = 1'b0;
|
||||||
|
parameter [0:0] IS_C_INVERTED = 1'b0;
|
||||||
|
parameter [0:0] IS_CE_INVERTED = 1'b0;
|
||||||
|
parameter [0:0] IS_D_INVERTED = 1'b0;
|
||||||
|
parameter [0:0] IS_R_INVERTED = 1'b0;
|
||||||
|
parameter [0:0] IS_S_INVERTED = 1'b0;
|
||||||
|
initial Q <= INIT;
|
||||||
|
wire c = C ^ IS_C_INVERTED;
|
||||||
|
wire ce = CE ^ IS_CE_INVERTED;
|
||||||
|
wire d = D ^ IS_D_INVERTED;
|
||||||
|
wire r = R ^ IS_R_INVERTED;
|
||||||
|
wire s = S ^ IS_S_INVERTED;
|
||||||
|
always @(posedge c)
|
||||||
|
if (r)
|
||||||
|
Q <= 0;
|
||||||
|
else if (s)
|
||||||
|
Q <= 1;
|
||||||
|
else if (ce)
|
||||||
|
Q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
module FDCE (
|
module FDCE (
|
||||||
(* abc9_arrival=303 *)
|
(* abc9_arrival=303 *)
|
||||||
output reg Q,
|
output reg Q,
|
||||||
|
@ -379,6 +456,51 @@ module FDPE (
|
||||||
endcase endgenerate
|
endcase endgenerate
|
||||||
endmodule
|
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 (
|
module FDRE_1 (
|
||||||
(* abc9_arrival=303 *)
|
(* abc9_arrival=303 *)
|
||||||
output reg Q,
|
output reg Q,
|
||||||
|
@ -445,8 +567,8 @@ module LDCE (
|
||||||
wire clr = CLR ^ IS_CLR_INVERTED;
|
wire clr = CLR ^ IS_CLR_INVERTED;
|
||||||
wire g = G ^ IS_G_INVERTED;
|
wire g = G ^ IS_G_INVERTED;
|
||||||
always @*
|
always @*
|
||||||
if (clr) Q = 1'b0;
|
if (clr) Q <= 1'b0;
|
||||||
else if (GE && g) Q = D;
|
else if (GE && g) Q <= D;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module LDPE (
|
module LDPE (
|
||||||
|
@ -467,8 +589,59 @@ module LDPE (
|
||||||
wire g = G ^ IS_G_INVERTED;
|
wire g = G ^ IS_G_INVERTED;
|
||||||
wire pre = PRE ^ IS_PRE_INVERTED;
|
wire pre = PRE ^ IS_PRE_INVERTED;
|
||||||
always @*
|
always @*
|
||||||
if (pre) Q = 1'b1;
|
if (pre) Q <= 1'b1;
|
||||||
else if (GE && g) Q = D;
|
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
|
endmodule
|
||||||
|
|
||||||
// LUTRAM.
|
// LUTRAM.
|
||||||
|
@ -939,8 +1112,8 @@ module RAM16X1D_1 (
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module RAM32X1D (
|
module RAM32X1D (
|
||||||
// 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#L857
|
||||||
(* abc9_arrival=1153 *)
|
(* abc9_arrival=1188 *)
|
||||||
output DPO, SPO,
|
output DPO, SPO,
|
||||||
input D,
|
input D,
|
||||||
(* clkbuf_sink *)
|
(* clkbuf_sink *)
|
||||||
|
@ -962,8 +1135,8 @@ module RAM32X1D (
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module RAM32X1D_1 (
|
module RAM32X1D_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#L857
|
||||||
(* abc9_arrival=1153 *)
|
(* abc9_arrival=1188 *)
|
||||||
output DPO, SPO,
|
output DPO, SPO,
|
||||||
input D,
|
input D,
|
||||||
(* clkbuf_sink *)
|
(* clkbuf_sink *)
|
||||||
|
@ -985,7 +1158,7 @@ module RAM32X1D_1 (
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module RAM64X1D (
|
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 *)
|
(* abc9_arrival=1153 *)
|
||||||
output DPO, SPO,
|
output DPO, SPO,
|
||||||
input D,
|
input D,
|
||||||
|
@ -1008,7 +1181,7 @@ module RAM64X1D (
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module RAM64X1D_1 (
|
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 *)
|
(* abc9_arrival=1153 *)
|
||||||
output DPO, SPO,
|
output DPO, SPO,
|
||||||
input D,
|
input D,
|
||||||
|
@ -1031,8 +1204,9 @@ module RAM64X1D_1 (
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module RAM128X1D (
|
module RAM128X1D (
|
||||||
// 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 *)
|
// plus 204ps to cross MUXF7
|
||||||
|
(* abc9_arrival=1357 *)
|
||||||
output DPO, SPO,
|
output DPO, SPO,
|
||||||
input D,
|
input D,
|
||||||
(* clkbuf_sink *)
|
(* clkbuf_sink *)
|
||||||
|
@ -1071,18 +1245,20 @@ endmodule
|
||||||
// Multi port.
|
// Multi port.
|
||||||
|
|
||||||
module RAM32M (
|
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,
|
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,
|
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,
|
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,
|
output [1:0] DOD,
|
||||||
input [4:0] ADDRA,
|
input [4:0] ADDRA, ADDRB, ADDRC, ADDRD,
|
||||||
input [4:0] ADDRB,
|
input [1:0] DIA, DIB, DIC, DID,
|
||||||
input [4:0] ADDRC,
|
|
||||||
input [4:0] ADDRD,
|
|
||||||
input [1:0] DIA,
|
|
||||||
input [1:0] DIB,
|
|
||||||
input [1:0] DIC,
|
|
||||||
input [1:0] DID,
|
|
||||||
(* clkbuf_sink *)
|
(* clkbuf_sink *)
|
||||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||||
input WCLK,
|
input WCLK,
|
||||||
|
@ -1181,18 +1357,20 @@ module RAM32M16 (
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module RAM64M (
|
module RAM64M (
|
||||||
|
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
|
||||||
|
(* abc9_arrival=1153 *)
|
||||||
output DOA,
|
output DOA,
|
||||||
|
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
|
||||||
|
(* abc9_arrival=1161 *)
|
||||||
output DOB,
|
output DOB,
|
||||||
|
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
|
||||||
|
(* abc9_arrival=1158 *)
|
||||||
output DOC,
|
output DOC,
|
||||||
|
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
|
||||||
|
(* abc9_arrival=1163 *)
|
||||||
output DOD,
|
output DOD,
|
||||||
input [4:0] ADDRA,
|
input [5:0] ADDRA, ADDRB, ADDRC, ADDRD,
|
||||||
input [4:0] ADDRB,
|
input DIA, DIB, DIC, DID,
|
||||||
input [4:0] ADDRC,
|
|
||||||
input [4:0] ADDRD,
|
|
||||||
input DIA,
|
|
||||||
input DIB,
|
|
||||||
input DIC,
|
|
||||||
input DID,
|
|
||||||
(* clkbuf_sink *)
|
(* clkbuf_sink *)
|
||||||
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
(* invertible_pin = "IS_WCLK_INVERTED" *)
|
||||||
input WCLK,
|
input WCLK,
|
||||||
|
@ -1230,14 +1408,14 @@ module RAM64M8 (
|
||||||
output DOF,
|
output DOF,
|
||||||
output DOG,
|
output DOG,
|
||||||
output DOH,
|
output DOH,
|
||||||
input [4:0] ADDRA,
|
input [5:0] ADDRA,
|
||||||
input [4:0] ADDRB,
|
input [5:0] ADDRB,
|
||||||
input [4:0] ADDRC,
|
input [5:0] ADDRC,
|
||||||
input [4:0] ADDRD,
|
input [5:0] ADDRD,
|
||||||
input [4:0] ADDRE,
|
input [5:0] ADDRE,
|
||||||
input [4:0] ADDRF,
|
input [5:0] ADDRF,
|
||||||
input [4:0] ADDRG,
|
input [5:0] ADDRG,
|
||||||
input [4:0] ADDRH,
|
input [5:0] ADDRH,
|
||||||
input DIA,
|
input DIA,
|
||||||
input DIB,
|
input DIB,
|
||||||
input DIC,
|
input DIC,
|
||||||
|
@ -1334,8 +1512,22 @@ endmodule
|
||||||
|
|
||||||
// Shift registers.
|
// 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 (
|
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 *)
|
(* abc9_arrival=1472 *)
|
||||||
output Q,
|
output Q,
|
||||||
input A0, A1, A2, A3, CE,
|
input A0, A1, A2, A3, CE,
|
||||||
|
@ -1358,6 +1550,22 @@ module SRL16E (
|
||||||
endgenerate
|
endgenerate
|
||||||
endmodule
|
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 (
|
module SRLC16E (
|
||||||
output Q,
|
output Q,
|
||||||
output Q15,
|
output Q15,
|
||||||
|
@ -1383,9 +1591,10 @@ module SRLC16E (
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module SRLC32E (
|
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 *)
|
(* abc9_arrival=1472 *)
|
||||||
output Q,
|
output Q,
|
||||||
|
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904
|
||||||
(* abc9_arrival=1114 *)
|
(* abc9_arrival=1114 *)
|
||||||
output Q31,
|
output Q31,
|
||||||
input [4:0] A,
|
input [4:0] A,
|
||||||
|
@ -1410,6 +1619,31 @@ module SRLC32E (
|
||||||
endgenerate
|
endgenerate
|
||||||
endmodule
|
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
|
// DSP
|
||||||
|
|
||||||
// Virtex 2, Virtex 2 Pro, Spartan 3.
|
// Virtex 2, Virtex 2 Pro, Spartan 3.
|
||||||
|
@ -1885,7 +2119,7 @@ always @* begin
|
||||||
2'b00: XMUX <= 0;
|
2'b00: XMUX <= 0;
|
||||||
2'b01: XMUX <= M;
|
2'b01: XMUX <= M;
|
||||||
2'b10: XMUX <= P;
|
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;
|
default: XMUX <= 48'hxxxxxxxxxxxx;
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -1903,8 +2137,8 @@ end
|
||||||
// The post-adder.
|
// The post-adder.
|
||||||
wire signed [48:0] X_EXT;
|
wire signed [48:0] X_EXT;
|
||||||
wire signed [48:0] Z_EXT;
|
wire signed [48:0] Z_EXT;
|
||||||
assign X_EXT = XMUX;
|
assign X_EXT = {1'b0, XMUX};
|
||||||
assign Z_EXT = ZMUX;
|
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);
|
assign {CARRYOUT_IN, P_IN} = OPMODE_OUT[7] ? (Z_EXT - (X_EXT + CARRYIN_OUT)) : (Z_EXT + X_EXT + CARRYIN_OUT);
|
||||||
|
|
||||||
// Cascade outputs.
|
// Cascade outputs.
|
||||||
|
@ -2002,7 +2236,7 @@ module DSP48E1 (
|
||||||
parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
|
parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
`ifdef __ICARUS__
|
`ifndef YOSYS
|
||||||
if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
|
if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
|
||||||
if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value");
|
if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value");
|
||||||
if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
|
if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
|
||||||
|
@ -2165,12 +2399,12 @@ module DSP48E1 (
|
||||||
case (OPMODEr[1:0])
|
case (OPMODEr[1:0])
|
||||||
2'b00: X = 48'b0;
|
2'b00: X = 48'b0;
|
||||||
2'b01: begin X = $signed(Mrx);
|
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");
|
if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
|
||||||
`endif
|
`endif
|
||||||
end
|
end
|
||||||
2'b10: begin X = P;
|
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");
|
if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
|
||||||
`endif
|
`endif
|
||||||
end
|
end
|
||||||
|
@ -2182,7 +2416,7 @@ module DSP48E1 (
|
||||||
case (OPMODEr[3:2])
|
case (OPMODEr[3:2])
|
||||||
2'b00: Y = 48'b0;
|
2'b00: Y = 48'b0;
|
||||||
2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling?
|
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");
|
if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
|
||||||
`endif
|
`endif
|
||||||
end
|
end
|
||||||
|
@ -2196,13 +2430,13 @@ module DSP48E1 (
|
||||||
3'b000: Z = 48'b0;
|
3'b000: Z = 48'b0;
|
||||||
3'b001: Z = PCIN;
|
3'b001: Z = PCIN;
|
||||||
3'b010: begin Z = P;
|
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");
|
if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
|
||||||
`endif
|
`endif
|
||||||
end
|
end
|
||||||
3'b011: Z = Cr;
|
3'b011: Z = Cr;
|
||||||
3'b100: begin Z = P;
|
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 (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");
|
if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
|
||||||
`endif
|
`endif
|
||||||
|
|
|
@ -65,9 +65,9 @@ CELLS = [
|
||||||
|
|
||||||
# CLB -- registers/latches.
|
# CLB -- registers/latches.
|
||||||
# Virtex 1/2/4/5, Spartan 3.
|
# Virtex 1/2/4/5, Spartan 3.
|
||||||
Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}),
|
# Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}),
|
||||||
Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}),
|
# Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}),
|
||||||
Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}),
|
# Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}),
|
||||||
# Virtex 6, Spartan 6, Series 7, Ultrascale.
|
# Virtex 6, Spartan 6, Series 7, Ultrascale.
|
||||||
# Cell('FDCE'),
|
# Cell('FDCE'),
|
||||||
# Cell('FDPE'),
|
# Cell('FDPE'),
|
||||||
|
@ -75,8 +75,8 @@ CELLS = [
|
||||||
# Cell('FDSE'),
|
# Cell('FDSE'),
|
||||||
# Cell('LDCE'),
|
# Cell('LDCE'),
|
||||||
# Cell('LDPE'),
|
# Cell('LDPE'),
|
||||||
Cell('AND2B1L'),
|
# Cell('AND2B1L'),
|
||||||
Cell('OR2L'),
|
# Cell('OR2L'),
|
||||||
|
|
||||||
# CLB -- other.
|
# CLB -- other.
|
||||||
# Cell('LUT1'),
|
# Cell('LUT1'),
|
||||||
|
@ -86,23 +86,23 @@ CELLS = [
|
||||||
# Cell('LUT5'),
|
# Cell('LUT5'),
|
||||||
# Cell('LUT6'),
|
# Cell('LUT6'),
|
||||||
# Cell('LUT6_2'),
|
# Cell('LUT6_2'),
|
||||||
Cell('MUXF5'),
|
# Cell('MUXF5'),
|
||||||
Cell('MUXF6'),
|
# Cell('MUXF6'),
|
||||||
# Cell('MUXF7'),
|
# Cell('MUXF7'),
|
||||||
# Cell('MUXF8'),
|
# Cell('MUXF8'),
|
||||||
Cell('MUXF9'),
|
# Cell('MUXF9'),
|
||||||
# Cell('CARRY4'),
|
# Cell('CARRY4'),
|
||||||
Cell('CARRY8'),
|
# Cell('CARRY8'),
|
||||||
# Cell('MUXCY'),
|
# Cell('MUXCY'),
|
||||||
# Cell('XORCY'),
|
# Cell('XORCY'),
|
||||||
Cell('ORCY'),
|
# Cell('ORCY'),
|
||||||
Cell('MULT_AND'),
|
# Cell('MULT_AND'),
|
||||||
Cell('SRL16', port_attrs={'CLK': ['clkbuf_sink']}),
|
# Cell('SRL16', port_attrs={'CLK': ['clkbuf_sink']}),
|
||||||
# Cell('SRL16E', 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('SRLC16E', port_attrs={'CLK': ['clkbuf_sink']}),
|
||||||
# Cell('SRLC32E', 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.
|
# Block RAM.
|
||||||
# Virtex.
|
# Virtex.
|
||||||
|
|
|
@ -1,165 +1,5 @@
|
||||||
// Created by cells_xtra.py from Xilinx models
|
// 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 (...);
|
module RAMB16_S1 (...);
|
||||||
parameter [0:0] INIT = 1'h0;
|
parameter [0:0] INIT = 1'h0;
|
||||||
parameter [0:0] SRVAL = 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
|
bram $__XILINX_RAM32X1D
|
||||||
init 1
|
init 1
|
||||||
abits 5
|
abits 5
|
||||||
|
@ -38,6 +51,70 @@ bram $__XILINX_RAM128X1D
|
||||||
clkpol 0 2
|
clkpol 0 2
|
||||||
endbram
|
endbram
|
||||||
|
|
||||||
|
|
||||||
|
bram $__XILINX_RAM32X6SDP
|
||||||
|
init 1
|
||||||
|
abits 5
|
||||||
|
dbits 6
|
||||||
|
groups 2
|
||||||
|
ports 1 1
|
||||||
|
wrmode 0 1
|
||||||
|
enable 0 1
|
||||||
|
transp 0 0
|
||||||
|
clocks 0 1
|
||||||
|
clkpol 0 2
|
||||||
|
endbram
|
||||||
|
|
||||||
|
bram $__XILINX_RAM64X3SDP
|
||||||
|
init 1
|
||||||
|
abits 6
|
||||||
|
dbits 3
|
||||||
|
groups 2
|
||||||
|
ports 1 1
|
||||||
|
wrmode 0 1
|
||||||
|
enable 0 1
|
||||||
|
transp 0 0
|
||||||
|
clocks 0 1
|
||||||
|
clkpol 0 2
|
||||||
|
endbram
|
||||||
|
|
||||||
|
bram $__XILINX_RAM32X2Q
|
||||||
|
init 1
|
||||||
|
abits 5
|
||||||
|
dbits 2
|
||||||
|
groups 2
|
||||||
|
ports 3 1
|
||||||
|
wrmode 0 1
|
||||||
|
enable 0 1
|
||||||
|
transp 0 0
|
||||||
|
clocks 0 1
|
||||||
|
clkpol 0 2
|
||||||
|
endbram
|
||||||
|
|
||||||
|
bram $__XILINX_RAM64X1Q
|
||||||
|
init 1
|
||||||
|
abits 6
|
||||||
|
dbits 1
|
||||||
|
groups 2
|
||||||
|
ports 3 1
|
||||||
|
wrmode 0 1
|
||||||
|
enable 0 1
|
||||||
|
transp 0 0
|
||||||
|
clocks 0 1
|
||||||
|
clkpol 0 2
|
||||||
|
endbram
|
||||||
|
|
||||||
|
|
||||||
|
# Disabled for now, pending support for LUT4 arches
|
||||||
|
# since on LUT6 arches this occupies same area as
|
||||||
|
# a RAM32X1D
|
||||||
|
#match $__XILINX_RAM16X1D
|
||||||
|
# min bits 2
|
||||||
|
# min wports 1
|
||||||
|
# make_outreg
|
||||||
|
# or_next_if_better
|
||||||
|
#endmatch
|
||||||
|
|
||||||
match $__XILINX_RAM32X1D
|
match $__XILINX_RAM32X1D
|
||||||
min bits 3
|
min bits 3
|
||||||
min wports 1
|
min wports 1
|
||||||
|
@ -56,5 +133,35 @@ match $__XILINX_RAM128X1D
|
||||||
min bits 9
|
min bits 9
|
||||||
min wports 1
|
min wports 1
|
||||||
make_outreg
|
make_outreg
|
||||||
|
or_next_if_better
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
|
|
||||||
|
match $__XILINX_RAM32X6SDP
|
||||||
|
min bits 5
|
||||||
|
min wports 1
|
||||||
|
make_outreg
|
||||||
|
or_next_if_better
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match $__XILINX_RAM64X3SDP
|
||||||
|
min bits 6
|
||||||
|
min wports 1
|
||||||
|
make_outreg
|
||||||
|
or_next_if_better
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match $__XILINX_RAM32X2Q
|
||||||
|
min bits 5
|
||||||
|
min rports 3
|
||||||
|
min wports 1
|
||||||
|
make_outreg
|
||||||
|
or_next_if_better
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match $__XILINX_RAM64X1Q
|
||||||
|
min bits 5
|
||||||
|
min rports 3
|
||||||
|
min wports 1
|
||||||
|
make_outreg
|
||||||
|
endmatch
|
||||||
|
|
|
@ -1,4 +1,36 @@
|
||||||
|
|
||||||
|
module \$__XILINX_RAM16X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
||||||
|
parameter [15:0] INIT = 16'bx;
|
||||||
|
parameter CLKPOL2 = 1;
|
||||||
|
input CLK1;
|
||||||
|
|
||||||
|
input [3:0] A1ADDR;
|
||||||
|
output A1DATA;
|
||||||
|
|
||||||
|
input [3:0] B1ADDR;
|
||||||
|
input B1DATA;
|
||||||
|
input B1EN;
|
||||||
|
|
||||||
|
RAM16X1D #(
|
||||||
|
.INIT(INIT),
|
||||||
|
.IS_WCLK_INVERTED(!CLKPOL2)
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.DPRA0(A1ADDR[0]),
|
||||||
|
.DPRA1(A1ADDR[1]),
|
||||||
|
.DPRA2(A1ADDR[2]),
|
||||||
|
.DPRA3(A1ADDR[3]),
|
||||||
|
.DPO(A1DATA),
|
||||||
|
|
||||||
|
.A0(B1ADDR[0]),
|
||||||
|
.A1(B1ADDR[1]),
|
||||||
|
.A2(B1ADDR[2]),
|
||||||
|
.A3(B1ADDR[3]),
|
||||||
|
.D(B1DATA),
|
||||||
|
.WCLK(CLK1),
|
||||||
|
.WE(B1EN)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
||||||
parameter [31:0] INIT = 32'bx;
|
parameter [31:0] INIT = 32'bx;
|
||||||
parameter CLKPOL2 = 1;
|
parameter CLKPOL2 = 1;
|
||||||
|
@ -95,3 +127,153 @@ module \$__XILINX_RAM128X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
||||||
);
|
);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module \$__XILINX_RAM32X6SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
||||||
|
parameter [32*6-1:0] INIT = {32*6{1'bx}};
|
||||||
|
parameter CLKPOL2 = 1;
|
||||||
|
input CLK1;
|
||||||
|
|
||||||
|
input [4:0] A1ADDR;
|
||||||
|
output [5:0] A1DATA;
|
||||||
|
|
||||||
|
input [4:0] B1ADDR;
|
||||||
|
input [5:0] B1DATA;
|
||||||
|
input B1EN;
|
||||||
|
|
||||||
|
wire [1:0] DOD_unused;
|
||||||
|
|
||||||
|
RAM32M #(
|
||||||
|
.INIT_A({INIT[187:186], INIT[181:180], INIT[175:174], INIT[169:168], INIT[163:162], INIT[157:156], INIT[151:150], INIT[145:144], INIT[139:138], INIT[133:132], INIT[127:126], INIT[121:120], INIT[115:114], INIT[109:108], INIT[103:102], INIT[ 97: 96], INIT[ 91: 90], INIT[ 85: 84], INIT[ 79: 78], INIT[ 73: 72], INIT[ 67: 66], INIT[ 61: 60], INIT[ 55: 54], INIT[ 49: 48], INIT[ 43: 42], INIT[ 37: 36], INIT[ 31: 30], INIT[ 25: 24], INIT[ 19: 18], INIT[ 13: 12], INIT[ 7: 6], INIT[ 1: 0]}),
|
||||||
|
.INIT_B({INIT[189:188], INIT[183:182], INIT[177:176], INIT[171:170], INIT[165:164], INIT[159:158], INIT[153:152], INIT[147:146], INIT[141:140], INIT[135:134], INIT[129:128], INIT[123:122], INIT[117:116], INIT[111:110], INIT[105:104], INIT[ 99: 98], INIT[ 93: 92], INIT[ 87: 86], INIT[ 81: 80], INIT[ 75: 74], INIT[ 69: 68], INIT[ 63: 62], INIT[ 57: 56], INIT[ 51: 50], INIT[ 45: 44], INIT[ 39: 38], INIT[ 33: 32], INIT[ 27: 26], INIT[ 21: 20], INIT[ 15: 14], INIT[ 9: 8], INIT[ 3: 2]}),
|
||||||
|
.INIT_C({INIT[191:190], INIT[185:184], INIT[179:178], INIT[173:172], INIT[167:166], INIT[161:160], INIT[155:154], INIT[149:148], INIT[143:142], INIT[137:136], INIT[131:130], INIT[125:124], INIT[119:118], INIT[113:112], INIT[107:106], INIT[101:100], INIT[ 95: 94], INIT[ 89: 88], INIT[ 83: 82], INIT[ 77: 76], INIT[ 71: 70], INIT[ 65: 64], INIT[ 59: 58], INIT[ 53: 52], INIT[ 47: 46], INIT[ 41: 40], INIT[ 35: 34], INIT[ 29: 28], INIT[ 23: 22], INIT[ 17: 16], INIT[ 11: 10], INIT[ 5: 4]}),
|
||||||
|
.INIT_D(64'bx),
|
||||||
|
.IS_WCLK_INVERTED(!CLKPOL2)
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.ADDRA(A1ADDR),
|
||||||
|
.ADDRB(A1ADDR),
|
||||||
|
.ADDRC(A1ADDR),
|
||||||
|
.DOA(A1DATA[1:0]),
|
||||||
|
.DOB(A1DATA[3:2]),
|
||||||
|
.DOC(A1DATA[5:4]),
|
||||||
|
.DOD(DOD_unused),
|
||||||
|
|
||||||
|
.ADDRD(B1ADDR),
|
||||||
|
.DIA(B1DATA[1:0]),
|
||||||
|
.DIB(B1DATA[3:2]),
|
||||||
|
.DIC(B1DATA[5:4]),
|
||||||
|
.DID(2'b00),
|
||||||
|
.WCLK(CLK1),
|
||||||
|
.WE(B1EN)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__XILINX_RAM64X3SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
|
||||||
|
parameter [64*3-1:0] INIT = {64*3{1'bx}};
|
||||||
|
parameter CLKPOL2 = 1;
|
||||||
|
input CLK1;
|
||||||
|
|
||||||
|
input [5:0] A1ADDR;
|
||||||
|
output [2:0] A1DATA;
|
||||||
|
|
||||||
|
input [5:0] B1ADDR;
|
||||||
|
input [2:0] B1DATA;
|
||||||
|
input B1EN;
|
||||||
|
|
||||||
|
wire DOD_unused;
|
||||||
|
|
||||||
|
RAM64M #(
|
||||||
|
.INIT_A({INIT[189], INIT[186], INIT[183], INIT[180], INIT[177], INIT[174], INIT[171], INIT[168], INIT[165], INIT[162], INIT[159], INIT[156], INIT[153], INIT[150], INIT[147], INIT[144], INIT[141], INIT[138], INIT[135], INIT[132], INIT[129], INIT[126], INIT[123], INIT[120], INIT[117], INIT[114], INIT[111], INIT[108], INIT[105], INIT[102], INIT[ 99], INIT[ 96], INIT[ 93], INIT[ 90], INIT[ 87], INIT[ 84], INIT[ 81], INIT[ 78], INIT[ 75], INIT[ 72], INIT[ 69], INIT[ 66], INIT[ 63], INIT[ 60], INIT[ 57], INIT[ 54], INIT[ 51], INIT[ 48], INIT[ 45], INIT[ 42], INIT[ 39], INIT[ 36], INIT[ 33], INIT[ 30], INIT[ 27], INIT[ 24], INIT[ 21], INIT[ 18], INIT[ 15], INIT[ 12], INIT[ 9], INIT[ 6], INIT[ 3], INIT[ 0]}),
|
||||||
|
.INIT_B({INIT[190], INIT[187], INIT[184], INIT[181], INIT[178], INIT[175], INIT[172], INIT[169], INIT[166], INIT[163], INIT[160], INIT[157], INIT[154], INIT[151], INIT[148], INIT[145], INIT[142], INIT[139], INIT[136], INIT[133], INIT[130], INIT[127], INIT[124], INIT[121], INIT[118], INIT[115], INIT[112], INIT[109], INIT[106], INIT[103], INIT[100], INIT[ 97], INIT[ 94], INIT[ 91], INIT[ 88], INIT[ 85], INIT[ 82], INIT[ 79], INIT[ 76], INIT[ 73], INIT[ 70], INIT[ 67], INIT[ 64], INIT[ 61], INIT[ 58], INIT[ 55], INIT[ 52], INIT[ 49], INIT[ 46], INIT[ 43], INIT[ 40], INIT[ 37], INIT[ 34], INIT[ 31], INIT[ 28], INIT[ 25], INIT[ 22], INIT[ 19], INIT[ 16], INIT[ 13], INIT[ 10], INIT[ 7], INIT[ 4], INIT[ 1]}),
|
||||||
|
.INIT_C({INIT[191], INIT[188], INIT[185], INIT[182], INIT[179], INIT[176], INIT[173], INIT[170], INIT[167], INIT[164], INIT[161], INIT[158], INIT[155], INIT[152], INIT[149], INIT[146], INIT[143], INIT[140], INIT[137], INIT[134], INIT[131], INIT[128], INIT[125], INIT[122], INIT[119], INIT[116], INIT[113], INIT[110], INIT[107], INIT[104], INIT[101], INIT[ 98], INIT[ 95], INIT[ 92], INIT[ 89], INIT[ 86], INIT[ 83], INIT[ 80], INIT[ 77], INIT[ 74], INIT[ 71], INIT[ 68], INIT[ 65], INIT[ 62], INIT[ 59], INIT[ 56], INIT[ 53], INIT[ 50], INIT[ 47], INIT[ 44], INIT[ 41], INIT[ 38], INIT[ 35], INIT[ 32], INIT[ 29], INIT[ 26], INIT[ 23], INIT[ 20], INIT[ 17], INIT[ 14], INIT[ 11], INIT[ 8], INIT[ 5], INIT[ 2]}),
|
||||||
|
.INIT_D(64'bx),
|
||||||
|
.IS_WCLK_INVERTED(!CLKPOL2)
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.ADDRA(A1ADDR),
|
||||||
|
.ADDRB(A1ADDR),
|
||||||
|
.ADDRC(A1ADDR),
|
||||||
|
.DOA(A1DATA[0]),
|
||||||
|
.DOB(A1DATA[1]),
|
||||||
|
.DOC(A1DATA[2]),
|
||||||
|
.DOD(DOD_unused),
|
||||||
|
|
||||||
|
.ADDRD(B1ADDR),
|
||||||
|
.DIA(B1DATA[0]),
|
||||||
|
.DIB(B1DATA[1]),
|
||||||
|
.DIC(B1DATA[2]),
|
||||||
|
.DID(1'b0),
|
||||||
|
.WCLK(CLK1),
|
||||||
|
.WE(B1EN)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__XILINX_RAM32X2Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN);
|
||||||
|
parameter [63:0] INIT = 64'bx;
|
||||||
|
parameter CLKPOL2 = 1;
|
||||||
|
input CLK1;
|
||||||
|
|
||||||
|
input [4:0] A1ADDR, A2ADDR, A3ADDR;
|
||||||
|
output [1:0] A1DATA, A2DATA, A3DATA;
|
||||||
|
|
||||||
|
input [4:0] B1ADDR;
|
||||||
|
input [1:0] B1DATA;
|
||||||
|
input B1EN;
|
||||||
|
|
||||||
|
RAM32M #(
|
||||||
|
.INIT_A(INIT),
|
||||||
|
.INIT_B(INIT),
|
||||||
|
.INIT_C(INIT),
|
||||||
|
.INIT_D(INIT),
|
||||||
|
.IS_WCLK_INVERTED(!CLKPOL2)
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.ADDRA(A1ADDR),
|
||||||
|
.ADDRB(A2ADDR),
|
||||||
|
.ADDRC(A3ADDR),
|
||||||
|
.DOA(A1DATA),
|
||||||
|
.DOB(A2DATA),
|
||||||
|
.DOC(A3DATA),
|
||||||
|
|
||||||
|
.ADDRD(B1ADDR),
|
||||||
|
.DIA(B1DATA),
|
||||||
|
.DIB(B1DATA),
|
||||||
|
.DIC(B1DATA),
|
||||||
|
.DID(B1DATA),
|
||||||
|
.WCLK(CLK1),
|
||||||
|
.WE(B1EN)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__XILINX_RAM64X1Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN);
|
||||||
|
parameter [63:0] INIT = 64'bx;
|
||||||
|
parameter CLKPOL2 = 1;
|
||||||
|
input CLK1;
|
||||||
|
|
||||||
|
input [5:0] A1ADDR, A2ADDR, A3ADDR;
|
||||||
|
output A1DATA, A2DATA, A3DATA;
|
||||||
|
|
||||||
|
input [5:0] B1ADDR;
|
||||||
|
input B1DATA;
|
||||||
|
input B1EN;
|
||||||
|
|
||||||
|
RAM64M #(
|
||||||
|
.INIT_A(INIT),
|
||||||
|
.INIT_B(INIT),
|
||||||
|
.INIT_C(INIT),
|
||||||
|
.INIT_D(INIT),
|
||||||
|
.IS_WCLK_INVERTED(!CLKPOL2)
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.ADDRA(A1ADDR),
|
||||||
|
.ADDRB(A2ADDR),
|
||||||
|
.ADDRC(A3ADDR),
|
||||||
|
.DOA(A1DATA),
|
||||||
|
.DOB(A2DATA),
|
||||||
|
.DOC(A3DATA),
|
||||||
|
|
||||||
|
.ADDRD(B1ADDR),
|
||||||
|
.DIA(B1DATA),
|
||||||
|
.DIB(B1DATA),
|
||||||
|
.DIC(B1DATA),
|
||||||
|
.DID(B1DATA),
|
||||||
|
.WCLK(CLK1),
|
||||||
|
.WE(B1EN)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
|
@ -64,7 +64,7 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
log(" (this feature is experimental and incomplete)\n");
|
log(" (this feature is experimental and incomplete)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -ise\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("\n");
|
||||||
log(" -nobram\n");
|
log(" -nobram\n");
|
||||||
log(" do not use block RAM cells in output netlist\n");
|
log(" do not use block RAM cells in output netlist\n");
|
||||||
|
@ -84,11 +84,9 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
log(" -nodsp\n");
|
log(" -nodsp\n");
|
||||||
log(" do not use DSP48E1s to implement multipliers and associated logic\n");
|
log(" do not use DSP48E1s to implement multipliers and associated logic\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -iopad\n");
|
|
||||||
log(" enable I/O buffer insertion (selected automatically by -ise)\n");
|
|
||||||
log("\n");
|
|
||||||
log(" -noiopad\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("\n");
|
||||||
log(" -noclkbuf\n");
|
log(" -noclkbuf\n");
|
||||||
log(" disable automatic clock buffer insertion\n");
|
log(" disable automatic clock buffer insertion\n");
|
||||||
|
@ -110,7 +108,7 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
log(" flatten design before synthesis\n");
|
log(" flatten design before synthesis\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -retime\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(" -abc9\n");
|
log(" -abc9\n");
|
||||||
log(" use new ABC9 flow (EXPERIMENTAL)\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;
|
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;
|
bool flatten_before_abc;
|
||||||
int widemux;
|
int widemux;
|
||||||
|
|
||||||
|
@ -136,7 +134,6 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
retime = false;
|
retime = false;
|
||||||
vpr = false;
|
vpr = false;
|
||||||
ise = false;
|
ise = false;
|
||||||
iopad = false;
|
|
||||||
noiopad = false;
|
noiopad = false;
|
||||||
noclkbuf = false;
|
noclkbuf = false;
|
||||||
nocarry = false;
|
nocarry = false;
|
||||||
|
@ -213,7 +210,6 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-iopad") {
|
if (args[argidx] == "-iopad") {
|
||||||
iopad = true;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-noiopad") {
|
if (args[argidx] == "-noiopad") {
|
||||||
|
@ -282,7 +278,6 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
|
|
||||||
void script() YS_OVERRIDE
|
void script() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
bool do_iopad = iopad || (ise && !noiopad);
|
|
||||||
std::string ff_map_file;
|
std::string ff_map_file;
|
||||||
if (help_mode)
|
if (help_mode)
|
||||||
ff_map_file = "+/xilinx/{family}_ff_map.v";
|
ff_map_file = "+/xilinx/{family}_ff_map.v";
|
||||||
|
@ -387,7 +382,10 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
run("opt_expr -fine");
|
run("opt_expr -fine");
|
||||||
run("wreduce");
|
run("wreduce");
|
||||||
run("select -clear");
|
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");
|
run("chtype -set $mul t:$__soft_mul");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,6 +442,16 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_ffram")) {
|
if (check_label("map_ffram")) {
|
||||||
|
// Required for dffsr2dff to work.
|
||||||
|
run("simplemap t:$dff t:$adff t:$mux");
|
||||||
|
// Needs to be done before opt -mux_bool happens.
|
||||||
|
run("dffsr2dff");
|
||||||
|
if (help_mode)
|
||||||
|
run("dff2dffs [-match-init]", "(-match-init for xc6s only)");
|
||||||
|
else if (family == "xc6s")
|
||||||
|
run("dff2dffs -match-init");
|
||||||
|
else
|
||||||
|
run("dff2dffs");
|
||||||
if (widemux > 0)
|
if (widemux > 0)
|
||||||
run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
|
run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
|
||||||
// performs less efficiently
|
// performs less efficiently
|
||||||
|
@ -453,14 +461,11 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("fine")) {
|
if (check_label("fine")) {
|
||||||
run("dffsr2dff");
|
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
|
||||||
run("dff2dffe");
|
|
||||||
if (help_mode) {
|
if (help_mode) {
|
||||||
run("simplemap t:$mux", " ('-widemux' only)");
|
|
||||||
run("muxcover <internal options>, ('-widemux' only)");
|
run("muxcover <internal options>, ('-widemux' only)");
|
||||||
}
|
}
|
||||||
else if (widemux > 0) {
|
else if (widemux > 0) {
|
||||||
run("simplemap t:$mux");
|
|
||||||
constexpr int cost_mux2 = 100;
|
constexpr int cost_mux2 = 100;
|
||||||
std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
|
std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
|
||||||
switch (widemux) {
|
switch (widemux) {
|
||||||
|
@ -507,8 +512,8 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
|
|
||||||
if (check_label("map_cells")) {
|
if (check_label("map_cells")) {
|
||||||
// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
|
// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
|
||||||
if (help_mode || do_iopad)
|
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 '-iopad' or '-ise' and not '-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";
|
std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v";
|
||||||
if (widemux > 0)
|
if (widemux > 0)
|
||||||
techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
|
techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
|
||||||
|
@ -545,9 +550,9 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (nowidelut)
|
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
|
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");
|
run("clean");
|
||||||
|
|
||||||
|
@ -563,6 +568,7 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
else
|
else
|
||||||
techmap_args += " -map " + ff_map_file;
|
techmap_args += " -map " + ff_map_file;
|
||||||
run("techmap " + techmap_args);
|
run("techmap " + techmap_args);
|
||||||
|
run("xilinx_dffopt");
|
||||||
run("clean");
|
run("clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
techlibs/xilinx/tests/.gitignore
vendored
4
techlibs/xilinx/tests/.gitignore
vendored
|
@ -8,4 +8,8 @@ dsp_work*/
|
||||||
test_dsp_model_ref.v
|
test_dsp_model_ref.v
|
||||||
test_dsp_model_uut.v
|
test_dsp_model_uut.v
|
||||||
test_dsp_model
|
test_dsp_model
|
||||||
|
test_dsp48a_model_ref.v
|
||||||
|
test_dsp48a1_model_ref.v
|
||||||
|
test_dsp48a1_model_uut.v
|
||||||
|
test_dsp48a1_model
|
||||||
*.vcd
|
*.vcd
|
||||||
|
|
17
techlibs/xilinx/tests/test_dsp48a1_model.sh
Normal file
17
techlibs/xilinx/tests/test_dsp48a1_model.sh
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
if [ -z $ISE_DIR ]; then
|
||||||
|
ISE_DIR=/opt/Xilinx/ISE/14.7
|
||||||
|
fi
|
||||||
|
sed 's/DSP48A1/MARKER1/; s/DSP48A/DSP48A_UUT/; s/MARKER1/DSP48A1_UUT/; /module DSP48A_UUT/,/endmodule/ p; /module DSP48A1_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp48a1_model_uut.v
|
||||||
|
if [ ! -f "test_dsp48a1_model_ref.v" ]; then
|
||||||
|
cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48A1.v test_dsp48a1_model_ref.v
|
||||||
|
fi
|
||||||
|
if [ ! -f "test_dsp48a_model_ref.v" ]; then
|
||||||
|
cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48A.v test_dsp48a_model_ref.v
|
||||||
|
fi
|
||||||
|
for tb in mult_allreg mult_noreg mult_inreg
|
||||||
|
do
|
||||||
|
iverilog -s $tb -s glbl -o test_dsp48a1_model test_dsp48a1_model.v test_dsp48a1_model_uut.v test_dsp48a1_model_ref.v test_dsp48a_model_ref.v $ISE_DIR/ISE_DS/ISE/verilog/src/glbl.v
|
||||||
|
vvp -N ./test_dsp48a1_model
|
||||||
|
done
|
331
techlibs/xilinx/tests/test_dsp48a1_model.v
Normal file
331
techlibs/xilinx/tests/test_dsp48a1_model.v
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module testbench;
|
||||||
|
parameter integer A0REG = 1;
|
||||||
|
parameter integer A1REG = 1;
|
||||||
|
parameter integer B0REG = 1;
|
||||||
|
parameter integer B1REG = 1;
|
||||||
|
parameter integer CREG = 1;
|
||||||
|
parameter integer DREG = 1;
|
||||||
|
parameter integer MREG = 1;
|
||||||
|
parameter integer PREG = 1;
|
||||||
|
parameter integer CARRYINREG = 1;
|
||||||
|
parameter integer CARRYOUTREG = 1;
|
||||||
|
parameter integer OPMODEREG = 1;
|
||||||
|
parameter CARRYINSEL = "OPMODE5";
|
||||||
|
parameter RSTTYPE = "SYNC";
|
||||||
|
|
||||||
|
reg CLK;
|
||||||
|
reg CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE;
|
||||||
|
reg RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE;
|
||||||
|
reg [17:0] A;
|
||||||
|
reg [17:0] B;
|
||||||
|
reg [47:0] C;
|
||||||
|
reg [17:0] D;
|
||||||
|
reg [47:0] PCIN;
|
||||||
|
reg [7:0] OPMODE;
|
||||||
|
reg CARRYIN;
|
||||||
|
|
||||||
|
output CARRYOUTF, REF_CARRYOUTF;
|
||||||
|
output CARRYOUT, REF_CARRYOUT, REF_OLD_CARRYOUT;
|
||||||
|
output [35:0] M, REF_M;
|
||||||
|
output [47:0] P, REF_P, REF_OLD_P;
|
||||||
|
output [17:0] BCOUT, REF_BCOUT, REF_OLD_BCOUT;
|
||||||
|
output [47:0] PCOUT, REF_PCOUT, REF_OLD_PCOUT;
|
||||||
|
|
||||||
|
integer errcount = 0;
|
||||||
|
|
||||||
|
reg ERROR_FLAG = 0;
|
||||||
|
|
||||||
|
task clkcycle;
|
||||||
|
begin
|
||||||
|
#5;
|
||||||
|
CLK = ~CLK;
|
||||||
|
#10;
|
||||||
|
CLK = ~CLK;
|
||||||
|
#2;
|
||||||
|
ERROR_FLAG = 0;
|
||||||
|
if (REF_BCOUT !== BCOUT || REF_OLD_BCOUT != BCOUT) begin
|
||||||
|
$display("ERROR at %1t: REF_BCOUT=%b REF_OLD_BCOUT=%b UUT_BCOUT=%b DIFF=%b", $time, REF_BCOUT, REF_OLD_BCOUT, BCOUT, REF_BCOUT ^ BCOUT);
|
||||||
|
errcount = errcount + 1;
|
||||||
|
ERROR_FLAG = 1;
|
||||||
|
end
|
||||||
|
if (REF_M !== M) begin
|
||||||
|
$display("ERROR at %1t: REF_M=%b UUT_M=%b DIFF=%b", $time, REF_M, M, REF_M ^ M);
|
||||||
|
errcount = errcount + 1;
|
||||||
|
ERROR_FLAG = 1;
|
||||||
|
end
|
||||||
|
if (REF_P !== P || REF_OLD_P != P) begin
|
||||||
|
$display("ERROR at %1t: REF_P=%b REF_OLD_P=%b UUT_P=%b DIFF=%b", $time, REF_P, REF_OLD_P, P, REF_P ^ P);
|
||||||
|
errcount = errcount + 1;
|
||||||
|
ERROR_FLAG = 1;
|
||||||
|
end
|
||||||
|
if (REF_PCOUT !== PCOUT || REF_OLD_PCOUT != PCOUT) begin
|
||||||
|
$display("ERROR at %1t: REF_PCOUT=%b REF_OLD_PCOUT=%b UUT_PCOUT=%b DIFF=%b", $time, REF_PCOUT, REF_OLD_PCOUT, PCOUT, REF_PCOUT ^ PCOUT);
|
||||||
|
errcount = errcount + 1;
|
||||||
|
ERROR_FLAG = 1;
|
||||||
|
end
|
||||||
|
if (REF_CARRYOUT !== CARRYOUT || (REF_OLD_CARRYOUT != CARRYOUT && !CARRYOUTREG)) begin
|
||||||
|
$display("ERROR at %1t: REF_CARRYOUT=%b REF_OLD_CARRYOUT=%b UUT_CARRYOUT=%b DIFF=%b", $time, REF_CARRYOUT, REF_OLD_CARRYOUT, CARRYOUT, REF_CARRYOUT ^ CARRYOUT);
|
||||||
|
errcount = errcount + 1;
|
||||||
|
ERROR_FLAG = 1;
|
||||||
|
end
|
||||||
|
if (REF_CARRYOUTF !== CARRYOUTF) begin
|
||||||
|
$display("ERROR at %1t: REF_CARRYOUTF=%b UUT_CARRYOUTF=%b", $time, REF_CARRYOUTF, CARRYOUTF);
|
||||||
|
errcount = errcount + 1;
|
||||||
|
ERROR_FLAG = 1;
|
||||||
|
end
|
||||||
|
#3;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
reg config_valid = 0;
|
||||||
|
task drc;
|
||||||
|
begin
|
||||||
|
config_valid = 1;
|
||||||
|
|
||||||
|
if (OPMODE[1:0] == 2'b10 && PREG != 1) config_valid = 0;
|
||||||
|
if (OPMODE[3:2] == 2'b10 && PREG != 1) config_valid = 0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("test_dsp48a1_model.vcd");
|
||||||
|
$dumpvars(0, testbench);
|
||||||
|
|
||||||
|
#2;
|
||||||
|
CLK = 1'b0;
|
||||||
|
{CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE} = 8'b11111111;
|
||||||
|
{A, B, C, D, PCIN, OPMODE, CARRYIN} = 0;
|
||||||
|
{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = 8'b11111111;
|
||||||
|
repeat (10) begin
|
||||||
|
#10;
|
||||||
|
CLK = 1'b1;
|
||||||
|
#10;
|
||||||
|
CLK = 1'b0;
|
||||||
|
#10;
|
||||||
|
CLK = 1'b1;
|
||||||
|
#10;
|
||||||
|
CLK = 1'b0;
|
||||||
|
end
|
||||||
|
{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = 0;
|
||||||
|
|
||||||
|
repeat (10000) begin
|
||||||
|
clkcycle;
|
||||||
|
config_valid = 0;
|
||||||
|
while (!config_valid) begin
|
||||||
|
A = $urandom;
|
||||||
|
B = $urandom;
|
||||||
|
C = {$urandom, $urandom};
|
||||||
|
D = $urandom;
|
||||||
|
PCIN = {$urandom, $urandom};
|
||||||
|
|
||||||
|
{CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE} = $urandom | $urandom | $urandom;
|
||||||
|
{RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom;
|
||||||
|
{CARRYIN, OPMODE} = $urandom;
|
||||||
|
|
||||||
|
drc;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (errcount == 0) begin
|
||||||
|
$display("All tests passed.");
|
||||||
|
$finish;
|
||||||
|
end else begin
|
||||||
|
$display("Caught %1d errors.", errcount);
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DSP48A #(
|
||||||
|
.A0REG (A0REG),
|
||||||
|
.A1REG (A1REG),
|
||||||
|
.B0REG (B0REG),
|
||||||
|
.B1REG (B1REG),
|
||||||
|
.CREG (CREG),
|
||||||
|
.DREG (DREG),
|
||||||
|
.MREG (MREG),
|
||||||
|
.PREG (PREG),
|
||||||
|
.CARRYINREG (CARRYINREG),
|
||||||
|
.OPMODEREG (OPMODEREG),
|
||||||
|
.CARRYINSEL (CARRYINSEL),
|
||||||
|
.RSTTYPE (RSTTYPE)
|
||||||
|
) ref_old (
|
||||||
|
.A (A),
|
||||||
|
.B (B),
|
||||||
|
.C (C),
|
||||||
|
.D (D),
|
||||||
|
.PCIN (PCIN),
|
||||||
|
.CARRYIN (CARRYIN),
|
||||||
|
.OPMODE (OPMODE),
|
||||||
|
.BCOUT (REF_OLD_BCOUT),
|
||||||
|
.CARRYOUT (REF_OLD_CARRYOUT),
|
||||||
|
.P (REF_OLD_P),
|
||||||
|
.PCOUT (REF_OLD_PCOUT),
|
||||||
|
.CEA (CEA),
|
||||||
|
.CEB (CEB),
|
||||||
|
.CEC (CEC),
|
||||||
|
.CED (CED),
|
||||||
|
.CEM (CEM),
|
||||||
|
.CEP (CEP),
|
||||||
|
.CECARRYIN (CECARRYIN),
|
||||||
|
.CEOPMODE (CEOPMODE),
|
||||||
|
.CLK (CLK),
|
||||||
|
.RSTA (RSTA),
|
||||||
|
.RSTB (RSTB),
|
||||||
|
.RSTC (RSTC),
|
||||||
|
.RSTD (RSTD),
|
||||||
|
.RSTM (RSTM),
|
||||||
|
.RSTP (RSTP),
|
||||||
|
.RSTCARRYIN (RSTCARRYIN),
|
||||||
|
.RSTOPMODE (RSTOPMODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
DSP48A1 #(
|
||||||
|
.A0REG (A0REG),
|
||||||
|
.A1REG (A1REG),
|
||||||
|
.B0REG (B0REG),
|
||||||
|
.B1REG (B1REG),
|
||||||
|
.CREG (CREG),
|
||||||
|
.DREG (DREG),
|
||||||
|
.MREG (MREG),
|
||||||
|
.PREG (PREG),
|
||||||
|
.CARRYINREG (CARRYINREG),
|
||||||
|
.CARRYOUTREG (CARRYOUTREG),
|
||||||
|
.OPMODEREG (OPMODEREG),
|
||||||
|
.CARRYINSEL (CARRYINSEL),
|
||||||
|
.RSTTYPE (RSTTYPE)
|
||||||
|
) ref (
|
||||||
|
.A (A),
|
||||||
|
.B (B),
|
||||||
|
.C (C),
|
||||||
|
.D (D),
|
||||||
|
.PCIN (PCIN),
|
||||||
|
.CARRYIN (CARRYIN),
|
||||||
|
.OPMODE (OPMODE),
|
||||||
|
.BCOUT (REF_BCOUT),
|
||||||
|
.CARRYOUTF (REF_CARRYOUTF),
|
||||||
|
.CARRYOUT (REF_CARRYOUT),
|
||||||
|
.P (REF_P),
|
||||||
|
.M (REF_M),
|
||||||
|
.PCOUT (REF_PCOUT),
|
||||||
|
.CEA (CEA),
|
||||||
|
.CEB (CEB),
|
||||||
|
.CEC (CEC),
|
||||||
|
.CED (CED),
|
||||||
|
.CEM (CEM),
|
||||||
|
.CEP (CEP),
|
||||||
|
.CECARRYIN (CECARRYIN),
|
||||||
|
.CEOPMODE (CEOPMODE),
|
||||||
|
.CLK (CLK),
|
||||||
|
.RSTA (RSTA),
|
||||||
|
.RSTB (RSTB),
|
||||||
|
.RSTC (RSTC),
|
||||||
|
.RSTD (RSTD),
|
||||||
|
.RSTM (RSTM),
|
||||||
|
.RSTP (RSTP),
|
||||||
|
.RSTCARRYIN (RSTCARRYIN),
|
||||||
|
.RSTOPMODE (RSTOPMODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
DSP48A1_UUT #(
|
||||||
|
.A0REG (A0REG),
|
||||||
|
.A1REG (A1REG),
|
||||||
|
.B0REG (B0REG),
|
||||||
|
.B1REG (B1REG),
|
||||||
|
.CREG (CREG),
|
||||||
|
.DREG (DREG),
|
||||||
|
.MREG (MREG),
|
||||||
|
.PREG (PREG),
|
||||||
|
.CARRYINREG (CARRYINREG),
|
||||||
|
.CARRYOUTREG (CARRYOUTREG),
|
||||||
|
.OPMODEREG (OPMODEREG),
|
||||||
|
.CARRYINSEL (CARRYINSEL),
|
||||||
|
.RSTTYPE (RSTTYPE)
|
||||||
|
) uut (
|
||||||
|
.A (A),
|
||||||
|
.B (B),
|
||||||
|
.C (C),
|
||||||
|
.D (D),
|
||||||
|
.PCIN (PCIN),
|
||||||
|
.CARRYIN (CARRYIN),
|
||||||
|
.OPMODE (OPMODE),
|
||||||
|
.BCOUT (BCOUT),
|
||||||
|
.CARRYOUTF (CARRYOUTF),
|
||||||
|
.CARRYOUT (CARRYOUT),
|
||||||
|
.P (P),
|
||||||
|
.M (M),
|
||||||
|
.PCOUT (PCOUT),
|
||||||
|
.CEA (CEA),
|
||||||
|
.CEB (CEB),
|
||||||
|
.CEC (CEC),
|
||||||
|
.CED (CED),
|
||||||
|
.CEM (CEM),
|
||||||
|
.CEP (CEP),
|
||||||
|
.CECARRYIN (CECARRYIN),
|
||||||
|
.CEOPMODE (CEOPMODE),
|
||||||
|
.CLK (CLK),
|
||||||
|
.RSTA (RSTA),
|
||||||
|
.RSTB (RSTB),
|
||||||
|
.RSTC (RSTC),
|
||||||
|
.RSTD (RSTD),
|
||||||
|
.RSTM (RSTM),
|
||||||
|
.RSTP (RSTP),
|
||||||
|
.RSTCARRYIN (RSTCARRYIN),
|
||||||
|
.RSTOPMODE (RSTOPMODE)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mult_noreg;
|
||||||
|
testbench #(
|
||||||
|
.A0REG (0),
|
||||||
|
.A1REG (0),
|
||||||
|
.B0REG (0),
|
||||||
|
.B1REG (0),
|
||||||
|
.CREG (0),
|
||||||
|
.DREG (0),
|
||||||
|
.MREG (0),
|
||||||
|
.PREG (0),
|
||||||
|
.CARRYINREG (0),
|
||||||
|
.CARRYOUTREG (0),
|
||||||
|
.OPMODEREG (0),
|
||||||
|
.CARRYINSEL ("CARRYIN"),
|
||||||
|
.RSTTYPE ("SYNC")
|
||||||
|
) testbench ();
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mult_allreg;
|
||||||
|
testbench #(
|
||||||
|
.A0REG (1),
|
||||||
|
.A1REG (1),
|
||||||
|
.B0REG (1),
|
||||||
|
.B1REG (1),
|
||||||
|
.CREG (1),
|
||||||
|
.DREG (1),
|
||||||
|
.MREG (1),
|
||||||
|
.PREG (1),
|
||||||
|
.CARRYINREG (1),
|
||||||
|
.CARRYOUTREG (1),
|
||||||
|
.OPMODEREG (1),
|
||||||
|
.CARRYINSEL ("OPMODE5"),
|
||||||
|
.RSTTYPE ("SYNC")
|
||||||
|
) testbench ();
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mult_inreg;
|
||||||
|
testbench #(
|
||||||
|
.A0REG (1),
|
||||||
|
.A1REG (1),
|
||||||
|
.B0REG (1),
|
||||||
|
.B1REG (1),
|
||||||
|
.CREG (1),
|
||||||
|
.DREG (1),
|
||||||
|
.MREG (0),
|
||||||
|
.PREG (0),
|
||||||
|
.CARRYINREG (1),
|
||||||
|
.CARRYOUTREG (0),
|
||||||
|
.OPMODEREG (0),
|
||||||
|
.CARRYINSEL ("CARRYIN"),
|
||||||
|
.RSTTYPE ("SYNC")
|
||||||
|
) testbench ();
|
||||||
|
endmodule
|
|
@ -1,14 +1,17 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -ex
|
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
|
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
|
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
|
fi
|
||||||
for tb in macc_overflow_underflow \
|
for tb in macc_overflow_underflow \
|
||||||
simd24_preadd_noreg_nocasc simd12_preadd_noreg_nocasc \
|
simd24_preadd_noreg_nocasc simd12_preadd_noreg_nocasc \
|
||||||
mult_allreg_nopreadd_nocasc mult_noreg_nopreadd_nocasc \
|
mult_allreg_nopreadd_nocasc mult_noreg_nopreadd_nocasc \
|
||||||
mult_allreg_preadd_nocasc mult_noreg_preadd_nocasc mult_inreg_preadd_nocasc
|
mult_allreg_preadd_nocasc mult_noreg_preadd_nocasc mult_inreg_preadd_nocasc
|
||||||
do
|
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
|
vvp -N ./test_dsp_model
|
||||||
done
|
done
|
||||||
|
|
|
@ -27,7 +27,7 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
|
||||||
.D(18'b0),
|
.D(18'b0),
|
||||||
.P(P_48),
|
.P(P_48),
|
||||||
|
|
||||||
.OPMODE(8'b0000010)
|
.OPMODE(8'b0000001)
|
||||||
);
|
);
|
||||||
assign Y = P_48;
|
assign Y = P_48;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -27,7 +27,7 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
|
||||||
.D(18'b0),
|
.D(18'b0),
|
||||||
.P(P_48),
|
.P(P_48),
|
||||||
|
|
||||||
.OPMODE(8'b0000010)
|
.OPMODE(8'b0000001)
|
||||||
);
|
);
|
||||||
assign Y = P_48;
|
assign Y = P_48;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
`ifndef _NO_FFS
|
`ifndef _NO_FFS
|
||||||
|
|
||||||
|
// No reset.
|
||||||
|
|
||||||
module \$_DFF_N_ (input D, C, output Q);
|
module \$_DFF_N_ (input D, C, output Q);
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
@ -46,6 +48,8 @@ module \$_DFF_P_ (input D, C, output Q);
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// No reset, enable.
|
||||||
|
|
||||||
module \$_DFFE_NP_ (input D, C, E, output Q);
|
module \$_DFFE_NP_ (input D, C, E, output Q);
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
@ -65,15 +69,8 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module \$_DFF_NN0_ (input D, C, R, output Q);
|
// Async reset.
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
|
||||||
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
|
|
||||||
else
|
|
||||||
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
|
|
||||||
endgenerate
|
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
|
||||||
endmodule
|
|
||||||
module \$_DFF_NP0_ (input D, C, R, output Q);
|
module \$_DFF_NP0_ (input D, C, R, output Q);
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
@ -83,15 +80,6 @@ module \$_DFF_NP0_ (input D, C, R, output Q);
|
||||||
endgenerate
|
endgenerate
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
module \$_DFF_PN0_ (input D, C, R, output Q);
|
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
|
||||||
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
|
|
||||||
else
|
|
||||||
FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
|
|
||||||
endgenerate
|
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
|
||||||
endmodule
|
|
||||||
module \$_DFF_PP0_ (input D, C, R, output Q);
|
module \$_DFF_PP0_ (input D, C, R, output Q);
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
@ -102,15 +90,6 @@ module \$_DFF_PP0_ (input D, C, R, output Q);
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module \$_DFF_NN1_ (input D, C, R, output Q);
|
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
|
||||||
$error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
|
|
||||||
else
|
|
||||||
FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
|
|
||||||
endgenerate
|
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
|
||||||
endmodule
|
|
||||||
module \$_DFF_NP1_ (input D, C, R, output Q);
|
module \$_DFF_NP1_ (input D, C, R, output Q);
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
||||||
|
@ -120,15 +99,6 @@ module \$_DFF_NP1_ (input D, C, R, output Q);
|
||||||
endgenerate
|
endgenerate
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
module \$_DFF_PN1_ (input D, C, R, output Q);
|
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
|
||||||
$error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
|
|
||||||
else
|
|
||||||
FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
|
|
||||||
endgenerate
|
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
|
||||||
endmodule
|
|
||||||
module \$_DFF_PP1_ (input D, C, R, output Q);
|
module \$_DFF_PP1_ (input D, C, R, output Q);
|
||||||
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
||||||
|
@ -139,6 +109,128 @@ module \$_DFF_PP1_ (input D, C, R, output Q);
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// Async reset, enable.
|
||||||
|
|
||||||
|
module \$__DFFE_NP0 (input D, C, E, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
|
||||||
|
else
|
||||||
|
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFE_PP0 (input D, C, E, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
$error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1");
|
||||||
|
else
|
||||||
|
FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__DFFE_NP1 (input D, C, E, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
||||||
|
$error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
|
||||||
|
else
|
||||||
|
FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFE_PP1 (input D, C, E, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
||||||
|
$error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0");
|
||||||
|
else
|
||||||
|
FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// Sync reset.
|
||||||
|
|
||||||
|
module \$__DFFS_NP0_ (input D, C, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
$error("Spartan 6 doesn't support FFs with reset initialized to 1");
|
||||||
|
else
|
||||||
|
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFS_PP0_ (input D, C, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
$error("Spartan 6 doesn't support FFs with reset initialized to 1");
|
||||||
|
else
|
||||||
|
FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__DFFS_NP1_ (input D, C, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
||||||
|
$error("Spartan 6 doesn't support FFs with set initialized to 0");
|
||||||
|
else
|
||||||
|
FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFS_PP1_ (input D, C, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
||||||
|
$error("Spartan 6 doesn't support FFs with set initialized to 0");
|
||||||
|
else
|
||||||
|
FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// Sync reset, enable.
|
||||||
|
|
||||||
|
module \$__DFFSE_NP0 (input D, C, E, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
$error("Spartan 6 doesn't support FFs with reset initialized to 1");
|
||||||
|
else
|
||||||
|
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFSE_PP0 (input D, C, E, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
$error("Spartan 6 doesn't support FFs with reset initialized to 1");
|
||||||
|
else
|
||||||
|
FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__DFFSE_NP1 (input D, C, E, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
||||||
|
$error("Spartan 6 doesn't support FFs with set initialized to 0");
|
||||||
|
else
|
||||||
|
FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFSE_PP1 (input D, C, E, R, output Q);
|
||||||
|
parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b0)
|
||||||
|
$error("Spartan 6 doesn't support FFs with set initialized to 0");
|
||||||
|
else
|
||||||
|
FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
|
||||||
|
endgenerate
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// Latches (no reset).
|
||||||
|
|
||||||
module \$_DLATCH_N_ (input E, D, output Q);
|
module \$_DLATCH_N_ (input E, D, output Q);
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
generate if (_TECHMAP_WIREINIT_Q_ === 1'b1)
|
||||||
|
@ -158,5 +250,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// Latches with reset (TODO).
|
||||||
|
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
`ifndef _NO_FFS
|
`ifndef _NO_FFS
|
||||||
|
|
||||||
|
// No reset.
|
||||||
|
|
||||||
module \$_DFF_N_ (input D, C, output Q);
|
module \$_DFF_N_ (input D, C, output Q);
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0));
|
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0));
|
||||||
|
@ -48,6 +50,8 @@ module \$_DFF_P_ (input D, C, output Q);
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// No reset, enable.
|
||||||
|
|
||||||
module \$_DFFE_NP_ (input D, C, E, output Q);
|
module \$_DFFE_NP_ (input D, C, E, output Q);
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0));
|
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0));
|
||||||
|
@ -59,48 +63,104 @@ module \$_DFFE_PP_ (input D, C, E, output Q);
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module \$_DFF_NN0_ (input D, C, R, output Q);
|
// Async reset.
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
|
||||||
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
|
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
|
||||||
endmodule
|
|
||||||
module \$_DFF_NP0_ (input D, C, R, output Q);
|
module \$_DFF_NP0_ (input D, C, R, output Q);
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
|
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
module \$_DFF_PN0_ (input D, C, R, output Q);
|
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
|
||||||
FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R));
|
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
|
||||||
endmodule
|
|
||||||
module \$_DFF_PP0_ (input D, C, R, output Q);
|
module \$_DFF_PP0_ (input D, C, R, output Q);
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
|
FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R));
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module \$_DFF_NN1_ (input D, C, R, output Q);
|
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
|
||||||
FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
|
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
|
||||||
endmodule
|
|
||||||
module \$_DFF_NP1_ (input D, C, R, output Q);
|
module \$_DFF_NP1_ (input D, C, R, output Q);
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
|
FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
module \$_DFF_PN1_ (input D, C, R, output Q);
|
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
|
||||||
FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R));
|
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
|
||||||
endmodule
|
|
||||||
module \$_DFF_PP1_ (input D, C, R, output Q);
|
module \$_DFF_PP1_ (input D, C, R, output Q);
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
|
FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R));
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// Async reset, enable.
|
||||||
|
|
||||||
|
module \$__DFFE_NP0 (input D, C, E, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFE_PP0 (input D, C, E, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__DFFE_NP1 (input D, C, E, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFE_PP1 (input D, C, E, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// Sync reset.
|
||||||
|
|
||||||
|
module \$__DFFS_NP0_ (input D, C, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFS_PP0_ (input D, C, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__DFFS_NP1_ (input D, C, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFS_PP1_ (input D, C, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// Sync reset, enable.
|
||||||
|
|
||||||
|
module \$__DFFSE_NP0 (input D, C, E, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFSE_PP0 (input D, C, E, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$__DFFSE_NP1 (input D, C, E, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
module \$__DFFSE_PP1 (input D, C, E, R, output Q);
|
||||||
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
|
FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R));
|
||||||
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// Latches (no reset).
|
||||||
|
|
||||||
module \$_DLATCH_N_ (input E, D, output Q);
|
module \$_DLATCH_N_ (input E, D, output Q);
|
||||||
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
parameter _TECHMAP_WIREINIT_Q_ = 1'bx;
|
||||||
LDCE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(1'b0));
|
LDCE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(1'b0));
|
||||||
|
@ -112,5 +172,7 @@ module \$_DLATCH_P_ (input E, D, output Q);
|
||||||
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
wire _TECHMAP_REMOVEINIT_Q_ = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// Latches with reset (TODO).
|
||||||
|
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
bram $__XILINX_RAMB36_SDP
|
bram $__XILINX_RAMB36_SDP
|
||||||
init 1
|
init 1
|
||||||
abits 9
|
abits 9
|
||||||
|
@ -72,8 +71,33 @@ bram $__XILINX_RAMB18_TDP
|
||||||
clkpol 2 3
|
clkpol 2 3
|
||||||
endbram
|
endbram
|
||||||
|
|
||||||
|
# The "min bits" value were taken from:
|
||||||
|
# [[CITE]] 7 Series FPGAs Memory Resources User Guide (UG473),
|
||||||
|
# v1.14 ed., p 29-30, July, 2019.
|
||||||
|
# https://www.xilinx.com/support/documentation/user_guides/ug473_7Series_Memory_Resources.pdf
|
||||||
|
|
||||||
match $__XILINX_RAMB36_SDP
|
match $__XILINX_RAMB36_SDP
|
||||||
min bits 4096
|
attribute !ram_style
|
||||||
|
attribute !logic_block
|
||||||
|
min bits 1024
|
||||||
|
min efficiency 5
|
||||||
|
shuffle_enable B
|
||||||
|
make_transp
|
||||||
|
or_next_if_better
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match $__XILINX_RAMB36_SDP
|
||||||
|
attribute ram_style=block ram_block
|
||||||
|
attribute !logic_block
|
||||||
|
shuffle_enable B
|
||||||
|
make_transp
|
||||||
|
or_next_if_better
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match $__XILINX_RAMB18_SDP
|
||||||
|
attribute !ram_style
|
||||||
|
attribute !logic_block
|
||||||
|
min bits 1024
|
||||||
min efficiency 5
|
min efficiency 5
|
||||||
shuffle_enable B
|
shuffle_enable B
|
||||||
make_transp
|
make_transp
|
||||||
|
@ -81,7 +105,17 @@ match $__XILINX_RAMB36_SDP
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
match $__XILINX_RAMB18_SDP
|
match $__XILINX_RAMB18_SDP
|
||||||
min bits 4096
|
attribute ram_style=block ram_block
|
||||||
|
attribute !logic_block
|
||||||
|
shuffle_enable B
|
||||||
|
make_transp
|
||||||
|
or_next_if_better
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match $__XILINX_RAMB36_TDP
|
||||||
|
attribute !ram_style
|
||||||
|
attribute !logic_block
|
||||||
|
min bits 1024
|
||||||
min efficiency 5
|
min efficiency 5
|
||||||
shuffle_enable B
|
shuffle_enable B
|
||||||
make_transp
|
make_transp
|
||||||
|
@ -89,7 +123,17 @@ match $__XILINX_RAMB18_SDP
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
match $__XILINX_RAMB36_TDP
|
match $__XILINX_RAMB36_TDP
|
||||||
min bits 4096
|
attribute ram_style=block ram_block
|
||||||
|
attribute !logic_block
|
||||||
|
shuffle_enable B
|
||||||
|
make_transp
|
||||||
|
or_next_if_better
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match $__XILINX_RAMB18_TDP
|
||||||
|
attribute !ram_style
|
||||||
|
attribute !logic_block
|
||||||
|
min bits 1024
|
||||||
min efficiency 5
|
min efficiency 5
|
||||||
shuffle_enable B
|
shuffle_enable B
|
||||||
make_transp
|
make_transp
|
||||||
|
@ -97,8 +141,8 @@ match $__XILINX_RAMB36_TDP
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
match $__XILINX_RAMB18_TDP
|
match $__XILINX_RAMB18_TDP
|
||||||
min bits 4096
|
attribute ram_style=block ram_block
|
||||||
min efficiency 5
|
attribute !logic_block
|
||||||
shuffle_enable B
|
shuffle_enable B
|
||||||
make_transp
|
make_transp
|
||||||
endmatch
|
endmatch
|
||||||
|
|
365
techlibs/xilinx/xilinx_dffopt.cc
Normal file
365
techlibs/xilinx/xilinx_dffopt.cc
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
typedef std::pair<Const, std::vector<SigBit>> LutData;
|
||||||
|
|
||||||
|
// Compute a LUT implementing (select ^ select_inv) ? alt_data : data. Returns true if successful.
|
||||||
|
bool merge_lut(LutData &result, const LutData &data, const LutData select, bool select_inv, SigBit alt_data, int max_lut_size) {
|
||||||
|
// First, gather input signals -- insert new signals at the beginning
|
||||||
|
// of the vector, so they don't disturb the likely-critical D LUT input
|
||||||
|
// timings.
|
||||||
|
result.second = data.second;
|
||||||
|
// D lut inputs initially start at 0.
|
||||||
|
int idx_data = 0;
|
||||||
|
// Now add the control input LUT inputs.
|
||||||
|
std::vector<int> idx_sel;
|
||||||
|
for (auto bit : select.second) {
|
||||||
|
int idx = -1;
|
||||||
|
for (int i = 0; i < GetSize(result.second); i++)
|
||||||
|
if (result.second[i] == bit)
|
||||||
|
idx = i;
|
||||||
|
if (idx == -1) {
|
||||||
|
idx = 0;
|
||||||
|
// Insert new signal at the beginning and bump all indices.
|
||||||
|
result.second.insert(result.second.begin(), bit);
|
||||||
|
idx_data++;
|
||||||
|
for (int &sidx : idx_sel)
|
||||||
|
sidx++;
|
||||||
|
}
|
||||||
|
idx_sel.push_back(idx);
|
||||||
|
}
|
||||||
|
// Insert the Q signal, if any, to the slowest input -- it will have
|
||||||
|
// no problem meeting timing.
|
||||||
|
int idx_alt = -1;
|
||||||
|
if (alt_data.wire) {
|
||||||
|
// Check if we already have it.
|
||||||
|
for (int i = 0; i < GetSize(result.second); i++)
|
||||||
|
if (result.second[i] == alt_data)
|
||||||
|
idx_alt = i;
|
||||||
|
// If not, add it.
|
||||||
|
if (idx_alt == -1) {
|
||||||
|
idx_alt = 0;
|
||||||
|
result.second.insert(result.second.begin(), alt_data);
|
||||||
|
idx_data++;
|
||||||
|
for (int &sidx : idx_sel)
|
||||||
|
sidx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If LUT would be too large, bail.
|
||||||
|
if (GetSize(result.second) > max_lut_size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Okay, we're doing it — compute the LUT mask.
|
||||||
|
result.first = Const(0, 1 << GetSize(result.second));
|
||||||
|
for (int i = 0; i < GetSize(result.first); i++) {
|
||||||
|
int sel_lut_idx = 0;
|
||||||
|
for (int j = 0; j < GetSize(select.second); j++)
|
||||||
|
if (i & 1 << idx_sel[j])
|
||||||
|
sel_lut_idx |= 1 << j;
|
||||||
|
bool select_val = (select.first.bits[sel_lut_idx] == State::S1);
|
||||||
|
bool new_bit;
|
||||||
|
if (select_val ^ select_inv) {
|
||||||
|
// Use alt_data.
|
||||||
|
if (alt_data.wire)
|
||||||
|
new_bit = (i & 1 << idx_alt) != 0;
|
||||||
|
else
|
||||||
|
new_bit = alt_data.data == State::S1;
|
||||||
|
} else {
|
||||||
|
// Use original LUT.
|
||||||
|
int lut_idx = i >> idx_data & ((1 << GetSize(data.second)) - 1);
|
||||||
|
new_bit = data.first.bits[lut_idx] == State::S1;
|
||||||
|
}
|
||||||
|
result.first.bits[i] = new_bit ? State::S1 : State::S0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct XilinxDffOptPass : public Pass {
|
||||||
|
XilinxDffOptPass() : Pass("xilinx_dffopt", "Xilinx: optimize FF control signal usage") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" xilinx_dffopt [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Converts hardware clock enable and set/reset signals on FFs to emulation\n");
|
||||||
|
log("using LUTs, if doing so would improve area. Operates on post-techmap Xilinx\n");
|
||||||
|
log("cells (LUT*, FD*).\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -lut4\n");
|
||||||
|
log(" Assume a LUT4-based device (instead of a LUT6-based device).\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
log_header(design, "Executing XILINX_DFFOPT pass (optimize FF control signal usage).\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
int max_lut_size = 6;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
if (args[argidx] == "-lut4") {
|
||||||
|
max_lut_size = 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules())
|
||||||
|
{
|
||||||
|
log("Optimizing FFs in %s.\n", log_id(module));
|
||||||
|
|
||||||
|
SigMap sigmap(module);
|
||||||
|
dict<SigBit, pair<LutData, Cell *>> bit_to_lut;
|
||||||
|
dict<SigBit, int> bit_uses;
|
||||||
|
|
||||||
|
// Gather LUTs.
|
||||||
|
for (auto cell : module->selected_cells())
|
||||||
|
{
|
||||||
|
for (auto port : cell->connections())
|
||||||
|
for (auto bit : port.second)
|
||||||
|
bit_uses[sigmap(bit)]++;
|
||||||
|
if (cell->get_bool_attribute(ID::keep))
|
||||||
|
continue;
|
||||||
|
if (cell->type == ID(INV)) {
|
||||||
|
SigBit sigout = sigmap(cell->getPort(ID(O)));
|
||||||
|
SigBit sigin = sigmap(cell->getPort(ID(I)));
|
||||||
|
bit_to_lut[sigout] = make_pair(LutData(Const(1, 2), {sigin}), cell);
|
||||||
|
} else if (cell->type.in(ID(LUT1), ID(LUT2), ID(LUT3), ID(LUT4), ID(LUT5), ID(LUT6))) {
|
||||||
|
SigBit sigout = sigmap(cell->getPort(ID(O)));
|
||||||
|
const Const &init = cell->getParam(ID(INIT));
|
||||||
|
std::vector<SigBit> sigin;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(I0))));
|
||||||
|
if (cell->type == ID(LUT1))
|
||||||
|
goto lut_sigin_done;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(I1))));
|
||||||
|
if (cell->type == ID(LUT2))
|
||||||
|
goto lut_sigin_done;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(I2))));
|
||||||
|
if (cell->type == ID(LUT3))
|
||||||
|
goto lut_sigin_done;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(I3))));
|
||||||
|
if (cell->type == ID(LUT4))
|
||||||
|
goto lut_sigin_done;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(I4))));
|
||||||
|
if (cell->type == ID(LUT5))
|
||||||
|
goto lut_sigin_done;
|
||||||
|
sigin.push_back(sigmap(cell->getPort(ID(I5))));
|
||||||
|
lut_sigin_done:
|
||||||
|
bit_to_lut[sigout] = make_pair(LutData(init, sigin), cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
if (wire->port_output || wire->port_input)
|
||||||
|
for (int i = 0; i < GetSize(wire); i++)
|
||||||
|
bit_uses[sigmap(SigBit(wire, i))]++;
|
||||||
|
|
||||||
|
// Iterate through FFs.
|
||||||
|
for (auto cell : module->selected_cells())
|
||||||
|
{
|
||||||
|
bool has_s = false, has_r = false;
|
||||||
|
if (cell->type.in(ID(FDCE), ID(FDPE), ID(FDCPE), ID(FDCE_1), ID(FDPE_1), ID(FDCPE_1))) {
|
||||||
|
// Async reset.
|
||||||
|
} else if (cell->type.in(ID(FDRE), ID(FDRE_1))) {
|
||||||
|
has_r = true;
|
||||||
|
} else if (cell->type.in(ID(FDSE), ID(FDSE_1))) {
|
||||||
|
has_s = true;
|
||||||
|
} else if (cell->type.in(ID(FDRSE), ID(FDRSE_1))) {
|
||||||
|
has_r = true;
|
||||||
|
has_s = true;
|
||||||
|
} else {
|
||||||
|
// Not a FF.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cell->get_bool_attribute(ID::keep))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Don't bother if D has more than one use.
|
||||||
|
SigBit sig_D = sigmap(cell->getPort(ID(D)));
|
||||||
|
if (bit_uses[sig_D] > 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Find the D LUT.
|
||||||
|
auto it_D = bit_to_lut.find(sig_D);
|
||||||
|
if (it_D == bit_to_lut.end())
|
||||||
|
continue;
|
||||||
|
LutData lut_d = it_D->second.first;
|
||||||
|
Cell *cell_d = it_D->second.second;
|
||||||
|
if (cell->hasParam(ID(IS_D_INVERTED)) && cell->getParam(ID(IS_D_INVERTED)).as_bool()) {
|
||||||
|
// Flip all bits in the LUT.
|
||||||
|
for (int i = 0; i < GetSize(lut_d.first); i++)
|
||||||
|
lut_d.first.bits[i] = (lut_d.first.bits[i] == State::S1) ? State::S0 : State::S1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LutData lut_d_post_ce;
|
||||||
|
LutData lut_d_post_s;
|
||||||
|
LutData lut_d_post_r;
|
||||||
|
bool worthy_post_ce = false;
|
||||||
|
bool worthy_post_s = false;
|
||||||
|
bool worthy_post_r = false;
|
||||||
|
|
||||||
|
// First, unmap CE.
|
||||||
|
SigBit sig_Q = sigmap(cell->getPort(ID(Q)));
|
||||||
|
SigBit sig_CE = sigmap(cell->getPort(ID(CE)));
|
||||||
|
LutData lut_ce = LutData(Const(2, 2), {sig_CE});
|
||||||
|
auto it_CE = bit_to_lut.find(sig_CE);
|
||||||
|
if (it_CE != bit_to_lut.end())
|
||||||
|
lut_ce = it_CE->second.first;
|
||||||
|
if (sig_CE.wire) {
|
||||||
|
// Merge CE LUT and D LUT into one. If it cannot be done, nothing to do about this FF.
|
||||||
|
if (!merge_lut(lut_d_post_ce, lut_d, lut_ce, true, sig_Q, max_lut_size))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If this gets rid of a CE LUT, it's worth it. If not, it still may be worth it, if we can remove set/reset as well.
|
||||||
|
if (it_CE != bit_to_lut.end())
|
||||||
|
worthy_post_ce = true;
|
||||||
|
} else if (sig_CE.data != State::S1) {
|
||||||
|
// Strange. Should not happen in a reasonable flow, so bail.
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
lut_d_post_ce = lut_d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second, unmap S, if any.
|
||||||
|
lut_d_post_s = lut_d_post_ce;
|
||||||
|
if (has_s) {
|
||||||
|
SigBit sig_S = sigmap(cell->getPort(ID(S)));
|
||||||
|
LutData lut_s = LutData(Const(2, 2), {sig_S});
|
||||||
|
bool inv_s = cell->hasParam(ID(IS_S_INVERTED)) && cell->getParam(ID(IS_S_INVERTED)).as_bool();
|
||||||
|
auto it_S = bit_to_lut.find(sig_S);
|
||||||
|
if (it_S != bit_to_lut.end())
|
||||||
|
lut_s = it_S->second.first;
|
||||||
|
if (sig_S.wire) {
|
||||||
|
// Merge S LUT and D LUT into one. If it cannot be done, try to at least merge CE.
|
||||||
|
if (!merge_lut(lut_d_post_s, lut_d_post_ce, lut_s, inv_s, SigBit(State::S1), max_lut_size))
|
||||||
|
goto unmap;
|
||||||
|
// If this gets rid of an S LUT, it's worth it.
|
||||||
|
if (it_S != bit_to_lut.end())
|
||||||
|
worthy_post_s = true;
|
||||||
|
} else if (sig_S.data != (inv_s ? State::S1 : State::S0)) {
|
||||||
|
// Strange. Should not happen in a reasonable flow, so bail.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third, unmap R, if any.
|
||||||
|
lut_d_post_r = lut_d_post_s;
|
||||||
|
if (has_r) {
|
||||||
|
SigBit sig_R = sigmap(cell->getPort(ID(R)));
|
||||||
|
LutData lut_r = LutData(Const(2, 2), {sig_R});
|
||||||
|
bool inv_r = cell->hasParam(ID(IS_R_INVERTED)) && cell->getParam(ID(IS_R_INVERTED)).as_bool();
|
||||||
|
auto it_R = bit_to_lut.find(sig_R);
|
||||||
|
if (it_R != bit_to_lut.end())
|
||||||
|
lut_r = it_R->second.first;
|
||||||
|
if (sig_R.wire) {
|
||||||
|
// Merge R LUT and D LUT into one. If it cannot be done, try to at least merge CE/S.
|
||||||
|
if (!merge_lut(lut_d_post_r, lut_d_post_s, lut_r, inv_r, SigBit(State::S0), max_lut_size))
|
||||||
|
goto unmap;
|
||||||
|
// If this gets rid of an S LUT, it's worth it.
|
||||||
|
if (it_R != bit_to_lut.end())
|
||||||
|
worthy_post_r = true;
|
||||||
|
} else if (sig_R.data != (inv_r ? State::S1 : State::S0)) {
|
||||||
|
// Strange. Should not happen in a reasonable flow, so bail.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unmap:
|
||||||
|
LutData final_lut;
|
||||||
|
if (worthy_post_r) {
|
||||||
|
final_lut = lut_d_post_r;
|
||||||
|
log(" Merging R LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
|
||||||
|
} else if (worthy_post_s) {
|
||||||
|
final_lut = lut_d_post_s;
|
||||||
|
log(" Merging S LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
|
||||||
|
} else if (worthy_post_ce) {
|
||||||
|
final_lut = lut_d_post_ce;
|
||||||
|
log(" Merging CE LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second));
|
||||||
|
} else {
|
||||||
|
// Nothing to do here.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, we're doing it. Unmap ports.
|
||||||
|
if (worthy_post_r) {
|
||||||
|
cell->unsetParam(ID(IS_R_INVERTED));
|
||||||
|
cell->setPort(ID(R), Const(0, 1));
|
||||||
|
}
|
||||||
|
if (has_s && (worthy_post_r || worthy_post_s)) {
|
||||||
|
cell->unsetParam(ID(IS_S_INVERTED));
|
||||||
|
cell->setPort(ID(S), Const(0, 1));
|
||||||
|
}
|
||||||
|
cell->setPort(ID(CE), Const(1, 1));
|
||||||
|
cell->unsetParam(ID(IS_D_INVERTED));
|
||||||
|
|
||||||
|
// Create the new LUT.
|
||||||
|
Cell *lut_cell = 0;
|
||||||
|
switch (GetSize(final_lut.second)) {
|
||||||
|
case 1:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(LUT1));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(LUT2));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(LUT3));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(LUT4));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(LUT5));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
lut_cell = module->addCell(NEW_ID, ID(LUT6));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_assert(!"unknown lut size");
|
||||||
|
}
|
||||||
|
lut_cell->attributes = cell_d->attributes;
|
||||||
|
Wire *lut_out = module->addWire(NEW_ID);
|
||||||
|
lut_cell->setParam(ID(INIT), final_lut.first);
|
||||||
|
cell->setPort(ID(D), lut_out);
|
||||||
|
lut_cell->setPort(ID(O), lut_out);
|
||||||
|
lut_cell->setPort(ID(I0), final_lut.second[0]);
|
||||||
|
if (GetSize(final_lut.second) >= 2)
|
||||||
|
lut_cell->setPort(ID(I1), final_lut.second[1]);
|
||||||
|
if (GetSize(final_lut.second) >= 3)
|
||||||
|
lut_cell->setPort(ID(I2), final_lut.second[2]);
|
||||||
|
if (GetSize(final_lut.second) >= 4)
|
||||||
|
lut_cell->setPort(ID(I3), final_lut.second[3]);
|
||||||
|
if (GetSize(final_lut.second) >= 5)
|
||||||
|
lut_cell->setPort(ID(I4), final_lut.second[4]);
|
||||||
|
if (GetSize(final_lut.second) >= 6)
|
||||||
|
lut_cell->setPort(ID(I5), final_lut.second[5]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} XilinxDffOptPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
||||||
|
|
|
@ -2,7 +2,7 @@ read_verilog ../common/counter.v
|
||||||
hierarchy -top top
|
hierarchy -top top
|
||||||
proc
|
proc
|
||||||
flatten
|
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)
|
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
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
read_verilog ../common/memory.v
|
read_verilog ../common/lutram.v
|
||||||
hierarchy -top top
|
hierarchy -top lutram_1w1r
|
||||||
proc
|
proc
|
||||||
memory -nomap
|
memory -nomap
|
||||||
equiv_opt -run :prove -map +/anlogic/cells_sim.v synth_anlogic
|
equiv_opt -run :prove -map +/anlogic/cells_sim.v synth_anlogic
|
||||||
|
@ -11,7 +11,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
#sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
|
#sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
|
||||||
|
|
||||||
design -load postopt
|
design -load postopt
|
||||||
cd top
|
cd lutram_1w1r
|
||||||
|
|
||||||
select -assert-count 8 t:AL_MAP_LUT2
|
select -assert-count 8 t:AL_MAP_LUT2
|
||||||
select -assert-count 8 t:AL_MAP_LUT4
|
select -assert-count 8 t:AL_MAP_LUT4
|
45
tests/arch/common/blockram.v
Normal file
45
tests/arch/common/blockram.v
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
`default_nettype none
|
||||||
|
module sync_ram_sp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||||
|
(input wire write_enable, clk,
|
||||||
|
input wire [DATA_WIDTH-1:0] data_in,
|
||||||
|
input wire [ADDRESS_WIDTH-1:0] address_in,
|
||||||
|
output wire [DATA_WIDTH-1:0] data_out);
|
||||||
|
|
||||||
|
localparam WORD = (DATA_WIDTH-1);
|
||||||
|
localparam DEPTH = (2**ADDRESS_WIDTH-1);
|
||||||
|
|
||||||
|
reg [WORD:0] data_out_r;
|
||||||
|
reg [WORD:0] memory [0:DEPTH];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_enable)
|
||||||
|
memory[address_in] <= data_in;
|
||||||
|
data_out_r <= memory[address_in];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_out = data_out_r;
|
||||||
|
endmodule // sync_ram_sp
|
||||||
|
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||||
|
(input wire clk, write_enable,
|
||||||
|
input wire [DATA_WIDTH-1:0] data_in,
|
||||||
|
input wire [ADDRESS_WIDTH-1:0] address_in_r, address_in_w,
|
||||||
|
output wire [DATA_WIDTH-1:0] data_out);
|
||||||
|
|
||||||
|
localparam WORD = (DATA_WIDTH-1);
|
||||||
|
localparam DEPTH = (2**ADDRESS_WIDTH-1);
|
||||||
|
|
||||||
|
reg [WORD:0] data_out_r;
|
||||||
|
reg [WORD:0] memory [0:DEPTH];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_enable)
|
||||||
|
memory[address_in_w] <= data_in;
|
||||||
|
data_out_r <= memory[address_in_r];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_out = data_out_r;
|
||||||
|
endmodule // sync_ram_sdp
|
||||||
|
|
42
tests/arch/common/lutram.v
Normal file
42
tests/arch/common/lutram.v
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
module lutram_1w1r
|
||||||
|
#(parameter D_WIDTH=8, A_WIDTH=6)
|
||||||
|
(
|
||||||
|
input [D_WIDTH-1:0] data_a,
|
||||||
|
input [A_WIDTH:1] addr_a,
|
||||||
|
input we_a, clk,
|
||||||
|
output reg [D_WIDTH-1:0] q_a
|
||||||
|
);
|
||||||
|
// Declare the RAM variable
|
||||||
|
reg [D_WIDTH-1:0] ram[(2**A_WIDTH)-1:0];
|
||||||
|
|
||||||
|
// Port A
|
||||||
|
always @ (posedge clk)
|
||||||
|
begin
|
||||||
|
if (we_a)
|
||||||
|
ram[addr_a] <= data_a;
|
||||||
|
q_a <= ram[addr_a];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module lutram_1w3r
|
||||||
|
#(parameter D_WIDTH=8, A_WIDTH=5)
|
||||||
|
(
|
||||||
|
input [D_WIDTH-1:0] data_a, data_b, data_c,
|
||||||
|
input [A_WIDTH:1] addr_a, addr_b, addr_c,
|
||||||
|
input we_a, clk,
|
||||||
|
output reg [D_WIDTH-1:0] q_a, q_b, q_c
|
||||||
|
);
|
||||||
|
// Declare the RAM variable
|
||||||
|
reg [D_WIDTH-1:0] ram[(2**A_WIDTH)-1:0];
|
||||||
|
|
||||||
|
// Port A
|
||||||
|
always @ (posedge clk)
|
||||||
|
begin
|
||||||
|
if (we_a)
|
||||||
|
ram[addr_a] <= data_a;
|
||||||
|
q_a <= ram[addr_a];
|
||||||
|
q_b <= ram[addr_b];
|
||||||
|
q_c <= ram[addr_c];
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -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
|
|
88
tests/arch/common/memory_attributes/attributes_test.v
Normal file
88
tests/arch/common/memory_attributes/attributes_test.v
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
`default_nettype none
|
||||||
|
module block_ram #(parameter DATA_WIDTH=4, ADDRESS_WIDTH=10)
|
||||||
|
(input wire write_enable, clk,
|
||||||
|
input wire [DATA_WIDTH-1:0] data_in,
|
||||||
|
input wire [ADDRESS_WIDTH-1:0] address_in,
|
||||||
|
output wire [DATA_WIDTH-1:0] data_out);
|
||||||
|
|
||||||
|
localparam WORD = (DATA_WIDTH-1);
|
||||||
|
localparam DEPTH = (2**ADDRESS_WIDTH-1);
|
||||||
|
|
||||||
|
reg [WORD:0] data_out_r;
|
||||||
|
reg [WORD:0] memory [0:DEPTH];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_enable)
|
||||||
|
memory[address_in] <= data_in;
|
||||||
|
data_out_r <= memory[address_in];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_out = data_out_r;
|
||||||
|
endmodule // block_ram
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
module distributed_ram #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=4)
|
||||||
|
(input wire write_enable, clk,
|
||||||
|
input wire [DATA_WIDTH-1:0] data_in,
|
||||||
|
input wire [ADDRESS_WIDTH-1:0] address_in,
|
||||||
|
output wire [DATA_WIDTH-1:0] data_out);
|
||||||
|
|
||||||
|
localparam WORD = (DATA_WIDTH-1);
|
||||||
|
localparam DEPTH = (2**ADDRESS_WIDTH-1);
|
||||||
|
|
||||||
|
reg [WORD:0] data_out_r;
|
||||||
|
reg [WORD:0] memory [0:DEPTH];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_enable)
|
||||||
|
memory[address_in] <= data_in;
|
||||||
|
data_out_r <= memory[address_in];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_out = data_out_r;
|
||||||
|
endmodule // distributed_ram
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
module distributed_ram_manual #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=4)
|
||||||
|
(input wire write_enable, clk,
|
||||||
|
input wire [DATA_WIDTH-1:0] data_in,
|
||||||
|
input wire [ADDRESS_WIDTH-1:0] address_in,
|
||||||
|
output wire [DATA_WIDTH-1:0] data_out);
|
||||||
|
|
||||||
|
localparam WORD = (DATA_WIDTH-1);
|
||||||
|
localparam DEPTH = (2**ADDRESS_WIDTH-1);
|
||||||
|
|
||||||
|
reg [WORD:0] data_out_r;
|
||||||
|
(* ram_style = "block" *) reg [WORD:0] memory [0:DEPTH];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_enable)
|
||||||
|
memory[address_in] <= data_in;
|
||||||
|
data_out_r <= memory[address_in];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_out = data_out_r;
|
||||||
|
endmodule // distributed_ram
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
module distributed_ram_manual_syn #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=4)
|
||||||
|
(input wire write_enable, clk,
|
||||||
|
input wire [DATA_WIDTH-1:0] data_in,
|
||||||
|
input wire [ADDRESS_WIDTH-1:0] address_in,
|
||||||
|
output wire [DATA_WIDTH-1:0] data_out);
|
||||||
|
|
||||||
|
localparam WORD = (DATA_WIDTH-1);
|
||||||
|
localparam DEPTH = (2**ADDRESS_WIDTH-1);
|
||||||
|
|
||||||
|
reg [WORD:0] data_out_r;
|
||||||
|
(* synthesis, ram_block *) reg [WORD:0] memory [0:DEPTH];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_enable)
|
||||||
|
memory[address_in] <= data_in;
|
||||||
|
data_out_r <= memory[address_in];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_out = data_out_r;
|
||||||
|
endmodule // distributed_ram
|
||||||
|
|
16
tests/arch/ecp5/bug1598.ys
Normal file
16
tests/arch/ecp5/bug1598.ys
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module led_blink (
|
||||||
|
input clk,
|
||||||
|
output ledc
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [6:0] led_counter = 0;
|
||||||
|
always @( posedge clk ) begin
|
||||||
|
led_counter <= led_counter + 1;
|
||||||
|
end
|
||||||
|
assign ledc = !led_counter[ 6:3 ];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
proc
|
||||||
|
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 -abc9
|
|
@ -2,7 +2,7 @@ read_verilog ../common/counter.v
|
||||||
hierarchy -top top
|
hierarchy -top top
|
||||||
proc
|
proc
|
||||||
flatten
|
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)
|
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
|
cd top # Constrain all select calls below inside the top module
|
||||||
select -assert-count 4 t:CCU2C
|
select -assert-count 4 t:CCU2C
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
read_verilog ../common/memory.v
|
read_verilog ../common/lutram.v
|
||||||
hierarchy -top top
|
hierarchy -top lutram_1w1r
|
||||||
proc
|
proc
|
||||||
memory -nomap
|
memory -nomap
|
||||||
equiv_opt -run :prove -map +/ecp5/cells_sim.v synth_ecp5
|
equiv_opt -run :prove -map +/ecp5/cells_sim.v synth_ecp5
|
||||||
|
@ -10,7 +10,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
||||||
|
|
||||||
design -load postopt
|
design -load postopt
|
||||||
cd top
|
cd lutram_1w1r
|
||||||
select -assert-count 24 t:L6MUX21
|
select -assert-count 24 t:L6MUX21
|
||||||
select -assert-count 71 t:LUT4
|
select -assert-count 71 t:LUT4
|
||||||
select -assert-count 32 t:PFUMX
|
select -assert-count 32 t:PFUMX
|
|
@ -3,8 +3,8 @@ hierarchy -top top
|
||||||
proc
|
proc
|
||||||
# Blocked by issue #1358 (Missing ECP5 simulation models)
|
# Blocked by issue #1358 (Missing ECP5 simulation models)
|
||||||
#equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
|
#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
|
cd top # Constrain all select calls below inside the top module
|
||||||
select -assert-count 1 t:MULT18X18D
|
select -assert-count 1 t:MULT18X18D
|
||||||
select -assert-count 4 t:CCU2C
|
select -assert-count 4 t:CCU2C
|
||||||
|
|
|
@ -3,9 +3,9 @@ hierarchy -top top
|
||||||
proc
|
proc
|
||||||
# Blocked by issue #1358 (Missing ECP5 simulation models)
|
# Blocked by issue #1358 (Missing ECP5 simulation models)
|
||||||
#equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
|
#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
|
cd top # Constrain all select calls below inside the top module
|
||||||
select -assert-count 1 t:MULT18X18D
|
select -assert-count 1 t:MULT18X18D
|
||||||
select -assert-none t:MULT18X18D %% t:* %D
|
select -assert-none t:MULT18X18D %% t:* %D
|
||||||
|
|
|
@ -39,8 +39,8 @@ proc
|
||||||
equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5 # equivalency check
|
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)
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
cd mux16 # Constrain all select calls below inside the top module
|
cd mux16 # Constrain all select calls below inside the top module
|
||||||
select -assert-count 8 t:L6MUX21
|
select -assert-count 12 t:L6MUX21
|
||||||
select -assert-count 26 t:LUT4
|
select -assert-count 34 t:LUT4
|
||||||
select -assert-count 12 t:PFUMX
|
select -assert-count 17 t:PFUMX
|
||||||
|
|
||||||
select -assert-none t:LUT4 t:L6MUX21 t:PFUMX %% t:* %D
|
select -assert-none t:LUT4 t:L6MUX21 t:PFUMX %% t:* %D
|
||||||
|
|
|
@ -2,7 +2,7 @@ read_verilog ../common/counter.v
|
||||||
hierarchy -top top
|
hierarchy -top top
|
||||||
proc
|
proc
|
||||||
flatten
|
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)
|
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
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
read_verilog ../common/memory.v
|
read_verilog ../common/lutram.v
|
||||||
hierarchy -top top
|
hierarchy -top lutram_1w1r
|
||||||
proc
|
proc
|
||||||
memory -nomap
|
memory -nomap
|
||||||
equiv_opt -run :prove -map +/efinix/cells_sim.v synth_efinix
|
equiv_opt -run :prove -map +/efinix/cells_sim.v synth_efinix
|
||||||
|
@ -12,7 +12,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
||||||
|
|
||||||
design -load postopt
|
design -load postopt
|
||||||
cd top
|
cd lutram_1w1r
|
||||||
select -assert-count 1 t:EFX_GBUFCE
|
select -assert-count 1 t:EFX_GBUFCE
|
||||||
select -assert-count 1 t:EFX_RAM_5K
|
select -assert-count 1 t:EFX_RAM_5K
|
||||||
select -assert-none t:EFX_GBUFCE t:EFX_RAM_5K %% t:* %D
|
select -assert-none t:EFX_GBUFCE t:EFX_RAM_5K %% t:* %D
|
|
@ -2,7 +2,7 @@ read_verilog ../common/counter.v
|
||||||
hierarchy -top top
|
hierarchy -top top
|
||||||
proc
|
proc
|
||||||
flatten
|
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)
|
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
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
read_verilog ../common/memory.v
|
read_verilog ../common/lutram.v
|
||||||
hierarchy -top top
|
hierarchy -top lutram_1w1r
|
||||||
proc
|
proc
|
||||||
memory -nomap
|
memory -nomap
|
||||||
equiv_opt -run :prove -map +/gowin/cells_sim.v synth_gowin
|
equiv_opt -run :prove -map +/gowin/cells_sim.v synth_gowin
|
||||||
|
@ -12,7 +12,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
||||||
|
|
||||||
design -load postopt
|
design -load postopt
|
||||||
cd top
|
cd lutram_1w1r
|
||||||
select -assert-count 8 t:RAM16S4
|
select -assert-count 8 t:RAM16S4
|
||||||
# other logic present that is not simple
|
# other logic present that is not simple
|
||||||
#select -assert-none t:RAM16S4 %% t:* %D
|
#select -assert-none t:RAM16S4 %% t:* %D
|
16
tests/arch/ice40/bug1598.ys
Normal file
16
tests/arch/ice40/bug1598.ys
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module led_blink (
|
||||||
|
input clk,
|
||||||
|
output ledc
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [6:0] led_counter = 0;
|
||||||
|
always @( posedge clk ) begin
|
||||||
|
led_counter <= led_counter + 1;
|
||||||
|
end
|
||||||
|
assign ledc = !led_counter[ 6:3 ];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
proc
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -abc9
|
|
@ -2,7 +2,7 @@ read_verilog ../common/counter.v
|
||||||
hierarchy -top top
|
hierarchy -top top
|
||||||
proc
|
proc
|
||||||
flatten
|
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)
|
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
|
cd top # Constrain all select calls below inside the top module
|
||||||
select -assert-count 6 t:SB_CARRY
|
select -assert-count 6 t:SB_CARRY
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
read_verilog ../common/memory.v
|
read_verilog ../common/lutram.v
|
||||||
hierarchy -top top
|
hierarchy -top lutram_1w1r
|
||||||
proc
|
proc
|
||||||
memory -nomap
|
memory -nomap
|
||||||
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
|
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
|
||||||
|
@ -10,6 +10,6 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
||||||
|
|
||||||
design -load postopt
|
design -load postopt
|
||||||
cd top
|
cd lutram_1w1r
|
||||||
select -assert-count 1 t:SB_RAM40_4K
|
select -assert-count 1 t:SB_RAM40_4K
|
||||||
select -assert-none t:SB_RAM40_4K %% t:* %D
|
select -assert-none t:SB_RAM40_4K %% t:* %D
|
|
@ -1,6 +1,6 @@
|
||||||
read_verilog ../common/mul.v
|
read_verilog ../common/mul.v
|
||||||
hierarchy -top top
|
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)
|
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
|
cd top # Constrain all select calls below inside the top module
|
||||||
select -assert-count 1 t:SB_MAC16
|
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].
|
Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 74].
|
||||||
*/
|
*/
|
||||||
module top(data, addr);
|
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;
|
input [4:0] addr;
|
||||||
always @(addr) begin
|
always @(addr) begin
|
||||||
case (addr)
|
case (addr)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
read_verilog ../common/add_sub.v
|
read_verilog ../common/add_sub.v
|
||||||
hierarchy -top top
|
hierarchy -top top
|
||||||
proc
|
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)
|
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
|
cd top # Constrain all select calls below inside the top module
|
||||||
select -assert-count 14 t:LUT2
|
select -assert-count 14 t:LUT2
|
||||||
|
|
|
@ -3,7 +3,7 @@ design -save read
|
||||||
|
|
||||||
hierarchy -top adff
|
hierarchy -top adff
|
||||||
proc
|
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)
|
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
|
cd adff # Constrain all select calls below inside the top module
|
||||||
select -assert-count 1 t:BUFG
|
select -assert-count 1 t:BUFG
|
||||||
|
@ -15,7 +15,7 @@ select -assert-none t:BUFG t:FDCE %% t:* %D
|
||||||
design -load read
|
design -load read
|
||||||
hierarchy -top adffn
|
hierarchy -top adffn
|
||||||
proc
|
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)
|
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
|
cd adffn # Constrain all select calls below inside the top module
|
||||||
select -assert-count 1 t:BUFG
|
select -assert-count 1 t:BUFG
|
||||||
|
@ -28,24 +28,23 @@ select -assert-none t:BUFG t:FDCE t:INV %% t:* %D
|
||||||
design -load read
|
design -load read
|
||||||
hierarchy -top dffs
|
hierarchy -top dffs
|
||||||
proc
|
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)
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
cd dffs # Constrain all select calls below inside the top module
|
cd dffs # Constrain all select calls below inside the top module
|
||||||
select -assert-count 1 t:BUFG
|
select -assert-count 1 t:BUFG
|
||||||
select -assert-count 1 t:FDRE
|
select -assert-count 1 t:FDSE
|
||||||
select -assert-count 1 t:LUT2
|
|
||||||
|
|
||||||
select -assert-none t:BUFG t:FDRE t:LUT2 %% t:* %D
|
select -assert-none t:BUFG t:FDSE %% t:* %D
|
||||||
|
|
||||||
|
|
||||||
design -load read
|
design -load read
|
||||||
hierarchy -top ndffnr
|
hierarchy -top ndffnr
|
||||||
proc
|
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)
|
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
|
cd ndffnr # Constrain all select calls below inside the top module
|
||||||
select -assert-count 1 t:BUFG
|
select -assert-count 1 t:BUFG
|
||||||
select -assert-count 1 t:FDRE_1
|
select -assert-count 1 t:FDRE_1
|
||||||
select -assert-count 1 t:LUT2
|
select -assert-count 1 t:INV
|
||||||
|
|
||||||
select -assert-none t:BUFG t:FDRE_1 t:LUT2 %% t:* %D
|
select -assert-none t:BUFG t:FDRE_1 t:INV %% t:* %D
|
||||||
|
|
47
tests/arch/xilinx/attributes_test.ys
Normal file
47
tests/arch/xilinx/attributes_test.ys
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# Check that blockram memory without parameters is not modified
|
||||||
|
read_verilog ../common/memory_attributes/attributes_test.v
|
||||||
|
hierarchy -top block_ram
|
||||||
|
synth_xilinx -top block_ram -noiopad
|
||||||
|
cd block_ram # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# Check that distributed memory without parameters is not modified
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/memory_attributes/attributes_test.v
|
||||||
|
hierarchy -top distributed_ram
|
||||||
|
synth_xilinx -top distributed_ram -noiopad
|
||||||
|
cd distributed_ram # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 8 t:RAM32X1D
|
||||||
|
|
||||||
|
# Set ram_style distributed to blockram memory; will be implemented as distributed
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/memory_attributes/attributes_test.v
|
||||||
|
prep
|
||||||
|
setattr -mod -set ram_style "distributed" block_ram
|
||||||
|
synth_xilinx -top block_ram -noiopad
|
||||||
|
cd block_ram # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 32 t:RAM128X1D
|
||||||
|
|
||||||
|
# Set synthesis, logic_block to blockram memory; will be implemented as distributed
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/memory_attributes/attributes_test.v
|
||||||
|
prep
|
||||||
|
setattr -mod -set logic_block 1 block_ram
|
||||||
|
synth_xilinx -top block_ram -noiopad
|
||||||
|
cd block_ram # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 0 t:RAMB18E1
|
||||||
|
select -assert-count 32 t:RAM128X1D
|
||||||
|
|
||||||
|
# Set ram_style block to a distributed memory; will be implemented as blockram
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/memory_attributes/attributes_test.v
|
||||||
|
synth_xilinx -top distributed_ram_manual -noiopad
|
||||||
|
cd distributed_ram_manual # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# Set synthesis, ram_block block to a distributed memory; will be implemented as blockram
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/memory_attributes/attributes_test.v
|
||||||
|
synth_xilinx -top distributed_ram_manual_syn -noiopad
|
||||||
|
cd distributed_ram_manual_syn # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
97
tests/arch/xilinx/blockram.ys
Normal file
97
tests/arch/xilinx/blockram.ys
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
### TODO: Not running equivalence checking because BRAM models does not exists
|
||||||
|
### currently. Checking instance counts instead.
|
||||||
|
# Memory bits <= 18K; Data width <= 36; Address width <= 14: -> RAMB18E1
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 1 sync_ram_sdp
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
chparam -set ADDRESS_WIDTH 8 -set DATA_WIDTH 18 sync_ram_sdp
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
chparam -set ADDRESS_WIDTH 14 -set DATA_WIDTH 1 sync_ram_sdp
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 36 sync_ram_sdp
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
# Anything memory bits < 1024 -> LUTRAM
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
chparam -set ADDRESS_WIDTH 8 -set DATA_WIDTH 2 sync_ram_sdp
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 0 t:RAMB18E1
|
||||||
|
select -assert-count 4 t:RAM128X1D
|
||||||
|
|
||||||
|
# More than 18K bits, data width <= 36 (TDP), and address width from 10 to 15b (non-cascaded) -> RAMB36E1
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 36 sync_ram_sdp
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB36E1
|
||||||
|
|
||||||
|
|
||||||
|
### With parameters
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1
|
||||||
|
setattr -set ram_style "block" m:memory
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1
|
||||||
|
setattr -set ram_block 1 m:memory
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1
|
||||||
|
setattr -set ram_style "dont_infer_a_ram_pretty_please" m:memory
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 0 t:RAMB18E1
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1
|
||||||
|
setattr -set logic_block 1 m:memory
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 0 t:RAMB18E1
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 8 -chparam DATA_WIDTH 1
|
||||||
|
setattr -set ram_style "block" m:memory
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog ../common/blockram.v
|
||||||
|
hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 8 -chparam DATA_WIDTH 1
|
||||||
|
setattr -set ram_block 1 m:memory
|
||||||
|
synth_xilinx -top sync_ram_sdp -noiopad
|
||||||
|
cd sync_ram_sdp
|
||||||
|
select -assert-count 1 t:RAMB18E1
|
34
tests/arch/xilinx/bug1460.ys
Normal file
34
tests/arch/xilinx/bug1460.ys
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module register_file(
|
||||||
|
input wire clk,
|
||||||
|
input wire write_enable,
|
||||||
|
input wire [63:0] write_data,
|
||||||
|
input wire [4:0] write_reg,
|
||||||
|
input wire [4:0] read1_reg,
|
||||||
|
input wire [4:0] read2_reg,
|
||||||
|
input wire [4:0] read3_reg,
|
||||||
|
output reg [63:0] read1_data,
|
||||||
|
output reg [63:0] read2_data,
|
||||||
|
output reg [63:0] read3_data
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [63:0] registers[0:31];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (write_enable == 1'b1) begin
|
||||||
|
registers[write_reg] <= write_data;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(all) begin
|
||||||
|
read1_data <= registers[read1_reg];
|
||||||
|
read2_data <= registers[read2_reg];
|
||||||
|
read3_data <= registers[read3_reg];
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
synth_xilinx -noiopad
|
||||||
|
cd register_file
|
||||||
|
select -assert-count 32 t:RAM32M
|
||||||
|
select -assert-none t:* t:BUFG %d t:RAM32M %d
|
16
tests/arch/xilinx/bug1598.ys
Normal file
16
tests/arch/xilinx/bug1598.ys
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module led_blink (
|
||||||
|
input clk,
|
||||||
|
output ledc
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [6:0] led_counter = 0;
|
||||||
|
always @( posedge clk ) begin
|
||||||
|
led_counter <= led_counter + 1;
|
||||||
|
end
|
||||||
|
assign ledc = !led_counter[ 6:3 ];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
proc
|
||||||
|
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -abc9
|
19
tests/arch/xilinx/bug1605.ys
Normal file
19
tests/arch/xilinx/bug1605.ys
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module top(inout io);
|
||||||
|
wire in;
|
||||||
|
wire t;
|
||||||
|
wire o;
|
||||||
|
|
||||||
|
IOBUF IOBUF(
|
||||||
|
.I(in),
|
||||||
|
.T(t),
|
||||||
|
.IO(io),
|
||||||
|
.O(o)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
synth_xilinx
|
||||||
|
cd top
|
||||||
|
select -assert-count 1 t:IOBUF
|
||||||
|
select -assert-none t:* t:IOBUF %d
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue