3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-13 04:28:18 +00:00

Merge branch 'xc7dsp' of github.com:YosysHQ/yosys into xc7dsp

This commit is contained in:
Eddie Hung 2019-08-30 09:50:20 -07:00
commit 295c18bd6b
70 changed files with 3088 additions and 552 deletions

View file

@ -6,3 +6,4 @@ brew "git"
brew "graphviz" brew "graphviz"
brew "pkg-config" brew "pkg-config"
brew "python3" brew "python3"
brew "tcl-tk"

123
CHANGELOG
View file

@ -12,7 +12,10 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added "synth_xilinx -abc9" (experimental) - Added "synth_xilinx -abc9" (experimental)
- Added "synth_ice40 -abc9" (experimental) - Added "synth_ice40 -abc9" (experimental)
- Added "synth -abc9" (experimental) - Added "synth -abc9" (experimental)
- Added "script -scriptwire - Added "script -scriptwire"
- Added "synth_xilinx -nocarry"
- Added "synth_xilinx -nowidelut"
- Added "synth_ecp5 -nowidelut"
- "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable) - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
- Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram) - Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram)
- Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram) - Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram)
@ -23,37 +26,135 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added automatic gzip compression (based on filename extension) for backends - Added automatic gzip compression (based on filename extension) for backends
- Improve attribute and parameter encoding in JSON to avoid ambiguities between - Improve attribute and parameter encoding in JSON to avoid ambiguities between
bit vectors and strings containing [01xz]* bit vectors and strings containing [01xz]*
- Added "clkbufmap" pass
- Added "synth_xilinx -family xc6s" for Spartan 6 support (experimental)
- Added "synth_xilinx -ise" (experimental)
- Added "synth_xilinx -iopad"
- "synth_xilinx" now automatically inserts clock buffers (add -noclkbuf to disable)
- Improvements in pmgen: subpattern and recursive matches - Improvements in pmgen: subpattern and recursive matches
- Added "opt_share" pass, run as part of "opt -full" - Added "opt_share" pass, run as part of "opt -full"
- 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
Yosys 0.8 .. Yosys 0.8-dev Yosys 0.8 .. Yosys 0.9
-------------------------- ----------------------
* Various * Various
- Added $changed support to read_verilog - Many bugfixes and small improvements
- Added support for SystemVerilog interfaces and modports
- Added "write_edif -attrprop" - Added "write_edif -attrprop"
- Added "ice40_unlut" pass
- Added "opt_lut" pass - Added "opt_lut" pass
- Added "synth_ice40 -relut"
- Added "synth_ice40 -noabc"
- Added "gate2lut.v" techmap rule - Added "gate2lut.v" techmap rule
- Added "rename -src" - Added "rename -src"
- Added "equiv_opt" pass - Added "equiv_opt" pass
- Added "shregmap -tech xilinx" - Added "flowmap" LUT mapping pass
- Added "rename -wire" to rename cells based on the wires they drive
- Added "bugpoint" for creating minimised testcases
- Added "write_edif -gndvccy"
- "write_verilog" to escape Verilog keywords
- Fixed sign handling of real constants
- "write_verilog" to write initial statement for initial flop state
- Added pmgen pattern matcher generator
- Fixed opt_rmdff handling of $_DFFSR_???_ and $_DLATCHSR_???_
- Added "setundef -params" to replace undefined cell parameters
- Renamed "yosys -D" to "yosys -U", added "yosys -D" to set Verilog defines
- Fixed handling of defparam when default_nettype is none
- Fixed "wreduce" flipflop handling
- Fixed FIRRTL to Verilog process instance subfield assignment
- Added "write_verilog -siminit"
- Several fixes and improvements for mem2reg memories
- Fixed handling of task output ports in clocked always blocks
- Improved handling of and-with-1 and or-with-0 in "opt_expr"
- Added "read_aiger" frontend - Added "read_aiger" frontend
- Added "mutate" pass
- Added "hdlname" attribute
- Added "rename -output"
- Added "read_ilang -lib"
- Improved "proc" full_case detection and handling
- Added "whitebox" and "lib_whitebox" attributes
- Added "read_verilog -nowb", "flatten -wb" and "wbflip"
- Added Python bindings and support for Python plug-ins
- Added "pmux2shiftx"
- Added log_debug framework for reduced default verbosity
- Improved "opt_expr" and "opt_clean" handling of (partially) undriven and/or unused wires
- Added "peepopt" peephole optimisation pass using pmgen
- Added approximate support for SystemVerilog "var" keyword
- Added parsing of "specify" blocks into $specrule and $specify[23]
- Added support for attributes on parameters and localparams
- Added support for parsing attributes on port connections
- Added "wreduce -keepdc"
- Added support for optimising $dffe and $_DFFE_* cells in "opt_rmdff"
- Added Verilog wand/wor wire type support
- Added support for elaboration system tasks
- Added "muxcover -mux{4,8,16}=<cost>" - Added "muxcover -mux{4,8,16}=<cost>"
- Added "muxcover -dmux=<cost>" - Added "muxcover -dmux=<cost>"
- Added "muxcover -nopartial" - Added "muxcover -nopartial"
- Added "muxpack" pass - Added "muxpack" pass
- Added "pmux2shiftx -norange" - Added "pmux2shiftx -norange"
- Added support for "~" in filename parsing
- Added "read_verilog -pwires" feature to turn parameters into wires
- Fixed sign extension of unsized constants with 'bx and 'bz MSB
- Fixed genvar to be a signed type
- Added support for attributes on case rules
- Added "upto" and "offset" to JSON frontend and backend
- Several liberty file parser improvements
- Fixed handling of more complex BRAM patterns
- Add "write_aiger -I -O -B"
* Formal Verification
- Added $changed support to read_verilog
- Added "read_verilog -noassert -noassume -assert-assumes"
- Added btor ops for $mul, $div, $mod and $concat
- Added yosys-smtbmc support for btor witnesses
- Added "supercover" pass
- Fixed $global_clock handling vs autowire
- Added $dffsr support to "async2sync"
- Added "fmcombine" pass
- Added memory init support in "write_btor"
- Added "cutpoint" pass
- Changed "ne" to "neq" in btor2 output
- Added support for SVA "final" keyword
- Added "fmcombine -initeq -anyeq"
- Added timescale and generated-by header to yosys-smtbmc vcd output
- Improved BTOR2 handling of undriven wires
* Verific support
- Enabled Verific flags vhdl_support_variable_slice and veri_elaborate_top_level_modules_having_interface_ports
- Improved support for asymmetric memories
- Added "verific -chparam"
- Fixed "verific -extnets" for more complex situations
- Added "read -verific" and "read -noverific"
- Added "hierarchy -chparam"
* New back-ends
- Added initial Anlogic support
- Added initial SmartFusion2 and IGLOO2 support
* ECP5 support
- Added "synth_ecp5 -nowidelut"
- Added BRAM inference support to "synth_ecp5"
- Added support for transforming Diamond IO and flipflop primitives
* iCE40 support
- Added "ice40_unlut" pass
- Added "synth_ice40 -relut"
- Added "synth_ice40 -noabc"
- Added "synth_ice40 -dffe_min_ce_use"
- Added DSP inference support using pmgen
- Added support for initialising BRAM primitives from a file
- Added iCE40 Ultra RGB LED driver cells
* Xilinx support
- Use "write_edif -pvector bra" for Xilinx EDIF files
- Fixes for VPR place and route support with "synth_xilinx"
- Added more cell simulation models
- Added "synth_xilinx -family"
- Added "stat -tech xilinx" to estimate logic cell usage
- Added "synth_xilinx -nocarry" - Added "synth_xilinx -nocarry"
- Added "synth_xilinx -nowidelut" - Added "synth_xilinx -nowidelut"
- Added "synth_ecp5 -nowidelut"
- "synth_xilinx" to now infer hard shift registers (-nosrl to disable) - "synth_xilinx" to now infer hard shift registers (-nosrl to disable)
- Fixed sign extension of unsized constants with 'bx and 'bz MSB - Added support for mapping RAM32X1D
Yosys 0.7 .. Yosys 0.8 Yosys 0.7 .. Yosys 0.8
---------------------- ----------------------

View file

@ -1,4 +1,4 @@
Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View file

@ -390,6 +390,7 @@ Finally run all tests with "make config-{clang,gcc,gcc-4.8}":
Release: Release:
- set YOSYS_VER to x.y.z in Makefile - set YOSYS_VER to x.y.z in Makefile
- remove "bumpversion" target from Makefile
- update version string in CHANGELOG - update version string in CHANGELOG
git commit -am "Yosys x.y.z" git commit -am "Yosys x.y.z"

View file

