Merge remote-tracking branch 'origin/master' into xaig_dff

This commit is contained in:
Eddie Hung 2019-09-27 15:14:31 -07:00
commit 8f5710c464
174 changed files with 26477 additions and 2398 deletions

View File

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

130
CHANGELOG
View File

@ -12,7 +12,10 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added "synth_xilinx -abc9" (experimental) - Added "synth_xilinx -abc9" (experimental)
- Added "synth_ice40 -abc9" (experimental) - Added "synth_ice40 -abc9" (experimental)
- Added "synth -abc9" (experimental) - Added "synth -abc9" (experimental)
- Added "script -scriptwire - Added "script -scriptwire"
- Added "synth_xilinx -nocarry"
- Added "synth_xilinx -nowidelut"
- Added "synth_ecp5 -nowidelut"
- "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable) - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
- Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram) - Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram)
- Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram) - Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram)
@ -23,37 +26,142 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added automatic gzip compression (based on filename extension) for backends - Added automatic gzip compression (based on filename extension) for backends
- Improve attribute and parameter encoding in JSON to avoid ambiguities between - Improve attribute and parameter encoding in JSON to avoid ambiguities between
bit vectors and strings containing [01xz]* bit vectors and strings containing [01xz]*
- Added "clkbufmap" pass
- Added "extractinv" pass and "invertible_pin" attribute
- Added "synth_xilinx -family xc6s" for Spartan 6 support (experimental)
- Added "synth_xilinx -ise" (experimental)
- Added "synth_xilinx -iopad"
- "synth_xilinx" now automatically inserts clock buffers (add -noclkbuf to disable)
- Improvements in pmgen: subpattern and recursive matches - Improvements in pmgen: subpattern and recursive matches
- Added "opt_share" pass, run as part of "opt -full" - Added "opt_share" pass, run as part of "opt -full"
- Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping - Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
- Removed "ice40_unlut" - Removed "ice40_unlut"
- Improvements in pmgen: slices, choices, define, generate
- Added "xilinx_srl" for Xilinx shift register extraction
- Removed "shregmap -tech xilinx" (superseded by "xilinx_srl")
- Added "_TECHMAP_WIREINIT_*_" attribute and "_TECHMAP_REMOVEINIT_*_" wire for "techmap" pass
- Added "-match-init" option to "dff2dffs" pass
- Added "techmap_autopurge" support to techmap
- Added "add -mod <modname[s]>"
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

@ -88,11 +88,13 @@ ifeq ($(OS), Darwin)
PLUGIN_LDFLAGS += -undefined dynamic_lookup PLUGIN_LDFLAGS += -undefined dynamic_lookup
# homebrew search paths # homebrew search paths
ifneq ($(shell which brew),) ifneq ($(shell :; command -v 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)
@ -100,8 +102,8 @@ PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)
# macports search paths # macports search paths
else ifneq ($(shell which port),) else ifneq ($(shell :; command -v port),)
PORT_PREFIX := $(patsubst %/bin/port,%,$(shell which port)) PORT_PREFIX := $(patsubst %/bin/port,%,$(shell :; command -v port))
CXXFLAGS += -I$(PORT_PREFIX)/include CXXFLAGS += -I$(PORT_PREFIX)/include
LDFLAGS += -L$(PORT_PREFIX)/lib LDFLAGS += -L$(PORT_PREFIX)/lib
PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(PORT_PREFIX)/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+431
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
@ -704,6 +709,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/opt && bash run-test.sh +cd tests/opt && bash run-test.sh
+cd tests/aiger && bash run-test.sh $(ABCOPT) +cd tests/aiger && bash run-test.sh $(ABCOPT)
+cd tests/arch && bash run-test.sh +cd tests/arch && bash run-test.sh
+cd tests/ice40 && bash run-test.sh $(SEEDOPT)
@echo "" @echo ""
@echo " Passed \"make test\"." @echo " Passed \"make test\"."
@echo "" @echo ""

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:
@ -327,7 +330,46 @@ Verilog Attributes and non-standard features
- The ``parameter`` and ``localparam`` attributes are used to mark wires - The ``parameter`` and ``localparam`` attributes are used to mark wires
that represent module parameters or localparams (when the HDL front-end that represent module parameters or localparams (when the HDL front-end
is run in -pwires mode). is run in ``-pwires`` mode).
- Wires marked with the ``hierconn`` attribute are connected to wires with the
same name (format ``cell_name.identifier``) when they are imported from
sub-modules by ``flatten``.
- 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 ``invertible_pin`` attribute can be set on a port to mark it as
invertible via a cell parameter. The name of the inversion parameter
is specified as the value of this attribute. The value of the inversion
parameter must be of the same width as the port, with 1 indicating
an inverted bit and 0 indicating a non-inverted bit.
- 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.
- 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_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.
- The port attribute ``abc_arrival`` specifies an integer (for output ports
only) to be used as the arrival time of this sequential port. It can be used,
for example, to specify the clk-to-Q delay of a flip-flop for consideration
during techmapping.
- 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
@ -405,15 +447,6 @@ Verilog Attributes and non-standard features
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
functionality. (By default specify .. endspecify blocks are ignored.) functionality. (By default specify .. endspecify blocks are ignored.)
- The module attribute ``abc_box_id`` specifies a positive integer linking a
blackbox or whitebox definition to a corresponding entry in a `abc9`
box-file.
- The port attribute ``abc_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

@ -101,7 +101,7 @@ struct AigerWriter
return a; return a;
} }
AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module) AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
{ {
pool<SigBit> undriven_bits; pool<SigBit> undriven_bits;
pool<SigBit> unused_bits; pool<SigBit> unused_bits;
@ -367,6 +367,12 @@ struct AigerWriter
aig_latchin.push_back(a); aig_latchin.push_back(a);
} }
if (lmode && aig_l == 0) {
aig_m++, aig_l++;
aig_latchinit.push_back(0);
aig_latchin.push_back(0);
}
if (!initstate_bits.empty() || !init_inputs.empty()) if (!initstate_bits.empty() || !init_inputs.empty())
aig_latchin.push_back(1); aig_latchin.push_back(1);
@ -704,9 +710,9 @@ struct AigerBackend : public Backend {
log(" -vmap <filename>\n"); log(" -vmap <filename>\n");
log(" like -map, but more verbose\n"); log(" like -map, but more verbose\n");
log("\n"); log("\n");
log(" -I, -O, -B\n"); log(" -I, -O, -B, -L\n");
log(" If the design contains no input/output/assert then create one\n"); log(" If the design contains no input/output/assert/flip-flop then create one\n");
log(" dummy input/output/bad_state pin to make the tools reading the\n"); log(" dummy input/output/bad_state-pin or latch to make the tools reading the\n");
log(" AIGER file happy.\n"); log(" AIGER file happy.\n");
log("\n"); log("\n");
} }
@ -720,6 +726,7 @@ struct AigerBackend : public Backend {
bool imode = false; bool imode = false;
bool omode = false; bool omode = false;
bool bmode = false; bool bmode = false;
bool lmode = false;
std::string map_filename; std::string map_filename;
log_header(design, "Executing AIGER backend.\n"); log_header(design, "Executing AIGER backend.\n");
@ -764,6 +771,10 @@ struct AigerBackend : public Backend {
bmode = true; bmode = true;
continue; continue;
} }
if (args[argidx] == "-L") {
lmode = true;
continue;
}
break; break;
} }
extra_args(f, filename, args, argidx); extra_args(f, filename, args, argidx);
@ -773,7 +784,7 @@ struct AigerBackend : public Backend {
if (top_module == nullptr) if (top_module == nullptr)
log_error("Can't find top module in current design!\n"); log_error("Can't find top module in current design!\n");
AigerWriter writer(top_module, zinit_mode, imode, omode, bmode); AigerWriter writer(top_module, zinit_mode, imode, omode, bmode, lmode);
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
if (!map_filename.empty()) { if (!map_filename.empty()) {

View File

@ -345,12 +345,12 @@ struct XAigerWriter
} }
} }
else { else {
bool cell_known = inst_module; bool cell_known = inst_module || cell->known();
for (const auto &c : cell->connections()) { for (const auto &c : cell->connections()) {
if (c.second.is_fully_const()) continue; if (c.second.is_fully_const()) continue;
auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr; auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr;
auto is_input = !cell_known || port_wire->port_input; auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first);
auto is_output = !cell_known || port_wire->port_output; auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first);
if (!is_input && !is_output) if (!is_input && !is_output)
log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type)); log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
@ -653,6 +653,11 @@ struct XAigerWriter
aig_outputs.push_back(bit2aig(bit)); aig_outputs.push_back(bit2aig(bit));
} }
if (output_bits.empty()) {
output_bits.insert(State::S0);
omode = true;
}
for (auto bit : output_bits) { for (auto bit : output_bits) {
ordered_outputs[bit] = aig_o++; ordered_outputs[bit] = aig_o++;
aig_outputs.push_back(bit2aig(bit)); aig_outputs.push_back(bit2aig(bit));
@ -749,6 +754,7 @@ struct XAigerWriter
f << "c"; f << "c";
log_assert(!output_bits.empty());
auto write_buffer = [](std::stringstream &buffer, int i32) { auto write_buffer = [](std::stringstream &buffer, int i32) {
int32_t i32_be = to_big_endian(i32); int32_t i32_be = to_big_endian(i32);
buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be)); buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
@ -1024,6 +1030,8 @@ struct XAigerWriter
f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
output_lines.sort(); output_lines.sort();
if (omode)
output_lines[State::S0] = "output 0 0 $__dummy__\n";
for (auto &it : output_lines) for (auto &it : output_lines)
f << it.second; f << it.second;
log_assert(output_lines.size() == output_bits.size()); log_assert(output_lines.size() == output_bits.size());

View File

@ -685,7 +685,7 @@ struct BtorWorker
} }
else else
{ {
int nid_init_val = next_nid++; nid_init_val = next_nid++;
btorf("%d state %d\n", nid_init_val, sid); btorf("%d state %d\n", nid_init_val, sid);
for (int i = 0; i < nwords; i++) { for (int i = 0; i < nwords; i++) {

View File

@ -16,7 +16,7 @@ yosys-smtbmc-script.py: backends/smt2/smtbmc.py
-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
$(P) gcc -DGUI=0 -O -s -o $@ $< $(P) $(CXX) -DGUI=0 -O -s -o $@ $<
# Other targets # Other targets
else else
TARGETS += yosys-smtbmc TARGETS += yosys-smtbmc

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

@ -158,6 +158,11 @@ std::string AST::type2str(AstNodeType type)
X(AST_POSEDGE) X(AST_POSEDGE)
X(AST_NEGEDGE) X(AST_NEGEDGE)
X(AST_EDGE) X(AST_EDGE)
X(AST_INTERFACE)
X(AST_INTERFACEPORT)
X(AST_INTERFACEPORTTYPE)
X(AST_MODPORT)
X(AST_MODPORTMEMBER)
X(AST_PACKAGE) X(AST_PACKAGE)
#undef X #undef X
default: default:
@ -1099,6 +1104,13 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
ignoreThisSignalsInInitial = RTLIL::SigSpec(); ignoreThisSignalsInInitial = RTLIL::SigSpec();
} }
else {
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
continue;
current_module->attributes[attr.first] = attr.second->asAttrConst();
}
}
if (ast->type == AST_INTERFACE) if (ast->type == AST_INTERFACE)
current_module->set_bool_attribute("\\is_interface"); current_module->set_bool_attribute("\\is_interface");
@ -1284,6 +1296,8 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule
// from AST. The interface members are copied into the AST module with the prefix of the interface. // from AST. The interface members are copied into the AST module with the prefix of the interface.
void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces) void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces)
{ {
loadconfig();
bool is_top = false; bool is_top = false;
AstNode *new_ast = ast->clone(); AstNode *new_ast = ast->clone();
for (auto &intf : local_interfaces) { for (auto &intf : local_interfaces) {
@ -1467,24 +1481,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
stripped_name = stripped_name.substr(9); stripped_name = stripped_name.substr(9);
log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
loadconfig();
current_ast = NULL;
flag_dump_ast1 = false;
flag_dump_ast2 = false;
flag_dump_vlog1 = false;
flag_dump_vlog2 = false;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_noblackbox = noblackbox;
flag_lib = lib;
flag_nowb = nowb;
flag_noopt = noopt;
flag_icells = icells;
flag_pwires = pwires;
flag_autowire = autowire;
use_internal_line_num();
std::string para_info; std::string para_info;
AstNode *new_ast = ast->clone(); AstNode *new_ast = ast->clone();
@ -1565,6 +1562,27 @@ RTLIL::Module *AstModule::clone() const
return new_mod; return new_mod;
} }
void AstModule::loadconfig() const
{
current_ast = NULL;
flag_dump_ast1 = false;
flag_dump_ast2 = false;
flag_dump_vlog1 = false;
flag_dump_vlog2 = false;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_noblackbox = noblackbox;
flag_lib = lib;
flag_nowb = nowb;
flag_noopt = noopt;
flag_icells = icells;
flag_pwires = pwires;
flag_autowire = autowire;
use_internal_line_num();
}
// internal dummy line number callbacks // internal dummy line number callbacks
namespace { namespace {
int internal_line_num; int internal_line_num;

View File

@ -299,6 +299,7 @@ namespace AST
std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail); std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail);
void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE; void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE;
RTLIL::Module *clone() const YS_OVERRIDE; RTLIL::Module *clone() const YS_OVERRIDE;
void loadconfig() const;
}; };
// this must be set by the language frontend before parsing the sources // this must be set by the language frontend before parsing the sources

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)) { }
} }
@ -1525,10 +1530,16 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_en->str] = wire_en; current_scope[wire_en->str] = wire_en;
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
std::vector<RTLIL::State> x_bit; AstNode *check_defval;
x_bit.push_back(RTLIL::State::Sx); if (type == AST_LIVE || type == AST_FAIR) {
check_defval = new AstNode(AST_REDUCE_BOOL, children[0]->clone());
} else {
std::vector<RTLIL::State> x_bit;
x_bit.push_back(RTLIL::State::Sx);
check_defval = mkconst_bits(x_bit, false);
}
AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false)); AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), check_defval);
assign_check->children[0]->str = id_check; assign_check->children[0]->str = id_check;
assign_check->children[0]->was_checked = true; assign_check->children[0]->was_checked = true;
@ -1541,9 +1552,13 @@ skip_dynamic_range_lvalue_expansion:;
default_signals->children.push_back(assign_en); default_signals->children.push_back(assign_en);
current_top_block->children.insert(current_top_block->children.begin(), default_signals); current_top_block->children.insert(current_top_block->children.begin(), default_signals);
assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); if (type == AST_LIVE || type == AST_FAIR) {
assign_check->children[0]->str = id_check; assign_check = nullptr;
assign_check->children[0]->was_checked = true; } else {
assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone()));
assign_check->children[0]->str = id_check;
assign_check->children[0]->was_checked = true;
}
if (current_always == nullptr || current_always->type != AST_INITIAL) { if (current_always == nullptr || current_always->type != AST_INITIAL) {
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
@ -1555,7 +1570,8 @@ skip_dynamic_range_lvalue_expansion:;
assign_en->children[0]->was_checked = true; assign_en->children[0]->was_checked = true;
newNode = new AstNode(AST_BLOCK); newNode = new AstNode(AST_BLOCK);
newNode->children.push_back(assign_check); if (assign_check != nullptr)
newNode->children.push_back(assign_check);
newNode->children.push_back(assign_en); newNode->children.push_back(assign_en);
AstNode *assertnode = new AstNode(type); AstNode *assertnode = new AstNode(type);
@ -2879,8 +2895,15 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map) void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map)
{ {
if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) { if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) {
current_scope[index_var]->children[0]->cloneInto(this); if (children.empty()) {
return; current_scope[index_var]->children[0]->cloneInto(this);
} else {
AstNode *p = new AstNode(AST_LOCALPARAM, current_scope[index_var]->children[0]->clone());
p->str = stringf("$genval$%d", autoidx++);
current_ast_mod->children.push_back(p);
str = p->str;
id2ast = p;
}
} }
if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0) if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0)

View File

@ -85,10 +85,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
digits.push_back(10 + *str - 'A'); digits.push_back(10 + *str - 'A');
else if (*str == 'x' || *str == 'X') else if (*str == 'x' || *str == 'X')
digits.push_back(0xf0); digits.push_back(0xf0);
else if (*str == 'z' || *str == 'Z') else if (*str == 'z' || *str == 'Z' || *str == '?')
digits.push_back(0xf1); digits.push_back(0xf1);
else if (*str == '?')
digits.push_back(0xf2);
str++; str++;
} }
@ -112,8 +110,6 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx); data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx);
else if (*it == 0xf1) else if (*it == 0xf1)
data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz); data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz);
else if (*it == 0xf2)
data.push_back(RTLIL::Sa);
else else
data.push_back((*it & bitmask) ? State::S1 : State::S0); data.push_back((*it & bitmask) ? State::S1 : State::S0);
} }
@ -199,13 +195,13 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
if (str == endptr) if (str == endptr)
len_in_bits = -1; len_in_bits = -1;
// The "<bits>'s?[bodhBODH]<digits>" syntax // The "<bits>'[sS]?[bodhBODH]<digits>" syntax
if (*endptr == '\'') if (*endptr == '\'')
{ {
std::vector<RTLIL::State> data; std::vector<RTLIL::State> data;
bool is_signed = false; bool is_signed = false;
bool is_unsized = len_in_bits < 0; bool is_unsized = len_in_bits < 0;
if (*(endptr+1) == 's') { if (*(endptr+1) == 's' || *(endptr+1) == 'S') {
is_signed = true; is_signed = true;
endptr++; endptr++;
} }

View File

@ -239,7 +239,7 @@ YOSYS_NAMESPACE_END
return TOK_CONSTVAL; return TOK_CONSTVAL;
} }
[0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { [0-9]*[ \t]*\'[sS]?[bodhBODH]?[ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext); frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONSTVAL; return TOK_CONSTVAL;
} }

View File

