Merge pull request #3 from YosysHQ/Sergey/tests_ice40

Merge my changes to tests_ice40 branch
This commit is contained in:
Sergey 2019-08-29 21:07:34 +03:00 committed by GitHub
commit d360693040
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 3640 additions and 824 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"

128
CHANGELOG
View File

@ -12,43 +12,149 @@ 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_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram)
- Renamed labels in synth_intel (e.g. bram -> map_bram)
- Renamed labels/options in synth_xilinx (e.g. dram -> map_lutram; -nodram -> -nolutram)
- Added automatic gzip decompression for frontends - Added automatic gzip decompression for frontends
- Added $_NMUX_ cell type - Added $_NMUX_ cell type
- 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
- 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+1
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
@ -487,6 +492,11 @@ define add_include_file
$(eval $(call add_share_file,$(dir share/include/$(1)),$(1))) $(eval $(call add_share_file,$(dir share/include/$(1)),$(1)))
endef endef
define add_extra_objs
EXTRA_OBJS += $(1)
.SECONDARY: $(1)
endef
ifeq ($(PRETTY), 1) ifeq ($(PRETTY), 1)
P_STATUS = 0 P_STATUS = 0
P_OFFSET = 0 P_OFFSET = 0

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
@ -405,6 +423,23 @@ Verilog Attributes and non-standard features
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
functionality. (By default specify .. endspecify blocks are ignored.) functionality. (By default specify .. endspecify blocks are ignored.)
- The module attribute ``abc_box_id`` specifies a positive integer linking a
blackbox or whitebox definition to a corresponding entry in a `abc9`
box-file.
- The port attribute ``abc_scc_break`` indicates a module input port that will
be treated as a primary output during `abc9` techmapping. Doing so eliminates
the possibility of a strongly-connected component (i.e. a combinatorial loop)
existing. Typically, this is specified for sequential inputs on otherwise
combinatorial boxes -- for example, applying ``abc_scc_break`` onto the `D`
port of a LUTRAM cell prevents `abc9` from interpreting any `Q` -> `D` paths
as a combinatorial loop.
- The port attribute ``abc_carry`` marks the carry-in (if an input port) and
carry-out (if output port) ports of a box. This information is necessary for
`abc9` to preserve the integrity of carry-chains. Specifying this attribute
onto a bus port will affect only its most significant bit.
Non-standard or SystemVerilog features for formal verification Non-standard or SystemVerilog features for formal verification
============================================================== ==============================================================

View File

@ -326,7 +326,6 @@ struct XAigerWriter
#endif #endif
log_assert(no_loops); log_assert(no_loops);
pool<IdString> seen_boxes;
for (auto cell_name : toposort.sorted) { for (auto cell_name : toposort.sorted) {
RTLIL::Cell *cell = module->cell(cell_name); RTLIL::Cell *cell = module->cell(cell_name);
log_assert(cell); log_assert(cell);
@ -335,47 +334,6 @@ struct XAigerWriter
if (!box_module || !box_module->attributes.count("\\abc_box_id")) if (!box_module || !box_module->attributes.count("\\abc_box_id"))
continue; continue;
if (seen_boxes.insert(cell->type).second) {
auto it = box_module->attributes.find("\\abc_carry");
if (it != box_module->attributes.end()) {
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
auto carry_in_out = it->second.decode_string();
auto pos = carry_in_out.find(',');
if (pos == std::string::npos)
log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type));
auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos));
carry_in = box_module->wire(carry_in_name);
if (!carry_in || !carry_in->port_input)
log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str());
auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1));
carry_out = box_module->wire(carry_out_name);
if (!carry_out || !carry_out->port_output)
log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str());
auto &ports = box_module->ports;
for (auto jt = ports.begin(); jt != ports.end(); ) {
RTLIL::Wire* w = box_module->wire(*jt);
log_assert(w);
if (w == carry_in || w == carry_out) {
jt = ports.erase(jt);
continue;
}
if (w->port_id > carry_in->port_id)
--w->port_id;
if (w->port_id > carry_out->port_id)
--w->port_id;
log_assert(w->port_input || w->port_output);
log_assert(ports[w->port_id-1] == w->name);
++jt;
}
ports.push_back(carry_in->name);
carry_in->port_id = ports.size();
ports.push_back(carry_out->name);
carry_out->port_id = ports.size();
}
}
// Fully pad all unused input connections of this box cell with S0 // Fully pad all unused input connections of this box cell with S0
// Fully pad all undriven output connections of this box cell with anonymous wires // Fully pad all undriven output connections of this box cell with anonymous wires
// NB: Assume box_module->ports are sorted alphabetically // NB: Assume box_module->ports are sorted alphabetically

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

@ -1502,7 +1502,10 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
rewrite_parameter: rewrite_parameter:
para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
delete child->children.at(0); delete child->children.at(0);
if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0) if ((parameters[para_id].flags & RTLIL::CONST_FLAG_REAL) != 0) {
child->children[0] = new AstNode(AST_REALVALUE);
child->children[0]->realvalue = std::stod(parameters[para_id].decode_string());
} else if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0)
child->children[0] = AstNode::mkconst_str(parameters[para_id].decode_string()); child->children[0] = AstNode::mkconst_str(parameters[para_id].decode_string());
else else
child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0); child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0);

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

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