@ -91,8 +91,10 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup
ifneq ($(shell which brew),) ifneq ($(shell which brew),)
BREW_PREFIX := $(shell brew --prefix)/opt BREW_PREFIX := $(shell brew --prefix)/opt
$(info $$BREW_PREFIX is [${BREW_PREFIX}]) $(info $$BREW_PREFIX is [${BREW_PREFIX}])
ifeq ($(ENABLE_PYOSYS),1)
CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost
LDFLAGS += -L$(BREW_PREFIX)/boost/lib LDFLAGS += -L$(BREW_PREFIX)/boost/lib
endif
CXXFLAGS += -I$(BREW_PREFIX)/readline/include CXXFLAGS += -I$(BREW_PREFIX)/readline/include
LDFLAGS += -L$(BREW_PREFIX)/readline/lib LDFLAGS += -L$(BREW_PREFIX)/readline/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
@ -113,10 +115,13 @@ LDFLAGS += -rdynamic
LDLIBS += -lrt LDLIBS += -lrt
endif endif
YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; }) 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
bumpversion:
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 8a4c6e6.. | wc -l`/;" Makefile
# set 'ABCREV = default' to use abc/ as it is # set 'ABCREV = default' to use abc/ as it is
# #
# Note: If you do ABC development, make sure that 'abc' in this directory # Note: If you do ABC development, make sure that 'abc' in this directory

View file

@ -1,7 +1,7 @@
``` ```
yosys -- Yosys Open SYnthesis Suite yosys -- Yosys Open SYnthesis Suite
Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@ -69,11 +69,14 @@ prerequisites for building yosys:
graphviz xdot pkg-config python3 libboost-system-dev \ graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev
Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies: Similarily, on Mac OS X Homebrew can be used to install dependencies:
$ brew tap Homebrew/bundle && brew bundle $ brew tap Homebrew/bundle && brew bundle
or MacPorts:
$ sudo port install bison flex readline gawk libffi \ $ sudo port install bison flex readline gawk libffi \
git graphviz pkgconfig python36 boost zlib git graphviz pkgconfig python36 boost zlib tcl
On FreeBSD use the following command to install all prerequisites: On FreeBSD use the following command to install all prerequisites:
@ -329,6 +332,21 @@ Verilog Attributes and non-standard features
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
module to mark it as a clock buffer output, and thus prevent ``clkbufmap``
from inserting another clock buffer on a net driven by such output.
- The ``clkbuf_sink`` attribute can be set on an input port of a module to
request clock buffer insertion by the ``clkbufmap`` pass.
- The ``clkbuf_inhibit`` is the default attribute to set on a wire to prevent
automatic clock buffer insertion by ``clkbufmap``. This behaviour can be
overridden by providing a custom selection to ``clkbufmap``.
- The ``iopad_external_pin`` attribute on a blackbox module's port marks
it as the external-facing pin of an I/O pad, and prevents ``iopadmap``
from inserting another pad cell on it.
- 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

View file

@ -1,4 +1,3 @@
read_verilog example.v read_verilog example.v
synth_xilinx -top example -family xc6s synth_xilinx -top example -family xc6s -ise
iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I
write_edif -pvector bra example.edif write_edif -pvector bra example.edif

View file

@ -150,6 +150,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
reg->str = stringf("%s[%d]", node->str.c_str(), i); reg->str = stringf("%s[%d]", node->str.c_str(), i);
reg->is_reg = true; reg->is_reg = true;
reg->is_signed = node->is_signed; reg->is_signed = node->is_signed;
for (auto &it : node->attributes)
if (it.first != ID(mem2reg))
reg->attributes.emplace(it.first, it.second->clone());
reg->filename = node->filename;
reg->linenum = node->linenum;
children.push_back(reg); children.push_back(reg);
while (reg->simplify(true, false, false, 1, -1, false, false)) { } while (reg->simplify(true, false, false, 1, -1, false, false)) { }
} }

View file

@ -129,7 +129,7 @@ void yosys_banner()
log(" | |\n"); log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n"); log(" | |\n");
log(" | Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> |\n"); log(" | Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> |\n");
log(" | |\n"); log(" | |\n");
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
log(" | purpose with or without fee is hereby granted, provided that the above |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n");

View file

@ -508,23 +508,17 @@ class TupleTranslator(PythonDictTranslator):
#Generate c++ code to translate to a boost::python::tuple #Generate c++ code to translate to a boost::python::tuple
@classmethod @classmethod
def translate_cpp(c, varname, types, prefix, ref): def translate_cpp(c, varname, types, prefix, ref):
text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + varname + ".first, " + varname + ".second);" # if the tuple is a pair of SigSpecs (aka SigSig), then we need
return text # to call get_py_obj() on each item in the tuple
tmp_name = "tmp_" + str(Translator.tmp_cntr) if types[0].name in classnames:
Translator.tmp_cntr = Translator.tmp_cntr + 1 first_var = types[0].name + "::get_py_obj(" + varname + ".first)"
if ref:
text += prefix + "for(auto " + tmp_name + " : *" + varname + ")"
else: else:
text += prefix + "for(auto " + tmp_name + " : " + varname + ")" first_var = varname + ".first"
text += prefix + "{" if types[1].name in classnames:
if types[0].name.split(" ")[-1] in primitive_types or types[0].name in enum_names: second_var = types[1].name + "::get_py_obj(" + varname + ".second)"
text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");" else:
elif types[0].name in known_containers: second_var = varname + ".second"
text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[1].attr_type == attr_types.star) text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + first_var + ", " + second_var + ");"
text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "___tmp);"
elif types[0].name in classnames:
text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));"
text += prefix + "}"
return text return text
#Associate the Translators with their c++ type #Associate the Translators with their c++ type

View file

@ -532,10 +532,10 @@ struct EquivMakePass : public Pass {
log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str()); log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str());
if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes()) if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes())
log_cmd_error("Gold module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); log_cmd_error("Gold module contains memories or processes. Run 'memory' or 'proc' respectively.\n");
if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes()) if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes())
log_cmd_error("Gate module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); log_cmd_error("Gate module contains memories or processes. Run 'memory' or 'proc' respectively.\n");
worker.read_blacklists(); worker.read_blacklists();
worker.read_encfiles(); worker.read_encfiles();

View file

@ -369,7 +369,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (auto cell : module->cells()) for (auto cell : module->cells())
if (design->selected(module, cell) && cell->type[0] == '$') { if (design->selected(module, cell) && cell->type[0] == '$') {
if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) &&
cell->getPort(ID::A).size() == 1 && cell->getPort(ID::Y).size() == 1) GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1)
invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A)); invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A));
if (cell->type.in(ID($mux), ID($_MUX_)) && if (cell->type.in(ID($mux), ID($_MUX_)) &&
cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0)) cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0))
@ -740,12 +740,34 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt)))
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
else else
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort(ID::Y).size())); replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, GetSize(cell->getPort(ID::Y))));
goto next_cell; goto next_cell;
} }
} }
if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && cell->getPort(ID::Y).size() == 1 && if (cell->type.in(ID($shiftx), ID($shift))) {
SigSpec sig_a = assign_map(cell->getPort(ID::A));
int width;
bool trim_x = cell->type == ID($shiftx) || !keepdc;
bool trim_0 = cell->type == ID($shift);
for (width = GetSize(sig_a); width > 1; width--) {
if ((trim_x && sig_a[width-1] == State::Sx) ||
(trim_0 && sig_a[width-1] == State::S0))
continue;
break;
}
if (width < GetSize(sig_a)) {
cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str());
sig_a.remove(width, GetSize(sig_a)-width);
cell->setPort(ID::A, sig_a);
cell->setParam(ID(A_WIDTH), width);
did_something = true;
goto next_cell;
}
}
if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 &&
invert_map.count(assign_map(cell->getPort(ID::A))) != 0) { invert_map.count(assign_map(cell->getPort(ID::A))) != 0) {
cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A)))); replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A))));
@ -1142,7 +1164,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (mux_undef && cell->type.in(ID($mux), ID($pmux))) { if (mux_undef && cell->type.in(ID($mux), ID($pmux))) {
RTLIL::SigSpec new_a, new_b, new_s; RTLIL::SigSpec new_a, new_b, new_s;
int width = cell->getPort(ID::A).size(); int width = GetSize(cell->getPort(ID::A));
if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) || if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) ||
cell->getPort(ID(S)).is_fully_undef()) { cell->getPort(ID(S)).is_fully_undef()) {
cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str()); cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());

View file

@ -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/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h
$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) $(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h))
# -------------------------------------- # --------------------------------------
@ -23,7 +23,7 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
OBJS += passes/pmgen/xilinx_dsp.o OBJS += passes/pmgen/xilinx_dsp.o
passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp.h)) $(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
# -------------------------------------- # --------------------------------------

View file

@ -178,6 +178,45 @@ evaluates to `false`.
The `semioptional` statement marks matches that must match if at least one The `semioptional` statement marks matches that must match if at least one
matching cell exists, but if no matching cell exists it is set to `nullptr`. matching cell exists, but if no matching cell exists it is set to `nullptr`.
Slices and choices
------------------
Cell matches can contain "slices" and "choices". Slices can be used to
create matches for different sections of a cell. For example:
state <int> pmux_slice
match pmux
select pmux->type == $pmux
slice idx GetSize(port(pmux, \S))
index <SigBit> port(pmux, \S)[idx] === port(eq, \Y)
set pmux_slice idx
endmatch
The first argument to `slice` is the local variable name used to identify the
slice. The second argument is the number of slices that should be created for
this cell. The `set` statement can be used to copy that index into a state
variable so that later matches and/or code blocks can refer to it.
A similar mechanism is "choices", where a list of options is given as
second argument, and the matcher will iterate over those options:
state <SigSpec> foo bar
state <IdString> eq_ab eq_ba
match eq
select eq->type == $eq
choice <IdString> AB {\A, \B}
define <IdString> BA (AB == \A ? \B : \A)
index <SigSpec> port(eq, AB) === foo
index <SigSpec> port(eq, BA) === bar
set eq_ab AB
set eq_ba BA
generate
Notice how `define` can be used to define additional local variables similar
to the loop variables defined by `slice` and `choice`.
Additional code Additional code
--------------- ---------------
@ -326,7 +365,7 @@ test-case generation. For example:
match mul match mul
... ...
generate 10 generate 10 0
SigSpec Y = port(ff, \D); SigSpec Y = port(ff, \D);
SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2)); SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2)); SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
@ -335,8 +374,11 @@ test-case generation. For example:
The expression `rng(n)` returns a non-negative integer less than `n`. The expression `rng(n)` returns a non-negative integer less than `n`.
The argument to `generate` is the chance of this generate block being executed The first argument to `generate` is the chance of this generate block being
when the match block did not match anything, in percent. executed when the match block did not match anything, in percent.
The second argument to `generate` is the chance of this generate block being
executed when the match block did match something, in percent.
The special statement `finish` can be used within generate blocks to terminate The special statement `finish` can be used within generate blocks to terminate
the current pattern matcher run. the current pattern matcher run.

View file

@ -207,9 +207,10 @@ def process_pmgfile(f, filename):
state_types[current_pattern][line[1]] = "Cell*"; state_types[current_pattern][line[1]] = "Cell*";
block["if"] = list() block["if"] = list()
block["select"] = list() block["setup"] = list()
block["index"] = list() block["index"] = list()
block["filter"] = list() block["filter"] = list()
block["sets"] = list()
block["optional"] = False block["optional"] = False
block["semioptional"] = False block["semioptional"] = False
@ -228,7 +229,22 @@ def process_pmgfile(f, filename):
if a[0] == "select": if a[0] == "select":
b = l.lstrip()[6:] b = l.lstrip()[6:]
block["select"].append(rewrite_cpp(b.strip())) block["setup"].append(("select", rewrite_cpp(b.strip())))
continue
if a[0] == "slice":
m = re.match(r"^\s*slice\s+(\S+)\s+(.*?)\s*$", l)
block["setup"].append(("slice", m.group(1), rewrite_cpp(m.group(2))))
continue
if a[0] == "choice":
m = re.match(r"^\s*choice\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l)
block["setup"].append(("choice", m.group(1), m.group(2), rewrite_cpp(m.group(3))))
continue
if a[0] == "define":
m = re.match(r"^\s*define\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l)
block["setup"].append(("define", m.group(1), m.group(2), rewrite_cpp(m.group(3))))
continue continue
if a[0] == "index": if a[0] == "index":
@ -242,6 +258,11 @@ def process_pmgfile(f, filename):
block["filter"].append(rewrite_cpp(b.strip())) block["filter"].append(rewrite_cpp(b.strip()))
continue continue
if a[0] == "set":
m = re.match(r"^\s*set\s+(\S+)\s+(.*?)\s*$", l)
block["sets"].append((m.group(1), rewrite_cpp(m.group(2))))
continue
if a[0] == "optional": if a[0] == "optional":
block["optional"] = True block["optional"] = True
continue continue
@ -252,14 +273,16 @@ def process_pmgfile(f, filename):
if a[0] == "generate": if a[0] == "generate":
block["genargs"] = list([int(s) for s in a[1:]]) block["genargs"] = list([int(s) for s in a[1:]])
if len(block["genargs"]) == 0: block["genargs"].append(100)
if len(block["genargs"]) == 1: block["genargs"].append(0)
assert len(block["genargs"]) == 2
block["gencode"] = list() block["gencode"] = list()
assert len(block["genargs"]) < 2
while True: while True:
linenr += 1 linenr += 1
l = f.readline() l = f.readline()
assert l != "" assert l != ""
a = l.split() a = l.split()
if a[0] == "endmatch": break if len(a) == 1 and a[0] == "endmatch": break
block["gencode"].append(rewrite_cpp(l.rstrip())) block["gencode"].append(rewrite_cpp(l.rstrip()))
break break
@ -357,8 +380,17 @@ with open(outfile, "w") as f:
index_types = list() index_types = list()
for entry in block["index"]: for entry in block["index"]:
index_types.append(entry[0]) index_types.append(entry[0])
value_types = ["Cell*"]
for entry in block["setup"]:
if entry[0] == "slice":
value_types.append("int")
if entry[0] == "choice":
value_types.append(entry[1])
if entry[0] == "define":
value_types.append(entry[1])
print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f) print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f)
print(" dict<index_{}_key_type, vector<Cell*>> index_{};".format(index, index), file=f) print(" typedef std::tuple<{}> index_{}_value_type;".format(", ".join(value_types), index), file=f)
print(" dict<index_{}_key_type, vector<index_{}_value_type>> index_{};".format(index, index, index), file=f)
print(" dict<SigBit, pool<Cell*>> sigusers;", file=f) print(" dict<SigBit, pool<Cell*>> sigusers;", file=f)
print(" pool<Cell*> blacklist_cells;", file=f) print(" pool<Cell*> blacklist_cells;", file=f)
print(" pool<Cell*> autoremove_cells;", file=f) print(" pool<Cell*> autoremove_cells;", file=f)
@ -390,8 +422,6 @@ with open(outfile, "w") as f:
print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f) print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f)
print(" for (auto bit : sigmap(sig)) {", file=f) print(" for (auto bit : sigmap(sig)) {", file=f)
print(" if (bit.wire == nullptr) continue;", file=f) print(" if (bit.wire == nullptr) continue;", file=f)
print(" if (sigusers.count(bit) == 0 && bit.wire->port_id)", file=f)
print(" sigusers[bit].insert(nullptr);", file=f)
print(" sigusers[bit].insert(cell);", file=f) print(" sigusers[bit].insert(cell);", file=f)
print(" }", file=f) print(" }", file=f)
print(" }", file=f) print(" }", file=f)
@ -446,10 +476,11 @@ with open(outfile, "w") as f:
else: else:
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f) print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
current_pattern = None current_pattern = None
print(" for (auto cell : module->cells()) {", file=f) print(" for (auto port : module->ports)", file=f)
print(" add_siguser(module->wire(port), nullptr);", file=f)
print(" for (auto cell : module->cells())", file=f)
print(" for (auto &conn : cell->connections())", file=f) print(" for (auto &conn : cell->connections())", file=f)
print(" add_siguser(conn.second, cell);", file=f) print(" add_siguser(conn.second, cell);", file=f)
print(" }", file=f)
print(" for (auto cell : cells) {", file=f) print(" for (auto cell : cells) {", file=f)
for index in range(len(blocks)): for index in range(len(blocks)):
@ -457,12 +488,34 @@ with open(outfile, "w") as f:
if block["type"] == "match": if block["type"] == "match":
print(" do {", file=f) print(" do {", file=f)
print(" Cell *{} = cell;".format(block["cell"]), file=f) print(" Cell *{} = cell;".format(block["cell"]), file=f)
for expr in block["select"]: print(" index_{}_value_type value;".format(index), file=f)
print(" if (!({})) break;".format(expr), file=f) print(" std::get<0>(value) = cell;", file=f)
loopcnt = 0
valueidx = 1
for item in block["setup"]:
if item[0] == "select":
print(" if (!({})) continue;".format(item[1]), file=f)
if item[0] == "slice":
print(" int &{} = std::get<{}>(value);".format(item[1], valueidx), file=f)
print(" for ({} = 0; {} < {}; {}++) {{".format(item[1], item[1], item[2], item[1]), file=f)
valueidx += 1
loopcnt += 1
if item[0] == "choice":
print(" vector<{}> _pmg_choices_{} = {};".format(item[1], item[2], item[3]), file=f)
print(" for (const {} &{} : _pmg_choices_{}) {{".format(item[1], item[2], item[2]), file=f)
print(" std::get<{}>(value) = {};".format(valueidx, item[2]), file=f)
valueidx += 1
loopcnt += 1
if item[0] == "define":
print(" {} &{} = std::get<{}>(value);".format(item[1], item[2], valueidx), file=f)
print(" {} = {};".format(item[2], item[3]), file=f)
valueidx += 1
print(" index_{}_key_type key;".format(index), file=f) print(" index_{}_key_type key;".format(index), file=f)
for field, entry in enumerate(block["index"]): for field, entry in enumerate(block["index"]):
print(" std::get<{}>(key) = {};".format(field, entry[1]), file=f) print(" std::get<{}>(key) = {};".format(field, entry[1]), file=f)
print(" index_{}[key].push_back(cell);".format(index), file=f) print(" index_{}[key].push_back(value);".format(index), file=f)
for i in range(loopcnt):
print(" }", file=f)
print(" } while (0);", file=f) print(" } while (0);", file=f)
print(" }", file=f) print(" }", file=f)
@ -535,6 +588,8 @@ with open(outfile, "w") as f:
const_st.add(s) const_st.add(s)
elif blocks[i]["type"] == "match": elif blocks[i]["type"] == "match":
const_st.add(blocks[i]["cell"]) const_st.add(blocks[i]["cell"])
for item in blocks[i]["sets"]:
const_st.add(item[0])
else: else:
assert False assert False
@ -548,6 +603,10 @@ with open(outfile, "w") as f:
s = block["cell"] s = block["cell"]
assert s not in const_st assert s not in const_st
nonconst_st.add(s) nonconst_st.add(s)
for item in block["sets"]:
if item[0] in const_st:
const_st.remove(item[0])
nonconst_st.add(item[0])
else: else:
assert False assert False
@ -570,7 +629,7 @@ with open(outfile, "w") as f:
print("", file=f) print("", file=f)
for s in sorted(restore_st): for s in sorted(restore_st):
t = state_types[current_pattern][s] t = state_types[current_pattern][s]
print(" {} backup_{} = {};".format(t, s, s), file=f) print(" {} _pmg_backup_{} = {};".format(t, s, s), file=f)
if block["type"] == "code": if block["type"] == "code":
print("", file=f) print("", file=f)
@ -610,7 +669,7 @@ with open(outfile, "w") as f:
print("", file=f) print("", file=f)
for s in sorted(restore_st): for s in sorted(restore_st):
t = state_types[current_pattern][s] t = state_types[current_pattern][s]
print(" {} = backup_{};".format(s, s), file=f) print(" {} = _pmg_backup_{};".format(s, s), file=f)
for s in sorted(nonconst_st): for s in sorted(nonconst_st):
if s not in restore_st: if s not in restore_st:
t = state_types[current_pattern][s] t = state_types[current_pattern][s]
@ -622,7 +681,7 @@ with open(outfile, "w") as f:
elif block["type"] == "match": elif block["type"] == "match":
assert len(restore_st) == 0 assert len(restore_st) == 0
print(" Cell* backup_{} = {};".format(block["cell"], block["cell"]), file=f) print(" Cell* _pmg_backup_{} = {};".format(block["cell"], block["cell"]), file=f)
if len(block["if"]): if len(block["if"]):
for expr in block["if"]: for expr in block["if"]:
@ -630,7 +689,7 @@ with open(outfile, "w") as f:
print(" if (!({})) {{".format(expr), file=f) print(" if (!({})) {{".format(expr), file=f)
print(" {} = nullptr;".format(block["cell"]), file=f) print(" {} = nullptr;".format(block["cell"]), file=f)
print(" block_{}(recursion+1);".format(index+1), file=f) print(" block_{}(recursion+1);".format(index+1), file=f)
print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
print(" return;", file=f) print(" return;", file=f)
print(" }", file=f) print(" }", file=f)
@ -645,21 +704,37 @@ with open(outfile, "w") as f:
print("", file=f) print("", file=f)
print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f) print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f)
print(" const vector<Cell*> &cells = cells_ptr->second;".format(index), file=f) print(" const vector<index_{}_value_type> &cells = cells_ptr->second;".format(index), file=f)
print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) print(" for (int _pmg_idx = 0; _pmg_idx < GetSize(cells); _pmg_idx++) {", file=f)
print(" {} = cells[idx];".format(block["cell"]), file=f) print(" {} = std::get<0>(cells[_pmg_idx]);".format(block["cell"]), file=f)
valueidx = 1
for item in block["setup"]:
if item[0] == "slice":
print(" const int &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], valueidx), file=f)
valueidx += 1
if item[0] == "choice":
print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
valueidx += 1
if item[0] == "define":
print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
valueidx += 1
print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f)
for expr in block["filter"]: for expr in block["filter"]:
print(" if (!({})) continue;".format(expr), file=f) print(" if (!({})) continue;".format(expr), file=f)
if block["semioptional"] or block["genargs"] is not None: if block["semioptional"] or block["genargs"] is not None:
print(" found_any_match = true;", file=f) print(" found_any_match = true;", file=f)
print(" auto rollback_ptr = rollback_cache.insert(make_pair(cells[idx], recursion));", file=f) for item in block["sets"]:
print(" auto _pmg_backup_{} = {};".format(item[0], item[0]), file=f)
print(" {} = {};".format(item[0], item[1]), file=f)
print(" auto rollback_ptr = rollback_cache.insert(make_pair(std::get<0>(cells[_pmg_idx]), recursion));", file=f)
print(" block_{}(recursion+1);".format(index+1), file=f) print(" block_{}(recursion+1);".format(index+1), file=f)
for item in block["sets"]:
print(" {} = _pmg_backup_{};".format(item[0], item[0]), file=f)
print(" if (rollback_ptr.second)", file=f) print(" if (rollback_ptr.second)", file=f)
print(" rollback_cache.erase(rollback_ptr.first);", file=f) print(" rollback_cache.erase(rollback_ptr.first);", file=f)
print(" if (rollback) {", file=f) print(" if (rollback) {", file=f)
print(" if (rollback != recursion) {{".format(index+1), file=f) print(" if (rollback != recursion) {{".format(index+1), file=f)
print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
print(" return;", file=f) print(" return;", file=f)
print(" }", file=f) print(" }", file=f)
print(" rollback = 0;", file=f) print(" rollback = 0;", file=f)
@ -676,13 +751,11 @@ with open(outfile, "w") as f:
if block["semioptional"]: if block["semioptional"]:
print(" if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f) print(" if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f)
print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
if block["genargs"] is not None: if block["genargs"] is not None:
print("#define finish do { rollback = -1; return; } while(0)", file=f) print("#define finish do { rollback = -1; return; } while(0)", file=f)
print(" if (generate_mode && !found_any_match) {", file=f) print(" if (generate_mode && rng(100) < (found_any_match ? {} : {})) {{".format(block["genargs"][1], block["genargs"][0]), file=f)
if len(block["genargs"]) == 1:
print(" if (rng(100) >= {}) return;".format(block["genargs"][0]), file=f)
for line in block["gencode"]: for line in block["gencode"]:
print(" " + line, file=f) print(" " + line, file=f)
print(" }", file=f) print(" }", file=f)

View file

@ -99,6 +99,24 @@ void reduce_tree(test_pmgen_pm &pm)
log(" -> %s (%s)\n", log_id(c), log_id(c->type)); log(" -> %s (%s)\n", log_id(c), log_id(c->type));
} }
void opt_eqpmux(test_pmgen_pm &pm)
{
auto &st = pm.st_eqpmux;
SigSpec Y = st.pmux->getPort(ID::Y);
int width = GetSize(Y);
SigSpec EQ = st.pmux->getPort(ID::B).extract(st.pmux_slice_eq*width, width);
SigSpec NE = st.pmux->getPort(ID::B).extract(st.pmux_slice_ne*width, width);
log("Found eqpmux circuit driving %s (eq=%s, ne=%s, pmux=%s).\n",
log_signal(Y), log_id(st.eq), log_id(st.ne), log_id(st.pmux));
pm.autoremove(st.pmux);
Cell *c = pm.module->addMux(NEW_ID, NE, EQ, st.eq->getPort(ID::Y), Y);
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
}
#define GENERATE_PATTERN(pmclass, pattern) \ #define GENERATE_PATTERN(pmclass, pattern) \
generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design) generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
@ -149,16 +167,17 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass); log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
int modcnt = 0; int modcnt = 0;
int maxmodcnt = 100;
int maxsubcnt = 4; int maxsubcnt = 4;
int timeout = 0; int timeout = 0;
vector<Module*> mods; vector<Module*> mods;
while (modcnt < 100) while (modcnt < maxmodcnt)
{ {
int submodcnt = 0, itercnt = 0, cellcnt = 0; int submodcnt = 0, itercnt = 0, cellcnt = 0;
Module *mod = design->addModule(NEW_ID); Module *mod = design->addModule(NEW_ID);
while (modcnt < 100 && 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 an no matching module generated.\n");
@ -232,6 +251,12 @@ struct TestPmgenPass : public Pass {
log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n"); log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n");
log("\n"); log("\n");
log("\n");
log(" test_pmgen -eqpmux [options] [selection]\n");
log("\n");
log("Demo for recursive pmgen patterns. Optimize EQ/NE/PMUX circuits.\n");
log("\n");
log("\n"); log("\n");
log(" test_pmgen -generate [options] <pattern_name>\n"); log(" test_pmgen -generate [options] <pattern_name>\n");
log("\n"); log("\n");
@ -277,6 +302,25 @@ struct TestPmgenPass : public Pass {
test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree); test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree);
} }
void execute_eqpmux(std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing TEST_PMGEN pass (-eqpmux).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-singleton") {
// singleton_mode = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
test_pmgen_pm(module, module->selected_cells()).run_eqpmux(opt_eqpmux);
}
void execute_generate(std::vector<std::string> args, RTLIL::Design *design) void execute_generate(std::vector<std::string> args, RTLIL::Design *design)
{ {
log_header(design, "Executing TEST_PMGEN pass (-generate).\n"); log_header(design, "Executing TEST_PMGEN pass (-generate).\n");
@ -299,6 +343,9 @@ struct TestPmgenPass : public Pass {
if (pattern == "reduce") if (pattern == "reduce")
return GENERATE_PATTERN(test_pmgen_pm, reduce); return GENERATE_PATTERN(test_pmgen_pm, reduce);
if (pattern == "eqpmux")
return GENERATE_PATTERN(test_pmgen_pm, eqpmux);
if (pattern == "ice40_dsp") if (pattern == "ice40_dsp")
return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp); return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
@ -319,6 +366,8 @@ struct TestPmgenPass : public Pass {
return execute_reduce_chain(args, design); return execute_reduce_chain(args, design);
if (args[1] == "-reduce_tree") if (args[1] == "-reduce_tree")
return execute_reduce_tree(args, design); return execute_reduce_tree(args, design);
if (args[1] == "-eqpmux")
return execute_eqpmux(args, design);
if (args[1] == "-generate") if (args[1] == "-generate")
return execute_generate(args, design); return execute_generate(args, design);
} }

View file

@ -60,8 +60,8 @@ code portname
endcode endcode
match next match next
select nusers(port(next, \Y)) == 2
select next->type.in($_AND_, $_OR_, $_XOR_) select next->type.in($_AND_, $_OR_, $_XOR_)
select nusers(port(next, \Y)) == 2
index <IdString> next->type === first->type index <IdString> next->type === first->type
index <SigSpec> port(next, \Y) === port(first, portname) index <SigSpec> port(next, \Y) === port(first, portname)
endmatch endmatch
@ -77,8 +77,8 @@ arg first
match next match next
semioptional semioptional
select nusers(port(next, \Y)) == 2
select next->type.in($_AND_, $_OR_, $_XOR_) select next->type.in($_AND_, $_OR_, $_XOR_)
select nusers(port(next, \Y)) == 2
index <IdString> next->type === chain.back().first->type index <IdString> next->type === chain.back().first->type
index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second) index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second)
generate 10 generate 10
@ -104,3 +104,86 @@ finally
if (next) if (next)
chain.pop_back(); chain.pop_back();
endcode endcode
// ==================================================================
pattern eqpmux
state <bool> eq_ne_signed
state <SigSpec> eq_inA eq_inB
state <int> pmux_slice_eq pmux_slice_ne
match eq
select eq->type == $eq
choice <IdString> AB {\A, \B}
define <IdString> BA AB == \A ? \B : \A
set eq_inA port(eq, \A)
set eq_inB port(eq, \B)
set eq_ne_signed param(eq, \A_SIGNED).as_bool()
generate 100 10
SigSpec A = module->addWire(NEW_ID, rng(7)+1);
SigSpec B = module->addWire(NEW_ID, rng(7)+1);
SigSpec Y = module->addWire(NEW_ID);
module->addEq(NEW_ID, A, B, Y, rng(2));
endmatch
match pmux
select pmux->type == $pmux
slice idx GetSize(port(pmux, \S))
index <SigBit> port(pmux, \S)[idx] === port(eq, \Y)
set pmux_slice_eq idx
generate 100 10
int width = rng(7) + 1;
int numsel = rng(4) + 1;
int idx = rng(numsel);
SigSpec A = module->addWire(NEW_ID, width);
SigSpec Y = module->addWire(NEW_ID, width);
SigSpec B, S;
for (int i = 0; i < numsel; i++) {
B.append(module->addWire(NEW_ID, width));
S.append(i == idx ? port(eq, \Y) : module->addWire(NEW_ID));
}
module->addPmux(NEW_ID, A, B, S, Y);
endmatch
match ne
select ne->type == $ne
choice <IdString> AB {\A, \B}
define <IdString> BA (AB == \A ? \B : \A)
index <SigSpec> port(ne, AB) === eq_inA
index <SigSpec> port(ne, BA) === eq_inB
index <int> param(ne, \A_SIGNED).as_bool() === eq_ne_signed
generate 100 10
SigSpec A = eq_inA, B = eq_inB, Y;
if (rng(2)) {
std::swap(A, B);
}
if (rng(2)) {
for (auto bit : port(pmux, \S)) {
if (nusers(bit) < 2)
Y.append(bit);
}
if (GetSize(Y))
Y = Y[rng(GetSize(Y))];
else
Y = module->addWire(NEW_ID);
} else {
Y = module->addWire(NEW_ID);
}
module->addNe(NEW_ID, A, B, Y, rng(2));
endmatch
match pmux2
select pmux2->type == $pmux
slice idx GetSize(port(pmux2, \S))
index <Cell*> pmux2 === pmux
index <SigBit> port(pmux2, \S)[idx] === port(ne, \Y)
set pmux_slice_ne idx
endmatch
code
accept;
endcode

View file

@ -39,7 +39,7 @@ struct Async2syncPass : public Pass {
log("reset value in the next cycle regardless of the data-in value at the time of\n"); log("reset value in the next cycle regardless of the data-in value at the time of\n");
log("the clock edge.\n"); log("the clock edge.\n");
log("\n"); log("\n");
log("Currently only $adff and $dffsr cells are supported by this pass.\n"); log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\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
@ -169,6 +169,41 @@ struct Async2syncPass : public Pass {
cell->type = "$dff"; cell->type = "$dff";
continue; continue;
} }
if (cell->type.in("$dlatch"))
{
bool en_pol = cell->parameters["\\EN_POLARITY"].as_bool();
SigSpec sig_en = cell->getPort("\\EN");
SigSpec sig_d = cell->getPort("\\D");
SigSpec sig_q = cell->getPort("\\Q");
log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
log_id(module), log_id(cell), log_id(cell->type),
log_signal(sig_en), log_signal(sig_d), log_signal(sig_q));
Const init_val;
for (int i = 0; i < GetSize(sig_q); i++) {
SigBit bit = sigmap(sig_q[i]);
init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
del_initbits.insert(bit);
}
Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
new_q->attributes["\\init"] = init_val;
if (en_pol) {
module->addMux(NEW_ID, new_q, sig_d, sig_en, sig_q);
} else {
module->addMux(NEW_ID, sig_d, new_q, sig_en, sig_q);
}
cell->setPort("\\Q", new_q);
cell->unsetPort("\\EN");
cell->unsetParam("\\EN_POLARITY");
cell->type = "$ff";
continue;
}
} }
for (auto wire : module->wires()) for (auto wire : module->wires())

View file

@ -268,7 +268,7 @@ struct SatHelper
RTLIL::SigSpec removed_bits; RTLIL::SigSpec removed_bits;
for (int i = 0; i < lhs.size(); i++) { for (int i = 0; i < lhs.size(); i++) {
RTLIL::SigSpec bit = lhs.extract(i, 1); RTLIL::SigSpec bit = lhs.extract(i, 1);
if (!satgen.initial_state.check_all(bit)) { if (rhs[i] == State::Sx || !satgen.initial_state.check_all(bit)) {
removed_bits.append(bit); removed_bits.append(bit);
lhs.remove(i, 1); lhs.remove(i, 1);
rhs.remove(i, 1); rhs.remove(i, 1);

View file

@ -16,6 +16,7 @@ endif
ifneq ($(SMALL),1) ifneq ($(SMALL),1)
OBJS += passes/techmap/iopadmap.o OBJS += passes/techmap/iopadmap.o
OBJS += passes/techmap/clkbufmap.o
OBJS += passes/techmap/hilomap.o OBJS += passes/techmap/hilomap.o
OBJS += passes/techmap/extract.o OBJS += passes/techmap/extract.o
OBJS += passes/techmap/extract_fa.o OBJS += passes/techmap/extract_fa.o

View file

@ -143,6 +143,82 @@ void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actio
attributes.swap(new_attributes); attributes.swap(new_attributes);
} }
void log_attrmap_paramap_options()
{
log(" -tocase <name>\n");
log(" Match attribute names case-insensitively and set it to the specified\n");
log(" name.\n");
log("\n");
log(" -rename <old_name> <new_name>\n");
log(" Rename attributes as specified\n");
log("\n");
log(" -map <old_name>=<old_value> <new_name>=<new_value>\n");
log(" Map key/value pairs as indicated.\n");
log("\n");
log(" -imap <old_name>=<old_value> <new_name>=<new_value>\n");
log(" Like -map, but use case-insensitive match for <old_value> when\n");
log(" it is a string value.\n");
log("\n");
log(" -remove <name>=<value>\n");
log(" Remove attributes matching this pattern.\n");
}
bool parse_attrmap_paramap_options(size_t &argidx, std::vector<std::string> &args, vector<std::unique_ptr<AttrmapAction>> &actions)
{
std::string arg = args[argidx];
if (arg == "-tocase" && argidx+1 < args.size()) {
auto action = new AttrmapTocase;
action->name = args[++argidx];
actions.push_back(std::unique_ptr<AttrmapAction>(action));
return true;
}
if (arg == "-rename" && argidx+2 < args.size()) {
auto action = new AttrmapRename;
action->old_name = args[++argidx];
action->new_name = args[++argidx];
actions.push_back(std::unique_ptr<AttrmapAction>(action));
return true;
}
if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) {
string arg1 = args[++argidx];
string arg2 = args[++argidx];
string val1, val2;
size_t p = arg1.find("=");
if (p != string::npos) {
val1 = arg1.substr(p+1);
arg1 = arg1.substr(0, p);
}
p = arg2.find("=");
if (p != string::npos) {
val2 = arg2.substr(p+1);
arg2 = arg2.substr(0, p);
}
auto action = new AttrmapMap;
action->imap = (arg == "-map");
action->old_name = arg1;
action->new_name = arg2;
action->old_value = val1;
action->new_value = val2;
actions.push_back(std::unique_ptr<AttrmapAction>(action));
return true;
}
if (arg == "-remove" && argidx+1 < args.size()) {
string arg1 = args[++argidx], val1;
size_t p = arg1.find("=");
if (p != string::npos) {
val1 = arg1.substr(p+1);
arg1 = arg1.substr(0, p);
}
auto action = new AttrmapRemove;
action->name = arg1;
action->has_value = (p != string::npos);
action->value = val1;
actions.push_back(std::unique_ptr<AttrmapAction>(action));
return true;
}
return false;
}
struct AttrmapPass : public Pass { struct AttrmapPass : public Pass {
AttrmapPass() : Pass("attrmap", "renaming attributes") { } AttrmapPass() : Pass("attrmap", "renaming attributes") { }
void help() YS_OVERRIDE void help() YS_OVERRIDE
@ -151,25 +227,10 @@ struct AttrmapPass : public Pass {
log("\n"); log("\n");
log(" attrmap [options] [selection]\n"); log(" attrmap [options] [selection]\n");
log("\n"); log("\n");
log("This command renames attributes and/or mapps key/value pairs to\n"); log("This command renames attributes and/or maps key/value pairs to\n");
log("other key/value pairs.\n"); log("other key/value pairs.\n");
log("\n"); log("\n");
log(" -tocase <name>\n"); log_attrmap_paramap_options();
log(" Match attribute names case-insensitively and set it to the specified\n");
log(" name.\n");
log("\n");
log(" -rename <old_name> <new_name>\n");
log(" Rename attributes as specified\n");
log("\n");
log(" -map <old_name>=<old_value> <new_name>=<new_value>\n");
log(" Map key/value pairs as indicated.\n");
log("\n");
log(" -imap <old_name>=<old_value> <new_name>=<new_value>\n");
log(" Like -map, but use case-insensitive match for <old_value> when\n");
log(" it is a string value.\n");
log("\n");
log(" -remove <name>=<value>\n");
log(" Remove attributes matching this pattern.\n");
log("\n"); log("\n");
log(" -modattr\n"); log(" -modattr\n");
log(" Operate on module attributes instead of attributes on wires and cells.\n"); log(" Operate on module attributes instead of attributes on wires and cells.\n");
@ -190,58 +251,9 @@ struct AttrmapPass : public Pass {
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
{ {
std::string arg = args[argidx]; if (parse_attrmap_paramap_options(argidx, args, actions))
if (arg == "-tocase" && argidx+1 < args.size()) {
auto action = new AttrmapTocase;
action->name = args[++argidx];
actions.push_back(std::unique_ptr<AttrmapAction>(action));
continue; continue;
} if (args[argidx] == "-modattr") {
if (arg == "-rename" && argidx+2 < args.size()) {
auto action = new AttrmapRename;
action->old_name = args[++argidx];
action->new_name = args[++argidx];
actions.push_back(std::unique_ptr<AttrmapAction>(action));
continue;
}
if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) {
string arg1 = args[++argidx];
string arg2 = args[++argidx];
string val1, val2;
size_t p = arg1.find("=");
if (p != string::npos) {
val1 = arg1.substr(p+1);
arg1 = arg1.substr(0, p);
}
p = arg2.find("=");
if (p != string::npos) {
val2 = arg2.substr(p+1);
arg2 = arg2.substr(0, p);
}
auto action = new AttrmapMap;
action->imap = (arg == "-map");
action->old_name = arg1;
action->new_name = arg2;
action->old_value = val1;
action->new_value = val2;
actions.push_back(std::unique_ptr<AttrmapAction>(action));
continue;
}
if (arg == "-remove" && argidx+1 < args.size()) {
string arg1 = args[++argidx], val1;
size_t p = arg1.find("=");
if (p != string::npos) {
val1 = arg1.substr(p+1);
arg1 = arg1.substr(0, p);
}
auto action = new AttrmapRemove;
action->name = arg1;
action->has_value = (p != string::npos);
action->value = val1;
actions.push_back(std::unique_ptr<AttrmapAction>(action));
continue;
}
if (arg == "-modattr") {
modattr_mode = true; modattr_mode = true;
continue; continue;
} }
@ -287,4 +299,43 @@ struct AttrmapPass : public Pass {
} }
} AttrmapPass; } AttrmapPass;
struct ParamapPass : public Pass {
ParamapPass() : Pass("paramap", "renaming cell parameters") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" paramap [options] [selection]\n");
log("\n");
log("This command renames cell parameters and/or maps key/value pairs to\n");
log("other key/value pairs.\n");
log("\n");
log_attrmap_paramap_options();
log("\n");
log("For example, mapping Diamond-style ECP5 \"init\" attributes to Yosys-style:\n");
log("\n");
log(" paramap -tocase INIT t:LUT4\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PARAMAP pass (move or copy cell parameters).\n");
vector<std::unique_ptr<AttrmapAction>> actions;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (parse_attrmap_paramap_options(argidx, args, actions))
continue;
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
for (auto cell : module->selected_cells())
attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->parameters);
}
} ParamapPass;
PRIVATE_NAMESPACE_END PRIVATE_NAMESPACE_END

298
passes/techmap/clkbufmap.cc Normal file
View file

@ -0,0 +1,298 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net>
*
* 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
void split_portname_pair(std::string &port1, std::string &port2)
{
size_t pos = port1.find_first_of(':');
if (pos != std::string::npos) {
port2 = port1.substr(pos+1);
port1 = port1.substr(0, pos);
}
}
struct ClkbufmapPass : public Pass {
ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" clkbufmap [options] [selection]\n");
log("\n");
log("Inserts global buffers between nets connected to clock inputs and their drivers.\n");
log("\n");
log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n");
log("attribute will be considered for global buffer insertion.\n");
log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n");
log("'none' or 'bufr' one would specify:\n");
log(" 'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n");
log("as the selection.\n");
log("\n");
log(" -buf <celltype> <portname_out>:<portname_in>\n");
log(" Specifies the cell type to use for the global buffers\n");
log(" and its port names. The first port will be connected to\n");
log(" the clock network sinks, and the second will be connected\n");
log(" to the actual clock source. This option is required.\n");
log("\n");
log(" -inpad <celltype> <portname_out>:<portname_in>\n");
log(" If specified, a PAD cell of the given type is inserted on\n");
log(" clock nets that are also top module's inputs (in addition\n");
log(" to the global buffer).\n");
log("\n");
}
void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) {
if (modules_processed.count(module))
return;
for (auto cell : module->cells()) {
Module *submodule = design->module(cell->type);
if (!submodule)
continue;
module_queue(design, submodule, modules_sorted, modules_processed);
}
modules_sorted.push_back(module);
modules_processed.insert(module);
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n");
std::string buf_celltype, buf_portname, buf_portname2;
std::string inpad_celltype, inpad_portname, inpad_portname2;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
if (arg == "-buf" && argidx+2 < args.size()) {
buf_celltype = args[++argidx];
buf_portname = args[++argidx];
split_portname_pair(buf_portname, buf_portname2);
continue;
}
if (arg == "-inpad" && argidx+2 < args.size()) {
inpad_celltype = args[++argidx];
inpad_portname = args[++argidx];
split_portname_pair(inpad_portname, inpad_portname2);
continue;
}
break;
}
bool select = false;
if (argidx < args.size()) {
if (args[argidx].compare(0, 1, "-") != 0)
select = true;
extra_args(args, argidx, design);
}
if (buf_celltype.empty())
log_error("The -buf option is required.\n");
// Cell type, port name, bit index.
pool<pair<IdString, pair<IdString, int>>> sink_ports;
pool<pair<IdString, pair<IdString, int>>> buf_ports;
// Process submodules before module using them.
std::vector<Module *> modules_sorted;
pool<Module *> modules_processed;
for (auto module : design->selected_modules())
module_queue(design, module, modules_sorted, modules_processed);
for (auto module : modules_sorted)
{
if (module->get_blackbox_attribute()) {
for (auto port : module->ports) {
auto wire = module->wire(port);
if (wire->get_bool_attribute("\\clkbuf_driver"))
for (int i = 0; i < GetSize(wire); i++)
buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
if (wire->get_bool_attribute("\\clkbuf_sink"))
for (int i = 0; i < GetSize(wire); i++)
sink_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
}
continue;
}
pool<SigBit> sink_wire_bits;
pool<SigBit> buf_wire_bits;
pool<SigBit> driven_wire_bits;
SigMap sigmap(module);
// bit -> (buffer, buffer's input)
dict<SigBit, pair<Cell *, Wire *>> buffered_bits;
// First, collect nets that could use a clock buffer.
for (auto cell : module->cells())
for (auto port : cell->connections())
for (int i = 0; i < port.second.size(); i++)
if (sink_ports.count(make_pair(cell->type, make_pair(port.first, i))))
sink_wire_bits.insert(sigmap(port.second[i]));
// Second, collect ones that already have a clock buffer.
for (auto cell : module->cells())
for (auto port : cell->connections())
for (int i = 0; i < port.second.size(); i++)
if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i))))
buf_wire_bits.insert(sigmap(port.second[i]));
// Collect all driven bits.
for (auto cell : module->cells())
for (auto port : cell->connections())
if (cell->output(port.first))
for (int i = 0; i < port.second.size(); i++)
driven_wire_bits.insert(port.second[i]);
// Insert buffers.
std::vector<pair<Wire *, Wire *>> input_queue;
// Copy current wire list, as we will be adding new ones during iteration.
std::vector<Wire *> wires(module->wires());
for (auto wire : wires)
{
// Should not happen.
if (wire->port_input && wire->port_output)
continue;
bool process_wire = module->selected(wire);
if (!select && wire->get_bool_attribute("\\clkbuf_inhibit"))
process_wire = false;
if (!process_wire) {
// This wire is supposed to be bypassed, so make sure we don't buffer it in
// some buffer higher up in the hierarchy.
if (wire->port_output)
for (int i = 0; i < GetSize(wire); i++)
buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
continue;
}
pool<int> input_bits;
for (int i = 0; i < GetSize(wire); i++)
{
SigBit wire_bit(wire, i);
SigBit mapped_wire_bit = sigmap(wire_bit);
if (buf_wire_bits.count(mapped_wire_bit)) {
// Already buffered downstream. If this is an output, mark it.
if (wire->port_output)
buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
} else if (!sink_wire_bits.count(mapped_wire_bit)) {
// Nothing to do.
} else if (driven_wire_bits.count(wire_bit) || (wire->port_input && module->get_bool_attribute("\\top"))) {
// Clock network not yet buffered, driven by one of
// our cells or a top-level input -- buffer it.
log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i);
RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype));
Wire *iwire = module->addWire(NEW_ID);
cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit);
cell->setPort(RTLIL::escape_id(buf_portname2), iwire);
if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute("\\top")) {
log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i);
RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype));
cell2->setPort(RTLIL::escape_id(inpad_portname), iwire);
iwire = module->addWire(NEW_ID);
cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire);
}
buffered_bits[mapped_wire_bit] = make_pair(cell, iwire);
if (wire->port_input) {
input_bits.insert(i);
}
} else if (wire->port_input) {
// A clock input in a submodule -- mark it, let higher level
// worry about it.
if (wire->port_input)
sink_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
}
}
if (!input_bits.empty()) {
// This is an input port and some buffers were inserted -- we need
// to create a new input wire and transfer attributes.
Wire *new_wire = module->addWire(NEW_ID, wire);
for (int i = 0; i < wire->width; i++) {
SigBit wire_bit(wire, i);
SigBit mapped_wire_bit = sigmap(wire_bit);
auto it = buffered_bits.find(mapped_wire_bit);
if (it != buffered_bits.end()) {
module->connect(it->second.second, SigSpec(new_wire, i));
} else {
module->connect(SigSpec(wire, i), SigSpec(new_wire, i));
}
}
input_queue.push_back(make_pair(wire, new_wire));
}
}
// Mark any newly-buffered output ports as such.
for (auto wire : module->selected_wires()) {
if (wire->port_input || !wire->port_output)
continue;
for (int i = 0; i < GetSize(wire); i++)
{
SigBit wire_bit(wire, i);
SigBit mapped_wire_bit = sigmap(wire_bit);
if (buffered_bits.count(mapped_wire_bit))
buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
}
}
// Reconnect the drivers to buffer inputs.
for (auto cell : module->cells())
for (auto port : cell->connections()) {
if (!cell->output(port.first))
continue;
SigSpec sig = port.second;
bool newsig = false;
for (auto &bit : sig) {
const auto it = buffered_bits.find(sigmap(bit));
if (it == buffered_bits.end())
continue;
// Avoid substituting buffer's own output pin.
if (cell == it->second.first)
continue;
bit = it->second.second;
newsig = true;
}
if (newsig)
cell->setPort(port.first, sig);
}
// This has to be done last, to avoid upsetting sigmap before the port reconnections.
for (auto &it : input_queue) {
Wire *wire = it.first;
Wire *new_wire = it.second;
module->swap_names(new_wire, wire);
wire->attributes.clear();
wire->port_id = 0;
wire->port_input = false;
wire->port_output = false;
}
module->fixup_ports();
}
}
} ClkbufmapPass;
PRIVATE_NAMESPACE_END

View file

@ -64,6 +64,11 @@ struct IopadmapPass : public Pass {
log(" of the tristate driver and the 2nd portname is the internal output\n"); log(" of the tristate driver and the 2nd portname is the internal output\n");
log(" buffering the external signal.\n"); log(" buffering the external signal.\n");
log("\n"); log("\n");
log(" -ignore <celltype> <portname>[:<portname>]*\n");
log(" Skips mapping inputs/outputs that are already connected to given\n");
log(" ports of the given cell. Can be used multiple times. This is in\n");
log(" addition to the cells specified as mapping targets.\n");
log("\n");
log(" -widthparam <param_name>\n"); log(" -widthparam <param_name>\n");
log(" Use the specified parameter name to set the port width.\n"); log(" Use the specified parameter name to set the port width.\n");
log("\n"); log("\n");
@ -88,6 +93,7 @@ struct IopadmapPass : public Pass {
std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3; std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3;
std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4; std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4;
std::string widthparam, nameparam; std::string widthparam, nameparam;
pool<pair<IdString, IdString>> ignore;
bool flag_bits = false; bool flag_bits = false;
size_t argidx; size_t argidx;
@ -127,6 +133,18 @@ struct IopadmapPass : public Pass {
split_portname_pair(tinoutpad_portname3, tinoutpad_portname4); split_portname_pair(tinoutpad_portname3, tinoutpad_portname4);
continue; continue;
} }
if (arg == "-ignore" && argidx+2 < args.size()) {
std::string ignore_celltype = args[++argidx];
std::string ignore_portname = args[++argidx];
std::string ignore_portname2;
while (!ignore_portname.empty()) {
split_portname_pair(ignore_portname, ignore_portname2);
ignore.insert(make_pair(RTLIL::escape_id(ignore_celltype), RTLIL::escape_id(ignore_portname)));
ignore_portname = ignore_portname2;
}
continue;
}
if (arg == "-widthparam" && argidx+1 < args.size()) { if (arg == "-widthparam" && argidx+1 < args.size()) {
widthparam = args[++argidx]; widthparam = args[++argidx];
continue; continue;
@ -143,6 +161,23 @@ struct IopadmapPass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (!inpad_portname2.empty())
ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname2)));
if (!outpad_portname2.empty())
ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname2)));
if (!inoutpad_portname2.empty())
ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname2)));
if (!toutpad_portname3.empty())
ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname3)));
if (!tinoutpad_portname4.empty())
ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname4)));
for (auto module : design->modules())
if (module->get_blackbox_attribute())
for (auto wire : module->wires())
if (wire->get_bool_attribute("\\iopad_external_pin"))
ignore.insert(make_pair(module->name, wire->name));
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
{ {
dict<IdString, pool<int>> skip_wires; dict<IdString, pool<int>> skip_wires;
@ -150,28 +185,11 @@ struct IopadmapPass : public Pass {
SigMap sigmap(module); SigMap sigmap(module);
for (auto cell : module->cells()) for (auto cell : module->cells())
{ for (auto port : cell->connections())
if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2))) if (ignore.count(make_pair(cell->type, port.first)))
for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2)))) for (auto bit : sigmap(port.second))
skip_wire_bits.insert(bit); skip_wire_bits.insert(bit);
if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2)))
for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2))))
skip_wire_bits.insert(bit);
if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2)))
for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2))))
skip_wire_bits.insert(bit);
if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3)))
for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3))))
skip_wire_bits.insert(bit);
if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4)))
for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4))))
skip_wire_bits.insert(bit);
}
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty()) if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
{ {
dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits; dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits;

View file

@ -346,7 +346,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);

View file

@ -943,7 +943,8 @@ struct TechmapPass : public Pass {
log(" instead of inlining them.\n"); log(" instead of inlining them.\n");
log("\n"); log("\n");
log(" -max_iter <number>\n"); log(" -max_iter <number>\n");
log(" only run the specified number of iterations.\n"); log(" only run the specified number of iterations on each module.\n");
log(" default: unlimited\n");
log("\n"); log("\n");
log(" -recursive\n"); log(" -recursive\n");
log(" instead of the iterative breadth-first algorithm use a recursive\n"); log(" instead of the iterative breadth-first algorithm use a recursive\n");
@ -1157,15 +1158,16 @@ struct TechmapPass : public Pass {
RTLIL::Module *module = *worker.module_queue.begin(); RTLIL::Module *module = *worker.module_queue.begin();
worker.module_queue.erase(module); worker.module_queue.erase(module);
int module_max_iter = max_iter;
bool did_something = true; bool did_something = true;
std::set<RTLIL::Cell*> handled_cells; std::set<RTLIL::Cell*> handled_cells;
while (did_something) { while (did_something) {
did_something = false; did_something = false;
if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false))
did_something = true; did_something = true;
if (did_something) if (did_something)
module->check(); module->check();
if (max_iter > 0 && --max_iter == 0) if (module_max_iter > 0 && --module_max_iter == 0)
break; break;
} }
} }

View file

@ -1,7 +1,7 @@
OBJS += techlibs/anlogic/synth_anlogic.o OBJS += techlibs/anlogic/synth_anlogic.o
OBJS += techlibs/anlogic/anlogic_eqn.o OBJS += techlibs/anlogic/anlogic_eqn.o
OBJS += techlibs/anlogic/anlogic_determine_init.o OBJS += techlibs/anlogic/anlogic_fixcarry.o
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v))

View file

@ -1,72 +0,0 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
*
* 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
struct AnlogicDetermineInitPass : public Pass {
AnlogicDetermineInitPass() : Pass("anlogic_determine_init", "Anlogic: Determine the init value of cells") { }
void help() YS_OVERRIDE
{
log("\n");
log(" anlogic_determine_init [selection]\n");
log("\n");
log("Determine the init value of cells that doesn't allow unknown init value.\n");
log("\n");
}
Const determine_init(Const init)
{
for (int i = 0; i < GetSize(init); i++) {
if (init[i] != State::S0 && init[i] != State::S1)
init[i] = State::S0;
}
return init;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ANLOGIC_DETERMINE_INIT pass (determine init value for cells).\n");
extra_args(args, args.size(), design);
int cnt = 0;
for (auto module : design->selected_modules())
{
for (auto cell : module->selected_cells())
{
if (cell->type == "\\EG_LOGIC_DRAM16X4")
{
cell->setParam("\\INIT_D0", determine_init(cell->getParam("\\INIT_D0")));
cell->setParam("\\INIT_D1", determine_init(cell->getParam("\\INIT_D1")));
cell->setParam("\\INIT_D2", determine_init(cell->getParam("\\INIT_D2")));
cell->setParam("\\INIT_D3", determine_init(cell->getParam("\\INIT_D3")));
cnt++;
}
}
}
log_header(design, "Updated %d cells with determined init value.\n", cnt);
}
} AnlogicDetermineInitPass;
PRIVATE_NAMESPACE_END

View file

@ -0,0 +1,130 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static SigBit get_bit_or_zero(const SigSpec &sig)
{
if (GetSize(sig) == 0)
return State::S0;
return sig[0];
}
static void fix_carry_chain(Module *module)
{
SigMap sigmap(module);
pool<SigBit> ci_bits;
dict<SigBit, SigBit> mapping_bits;
for (auto cell : module->cells())
{
if (cell->type == "\\AL_MAP_ADDER") {
if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue;
SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a"));
SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b"));
if (bit_i0 == State::S0 && bit_i1== State::S0) {
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
SigSpec o = cell->getPort("\\o");
if (GetSize(o) == 2) {
SigBit bit_o = o[0];
ci_bits.insert(bit_ci);
mapping_bits[bit_ci] = bit_o;
}
}
}
}
vector<Cell*> adders_to_fix_cells;
for (auto cell : module->cells())
{
if (cell->type == "\\AL_MAP_ADDER") {
if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue;
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a"));
SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b"));
SigBit canonical_bit = sigmap(bit_ci);
if (!ci_bits.count(canonical_bit))
continue;
if (bit_i0 == State::S0 && bit_i1== State::S0)
continue;
adders_to_fix_cells.push_back(cell);
log("Found %s cell named %s with invalid 'c' signal.\n", log_id(cell->type), log_id(cell));
}
}
for (auto cell : adders_to_fix_cells)
{
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
SigBit canonical_bit = sigmap(bit_ci);
auto bit = mapping_bits.at(canonical_bit);
log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell));
Cell *c = module->addCell(NEW_ID, "\\AL_MAP_ADDER");
SigBit new_bit = module->addWire(NEW_ID);
SigBit dummy_bit = module->addWire(NEW_ID);
SigSpec bits;
bits.append(dummy_bit);
bits.append(new_bit);
c->setParam("\\ALUTYPE", Const("ADD_CARRY"));
c->setPort("\\a", bit);
c->setPort("\\b", State::S0);
c->setPort("\\c", State::S0);
c->setPort("\\o", bits);
cell->setPort("\\c", new_bit);
}
}
struct AnlogicCarryFixPass : public Pass {
AnlogicCarryFixPass() : Pass("anlogic_fixcarry", "Anlogic: fix carry chain") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" anlogic_fixcarry [options] [selection]\n");
log("\n");
log("Add Anlogic adders to fix carry chain if needed.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing anlogic_fixcarry pass (fix invalid carry chain).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
break;
}
extra_args(args, argidx, design);
Module *module = design->top_module();
if (module == nullptr)
log_cmd_error("No top module found.\n");
fix_carry_chain(module);
}
} AnlogicCarryFixPass;
PRIVATE_NAMESPACE_END

View file

@ -31,7 +31,10 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
output [Y_WIDTH-1:0] X, Y; output [Y_WIDTH-1:0] X, Y;
input CI, BI; input CI, BI;
output CO; output [Y_WIDTH-1:0] CO;
wire CIx;
wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
@ -41,15 +44,16 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH+1:0] COx; wire [Y_WIDTH-1:0] C = { COx, CIx };
wire [Y_WIDTH+2:0] C = {COx, CI};
wire dummy; wire dummy;
AL_MAP_ADDER #( AL_MAP_ADDER #(
.ALUTYPE("ADD_CARRY")) .ALUTYPE("ADD_CARRY"))
adder_cin ( adder_cin (
.a(C[0]), .a(CI),
.o({COx[0], dummy}) .b(1'b0),
.c(1'b0),
.o({CIx, dummy})
); );
genvar i; genvar i;
@ -59,18 +63,22 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
) adder_i ( ) adder_i (
.a(AA[i]), .a(AA[i]),
.b(BB[i]), .b(BB[i]),
.c(C[i+1]), .c(C[i]),
.o({COx[i+1],Y[i]}) .o({COx[i],Y[i]})
); );
end: slice
wire cout;
AL_MAP_ADDER #(
.ALUTYPE("ADD"))
adder_cout (
.a(1'b0),
.b(1'b0),
.c(COx[i]),
.o({cout, CO[i]})
);
end: slice
endgenerate endgenerate
/* End implementation */
AL_MAP_ADDER #( /* End implementation */
.ALUTYPE("ADD")) assign X = AA ^ BB;
adder_cout ( endmodule
.c(C[Y_WIDTH+1]),
.o(COx[Y_WIDTH+1])
);
assign CO = COx[Y_WIDTH+1];
assign X = AA ^ BB;
endmodule

View file

@ -154,7 +154,7 @@ struct SynthAnlogicPass : public ScriptPass
{ {
run("memory_bram -rules +/anlogic/drams.txt"); run("memory_bram -rules +/anlogic/drams.txt");
run("techmap -map +/anlogic/drams_map.v"); run("techmap -map +/anlogic/drams_map.v");
run("anlogic_determine_init"); run("setundef -zero -params t:EG_LOGIC_DRAM16X4");
} }
if (check_label("fine")) if (check_label("fine"))
@ -186,6 +186,11 @@ struct SynthAnlogicPass : public ScriptPass
{ {
run("techmap -map +/anlogic/cells_map.v"); run("techmap -map +/anlogic/cells_map.v");
run("clean"); run("clean");
}
if (check_label("map_anlogic"))
{
run("anlogic_fixcarry");
run("anlogic_eqn"); run("anlogic_eqn");
} }

View file

@ -175,7 +175,7 @@ struct SynthPass : public ScriptPass
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
if (abc == "abc9" && !lut) if (abc == "abc9" && !lut)
log_cmd_error("ABC9 flow only supported for FPGA synthesis (using '-lut' option)"); log_cmd_error("ABC9 flow only supported for FPGA synthesis (using '-lut' option)\n");
log_header(design, "Executing SYNTH pass.\n"); log_header(design, "Executing SYNTH pass.\n");
log_push(); log_push();

View file

@ -1,5 +1,6 @@
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
$(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))

View file

@ -33,7 +33,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
.CLKBMUX(CLKBMUX), .CLKBMUX(CLKBMUX),
.WRITEMODE_A(WRITEMODE_A), .WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B("READBEFOREWRITE"), .WRITEMODE_B("READBEFOREWRITE"),
.GSR("DISABLED") .GSR("AUTO")
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
`include "bram_conn_1.vh" `include "bram_conn_1.vh"
.CLKA(CLK2), .CLKB(CLK3), .CLKA(CLK2), .CLKB(CLK3),
@ -50,7 +50,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
.CLKBMUX(CLKBMUX), .CLKBMUX(CLKBMUX),
.WRITEMODE_A(WRITEMODE_A), .WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B("READBEFOREWRITE"), .WRITEMODE_B("READBEFOREWRITE"),
.GSR("DISABLED") .GSR("AUTO")
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
`include "bram_conn_2.vh" `include "bram_conn_2.vh"
.CLKA(CLK2), .CLKB(CLK3), .CLKA(CLK2), .CLKB(CLK3),
@ -67,7 +67,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
.CLKBMUX(CLKBMUX), .CLKBMUX(CLKBMUX),
.WRITEMODE_A(WRITEMODE_A), .WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B("READBEFOREWRITE"), .WRITEMODE_B("READBEFOREWRITE"),
.GSR("DISABLED") .GSR("AUTO")
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
`include "bram_conn_4.vh" `include "bram_conn_4.vh"
.CLKA(CLK2), .CLKB(CLK3), .CLKA(CLK2), .CLKB(CLK3),
@ -84,7 +84,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
.CLKBMUX(CLKBMUX), .CLKBMUX(CLKBMUX),
.WRITEMODE_A(WRITEMODE_A), .WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B("READBEFOREWRITE"), .WRITEMODE_B("READBEFOREWRITE"),
.GSR("DISABLED") .GSR("AUTO")
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
`include "bram_conn_9.vh" `include "bram_conn_9.vh"
.CLKA(CLK2), .CLKB(CLK3), .CLKA(CLK2), .CLKB(CLK3),
@ -101,7 +101,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
.CLKBMUX(CLKBMUX), .CLKBMUX(CLKBMUX),
.WRITEMODE_A(WRITEMODE_A), .WRITEMODE_A(WRITEMODE_A),
.WRITEMODE_B("READBEFOREWRITE"), .WRITEMODE_B("READBEFOREWRITE"),
.GSR("DISABLED") .GSR("AUTO")
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
`include "bram_conn_18.vh" `include "bram_conn_18.vh"
.CLKA(CLK2), .CLKB(CLK3), .CLKA(CLK2), .CLKB(CLK3),

View file

@ -664,3 +664,23 @@ module PCSCLKDIV (
); );
parameter GSR = "DISABLED"; parameter GSR = "DISABLED";
endmodule endmodule
// Note: this module is not marked keep as we want it swept away in synth (sim use only)
(* blackbox *)
module PUR (
input PUR
);
parameter RST_PULSE = 1;
endmodule
(* blackbox, keep *)
module GSR (
input GSR
);
endmodule
(* blackbox, keep *)
module SGSR (
input GSR, CLK
);
endmodule

View file

@ -1,51 +1,51 @@
module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .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_PN0 (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_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .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_PN1 (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_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .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("DISABLED"), .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("DISABLED"), .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 // TODO: Diamond flip-flops
// module FD1P3AX(); endmodule // module FD1P3AX(); endmodule

View file

@ -17,10 +17,12 @@ endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=1, lib_whitebox *) (* abc_box_id=1, lib_whitebox *)
module CCU2C( module CCU2C(
(* abc_carry *) input CIN, (* abc_carry *)
input CIN,
input A0, B0, C0, D0, A1, B1, C1, D1, input A0, B0, C0, D0, A1, B1, C1, D1,
output S0, S1, output S0, S1,
(* abc_carry *) output COUT (* abc_carry *)
output COUT
); );
parameter [15:0] INIT0 = 16'h0000; parameter [15:0] INIT0 = 16'h0000;
parameter [15:0] INIT1 = 16'h0000; parameter [15:0] INIT1 = 16'h0000;
@ -109,9 +111,12 @@ endmodule
// --------------------------------------- // ---------------------------------------
//(* abc_box_id=2 *) //(* abc_box_id=2 *)
module TRELLIS_DPR16X4 ( module TRELLIS_DPR16X4 (
(* abc_scc_break *) input [3:0] DI, (* abc_scc_break *)
(* abc_scc_break *) input [3:0] WAD, input [3:0] DI,
(* abc_scc_break *) input WRE, (* abc_scc_break *)
input [3:0] WAD,
(* abc_scc_break *)
input WRE,
input WCK, input WCK,
input [3:0] RAD, input [3:0] RAD,
output [3:0] DO output [3:0] DO

135
techlibs/ecp5/ecp5_gsr.cc Normal file
View file

@ -0,0 +1,135 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2019 David Shah <david@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct Ecp5GsrPass : public Pass {
Ecp5GsrPass() : Pass("ecp5_gsr", "ECP5: handle GSR") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" ecp5_gsr [options] [selection]\n");
log("\n");
log("Trim active low async resets connected to GSR and resolve GSR parameter,\n");
log("if a GSR or SGSR primitive is used in the design.\n");
log("\n");
log("If any cell has the GSR parameter set to \"AUTO\", this will be resolved\n");
log("to \"ENABLED\" if a GSR primitive is present and the (* nogsr *) attribute\n");
log("is not set, otherwise it will be resolved to \"DISABLED\".\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ECP5_GSR pass (implement FF init values).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-singleton") {
// singleton_mode = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
log("Handling GSR in %s.\n", log_id(module));
SigMap sigmap(module);
SigBit gsr;
bool found_gsr = false;
for (auto cell : module->selected_cells())
{
if (cell->type != ID(GSR) && cell->type != ID(SGSR))
continue;
if (found_gsr)
log_error("Found more than one GSR or SGSR cell in module %s.\n", log_id(module));
found_gsr = true;
SigSpec sig_gsr = cell->getPort(ID(GSR));
if (GetSize(sig_gsr) < 1)
log_error("GSR cell %s has disconnected GSR input.\n", log_id(cell));
gsr = sigmap(sig_gsr[0]);
}
// Resolve GSR parameter
for (auto cell : module->selected_cells())
{
if (!cell->hasParam(ID(GSR)) || cell->getParam(ID(GSR)).decode_string() != "AUTO")
continue;
bool gsren = found_gsr;
if (cell->get_bool_attribute("\\nogsr"))
gsren = false;
cell->setParam(ID(GSR), gsren ? Const("ENABLED") : Const("DISABLED"));
}
if (!found_gsr)
continue;
// For finding active low FF inputs
pool<SigBit> inverted_gsr;
log_debug("GSR net in module %s is %s.\n", log_id(module), log_signal(gsr));
for (auto cell : module->selected_cells())
{
if (cell->type != ID($_NOT_))
continue;
SigSpec sig_a = cell->getPort(ID(A)), sig_y = cell->getPort(ID(Y));
if (GetSize(sig_a) < 1 || GetSize(sig_y) < 1)
continue;
SigBit a = sigmap(sig_a[0]);
if (a == gsr)
inverted_gsr.insert(sigmap(sig_y[0]));
}
for (auto cell : module->selected_cells())
{
if (cell->type != ID(TRELLIS_FF))
continue;
if (!cell->hasParam(ID(GSR)) || cell->getParam(ID(GSR)).decode_string() != "ENABLED")
continue;
if (!cell->hasParam(ID(SRMODE)) || cell->getParam(ID(SRMODE)).decode_string() != "ASYNC")
continue;
SigSpec sig_lsr = cell->getPort(ID(LSR));
if (GetSize(sig_lsr) < 1)
continue;
SigBit lsr = sigmap(sig_lsr[0]);
if (!inverted_gsr.count(lsr))
continue;
cell->setParam(ID(SRMODE), Const("SYNC"));
cell->unsetPort(ID(LSR));
}
}
}
} Ecp5GsrPass;
PRIVATE_NAMESPACE_END

View file

@ -301,6 +301,8 @@ struct SynthEcp5Pass : public ScriptPass
run("opt_expr -undriven -mux_undef"); run("opt_expr -undriven -mux_undef");
run("simplemap"); run("simplemap");
run("ecp5_ffinit"); run("ecp5_ffinit");
run("ecp5_gsr");
run("opt_clean");
} }
if (check_label("map_luts")) if (check_label("map_luts"))

View file

@ -0,0 +1,10 @@
OBJS += techlibs/efinix/synth_efinix.o
OBJS += techlibs/efinix/efinix_gbuf.o
OBJS += techlibs/efinix/efinix_fixcarry.o
$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/arith_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/brams_map.v))
$(eval $(call add_share_file,share/efinix,techlibs/efinix/bram.txt))

View file

@ -0,0 +1,79 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
(* techmap_celltype = "$alu" *)
module _80_efinix_alu (A, B, CI, BI, X, Y, CO);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] X, Y;
input CI, BI;
output [Y_WIDTH-1:0] CO;
wire CIx;
wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
wire [Y_WIDTH-1:0] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH-1:0] C = { COx, CIx };
EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
adder_cin (
.I0(CI),
.I1(1'b1),
.CI(1'b0),
.CO(CIx)
);
genvar i;
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
adder_i (
.I0(AA[i]),
.I1(BB[i]),
.CI(C[i]),
.O(Y[i]),
.CO(COx[i])
);
EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
adder_cout (
.I0(1'b0),
.I1(1'b0),
.CI(COx[i]),
.O(CO[i])
);
end: slice
endgenerate
/* End implementation */
assign X = AA ^ BB;
endmodule

32
techlibs/efinix/bram.txt Normal file
View file

@ -0,0 +1,32 @@
bram $__EFINIX_5K
init 1
abits 8 @a8d16
dbits 16 @a8d16
abits 9 @a9d8
dbits 8 @a9d8
abits 10 @a10d4
dbits 4 @a10d4
abits 11 @a11d2
dbits 2 @a11d2
abits 12 @a12d1
dbits 1 @a12d1
abits 8 @a8d20
dbits 20 @a8d20
abits 9 @a9d10
dbits 10 @a9d10
groups 2
ports 1 1
wrmode 1 0
enable 1 1
transp 0 2
clocks 2 3
clkpol 2 3
endbram
match $__EFINIX_5K
min bits 256
min efficiency 5
shuffle_enable B
endmatch

View file

@ -0,0 +1,65 @@
module \$__EFINIX_5K (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CFG_ABITS = 8;
parameter CFG_DBITS = 20;
parameter CFG_ENABLE_A = 1;
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;
parameter [5119:0] INIT = 5119'bx;
parameter TRANSP2 = 0;
input CLK2;
input CLK3;
input [CFG_ABITS-1:0] A1ADDR;
input [CFG_DBITS-1:0] A1DATA;
input [CFG_ENABLE_A-1:0] A1EN;
input [CFG_ABITS-1:0] B1ADDR;
output [CFG_DBITS-1:0] B1DATA;
input B1EN;
localparam WRITEMODE_A = TRANSP2 ? "WRITE_FIRST" : "READ_FIRST";
EFX_RAM_5K #(
.READ_WIDTH(CFG_DBITS),
.WRITE_WIDTH(CFG_DBITS),
.OUTPUT_REG(1'b0),
.RCLK_POLARITY(1'b1),
.RE_POLARITY(1'b1),
.WCLK_POLARITY(1'b1),
.WE_POLARITY(1'b1),
.WCLKE_POLARITY(1'b1),
.WRITE_MODE(WRITEMODE_A),
.INIT_0(INIT[ 0*256 +: 256]),
.INIT_1(INIT[ 1*256 +: 256]),
.INIT_2(INIT[ 2*256 +: 256]),
.INIT_3(INIT[ 3*256 +: 256]),
.INIT_4(INIT[ 4*256 +: 256]),
.INIT_5(INIT[ 5*256 +: 256]),
.INIT_6(INIT[ 6*256 +: 256]),
.INIT_7(INIT[ 7*256 +: 256]),
.INIT_8(INIT[ 8*256 +: 256]),
.INIT_9(INIT[ 9*256 +: 256]),
.INIT_A(INIT[10*256 +: 256]),
.INIT_B(INIT[11*256 +: 256]),
.INIT_C(INIT[12*256 +: 256]),
.INIT_D(INIT[13*256 +: 256]),
.INIT_E(INIT[14*256 +: 256]),
.INIT_F(INIT[15*256 +: 256]),
.INIT_10(INIT[16*256 +: 256]),
.INIT_11(INIT[17*256 +: 256]),
.INIT_12(INIT[18*256 +: 256]),
.INIT_13(INIT[19*256 +: 256])
) _TECHMAP_REPLACE_ (
.WDATA(A1DATA),
.WADDR(A1ADDR),
.WE(A1EN),
.WCLK(CLK2),
.WCLKE(1'b1),
.RDATA(B1DATA),
.RADDR(B1ADDR),
.RE(B1EN),
.RCLK(CLK3)
);
endmodule

View file

@ -0,0 +1,45 @@
module \$_DFF_N_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFF_P_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFFE_NN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFFE_PN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
input [WIDTH-1:0] A;
output Y;
generate
if (WIDTH == 1) begin
EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0));
end else
if (WIDTH == 2) begin
EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0));
end else
if (WIDTH == 3) begin
EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0));
end else
if (WIDTH == 4) begin
EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
endgenerate
endmodule
`endif