@ -48,7 +48,7 @@ using zlib to write gzip-compressed data every time the stream is flushed.
*/ */
class gzip_ostream : public std::ostream { class gzip_ostream : public std::ostream {
public: public:
gzip_ostream() gzip_ostream() : std::ostream(nullptr)
{ {
rdbuf(&outbuf); rdbuf(&outbuf);
} }
@ -71,7 +71,7 @@ private:
str(""); str("");
return 0; return 0;
} }
~gzip_streambuf() virtual ~gzip_streambuf()
{ {
sync(); sync();
gzclose(gzf); gzclose(gzf);
@ -498,7 +498,15 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
if (f != NULL) { if (f != NULL) {
// Check for gzip magic // Check for gzip magic
unsigned char magic[3]; unsigned char magic[3];
int n = readsome(*ff, reinterpret_cast<char*>(magic), 3); int n = 0;
while (n < 3)
{
int c = ff->get();
if (c != EOF) {
magic[n] = (unsigned char) c;
}
n++;
}
if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) { if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) {
#ifdef YOSYS_ENABLE_ZLIB #ifdef YOSYS_ENABLE_ZLIB
log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str()); log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str());

View File

@ -135,9 +135,11 @@ struct SigPool
} }
}; };
template <typename T, class Compare = std::less<T>> template <typename T, class Compare = void>
struct SigSet struct SigSet
{ {
static_assert(!std::is_same<Compare,void>::value, "Default value for `Compare' class not found for SigSet<T>. Please specify.");
struct bitDef_t : public std::pair<RTLIL::Wire*, int> { struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { } bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
@ -220,6 +222,13 @@ struct SigSet
} }
}; };
template<typename T>
class SigSet<T, typename std::enable_if<!std::is_pointer<T>::value>::type> : public SigSet<T, std::less<T>> {};
template<typename T>
using sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell*>::value>::type;
template<typename T>
class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {};
struct SigMap struct SigMap
{ {
mfp<SigBit> database; mfp<SigBit> database;

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

@ -65,7 +65,7 @@ SOFTWARE. */
int child_pid=0; int child_pid=0;
int fail(char *format, char *data) { int fail(const char *format, const char *data) {
/* Print error message to stderr and return 2 */ /* Print error message to stderr and return 2 */
fprintf(stderr, format, data); fprintf(stderr, format, data);
return 2; return 2;
@ -76,7 +76,7 @@ char *quoted(char *data) {
/* We allocate twice as much space as needed to deal with worse-case /* We allocate twice as much space as needed to deal with worse-case
of having to escape everything. */ of having to escape everything. */
char *result = calloc(ln*2+3, sizeof(char)); char *result = (char *)calloc(ln*2+3, sizeof(char));
char *presult = result; char *presult = result;
*presult++ = '"'; *presult++ = '"';
@ -120,7 +120,7 @@ char *loadable_exe(char *exename) {
if (!hPython) return NULL; */ if (!hPython) return NULL; */
/* Return the absolute filename for spawnv */ /* Return the absolute filename for spawnv */
result = calloc(MAX_PATH, sizeof(char)); result = (char *)calloc(MAX_PATH, sizeof(char));
strncpy(result, exename, MAX_PATH); strncpy(result, exename, MAX_PATH);
/*if (result) GetModuleFileNameA(hPython, result, MAX_PATH); /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
@ -158,7 +158,7 @@ char **parse_argv(char *cmdline, int *argc)
{ {
/* Parse a command line in-place using MS C rules */ /* Parse a command line in-place using MS C rules */
char **result = calloc(strlen(cmdline), sizeof(char *)); char **result = (char **)calloc(strlen(cmdline), sizeof(char *));
char *output = cmdline; char *output = cmdline;
char c; char c;
int nb = 0; int nb = 0;

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

@ -25,6 +25,7 @@ OBJS += passes/cmds/plugin.o
OBJS += passes/cmds/check.o OBJS += passes/cmds/check.o
OBJS += passes/cmds/qwp.o OBJS += passes/cmds/qwp.o
OBJS += passes/cmds/edgetypes.o OBJS += passes/cmds/edgetypes.o
OBJS += passes/cmds/portlist.o
OBJS += passes/cmds/chformal.o OBJS += passes/cmds/chformal.o
OBJS += passes/cmds/chtype.o OBJS += passes/cmds/chtype.o
OBJS += passes/cmds/blackbox.o OBJS += passes/cmds/blackbox.o

View File

@ -105,6 +105,11 @@ struct AddPass : public Pass {
log("Like 'add -input', but also connect the signal between instances of the\n"); log("Like 'add -input', but also connect the signal between instances of the\n");
log("selected modules.\n"); log("selected modules.\n");
log("\n"); log("\n");
log("\n");
log(" add -mod <name[s]>\n");
log("\n");
log("Add module[s] with the specified name[s].\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
{ {
@ -113,6 +118,7 @@ struct AddPass : public Pass {
bool arg_flag_input = false; bool arg_flag_input = false;
bool arg_flag_output = false; bool arg_flag_output = false;
bool arg_flag_global = false; bool arg_flag_global = false;
bool mod_mode = false;
int arg_width = 0; int arg_width = 0;
size_t argidx; size_t argidx;
@ -133,8 +139,20 @@ struct AddPass : public Pass {
arg_width = atoi(args[++argidx].c_str()); arg_width = atoi(args[++argidx].c_str());
continue; continue;
} }
if (arg == "-mod") {
mod_mode = true;
argidx++;
break;
}
break; break;
} }
if (mod_mode) {
for (; argidx < args.size(); argidx++)
design->addModule(RTLIL::escape_id(args[argidx]));
return;
}
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto &mod : design->modules_) for (auto &mod : design->modules_)

93
passes/cmds/portlist.cc Normal file
View File

@ -0,0 +1,93 @@
/*
* 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
struct PortlistPass : public Pass {
PortlistPass() : Pass("portlist", "list (top-level) ports") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" portlist [options] [selection]\n");
log("\n");
log("This command lists all module ports found in the selected modules.\n");
log("\n");
log("If no selection is provided then it lists the ports on the top module.\n");
log("\n");
log(" -m\n");
log(" print verilog blackbox module definitions instead of port lists\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool m_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-m") {
m_mode = true;
continue;
}
break;
}
bool first_module = true;
auto handle_module = [&](RTLIL::Module *module) {
vector<string> ports;
if (first_module)
first_module = false;
else
log("\n");
for (auto port : module->ports) {
auto *w = module->wire(port);
ports.push_back(stringf("%s [%d:%d] %s", w->port_input ? w->port_output ? "inout" : "input" : "output",
w->upto ? w->start_offset : w->start_offset + w->width - 1,
w->upto ? w->start_offset + w->width - 1 : w->start_offset,
log_id(w)));
}
log("module %s%s\n", log_id(module), m_mode ? " (" : "");
for (int i = 0; i < GetSize(ports); i++)
log("%s%s\n", ports[i].c_str(), m_mode && i+1 < GetSize(ports) ? "," : "");
if (m_mode)
log(");\nendmodule\n");
};
if (argidx == args.size())
{
auto *top = design->top_module();
if (top == nullptr)
log_cmd_error("Can't find top module in current design!\n");
handle_module(top);
}
else
{
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
handle_module(module);
}
}
} PortlistPass;
PRIVATE_NAMESPACE_END

View File

@ -664,7 +664,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
} else } else
if (arg == "%D") { if (arg == "%D") {
if (work_stack.size() < 2) if (work_stack.size() < 2)
log_cmd_error("Must have at least two elements on the stack for operator %%d.\n"); log_cmd_error("Must have at least two elements on the stack for operator %%D.\n");
select_op_diff(design, work_stack[work_stack.size()-1], work_stack[work_stack.size()-2]); select_op_diff(design, work_stack[work_stack.size()-1], work_stack[work_stack.size()-2]);
work_stack[work_stack.size()-2] = work_stack[work_stack.size()-1]; work_stack[work_stack.size()-2] = work_stack[work_stack.size()-1];
work_stack.pop_back(); work_stack.pop_back();
@ -693,7 +693,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
} else } else
if (arg == "%C") { if (arg == "%C") {
if (work_stack.size() < 1) if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%M.\n"); log_cmd_error("Must have at least one element on the stack for operator %%C.\n");
select_op_module_to_cells(design, work_stack[work_stack.size()-1]); select_op_module_to_cells(design, work_stack[work_stack.size()-1]);
} else } else
if (arg == "%c") { if (arg == "%c") {

View File

@ -26,6 +26,10 @@
# include <dirent.h> # include <dirent.h>
#endif #endif
#ifdef __APPLE__
# include <unistd.h>
#endif
#ifdef YOSYS_ENABLE_READLINE #ifdef YOSYS_ENABLE_READLINE
# include <readline/readline.h> # include <readline/readline.h>
#endif #endif
@ -866,7 +870,11 @@ struct ShowPass : public Pass {
log_cmd_error("Shell command failed!\n"); log_cmd_error("Shell command failed!\n");
} else } else
if (format.empty()) { if (format.empty()) {
#ifdef __APPLE__
std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str());
#else
std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str()); std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
#endif
log("Exec: %s\n", cmd.c_str()); log("Exec: %s\n", cmd.c_str());
if (run_command(cmd) != 0) if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n"); log_cmd_error("Shell command failed!\n");

View File

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

View File

@ -46,6 +46,9 @@ struct EquivOptPass:public ScriptPass
log(" -assert\n"); log(" -assert\n");
log(" produce an error if the circuits are not equivalent.\n"); log(" produce an error if the circuits are not equivalent.\n");
log("\n"); log("\n");
log(" -multiclock\n");
log(" run clk2fflogic before equivalence checking.\n");
log("\n");
log(" -undef\n"); log(" -undef\n");
log(" enable modelling of undef states during equiv_induct.\n"); log(" enable modelling of undef states during equiv_induct.\n");
log("\n"); log("\n");
@ -55,7 +58,7 @@ struct EquivOptPass:public ScriptPass
} }
std::string command, techmap_opts; std::string command, techmap_opts;
bool assert, undef; bool assert, undef, multiclock;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
@ -63,6 +66,7 @@ struct EquivOptPass:public ScriptPass
techmap_opts = ""; techmap_opts = "";
assert = false; assert = false;
undef = false; undef = false;
multiclock = false;
} }
void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE
@ -92,6 +96,10 @@ struct EquivOptPass:public ScriptPass
undef = true; undef = true;
continue; continue;
} }
if (args[argidx] == "-multiclock") {
multiclock = true;
continue;
}
break; break;
} }
@ -146,6 +154,8 @@ struct EquivOptPass:public ScriptPass
} }
if (check_label("prove")) { if (check_label("prove")) {
if (multiclock || help_mode)
run("clk2fflogic", "(only with -multiclock)");
run("equiv_make gold gate equiv"); run("equiv_make gold gate equiv");
if (help_mode) if (help_mode)
run("equiv_induct [-undef] equiv"); run("equiv_induct [-undef] equiv");

View File

@ -808,6 +808,30 @@ struct HierarchyPass : public Pass {
if (mod_it.second->get_bool_attribute("\\top")) if (mod_it.second->get_bool_attribute("\\top"))
top_mod = mod_it.second; top_mod = mod_it.second;
if (top_mod != nullptr && top_mod->name.begins_with("$abstract")) {
IdString top_name = top_mod->name.substr(strlen("$abstract"));
dict<RTLIL::IdString, RTLIL::Const> top_parameters;
for (auto &para : parameters) {
SigSpec sig_value;
if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
}
top_mod = design->module(top_mod->derive(design, top_parameters));
if (top_mod != nullptr && top_mod->name != top_name) {
Module *m = top_mod->clone();
m->name = top_name;
Module *old_mod = design->module(top_name);
if (old_mod)
design->remove(old_mod);
design->add(m);
top_mod = m;
}
}
if (top_mod == nullptr && auto_top_mode) { if (top_mod == nullptr && auto_top_mode) {
log_header(design, "Finding top of design hierarchy..\n"); log_header(design, "Finding top of design hierarchy..\n");
dict<Module*, int> db; dict<Module*, int> db;

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))));
@ -931,6 +953,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (b.is_fully_const()) { if (b.is_fully_const()) {
if (b.is_fully_undef()) {
RTLIL::SigSpec input = b;
ACTION_DO(ID::Y, Const(State::Sx, GetSize(cell->getPort(ID::Y))));
} else
if (b.as_bool() == (cell->type == ID($eq))) { if (b.as_bool() == (cell->type == ID($eq))) {
RTLIL::SigSpec input = b; RTLIL::SigSpec input = b;
ACTION_DO(ID::Y, cell->getPort(ID::A)); ACTION_DO(ID::Y, cell->getPort(ID::A));
@ -1142,7 +1168,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

@ -108,12 +108,13 @@ bool cell_supported(RTLIL::Cell *cell)
return false; return false;
} }
std::map<IdString, IdString> mergeable_type_map{ std::map<IdString, IdString> mergeable_type_map;
{ID($sub), ID($add)},
};
bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b) bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b)
{ {
if (mergeable_type_map.empty()) {
mergeable_type_map.insert({ID($sub), ID($add)});
}
auto a_type = a->type; auto a_type = a->type;
if (mergeable_type_map.count(a_type)) if (mergeable_type_map.count(a_type))
a_type = mergeable_type_map.at(a_type); a_type = mergeable_type_map.at(a_type);

View File

@ -4,7 +4,7 @@
# -------------------------------------- # --------------------------------------
OBJS += passes/pmgen/test_pmgen.o OBJS += passes/pmgen/test_pmgen.o
passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h passes/pmgen/xilinx_srl_pm.h
$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) $(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h))
# -------------------------------------- # --------------------------------------
@ -17,7 +17,7 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_dsp_pm.h))
OBJS += passes/pmgen/ice40_wrapcarry.o 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
$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
# -------------------------------------- # --------------------------------------
@ -27,6 +27,13 @@ $(eval $(call add_extra_objs,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
PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmux.pmg
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)
# --------------------------------------
OBJS += passes/pmgen/xilinx_srl.o
passes/pmgen/xilinx_srl.o: passes/pmgen/xilinx_srl_pm.h
$(eval $(call add_extra_objs,passes/pmgen/xilinx_srl_pm.h))

View File

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

View File

@ -64,11 +64,6 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool(); bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool();
if (mul_signed) {
log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n");
return;
}
log(" replacing $mul with SB_MAC16 cell.\n"); log(" replacing $mul with SB_MAC16 cell.\n");
Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");

View File

@ -60,6 +60,7 @@ struct PeepoptPass : public Pass {
peepopt_pm pm(module, module->selected_cells()); peepopt_pm pm(module, module->selected_cells());
pm.run_shiftmul(); pm.run_shiftmul();
pm.run_muldiv(); pm.run_muldiv();
pm.run_dffmux();
} }
} }
} }

View File

@ -0,0 +1,113 @@
pattern dffmux
state <IdString> cemuxAB rstmuxBA
state <SigSpec> sigD
match dff
select dff->type == $dff
select GetSize(port(dff, \D)) > 1
endmatch
match rstmux
select rstmux->type == $mux
select GetSize(port(rstmux, \Y)) > 1
index <SigSpec> port(rstmux, \Y) === port(dff, \D)
choice <IdString> BA {\B, \A}
select port(rstmux, BA).is_fully_const()
set rstmuxBA BA
optional
endmatch
code sigD
if (rstmux)
sigD = port(rstmux, rstmuxBA == \B ? \A : \B);
else
sigD = port(dff, \D);
endcode
match cemux
select cemux->type == $mux
select GetSize(port(cemux, \Y)) > 1
index <SigSpec> port(cemux, \Y) === sigD
choice <IdString> AB {\A, \B}
index <SigSpec> port(cemux, AB) === port(dff, \Q)
set cemuxAB AB
endmatch
code
SigSpec D = port(cemux, cemuxAB == \A ? \B : \A);
SigSpec Q = port(dff, \Q);
Const rst;
if (rstmux)
rst = port(rstmux, rstmuxBA).as_const();
int width = GetSize(D);
SigSpec &ceA = cemux->connections_.at(\A);
SigSpec &ceB = cemux->connections_.at(\B);
SigSpec &ceY = cemux->connections_.at(\Y);
SigSpec &dffD = dff->connections_.at(\D);
SigSpec &dffQ = dff->connections_.at(\Q);
if (D[width-1] == D[width-2]) {
did_something = true;
SigBit sign = D[width-1];
bool is_signed = sign.wire;
int i;
for (i = width-1; i >= 2; i--) {
if (!is_signed) {
module->connect(Q[i], sign);
if (D[i-1] != sign || (rst.size() && rst[i-1] != rst[width-1]))
break;
}
else {
module->connect(Q[i], Q[i-1]);
if (D[i-2] != sign || (rst.size() && rst[i-1] != rst[width-1]))
break;
}
}
ceA.remove(i, width-i);
ceB.remove(i, width-i);
ceY.remove(i, width-i);
cemux->fixup_parameters();
dffD.remove(i, width-i);
dffQ.remove(i, width-i);
dff->fixup_parameters();
log("dffcemux pattern in %s: dff=%s, cemux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux), width-i);
accept;
}
else {
int count = 0;
for (int i = width-1; i >= 0; i--) {
if (D[i].wire)
continue;
Wire *w = Q[i].wire;
auto it = w->attributes.find(\init);
State init;
if (it != w->attributes.end())
init = it->second[Q[i].offset];
else
init = State::Sx;
if (init == State::Sx || init == D[i].data) {
count++;
module->connect(Q[i], D[i]);
ceA.remove(i);
ceB.remove(i);
ceY.remove(i);
dffD.remove(i);
dffQ.remove(i);
}
}
if (count > 0) {
did_something = true;
cemux->fixup_parameters();
dff->fixup_parameters();
log("dffcemux pattern in %s: dff=%s, cemux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), count);
}
accept;
}
endcode

View File

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

View File

@ -28,6 +28,7 @@ bool did_something;
#include "passes/pmgen/test_pmgen_pm.h" #include "passes/pmgen/test_pmgen_pm.h"
#include "passes/pmgen/ice40_dsp_pm.h" #include "passes/pmgen/ice40_dsp_pm.h"
#include "passes/pmgen/xilinx_srl_pm.h"
#include "passes/pmgen/peepopt_pm.h" #include "passes/pmgen/peepopt_pm.h"
void reduce_chain(test_pmgen_pm &pm) void reduce_chain(test_pmgen_pm &pm)
@ -99,6 +100,24 @@ void reduce_tree(test_pmgen_pm &pm)
log(" -> %s (%s)\n", log_id(c), log_id(c->type)); log(" -> %s (%s)\n", log_id(c), log_id(c->type));
} }
void opt_eqpmux(test_pmgen_pm &pm)
{
auto &st = pm.st_eqpmux;
SigSpec Y = st.pmux->getPort(ID::Y);
int width = GetSize(Y);
SigSpec EQ = st.pmux->getPort(ID::B).extract(st.pmux_slice_eq*width, width);
SigSpec NE = st.pmux->getPort(ID::B).extract(st.pmux_slice_ne*width, width);
log("Found eqpmux circuit driving %s (eq=%s, ne=%s, pmux=%s).\n",
log_signal(Y), log_id(st.eq), log_id(st.ne), log_id(st.pmux));
pm.autoremove(st.pmux);
Cell *c = pm.module->addMux(NEW_ID, NE, EQ, st.eq->getPort(ID::Y), Y);
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
}
#define GENERATE_PATTERN(pmclass, pattern) \ #define GENERATE_PATTERN(pmclass, pattern) \
generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design) generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
@ -149,19 +168,20 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass); log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
int modcnt = 0; int modcnt = 0;
int maxmodcnt = 100;
int maxsubcnt = 4; int maxsubcnt = 4;
int timeout = 0; int timeout = 0;
vector<Module*> mods; vector<Module*> mods;
while (modcnt < 100) while (modcnt < maxmodcnt)
{ {
int submodcnt = 0, itercnt = 0, cellcnt = 0; int submodcnt = 0, itercnt = 0, cellcnt = 0;
Module *mod = design->addModule(NEW_ID); Module *mod = design->addModule(NEW_ID);
while (modcnt < 100 && submodcnt < maxsubcnt && itercnt++ < 1000) while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
{ {
if (timeout++ > 10000) if (timeout++ > 10000)
log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n"); log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
pm matcher(mod, mod->cells()); pm matcher(mod, mod->cells());
@ -197,7 +217,7 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
run(matcher, [](){}); run(matcher, [](){});
} }
if (submodcnt) if (submodcnt && maxsubcnt < (1 << 16))
maxsubcnt *= 2; maxsubcnt *= 2;
design->remove(mod); design->remove(mod);
@ -232,6 +252,12 @@ struct TestPmgenPass : public Pass {
log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n"); log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n");
log("\n"); log("\n");
log("\n");
log(" test_pmgen -eqpmux [options] [selection]\n");
log("\n");
log("Demo for recursive pmgen patterns. Optimize EQ/NE/PMUX circuits.\n");
log("\n");
log("\n"); log("\n");
log(" test_pmgen -generate [options] <pattern_name>\n"); log(" test_pmgen -generate [options] <pattern_name>\n");
log("\n"); log("\n");
@ -277,6 +303,25 @@ struct TestPmgenPass : public Pass {
test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree); test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree);
} }
void execute_eqpmux(std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing TEST_PMGEN pass (-eqpmux).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-singleton") {
// singleton_mode = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
test_pmgen_pm(module, module->selected_cells()).run_eqpmux(opt_eqpmux);
}
void execute_generate(std::vector<std::string> args, RTLIL::Design *design) void execute_generate(std::vector<std::string> args, RTLIL::Design *design)
{ {
log_header(design, "Executing TEST_PMGEN pass (-generate).\n"); log_header(design, "Executing TEST_PMGEN pass (-generate).\n");
@ -299,16 +344,24 @@ struct TestPmgenPass : public Pass {
if (pattern == "reduce") if (pattern == "reduce")
return GENERATE_PATTERN(test_pmgen_pm, reduce); return GENERATE_PATTERN(test_pmgen_pm, reduce);
if (pattern == "eqpmux")
return GENERATE_PATTERN(test_pmgen_pm, eqpmux);
if (pattern == "ice40_dsp") if (pattern == "ice40_dsp")
return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp); return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
if (pattern == "xilinx_srl.fixed")
return GENERATE_PATTERN(xilinx_srl_pm, fixed);
if (pattern == "xilinx_srl.variable")
return GENERATE_PATTERN(xilinx_srl_pm, variable);
if (pattern == "peepopt-muldiv") if (pattern == "peepopt-muldiv")
return GENERATE_PATTERN(peepopt_pm, muldiv); return GENERATE_PATTERN(peepopt_pm, muldiv);
if (pattern == "peepopt-shiftmul") if (pattern == "peepopt-shiftmul")
return GENERATE_PATTERN(peepopt_pm, shiftmul); return GENERATE_PATTERN(peepopt_pm, shiftmul);
log_cmd_error("Unkown pattern: %s\n", pattern.c_str()); log_cmd_error("Unknown pattern: %s\n", pattern.c_str());
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -319,6 +372,8 @@ struct TestPmgenPass : public Pass {
return execute_reduce_chain(args, design); return execute_reduce_chain(args, design);
if (args[1] == "-reduce_tree") if (args[1] == "-reduce_tree")
return execute_reduce_tree(args, design); return execute_reduce_tree(args, design);
if (args[1] == "-eqpmux")
return execute_eqpmux(args, design);
if (args[1] == "-generate") if (args[1] == "-generate")
return execute_generate(args, design); return execute_generate(args, design);
} }

View File

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

258
passes/pmgen/xilinx_srl.cc Normal file
View File

@ -0,0 +1,258 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* (C) 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
#include "passes/pmgen/xilinx_srl_pm.h"
void run_fixed(xilinx_srl_pm &pm)
{
auto &st = pm.st_fixed;
auto &ud = pm.ud_fixed;
log("Found fixed chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
SigSpec initval;
for (auto cell : ud.longest_chain) {
log_debug(" %s\n", log_id(cell));
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
SigBit Q = cell->getPort(ID(Q));
log_assert(Q.wire);
auto it = Q.wire->attributes.find(ID(init));
if (it != Q.wire->attributes.end()) {
auto &i = it->second[Q.offset];
initval.append(i);
i = State::Sx;
}
else
initval.append(State::Sx);
}
else if (cell->type.in(ID(FDRE), ID(FDRE_1))) {
if (cell->parameters.at(ID(INIT), State::S0).as_bool())
initval.append(State::S1);
else
initval.append(State::S0);
}
else
log_abort();
pm.autoremove(cell);
}
auto first_cell = ud.longest_chain.back();
auto last_cell = ud.longest_chain.front();
Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
pm.module->swap_names(c, first_cell);
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID(FDRE), ID(FDRE_1))) {
c->setParam(ID(DEPTH), GetSize(ud.longest_chain));
c->setParam(ID(INIT), initval.as_const());
if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
c->setParam(ID(CLKPOL), 1);
else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1)))
c->setParam(ID(CLKPOL), 0);
else if (first_cell->type.in(ID(FDRE))) {
if (!first_cell->parameters.at(ID(IS_C_INVERTED), State::S0).as_bool())
c->setParam(ID(CLKPOL), 1);
else
c->setParam(ID(CLKPOL), 0);
}
else
log_abort();
if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
c->setParam(ID(ENPOL), 1);
else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
c->setParam(ID(ENPOL), 0);
else
c->setParam(ID(ENPOL), 2);
c->setPort(ID(C), first_cell->getPort(ID(C)));
c->setPort(ID(D), first_cell->getPort(ID(D)));
c->setPort(ID(Q), last_cell->getPort(ID(Q)));
c->setPort(ID(L), GetSize(ud.longest_chain)-1);
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
c->setPort(ID(E), State::S1);
else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
c->setPort(ID(E), first_cell->getPort(ID(E)));
else if (first_cell->type.in(ID(FDRE), ID(FDRE_1)))
c->setPort(ID(E), first_cell->getPort(ID(CE)));
else
log_abort();
}
else
log_abort();
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
}
void run_variable(xilinx_srl_pm &pm)
{
auto &st = pm.st_variable;
auto &ud = pm.ud_variable;
log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type));
SigSpec initval;
for (const auto &i : ud.chain) {
auto cell = i.first;
auto slice = i.second;
log_debug(" %s\n", log_id(cell));
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) {
SigBit Q = cell->getPort(ID(Q))[slice];
log_assert(Q.wire);
auto it = Q.wire->attributes.find(ID(init));
if (it != Q.wire->attributes.end()) {
auto &i = it->second[Q.offset];
initval.append(i);
i = State::Sx;
}
else
initval.append(State::Sx);
}
else
log_abort();
}
pm.autoremove(st.shiftx);
auto first_cell = ud.chain.back().first;
auto first_slice = ud.chain.back().second;
Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
pm.module->swap_names(c, first_cell);
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) {
c->setParam(ID(DEPTH), GetSize(ud.chain));
c->setParam(ID(INIT), initval.as_const());
Const clkpol, enpol;
if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
clkpol = 1;
else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_)))
clkpol = 0;
else if (first_cell->type.in(ID($dff), ID($dffe)))
clkpol = first_cell->getParam(ID(CLK_POLARITY));
else
log_abort();
if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
enpol = 1;
else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
enpol = 0;
else if (first_cell->type.in(ID($dffe)))
enpol = first_cell->getParam(ID(EN_POLARITY));
else
enpol = 2;
c->setParam(ID(CLKPOL), clkpol);
c->setParam(ID(ENPOL), enpol);
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
c->setPort(ID(C), first_cell->getPort(ID(C)));
else if (first_cell->type.in(ID($dff), ID($dffe)))
c->setPort(ID(C), first_cell->getPort(ID(CLK)));
else
log_abort();
c->setPort(ID(D), first_cell->getPort(ID(D))[first_slice]);
c->setPort(ID(Q), st.shiftx->getPort(ID(Y)));
c->setPort(ID(L), st.shiftx->getPort(ID(B)));
if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($dff)))
c->setPort(ID(E), State::S1);
else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
c->setPort(ID(E), first_cell->getPort(ID(E)));
else if (first_cell->type.in(ID($dffe)))
c->setPort(ID(E), first_cell->getPort(ID(EN)));
else
log_abort();
}
else
log_abort();
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
}
struct XilinxSrlPass : public Pass {
XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" xilinx_srl [options] [selection]\n");
log("\n");
log("This pass converts chains of built-in flops (bit-level: $_DFF_[NP]_, $_DFFE_*\n");
log("and word-level: $dff, $dffe) as well as Xilinx flops (FDRE, FDRE_1) into a\n");
log("$__XILINX_SHREG cell. Chains must be of the same cell type, clock, clock polarity,\n");
log("enable, and enable polarity (where relevant).\n");
log("Flops with resets cannot be mapped to Xilinx devices and will not be inferred.");
log("\n");
log(" -minlen N\n");
log(" min length of shift register (default = 3)\n");
log("\n");
log(" -fixed\n");
log(" infer fixed-length shift registers.\n");
log("\n");
log(" -variable\n");
log(" infer variable-length shift registers (i.e. fixed-length shifts where\n");
log(" each element also fans-out to a $shiftx cell).\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n");
bool fixed = false;
bool variable = false;
int minlen = 3;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
minlen = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-fixed") {
fixed = true;
continue;
}
if (args[argidx] == "-variable") {
variable = true;
continue;
}
break;
}
extra_args(args, argidx, design);
if (!fixed && !variable)
log_cmd_error("'-fixed' and/or '-variable' must be specified.\n");
for (auto module : design->selected_modules()) {
auto pm = xilinx_srl_pm(module, module->selected_cells());
pm.ud_fixed.minlen = minlen;
pm.ud_variable.minlen = minlen;
if (fixed)
pm.run_fixed(run_fixed);
if (variable)
pm.run_variable(run_variable);
}
}
} XilinxSrlPass;
PRIVATE_NAMESPACE_END

326
passes/pmgen/xilinx_srl.pmg Normal file
View File

@ -0,0 +1,326 @@
pattern fixed
state <IdString> clk_port en_port
udata <vector<Cell*>> chain longest_chain
udata <pool<Cell*>> non_first_cells
udata <int> minlen
code
non_first_cells.clear();
subpattern(setup);
endcode
match first
select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
select !first->has_keep_attr()
select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero()
filter !non_first_cells.count(first)
generate
SigSpec C = module->addWire(NEW_ID);
SigSpec D = module->addWire(NEW_ID);
SigSpec Q = module->addWire(NEW_ID);
auto r = rng(8);
Cell* cell;
switch (r)
{
case 0:
case 1:
cell = module->addCell(NEW_ID, \FDRE);
cell->setPort(\C, C);
cell->setPort(\D, D);
cell->setPort(\Q, Q);
cell->setPort(\CE, module->addWire(NEW_ID));
if (r & 1)
cell->setPort(\R, module->addWire(NEW_ID));
else {
if (rng(2) == 0)
cell->setPort(\R, State::S0);
}
break;
case 2:
case 3:
cell = module->addDffGate(NEW_ID, C, D, Q, r & 1);
break;
case 4:
case 5:
case 6:
case 7:
cell = module->addDffeGate(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 2);
break;
default: log_abort();
}
endmatch
code clk_port en_port
if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1))
clk_port = \C;
else log_abort();
if (first->type.in($_DFF_N_, $_DFF_P_))
en_port = IdString();
else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
en_port = \E;
else if (first->type.in(\FDRE, \FDRE_1))
en_port = \CE;
else log_abort();
longest_chain.clear();
chain.push_back(first);
subpattern(tail);
finally
chain.pop_back();
log_assert(chain.empty());
if (GetSize(longest_chain) >= minlen)
accept;
endcode
// ------------------------------------------------------------------
subpattern setup
arg clk_port
arg en_port
match first
select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
select !first->has_keep_attr()
select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero()
endmatch
code clk_port en_port
if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1))
clk_port = \C;
else log_abort();
if (first->type.in($_DFF_N_, $_DFF_P_))
en_port = IdString();
else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
en_port = \E;
else if (first->type.in(\FDRE, \FDRE_1))
en_port = \CE;
else log_abort();
endcode
match next
select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
select !next->has_keep_attr()
select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
select nusers(port(next, \Q)) == 2
index <IdString> next->type === first->type
index <SigBit> port(next, \Q) === port(first, \D)
filter port(next, clk_port) == port(first, clk_port)
filter en_port == IdString() || port(next, en_port) == port(first, en_port)
filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool()
filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero()
endmatch
code
non_first_cells.insert(next);
endcode
// ------------------------------------------------------------------
subpattern tail
arg first
arg clk_port
arg en_port
match next
semioptional
select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)
select !next->has_keep_attr()
select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
select nusers(port(next, \Q)) == 2
index <IdString> next->type === chain.back()->type
index <SigBit> port(next, \Q) === port(chain.back(), \D)
filter port(next, clk_port) == port(first, clk_port)
filter en_port == IdString() || port(next, en_port) == port(first, en_port)
filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool()
filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool()
filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool()
filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero()
generate
Cell *cell = module->addCell(NEW_ID, chain.back()->type);
cell->setPort(\C, chain.back()->getPort(\C));
cell->setPort(\D, module->addWire(NEW_ID));
cell->setPort(\Q, chain.back()->getPort(\D));
if (cell->type == \FDRE) {
if (rng(2) == 0)
cell->setPort(\R, chain.back()->connections_.at(\R, State::S0));
cell->setPort(\CE, chain.back()->getPort(\CE));
}
else if (cell->type.begins_with("$_DFFE_"))
cell->setPort(\E, chain.back()->getPort(\E));
endmatch
code
if (next) {
chain.push_back(next);
subpattern(tail);
} else {
if (GetSize(chain) > GetSize(longest_chain))
longest_chain = chain;
}
finally
if (next)
chain.pop_back();
endcode
// -----------
pattern variable
state <IdString> clk_port en_port
state <int> shiftx_width
state <int> slice
udata <int> minlen
udata <vector<pair<Cell*,int>>> chain
udata <pool<SigBit>> chain_bits
code
chain_bits.clear();
endcode
match shiftx
select shiftx->type.in($shiftx)
select !shiftx->has_keep_attr()
select param(shiftx, \Y_WIDTH).as_int() == 1
filter param(shiftx, \A_WIDTH).as_int() >= minlen
generate
minlen = 3;
module->addShiftx(NEW_ID, module->addWire(NEW_ID, rng(6)+minlen), module->addWire(NEW_ID, 3), module->addWire(NEW_ID));
endmatch
code shiftx_width
shiftx_width = param(shiftx, \A_WIDTH).as_int();
endcode
match first
select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe)
select !first->has_keep_attr()
select port(first, \Q)[0].wire && !port(first, \Q)[0].wire->get_bool_attribute(\keep)
slice idx GetSize(port(first, \Q))
select nusers(port(first, \Q)[idx]) <= 2
index <SigBit> port(first, \Q)[idx] === port(shiftx, \A)[shiftx_width-1]
set slice idx
generate
SigSpec C = module->addWire(NEW_ID);
auto WIDTH = rng(3)+1;
SigSpec D = module->addWire(NEW_ID, WIDTH);
SigSpec Q = module->addWire(NEW_ID, WIDTH);
auto r = rng(8);
Cell *cell = nullptr;
switch (r)
{
case 0:
case 1:
cell = module->addDff(NEW_ID, C, D, Q, r & 1);
break;
case 2:
case 3:
case 4:
case 5:
//cell = module->addDffe(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 4);
//break;
case 6:
case 7:
WIDTH = 1;
cell = module->addDffGate(NEW_ID, C, D[0], Q[0], r & 1);
break;
default: log_abort();
}
shiftx->connections_.at(\A)[shiftx_width-1] = port(cell, \Q)[rng(WIDTH)];
endmatch
code clk_port en_port
if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
clk_port = \C;
else if (first->type.in($dff, $dffe))
clk_port = \CLK;
else log_abort();
if (first->type.in($_DFF_N_, $_DFF_P_, $dff))
en_port = IdString();
else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_))
en_port = \E;
else if (first->type.in($dffe))
en_port = \EN;
else log_abort();
chain_bits.insert(port(first, \Q)[slice]);
chain.emplace_back(first, slice);
subpattern(tail);
finally
if (GetSize(chain) == shiftx_width)
accept;
chain.clear();
endcode
// ------------------------------------------------------------------
subpattern tail
arg first
arg shiftx
arg shiftx_width
arg slice
arg clk_port
arg en_port
match next
semioptional
select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe)
select !next->has_keep_attr()
select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep)
slice idx GetSize(port(next, \Q))
select nusers(port(next, \Q)[idx]) <= 3
index <IdString> next->type === chain.back().first->type
index <SigBit> port(next, \Q)[idx] === port(chain.back().first, \D)[chain.back().second]
index <SigBit> port(next, \Q)[idx] === port(shiftx, \A)[shiftx_width-1-GetSize(chain)]
filter port(next, clk_port) == port(first, clk_port)
filter en_port == IdString() || port(next, en_port) == port(first, en_port)
filter !next->type.in($dff, $dffe) || param(next, \CLK_POLARITY).as_bool() == param(first, \CLK_POLARITY).as_bool()
filter !next->type.in($dffe) || param(next, \EN_POLARITY).as_bool() == param(first, \EN_POLARITY).as_bool()
filter !chain_bits.count(port(next, \D)[idx])
set slice idx
generate
if (GetSize(chain) < shiftx_width) {
auto back = chain.back().first;
auto slice = chain.back().second;
if (back->type.in($dff, $dffe)) {
auto WIDTH = GetSize(port(back, \D));
if (rng(2) == 0 && slice < WIDTH-1) {
auto new_slice = slice + rng(WIDTH-1-slice);
back->connections_.at(\D)[slice] = port(back, \Q)[new_slice];
}
else {
auto D = module->addWire(NEW_ID, WIDTH);
if (back->type == $dff)
module->addDff(NEW_ID, port(back, \CLK), D, port(back, \D), param(back, \CLK_POLARITY).as_bool());
else if (back->type == $dffe)
module->addDffe(NEW_ID, port(back, \CLK), port(back, \EN), D, port(back, \D), param(back, \CLK_POLARITY).as_bool(), param(back, \EN_POLARITY).as_bool());
else
log_abort();
}
}
else if (back->type.begins_with("$_DFF_")) {
Cell *cell = module->addCell(NEW_ID, back->type);
cell->setPort(\C, back->getPort(\C));
cell->setPort(\D, module->addWire(NEW_ID));
cell->setPort(\Q, back->getPort(\D));
}
else
log_abort();
shiftx->connections_.at(\A)[shiftx_width-1-GetSize(chain)] = port(back, \D)[slice];
}
endmatch
code
if (next) {
chain_bits.insert(port(next, \Q)[slice]);
chain.emplace_back(next, slice);
if (GetSize(chain) < shiftx_width)
subpattern(tail);
}
endcode

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
@ -39,6 +40,7 @@ OBJS += passes/techmap/attrmap.o
OBJS += passes/techmap/zinit.o OBJS += passes/techmap/zinit.o
OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/dff2dffs.o
OBJS += passes/techmap/flowmap.o OBJS += passes/techmap/flowmap.o
OBJS += passes/techmap/extractinv.o
endif endif
GENFILES += passes/techmap/techmap.inc GENFILES += passes/techmap/techmap.inc

View File

@ -76,8 +76,7 @@ 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 {}");
@ -85,7 +84,7 @@ void handle_loops(RTLIL::Design *design,
// cell in the component, and select (and mark) all its output // cell in the component, and select (and mark) all its output
// wires // wires
pool<RTLIL::Const> ids_seen; pool<RTLIL::Const> ids_seen;
for (auto cell : module->selected_cells()) { for (auto cell : module->cells()) {
auto it = cell->attributes.find(ID(abc_scc_id)); auto it = cell->attributes.find(ID(abc_scc_id));
if (it != cell->attributes.end()) { if (it != cell->attributes.end()) {
auto r = ids_seen.insert(it->second); auto r = ids_seen.insert(it->second);
@ -114,30 +113,6 @@ void handle_loops(RTLIL::Design *design,
} }
cell->attributes.erase(it); cell->attributes.erase(it);
} }
auto jt = scc_break_inputs.find(cell->type);
if (jt != scc_break_inputs.end())
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();
@ -269,11 +244,10 @@ struct abc_output_filter
}; };
void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
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;
@ -309,8 +283,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
} }
//if (dff_mode && clk_sig.empty()) if (dff_mode && clk_sig.empty())
// log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
if (!cleanup) if (!cleanup)
@ -383,7 +357,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
fprintf(f, "%s\n", abc_script.c_str()); fprintf(f, "%s\n", abc_script.c_str());
fclose(f); fclose(f);
if (/*dff_mode ||*/ !clk_str.empty()) if (dff_mode || !clk_str.empty())
{ {
if (clk_sig.size() == 0) if (clk_sig.size() == 0)
log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching");
@ -413,16 +387,13 @@ 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, scc_break_inputs); handle_loops(design);
Pass::call(design, "aigmap"); Pass::call(design, "aigmap");
//log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n", //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
// count_gates, GetSize(signal_list), count_input, count_output); // count_gates, GetSize(signal_list), count_input, count_output);
#if 0
Pass::call(design, stringf("write_verilog -noexpr -norename %s/before.v", tempdir_name.c_str()));
#endif
Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
std::string buffer; std::string buffer;
@ -531,12 +502,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
for (int i = 0; i < GetSize(w); i++) for (int i = 0; i < GetSize(w); i++)
output_bits.insert({wire, i}); output_bits.insert({wire, i});
} }
auto jt = w->attributes.find("\\init");
if (jt != w->attributes.end()) {
auto r = remap_wire->attributes.insert(std::make_pair("\\init", jt->second));
log_assert(r.second);
}
} }
for (auto &it : module->connections_) { for (auto &it : module->connections_) {
@ -578,6 +543,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (mapped_cell->type == ID($_NOT_)) { if (mapped_cell->type == ID($_NOT_)) {
RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
bit_users[a_bit].insert(mapped_cell->name);
bit_drivers[y_bit].insert(mapped_cell->name);
if (!a_bit.wire) { if (!a_bit.wire) {
mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); mapped_cell->setPort(ID::Y, module->addWire(NEW_ID));
@ -585,8 +552,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
log_assert(wire); log_assert(wire);
module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
} }
else { else if (!lut_costs.empty() || !lut_file.empty()) {
RTLIL::Cell* driving_lut = nullptr; RTLIL::Cell* driver_lut = nullptr;
// ABC can return NOT gates that drive POs // ABC can return NOT gates that drive POs
if (!a_bit.wire->port_input) { if (!a_bit.wire->port_input) {
// If it's not a NOT gate that that comes from a PI directly, // If it's not a NOT gate that that comes from a PI directly,
@ -598,10 +565,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
else else
driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
driving_lut = mapped_mod->cell(driver_name); driver_lut = mapped_mod->cell(driver_name);
} }
if (!driving_lut) { if (!driver_lut) {
// If a driver couldn't be found (could be from PI or box CI) // If a driver couldn't be found (could be from PI or box CI)
// then implement using a LUT // then implement using a LUT
cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())),
@ -610,13 +577,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
RTLIL::Const::from_string("01")); RTLIL::Const::from_string("01"));
bit2sinks[cell->getPort(ID::A)].push_back(cell); bit2sinks[cell->getPort(ID::A)].push_back(cell);
cell_stats[ID($lut)]++; cell_stats[ID($lut)]++;
bit_users[a_bit].insert(mapped_cell->name);
bit_drivers[y_bit].insert(mapped_cell->name);
} }
else else
not2drivers[mapped_cell] = driving_lut; not2drivers[mapped_cell] = driver_lut;
continue; continue;
} }
else
log_abort();
if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
continue; continue;
} }
@ -700,32 +667,31 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
} }
for (auto &it : cell_stats) for (auto &it : cell_stats)
log("ABC RESULTS: %15s cells: %8d\n", log_id(it.first), it.second); log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
int in_wires = 0, out_wires = 0; int in_wires = 0, out_wires = 0;
// Stitch in mapped_mod's inputs/outputs into module // Stitch in mapped_mod's inputs/outputs into module
for (auto port_name : mapped_mod->ports) { for (auto port : mapped_mod->ports) {
RTLIL::Wire *port = mapped_mod->wire(port_name); RTLIL::Wire *w = mapped_mod->wire(port);
log_assert(port); RTLIL::Wire *wire = module->wire(port);
RTLIL::Wire *wire = module->wire(port->name);
log_assert(wire); log_assert(wire);
RTLIL::Wire *remap_wire = module->wire(remap_name(port->name)); RTLIL::Wire *remap_wire = module->wire(remap_name(port));
RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
log_assert(GetSize(signal) >= GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire));
RTLIL::SigSig conn; RTLIL::SigSig conn;
if (port->port_input) { if (w->port_output) {
conn.first = remap_wire;
conn.second = signal;
in_wires++;
module->connect(conn);
}
if (port->port_output) {
conn.first = signal; conn.first = signal;
conn.second = remap_wire; conn.second = remap_wire;
out_wires++; out_wires++;
module->connect(conn); module->connect(conn);
} }
else if (w->port_input) {
conn.first = remap_wire;
conn.second = signal;
in_wires++;
module->connect(conn);
}
} }
for (auto &it : bit_users) for (auto &it : bit_users)
@ -733,21 +699,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
for (auto driver_cell : bit_drivers.at(it.first)) for (auto driver_cell : bit_drivers.at(it.first))
for (auto user_cell : it.second) for (auto user_cell : it.second)
toposort.edge(driver_cell, user_cell); toposort.edge(driver_cell, user_cell);
#if 0
toposort.analyze_loops = true;
#endif
bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
#if 0
unsigned i = 0;
for (auto &it : toposort.loops) {
log(" loop %d\n", i++);
for (auto cell_name : it) {
auto cell = mapped_mod->cell(cell_name);
log_assert(cell);
log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
}
}
#endif
log_assert(no_loops); log_assert(no_loops);
for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {
@ -1048,7 +1000,7 @@ struct Abc9Pass : public Pass {
fast_mode = true; fast_mode = true;
continue; continue;
} }
//if (arg == "-retime") { //if (arg == "-dff") {
// dff_mode = true; // dff_mode = true;
// continue; // continue;
//} //}
@ -1075,9 +1027,6 @@ struct Abc9Pass : public Pass {
} }
if (arg == "-box" && argidx+1 < args.size()) { if (arg == "-box" && argidx+1 < args.size()) {
box_file = args[++argidx]; box_file = args[++argidx];
rewrite_filename(box_file);
if (!box_file.empty() && !is_absolute_path(box_file))
box_file = std::string(pwd) + "/" + box_file;
continue; continue;
} }
if (arg == "-W" && argidx+1 < args.size()) { if (arg == "-W" && argidx+1 < args.size()) {
@ -1088,11 +1037,15 @@ struct Abc9Pass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (lut_costs.empty() && lut_file.empty()) // ABC expects a box file for XAIG
log_cmd_error("abc9 must be called with '-lut' or '-luts'\n"); if (box_file.empty())
box_file = "+/dummy.box";
rewrite_filename(box_file);
if (!box_file.empty() && !is_absolute_path(box_file))
box_file = std::string(pwd) + "/" + box_file;
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())
@ -1110,17 +1063,13 @@ struct Abc9Pass : public Pass {
for (auto p : m->ports) { for (auto p : m->ports) {
auto w = m->wire(p); auto w = m->wire(p);
log_assert(w); log_assert(w);
if (w->port_input) { if (w->attributes.count(ID(abc_carry))) {
if (w->attributes.count(ID(abc_scc_break))) if (w->port_input) {
scc_break_inputs[m->name].insert(p);
if (w->attributes.count(ID(abc_carry))) {
if (carry_in) if (carry_in)
log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m));
carry_in = w; carry_in = w;
} }
} else if (w->port_output) {
if (w->port_output) {
if (w->attributes.count(ID(abc_carry))) {
if (carry_out) if (carry_out)
log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m));
carry_out = w; carry_out = w;
@ -1177,7 +1126,8 @@ struct Abc9Pass : public Pass {
abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, false, clk_str, keepff, abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, false, 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, scc_break_inputs); box_file, lut_file, wire_delay, box_lookup);
design->selection_stack.pop_back(); design->selection_stack.pop_back();
continue; continue;
} }
@ -1361,36 +1311,20 @@ struct Abc9Pass : public Pass {
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
design->selection_stack.emplace_back(false);
for (auto &it : assigned_cells) { for (auto &it : assigned_cells) {
// FIXME: abc9_module calls below can delete cells,
// leaving a dangling pointer here...
clk_polarity = std::get<0>(it.first); clk_polarity = std::get<0>(it.first);
clk_sig = assign_map(std::get<1>(it.first)); clk_sig = assign_map(std::get<1>(it.first));
en_polarity = std::get<2>(it.first); en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first)); en_sig = assign_map(std::get<3>(it.first));
pool<RTLIL::IdString> assigned_names;
for (auto i : it.second)
assigned_names.insert(i->name);
RTLIL::Selection& sel = design->selection_stack.back();
sel.selected_members[mod->name] = std::move(assigned_names);
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, scc_break_inputs); box_file, lut_file, wire_delay, box_lookup);
assign_map.set(mod); assign_map.set(mod);
} }
design->selection_stack.pop_back();
} }
assign_map.clear(); assign_map.clear();
// The "clean" pass also contains a design->check() call
Pass::call(design, "clean");
log_pop(); log_pop();
} }
} Abc9Pass; } Abc9Pass;