@ -1 +1 @@
/*_pm.h /*_pm.h

View File

@ -1,30 +1,29 @@
%_pm.h: passes/pmgen/pmgen.py %.pmg
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p $(subst _pm.h,,$(notdir $@)) $(filter-out $<,$^)
# --------------------------------------
OBJS += passes/pmgen/test_pmgen.o
passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h
$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h))
# --------------------------------------
OBJS += passes/pmgen/ice40_dsp.o OBJS += passes/pmgen/ice40_dsp.o
OBJS += passes/pmgen/ice40_wrapcarry.o
OBJS += passes/pmgen/peepopt.o
# --------------------------------------
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h $(eval $(call add_extra_objs,passes/pmgen/ice40_dsp_pm.h))
.SECONDARY: passes/pmgen/ice40_dsp_pm.h
passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^)
# -------------------------------------- # --------------------------------------
OBJS += passes/pmgen/ice40_wrapcarry.o
passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h
EXTRA_OBJS += passes/pmgen/ice40_wrapcarry_pm.h $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
.SECONDARY: passes/pmgen/ice40_wrapcarry_pm.h
passes/pmgen/ice40_wrapcarry_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_wrapcarry.pmg
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_wrapcarry $(filter-out $<,$^)
# -------------------------------------- # --------------------------------------
OBJS += passes/pmgen/peepopt.o
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
EXTRA_OBJS += passes/pmgen/peepopt_pm.h $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h))
.SECONDARY: passes/pmgen/peepopt_pm.h
PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg

View File

@ -45,9 +45,9 @@ of type `foobar_pm::state_<pattern_name>_t`.)
Similarly the `.pmg` file declares user data variables that become members of Similarly the `.pmg` file declares user data variables that become members of
`.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`. `.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`.
There are four versions of the `run_<pattern_name>()` method: Without callback, There are three versions of the `run_<pattern_name>()` method: Without callback,
callback without arguments, callback with reference to `pm`, and callback with callback without arguments, and callback with reference to `pm`. All versions
reference to `pm.st_<pattern_name>`. of the `run_<pattern_name>()` method return the number of found matches.
The .pmg File Format The .pmg File Format
@ -118,8 +118,8 @@ write matchers:
connected to any of the given signal bits, plus one if any of the signal connected to any of the given signal bits, plus one if any of the signal
bits is also a primary input or primary output. bits is also a primary input or primary output.
- In `code..endcode` blocks there exist `accept`, `reject`, and `branch` - In `code..endcode` blocks there exist `accept`, `reject`, `branch`,
statements. `finish`, and `subpattern` statements.
- In `index` statements there is a special `===` operator for the index - In `index` statements there is a special `===` operator for the index
lookup. lookup.
@ -175,6 +175,48 @@ explore the case where `mul` is set to `nullptr`. Without the `optional`
statement a match may only be assigned nullptr when one of the `if` expressions statement a match may only be assigned nullptr when one of the `if` expressions
evaluates to `false`. evaluates to `false`.
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`.
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
--------------- ---------------
@ -232,5 +274,111 @@ But in some cases it is more natural to utilize the implicit branch statement:
portAB = \B; portAB = \B;
endcode endcode
There is an implicit `code..endcode` block at the end of each `.pmg` file There is an implicit `code..endcode` block at the end of each (sub)pattern
that just accepts everything that gets all the way there. that just rejects.
A `code..finally..endcode` block executes the code after `finally` during
back-tracking. This is useful for maintaining user data state or printing
debug messages. For example:
udata <vector<Cell*>> stack
code
stack.push_back(addAB);
...
finally
stack.pop_back();
endcode
`accept` and `finish` statements can be used inside the `finally` section,
but not `reject`, `branch`, or `subpattern`.
Declaring a subpattern
----------------------
A subpattern starts with a line containing the `subpattern` keyword followed
by the name of the subpattern. Subpatterns can be called from a `code` block
using a `subpattern(<subpattern_name>);` C statement.
Arguments may be passed to subpattern via state variables. The `subpattern`
line must be followed by a `arg <arg1> <arg2> ...` line that lists the
state variables used to pass arguments.
state <IdString> foobar_type
state <bool> foobar_state
code foobar_type foobar_state
foobar_state = false;
foobar_type = $add;
subpattern(foo);
foobar_type = $sub;
subpattern(bar);
endcode
subpattern foo
arg foobar_type foobar_state
match addsub
index <IdString> addsub->type === foobar_type
...
endmatch
code
if (foobar_state) {
subpattern(tail);
} else {
foobar_state = true;
subpattern(bar);
}
endcode
subpattern bar
arg foobar_type foobar_state
match addsub
index <IdString> addsub->type === foobar_type
...
endmatch
code
if (foobar_state) {
subpattern(tail);
} else {
foobar_state = true;
subpattern(foo);
}
endcode
subpattern tail
...
Subpatterns cann be called recursively.
If a `subpattern` statement is preceded by a `fallthrough` statement, this is
equivalent to calling the subpattern at the end of the preceding block.
Generate Blocks
---------------
Match blocks may contain an optional `generate` section that is used for automatic
test-case generation. For example:
match mul
...
generate 10 0
SigSpec Y = port(ff, \D);
SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
module->addMul(NEW_ID, A, B, Y, rng(2));
endmatch
The expression `rng(n)` returns a non-negative integer less than `n`.
The first argument to `generate` is the chance of this generate block being
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 current pattern matcher run.

View File

@ -159,4 +159,5 @@ code clock clock_pol clock_vld
clock_pol = cp; clock_pol = cp;
clock_vld = true; clock_vld = true;
} }
accept;
endcode endcode

View File

@ -32,5 +32,5 @@ code
log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div)); log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
module->connect(div_y, val_y); module->connect(div_y, val_y);
autoremove(div); autoremove(div);
reject; accept;
endcode endcode

View File

@ -34,6 +34,7 @@ match mul
endmatch endmatch
code code
{
IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B;
IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED; IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED;
Const const_factor_cnst = port(mul, const_factor_port).as_const(); Const const_factor_cnst = port(mul, const_factor_port).as_const();
@ -90,5 +91,6 @@ code
shift->setParam(\B_WIDTH, GetSize(new_b)); shift->setParam(\B_WIDTH, GetSize(new_b));
blacklist(shift); blacklist(shift);
reject; accept;
}
endcode endcode

View File

@ -38,7 +38,10 @@ for a in args:
assert prefix is not None assert prefix is not None
current_pattern = None current_pattern = None
current_subpattern = None
patterns = dict() patterns = dict()
subpatterns = dict()
subpattern_args = dict()
state_types = dict() state_types = dict()
udata_types = dict() udata_types = dict()
blocks = list() blocks = list()
@ -104,9 +107,12 @@ def rewrite_cpp(s):
return "".join(t) return "".join(t)
def process_pmgfile(f): def process_pmgfile(f, filename):
linenr = 0
global current_pattern global current_pattern
global current_subpattern
while True: while True:
linenr += 1
line = f.readline() line = f.readline()
if line == "": break if line == "": break
line = line.strip() line = line.strip()
@ -119,19 +125,52 @@ def process_pmgfile(f):
if current_pattern is not None: if current_pattern is not None:
block = dict() block = dict()
block["type"] = "final" block["type"] = "final"
block["pattern"] = current_pattern block["pattern"] = (current_pattern, current_subpattern)
blocks.append(block) blocks.append(block)
line = line.split() line = line.split()
assert len(line) == 2 assert len(line) == 2
assert line[1] not in patterns assert line[1] not in patterns
current_pattern = line[1] current_pattern = line[1]
current_subpattern = ""
patterns[current_pattern] = len(blocks) patterns[current_pattern] = len(blocks)
subpatterns[(current_pattern, current_subpattern)] = len(blocks)
subpattern_args[(current_pattern, current_subpattern)] = list()
state_types[current_pattern] = dict() state_types[current_pattern] = dict()
udata_types[current_pattern] = dict() udata_types[current_pattern] = dict()
continue continue
assert current_pattern is not None assert current_pattern is not None
if cmd == "fallthrough":
block = dict()
block["type"] = "fallthrough"
blocks.append(block)
line = line.split()
assert len(line) == 1
continue
if cmd == "subpattern":
if len(blocks) == 0 or blocks[-1]["type"] != "fallthrough":
block = dict()
block["type"] = "final"
block["pattern"] = (current_pattern, current_subpattern)
blocks.append(block)
elif len(blocks) and blocks[-1]["type"] == "fallthrough":
del blocks[-1]
line = line.split()
assert len(line) == 2
current_subpattern = line[1]
subpattern_args[(current_pattern, current_subpattern)] = list()
assert (current_pattern, current_subpattern) not in subpatterns
subpatterns[(current_pattern, current_subpattern)] = len(blocks)
continue
if cmd == "arg":
line = line.split()
assert len(line) > 1
subpattern_args[(current_pattern, current_subpattern)] += line[1:]
continue
if cmd == "state": if cmd == "state":
m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
assert m assert m
@ -155,21 +194,28 @@ def process_pmgfile(f):
if cmd == "match": if cmd == "match":
block = dict() block = dict()
block["type"] = "match" block["type"] = "match"
block["pattern"] = current_pattern block["src"] = "%s:%d" % (filename, linenr)
block["pattern"] = (current_pattern, current_subpattern)
block["genargs"] = None
block["gencode"] = None
line = line.split() line = line.split()
assert len(line) == 2 assert len(line) == 2
assert line[1] not in state_types[current_pattern] assert (line[1] not in state_types[current_pattern]) or (state_types[current_pattern][line[1]] == "Cell*")
block["cell"] = line[1] block["cell"] = line[1]
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
while True: while True:
linenr += 1
l = f.readline() l = f.readline()
assert l != "" assert l != ""
a = l.split() a = l.split()
@ -183,7 +229,22 @@ def process_pmgfile(f):
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":
@ -197,35 +258,71 @@ def process_pmgfile(f):
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
if a[0] == "semioptional":
block["semioptional"] = True
continue
if a[0] == "generate":
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()
while True:
linenr += 1
l = f.readline()
assert l != ""
a = l.split()
if len(a) == 1 and a[0] == "endmatch": break
block["gencode"].append(rewrite_cpp(l.rstrip()))
break
assert False assert False
if block["optional"]:
assert not block["semioptional"]
blocks.append(block) blocks.append(block)
continue continue
if cmd == "code": if cmd == "code":
block = dict() block = dict()
block["type"] = "code" block["type"] = "code"
block["pattern"] = current_pattern block["src"] = "%s:%d" % (filename, linenr)
block["pattern"] = (current_pattern, current_subpattern)
block["code"] = list() block["code"] = list()
block["fcode"] = list()
block["states"] = set() block["states"] = set()
for s in line.split()[1:]: for s in line.split()[1:]:
assert s in state_types[current_pattern] assert s in state_types[current_pattern]
block["states"].add(s) block["states"].add(s)
codetype = "code"
while True: while True:
linenr += 1
l = f.readline() l = f.readline()
assert l != "" assert l != ""
a = l.split() a = l.split()
if len(a) == 0: continue if len(a) == 0: continue
if a[0] == "endcode": break if a[0] == "endcode": break
block["code"].append(rewrite_cpp(l.rstrip())) if a[0] == "finally":
codetype = "fcode"
continue
block[codetype].append(rewrite_cpp(l.rstrip()))
blocks.append(block) blocks.append(block)
continue continue
@ -234,15 +331,16 @@ def process_pmgfile(f):
for fn in pmgfiles: for fn in pmgfiles:
with open(fn, "r") as f: with open(fn, "r") as f:
process_pmgfile(f) process_pmgfile(f, fn)
if current_pattern is not None: if current_pattern is not None:
block = dict() block = dict()
block["type"] = "final" block["type"] = "final"
block["pattern"] = current_pattern block["pattern"] = (current_pattern, current_subpattern)
blocks.append(block) blocks.append(block)
current_pattern = None current_pattern = None
current_subpattern = None
if debug: if debug:
pp.pprint(blocks) pp.pprint(blocks)
@ -262,7 +360,18 @@ with open(outfile, "w") as f:
print("struct {}_pm {{".format(prefix), file=f) print("struct {}_pm {{".format(prefix), file=f)
print(" Module *module;", file=f) print(" Module *module;", file=f)
print(" SigMap sigmap;", file=f) print(" SigMap sigmap;", file=f)
print(" std::function<void()> on_accept;".format(prefix), file=f) print(" std::function<void()> on_accept;", file=f)
print(" bool generate_mode;", file=f)
print(" int accept_cnt;", file=f)
print("", file=f)
print(" uint32_t rngseed;", file=f)
print(" int rng(unsigned int n) {", file=f)
print(" rngseed ^= rngseed << 13;", file=f)
print(" rngseed ^= rngseed >> 17;", file=f)
print(" rngseed ^= rngseed << 5;", file=f)
print(" return rngseed % n;", file=f)
print(" }", file=f)
print("", file=f) print("", file=f)
for index in range(len(blocks)): for index in range(len(blocks)):
@ -271,12 +380,21 @@ 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)
print(" bool blacklist_dirty;", file=f) print(" dict<Cell*,int> rollback_cache;", file=f)
print(" int rollback;", file=f) print(" int rollback;", file=f)
print("", file=f) print("", file=f)
@ -304,47 +422,30 @@ 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)
print("", file=f) print("", file=f)
print(" void blacklist(Cell *cell) {", file=f) print(" void blacklist(Cell *cell) {", file=f)
print(" if (cell != nullptr) {", file=f) print(" if (cell != nullptr && blacklist_cells.insert(cell).second) {", file=f)
print(" if (blacklist_cells.insert(cell).second)", file=f) print(" auto ptr = rollback_cache.find(cell);", file=f)
print(" blacklist_dirty = true;", file=f) print(" if (ptr == rollback_cache.end()) return;", file=f)
print(" int rb = ptr->second;", file=f)
print(" if (rollback == 0 || rollback > rb)", file=f)
print(" rollback = rb;", file=f)
print(" }", file=f) print(" }", file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void autoremove(Cell *cell) {", file=f) print(" void autoremove(Cell *cell) {", file=f)
print(" if (cell != nullptr) {", file=f) print(" if (cell != nullptr) {", file=f)
print(" if (blacklist_cells.insert(cell).second)", file=f)
print(" blacklist_dirty = true;", file=f)
print(" autoremove_cells.insert(cell);", file=f) print(" autoremove_cells.insert(cell);", file=f)
print(" blacklist(cell);", file=f)
print(" }", file=f) print(" }", file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
for current_pattern in sorted(patterns.keys()):
print(" void check_blacklist_{}() {{".format(current_pattern), file=f)
print(" if (!blacklist_dirty)", file=f)
print(" return;", file=f)
print(" blacklist_dirty = false;", file=f)
for index in range(len(blocks)):
block = blocks[index]
if block["pattern"] != current_pattern:
continue
if block["type"] == "match":
print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f)
print(" rollback = {};".format(index+1), file=f)
print(" return;", file=f)
print(" }", file=f)
print(" rollback = 0;", file=f)
print(" }", file=f)
print("", file=f)
current_pattern = None current_pattern = None
print(" SigSpec port(Cell *cell, IdString portname) {", file=f) print(" SigSpec port(Cell *cell, IdString portname) {", file=f)
@ -367,7 +468,7 @@ with open(outfile, "w") as f:
print("", file=f) print("", file=f)
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
print(" module(module), sigmap(module) {", file=f) print(" module(module), sigmap(module), generate_mode(false), rngseed(12345678) {", file=f)
for current_pattern in sorted(patterns.keys()): for current_pattern in sorted(patterns.keys()):
for s, t in sorted(udata_types[current_pattern].items()): for s, t in sorted(udata_types[current_pattern].items()):
if t.endswith("*"): if t.endswith("*"):
@ -375,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)):
@ -386,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)
@ -405,41 +529,47 @@ with open(outfile, "w") as f:
print("", file=f) print("", file=f)
for current_pattern in sorted(patterns.keys()): for current_pattern in sorted(patterns.keys()):
print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f) print(" int run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
print(" accept_cnt = 0;", file=f)
print(" on_accept = on_accept_f;", file=f) print(" on_accept = on_accept_f;", file=f)
print(" rollback = 0;", file=f) print(" rollback = 0;", file=f)
print(" blacklist_dirty = false;", file=f)
for s, t in sorted(state_types[current_pattern].items()): for s, t in sorted(state_types[current_pattern].items()):
if t.endswith("*"): if t.endswith("*"):
print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f) print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
else: else:
print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f) print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
print(" block_{}();".format(patterns[current_pattern]), file=f) print(" block_{}(1);".format(patterns[current_pattern]), file=f)
print(" log_assert(rollback_cache.empty());", file=f)
print(" return accept_cnt;", file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f) print(" int run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f) print(" return run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}(std::function<void(state_{}_t&)> on_accept_f) {{".format(current_pattern, current_pattern), file=f) print(" int run_{}() {{".format(current_pattern), file=f)
print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f) print(" return run_{}([](){{}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}() {{".format(current_pattern), file=f)
print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f) if len(subpatterns):
print(" }", file=f) for p, s in sorted(subpatterns.keys()):
print(" void block_subpattern_{}_{}(int recursion) {{ block_{}(recursion); }}".format(p, s, subpatterns[(p, s)]), file=f)
print("", file=f) print("", file=f)
current_pattern = None current_pattern = None
current_subpattern = None
for index in range(len(blocks)): for index in range(len(blocks)):
block = blocks[index] block = blocks[index]
print(" void block_{}() {{".format(index), file=f) if block["type"] in ("match", "code"):
current_pattern = block["pattern"] print(" // {}".format(block["src"]), file=f)
print(" void block_{}(int recursion YS_ATTRIBUTE(unused)) {{".format(index), file=f)
current_pattern, current_subpattern = block["pattern"]
if block["type"] == "final": if block["type"] == "final":
print(" on_accept();", file=f)
print(" check_blacklist_{}();".format(current_pattern), file=f)
print(" }", file=f) print(" }", file=f)
if index+1 != len(blocks): if index+1 != len(blocks):
print("", file=f) print("", file=f)
@ -449,12 +579,17 @@ with open(outfile, "w") as f:
nonconst_st = set() nonconst_st = set()
restore_st = set() restore_st = set()
for i in range(patterns[current_pattern], index): for s in subpattern_args[(current_pattern, current_subpattern)]:
const_st.add(s)
for i in range(subpatterns[(current_pattern, current_subpattern)], index):
if blocks[i]["type"] == "code": if blocks[i]["type"] == "code":
for s in blocks[i]["states"]: for s in blocks[i]["states"]:
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
@ -468,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
@ -482,37 +621,55 @@ with open(outfile, "w") as f:
t = state_types[current_pattern][s] t = state_types[current_pattern][s]
print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
for u in sorted(udata_types[current_pattern].keys()):
t = udata_types[current_pattern][u]
print(" {} &{} YS_ATTRIBUTE(unused) = ud_{}.{};".format(t, u, current_pattern, u), file=f)
if len(restore_st): if len(restore_st):
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)
print(" do {", file=f) print("#define reject do { goto rollback_label; } while(0)", file=f)
print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f) print("#define accept do { accept_cnt++; on_accept(); if (rollback) goto rollback_label; } while(0)", file=f)
print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f) print("#define finish do { rollback = -1; goto rollback_label; } while(0)", file=f)
print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) print("#define branch do {{ block_{}(recursion+1); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
print("#define subpattern(pattern_name) do {{ block_subpattern_{}_ ## pattern_name (recursion+1); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f)
for line in block["code"]: for line in block["code"]:
print(" " + line, file=f) print(" " + line, file=f)
print("", file=f) print("", file=f)
print(" block_{}();".format(index+1), file=f) print(" block_{}(recursion+1);".format(index+1), file=f)
print("#undef reject", file=f) print("#undef reject", file=f)
print("#undef accept", file=f) print("#undef accept", file=f)
print("#undef finish", file=f)
print("#undef branch", file=f) print("#undef branch", file=f)
print(" } while (0);", file=f) print("#undef subpattern", file=f)
print("", file=f) print("", file=f)
print("rollback_label:", file=f) print("rollback_label:", file=f)
print(" YS_ATTRIBUTE(unused);", file=f) print(" YS_ATTRIBUTE(unused);", file=f)
if len(block["fcode"]):
print("#define accept do { accept_cnt++; on_accept(); } while(0)", file=f)
print("#define finish do { rollback = -1; goto finish_label; } while(0)", file=f)
for line in block["fcode"]:
print(" " + line, file=f)
print("finish_label:", file=f)
print(" YS_ATTRIBUTE(unused);", file=f)
print("#undef accept", file=f)
print("#undef finish", file=f)
if len(restore_st) or len(nonconst_st): if len(restore_st) or len(nonconst_st):
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]
@ -524,12 +681,15 @@ 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* _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"]:
print("", file=f) print("", file=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_{}();".format(index+1), file=f) print(" block_{}(recursion+1);".format(index+1), 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)
@ -537,21 +697,48 @@ with open(outfile, "w") as f:
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[2]), file=f) print(" std::get<{}>(key) = {};".format(field, entry[2]), file=f)
print(" const vector<Cell*> &cells = index_{}[key];".format(index), file=f) print(" auto cells_ptr = index_{}.find(key);".format(index), file=f)
if block["semioptional"] or block["genargs"] is not None:
print(" bool found_any_match = false;", file=f)
print("", file=f) print("", file=f)
print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f)
print(" {} = cells[idx];".format(block["cell"]), file=f) print(" const vector<index_{}_value_type> &cells = cells_ptr->second;".format(index), file=f)
print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) print(" for (int _pmg_idx = 0; _pmg_idx < GetSize(cells); _pmg_idx++) {", 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)
for expr in block["filter"]: for expr in block["filter"]:
print(" if (!({})) continue;".format(expr), file=f) print(" if (!({})) continue;".format(expr), file=f)
print(" block_{}();".format(index+1), file=f) if block["semioptional"] or block["genargs"] is not None:
print(" if (rollback) {", file=f) print(" found_any_match = true;", file=f)
print(" if (rollback != {}) {{".format(index+1), file=f) for item in block["sets"]:
print(" {} = nullptr;".format(block["cell"]), file=f) print(" auto _pmg_backup_{} = {};".format(item[0], item[0]), file=f)
print(" return;", 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)
for item in block["sets"]:
print(" {} = _pmg_backup_{};".format(item[0], item[0]), file=f)
print(" if (rollback_ptr.second)", file=f)
print(" rollback_cache.erase(rollback_ptr.first);", file=f)
print(" if (rollback) {", file=f)
print(" if (rollback != recursion) {{".format(index+1), file=f)
print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
print(" return;", file=f)
print(" }", file=f)
print(" rollback = 0;", file=f)
print(" }", file=f) print(" }", file=f)
print(" rollback = 0;", file=f)
print(" }", file=f) print(" }", file=f)
print(" }", file=f) print(" }", file=f)
@ -559,8 +746,20 @@ with open(outfile, "w") as f:
print(" {} = nullptr;".format(block["cell"]), file=f) print(" {} = nullptr;".format(block["cell"]), file=f)
if block["optional"]: if block["optional"]:
print(" block_{}();".format(index+1), file=f) print(" block_{}(recursion+1);".format(index+1), file=f)
if block["semioptional"]:
print(" if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f)
print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
if block["genargs"] is not None:
print("#define finish do { rollback = -1; return; } while(0)", file=f)
print(" if (generate_mode && rng(100) < (found_any_match ? {} : {})) {{".format(block["genargs"][1], block["genargs"][0]), file=f)
for line in block["gencode"]:
print(" " + line, file=f)
print(" }", file=f)
print("#undef finish", file=f)
else: else:
assert False assert False

379
passes/pmgen/test_pmgen.cc Normal file
View File

@ -0,0 +1,379 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
// for peepopt_pm
bool did_something;
#include "passes/pmgen/test_pmgen_pm.h"
#include "passes/pmgen/ice40_dsp_pm.h"
#include "passes/pmgen/peepopt_pm.h"
void reduce_chain(test_pmgen_pm &pm)
{
auto &st = pm.st_reduce;
auto &ud = pm.ud_reduce;
if (ud.longest_chain.empty())
return;
log("Found chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
SigSpec A;
SigSpec Y = ud.longest_chain.front().first->getPort(ID(Y));
auto last_cell = ud.longest_chain.back().first;
for (auto it : ud.longest_chain) {
auto cell = it.first;
if (cell == last_cell) {
A.append(cell->getPort(ID(A)));
A.append(cell->getPort(ID(B)));
} else {
A.append(cell->getPort(it.second == ID(A) ? ID(B) : ID(A)));
}
log(" %s\n", log_id(cell));
pm.autoremove(cell);
}
Cell *c;
if (last_cell->type == ID($_AND_))
c = pm.module->addReduceAnd(NEW_ID, A, Y);
else if (last_cell->type == ID($_OR_))
c = pm.module->addReduceOr(NEW_ID, A, Y);
else if (last_cell->type == ID($_XOR_))
c = pm.module->addReduceXor(NEW_ID, A, Y);
else
log_abort();
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
}
void reduce_tree(test_pmgen_pm &pm)
{
auto &st = pm.st_reduce;
auto &ud = pm.ud_reduce;
if (ud.longest_chain.empty())
return;
SigSpec A = ud.leaves;
SigSpec Y = st.first->getPort(ID(Y));
pm.autoremove(st.first);
log("Found %s tree with %d leaves for %s (%s).\n", log_id(st.first->type),
GetSize(A), log_signal(Y), log_id(st.first));
Cell *c;
if (st.first->type == ID($_AND_))
c = pm.module->addReduceAnd(NEW_ID, A, Y);
else if (st.first->type == ID($_OR_))
c = pm.module->addReduceOr(NEW_ID, A, Y);
else if (st.first->type == ID($_XOR_))
c = pm.module->addReduceXor(NEW_ID, A, Y);
else
log_abort();
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) \
generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
void pmtest_addports(Module *module)
{
pool<SigBit> driven_bits, used_bits;
SigMap sigmap(module);
int icnt = 0, ocnt = 0;
for (auto cell : module->cells())
for (auto conn : cell->connections())
{
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
used_bits.insert(bit);
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
driven_bits.insert(bit);
}
for (auto wire : vector<Wire*>(module->wires()))
{
SigSpec ibits, obits;
for (auto bit : sigmap(wire)) {
if (!used_bits.count(bit))
obits.append(bit);
if (!driven_bits.count(bit))
ibits.append(bit);
}
if (!ibits.empty()) {
Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits));
w->port_input = true;
module->connect(ibits, w);
}
if (!obits.empty()) {
Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits));
w->port_output = true;
module->connect(w, obits);
}
}
module->fixup_ports();
}
template <class pm>
void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design)
{
log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
int modcnt = 0;
int maxmodcnt = 100;
int maxsubcnt = 4;
int timeout = 0;
vector<Module*> mods;
while (modcnt < maxmodcnt)
{
int submodcnt = 0, itercnt = 0, cellcnt = 0;
Module *mod = design->addModule(NEW_ID);
while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
{
if (timeout++ > 10000)
log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n");
pm matcher(mod, mod->cells());
matcher.rng(1);
matcher.rngseed += modcnt;
matcher.rng(1);
matcher.rngseed += submodcnt;
matcher.rng(1);
matcher.rngseed += itercnt;
matcher.rng(1);
matcher.rngseed += cellcnt;
matcher.rng(1);
if (GetSize(mod->cells()) != cellcnt)
{
bool found_match = false;
run(matcher, [&](){ found_match = true; });
cellcnt = GetSize(mod->cells());
if (found_match) {
Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d",
pmclass, pattern, modcnt++));
log("Creating module %s with %d cells.\n", log_id(m), cellcnt);
mod->cloneInto(m);
pmtest_addports(m);
mods.push_back(m);
submodcnt++;
timeout = 0;
}
}
matcher.generate_mode = true;
run(matcher, [](){});
}
if (submodcnt)
maxsubcnt *= 2;
design->remove(mod);
}
Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern));
log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods));
for (auto mod : mods) {
Cell *c = m->addCell(mod->name, mod->name);
for (auto port : mod->ports) {
Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port)));
c->setPort(port, w);
}
}
pmtest_addports(m);
}
struct TestPmgenPass : public Pass {
TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" test_pmgen -reduce_chain [options] [selection]\n");
log("\n");
log("Demo for recursive pmgen patterns. Map chains of AND/OR/XOR to $reduce_*.\n");
log("\n");
log("\n");
log(" test_pmgen -reduce_tree [options] [selection]\n");
log("\n");
log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\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(" test_pmgen -generate [options] <pattern_name>\n");
log("\n");
log("Create modules that match the specified pattern.\n");
log("\n");
}
void execute_reduce_chain(std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing TEST_PMGEN pass (-reduce_chain).\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())
while (test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_chain)) {}
}
void execute_reduce_tree(std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing TEST_PMGEN pass (-reduce_tree).\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_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)
{
log_header(design, "Executing TEST_PMGEN pass (-generate).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-singleton") {
// singleton_mode = true;
// continue;
// }
break;
}
if (argidx+1 != args.size())
log_cmd_error("Expected exactly one pattern.\n");
string pattern = args[argidx];
if (pattern == "reduce")
return GENERATE_PATTERN(test_pmgen_pm, reduce);
if (pattern == "eqpmux")
return GENERATE_PATTERN(test_pmgen_pm, eqpmux);
if (pattern == "ice40_dsp")
return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
if (pattern == "peepopt-muldiv")
return GENERATE_PATTERN(peepopt_pm, muldiv);
if (pattern == "peepopt-shiftmul")
return GENERATE_PATTERN(peepopt_pm, shiftmul);
log_cmd_error("Unkown pattern: %s\n", pattern.c_str());
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
if (GetSize(args) > 1)
{
if (args[1] == "-reduce_chain")
return execute_reduce_chain(args, design);
if (args[1] == "-reduce_tree")
return execute_reduce_tree(args, design);
if (args[1] == "-eqpmux")
return execute_eqpmux(args, design);
if (args[1] == "-generate")
return execute_generate(args, design);
}
help();
log_cmd_error("Missing or unsupported mode parameter.\n");
}
} TestPmgenPass;
PRIVATE_NAMESPACE_END

189
passes/pmgen/test_pmgen.pmg Normal file
View File

@ -0,0 +1,189 @@
pattern reduce
state <IdString> portname
udata <vector<pair<Cell*, IdString>>> chain longest_chain
udata <pool<Cell*>> non_first_cells
udata <SigSpec> leaves
code
non_first_cells.clear();
subpattern(setup);
endcode
match first
select first->type.in($_AND_, $_OR_, $_XOR_)
filter !non_first_cells.count(first)
generate
SigSpec A = module->addWire(NEW_ID);
SigSpec B = module->addWire(NEW_ID);
SigSpec Y = module->addWire(NEW_ID);
switch (rng(3))
{
case 0:
module->addAndGate(NEW_ID, A, B, Y);
break;
case 1:
module->addOrGate(NEW_ID, A, B, Y);
break;
case 2:
module->addXorGate(NEW_ID, A, B, Y);
break;
}
endmatch
code
leaves = SigSpec();
longest_chain.clear();
chain.push_back(make_pair(first, \A));
subpattern(tail);
chain.back().second = \B;
subpattern(tail);
finally
chain.pop_back();
log_assert(chain.empty());
if (GetSize(longest_chain) > 1)
accept;
endcode
// ------------------------------------------------------------------
subpattern setup
match first
select first->type.in($_AND_, $_OR_, $_XOR_)
endmatch
code portname
portname = \A;
branch;
portname = \B;
endcode
match next
select next->type.in($_AND_, $_OR_, $_XOR_)
select nusers(port(next, \Y)) == 2
index <IdString> next->type === first->type
index <SigSpec> port(next, \Y) === port(first, portname)
endmatch
code
non_first_cells.insert(next);
endcode
// ------------------------------------------------------------------
subpattern tail
arg first
match next
semioptional
select next->type.in($_AND_, $_OR_, $_XOR_)
select nusers(port(next, \Y)) == 2
index <IdString> next->type === chain.back().first->type
index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second)
generate 10
SigSpec A = module->addWire(NEW_ID);
SigSpec B = module->addWire(NEW_ID);
SigSpec Y = port(chain.back().first, chain.back().second);
Cell *c = module->addAndGate(NEW_ID, A, B, Y);
c->type = chain.back().first->type;
endmatch
code
if (next) {
chain.push_back(make_pair(next, \A));
subpattern(tail);
chain.back().second = \B;
subpattern(tail);
} else {
if (GetSize(chain) > GetSize(longest_chain))
longest_chain = chain;
leaves.append(port(chain.back().first, chain.back().second));
}
finally
if (next)
chain.pop_back();
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

@ -76,12 +76,11 @@ inline std::string remap_name(RTLIL::IdString abc_name)
return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1);
} }
void handle_loops(RTLIL::Design *design) void handle_loops(RTLIL::Design *design,
const dict<IdString,pool<IdString>> &scc_break_inputs)
{ {
Pass::call(design, "scc -set_attr abc_scc_id {}"); Pass::call(design, "scc -set_attr abc_scc_id {}");
dict<IdString, vector<IdString>> abc_scc_break;
// For every unique SCC found, (arbitrarily) find the first // For every unique SCC found, (arbitrarily) find the first
// cell in the component, and select (and mark) all its output // cell in the component, and select (and mark) all its output
// wires // wires
@ -116,44 +115,29 @@ void handle_loops(RTLIL::Design *design)
cell->attributes.erase(it); cell->attributes.erase(it);
} }
auto jt = abc_scc_break.find(cell->type); auto jt = scc_break_inputs.find(cell->type);
if (jt == abc_scc_break.end()) { if (jt != scc_break_inputs.end())
std::vector<IdString> ports; for (auto port_name : jt->second) {
RTLIL::Module* box_module = design->module(cell->type); RTLIL::SigSpec sig;
if (box_module) { auto &rhs = cell->connections_.at(port_name);
auto ports_csv = box_module->attributes.at(ID(abc_scc_break), RTLIL::Const::from_string("")).decode_string(); for (auto b : rhs) {
for (const auto &port_name : split_tokens(ports_csv, ",")) { Wire *w = b.wire;
auto port_id = RTLIL::escape_id(port_name); if (!w) continue;
auto kt = cell->connections_.find(port_id); w->port_output = true;
if (kt == cell->connections_.end()) w->set_bool_attribute(ID(abc_scc_break));
log_error("abc_scc_break attribute value '%s' does not exist as port on module '%s'\n", port_name.c_str(), log_id(box_module)); w = module->wire(stringf("%s.abci", w->name.c_str()));
ports.push_back(port_id); if (!w) {
w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire));
w->port_input = true;
}
else {
log_assert(b.offset < GetSize(w));
log_assert(w->port_input);
}
sig.append(RTLIL::SigBit(w, b.offset));
} }
rhs = sig;
} }
jt = abc_scc_break.insert(std::make_pair(cell->type, std::move(ports))).first;
}
for (auto port_name : jt->second) {
RTLIL::SigSpec sig;
auto &rhs = cell->connections_.at(port_name);
for (auto b : rhs) {
Wire *w = b.wire;
if (!w) continue;
w->port_output = true;
w->set_bool_attribute(ID(abc_scc_break));
w = module->wire(stringf("%s.abci", w->name.c_str()));
if (!w) {
w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire));
w->port_input = true;
}
else {
log_assert(b.offset < GetSize(w));
log_assert(w->port_input);
}
sig.append(RTLIL::SigBit(w, b.offset));
}
rhs = sig;
}
} }
module->fixup_ports(); module->fixup_ports();
@ -288,7 +272,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
bool show_tempdir, std::string box_file, std::string lut_file, bool show_tempdir, std::string box_file, std::string lut_file,
std::string wire_delay, const dict<int,IdString> &box_lookup) std::string wire_delay, const dict<int,IdString> &box_lookup,
const dict<IdString,pool<IdString>> &scc_break_inputs
)
{ {
module = current_module; module = current_module;
map_autoidx = autoidx++; map_autoidx = autoidx++;
@ -427,7 +413,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
RTLIL::Selection& sel = design->selection_stack.back(); RTLIL::Selection& sel = design->selection_stack.back();
sel.select(module); sel.select(module);
handle_loops(design); handle_loops(design, scc_break_inputs);
Pass::call(design, "aigmap"); Pass::call(design, "aigmap");
@ -1081,6 +1067,7 @@ struct Abc9Pass : public Pass {
extra_args(args, argidx, design); extra_args(args, argidx, design);
dict<int,IdString> box_lookup; dict<int,IdString> box_lookup;
dict<IdString,pool<IdString>> scc_break_inputs;
for (auto m : design->modules()) { for (auto m : design->modules()) {
auto it = m->attributes.find(ID(abc_box_id)); auto it = m->attributes.find(ID(abc_box_id));
if (it == m->attributes.end()) if (it == m->attributes.end())
@ -1093,6 +1080,56 @@ struct Abc9Pass : public Pass {
log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n", log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n",
log_id(m), id, log_id(r.first->second)); log_id(m), id, log_id(r.first->second));
log_assert(r.second); log_assert(r.second);
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
for (auto p : m->ports) {
auto w = m->wire(p);
log_assert(w);
if (w->port_input) {
if (w->attributes.count(ID(abc_scc_break)))
scc_break_inputs[m->name].insert(p);
if (w->attributes.count(ID(abc_carry))) {
if (carry_in)
log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m));
carry_in = w;
}
}
if (w->port_output) {
if (w->attributes.count(ID(abc_carry))) {
if (carry_out)
log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m));
carry_out = w;
}
}
}
if (carry_in || carry_out) {
if (carry_in && !carry_out)
log_error("Module '%s' contains an 'abc_carry' input port but no output port.\n", log_id(m));
if (!carry_in && carry_out)
log_error("Module '%s' contains an 'abc_carry' output port but no input port.\n", log_id(m));
// Make carry_in the last PI, and carry_out the last PO
// since ABC requires it this way
auto &ports = m->ports;
for (auto it = ports.begin(); it != ports.end(); ) {
RTLIL::Wire* w = m->wire(*it);
log_assert(w);
if (w == carry_in || w == carry_out) {
it = ports.erase(it);
continue;
}
if (w->port_id > carry_in->port_id)
--w->port_id;
if (w->port_id > carry_out->port_id)
--w->port_id;
log_assert(w->port_input || w->port_output);
log_assert(ports[w->port_id-1] == w->name);
++it;
}
ports.push_back(carry_in->name);
carry_in->port_id = ports.size();
ports.push_back(carry_out->name);
carry_out->port_id = ports.size();
}
} }
for (auto mod : design->selected_modules()) for (auto mod : design->selected_modules())
@ -1110,7 +1147,7 @@ struct Abc9Pass : public Pass {
if (!dff_mode || !clk_str.empty()) { if (!dff_mode || !clk_str.empty()) {
abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
delay_target, lutin_shared, fast_mode, show_tempdir, delay_target, lutin_shared, fast_mode, show_tempdir,
box_file, lut_file, wire_delay, box_lookup); box_file, lut_file, wire_delay, box_lookup, scc_break_inputs);
continue; continue;
} }
@ -1256,7 +1293,7 @@ struct Abc9Pass : public Pass {
en_sig = assign_map(std::get<3>(it.first)); en_sig = assign_map(std::get<3>(it.first));
abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$",
keepff, delay_target, lutin_shared, fast_mode, show_tempdir, keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
box_file, lut_file, wire_delay, box_lookup); box_file, lut_file, wire_delay, box_lookup, scc_break_inputs);
assign_map.set(mod); assign_map.set(mod);
} }
} }

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

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

@ -15,10 +15,15 @@ module L6MUX21 (input D0, D1, SD, output Z);
endmodule endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=1, abc_carry="CIN,COUT", lib_whitebox *) (* abc_box_id=1, lib_whitebox *)
module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1, module CCU2C(
output S0, S1, COUT); (* abc_carry *)
input CIN,
input A0, B0, C0, D0, A1, B1, C1, D1,
output S0, S1,
(* 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;
parameter INJECT1_0 = "YES"; parameter INJECT1_0 = "YES";
@ -104,12 +109,16 @@ module PFUMX (input ALUT, BLUT, C0, output Z);
endmodule endmodule
// --------------------------------------- // ---------------------------------------
//(* abc_box_id=2, abc_scc_break="DI,WAD,WRE" *) //(* abc_box_id=2 *)
module TRELLIS_DPR16X4 ( module TRELLIS_DPR16X4 (
input [3:0] DI, (* abc_scc_break *)
input [3:0] WAD, input [3:0] DI,
input WRE, WCK, (* abc_scc_break *)
input [3:0] RAD, input [3:0] WAD,
(* abc_scc_break *)
input WRE,
input WCK,
input [3:0] RAD,
output [3:0] DO output [3:0] DO
); );
parameter WCKMUX = "WCK"; parameter WCKMUX = "WCK";

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

@ -141,8 +141,16 @@ module SB_CARRY (output CO, input I0, I1, CI);
assign CO = (I0 && I1) || ((I0 || I1) && CI); assign CO = (I0 && I1) || ((I0 || I1) && CI);
endmodule endmodule
(* abc_box_id = 1, abc_carry="CI,CO", lib_whitebox *) (* abc_box_id = 1, lib_whitebox *)
module \$__ICE40_FULL_ADDER (output CO, O, input A, B, CI); module \$__ICE40_FULL_ADDER (
(* abc_carry *)
output CO,
output O,
input A,
input B,
(* abc_carry *)
input CI
);
SB_CARRY carry ( SB_CARRY carry (
.I0(A), .I0(A),
.I1(B), .I1(B),

View File

@ -32,8 +32,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_bb.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_bb.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_bb.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))

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";
@ -181,8 +196,16 @@ module XORCY(output O, input CI, LI);
assign O = CI ^ LI; assign O = CI ^ LI;
endmodule endmodule
(* abc_box_id = 4, abc_carry="CI,CO", lib_whitebox *) (* abc_box_id = 4, lib_whitebox *)
module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S); module CARRY4(
(* abc_carry *)
output [3:0] CO,
output [3:0] O,
(* abc_carry *)
input CI,
input CYINIT,
input [3:0] DI, S
);
assign O = S ^ {CO[2:0], CI | CYINIT}; assign O = S ^ {CO[2:0], CI | CYINIT};
assign CO[0] = S[0] ? CI | CYINIT : DI[0]; assign CO[0] = S[0] ? CI | CYINIT : DI[0];
assign CO[1] = S[1] ? CO[0] : DI[1]; assign CO[1] = S[1] ? CO[0] : DI[1];
@ -213,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;
@ -225,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;
@ -237,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;
@ -251,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;
@ -265,34 +288,39 @@ 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;
endmodule endmodule
(* abc_box_id = 5, abc_scc_break="D,WE" *) (* abc_box_id = 5 *)
module RAM32X1D ( module RAM32X1D (
output DPO, SPO, output DPO, SPO,
input D, WCLK, WE, (* abc_scc_break *)
input D,
(* clkbuf_sink *)
input WCLK,
(* 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
); );
@ -307,10 +335,15 @@ module RAM32X1D (
always @(posedge clk) if (WE) mem[a] <= D; always @(posedge clk) if (WE) mem[a] <= D;
endmodule endmodule
(* abc_box_id = 6, abc_scc_break="D,WE" *) (* abc_box_id = 6 *)
module RAM64X1D ( module RAM64X1D (
output DPO, SPO, output DPO, SPO,
input D, WCLK, WE, (* abc_scc_break *)
input D,
(* clkbuf_sink *)
input WCLK,
(* 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
); );
@ -325,10 +358,15 @@ module RAM64X1D (
always @(posedge clk) if (WE) mem[a] <= D; always @(posedge clk) if (WE) mem[a] <= D;
endmodule endmodule
(* abc_box_id = 7, abc_scc_break="D,WE" *) (* abc_box_id = 7 *)
module RAM128X1D ( module RAM128X1D (
output DPO, SPO, output DPO, SPO,
input D, WCLK, WE, (* abc_scc_break *)
input D,
(* clkbuf_sink *)
input WCLK,
(* abc_scc_break *)
input WE,
input [6:0] A, DPRA input [6:0] A, DPRA
); );
parameter INIT = 128'h0; parameter INIT = 128'h0;
@ -342,7 +380,9 @@ endmodule
module SRL16E ( module SRL16E (
output Q, output Q,
input A0, A1, A2, A3, CE, CLK, D (* clkbuf_sink *)
input CLK,
input A0, A1, A2, A3, CE, 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;
@ -354,7 +394,27 @@ 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, CLK, 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
@ -362,7 +422,9 @@ module SRLC32E (
output Q, output Q,
output Q31, output Q31,
input [4:0] A, input [4:0] A,
input CE, CLK, D (* clkbuf_sink *)
input CLK,
input CE, 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;

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 DSP48E1 (...); module DSP48E1 (...);
@ -175,6 +201,7 @@ module DSP48E1 (...);
input CEINMODE; input CEINMODE;
input CEM; input CEM;
input CEP; input CEP;
(* clkbuf_sink *)
input CLK; input CLK;
input [24:0] D; input [24:0] D;
input [4:0] INMODE; input [4:0] INMODE;
@ -227,11 +254,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
@ -272,11 +301,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
@ -1969,6 +2000,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
@ -1979,6 +2011,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;
@ -1993,7 +2026,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 (...);
@ -2001,8 +2037,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 (...);
@ -2014,7 +2054,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
@ -2028,7 +2070,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;
@ -2041,7 +2085,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
@ -2053,7 +2099,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
@ -2066,12 +2114,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;
@ -2095,6 +2181,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;
@ -2112,7 +2199,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;
@ -2124,6 +2213,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
@ -2143,6 +2233,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;
@ -2174,9 +2265,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;
@ -2197,8 +2290,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 (...);
@ -2209,6 +2304,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;
@ -2224,6 +2320,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;
@ -2238,8 +2335,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 (...);
@ -2251,7 +2351,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;
@ -2266,7 +2368,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;
@ -2282,7 +2386,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;
@ -2300,7 +2406,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;
@ -2348,15 +2456,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;
@ -2375,7 +2489,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 (...);
@ -2385,7 +2502,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 (...);
@ -2533,7 +2653,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
@ -2542,20 +2665,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;
@ -2586,6 +2716,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;
@ -2631,7 +2762,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;
@ -2673,9 +2806,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;
@ -3659,7 +3794,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 (...);
@ -3668,6 +3813,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
@ -3690,6 +3836,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
@ -3698,22 +3845,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 (...);
@ -3734,6 +3907,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
@ -3742,46 +3916,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,14 +63,17 @@ 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(" -nobram\n"); log(" -ise\n");
log(" disable inference of block rams\n"); log(" generate an output netlist suitable for ISE (enables -iopad)\n");
log("\n"); log("\n");
log(" -nodram\n"); log(" -nobram\n");
log(" disable inference of distributed rams\n"); log(" do not use block RAM cells in output netlist\n");
log("\n");
log(" -nolutram\n");
log(" do not use distributed RAM cells in output netlist\n");
log("\n"); log("\n");
log(" -nosrl\n"); log(" -nosrl\n");
log(" disable inference of shift registers\n"); log(" do not use distributed SRL cells in output netlist\n");
log("\n"); log("\n");
log(" -nocarry\n"); log(" -nocarry\n");
log(" do not use XORCY/MUXCY/CARRY4 cells in output netlist\n"); log(" do not use XORCY/MUXCY/CARRY4 cells in output netlist\n");
@ -78,6 +81,15 @@ struct SynthXilinxPass : public ScriptPass
log(" -nowidelut\n"); log(" -nowidelut\n");
log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n"); log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
log("\n"); log("\n");
log(" -iopad\n");
log(" enable I/O buffer insertion (selected automatically by -ise)\n");
log("\n");
log(" -noiopad\n");
log(" 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(" -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");
log(" above this number of inputs (minimum value 2, recommended value >= 5).\n"); log(" above this number of inputs (minimum value 2, recommended value >= 5).\n");
@ -104,7 +116,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, nodram, nosrl, nocarry, nowidelut, abc9; bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, abc9;
bool flatten_before_abc;
int widemux; int widemux;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
@ -116,13 +129,18 @@ 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;
nodram = false; nolutram = false;
nosrl = false; nosrl = false;
nocarry = false; nocarry = false;
nowidelut = false; nowidelut = false;
abc9 = false; abc9 = false;
flatten_before_abc = false;
widemux = 0; widemux = 0;
} }
@ -162,6 +180,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;
@ -178,6 +200,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;
@ -186,8 +224,8 @@ struct SynthXilinxPass : public ScriptPass
nobram = true; nobram = true;
continue; continue;
} }
if (args[argidx] == "-nodram") { if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
nodram = true; nolutram = true;
continue; continue;
} }
if (args[argidx] == "-nosrl") { if (args[argidx] == "-nosrl") {
@ -284,7 +322,7 @@ struct SynthXilinxPass : public ScriptPass
run("opt_clean"); run("opt_clean");
} }
if (check_label("bram", "(skip if '-nobram')")) { if (check_label("map_bram", "(skip if '-nobram')")) {
if (help_mode) { if (help_mode) {
run("memory_bram -rules +/xilinx/{family}_brams.txt"); run("memory_bram -rules +/xilinx/{family}_brams.txt");
run("techmap -map +/xilinx/{family}_brams_map.v"); run("techmap -map +/xilinx/{family}_brams_map.v");
@ -301,20 +339,23 @@ struct SynthXilinxPass : public ScriptPass
} }
} }
if (check_label("dram", "(skip if '-nodram')")) { if (check_label("map_lutram", "(skip if '-nolutram')")) {
if (!nodram || help_mode) { if (!nolutram || help_mode) {
run("memory_bram -rules +/xilinx/drams.txt"); run("memory_bram -rules +/xilinx/lutrams.txt");
run("techmap -map +/xilinx/drams_map.v"); run("techmap -map +/xilinx/lutrams_map.v");
} }
} }
if (check_label("fine")) { if (check_label("map_ffram")) {
if (widemux > 0) if (widemux > 0)
run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
// performs less efficiently // performs less efficiently
else else
run("opt -fast -full"); run("opt -fast -full");
run("memory_map"); run("memory_map");
}
if (check_label("fine")) {
run("dffsr2dff"); run("dffsr2dff");
run("dff2dffe"); run("dff2dffe");
if (help_mode) { if (help_mode) {
@ -382,6 +423,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) {
@ -410,6 +453,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,

View File

@ -6,13 +6,10 @@ equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
memory memory
opt -full opt -full
# TODO
#equiv_opt -run prove: -assert null
miter -equiv -flatten -make_assert -make_outputs gold gate miter miter -equiv -flatten -make_assert -make_outputs gold gate miter
#sat -verify -prove-asserts -tempinduct -show-inputs -show-outputs miter sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
design -load postopt design -load postopt
cd top cd top
select -assert-count 1 t:SB_RAM40_4K select -assert-count 1 t:SB_RAM40_4K
select -assert-none t:SB_RAM40_4K %% t:* %D select -assert-none t:SB_RAM40_4K %% t:* %D
write_verilog dpram_synth.v

View File

@ -1,81 +0,0 @@
module testbench;
reg clk;
initial begin
// $dumpfile("testbench.vcd");
// $dumpvars(0, testbench);
#5 clk = 0;
repeat (10000) begin
#5 clk = 1;
#5 clk = 0;
end
end
reg [7:0] data_a = 0;
reg [7:0] addr_a = 0;
reg [7:0] addr_b = 0;
reg we_a = 0;
reg re_a = 1;
wire [7:0] q_a;
reg mem_init = 0;
reg [7:0] pq_a;
always @(posedge clk) begin
#3;
data_a <= data_a + 17;
addr_a <= addr_a + 1;
addr_b <= addr_b + 1;
end
always @(posedge addr_a) begin
#10;
if(addr_a > 6'h3E)
mem_init <= 1;
end
always @(posedge clk) begin
//#3;
we_a <= !we_a;
end
reg [7:0] mem [(1<<8)-1:0];
always @(posedge clk) // Write memory.
begin
if (we_a)
mem[addr_a] <= data_a; // Using write address bus.
end
always @(posedge clk) // Read memory.
begin
pq_a <= mem[addr_b]; // Using read address bus.
end
top uut (
.din(data_a),
.write_en(we_a),
.waddr(addr_a),
.wclk(clk),
.raddr(addr_b),
.rclk(clk),
.dout(q_a)
);
uut_mem_checker port_a_test(.clk(clk), .init(mem_init), .en(!we_a), .A(q_a), .B(pq_a));
endmodule
module uut_mem_checker(input clk, input init, input en, input [7:0] A, input [7:0] B);
always @(posedge clk)
begin
#1;
if (en == 1 & init == 1 & A !== B)
begin
$display("ERROR: ASSERTION FAILED in %m:",$time," ",A," ",B);
$stop;
end
end
endmodule

View File

@ -1,6 +1,15 @@
read_verilog latches.v read_verilog latches.v
design -save read
proc
async2sync # converts latches to a 'sync' variant clocked by a 'super'-clock
flatten
synth_ice40
equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
design -load read
synth_ice40 synth_ice40
cd top cd top
select -assert-count 4 t:SB_LUT4 select -assert-count 4 t:SB_LUT4
select -assert-none t:SB_LUT4 %% t:* %D select -assert-none t:SB_LUT4 %% t:* %D
write_verilog latches_synth.v

View File

@ -1,57 +0,0 @@
module testbench;
reg clk;
initial begin
// $dumpfile("testbench.vcd");
// $dumpvars(0, testbench);
#5 clk = 0;
repeat (10000) begin
#5 clk = 1;
#5 clk = 0;
end
end
reg [2:0] dinA = 0;
wire doutB,doutB1,doutB2;
reg lat,latn,latsr = 0;
top uut (
.clk (clk ),
.a (dinA[0] ),
.pre (dinA[1] ),
.clr (dinA[2] ),
.b (doutB ),
.b1 (doutB1 ),
.b2 (doutB2 )
);
always @(posedge clk) begin
#3;
dinA <= dinA + 1;
end
always @*
if ( clk )
lat <= dinA[0];
always @*
if ( !clk )
latn <= dinA[0];
always @*
if ( dinA[2] )
latsr <= 1'b0;
else if ( dinA[1] )
latsr <= 1'b1;
else if ( clk )
latsr <= dinA[0];
assert_dff lat_test(.clk(clk), .test(doutB), .pat(lat));
assert_dff latn_test(.clk(clk), .test(doutB1), .pat(latn));
assert_dff latsr_test(.clk(clk), .test(doutB2), .pat(latsr));
endmodule

View File

@ -6,13 +6,10 @@ equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
memory memory
opt -full opt -full
# TODO
#equiv_opt -run prove: -assert null
miter -equiv -flatten -make_assert -make_outputs gold gate miter miter -equiv -flatten -make_assert -make_outputs gold gate miter
#sat -verify -prove-asserts -tempinduct -show-inputs -show-outputs miter sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
design -load postopt design -load postopt
cd top cd top
select -assert-count 1 t:SB_RAM40_4K select -assert-count 1 t:SB_RAM40_4K
select -assert-none t:SB_RAM40_4K %% t:* %D select -assert-none t:SB_RAM40_4K %% t:* %D
write_verilog memory_synth.v

View File

@ -1,79 +0,0 @@
module testbench;
reg clk;
initial begin
// $dumpfile("testbench.vcd");
// $dumpvars(0, testbench);
#5 clk = 0;
repeat (10000) begin
#5 clk = 1;
#5 clk = 0;
end
end
reg [7:0] data_a = 0;
reg [5:0] addr_a = 0;
reg we_a = 0;
reg re_a = 1;
wire [7:0] q_a;
reg mem_init = 0;
reg [7:0] pq_a;
top uut (
.data_a(data_a),
.addr_a(addr_a),
.we_a(we_a),
.clk(clk),
.q_a(q_a)
);
always @(posedge clk) begin
#3;
data_a <= data_a + 17;
addr_a <= addr_a + 1;
end
always @(posedge addr_a) begin
#10;
if(addr_a > 6'h3E)
mem_init <= 1;
end
always @(posedge clk) begin
//#3;
we_a <= !we_a;
end
// Declare the RAM variable for check
reg [7:0] ram[63:0];
// Port A for check
always @ (posedge clk)
begin
if (we_a)
begin
ram[addr_a] <= data_a;
pq_a <= data_a;
end
pq_a <= ram[addr_a];
end
uut_mem_checker port_a_test(.clk(clk), .init(mem_init), .en(!we_a), .A(q_a), .B(pq_a));
endmodule
module uut_mem_checker(input clk, input init, input en, input [7:0] A, input [7:0] B);
always @(posedge clk)
begin
#1;
if (en == 1 & init == 1 & A !== B)
begin
$display("ERROR: ASSERTION FAILED in %m:",$time," ",A," ",B);
$stop;
end
end
endmodule

View File

@ -21,13 +21,13 @@ for x in *.ys; do
fi fi
done done
for s in *.sh; do #for s in *.sh; do
if [ "$s" != "run-test.sh" ]; then # if [ "$s" != "run-test.sh" ]; then
echo "all:: run-$s" # echo "all:: run-$s"
echo "run-$s:" # echo "run-$s:"
echo " @echo 'Running $s..'" # echo " @echo 'Running $s..'"
echo " @bash $s" # echo " @bash $s"
fi # fi
done #done
} > run-test.mk } > run-test.mk
exec ${MAKE:-make} -f 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,4 +1,3 @@
module demo_001(y1, y2, y3, y4); module demo_001(y1, y2, y3, y4);
output [7:0] y1, y2, y3, y4; output [7:0] y1, y2, y3, y4;
@ -22,3 +21,13 @@ module demo_002(y0, y1, y2, y3);
assign y3 = 1 ? -1 : 'd0; assign y3 = 1 ? -1 : 'd0;
endmodule endmodule
module demo_003(output A, B);
parameter real p = 0;
assign A = (p==1.0);
assign B = (p!="1.000000");
endmodule
module demo_004(output A, B, C, D);
demo_003 #(1.0) demo_real (A, B);
demo_003 #(1) demo_int (C, D);
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

View File

@ -0,0 +1,21 @@
test_pmgen -generate reduce
hierarchy -top pmtest_test_pmgen_pm_reduce
flatten; opt_clean
design -save gold
test_pmgen -reduce_chain
design -stash gate
design -copy-from gold -as gold pmtest_test_pmgen_pm_reduce
design -copy-from gate -as gate pmtest_test_pmgen_pm_reduce
miter -equiv -flatten -make_assert gold gate miter
sat -verify -prove-asserts miter
design -load gold
test_pmgen -reduce_tree
design -stash gate
design -copy-from gold -as gold pmtest_test_pmgen_pm_reduce
design -copy-from gate -as gate pmtest_test_pmgen_pm_reduce
miter -equiv -flatten -make_assert gold gate miter
sat -verify -prove-asserts miter