107
techlibs/efinix/cells_sim.v Normal file
View file

@ -0,0 +1,107 @@
module EFX_LUT4(
output O,
input I0,
input I1,
input I2,
input I3
);
parameter LUTMASK = 16'h0000;
endmodule
module EFX_ADD(
output O,
output CO,
input I0,
input I1,
input CI
);
parameter I0_POLARITY = 1;
parameter I1_POLARITY = 1;
endmodule
module EFX_FF(
output Q,
input D,
input CE,
input CLK,
input SR
);
parameter CLK_POLARITY = 1;
parameter CE_POLARITY = 1;
parameter SR_POLARITY = 1;
parameter SR_SYNC = 0;
parameter SR_VALUE = 0;
parameter SR_SYNC_PRIORITY = 0;
parameter D_POLARITY = 1;
endmodule
module EFX_GBUFCE(
input CE,
input I,
output O
);
parameter CE_POLARITY = 1'b1;
endmodule
module EFX_RAM_5K(
input [WRITE_WIDTH-1:0] WDATA,
input [WRITE_ADDR_WIDTH-1:0] WADDR,
input WE,
input WCLK,
input WCLKE,
output [READ_WIDTH-1:0] RDATA,
input [READ_ADDR_WIDTH-1:0] RADDR,
input RE,
input RCLK
);
parameter READ_WIDTH = 20;
parameter WRITE_WIDTH = 20;
parameter OUTPUT_REG = 1'b0;
parameter RCLK_POLARITY = 1'b1;
parameter RE_POLARITY = 1'b1;
parameter WCLK_POLARITY = 1'b1;
parameter WE_POLARITY = 1'b1;
parameter WCLKE_POLARITY = 1'b1;
parameter WRITE_MODE = "READ_FIRST";
parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
localparam READ_ADDR_WIDTH =
(READ_WIDTH == 16) ? 8 : // 256x16
(READ_WIDTH == 8) ? 9 : // 512x8
(READ_WIDTH == 4) ? 10 : // 1024x4
(READ_WIDTH == 2) ? 11 : // 2048x2
(READ_WIDTH == 1) ? 12 : // 4096x1
(READ_WIDTH == 20) ? 8 : // 256x20
(READ_WIDTH == 10) ? 9 : // 512x10
(READ_WIDTH == 5) ? 10 : -1; // 1024x5
localparam WRITE_ADDR_WIDTH =
(WRITE_WIDTH == 16) ? 8 : // 256x16
(WRITE_WIDTH == 8) ? 9 : // 512x8
(WRITE_WIDTH == 4) ? 10 : // 1024x4
(WRITE_WIDTH == 2) ? 11 : // 2048x2
(WRITE_WIDTH == 1) ? 12 : // 4096x1
(WRITE_WIDTH == 20) ? 8 : // 256x20
(WRITE_WIDTH == 10) ? 9 : // 512x10
(WRITE_WIDTH == 5) ? 10 : -1; // 1024x5
endmodule