View File

@ -48,14 +48,25 @@ struct AlumaccWorker
RTLIL::SigSpec cached_cf, cached_of, cached_sf; RTLIL::SigSpec cached_cf, cached_of, cached_sf;
RTLIL::SigSpec get_lt() { RTLIL::SigSpec get_lt() {
if (GetSize(cached_lt) == 0) if (GetSize(cached_lt) == 0) {
cached_lt = is_signed ? alu_cell->module->Xor(NEW_ID, get_of(), get_sf()) : get_cf(); if (is_signed) {
get_of();
get_sf();
cached_lt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf);
}
else
cached_lt = get_cf();
}
return cached_lt; return cached_lt;
} }
RTLIL::SigSpec get_gt() { RTLIL::SigSpec get_gt() {
if (GetSize(cached_gt) == 0) if (GetSize(cached_gt) == 0) {
cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()), false, alu_cell->get_src_attribute()); get_lt();
get_eq();
SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq);
cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute());
}
return cached_gt; return cached_gt;
} }

View File

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

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

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

View File

@ -34,11 +34,16 @@ struct Dff2dffsPass : public Pass {
log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n"); log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n");
log("dff2dffe for SR over CE priority.\n"); log("dff2dffe for SR over CE priority.\n");
log("\n"); log("\n");
log(" -match-init\n");
log(" Disallow merging synchronous set/reset that has polarity opposite of the\n");
log(" output wire's init attribute (if any).\n");
log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n"); log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n");
bool match_init = false;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
{ {
@ -46,6 +51,10 @@ struct Dff2dffsPass : public Pass {
// singleton_mode = true; // singleton_mode = true;
// continue; // continue;
// } // }
if (args[argidx] == "-match-init") {
match_init = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -96,9 +105,6 @@ struct Dff2dffsPass : public Pass {
SigBit bit_b = sigmap(mux_cell->getPort(ID::B)); SigBit bit_b = sigmap(mux_cell->getPort(ID::B));
SigBit bit_s = sigmap(mux_cell->getPort(ID(S))); SigBit bit_s = sigmap(mux_cell->getPort(ID(S)));
log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
SigBit sr_val, sr_sig; SigBit sr_val, sr_sig;
bool invert_sr; bool invert_sr;
sr_sig = bit_s; sr_sig = bit_s;
@ -113,6 +119,23 @@ struct Dff2dffsPass : public Pass {
invert_sr = false; invert_sr = false;
} }
if (match_init) {
SigBit bit_q = cell->getPort(ID(Q));
if (bit_q.wire) {
auto it = bit_q.wire->attributes.find(ID(init));
if (it != bit_q.wire->attributes.end()) {
auto init_val = it->second[bit_q.offset];
if (init_val == State::S1 && sr_val != State::S1)
continue;
if (init_val == State::S0 && sr_val != State::S0)
continue;
}
}
}
log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
if (sr_val == State::S1) { if (sr_val == State::S1) {
if (cell->type == ID($_DFF_N_)) { if (cell->type == ID($_DFF_N_)) {
if (invert_sr) cell->type = ID($__DFFS_NN1_); if (invert_sr) cell->type = ID($__DFFS_NN1_);

View File

@ -0,0 +1,123 @@
/*
* 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 ExtractinvPass : public Pass {
ExtractinvPass() : Pass("extractinv", "extract explicit inverter cells for invertible cell pins") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" extractinv [options] [selection]\n");
log("\n");
log("Searches the design for all cells with invertible pins controlled by a cell\n");
log("parameter (eg. IS_CLK_INVERTED on many Xilinx cells) and removes the parameter.\n");
log("If the parameter was set to 1, inserts an explicit inverter cell in front of\n");
log("the pin instead. Normally used for output to ISE, which does not support the\n");
log("inversion parameters.\n");
log("\n");
log("To mark a cell port as invertible, use (* invertible_pin = \"param_name\" *)\n");
log("on the wire in the blackbox module. The parameter value should have\n");
log("the same width as the port, and will be effectively XORed with it.\n");
log("\n");
log(" -inv <celltype> <portname_out>:<portname_in>\n");
log(" Specifies the cell type to use for the inverters and its port names.\n");
log(" This option is required.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing EXTRACTINV pass (extracting pin inverters).\n");
std::string inv_celltype, inv_portname, inv_portname2;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
if (arg == "-inv" && argidx+2 < args.size()) {
inv_celltype = args[++argidx];
inv_portname = args[++argidx];
split_portname_pair(inv_portname, inv_portname2);
continue;
}
break;
}
extra_args(args, argidx, design);
if (inv_celltype.empty())
log_error("The -inv option is required.\n");
for (auto module : design->selected_modules())
{
for (auto cell : module->selected_cells())
for (auto port : cell->connections()) {
auto cell_module = design->module(cell->type);
if (!cell_module)
continue;
auto cell_wire = cell_module->wire(port.first);
if (!cell_wire)
continue;
auto it = cell_wire->attributes.find("\\invertible_pin");
if (it == cell_wire->attributes.end())
continue;
IdString param_name = RTLIL::escape_id(it->second.decode_string());
auto it2 = cell->parameters.find(param_name);
// Inversion not used -- skip.
if (it2 == cell->parameters.end())
continue;
SigSpec sig = port.second;
if (it2->second.size() != sig.size())
log_error("The inversion parameter needs to be the same width as the port (%s.%s port %s parameter %s)", log_id(module->name), log_id(cell->type), log_id(port.first), log_id(param_name));
RTLIL::Const invmask = it2->second;
cell->parameters.erase(param_name);
if (invmask.is_fully_zero())
continue;
Wire *iwire = module->addWire(NEW_ID, sig.size());
for (int i = 0; i < sig.size(); i++)
if (invmask[i] == State::S1) {
RTLIL::Cell *icell = module->addCell(NEW_ID, RTLIL::escape_id(inv_celltype));
icell->setPort(RTLIL::escape_id(inv_portname), SigSpec(iwire, i));
icell->setPort(RTLIL::escape_id(inv_portname2), sig[i]);
log("Inserting %s on %s.%s.%s[%d].\n", inv_celltype.c_str(), log_id(module), log_id(cell->type), log_id(port.first), i);
sig[i] = SigBit(iwire, i);
}
cell->setPort(port.first, sig);
}
}
}
} ExtractinvPass;
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

@ -26,9 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ShregmapTech struct ShregmapTech
{ {
virtual ~ShregmapTech() { } virtual ~ShregmapTech() { }
virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {} virtual bool analyze(vector<int> &taps) = 0;
virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {}
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0;
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0; virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
}; };
@ -56,7 +54,7 @@ struct ShregmapOptions
struct ShregmapTechGreenpak4 : ShregmapTech struct ShregmapTechGreenpak4 : ShregmapTech
{ {
bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/) bool analyze(vector<int> &taps)
{ {
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) { if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
taps.clear(); taps.clear();
@ -93,155 +91,6 @@ struct ShregmapTechGreenpak4 : ShregmapTech
} }
}; };
struct ShregmapTechXilinx7 : ShregmapTech
{
dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
const ShregmapOptions &opts;
ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {}
virtual void init(const Module* module, const SigMap &sigmap) override
{
for (const auto &i : module->cells_) {
auto cell = i.second;
if (cell->type == ID($shiftx)) {
if (cell->getParam(ID(Y_WIDTH)) != 1) continue;
int j = 0;
for (auto bit : sigmap(cell->getPort(ID::A)))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
log_assert(j == cell->getParam(ID(A_WIDTH)).as_int());
}
else if (cell->type == ID($mux)) {
int j = 0;
for (auto bit : sigmap(cell->getPort(ID::A)))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
j = 0;
for (auto bit : sigmap(cell->getPort(ID::B)))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
}
}
}
virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override
{
auto it = sigbit_to_shiftx_offset.find(bit);
if (it == sigbit_to_shiftx_offset.end())
return;
if (cell) {
if (cell->type == ID($shiftx) && port == ID::A)
return;
if (cell->type == ID($mux) && port.in(ID::A, ID::B))
return;
}
sigbit_to_shiftx_offset.erase(it);
}
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override
{
if (GetSize(taps) == 1)
return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]);
if (taps.back() < opts.minlen-1)
return false;
Cell *shiftx = nullptr;
int group = 0;
for (int i = 0; i < GetSize(taps); ++i) {
auto it = sigbit_to_shiftx_offset.find(qbits[i]);
if (it == sigbit_to_shiftx_offset.end())
return false;
// Check taps are sequential
if (i != taps[i])
return false;
// Check taps are not connected to a shift register,
// or sequential to the same shift register
if (i == 0) {
int offset;
std::tie(shiftx,offset,group) = it->second;
if (offset != i)
return false;
}
else {
Cell *shiftx_ = std::get<0>(it->second);
if (shiftx_ != shiftx)
return false;
int offset = std::get<1>(it->second);
if (offset != i)
return false;
int group_ = std::get<2>(it->second);
if (group_ != group)
return false;
}
}
log_assert(shiftx);
// Only map if $shiftx exclusively covers the shift register
if (shiftx->type == ID($shiftx)) {
if (GetSize(taps) > shiftx->getParam(ID(A_WIDTH)).as_int())
return false;
// Due to padding the most significant bits of A may be 1'bx,
// and if so, discount them
if (GetSize(taps) < shiftx->getParam(ID(A_WIDTH)).as_int()) {
const SigSpec A = shiftx->getPort(ID::A);
const int A_width = shiftx->getParam(ID(A_WIDTH)).as_int();
for (int i = GetSize(taps); i < A_width; ++i)
if (A[i] != RTLIL::Sx) return false;
}
else if (GetSize(taps) != shiftx->getParam(ID(A_WIDTH)).as_int())
return false;
}
else if (shiftx->type == ID($mux)) {
if (GetSize(taps) != 2)
return false;
}
else log_abort();
return true;
}
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override
{
const auto &tap = *taps.begin();
auto bit = tap.second;
auto it = sigbit_to_shiftx_offset.find(bit);
log_assert(it != sigbit_to_shiftx_offset.end());
auto newcell = cell->module->addCell(NEW_ID, ID($__XILINX_SHREG_));
newcell->set_src_attribute(cell->get_src_attribute());
newcell->setParam(ID(DEPTH), cell->getParam(ID(DEPTH)));
newcell->setParam(ID(INIT), cell->getParam(ID(INIT)));
newcell->setParam(ID(CLKPOL), cell->getParam(ID(CLKPOL)));
newcell->setParam(ID(ENPOL), cell->getParam(ID(ENPOL)));
newcell->setPort(ID(C), cell->getPort(ID(C)));
newcell->setPort(ID(D), cell->getPort(ID(D)));
if (cell->hasPort(ID(E)))
newcell->setPort(ID(E), cell->getPort(ID(E)));
Cell* shiftx = std::get<0>(it->second);
RTLIL::SigSpec l_wire, q_wire;
if (shiftx->type == ID($shiftx)) {
l_wire = shiftx->getPort(ID::B);
q_wire = shiftx->getPort(ID::Y);
shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
}
else if (shiftx->type == ID($mux)) {
l_wire = shiftx->getPort(ID(S));
q_wire = shiftx->getPort(ID::Y);
shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
}
else log_abort();
newcell->setPort(ID(Q), q_wire);
newcell->setPort(ID(L), l_wire);
return false;
}
};
struct ShregmapWorker struct ShregmapWorker
{ {
Module *module; Module *module;
@ -264,10 +113,8 @@ struct ShregmapWorker
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if (wire->port_output || wire->get_bool_attribute(ID::keep)) { if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
for (auto bit : sigmap(wire)) { for (auto bit : sigmap(wire))
sigbit_with_non_chain_users.insert(bit); sigbit_with_non_chain_users.insert(bit);
if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
}
} }
if (wire->attributes.count(ID(init))) { if (wire->attributes.count(ID(init))) {
@ -317,10 +164,8 @@ struct ShregmapWorker
for (auto conn : cell->connections()) for (auto conn : cell->connections())
if (cell->input(conn.first)) if (cell->input(conn.first))
for (auto bit : sigmap(conn.second)) { for (auto bit : sigmap(conn.second))
sigbit_with_non_chain_users.insert(bit); sigbit_with_non_chain_users.insert(bit);
if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first);
}
} }
} }
@ -346,7 +191,7 @@ struct ShregmapWorker
IdString q_port = opts.ffcells.at(c1->type).second; IdString q_port = opts.ffcells.at(c1->type).second;
auto c1_conn = c1->connections(); auto c1_conn = c1->connections();
auto c2_conn = c1->connections(); auto c2_conn = c2->connections();
c1_conn.erase(d_port); c1_conn.erase(d_port);
c1_conn.erase(q_port); c1_conn.erase(q_port);
@ -425,7 +270,7 @@ struct ShregmapWorker
if (taps.empty() || taps.back() < depth-1) if (taps.empty() || taps.back() < depth-1)
taps.push_back(depth-1); taps.push_back(depth-1);
if (opts.tech->analyze(taps, qbits)) if (opts.tech->analyze(taps))
break; break;
taps.pop_back(); taps.pop_back();
@ -544,9 +389,6 @@ struct ShregmapWorker
ShregmapWorker(Module *module, const ShregmapOptions &opts) : ShregmapWorker(Module *module, const ShregmapOptions &opts) :
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
{ {
if (opts.tech)
opts.tech->init(module, sigmap);
make_sigbit_chain_next_prev(); make_sigbit_chain_next_prev();
find_chain_start_cells(); find_chain_start_cells();
@ -617,11 +459,6 @@ struct ShregmapPass : public Pass {
log("\n"); log("\n");
log(" -tech greenpak4\n"); log(" -tech greenpak4\n");
log(" map to greenpak4 shift registers.\n"); log(" map to greenpak4 shift registers.\n");
log(" this option also implies -clkpol pos -zinit\n");
log("\n");
log(" -tech xilinx\n");
log(" map to xilinx dynamic-length shift registers.\n");
log(" this option also implies -params -init\n");
log("\n"); log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -676,12 +513,6 @@ struct ShregmapPass : public Pass {
clkpol = "pos"; clkpol = "pos";
opts.zinit = true; opts.zinit = true;
opts.tech = new ShregmapTechGreenpak4; opts.tech = new ShregmapTechGreenpak4;
}
else if (tech == "xilinx") {
opts.init = true;
opts.params = true;
enpol = "any_or_none";
opts.tech = new ShregmapTechXilinx7(opts);
} else { } else {
argidx--; argidx--;
break; break;

View File

@ -205,20 +205,57 @@ struct TechmapWorker
} }
std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
dict<Wire*, IdString> temp_renamed_wires;
pool<SigBit> autopurge_tpl_bits;
for (auto &it : tpl->wires_) { for (auto &it : tpl->wires_)
{
if (it.second->port_id > 0) if (it.second->port_id > 0)
positional_ports[stringf("$%d", it.second->port_id)] = it.first; {
IdString posportname = stringf("$%d", it.second->port_id);
positional_ports[posportname] = it.first;
if (!flatten_mode && it.second->get_bool_attribute(ID(techmap_autopurge)) &&
(!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) &&
(!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname))))
{
if (sigmaps.count(tpl) == 0)
sigmaps[tpl].set(tpl);
for (auto bit : sigmaps.at(tpl)(it.second))
if (bit.wire != nullptr)
autopurge_tpl_bits.insert(bit);
}
}
IdString w_name = it.second->name; IdString w_name = it.second->name;
apply_prefix(cell->name, w_name); apply_prefix(cell->name, w_name);
RTLIL::Wire *w = module->addWire(w_name, it.second); RTLIL::Wire *w = module->wire(w_name);
w->port_input = false; if (w != nullptr) {
w->port_output = false; if (!flatten_mode || !w->get_bool_attribute(ID(hierconn))) {
w->port_id = 0; temp_renamed_wires[w] = w->name;
if (it.second->get_bool_attribute(ID(_techmap_special_))) module->rename(w, NEW_ID);
w->attributes.clear(); w = nullptr;
if (w->attributes.count(ID(src))) } else {
w->add_strpool_attribute(ID(src), extra_src_attrs); w->attributes.erase(ID(hierconn));
if (GetSize(w) < GetSize(it.second)) {
log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w),
log_id(tpl), log_id(it.second), log_id(module), log_id(cell));
w->width = GetSize(it.second);
}
}
}
if (w == nullptr) {
w = module->addWire(w_name, it.second);
w->port_input = false;
w->port_output = false;
w->port_id = 0;
if (!flatten_mode)
w->attributes.erase(ID(techmap_autopurge));
if (it.second->get_bool_attribute(ID(_techmap_special_)))
w->attributes.clear();
if (w->attributes.count(ID(src)))
w->add_strpool_attribute(ID(src), extra_src_attrs);
}
design->select(module, w); design->select(module, w);
} }
@ -322,6 +359,12 @@ struct TechmapWorker
for (auto &attr : w->attributes) { for (auto &attr : w->attributes) {
if (attr.first == ID(src)) if (attr.first == ID(src))
continue; continue;
auto lhs = GetSize(extra_connect.first);
auto rhs = GetSize(extra_connect.second);
if (lhs > rhs)
extra_connect.first.remove(rhs, lhs-rhs);
else if (rhs > lhs)
extra_connect.second.remove(lhs, rhs-lhs);
module->connect(extra_connect); module->connect(extra_connect);
break; break;
} }
@ -344,11 +387,31 @@ struct TechmapWorker
if (!flatten_mode && c->type.begins_with("\\$")) if (!flatten_mode && c->type.begins_with("\\$"))
c->type = c->type.substr(1); c->type = c->type.substr(1);
for (auto &it2 : c->connections_) { vector<IdString> autopurge_ports;
apply_prefix(cell->name, it2.second, module);
port_signal_map.apply(it2.second); for (auto &it2 : c->connections_)
{
bool autopurge = false;
if (!autopurge_tpl_bits.empty()) {
autopurge = GetSize(it2.second) != 0;
for (auto &bit : sigmaps.at(tpl)(it2.second))
if (!autopurge_tpl_bits.count(bit)) {
autopurge = false;
break;
}
}
if (autopurge) {
autopurge_ports.push_back(it2.first);
} else {
apply_prefix(cell->name, it2.second, module);
port_signal_map.apply(it2.second);
}
} }
for (auto &it2 : autopurge_ports)
c->unsetPort(it2);
if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) { if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) {
IdString memid = c->getParam(ID(MEMID)).decode_string(); IdString memid = c->getParam(ID(MEMID)).decode_string();
log_assert(memory_renames.count(memid) != 0); log_assert(memory_renames.count(memid) != 0);
@ -380,6 +443,16 @@ struct TechmapWorker
} }
module->remove(cell); module->remove(cell);
for (auto &it : temp_renamed_wires)
{
Wire *w = it.first;
IdString name = it.second;
IdString altname = module->uniquify(name);
Wire *other_w = module->wire(name);
module->rename(other_w, altname);
module->rename(w, name);
}
} }
bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells, bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
@ -396,6 +469,18 @@ struct TechmapWorker
SigMap sigmap(module); SigMap sigmap(module);
dict<SigBit, State> init_bits;
pool<SigBit> remove_init_bits;
for (auto wire : module->wires()) {
if (wire->attributes.count("\\init")) {
Const value = wire->attributes.at("\\init");
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
if (value[i] != State::Sx)
init_bits[sigmap(SigBit(wire, i))] = value[i];
}
}
TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells; TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit; std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell; std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
@ -633,6 +718,17 @@ struct TechmapWorker
bit = RTLIL::SigBit(RTLIL::State::Sx); bit = RTLIL::SigBit(RTLIL::State::Sx);
parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
} }
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))) != 0) {
auto sig = sigmap(conn.second);
RTLIL::Const value(State::Sx, sig.size());
for (int i = 0; i < sig.size(); i++) {
auto it = init_bits.find(sig[i]);
if (it != init_bits.end()) {
value[i] = it->second;
}
}
parameters[stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))] = value;
}
} }
int unique_bit_id_counter = 0; int unique_bit_id_counter = 0;
@ -833,7 +929,7 @@ struct TechmapWorker
TechmapWires twd = techmap_find_special_wires(tpl); TechmapWires twd = techmap_find_special_wires(tpl);
for (auto &it : twd) { for (auto &it : twd) {
if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") if (it.first != "_TECHMAP_FAIL_" && (it.first.substr(0, 20) != "_TECHMAP_REMOVEINIT_" || it.first[it.first.size()-1] != '_') && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_")
log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
if (techmap_do_cache[tpl]) if (techmap_do_cache[tpl])
for (auto &it2 : it.second) for (auto &it2 : it.second)
@ -864,6 +960,23 @@ struct TechmapWorker
mkdebug.off(); mkdebug.off();
} }
TechmapWires twd = techmap_find_special_wires(tpl);
for (auto &it : twd) {
if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_") {
for (auto &it2 : it.second) {
auto val = it2.value.as_const();
auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1));
auto it = cell->connections().find(wirename);
if (it != cell->connections().end()) {
auto sig = sigmap(it->second);
for (int i = 0; i < sig.size(); i++)
if (val[i] == State::S1)
remove_init_bits.insert(sig[i]);
}
}
}
}
if (extern_mode && !in_recursion) if (extern_mode && !in_recursion)
{ {
std::string m_name = stringf("$extern:%s", log_id(tpl)); std::string m_name = stringf("$extern:%s", log_id(tpl));
@ -907,6 +1020,25 @@ struct TechmapWorker
handled_cells.insert(cell); handled_cells.insert(cell);
} }
if (!remove_init_bits.empty()) {
for (auto wire : module->wires())
if (wire->attributes.count("\\init")) {
Const &value = wire->attributes.at("\\init");
bool do_cleanup = true;
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) {
SigBit bit = sigmap(SigBit(wire, i));
if (remove_init_bits.count(bit))
value[i] = State::Sx;
else if (value[i] != State::Sx)
do_cleanup = false;
}
if (do_cleanup) {
log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire));
wire->attributes.erase("\\init");
}
}
}
if (log_continue) { if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n"); log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false; log_continue = false;
@ -943,7 +1075,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");
@ -980,6 +1113,11 @@ struct TechmapPass : public Pass {
log("will create a wrapper for the cell and then run the command string that the\n"); log("will create a wrapper for the cell and then run the command string that the\n");
log("attribute is set to on the wrapper module.\n"); log("attribute is set to on the wrapper module.\n");
log("\n"); log("\n");
log("When a port on a module in the map file has the 'techmap_autopurge' attribute\n");
log("set, and that port is not connected in the instantiation that is mapped, then\n");
log("then a cell port connected only to such wires will be omitted in the mapped\n");
log("version of the circuit.\n");
log("\n");
log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n"); log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n");
log("or *._TECHMAP_* are special wires that are used to pass instructions from\n"); log("or *._TECHMAP_* are special wires that are used to pass instructions from\n");
log("the mapping module to the techmap command. At the moment the following special\n"); log("the mapping module to the techmap command. At the moment the following special\n");
@ -1018,6 +1156,13 @@ struct TechmapPass : public Pass {
log("\n"); log("\n");
log(" It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n"); log(" It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n");
log("\n"); log("\n");
log(" _TECHMAP_REMOVEINIT_<port-name>_\n");
log(" When this wire is set to a constant value, the init attribute of the wire(s)\n");
log(" connected to this port will be consumed. This wire must have the same\n");
log(" width as the given port, and for every bit that is set to 1 in the value,\n");
log(" the corresponding init attribute bit will be changed to 1'bx. If all\n");
log(" bits of an init attribute are left as x, it will be removed.\n");
log("\n");
log("In addition to this special wires, techmap also supports special parameters in\n"); log("In addition to this special wires, techmap also supports special parameters in\n");
log("modules in the map file:\n"); log("modules in the map file:\n");
log("\n"); log("\n");
@ -1031,6 +1176,13 @@ struct TechmapPass : public Pass {
log(" former has a 1-bit for each constant input bit and the latter has the\n"); log(" former has a 1-bit for each constant input bit and the latter has the\n");
log(" value for this bit. The unused bits of the latter are set to undef (x).\n"); log(" value for this bit. The unused bits of the latter are set to undef (x).\n");
log("\n"); log("\n");
log(" _TECHMAP_WIREINIT_<port-name>_\n");
log(" When a parameter with this name exists, it will be set to the initial\n");
log(" value of the wire(s) connected to the given port, as specified by the init\n");
log(" attribute. If the attribute doesn't exist, x will be filled for the\n");
log(" missing bits. To remove the init attribute bits used, use the\n");
log(" _TECHMAP_REMOVEINIT_*_ wires.\n");
log("\n");
log(" _TECHMAP_BITS_CONNMAP_\n"); log(" _TECHMAP_BITS_CONNMAP_\n");
log(" _TECHMAP_CONNMAP_<port-name>_\n"); log(" _TECHMAP_CONNMAP_<port-name>_\n");
log(" For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n"); log(" For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n");
@ -1157,15 +1309,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

@ -345,6 +345,9 @@ struct TestAutotbBackend : public Backend {
log("value after initialization. This can e.g. be used to force a reset signal\n"); log("value after initialization. This can e.g. be used to force a reset signal\n");
log("low in order to explore more inner states in a state machine.\n"); log("low in order to explore more inner states in a state machine.\n");
log("\n"); log("\n");
log("The attribute 'gentb_skip' can be attached to modules to suppress testbench\n");
log("generation.\n");
log("\n");
log(" -n <int>\n"); log(" -n <int>\n");
log(" number of iterations the test bench should run (default = 1000)\n"); log(" number of iterations the test bench should run (default = 1000)\n");
log("\n"); log("\n");

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

@ -1,5 +1,5 @@
module AL_MAP_SEQ ( module AL_MAP_SEQ (
output q, output reg q,
input ce, input ce,
input clk, input clk,
input sr, input sr,
@ -9,6 +9,71 @@ module AL_MAP_SEQ (
parameter REGSET = "RESET"; //RESET/SET parameter REGSET = "RESET"; //RESET/SET
parameter SRMUX = "SR"; //SR/INV parameter SRMUX = "SR"; //SR/INV
parameter SRMODE = "SYNC"; //SYNC/ASYNC parameter SRMODE = "SYNC"; //SYNC/ASYNC
wire clk_ce;
assign clk_ce = ce ? clk : 1'b0;
wire srmux;
generate
case (SRMUX)
"SR": assign srmux = sr;
"INV": assign srmux = ~sr;
default: assign srmux = sr;
endcase
endgenerate
wire regset;
generate
case (REGSET)
"RESET": assign regset = 1'b0;
"SET": assign regset = 1'b1;
default: assign regset = 1'b0;
endcase
endgenerate
initial q = regset;
generate
if (DFFMODE == "FF")
begin
if (SRMODE == "ASYNC")
begin
always @(posedge clk_ce, posedge srmux)
if (srmux)
q <= regset;
else
q <= d;
end
else
begin
always @(posedge clk_ce)
if (srmux)
q <= regset;
else
q <= d;
end
end
else
begin
// DFFMODE == "LATCH"
if (SRMODE == "ASYNC")
begin
always @(clk_ce, srmux)
if (srmux)
q <= regset;
else
q <= d;
end
else
begin
always @(clk_ce)
if (srmux)
q <= regset;
else
q <= d;
end
end
endgenerate
endmodule endmodule
module AL_MAP_LUT1 ( module AL_MAP_LUT1 (
@ -17,7 +82,8 @@ module AL_MAP_LUT1 (
); );
parameter [1:0] INIT = 2'h0; parameter [1:0] INIT = 2'h0;
parameter EQN = "(A)"; parameter EQN = "(A)";
assign o = INIT >> a;
assign o = a ? INIT[1] : INIT[0];
endmodule endmodule
module AL_MAP_LUT2 ( module AL_MAP_LUT2 (
@ -27,7 +93,9 @@ module AL_MAP_LUT2 (
); );
parameter [3:0] INIT = 4'h0; parameter [3:0] INIT = 4'h0;
parameter EQN = "(A)"; parameter EQN = "(A)";
assign o = INIT >> {b, a};
wire [1:0] s1 = b ? INIT[ 3:2] : INIT[1:0];
assign o = a ? s1[1] : s1[0];
endmodule endmodule
module AL_MAP_LUT3 ( module AL_MAP_LUT3 (
@ -38,7 +106,10 @@ module AL_MAP_LUT3 (
); );
parameter [7:0] INIT = 8'h0; parameter [7:0] INIT = 8'h0;
parameter EQN = "(A)"; parameter EQN = "(A)";
assign o = INIT >> {c, b, a};
wire [3:0] s2 = c ? INIT[ 7:4] : INIT[3:0];
wire [1:0] s1 = b ? s2[ 3:2] : s2[1:0];
assign o = a ? s1[1] : s1[0];
endmodule endmodule
module AL_MAP_LUT4 ( module AL_MAP_LUT4 (
@ -50,7 +121,11 @@ module AL_MAP_LUT4 (
); );
parameter [15:0] INIT = 16'h0; parameter [15:0] INIT = 16'h0;
parameter EQN = "(A)"; parameter EQN = "(A)";
assign o = INIT >> {d, c, b, a};
wire [7:0] s3 = d ? INIT[15:8] : INIT[7:0];
wire [3:0] s2 = c ? s3[ 7:4] : s3[3:0];
wire [1:0] s1 = b ? s2[ 3:2] : s2[1:0];
assign o = a ? s1[1] : s1[0];
endmodule endmodule
module AL_MAP_LUT5 ( module AL_MAP_LUT5 (
@ -100,4 +175,18 @@ module AL_MAP_ADDER (
output [1:0] o output [1:0] o
); );
parameter ALUTYPE = "ADD"; parameter ALUTYPE = "ADD";
generate
case (ALUTYPE)
"ADD": assign o = a + b + c;
"SUB": assign o = a - b - c;
"A_LE_B": assign o = a - b - c;
"ADD_CARRY": assign o = { a, 1'b0 };
"SUB_CARRY": assign o = { ~a, 1'b0 };
"A_LE_B_CARRY": assign o = { a, 1'b0 };
default: assign o = a + b + c;
endcase
endgenerate
endmodule 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

@ -28,3 +28,4 @@ $(eval $(call add_share_file,share,techlibs/common/dff2ff.v))
$(eval $(call add_share_file,share,techlibs/common/gate2lut.v)) $(eval $(call add_share_file,share,techlibs/common/gate2lut.v))
$(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v))
$(eval $(call add_share_file,share,techlibs/common/cells.lib)) $(eval $(call add_share_file,share,techlibs/common/cells.lib))
$(eval $(call add_share_file,share,techlibs/common/dummy.box))

View File

@ -0,0 +1 @@
(dummy) 1 0 0 0

View File

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

View File

@ -1,6 +1,9 @@
OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \
techlibs/ecp5/ecp5_gsr.o
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v))
@ -11,6 +14,9 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_unmap.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_model.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g_nowide.lut)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g_nowide.lut))

View File

@ -15,16 +15,16 @@ CCU2C 1 1 9 3
630 379 630 379 526 275 392 141 273 630 379 630 379 526 275 392 141 273
516 516 516 516 412 412 278 278 43 516 516 516 516 412 412 278 278 43
# Box 2 : TRELLIS_DPR16X4 (16x4 dist ram) # Box 2 : TRELLIS_DPR16X4_COMB (16x4 dist ram)
# Outputs: DO0, DO1, DO2, DO3 # Outputs: DO0, DO1, DO2, DO3
# name ID w/b ins outs # name ID w/b ins outs
TRELLIS_DPR16X4 2 0 14 4 $__ABC_DPR16X4_COMB 2 0 8 4
#DI0 DI1 DI2 DI3 RAD0 RAD1 RAD2 RAD3 WAD0 WAD1 WAD2 WAD3 WCK WRE #A0 A1 A2 A3 RAD0 RAD1 RAD2 RAD3
- - - - 141 379 275 379 - - - - - - 0 0 0 0 141 379 275 379
- - - - 141 379 275 379 - - - - - - 0 0 0 0 141 379 275 379
- - - - 141 379 275 379 - - - - - - 0 0 0 0 141 379 275 379
- - - - 141 379 275 379 - - - - - - 0 0 0 0 141 379 275 379
# Box 3 : PFUMX (MUX2) # Box 3 : PFUMX (MUX2)
# Outputs: Z # Outputs: Z

24
techlibs/ecp5/abc_map.v Normal file
View File

@ -0,0 +1,24 @@
// ---------------------------------------
module TRELLIS_DPR16X4 (
input [3:0] DI,
input [3:0] WAD,
input WRE,
input WCK,
input [3:0] RAD,
output [3:0] DO
);
parameter WCKMUX = "WCK";
parameter WREMUX = "WRE";
parameter [63:0] INITVAL = 64'h0000000000000000;
wire [3:0] \$DO ;
TRELLIS_DPR16X4 #(
.WCKMUX(WCKMUX), .WREMUX(WREMUX), .INITVAL(INITVAL)
) _TECHMAP_REPLACE_ (
.DI(DI), .WAD(WAD), .WRE(WRE), .WCK(WCK),
.RAD(RAD), .DO(\$DO )
);
\$__ABC_DPR16X4_COMB do (.A(\$DO ), .S(RAD), .Y(DO));
endmodule

View File

@ -0,0 +1,5 @@
// ---------------------------------------
(* abc_box_id=2 *)
module \$__ABC_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y);
endmodule

View File

@ -0,0 +1,5 @@
// ---------------------------------------
module \$__ABC_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y);
assign Y = A;
endmodule

View File

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

View File

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

40
techlibs/ecp5/cells_ff.vh Normal file
View File

@ -0,0 +1,40 @@
// Diamond flip-flops
module FD1P3AX(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .CE(SP), .DI(D), .Q(Q)); endmodule
module FD1P3AY(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .CE(SP), .DI(D), .Q(Q)); endmodule
module FD1P3BX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module FD1P3DX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module FD1P3IX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module FD1P3JX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module FD1S3AX(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .DI(D), .Q(Q)); endmodule
module FD1S3AY(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .DI(D), .Q(Q)); endmodule
module FD1S3BX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
module FD1S3DX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
module FD1S3IX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
module FD1S3JX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
// TODO: Diamond latches
// module FL1P3AY(); endmodule
// module FL1P3AZ(); endmodule
// module FL1P3BX(); endmodule
// module FL1P3DX(); endmodule
// module FL1P3IY(); endmodule
// module FL1P3JY(); endmodule
// module FL1S3AX(); endmodule
// module FL1S3AY(); endmodule
// Diamond I/O registers
module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
// TODO: Diamond I/O latches
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
// module IFS1S1J(input CD, D, SCLK, output Q); endmodule

14
techlibs/ecp5/cells_io.vh Normal file
View File

@ -0,0 +1,14 @@
// Diamond I/O buffers
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module ILVDS(input A, AN, output Z ); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule

View File

@ -1,105 +1,54 @@
module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
// TODO: Diamond flip-flops `include "cells_ff.vh"
// module FD1P3AX(); endmodule `include "cells_io.vh"
// module FD1P3AY(); endmodule
// module FD1P3BX(); endmodule
// module FD1P3DX(); endmodule
// module FD1P3IX(); endmodule
// module FD1P3JX(); endmodule
// module FD1S3AX(); endmodule
// module FD1S3AY(); endmodule
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
// module FL1P3AY(); endmodule
// module FL1P3AZ(); endmodule
// module FL1P3BX(); endmodule
// module FL1P3DX(); endmodule
// module FL1P3IY(); endmodule
// module FL1P3JY(); endmodule
// module FL1S3AX(); endmodule
// module FL1S3AY(); endmodule
// Diamond I/O buffers
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule
module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
// Diamond I/O registers
module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
// TODO: Diamond I/O latches
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
`ifndef NO_LUT `ifndef NO_LUT
module \$lut (A, Y); module \$lut (A, Y);

View File

@ -17,10 +17,12 @@ endmodule
// --------------------------------------- // ---------------------------------------
(* abc_box_id=1, lib_whitebox *) (* abc_box_id=1, lib_whitebox *)
module CCU2C( module CCU2C(
(* abc_carry *) input CIN, (* abc_carry *)
input CIN,
input A0, B0, C0, D0, A1, B1, C1, D1, input A0, B0, C0, D0, A1, B1, C1, D1,
output S0, S1, output S0, S1,
(* abc_carry *) output COUT (* abc_carry *)
output COUT
); );
parameter [15:0] INIT0 = 16'h0000; parameter [15:0] INIT0 = 16'h0000;
parameter [15:0] INIT1 = 16'h0000; parameter [15:0] INIT1 = 16'h0000;
@ -107,13 +109,13 @@ module PFUMX (input ALUT, BLUT, C0, output Z);
endmodule endmodule
// --------------------------------------- // ---------------------------------------
//(* abc_box_id=2 *)
module TRELLIS_DPR16X4 ( module TRELLIS_DPR16X4 (
(* abc_scc_break *) input [3:0] DI, input [3:0] DI,
(* abc_scc_break *) input [3:0] WAD, input [3:0] WAD,
(* abc_scc_break *) input WRE, input WRE,
input WCK, input WCK,
input [3:0] RAD, input [3:0] RAD,
/* (* abc_arrival=<TODO> *) */
output [3:0] DO output [3:0] DO
); );
parameter WCKMUX = "WCK"; parameter WCKMUX = "WCK";
@ -224,14 +226,15 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
parameter REGSET = "RESET"; parameter REGSET = "RESET";
parameter [127:0] LSRMODE = "LSR"; parameter [127:0] LSRMODE = "LSR";
reg muxce; wire muxce;
always @(*) generate
case (CEMUX) case (CEMUX)
"1": muxce = 1'b1; "1": assign muxce = 1'b1;
"0": muxce = 1'b0; "0": assign muxce = 1'b0;
"INV": muxce = ~CE; "INV": assign muxce = ~CE;
default: muxce = CE; default: assign muxce = CE;
endcase endcase
endgenerate
wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
@ -688,56 +691,9 @@ module DP16KD(
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
endmodule endmodule
// TODO: Diamond flip-flops `ifndef NO_INCLUDES
// module FD1P3AX(); endmodule
// module FD1P3AY(); endmodule
// module FD1P3BX(); endmodule
// module FD1P3DX(); endmodule
// module FD1P3IX(); endmodule
// module FD1P3JX(); endmodule
// module FD1S3AX(); endmodule
// module FD1S3AY(); endmodule
module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
// module FL1P3AY(); endmodule
// module FL1P3AZ(); endmodule
// module FL1P3BX(); endmodule
// module FL1P3DX(); endmodule
// module FL1P3IY(); endmodule
// module FL1P3JY(); endmodule
// module FL1S3AX(); endmodule
// module FL1S3AY(); endmodule
// Diamond I/O buffers `include "cells_ff.vh"
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule `include "cells_io.vh"
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule
module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) tio (.B(A), .O(Z)); endmodule
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule
// Diamond I/O registers `endif
module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
// TODO: Diamond I/O latches
// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
// module IFS1S1J(input CD, D, SCLK, output Q); endmodule

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

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

View File

@ -271,6 +271,8 @@ struct SynthEcp5Pass : public ScriptPass
run("opt_expr -undriven -mux_undef"); run("opt_expr -undriven -mux_undef");
run("simplemap"); run("simplemap");
run("ecp5_ffinit"); run("ecp5_ffinit");
run("ecp5_gsr");
run("opt_clean");
} }
if (check_label("map_luts")) if (check_label("map_luts"))
@ -278,12 +280,17 @@ struct SynthEcp5Pass : public ScriptPass
if (abc2 || help_mode) { if (abc2 || help_mode) {
run("abc", " (only if -abc2)"); run("abc", " (only if -abc2)");
} }
run("techmap -map +/ecp5/latches_map.v"); std::string techmap_args = "-map +/ecp5/latches_map.v";
if (abc9)
techmap_args += " -map +/ecp5/abc_map.v -max_iter 1";
run("techmap " + techmap_args);
if (abc9) { if (abc9) {
if (nowidelut) if (nowidelut)
run("abc9 -lut +/ecp5/abc_5g_nowide.lut -box +/ecp5/abc_5g.box -W 200"); run("abc9 -lut +/ecp5/abc_5g_nowide.lut -box +/ecp5/abc_5g.box -W 200");
else else
run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200"); run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200");
run("techmap -map +/ecp5/abc_unmap.v");
} else { } else {
if (nowidelut) if (nowidelut)
run("abc -lut 4 -dress"); run("abc -lut 4 -dress");

1
techlibs/ecp5/tests/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
work_*

View File

@ -0,0 +1,82 @@
import os
import subprocess
if not os.path.exists("work_ff"):
os.mkdir("work_ff")
modules = []
with open("../cells_ff.vh", "r") as f:
with open("work_ff/cells_ff_gate.v", "w") as g:
for line in f:
if not line.startswith("module"):
g.write(line)
continue
else:
spidx = line.find(" ")
bridx = line.find("(")
modname = line[spidx+1 : bridx]
g.write("module %s_gate" % modname)
g.write(line[bridx:])
inpidx = line.find("input ")
outpidx = line.find(", output")
modules.append((modname, [x.strip() for x in line[inpidx+6:outpidx].split(",")]))
with open("work_ff/testbench.v", "w") as f:
print("""
`timescale 1ns/ 1ps
module testbench;
reg pur = 0, clk, rst, cen, d;
// Needed for Diamond sim models
GSR GSR_INST (.GSR(1'b1));
PUR PUR_INST (.PUR(pur));
initial begin
$dumpfile("work_ff/ffs.vcd");
$dumpvars(0, testbench);
#5;
pur = 1;
#95;
repeat (2500) begin
{clk, rst, cen, d} = $random;
#10;
check_outputs;
#1;
end
$finish;
end
""", file=f)
for modname, inputs in modules:
print(" wire %s_gold_q, %s_gate_q;" % (modname, modname), file=f)
portconns = []
for inp in inputs:
if inp in ("SCLK", "CK"):
portconns.append(".%s(clk)" % inp)
elif inp in ("CD", "PD"):
portconns.append(".%s(rst)" % inp)
elif inp == "SP":
portconns.append(".%s(cen)" % inp)
elif inp == "D":
portconns.append(".%s(d)" % inp)
else:
assert False
portconns.append(".Q(%s_gold_q)" % modname)
print(" %s %s_gold_i (%s);" % (modname, modname, ", ".join(portconns)), file=f)
portconns[-1] = (".Q(%s_gate_q)" % modname)
print(" %s_gate %s_gate_i (%s);" % (modname, modname, ", ".join(portconns)), file=f)
print("", file=f)
print(" task check_outputs;", file=f)
print(" begin", file=f)
print(" if (%s_gold_q != %s_gate_q) $display(\"MISMATCH at %%1t: %s_gold_q=%%b, %s_gate_q=%%b\", $time, %s_gold_q, %s_gate_q);" %
(modname, modname, modname, modname, modname, modname), file=f)
print(" end", file=f)
print(" endtask", file=f)
print("endmodule", file=f)
diamond_models = "/usr/local/diamond/3.10_x64/cae_library/simulation/verilog/ecp5u"
subprocess.call(["iverilog", "-s", "testbench", "-o", "work_ff/testbench", "-Dmixed_hdl", "-DNO_INCLUDES", "-y", diamond_models, "work_ff/cells_ff_gate.v", "../cells_sim.v", "work_ff/testbench.v"])
subprocess.call(["vvp", "work_ff/testbench"])

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

173
techlibs/efinix/cells_sim.v Normal file
View File

@ -0,0 +1,173 @@
module EFX_LUT4(
output O,
input I0,
input I1,
input I2,
input I3
);
parameter LUTMASK = 16'h0000;
wire [7:0] s3 = I3 ? LUTMASK[15:8] : LUTMASK[7:0];
wire [3:0] s2 = I2 ? s3[ 7:4] : s3[3:0];
wire [1:0] s1 = I1 ? s2[ 3:2] : s2[1:0];
assign O = I0 ? s1[1] : s1[0];
endmodule
module EFX_ADD(
output O,
output CO,
input I0,
input I1,
input CI
);
parameter I0_POLARITY = 1;
parameter I1_POLARITY = 1;
wire i0;
wire i1;
assign i0 = I0_POLARITY ? I0 : ~I0;
assign i1 = I1_POLARITY ? I1 : ~I1;
assign {CO, O} = i0 + i1 + CI;
endmodule
module EFX_FF(
output reg 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;
wire clk;
wire ce;
wire sr;
wire d;
wire prio;
wire sync;
wire async;
assign clk = CLK_POLARITY ? CLK : ~CLK;
assign ce = CE_POLARITY ? CE : ~CE;
assign sr = SR_POLARITY ? SR : ~SR;
assign d = D_POLARITY ? D : ~D;
generate
if (SR_SYNC == 1)
begin
if (SR_SYNC_PRIORITY == 1)
begin
always @(posedge clk)
if (sr)
Q <= SR_VALUE;
else if (ce)
Q <= d;
end
else
begin
always @(posedge clk)
if (ce)
begin
if (sr)
Q <= SR_VALUE;
else
Q <= d;
end
end
end
else
begin
always @(posedge clk or posedge sr)
if (sr)
Q <= SR_VALUE;
else if (ce)
Q <= d;
end
endgenerate
endmodule
module EFX_GBUFCE(
input CE,
input I,
output O
);
parameter CE_POLARITY = 1'b1;
wire ce;
assign ce = CE_POLARITY ? CE : ~CE;
assign O = I & ce;
endmodule
module EFX_RAM_5K(
input [WRITE_WIDTH-1:0] WDATA,
input [WRITE_ADDR_WIDTH-1:0] WADDR,
input WE,
input WCLK,
input WCLKE,
output [READ_WIDTH-1:0] RDATA,
input [READ_ADDR_WIDTH-1:0] RADDR,
input RE,
input RCLK
);
parameter READ_WIDTH = 20;
parameter WRITE_WIDTH = 20;
parameter OUTPUT_REG = 1'b0;
parameter RCLK_POLARITY = 1'b1;
parameter RE_POLARITY = 1'b1;
parameter WCLK_POLARITY = 1'b1;
parameter WE_POLARITY = 1'b1;
parameter WCLKE_POLARITY = 1'b1;
parameter WRITE_MODE = "READ_FIRST";
parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
localparam READ_ADDR_WIDTH =
(READ_WIDTH == 16) ? 8 : // 256x16
(READ_WIDTH == 8) ? 9 : // 512x8
(READ_WIDTH == 4) ? 10 : // 1024x4
(READ_WIDTH == 2) ? 11 : // 2048x2
(READ_WIDTH == 1) ? 12 : // 4096x1
(READ_WIDTH == 20) ? 8 : // 256x20
(READ_WIDTH == 10) ? 9 : // 512x10
(READ_WIDTH == 5) ? 10 : -1; // 1024x5
localparam WRITE_ADDR_WIDTH =
(WRITE_WIDTH == 16) ? 8 : // 256x16
(WRITE_WIDTH == 8) ? 9 : // 512x8
(WRITE_WIDTH == 4) ? 10 : // 1024x4
(WRITE_WIDTH == 2) ? 11 : // 2048x2
(WRITE_WIDTH == 1) ? 12 : // 4096x1
(WRITE_WIDTH == 20) ? 8 : // 256x20
(WRITE_WIDTH == 10) ? 9 : // 512x10
(WRITE_WIDTH == 5) ? 10 : -1; // 1024x5
endmodule

View File

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

View File

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

View File

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

View File

@ -3,11 +3,11 @@
# NB: Inputs/Outputs must be ordered alphabetically # NB: Inputs/Outputs must be ordered alphabetically
# (with exceptions for carry in/out) # (with exceptions for carry in/out)
# Inputs: A B CI # Inputs: A B I0 I3 CI
# Outputs: O CO # Outputs: O CO
# (NB: carry chain input/output must be last # (NB: carry chain input/output must be last
# input/output and have been moved there # input/output and have been moved there
# overriding the alphabetical ordering) # overriding the alphabetical ordering)
$__ICE40_FULL_ADDER 1 1 3 2 $__ICE40_CARRY_WRAPPER 1 1 5 2
400 379 316 400 379 449 316 316
259 231 126 259 231 - - 126

View File

@ -3,11 +3,11 @@
# NB: Inputs/Outputs must be ordered alphabetically # NB: Inputs/Outputs must be ordered alphabetically
# (with exceptions for carry in/out) # (with exceptions for carry in/out)
# Inputs: A B CI # Inputs: A B I0 I3 CI
# Outputs: O CO # Outputs: O CO
# (NB: carry chain input/output must be last # (NB: carry chain input/output must be last
# input/output and have been moved there # input/output and have been moved there
# overriding the alphabetical ordering) # overriding the alphabetical ordering)
$__ICE40_FULL_ADDER 1 1 3 2 $__ICE40_CARRY_WRAPPER 1 1 5 2
589 558 465 589 558 661 465 465
675 609 186 675 609 - - 186

View File

@ -3,11 +3,11 @@
# NB: Inputs/Outputs must be ordered alphabetically # NB: Inputs/Outputs must be ordered alphabetically
# (with exceptions for carry in/out) # (with exceptions for carry in/out)
# Inputs: A B CI # Inputs: A B I0 I3 CI
# Outputs: O CO # Outputs: O CO
# (NB: carry chain input/output must be last # (NB: carry chain input/output must be last
# input/output and have been moved there # input/output and have been moved there
# overriding the alphabetical ordering) # overriding the alphabetical ordering)
$__ICE40_FULL_ADDER 1 1 3 2 $__ICE40_CARRY_WRAPPER 1 1 5 2
1231 1205 874 1231 1205 1285 874 874
675 609 278 675 609 - - 278

View File

@ -2,6 +2,10 @@
`define SB_DFF_REG reg Q = 0 `define SB_DFF_REG reg Q = 0
// `define SB_DFF_REG reg Q // `define SB_DFF_REG reg Q
`define ABC_ARRIVAL_HX(TIME) `ifdef ICE40_HX (* abc_arrival=TIME *) `endif
`define ABC_ARRIVAL_LP(TIME) `ifdef ICE40_LP (* abc_arrival=TIME *) `endif
`define ABC_ARRIVAL_U(TIME) `ifdef ICE40_U (* abc_arrival=TIME *) `endif
// SiliconBlue IO Cells // SiliconBlue IO Cells
module SB_IO ( module SB_IO (
@ -142,13 +146,16 @@ module SB_CARRY (output CO, input I0, I1, CI);
endmodule endmodule
(* abc_box_id = 1, lib_whitebox *) (* abc_box_id = 1, lib_whitebox *)
module \$__ICE40_FULL_ADDER ( module \$__ICE40_CARRY_WRAPPER (
(* abc_carry *) output CO, (* abc_carry *)
output CO,
output O, output O,
input A, input A, B,
input B, (* abc_carry *)
(* abc_carry *) input CI input CI,
input I0, I3
); );
parameter LUT = 0;
SB_CARRY carry ( SB_CARRY carry (
.I0(A), .I0(A),
.I1(B), .I1(B),
@ -156,34 +163,52 @@ module \$__ICE40_FULL_ADDER (
.CO(CO) .CO(CO)
); );
SB_LUT4 #( SB_LUT4 #(
// I0: 1010 1010 1010 1010 .LUT_INIT(LUT)
// I1: 1100 1100 1100 1100
// I2: 1111 0000 1111 0000
// I3: 1111 1111 0000 0000
.LUT_INIT(16'b 0110_1001_1001_0110)
) adder ( ) adder (
.I0(1'b0), .I0(I0),
.I1(A), .I1(A),
.I2(B), .I2(B),
.I3(CI), .I3(I3),
.O(O) .O(O)
); );
endmodule endmodule
// Max delay from: https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90
// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102
// Positive Edge SiliconBlue FF Cells // Positive Edge SiliconBlue FF Cells
module SB_DFF (output `SB_DFF_REG, input C, D); module SB_DFF (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, D
);
always @(posedge C) always @(posedge C)
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFE (output `SB_DFF_REG, input C, E, D); module SB_DFFE (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, D
);
always @(posedge C) always @(posedge C)
if (E) if (E)
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFSR (output `SB_DFF_REG, input C, R, D); module SB_DFFSR (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, R, D
);
always @(posedge C) always @(posedge C)
if (R) if (R)
Q <= 0; Q <= 0;
@ -191,7 +216,13 @@ module SB_DFFSR (output `SB_DFF_REG, input C, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFR (output `SB_DFF_REG, input C, R, D); module SB_DFFR (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, R, D
);
always @(posedge C, posedge R) always @(posedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -199,7 +230,13 @@ module SB_DFFR (output `SB_DFF_REG, input C, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFSS (output `SB_DFF_REG, input C, S, D); module SB_DFFSS (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, S, D
);
always @(posedge C) always @(posedge C)
if (S) if (S)
Q <= 1; Q <= 1;
@ -207,7 +244,13 @@ module SB_DFFSS (output `SB_DFF_REG, input C, S, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFS (output `SB_DFF_REG, input C, S, D); module SB_DFFS (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, S, D
);
always @(posedge C, posedge S) always @(posedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -215,7 +258,13 @@ module SB_DFFS (output `SB_DFF_REG, input C, S, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D); module SB_DFFESR (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, R, D
);
always @(posedge C) always @(posedge C)
if (E) begin if (E) begin
if (R) if (R)
@ -225,7 +274,13 @@ module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D);
end end
endmodule endmodule
module SB_DFFER (output `SB_DFF_REG, input C, E, R, D); module SB_DFFER (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, R, D
);
always @(posedge C, posedge R) always @(posedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -233,7 +288,13 @@ module SB_DFFER (output `SB_DFF_REG, input C, E, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D); module SB_DFFESS (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, S, D
);
always @(posedge C) always @(posedge C)
if (E) begin if (E) begin
if (S) if (S)
@ -243,7 +304,13 @@ module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D);
end end
endmodule endmodule
module SB_DFFES (output `SB_DFF_REG, input C, E, S, D); module SB_DFFES (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, S, D
);
always @(posedge C, posedge S) always @(posedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -253,18 +320,36 @@ endmodule
// Negative Edge SiliconBlue FF Cells // Negative Edge SiliconBlue FF Cells
module SB_DFFN (output `SB_DFF_REG, input C, D); module SB_DFFN (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, D
);
always @(negedge C) always @(negedge C)
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNE (output `SB_DFF_REG, input C, E, D); module SB_DFFNE (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, D
);
always @(negedge C) always @(negedge C)
if (E) if (E)
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNSR (output `SB_DFF_REG, input C, R, D); module SB_DFFNSR (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, R, D
);
always @(negedge C) always @(negedge C)
if (R) if (R)
Q <= 0; Q <= 0;
@ -272,7 +357,13 @@ module SB_DFFNSR (output `SB_DFF_REG, input C, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNR (output `SB_DFF_REG, input C, R, D); module SB_DFFNR (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, R, D
);
always @(negedge C, posedge R) always @(negedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -280,7 +371,13 @@ module SB_DFFNR (output `SB_DFF_REG, input C, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNSS (output `SB_DFF_REG, input C, S, D); module SB_DFFNSS (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, S, D
);
always @(negedge C) always @(negedge C)
if (S) if (S)
Q <= 1; Q <= 1;
@ -288,7 +385,13 @@ module SB_DFFNSS (output `SB_DFF_REG, input C, S, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNS (output `SB_DFF_REG, input C, S, D); module SB_DFFNS (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, S, D
);
always @(negedge C, posedge S) always @(negedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -296,7 +399,13 @@ module SB_DFFNS (output `SB_DFF_REG, input C, S, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D); module SB_DFFNESR (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, R, D
);
always @(negedge C) always @(negedge C)
if (E) begin if (E) begin
if (R) if (R)
@ -306,7 +415,13 @@ module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D);
end end
endmodule endmodule
module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D); module SB_DFFNER (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, R, D
);
always @(negedge C, posedge R) always @(negedge C, posedge R)
if (R) if (R)
Q <= 0; Q <= 0;
@ -314,7 +429,13 @@ module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D);
Q <= D; Q <= D;
endmodule endmodule
module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D); module SB_DFFNESS (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, S, D
);
always @(negedge C) always @(negedge C)
if (E) begin if (E) begin
if (S) if (S)
@ -324,7 +445,13 @@ module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D);
end end
endmodule endmodule
module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D); module SB_DFFNES (
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output `SB_DFF_REG,
input C, E, S, D
);
always @(negedge C, posedge S) always @(negedge C, posedge S)
if (S) if (S)
Q <= 1; Q <= 1;
@ -335,6 +462,9 @@ endmodule
// SiliconBlue RAM Cells // SiliconBlue RAM Cells
module SB_RAM40_4K ( module SB_RAM40_4K (
`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401
`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401
`ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [15:0] RDATA, output [15:0] RDATA,
input RCLK, RCLKE, RE, input RCLK, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
@ -503,6 +633,9 @@ module SB_RAM40_4K (
endmodule endmodule
module SB_RAM40_4KNR ( module SB_RAM40_4KNR (
`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401
`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401
`ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [15:0] RDATA, output [15:0] RDATA,
input RCLKN, RCLKE, RE, input RCLKN, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
@ -568,6 +701,9 @@ module SB_RAM40_4KNR (
endmodule endmodule
module SB_RAM40_4KNW ( module SB_RAM40_4KNW (
`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401
`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401
`ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [15:0] RDATA, output [15:0] RDATA,
input RCLK, RCLKE, RE, input RCLK, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
@ -633,6 +769,9 @@ module SB_RAM40_4KNW (
endmodule endmodule
module SB_RAM40_4KNRNW ( module SB_RAM40_4KNRNW (
`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401
`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401
`ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [15:0] RDATA, output [15:0] RDATA,
input RCLKN, RCLKE, RE, input RCLKN, RCLKE, RE,
input [10:0] RADDR, input [10:0] RADDR,
@ -701,7 +840,12 @@ endmodule
module ICESTORM_LC ( module ICESTORM_LC (
input I0, I1, I2, I3, CIN, CLK, CEN, SR, input I0, I1, I2, I3, CIN, CLK, CEN, SR,
output LO, O, COUT output LO,
`ABC_ARRIVAL_HX(540)
`ABC_ARRIVAL_LP(796)
`ABC_ARRIVAL_U(1391)
output O,
output COUT
); );
parameter [15:0] LUT_INIT = 0; parameter [15:0] LUT_INIT = 0;
@ -1301,6 +1445,7 @@ module SB_MAC16 (
input ADDSUBTOP, ADDSUBBOT, input ADDSUBTOP, ADDSUBBOT,
input OHOLDTOP, OHOLDBOT, input OHOLDTOP, OHOLDBOT,
input CI, ACCUMCI, SIGNEXTIN, input CI, ACCUMCI, SIGNEXTIN,
//`ABC_ARRIVAL_U(1984) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026
output [31:0] O, output [31:0] O,
output CO, ACCUMCO, SIGNEXTOUT output CO, ACCUMCO, SIGNEXTOUT
); );

View File

@ -84,7 +84,7 @@ static void run_ice40_opts(Module *module)
continue; continue;
} }
if (cell->type == "$__ICE40_FULL_ADDER") if (cell->type == "$__ICE40_CARRY_WRAPPER")
{ {
SigSpec non_const_inputs, replacement_output; SigSpec non_const_inputs, replacement_output;
int count_zeros = 0, count_ones = 0; int count_zeros = 0, count_ones = 0;
@ -114,16 +114,17 @@ static void run_ice40_opts(Module *module)
optimized_co.insert(sigmap(cell->getPort("\\CO")[0])); optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
module->connect(cell->getPort("\\CO")[0], replacement_output); module->connect(cell->getPort("\\CO")[0], replacement_output);
module->design->scratchpad_set_bool("opt.did_something", true); module->design->scratchpad_set_bool("opt.did_something", true);
log("Optimized $__ICE40_FULL_ADDER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n", log("Optimized $__ICE40_CARRY_WRAPPER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n",
log_id(module), log_id(cell), log_signal(replacement_output)); log_id(module), log_id(cell), log_signal(replacement_output));
cell->type = "$lut"; cell->type = "$lut";
cell->setPort("\\A", { State::S0, inbit[0], inbit[1], inbit[2] }); cell->setPort("\\A", { cell->getPort("\\I0"), inbit[0], inbit[1], cell->getPort("\\I3") });
cell->setPort("\\Y", cell->getPort("\\O")); cell->setPort("\\Y", cell->getPort("\\O"));
cell->unsetPort("\\B"); cell->unsetPort("\\B");
cell->unsetPort("\\CI"); cell->unsetPort("\\CI");
cell->unsetPort("\\I0");
cell->unsetPort("\\I3");
cell->unsetPort("\\CO"); cell->unsetPort("\\CO");
cell->unsetPort("\\O"); cell->unsetPort("\\O");
cell->setParam("\\LUT", RTLIL::Const::from_string("0110100110010110"));
cell->setParam("\\WIDTH", 4); cell->setParam("\\WIDTH", 4);
} }
continue; continue;

View File

@ -238,7 +238,14 @@ struct SynthIce40Pass : public ScriptPass
{ {
if (check_label("begin")) if (check_label("begin"))
{ {
run("read_verilog -icells -lib +/ice40/cells_sim.v"); std::string define;
if (device_opt == "lp")
define = "-D ICE40_LP";
else if (device_opt == "u")
define = "-D ICE40_U";
else
define = "-D ICE40_HX";
run("read_verilog -icells " + define + " -lib +/ice40/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
run("proc"); run("proc");
} }

View File

@ -25,7 +25,10 @@ techlibs/xilinx/brams_init_8.vh: techlibs/xilinx/brams_init.mk
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_cells_xtra.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6v_cells_xtra.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_cells_xtra.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_cells_xtra.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_bb.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_bb.v))
@ -35,7 +38,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_bb.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_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/xc6s_ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_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))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v))

View File

@ -128,7 +128,7 @@ module RAM32X1D (
parameter INIT = 32'h0; parameter INIT = 32'h0;
parameter IS_WCLK_INVERTED = 1'b0; parameter IS_WCLK_INVERTED = 1'b0;
wire \$DPO , \$SPO ; wire \$DPO , \$SPO ;
\$__ABC_RAM32X1D #( RAM32X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.DPO(\$DPO ), .SPO(\$SPO ), .DPO(\$DPO ), .SPO(\$SPO ),
@ -136,8 +136,8 @@ module RAM32X1D (
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
.DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
); );
\$__ABC_LUTMUX6 dpo (.A(\$DPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(DPO)); \$__ABC_LUT6 dpo (.A(\$DPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(DPO));
\$__ABC_LUTMUX6 spo (.A(\$SPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(SPO)); \$__ABC_LUT6 spo (.A(\$SPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(SPO));
endmodule endmodule
module RAM64X1D ( module RAM64X1D (
@ -151,7 +151,7 @@ module RAM64X1D (
parameter INIT = 64'h0; parameter INIT = 64'h0;
parameter IS_WCLK_INVERTED = 1'b0; parameter IS_WCLK_INVERTED = 1'b0;
wire \$DPO , \$SPO ; wire \$DPO , \$SPO ;
\$__ABC_RAM64X1D #( RAM64X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.DPO(\$DPO ), .SPO(\$SPO ), .DPO(\$DPO ), .SPO(\$SPO ),
@ -159,8 +159,8 @@ module RAM64X1D (
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
.DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
); );
\$__ABC_LUTMUX6 dpo (.A(\$DPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(DPO)); \$__ABC_LUT6 dpo (.A(\$DPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(DPO));
\$__ABC_LUTMUX6 spo (.A(\$SPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(SPO)); \$__ABC_LUT6 spo (.A(\$SPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(SPO));
endmodule endmodule
module RAM128X1D ( module RAM128X1D (
@ -173,7 +173,7 @@ module RAM128X1D (
parameter INIT = 128'h0; parameter INIT = 128'h0;
parameter IS_WCLK_INVERTED = 1'b0; parameter IS_WCLK_INVERTED = 1'b0;
wire \$DPO , \$SPO ; wire \$DPO , \$SPO ;
\$__ABC_RAM128X1D #( RAM128X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.DPO(\$DPO ), .SPO(\$SPO ), .DPO(\$DPO ), .SPO(\$SPO ),
@ -181,8 +181,8 @@ module RAM128X1D (
.A(A), .A(A),
.DPRA(DPRA) .DPRA(DPRA)
); );
\$__ABC_LUTMUX7 dpo (.A(\$DPO ), .S(A), .Y(DPO)); \$__ABC_LUT7 dpo (.A(\$DPO ), .S(A), .Y(DPO));
\$__ABC_LUTMUX7 spo (.A(\$SPO ), .S(A), .Y(SPO)); \$__ABC_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO));
endmodule endmodule
module SRL16E ( module SRL16E (
@ -192,14 +192,13 @@ module SRL16E (
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;
wire \$Q ; wire \$Q ;
\$__ABC_SRL16E #( SRL16E #(
.INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.Q(\$Q ), .Q(\$Q ),
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
); );
// TODO: Check if SRL uses fast inputs or slow inputs \$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A0, A1, A2, A3, 1'b1}), .Y(Q));
\$__ABC_LUTMUX6 q (.A(\$Q ), .S({A0, A1, A2, A3, 1'b0, 1'b0}), .Y(Q));
endmodule endmodule
module SRLC32E ( module SRLC32E (
@ -211,12 +210,11 @@ module SRLC32E (
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;
wire \$Q ; wire \$Q ;
\$__ABC_SRLC32E #( SRLC32E #(
.INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.Q(\$Q ), .Q31(Q31), .Q(\$Q ), .Q31(Q31),
.A(A), .CE(CE), .CLK(CLK), .D(D) .A(A), .CE(CE), .CLK(CLK), .D(D)
); );
// TODO: Check if SRL uses fast inputs or slow inputs \$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q));
\$__ABC_LUTMUX6 q (.A(\$Q ), .S({A, 1'b0}), .Y(Q));
endmodule endmodule

View File

@ -115,65 +115,8 @@ module \$__ABC_FDPE_1 ((* abc_flop_q, abc_arrival=303 *) output Q,
endmodule endmodule
(* abc_box_id=2000 *) (* abc_box_id=2000 *)
module \$__ABC_LUTMUX6 (input A, input [5:0] S, output Y); module \$__ABC_LUT6 (input A, input [5:0] S, output Y);
endmodule endmodule
(* abc_box_id=2001 *) (* abc_box_id=2001 *)
module \$__ABC_LUTMUX7 (input A, input [6:0] S, output Y); module \$__ABC_LUT7 (input A, input [6:0] S, output Y);
endmodule
module \$__ABC_RAM32X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *) output DPO, SPO,
input D,
input WCLK,
input WE,
input A0, A1, A2, A3, A4,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
endmodule
module \$__ABC_RAM64X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *) output DPO, SPO,
input D,
input WCLK,
input WE,
input A0, A1, A2, A3, A4, A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
parameter INIT = 64'h0;
parameter IS_WCLK_INVERTED = 1'b0;
endmodule
module \$__ABC_RAM128X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *) output DPO, SPO,
input D,
input WCLK,
input WE,
input [6:0] A, DPRA
);
parameter INIT = 128'h0;
parameter IS_WCLK_INVERTED = 1'b0;
endmodule
module SRL16E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
(* abc_arrival=1472 *) output Q,
input A0, A1, A2, A3, CE, CLK, D
);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
endmodule
module SRLC32E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
(* abc_arrival=1472 *) output Q,
(* abc_arrival=1114 *) output Q31,
input [4:0] A,
input CE, CLK, D
);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
endmodule endmodule

View File

@ -139,101 +139,9 @@ module \$__ABC_FDPE_1 (output Q,
); );
endmodule endmodule
module \$__ABC_LUTMUX6 (input A, input [5:0] S, output Y); module \$__ABC_LUT6 (input A, input [5:0] S, output Y);
assign Y = A; assign Y = A;
endmodule endmodule
module \$__ABC_LUTMUX7 (input A, input [6:0] S, output Y); module \$__ABC_LUT7 (input A, input [6:0] S, output Y);
assign Y = A; assign Y = A;
endmodule endmodule
module \$__ABC_RAM32X1D (
output DPO, SPO,
input D,
input WCLK,
input WE,
input A0, A1, A2, A3, A4,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
parameter INIT = 32'h0;
parameter IS_WCLK_INVERTED = 1'b0;
RAM32X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ (
.DPO(DPO), .SPO(SPO),
.D(D), .WCLK(WCLK), .WE(WE),
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
.DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
);
endmodule
module \$__ABC_RAM64X1D (
output DPO, SPO,
input D,
input WCLK,
input WE,
input A0, A1, A2, A3, A4, A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
parameter INIT = 64'h0;
parameter IS_WCLK_INVERTED = 1'b0;
RAM64X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ (
.DPO(DPO), .SPO(SPO),
.D(D), .WCLK(WCLK), .WE(WE),
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
.DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
);
endmodule
module \$__ABC_RAM128X1D (
output DPO, SPO,
input D,
input WCLK,
input WE,
input A,
input DPRA,
);
parameter INIT = 128'h0;
parameter IS_WCLK_INVERTED = 1'b0;
RAM128X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ (
.DPO(DPO), .SPO(SPO),
.D(D), .WCLK(WCLK), .WE(WE),
.A(A),
.DPRA(DPRA)
);
endmodule
module \$__ABC_SRL16E (
output Q,
input A0, A1, A2, A3, CE, CLK, D
);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
SRL16E #(
.INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
) _TECHMAP_REPLACE_ (
.Q(Q),
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
);
endmodule
module \$__ABC_SRLC32E (
output Q,
output Q31,
input [4:0] A,
input CE, CLK, D
);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
SRLC32E #(
.INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
) _TECHMAP_REPLACE_ (
.Q(Q), .Q31(Q31),
.A(A), .CE(CE), .CLK(CLK), .D(D)
);
endmodule

View File

@ -15,7 +15,10 @@ F7MUX 1 1 3 1
MUXF8 2 1 3 1 MUXF8 2 1 3 1
104 94 273 104 94 273
# Box containing MUXF7.[AB] + MUXF8 # Box containing MUXF7.[AB] + MUXF8,
# Necessary to make these an atomic unit so that
# ABC cannot optimise just one of the MUXF7 away
# and expect to save on its delay
# Inputs: I0 I1 I2 I3 S0 S1 # Inputs: I0 I1 I2 I3 S0 S1
# Outputs: O # Outputs: O
$__MUXF78 3 1 6 1 $__MUXF78 3 1 6 1
@ -81,14 +84,19 @@ FDPE_1 1006 1 5 1
# SLICEM/A6LUT # SLICEM/A6LUT
# Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32} # Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32}
# Necessary since RAMD* and SRL* have both combinatorial (i.e.
# same-cycle read operation) and sequential (write operation
# is only committed on the next clock edge).
# To model the combinatorial path, such cells have to be split
# into comb and seq parts, with this box modelling only the former.
# Inputs: A S0 S1 S2 S3 S4 S5 # Inputs: A S0 S1 S2 S3 S4 S5
# Outputs: Y # Outputs: Y
$__ABC_LUTRAM6 2000 0 7 1 $__ABC_LUT6 2000 0 7 1
0 642 631 472 407 238 127 0 642 631 472 407 238 127
# SLICEM/A6LUT + F7BMUX # SLICEM/A6LUT + F7BMUX
# Box to emulate comb/seq behaviour of RAMD128 # Box to emulate comb/seq behaviour of RAMD128
# Inputs: A S0 S1 S2 S3 S4 S5 S6 # Inputs: A S0 S1 S2 S3 S4 S5 S6
# Outputs: DPO SPO # Outputs: DPO SPO
$__ABC_LUTRAM7 2001 0 8 1 $__ABC_LUT7 2001 0 8 1
0 1047 1036 877 812 643 532 478 0 1047 1036 877 812 643 532 478

View File

@ -29,29 +29,49 @@ 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, (* invertible_pin = "IS_S0_INVERTED" *)
input CE0, input CE1, input S0,
input IGNORE0, input IGNORE1); (* invertible_pin = "IS_S1_INVERTED" *)
input S1,
(* invertible_pin = "IS_CE0_INVERTED" *)
input CE0,
(* invertible_pin = "IS_CE1_INVERTED" *)
input CE1,
(* invertible_pin = "IS_IGNORE0_INVERTED" *)
input IGNORE0,
(* invertible_pin = "IS_IGNORE1_INVERTED" *)
input IGNORE1);
parameter [0:0] INIT_OUT = 1'b0; parameter [0:0] INIT_OUT = 1'b0;
parameter PRESELECT_I0 = "FALSE"; parameter PRESELECT_I0 = "FALSE";
@ -72,7 +92,12 @@ 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,
(* invertible_pin = "IS_CE_INVERTED" *)
input CE);
parameter [0:0] INIT_OUT = 1'b0; parameter [0:0] INIT_OUT = 1'b0;
parameter CE_TYPE = "SYNC"; parameter CE_TYPE = "SYNC";
@ -175,9 +200,11 @@ endmodule
(* abc_box_id = 4, lib_whitebox *) (* abc_box_id = 4, lib_whitebox *)
module CARRY4( module CARRY4(
(* abc_carry *) output [3:0] CO, (* abc_carry *)
output [3:0] CO,
output [3:0] O, output [3:0] O,
(* abc_carry *) input CI, (* abc_carry *)
input CI,
input CYINIT, input CYINIT,
input [3:0] DI, S input [3:0] DI, S
); );
@ -211,7 +238,20 @@ endmodule
`endif `endif
module FDRE (output reg Q, input C, CE, D, R); // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
module FDRE (
(* abc_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
input D,
(* invertible_pin = "IS_R_INVERTED" *)
input 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;
@ -223,7 +263,18 @@ 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 (
(* abc_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
input D,
(* invertible_pin = "IS_S_INVERTED" *)
input 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;
@ -235,7 +286,18 @@ 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 (
(* abc_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
input D,
(* invertible_pin = "IS_CLR_INVERTED" *)
input 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;
@ -249,7 +311,18 @@ 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 (
(* abc_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
input D,
(* invertible_pin = "IS_PRE_INVERTED" *)
input 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;
@ -263,33 +336,61 @@ 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 (
(* abc_arrival=303 *)
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 (
(* abc_arrival=303 *)
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 (
(* abc_arrival=303 *)
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 (
(* abc_arrival=303 *)
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
module RAM32X1D ( module RAM32X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *)
output DPO, SPO, output DPO, SPO,
input D, input D,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK, input WCLK,
input WE, input WE,
input A0, A1, A2, A3, A4, input A0, A1, A2, A3, A4,
@ -307,8 +408,12 @@ module RAM32X1D (
endmodule endmodule
module RAM64X1D ( module RAM64X1D (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *)
output DPO, SPO, output DPO, SPO,
input D, input D,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK, input WCLK,
input WE, input WE,
input A0, A1, A2, A3, A4, A5, input A0, A1, A2, A3, A4, A5,
@ -326,8 +431,12 @@ module RAM64X1D (
endmodule endmodule
module RAM128X1D ( module RAM128X1D (
output DPO, SPO, // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc_arrival=1153 *)
output DPO, SPO,
input D, input D,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK, input WCLK,
input WE, input WE,
input [6:0] A, DPRA input [6:0] A, DPRA
@ -342,8 +451,14 @@ module RAM128X1D (
endmodule endmodule
module SRL16E ( module SRL16E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
(* abc_arrival=1472 *)
output Q, output Q,
input A0, A1, A2, A3, CE, CLK, D input A0, A1, A2, A3, CE,
(* clkbuf_sink *)
(* invertible_pin = "IS_CLK_INVERTED" *)
input CLK,
input D
); );
parameter [15:0] INIT = 16'h0000; parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0; parameter [0:0] IS_CLK_INVERTED = 1'b0;
@ -355,15 +470,46 @@ module SRL16E (
always @(negedge CLK) if (CE) r <= { r[14:0], D }; always @(negedge CLK) if (CE) r <= { r[14:0], D };
end end
else else
always @(posedge CLK) if (CE) r <= { r[14:0], D }; always @(posedge CLK) if (CE) r <= { r[14:0], D };
endgenerate
endmodule
module SRLC16E (
output Q,
output Q15,
input A0, A1, A2, A3, CE,
(* clkbuf_sink *)
(* invertible_pin = "IS_CLK_INVERTED" *)
input CLK,
input D
);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
reg [15:0] r = INIT;
assign Q15 = r[15];
assign Q = r[{A3,A2,A1,A0}];
generate
if (IS_CLK_INVERTED) begin
always @(negedge CLK) if (CE) r <= { r[14:0], D };
end
else
always @(posedge CLK) if (CE) r <= { r[14:0], D };
endgenerate endgenerate
endmodule endmodule
module SRLC32E ( module SRLC32E (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
(* abc_arrival=1472 *)
output Q, output Q,
(* abc_arrival=1114 *)
output Q31, output Q31,
input [4:0] A, input [4:0] A,
input CE, CLK, D input CE,
(* clkbuf_sink *)
(* invertible_pin = "IS_CLK_INVERTED" *)
input CLK,
input D
); );
parameter [31:0] INIT = 32'h00000000; parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0; parameter [0:0] IS_CLK_INVERTED = 1'b0;

View File

@ -0,0 +1,708 @@
#!/usr/bin/env python3
from argparse import ArgumentParser
from io import StringIO
from enum import Enum, auto
import os.path
import sys
import re
class Cell:
def __init__(self, name, keep=False, port_attrs={}):
self.name = name
self.keep = keep
self.port_attrs = port_attrs
XC6S_CELLS = [
# Design elements types listed in Xilinx UG615.
# Advanced.
Cell('MCB'),
Cell('PCIE_A1'),
# Arithmetic functions.
Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}),
# Clock components.
# Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFIO2', port_attrs={'IOCLK': ['clkbuf_driver'], 'DIVCLK': ['clkbuf_driver']}),
Cell('BUFIO2_2CLK', port_attrs={'IOCLK': ['clkbuf_driver'], 'DIVCLK': ['clkbuf_driver']}),
Cell('BUFIO2FB', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFPLL_MCB', port_attrs={'IOCLK0': ['clkbuf_driver'], 'IOCLK1': ['clkbuf_driver']}),
Cell('DCM_CLKGEN'),
Cell('DCM_SP'),
Cell('PLL_BASE'),
# Config/BSCAN components.
Cell('BSCAN_SPARTAN6', keep=True),
Cell('DNA_PORT'),
Cell('ICAP_SPARTAN6', keep=True),
Cell('POST_CRC_INTERNAL'),
Cell('STARTUP_SPARTAN6', keep=True),
Cell('SUSPEND_SYNC', keep=True),
# I/O components.
Cell('GTPA1_DUAL'),
# Cell('IBUF', 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('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('IOBUF', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IODELAY2', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}),
Cell('IODRP2', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}),
Cell('IODRP2_MCB', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}),
Cell('ISERDES2', port_attrs={
'CLK0': ['clkbuf_sink'],
'CLK1': ['clkbuf_sink'],
'CLKDIV': ['clkbuf_sink'],
}),
Cell('KEEPER'),
# 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('OSERDES2', port_attrs={
'CLK0': ['clkbuf_sink'],
'CLK1': ['clkbuf_sink'],
'CLKDIV': ['clkbuf_sink'],
}),
Cell('PULLDOWN'),
Cell('PULLUP'),
# RAM/ROM.
#Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
# NOTE: not in the official library guide!
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']}),
# NOTE: not in the official library guide!
Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}),
# Cell('RAMB8BWER', port_attrs={'CLKAWRCLK': ['clkbuf_sink'], 'CLKBRDCLK': ['clkbuf_sink']}),
# Cell('RAMB16BWER', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}),
Cell('ROM128X1'),
Cell('ROM256X1'),
Cell('ROM32X1'),
Cell('ROM64X1'),
# Registers/latches.
# Cell('FDCE'),
# Cell('FDPE'),
# Cell('FDRE'),
# Cell('FDSE'),
Cell('IDDR2', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}),
Cell('LDCE'),
Cell('LDPE'),
Cell('ODDR2', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}),
# Slice/CLB primitives.
# Cell('CARRY4'),
Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('LUT1'),
# Cell('LUT2'),
# Cell('LUT3'),
# Cell('LUT4'),
# Cell('LUT5'),
# Cell('LUT6'),
# Cell('LUT6_2'),
# Cell('MUXF7'),
# Cell('MUXF8'),
# Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}),
]
XC6V_CELLS = [
# Design elements types listed in Xilinx UG623.
# Advanced.
Cell('PCIE_2_0'),
Cell('SYSMON'),
# Arithmetic functions.
Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}),
# Clock components.
# 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('BUFIODQS', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFR', port_attrs={'O': ['clkbuf_driver']}),
Cell('IBUFDS_GTXE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('MMCM_ADV'),
Cell('MMCM_BASE'),
# Config/BSCAN components.
Cell('BSCAN_VIRTEX6', keep=True),
Cell('CAPTURE_VIRTEX6', keep=True),
Cell('DNA_PORT'),
Cell('EFUSE_USR'),
Cell('FRAME_ECC_VIRTEX6'),
Cell('ICAP_VIRTEX6', keep=True),
Cell('STARTUP_VIRTEX6', keep=True),
Cell('USR_ACCESS_VIRTEX6'),
# I/O components.
Cell('DCIRESET', keep=True),
Cell('GTHE1_QUAD'),
Cell('GTXE1'),
# Cell('IBUF', 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_GTHE1', 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('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}),
Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IODELAYE1', port_attrs={'C': ['clkbuf_sink']}),
Cell('ISERDESE1', port_attrs={
'CLK': ['clkbuf_sink'],
'CLKB': ['clkbuf_sink'],
'OCLK': ['clkbuf_sink'],
'CLKDIV': ['clkbuf_sink'],
}),
Cell('KEEPER'),
# 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('OSERDESE1', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}),
Cell('PULLDOWN'),
Cell('PULLUP'),
Cell('TEMAC_SINGLE'),
# RAM/ROM.
Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
#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']}),
# NOTE: not in the official library guide!
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'),
# Registers/latches.
# Cell('FDCE'),
# Cell('FDPE'),
# Cell('FDRE'),
# Cell('FDSE'),
Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}),
Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}),
Cell('LDCE'),
Cell('LDPE'),
Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}),
# Slice/CLB primitives.
# Cell('CARRY4'),
Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('LUT1'),
# Cell('LUT2'),
# Cell('LUT3'),
# Cell('LUT4'),
# Cell('LUT5'),
# Cell('LUT6'),
# Cell('LUT6_2'),
# Cell('MUXF7'),
# Cell('MUXF8'),
# Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}),
]
XC7_CELLS = [
# Design elements types listed in Xilinx UG953.
# Advanced.
Cell('GTHE2_CHANNEL'),
Cell('GTHE2_COMMON'),
Cell('GTPE2_CHANNEL'),
Cell('GTPE2_COMMON'),
Cell('GTXE2_CHANNEL'),
Cell('GTXE2_COMMON'),
Cell('PCIE_2_1'),
Cell('PCIE_3_0'),
Cell('XADC'),
# Arithmetic functions.
Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}),
# Clock components.
# 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('MMCME2_ADV'),
Cell('MMCME2_BASE'),
Cell('PLLE2_ADV'),
Cell('PLLE2_BASE'),
# Config/BSCAN components.
Cell('BSCANE2', keep=True),
Cell('CAPTUREE2', keep=True),
Cell('DNA_PORT'),
Cell('EFUSE_USR'),
Cell('FRAME_ECCE2'),
Cell('ICAPE2', keep=True),
Cell('STARTUPE2', keep=True),
Cell('USR_ACCESSE2'),
# I/O components.
Cell('DCIRESET', keep=True),
# 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('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('IOBUFDS_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('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('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('PULLDOWN'),
Cell('PULLUP'),
# RAM/ROM.
Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
#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']}),
# NOTE: not in the official library guide!
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'),
# Registers/latches.
# Cell('FDCE'),
# Cell('FDPE'),
# Cell('FDRE'),
# Cell('FDSE'),
Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}),
Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}),
Cell('LDCE'),
Cell('LDPE'),
Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}),
# Slice/CLB primitives.
# Cell('CARRY4'),
Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('LUT1'),
# Cell('LUT2'),
# Cell('LUT3'),
# Cell('LUT4'),
# Cell('LUT5'),
# Cell('LUT6'),
# Cell('LUT6_2'),
# Cell('MUXF7'),
# Cell('MUXF8'),
# Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}),
# NOTE: not in the official library guide!
Cell('PS7', keep=True),
]
XCU_CELLS = [
# Design elements types listed in Xilinx UG974.
# Advanced.
Cell('CMAC'),
Cell('CMACE4'),
Cell('GTHE3_CHANNEL'),
Cell('GTHE3_COMMON'),
Cell('GTHE4_CHANNEL'),
Cell('GTHE4_COMMON'),
Cell('GTYE3_CHANNEL'),
Cell('GTYE3_COMMON'),
Cell('GTYE4_CHANNEL'),
Cell('GTYE4_COMMON'),
Cell('IBUFDS_GTE3', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFDS_GTE4', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('ILKN'),
Cell('ILKNE4'),
Cell('OBUFDS_GTE3', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
Cell('OBUFDS_GTE3_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
Cell('OBUFDS_GTE4', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
Cell('OBUFDS_GTE4_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
Cell('PCIE40E4'),
Cell('PCIE_3_1'),
Cell('SYSMONE1'),
Cell('SYSMONE4'),
# Arithmetic functions.
Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}),
# Blockram.
Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
Cell('FIFO36E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
Cell('RAMB18E2', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}),
Cell('RAMB36E2', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}),
Cell('URAM288', port_attrs={'CLK': ['clkbuf_sink']}),
Cell('URAM288_BASE', port_attrs={'CLK': ['clkbuf_sink']}),
# CLB.
# Cell('LUT6_2'),
#Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM256X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM32M16', port_attrs={'WCLK': ['clkbuf_sink']}),
#Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM512X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM64M8', port_attrs={'WCLK': ['clkbuf_sink']}),
#Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
Cell('AND2B1L'),
Cell('CARRY8'),
Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('LUT1'),
# Cell('LUT2'),
# Cell('LUT3'),
# Cell('LUT4'),
# Cell('LUT5'),
# Cell('LUT6'),
# Cell('MUXF7'),
# Cell('MUXF8'),
Cell('MUXF9'),
Cell('OR2L'),
# Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}),
# Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}),
# Clock.
# Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFG_GT', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFG_GT_SYNC'),
Cell('BUFG_PS', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}),
Cell('BUFGCE_DIV', 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('MMCME3_ADV'),
Cell('MMCME3_BASE'),
Cell('MMCME4_ADV'),
Cell('MMCME4_BASE'),
Cell('PLLE3_ADV'),
Cell('PLLE3_BASE'),
Cell('PLLE4_ADV'),
Cell('PLLE4_BASE'),
# Configuration.
Cell('BSCANE2', keep=True),
Cell('DNA_PORTE2'),
Cell('EFUSE_USR'),
Cell('FRAME_ECCE3'),
Cell('ICAPE3', keep=True),
Cell('MASTER_JTAG', keep=True),
Cell('STARTUPE3', keep=True),
Cell('USR_ACCESSE2'),
# I/O.
Cell('BITSLICE_CONTROL', keep=True),
Cell('DCIRESET', keep=True),
Cell('HPIO_VREF'),
# XXX
# Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}),
Cell('IBUF_ANALOG', 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_DPHY', 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('IBUFDSE3', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
Cell('IBUFE3', port_attrs={'I': ['iopad_external_pin']}),
Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}),
Cell('IDELAYE3', port_attrs={'CLK': ['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('IOBUFDS_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
Cell('IOBUFDSE3', port_attrs={'IO': ['iopad_external_pin']}),
Cell('IOBUFE3', port_attrs={'IO': ['iopad_external_pin']}),
Cell('ISERDESE3', port_attrs={
'CLK': ['clkbuf_sink'],
'CLK_B': ['clkbuf_sink'],
'FIFO_RD_CLK': ['clkbuf_sink'],
'CLKDIV': ['clkbuf_sink'],
}),
Cell('KEEPER'),
# Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}),
Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
Cell('OBUFDS_DPHY', 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('ODELAYE3', port_attrs={'CLK': ['clkbuf_sink']}),
Cell('OSERDESE3', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}),
Cell('PULLDOWN'),
Cell('PULLUP'),
Cell('RIU_OR'),
Cell('RX_BITSLICE'),
Cell('RXTX_BITSLICE'),
Cell('TX_BITSLICE'),
Cell('TX_BITSLICE_TRI'),
# Registers.
# Cell('FDCE'),
# Cell('FDPE'),
# Cell('FDRE'),
# Cell('FDSE'),
Cell('HARD_SYNC', port_attrs={'CLK': ['clkbuf_sink']}),
Cell('IDDRE1', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}),
Cell('LDCE'),
Cell('LDPE'),
Cell('ODDRE1', port_attrs={'C': ['clkbuf_sink']}),
# NOTE: not in the official library guide!
Cell('PS8', keep=True),
]
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.
module_ports = []
invertible_ports = set()
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:
for kind, rng, port in module_ports:
for attr in cell.port_attrs.get(port, []):
outf.write(' (* {} *)\n'.format(attr))
if port in invertible_ports:
outf.write(' (* invertible_pin = "IS_{}_INVERTED" *)\n'.format(port))
if rng is None:
outf.write(' {} {};\n'.format(kind, port))
else:
outf.write(' {} {} {};\n'.format(kind, rng, port))
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()
if port.startswith('['):
rng, port = port.split()
else:
rng = None
module_ports.append((kind, rng, 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))
match = re.search('IS_([a-zA-Z0-9_]+)_INVERTED', l)
if match:
invertible_ports.add(match[1])
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 ISE and Vivado.')
parser.add_argument('vivado_dir', nargs='?', default='/opt/Xilinx/Vivado/2018.1')
parser.add_argument('ise_dir', nargs='?', default='/opt/Xilinx/ISE/14.7')
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'),
os.path.join(args.ise_dir, 'ISE_DS/ISE/verilog/xeclib/unisims'),
]
for dir in dirs:
if not os.path.isdir(dir):
print('{} is not a directory'.format(dir))
for ofile, cells in [
('xc6s_cells_xtra.v', XC6S_CELLS),
('xc6v_cells_xtra.v', XC6V_CELLS),
('xc7_cells_xtra.v', XC7_CELLS),
('xcu_cells_xtra.v', XCU_CELLS),
]:
out = StringIO()
for cell in cells:
xtract_cell_decl(cell, dirs, out)
with open(ofile, 'w') as f:
f.write('// Created by cells_xtra.py from Xilinx models\n')
f.write('\n')
f.write(out.getvalue())

Some files were not shown because too many files have changed in this diff Show More