mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'origin/master' into eddie/deferred_top
This commit is contained in:
commit
d6a84a78a7
|
@ -36,6 +36,8 @@ Yosys 0.9 .. Yosys 0.9-dev
|
||||||
- Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
|
- Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
|
||||||
- Removed "ice40_unlut"
|
- Removed "ice40_unlut"
|
||||||
- Improvements in pmgen: slices, choices, define, generate
|
- Improvements in pmgen: slices, choices, define, generate
|
||||||
|
- Added "xilinx_srl" for Xilinx shift register extraction
|
||||||
|
- Removed "shregmap -tech xilinx" (superseded by "xilinx_srl")
|
||||||
|
|
||||||
Yosys 0.8 .. Yosys 0.9
|
Yosys 0.8 .. Yosys 0.9
|
||||||
----------------------
|
----------------------
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -115,7 +115,7 @@ LDFLAGS += -rdynamic
|
||||||
LDLIBS += -lrt
|
LDLIBS += -lrt
|
||||||
endif
|
endif
|
||||||
|
|
||||||
YOSYS_VER := 0.9+1
|
YOSYS_VER := 0.9+36
|
||||||
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
|
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
|
||||||
OBJS = kernel/version_$(GIT_REV).o
|
OBJS = kernel/version_$(GIT_REV).o
|
||||||
|
|
||||||
|
@ -709,6 +709,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
+cd tests/opt && bash run-test.sh
|
+cd tests/opt && bash run-test.sh
|
||||||
+cd tests/aiger && bash run-test.sh $(ABCOPT)
|
+cd tests/aiger && bash run-test.sh $(ABCOPT)
|
||||||
+cd tests/arch && bash run-test.sh
|
+cd tests/arch && bash run-test.sh
|
||||||
|
+cd tests/ice40 && bash run-test.sh $(SEEDOPT)
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " Passed \"make test\"."
|
@echo " Passed \"make test\"."
|
||||||
@echo ""
|
@echo ""
|
||||||
|
|
36
README.md
36
README.md
|
@ -330,7 +330,7 @@ Verilog Attributes and non-standard features
|
||||||
|
|
||||||
- The ``parameter`` and ``localparam`` attributes are used to mark wires
|
- The ``parameter`` and ``localparam`` attributes are used to mark wires
|
||||||
that represent module parameters or localparams (when the HDL front-end
|
that represent module parameters or localparams (when the HDL front-end
|
||||||
is run in -pwires mode).
|
is run in ``-pwires`` mode).
|
||||||
|
|
||||||
- The ``clkbuf_driver`` attribute can be set on an output port of a blackbox
|
- The ``clkbuf_driver`` attribute can be set on an output port of a blackbox
|
||||||
module to mark it as a clock buffer output, and thus prevent ``clkbufmap``
|
module to mark it as a clock buffer output, and thus prevent ``clkbufmap``
|
||||||
|
@ -347,6 +347,23 @@ Verilog Attributes and non-standard features
|
||||||
it as the external-facing pin of an I/O pad, and prevents ``iopadmap``
|
it as the external-facing pin of an I/O pad, and prevents ``iopadmap``
|
||||||
from inserting another pad cell on it.
|
from inserting another pad cell on it.
|
||||||
|
|
||||||
|
- The module attribute ``abc_box_id`` specifies a positive integer linking a
|
||||||
|
blackbox or whitebox definition to a corresponding entry in a `abc9`
|
||||||
|
box-file.
|
||||||
|
|
||||||
|
- The port attribute ``abc_scc_break`` indicates a module input port that will
|
||||||
|
be treated as a primary output during `abc9` techmapping. Doing so eliminates
|
||||||
|
the possibility of a strongly-connected component (i.e. a combinatorial loop)
|
||||||
|
existing. Typically, this is specified for sequential inputs on otherwise
|
||||||
|
combinatorial boxes -- for example, applying ``abc_scc_break`` onto the `D`
|
||||||
|
port of a LUTRAM cell prevents `abc9` from interpreting any `Q` -> `D` paths
|
||||||
|
as a combinatorial loop.
|
||||||
|
|
||||||
|
- The port attribute ``abc_carry`` marks the carry-in (if an input port) and
|
||||||
|
carry-out (if output port) ports of a box. This information is necessary for
|
||||||
|
`abc9` to preserve the integrity of carry-chains. Specifying this attribute
|
||||||
|
onto a bus port will affect only its most significant bit.
|
||||||
|
|
||||||
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
|
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
|
||||||
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
||||||
for everything that comes after the ``{* ... *}`` statement. (Reset
|
for everything that comes after the ``{* ... *}`` statement. (Reset
|
||||||
|
@ -423,23 +440,6 @@ Verilog Attributes and non-standard features
|
||||||
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
|
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
|
||||||
functionality. (By default specify .. endspecify blocks are ignored.)
|
functionality. (By default specify .. endspecify blocks are ignored.)
|
||||||
|
|
||||||
- The module attribute ``abc_box_id`` specifies a positive integer linking a
|
|
||||||
blackbox or whitebox definition to a corresponding entry in a `abc9`
|
|
||||||
box-file.
|
|
||||||
|
|
||||||
- The port attribute ``abc_scc_break`` indicates a module input port that will
|
|
||||||
be treated as a primary output during `abc9` techmapping. Doing so eliminates
|
|
||||||
the possibility of a strongly-connected component (i.e. a combinatorial loop)
|
|
||||||
existing. Typically, this is specified for sequential inputs on otherwise
|
|
||||||
combinatorial boxes -- for example, applying ``abc_scc_break`` onto the `D`
|
|
||||||
port of a LUTRAM cell prevents `abc9` from interpreting any `Q` -> `D` paths
|
|
||||||
as a combinatorial loop.
|
|
||||||
|
|
||||||
- The port attribute ``abc_carry`` marks the carry-in (if an input port) and
|
|
||||||
carry-out (if output port) ports of a box. This information is necessary for
|
|
||||||
`abc9` to preserve the integrity of carry-chains. Specifying this attribute
|
|
||||||
onto a bus port will affect only its most significant bit.
|
|
||||||
|
|
||||||
|
|
||||||
Non-standard or SystemVerilog features for formal verification
|
Non-standard or SystemVerilog features for formal verification
|
||||||
==============================================================
|
==============================================================
|
||||||
|
|
|
@ -261,11 +261,12 @@ struct XAigerWriter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bool cell_known = cell->known();
|
bool cell_known = inst_module || cell->known();
|
||||||
for (const auto &c : cell->connections()) {
|
for (const auto &c : cell->connections()) {
|
||||||
if (c.second.is_fully_const()) continue;
|
if (c.second.is_fully_const()) continue;
|
||||||
auto is_input = !cell_known || cell->input(c.first);
|
auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr;
|
||||||
auto is_output = !cell_known || cell->output(c.first);
|
auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first);
|
||||||
|
auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first);
|
||||||
if (!is_input && !is_output)
|
if (!is_input && !is_output)
|
||||||
log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
|
log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
|
||||||
|
|
||||||
|
|
|
@ -974,7 +974,7 @@ void AigerReader::post_process()
|
||||||
// operate (and run checks on) this one module
|
// operate (and run checks on) this one module
|
||||||
RTLIL::Design *mapped_design = new RTLIL::Design;
|
RTLIL::Design *mapped_design = new RTLIL::Design;
|
||||||
mapped_design->add(module);
|
mapped_design->add(module);
|
||||||
Pass::call(mapped_design, "clean");
|
Pass::call(mapped_design, "clean -purge");
|
||||||
mapped_design->modules_.erase(module->name);
|
mapped_design->modules_.erase(module->name);
|
||||||
delete mapped_design;
|
delete mapped_design;
|
||||||
|
|
||||||
|
|
|
@ -664,7 +664,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
|
||||||
} else
|
} else
|
||||||
if (arg == "%D") {
|
if (arg == "%D") {
|
||||||
if (work_stack.size() < 2)
|
if (work_stack.size() < 2)
|
||||||
log_cmd_error("Must have at least two elements on the stack for operator %%d.\n");
|
log_cmd_error("Must have at least two elements on the stack for operator %%D.\n");
|
||||||
select_op_diff(design, work_stack[work_stack.size()-1], work_stack[work_stack.size()-2]);
|
select_op_diff(design, work_stack[work_stack.size()-1], work_stack[work_stack.size()-2]);
|
||||||
work_stack[work_stack.size()-2] = work_stack[work_stack.size()-1];
|
work_stack[work_stack.size()-2] = work_stack[work_stack.size()-1];
|
||||||
work_stack.pop_back();
|
work_stack.pop_back();
|
||||||
|
@ -693,7 +693,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
|
||||||
} else
|
} else
|
||||||
if (arg == "%C") {
|
if (arg == "%C") {
|
||||||
if (work_stack.size() < 1)
|
if (work_stack.size() < 1)
|
||||||
log_cmd_error("Must have at least one element on the stack for operator %%M.\n");
|
log_cmd_error("Must have at least one element on the stack for operator %%C.\n");
|
||||||
select_op_module_to_cells(design, work_stack[work_stack.size()-1]);
|
select_op_module_to_cells(design, work_stack[work_stack.size()-1]);
|
||||||
} else
|
} else
|
||||||
if (arg == "%c") {
|
if (arg == "%c") {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
|
||||||
OBJS += passes/pmgen/test_pmgen.o
|
OBJS += passes/pmgen/test_pmgen.o
|
||||||
passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h
|
passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h passes/pmgen/xilinx_srl_pm.h
|
||||||
$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h))
|
$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h))
|
||||||
|
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
@ -30,3 +30,9 @@ PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
|
||||||
|
|
||||||
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
||||||
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)
|
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)
|
||||||
|
|
||||||
|
# --------------------------------------
|
||||||
|
|
||||||
|
OBJS += passes/pmgen/xilinx_srl.o
|
||||||
|
passes/pmgen/xilinx_srl.o: passes/pmgen/xilinx_srl_pm.h
|
||||||
|
$(eval $(call add_extra_objs,passes/pmgen/xilinx_srl_pm.h))
|
||||||
|
|
|
@ -64,11 +64,6 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
||||||
|
|
||||||
bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool();
|
bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool();
|
||||||
|
|
||||||
if (mul_signed) {
|
|
||||||
log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log(" replacing $mul with SB_MAC16 cell.\n");
|
log(" replacing $mul with SB_MAC16 cell.\n");
|
||||||
|
|
||||||
Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
|
Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
|
||||||
|
|
|
@ -28,6 +28,7 @@ bool did_something;
|
||||||
|
|
||||||
#include "passes/pmgen/test_pmgen_pm.h"
|
#include "passes/pmgen/test_pmgen_pm.h"
|
||||||
#include "passes/pmgen/ice40_dsp_pm.h"
|
#include "passes/pmgen/ice40_dsp_pm.h"
|
||||||
|
#include "passes/pmgen/xilinx_srl_pm.h"
|
||||||
#include "passes/pmgen/peepopt_pm.h"
|
#include "passes/pmgen/peepopt_pm.h"
|
||||||
|
|
||||||
void reduce_chain(test_pmgen_pm &pm)
|
void reduce_chain(test_pmgen_pm &pm)
|
||||||
|
@ -180,7 +181,7 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
|
||||||
while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
|
while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
|
||||||
{
|
{
|
||||||
if (timeout++ > 10000)
|
if (timeout++ > 10000)
|
||||||
log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n");
|
log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
|
||||||
|
|
||||||
pm matcher(mod, mod->cells());
|
pm matcher(mod, mod->cells());
|
||||||
|
|
||||||
|
@ -216,7 +217,7 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
|
||||||
run(matcher, [](){});
|
run(matcher, [](){});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (submodcnt)
|
if (submodcnt && maxsubcnt < (1 << 16))
|
||||||
maxsubcnt *= 2;
|
maxsubcnt *= 2;
|
||||||
|
|
||||||
design->remove(mod);
|
design->remove(mod);
|
||||||
|
@ -349,13 +350,18 @@ struct TestPmgenPass : public Pass {
|
||||||
if (pattern == "ice40_dsp")
|
if (pattern == "ice40_dsp")
|
||||||
return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
|
return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
|
||||||
|
|
||||||
|
if (pattern == "xilinx_srl.fixed")
|
||||||
|
return GENERATE_PATTERN(xilinx_srl_pm, fixed);
|
||||||
|
if (pattern == "xilinx_srl.variable")
|
||||||
|
return GENERATE_PATTERN(xilinx_srl_pm, variable);
|
||||||
|
|
||||||
if (pattern == "peepopt-muldiv")
|
if (pattern == "peepopt-muldiv")
|
||||||
return GENERATE_PATTERN(peepopt_pm, muldiv);
|
return GENERATE_PATTERN(peepopt_pm, muldiv);
|
||||||
|
|
||||||
if (pattern == "peepopt-shiftmul")
|
if (pattern == "peepopt-shiftmul")
|
||||||
return GENERATE_PATTERN(peepopt_pm, shiftmul);
|
return GENERATE_PATTERN(peepopt_pm, shiftmul);
|
||||||
|
|
||||||
log_cmd_error("Unkown pattern: %s\n", pattern.c_str());
|
log_cmd_error("Unknown pattern: %s\n", pattern.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* (C) 2019 Eddie Hung <eddie@fpgeh.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/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#include "passes/pmgen/xilinx_srl_pm.h"
|
||||||
|
|
||||||
|
void run_fixed(xilinx_srl_pm &pm)
|
||||||
|
{
|
||||||
|
auto &st = pm.st_fixed;
|
||||||
|
auto &ud = pm.ud_fixed;
|
||||||
|
log("Found fixed chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
|
||||||
|
|
||||||
|
SigSpec initval;
|
||||||
|
for (auto cell : ud.longest_chain) {
|
||||||
|
log_debug(" %s\n", log_id(cell));
|
||||||
|
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
|
||||||
|
SigBit Q = cell->getPort(ID(Q));
|
||||||
|
log_assert(Q.wire);
|
||||||
|
auto it = Q.wire->attributes.find(ID(init));
|
||||||
|
if (it != Q.wire->attributes.end()) {
|
||||||
|
auto &i = it->second[Q.offset];
|
||||||
|
initval.append(i);
|
||||||
|
i = State::Sx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
initval.append(State::Sx);
|
||||||
|
}
|
||||||
|
else if (cell->type.in(ID(FDRE), ID(FDRE_1))) {
|
||||||
|
if (cell->parameters.at(ID(INIT), State::S0).as_bool())
|
||||||
|
initval.append(State::S1);
|
||||||
|
else
|
||||||
|
initval.append(State::S0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
pm.autoremove(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto first_cell = ud.longest_chain.back();
|
||||||
|
auto last_cell = ud.longest_chain.front();
|
||||||
|
Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
|
||||||
|
pm.module->swap_names(c, first_cell);
|
||||||
|
|
||||||
|
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID(FDRE), ID(FDRE_1))) {
|
||||||
|
c->setParam(ID(DEPTH), GetSize(ud.longest_chain));
|
||||||
|
c->setParam(ID(INIT), initval.as_const());
|
||||||
|
if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
|
||||||
|
c->setParam(ID(CLKPOL), 1);
|
||||||
|
else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1)))
|
||||||
|
c->setParam(ID(CLKPOL), 0);
|
||||||
|
else if (first_cell->type.in(ID(FDRE))) {
|
||||||
|
if (!first_cell->parameters.at(ID(IS_C_INVERTED), State::S0).as_bool())
|
||||||
|
c->setParam(ID(CLKPOL), 1);
|
||||||
|
else
|
||||||
|
c->setParam(ID(CLKPOL), 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
|
||||||
|
c->setParam(ID(ENPOL), 1);
|
||||||
|
else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
|
||||||
|
c->setParam(ID(ENPOL), 0);
|
||||||
|
else
|
||||||
|
c->setParam(ID(ENPOL), 2);
|
||||||
|
|
||||||
|
c->setPort(ID(C), first_cell->getPort(ID(C)));
|
||||||
|
c->setPort(ID(D), first_cell->getPort(ID(D)));
|
||||||
|
c->setPort(ID(Q), last_cell->getPort(ID(Q)));
|
||||||
|
c->setPort(ID(L), GetSize(ud.longest_chain)-1);
|
||||||
|
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
|
||||||
|
c->setPort(ID(E), State::S1);
|
||||||
|
else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
|
||||||
|
c->setPort(ID(E), first_cell->getPort(ID(E)));
|
||||||
|
else if (first_cell->type.in(ID(FDRE), ID(FDRE_1)))
|
||||||
|
c->setPort(ID(E), first_cell->getPort(ID(CE)));
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
|
||||||
|
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_variable(xilinx_srl_pm &pm)
|
||||||
|
{
|
||||||
|
auto &st = pm.st_variable;
|
||||||
|
auto &ud = pm.ud_variable;
|
||||||
|
|
||||||
|
log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type));
|
||||||
|
|
||||||
|
SigSpec initval;
|
||||||
|
for (const auto &i : ud.chain) {
|
||||||
|
auto cell = i.first;
|
||||||
|
auto slice = i.second;
|
||||||
|
log_debug(" %s\n", log_id(cell));
|
||||||
|
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) {
|
||||||
|
SigBit Q = cell->getPort(ID(Q))[slice];
|
||||||
|
log_assert(Q.wire);
|
||||||
|
auto it = Q.wire->attributes.find(ID(init));
|
||||||
|
if (it != Q.wire->attributes.end()) {
|
||||||
|
auto &i = it->second[Q.offset];
|
||||||
|
initval.append(i);
|
||||||
|
i = State::Sx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
initval.append(State::Sx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
}
|
||||||
|
pm.autoremove(st.shiftx);
|
||||||
|
|
||||||
|
auto first_cell = ud.chain.back().first;
|
||||||
|
auto first_slice = ud.chain.back().second;
|
||||||
|
|
||||||
|
Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
|
||||||
|
pm.module->swap_names(c, first_cell);
|
||||||
|
|
||||||
|
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) {
|
||||||
|
c->setParam(ID(DEPTH), GetSize(ud.chain));
|
||||||
|
c->setParam(ID(INIT), initval.as_const());
|
||||||
|
Const clkpol, enpol;
|
||||||
|
if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
|
||||||
|
clkpol = 1;
|
||||||
|
else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_)))
|
||||||
|
clkpol = 0;
|
||||||
|
else if (first_cell->type.in(ID($dff), ID($dffe)))
|
||||||
|
clkpol = first_cell->getParam(ID(CLK_POLARITY));
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
|
||||||
|
enpol = 1;
|
||||||
|
else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
|
||||||
|
enpol = 0;
|
||||||
|
else if (first_cell->type.in(ID($dffe)))
|
||||||
|
enpol = first_cell->getParam(ID(EN_POLARITY));
|
||||||
|
else
|
||||||
|
enpol = 2;
|
||||||
|
c->setParam(ID(CLKPOL), clkpol);
|
||||||
|
c->setParam(ID(ENPOL), enpol);
|
||||||
|
|
||||||
|
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
|
||||||
|
c->setPort(ID(C), first_cell->getPort(ID(C)));
|
||||||
|
else if (first_cell->type.in(ID($dff), ID($dffe)))
|
||||||
|
c->setPort(ID(C), first_cell->getPort(ID(CLK)));
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
c->setPort(ID(D), first_cell->getPort(ID(D))[first_slice]);
|
||||||
|
c->setPort(ID(Q), st.shiftx->getPort(ID(Y)));
|
||||||
|
c->setPort(ID(L), st.shiftx->getPort(ID(B)));
|
||||||
|
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($dff)))
|
||||||
|
c->setPort(ID(E), State::S1);
|
||||||
|
else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
|
||||||
|
c->setPort(ID(E), first_cell->getPort(ID(E)));
|
||||||
|
else if (first_cell->type.in(ID($dffe)))
|
||||||
|
c->setPort(ID(E), first_cell->getPort(ID(EN)));
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
|
||||||
|
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct XilinxSrlPass : public Pass {
|
||||||
|
XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" xilinx_srl [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("This pass converts chains of built-in flops (bit-level: $_DFF_[NP]_, $_DFFE_*\n");
|
||||||
|
log("and word-level: $dff, $dffe) as well as Xilinx flops (FDRE, FDRE_1) into a\n");
|
||||||
|
log("$__XILINX_SHREG cell. Chains must be of the same cell type, clock, clock polarity,\n");
|
||||||
|
log("enable, and enable polarity (where relevant).\n");
|
||||||
|
log("Flops with resets cannot be mapped to Xilinx devices and will not be inferred.");
|
||||||
|
log("\n");
|
||||||
|
log(" -minlen N\n");
|
||||||
|
log(" min length of shift register (default = 3)\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -fixed\n");
|
||||||
|
log(" infer fixed-length shift registers.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -variable\n");
|
||||||
|
log(" infer variable-length shift registers (i.e. fixed-length shifts where\n");
|
||||||
|
log(" each element also fans-out to a $shiftx cell).\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n");
|
||||||
|
|
||||||
|
bool fixed = false;
|
||||||
|
bool variable = false;
|
||||||
|
int minlen = 3;
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
|
||||||
|
minlen = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-fixed") {
|
||||||
|
fixed = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-variable") {
|
||||||
|
variable = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
if (!fixed && !variable)
|
||||||
|
log_cmd_error("'-fixed' and/or '-variable' must be specified.\n");
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules()) {
|
||||||
|
auto pm = xilinx_srl_pm(module, module->selected_cells());
|
||||||
|
pm.ud_fixed.minlen = minlen;
|
||||||
|
pm.ud_variable.minlen = minlen;
|
||||||
|
|
||||||
|
if (fixed)
|
||||||
|
pm.run_fixed(run_fixed);
|
||||||
|
if (variable)
|
||||||
|
pm.run_variable(run_variable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} XilinxSrlPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,326 @@
|
||||||
|
pattern fixed
|
||||||
|
|
||||||
|
state <IdString> clk_port en_port
|
||||||
|
udata <vector<Cell*>> chain longest_chain
|
||||||
|
udata <pool<Cell*>> non_first_cells
|
||||||
|
udata <int> minlen
|
||||||
|
|
||||||
|
code
|
||||||
|
non_first_cells.clear();
|
||||||
|
subpattern(setup);
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match first
|
||||||
|
select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
|
||||||
|
select !first->has_keep_attr()
|
||||||
|
select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
|
||||||
|
select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
|
||||||
|
select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero()
|
||||||
|
filter !non_first_cells.count(first)
|
||||||
|
generate
|
||||||
|
SigSpec C = module->addWire(NEW_ID);
|
||||||
|
SigSpec D = module->addWire(NEW_ID);
|
||||||
|
SigSpec Q = module->addWire(NEW_ID);
|
||||||
|
auto r = rng(8);
|
||||||
|
Cell* cell;
|
||||||
|
switch (r)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
cell = module->addCell(NEW_ID, \FDRE);
|
||||||
|
cell->setPort(\C, C);
|
||||||
|
cell->setPort(\D, D);
|
||||||
|
cell->setPort(\Q, Q);
|
||||||
|
cell->setPort(\CE, module->addWire(NEW_ID));
|
||||||
|
if (r & 1)
|
||||||
|
cell->setPort(\R, module->addWire(NEW_ID));
|
||||||
|
else {
|
||||||
|
if (rng(2) == 0)
|
||||||
|
cell->setPort(\R, State::S0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
cell = module->addDffGate(NEW_ID, C, D, Q, r & 1);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
cell = module->addDffeGate(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 2);
|
||||||
|
break;
|
||||||
|
default: log_abort();
|
||||||
|
}
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code clk_port en_port
|
||||||
|
if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1))
|
||||||
|
clk_port = \C;
|
||||||
|
else log_abort();
|
||||||
|
if (first->type.in($_DFF_N_, $_DFF_P_))
|
||||||
|
en_port = IdString();
|
||||||
|
else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
|
||||||
|
en_port = \E;
|
||||||
|
else if (first->type.in(\FDRE, \FDRE_1))
|
||||||
|
en_port = \CE;
|
||||||
|
else log_abort();
|
||||||
|
|
||||||
|
longest_chain.clear();
|
||||||
|
chain.push_back(first);
|
||||||
|
subpattern(tail);
|
||||||
|
finally
|
||||||
|
chain.pop_back();
|
||||||
|
log_assert(chain.empty());
|
||||||
|
if (GetSize(longest_chain) >= minlen)
|
||||||
|
accept;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
subpattern setup
|
||||||
|
arg clk_port
|
||||||
|
arg en_port
|
||||||
|
|
||||||
|
match first
|
||||||
|
select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
|
||||||
|
select !first->has_keep_attr()
|
||||||
|
select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
|
||||||
|
select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
|
||||||
|
select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero()
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code clk_port en_port
|
||||||
|
if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1))
|
||||||
|
clk_port = \C;
|
||||||
|
else log_abort();
|
||||||
|
if (first->type.in($_DFF_N_, $_DFF_P_))
|
||||||
|
en_port = IdString();
|
||||||
|
else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
|
||||||
|
en_port = \E;
|
||||||
|
else if (first->type.in(\FDRE, \FDRE_1))
|
||||||
|
en_port = \CE;
|
||||||
|
else log_abort();
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match next
|
||||||
|
select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
|
||||||
|
select !next->has_keep_attr()
|
||||||
|
select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
|
||||||
|
select nusers(port(next, \Q)) == 2
|
||||||
|
index <IdString> next->type === first->type
|
||||||
|
index <SigBit> port(next, \Q) === port(first, \D)
|
||||||
|
filter port(next, clk_port) == port(first, clk_port)
|
||||||
|
filter en_port == IdString() || port(next, en_port) == port(first, en_port)
|
||||||
|
filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool()
|
||||||
|
filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
|
||||||
|
filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
|
||||||
|
filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero()
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code
|
||||||
|
non_first_cells.insert(next);
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
subpattern tail
|
||||||
|
arg first
|
||||||
|
arg clk_port
|
||||||
|
arg en_port
|
||||||
|
|
||||||
|
match next
|
||||||
|
semioptional
|
||||||
|
select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
|
||||||
|
select !next->has_keep_attr()
|
||||||
|
select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
|
||||||
|
select nusers(port(next, \Q)) == 2
|
||||||
|
index <IdString> next->type === chain.back()->type
|
||||||
|
index <SigBit> port(next, \Q) === port(chain.back(), \D)
|
||||||
|
filter port(next, clk_port) == port(first, clk_port)
|
||||||
|
filter en_port == IdString() || port(next, en_port) == port(first, en_port)
|
||||||
|
filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool()
|
||||||
|
filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
|
||||||
|
filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
|
||||||
|
filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero()
|
||||||
|
generate
|
||||||
|
Cell *cell = module->addCell(NEW_ID, chain.back()->type);
|
||||||
|
cell->setPort(\C, chain.back()->getPort(\C));
|
||||||
|
cell->setPort(\D, module->addWire(NEW_ID));
|
||||||
|
cell->setPort(\Q, chain.back()->getPort(\D));
|
||||||
|
if (cell->type == \FDRE) {
|
||||||
|
if (rng(2) == 0)
|
||||||
|
cell->setPort(\R, chain.back()->connections_.at(\R, State::S0));
|
||||||
|
cell->setPort(\CE, chain.back()->getPort(\CE));
|
||||||
|
}
|
||||||
|
else if (cell->type.begins_with("$_DFFE_"))
|
||||||
|
cell->setPort(\E, chain.back()->getPort(\E));
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code
|
||||||
|
if (next) {
|
||||||
|
chain.push_back(next);
|
||||||
|
subpattern(tail);
|
||||||
|
} else {
|
||||||
|
if (GetSize(chain) > GetSize(longest_chain))
|
||||||
|
longest_chain = chain;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
if (next)
|
||||||
|
chain.pop_back();
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// -----------
|
||||||
|
|
||||||
|
pattern variable
|
||||||
|
|
||||||
|
state <IdString> clk_port en_port
|
||||||
|
state <int> shiftx_width
|
||||||
|
state <int> slice
|
||||||
|
udata <int> minlen
|
||||||
|
udata <vector<pair<Cell*,int>>> chain
|
||||||
|
udata <pool<SigBit>> chain_bits
|
||||||
|
|
||||||
|
code
|
||||||
|
chain_bits.clear();
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match shiftx
|
||||||
|
select shiftx->type.in($shiftx)
|
||||||
|
select !shiftx->has_keep_attr()
|
||||||
|
select param(shiftx, \Y_WIDTH).as_int() == 1
|
||||||
|
filter param(shiftx, \A_WIDTH).as_int() >= minlen
|
||||||
|
generate
|
||||||
|
minlen = 3;
|
||||||
|
module->addShiftx(NEW_ID, module->addWire(NEW_ID, rng(6)+minlen), module->addWire(NEW_ID, 3), module->addWire(NEW_ID));
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code shiftx_width
|
||||||
|
shiftx_width = param(shiftx, \A_WIDTH).as_int();
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match first
|
||||||
|
select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe)
|
||||||
|
select !first->has_keep_attr()
|
||||||
|
select port(first, \Q)[0].wire && !port(first, \Q)[0].wire->get_bool_attribute(\keep)
|
||||||
|
slice idx GetSize(port(first, \Q))
|
||||||
|
select nusers(port(first, \Q)[idx]) <= 2
|
||||||
|
index <SigBit> port(first, \Q)[idx] === port(shiftx, \A)[shiftx_width-1]
|
||||||
|
set slice idx
|
||||||
|
generate
|
||||||
|
SigSpec C = module->addWire(NEW_ID);
|
||||||
|
auto WIDTH = rng(3)+1;
|
||||||
|
SigSpec D = module->addWire(NEW_ID, WIDTH);
|
||||||
|
SigSpec Q = module->addWire(NEW_ID, WIDTH);
|
||||||
|
auto r = rng(8);
|
||||||
|
Cell *cell = nullptr;
|
||||||
|
switch (r)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
cell = module->addDff(NEW_ID, C, D, Q, r & 1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
//cell = module->addDffe(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 4);
|
||||||
|
//break;
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
WIDTH = 1;
|
||||||
|
cell = module->addDffGate(NEW_ID, C, D[0], Q[0], r & 1);
|
||||||
|
break;
|
||||||
|
default: log_abort();
|
||||||
|
}
|
||||||
|
shiftx->connections_.at(\A)[shiftx_width-1] = port(cell, \Q)[rng(WIDTH)];
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code clk_port en_port
|
||||||
|
if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
|
||||||
|
clk_port = \C;
|
||||||
|
else if (first->type.in($dff, $dffe))
|
||||||
|
clk_port = \CLK;
|
||||||
|
else log_abort();
|
||||||
|
if (first->type.in($_DFF_N_, $_DFF_P_, $dff))
|
||||||
|
en_port = IdString();
|
||||||
|
else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
|
||||||
|
en_port = \E;
|
||||||
|
else if (first->type.in($dffe))
|
||||||
|
en_port = \EN;
|
||||||
|
else log_abort();
|
||||||
|
|
||||||
|
chain_bits.insert(port(first, \Q)[slice]);
|
||||||
|
chain.emplace_back(first, slice);
|
||||||
|
subpattern(tail);
|
||||||
|
finally
|
||||||
|
if (GetSize(chain) == shiftx_width)
|
||||||
|
accept;
|
||||||
|
chain.clear();
|
||||||
|
endcode
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
subpattern tail
|
||||||
|
arg first
|
||||||
|
arg shiftx
|
||||||
|
arg shiftx_width
|
||||||
|
arg slice
|
||||||
|
arg clk_port
|
||||||
|
arg en_port
|
||||||
|
|
||||||
|
match next
|
||||||
|
semioptional
|
||||||
|
select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe)
|
||||||
|
select !next->has_keep_attr()
|
||||||
|
select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
|
||||||
|
slice idx GetSize(port(next, \Q))
|
||||||
|
select nusers(port(next, \Q)[idx]) <= 3
|
||||||
|
index <IdString> next->type === chain.back().first->type
|
||||||
|
index <SigBit> port(next, \Q)[idx] === port(chain.back().first, \D)[chain.back().second]
|
||||||
|
index <SigBit> port(next, \Q)[idx] === port(shiftx, \A)[shiftx_width-1-GetSize(chain)]
|
||||||
|
filter port(next, clk_port) == port(first, clk_port)
|
||||||
|
filter en_port == IdString() || port(next, en_port) == port(first, en_port)
|
||||||
|
filter !next->type.in($dff, $dffe) || param(next, \CLK_POLARITY).as_bool() == param(first, \CLK_POLARITY).as_bool()
|
||||||
|
filter !next->type.in($dffe) || param(next, \EN_POLARITY).as_bool() == param(first, \EN_POLARITY).as_bool()
|
||||||
|
filter !chain_bits.count(port(next, \D)[idx])
|
||||||
|
set slice idx
|
||||||
|
generate
|
||||||
|
if (GetSize(chain) < shiftx_width) {
|
||||||
|
auto back = chain.back().first;
|
||||||
|
auto slice = chain.back().second;
|
||||||
|
if (back->type.in($dff, $dffe)) {
|
||||||
|
auto WIDTH = GetSize(port(back, \D));
|
||||||
|
if (rng(2) == 0 && slice < WIDTH-1) {
|
||||||
|
auto new_slice = slice + rng(WIDTH-1-slice);
|
||||||
|
back->connections_.at(\D)[slice] = port(back, \Q)[new_slice];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto D = module->addWire(NEW_ID, WIDTH);
|
||||||
|
if (back->type == $dff)
|
||||||
|
module->addDff(NEW_ID, port(back, \CLK), D, port(back, \D), param(back, \CLK_POLARITY).as_bool());
|
||||||
|
else if (back->type == $dffe)
|
||||||
|
module->addDffe(NEW_ID, port(back, \CLK), port(back, \EN), D, port(back, \D), param(back, \CLK_POLARITY).as_bool(), param(back, \EN_POLARITY).as_bool());
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (back->type.begins_with("$_DFF_")) {
|
||||||
|
Cell *cell = module->addCell(NEW_ID, back->type);
|
||||||
|
cell->setPort(\C, back->getPort(\C));
|
||||||
|
cell->setPort(\D, module->addWire(NEW_ID));
|
||||||
|
cell->setPort(\Q, back->getPort(\D));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
shiftx->connections_.at(\A)[shiftx_width-1-GetSize(chain)] = port(back, \D)[slice];
|
||||||
|
}
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code
|
||||||
|
if (next) {
|
||||||
|
chain_bits.insert(port(next, \Q)[slice]);
|
||||||
|
chain.emplace_back(next, slice);
|
||||||
|
if (GetSize(chain) < shiftx_width)
|
||||||
|
subpattern(tail);
|
||||||
|
}
|
||||||
|
endcode
|
|
@ -694,30 +694,27 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
|
||||||
int in_wires = 0, out_wires = 0;
|
int in_wires = 0, out_wires = 0;
|
||||||
|
|
||||||
// Stitch in mapped_mod's inputs/outputs into module
|
// Stitch in mapped_mod's inputs/outputs into module
|
||||||
for (auto &it : mapped_mod->wires_) {
|
for (auto port : mapped_mod->ports) {
|
||||||
RTLIL::Wire *w = it.second;
|
RTLIL::Wire *w = mapped_mod->wire(port);
|
||||||
if (!w->port_input && !w->port_output)
|
RTLIL::Wire *wire = module->wire(port);
|
||||||
continue;
|
|
||||||
RTLIL::Wire *wire = module->wire(w->name);
|
|
||||||
log_assert(wire);
|
log_assert(wire);
|
||||||
RTLIL::Wire *remap_wire = module->wire(remap_name(w->name));
|
RTLIL::Wire *remap_wire = module->wire(remap_name(port));
|
||||||
RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
|
RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
|
||||||
log_assert(GetSize(signal) >= GetSize(remap_wire));
|
log_assert(GetSize(signal) >= GetSize(remap_wire));
|
||||||
|
|
||||||
log_assert(w->port_input || w->port_output);
|
|
||||||
RTLIL::SigSig conn;
|
RTLIL::SigSig conn;
|
||||||
if (w->port_input) {
|
|
||||||
conn.first = remap_wire;
|
|
||||||
conn.second = signal;
|
|
||||||
in_wires++;
|
|
||||||
module->connect(conn);
|
|
||||||
}
|
|
||||||
if (w->port_output) {
|
if (w->port_output) {
|
||||||
conn.first = signal;
|
conn.first = signal;
|
||||||
conn.second = remap_wire;
|
conn.second = remap_wire;
|
||||||
out_wires++;
|
out_wires++;
|
||||||
module->connect(conn);
|
module->connect(conn);
|
||||||
}
|
}
|
||||||
|
else if (w->port_input) {
|
||||||
|
conn.first = remap_wire;
|
||||||
|
conn.second = signal;
|
||||||
|
in_wires++;
|
||||||
|
module->connect(conn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &it : bit_users)
|
for (auto &it : bit_users)
|
||||||
|
@ -1300,9 +1297,6 @@ struct Abc9Pass : public Pass {
|
||||||
|
|
||||||
assign_map.clear();
|
assign_map.clear();
|
||||||
|
|
||||||
// The "clean" pass also contains a design->check() call
|
|
||||||
Pass::call(design, "clean");
|
|
||||||
|
|
||||||
log_pop();
|
log_pop();
|
||||||
}
|
}
|
||||||
} Abc9Pass;
|
} Abc9Pass;
|
||||||
|
|
|
@ -26,9 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
struct ShregmapTech
|
struct ShregmapTech
|
||||||
{
|
{
|
||||||
virtual ~ShregmapTech() { }
|
virtual ~ShregmapTech() { }
|
||||||
virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {}
|
virtual bool analyze(vector<int> &taps) = 0;
|
||||||
virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {}
|
|
||||||
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0;
|
|
||||||
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
|
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,7 +54,7 @@ struct ShregmapOptions
|
||||||
|
|
||||||
struct ShregmapTechGreenpak4 : ShregmapTech
|
struct ShregmapTechGreenpak4 : ShregmapTech
|
||||||
{
|
{
|
||||||
bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/)
|
bool analyze(vector<int> &taps)
|
||||||
{
|
{
|
||||||
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
|
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
|
||||||
taps.clear();
|
taps.clear();
|
||||||
|
@ -93,155 +91,6 @@ struct ShregmapTechGreenpak4 : ShregmapTech
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShregmapTechXilinx7 : ShregmapTech
|
|
||||||
{
|
|
||||||
dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
|
|
||||||
const ShregmapOptions &opts;
|
|
||||||
|
|
||||||
ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {}
|
|
||||||
|
|
||||||
virtual void init(const Module* module, const SigMap &sigmap) override
|
|
||||||
{
|
|
||||||
for (const auto &i : module->cells_) {
|
|
||||||
auto cell = i.second;
|
|
||||||
if (cell->type == ID($shiftx)) {
|
|
||||||
if (cell->getParam(ID(Y_WIDTH)) != 1) continue;
|
|
||||||
int j = 0;
|
|
||||||
for (auto bit : sigmap(cell->getPort(ID::A)))
|
|
||||||
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
|
|
||||||
log_assert(j == cell->getParam(ID(A_WIDTH)).as_int());
|
|
||||||
}
|
|
||||||
else if (cell->type == ID($mux)) {
|
|
||||||
int j = 0;
|
|
||||||
for (auto bit : sigmap(cell->getPort(ID::A)))
|
|
||||||
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
|
|
||||||
j = 0;
|
|
||||||
for (auto bit : sigmap(cell->getPort(ID::B)))
|
|
||||||
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override
|
|
||||||
{
|
|
||||||
auto it = sigbit_to_shiftx_offset.find(bit);
|
|
||||||
if (it == sigbit_to_shiftx_offset.end())
|
|
||||||
return;
|
|
||||||
if (cell) {
|
|
||||||
if (cell->type == ID($shiftx) && port == ID::A)
|
|
||||||
return;
|
|
||||||
if (cell->type == ID($mux) && port.in(ID::A, ID::B))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sigbit_to_shiftx_offset.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override
|
|
||||||
{
|
|
||||||
if (GetSize(taps) == 1)
|
|
||||||
return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]);
|
|
||||||
|
|
||||||
if (taps.back() < opts.minlen-1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Cell *shiftx = nullptr;
|
|
||||||
int group = 0;
|
|
||||||
for (int i = 0; i < GetSize(taps); ++i) {
|
|
||||||
auto it = sigbit_to_shiftx_offset.find(qbits[i]);
|
|
||||||
if (it == sigbit_to_shiftx_offset.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check taps are sequential
|
|
||||||
if (i != taps[i])
|
|
||||||
return false;
|
|
||||||
// Check taps are not connected to a shift register,
|
|
||||||
// or sequential to the same shift register
|
|
||||||
if (i == 0) {
|
|
||||||
int offset;
|
|
||||||
std::tie(shiftx,offset,group) = it->second;
|
|
||||||
if (offset != i)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Cell *shiftx_ = std::get<0>(it->second);
|
|
||||||
if (shiftx_ != shiftx)
|
|
||||||
return false;
|
|
||||||
int offset = std::get<1>(it->second);
|
|
||||||
if (offset != i)
|
|
||||||
return false;
|
|
||||||
int group_ = std::get<2>(it->second);
|
|
||||||
if (group_ != group)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log_assert(shiftx);
|
|
||||||
|
|
||||||
// Only map if $shiftx exclusively covers the shift register
|
|
||||||
if (shiftx->type == ID($shiftx)) {
|
|
||||||
if (GetSize(taps) > shiftx->getParam(ID(A_WIDTH)).as_int())
|
|
||||||
return false;
|
|
||||||
// Due to padding the most significant bits of A may be 1'bx,
|
|
||||||
// and if so, discount them
|
|
||||||
if (GetSize(taps) < shiftx->getParam(ID(A_WIDTH)).as_int()) {
|
|
||||||
const SigSpec A = shiftx->getPort(ID::A);
|
|
||||||
const int A_width = shiftx->getParam(ID(A_WIDTH)).as_int();
|
|
||||||
for (int i = GetSize(taps); i < A_width; ++i)
|
|
||||||
if (A[i] != RTLIL::Sx) return false;
|
|
||||||
}
|
|
||||||
else if (GetSize(taps) != shiftx->getParam(ID(A_WIDTH)).as_int())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (shiftx->type == ID($mux)) {
|
|
||||||
if (GetSize(taps) != 2)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else log_abort();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override
|
|
||||||
{
|
|
||||||
const auto &tap = *taps.begin();
|
|
||||||
auto bit = tap.second;
|
|
||||||
|
|
||||||
auto it = sigbit_to_shiftx_offset.find(bit);
|
|
||||||
log_assert(it != sigbit_to_shiftx_offset.end());
|
|
||||||
|
|
||||||
auto newcell = cell->module->addCell(NEW_ID, ID($__XILINX_SHREG_));
|
|
||||||
newcell->set_src_attribute(cell->get_src_attribute());
|
|
||||||
newcell->setParam(ID(DEPTH), cell->getParam(ID(DEPTH)));
|
|
||||||
newcell->setParam(ID(INIT), cell->getParam(ID(INIT)));
|
|
||||||
newcell->setParam(ID(CLKPOL), cell->getParam(ID(CLKPOL)));
|
|
||||||
newcell->setParam(ID(ENPOL), cell->getParam(ID(ENPOL)));
|
|
||||||
|
|
||||||
newcell->setPort(ID(C), cell->getPort(ID(C)));
|
|
||||||
newcell->setPort(ID(D), cell->getPort(ID(D)));
|
|
||||||
if (cell->hasPort(ID(E)))
|
|
||||||
newcell->setPort(ID(E), cell->getPort(ID(E)));
|
|
||||||
|
|
||||||
Cell* shiftx = std::get<0>(it->second);
|
|
||||||
RTLIL::SigSpec l_wire, q_wire;
|
|
||||||
if (shiftx->type == ID($shiftx)) {
|
|
||||||
l_wire = shiftx->getPort(ID::B);
|
|
||||||
q_wire = shiftx->getPort(ID::Y);
|
|
||||||
shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
|
|
||||||
}
|
|
||||||
else if (shiftx->type == ID($mux)) {
|
|
||||||
l_wire = shiftx->getPort(ID(S));
|
|
||||||
q_wire = shiftx->getPort(ID::Y);
|
|
||||||
shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
|
|
||||||
}
|
|
||||||
else log_abort();
|
|
||||||
|
|
||||||
newcell->setPort(ID(Q), q_wire);
|
|
||||||
newcell->setPort(ID(L), l_wire);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct ShregmapWorker
|
struct ShregmapWorker
|
||||||
{
|
{
|
||||||
Module *module;
|
Module *module;
|
||||||
|
@ -264,10 +113,8 @@ struct ShregmapWorker
|
||||||
for (auto wire : module->wires())
|
for (auto wire : module->wires())
|
||||||
{
|
{
|
||||||
if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
|
if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
|
||||||
for (auto bit : sigmap(wire)) {
|
for (auto bit : sigmap(wire))
|
||||||
sigbit_with_non_chain_users.insert(bit);
|
sigbit_with_non_chain_users.insert(bit);
|
||||||
if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire->attributes.count(ID(init))) {
|
if (wire->attributes.count(ID(init))) {
|
||||||
|
@ -317,10 +164,8 @@ struct ShregmapWorker
|
||||||
|
|
||||||
for (auto conn : cell->connections())
|
for (auto conn : cell->connections())
|
||||||
if (cell->input(conn.first))
|
if (cell->input(conn.first))
|
||||||
for (auto bit : sigmap(conn.second)) {
|
for (auto bit : sigmap(conn.second))
|
||||||
sigbit_with_non_chain_users.insert(bit);
|
sigbit_with_non_chain_users.insert(bit);
|
||||||
if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +191,7 @@ struct ShregmapWorker
|
||||||
IdString q_port = opts.ffcells.at(c1->type).second;
|
IdString q_port = opts.ffcells.at(c1->type).second;
|
||||||
|
|
||||||
auto c1_conn = c1->connections();
|
auto c1_conn = c1->connections();
|
||||||
auto c2_conn = c1->connections();
|
auto c2_conn = c2->connections();
|
||||||
|
|
||||||
c1_conn.erase(d_port);
|
c1_conn.erase(d_port);
|
||||||
c1_conn.erase(q_port);
|
c1_conn.erase(q_port);
|
||||||
|
@ -425,7 +270,7 @@ struct ShregmapWorker
|
||||||
if (taps.empty() || taps.back() < depth-1)
|
if (taps.empty() || taps.back() < depth-1)
|
||||||
taps.push_back(depth-1);
|
taps.push_back(depth-1);
|
||||||
|
|
||||||
if (opts.tech->analyze(taps, qbits))
|
if (opts.tech->analyze(taps))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
taps.pop_back();
|
taps.pop_back();
|
||||||
|
@ -544,9 +389,6 @@ struct ShregmapWorker
|
||||||
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
|
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
|
||||||
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
|
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
|
||||||
{
|
{
|
||||||
if (opts.tech)
|
|
||||||
opts.tech->init(module, sigmap);
|
|
||||||
|
|
||||||
make_sigbit_chain_next_prev();
|
make_sigbit_chain_next_prev();
|
||||||
find_chain_start_cells();
|
find_chain_start_cells();
|
||||||
|
|
||||||
|
@ -617,11 +459,6 @@ struct ShregmapPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -tech greenpak4\n");
|
log(" -tech greenpak4\n");
|
||||||
log(" map to greenpak4 shift registers.\n");
|
log(" map to greenpak4 shift registers.\n");
|
||||||
log(" this option also implies -clkpol pos -zinit\n");
|
|
||||||
log("\n");
|
|
||||||
log(" -tech xilinx\n");
|
|
||||||
log(" map to xilinx dynamic-length shift registers.\n");
|
|
||||||
log(" this option also implies -params -init\n");
|
|
||||||
log("\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
|
||||||
|
@ -676,12 +513,6 @@ struct ShregmapPass : public Pass {
|
||||||
clkpol = "pos";
|
clkpol = "pos";
|
||||||
opts.zinit = true;
|
opts.zinit = true;
|
||||||
opts.tech = new ShregmapTechGreenpak4;
|
opts.tech = new ShregmapTechGreenpak4;
|
||||||
}
|
|
||||||
else if (tech == "xilinx") {
|
|
||||||
opts.init = true;
|
|
||||||
opts.params = true;
|
|
||||||
enpol = "any_or_none";
|
|
||||||
opts.tech = new ShregmapTechXilinx7(opts);
|
|
||||||
} else {
|
} else {
|
||||||
argidx--;
|
argidx--;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \
|
OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \
|
||||||
techlibs/ecp5/ecp5_gsr.o
|
techlibs/ecp5/ecp5_gsr.o
|
||||||
|
|
||||||
|
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh))
|
||||||
|
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh))
|
||||||
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
|
$(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))
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Diamond flip-flops
|
||||||
|
module FD1P3AX(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1P3AY(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1P3BX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1P3DX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1P3IX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1P3JX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3AX(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3AY(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3BX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3DX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3IX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
||||||
|
module FD1S3JX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
// TODO: Diamond latches
|
||||||
|
// module FL1P3AY(); endmodule
|
||||||
|
// module FL1P3AZ(); endmodule
|
||||||
|
// module FL1P3BX(); endmodule
|
||||||
|
// module FL1P3DX(); endmodule
|
||||||
|
// module FL1P3IY(); endmodule
|
||||||
|
// module FL1P3JY(); endmodule
|
||||||
|
// module FL1S3AX(); endmodule
|
||||||
|
// module FL1S3AY(); endmodule
|
||||||
|
|
||||||
|
// Diamond I/O registers
|
||||||
|
module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module IFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
module OFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
module OFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
||||||
|
|
||||||
|
// TODO: Diamond I/O latches
|
||||||
|
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
|
||||||
|
// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Diamond I/O buffers
|
||||||
|
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
||||||
|
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
||||||
|
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
||||||
|
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule
|
||||||
|
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
||||||
|
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
||||||
|
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
||||||
|
module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
|
||||||
|
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||||
|
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||||
|
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
||||||
|
module ILVDS(input A, AN, output Z ); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
|
||||||
|
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
|
|
@ -47,59 +47,8 @@ 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
|
||||||
|
|
||||||
// TODO: Diamond flip-flops
|
`include "cells_ff.vh"
|
||||||
// module FD1P3AX(); endmodule
|
`include "cells_io.vh"
|
||||||
// module FD1P3AY(); endmodule
|
|
||||||
// module FD1P3BX(); endmodule
|
|
||||||
// module FD1P3DX(); endmodule
|
|
||||||
// module FD1P3IX(); endmodule
|
|
||||||
// module FD1P3JX(); endmodule
|
|
||||||
// module FD1S3AX(); endmodule
|
|
||||||
// module FD1S3AY(); endmodule
|
|
||||||
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
|
||||||
module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
|
||||||
module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
|
||||||
module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
|
||||||
// module FL1P3AY(); endmodule
|
|
||||||
// module FL1P3AZ(); endmodule
|
|
||||||
// module FL1P3BX(); endmodule
|
|
||||||
// module FL1P3DX(); endmodule
|
|
||||||
// module FL1P3IY(); endmodule
|
|
||||||
// module FL1P3JY(); endmodule
|
|
||||||
// module FL1S3AX(); endmodule
|
|
||||||
// module FL1S3AY(); endmodule
|
|
||||||
|
|
||||||
// Diamond I/O buffers
|
|
||||||
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
|
||||||
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
|
||||||
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
|
|
||||||
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule
|
|
||||||
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
|
||||||
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
|
||||||
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
|
|
||||||
module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule
|
|
||||||
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
|
||||||
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
|
||||||
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
|
|
||||||
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
|
|
||||||
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
|
|
||||||
|
|
||||||
// Diamond I/O registers
|
|
||||||
module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
|
|
||||||
module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
|
|
||||||
// TODO: Diamond I/O latches
|
|
||||||
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
|
|
||||||
// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
|
|
||||||
// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
|
|
||||||
// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
|
|
||||||
|
|
||||||
`ifndef NO_LUT
|
`ifndef NO_LUT
|
||||||
module \$lut (A, Y);
|
module \$lut (A, Y);
|
||||||
|
|
|
@ -229,14 +229,15 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
|
||||||
parameter REGSET = "RESET";
|
parameter REGSET = "RESET";
|
||||||
parameter [127:0] LSRMODE = "LSR";
|
parameter [127:0] LSRMODE = "LSR";
|
||||||
|
|
||||||
reg muxce;
|
wire muxce;
|
||||||
always @(*)
|
generate
|
||||||
case (CEMUX)
|
case (CEMUX)
|
||||||
"1": muxce = 1'b1;
|
"1": assign muxce = 1'b1;
|
||||||
"0": muxce = 1'b0;
|
"0": assign muxce = 1'b0;
|
||||||
"INV": muxce = ~CE;
|
"INV": assign muxce = ~CE;
|
||||||
default: muxce = CE;
|
default: assign muxce = CE;
|
||||||
endcase
|
endcase
|
||||||
|
endgenerate
|
||||||
|
|
||||||
wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
|
wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
|
||||||
wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
|
wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
|
||||||
|
@ -693,56 +694,9 @@ module DP16KD(
|
||||||
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
|
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
// TODO: Diamond flip-flops
|
`ifndef NO_INCLUDES
|
||||||
// module FD1P3AX(); endmodule
|
|
||||||
// module FD1P3AY(); endmodule
|
|
||||||
// module FD1P3BX(); endmodule
|
|
||||||
// module FD1P3DX(); endmodule
|
|
||||||
// module FD1P3IX(); endmodule
|
|
||||||
// module FD1P3JX(); endmodule
|
|
||||||
// module FD1S3AX(); endmodule
|
|
||||||
// module FD1S3AY(); endmodule
|
|
||||||
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
|
||||||
module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
|
||||||
module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
|
|
||||||
module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
|
|
||||||
// module FL1P3AY(); endmodule
|
|
||||||
// module FL1P3AZ(); endmodule
|
|
||||||
// module FL1P3BX(); endmodule
|
|
||||||
// module FL1P3DX(); endmodule
|
|
||||||
// module FL1P3IY(); endmodule
|
|
||||||
// module FL1P3JY(); endmodule
|
|
||||||
// module FL1S3AX(); endmodule
|
|
||||||
// module FL1S3AY(); endmodule
|
|
||||||
|
|
||||||
// Diamond I/O buffers
|
`include "cells_ff.vh"
|
||||||
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
|
`include "cells_io.vh"
|
||||||
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
|
|
||||||
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
|
|
||||||
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule
|
|
||||||
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
|
|
||||||
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
|
|
||||||
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
|
|
||||||
module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
|
|
||||||
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
|
|
||||||
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
|
|
||||||
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
|
|
||||||
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) tio (.B(A), .O(Z)); endmodule
|
|
||||||
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule
|
|
||||||
|
|
||||||
// Diamond I/O registers
|
`endif
|
||||||
module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
|
|
||||||
module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
|
|
||||||
|
|
||||||
// TODO: Diamond I/O latches
|
|
||||||
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
|
|
||||||
// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
|
|
||||||
// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
|
|
||||||
// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ struct Ecp5GsrPass : public Pass {
|
||||||
SigBit lsr = sigmap(sig_lsr[0]);
|
SigBit lsr = sigmap(sig_lsr[0]);
|
||||||
if (!inverted_gsr.count(lsr))
|
if (!inverted_gsr.count(lsr))
|
||||||
continue;
|
continue;
|
||||||
cell->setParam(ID(SRMODE), Const("SYNC"));
|
cell->setParam(ID(SRMODE), Const("LSR_OVER_CE"));
|
||||||
cell->unsetPort(ID(LSR));
|
cell->unsetPort(ID(LSR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
work_*
|
|
@ -0,0 +1,82 @@
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
if not os.path.exists("work_ff"):
|
||||||
|
os.mkdir("work_ff")
|
||||||
|
|
||||||
|
modules = []
|
||||||
|
|
||||||
|
with open("../cells_ff.vh", "r") as f:
|
||||||
|
with open("work_ff/cells_ff_gate.v", "w") as g:
|
||||||
|
for line in f:
|
||||||
|
if not line.startswith("module"):
|
||||||
|
g.write(line)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
spidx = line.find(" ")
|
||||||
|
bridx = line.find("(")
|
||||||
|
modname = line[spidx+1 : bridx]
|
||||||
|
g.write("module %s_gate" % modname)
|
||||||
|
g.write(line[bridx:])
|
||||||
|
inpidx = line.find("input ")
|
||||||
|
outpidx = line.find(", output")
|
||||||
|
modules.append((modname, [x.strip() for x in line[inpidx+6:outpidx].split(",")]))
|
||||||
|
|
||||||
|
with open("work_ff/testbench.v", "w") as f:
|
||||||
|
print("""
|
||||||
|
`timescale 1ns/ 1ps
|
||||||
|
|
||||||
|
module testbench;
|
||||||
|
reg pur = 0, clk, rst, cen, d;
|
||||||
|
|
||||||
|
// Needed for Diamond sim models
|
||||||
|
GSR GSR_INST (.GSR(1'b1));
|
||||||
|
PUR PUR_INST (.PUR(pur));
|
||||||
|
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("work_ff/ffs.vcd");
|
||||||
|
$dumpvars(0, testbench);
|
||||||
|
#5;
|
||||||
|
pur = 1;
|
||||||
|
#95;
|
||||||
|
repeat (2500) begin
|
||||||
|
{clk, rst, cen, d} = $random;
|
||||||
|
#10;
|
||||||
|
check_outputs;
|
||||||
|
#1;
|
||||||
|
end
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
""", file=f)
|
||||||
|
|
||||||
|
for modname, inputs in modules:
|
||||||
|
print(" wire %s_gold_q, %s_gate_q;" % (modname, modname), file=f)
|
||||||
|
portconns = []
|
||||||
|
for inp in inputs:
|
||||||
|
if inp in ("SCLK", "CK"):
|
||||||
|
portconns.append(".%s(clk)" % inp)
|
||||||
|
elif inp in ("CD", "PD"):
|
||||||
|
portconns.append(".%s(rst)" % inp)
|
||||||
|
elif inp == "SP":
|
||||||
|
portconns.append(".%s(cen)" % inp)
|
||||||
|
elif inp == "D":
|
||||||
|
portconns.append(".%s(d)" % inp)
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
portconns.append(".Q(%s_gold_q)" % modname)
|
||||||
|
print(" %s %s_gold_i (%s);" % (modname, modname, ", ".join(portconns)), file=f)
|
||||||
|
portconns[-1] = (".Q(%s_gate_q)" % modname)
|
||||||
|
print(" %s_gate %s_gate_i (%s);" % (modname, modname, ", ".join(portconns)), file=f)
|
||||||
|
print("", file=f)
|
||||||
|
print(" task check_outputs;", file=f)
|
||||||
|
print(" begin", file=f)
|
||||||
|
print(" if (%s_gold_q != %s_gate_q) $display(\"MISMATCH at %%1t: %s_gold_q=%%b, %s_gate_q=%%b\", $time, %s_gold_q, %s_gate_q);" %
|
||||||
|
(modname, modname, modname, modname, modname, modname), file=f)
|
||||||
|
print(" end", file=f)
|
||||||
|
print(" endtask", file=f)
|
||||||
|
print("endmodule", file=f)
|
||||||
|
|
||||||
|
diamond_models = "/usr/local/diamond/3.10_x64/cae_library/simulation/verilog/ecp5u"
|
||||||
|
subprocess.call(["iverilog", "-s", "testbench", "-o", "work_ff/testbench", "-Dmixed_hdl", "-DNO_INCLUDES", "-y", diamond_models, "work_ff/cells_ff_gate.v", "../cells_sim.v", "work_ff/testbench.v"])
|
||||||
|
subprocess.call(["vvp", "work_ff/testbench"])
|
|
@ -3,11 +3,11 @@
|
||||||
# NB: Inputs/Outputs must be ordered alphabetically
|
# NB: Inputs/Outputs must be ordered alphabetically
|
||||||
# (with exceptions for carry in/out)
|
# (with exceptions for carry in/out)
|
||||||
|
|
||||||
# Inputs: A B CI
|
# Inputs: A B I0 I3 CI
|
||||||
# Outputs: O CO
|
# Outputs: O CO
|
||||||
# (NB: carry chain input/output must be last
|
# (NB: carry chain input/output must be last
|
||||||
# input/output and have been moved there
|
# input/output and have been moved there
|
||||||
# overriding the alphabetical ordering)
|
# overriding the alphabetical ordering)
|
||||||
$__ICE40_FULL_ADDER 1 1 3 2
|
$__ICE40_CARRY_WRAPPER 1 1 5 2
|
||||||
400 379 316
|
400 379 449 316 316
|
||||||
259 231 126
|
259 231 - - 126
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
# NB: Inputs/Outputs must be ordered alphabetically
|
# NB: Inputs/Outputs must be ordered alphabetically
|
||||||
# (with exceptions for carry in/out)
|
# (with exceptions for carry in/out)
|
||||||
|
|
||||||
# Inputs: A B CI
|
# Inputs: A B I0 I3 CI
|
||||||
# Outputs: O CO
|
# Outputs: O CO
|
||||||
# (NB: carry chain input/output must be last
|
# (NB: carry chain input/output must be last
|
||||||
# input/output and have been moved there
|
# input/output and have been moved there
|
||||||
# overriding the alphabetical ordering)
|
# overriding the alphabetical ordering)
|
||||||
$__ICE40_FULL_ADDER 1 1 3 2
|
$__ICE40_CARRY_WRAPPER 1 1 5 2
|
||||||
589 558 465
|
589 558 661 465 465
|
||||||
675 609 186
|
675 609 - - 186
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
# NB: Inputs/Outputs must be ordered alphabetically
|
# NB: Inputs/Outputs must be ordered alphabetically
|
||||||
# (with exceptions for carry in/out)
|
# (with exceptions for carry in/out)
|
||||||
|
|
||||||
# Inputs: A B CI
|
# Inputs: A B I0 I3 CI
|
||||||
# Outputs: O CO
|
# Outputs: O CO
|
||||||
# (NB: carry chain input/output must be last
|
# (NB: carry chain input/output must be last
|
||||||
# input/output and have been moved there
|
# input/output and have been moved there
|
||||||
# overriding the alphabetical ordering)
|
# overriding the alphabetical ordering)
|
||||||
$__ICE40_FULL_ADDER 1 1 3 2
|
$__ICE40_CARRY_WRAPPER 1 1 5 2
|
||||||
1231 1205 874
|
1231 1205 1285 874 874
|
||||||
675 609 278
|
675 609 - - 278
|
||||||
|
|
|
@ -142,15 +142,16 @@ module SB_CARRY (output CO, input I0, I1, CI);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
(* abc_box_id = 1, lib_whitebox *)
|
(* abc_box_id = 1, lib_whitebox *)
|
||||||
module \$__ICE40_FULL_ADDER (
|
module \$__ICE40_CARRY_WRAPPER (
|
||||||
(* abc_carry *)
|
(* abc_carry *)
|
||||||
output CO,
|
output CO,
|
||||||
output O,
|
output O,
|
||||||
input A,
|
input A, B,
|
||||||
input B,
|
|
||||||
(* abc_carry *)
|
(* abc_carry *)
|
||||||
input CI
|
input CI,
|
||||||
|
input I0, I3
|
||||||
);
|
);
|
||||||
|
parameter LUT = 0;
|
||||||
SB_CARRY carry (
|
SB_CARRY carry (
|
||||||
.I0(A),
|
.I0(A),
|
||||||
.I1(B),
|
.I1(B),
|
||||||
|
@ -158,16 +159,12 @@ module \$__ICE40_FULL_ADDER (
|
||||||
.CO(CO)
|
.CO(CO)
|
||||||
);
|
);
|
||||||
SB_LUT4 #(
|
SB_LUT4 #(
|
||||||
// I0: 1010 1010 1010 1010
|
.LUT_INIT(LUT)
|
||||||
// I1: 1100 1100 1100 1100
|
|
||||||
// I2: 1111 0000 1111 0000
|
|
||||||
// I3: 1111 1111 0000 0000
|
|
||||||
.LUT_INIT(16'b 0110_1001_1001_0110)
|
|
||||||
) adder (
|
) adder (
|
||||||
.I0(1'b0),
|
.I0(I0),
|
||||||
.I1(A),
|
.I1(A),
|
||||||
.I2(B),
|
.I2(B),
|
||||||
.I3(CI),
|
.I3(I3),
|
||||||
.O(O)
|
.O(O)
|
||||||
);
|
);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -84,7 +84,7 @@ static void run_ice40_opts(Module *module)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell->type == "$__ICE40_FULL_ADDER")
|
if (cell->type == "$__ICE40_CARRY_WRAPPER")
|
||||||
{
|
{
|
||||||
SigSpec non_const_inputs, replacement_output;
|
SigSpec non_const_inputs, replacement_output;
|
||||||
int count_zeros = 0, count_ones = 0;
|
int count_zeros = 0, count_ones = 0;
|
||||||
|
@ -114,16 +114,17 @@ static void run_ice40_opts(Module *module)
|
||||||
optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
|
optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
|
||||||
module->connect(cell->getPort("\\CO")[0], replacement_output);
|
module->connect(cell->getPort("\\CO")[0], replacement_output);
|
||||||
module->design->scratchpad_set_bool("opt.did_something", true);
|
module->design->scratchpad_set_bool("opt.did_something", true);
|
||||||
log("Optimized $__ICE40_FULL_ADDER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n",
|
log("Optimized $__ICE40_CARRY_WRAPPER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n",
|
||||||
log_id(module), log_id(cell), log_signal(replacement_output));
|
log_id(module), log_id(cell), log_signal(replacement_output));
|
||||||
cell->type = "$lut";
|
cell->type = "$lut";
|
||||||
cell->setPort("\\A", { State::S0, inbit[0], inbit[1], inbit[2] });
|
cell->setPort("\\A", { cell->getPort("\\I0"), inbit[0], inbit[1], cell->getPort("\\I3") });
|
||||||
cell->setPort("\\Y", cell->getPort("\\O"));
|
cell->setPort("\\Y", cell->getPort("\\O"));
|
||||||
cell->unsetPort("\\B");
|
cell->unsetPort("\\B");
|
||||||
cell->unsetPort("\\CI");
|
cell->unsetPort("\\CI");
|
||||||
|
cell->unsetPort("\\I0");
|
||||||
|
cell->unsetPort("\\I3");
|
||||||
cell->unsetPort("\\CO");
|
cell->unsetPort("\\CO");
|
||||||
cell->unsetPort("\\O");
|
cell->unsetPort("\\O");
|
||||||
cell->setParam("\\LUT", RTLIL::Const::from_string("0110100110010110"));
|
|
||||||
cell->setParam("\\WIDTH", 4);
|
cell->setParam("\\WIDTH", 4);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -303,9 +303,8 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
if (widemux > 0 || help_mode)
|
if (widemux > 0 || help_mode)
|
||||||
run("muxpack", " ('-widemux' only)");
|
run("muxpack", " ('-widemux' only)");
|
||||||
|
|
||||||
// shregmap -tech xilinx can cope with $shiftx and $mux
|
// xilinx_srl looks for $shiftx cells for identifying variable-length
|
||||||
// cells for identifying variable-length shift registers,
|
// shift registers, so attempt to convert $pmux-es to this
|
||||||
// so attempt to convert $pmux-es to the former
|
|
||||||
// Also: wide multiplexer inference benefits from this too
|
// Also: wide multiplexer inference benefits from this too
|
||||||
if (!(nosrl && widemux == 0) || help_mode) {
|
if (!(nosrl && widemux == 0) || help_mode) {
|
||||||
run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')");
|
run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')");
|
||||||
|
@ -387,13 +386,8 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
}
|
}
|
||||||
run("opt -full");
|
run("opt -full");
|
||||||
|
|
||||||
if (!nosrl || help_mode) {
|
if (!nosrl || help_mode)
|
||||||
// shregmap operates on bit-level flops, not word-level,
|
run("xilinx_srl -variable -minlen 3", "(skip if '-nosrl')");
|
||||||
// so break those down here
|
|
||||||
run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')");
|
|
||||||
// shregmap with '-tech xilinx' infers variable length shift regs
|
|
||||||
run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string techmap_args = " -map +/techmap.v";
|
std::string techmap_args = " -map +/techmap.v";
|
||||||
if (help_mode)
|
if (help_mode)
|
||||||
|
@ -421,6 +415,14 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
run("clean");
|
run("clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_label("map_ffs")) {
|
||||||
|
if (abc9 || help_mode) {
|
||||||
|
run("techmap -map +/xilinx/ff_map.v", "('-abc9' only)");
|
||||||
|
run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
|
||||||
|
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT", "('-abc9' only)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (check_label("map_luts")) {
|
if (check_label("map_luts")) {
|
||||||
run("opt_expr -mux_undef");
|
run("opt_expr -mux_undef");
|
||||||
if (flatten_before_abc)
|
if (flatten_before_abc)
|
||||||
|
@ -446,10 +448,17 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
// This shregmap call infers fixed length shift registers after abc
|
// This shregmap call infers fixed length shift registers after abc
|
||||||
// has performed any necessary retiming
|
// has performed any necessary retiming
|
||||||
if (!nosrl || help_mode)
|
if (!nosrl || help_mode)
|
||||||
run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
|
run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
|
||||||
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
|
|
||||||
run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
|
std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
|
||||||
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
|
if (help_mode)
|
||||||
|
techmap_args += " [-map +/xilinx/ff_map.v]";
|
||||||
|
else if (!abc9)
|
||||||
|
techmap_args += " -map +/xilinx/ff_map.v";
|
||||||
|
run("techmap " + techmap_args);
|
||||||
|
if (!abc9)
|
||||||
|
run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
|
||||||
|
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT", "(without '-abc9' only)");
|
||||||
run("clean");
|
run("clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.log
|
||||||
|
/run-test.mk
|
||||||
|
+*_synth.v
|
||||||
|
+*_testbench
|
|
@ -0,0 +1,13 @@
|
||||||
|
module top
|
||||||
|
(
|
||||||
|
input [3:0] x,
|
||||||
|
input [3:0] y,
|
||||||
|
|
||||||
|
output [3:0] A,
|
||||||
|
output [3:0] B
|
||||||
|
);
|
||||||
|
|
||||||
|
assign A = x + y;
|
||||||
|
assign B = x - y;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,9 @@
|
||||||
|
read_verilog add_sub.v
|
||||||
|
hierarchy -top top
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 11 t:SB_LUT4
|
||||||
|
select -assert-count 6 t:SB_CARRY
|
||||||
|
select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
module adff
|
||||||
|
( input d, clk, clr, output reg q );
|
||||||
|
initial begin
|
||||||
|
q = 0;
|
||||||
|
end
|
||||||
|
always @( posedge clk, posedge clr )
|
||||||
|
if ( clr )
|
||||||
|
q <= 1'b0;
|
||||||
|
else
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module adffn
|
||||||
|
( input d, clk, clr, output reg q );
|
||||||
|
initial begin
|
||||||
|
q = 0;
|
||||||
|
end
|
||||||
|
always @( posedge clk, negedge clr )
|
||||||
|
if ( !clr )
|
||||||
|
q <= 1'b0;
|
||||||
|
else
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module dffsr
|
||||||
|
( input d, clk, pre, clr, output reg q );
|
||||||
|
initial begin
|
||||||
|
q = 0;
|
||||||
|
end
|
||||||
|
always @( posedge clk, posedge pre, posedge clr )
|
||||||
|
if ( clr )
|
||||||
|
q <= 1'b0;
|
||||||
|
else if ( pre )
|
||||||
|
q <= 1'b1;
|
||||||
|
else
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ndffnsnr
|
||||||
|
( input d, clk, pre, clr, output reg q );
|
||||||
|
initial begin
|
||||||
|
q = 0;
|
||||||
|
end
|
||||||
|
always @( negedge clk, negedge pre, negedge clr )
|
||||||
|
if ( !clr )
|
||||||
|
q <= 1'b0;
|
||||||
|
else if ( !pre )
|
||||||
|
q <= 1'b1;
|
||||||
|
else
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top (
|
||||||
|
input clk,
|
||||||
|
input clr,
|
||||||
|
input pre,
|
||||||
|
input a,
|
||||||
|
output b,b1,b2,b3
|
||||||
|
);
|
||||||
|
|
||||||
|
dffsr u_dffsr (
|
||||||
|
.clk (clk ),
|
||||||
|
.clr (clr),
|
||||||
|
.pre (pre),
|
||||||
|
.d (a ),
|
||||||
|
.q (b )
|
||||||
|
);
|
||||||
|
|
||||||
|
ndffnsnr u_ndffnsnr (
|
||||||
|
.clk (clk ),
|
||||||
|
.clr (clr),
|
||||||
|
.pre (pre),
|
||||||
|
.d (a ),
|
||||||
|
.q (b1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
adff u_adff (
|
||||||
|
.clk (clk ),
|
||||||
|
.clr (clr),
|
||||||
|
.d (a ),
|
||||||
|
.q (b2 )
|
||||||
|
);
|
||||||
|
|
||||||
|
adffn u_adffn (
|
||||||
|
.clk (clk ),
|
||||||
|
.clr (clr),
|
||||||
|
.d (a ),
|
||||||
|
.q (b3 )
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,12 @@
|
||||||
|
read_verilog adffs.v
|
||||||
|
proc
|
||||||
|
async2sync # converts async flops to a 'sync' variant clocked by a 'super'-clock
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:SB_DFF
|
||||||
|
select -assert-count 1 t:SB_DFFN
|
||||||
|
select -assert-count 2 t:SB_DFFSR
|
||||||
|
select -assert-count 7 t:SB_LUT4
|
||||||
|
select -assert-none t:SB_DFF t:SB_DFFN t:SB_DFFSR t:SB_LUT4 %% t:* %D
|
|
@ -0,0 +1,19 @@
|
||||||
|
module top (
|
||||||
|
input clock,
|
||||||
|
input [31:0] dinA, dinB,
|
||||||
|
input [2:0] opcode,
|
||||||
|
output reg [31:0] dout
|
||||||
|
);
|
||||||
|
always @(posedge clock) begin
|
||||||
|
case (opcode)
|
||||||
|
0: dout <= dinA + dinB;
|
||||||
|
1: dout <= dinA - dinB;
|
||||||
|
2: dout <= dinA >> dinB;
|
||||||
|
3: dout <= $signed(dinA) >>> dinB;
|
||||||
|
4: dout <= dinA << dinB;
|
||||||
|
5: dout <= dinA & dinB;
|
||||||
|
6: dout <= dinA | dinB;
|
||||||
|
7: dout <= dinA ^ dinB;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -0,0 +1,11 @@
|
||||||
|
read_verilog alu.v
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 62 t:SB_CARRY
|
||||||
|
select -assert-count 32 t:SB_DFF
|
||||||
|
select -assert-count 655 t:SB_LUT4
|
||||||
|
select -assert-none t:SB_CARRY t:SB_DFF t:SB_LUT4 %% t:* %D
|
|
@ -0,0 +1,17 @@
|
||||||
|
module top (
|
||||||
|
out,
|
||||||
|
clk,
|
||||||
|
reset
|
||||||
|
);
|
||||||
|
output [7:0] out;
|
||||||
|
input clk, reset;
|
||||||
|
reg [7:0] out;
|
||||||
|
|
||||||
|
always @(posedge clk, posedge reset)
|
||||||
|
if (reset) begin
|
||||||
|
out <= 8'b0 ;
|
||||||
|
end else
|
||||||
|
out <= out + 1;
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,11 @@
|
||||||
|
read_verilog counter.v
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
flatten
|
||||||
|
equiv_opt -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 6 t:SB_CARRY
|
||||||
|
select -assert-count 8 t:SB_DFFR
|
||||||
|
select -assert-count 8 t:SB_LUT4
|
||||||
|
select -assert-none t:SB_CARRY t:SB_DFFR t:SB_LUT4 %% t:* %D
|
|
@ -0,0 +1,37 @@
|
||||||
|
module dff
|
||||||
|
( input d, clk, output reg q );
|
||||||
|
always @( posedge clk )
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module dffe
|
||||||
|
( input d, clk, en, output reg q );
|
||||||
|
initial begin
|
||||||
|
q = 0;
|
||||||
|
end
|
||||||
|
always @( posedge clk )
|
||||||
|
if ( en )
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top (
|
||||||
|
input clk,
|
||||||
|
input en,
|
||||||
|
input a,
|
||||||
|
output b,b1,
|
||||||
|
);
|
||||||
|
|
||||||
|
dff u_dff (
|
||||||
|
.clk (clk ),
|
||||||
|
.d (a ),
|
||||||
|
.q (b )
|
||||||
|
);
|
||||||
|
|
||||||
|
dffe u_ndffe (
|
||||||
|
.clk (clk ),
|
||||||
|
.en (en),
|
||||||
|
.d (a ),
|
||||||
|
.q (b1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,10 @@
|
||||||
|
read_verilog dffs.v
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:SB_DFF
|
||||||
|
select -assert-count 1 t:SB_DFFE
|
||||||
|
select -assert-none t:SB_DFF t:SB_DFFE %% t:* %D
|
|
@ -0,0 +1,13 @@
|
||||||
|
module top
|
||||||
|
(
|
||||||
|
input [3:0] x,
|
||||||
|
input [3:0] y,
|
||||||
|
|
||||||
|
output [3:0] A,
|
||||||
|
output [3:0] B
|
||||||
|
);
|
||||||
|
|
||||||
|
assign A = x % y;
|
||||||
|
assign B = x / y;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,9 @@
|
||||||
|
read_verilog div_mod.v
|
||||||
|
hierarchy -top top
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 62 t:SB_LUT4
|
||||||
|
select -assert-count 41 t:SB_CARRY
|
||||||
|
select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 72].
|
||||||
|
*/
|
||||||
|
module top (din, write_en, waddr, wclk, raddr, rclk, dout);
|
||||||
|
parameter addr_width = 8;
|
||||||
|
parameter data_width = 8;
|
||||||
|
input [addr_width-1:0] waddr, raddr;
|
||||||
|
input [data_width-1:0] din;
|
||||||
|
input write_en, wclk, rclk;
|
||||||
|
output [data_width-1:0] dout;
|
||||||
|
reg [data_width-1:0] dout;
|
||||||
|
reg [data_width-1:0] mem [(1<<addr_width)-1:0]
|
||||||
|
/* synthesis syn_ramstyle = "no_rw_check" */ ;
|
||||||
|
always @(posedge wclk) // Write memory.
|
||||||
|
begin
|
||||||
|
if (write_en)
|
||||||
|
mem[waddr] <= din; // Using write address bus.
|
||||||
|
end
|
||||||
|
always @(posedge rclk) // Read memory.
|
||||||
|
begin
|
||||||
|
dout <= mem[raddr]; // Using read address bus.
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -0,0 +1,15 @@
|
||||||
|
read_verilog dpram.v
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
memory -nomap
|
||||||
|
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
|
||||||
|
memory
|
||||||
|
opt -full
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
|
||||||
|
|
||||||
|
design -load postopt
|
||||||
|
cd top
|
||||||
|
select -assert-count 1 t:SB_RAM40_4K
|
||||||
|
select -assert-none t:SB_RAM40_4K %% t:* %D
|
|
@ -0,0 +1,73 @@
|
||||||
|
module fsm (
|
||||||
|
clock,
|
||||||
|
reset,
|
||||||
|
req_0,
|
||||||
|
req_1,
|
||||||
|
gnt_0,
|
||||||
|
gnt_1
|
||||||
|
);
|
||||||
|
input clock,reset,req_0,req_1;
|
||||||
|
output gnt_0,gnt_1;
|
||||||
|
wire clock,reset,req_0,req_1;
|
||||||
|
reg gnt_0,gnt_1;
|
||||||
|
|
||||||
|
parameter SIZE = 3 ;
|
||||||
|
parameter IDLE = 3'b001,GNT0 = 3'b010,GNT1 = 3'b100,GNT2 = 3'b101 ;
|
||||||
|
|
||||||
|
reg [SIZE-1:0] state;
|
||||||
|
reg [SIZE-1:0] next_state;
|
||||||
|
|
||||||
|
always @ (posedge clock)
|
||||||
|
begin : FSM
|
||||||
|
if (reset == 1'b1) begin
|
||||||
|
state <= #1 IDLE;
|
||||||
|
gnt_0 <= 0;
|
||||||
|
gnt_1 <= 0;
|
||||||
|
end else
|
||||||
|
case(state)
|
||||||
|
IDLE : if (req_0 == 1'b1) begin
|
||||||
|
state <= #1 GNT0;
|
||||||
|
gnt_0 <= 1;
|
||||||
|
end else if (req_1 == 1'b1) begin
|
||||||
|
gnt_1 <= 1;
|
||||||
|
state <= #1 GNT0;
|
||||||
|
end else begin
|
||||||
|
state <= #1 IDLE;
|
||||||
|
end
|
||||||
|
GNT0 : if (req_0 == 1'b1) begin
|
||||||
|
state <= #1 GNT0;
|
||||||
|
end else begin
|
||||||
|
gnt_0 <= 0;
|
||||||
|
state <= #1 IDLE;
|
||||||
|
end
|
||||||
|
GNT1 : if (req_1 == 1'b1) begin
|
||||||
|
state <= #1 GNT2;
|
||||||
|
gnt_1 <= req_0;
|
||||||
|
end
|
||||||
|
GNT2 : if (req_0 == 1'b1) begin
|
||||||
|
state <= #1 GNT1;
|
||||||
|
gnt_1 <= req_1;
|
||||||
|
end
|
||||||
|
default : state <= #1 IDLE;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top (
|
||||||
|
input clk,
|
||||||
|
input rst,
|
||||||
|
input a,
|
||||||
|
input b,
|
||||||
|
output g0,
|
||||||
|
output g1
|
||||||
|
);
|
||||||
|
|
||||||
|
fsm u_fsm ( .clock(clk),
|
||||||
|
.reset(rst),
|
||||||
|
.req_0(a),
|
||||||
|
.req_1(b),
|
||||||
|
.gnt_0(g0),
|
||||||
|
.gnt_1(g1));
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,13 @@
|
||||||
|
read_verilog fsm.v
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
|
||||||
|
select -assert-count 2 t:SB_DFFESR
|
||||||
|
select -assert-count 2 t:SB_DFFSR
|
||||||
|
select -assert-count 1 t:SB_DFFSS
|
||||||
|
select -assert-count 13 t:SB_LUT4
|
||||||
|
select -assert-none t:SB_DFFESR t:SB_DFFSR t:SB_DFFSS t:SB_LUT4 %% t:* %D
|
|
@ -0,0 +1,26 @@
|
||||||
|
read_verilog -icells -formal <<EOT
|
||||||
|
module top(input CI, I0, output [1:0] CO, output O);
|
||||||
|
wire A = 1'b0, B = 1'b0;
|
||||||
|
\$__ICE40_CARRY_WRAPPER #(
|
||||||
|
// A[0]: 1010 1010 1010 1010
|
||||||
|
// A[1]: 1100 1100 1100 1100
|
||||||
|
// A[2]: 1111 0000 1111 0000
|
||||||
|
// A[3]: 1111 1111 0000 0000
|
||||||
|
.LUT(~16'b 0110_1001_1001_0110)
|
||||||
|
) u0 (
|
||||||
|
.A(A),
|
||||||
|
.B(B),
|
||||||
|
.CI(CI),
|
||||||
|
.I0(I0),
|
||||||
|
.I3(CI),
|
||||||
|
.CO(CO[0]),
|
||||||
|
.O(O)
|
||||||
|
);
|
||||||
|
SB_CARRY u1 (.I0(~A), .I1(~B), .CI(CI), .CO(CO[1]));
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
equiv_opt -assert -map +/ice40/cells_map.v -map +/ice40/cells_sim.v ice40_opt
|
||||||
|
design -load postopt
|
||||||
|
select -assert-count 1 t:*
|
||||||
|
select -assert-count 1 t:$lut
|
|
@ -0,0 +1,58 @@
|
||||||
|
module latchp
|
||||||
|
( input d, clk, en, output reg q );
|
||||||
|
always @*
|
||||||
|
if ( en )
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module latchn
|
||||||
|
( input d, clk, en, output reg q );
|
||||||
|
always @*
|
||||||
|
if ( !en )
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module latchsr
|
||||||
|
( input d, clk, en, clr, pre, output reg q );
|
||||||
|
always @*
|
||||||
|
if ( clr )
|
||||||
|
q <= 1'b0;
|
||||||
|
else if ( pre )
|
||||||
|
q <= 1'b1;
|
||||||
|
else if ( en )
|
||||||
|
q <= d;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module top (
|
||||||
|
input clk,
|
||||||
|
input clr,
|
||||||
|
input pre,
|
||||||
|
input a,
|
||||||
|
output b,b1,b2
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
latchp u_latchp (
|
||||||
|
.en (clk ),
|
||||||
|
.d (a ),
|
||||||
|
.q (b )
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
latchn u_latchn (
|
||||||
|
.en (clk ),
|
||||||
|
.d (a ),
|
||||||
|
.q (b1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
latchsr u_latchsr (
|
||||||
|
.en (clk ),
|
||||||
|
.clr (clr),
|
||||||
|
.pre (pre),
|
||||||
|
.d (a ),
|
||||||
|
.q (b2 )
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,15 @@
|
||||||
|
read_verilog latches.v
|
||||||
|
design -save read
|
||||||
|
|
||||||
|
proc
|
||||||
|
async2sync # converts latches to a 'sync' variant clocked by a 'super'-clock
|
||||||
|
flatten
|
||||||
|
synth_ice40
|
||||||
|
equiv_opt -assert -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 read
|
||||||
|
synth_ice40
|
||||||
|
cd top
|
||||||
|
select -assert-count 4 t:SB_LUT4
|
||||||
|
select -assert-none t:SB_LUT4 %% t:* %D
|
|
@ -0,0 +1,18 @@
|
||||||
|
module top
|
||||||
|
(
|
||||||
|
input [0:7] in,
|
||||||
|
output B1,B2,B3,B4,B5,B6,B7,B8,B9,B10
|
||||||
|
);
|
||||||
|
|
||||||
|
assign B1 = in[0] & in[1];
|
||||||
|
assign B2 = in[0] | in[1];
|
||||||
|
assign B3 = in[0] ~& in[1];
|
||||||
|
assign B4 = in[0] ~| in[1];
|
||||||
|
assign B5 = in[0] ^ in[1];
|
||||||
|
assign B6 = in[0] ~^ in[1];
|
||||||
|
assign B7 = ~in[0];
|
||||||
|
assign B8 = in[0];
|
||||||
|
assign B9 = in[0:1] && in [2:3];
|
||||||
|
assign B10 = in[0:1] || in [2:3];
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,7 @@
|
||||||
|
read_verilog logic.v
|
||||||
|
hierarchy -top top
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 9 t:SB_LUT4
|
||||||
|
select -assert-none t:SB_LUT4 %% t:* %D
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 77].
|
||||||
|
*/
|
||||||
|
module top(clk,a,b,c,set);
|
||||||
|
parameter A_WIDTH = 6 /*4*/;
|
||||||
|
parameter B_WIDTH = 6 /*3*/;
|
||||||
|
input set;
|
||||||
|
input clk;
|
||||||
|
input signed [(A_WIDTH - 1):0] a;
|
||||||
|
input signed [(B_WIDTH - 1):0] b;
|
||||||
|
output signed [(A_WIDTH + B_WIDTH - 1):0] c;
|
||||||
|
reg [(A_WIDTH + B_WIDTH - 1):0] reg_tmp_c;
|
||||||
|
assign c = reg_tmp_c;
|
||||||
|
always @(posedge clk)
|
||||||
|
begin
|
||||||
|
if(set)
|
||||||
|
begin
|
||||||
|
reg_tmp_c <= 0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
reg_tmp_c <= a * b + c;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -0,0 +1,13 @@
|
||||||
|
read_verilog macc.v
|
||||||
|
proc
|
||||||
|
hierarchy -top top
|
||||||
|
#equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
|
||||||
|
|
||||||
|
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40 -dsp
|
||||||
|
async2sync
|
||||||
|
equiv_opt -run prove: -assert null
|
||||||
|
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:SB_MAC16
|
||||||
|
select -assert-none t:SB_MAC16 %% t:* %D
|
|
@ -0,0 +1,21 @@
|
||||||
|
module top
|
||||||
|
(
|
||||||
|
input [7:0] data_a,
|
||||||
|
input [6:1] addr_a,
|
||||||
|
input we_a, clk,
|
||||||
|
output reg [7:0] q_a
|
||||||
|
);
|
||||||
|
// Declare the RAM variable
|
||||||
|
reg [7:0] ram[63:0];
|
||||||
|
|
||||||
|
// Port A
|
||||||
|
always @ (posedge clk)
|
||||||
|
begin
|
||||||
|
if (we_a)
|
||||||
|
begin
|
||||||
|
ram[addr_a] <= data_a;
|
||||||
|
q_a <= data_a;
|
||||||
|
end
|
||||||
|
q_a <= ram[addr_a];
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -0,0 +1,15 @@
|
||||||
|
read_verilog memory.v
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
memory -nomap
|
||||||
|
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
|
||||||
|
memory
|
||||||
|
opt -full
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
|
||||||
|
|
||||||
|
design -load postopt
|
||||||
|
cd top
|
||||||
|
select -assert-count 1 t:SB_RAM40_4K
|
||||||
|
select -assert-none t:SB_RAM40_4K %% t:* %D
|
|
@ -0,0 +1,11 @@
|
||||||
|
module top
|
||||||
|
(
|
||||||
|
input [5:0] x,
|
||||||
|
input [5:0] y,
|
||||||
|
|
||||||
|
output [11:0] A,
|
||||||
|
);
|
||||||
|
|
||||||
|
assign A = x * y;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,7 @@
|
||||||
|
read_verilog mul.v
|
||||||
|
hierarchy -top top
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:SB_MAC16
|
||||||
|
select -assert-none t:SB_MAC16 %% t:* %D
|
|
@ -0,0 +1,100 @@
|
||||||
|
module mux2 (S,A,B,Y);
|
||||||
|
input S;
|
||||||
|
input A,B;
|
||||||
|
output reg Y;
|
||||||
|
|
||||||
|
always @(*)
|
||||||
|
Y = (S)? B : A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux4 ( S, D, Y );
|
||||||
|
|
||||||
|
input[1:0] S;
|
||||||
|
input[3:0] D;
|
||||||
|
output Y;
|
||||||
|
|
||||||
|
reg Y;
|
||||||
|
wire[1:0] S;
|
||||||
|
wire[3:0] D;
|
||||||
|
|
||||||
|
always @*
|
||||||
|
begin
|
||||||
|
case( S )
|
||||||
|
0 : Y = D[0];
|
||||||
|
1 : Y = D[1];
|
||||||
|
2 : Y = D[2];
|
||||||
|
3 : Y = D[3];
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux8 ( S, D, Y );
|
||||||
|
|
||||||
|
input[2:0] S;
|
||||||
|
input[7:0] D;
|
||||||
|
output Y;
|
||||||
|
|
||||||
|
reg Y;
|
||||||
|
wire[2:0] S;
|
||||||
|
wire[7:0] D;
|
||||||
|
|
||||||
|
always @*
|
||||||
|
begin
|
||||||
|
case( S )
|
||||||
|
0 : Y = D[0];
|
||||||
|
1 : Y = D[1];
|
||||||
|
2 : Y = D[2];
|
||||||
|
3 : Y = D[3];
|
||||||
|
4 : Y = D[4];
|
||||||
|
5 : Y = D[5];
|
||||||
|
6 : Y = D[6];
|
||||||
|
7 : Y = D[7];
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mux16 (D, S, Y);
|
||||||
|
input [15:0] D;
|
||||||
|
input [3:0] S;
|
||||||
|
output Y;
|
||||||
|
|
||||||
|
assign Y = D[S];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module top (
|
||||||
|
input [3:0] S,
|
||||||
|
input [15:0] D,
|
||||||
|
output M2,M4,M8,M16
|
||||||
|
);
|
||||||
|
|
||||||
|
mux2 u_mux2 (
|
||||||
|
.S (S[0]),
|
||||||
|
.A (D[0]),
|
||||||
|
.B (D[1]),
|
||||||
|
.Y (M2)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
mux4 u_mux4 (
|
||||||
|
.S (S[1:0]),
|
||||||
|
.D (D[3:0]),
|
||||||
|
.Y (M4)
|
||||||
|
);
|
||||||
|
|
||||||
|
mux8 u_mux8 (
|
||||||
|
.S (S[2:0]),
|
||||||
|
.D (D[7:0]),
|
||||||
|
.Y (M8)
|
||||||
|
);
|
||||||
|
|
||||||
|
mux16 u_mux16 (
|
||||||
|
.S (S[3:0]),
|
||||||
|
.D (D[15:0]),
|
||||||
|
.Y (M16)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,8 @@
|
||||||
|
read_verilog mux.v
|
||||||
|
proc
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 19 t:SB_LUT4
|
||||||
|
select -assert-none t:SB_LUT4 %% t:* %D
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 74].
|
||||||
|
*/
|
||||||
|
module top(data, addr);
|
||||||
|
output [3:0] data;
|
||||||
|
input [4:0] addr;
|
||||||
|
always @(addr) begin
|
||||||
|
case (addr)
|
||||||
|
0 : data = 'h4;
|
||||||
|
1 : data = 'h9;
|
||||||
|
2 : data = 'h1;
|
||||||
|
15 : data = 'h8;
|
||||||
|
16 : data = 'h1;
|
||||||
|
17 : data = 'h0;
|
||||||
|
default : data = 'h0;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -0,0 +1,8 @@
|
||||||
|
read_verilog rom.v
|
||||||
|
proc
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 5 t:SB_LUT4
|
||||||
|
select -assert-none t:SB_LUT4 %% t:* %D
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
{
|
||||||
|
echo "all::"
|
||||||
|
for x in *.ys; do
|
||||||
|
echo "all:: run-$x"
|
||||||
|
echo "run-$x:"
|
||||||
|
echo " @echo 'Running $x..'"
|
||||||
|
echo " @../../yosys -ql ${x%.ys}.log $x -w 'Yosys has only limited support for tri-state logic at the moment.'"
|
||||||
|
done
|
||||||
|
for s in *.sh; do
|
||||||
|
if [ "$s" != "run-test.sh" ]; then
|
||||||
|
echo "all:: run-$s"
|
||||||
|
echo "run-$s:"
|
||||||
|
echo " @echo 'Running $s..'"
|
||||||
|
echo " @bash $s"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
} > run-test.mk
|
||||||
|
exec ${MAKE:-make} -f run-test.mk
|
|
@ -0,0 +1,22 @@
|
||||||
|
module top (
|
||||||
|
out,
|
||||||
|
clk,
|
||||||
|
in
|
||||||
|
);
|
||||||
|
output [7:0] out;
|
||||||
|
input signed clk, in;
|
||||||
|
reg signed [7:0] out = 0;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
begin
|
||||||
|
`ifndef BUG
|
||||||
|
out <= out >> 1;
|
||||||
|
out[7] <= in;
|
||||||
|
`else
|
||||||
|
|
||||||
|
out <= out << 1;
|
||||||
|
out[7] <= in;
|
||||||
|
`endif
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,9 @@
|
||||||
|
read_verilog shifter.v
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 8 t:SB_DFF
|
||||||
|
select -assert-none t:SB_DFF %% t:* %D
|
|
@ -0,0 +1,23 @@
|
||||||
|
module tristate (en, i, o);
|
||||||
|
input en;
|
||||||
|
input i;
|
||||||
|
output o;
|
||||||
|
|
||||||
|
assign o = en ? i : 1'bz;
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module top (
|
||||||
|
input en,
|
||||||
|
input a,
|
||||||
|
output b
|
||||||
|
);
|
||||||
|
|
||||||
|
tristate u_tri (
|
||||||
|
.en (en ),
|
||||||
|
.i (a ),
|
||||||
|
.o (b )
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,9 @@
|
||||||
|
read_verilog tribuf.v
|
||||||
|
hierarchy -top top
|
||||||
|
proc
|
||||||
|
flatten
|
||||||
|
equiv_opt -assert -map +/ice40/cells_sim.v -map +/simcells.v synth_ice40 # equivalency check
|
||||||
|
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
|
||||||
|
cd top # Constrain all select calls below inside the top module
|
||||||
|
select -assert-count 1 t:$_TBUF_
|
||||||
|
select -assert-none t:$_TBUF_ %% t:* %D
|
|
@ -12,7 +12,7 @@ done
|
||||||
shift "$((OPTIND-1))"
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
# check for Icarus Verilog
|
# check for Icarus Verilog
|
||||||
if ! which iverilog > /dev/null ; then
|
if ! command -v iverilog > /dev/null ; then
|
||||||
echo "$0: Error: Icarus Verilog 'iverilog' not found."
|
echo "$0: Error: Icarus Verilog 'iverilog' not found."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -12,7 +12,7 @@ done
|
||||||
shift "$((OPTIND-1))"
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
# check for Icarus Verilog
|
# check for Icarus Verilog
|
||||||
if ! which iverilog > /dev/null ; then
|
if ! command -v iverilog > /dev/null ; then
|
||||||
echo "$0: Error: Icarus Verilog 'iverilog' not found."
|
echo "$0: Error: Icarus Verilog 'iverilog' not found."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -20,4 +20,10 @@ fi
|
||||||
cp ../simple/*.v .
|
cp ../simple/*.v .
|
||||||
cp ../simple/*.sv .
|
cp ../simple/*.sv .
|
||||||
DOLLAR='?'
|
DOLLAR='?'
|
||||||
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p 'hierarchy; synth -run coarse; opt -full; techmap; abc9 -lut 4 -box ../abc.box; stat; check -assert; select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
|
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p '\
|
||||||
|
hierarchy; \
|
||||||
|
synth -run coarse; \
|
||||||
|
opt -full; \
|
||||||
|
techmap; abc9 -lut 4 -box ../abc.box; \
|
||||||
|
check -assert; \
|
||||||
|
select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
|
||||||
|
|
|
@ -31,36 +31,3 @@ sat -verify -prove-asserts -show-ports -seq 5 miter
|
||||||
|
|
||||||
#design -load gate
|
#design -load gate
|
||||||
#stat
|
#stat
|
||||||
|
|
||||||
##########
|
|
||||||
|
|
||||||
design -load read
|
|
||||||
design -copy-to model $__XILINX_SHREG_
|
|
||||||
hierarchy -top shregmap_variable_test
|
|
||||||
prep
|
|
||||||
design -save gold
|
|
||||||
|
|
||||||
simplemap t:$dff t:$dffe
|
|
||||||
shregmap -tech xilinx
|
|
||||||
|
|
||||||
#stat
|
|
||||||
# show -width
|
|
||||||
# write_verilog -noexpr -norename
|
|
||||||
select -assert-count 1 t:$_DFF_P_
|
|
||||||
select -assert-count 2 t:$__XILINX_SHREG_
|
|
||||||
|
|
||||||
design -stash gate
|
|
||||||
|
|
||||||
design -import gold -as gold
|
|
||||||
design -import gate -as gate
|
|
||||||
design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
|
|
||||||
prep
|
|
||||||
|
|
||||||
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
|
||||||
sat -verify -prove-asserts -show-ports -seq 5 miter
|
|
||||||
|
|
||||||
# design -load gold
|
|
||||||
# stat
|
|
||||||
|
|
||||||
# design -load gate
|
|
||||||
# stat
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
/*.log
|
||||||
|
/*.out
|
||||||
|
/run-test.mk
|
|
@ -0,0 +1,57 @@
|
||||||
|
read_verilog -icells <<EOT
|
||||||
|
module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO);
|
||||||
|
parameter DEPTH = 1;
|
||||||
|
parameter [DEPTH-1:0] INIT = 0;
|
||||||
|
parameter CLKPOL = 1;
|
||||||
|
parameter ENPOL = 2;
|
||||||
|
|
||||||
|
wire pos_clk = C == CLKPOL;
|
||||||
|
reg pos_en;
|
||||||
|
always @(E)
|
||||||
|
if (ENPOL == 2) pos_en = 1'b1;
|
||||||
|
else pos_en = (E == ENPOL[0]);
|
||||||
|
|
||||||
|
reg [DEPTH-1:0] r;
|
||||||
|
always @(posedge pos_clk)
|
||||||
|
if (pos_en)
|
||||||
|
r <= {r[DEPTH-2:0], D};
|
||||||
|
|
||||||
|
assign Q = r[L];
|
||||||
|
assign SO = r[DEPTH-1];
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
read_verilog +/xilinx/cells_sim.v
|
||||||
|
proc
|
||||||
|
design -save model
|
||||||
|
|
||||||
|
test_pmgen -generate xilinx_srl.fixed
|
||||||
|
hierarchy -top pmtest_xilinx_srl_pm_fixed
|
||||||
|
flatten; opt_clean
|
||||||
|
|
||||||
|
design -save gold
|
||||||
|
xilinx_srl -fixed
|
||||||
|
techmap -autoproc -map %model
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -copy-from gold -as gold pmtest_xilinx_srl_pm_fixed
|
||||||
|
design -copy-from gate -as gate pmtest_xilinx_srl_pm_fixed
|
||||||
|
dff2dffe -unmap # sat does not support flops-with-enable yet
|
||||||
|
miter -equiv -flatten -make_assert gold gate miter
|
||||||
|
sat -set-init-zero -seq 5 -verify -prove-asserts miter
|
||||||
|
|
||||||
|
design -load model
|
||||||
|
|
||||||
|
test_pmgen -generate xilinx_srl.variable
|
||||||
|
hierarchy -top pmtest_xilinx_srl_pm_variable
|
||||||
|
flatten; opt_clean
|
||||||
|
|
||||||
|
design -save gold
|
||||||
|
xilinx_srl -variable
|
||||||
|
techmap -autoproc -map %model
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -copy-from gold -as gold pmtest_xilinx_srl_pm_variable
|
||||||
|
design -copy-from gate -as gate pmtest_xilinx_srl_pm_variable
|
||||||
|
dff2dffe -unmap # sat does not support flops-with-enable yet
|
||||||
|
miter -equiv -flatten -make_assert gold gate miter
|
||||||
|
sat -set-init-zero -seq 5 -verify -prove-asserts miter
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
{
|
||||||
|
echo "all::"
|
||||||
|
for x in *.ys; do
|
||||||
|
echo "all:: run-$x"
|
||||||
|
echo "run-$x:"
|
||||||
|
echo " @echo 'Running $x..'"
|
||||||
|
echo " @../../yosys -ql ${x%.ys}.log $x"
|
||||||
|
done
|
||||||
|
for s in *.sh; do
|
||||||
|
if [ "$s" != "run-test.sh" ]; then
|
||||||
|
echo "all:: run-$s"
|
||||||
|
echo "run-$s:"
|
||||||
|
echo " @echo 'Running $s..'"
|
||||||
|
echo " @bash $s"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
} > run-test.mk
|
||||||
|
exec ${MAKE:-make} -f run-test.mk
|
|
@ -0,0 +1,40 @@
|
||||||
|
module xilinx_srl_static_test(input i, clk, output [1:0] q);
|
||||||
|
reg head = 1'b0;
|
||||||
|
reg [3:0] shift1 = 4'b0000;
|
||||||
|
reg [3:0] shift2 = 4'b0000;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
head <= i;
|
||||||
|
shift1 <= {shift1[2:0], head};
|
||||||
|
shift2 <= {shift2[2:0], head};
|
||||||
|
end
|
||||||
|
|
||||||
|
assign q = {shift2[3], shift1[3]};
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module xilinx_srl_variable_test(input i, clk, input [1:0] l1, l2, output [1:0] q);
|
||||||
|
reg head = 1'b0;
|
||||||
|
reg [3:0] shift1 = 4'b0000;
|
||||||
|
reg [3:0] shift2 = 4'b0000;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
head <= i;
|
||||||
|
shift1 <= {shift1[2:0], head};
|
||||||
|
shift2 <= {shift2[2:0], head};
|
||||||
|
end
|
||||||
|
|
||||||
|
assign q = {shift2[l2], shift1[l1]};
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module $__XILINX_SHREG_(input C, D, E, input [1:0] L, output Q);
|
||||||
|
parameter CLKPOL = 1;
|
||||||
|
parameter ENPOL = 1;
|
||||||
|
parameter DEPTH = 1;
|
||||||
|
parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
|
||||||
|
reg [DEPTH-1:0] r = INIT;
|
||||||
|
wire clk = C ^ CLKPOL;
|
||||||
|
always @(posedge C)
|
||||||
|
if (E)
|
||||||
|
r <= { r[DEPTH-2:0], D };
|
||||||
|
assign Q = r[L];
|
||||||
|
endmodule
|
|
@ -0,0 +1,67 @@
|
||||||
|
read_verilog xilinx_srl.v
|
||||||
|
design -save read
|
||||||
|
|
||||||
|
design -copy-to model $__XILINX_SHREG_
|
||||||
|
hierarchy -top xilinx_srl_static_test
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
techmap
|
||||||
|
xilinx_srl -fixed
|
||||||
|
opt
|
||||||
|
|
||||||
|
# stat
|
||||||
|
# show -width
|
||||||
|
select -assert-count 1 t:$_DFF_P_
|
||||||
|
select -assert-count 2 t:$__XILINX_SHREG_
|
||||||
|
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
|
||||||
|
prep
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
dump gate
|
||||||
|
sat -verify -prove-asserts -show-ports -seq 5 miter
|
||||||
|
|
||||||
|
#design -load gold
|
||||||
|
#stat
|
||||||
|
|
||||||
|
#design -load gate
|
||||||
|
#stat
|
||||||
|
|
||||||
|
##########
|
||||||
|
|
||||||
|
design -load read
|
||||||
|
design -copy-to model $__XILINX_SHREG_
|
||||||
|
hierarchy -top xilinx_srl_variable_test
|
||||||
|
prep
|
||||||
|
design -save gold
|
||||||
|
|
||||||
|
xilinx_srl -variable
|
||||||
|
opt
|
||||||
|
|
||||||
|
#stat
|
||||||
|
# show -width
|
||||||
|
# write_verilog -noexpr -norename
|
||||||
|
select -assert-count 1 t:$dff
|
||||||
|
select -assert-count 1 t:$dff r:WIDTH=1 %i
|
||||||
|
select -assert-count 2 t:$__XILINX_SHREG_
|
||||||
|
|
||||||
|
design -stash gate
|
||||||
|
|
||||||
|
design -import gold -as gold
|
||||||
|
design -import gate -as gate
|
||||||
|
design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
|
||||||
|
prep
|
||||||
|
|
||||||
|
miter -equiv -flatten -make_assert -make_outputs gold gate miter
|
||||||
|
sat -verify -prove-asserts -show-ports -seq 5 miter
|
||||||
|
|
||||||
|
# design -load gold
|
||||||
|
# stat
|
||||||
|
|
||||||
|
# design -load gate
|
||||||
|
# stat
|
Loading…
Reference in New Issue