View file

@ -0,0 +1,122 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static SigBit get_bit_or_zero(const SigSpec &sig)
{
if (GetSize(sig) == 0)
return State::S0;
return sig[0];
}
static void fix_carry_chain(Module *module)
{
SigMap sigmap(module);
pool<SigBit> ci_bits;
dict<SigBit, SigBit> mapping_bits;
for (auto cell : module->cells())
{
if (cell->type == "\\EFX_ADD") {
SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0"));
SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1"));
if (bit_i0 == State::S0 && bit_i1== State::S0) {
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
SigBit bit_o = sigmap(cell->getPort("\\O"));
ci_bits.insert(bit_ci);
mapping_bits[bit_ci] = bit_o;
}
}
}
vector<Cell*> adders_to_fix_cells;
for (auto cell : module->cells())
{
if (cell->type == "\\EFX_ADD") {
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0"));
SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1"));
SigBit canonical_bit = sigmap(bit_ci);
if (!ci_bits.count(canonical_bit))
continue;
if (bit_i0 == State::S0 && bit_i1== State::S0)
continue;
adders_to_fix_cells.push_back(cell);
log("Found %s cell named %s with invalid CI signal.\n", log_id(cell->type), log_id(cell));
}
}
for (auto cell : adders_to_fix_cells)
{
SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
SigBit canonical_bit = sigmap(bit_ci);
auto bit = mapping_bits.at(canonical_bit);
log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell));
Cell *c = module->addCell(NEW_ID, "\\EFX_ADD");
SigBit new_bit = module->addWire(NEW_ID);
c->setParam("\\I0_POLARITY", State::S1);
c->setParam("\\I1_POLARITY", State::S1);
c->setPort("\\I0", bit);
c->setPort("\\I1", State::S1);
c->setPort("\\CI", State::S0);
c->setPort("\\CO", new_bit);
cell->setPort("\\CI", new_bit);
}
}
struct EfinixCarryFixPass : public Pass {
EfinixCarryFixPass() : Pass("efinix_fixcarry", "Efinix: fix carry chain") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" efinix_fixcarry [options] [selection]\n");
log("\n");
log("Add Efinix adders to fix carry chain if needed.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing efinix_fixcarry pass (fix invalid carry chain).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
break;
}
extra_args(args, argidx, design);
Module *module = design->top_module();
if (module == nullptr)
log_cmd_error("No top module found.\n");
fix_carry_chain(module);
}
} EfinixCarryFixPass;
PRIVATE_NAMESPACE_END

View file

@ -0,0 +1,119 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static void handle_gbufs(Module *module)
{
SigMap sigmap(module);
pool<SigBit> clk_bits;
dict<SigBit, SigBit> rewrite_bits;
vector<pair<Cell*, SigBit>> pad_bits;
for (auto cell : module->cells())
{
if (cell->type == "\\EFX_FF") {
for (auto bit : sigmap(cell->getPort("\\CLK")))
clk_bits.insert(bit);
}
if (cell->type == "\\EFX_RAM_5K") {
for (auto bit : sigmap(cell->getPort("\\RCLK")))
clk_bits.insert(bit);
for (auto bit : sigmap(cell->getPort("\\WCLK")))
clk_bits.insert(bit);
}
}
for (auto wire : vector<Wire*>(module->wires()))
{
if (!wire->port_input)
continue;
for (int index = 0; index < GetSize(wire); index++)
{
SigBit bit(wire, index);
SigBit canonical_bit = sigmap(bit);
if (!clk_bits.count(canonical_bit))
continue;
Cell *c = module->addCell(NEW_ID, "\\EFX_GBUFCE");
SigBit new_bit = module->addWire(NEW_ID);
c->setParam("\\CE_POLARITY", State::S1);
c->setPort("\\O", new_bit);
c->setPort("\\CE", State::S1);
pad_bits.push_back(make_pair(c, bit));
rewrite_bits[canonical_bit] = new_bit;
log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit));
}
}
auto rewrite_function = [&](SigSpec &s) {
for (auto &bit : s) {
SigBit canonical_bit = sigmap(bit);
if (rewrite_bits.count(canonical_bit))
bit = rewrite_bits.at(canonical_bit);
}
};
module->rewrite_sigspecs(rewrite_function);
for (auto &it : pad_bits)
it.first->setPort("\\I", it.second);
}
struct EfinixGbufPass : public Pass {
EfinixGbufPass() : Pass("efinix_gbuf", "Efinix: insert global clock buffers") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" efinix_gbuf [options] [selection]\n");
log("\n");
log("Add Efinix global clock buffers to top module as needed.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing efinix_gbuf pass (insert global clock buffers).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
break;
}
extra_args(args, argidx, design);
Module *module = design->top_module();
if (module == nullptr)
log_cmd_error("No top module found.\n");
handle_gbufs(module);
}
} EfinixGbufPass;
PRIVATE_NAMESPACE_END

View file

@ -0,0 +1,219 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
* Copyright (C) 2019 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct SynthEfinixPass : public ScriptPass
{
SynthEfinixPass() : ScriptPass("synth_efinix", "synthesis for Efinix FPGAs") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" synth_efinix [options]\n");
log("\n");
log("This command runs synthesis for Efinix FPGAs.\n");
log("\n");
log(" -top <module>\n");
log(" use the specified module as top module\n");
log("\n");
log(" -edif <file>\n");
log(" write the design to the specified EDIF file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -json <file>\n");
log(" write the design to the specified JSON file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n");
log(" from label is synonymous to 'begin', and empty to label is\n");
log(" synonymous to the end of the command list.\n");
log("\n");
log(" -noflatten\n");
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
string top_opt, edif_file, json_file;
bool flatten, retime;
void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
edif_file = "";
json_file = "";
flatten = true;
retime = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
clear_flags();
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-top" && argidx+1 < args.size()) {
top_opt = "-top " + args[++argidx];
continue;
}
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
edif_file = args[++argidx];
continue;
}
if (args[argidx] == "-json" && argidx+1 < args.size()) {
json_file = args[++argidx];
continue;
}
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos)
break;
run_from = args[++argidx].substr(0, pos);
run_to = args[argidx].substr(pos+1);
continue;
}
if (args[argidx] == "-noflatten") {
flatten = false;
continue;
}
if (args[argidx] == "-retime") {
retime = true;
continue;
}
break;
}
extra_args(args, argidx, design);
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_EFINIX pass.\n");
log_push();
run_script(design, run_from, run_to);
log_pop();
}
void script() YS_OVERRIDE
{
if (check_label("begin"))
{
run("read_verilog -lib +/efinix/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
if (flatten && check_label("flatten", "(unless -noflatten)"))
{
run("proc");
run("flatten");
run("tribuf -logic");
run("deminout");
}
if (check_label("coarse"))
{
run("synth -run coarse");
}
if (check_label("map_bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/efinix/bram.txt");
run("techmap -map +/efinix/brams_map.v");
run("setundef -zero -params t:EFX_RAM_5K");
}
if (check_label("fine"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
run("techmap -map +/techmap.v -map +/efinix/arith_map.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
}
if (check_label("map_ffs"))
{
run("dffsr2dff");
run("techmap -D NO_LUT -map +/efinix/cells_map.v");
run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit");
run("opt_expr -mux_undef");
run("simplemap");
}
if (check_label("map_luts"))
{
run("abc -lut 4");
run("clean");
}
if (check_label("map_cells"))
{
run("techmap -map +/efinix/cells_map.v");
run("clean");
}
if (check_label("map_gbuf"))
{
run("efinix_gbuf");
run("efinix_fixcarry");
run("clean");
}
if (check_label("check"))
{
run("hierarchy -check");
run("stat");
run("check -noinit");
}
if (check_label("edif"))
{
if (!edif_file.empty() || help_mode)
run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
}
if (check_label("json"))
{
if (!json_file.empty() || help_mode)
run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
}
}
} SynthEfinixPass;
PRIVATE_NAMESPACE_END

View file

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

View file

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

View file

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

View file

@ -142,13 +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 *) output CO, (* abc_carry *)
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),
@ -156,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

View file

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

View file

@ -29,24 +29,35 @@ module GND(output G);
assign G = 0; assign G = 0;
endmodule endmodule
module IBUF(output O, input I); module IBUF(
output O,
(* iopad_external_pin *)
input I);
parameter IOSTANDARD = "default"; parameter IOSTANDARD = "default";
parameter IBUF_LOW_PWR = 0; parameter IBUF_LOW_PWR = 0;
assign O = I; assign O = I;
endmodule endmodule
module OBUF(output O, input I); module OBUF(
(* iopad_external_pin *)
output O,
input I);
parameter IOSTANDARD = "default"; parameter IOSTANDARD = "default";
parameter DRIVE = 12; parameter DRIVE = 12;
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
assign O = I; assign O = I;
endmodule endmodule
module BUFG(output O, input I); module BUFG(
(* clkbuf_driver *)
output O,
input I);
assign O = I; assign O = I;
endmodule endmodule
module BUFGCTRL( module BUFGCTRL(
(* clkbuf_driver *)
output O, output O,
input I0, input I1, input I0, input I1,
input S0, input S1, input S0, input S1,
@ -72,7 +83,11 @@ assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT);
endmodule endmodule
module BUFHCE(output O, input I, input CE); module BUFHCE(
(* clkbuf_driver *)
output O,
input I,
input CE);
parameter [0:0] INIT_OUT = 1'b0; parameter [0:0] INIT_OUT = 1'b0;
parameter CE_TYPE = "SYNC"; parameter CE_TYPE = "SYNC";
@ -183,9 +198,11 @@ endmodule
(* abc_box_id = 4, lib_whitebox *) (* abc_box_id = 4, lib_whitebox *)
module CARRY4( module CARRY4(
(* abc_carry *) output [3:0] CO, (* abc_carry *)
output [3:0] CO,
output [3:0] O, output [3:0] O,
(* abc_carry *) input CI, (* abc_carry *)
input CI,
input CYINIT, input CYINIT,
input [3:0] DI, S input [3:0] DI, S
); );
@ -219,7 +236,7 @@ endmodule
`endif `endif
module FDRE (output reg Q, input C, CE, D, R); module FDRE (output reg Q, (* clkbuf_sink *) input C, input CE, D, R);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0;
@ -231,7 +248,7 @@ module FDRE (output reg Q, input C, CE, D, R);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDSE (output reg Q, input C, CE, D, S); module FDSE (output reg Q, (* clkbuf_sink *) input C, input CE, D, S);
parameter [0:0] INIT = 1'b1; parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0;
@ -243,7 +260,7 @@ module FDSE (output reg Q, input C, CE, D, S);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDCE (output reg Q, input C, CE, D, CLR); module FDCE (output reg Q, (* clkbuf_sink *) input C, input CE, D, CLR);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0;
@ -257,7 +274,7 @@ module FDCE (output reg Q, input C, CE, D, CLR);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDPE (output reg Q, input C, CE, D, PRE); module FDPE (output reg Q, (* clkbuf_sink *) input C, input CE, D, PRE);
parameter [0:0] INIT = 1'b1; parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0;
@ -271,25 +288,25 @@ module FDPE (output reg Q, input C, CE, D, PRE);
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDRE_1 (output reg Q, input C, CE, D, R); module FDRE_1 (output reg Q, (* clkbuf_sink *) input C, input CE, D, R);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
endmodule endmodule
module FDSE_1 (output reg Q, input C, CE, D, S); module FDSE_1 (output reg Q, (* clkbuf_sink *) input C, input CE, D, S);
parameter [0:0] INIT = 1'b1; parameter [0:0] INIT = 1'b1;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
endmodule endmodule
module FDCE_1 (output reg Q, input C, CE, D, CLR); module FDCE_1 (output reg Q, (* clkbuf_sink *) input C, input CE, D, CLR);
parameter [0:0] INIT = 1'b0; parameter [0:0] INIT = 1'b0;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
endmodule endmodule
module FDPE_1 (output reg Q, input C, CE, D, PRE); module FDPE_1 (output reg Q, (* clkbuf_sink *) input C, input CE, D, PRE);
parameter [0:0] INIT = 1'b1; parameter [0:0] INIT = 1'b1;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
@ -298,9 +315,12 @@ endmodule
(* abc_box_id = 5 *) (* abc_box_id = 5 *)
module RAM32X1D ( module RAM32X1D (
output DPO, SPO, output DPO, SPO,
(* abc_scc_break *) input D, (* abc_scc_break *)
input D,
(* clkbuf_sink *)
input WCLK, input WCLK,
(* abc_scc_break *) input WE, (* abc_scc_break *)
input WE,
input A0, A1, A2, A3, A4, input A0, A1, A2, A3, A4,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
); );
@ -318,9 +338,12 @@ endmodule
(* abc_box_id = 6 *) (* abc_box_id = 6 *)
module RAM64X1D ( module RAM64X1D (
output DPO, SPO, output DPO, SPO,
(* abc_scc_break *) input D, (* abc_scc_break *)
input D,
(* clkbuf_sink *)
input WCLK, input WCLK,
(* abc_scc_break *) input WE, (* abc_scc_break *)
input WE,
input A0, A1, A2, A3, A4, A5, input A0, A1, A2, A3, A4, A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
); );
@ -338,9 +361,12 @@ endmodule
(* abc_box_id = 7 *) (* abc_box_id = 7 *)
module RAM128X1D ( module RAM128X1D (
output DPO, SPO, output DPO, SPO,
(* abc_scc_break *) input D, (* abc_scc_break *)
input D,
(* clkbuf_sink *)
input WCLK, input WCLK,
(* abc_scc_break *) input WE, (* abc_scc_break *)
input WE,
input [6:0] A, DPRA input [6:0] A, DPRA
); );
parameter INIT = 128'h0; parameter INIT = 128'h0;
@ -354,7 +380,10 @@ endmodule
module SRL16E ( module SRL16E (
output Q, output Q,
input A0, A1, A2, A3, CE, CLK, D input A0, A1, A2, A3, CE,
(* clkbuf_sink *)
input CLK,
input D
); );
parameter [15:0] INIT = 16'h0000; parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0; parameter [0:0] IS_CLK_INVERTED = 1'b0;
@ -366,7 +395,30 @@ module SRL16E (
always @(negedge CLK) if (CE) r <= { r[14:0], D }; always @(negedge CLK) if (CE) r <= { r[14:0], D };
end end
else else
always @(posedge CLK) if (CE) r <= { r[14:0], D }; always @(posedge CLK) if (CE) r <= { r[14:0], D };
endgenerate
endmodule
module SRLC16E (
output Q,
output Q15,
input A0, A1, A2, A3, CE,
(* clkbuf_sink *)
input CLK,
input D
);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
reg [15:0] r = INIT;
assign Q15 = r[15];
assign Q = r[{A3,A2,A1,A0}];
generate
if (IS_CLK_INVERTED) begin
always @(negedge CLK) if (CE) r <= { r[14:0], D };
end
else
always @(posedge CLK) if (CE) r <= { r[14:0], D };
endgenerate endgenerate
endmodule endmodule
@ -374,7 +426,10 @@ module SRLC32E (
output Q, output Q,
output Q31, output Q31,
input [4:0] A, input [4:0] A,
input CE, CLK, D input CE,
(* clkbuf_sink *)
input CLK,
input D
); );
parameter [31:0] INIT = 32'h00000000; parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0; parameter [0:0] IS_CLK_INVERTED = 1'b0;
@ -425,7 +480,7 @@ module DSP48E1 (
input CEINMODE, input CEINMODE,
input CEM, input CEM,
input CEP, input CEP,
input CLK, (* clkbuf_sink *) input CLK,
input [24:0] D, input [24:0] D,
input [4:0] INMODE, input [4:0] INMODE,
input MULTSIGNIN, input MULTSIGNIN,

View file

@ -0,0 +1,257 @@
#!/usr/bin/env python3
from argparse import ArgumentParser
from io import StringIO
from enum import Enum, auto
import os.path
import sys
class Cell:
def __init__(self, name, keep=False, port_attrs={}):
self.name = name
self.keep = keep
self.port_attrs = port_attrs
CELLS = [
# Design elements types listed in Xilinx UG953
Cell('BSCANE2', keep=True),
# Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}),
#Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}),
#Cell('BUFHCE', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFIO', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFMR', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFMRCE', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFR', port_attrs={'O': ['clkbuf_driver']}),
Cell('CAPTUREE2', keep=True),
# Cell('CARRY4'),
Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}),
Cell('DCIRESET', keep=True),
Cell('DNA_PORT'),
Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}),
Cell('EFUSE_USR'),
# Cell('FDCE'),
# Cell('FDPE'),
# Cell('FDRE'),
# Cell('FDSE'),
Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
Cell('FRAME_ECCE2'),
Cell('GTHE2_CHANNEL'),
Cell('GTHE2_COMMON'),
Cell('GTPE2_CHANNEL'),
Cell('GTPE2_COMMON'),
Cell('GTXE2_CHANNEL'),
Cell('GTXE2_COMMON'),
# Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUF_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUF_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_DIFF_OUT_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_GTE2', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('ICAPE2', keep=True),
Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}),
Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}),
Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}),
Cell('IDELAYE2', port_attrs={'C': ['clkbuf_sink']}),
Cell('IN_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IOBUFDS_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
Cell('IOBUFDS_DIFF_OUT', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
Cell('IOBUFDS_DIFF_OUT_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
Cell('IOBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
Cell('ISERDESE2', port_attrs={
'CLK': ['clkbuf_sink'],
'CLKB': ['clkbuf_sink'],
'OCLK': ['clkbuf_sink'],
'OCLKB': ['clkbuf_sink'],
'CLKDIV': ['clkbuf_sink'],
'CLKDIVP': ['clkbuf_sink'],
}),
Cell('KEEPER'),
Cell('LDCE'),
Cell('LDPE'),
# Cell('LUT1'),
# Cell('LUT2'),
# Cell('LUT3'),
# Cell('LUT4'),
# Cell('LUT5'),
# Cell('LUT6'),
#Cell('LUT6_2'),
Cell('MMCME2_ADV'),
Cell('MMCME2_BASE'),
# Cell('MUXF7'),
# Cell('MUXF8'),
# Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}),
Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}),
Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}),
Cell('ODELAYE2', port_attrs={'C': ['clkbuf_sink']}),
Cell('OSERDESE2', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}),
Cell('OUT_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
Cell('PHASER_IN'),
Cell('PHASER_IN_PHY'),
Cell('PHASER_OUT'),
Cell('PHASER_OUT_PHY'),
Cell('PHASER_REF'),
Cell('PHY_CONTROL'),
Cell('PLLE2_ADV'),
Cell('PLLE2_BASE'),
Cell('PS7', keep=True),
Cell('PULLDOWN'),
Cell('PULLUP'),
#Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}),
#Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}),
#Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}),
# Cell('RAMB18E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}),
# Cell('RAMB36E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}),
Cell('ROM128X1'),
Cell('ROM256X1'),
Cell('ROM32X1'),
Cell('ROM64X1'),
#Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}),
#Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}),
Cell('STARTUPE2', keep=True),
Cell('USR_ACCESSE2'),
Cell('XADC'),
]
class State(Enum):
OUTSIDE = auto()
IN_MODULE = auto()
IN_OTHER_MODULE = auto()
IN_FUNCTION = auto()
IN_TASK = auto()
def xtract_cell_decl(cell, dirs, outf):
for dir in dirs:
fname = os.path.join(dir, cell.name + '.v')
try:
with open(fname) as f:
state = State.OUTSIDE
found = False
# Probably the most horrible Verilog "parser" ever written.
for l in f:
l = l.partition('//')[0]
l = l.strip()
if l == 'module {}'.format(cell.name) or l.startswith('module {} '.format(cell.name)):
if found:
print('Multiple modules in {}.'.format(fname))
sys.exit(1)
elif state != State.OUTSIDE:
print('Nested modules in {}.'.format(fname))
sys.exit(1)
found = True
state = State.IN_MODULE
if cell.keep:
outf.write('(* keep *)\n')
outf.write('module {} (...);\n'.format(cell.name))
elif l.startswith('module '):
if state != State.OUTSIDE:
print('Nested modules in {}.'.format(fname))
sys.exit(1)
state = State.IN_OTHER_MODULE
elif l.startswith('task '):
if state == State.IN_MODULE:
state = State.IN_TASK
elif l.startswith('function '):
if state == State.IN_MODULE:
state = State.IN_FUNCTION
elif l == 'endtask':
if state == State.IN_TASK:
state = State.IN_MODULE
elif l == 'endfunction':
if state == State.IN_FUNCTION:
state = State.IN_MODULE
elif l == 'endmodule':
if state == State.IN_MODULE:
outf.write(l + '\n')
outf.write('\n')
elif state != State.IN_OTHER_MODULE:
print('endmodule in weird place in {}.'.format(cell.name, fname))
sys.exit(1)
state = State.OUTSIDE
elif l.startswith(('input ', 'output ', 'inout ')) and state == State.IN_MODULE:
if l.endswith((';', ',')):
l = l[:-1]
if ';' in l:
print('Weird port line in {} [{}].'.format(fname, l))
sys.exit(1)
kind, _, ports = l.partition(' ')
for port in ports.split(','):
port = port.strip()
for attr in cell.port_attrs.get(port, []):
outf.write(' (* {} *)\n'.format(attr))
outf.write(' {} {};\n'.format(kind, port))
elif l.startswith('parameter ') and state == State.IN_MODULE:
if 'UNPLACED' in l:
continue
if l.endswith((';', ',')):
l = l[:-1]
while ' ' in l:
l = l.replace(' ', ' ')
if ';' in l:
print('Weird parameter line in {} [{}].'.format(fname, l))
sys.exit(1)
outf.write(' {};\n'.format(l))
if state != State.OUTSIDE:
print('endmodule not found in {}.'.format(fname))
sys.exit(1)
if not found:
print('Cannot find module {} in {}.'.format(cell.name, fname))
sys.exit(1)
return
except FileNotFoundError:
continue
print('Cannot find {}.'.format(cell.name))
sys.exit(1)
if __name__ == '__main__':
parser = ArgumentParser(description='Extract Xilinx blackbox cell definitions from Vivado.')
parser.add_argument('vivado_dir', nargs='?', default='/opt/Xilinx/Vivado/2018.1')
args = parser.parse_args()
dirs = [
os.path.join(args.vivado_dir, 'data/verilog/src/xeclib'),
os.path.join(args.vivado_dir, 'data/verilog/src/retarget'),
]
for dir in dirs:
if not os.path.isdir(dir):
print('{} is not a directory'.format(dir))
out = StringIO()
for cell in CELLS:
xtract_cell_decl(cell, dirs, out)
with open('cells_xtra.v', 'w') as f:
f.write('// Created by cells_xtra.py from Xilinx models\n')
f.write('\n')
f.write(out.getvalue())

View file

@ -1,147 +0,0 @@
#!/bin/bash
set -e
libdir="/opt/Xilinx/Vivado/2018.1/data/verilog/src"
function xtract_cell_decl()
{
for dir in $libdir/xeclib $libdir/retarget; do
[ -f $dir/$1.v ] || continue
[ -z "$2" ] || echo $2
egrep '^\s*((end)?module|parameter|input|inout|output|(end)?function|(end)?task)' $dir/$1.v |
sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d;
s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/;
s/\s+$//; s/,$/;/; /input|output|parameter/ s/[^;]$/&;/; s/\s+/ /g;
s/^ ((end)?module)/\1/; s/^ / /; /module.*_bb/,/endmodule/ d;'
echo; return
done
echo "Can't find $1."
exit 1
}
{
echo "// Created by cells_xtra.sh from Xilinx models"
echo
# Design elements types listed in Xilinx UG953
xtract_cell_decl BSCANE2
# xtract_cell_decl BUFG
xtract_cell_decl BUFGCE
xtract_cell_decl BUFGCE_1
#xtract_cell_decl BUFGCTRL
xtract_cell_decl BUFGMUX
xtract_cell_decl BUFGMUX_1
xtract_cell_decl BUFGMUX_CTRL
xtract_cell_decl BUFH
#xtract_cell_decl BUFHCE
xtract_cell_decl BUFIO
xtract_cell_decl BUFMR
xtract_cell_decl BUFMRCE
xtract_cell_decl BUFR
xtract_cell_decl CAPTUREE2 "(* keep *)"
# xtract_cell_decl CARRY4
xtract_cell_decl CFGLUT5
xtract_cell_decl DCIRESET "(* keep *)"
xtract_cell_decl DNA_PORT
xtract_cell_decl DSP48E1
xtract_cell_decl EFUSE_USR
# xtract_cell_decl FDCE
# xtract_cell_decl FDPE
# xtract_cell_decl FDRE
# xtract_cell_decl FDSE
xtract_cell_decl FIFO18E1
xtract_cell_decl FIFO36E1
xtract_cell_decl FRAME_ECCE2
xtract_cell_decl GTHE2_CHANNEL
xtract_cell_decl GTHE2_COMMON
xtract_cell_decl GTPE2_CHANNEL
xtract_cell_decl GTPE2_COMMON
xtract_cell_decl GTXE2_CHANNEL
xtract_cell_decl GTXE2_COMMON
# xtract_cell_decl IBUF
xtract_cell_decl IBUF_IBUFDISABLE
xtract_cell_decl IBUF_INTERMDISABLE
xtract_cell_decl IBUFDS
xtract_cell_decl IBUFDS_DIFF_OUT
xtract_cell_decl IBUFDS_DIFF_OUT_IBUFDISABLE
xtract_cell_decl IBUFDS_DIFF_OUT_INTERMDISABLE
xtract_cell_decl IBUFDS_GTE2
xtract_cell_decl IBUFDS_IBUFDISABLE
xtract_cell_decl IBUFDS_INTERMDISABLE
xtract_cell_decl ICAPE2 "(* keep *)"
xtract_cell_decl IDDR
xtract_cell_decl IDDR_2CLK
xtract_cell_decl IDELAYCTRL "(* keep *)"
xtract_cell_decl IDELAYE2
xtract_cell_decl IN_FIFO
xtract_cell_decl IOBUF
xtract_cell_decl IOBUF_DCIEN
xtract_cell_decl IOBUF_INTERMDISABLE
xtract_cell_decl IOBUFDS
xtract_cell_decl IOBUFDS_DCIEN
xtract_cell_decl IOBUFDS_DIFF_OUT
xtract_cell_decl IOBUFDS_DIFF_OUT_DCIEN
xtract_cell_decl IOBUFDS_DIFF_OUT_INTERMDISABLE
xtract_cell_decl ISERDESE2
xtract_cell_decl KEEPER
xtract_cell_decl LDCE
xtract_cell_decl LDPE
# xtract_cell_decl LUT1
# xtract_cell_decl LUT2
# xtract_cell_decl LUT3
# xtract_cell_decl LUT4
# xtract_cell_decl LUT5
# xtract_cell_decl LUT6
#xtract_cell_decl LUT6_2
xtract_cell_decl MMCME2_ADV
xtract_cell_decl MMCME2_BASE
# xtract_cell_decl MUXF7
# xtract_cell_decl MUXF8
# xtract_cell_decl OBUF
xtract_cell_decl OBUFDS
xtract_cell_decl OBUFT
xtract_cell_decl OBUFTDS
xtract_cell_decl ODDR
xtract_cell_decl ODELAYE2
xtract_cell_decl OSERDESE2
xtract_cell_decl OUT_FIFO
xtract_cell_decl PHASER_IN
xtract_cell_decl PHASER_IN_PHY
xtract_cell_decl PHASER_OUT
xtract_cell_decl PHASER_OUT_PHY
xtract_cell_decl PHASER_REF
xtract_cell_decl PHY_CONTROL
xtract_cell_decl PLLE2_ADV
xtract_cell_decl PLLE2_BASE
xtract_cell_decl PS7 "(* keep *)"
xtract_cell_decl PULLDOWN
xtract_cell_decl PULLUP
#xtract_cell_decl RAM128X1D
xtract_cell_decl RAM128X1S
xtract_cell_decl RAM256X1S
xtract_cell_decl RAM32M
#xtract_cell_decl RAM32X1D
xtract_cell_decl RAM32X1S
xtract_cell_decl RAM32X1S_1
xtract_cell_decl RAM32X2S
xtract_cell_decl RAM64M
#xtract_cell_decl RAM64X1D
xtract_cell_decl RAM64X1S
xtract_cell_decl RAM64X1S_1
xtract_cell_decl RAM64X2S
# xtract_cell_decl RAMB18E1
# xtract_cell_decl RAMB36E1
xtract_cell_decl ROM128X1
xtract_cell_decl ROM256X1
xtract_cell_decl ROM32X1
xtract_cell_decl ROM64X1
#xtract_cell_decl SRL16E
#xtract_cell_decl SRLC32E
xtract_cell_decl STARTUPE2 "(* keep *)"
xtract_cell_decl USR_ACCESSE2
xtract_cell_decl XADC
} > cells_xtra.new
mv cells_xtra.new cells_xtra.v
exit 0

View file

@ -1,5 +1,6 @@
// Created by cells_xtra.sh from Xilinx models // Created by cells_xtra.py from Xilinx models
(* keep *)
module BSCANE2 (...); module BSCANE2 (...);
parameter DISABLE_JTAG = "FALSE"; parameter DISABLE_JTAG = "FALSE";
parameter integer JTAG_CHAIN = 1; parameter integer JTAG_CHAIN = 1;
@ -20,29 +21,39 @@ module BUFGCE (...);
parameter CE_TYPE = "SYNC"; parameter CE_TYPE = "SYNC";
parameter [0:0] IS_CE_INVERTED = 1'b0; parameter [0:0] IS_CE_INVERTED = 1'b0;
parameter [0:0] IS_I_INVERTED = 1'b0; parameter [0:0] IS_I_INVERTED = 1'b0;
(* clkbuf_driver *)
output O; output O;
input CE; input CE;
input I; input I;
endmodule endmodule
module BUFGCE_1 (...); module BUFGCE_1 (...);
(* clkbuf_driver *)
output O; output O;
input CE, I; input CE;
input I;
endmodule endmodule
module BUFGMUX (...); module BUFGMUX (...);
parameter CLK_SEL_TYPE = "SYNC"; parameter CLK_SEL_TYPE = "SYNC";
(* clkbuf_driver *)
output O; output O;
input I0, I1, S; input I0;
input I1;
input S;
endmodule endmodule
module BUFGMUX_1 (...); module BUFGMUX_1 (...);
parameter CLK_SEL_TYPE = "SYNC"; parameter CLK_SEL_TYPE = "SYNC";
(* clkbuf_driver *)
output O; output O;
input I0, I1, S; input I0;
input I1;
input S;
endmodule endmodule
module BUFGMUX_CTRL (...); module BUFGMUX_CTRL (...);
(* clkbuf_driver *)
output O; output O;
input I0; input I0;
input I1; input I1;
@ -50,16 +61,19 @@ module BUFGMUX_CTRL (...);
endmodule endmodule
module BUFH (...); module BUFH (...);
(* clkbuf_driver *)
output O; output O;
input I; input I;
endmodule endmodule
module BUFIO (...); module BUFIO (...);
(* clkbuf_driver *)
output O; output O;
input I; input I;
endmodule endmodule
module BUFMR (...); module BUFMR (...);
(* clkbuf_driver *)
output O; output O;
input I; input I;
endmodule endmodule
@ -68,12 +82,14 @@ module BUFMRCE (...);
parameter CE_TYPE = "SYNC"; parameter CE_TYPE = "SYNC";
parameter integer INIT_OUT = 0; parameter integer INIT_OUT = 0;
parameter [0:0] IS_CE_INVERTED = 1'b0; parameter [0:0] IS_CE_INVERTED = 1'b0;
(* clkbuf_driver *)
output O; output O;
input CE; input CE;
input I; input I;
endmodule endmodule
module BUFR (...); module BUFR (...);
(* clkbuf_driver *)
output O; output O;
input CE; input CE;
input CLR; input CLR;
@ -95,8 +111,15 @@ module CFGLUT5 (...);
output CDO; output CDO;
output O5; output O5;
output O6; output O6;
input I4, I3, I2, I1, I0; input I4;
input CDI, CE, CLK; input I3;
input I2;
input I1;
input I0;
input CDI;
input CE;
(* clkbuf_sink *)
input CLK;
endmodule endmodule
(* keep *) (* keep *)
@ -108,7 +131,10 @@ endmodule
module DNA_PORT (...); module DNA_PORT (...);
parameter [56:0] SIM_DNA_VALUE = 57'h0; parameter [56:0] SIM_DNA_VALUE = 57'h0;
output DOUT; output DOUT;
input CLK, DIN, READ, SHIFT; input CLK;
input DIN;
input READ;
input SHIFT;
endmodule endmodule
module EFUSE_USR (...); module EFUSE_USR (...);
@ -145,11 +171,13 @@ module FIFO18E1 (...);
output WRERR; output WRERR;
input [31:0] DI; input [31:0] DI;
input [3:0] DIP; input [3:0] DIP;
(* clkbuf_sink *)
input RDCLK; input RDCLK;
input RDEN; input RDEN;
input REGCE; input REGCE;
input RST; input RST;
input RSTREG; input RSTREG;
(* clkbuf_sink *)
input WRCLK; input WRCLK;
input WREN; input WREN;
endmodule endmodule
@ -190,11 +218,13 @@ module FIFO36E1 (...);
input [7:0] DIP; input [7:0] DIP;
input INJECTDBITERR; input INJECTDBITERR;
input INJECTSBITERR; input INJECTSBITERR;
(* clkbuf_sink *)
input RDCLK; input RDCLK;
input RDEN; input RDEN;
input REGCE; input REGCE;
input RST; input RST;
input RSTREG; input RSTREG;
(* clkbuf_sink *)
input WRCLK; input WRCLK;
input WREN; input WREN;
endmodule endmodule
@ -1887,6 +1917,7 @@ module IBUF_IBUFDISABLE (...);
parameter SIM_DEVICE = "7SERIES"; parameter SIM_DEVICE = "7SERIES";
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
(* iopad_external_pin *)
input I; input I;
input IBUFDISABLE; input IBUFDISABLE;
endmodule endmodule
@ -1897,6 +1928,7 @@ module IBUF_INTERMDISABLE (...);
parameter SIM_DEVICE = "7SERIES"; parameter SIM_DEVICE = "7SERIES";
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
(* iopad_external_pin *)
input I; input I;
input IBUFDISABLE; input IBUFDISABLE;
input INTERMDISABLE; input INTERMDISABLE;
@ -1911,7 +1943,10 @@ module IBUFDS (...);
parameter IFD_DELAY_VALUE = "AUTO"; parameter IFD_DELAY_VALUE = "AUTO";
parameter IOSTANDARD = "DEFAULT"; parameter IOSTANDARD = "DEFAULT";
output O; output O;
input I, IB; (* iopad_external_pin *)
input I;
(* iopad_external_pin *)
input IB;
endmodule endmodule
module IBUFDS_DIFF_OUT (...); module IBUFDS_DIFF_OUT (...);
@ -1919,8 +1954,12 @@ module IBUFDS_DIFF_OUT (...);
parameter DQS_BIAS = "FALSE"; parameter DQS_BIAS = "FALSE";
parameter IBUF_LOW_PWR = "TRUE"; parameter IBUF_LOW_PWR = "TRUE";
parameter IOSTANDARD = "DEFAULT"; parameter IOSTANDARD = "DEFAULT";
output O, OB; output O;
input I, IB; output OB;
(* iopad_external_pin *)
input I;
(* iopad_external_pin *)
input IB;
endmodule endmodule
module IBUFDS_DIFF_OUT_IBUFDISABLE (...); module IBUFDS_DIFF_OUT_IBUFDISABLE (...);
@ -1932,7 +1971,9 @@ module IBUFDS_DIFF_OUT_IBUFDISABLE (...);
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
output OB; output OB;
(* iopad_external_pin *)
input I; input I;
(* iopad_external_pin *)
input IB; input IB;
input IBUFDISABLE; input IBUFDISABLE;
endmodule endmodule
@ -1946,7 +1987,9 @@ module IBUFDS_DIFF_OUT_INTERMDISABLE (...);
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
output OB; output OB;
(* iopad_external_pin *)
input I; input I;
(* iopad_external_pin *)
input IB; input IB;
input IBUFDISABLE; input IBUFDISABLE;
input INTERMDISABLE; input INTERMDISABLE;
@ -1959,7 +2002,9 @@ module IBUFDS_GTE2 (...);
output O; output O;
output ODIV2; output ODIV2;
input CEB; input CEB;
(* iopad_external_pin *)
input I; input I;
(* iopad_external_pin *)
input IB; input IB;
endmodule endmodule
@ -1971,7 +2016,9 @@ module IBUFDS_IBUFDISABLE (...);
parameter SIM_DEVICE = "7SERIES"; parameter SIM_DEVICE = "7SERIES";
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
(* iopad_external_pin *)
input I; input I;
(* iopad_external_pin *)
input IB; input IB;
input IBUFDISABLE; input IBUFDISABLE;
endmodule endmodule
@ -1984,12 +2031,50 @@ module IBUFDS_INTERMDISABLE (...);
parameter SIM_DEVICE = "7SERIES"; parameter SIM_DEVICE = "7SERIES";
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
(* iopad_external_pin *)
input I; input I;
(* iopad_external_pin *)
input IB; input IB;
input IBUFDISABLE; input IBUFDISABLE;
input INTERMDISABLE; input INTERMDISABLE;
endmodule endmodule
module IBUFG (...);
parameter CAPACITANCE = "DONT_CARE";
parameter IBUF_DELAY_VALUE = "0";
parameter IBUF_LOW_PWR = "TRUE";
parameter IOSTANDARD = "DEFAULT";
output O;
(* iopad_external_pin *)
input I;
endmodule
module IBUFGDS (...);
parameter CAPACITANCE = "DONT_CARE";
parameter DIFF_TERM = "FALSE";
parameter IBUF_DELAY_VALUE = "0";
parameter IBUF_LOW_PWR = "TRUE";
parameter IOSTANDARD = "DEFAULT";
output O;
(* iopad_external_pin *)
input I;
(* iopad_external_pin *)
input IB;
endmodule
module IBUFGDS_DIFF_OUT (...);
parameter DIFF_TERM = "FALSE";
parameter DQS_BIAS = "FALSE";
parameter IBUF_LOW_PWR = "TRUE";
parameter IOSTANDARD = "DEFAULT";
output O;
output OB;
(* iopad_external_pin *)
input I;
(* iopad_external_pin *)
input IB;
endmodule
(* keep *) (* keep *)
module ICAPE2 (...); module ICAPE2 (...);
parameter [31:0] DEVICE_ID = 32'h04244093; parameter [31:0] DEVICE_ID = 32'h04244093;
@ -2013,6 +2098,7 @@ module IDDR (...);
parameter XON = "TRUE"; parameter XON = "TRUE";
output Q1; output Q1;
output Q2; output Q2;
(* clkbuf_sink *)
input C; input C;
input CE; input CE;
input D; input D;
@ -2030,7 +2116,9 @@ module IDDR_2CLK (...);
parameter SRTYPE = "SYNC"; parameter SRTYPE = "SYNC";
output Q1; output Q1;
output Q2; output Q2;
(* clkbuf_sink *)
input C; input C;
(* clkbuf_sink *)
input CB; input CB;
input CE; input CE;
input D; input D;
@ -2042,6 +2130,7 @@ endmodule
module IDELAYCTRL (...); module IDELAYCTRL (...);
parameter SIM_DEVICE = "7SERIES"; parameter SIM_DEVICE = "7SERIES";
output RDY; output RDY;
(* clkbuf_sink *)
input REFCLK; input REFCLK;
input RST; input RST;
endmodule endmodule
@ -2061,6 +2150,7 @@ module IDELAYE2 (...);
parameter integer SIM_DELAY_D = 0; parameter integer SIM_DELAY_D = 0;
output [4:0] CNTVALUEOUT; output [4:0] CNTVALUEOUT;
output DATAOUT; output DATAOUT;
(* clkbuf_sink *)
input C; input C;
input CE; input CE;
input CINVCTRL; input CINVCTRL;
@ -2092,9 +2182,11 @@ module IN_FIFO (...);
output [7:0] Q7; output [7:0] Q7;
output [7:0] Q8; output [7:0] Q8;
output [7:0] Q9; output [7:0] Q9;
(* clkbuf_sink *)
input RDCLK; input RDCLK;
input RDEN; input RDEN;
input RESET; input RESET;
(* clkbuf_sink *)
input WRCLK; input WRCLK;
input WREN; input WREN;
input [3:0] D0; input [3:0] D0;
@ -2115,8 +2207,10 @@ module IOBUF (...);
parameter IOSTANDARD = "DEFAULT"; parameter IOSTANDARD = "DEFAULT";
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
output O; output O;
(* iopad_external_pin *)
inout IO; inout IO;
input I, T; input I;
input T;
endmodule endmodule
module IOBUF_DCIEN (...); module IOBUF_DCIEN (...);
@ -2127,6 +2221,7 @@ module IOBUF_DCIEN (...);
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
(* iopad_external_pin *)
inout IO; inout IO;
input DCITERMDISABLE; input DCITERMDISABLE;
input I; input I;
@ -2142,6 +2237,7 @@ module IOBUF_INTERMDISABLE (...);
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
(* iopad_external_pin *)
inout IO; inout IO;
input I; input I;
input IBUFDISABLE; input IBUFDISABLE;
@ -2156,8 +2252,11 @@ module IOBUFDS (...);
parameter IOSTANDARD = "DEFAULT"; parameter IOSTANDARD = "DEFAULT";
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
output O; output O;
inout IO, IOB; (* iopad_external_pin *)
input I, T; inout IO;
inout IOB;
input I;
input T;
endmodule endmodule
module IOBUFDS_DCIEN (...); module IOBUFDS_DCIEN (...);
@ -2169,7 +2268,9 @@ module IOBUFDS_DCIEN (...);
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
(* iopad_external_pin *)
inout IO; inout IO;
(* iopad_external_pin *)
inout IOB; inout IOB;
input DCITERMDISABLE; input DCITERMDISABLE;
input I; input I;
@ -2184,7 +2285,9 @@ module IOBUFDS_DIFF_OUT (...);
parameter IOSTANDARD = "DEFAULT"; parameter IOSTANDARD = "DEFAULT";
output O; output O;
output OB; output OB;
(* iopad_external_pin *)
inout IO; inout IO;
(* iopad_external_pin *)
inout IOB; inout IOB;
input I; input I;
input TM; input TM;
@ -2200,7 +2303,9 @@ module IOBUFDS_DIFF_OUT_DCIEN (...);
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
output OB; output OB;
(* iopad_external_pin *)
inout IO; inout IO;
(* iopad_external_pin *)
inout IOB; inout IOB;
input DCITERMDISABLE; input DCITERMDISABLE;
input I; input I;
@ -2218,7 +2323,9 @@ module IOBUFDS_DIFF_OUT_INTERMDISABLE (...);
parameter USE_IBUFDISABLE = "TRUE"; parameter USE_IBUFDISABLE = "TRUE";
output O; output O;
output OB; output OB;
(* iopad_external_pin *)
inout IO; inout IO;
(* iopad_external_pin *)
inout IOB; inout IOB;
input I; input I;
input IBUFDISABLE; input IBUFDISABLE;
@ -2266,15 +2373,21 @@ module ISERDESE2 (...);
input BITSLIP; input BITSLIP;
input CE1; input CE1;
input CE2; input CE2;
(* clkbuf_sink *)
input CLK; input CLK;
(* clkbuf_sink *)
input CLKB; input CLKB;
(* clkbuf_sink *)
input CLKDIV; input CLKDIV;
(* clkbuf_sink *)
input CLKDIVP; input CLKDIVP;
input D; input D;
input DDLY; input DDLY;
input DYNCLKDIVSEL; input DYNCLKDIVSEL;
input DYNCLKSEL; input DYNCLKSEL;
(* clkbuf_sink *)
input OCLK; input OCLK;
(* clkbuf_sink *)
input OCLKB; input OCLKB;
input OFB; input OFB;
input RST; input RST;
@ -2293,7 +2406,10 @@ module LDCE (...);
parameter MSGON = "TRUE"; parameter MSGON = "TRUE";
parameter XON = "TRUE"; parameter XON = "TRUE";
output Q; output Q;
input CLR, D, G, GE; input CLR;
input D;
input G;
input GE;
endmodule endmodule
module LDPE (...); module LDPE (...);
@ -2303,7 +2419,10 @@ module LDPE (...);
parameter MSGON = "TRUE"; parameter MSGON = "TRUE";
parameter XON = "TRUE"; parameter XON = "TRUE";
output Q; output Q;
input D, G, GE, PRE; input D;
input G;
input GE;
input PRE;
endmodule endmodule
module MMCME2_ADV (...); module MMCME2_ADV (...);
@ -2451,7 +2570,10 @@ module OBUFDS (...);
parameter CAPACITANCE = "DONT_CARE"; parameter CAPACITANCE = "DONT_CARE";
parameter IOSTANDARD = "DEFAULT"; parameter IOSTANDARD = "DEFAULT";
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
output O, OB; (* iopad_external_pin *)
output O;
(* iopad_external_pin *)
output OB;
input I; input I;
endmodule endmodule
@ -2460,20 +2582,27 @@ module OBUFT (...);
parameter integer DRIVE = 12; parameter integer DRIVE = 12;
parameter IOSTANDARD = "DEFAULT"; parameter IOSTANDARD = "DEFAULT";
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
(* iopad_external_pin *)
output O; output O;
input I, T; input I;
input T;
endmodule endmodule
module OBUFTDS (...); module OBUFTDS (...);
parameter CAPACITANCE = "DONT_CARE"; parameter CAPACITANCE = "DONT_CARE";
parameter IOSTANDARD = "DEFAULT"; parameter IOSTANDARD = "DEFAULT";
parameter SLEW = "SLOW"; parameter SLEW = "SLOW";
output O, OB; (* iopad_external_pin *)
input I, T; output O;
(* iopad_external_pin *)
output OB;
input I;
input T;
endmodule endmodule
module ODDR (...); module ODDR (...);
output Q; output Q;
(* clkbuf_sink *)
input C; input C;
input CE; input CE;
input D1; input D1;
@ -2504,6 +2633,7 @@ module ODELAYE2 (...);
parameter integer SIM_DELAY_D = 0; parameter integer SIM_DELAY_D = 0;
output [4:0] CNTVALUEOUT; output [4:0] CNTVALUEOUT;
output DATAOUT; output DATAOUT;
(* clkbuf_sink *)
input C; input C;
input CE; input CE;
input CINVCTRL; input CINVCTRL;
@ -2549,7 +2679,9 @@ module OSERDESE2 (...);
output TBYTEOUT; output TBYTEOUT;
output TFB; output TFB;
output TQ; output TQ;
(* clkbuf_sink *)
input CLK; input CLK;
(* clkbuf_sink *)
input CLKDIV; input CLKDIV;
input D1; input D1;
input D2; input D2;
@ -2591,9 +2723,11 @@ module OUT_FIFO (...);
output [3:0] Q9; output [3:0] Q9;
output [7:0] Q5; output [7:0] Q5;
output [7:0] Q6; output [7:0] Q6;
(* clkbuf_sink *)
input RDCLK; input RDCLK;
input RDEN; input RDEN;
input RESET; input RESET;
(* clkbuf_sink *)
input WRCLK; input WRCLK;
input WREN; input WREN;
input [7:0] D0; input [7:0] D0;
@ -3577,7 +3711,17 @@ module RAM128X1S (...);
parameter [127:0] INIT = 128'h00000000000000000000000000000000; parameter [127:0] INIT = 128'h00000000000000000000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output O; output O;
input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE; input A0;
input A1;
input A2;
input A3;
input A4;
input A5;
input A6;
input D;
(* clkbuf_sink *)
input WCLK;
input WE;
endmodule endmodule
module RAM256X1S (...); module RAM256X1S (...);
@ -3586,6 +3730,7 @@ module RAM256X1S (...);
output O; output O;
input [7:0] A; input [7:0] A;
input D; input D;
(* clkbuf_sink *)
input WCLK; input WCLK;
input WE; input WE;
endmodule endmodule
@ -3608,6 +3753,7 @@ module RAM32M (...);
input [1:0] DIB; input [1:0] DIB;
input [1:0] DIC; input [1:0] DIC;
input [1:0] DID; input [1:0] DID;
(* clkbuf_sink *)
input WCLK; input WCLK;
input WE; input WE;
endmodule endmodule
@ -3616,22 +3762,48 @@ module RAM32X1S (...);
parameter [31:0] INIT = 32'h00000000; parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output O; output O;
input A0, A1, A2, A3, A4, D, WCLK, WE; input A0;
input A1;
input A2;
input A3;
input A4;
input D;
(* clkbuf_sink *)
input WCLK;
input WE;
endmodule endmodule
module RAM32X1S_1 (...); module RAM32X1S_1 (...);
parameter [31:0] INIT = 32'h00000000; parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output O; output O;
input A0, A1, A2, A3, A4, D, WCLK, WE; input A0;
input A1;
input A2;
input A3;
input A4;
input D;
(* clkbuf_sink *)
input WCLK;
input WE;
endmodule endmodule
module RAM32X2S (...); module RAM32X2S (...);
parameter [31:0] INIT_00 = 32'h00000000; parameter [31:0] INIT_00 = 32'h00000000;
parameter [31:0] INIT_01 = 32'h00000000; parameter [31:0] INIT_01 = 32'h00000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output O0, O1; output O0;
input A0, A1, A2, A3, A4, D0, D1, WCLK, WE; output O1;
input A0;
input A1;
input A2;
input A3;
input A4;
input D0;
input D1;
(* clkbuf_sink *)
input WCLK;
input WE;
endmodule endmodule
module RAM64M (...); module RAM64M (...);
@ -3652,6 +3824,7 @@ module RAM64M (...);
input DIB; input DIB;
input DIC; input DIC;
input DID; input DID;
(* clkbuf_sink *)
input WCLK; input WCLK;
input WE; input WE;
endmodule endmodule
@ -3660,46 +3833,97 @@ module RAM64X1S (...);
parameter [63:0] INIT = 64'h0000000000000000; parameter [63:0] INIT = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output O; output O;
input A0, A1, A2, A3, A4, A5, D, WCLK, WE; input A0;
input A1;
input A2;
input A3;
input A4;
input A5;
input D;
(* clkbuf_sink *)
input WCLK;
input WE;
endmodule endmodule
module RAM64X1S_1 (...); module RAM64X1S_1 (...);
parameter [63:0] INIT = 64'h0000000000000000; parameter [63:0] INIT = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output O; output O;
input A0, A1, A2, A3, A4, A5, D, WCLK, WE; input A0;
input A1;
input A2;
input A3;
input A4;
input A5;
input D;
(* clkbuf_sink *)
input WCLK;
input WE;
endmodule endmodule
module RAM64X2S (...); module RAM64X2S (...);
parameter [63:0] INIT_00 = 64'h0000000000000000; parameter [63:0] INIT_00 = 64'h0000000000000000;
parameter [63:0] INIT_01 = 64'h0000000000000000; parameter [63:0] INIT_01 = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
output O0, O1; output O0;
input A0, A1, A2, A3, A4, A5, D0, D1, WCLK, WE; output O1;
input A0;
input A1;
input A2;
input A3;
input A4;
input A5;
input D0;
input D1;
(* clkbuf_sink *)
input WCLK;
input WE;
endmodule endmodule
module ROM128X1 (...); module ROM128X1 (...);
parameter [127:0] INIT = 128'h00000000000000000000000000000000; parameter [127:0] INIT = 128'h00000000000000000000000000000000;
output O; output O;
input A0, A1, A2, A3, A4, A5, A6; input A0;
input A1;
input A2;
input A3;
input A4;
input A5;
input A6;
endmodule endmodule
module ROM256X1 (...); module ROM256X1 (...);
parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000;
output O; output O;
input A0, A1, A2, A3, A4, A5, A6, A7; input A0;
input A1;
input A2;
input A3;
input A4;
input A5;
input A6;
input A7;
endmodule endmodule
module ROM32X1 (...); module ROM32X1 (...);
parameter [31:0] INIT = 32'h00000000; parameter [31:0] INIT = 32'h00000000;
output O; output O;
input A0, A1, A2, A3, A4; input A0;
input A1;
input A2;
input A3;
input A4;
endmodule endmodule
module ROM64X1 (...); module ROM64X1 (...);
parameter [63:0] INIT = 64'h0000000000000000; parameter [63:0] INIT = 64'h0000000000000000;
output O; output O;
input A0, A1, A2, A3, A4, A5; input A0;
input A1;
input A2;
input A3;
input A4;
input A5;
endmodule endmodule
(* keep *) (* keep *)

View file

@ -63,6 +63,9 @@ struct SynthXilinxPass : public ScriptPass
log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" generate an output netlist (and BLIF file) suitable for VPR\n");
log(" (this feature is experimental and incomplete)\n"); log(" (this feature is experimental and incomplete)\n");
log("\n"); log("\n");
log(" -ise\n");
log(" generate an output netlist suitable for ISE (enables -iopad)\n");
log("\n");
log(" -nobram\n"); log(" -nobram\n");
log(" do not use block RAM cells in output netlist\n"); log(" do not use block RAM cells in output netlist\n");
log("\n"); log("\n");
@ -80,6 +83,14 @@ struct SynthXilinxPass : public ScriptPass
log("\n"); log("\n");
log(" -nodsp\n"); log(" -nodsp\n");
log(" do not use DSP48E1s to implement multipliers and associated logic\n"); log(" do not use DSP48E1s to implement multipliers and associated logic\n");
log(" -iopad\n");
log(" enable I/O buffer insertion (selected automatically by -ise)\n");
log("\n");
log(" -noiopad\n");
log(" disable I/O buffer insertion (only useful with -ise)\n");
log("\n");
log(" -noclkbuf\n");
log(" disable automatic clock buffer insertion\n");
log("\n"); log("\n");
log(" -widemux <int>\n"); log(" -widemux <int>\n");
log(" enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n"); log(" enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n");
@ -107,7 +118,8 @@ struct SynthXilinxPass : public ScriptPass
} }
std::string top_opt, edif_file, blif_file, family; std::string top_opt, edif_file, blif_file, family;
bool flatten, retime, vpr, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, abc9; bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, abc9;
bool flatten_before_abc;
int widemux; int widemux;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
@ -119,6 +131,10 @@ struct SynthXilinxPass : public ScriptPass
flatten = false; flatten = false;
retime = false; retime = false;
vpr = false; vpr = false;
ise = false;
iopad = false;
noiopad = false;
noclkbuf = false;
nocarry = false; nocarry = false;
nobram = false; nobram = false;
nolutram = false; nolutram = false;
@ -127,6 +143,7 @@ struct SynthXilinxPass : public ScriptPass
nowidelut = false; nowidelut = false;
nodsp = false; nodsp = false;
abc9 = false; abc9 = false;
flatten_before_abc = false;
widemux = 0; widemux = 0;
} }
@ -166,6 +183,10 @@ struct SynthXilinxPass : public ScriptPass
flatten = true; flatten = true;
continue; continue;
} }
if (args[argidx] == "-flatten_before_abc") {
flatten_before_abc = true;
continue;
}
if (args[argidx] == "-retime") { if (args[argidx] == "-retime") {
retime = true; retime = true;
continue; continue;
@ -182,6 +203,22 @@ struct SynthXilinxPass : public ScriptPass
vpr = true; vpr = true;
continue; continue;
} }
if (args[argidx] == "-ise") {
ise = true;
continue;
}
if (args[argidx] == "-iopad") {
iopad = true;
continue;
}
if (args[argidx] == "-noiopad") {
noiopad = true;
continue;
}
if (args[argidx] == "-noclkbuf") {
noclkbuf = true;
continue;
}
if (args[argidx] == "-nocarry") { if (args[argidx] == "-nocarry") {
nocarry = true; nocarry = true;
continue; continue;
@ -407,6 +444,8 @@ struct SynthXilinxPass : public ScriptPass
if (check_label("map_luts")) { if (check_label("map_luts")) {
run("opt_expr -mux_undef"); run("opt_expr -mux_undef");
if (flatten_before_abc)
run("flatten");
if (help_mode) if (help_mode)
run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut', option for '-retime')"); run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut', option for '-retime')");
else if (abc9) { else if (abc9) {
@ -435,6 +474,18 @@ struct SynthXilinxPass : public ScriptPass
run("clean"); run("clean");
} }
if (check_label("finalize")) {
bool do_iopad = iopad || (ise && !noiopad);
if (help_mode || !noclkbuf) {
if (help_mode || do_iopad)
run("clkbufmap -buf BUFG O:I -inpad IBUFG O:I", "(skip if '-noclkbuf', '-inpad' passed if '-iopad' or '-ise' and not '-noiopad')");
else
run("clkbufmap -buf BUFG O:I");
}
if (do_iopad)
run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I A:top", "(only if '-iopad' or '-ise' and not '-noiopad')");
}
if (check_label("check")) { if (check_label("check")) {
run("hierarchy -check"); run("hierarchy -check");
run("stat -tech xilinx"); run("stat -tech xilinx");

View file

@ -1,5 +1,7 @@
module RAMB8BWER ( module RAMB8BWER (
(* clkbuf_sink *)
input CLKAWRCLK, input CLKAWRCLK,
(* clkbuf_sink *)
input CLKBRDCLK, input CLKBRDCLK,
input ENAWREN, input ENAWREN,
input ENBRDEN, input ENBRDEN,
@ -87,7 +89,9 @@ module RAMB8BWER (
endmodule endmodule
module RAMB16BWER ( module RAMB16BWER (
(* clkbuf_sink *)
input CLKA, input CLKA,
(* clkbuf_sink *)
input CLKB, input CLKB,
input ENA, input ENA,
input ENB, input ENB,

View file

@ -1,5 +1,7 @@
module RAMB18E1 ( module RAMB18E1 (
(* clkbuf_sink *)
input CLKARDCLK, input CLKARDCLK,
(* clkbuf_sink *)
input CLKBWRCLK, input CLKBWRCLK,
input ENARDEN, input ENARDEN,
input ENBWREN, input ENBWREN,
@ -123,7 +125,9 @@ module RAMB18E1 (
endmodule endmodule
module RAMB36E1 ( module RAMB36E1 (
(* clkbuf_sink *)
input CLKARDCLK, input CLKARDCLK,
(* clkbuf_sink *)
input CLKBWRCLK, input CLKBWRCLK,
input ENARDEN, input ENARDEN,
input ENBWREN, input ENBWREN,

26
tests/ice40/ice40_opt.ys Normal file
View file

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

20
tests/ice40/run-test.sh Executable file
View file

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

View file

@ -221,3 +221,73 @@ check
equiv_opt opt_expr -fine equiv_opt opt_expr -fine
design -load postopt design -load postopt
select -assert-count 1 t:$alu r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i select -assert-count 1 t:$alu r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shiftx_1bit(input [2:0] a, input [1:0] b, output y);
\$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shiftx (.A({1'bx,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr
design -load postopt
select -assert-count 1 t:$shiftx r:A_WIDTH=3 %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shiftx_3bit(input [9:0] a, input [3:0] b, output [2:0] y);
\$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shiftx (.A({4'bxx00,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr
design -load postopt
select -assert-count 1 t:$shiftx r:A_WIDTH=12 %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shift_1bit(input [2:0] a, input [1:0] b, output y);
\$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shift (.A({1'b0,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr
design -load postopt
select -assert-count 1 t:$shift r:A_WIDTH=3 %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shift_3bit(input [9:0] a, input [3:0] b, output [2:0] y);
\$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr
design -load postopt
select -assert-count 1 t:$shift r:A_WIDTH=10 %i
###########
design -reset
read_verilog -icells <<EOT
module opt_expr_shift_3bit_keepdc(input [9:0] a, input [3:0] b, output [2:0] y);
\$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y));
endmodule
EOT
check
equiv_opt opt_expr -keepdc
design -load postopt
select -assert-count 1 t:$shift r:A_WIDTH=13 %i

View file

@ -1,6 +1,7 @@
module test(input clk, input [3:0] bar, output [3:0] foo); module test(input clk, input [3:0] bar, output [3:0] foo, asdf);
reg [3:0] foo = 0; reg [3:0] foo = 0;
reg [3:0] last_bar = 0; reg [3:0] last_bar = 0;
reg [3:0] asdf = 4'b1xxx;
always @* always @*
foo[1:0] <= bar[1:0]; foo[1:0] <= bar[1:0];
@ -11,5 +12,10 @@ module test(input clk, input [3:0] bar, output [3:0] foo);
always @(posedge clk) always @(posedge clk)
last_bar <= bar; last_bar <= bar;
always @(posedge clk)
asdf[3] <= bar[3];
always @*
asdf[2:0] = 3'b111;
assert property (foo == {last_bar[3:2], bar[1:0]}); assert property (foo == {last_bar[3:2], bar[1:0]});
endmodule endmodule

View file

@ -1 +1,2 @@
*.log *.log
/*.mk

View file

@ -0,0 +1,96 @@
read_verilog <<EOT
module clkbuf (input i, (* clkbuf_driver *) output o); endmodule
module dff ((* clkbuf_sink *) input clk, input d, output q); endmodule
module dffe ((* clkbuf_sink *) input c, input d, e, output q); endmodule
module latch (input e, d, output q); endmodule
module clkgen (output o); endmodule
module top(input clk1, clk2, clk3, d, e, output [4:0] q);
wire clk4, clk5, clk6;
dff s0 (.clk(clk1), .d(d), .q(q[0]));
dffe s1 (.c(clk2), .d(d), .e(e), .q(q[1]));
latch s2 (.e(clk3), .d(d), .q(q[2]));
sub s3 (.sclk4(clk4), .sclk5(clk5), .sclk6(clk6), .sd(d), .sq(q[3]));
dff s4 (.clk(clk4), .d(d), .q(q[4]));
dff s5 (.clk(clk5), .d(d), .q(q[4]));
dff s6 (.clk(clk6), .d(d), .q(q[4]));
endmodule
module sub(output sclk4, output sclk5, output sclk6, input sd, output sq);
wire tmp;
clkgen s7(.o(sclk4));
clkgen s8(.o(sclk5));
clkgen s9(.o(tmp));
clkbuf s10(.i(tmp), .o(sclk6));
dff s11(.clk(sclk4), .d(sd), .q(sq));
endmodule
EOT
hierarchy -auto-top
design -save ref
# ----------------------
design -load ref
clkbufmap -buf clkbuf o:i
select -assert-count 3 top/t:clkbuf
select -assert-count 2 sub/t:clkbuf
select -set clk1 w:clk1 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf'
select -assert-count 1 @clk1 # Check there is one such fanout
select -assert-count 1 @clk1 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout
select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i # And that one fanout is 's0'
select -set clk2 w:clk2 %a %co t:clkbuf %i
select -assert-count 1 @clk2
select -assert-count 1 @clk2 %x:+[o] %co c:s* %i
select -assert-count 1 @clk2 %x:+[o] %co c:s1 %i
select -set clk5 w:clk5 %a %ci t:clkbuf %i
select -assert-count 1 @clk5
select -assert-count 1 @clk5 %x:+[o] %co c:s5 %i
select -assert-count 1 @clk5 %x:+[i] %ci c:s3 %i
select -set sclk4 w:sclk4 %a %ci t:clkbuf %i
select -assert-count 1 @sclk4
select -assert-count 1 @sclk4 %x:+[o] %co c:s11 %i
select -assert-count 1 @sclk4 %x:+[i] %ci c:s7 %i
# ----------------------
design -load ref
setattr -set clkbuf_inhibit 0 w:clk1
setattr -set clkbuf_inhibit 1 w:clk2
clkbufmap -buf clkbuf o:i
select -assert-count 2 top/t:clkbuf
select -set clk1 w:clk1 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf'
select -assert-count 1 @clk1 # Check there is one such fanout
select -assert-count 1 @clk1 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout
select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i # And that one fanout is 's0'
select -assert-count 0 w:clk2 %a %co t:clkbuf %i
# ----------------------
design -load ref
setattr -set clkbuf_inhibit 1 w:clk1
setattr -set buffer_type "bufg" w:clk2
clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d
select -assert-count 3 top/t:clkbuf
select -assert-count 2 sub/t:clkbuf
select -set clk1 w:clk1 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf'
select -assert-count 1 @clk1 # Check there is one such fanout
select -assert-count 1 @clk1 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout
select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i # And that one fanout is 's0'
select -set clk2 w:clk2 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf'
select -assert-count 1 @clk2 # Check there is one such fanout
select -assert-count 1 @clk2 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout
select -assert-count 1 @clk2 %x:+[o] %co c:s1 %i # And that one fanout is 's0'
# ----------------------
design -load ref
setattr -set buffer_type "none" w:clk1
setattr -set buffer_type "bufr" w:clk2
setattr -set buffer_type "bufr" w:sclk4
setattr -set buffer_type "bufr" w:sclk5
clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d
select -assert-count 0 w:clk1 %a %co t:clkbuf %i
select -assert-count 0 w:clk2 %a %co t:clkbuf %i
select -assert-count 0 top/t:clkbuf
select -assert-count 1 sub/t:clkbuf

View file

@ -0,0 +1,8 @@
module top;
sub s0();
foo f0();
endmodule
module foo;
sub s0();
endmodule

View file

@ -0,0 +1,4 @@
module sub;
sub _TECHMAP_REPLACE_ ();
bar f0();
endmodule

View file

@ -0,0 +1,3 @@
set -ev
../../yosys -p 'hierarchy -top top; techmap -map recursive_map.v -max_iter 1; select -assert-count 2 t:sub; select -assert-count 2 t:bar' recursive.v

View file

@ -1,10 +1,20 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
for x in *_runtest.sh; do {
echo "Running $x.." echo "all::"
if ! bash $x &> ${x%.sh}.log; then for x in *.ys; do
tail ${x%.sh}.log echo "all:: run-$x"
echo ERROR echo "run-$x:"
exit 1 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 > ${s%.sh}.log 2>&1"
fi fi
done done
} > run-test.mk
exec ${MAKE:-make} -f run-test.mk

14
tests/various/mem2reg.ys Normal file
View file

@ -0,0 +1,14 @@
read_verilog <<EOT
module top;
parameter DATADEPTH=2;
parameter DATAWIDTH=1;
(* keep, nomem2reg *) reg [DATAWIDTH-1:0] data1 [DATADEPTH-1:0];
(* keep, mem2reg *) reg [DATAWIDTH-1:0] data2 [DATADEPTH-1:0];
endmodule
EOT
proc
cd top
select -assert-count 1 m:data1 a:src=<<EOT:4 %i
select -assert-count 2 w:data2[*] a:src=<<EOT:5 %i
select -assert-none a:mem2reg