mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'master' of https://github.com/cliffordwolf/yosys
This commit is contained in:
commit
bdf6b2b19a
|
@ -11,9 +11,17 @@
|
|||
/qtcreator.creator.user
|
||||
/Makefile.conf
|
||||
/abc
|
||||
/viz.js
|
||||
/yosys
|
||||
/yosys.exe
|
||||
/yosys.js
|
||||
/yosys-abc
|
||||
/yosys-abc.exe
|
||||
/yosys-config
|
||||
/yosys-filterlib
|
||||
/yosys-filterlib.exe
|
||||
/kernel/version_*.cc
|
||||
/share
|
||||
/yosys-win32-mxebin-*
|
||||
/yosys-win32-vcxsrc-*
|
||||
/yosysjs-*
|
||||
|
|
132
CHANGELOG
132
CHANGELOG
|
@ -1,15 +1,133 @@
|
|||
|
||||
List of changes and major improvements between releases
|
||||
List of major changes and improvements between releases
|
||||
=======================================================
|
||||
|
||||
|
||||
Yosys 0.3.0 .. Yoys 0.3.0+
|
||||
--------------------------
|
||||
Yosys 0.4 .. Yosys 0.5
|
||||
----------------------
|
||||
|
||||
... TBD ...
|
||||
* API changes
|
||||
- Added log_warning()
|
||||
- Added eval_select_args() and eval_select_op()
|
||||
- Added cell->known(), cell->input(portname), cell->output(portname)
|
||||
- Skip blackbox modules in design->selected_modules()
|
||||
- Replaced std::map<> and std::set<> with dict<> and pool<>
|
||||
- New SigSpec::extend() is what used to be SigSpec::extend_u0()
|
||||
- Added YS_OVERRIDE, YS_FINAL, YS_ATTRIBUTE, YS_NORETURN
|
||||
|
||||
* Cell library changes
|
||||
- Added flip-flops with enable ($dffe etc.)
|
||||
- Added $equiv cells for equivalence checking framework
|
||||
|
||||
* Various
|
||||
- Updated ABC to hg rev 61ad5f908c03
|
||||
- Added clock domain partitioning to ABC pass
|
||||
- Improved plugin building (see "yosys-config --build")
|
||||
- Added ENABLE_NDEBUG Makefile flag for high-performance builds
|
||||
- Added "yosys -d", "yosys -L" and other driver improvements
|
||||
- Added support for multi-bit (array) cell ports to "write_edif"
|
||||
- Now printing most output to stdout, not stderr
|
||||
- Added "onehot" attribute (set by "fsm_map")
|
||||
- Various performance improvements
|
||||
- Vastly improved Xilinx flow
|
||||
- Added "make unsintall"
|
||||
|
||||
* Equivalence checking
|
||||
- Added equivalence checking commands:
|
||||
equiv_make equiv_simple equiv_status
|
||||
equiv_induct equiv_miter
|
||||
equiv_add equiv_remove
|
||||
|
||||
* Block RAM support:
|
||||
- Added "memory_bram" command
|
||||
- Added BRAM support to Xilinx flow
|
||||
|
||||
* Other New Commands and Options
|
||||
- Added "dff2dffe"
|
||||
- Added "fsm -encfile"
|
||||
- Added "dfflibmap -prepare"
|
||||
- Added "write_blid -unbuf -undef -blackbox"
|
||||
- Added "write_smt2" for writing SMT-LIBv2 files
|
||||
- Added "test_cell -w -muxdiv"
|
||||
- Added "select -read"
|
||||
|
||||
|
||||
Yosys 0.2.0 .. Yoys 0.3.0
|
||||
Yosys 0.3.0 .. Yosys 0.4
|
||||
------------------------
|
||||
|
||||
* Platform Support
|
||||
- Added support for mxe-based cross-builds for win32
|
||||
- Added sourcecode-export as VisualStudio project
|
||||
- Added experimental EMCC (JavaScript) support
|
||||
|
||||
* Verilog Frontend
|
||||
- Added -sv option for SystemVerilog (and automatic *.sv file support)
|
||||
- Added support for real-valued constants and constant expressions
|
||||
- Added support for non-standard "via_celltype" attribute on task/func
|
||||
- Added support for non-standard "module mod_name(...);" syntax
|
||||
- Added support for non-standard """ macro bodies
|
||||
- Added support for array with more than one dimension
|
||||
- Added support for $readmemh and $readmemb
|
||||
- Added support for DPI functions
|
||||
|
||||
* Changes in internal cell library
|
||||
- Added $shift and $shiftx cell types
|
||||
- Added $alu, $lcu, $fa and $macc cell types
|
||||
- Removed $bu0 and $safe_pmux cell types
|
||||
- $mem/$memwr WR_EN input is now a per-data-bit enable signal
|
||||
- Added $_NAND_ $_NOR_ $_XNOR_ $_AOI3_ $_OAI3_ $_AOI4_ $_OAI4_
|
||||
- Renamed ports of $lut cells (from I->O to A->Y)
|
||||
- Renamed $_INV_ to $_NOT_
|
||||
|
||||
* Changes for simple synthesis flows
|
||||
- There is now a "synth" command with a recommended default script
|
||||
- Many improvements in synthesis of arithmetic functions to gates
|
||||
- Multiplieres and adders with many operands are using carry-save adder trees
|
||||
- Remaining adders are now implemented using Brent–Kung carry look-ahead adders
|
||||
- Various new high-level optimizations on RTL netlist
|
||||
- Various improvements in FSM optimization
|
||||
- Updated ABC to hg 5b5af75f1dda (from 2014-11-07)
|
||||
|
||||
* Changes in internal APIs and RTLIL
|
||||
- Added log_id() and log_cell() helper functions
|
||||
- Added function-like cell creation helpers
|
||||
- Added GetSize() function (like .size() but with int)
|
||||
- Major refactoring of RTLIL::Module and related classes
|
||||
- Major refactoring of RTLIL::SigSpec and related classes
|
||||
- Now RTLIL::IdString is essentially an int
|
||||
- Added macros for code coverage counters
|
||||
- Added some Makefile magic for pretty make logs
|
||||
- Added "kernel/yosys.h" with all the core definitions
|
||||
- Chanded a lot of code from FILE* to c++ streams
|
||||
- Added RTLIL::Monitor API and "trace" command
|
||||
- Added "Yosys" C++ namespace
|
||||
|
||||
* Changes relevant to SAT solving
|
||||
- Added ezSAT::keep_cnf() and ezSAT::non_incremental()
|
||||
- Added native ezSAT support for vector shift ops
|
||||
- Updated MiniSAT to git 37dc6c67e2 (from 2013-09-25)
|
||||
|
||||
* New commands (or large improvements to commands)
|
||||
- Added "synth" command with default script
|
||||
- Added "share" (finally some real resource sharing)
|
||||
- Added "memory_share" (reduce number of ports on memories)
|
||||
- Added "wreduce" and "alumacc" commands
|
||||
- Added "opt -keepdc -fine -full -fast"
|
||||
- Added some "test_*" commands
|
||||
|
||||
* Various other changes
|
||||
- Added %D and %c select operators
|
||||
- Added support for labels in yosys scripts
|
||||
- Added support for here-documents in yosys scripts
|
||||
- Support "+/" prefix for files from proc_share_dir
|
||||
- Added "autoidx" statement to ilang language
|
||||
- Switched from "yosys-svgviewer" to "xdot"
|
||||
- Renamed "stdcells.v" to "techmap.v"
|
||||
- Various bug fixes and small improvements
|
||||
- Improved welcome and bye messages
|
||||
|
||||
|
||||
Yosys 0.2.0 .. Yosys 0.3.0
|
||||
--------------------------
|
||||
|
||||
* Driver program and overall behavior:
|
||||
|
@ -59,8 +177,8 @@ Yosys 0.2.0 .. Yoys 0.3.0
|
|||
- Various build fixes for OSX (Darwin) and OpenBSD
|
||||
|
||||
|
||||
Yosys 0.1.0 .. Yoys 0.2.0
|
||||
-------------------------
|
||||
Yosys 0.1.0 .. Yosys 0.2.0
|
||||
--------------------------
|
||||
|
||||
* Changes to the driver program:
|
||||
- Added "yosys -h" and "yosys -H"
|
||||
|
|
326
CodingReadme
326
CodingReadme
|
@ -1,31 +1,209 @@
|
|||
|
||||
This file contains some very brief documentation on things like programming APIs.
|
||||
Also consult the Yosys manual and the section about programming in the presentation.
|
||||
(Both can be downloaded as PDF from the yosys webpage.)
|
||||
|
||||
|
||||
--snip-- only the lines below this mark are included in the yosys manual --snip--
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
|
||||
Reading List
|
||||
------------
|
||||
Outline of a Yosys command
|
||||
--------------------------
|
||||
|
||||
To write Yosys C++ code you need to know at least the following classes in kernel/rtlil.h:
|
||||
Here is a the C++ code for a "hello_world" Yosys command (hello.cc):
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct HelloWorldPass : public Pass {
|
||||
HelloWorldPass() : Pass("hello_world") { }
|
||||
virtual void execute(vector<string>, Design*) {
|
||||
log("Hello World!\n");
|
||||
}
|
||||
} HelloWorldPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
||||
This can be built into a Yosys module using the following command:
|
||||
|
||||
yosys-config --exec --cxx --cxxflags --ldflags -o hello.so -shared hello.cc --ldlibs
|
||||
|
||||
Or short:
|
||||
|
||||
yosys-config --build hello.so hello.cc
|
||||
|
||||
And then executed using the following command:
|
||||
|
||||
yosys -m hello.so -p hello_world
|
||||
|
||||
|
||||
Yosys Data Structures
|
||||
---------------------
|
||||
|
||||
Here is a short list of data structures that you should make yourself familiar
|
||||
with before you write C++ code for Yosys. The following data structures are all
|
||||
defined when "kernel/yosys.h" is included and USING_YOSYS_NAMESPACE is used.
|
||||
|
||||
1. Yosys Container Classes
|
||||
|
||||
Yosys uses dict<K, T> and pool<T> as main container classes. dict<K, T> is
|
||||
essentially a replacement for std::unordered_map<K, T> and pool<T> is a
|
||||
replacement for std::unordered_set<T>. The main characteristics are:
|
||||
|
||||
- dict<K, T> and pool<T> are about 2x faster than the std containers
|
||||
|
||||
- references to elements in a dict<K, T> or pool<T> are invalidated by
|
||||
insert and remove operations (similar to std::vector<T> on push_back()).
|
||||
|
||||
- some iterators are invalidated by erase(). specifically, iterators
|
||||
that have not passed the erased element yet are invalidated. (erase()
|
||||
itself returns valid iterator to the next element.)
|
||||
|
||||
- no iterators are invalidated by insert(). elements are inserted at
|
||||
begin(). i.e. only a new iterator that starts at begin() will see the
|
||||
inserted elements.
|
||||
|
||||
- the method .count(key, iterator) is like .count(key) but only
|
||||
considers elements that can be reached via the iterator.
|
||||
|
||||
- iterators can be compared. it1 < it2 means that the position of t2
|
||||
can be reached via t1 but not vice versa.
|
||||
|
||||
- the method .sort() can be used to sort the elements in the container
|
||||
the container stays sorted until elements are added or removed.
|
||||
|
||||
- dict<K, T> and pool<T> will have the same order of iteration across
|
||||
all compilers, standard libraries and architectures.
|
||||
|
||||
In addition to dict<K, T> and pool<T> there is also an idict<K> that
|
||||
creates a bijective map from K to the integers. For example:
|
||||
|
||||
idict<string, 42> si;
|
||||
log("%d\n", si("hello")); // will print 42
|
||||
log("%d\n", si("world")); // will print 43
|
||||
log("%d\n", si.at("world")); // will print 43
|
||||
log("%d\n", si.at("dummy")); // will throw exception
|
||||
log("%s\n", si[42].c_str())); // will print hello
|
||||
log("%s\n", si[43].c_str())); // will print world
|
||||
log("%s\n", si[44].c_str())); // will throw exception
|
||||
|
||||
It is not possible to remove elements from an idict.
|
||||
|
||||
2. Standard STL data types
|
||||
|
||||
In Yosys we use std::vector<T> and std::string whenever applicable. When
|
||||
dict<K, T> and pool<T> are not suitable then std::map<K, T> and std::set<T>
|
||||
are used instead.
|
||||
|
||||
The types std::vector<T> and std::string are also available as vector<T>
|
||||
and string in the Yosys namespace.
|
||||
|
||||
3. RTLIL objects
|
||||
|
||||
The current design (essentially a collection of modules, each defined by a
|
||||
netlist) is stored in memory using RTLIL object (declared in kernel/rtlil.h,
|
||||
automatically included by kernel/yosys.h). You should glance over at least
|
||||
the declarations for the following types in kernel/rtlil.h:
|
||||
|
||||
RTLIL::IdString
|
||||
This is a handle for an identifier (e.g. cell or wire name).
|
||||
It feels a lot like a std::string, but is only a single int
|
||||
in size. (The actual string is stored in a global lookup
|
||||
table.)
|
||||
|
||||
RTLIL::SigBit
|
||||
A single signal bit. I.e. either a constant state (0, 1,
|
||||
x, z) or a single bit from a wire.
|
||||
|
||||
RTLIL::SigSpec
|
||||
Essentially a vector of SigBits.
|
||||
|
||||
RTLIL::Wire
|
||||
RTLIL::Cell
|
||||
The building blocks of the netlist in a module.
|
||||
|
||||
RTLIL::Module
|
||||
RTLIL::SigSpec
|
||||
RTLIL::Design
|
||||
The module is a container with connected cells and wires
|
||||
in it. The design is a container with modules in it.
|
||||
|
||||
All this types are also available without the RTLIL:: prefix in the Yosys
|
||||
namespace.
|
||||
|
||||
4. SigMap and other Helper Classes
|
||||
|
||||
There are a couple of additional helper classes that are in wide use
|
||||
in Yosys. Most importantly there is SigMap (declared in kernel/sigtools.h).
|
||||
|
||||
When a design has many wires in it that are connected to each other, then a
|
||||
single signal bit can have multiple valid names. The SigMap object can be used
|
||||
to map SigSpecs or SigBits to unique SigSpecs and SigBits that consistently
|
||||
only use one wire from such a group of connected wires. For example:
|
||||
|
||||
SigBit a = module->addWire(NEW_ID);
|
||||
SigBit b = module->addWire(NEW_ID);
|
||||
module->connect(a, b);
|
||||
|
||||
log("%d\n", a == b); // will print 0
|
||||
|
||||
SigMap sigmap(module);
|
||||
log("%d\n", sigmap(a) == sigmap(b)); // will print 1
|
||||
|
||||
|
||||
Using the RTLIL Netlist Format
|
||||
------------------------------
|
||||
|
||||
In the RTLIL netlist format the cell ports contain SigSpecs that point to the
|
||||
Wires. There are no references in the other direction. This has two direct
|
||||
consequences:
|
||||
|
||||
(1) It is very easy to go from cells to wires but hard to go in the other way.
|
||||
|
||||
(2) There is no danger in removing cells from the netlists, but removing wires
|
||||
can break the netlist format when there are still references to the wire
|
||||
somewhere in the netlist.
|
||||
|
||||
The solution to (1) is easy: Create custom indexes that allow you to make fast
|
||||
lookups for the wire-to-cell direction. You can either use existing generic
|
||||
index structures to do that (such as the ModIndex class) or write your own
|
||||
index. For many application it is simplest to construct a custom index. For
|
||||
example:
|
||||
|
||||
SigMap sigmap(module);
|
||||
dict<SigBit, Cell*> sigbit_to_driver_index;
|
||||
|
||||
for (auto cell : module->cells())
|
||||
for (auto &conn : cell->connections())
|
||||
if (cell->output(conn.first))
|
||||
for (auto bit : sigmap(conn.second))
|
||||
sigbit_to_driver_index[bit] = cell;
|
||||
|
||||
Regarding (2): There is a general theme in Yosys that you don't remove wires
|
||||
from the design. You can rename them, unconnect them, but you do not actually remove
|
||||
the Wire object from the module. Instead you let the "clean" command take care
|
||||
of the dangling wires. On the other hand it is safe to remove cells (as long as
|
||||
you make sure this does not invalidate a custom index you are using in your code).
|
||||
|
||||
|
||||
Example Code
|
||||
------------
|
||||
|
||||
The following yosys commands are a good starting point if you are looking for examples
|
||||
of how to use the Yosys API:
|
||||
|
||||
passes/opt/wreduce.cc
|
||||
passes/techmap/maccmap.cc
|
||||
manual/CHAPTER_Prog/stubnets.cc
|
||||
manual/PRESENTATION_Prog/my_cmd.cc
|
||||
|
||||
|
||||
Notes on the existing codebase
|
||||
------------------------------
|
||||
|
||||
For historical reasons not all parts of Yosys adhere to the current coding
|
||||
styles. When adding code to existing parts of the system, adhere to this guide
|
||||
style. When adding code to existing parts of the system, adhere to this guide
|
||||
for the new code instead of trying to mimic the style of the surrounding code.
|
||||
|
||||
|
||||
|
@ -58,15 +236,58 @@ C++ Langugage
|
|||
-------------
|
||||
|
||||
Yosys is written in C++11. At the moment only constructs supported by
|
||||
gcc 4.6 is allowed in Yosys code. This will change in future releases.
|
||||
gcc 4.6 are allowed in Yosys code. This will change in future releases.
|
||||
|
||||
In general Yosys uses "int" instead of "size_t". To avoid compiler
|
||||
warnings for implicit type casts, always use "SIZE(foobar)" instead
|
||||
of "foobar.size()". (the macro SIZE() is defined by kernel/yosys.h)
|
||||
warnings for implicit type casts, always use "GetSize(foobar)" instead
|
||||
of "foobar.size()". (GetSize() is defined in kernel/yosys.h)
|
||||
|
||||
Use range-based for loops whenever applicable.
|
||||
|
||||
|
||||
--snap-- only the lines above this mark are included in the yosys manual --snap--
|
||||
|
||||
|
||||
Creating the Visual Studio Template Project
|
||||
===========================================
|
||||
|
||||
1. Create an empty Visual C++ Win32 Console App project
|
||||
|
||||
Microsoft Visual Studio Express 2013 for Windows Desktop
|
||||
Open New Project Wizard (File -> New Project..)
|
||||
|
||||
Project Name: YosysVS
|
||||
Solution Name: YosysVS
|
||||
[X] Create directory for solution
|
||||
[ ] Add to source control
|
||||
|
||||
[X] Console applications
|
||||
[X] Empty Projcect
|
||||
[ ] SDL checks
|
||||
|
||||
2. Open YosysVS Project Properties
|
||||
|
||||
Select Configuration: All Configurations
|
||||
|
||||
C/C++ -> General -> Additional Include Directories
|
||||
Add: ..\yosys
|
||||
|
||||
C/C++ -> Preprocessor -> Preprocessor Definitions
|
||||
Add: _YOSYS_;_CRT_SECURE_NO_WARNINGS
|
||||
|
||||
3. Resulting file system tree:
|
||||
|
||||
YosysVS/
|
||||
YosysVS/YosysVS
|
||||
YosysVS/YosysVS/YosysVS.vcxproj
|
||||
YosysVS/YosysVS/YosysVS.vcxproj.filters
|
||||
YosysVS/YosysVS.sdf
|
||||
YosysVS/YosysVS.sln
|
||||
YosysVS/YosysVS.v12.suo
|
||||
|
||||
4. Zip YosysVS as YosysVS-Tpl-v1.zip
|
||||
|
||||
|
||||
|
||||
Checklist for adding internal cell types
|
||||
========================================
|
||||
|
@ -96,50 +317,45 @@ Update the CHANGELOG file:
|
|||
vi CHANGELOG
|
||||
|
||||
|
||||
Run all tests with "make config-{clang-debug,gcc-debug,gcc-4.6,release}":
|
||||
|
||||
cd ~yosys
|
||||
make clean
|
||||
make test vloghtb
|
||||
make install
|
||||
|
||||
cd ~yosys-bigsim
|
||||
make clean
|
||||
make full
|
||||
|
||||
cd ~vloghammer
|
||||
make purge
|
||||
make gen_issues gen_samples
|
||||
make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" FULL=1 world
|
||||
chromium-browser report.html
|
||||
|
||||
|
||||
Then with default config setting:
|
||||
|
||||
cd ~yosys
|
||||
./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
|
||||
./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
|
||||
Update and check documentation:
|
||||
|
||||
cd ~yosys
|
||||
make update-manual
|
||||
make manual
|
||||
- sanity check the figures in the appnotes and presentation
|
||||
- if there are any odd things -> investigate
|
||||
- make cosmetic changes to the .tex files if necessary
|
||||
|
||||
cd ~yosys
|
||||
vi README CodingReadme
|
||||
- is the information provided in those file still up to date
|
||||
|
||||
Also with default config setting:
|
||||
|
||||
Then with default config setting:
|
||||
|
||||
cd ~yosys
|
||||
make vgtest
|
||||
|
||||
cd ~yosys
|
||||
./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
|
||||
./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
|
||||
./yosys -p 'synth; show' tests/simple/fiedler-cooley.v
|
||||
./yosys -p 'synth_xilinx -top up3down5; show' tests/simple/fiedler-cooley.v
|
||||
|
||||
cd ~yosys/techlibs/cmos
|
||||
bash testbench.sh
|
||||
|
||||
cd ~yosys/techlibs/xilinx/example_sim_counter
|
||||
bash run_sim.sh
|
||||
|
||||
cd ~yosys/techlibs/xilinx/example_mojo_counter
|
||||
bash example.sh
|
||||
cd ~yosys/techlibs/xilinx/example_basys3
|
||||
bash run.sh
|
||||
|
||||
|
||||
Finally if a current verific library is available:
|
||||
Test building plugins with various of the standard passes:
|
||||
|
||||
yosys-config --build test.so equiv_simple.cc
|
||||
- also check the code examples in CodingReadme
|
||||
|
||||
|
||||
And if a version of the verific library is currently available:
|
||||
|
||||
cd ~yosys
|
||||
cat frontends/verific/build_amd64.txt
|
||||
|
@ -149,12 +365,22 @@ Finally if a current verific library is available:
|
|||
../../yosys test_navre.ys
|
||||
|
||||
|
||||
Release candiate:
|
||||
Finally run all tests with "make config-{clang,gcc,gcc-4.6}":
|
||||
|
||||
- create branch yosys-x.y.z-rc and push to github
|
||||
- contact the usual suspects per mail and ask them to test
|
||||
- post on the reddit and ask people to test
|
||||
- commit KISS fixes to the -rc branch if necessary
|
||||
cd ~yosys
|
||||
make clean
|
||||
make test
|
||||
make vloghtb
|
||||
make install
|
||||
|
||||
cd ~yosys-bigsim
|
||||
make clean
|
||||
make full
|
||||
|
||||
cd ~vloghammer
|
||||
make purge gen_issues gen_samples
|
||||
make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" REPORT_FULL=1 world
|
||||
chromium-browser report.html
|
||||
|
||||
|
||||
Release:
|
||||
|
@ -166,7 +392,6 @@ Release:
|
|||
- push tag to github
|
||||
- post changelog on github
|
||||
- post short release note on reddit
|
||||
- delete -rc branch from github
|
||||
|
||||
|
||||
Updating the website:
|
||||
|
@ -183,12 +408,3 @@ Updating the website:
|
|||
git commit -am update
|
||||
make push
|
||||
|
||||
|
||||
In master branch:
|
||||
|
||||
git merge {release-tag}
|
||||
- set version to x.y.z+ in Makefile
|
||||
- add section "Yosys x.y.z .. x.y.z+" to CHANGELOG
|
||||
git commit --amend -am "Yosys x.y.z+"
|
||||
|
||||
|
||||
|
|
201
Makefile
201
Makefile
|
@ -3,6 +3,7 @@ CONFIG := clang
|
|||
# CONFIG := gcc
|
||||
# CONFIG := gcc-4.6
|
||||
# CONFIG := emcc
|
||||
# CONFIG := mxe
|
||||
|
||||
# features (the more the better)
|
||||
ENABLE_TCL := 1
|
||||
|
@ -10,41 +11,53 @@ ENABLE_ABC := 1
|
|||
ENABLE_PLUGINS := 1
|
||||
ENABLE_READLINE := 1
|
||||
ENABLE_VERIFIC := 0
|
||||
ENABLE_COVER := 1
|
||||
|
||||
# other configuration flags
|
||||
ENABLE_GPROF := 0
|
||||
ENABLE_NDEBUG := 0
|
||||
|
||||
DESTDIR := /usr/local
|
||||
INSTALL_SUDO :=
|
||||
|
||||
TARGET_BINDIR := $(DESTDIR)/bin
|
||||
TARGET_DATDIR := $(DESTDIR)/share/yosys
|
||||
|
||||
EXE =
|
||||
OBJS =
|
||||
GENFILES =
|
||||
EXTRA_OBJS =
|
||||
EXTRA_TARGETS =
|
||||
TARGETS = yosys yosys-config
|
||||
TARGETS = yosys$(EXE) yosys-config
|
||||
|
||||
PRETTY = 1
|
||||
SMALL = 0
|
||||
|
||||
all: top-all
|
||||
|
||||
CXXFLAGS = -Wall -Wextra -ggdb -I"$(shell pwd)" -MD -DYOSYS_SRC='"$(shell pwd)"' -D_YOSYS_ -fPIC -I${DESTDIR}/include
|
||||
LDFLAGS = -L${DESTDIR}/lib
|
||||
YOSYS_SRC := $(shell pwd)
|
||||
CXXFLAGS = -Wall -Wextra -ggdb -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(DESTDIR)/include
|
||||
LDFLAGS = -L$(DESTDIR)/lib
|
||||
LDLIBS = -lstdc++ -lm
|
||||
QMAKE = qmake-qt4
|
||||
SED = sed
|
||||
BISON = bison
|
||||
|
||||
ifeq (Darwin,$(findstring Darwin,$(shell uname)))
|
||||
# add macports include and library path to search directories, don't use '-rdynamic' and '-lrt':
|
||||
CXXFLAGS += -I/opt/local/include
|
||||
LDFLAGS += -L/opt/local/lib
|
||||
QMAKE = qmake
|
||||
# add macports/homebrew include and library path to search directories, don't use '-rdynamic' and '-lrt':
|
||||
CXXFLAGS += -I/opt/local/include -I/usr/local/opt/readline/include
|
||||
LDFLAGS += -L/opt/local/lib -L/usr/local/opt/readline/lib
|
||||
# add homebrew's libffi include and library path
|
||||
CXXFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --cflags libffi)
|
||||
LDFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --libs libffi)
|
||||
# use bison installed by homebrew if available
|
||||
BISON = $(shell (brew list bison | grep -m1 "bin/bison") || echo bison)
|
||||
SED = gsed
|
||||
else
|
||||
LDFLAGS += -rdynamic
|
||||
LDLIBS += -lrt
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.3.0+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline ca125bf41.. | wc -l; })
|
||||
YOSYS_VER := 0.5+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline c3c9fbfb8c678.. | wc -l; })
|
||||
GIT_REV := $(shell git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
|
||||
OBJS = kernel/version_$(GIT_REV).o
|
||||
|
||||
|
@ -54,8 +67,9 @@ OBJS = kernel/version_$(GIT_REV).o
|
|||
# is just a symlink to your actual ABC working directory, as 'make mrproper'
|
||||
# will remove the 'abc' directory and you do not want to accidentally
|
||||
# delete your work on ABC..
|
||||
ABCREV = 4d547a5e065b
|
||||
ABCREV = 61ad5f908c03
|
||||
ABCPULL = 1
|
||||
ABCMKARGS = # CC="$(CXX)" CXX="$(CXX)"
|
||||
|
||||
define newline
|
||||
|
||||
|
@ -81,8 +95,42 @@ CXXFLAGS += -std=gnu++0x -Os
|
|||
|
||||
else ifeq ($(CONFIG),emcc)
|
||||
CXX = emcc
|
||||
CXXFLAGS += -std=c++11 -Os -Wno-warn-absolute-paths
|
||||
CXXFLAGS := $(filter-out -ggdb,$(CXXFLAGS))
|
||||
CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS))
|
||||
EMCCFLAGS := -Os -Wno-warn-absolute-paths
|
||||
EMCCFLAGS += --memory-init-file 0 --embed-file share -s NO_EXIT_RUNTIME=1
|
||||
EMCCFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg']"
|
||||
EMCCFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1
|
||||
# https://github.com/kripken/emscripten/blob/master/src/settings.js
|
||||
CXXFLAGS += $(EMCCFLAGS)
|
||||
LDFLAGS += $(EMCCFLAGS)
|
||||
LDLIBS =
|
||||
EXE = .js
|
||||
|
||||
TARGETS := $(filter-out yosys-config,$(TARGETS))
|
||||
EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip
|
||||
|
||||
viz.js:
|
||||
wget -O viz.js.part https://github.com/mdaines/viz.js/releases/download/0.0.3/viz.js
|
||||
mv viz.js.part viz.js
|
||||
|
||||
yosysjs-$(YOSYS_VER).zip: yosys.js viz.js misc/yosysjs/*
|
||||
rm -rf yosysjs-$(YOSYS_VER) yosysjs-$(YOSYS_VER).zip
|
||||
mkdir -p yosysjs-$(YOSYS_VER)
|
||||
cp viz.js misc/yosysjs/* yosys.js yosysjs-$(YOSYS_VER)/
|
||||
zip -r yosysjs-$(YOSYS_VER).zip yosysjs-$(YOSYS_VER)
|
||||
|
||||
yosys.html: misc/yosys.html
|
||||
$(P) cp misc/yosys.html yosys.html
|
||||
|
||||
else ifeq ($(CONFIG),mxe)
|
||||
CXX = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc
|
||||
CXXFLAGS += -std=gnu++0x -Os -D_POSIX_SOURCE
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
|
||||
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
||||
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -x c++ -fpermissive -w"
|
||||
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" READLINE=0 CC="$(CXX)" CXX="$(CXX)"
|
||||
EXE = .exe
|
||||
|
||||
else ifneq ($(CONFIG),none)
|
||||
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.6, emcc, none)
|
||||
|
@ -91,6 +139,9 @@ endif
|
|||
ifeq ($(ENABLE_READLINE),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_READLINE
|
||||
LDLIBS += -lreadline
|
||||
ifeq ($(CONFIG),mxe)
|
||||
LDLIBS += -lpdcurses
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_PLUGINS),1)
|
||||
|
@ -99,7 +150,7 @@ LDLIBS += $(shell pkg-config --silence-errors --libs libffi || echo -lffi) -ldl
|
|||
endif
|
||||
|
||||
ifeq ($(ENABLE_TCL),1)
|
||||
TCL_VERSION ?= tcl8.5
|
||||
TCL_VERSION ?= tcl$(shell echo 'puts [info tclversion]' | tclsh)
|
||||
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
|
||||
CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
|
||||
LDLIBS += -l$(TCL_VERSION)
|
||||
|
@ -110,9 +161,13 @@ CXXFLAGS += -pg
|
|||
LDFLAGS += -pg
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_NDEBUG),1)
|
||||
CXXFLAGS := -O3 -DNDEBUG $(filter-out -Os,$(CXXFLAGS))
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_ABC),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_ABC
|
||||
TARGETS += yosys-abc
|
||||
TARGETS += yosys-abc$(EXE)
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
|
@ -122,11 +177,26 @@ CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABL
|
|||
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS))
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_COVER),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_COVER
|
||||
endif
|
||||
|
||||
define add_share_file
|
||||
EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2)))
|
||||
$(subst //,/,$(1)/$(notdir $(2))): $(2)
|
||||
$$(P) mkdir -p $(1)
|
||||
$$(Q) cp $(2) $(subst //,/,$(1)/$(notdir $(2)))
|
||||
endef
|
||||
|
||||
define add_include_file
|
||||
$(eval $(call add_share_file,$(dir share/include/$(1)),$(1)))
|
||||
endef
|
||||
|
||||
ifeq ($(PRETTY), 1)
|
||||
P_STATUS = 0
|
||||
P_OFFSET = 0
|
||||
P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
|
||||
P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
|
||||
P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
|
||||
P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
|
||||
P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
|
||||
Q = @
|
||||
S = -s
|
||||
|
@ -137,7 +207,26 @@ Q =
|
|||
S =
|
||||
endif
|
||||
|
||||
$(eval $(call add_include_file,kernel/yosys.h))
|
||||
$(eval $(call add_include_file,kernel/hashlib.h))
|
||||
$(eval $(call add_include_file,kernel/log.h))
|
||||
$(eval $(call add_include_file,kernel/rtlil.h))
|
||||
$(eval $(call add_include_file,kernel/register.h))
|
||||
$(eval $(call add_include_file,kernel/celltypes.h))
|
||||
$(eval $(call add_include_file,kernel/consteval.h))
|
||||
$(eval $(call add_include_file,kernel/sigtools.h))
|
||||
$(eval $(call add_include_file,kernel/modtools.h))
|
||||
$(eval $(call add_include_file,kernel/macc.h))
|
||||
$(eval $(call add_include_file,kernel/utils.h))
|
||||
$(eval $(call add_include_file,kernel/satgen.h))
|
||||
$(eval $(call add_include_file,libs/ezsat/ezsat.h))
|
||||
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
|
||||
$(eval $(call add_include_file,libs/sha1/sha1.h))
|
||||
$(eval $(call add_include_file,passes/fsm/fsmdata.h))
|
||||
$(eval $(call add_include_file,backends/ilang/ilang_backend.h))
|
||||
|
||||
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
|
||||
kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
|
||||
|
||||
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
|
||||
OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o
|
||||
|
@ -192,8 +281,8 @@ top-all: $(TARGETS) $(EXTRA_TARGETS)
|
|||
@echo " Build successful."
|
||||
@echo ""
|
||||
|
||||
yosys: $(OBJS)
|
||||
$(P) $(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
|
||||
yosys$(EXE): $(OBJS)
|
||||
$(P) $(CXX) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
|
||||
|
||||
%.o: %.cc
|
||||
$(P) $(CXX) -o $@ -c $(CXXFLAGS) $<
|
||||
|
@ -203,15 +292,16 @@ yosys: $(OBJS)
|
|||
|
||||
kernel/version_$(GIT_REV).cc: Makefile
|
||||
$(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
|
||||
$(Q) echo "extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(CXX) ` \
|
||||
$(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\";" > kernel/version_$(GIT_REV).cc
|
||||
$(Q) echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) ` \
|
||||
$(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\"; }" > kernel/version_$(GIT_REV).cc
|
||||
|
||||
yosys-config: yosys-config.in
|
||||
$(P) $(SED) -e 's,@CXX@,$(CXX),;' -e 's,@CXXFLAGS@,$(CXXFLAGS),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
|
||||
-e 's,@BINDIR@,$(DESTDIR)/bin,;' -e 's,@DATDIR@,$(DESTDIR)/share/yosys,;' < yosys-config.in > yosys-config
|
||||
yosys-config: misc/yosys-config.in
|
||||
$(P) $(SED) -e 's,@CXXFLAGS@,$(subst -I"$(YOSYS_SRC)",-I"$(TARGET_DATDIR)/include",$(CXXFLAGS)),;' \
|
||||
-e 's,@CXX@,$(CXX),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
|
||||
-e 's,@BINDIR@,$(TARGET_BINDIR),;' -e 's,@DATDIR@,$(TARGET_DATDIR),;' < misc/yosys-config.in > yosys-config
|
||||
$(Q) chmod +x yosys-config
|
||||
|
||||
abc/abc-$(ABCREV):
|
||||
abc/abc-$(ABCREV)$(EXE):
|
||||
$(P)
|
||||
ifneq ($(ABCREV),default)
|
||||
$(Q) if ( cd abc 2> /dev/null && hg identify; ) | grep -q +; then \
|
||||
|
@ -219,20 +309,20 @@ ifneq ($(ABCREV),default)
|
|||
fi
|
||||
$(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
|
||||
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
|
||||
echo "Pulling ABC from bitbucket.org:"; \
|
||||
echo "Pulling ABC from bitbucket.org:"; set -x; \
|
||||
test -d abc || hg clone https://bitbucket.org/alanmi/abc abc; \
|
||||
cd abc && hg pull && hg update -r $(ABCREV); \
|
||||
cd abc && $(MAKE) DEP= clean && hg pull && hg update -r $(ABCREV); \
|
||||
fi
|
||||
endif
|
||||
$(Q) rm -f abc/abc-[0-9a-f]*
|
||||
$(Q) cd abc && $(MAKE) $(S) PROG="abc-$(ABCREV)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
|
||||
$(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) PROG="abc-$(ABCREV)$(EXE)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
|
||||
|
||||
ifeq ($(ABCREV),default)
|
||||
.PHONY: abc/abc-$(ABCREV)
|
||||
.PHONY: abc/abc-$(ABCREV)$(EXE)
|
||||
endif
|
||||
|
||||
yosys-abc: abc/abc-$(ABCREV)
|
||||
$(P) cp abc/abc-$(ABCREV) yosys-abc
|
||||
yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
|
||||
$(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE)
|
||||
|
||||
test: $(TARGETS) $(EXTRA_TARGETS)
|
||||
+cd tests/simple && bash run-test.sh
|
||||
|
@ -243,6 +333,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
|||
+cd tests/fsm && bash run-test.sh
|
||||
+cd tests/techmap && bash run-test.sh
|
||||
+cd tests/memories && bash run-test.sh
|
||||
+cd tests/bram && bash run-test.sh
|
||||
+cd tests/various && bash run-test.sh
|
||||
+cd tests/sat && bash run-test.sh
|
||||
@echo ""
|
||||
|
@ -252,7 +343,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
|||
VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
|
||||
|
||||
vgtest: $(TARGETS) $(EXTRA_TARGETS)
|
||||
$(VALGRIND) ./yosys -p 'setattr -mod -unset top; hierarchy; proc; opt; memory -nomap; opt -fine; techmap; opt' $$( ls tests/simple/*.v | grep -v repwhile.v )
|
||||
$(VALGRIND) ./yosys -p 'setattr -mod -unset top; synth' $$( ls tests/simple/*.v | grep -v repwhile.v )
|
||||
@echo ""
|
||||
@echo " Passed \"make vgtest\"."
|
||||
@echo ""
|
||||
|
@ -269,6 +360,13 @@ install: $(TARGETS) $(EXTRA_TARGETS)
|
|||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)/share/yosys
|
||||
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)/share/yosys/.
|
||||
|
||||
uninstall:
|
||||
$(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)/bin/,$(notdir $(TARGETS)))
|
||||
$(INSTALL_SUDO) rm -rvf $(DESTDIR)/share/yosys/
|
||||
|
||||
update-manual: $(TARGETS) $(EXTRA_TARGETS)
|
||||
cd manual && ../yosys -p 'help -write-tex-command-reference-manual'
|
||||
|
||||
manual: $(TARGETS) $(EXTRA_TARGETS)
|
||||
cd manual && bash appnotes.sh
|
||||
cd manual && bash presentation.sh
|
||||
|
@ -277,13 +375,13 @@ manual: $(TARGETS) $(EXTRA_TARGETS)
|
|||
clean:
|
||||
rm -rf share
|
||||
cd manual && bash clean.sh
|
||||
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS)
|
||||
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
|
||||
rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
|
||||
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
|
||||
|
||||
clean-abc:
|
||||
make -C abc clean
|
||||
rm -f yosys-abc abc/abc-[0-9a-f]*
|
||||
$(MAKE) -C abc DEP= clean
|
||||
rm -f yosys-abc$(EXE) abc/abc-[0-9a-f]*
|
||||
|
||||
mrproper: clean
|
||||
git clean -xdf
|
||||
|
@ -295,6 +393,29 @@ qtcreator:
|
|||
{ echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes
|
||||
touch qtcreator.config qtcreator.creator
|
||||
|
||||
vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
|
||||
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
|
||||
set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \
|
||||
echo "Analyse: $$f" >&2; cpp -std=gnu++0x -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
|
||||
bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV)
|
||||
echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc
|
||||
zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc
|
||||
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
|
||||
rm -f srcfiles.txt kernel/version.cc
|
||||
|
||||
ifeq ($(CONFIG),mxe)
|
||||
mxebin: $(TARGETS) $(EXTRA_TARGETS)
|
||||
rm -rf yosys-win32-mxebin-$(YOSYS_VER){,.zip}
|
||||
mkdir -p yosys-win32-mxebin-$(YOSYS_VER)
|
||||
cp -r yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
ifeq ($(ENABLE_ABC),1)
|
||||
cp -r yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
endif
|
||||
echo -en 'This is Yosys $(YOSYS_VER) for Win32.\r\n' > yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
|
||||
echo -en 'Documentation at http://www.clifford.at/yosys/.\r\n' >> yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
|
||||
zip -r yosys-win32-mxebin-$(YOSYS_VER).zip yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
endif
|
||||
|
||||
config-clean: clean
|
||||
rm -f Makefile.conf
|
||||
|
||||
|
@ -314,6 +435,12 @@ config-emcc: clean
|
|||
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
|
||||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||
|
||||
config-mxe: clean
|
||||
echo 'CONFIG := mxe' > Makefile.conf
|
||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
|
||||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||
|
||||
config-gprof: clean
|
||||
echo 'CONFIG := gcc' > Makefile.conf
|
||||
echo 'ENABLE_GPROF := 1' >> Makefile.conf
|
||||
|
@ -321,6 +448,12 @@ config-gprof: clean
|
|||
config-sudo:
|
||||
echo "INSTALL_SUDO := sudo" >> Makefile.conf
|
||||
|
||||
echo-yosys-ver:
|
||||
@echo "$(YOSYS_VER)"
|
||||
|
||||
echo-git-rev:
|
||||
@echo "$(GIT_REV)"
|
||||
|
||||
-include libs/*/*.d
|
||||
-include frontends/*/*.d
|
||||
-include passes/*/*.d
|
||||
|
|
65
README
65
README
|
@ -3,7 +3,7 @@
|
|||
| |
|
||||
| yosys -- Yosys Open SYnthesis Suite |
|
||||
| |
|
||||
| Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |
|
||||
| Copyright (C) 2012 - 2015 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 |
|
||||
|
@ -55,12 +55,13 @@ Xdot (graphviz) is used by the "show" command in yosys to display schematics.
|
|||
For example on Ubuntu Linux 14.04 LTS the following commands will install all
|
||||
prerequisites for building yosys:
|
||||
|
||||
$ yosys_deps="build-essential clang bison flex libreadline-dev
|
||||
tcl8.5-dev libffi-dev git mercurial graphviz xdot"
|
||||
$ yosys_deps="build-essential clang bison flex libreadline-dev gawk
|
||||
tcl-dev libffi-dev git mercurial graphviz xdot pkg-config"
|
||||
$ sudo apt-get install $yosys_deps
|
||||
|
||||
There are also pre-compiled packages for Yosys on Ubuntu. Visit the Yosys
|
||||
download page to learn more about this:
|
||||
There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
|
||||
as a source distribution for Visual Studio. Visit the Yosys download page for
|
||||
more information:
|
||||
|
||||
http://www.clifford.at/yosys/download.html
|
||||
|
||||
|
@ -248,11 +249,19 @@ Verilog Attributes and non-standard features
|
|||
is strongly recommended instead).
|
||||
|
||||
- The "nomem2reg" attribute on modules or arrays prohibits the
|
||||
automatic early conversion of arrays to separate registers.
|
||||
automatic early conversion of arrays to separate registers. This
|
||||
is potentially dangerous. Usually the front-end has good reasons
|
||||
for converting an array to a list of registers. Prohibiting this
|
||||
step will likely result in incorrect synthesis results.
|
||||
|
||||
- The "mem2reg" attribute on modules or arrays forces the early
|
||||
conversion of arrays to separate registers.
|
||||
|
||||
- The "nomeminit" attribute on modules or arrays prohibits the
|
||||
creation of initialized memories. This effectively puts "mem2reg"
|
||||
on all memories that are written to in an "initial" block and
|
||||
are not ROMs.
|
||||
|
||||
- The "nolatches" attribute on modules or always-blocks
|
||||
prohibits the generation of logic-loops for latches. Instead
|
||||
all not explicitly assigned values default to x-bits. This does
|
||||
|
@ -264,6 +273,9 @@ Verilog Attributes and non-standard features
|
|||
temporary variable within an always block. This is mostly used internally
|
||||
by yosys to synthesize verilog functions and access arrays.
|
||||
|
||||
- The "onehot" attribute on wires mark them as onehot state register. This
|
||||
is used for example for memory port sharing and set by the fsm_map pass.
|
||||
|
||||
- The "blackbox" attribute on modules is used to mark empty stub modules
|
||||
that have the same ports as the real thing but do not contain information
|
||||
on the internal configuration. This modules are only used by the synthesis
|
||||
|
@ -273,6 +285,11 @@ Verilog Attributes and non-standard features
|
|||
- The "keep" attribute on cells and wires is used to mark objects that should
|
||||
never be removed by the optimizer. This is used for example for cells that
|
||||
have hidden connections that are not part of the netlist, such as IO pads.
|
||||
Setting the "keep" attribute on a module has the same effect as setting it
|
||||
on all instances of the module.
|
||||
|
||||
- The "keep_hierarchy" attribute on cells and modules keeps the "flatten"
|
||||
command from flattening the indicated cells and modules.
|
||||
|
||||
- The "init" attribute on wires is set by the frontend when a register is
|
||||
initialized "FPGA-style" with 'reg foo = val'. It can be used during synthesis
|
||||
|
@ -289,7 +306,7 @@ Verilog Attributes and non-standard features
|
|||
by adding an empty {* *} statement.)
|
||||
|
||||
- Modules can be declared with "module mod_name(...);" (with three dots
|
||||
instead of a list of moudle ports). With this syntax it is sufficient
|
||||
instead of a list of module ports). With this syntax it is sufficient
|
||||
to simply declare a module port as 'input' or 'output' in the module
|
||||
body.
|
||||
|
||||
|
@ -354,40 +371,8 @@ from SystemVerilog:
|
|||
|
||||
- The "assert" statement from SystemVerilog is supported in its most basic
|
||||
form. In module context: "assert property (<expression>);" and within an
|
||||
always block: "assert(<expression>);". It is transformed to a $assert cell
|
||||
that is supported by the "sat" and "write_btor" commands.
|
||||
always block: "assert(<expression>);". It is transformed to a $assert cell.
|
||||
|
||||
- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
|
||||
"bit" are supported.
|
||||
|
||||
|
||||
Roadmap / Large-scale TODOs
|
||||
===========================
|
||||
|
||||
- Technology mapping for real-world applications
|
||||
- Improve Xilinx FGPA synthesis (RAMB, CARRY4, SLR, etc.)
|
||||
|
||||
- Implement SAT-based formal equivialence checker
|
||||
- Write equiv pass based on hint-based register mapping
|
||||
|
||||
- Re-implement Verilog frontend (far future)
|
||||
- cleaner (easier to use, harder to use wrong) AST format
|
||||
- pipeline of well structured AST transformations
|
||||
- true contextual name lookup
|
||||
|
||||
|
||||
Other Unsorted TODOs
|
||||
====================
|
||||
|
||||
- Implement missing Verilog 2005 features:
|
||||
|
||||
- Support for real (float) const. expressions and parameters
|
||||
- ROM modeling using $readmemh/$readmemb in "initial" blocks
|
||||
- Ignore what needs to be ignored (e.g. drive and charge strengths)
|
||||
- Check standard vs. implementation to identify missing features
|
||||
|
||||
- Miscellaneous TODO items:
|
||||
|
||||
- Add brief source code documentation to most passes and kernel code
|
||||
- Implement mux-to-tribuf pass and rebalance mixed mux/tribuf trees
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct BlifDumperConfig
|
||||
{
|
||||
bool icells_mode;
|
||||
|
@ -35,11 +38,14 @@ struct BlifDumperConfig
|
|||
bool impltf_mode;
|
||||
bool gates_mode;
|
||||
bool param_mode;
|
||||
bool attr_mode;
|
||||
bool blackbox_mode;
|
||||
|
||||
std::string buf_type, buf_in, buf_out;
|
||||
std::string true_type, true_out, false_type, false_out;
|
||||
std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types;
|
||||
std::string true_type, true_out, false_type, false_out, undef_type, undef_out;
|
||||
|
||||
BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false) { }
|
||||
BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false) { }
|
||||
};
|
||||
|
||||
struct BlifDumper
|
||||
|
@ -69,8 +75,11 @@ struct BlifDumper
|
|||
|
||||
const char *cstr(RTLIL::SigBit sig)
|
||||
{
|
||||
if (sig.wire == NULL)
|
||||
return sig == RTLIL::State::S1 ? "$true" : "$false";
|
||||
if (sig.wire == NULL) {
|
||||
if (sig == RTLIL::State::S0) return config->false_type == "-" ? config->false_out.c_str() : "$false";
|
||||
if (sig == RTLIL::State::S1) return config->true_type == "-" ? config->true_out.c_str() : "$true";
|
||||
return config->undef_type == "-" ? config->undef_out.c_str() : "$undef";
|
||||
}
|
||||
|
||||
std::string str = RTLIL::unescape_id(sig.wire->name);
|
||||
for (size_t i = 0; i < str.size(); i++)
|
||||
|
@ -95,6 +104,26 @@ struct BlifDumper
|
|||
return "subckt";
|
||||
}
|
||||
|
||||
void dump_params(const char *command, dict<IdString, Const> ¶ms)
|
||||
{
|
||||
for (auto ¶m : params) {
|
||||
f << stringf("%s %s ", command, RTLIL::id2cstr(param.first));
|
||||
if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
|
||||
std::string str = param.second.decode_string();
|
||||
f << stringf("\"");
|
||||
for (char ch : str)
|
||||
if (ch == '"' || ch == '\\')
|
||||
f << stringf("\\%c", ch);
|
||||
else if (ch < 32 || ch >= 127)
|
||||
f << stringf("\\%03o", ch);
|
||||
else
|
||||
f << stringf("%c", ch);
|
||||
f << stringf("\"\n");
|
||||
} else
|
||||
f << stringf("%s\n", param.second.as_string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void dump()
|
||||
{
|
||||
f << stringf("\n");
|
||||
|
@ -126,23 +155,44 @@ struct BlifDumper
|
|||
}
|
||||
f << stringf("\n");
|
||||
|
||||
if (module->get_bool_attribute("\\blackbox")) {
|
||||
f << stringf(".blackbox\n");
|
||||
f << stringf(".end\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!config->impltf_mode) {
|
||||
if (!config->false_type.empty())
|
||||
f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
|
||||
config->false_type.c_str(), config->false_out.c_str());
|
||||
else
|
||||
if (!config->false_type.empty()) {
|
||||
if (config->false_type != "-")
|
||||
f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
|
||||
config->false_type.c_str(), config->false_out.c_str());
|
||||
} else
|
||||
f << stringf(".names $false\n");
|
||||
if (!config->true_type.empty())
|
||||
f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
|
||||
config->true_type.c_str(), config->true_out.c_str());
|
||||
else
|
||||
if (!config->true_type.empty()) {
|
||||
if (config->true_type != "-")
|
||||
f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
|
||||
config->true_type.c_str(), config->true_out.c_str());
|
||||
} else
|
||||
f << stringf(".names $true\n1\n");
|
||||
if (!config->undef_type.empty()) {
|
||||
if (config->undef_type != "-")
|
||||
f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type),
|
||||
config->undef_type.c_str(), config->undef_out.c_str());
|
||||
} else
|
||||
f << stringf(".names $undef\n");
|
||||
}
|
||||
|
||||
for (auto &cell_it : module->cells_)
|
||||
{
|
||||
RTLIL::Cell *cell = cell_it.second;
|
||||
|
||||
if (config->unbuf_types.count(cell->type)) {
|
||||
auto portnames = config->unbuf_types.at(cell->type);
|
||||
f << stringf(".names %s %s\n1 1\n",
|
||||
cstr(cell->getPort(portnames.first)), cstr(cell->getPort(portnames.second)));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!config->icells_mode && cell->type == "$_NOT_") {
|
||||
f << stringf(".names %s %s\n0 1\n",
|
||||
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y")));
|
||||
|
@ -191,21 +241,21 @@ struct BlifDumper
|
|||
auto &inputs = cell->getPort("\\A");
|
||||
auto width = cell->parameters.at("\\WIDTH").as_int();
|
||||
log_assert(inputs.size() == width);
|
||||
for (int i = 0; i < inputs.size(); i++) {
|
||||
for (int i = width-1; i >= 0; i--) {
|
||||
f << stringf(" %s", cstr(inputs.extract(i, 1)));
|
||||
}
|
||||
auto &output = cell->getPort("\\Y");
|
||||
log_assert(output.size() == 1);
|
||||
f << stringf(" %s", cstr(output));
|
||||
f << stringf("\n");
|
||||
auto mask = cell->parameters.at("\\LUT").as_string();
|
||||
for (int i = 0; i < (1 << width); i++) {
|
||||
if (mask[i] == '0') continue;
|
||||
for (int j = width-1; j >= 0; j--) {
|
||||
f << ((i>>j)&1 ? '1' : '0');
|
||||
RTLIL::SigSpec mask = cell->parameters.at("\\LUT");
|
||||
for (int i = 0; i < (1 << width); i++)
|
||||
if (mask[i] == RTLIL::S1) {
|
||||
for (int j = width-1; j >= 0; j--) {
|
||||
f << ((i>>j)&1 ? '1' : '0');
|
||||
}
|
||||
f << " 1\n";
|
||||
}
|
||||
f << stringf(" %c\n", mask[i]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -220,23 +270,10 @@ struct BlifDumper
|
|||
}
|
||||
f << stringf("\n");
|
||||
|
||||
if (config->attr_mode)
|
||||
dump_params(".attr", cell->attributes);
|
||||
if (config->param_mode)
|
||||
for (auto ¶m : cell->parameters) {
|
||||
f << stringf(".param %s ", RTLIL::id2cstr(param.first));
|
||||
if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
|
||||
std::string str = param.second.decode_string();
|
||||
f << stringf("\"");
|
||||
for (char ch : str)
|
||||
if (ch == '"' || ch == '\\')
|
||||
f << stringf("\\%c", ch);
|
||||
else if (ch < 32 || ch >= 127)
|
||||
f << stringf("\\%03o", ch);
|
||||
else
|
||||
f << stringf("%c", ch);
|
||||
f << stringf("\"\n");
|
||||
} else
|
||||
f << stringf("%s\n", param.second.as_string().c_str());
|
||||
}
|
||||
dump_params(".param", cell->parameters);
|
||||
}
|
||||
|
||||
for (auto &conn : module->connections())
|
||||
|
@ -276,9 +313,17 @@ struct BlifBackend : public Backend {
|
|||
log(" -buf <cell-type> <in-port> <out-port>\n");
|
||||
log(" use cells of type <cell-type> with the specified port names for buffers\n");
|
||||
log("\n");
|
||||
log(" -unbuf <cell-type> <in-port> <out-port>\n");
|
||||
log(" replace buffer cells with the specified name and port names with\n");
|
||||
log(" a .names statement that models a buffer\n");
|
||||
log("\n");
|
||||
log(" -true <cell-type> <out-port>\n");
|
||||
log(" -false <cell-type> <out-port>\n");
|
||||
log(" use the specified cell types to drive nets that are constant 1 or 0\n");
|
||||
log(" -undef <cell-type> <out-port>\n");
|
||||
log(" use the specified cell types to drive nets that are constant 1, 0, or\n");
|
||||
log(" undefined. when '-' is used as <cell-type>, then <out-port> specifies\n");
|
||||
log(" the wire name to be used for the constant signal and no cell driving\n");
|
||||
log(" that wire is generated.\n");
|
||||
log("\n");
|
||||
log("The following options can be useful when the generated file is not going to be\n");
|
||||
log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n");
|
||||
|
@ -296,11 +341,17 @@ struct BlifBackend : public Backend {
|
|||
log(" do not generate buffers for connected wires. instead use the\n");
|
||||
log(" non-standard .conn statement.\n");
|
||||
log("\n");
|
||||
log(" -attr\n");
|
||||
log(" use the non-standard .attr statement to write cell attributes\n");
|
||||
log("\n");
|
||||
log(" -param\n");
|
||||
log(" use the non-standard .param statement to write module parameters\n");
|
||||
log(" use the non-standard .param statement to write cell parameters\n");
|
||||
log("\n");
|
||||
log(" -blackbox\n");
|
||||
log(" write blackbox cells with .blackbox statement.\n");
|
||||
log("\n");
|
||||
log(" -impltf\n");
|
||||
log(" do not write definitions for the $true and $false wires.\n");
|
||||
log(" do not write definitions for the $true, $false and $undef wires.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
|
@ -326,6 +377,13 @@ struct BlifBackend : public Backend {
|
|||
config.buf_out = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-unbuf" && argidx+3 < args.size()) {
|
||||
RTLIL::IdString unbuf_type = RTLIL::escape_id(args[++argidx]);
|
||||
RTLIL::IdString unbuf_in = RTLIL::escape_id(args[++argidx]);
|
||||
RTLIL::IdString unbuf_out = RTLIL::escape_id(args[++argidx]);
|
||||
config.unbuf_types[unbuf_type] = std::pair<RTLIL::IdString, RTLIL::IdString>(unbuf_in, unbuf_out);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-true" && argidx+2 < args.size()) {
|
||||
config.true_type = args[++argidx];
|
||||
config.true_out = args[++argidx];
|
||||
|
@ -336,6 +394,11 @@ struct BlifBackend : public Backend {
|
|||
config.false_out = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-undef" && argidx+2 < args.size()) {
|
||||
config.undef_type = args[++argidx];
|
||||
config.undef_out = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-icells") {
|
||||
config.icells_mode = true;
|
||||
continue;
|
||||
|
@ -352,6 +415,14 @@ struct BlifBackend : public Backend {
|
|||
config.param_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-attr") {
|
||||
config.attr_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-blackbox") {
|
||||
config.blackbox_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-impltf") {
|
||||
config.impltf_mode = true;
|
||||
continue;
|
||||
|
@ -372,7 +443,7 @@ struct BlifBackend : public Backend {
|
|||
for (auto module_it : design->modules_)
|
||||
{
|
||||
RTLIL::Module *module = module_it.second;
|
||||
if (module->get_bool_attribute("\\blackbox"))
|
||||
if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode)
|
||||
continue;
|
||||
|
||||
if (module->processes.size() != 0)
|
||||
|
@ -397,3 +468,4 @@ struct BlifBackend : public Backend {
|
|||
}
|
||||
} BlifBackend;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include <string>
|
||||
#include <math.h>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct BtorDumperConfig
|
||||
{
|
||||
bool subckt_mode;
|
||||
|
@ -476,7 +479,7 @@ struct BtorDumper
|
|||
log_assert(!(cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
|
||||
cell->type == "$ge" || cell->type == "$gt") || output_width == 1);
|
||||
bool l1_signed = cell->parameters.at(RTLIL::IdString("\\A_SIGNED")).as_bool();
|
||||
bool l2_signed = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
|
||||
bool l2_signed YS_ATTRIBUTE(unused) = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
|
||||
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
|
||||
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
|
||||
|
||||
|
@ -817,7 +820,7 @@ struct BtorDumper
|
|||
int input_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
|
||||
log_assert(input->size() == input_width);
|
||||
int input_line = dump_sigspec(input, input_width);
|
||||
const RTLIL::SigSpec* output = &cell->getPort(RTLIL::IdString("\\Y"));
|
||||
const RTLIL::SigSpec* output YS_ATTRIBUTE(unused) = &cell->getPort(RTLIL::IdString("\\Y"));
|
||||
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
|
||||
log_assert(output->size() == output_width);
|
||||
int offset = cell->parameters.at(RTLIL::IdString("\\OFFSET")).as_int();
|
||||
|
@ -1057,3 +1060,4 @@ struct BtorBackend : public Backend {
|
|||
}
|
||||
} BtorBackend;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str()
|
||||
#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str()
|
||||
|
||||
|
@ -108,7 +111,7 @@ struct EdifBackend : public Backend {
|
|||
log_header("Executing EDIF backend.\n");
|
||||
|
||||
std::string top_module_name;
|
||||
std::map<RTLIL::IdString, std::set<RTLIL::IdString>> lib_cell_ports;
|
||||
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
|
||||
CellTypes ct(design);
|
||||
EdifNames edif_names;
|
||||
|
||||
|
@ -147,12 +150,8 @@ struct EdifBackend : public Backend {
|
|||
RTLIL::Cell *cell = cell_it.second;
|
||||
if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
|
||||
lib_cell_ports[cell->type];
|
||||
for (auto p : cell->connections()) {
|
||||
if (p.second.size() > 1)
|
||||
log_error("Found multi-bit port %s on library cell %s.%s (%s): not supported in EDIF backend!\n",
|
||||
RTLIL::id2cstr(p.first), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
|
||||
lib_cell_ports[cell->type].insert(p.first);
|
||||
}
|
||||
for (auto p : cell->connections())
|
||||
lib_cell_ports[cell->type][p.first] = GetSize(p.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,12 +194,15 @@ struct EdifBackend : public Backend {
|
|||
for (auto &port_it : cell_it.second) {
|
||||
const char *dir = "INOUT";
|
||||
if (ct.cell_known(cell_it.first)) {
|
||||
if (!ct.cell_output(cell_it.first, port_it))
|
||||
if (!ct.cell_output(cell_it.first, port_it.first))
|
||||
dir = "INPUT";
|
||||
else if (!ct.cell_input(cell_it.first, port_it))
|
||||
else if (!ct.cell_input(cell_it.first, port_it.first))
|
||||
dir = "OUTPUT";
|
||||
}
|
||||
*f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it), dir);
|
||||
if (port_it.second == 1)
|
||||
*f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it.first), dir);
|
||||
else
|
||||
*f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEF(port_it.first), port_it.second, dir);
|
||||
}
|
||||
*f << stringf(" )\n");
|
||||
*f << stringf(" )\n");
|
||||
|
@ -300,12 +302,12 @@ struct EdifBackend : public Backend {
|
|||
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
|
||||
hex_string = std::string(digit_str) + hex_string;
|
||||
}
|
||||
*f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), hex_string.c_str());
|
||||
*f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(p.first), GetSize(p.second.bits), hex_string.c_str());
|
||||
}
|
||||
*f << stringf(")\n");
|
||||
for (auto &p : cell->connections()) {
|
||||
RTLIL::SigSpec sig = sigmap(p.second);
|
||||
for (int i = 0; i < SIZE(sig); i++)
|
||||
for (int i = 0; i < GetSize(sig); i++)
|
||||
if (sig.size() == 1)
|
||||
net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)));
|
||||
else
|
||||
|
@ -345,3 +347,4 @@ struct EdifBackend : public Backend {
|
|||
}
|
||||
} EdifBackend;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
#include "kernel/yosys.h"
|
||||
#include <errno.h>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
using namespace ILANG_BACKEND;
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
|
||||
{
|
||||
|
@ -101,7 +103,7 @@ void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
|
|||
dump_sigchunk(f, sig.as_chunk(), autoint);
|
||||
} else {
|
||||
f << stringf("{ ");
|
||||
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
|
||||
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
|
||||
dump_sigchunk(f, *it, false);
|
||||
f << stringf(" ");
|
||||
}
|
||||
|
@ -111,11 +113,9 @@ void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
|
|||
|
||||
void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
|
||||
{
|
||||
std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(wire->attributes.begin(), wire->attributes.end());
|
||||
|
||||
for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
|
||||
dump_const(f, it->second);
|
||||
for (auto &it : wire->attributes) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
|
||||
dump_const(f, it.second);
|
||||
f << stringf("\n");
|
||||
}
|
||||
f << stringf("%s" "wire ", indent.c_str());
|
||||
|
@ -136,11 +136,9 @@ void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::
|
|||
|
||||
void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
|
||||
{
|
||||
std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(memory->attributes.begin(), memory->attributes.end());
|
||||
|
||||
for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
|
||||
dump_const(f, it->second);
|
||||
for (auto &it : memory->attributes) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
|
||||
dump_const(f, it.second);
|
||||
f << stringf("\n");
|
||||
}
|
||||
f << stringf("%s" "memory ", indent.c_str());
|
||||
|
@ -148,29 +146,27 @@ void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL
|
|||
f << stringf("width %d ", memory->width);
|
||||
if (memory->size != 0)
|
||||
f << stringf("size %d ", memory->size);
|
||||
if (memory->start_offset != 0)
|
||||
f << stringf("offset %d ", memory->start_offset);
|
||||
f << stringf("%s\n", memory->name.c_str());
|
||||
}
|
||||
|
||||
void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
|
||||
{
|
||||
std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(cell->attributes.begin(), cell->attributes.end());
|
||||
std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_parameters(cell->parameters.begin(), cell->parameters.end());
|
||||
std::map<RTLIL::IdString, RTLIL::SigSpec, RTLIL::sort_by_id_str> sorted_connections(cell->connections().begin(), cell->connections().end());
|
||||
|
||||
for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
|
||||
dump_const(f, it->second);
|
||||
for (auto &it : cell->attributes) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
|
||||
dump_const(f, it.second);
|
||||
f << stringf("\n");
|
||||
}
|
||||
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
|
||||
for (auto it = sorted_parameters.begin(); it != sorted_parameters.end(); it++) {
|
||||
f << stringf("%s parameter%s %s ", indent.c_str(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it->first.c_str());
|
||||
dump_const(f, it->second);
|
||||
for (auto &it : cell->parameters) {
|
||||
f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str());
|
||||
dump_const(f, it.second);
|
||||
f << stringf("\n");
|
||||
}
|
||||
for (auto it = sorted_connections.begin(); it != sorted_connections.end(); it++) {
|
||||
f << stringf("%s connect %s ", indent.c_str(), it->first.c_str());
|
||||
dump_sigspec(f, it->second);
|
||||
for (auto &it : cell->connections()) {
|
||||
f << stringf("%s connect %s ", indent.c_str(), it.first.c_str());
|
||||
dump_sigspec(f, it.second);
|
||||
f << stringf("\n");
|
||||
}
|
||||
f << stringf("%s" "end\n", indent.c_str());
|
||||
|
@ -178,7 +174,7 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
|
|||
|
||||
void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
|
||||
{
|
||||
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
|
||||
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it)
|
||||
{
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, it->first);
|
||||
|
@ -187,13 +183,13 @@ void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, con
|
|||
f << stringf("\n");
|
||||
}
|
||||
|
||||
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
|
||||
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
|
||||
dump_proc_switch(f, indent, *it);
|
||||
}
|
||||
|
||||
void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw)
|
||||
{
|
||||
for (auto it = sw->attributes.begin(); it != sw->attributes.end(); it++) {
|
||||
for (auto it = sw->attributes.begin(); it != sw->attributes.end(); ++it) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
|
||||
dump_const(f, it->second);
|
||||
f << stringf("\n");
|
||||
|
@ -203,7 +199,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
|
|||
dump_sigspec(f, sw->signal);
|
||||
f << stringf("\n");
|
||||
|
||||
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++)
|
||||
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it)
|
||||
{
|
||||
f << stringf("%s case ", indent.c_str());
|
||||
for (size_t i = 0; i < (*it)->compare.size(); i++) {
|
||||
|
@ -235,7 +231,7 @@ void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
|
|||
case RTLIL::STi: f << stringf("init\n"); break;
|
||||
}
|
||||
|
||||
for (auto it = sy->actions.begin(); it != sy->actions.end(); it++) {
|
||||
for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) {
|
||||
f << stringf("%s update ", indent.c_str());
|
||||
dump_sigspec(f, it->first);
|
||||
f << stringf(" ");
|
||||
|
@ -246,14 +242,14 @@ void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
|
|||
|
||||
void ILANG_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc)
|
||||
{
|
||||
for (auto it = proc->attributes.begin(); it != proc->attributes.end(); it++) {
|
||||
for (auto it = proc->attributes.begin(); it != proc->attributes.end(); ++it) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
|
||||
dump_const(f, it->second);
|
||||
f << stringf("\n");
|
||||
}
|
||||
f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str());
|
||||
dump_proc_case_body(f, indent + " ", &proc->root_case);
|
||||
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
|
||||
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
|
||||
dump_proc_sync(f, indent + " ", *it);
|
||||
f << stringf("%s" "end\n", indent.c_str());
|
||||
}
|
||||
|
@ -274,7 +270,7 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
|
|||
|
||||
if (print_header)
|
||||
{
|
||||
for (auto it = module->attributes.begin(); it != module->attributes.end(); it++) {
|
||||
for (auto it = module->attributes.begin(); it != module->attributes.end(); ++it) {
|
||||
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
|
||||
dump_const(f, it->second);
|
||||
f << stringf("\n");
|
||||
|
@ -285,56 +281,36 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
|
|||
|
||||
if (print_body)
|
||||
{
|
||||
std::vector<RTLIL::Wire*> sorted_wires;
|
||||
for (auto it : module->wires())
|
||||
sorted_wires.push_back(it);
|
||||
std::sort(sorted_wires.begin(), sorted_wires.end(), RTLIL::sort_by_name_str<RTLIL::Wire>());
|
||||
|
||||
std::vector<RTLIL::Memory*> sorted_memories;
|
||||
for (auto it : module->memories)
|
||||
sorted_memories.push_back(it.second);
|
||||
std::sort(sorted_memories.begin(), sorted_memories.end(), RTLIL::sort_by_name_str<RTLIL::Memory>());
|
||||
|
||||
std::vector<RTLIL::Cell*> sorted_cells;
|
||||
for (auto it : module->cells())
|
||||
sorted_cells.push_back(it);
|
||||
std::sort(sorted_cells.begin(), sorted_cells.end(), RTLIL::sort_by_name_str<RTLIL::Cell>());
|
||||
|
||||
std::vector<RTLIL::Process*> sorted_processes;
|
||||
for (auto it : module->processes)
|
||||
sorted_processes.push_back(it.second);
|
||||
std::sort(sorted_processes.begin(), sorted_processes.end(), RTLIL::sort_by_name_str<RTLIL::Process>());
|
||||
|
||||
for (auto it : sorted_wires)
|
||||
if (!only_selected || design->selected(module, it)) {
|
||||
if (only_selected)
|
||||
f << stringf("\n");
|
||||
dump_wire(f, indent + " ", it);
|
||||
}
|
||||
|
||||
for (auto it : sorted_memories)
|
||||
if (!only_selected || design->selected(module, it)) {
|
||||
for (auto it : module->memories)
|
||||
if (!only_selected || design->selected(module, it.second)) {
|
||||
if (only_selected)
|
||||
f << stringf("\n");
|
||||
dump_memory(f, indent + " ", it);
|
||||
dump_memory(f, indent + " ", it.second);
|
||||
}
|
||||
|
||||
for (auto it : sorted_cells)
|
||||
for (auto it : module->cells())
|
||||
if (!only_selected || design->selected(module, it)) {
|
||||
if (only_selected)
|
||||
f << stringf("\n");
|
||||
dump_cell(f, indent + " ", it);
|
||||
}
|
||||
|
||||
for (auto it : sorted_processes)
|
||||
if (!only_selected || design->selected(module, it)) {
|
||||
for (auto it : module->processes)
|
||||
if (!only_selected || design->selected(module, it.second)) {
|
||||
if (only_selected)
|
||||
f << stringf("\n");
|
||||
dump_proc(f, indent + " ", it);
|
||||
dump_proc(f, indent + " ", it.second);
|
||||
}
|
||||
|
||||
bool first_conn_line = true;
|
||||
for (auto it = module->connections().begin(); it != module->connections().end(); it++) {
|
||||
for (auto it = module->connections().begin(); it != module->connections().end(); ++it) {
|
||||
bool show_conn = !only_selected;
|
||||
if (only_selected) {
|
||||
RTLIL::SigSpec sigs = it->first;
|
||||
|
@ -360,11 +336,13 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
|
|||
|
||||
void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
int init_autoidx = autoidx;
|
||||
#endif
|
||||
|
||||
if (!flag_m) {
|
||||
int count_selected_mods = 0;
|
||||
for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
|
||||
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
|
||||
if (design->selected_whole_module(it->first))
|
||||
flag_m = true;
|
||||
if (design->selected(it->second))
|
||||
|
@ -380,7 +358,7 @@ void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
|
|||
f << stringf("autoidx %d\n", autoidx);
|
||||
}
|
||||
|
||||
for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
|
||||
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
|
||||
if (!only_selected || design->selected(it->second)) {
|
||||
if (only_selected)
|
||||
f << stringf("\n");
|
||||
|
@ -391,6 +369,9 @@ void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
|
|||
log_assert(init_autoidx == autoidx);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct IlangBackend : public Backend {
|
||||
IlangBackend() : Backend("ilang", "write design to ilang file") { }
|
||||
virtual void help()
|
||||
|
@ -423,6 +404,8 @@ struct IlangBackend : public Backend {
|
|||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
design->sort();
|
||||
|
||||
log("Output filename: %s\n", filename.c_str());
|
||||
*f << stringf("# Generated by %s\n", yosys_version_str);
|
||||
ILANG_BACKEND::dump_design(*f, design, selected, true, false);
|
||||
|
@ -447,10 +430,10 @@ struct DumpPass : public Pass {
|
|||
log(" -n\n");
|
||||
log(" only dump the module headers if the entire module is selected\n");
|
||||
log("\n");
|
||||
log(" -outfile <filename>\n");
|
||||
log(" -o <filename>\n");
|
||||
log(" write to the specified file.\n");
|
||||
log("\n");
|
||||
log(" -append <filename>\n");
|
||||
log(" -a <filename>\n");
|
||||
log(" like -outfile but append instead of overwrite\n");
|
||||
log("\n");
|
||||
}
|
||||
|
@ -463,12 +446,12 @@ struct DumpPass : public Pass {
|
|||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
std::string arg = args[argidx];
|
||||
if (arg == "-outfile" && argidx+1 < args.size()) {
|
||||
if ((arg == "-o" || arg == "-outfile") && argidx+1 < args.size()) {
|
||||
filename = args[++argidx];
|
||||
append = false;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-append" && argidx+1 < args.size()) {
|
||||
if ((arg == "-a" || arg == "-append") && argidx+1 < args.size()) {
|
||||
filename = args[++argidx];
|
||||
append = true;
|
||||
continue;
|
||||
|
@ -510,3 +493,4 @@ struct DumpPass : public Pass {
|
|||
}
|
||||
} DumpPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
static std::string netname(std::set<std::string> &conntypes_code, std::set<std::string> &celltypes_code, std::set<std::string> &constcells_code, RTLIL::SigSpec sig)
|
||||
{
|
||||
|
@ -215,3 +217,4 @@ struct IntersynthBackend : public Backend {
|
|||
}
|
||||
} IntersynthBackend;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
OBJS += backends/json/json.o
|
||||
|
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* 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/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct JsonWriter
|
||||
{
|
||||
std::ostream &f;
|
||||
bool use_selection;
|
||||
|
||||
Design *design;
|
||||
Module *module;
|
||||
|
||||
SigMap sigmap;
|
||||
int sigidcounter;
|
||||
dict<SigBit, string> sigids;
|
||||
|
||||
JsonWriter(std::ostream &f, bool use_selection) : f(f), use_selection(use_selection) { }
|
||||
|
||||
string get_string(string str)
|
||||
{
|
||||
string newstr = "\"";
|
||||
for (char c : str) {
|
||||
if (c == '\\')
|
||||
newstr += c;
|
||||
newstr += c;
|
||||
}
|
||||
return newstr + "\"";
|
||||
}
|
||||
|
||||
string get_name(IdString name)
|
||||
{
|
||||
return get_string(RTLIL::unescape_id(name));
|
||||
}
|
||||
|
||||
string get_bits(SigSpec sig)
|
||||
{
|
||||
bool first = true;
|
||||
string str = "[";
|
||||
for (auto bit : sigmap(sig)) {
|
||||
str += first ? " " : ", ";
|
||||
first = false;
|
||||
if (sigids.count(bit) == 0) {
|
||||
string &s = sigids[bit];
|
||||
if (bit.wire == nullptr) {
|
||||
if (bit == State::S0) s = "\"0\"";
|
||||
else if (bit == State::S1) s = "\"1\"";
|
||||
else if (bit == State::Sz) s = "\"z\"";
|
||||
else s = "\"x\"";
|
||||
} else
|
||||
s = stringf("%d", sigidcounter++);
|
||||
}
|
||||
str += sigids[bit];
|
||||
}
|
||||
return str + " ]";
|
||||
}
|
||||
|
||||
void write_parameters(const dict<IdString, Const> ¶meters)
|
||||
{
|
||||
bool first = true;
|
||||
for (auto ¶m : parameters) {
|
||||
f << stringf("%s\n", first ? "" : ",");
|
||||
f << stringf(" %s: ", get_name(param.first).c_str());
|
||||
if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
|
||||
f << get_string(param.second.decode_string());
|
||||
else if (GetSize(param.second.bits) > 32)
|
||||
f << get_string(param.second.as_string());
|
||||
else
|
||||
f << stringf("%d", param.second.as_int());
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
void write_module(Module *module_)
|
||||
{
|
||||
module = module_;
|
||||
log_assert(module->design == design);
|
||||
sigmap.set(module);
|
||||
sigids.clear();
|
||||
|
||||
// reserve 0 and 1 to avoid confusion with "0" and "1"
|
||||
sigidcounter = 2;
|
||||
|
||||
f << stringf(" %s: {\n", get_name(module->name).c_str());
|
||||
|
||||
f << stringf(" \"ports\": {");
|
||||
bool first = true;
|
||||
for (auto n : module->ports) {
|
||||
Wire *w = module->wire(n);
|
||||
if (use_selection && !module->selected(w))
|
||||
continue;
|
||||
f << stringf("%s\n", first ? "" : ",");
|
||||
f << stringf(" %s: {\n", get_name(n).c_str());
|
||||
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
|
||||
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
|
||||
f << stringf(" }");
|
||||
first = false;
|
||||
}
|
||||
f << stringf("\n },\n");
|
||||
|
||||
f << stringf(" \"cells\": {");
|
||||
first = true;
|
||||
for (auto c : module->cells()) {
|
||||
if (use_selection && !module->selected(c))
|
||||
continue;
|
||||
f << stringf("%s\n", first ? "" : ",");
|
||||
f << stringf(" %s: {\n", get_name(c->name).c_str());
|
||||
f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
|
||||
f << stringf(" \"type\": %s,\n", get_name(c->type).c_str());
|
||||
f << stringf(" \"parameters\": {");
|
||||
write_parameters(c->parameters);
|
||||
f << stringf("\n },\n");
|
||||
f << stringf(" \"attributes\": {");
|
||||
write_parameters(c->attributes);
|
||||
f << stringf("\n },\n");
|
||||
f << stringf(" \"connections\": {");
|
||||
bool first2 = true;
|
||||
for (auto &conn : c->connections()) {
|
||||
f << stringf("%s\n", first2 ? "" : ",");
|
||||
f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
|
||||
first2 = false;
|
||||
}
|
||||
f << stringf("\n }\n");
|
||||
f << stringf(" }");
|
||||
first = false;
|
||||
}
|
||||
f << stringf("\n },\n");
|
||||
|
||||
f << stringf(" \"netnames\": {");
|
||||
first = true;
|
||||
for (auto w : module->wires()) {
|
||||
if (use_selection && !module->selected(w))
|
||||
continue;
|
||||
f << stringf("%s\n", first ? "" : ",");
|
||||
f << stringf(" %s: {\n", get_name(w->name).c_str());
|
||||
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
|
||||
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
|
||||
f << stringf(" \"attributes\": {");
|
||||
write_parameters(w->attributes);
|
||||
f << stringf("\n }\n");
|
||||
f << stringf(" }");
|
||||
first = false;
|
||||
}
|
||||
f << stringf("\n }\n");
|
||||
|
||||
f << stringf(" }");
|
||||
}
|
||||
|
||||
void write_design(Design *design_)
|
||||
{
|
||||
design = design_;
|
||||
f << stringf("{\n");
|
||||
f << stringf(" \"creator\": %s,\n", get_string(yosys_version_str).c_str());
|
||||
f << stringf(" \"modules\": {\n");
|
||||
vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
|
||||
bool first_module = true;
|
||||
for (auto mod : modules) {
|
||||
if (!first_module)
|
||||
f << stringf(",\n");
|
||||
write_module(mod);
|
||||
first_module = false;
|
||||
}
|
||||
f << stringf("\n }\n");
|
||||
f << stringf("}\n");
|
||||
}
|
||||
};
|
||||
|
||||
struct JsonBackend : public Backend {
|
||||
JsonBackend() : Backend("json", "write design to a JSON file") { }
|
||||
virtual void help()
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" write_json [options] [filename]\n");
|
||||
log("\n");
|
||||
log("Write a JSON netlist of the current design.\n");
|
||||
log("\n");
|
||||
log("The general syntax of the JSON output created by this command is as follows:\n");
|
||||
log("\n");
|
||||
log(" {\n");
|
||||
log(" \"modules\": {\n");
|
||||
log(" <module_name>: {\n");
|
||||
log(" \"ports\": {\n");
|
||||
log(" <port_name>: <port_details>,\n");
|
||||
log(" ...\n");
|
||||
log(" },\n");
|
||||
log(" \"cells\": {\n");
|
||||
log(" <cell_name>: <cell_details>,\n");
|
||||
log(" ...\n");
|
||||
log(" },\n");
|
||||
log(" \"netnames\": {\n");
|
||||
log(" <net_name>: <net_details>,\n");
|
||||
log(" ...\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log("\n");
|
||||
log("Where <port_details> is:\n");
|
||||
log("\n");
|
||||
log(" {\n");
|
||||
log(" \"direction\": <\"input\" | \"output\" | \"inout\">,\n");
|
||||
log(" \"bits\": <bit_vector>\n");
|
||||
log(" }\n");
|
||||
log("\n");
|
||||
log("And <cell_details> is:\n");
|
||||
log("\n");
|
||||
log(" {\n");
|
||||
log(" \"hide_name\": <1 | 0>,\n");
|
||||
log(" \"type\": <cell_type>,\n");
|
||||
log(" \"parameters\": {\n");
|
||||
log(" <parameter_name>: <parameter_value>,\n");
|
||||
log(" ...\n");
|
||||
log(" },\n");
|
||||
log(" \"attributes\": {\n");
|
||||
log(" <attribute_name>: <attribute_value>,\n");
|
||||
log(" ...\n");
|
||||
log(" },\n");
|
||||
log(" \"connections\": {\n");
|
||||
log(" <port_name>: <bit_vector>,\n");
|
||||
log(" ...\n");
|
||||
log(" },\n");
|
||||
log(" }\n");
|
||||
log("\n");
|
||||
log("And <net_details> is:\n");
|
||||
log("\n");
|
||||
log(" {\n");
|
||||
log(" \"hide_name\": <1 | 0>,\n");
|
||||
log(" \"bits\": <bit_vector>\n");
|
||||
log(" }\n");
|
||||
log("\n");
|
||||
log("The \"hide_name\" fields are set to 1 when the name of this cell or net is\n");
|
||||
log("automatically created and is likely not of interest for a regular user.\n");
|
||||
log("\n");
|
||||
log("Module and cell ports and nets can be single bit wide or vectors of multiple\n");
|
||||
log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n");
|
||||
log("values referenced above are vectors of this integers. Signal bits that are\n");
|
||||
log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
|
||||
log("a number.\n");
|
||||
log("\n");
|
||||
log("For example the following verilog code:\n");
|
||||
log("\n");
|
||||
log(" module test(input x, y);\n");
|
||||
log(" (* keep *) foo #(.P(42), .Q(1337))\n");
|
||||
log(" foo_inst (.A({x, y}), .B({y, x}), .C({4'd10, {4{x}}}));\n");
|
||||
log(" endmodule\n");
|
||||
log("\n");
|
||||
log("Translates to the following JSON output:\n");
|
||||
log("\n");
|
||||
log(" {\n");
|
||||
log(" \"modules\": {\n");
|
||||
log(" \"test\": {\n");
|
||||
log(" \"ports\": {\n");
|
||||
log(" \"x\": {\n");
|
||||
log(" \"direction\": \"input\",\n");
|
||||
log(" \"bits\": [ 2 ]\n");
|
||||
log(" },\n");
|
||||
log(" \"y\": {\n");
|
||||
log(" \"direction\": \"input\",\n");
|
||||
log(" \"bits\": [ 3 ]\n");
|
||||
log(" }\n");
|
||||
log(" },\n");
|
||||
log(" \"cells\": {\n");
|
||||
log(" \"foo_inst\": {\n");
|
||||
log(" \"hide_name\": 0,\n");
|
||||
log(" \"type\": \"foo\",\n");
|
||||
log(" \"parameters\": {\n");
|
||||
log(" \"Q\": 1337,\n");
|
||||
log(" \"P\": 42\n");
|
||||
log(" },\n");
|
||||
log(" \"attributes\": {\n");
|
||||
log(" \"keep\": 1,\n");
|
||||
log(" \"src\": \"test.v:2\"\n");
|
||||
log(" },\n");
|
||||
log(" \"connections\": {\n");
|
||||
log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ],\n");
|
||||
log(" \"B\": [ 2, 3 ],\n");
|
||||
log(" \"A\": [ 3, 2 ]\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log(" },\n");
|
||||
log(" \"netnames\": {\n");
|
||||
log(" \"y\": {\n");
|
||||
log(" \"hide_name\": 0,\n");
|
||||
log(" \"bits\": [ 3 ],\n");
|
||||
log(" \"attributes\": {\n");
|
||||
log(" \"src\": \"test.v:1\"\n");
|
||||
log(" }\n");
|
||||
log(" },\n");
|
||||
log(" \"x\": {\n");
|
||||
log(" \"hide_name\": 0,\n");
|
||||
log(" \"bits\": [ 2 ],\n");
|
||||
log(" \"attributes\": {\n");
|
||||
log(" \"src\": \"test.v:1\"\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log(" }\n");
|
||||
log("\n");
|
||||
log("Future version of Yosys might add support for additional fields in the JSON\n");
|
||||
log("format. A program processing this format must ignore all unkown fields.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
{
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
// if (args[argidx] == "-verbose") {
|
||||
// verbose = true;
|
||||
// continue;
|
||||
// }
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
log_header("Executing JSON backend.\n");
|
||||
|
||||
JsonWriter json_writer(*f, false);
|
||||
json_writer.write_design(design);
|
||||
}
|
||||
} JsonBackend;
|
||||
|
||||
struct JsonPass : public Pass {
|
||||
JsonPass() : Pass("json", "write design in JSON format") { }
|
||||
virtual void help()
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" json [options] [selection]\n");
|
||||
log("\n");
|
||||
log("Write a JSON netlist of all selected objects.\n");
|
||||
log("\n");
|
||||
log(" -o <filename>\n");
|
||||
log(" write to the specified file.\n");
|
||||
log("\n");
|
||||
log("See 'help write_json' for a description of the JSON format used.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
{
|
||||
std::string filename;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-o" && argidx+1 < args.size()) {
|
||||
filename = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
std::ostream *f;
|
||||
std::stringstream buf;
|
||||
|
||||
if (!filename.empty()) {
|
||||
std::ofstream *ff = new std::ofstream;
|
||||
ff->open(filename.c_str(), std::ofstream::trunc);
|
||||
if (ff->fail()) {
|
||||
delete ff;
|
||||
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
|
||||
}
|
||||
f = ff;
|
||||
} else {
|
||||
f = &buf;
|
||||
}
|
||||
|
||||
JsonWriter json_writer(*f, true);
|
||||
json_writer.write_design(design);
|
||||
|
||||
if (!filename.empty()) {
|
||||
delete f;
|
||||
} else {
|
||||
log("%s", buf.str().c_str());
|
||||
}
|
||||
}
|
||||
} JsonPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1 @@
|
|||
test_cells
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
OBJS += backends/smt2/smt2.o
|
||||
|
|
@ -0,0 +1,711 @@
|
|||
/*
|
||||
* 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/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct Smt2Worker
|
||||
{
|
||||
CellTypes ct;
|
||||
SigMap sigmap;
|
||||
RTLIL::Module *module;
|
||||
bool bvmode, verbose;
|
||||
int idcounter;
|
||||
|
||||
std::vector<std::string> decls, trans;
|
||||
std::map<RTLIL::SigBit, RTLIL::Cell*> bit_driver;
|
||||
std::set<RTLIL::Cell*> exported_cells;
|
||||
pool<Cell*> recursive_cells, registers;
|
||||
|
||||
std::map<RTLIL::SigBit, std::pair<int, int>> fcache;
|
||||
std::map<int, int> bvsizes;
|
||||
|
||||
Smt2Worker(RTLIL::Module *module, bool bvmode, bool verbose) :
|
||||
ct(module->design), sigmap(module), module(module), bvmode(bvmode), verbose(verbose), idcounter(0)
|
||||
{
|
||||
decls.push_back(stringf("(declare-sort |%s_s| 0)\n", log_id(module)));
|
||||
|
||||
for (auto cell : module->cells())
|
||||
for (auto &conn : cell->connections()) {
|
||||
bool is_input = ct.cell_input(cell->type, conn.first);
|
||||
bool is_output = ct.cell_output(cell->type, conn.first);
|
||||
if (is_output && !is_input)
|
||||
for (auto bit : sigmap(conn.second)) {
|
||||
if (bit_driver.count(bit))
|
||||
log_error("Found multiple drivers for %s.\n", log_signal(bit));
|
||||
bit_driver[bit] = cell;
|
||||
}
|
||||
else if (is_output || !is_input)
|
||||
log_error("Unsupported or unknown directionality on port %s of cell %s.%s (%s).\n",
|
||||
log_id(conn.first), log_id(module), log_id(cell), log_id(cell->type));
|
||||
}
|
||||
}
|
||||
|
||||
void register_bool(RTLIL::SigBit bit, int id)
|
||||
{
|
||||
if (verbose) log("%*s-> register_bool: %s %d\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_signal(bit), id);
|
||||
|
||||
sigmap.apply(bit);
|
||||
log_assert(fcache.count(bit) == 0);
|
||||
fcache[bit] = std::pair<int, int>(id, -1);
|
||||
}
|
||||
|
||||
void register_bv(RTLIL::SigSpec sig, int id)
|
||||
{
|
||||
if (verbose) log("%*s-> register_bv: %s %d\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_signal(sig), id);
|
||||
|
||||
log_assert(bvmode);
|
||||
sigmap.apply(sig);
|
||||
|
||||
log_assert(bvsizes.count(id) == 0);
|
||||
bvsizes[id] = GetSize(sig);
|
||||
|
||||
for (int i = 0; i < GetSize(sig); i++) {
|
||||
log_assert(fcache.count(sig[i]) == 0);
|
||||
fcache[sig[i]] = std::pair<int, int>(id, i);
|
||||
}
|
||||
}
|
||||
|
||||
void register_boolvec(RTLIL::SigSpec sig, int id)
|
||||
{
|
||||
if (verbose) log("%*s-> register_boolvec: %s %d\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_signal(sig), id);
|
||||
|
||||
log_assert(bvmode);
|
||||
sigmap.apply(sig);
|
||||
register_bool(sig[0], id);
|
||||
|
||||
for (int i = 1; i < GetSize(sig); i++)
|
||||
sigmap.add(sig[i], RTLIL::State::S0);
|
||||
}
|
||||
|
||||
std::string get_bool(RTLIL::SigBit bit, const char *state_name = "state")
|
||||
{
|
||||
sigmap.apply(bit);
|
||||
|
||||
if (bit.wire == nullptr)
|
||||
return bit == RTLIL::State::S1 ? "true" : "false";
|
||||
|
||||
if (bit_driver.count(bit))
|
||||
export_cell(bit_driver.at(bit));
|
||||
sigmap.apply(bit);
|
||||
|
||||
if (fcache.count(bit) == 0) {
|
||||
if (verbose) log("%*s-> external bool: %s\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_signal(bit));
|
||||
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), log_signal(bit)));
|
||||
register_bool(bit, idcounter++);
|
||||
}
|
||||
|
||||
auto f = fcache.at(bit);
|
||||
if (f.second >= 0)
|
||||
return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, log_id(module), f.first, state_name);
|
||||
return stringf("(|%s#%d| %s)", log_id(module), f.first, state_name);
|
||||
}
|
||||
|
||||
std::string get_bool(RTLIL::SigSpec sig, const char *state_name = "state")
|
||||
{
|
||||
return get_bool(sig.to_single_sigbit(), state_name);
|
||||
}
|
||||
|
||||
std::string get_bv(RTLIL::SigSpec sig, const char *state_name = "state")
|
||||
{
|
||||
log_assert(bvmode);
|
||||
sigmap.apply(sig);
|
||||
|
||||
std::vector<std::string> subexpr;
|
||||
|
||||
SigSpec orig_sig;
|
||||
while (orig_sig != sig) {
|
||||
for (auto bit : sig)
|
||||
if (bit_driver.count(bit))
|
||||
export_cell(bit_driver.at(bit));
|
||||
orig_sig = sig;
|
||||
sigmap.apply(sig);
|
||||
}
|
||||
|
||||
for (int i = 0, j = 1; i < GetSize(sig); i += j, j = 1)
|
||||
{
|
||||
if (sig[i].wire == nullptr) {
|
||||
while (i+j < GetSize(sig) && sig[i+j].wire == nullptr) j++;
|
||||
subexpr.push_back("#b");
|
||||
for (int k = i+j-1; k >= i; k--)
|
||||
subexpr.back() += sig[k] == RTLIL::State::S1 ? "1" : "0";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fcache.count(sig[i]) && fcache.at(sig[i]).second == -1) {
|
||||
subexpr.push_back(stringf("(ite %s #b1 #b0)", get_bool(sig[i], state_name).c_str()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fcache.count(sig[i])) {
|
||||
auto t1 = fcache.at(sig[i]);
|
||||
while (i+j < GetSize(sig)) {
|
||||
if (fcache.count(sig[i+j]) == 0)
|
||||
break;
|
||||
auto t2 = fcache.at(sig[i+j]);
|
||||
if (t1.first != t2.first)
|
||||
break;
|
||||
if (t1.second+j != t2.second)
|
||||
break;
|
||||
j++;
|
||||
}
|
||||
if (t1.second == 0 && j == bvsizes.at(t1.first))
|
||||
subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), t1.first, state_name));
|
||||
else
|
||||
subexpr.push_back(stringf("((_ extract %d %d) (|%s#%d| %s))",
|
||||
t1.second + j - 1, t1.second, log_id(module), t1.first, state_name));
|
||||
continue;
|
||||
}
|
||||
|
||||
std::set<RTLIL::SigBit> seen_bits = { sig[i] };
|
||||
while (i+j < GetSize(sig) && sig[i+j].wire && !fcache.count(sig[i+j]) && !seen_bits.count(sig[i+j]))
|
||||
seen_bits.insert(sig[i+j]), j++;
|
||||
|
||||
if (verbose) log("%*s-> external bv: %s\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_signal(sig.extract(i, j)));
|
||||
for (auto bit : sig.extract(i, j))
|
||||
log_assert(bit_driver.count(bit) == 0);
|
||||
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), j, log_signal(sig.extract(i, j))));
|
||||
subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), idcounter, state_name));
|
||||
register_bv(sig.extract(i, j), idcounter++);
|
||||
}
|
||||
|
||||
if (GetSize(subexpr) > 1) {
|
||||
std::string expr = "(concat";
|
||||
for (int i = GetSize(subexpr)-1; i >= 0; i--)
|
||||
expr += " " + subexpr[i];
|
||||
return expr + ")";
|
||||
} else {
|
||||
log_assert(GetSize(subexpr) == 1);
|
||||
return subexpr[0];
|
||||
}
|
||||
}
|
||||
|
||||
void export_gate(RTLIL::Cell *cell, std::string expr)
|
||||
{
|
||||
RTLIL::SigBit bit = sigmap(cell->getPort("\\Y").to_single_sigbit());
|
||||
std::string processed_expr;
|
||||
|
||||
for (char ch : expr) {
|
||||
if (ch == 'A') processed_expr += get_bool(cell->getPort("\\A"));
|
||||
else if (ch == 'B') processed_expr += get_bool(cell->getPort("\\B"));
|
||||
else if (ch == 'C') processed_expr += get_bool(cell->getPort("\\C"));
|
||||
else if (ch == 'D') processed_expr += get_bool(cell->getPort("\\D"));
|
||||
else if (ch == 'S') processed_expr += get_bool(cell->getPort("\\S"));
|
||||
else processed_expr += ch;
|
||||
}
|
||||
|
||||
if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_id(cell));
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(bit)));
|
||||
register_bool(bit, idcounter++);
|
||||
recursive_cells.erase(cell);
|
||||
}
|
||||
|
||||
void export_bvop(RTLIL::Cell *cell, std::string expr, char type = 0)
|
||||
{
|
||||
RTLIL::SigSpec sig_a, sig_b;
|
||||
RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
|
||||
bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
|
||||
int width = GetSize(sig_y);
|
||||
|
||||
if (type == 's' || type == 'd' || type == 'b') {
|
||||
width = std::max(width, GetSize(cell->getPort("\\A")));
|
||||
width = std::max(width, GetSize(cell->getPort("\\B")));
|
||||
}
|
||||
|
||||
if (cell->hasPort("\\A")) {
|
||||
sig_a = cell->getPort("\\A");
|
||||
sig_a.extend_u0(width, is_signed);
|
||||
}
|
||||
|
||||
if (cell->hasPort("\\B")) {
|
||||
sig_b = cell->getPort("\\B");
|
||||
sig_b.extend_u0(width, is_signed && !(type == 's'));
|
||||
}
|
||||
|
||||
std::string processed_expr;
|
||||
|
||||
for (char ch : expr) {
|
||||
if (ch == 'A') processed_expr += get_bv(sig_a);
|
||||
else if (ch == 'B') processed_expr += get_bv(sig_b);
|
||||
else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
|
||||
else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
|
||||
else processed_expr += ch;
|
||||
}
|
||||
|
||||
if (width != GetSize(sig_y) && type != 'b')
|
||||
processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr.c_str());
|
||||
|
||||
if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_id(cell));
|
||||
|
||||
if (type == 'b') {
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y)));
|
||||
register_boolvec(sig_y, idcounter++);
|
||||
} else {
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y)));
|
||||
register_bv(sig_y, idcounter++);
|
||||
}
|
||||
|
||||
recursive_cells.erase(cell);
|
||||
}
|
||||
|
||||
void export_reduce(RTLIL::Cell *cell, std::string expr, bool identity_val)
|
||||
{
|
||||
RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
|
||||
std::string processed_expr;
|
||||
|
||||
for (char ch : expr)
|
||||
if (ch == 'A' || ch == 'B') {
|
||||
RTLIL::SigSpec sig = sigmap(cell->getPort(stringf("\\%c", ch)));
|
||||
for (auto bit : sig)
|
||||
processed_expr += " " + get_bool(bit);
|
||||
if (GetSize(sig) == 1)
|
||||
processed_expr += identity_val ? " true" : " false";
|
||||
} else
|
||||
processed_expr += ch;
|
||||
|
||||
if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_id(cell));
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y)));
|
||||
register_boolvec(sig_y, idcounter++);
|
||||
recursive_cells.erase(cell);
|
||||
}
|
||||
|
||||
void export_cell(RTLIL::Cell *cell)
|
||||
{
|
||||
if (verbose) log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new");
|
||||
|
||||
if (recursive_cells.count(cell))
|
||||
log_error("Found logic loop in module %s! See cell %s.\n", log_id(module), log_id(cell));
|
||||
|
||||
if (exported_cells.count(cell))
|
||||
return;
|
||||
exported_cells.insert(cell);
|
||||
recursive_cells.insert(cell);
|
||||
|
||||
if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_")
|
||||
{
|
||||
registers.insert(cell);
|
||||
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), log_signal(cell->getPort("\\Q"))));
|
||||
register_bool(cell->getPort("\\Q"), idcounter++);
|
||||
recursive_cells.erase(cell);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == "$_BUF_") return export_gate(cell, "A");
|
||||
if (cell->type == "$_NOT_") return export_gate(cell, "(not A)");
|
||||
if (cell->type == "$_AND_") return export_gate(cell, "(and A B)");
|
||||
if (cell->type == "$_NAND_") return export_gate(cell, "(not (and A B))");
|
||||
if (cell->type == "$_OR_") return export_gate(cell, "(or A B)");
|
||||
if (cell->type == "$_NOR_") return export_gate(cell, "(not (or A B))");
|
||||
if (cell->type == "$_XOR_") return export_gate(cell, "(xor A B)");
|
||||
if (cell->type == "$_XNOR_") return export_gate(cell, "(not (xor A B))");
|
||||
if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)");
|
||||
if (cell->type == "$_AOI3_") return export_gate(cell, "(not (or (and A B) C))");
|
||||
if (cell->type == "$_OAI3_") return export_gate(cell, "(not (and (or A B) C))");
|
||||
if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))");
|
||||
if (cell->type == "$_OAI4_") return export_gate(cell, "(not (and (or A B) (or C D)))");
|
||||
|
||||
// FIXME: $lut
|
||||
|
||||
if (!bvmode)
|
||||
log_error("Unsupported cell type %s for cell %s.%s. (Maybe this cell type would be supported in -bv mode?)\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
|
||||
if (cell->type == "$dff")
|
||||
{
|
||||
registers.insert(cell);
|
||||
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
|
||||
register_bv(cell->getPort("\\Q"), idcounter++);
|
||||
recursive_cells.erase(cell);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == "$and") return export_bvop(cell, "(bvand A B)");
|
||||
if (cell->type == "$or") return export_bvop(cell, "(bvor A B)");
|
||||
if (cell->type == "$xor") return export_bvop(cell, "(bvxor A B)");
|
||||
if (cell->type == "$xnor") return export_bvop(cell, "(bvxnor A B)");
|
||||
|
||||
if (cell->type == "$shl") return export_bvop(cell, "(bvshl A B)", 's');
|
||||
if (cell->type == "$shr") return export_bvop(cell, "(bvlshr A B)", 's');
|
||||
if (cell->type == "$sshl") return export_bvop(cell, "(bvshl A B)", 's');
|
||||
if (cell->type == "$sshr") return export_bvop(cell, "(bvLshr A B)", 's');
|
||||
|
||||
// FIXME: $shift $shiftx
|
||||
|
||||
if (cell->type == "$lt") return export_bvop(cell, "(bvUlt A B)", 'b');
|
||||
if (cell->type == "$le") return export_bvop(cell, "(bvUle A B)", 'b');
|
||||
if (cell->type == "$ge") return export_bvop(cell, "(bvUge A B)", 'b');
|
||||
if (cell->type == "$gt") return export_bvop(cell, "(bvUgt A B)", 'b');
|
||||
|
||||
if (cell->type == "$ne") return export_bvop(cell, "(distinct A B)", 'b');
|
||||
if (cell->type == "$nex") return export_bvop(cell, "(distinct A B)", 'b');
|
||||
if (cell->type == "$eq") return export_bvop(cell, "(= A B)", 'b');
|
||||
if (cell->type == "$eqx") return export_bvop(cell, "(= A B)", 'b');
|
||||
|
||||
if (cell->type == "$not") return export_bvop(cell, "(bvnot A)");
|
||||
if (cell->type == "$pos") return export_bvop(cell, "A");
|
||||
if (cell->type == "$neg") return export_bvop(cell, "(bvneg A)");
|
||||
|
||||
if (cell->type == "$add") return export_bvop(cell, "(bvadd A B)");
|
||||
if (cell->type == "$sub") return export_bvop(cell, "(bvsub A B)");
|
||||
if (cell->type == "$mul") return export_bvop(cell, "(bvmul A B)");
|
||||
if (cell->type == "$div") return export_bvop(cell, "(bvUdiv A B)", 'd');
|
||||
if (cell->type == "$mod") return export_bvop(cell, "(bvUrem A B)", 'd');
|
||||
|
||||
if (cell->type == "$reduce_and") return export_reduce(cell, "(and A)", true);
|
||||
if (cell->type == "$reduce_or") return export_reduce(cell, "(or A)", false);
|
||||
if (cell->type == "$reduce_xor") return export_reduce(cell, "(xor A)", false);
|
||||
if (cell->type == "$reduce_xnor") return export_reduce(cell, "(not (xor A))", false);
|
||||
if (cell->type == "$reduce_bool") return export_reduce(cell, "(or A)", false);
|
||||
|
||||
if (cell->type == "$logic_not") return export_reduce(cell, "(not (or A))", false);
|
||||
if (cell->type == "$logic_and") return export_reduce(cell, "(and (or A) (or B))", false);
|
||||
if (cell->type == "$logic_or") return export_reduce(cell, "(or A B)", false);
|
||||
|
||||
if (cell->type == "$mux" || cell->type == "$pmux")
|
||||
{
|
||||
int width = GetSize(cell->getPort("\\Y"));
|
||||
std::string processed_expr = get_bv(cell->getPort("\\A"));
|
||||
|
||||
RTLIL::SigSpec sig_b = cell->getPort("\\B");
|
||||
RTLIL::SigSpec sig_s = cell->getPort("\\S");
|
||||
get_bv(sig_b);
|
||||
get_bv(sig_s);
|
||||
|
||||
for (int i = 0; i < GetSize(sig_s); i++)
|
||||
processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(),
|
||||
get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str());
|
||||
|
||||
if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_id(cell));
|
||||
RTLIL::SigSpec sig = sigmap(cell->getPort("\\Y"));
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), width, processed_expr.c_str(), log_signal(sig)));
|
||||
register_bv(sig, idcounter++);
|
||||
recursive_cells.erase(cell);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: $slice $concat
|
||||
|
||||
log_error("Unsupported cell type %s for cell %s.%s.\n",
|
||||
log_id(cell->type), log_id(module), log_id(cell));
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
if (verbose) log("=> export logic driving outputs\n");
|
||||
|
||||
for (auto wire : module->wires())
|
||||
if (wire->port_id || wire->get_bool_attribute("\\keep")) {
|
||||
RTLIL::SigSpec sig = sigmap(wire);
|
||||
if (bvmode && GetSize(sig) > 1) {
|
||||
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) (_ BitVec %d) %s)\n",
|
||||
log_id(module), log_id(wire), log_id(module), GetSize(sig), get_bv(sig).c_str()));
|
||||
} else {
|
||||
for (int i = 0; i < GetSize(sig); i++)
|
||||
if (GetSize(sig) > 1)
|
||||
decls.push_back(stringf("(define-fun |%s_n %s %d| ((state |%s_s|)) Bool %s)\n",
|
||||
log_id(module), log_id(wire), i, log_id(module), get_bool(sig[i]).c_str()));
|
||||
else
|
||||
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) Bool %s)\n",
|
||||
log_id(module), log_id(wire), log_id(module), get_bool(sig[i]).c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) log("=> export logic associated with the initial state\n");
|
||||
|
||||
vector<string> init_list;
|
||||
for (auto wire : module->wires())
|
||||
if (wire->attributes.count("\\init")) {
|
||||
RTLIL::SigSpec sig = sigmap(wire);
|
||||
Const val = wire->attributes.at("\\init");
|
||||
val.bits.resize(GetSize(sig));
|
||||
if (bvmode && GetSize(sig) > 1) {
|
||||
init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), log_id(wire)));
|
||||
} else {
|
||||
for (int i = 0; i < GetSize(sig); i++)
|
||||
init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val.bits[i] == State::S1 ? "true" : "false", log_id(wire)));
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) log("=> export logic driving asserts\n");
|
||||
|
||||
vector<int> assert_list, assume_list;
|
||||
for (auto cell : module->cells())
|
||||
if (cell->type.in("$assert", "$assume")) {
|
||||
string name_a = get_bool(cell->getPort("\\A"));
|
||||
string name_en = get_bool(cell->getPort("\\EN"));
|
||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n",
|
||||
log_id(module), idcounter, log_id(module), name_a.c_str(), name_en.c_str(), log_id(cell)));
|
||||
if (cell->type == "$assert")
|
||||
assert_list.push_back(idcounter++);
|
||||
else
|
||||
assume_list.push_back(idcounter++);
|
||||
}
|
||||
|
||||
for (int iter = 1; !registers.empty(); iter++)
|
||||
{
|
||||
pool<Cell*> this_regs;
|
||||
this_regs.swap(registers);
|
||||
|
||||
if (verbose) log("=> export logic driving registers [iteration %d]\n", iter);
|
||||
|
||||
for (auto cell : this_regs) {
|
||||
if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_") {
|
||||
std::string expr_d = get_bool(cell->getPort("\\D"));
|
||||
std::string expr_q = get_bool(cell->getPort("\\Q"), "next_state");
|
||||
trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));
|
||||
}
|
||||
if (cell->type == "$dff") {
|
||||
std::string expr_d = get_bv(cell->getPort("\\D"));
|
||||
std::string expr_q = get_bv(cell->getPort("\\Q"), "next_state");
|
||||
trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string assert_expr = assert_list.empty() ? "true" : "(and";
|
||||
if (!assert_list.empty()) {
|
||||
for (int i : assert_list)
|
||||
assert_expr += stringf(" (|%s#%d| state)", log_id(module), i);
|
||||
assert_expr += ")";
|
||||
}
|
||||
decls.push_back(stringf("(define-fun |%s_a| ((state |%s_s|)) Bool %s)\n",
|
||||
log_id(module), log_id(module), assert_expr.c_str()));
|
||||
|
||||
string assume_expr = assume_list.empty() ? "true" : "(and";
|
||||
if (!assume_list.empty()) {
|
||||
for (int i : assume_list)
|
||||
assume_expr += stringf(" (|%s#%d| state)", log_id(module), i);
|
||||
assume_expr += ")";
|
||||
}
|
||||
decls.push_back(stringf("(define-fun |%s_u| ((state |%s_s|)) Bool %s)\n",
|
||||
log_id(module), log_id(module), assume_expr.c_str()));
|
||||
|
||||
string init_expr = init_list.empty() ? "true" : "(and";
|
||||
if (!init_list.empty()) {
|
||||
for (auto &str : init_list)
|
||||
init_expr += stringf("\n\t%s", str.c_str());
|
||||
init_expr += "\n)";
|
||||
}
|
||||
decls.push_back(stringf("(define-fun |%s_i| ((state |%s_s|)) Bool %s)\n",
|
||||
log_id(module), log_id(module), init_expr.c_str()));
|
||||
}
|
||||
|
||||
void write(std::ostream &f)
|
||||
{
|
||||
for (auto it : decls)
|
||||
f << it;
|
||||
|
||||
f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", log_id(module), log_id(module), log_id(module));
|
||||
if (GetSize(trans) > 1) {
|
||||
f << "(and\n";
|
||||
for (auto it : trans)
|
||||
f << it;
|
||||
f << "))";
|
||||
} else
|
||||
if (GetSize(trans) == 1)
|
||||
f << "\n" + trans.front() + ")";
|
||||
else
|
||||
f << "true)";
|
||||
f << stringf(" ; end of module %s\n", log_id(module));
|
||||
}
|
||||
};
|
||||
|
||||
struct Smt2Backend : public Backend {
|
||||
Smt2Backend() : Backend("smt2", "write design to SMT-LIBv2 file") { }
|
||||
virtual void help()
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" write_smt2 [options] [filename]\n");
|
||||
log("\n");
|
||||
log("Write a SMT-LIBv2 [1] description of the current design. For a module with name\n");
|
||||
log("'<mod>' this will declare the sort '<mod>_s' (state of the module) and the\n");
|
||||
log("functions operating on that state.\n");
|
||||
log("\n");
|
||||
log("The '<mod>_s' sort represents a module state. Additional '<mod>_n' functions\n");
|
||||
log("are provided that can be used to access the values of the signals in the module.\n");
|
||||
log("Only ports, and signals with the 'keep' attribute set are made available via\n");
|
||||
log("such functions. Without the -bv option, multi-bit wires are exported as\n");
|
||||
log("separate functions of type Bool for the individual bits. With the -bv option\n");
|
||||
log("multi-bit wires are exported as single functions of type BitVec.\n");
|
||||
log("\n");
|
||||
log("The '<mod>_t' function evaluates to 'true' when the given pair of states\n");
|
||||
log("describes a valid state transition.\n");
|
||||
log("\n");
|
||||
log("The '<mod>_a' function evaluates to 'true' when the given state satisfies\n");
|
||||
log("the asserts in the module.\n");
|
||||
log("\n");
|
||||
log("The '<mod>_u' function evaluates to 'true' when the given state satisfies\n");
|
||||
log("the assumptions in the module.\n");
|
||||
log("\n");
|
||||
log("The '<mod>_i' function evaluates to 'true' when the given state conforms\n");
|
||||
log("to the initial state.\n");
|
||||
log("\n");
|
||||
log(" -verbose\n");
|
||||
log(" this will print the recursive walk used to export the modules.\n");
|
||||
log("\n");
|
||||
log(" -bv\n");
|
||||
log(" enable support for BitVec (FixedSizeBitVectors theory). with this\n");
|
||||
log(" option set multi-bit wires are represented using the BitVec sort and\n");
|
||||
log(" support for coarse grain cells (incl. arithmetic) is enabled.\n");
|
||||
log("\n");
|
||||
log(" -tpl <template_file>\n");
|
||||
log(" use the given template file. the line containing only the token '%%%%'\n");
|
||||
log(" is replaced with the regular output of this command.\n");
|
||||
log("\n");
|
||||
log("[1] For more information on SMT-LIBv2 visit http://smt-lib.org/ or read David\n");
|
||||
log("R. Cok's tutorial: http://www.grammatech.com/resources/smt/SMTLIBTutorial.pdf\n");
|
||||
log("\n");
|
||||
log("---------------------------------------------------------------------------\n");
|
||||
log("\n");
|
||||
log("Example:\n");
|
||||
log("\n");
|
||||
log("Consider the following module (test.v). We want to prove that the output can\n");
|
||||
log("never transition from a non-zero value to a zero value.\n");
|
||||
log("\n");
|
||||
log(" module test(input clk, output reg [3:0] y);\n");
|
||||
log(" always @(posedge clk)\n");
|
||||
log(" y <= (y << 1) | ^y;\n");
|
||||
log(" endmodule\n");
|
||||
log("\n");
|
||||
log("For this proof we create the following template (test.tpl).\n");
|
||||
log("\n");
|
||||
log(" ; we need QF_UFBV for this poof\n");
|
||||
log(" (set-logic QF_UFBV)\n");
|
||||
log("\n");
|
||||
log(" ; insert the auto-generated code here\n");
|
||||
log(" %%%%\n");
|
||||
log("\n");
|
||||
log(" ; declare two state variables s1 and s2\n");
|
||||
log(" (declare-fun s1 () test_s)\n");
|
||||
log(" (declare-fun s2 () test_s)\n");
|
||||
log("\n");
|
||||
log(" ; state s2 is the successor of state s1\n");
|
||||
log(" (assert (test_t s1 s2))\n");
|
||||
log("\n");
|
||||
log(" ; we are looking for a model with y non-zero in s1\n");
|
||||
log(" (assert (distinct (|test_n y| s1) #b0000))\n");
|
||||
log("\n");
|
||||
log(" ; we are looking for a model with y zero in s2\n");
|
||||
log(" (assert (= (|test_n y| s2) #b0000))\n");
|
||||
log("\n");
|
||||
log(" ; is there such a model?\n");
|
||||
log(" (check-sat)\n");
|
||||
log("\n");
|
||||
log("The following yosys script will create a 'test.smt2' file for our proof:\n");
|
||||
log("\n");
|
||||
log(" read_verilog test.v\n");
|
||||
log(" hierarchy -check; proc; opt; check -assert\n");
|
||||
log(" write_smt2 -bv -tpl test.tpl test.smt2\n");
|
||||
log("\n");
|
||||
log("Running 'cvc4 test.smt2' will print 'unsat' because y can never transition\n");
|
||||
log("from non-zero to zero in the test design.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
{
|
||||
std::ifstream template_f;
|
||||
bool bvmode = false, verbose = false;
|
||||
|
||||
log_header("Executing SMT2 backend.\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-tpl" && argidx+1 < args.size()) {
|
||||
template_f.open(args[++argidx]);
|
||||
if (template_f.fail())
|
||||
log_error("Can't open template file `%s'.\n", args[argidx].c_str());
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-bv") {
|
||||
bvmode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-verbose") {
|
||||
verbose = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
if (template_f.is_open()) {
|
||||
std::string line;
|
||||
while (std::getline(template_f, line)) {
|
||||
int indent = 0;
|
||||
while (indent < GetSize(line) && (line[indent] == ' ' || line[indent] == '\t'))
|
||||
indent++;
|
||||
if (line.substr(indent, 2) == "%%")
|
||||
break;
|
||||
*f << line << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
*f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_version_str);
|
||||
|
||||
for (auto module : design->modules())
|
||||
{
|
||||
if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn())
|
||||
continue;
|
||||
|
||||
log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));
|
||||
|
||||
Smt2Worker worker(module, bvmode, verbose);
|
||||
worker.run();
|
||||
worker.write(*f);
|
||||
}
|
||||
|
||||
*f << stringf("; end of yosys output\n");
|
||||
|
||||
if (template_f.is_open()) {
|
||||
std::string line;
|
||||
while (std::getline(template_f, line))
|
||||
*f << line << std::endl;
|
||||
}
|
||||
}
|
||||
} Smt2Backend;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
rm -rf test_cells
|
||||
mkdir test_cells
|
||||
cd test_cells
|
||||
|
||||
../../../yosys -p 'test_cell -muxdiv -w test all /$alu /$macc /$fa /$lcu /$lut /$shift /$shiftx'
|
||||
|
||||
cat > miter.tpl <<- EOT
|
||||
; #model# (set-option :produce-models true)
|
||||
(set-logic QF_UFBV)
|
||||
%%
|
||||
(declare-fun s () miter_s)
|
||||
(assert (|miter_n trigger| s))
|
||||
(check-sat)
|
||||
; #model# (get-value ((|miter_n in_A| s) (|miter_n in_B| s) (|miter_n gold_Y| s) (|miter_n gate_Y| s) (|miter_n trigger| s)))
|
||||
EOT
|
||||
|
||||
for x in $(set +x; ls test_*.il | sort -R); do
|
||||
x=${x%.il}
|
||||
cat > $x.ys <<- EOT
|
||||
read_ilang $x.il
|
||||
copy gold gate
|
||||
|
||||
cd gate
|
||||
techmap; opt; abc;;
|
||||
cd ..
|
||||
|
||||
miter -equiv -flatten -make_outputs gold gate miter
|
||||
hierarchy -check -top miter
|
||||
|
||||
dump
|
||||
write_smt2 -bv -tpl miter.tpl $x.smt2
|
||||
EOT
|
||||
../../../yosys -q $x.ys
|
||||
if ! cvc4 $x.smt2 > $x.result; then
|
||||
cat $x.result
|
||||
exit 1
|
||||
fi
|
||||
if ! grep unsat $x.result; then
|
||||
echo "Proof failed! Extracting model..."
|
||||
sed -i 's/^; #model# //' $x.smt2
|
||||
cvc4 $x.smt2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
set +x
|
||||
echo ""
|
||||
echo " All tests passed."
|
||||
echo ""
|
||||
exit 0
|
||||
|
|
@ -24,6 +24,9 @@
|
|||
#include "kernel/log.h"
|
||||
#include <string>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter)
|
||||
{
|
||||
if (s.wire) {
|
||||
|
@ -55,7 +58,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
|
|||
|
||||
if (design->modules_.count(cell->type) == 0)
|
||||
{
|
||||
log("Warning: no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
|
||||
log_warning("no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
|
||||
RTLIL::id2cstr(cell->type), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name));
|
||||
for (auto &conn : cell->connections()) {
|
||||
RTLIL::SigSpec sig = sigmap(conn.second);
|
||||
|
@ -81,7 +84,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
|
|||
RTLIL::SigSpec sig(RTLIL::State::Sz, wire->width);
|
||||
if (cell->hasPort(wire->name)) {
|
||||
sig = sigmap(cell->getPort(wire->name));
|
||||
sig.extend(wire->width, false);
|
||||
sig.extend_u0(wire->width, false);
|
||||
}
|
||||
port_sigs.push_back(sig);
|
||||
}
|
||||
|
@ -231,3 +234,4 @@ struct SpiceBackend : public Backend {
|
|||
}
|
||||
} SpiceBackend;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "verilog_backend.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/log.h"
|
||||
|
@ -35,7 +34,8 @@
|
|||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace {
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
bool norename, noattr, attr2comment, noexpr;
|
||||
int auto_name_counter, auto_name_offset, auto_name_digits;
|
||||
|
@ -51,16 +51,17 @@ void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
|
|||
if (*str == '$' && may_rename && !norename)
|
||||
auto_name_map[id] = auto_name_counter++;
|
||||
|
||||
if (str[0] != '_' && str[1] != 0)
|
||||
if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
|
||||
return;
|
||||
for (int i = 0; str[i] != 0; i++) {
|
||||
if (str[i] == '_')
|
||||
|
||||
for (int i = 2; str[i] != 0; i++) {
|
||||
if (str[i] == '_' && str[i+1] == 0)
|
||||
continue;
|
||||
if (str[i] < '0' || str[i] > '9')
|
||||
return;
|
||||
}
|
||||
|
||||
int num = atoi(str+1);
|
||||
int num = atoi(str+2);
|
||||
if (num >= auto_name_offset)
|
||||
auto_name_offset = num + 1;
|
||||
}
|
||||
|
@ -73,22 +74,22 @@ void reset_auto_counter(RTLIL::Module *module)
|
|||
|
||||
reset_auto_counter_id(module->name, false);
|
||||
|
||||
for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
|
||||
for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
|
||||
reset_auto_counter_id(it->second->name, true);
|
||||
|
||||
for (auto it = module->cells_.begin(); it != module->cells_.end(); it++) {
|
||||
for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) {
|
||||
reset_auto_counter_id(it->second->name, true);
|
||||
reset_auto_counter_id(it->second->type, false);
|
||||
}
|
||||
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
|
||||
reset_auto_counter_id(it->second->name, false);
|
||||
|
||||
auto_name_digits = 1;
|
||||
for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
|
||||
auto_name_digits++;
|
||||
|
||||
for (auto it = auto_name_map.begin(); it != auto_name_map.end(); it++)
|
||||
for (auto it = auto_name_map.begin(); it != auto_name_map.end(); ++it)
|
||||
log(" renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
|
||||
}
|
||||
|
||||
|
@ -150,7 +151,7 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name)
|
|||
return true;
|
||||
}
|
||||
|
||||
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false)
|
||||
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false)
|
||||
{
|
||||
if (width < 0)
|
||||
width = data.bits.size() - offset;
|
||||
|
@ -166,7 +167,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
|||
if (data.bits[i] == RTLIL::S1)
|
||||
val |= 1 << (i - offset);
|
||||
}
|
||||
f << stringf("32'%sd%d", set_signed ? "s" : "", val);
|
||||
f << stringf("32'%sd %d", set_signed ? "s" : "", val);
|
||||
} else {
|
||||
dump_bits:
|
||||
f << stringf("%d'%sb", width, set_signed ? "s" : "");
|
||||
|
@ -198,6 +199,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
|||
f << stringf("\\\"");
|
||||
else if (str[i] == '\\')
|
||||
f << stringf("\\\\");
|
||||
else if (str[i] == '/' && escape_comment && i > 0 && str[i-1] == '*')
|
||||
f << stringf("\\/");
|
||||
else
|
||||
f << str[i];
|
||||
}
|
||||
|
@ -236,7 +239,7 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
|
|||
dump_sigchunk(f, sig.as_chunk());
|
||||
} else {
|
||||
f << stringf("{ ");
|
||||
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
|
||||
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
|
||||
if (it != sig.chunks().rbegin())
|
||||
f << stringf(", ");
|
||||
dump_sigchunk(f, *it, true);
|
||||
|
@ -245,14 +248,19 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
|
|||
}
|
||||
}
|
||||
|
||||
void dump_attributes(std::ostream &f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
|
||||
void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
|
||||
{
|
||||
if (noattr)
|
||||
return;
|
||||
for (auto it = attributes.begin(); it != attributes.end(); it++) {
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
|
||||
f << stringf(" = ");
|
||||
dump_const(f, it->second);
|
||||
if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
|
||||
f << stringf(" 0 ");
|
||||
else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
|
||||
f << stringf(" 1 ");
|
||||
else
|
||||
dump_const(f, it->second, -1, 0, false, false, attr2comment);
|
||||
f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +323,7 @@ std::string cellname(RTLIL::Cell *cell)
|
|||
if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
|
||||
{
|
||||
RTLIL::SigSpec sig = cell->getPort("\\Q");
|
||||
if (SIZE(sig) != 1 || sig.is_fully_const())
|
||||
if (GetSize(sig) != 1 || sig.is_fully_const())
|
||||
goto no_special_reg_name;
|
||||
|
||||
RTLIL::Wire *wire = sig[0].wire;
|
||||
|
@ -663,10 +671,60 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$dff" || cell->type == "$adff")
|
||||
if (cell->type == "$dffsr")
|
||||
{
|
||||
RTLIL::SigSpec sig_clk, sig_arst, val_arst;
|
||||
bool pol_clk, pol_arst = false;
|
||||
SigSpec sig_clk = cell->getPort("\\CLK");
|
||||
SigSpec sig_set = cell->getPort("\\SET");
|
||||
SigSpec sig_clr = cell->getPort("\\CLR");
|
||||
SigSpec sig_d = cell->getPort("\\D");
|
||||
SigSpec sig_q = cell->getPort("\\Q");
|
||||
|
||||
int width = cell->parameters["\\WIDTH"].as_int();
|
||||
bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
|
||||
bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool();
|
||||
bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool();
|
||||
|
||||
std::string reg_name = cellname(cell);
|
||||
bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
|
||||
|
||||
if (!out_is_reg_wire)
|
||||
f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
|
||||
dump_sigspec(f, sig_clk);
|
||||
f << stringf(", %sedge ", pol_set ? "pos" : "neg");
|
||||
dump_sigspec(f, sig_set);
|
||||
f << stringf(", %sedge ", pol_clr ? "pos" : "neg");
|
||||
dump_sigspec(f, sig_clr);
|
||||
f << stringf(")\n");
|
||||
|
||||
f << stringf("%s" " if (%s", indent.c_str(), pol_clr ? "" : "!");
|
||||
dump_sigspec(f, sig_clr);
|
||||
f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i);
|
||||
|
||||
f << stringf("%s" " else if (%s", indent.c_str(), pol_set ? "" : "!");
|
||||
dump_sigspec(f, sig_set);
|
||||
f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i);
|
||||
|
||||
f << stringf("%s" " else %s[%d] <= ", indent.c_str(), reg_name.c_str(), i);
|
||||
dump_sigspec(f, sig_d[i]);
|
||||
f << stringf(";\n");
|
||||
}
|
||||
|
||||
if (!out_is_reg_wire) {
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, sig_q);
|
||||
f << stringf(" = %s;\n", reg_name.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
|
||||
{
|
||||
RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
|
||||
bool pol_clk, pol_arst = false, pol_en = false;
|
||||
|
||||
sig_clk = cell->getPort("\\CLK");
|
||||
pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
|
||||
|
@ -677,6 +735,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
|
||||
}
|
||||
|
||||
if (cell->type == "$dffe") {
|
||||
sig_en = cell->getPort("\\EN");
|
||||
pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
|
||||
}
|
||||
|
||||
std::string reg_name = cellname(cell);
|
||||
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
|
||||
|
||||
|
@ -701,6 +764,12 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
f << stringf("%s" " else\n", indent.c_str());
|
||||
}
|
||||
|
||||
if (cell->type == "$dffe") {
|
||||
f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
|
||||
dump_sigspec(f, sig_en);
|
||||
f << stringf(")\n");
|
||||
}
|
||||
|
||||
f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
|
||||
dump_cell_expr_port(f, cell, "D", false);
|
||||
f << stringf(";\n");
|
||||
|
@ -715,7 +784,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
}
|
||||
|
||||
// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
|
||||
// FIXME: $sr, $dffsr, $dlatch, $memrd, $memwr, $mem, $fsm
|
||||
// FIXME: $sr, $dlatch, $memrd, $memwr, $mem, $fsm
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -732,12 +801,12 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
|
||||
if (cell->parameters.size() > 0) {
|
||||
f << stringf(" #(");
|
||||
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
|
||||
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
|
||||
if (it != cell->parameters.begin())
|
||||
f << stringf(",");
|
||||
f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
|
||||
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
|
||||
dump_const(f, it->second, -1, 0, !is_signed, is_signed);
|
||||
dump_const(f, it->second, -1, 0, false, is_signed);
|
||||
f << stringf(")");
|
||||
}
|
||||
f << stringf("\n%s" ")", indent.c_str());
|
||||
|
@ -754,7 +823,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
for (int i = 1; true; i++) {
|
||||
char str[16];
|
||||
snprintf(str, 16, "$%d", i);
|
||||
for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
|
||||
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
|
||||
if (it->first != str)
|
||||
continue;
|
||||
if (!first_arg)
|
||||
|
@ -768,7 +837,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
break;
|
||||
found_numbered_port:;
|
||||
}
|
||||
for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
|
||||
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
|
||||
if (numbered_ports.count(it->first))
|
||||
continue;
|
||||
if (!first_arg)
|
||||
|
@ -800,7 +869,7 @@ void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bo
|
|||
if (!omit_trailing_begin && number_of_stmts >= 2)
|
||||
f << stringf("%s" "begin\n", indent.c_str());
|
||||
|
||||
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
|
||||
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
|
||||
if (it->first.size() == 0)
|
||||
continue;
|
||||
f << stringf("%s ", indent.c_str());
|
||||
|
@ -810,7 +879,7 @@ void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bo
|
|||
f << stringf(";\n");
|
||||
}
|
||||
|
||||
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
|
||||
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
|
||||
dump_proc_switch(f, indent + " ", *it);
|
||||
|
||||
if (!omit_trailing_begin && number_of_stmts == 0)
|
||||
|
@ -824,7 +893,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
|
|||
{
|
||||
if (sw->signal.size() == 0) {
|
||||
f << stringf("%s" "begin\n", indent.c_str());
|
||||
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
|
||||
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
|
||||
if ((*it)->compare.size() == 0)
|
||||
dump_case_body(f, indent + " ", *it);
|
||||
}
|
||||
|
@ -836,7 +905,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
|
|||
dump_sigspec(f, sw->signal);
|
||||
f << stringf(")\n");
|
||||
|
||||
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
|
||||
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
|
||||
f << stringf("%s ", indent.c_str());
|
||||
if ((*it)->compare.size() == 0)
|
||||
f << stringf("default");
|
||||
|
@ -856,11 +925,11 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
|
|||
|
||||
void case_body_find_regs(RTLIL::CaseRule *cs)
|
||||
{
|
||||
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
|
||||
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
|
||||
for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
|
||||
case_body_find_regs(*it2);
|
||||
|
||||
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
|
||||
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
|
||||
for (auto &c : it->first.chunks())
|
||||
if (c.wire != NULL)
|
||||
reg_wires.insert(c.wire->name);
|
||||
|
@ -871,7 +940,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
|
|||
{
|
||||
if (find_regs) {
|
||||
case_body_find_regs(&proc->root_case);
|
||||
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
|
||||
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
|
||||
for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
|
||||
for (auto &c : it2->first.chunks())
|
||||
if (c.wire != NULL)
|
||||
|
@ -925,7 +994,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
|
|||
}
|
||||
}
|
||||
|
||||
for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
|
||||
for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
|
||||
if (it->first.size() == 0)
|
||||
continue;
|
||||
f << stringf("%s ", indent.c_str());
|
||||
|
@ -946,7 +1015,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
active_module = module;
|
||||
|
||||
f << stringf("\n");
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
|
||||
dump_process(f, indent + " ", it->second, true);
|
||||
|
||||
if (!noexpr)
|
||||
|
@ -979,12 +1048,12 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
}
|
||||
}
|
||||
|
||||
dump_attributes(f, indent, module->attributes);
|
||||
dump_attributes(f, indent, module->attributes, '\n', true);
|
||||
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
|
||||
bool keep_running = true;
|
||||
for (int port_id = 1; keep_running; port_id++) {
|
||||
keep_running = false;
|
||||
for (auto it = module->wires_.begin(); it != module->wires_.end(); it++) {
|
||||
for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
|
||||
RTLIL::Wire *wire = it->second;
|
||||
if (wire->port_id == port_id) {
|
||||
if (port_id != 1)
|
||||
|
@ -997,27 +1066,25 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
}
|
||||
f << stringf(");\n");
|
||||
|
||||
for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
|
||||
for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
|
||||
dump_wire(f, indent + " ", it->second);
|
||||
|
||||
for (auto it = module->memories.begin(); it != module->memories.end(); it++)
|
||||
for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
|
||||
dump_memory(f, indent + " ", it->second);
|
||||
|
||||
for (auto it = module->cells_.begin(); it != module->cells_.end(); it++)
|
||||
for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
|
||||
dump_cell(f, indent + " ", it->second);
|
||||
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
|
||||
dump_process(f, indent + " ", it->second);
|
||||
|
||||
for (auto it = module->connections().begin(); it != module->connections().end(); it++)
|
||||
for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
|
||||
dump_conn(f, indent + " ", it->first, it->second);
|
||||
|
||||
f << stringf("%s" "endmodule\n", indent.c_str());
|
||||
active_module = NULL;
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
struct VerilogBackend : public Backend {
|
||||
VerilogBackend() : Backend("verilog", "write design to verilog file") { }
|
||||
virtual void help()
|
||||
|
@ -1122,8 +1189,10 @@ struct VerilogBackend : public Backend {
|
|||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
design->sort();
|
||||
|
||||
*f << stringf("/* Generated by %s */\n", yosys_version_str);
|
||||
for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
|
||||
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
|
||||
if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
|
||||
continue;
|
||||
if (selected && !design->selected_whole_module(it->first)) {
|
||||
|
@ -1139,3 +1208,4 @@ struct VerilogBackend : public Backend {
|
|||
}
|
||||
} VerilogBackend;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* A simple and straightforward verilog backend.
|
||||
*
|
||||
* Note that RTLIL processes can't always be mapped easily to a Verilog
|
||||
* process. Therefore this frontend should only be used to export a
|
||||
* Verilog netlist (i.e. after the "proc" pass has converted all processes
|
||||
* to logic networks and registers).
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VERILOG_BACKEND_H
|
||||
#define VERILOG_BACKEND_H
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
namespace VERILOG_BACKEND {
|
||||
void verilog_backend(std::ostream &f, std::vector<std::string> args, RTLIL::Design *design);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -26,13 +26,18 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/yosys.h"
|
||||
#include "libs/sha1/sha1.h"
|
||||
#include "ast.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <cmath>
|
||||
#else
|
||||
# include <math.h>
|
||||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -48,12 +53,12 @@ namespace AST {
|
|||
|
||||
// instanciate global variables (private API)
|
||||
namespace AST_INTERNAL {
|
||||
bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
||||
bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
||||
AstNode *current_ast, *current_ast_mod;
|
||||
std::map<std::string, AstNode*> current_scope;
|
||||
const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
|
||||
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
|
||||
RTLIL::SigSpec ignoreThisSignalsInInitial;
|
||||
AstNode *current_top_block, *current_block, *current_block_child;
|
||||
AstNode *current_always, *current_top_block, *current_block, *current_block_child;
|
||||
AstModule *current_module;
|
||||
}
|
||||
|
||||
|
@ -85,6 +90,7 @@ std::string AST::type2str(AstNodeType type)
|
|||
X(AST_IDENTIFIER)
|
||||
X(AST_PREFIX)
|
||||
X(AST_ASSERT)
|
||||
X(AST_ASSUME)
|
||||
X(AST_FCALL)
|
||||
X(AST_TO_BITS)
|
||||
X(AST_TO_SIGNED)
|
||||
|
@ -127,6 +133,7 @@ std::string AST::type2str(AstNodeType type)
|
|||
X(AST_TERNARY)
|
||||
X(AST_MEMRD)
|
||||
X(AST_MEMWR)
|
||||
X(AST_MEMINIT)
|
||||
X(AST_TCALL)
|
||||
X(AST_ASSIGN)
|
||||
X(AST_CELL)
|
||||
|
@ -175,6 +182,10 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
|
|||
// (the optional child arguments make it easier to create AST trees)
|
||||
AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
|
||||
{
|
||||
static unsigned int hashidx_count = 123456789;
|
||||
hashidx_count = mkhash_xorshift(hashidx_count);
|
||||
hashidx_ = hashidx_count;
|
||||
|
||||
this->type = type;
|
||||
filename = current_filename;
|
||||
linenum = get_line_num();
|
||||
|
@ -267,7 +278,7 @@ void AstNode::dumpAst(FILE *f, std::string indent)
|
|||
bits[i-1] == RTLIL::S1 ? '1' :
|
||||
bits[i-1] == RTLIL::Sx ? 'x' :
|
||||
bits[i-1] == RTLIL::Sz ? 'z' : '?');
|
||||
fprintf(f, "'(%zd)", bits.size());
|
||||
fprintf(f, "'(%d)", GetSize(bits));
|
||||
}
|
||||
if (is_input)
|
||||
fprintf(f, " input");
|
||||
|
@ -471,7 +482,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
|
|||
else if (bits.size() == 32)
|
||||
fprintf(f, "%d", RTLIL::Const(bits).as_int());
|
||||
else
|
||||
fprintf(f, "%zd'b %s", bits.size(), RTLIL::Const(bits).as_string().c_str());
|
||||
fprintf(f, "%d'b %s", GetSize(bits), RTLIL::Const(bits).as_string().c_str());
|
||||
break;
|
||||
|
||||
case AST_REALVALUE:
|
||||
|
@ -701,6 +712,8 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
|
|||
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
|
||||
{
|
||||
AstNode *node = mkconst_str(RTLIL::Const(v).decode_string());
|
||||
while (GetSize(node->bits) < GetSize(v))
|
||||
node->bits.push_back(RTLIL::State::S0);
|
||||
log_assert(node->bits == v);
|
||||
return node;
|
||||
}
|
||||
|
@ -946,6 +959,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
|
|||
|
||||
current_module->ast = ast_before_simplify;
|
||||
current_module->nolatches = flag_nolatches;
|
||||
current_module->nomeminit = flag_nomeminit;
|
||||
current_module->nomem2reg = flag_nomem2reg;
|
||||
current_module->mem2reg = flag_mem2reg;
|
||||
current_module->lib = flag_lib;
|
||||
|
@ -957,13 +971,14 @@ static AstModule* process_module(AstNode *ast, bool defer)
|
|||
}
|
||||
|
||||
// create AstModule instances for all modules in the AST tree and add them to 'design'
|
||||
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
|
||||
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
|
||||
{
|
||||
current_ast = ast;
|
||||
flag_dump_ast1 = dump_ast1;
|
||||
flag_dump_ast2 = dump_ast2;
|
||||
flag_dump_vlog = dump_vlog;
|
||||
flag_nolatches = nolatches;
|
||||
flag_nomeminit = nomeminit;
|
||||
flag_nomem2reg = nomem2reg;
|
||||
flag_mem2reg = mem2reg;
|
||||
flag_lib = lib;
|
||||
|
@ -1011,7 +1026,7 @@ AstModule::~AstModule()
|
|||
}
|
||||
|
||||
// create a new parametric module (when needed) and return the name of the generated module
|
||||
RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
|
||||
RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters)
|
||||
{
|
||||
std::string stripped_name = name.str();
|
||||
|
||||
|
@ -1025,6 +1040,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
|
|||
flag_dump_ast2 = false;
|
||||
flag_dump_vlog = false;
|
||||
flag_nolatches = nolatches;
|
||||
flag_nomeminit = nomeminit;
|
||||
flag_nomem2reg = nomem2reg;
|
||||
flag_mem2reg = mem2reg;
|
||||
flag_lib = lib;
|
||||
|
@ -1091,6 +1107,7 @@ RTLIL::Module *AstModule::clone() const
|
|||
|
||||
new_mod->ast = ast->clone();
|
||||
new_mod->nolatches = nolatches;
|
||||
new_mod->nomeminit = nomeminit;
|
||||
new_mod->nomem2reg = nomem2reg;
|
||||
new_mod->mem2reg = mem2reg;
|
||||
new_mod->lib = lib;
|
||||
|
|
|
@ -64,6 +64,7 @@ namespace AST
|
|||
AST_IDENTIFIER,
|
||||
AST_PREFIX,
|
||||
AST_ASSERT,
|
||||
AST_ASSUME,
|
||||
|
||||
AST_FCALL,
|
||||
AST_TO_BITS,
|
||||
|
@ -107,6 +108,7 @@ namespace AST
|
|||
AST_TERNARY,
|
||||
AST_MEMRD,
|
||||
AST_MEMWR,
|
||||
AST_MEMINIT,
|
||||
|
||||
AST_TCALL,
|
||||
AST_ASSIGN,
|
||||
|
@ -142,6 +144,10 @@ namespace AST
|
|||
// The AST is built using instances of this struct
|
||||
struct AstNode
|
||||
{
|
||||
// for dict<> and pool<>
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
|
||||
// this nodes type
|
||||
AstNodeType type;
|
||||
|
||||
|
@ -204,11 +210,13 @@ namespace AST
|
|||
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
|
||||
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
|
||||
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
|
||||
AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr);
|
||||
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
|
||||
void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
|
||||
void mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
|
||||
std::map<AstNode*, uint32_t> &mem2reg_flags, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
|
||||
void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
|
||||
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
|
||||
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
|
||||
void mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
|
||||
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
|
||||
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
|
||||
|
||||
// additional functionality for evaluating constant functions
|
||||
|
@ -229,7 +237,7 @@ namespace AST
|
|||
// for expressions the resulting signal vector is returned
|
||||
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
|
||||
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
|
||||
RTLIL::SigSpec genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
|
||||
RTLIL::SigSpec genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
|
||||
|
||||
// compare AST nodes
|
||||
bool operator==(const AstNode &other) const;
|
||||
|
@ -258,15 +266,15 @@ namespace AST
|
|||
};
|
||||
|
||||
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
|
||||
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
|
||||
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
|
||||
|
||||
// parametric modules are supported directly by the AST library
|
||||
// therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
|
||||
struct AstModule : RTLIL::Module {
|
||||
AstNode *ast;
|
||||
bool nolatches, nomem2reg, mem2reg, lib, noopt, icells, autowire;
|
||||
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
|
||||
virtual ~AstModule();
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
|
||||
virtual RTLIL::Module *clone() const;
|
||||
};
|
||||
|
||||
|
@ -288,12 +296,12 @@ namespace AST
|
|||
namespace AST_INTERNAL
|
||||
{
|
||||
// internal state variables
|
||||
extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
||||
extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
||||
extern AST::AstNode *current_ast, *current_ast_mod;
|
||||
extern std::map<std::string, AST::AstNode*> current_scope;
|
||||
extern const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
|
||||
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
|
||||
extern RTLIL::SigSpec ignoreThisSignalsInInitial;
|
||||
extern AST::AstNode *current_top_block, *current_block, *current_block_child;
|
||||
extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;
|
||||
extern AST::AstModule *current_module;
|
||||
struct ProcessGenerator;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <dlfcn.h>
|
||||
#include <ffi.h>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
typedef void (*ffi_fptr) ();
|
||||
|
||||
static ffi_fptr resolve_fn (std::string symbol_name)
|
||||
|
@ -73,8 +75,8 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
|
|||
|
||||
log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());
|
||||
|
||||
log_assert(SIZE(args) == SIZE(argtypes));
|
||||
for (int i = 0; i < SIZE(args); i++) {
|
||||
log_assert(GetSize(args) == GetSize(argtypes));
|
||||
for (int i = 0; i < GetSize(args); i++) {
|
||||
if (argtypes[i] == "real") {
|
||||
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
|
||||
value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
|
||||
|
@ -129,12 +131,18 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
|
|||
return newNode;
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#else /* YOSYS_ENABLE_PLUGINS */
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
|
||||
{
|
||||
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif /* YOSYS_ENABLE_PLUGINS */
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
|
|||
static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_signed)
|
||||
{
|
||||
if (width <= sig.size()) {
|
||||
sig.extend(width, is_signed);
|
||||
sig.extend_u0(width, is_signed);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
// create initial assignments for the temporary signals
|
||||
if ((flag_nolatches || always->get_bool_attribute("\\nolatches") || current_module->get_bool_attribute("\\nolatches")) && !found_clocked_sync) {
|
||||
subst_rvalue_map = subst_lvalue_from.to_sigbit_map(RTLIL::SigSpec(RTLIL::State::Sx, SIZE(subst_lvalue_from)));
|
||||
subst_rvalue_map = subst_lvalue_from.to_sigbit_dict(RTLIL::SigSpec(RTLIL::State::Sx, GetSize(subst_lvalue_from)));
|
||||
} else {
|
||||
addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
|
||||
}
|
||||
|
@ -289,8 +289,8 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
{
|
||||
RTLIL::SigSpec new_lhs, new_rhs;
|
||||
|
||||
log_assert(SIZE(lhs) == SIZE(rhs));
|
||||
for (int i = 0; i < SIZE(lhs); i++) {
|
||||
log_assert(GetSize(lhs) == GetSize(rhs));
|
||||
for (int i = 0; i < GetSize(lhs); i++) {
|
||||
if (lhs[i].wire == nullptr)
|
||||
continue;
|
||||
new_lhs.append(lhs[i]);
|
||||
|
@ -306,7 +306,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
{
|
||||
std::vector<RTLIL::SigChunk> chunks = sig.chunks();
|
||||
|
||||
for (int i = 0; i < SIZE(chunks); i++)
|
||||
for (int i = 0; i < GetSize(chunks); i++)
|
||||
{
|
||||
RTLIL::SigChunk &chunk = chunks[i];
|
||||
if (chunk.wire == NULL)
|
||||
|
@ -430,7 +430,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
lvalue.replace(subst_lvalue_map.stdmap());
|
||||
|
||||
if (ast->type == AST_ASSIGN_EQ) {
|
||||
for (int i = 0; i < SIZE(unmapped_lvalue); i++)
|
||||
for (int i = 0; i < GetSize(unmapped_lvalue); i++)
|
||||
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
|
||||
}
|
||||
|
||||
|
@ -472,7 +472,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
subst_lvalue_map.save();
|
||||
subst_rvalue_map.save();
|
||||
|
||||
for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
|
||||
for (int i = 0; i < GetSize(this_case_eq_lvalue); i++)
|
||||
subst_lvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
|
||||
|
||||
RTLIL::CaseRule *backup_case = current_case;
|
||||
|
@ -507,7 +507,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
sw->cases.push_back(default_case);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
|
||||
for (int i = 0; i < GetSize(this_case_eq_lvalue); i++)
|
||||
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
|
||||
|
||||
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
|
||||
|
@ -567,9 +567,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
|
||||
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
|
||||
} else
|
||||
if (id_ast->children[0]->type == AST_CONSTANT) {
|
||||
if (id_ast->children[0]->type != AST_CONSTANT)
|
||||
while (id_ast->simplify(true, false, false, 1, -1, false, true)) { }
|
||||
if (id_ast->children[0]->type == AST_CONSTANT)
|
||||
this_width = id_ast->children[0]->bits.size();
|
||||
} else
|
||||
else
|
||||
log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
if (children.size() != 0)
|
||||
range = children[0];
|
||||
|
@ -839,14 +841,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
memory->name = str;
|
||||
memory->width = children[0]->range_left - children[0]->range_right + 1;
|
||||
memory->start_offset = children[0]->range_right;
|
||||
memory->size = children[1]->range_left - children[1]->range_right;
|
||||
if (children[1]->range_right < children[1]->range_left) {
|
||||
memory->start_offset = children[1]->range_right;
|
||||
memory->size = children[1]->range_left - children[1]->range_right + 1;
|
||||
} else {
|
||||
memory->start_offset = children[1]->range_left;
|
||||
memory->size = children[1]->range_right - children[1]->range_left + 1;
|
||||
}
|
||||
current_module->memories[memory->name] = memory;
|
||||
|
||||
if (memory->size < 0)
|
||||
memory->size *= -1;
|
||||
memory->size += std::min(children[1]->range_left, children[1]->range_right) + 1;
|
||||
|
||||
for (auto &attr : attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
|
@ -869,7 +872,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
case AST_REALVALUE:
|
||||
{
|
||||
RTLIL::SigSpec sig = realAsConst(width_hint);
|
||||
log("Warning: converting real value %e to binary %s at %s:%d.\n",
|
||||
log_warning("converting real value %e to binary %s at %s:%d.\n",
|
||||
realvalue, log_signal(sig), filename.c_str(), linenum);
|
||||
return sig;
|
||||
}
|
||||
|
@ -890,7 +893,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
wire->name = str;
|
||||
if (flag_autowire)
|
||||
log("Warning: Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_warning("Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
else
|
||||
log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum);
|
||||
}
|
||||
|
@ -941,7 +944,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed);
|
||||
fake_ast->children[1]->is_signed = true;
|
||||
}
|
||||
if (SIZE(shift_val) >= 32)
|
||||
if (GetSize(shift_val) >= 32)
|
||||
fake_ast->children[1]->is_signed = true;
|
||||
RTLIL::SigSpec sig = binop2rtlil(fake_ast, "$shiftx", width, fake_ast->children[0]->genRTLIL(), shift_val);
|
||||
delete left_at_zero_ast;
|
||||
|
@ -955,10 +958,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width);
|
||||
if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
|
||||
if (chunk.width == 1)
|
||||
log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
|
||||
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
else
|
||||
log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
|
||||
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
|
||||
str.c_str(), filename.c_str(), linenum, chunk.width);
|
||||
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
|
||||
} else {
|
||||
|
@ -972,10 +975,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
chunk.offset += add_undef_bits_lsb;
|
||||
}
|
||||
if (add_undef_bits_lsb)
|
||||
log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
|
||||
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
|
||||
str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb);
|
||||
if (add_undef_bits_msb)
|
||||
log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
|
||||
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
|
||||
str.c_str(), filename.c_str(), linenum, add_undef_bits_msb);
|
||||
}
|
||||
}
|
||||
|
@ -1213,9 +1216,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width);
|
||||
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
|
||||
int addr_bits = 1;
|
||||
while ((1 << addr_bits) < current_module->memories[str]->size)
|
||||
addr_bits++;
|
||||
int mem_width, mem_size, addr_bits;
|
||||
id2ast->meminfo(mem_width, mem_size, addr_bits);
|
||||
|
||||
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
|
||||
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
|
||||
|
@ -1234,28 +1236,30 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
|
||||
// generate $memwr cells for memory write ports
|
||||
case AST_MEMWR:
|
||||
case AST_MEMINIT:
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||
sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memwr");
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit");
|
||||
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
|
||||
int addr_bits = 1;
|
||||
while ((1 << addr_bits) < current_module->memories[str]->size)
|
||||
addr_bits++;
|
||||
int mem_width, mem_size, addr_bits;
|
||||
id2ast->meminfo(mem_width, mem_size, addr_bits);
|
||||
|
||||
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
|
||||
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
|
||||
cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width));
|
||||
cell->setPort("\\EN", children[2]->genRTLIL());
|
||||
|
||||
cell->parameters["\\MEMID"] = RTLIL::Const(str);
|
||||
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
|
||||
cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
|
||||
|
||||
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
|
||||
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
|
||||
if (type == AST_MEMWR) {
|
||||
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
|
||||
cell->setPort("\\EN", children[2]->genRTLIL());
|
||||
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
|
||||
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
|
||||
}
|
||||
|
||||
cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);
|
||||
}
|
||||
|
@ -1263,19 +1267,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
|
||||
// generate $assert cells
|
||||
case AST_ASSERT:
|
||||
case AST_ASSUME:
|
||||
{
|
||||
log_assert(children.size() == 2);
|
||||
|
||||
RTLIL::SigSpec check = children[0]->genRTLIL();
|
||||
log_assert(check.size() == 1);
|
||||
if (GetSize(check) != 1)
|
||||
check = current_module->ReduceBool(NEW_ID, check);
|
||||
|
||||
RTLIL::SigSpec en = children[1]->genRTLIL();
|
||||
log_assert(en.size() == 1);
|
||||
if (GetSize(en) != 1)
|
||||
en = current_module->ReduceBool(NEW_ID, en);
|
||||
|
||||
std::stringstream sstr;
|
||||
sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||
sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++);
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$assert");
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume");
|
||||
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
|
||||
for (auto &attr : attributes) {
|
||||
|
@ -1293,15 +1300,23 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
// add entries to current_module->connections for assignments (outside of always blocks)
|
||||
case AST_ASSIGN:
|
||||
{
|
||||
if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_AUTOWIRE) {
|
||||
RTLIL::SigSpec right = children[1]->genRTLIL();
|
||||
RTLIL::SigSpec left = children[0]->genWidthRTLIL(right.size());
|
||||
current_module->connect(RTLIL::SigSig(left, right));
|
||||
} else {
|
||||
RTLIL::SigSpec left = children[0]->genRTLIL();
|
||||
RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
|
||||
current_module->connect(RTLIL::SigSig(left, right));
|
||||
RTLIL::SigSpec left = children[0]->genRTLIL();
|
||||
RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
|
||||
if (left.has_const()) {
|
||||
RTLIL::SigSpec new_left, new_right;
|
||||
for (int i = 0; i < GetSize(left); i++)
|
||||
if (left[i].wire) {
|
||||
new_left.append(left[i]);
|
||||
new_right.append(right[i]);
|
||||
}
|
||||
log_warning("Ignoring assignment to constant bits at %s:%d:\n"
|
||||
" old assignment: %s = %s\n new assignment: %s = %s.\n",
|
||||
filename.c_str(), linenum, log_signal(left), log_signal(right),
|
||||
log_signal(new_left), log_signal(new_right));
|
||||
left = new_left;
|
||||
right = new_right;
|
||||
}
|
||||
current_module->connect(RTLIL::SigSig(left, right));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1326,16 +1341,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
continue;
|
||||
}
|
||||
if (child->type == AST_PARASET) {
|
||||
if (child->children[0]->type != AST_CONSTANT)
|
||||
log_error("Parameter `%s' with non-constant value at %s:%d!\n",
|
||||
child->str.c_str(), filename.c_str(), linenum);
|
||||
if (child->str.size() == 0) {
|
||||
char buf[100];
|
||||
snprintf(buf, 100, "$%d", ++para_counter);
|
||||
cell->parameters[buf] = child->children[0]->asParaConst();
|
||||
} else {
|
||||
cell->parameters[child->str] = child->children[0]->asParaConst();
|
||||
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
|
||||
if (child->children[0]->type == AST_REALVALUE) {
|
||||
log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n",
|
||||
log_id(cell), log_id(paraname), child->children[0]->realvalue,
|
||||
filename.c_str(), linenum);
|
||||
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
|
||||
strnode->cloneInto(child->children[0]);
|
||||
delete strnode;
|
||||
}
|
||||
if (child->children[0]->type != AST_CONSTANT)
|
||||
log_error("Parameter %s.%s with non-constant value at %s:%d!\n",
|
||||
log_id(cell), log_id(paraname), filename.c_str(), linenum);
|
||||
cell->parameters[paraname] = child->children[0]->asParaConst();
|
||||
continue;
|
||||
}
|
||||
if (child->type == AST_ARGUMENT) {
|
||||
|
@ -1391,9 +1409,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or
|
||||
// signals must be substituted before beeing used as input values (used by ProcessGenerator)
|
||||
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
|
||||
RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
|
||||
RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
|
||||
{
|
||||
const std::map<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
|
||||
const dict<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
|
||||
|
||||
if (new_subst_ptr)
|
||||
genRTLIL_subst_ptr = new_subst_ptr;
|
||||
|
|
|
@ -28,10 +28,12 @@
|
|||
|
||||
#include "kernel/log.h"
|
||||
#include "libs/sha1/sha1.h"
|
||||
#include "frontends/verilog/verilog_frontend.h"
|
||||
#include "ast.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
@ -47,39 +49,55 @@ using namespace AST_INTERNAL;
|
|||
// nodes that link to a different node using names and lexical scoping.
|
||||
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
|
||||
{
|
||||
static int recursion_counter = 0;
|
||||
static pair<string, int> last_blocking_assignment_warn;
|
||||
static bool deep_recursion_warning = false;
|
||||
|
||||
if (recursion_counter++ == 1000 && deep_recursion_warning) {
|
||||
log_warning("Deep recursion in AST simplifier.\nDoes this design contain insanely long expressions?\n");
|
||||
deep_recursion_warning = false;
|
||||
}
|
||||
|
||||
AstNode *newNode = NULL;
|
||||
bool did_something = false;
|
||||
|
||||
#if 0
|
||||
log("-------------\n");
|
||||
log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum);
|
||||
log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
|
||||
int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
|
||||
dumpAst(NULL, "> ");
|
||||
// dumpAst(NULL, "> ");
|
||||
#endif
|
||||
|
||||
if (stage == 0)
|
||||
{
|
||||
log_assert(type == AST_MODULE);
|
||||
last_blocking_assignment_warn = pair<string, int>();
|
||||
|
||||
deep_recursion_warning = true;
|
||||
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
|
||||
|
||||
if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg"))
|
||||
{
|
||||
std::map<AstNode*, std::set<std::string>> mem2reg_places;
|
||||
std::map<AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
|
||||
dict<AstNode*, pool<std::string>> mem2reg_places;
|
||||
dict<AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
|
||||
uint32_t flags = flag_mem2reg ? AstNode::MEM2REG_FL_ALL : 0;
|
||||
mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, dummy_proc_flags, flags);
|
||||
|
||||
std::set<AstNode*> mem2reg_set;
|
||||
pool<AstNode*> mem2reg_set;
|
||||
for (auto &it : mem2reg_candidates)
|
||||
{
|
||||
AstNode *mem = it.first;
|
||||
uint32_t memflags = it.second;
|
||||
bool this_nomeminit = flag_nomeminit;
|
||||
log_assert((memflags & ~0x00ffff00) == 0);
|
||||
|
||||
if (mem->get_bool_attribute("\\nomem2reg"))
|
||||
continue;
|
||||
|
||||
if (mem->get_bool_attribute("\\nomeminit") || get_bool_attribute("\\nomeminit"))
|
||||
this_nomeminit = true;
|
||||
|
||||
if (memflags & AstNode::MEM2REG_FL_FORCED)
|
||||
goto silent_activate;
|
||||
|
||||
|
@ -89,7 +107,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
if (memflags & AstNode::MEM2REG_FL_SET_ASYNC)
|
||||
goto verbose_activate;
|
||||
|
||||
if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE))
|
||||
if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit)
|
||||
goto verbose_activate;
|
||||
|
||||
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
|
||||
|
@ -100,13 +118,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
|
||||
verbose_activate:
|
||||
if (mem2reg_set.count(mem) == 0) {
|
||||
log("Warning: Replacing memory %s with list of registers.", mem->str.c_str());
|
||||
std::string message = stringf("Replacing memory %s with list of registers.", mem->str.c_str());
|
||||
bool first_element = true;
|
||||
for (auto &place : mem2reg_places[it.first]) {
|
||||
log("%s%s", first_element ? " See " : ", ", place.c_str());
|
||||
message += stringf("%s%s", first_element ? " See " : ", ", place.c_str());
|
||||
first_element = false;
|
||||
}
|
||||
log("\n");
|
||||
log_warning("%s\n", message.c_str());
|
||||
}
|
||||
|
||||
silent_activate:
|
||||
|
@ -141,6 +159,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
}
|
||||
|
||||
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
|
||||
recursion_counter--;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -149,11 +168,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
|
||||
// we do not look inside a task or function
|
||||
// (but as soon as a task of function is instanciated we process the generated AST as usual)
|
||||
if (type == AST_FUNCTION || type == AST_TASK)
|
||||
if (type == AST_FUNCTION || type == AST_TASK) {
|
||||
recursion_counter--;
|
||||
return false;
|
||||
}
|
||||
|
||||
// deactivate all calls to non-synthesis system taks
|
||||
if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$stop" || str == "$finish")) {
|
||||
if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" ||
|
||||
str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) {
|
||||
log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum);
|
||||
delete_children();
|
||||
str = std::string();
|
||||
}
|
||||
|
@ -182,6 +205,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
AstNode *first_node = this_wire_scope[node->str];
|
||||
if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0)
|
||||
goto wires_are_compatible;
|
||||
if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
|
||||
AstNode *r = node->children[0];
|
||||
if (r->range_valid && r->range_left == 0 && r->range_right == 0) {
|
||||
delete r;
|
||||
node->children.pop_back();
|
||||
}
|
||||
}
|
||||
if (first_node->children.size() != node->children.size())
|
||||
goto wires_are_incompatible;
|
||||
for (size_t j = 0; j < node->children.size(); j++) {
|
||||
|
@ -242,6 +272,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
auto backup_current_block = current_block;
|
||||
auto backup_current_block_child = current_block_child;
|
||||
auto backup_current_top_block = current_top_block;
|
||||
auto backup_current_always = current_always;
|
||||
|
||||
if (type == AST_ALWAYS || type == AST_INITIAL)
|
||||
current_always = this;
|
||||
|
||||
int backup_width_hint = width_hint;
|
||||
bool backup_sign_hint = sign_hint;
|
||||
|
@ -382,6 +416,41 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
}
|
||||
}
|
||||
|
||||
if (const_fold && type == AST_CASE)
|
||||
{
|
||||
while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
|
||||
if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
|
||||
std::vector<AstNode*> new_children;
|
||||
new_children.push_back(children[0]);
|
||||
for (int i = 1; i < GetSize(children); i++) {
|
||||
AstNode *child = children[i];
|
||||
log_assert(child->type == AST_COND);
|
||||
for (auto v : child->children) {
|
||||
if (v->type == AST_DEFAULT)
|
||||
goto keep_const_cond;
|
||||
if (v->type == AST_BLOCK)
|
||||
continue;
|
||||
while (v->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
|
||||
if (v->type == AST_CONSTANT && v->bits_only_01()) {
|
||||
if (v->bits == children[0]->bits) {
|
||||
while (i+1 < GetSize(children))
|
||||
delete children[++i];
|
||||
goto keep_const_cond;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
goto keep_const_cond;
|
||||
}
|
||||
if (0)
|
||||
keep_const_cond:
|
||||
new_children.push_back(child);
|
||||
else
|
||||
delete child;
|
||||
}
|
||||
new_children.swap(children);
|
||||
}
|
||||
}
|
||||
|
||||
// simplify all children first
|
||||
// (iterate by index as e.g. auto wires can add new children in the process)
|
||||
for (size_t i = 0; i < children.size(); i++) {
|
||||
|
@ -446,6 +515,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
current_block = backup_current_block;
|
||||
current_block_child = backup_current_block_child;
|
||||
current_top_block = backup_current_top_block;
|
||||
current_always = backup_current_always;
|
||||
|
||||
for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {
|
||||
if (it->second == NULL)
|
||||
|
@ -575,9 +645,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
{
|
||||
AstNode *index_expr = nullptr;
|
||||
|
||||
for (int i = 0; 2*i < SIZE(id2ast->multirange_dimensions); i++)
|
||||
for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++)
|
||||
{
|
||||
if (SIZE(children[0]->children) < i)
|
||||
if (GetSize(children[0]->children) < i)
|
||||
log_error("Insufficient number of array indices for %s at %s:%d.\n", log_id(str), filename.c_str(), linenum);
|
||||
|
||||
AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone();
|
||||
|
@ -591,7 +661,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i-1], true)), new_index_expr);
|
||||
}
|
||||
|
||||
for (int i = SIZE(id2ast->multirange_dimensions)/1; i < SIZE(children[0]->children); i++)
|
||||
for (int i = GetSize(id2ast->multirange_dimensions)/1; i < GetSize(children[0]->children); i++)
|
||||
children.push_back(children[0]->children[i]->clone());
|
||||
|
||||
delete children[0];
|
||||
|
@ -611,7 +681,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
int width = children[1]->range_left - children[1]->range_right + 1;
|
||||
if (children[0]->type == AST_REALVALUE) {
|
||||
RTLIL::Const constvalue = children[0]->realAsConst(width);
|
||||
log("Warning: converting real value %e to binary %s at %s:%d.\n",
|
||||
log_warning("converting real value %e to binary %s at %s:%d.\n",
|
||||
children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum);
|
||||
delete children[0];
|
||||
children[0] = mkconst_bits(constvalue.bits, sign_hint);
|
||||
|
@ -653,7 +723,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
}
|
||||
}
|
||||
if (current_scope.count(str) == 0) {
|
||||
// log("Warning: Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
|
||||
// log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
|
||||
AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
|
||||
auto_wire->str = str;
|
||||
current_ast_mod->children.push_back(auto_wire);
|
||||
|
@ -1123,7 +1193,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
|
||||
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
result_width = abs(left_at_zero_ast->integer - right_at_zero_ast->integer) + 1;
|
||||
result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
|
||||
}
|
||||
did_something = true;
|
||||
newNode = new AstNode(AST_CASE, shift_expr);
|
||||
|
@ -1141,7 +1211,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
}
|
||||
skip_dynamic_range_lvalue_expansion:;
|
||||
|
||||
if (stage > 1 && type == AST_ASSERT && current_block != NULL)
|
||||
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||
|
@ -1185,7 +1255,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
newNode->children.push_back(assign_check);
|
||||
newNode->children.push_back(assign_en);
|
||||
|
||||
AstNode *assertnode = new AstNode(AST_ASSERT);
|
||||
AstNode *assertnode = new AstNode(type);
|
||||
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||
assertnode->children[0]->str = id_check;
|
||||
|
@ -1196,9 +1266,8 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
goto apply_newNode;
|
||||
}
|
||||
|
||||
if (stage > 1 && type == AST_ASSERT && children.size() == 1)
|
||||
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && children.size() == 1)
|
||||
{
|
||||
children[0] = new AstNode(AST_REDUCE_BOOL, children[0]->clone());
|
||||
children.push_back(mkconst_int(1, false, 1));
|
||||
did_something = true;
|
||||
}
|
||||
|
@ -1222,9 +1291,13 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
|
||||
|
||||
if (type == AST_ASSIGN_EQ)
|
||||
log("Warning: Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
|
||||
filename.c_str(), linenum);
|
||||
if (type == AST_ASSIGN_EQ) {
|
||||
pair<string, int> this_blocking_assignment_warn(filename, linenum);
|
||||
if (this_blocking_assignment_warn != last_blocking_assignment_warn)
|
||||
log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
|
||||
filename.c_str(), linenum);
|
||||
last_blocking_assignment_warn = this_blocking_assignment_warn;
|
||||
}
|
||||
|
||||
int mem_width, mem_size, addr_bits;
|
||||
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
|
||||
|
@ -1241,11 +1314,14 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
current_scope[wire_data->str] = wire_data;
|
||||
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
|
||||
|
||||
AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
||||
wire_en->str = id_en;
|
||||
current_ast_mod->children.push_back(wire_en);
|
||||
current_scope[wire_en->str] = wire_en;
|
||||
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
|
||||
AstNode *wire_en = nullptr;
|
||||
if (current_always->type != AST_INITIAL) {
|
||||
wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
||||
wire_en->str = id_en;
|
||||
current_ast_mod->children.push_back(wire_en);
|
||||
current_scope[wire_en->str] = wire_en;
|
||||
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
|
||||
}
|
||||
|
||||
std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;
|
||||
for (int i = 0; i < addr_bits; i++)
|
||||
|
@ -1261,13 +1337,17 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));
|
||||
assign_data->children[0]->str = id_data;
|
||||
|
||||
AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
|
||||
assign_en->children[0]->str = id_en;
|
||||
AstNode *assign_en = nullptr;
|
||||
if (current_always->type != AST_INITIAL) {
|
||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
|
||||
assign_en->children[0]->str = id_en;
|
||||
}
|
||||
|
||||
AstNode *default_signals = new AstNode(AST_BLOCK);
|
||||
default_signals->children.push_back(assign_addr);
|
||||
default_signals->children.push_back(assign_data);
|
||||
default_signals->children.push_back(assign_en);
|
||||
if (current_always->type != AST_INITIAL)
|
||||
default_signals->children.push_back(assign_en);
|
||||
current_top_block->children.insert(current_top_block->children.begin(), default_signals);
|
||||
|
||||
assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
|
||||
|
@ -1282,15 +1362,16 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
|
||||
std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx);
|
||||
|
||||
for (int i = 0; i < mem_width; i++)
|
||||
set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
|
||||
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
||||
new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));
|
||||
assign_data->children[0]->str = id_data;
|
||||
|
||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
|
||||
assign_en->children[0]->str = id_en;
|
||||
if (current_always->type != AST_INITIAL) {
|
||||
for (int i = 0; i < mem_width; i++)
|
||||
set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
|
||||
assign_en->children[0]->str = id_en;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1305,16 +1386,17 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
|
||||
|
||||
for (int i = 0; i < mem_width; i++)
|
||||
set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
|
||||
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
||||
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
|
||||
assign_data->children[0]->str = id_data;
|
||||
|
||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
||||
new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
|
||||
assign_en->children[0]->str = id_en;
|
||||
if (current_always->type != AST_INITIAL) {
|
||||
for (int i = 0; i < mem_width; i++)
|
||||
set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
|
||||
new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
|
||||
assign_en->children[0]->str = id_en;
|
||||
}
|
||||
|
||||
delete left_at_zero_ast;
|
||||
delete right_at_zero_ast;
|
||||
|
@ -1326,23 +1408,29 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
|
||||
assign_data->children[0]->str = id_data;
|
||||
|
||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
|
||||
assign_en->children[0]->str = id_en;
|
||||
if (current_always->type != AST_INITIAL) {
|
||||
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
|
||||
assign_en->children[0]->str = id_en;
|
||||
}
|
||||
}
|
||||
|
||||
newNode = new AstNode(AST_BLOCK);
|
||||
newNode->children.push_back(assign_addr);
|
||||
newNode->children.push_back(assign_data);
|
||||
newNode->children.push_back(assign_en);
|
||||
if (current_always->type != AST_INITIAL)
|
||||
newNode->children.push_back(assign_en);
|
||||
|
||||
AstNode *wrnode = new AstNode(AST_MEMWR);
|
||||
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||
AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR);
|
||||
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||
if (current_always->type != AST_INITIAL)
|
||||
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||
wrnode->str = children[0]->str;
|
||||
wrnode->id2ast = children[0]->id2ast;
|
||||
wrnode->children[0]->str = id_addr;
|
||||
wrnode->children[1]->str = id_data;
|
||||
wrnode->children[2]->str = id_en;
|
||||
if (current_always->type != AST_INITIAL)
|
||||
wrnode->children[2]->str = id_en;
|
||||
current_ast_mod->children.push_back(wrnode);
|
||||
|
||||
goto apply_newNode;
|
||||
|
@ -1366,7 +1454,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
|
||||
RTLIL::Const arg_value = buf->bitsAsConst();
|
||||
if (arg_value.as_bool())
|
||||
arg_value = const_sub(arg_value, 1, false, false, SIZE(arg_value));
|
||||
arg_value = const_sub(arg_value, 1, false, false, GetSize(arg_value));
|
||||
delete buf;
|
||||
|
||||
uint32_t result = 0;
|
||||
|
@ -1455,9 +1543,9 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str);
|
||||
fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str);
|
||||
|
||||
for (int i = 2; i < SIZE(dpi_decl->children); i++)
|
||||
for (int i = 2; i < GetSize(dpi_decl->children); i++)
|
||||
{
|
||||
if (i-2 >= SIZE(children))
|
||||
if (i-2 >= GetSize(children))
|
||||
log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum);
|
||||
|
||||
argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
|
||||
|
@ -1480,6 +1568,44 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
}
|
||||
if (type == AST_TCALL) {
|
||||
if (str == "\\$readmemh" || str == "\\$readmemb")
|
||||
{
|
||||
if (GetSize(children) < 2 || GetSize(children) > 4)
|
||||
log_error("System function %s got %d arguments, expected 2-4 at %s:%d.\n",
|
||||
RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
|
||||
|
||||
AstNode *node_filename = children[0]->clone();
|
||||
while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_filename->type != AST_CONSTANT)
|
||||
log_error("Failed to evaluate system function `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
|
||||
AstNode *node_memory = children[1]->clone();
|
||||
while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY)
|
||||
log_error("Failed to evaluate system function `%s' with non-memory 2nd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
|
||||
int start_addr = -1, finish_addr = -1;
|
||||
|
||||
if (GetSize(children) > 2) {
|
||||
AstNode *node_addr = children[2]->clone();
|
||||
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_addr->type != AST_CONSTANT)
|
||||
log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
start_addr = node_addr->asInt(false);
|
||||
}
|
||||
|
||||
if (GetSize(children) > 3) {
|
||||
AstNode *node_addr = children[3]->clone();
|
||||
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_addr->type != AST_CONSTANT)
|
||||
log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
finish_addr = node_addr->asInt(false);
|
||||
}
|
||||
|
||||
newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr);
|
||||
goto apply_newNode;
|
||||
}
|
||||
|
||||
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK)
|
||||
log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
}
|
||||
|
@ -1558,7 +1684,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
celltype = RTLIL::escape_id(celltype);
|
||||
|
||||
AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE));
|
||||
cell->str = prefix.substr(0, SIZE(prefix)-1);
|
||||
cell->str = prefix.substr(0, GetSize(prefix)-1);
|
||||
cell->children[0]->str = celltype;
|
||||
|
||||
for (auto attr : decl->attributes)
|
||||
|
@ -1681,7 +1807,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
bool param_upto = current_scope[str]->range_valid && current_scope[str]->range_swapped;
|
||||
int param_offset = current_scope[str]->range_valid ? current_scope[str]->range_right : 0;
|
||||
int param_width = current_scope[str]->range_valid ? current_scope[str]->range_left - current_scope[str]->range_right + 1 :
|
||||
SIZE(current_scope[str]->children[0]->bits);
|
||||
GetSize(current_scope[str]->children[0]->bits);
|
||||
int tmp_range_left = children[0]->range_left, tmp_range_right = children[0]->range_right;
|
||||
if (param_upto) {
|
||||
tmp_range_left = (param_width + 2*param_offset) - children[0]->range_right - 1;
|
||||
|
@ -1843,37 +1969,6 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
newNode->realvalue = -children[0]->asReal(sign_hint);
|
||||
}
|
||||
break;
|
||||
case AST_CASE:
|
||||
if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
|
||||
std::vector<AstNode*> new_children;
|
||||
new_children.push_back(children[0]);
|
||||
for (int i = 1; i < SIZE(children); i++) {
|
||||
AstNode *child = children[i];
|
||||
log_assert(child->type == AST_COND);
|
||||
for (auto v : child->children) {
|
||||
if (v->type == AST_DEFAULT)
|
||||
goto keep_const_cond;
|
||||
if (v->type == AST_BLOCK)
|
||||
continue;
|
||||
if (v->type == AST_CONSTANT && v->bits_only_01()) {
|
||||
if (v->bits == children[0]->bits) {
|
||||
while (i+1 < SIZE(children))
|
||||
delete children[++i];
|
||||
goto keep_const_cond;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
goto keep_const_cond;
|
||||
}
|
||||
if (0)
|
||||
keep_const_cond:
|
||||
new_children.push_back(child);
|
||||
else
|
||||
delete child;
|
||||
}
|
||||
new_children.swap(children);
|
||||
}
|
||||
break;
|
||||
case AST_TERNARY:
|
||||
if (children[0]->isConst())
|
||||
{
|
||||
|
@ -1977,6 +2072,7 @@ apply_newNode:
|
|||
if (!did_something)
|
||||
basic_prep = true;
|
||||
|
||||
recursion_counter--;
|
||||
return did_something;
|
||||
}
|
||||
|
||||
|
@ -1988,6 +2084,83 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro
|
|||
node->str = to;
|
||||
}
|
||||
|
||||
// replace a readmem[bh] TCALL ast node with a block of memory assignments
|
||||
AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr)
|
||||
{
|
||||
AstNode *block = new AstNode(AST_BLOCK);
|
||||
|
||||
std::ifstream f;
|
||||
f.open(mem_filename.c_str());
|
||||
|
||||
if (f.fail())
|
||||
log_error("Can not open file `%s` for %s at %s:%d.\n", mem_filename.c_str(), str.c_str(), filename.c_str(), linenum);
|
||||
|
||||
log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid);
|
||||
int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right;
|
||||
int range_min = std::min(range_left, range_right), range_max = std::max(range_left, range_right);
|
||||
|
||||
if (start_addr < 0)
|
||||
start_addr = range_min;
|
||||
|
||||
if (finish_addr < 0)
|
||||
finish_addr = range_max;
|
||||
|
||||
bool in_comment = false;
|
||||
int increment = start_addr <= finish_addr ? +1 : -1;
|
||||
int cursor = start_addr;
|
||||
|
||||
while (!f.eof())
|
||||
{
|
||||
std::string line, token;
|
||||
std::getline(f, line);
|
||||
|
||||
for (int i = 0; i < GetSize(line); i++) {
|
||||
if (in_comment && line.substr(i, 2) == "*/") {
|
||||
line[i] = ' ';
|
||||
line[i+1] = ' ';
|
||||
in_comment = false;
|
||||
continue;
|
||||
}
|
||||
if (!in_comment && line.substr(i, 2) == "/*")
|
||||
in_comment = true;
|
||||
if (in_comment)
|
||||
line[i] = ' ';
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
token = next_token(line, " \t\r\n");
|
||||
if (token.empty() || token.substr(0, 2) == "//")
|
||||
break;
|
||||
|
||||
if (token[0] == '@') {
|
||||
token = token.substr(1);
|
||||
const char *nptr = token.c_str();
|
||||
char *endptr;
|
||||
cursor = strtol(nptr, &endptr, 16);
|
||||
if (!*nptr || *endptr)
|
||||
log_error("Can not parse address `%s` for %s at %s:%d.\n", nptr, str.c_str(), filename.c_str(), linenum);
|
||||
continue;
|
||||
}
|
||||
|
||||
AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token);
|
||||
|
||||
block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));
|
||||
block->children.back()->children[0]->str = memory->str;
|
||||
block->children.back()->children[0]->id2ast = memory;
|
||||
|
||||
if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
|
||||
break;
|
||||
cursor += increment;
|
||||
}
|
||||
|
||||
if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
|
||||
break;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
// annotate the names of all wires and other named objects in a generate block
|
||||
void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map)
|
||||
{
|
||||
|
@ -2063,8 +2236,8 @@ void AstNode::replace_ids(const std::string &prefix, const std::map<std::string,
|
|||
}
|
||||
|
||||
// helper function for mem2reg_as_needed_pass1
|
||||
static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
|
||||
std::map<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
|
||||
static void mark_memories_assign_lhs_complex(dict<AstNode*, pool<std::string>> &mem2reg_places,
|
||||
dict<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
|
||||
{
|
||||
for (auto &child : that->children)
|
||||
mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child);
|
||||
|
@ -2078,8 +2251,8 @@ static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::st
|
|||
}
|
||||
|
||||
// find memories that should be replaced by registers
|
||||
void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
|
||||
std::map<AstNode*, uint32_t> &mem2reg_candidates, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
|
||||
void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
|
||||
dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
|
||||
{
|
||||
uint32_t children_flags = 0;
|
||||
int ignore_children_counter = 0;
|
||||
|
@ -2141,7 +2314,7 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
|
|||
if (type == AST_MODULE && get_bool_attribute("\\mem2reg"))
|
||||
children_flags |= AstNode::MEM2REG_FL_ALL;
|
||||
|
||||
std::map<AstNode*, uint32_t> *proc_flags_p = NULL;
|
||||
dict<AstNode*, uint32_t> *proc_flags_p = NULL;
|
||||
|
||||
if (type == AST_ALWAYS) {
|
||||
int count_edge_events = 0;
|
||||
|
@ -2150,12 +2323,12 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
|
|||
count_edge_events++;
|
||||
if (count_edge_events != 1)
|
||||
children_flags |= AstNode::MEM2REG_FL_ASYNC;
|
||||
proc_flags_p = new std::map<AstNode*, uint32_t>;
|
||||
proc_flags_p = new dict<AstNode*, uint32_t>;
|
||||
}
|
||||
|
||||
if (type == AST_INITIAL) {
|
||||
children_flags |= AstNode::MEM2REG_FL_INIT;
|
||||
proc_flags_p = new std::map<AstNode*, uint32_t>;
|
||||
proc_flags_p = new dict<AstNode*, uint32_t>;
|
||||
}
|
||||
|
||||
uint32_t backup_flags = flags;
|
||||
|
@ -2173,20 +2346,33 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
|
|||
flags &= ~children_flags | backup_flags;
|
||||
|
||||
if (proc_flags_p) {
|
||||
#ifndef NDEBUG
|
||||
for (auto it : *proc_flags_p)
|
||||
log_assert((it.second & ~0xff000000) == 0);
|
||||
#endif
|
||||
delete proc_flags_p;
|
||||
}
|
||||
}
|
||||
|
||||
bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
|
||||
{
|
||||
if (type != AST_IDENTIFIER || !id2ast || !mem2reg_set.count(id2ast))
|
||||
return false;
|
||||
|
||||
if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1)
|
||||
log_error("Invalid array access at %s:%d.\n", filename.c_str(), linenum);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// actually replace memories with registers
|
||||
void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
|
||||
void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
|
||||
{
|
||||
if (type == AST_BLOCK)
|
||||
block = this;
|
||||
|
||||
if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL && children[0]->id2ast &&
|
||||
mem2reg_set.count(children[0]->id2ast) > 0 && children[0]->children[0]->children[0]->type != AST_CONSTANT)
|
||||
if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL &&
|
||||
children[0]->mem2reg_check(mem2reg_set) && children[0]->children[0]->children[0]->type != AST_CONSTANT)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||
|
@ -2242,7 +2428,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
|
|||
type = AST_ASSIGN_EQ;
|
||||
}
|
||||
|
||||
if (type == AST_IDENTIFIER && id2ast && mem2reg_set.count(id2ast) > 0)
|
||||
if (mem2reg_check(mem2reg_set))
|
||||
{
|
||||
AstNode *bit_part_sel = NULL;
|
||||
if (children.size() == 2)
|
||||
|
@ -2446,7 +2632,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
|||
}
|
||||
|
||||
log_assert(block != NULL);
|
||||
log_assert(variables.count(str));
|
||||
log_assert(variables.count(str) != 0);
|
||||
|
||||
while (!block->children.empty())
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
lexer.cc
|
||||
parser.output
|
||||
parser.tab.cc
|
||||
parser.tab.h
|
||||
ilang_lexer.cc
|
||||
ilang_parser.output
|
||||
ilang_parser.tab.cc
|
||||
ilang_parser.tab.h
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
|
||||
GENFILES += frontends/ilang/parser.tab.cc
|
||||
GENFILES += frontends/ilang/parser.tab.h
|
||||
GENFILES += frontends/ilang/parser.output
|
||||
GENFILES += frontends/ilang/lexer.cc
|
||||
GENFILES += frontends/ilang/ilang_parser.tab.cc
|
||||
GENFILES += frontends/ilang/ilang_parser.tab.h
|
||||
GENFILES += frontends/ilang/ilang_parser.output
|
||||
GENFILES += frontends/ilang/ilang_lexer.cc
|
||||
|
||||
frontends/ilang/parser.tab.cc: frontends/ilang/parser.y
|
||||
$(P) bison -d -r all -b frontends/ilang/parser frontends/ilang/parser.y
|
||||
$(Q) mv frontends/ilang/parser.tab.c frontends/ilang/parser.tab.cc
|
||||
frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y
|
||||
$(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser frontends/ilang/ilang_parser.y
|
||||
$(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc
|
||||
|
||||
frontends/ilang/parser.tab.h: frontends/ilang/parser.tab.cc
|
||||
frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc
|
||||
|
||||
frontends/ilang/lexer.cc: frontends/ilang/lexer.l
|
||||
$(P) flex -o frontends/ilang/lexer.cc frontends/ilang/lexer.l
|
||||
frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l
|
||||
$(P) flex -o frontends/ilang/ilang_lexer.cc frontends/ilang/ilang_lexer.l
|
||||
|
||||
OBJS += frontends/ilang/parser.tab.o frontends/ilang/lexer.o
|
||||
OBJS += frontends/ilang/ilang_parser.tab.o frontends/ilang/ilang_lexer.o
|
||||
OBJS += frontends/ilang/ilang_frontend.o
|
||||
|
||||
|
|
|
@ -26,13 +26,13 @@
|
|||
#include "kernel/register.h"
|
||||
#include "kernel/log.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
void rtlil_frontend_ilang_yyerror(char const *s)
|
||||
{
|
||||
log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
|
||||
YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct IlangFrontend : public Frontend {
|
||||
IlangFrontend() : Frontend("ilang", "read modules from ilang file") { }
|
||||
virtual void help()
|
||||
|
|
|
@ -30,10 +30,12 @@
|
|||
#endif
|
||||
|
||||
#include "ilang_frontend.h"
|
||||
#include "parser.tab.h"
|
||||
#include "ilang_parser.tab.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
result = ILANG_FRONTEND::lexin->readsome(buf, max_size);
|
||||
result = readsome(*ILANG_FRONTEND::lexin, buf, max_size)
|
||||
|
||||
%}
|
||||
|
|
@ -36,7 +36,7 @@ namespace ILANG_FRONTEND {
|
|||
RTLIL::Process *current_process;
|
||||
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
|
||||
std::vector<RTLIL::CaseRule*> case_stack;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> attrbuf;
|
||||
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
|
||||
}
|
||||
using namespace ILANG_FRONTEND;
|
||||
YOSYS_NAMESPACE_END
|
||||
|
@ -183,6 +183,9 @@ memory_options:
|
|||
memory_options TOK_SIZE TOK_INT {
|
||||
current_memory->size = $3;
|
||||
} |
|
||||
memory_options TOK_OFFSET TOK_INT {
|
||||
current_memory->start_offset = $3;
|
||||
} |
|
||||
/* empty */;
|
||||
|
||||
cell_stmt:
|
|
@ -22,7 +22,6 @@
|
|||
#include "kernel/log.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
using namespace PASS_DFFLIBMAP;
|
||||
|
||||
struct token_t {
|
||||
char type;
|
||||
|
|
|
@ -10,6 +10,7 @@ CONFIG := clang
|
|||
ENABLE_TCL := 0
|
||||
ENABLE_QT4 := 0
|
||||
ENABLE_ABC := 0
|
||||
ENABLE_PLUGINS := 0
|
||||
ENABLE_VERIFIC := 1
|
||||
CXXFLAGS += -m32
|
||||
LDFLAGS += -m32
|
||||
|
|
|
@ -20,11 +20,14 @@
|
|||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/log.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
|
@ -324,7 +327,7 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
|
|||
if (inst->GetCin()->IsGnd()) {
|
||||
module->addAdd(RTLIL::escape_id(inst->Name()), IN1, IN2, out, SIGNED);
|
||||
} else {
|
||||
RTLIL::SigSpec tmp = module->addWire(NEW_ID, SIZE(out));
|
||||
RTLIL::SigSpec tmp = module->addWire(NEW_ID, GetSize(out));
|
||||
module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED);
|
||||
module->addAdd(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetCin()), out, false);
|
||||
}
|
||||
|
@ -687,8 +690,8 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
|
|||
cell->parameters["\\CLK_ENABLE"] = false;
|
||||
cell->parameters["\\CLK_POLARITY"] = true;
|
||||
cell->parameters["\\TRANSPARENT"] = false;
|
||||
cell->parameters["\\ABITS"] = SIZE(addr);
|
||||
cell->parameters["\\WIDTH"] = SIZE(data);
|
||||
cell->parameters["\\ABITS"] = GetSize(addr);
|
||||
cell->parameters["\\WIDTH"] = GetSize(data);
|
||||
cell->setPort("\\CLK", RTLIL::State::S0);
|
||||
cell->setPort("\\ADDR", addr);
|
||||
cell->setPort("\\DATA", data);
|
||||
|
@ -709,9 +712,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
|
|||
cell->parameters["\\CLK_ENABLE"] = false;
|
||||
cell->parameters["\\CLK_POLARITY"] = true;
|
||||
cell->parameters["\\PRIORITY"] = 0;
|
||||
cell->parameters["\\ABITS"] = SIZE(addr);
|
||||
cell->parameters["\\WIDTH"] = SIZE(data);
|
||||
cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(SIZE(data)));
|
||||
cell->parameters["\\ABITS"] = GetSize(addr);
|
||||
cell->parameters["\\WIDTH"] = GetSize(data);
|
||||
cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(GetSize(data)));
|
||||
cell->setPort("\\CLK", RTLIL::State::S0);
|
||||
cell->setPort("\\ADDR", addr);
|
||||
cell->setPort("\\DATA", data);
|
||||
|
@ -727,7 +730,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
|
|||
if (import_netlist_instance_cells(module, net_map, inst))
|
||||
continue;
|
||||
if (inst->IsOperator())
|
||||
log("Warning: Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name());
|
||||
log_warning("Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name());
|
||||
} else {
|
||||
if (import_netlist_instance_gates(module, net_map, inst))
|
||||
continue;
|
||||
|
@ -753,9 +756,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
|
|||
RTLIL::SigSpec conn;
|
||||
if (cell->hasPort(RTLIL::escape_id(port_name)))
|
||||
conn = cell->getPort(RTLIL::escape_id(port_name));
|
||||
while (SIZE(conn) <= port_offset) {
|
||||
while (GetSize(conn) <= port_offset) {
|
||||
if (pr->GetPort()->GetDir() != DIR_IN)
|
||||
conn.append(module->addWire(NEW_ID, port_offset - SIZE(conn)));
|
||||
conn.append(module->addWire(NEW_ID, port_offset - GetSize(conn)));
|
||||
conn.append(RTLIL::State::Sz);
|
||||
}
|
||||
conn.replace(port_offset, net_map.at(pr->GetNet()));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
lexer.cc
|
||||
parser.output
|
||||
parser.tab.cc
|
||||
parser.tab.h
|
||||
verilog_lexer.cc
|
||||
verilog_parser.output
|
||||
verilog_parser.tab.cc
|
||||
verilog_parser.tab.h
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
|
||||
GENFILES += frontends/verilog/parser.tab.cc
|
||||
GENFILES += frontends/verilog/parser.tab.h
|
||||
GENFILES += frontends/verilog/parser.output
|
||||
GENFILES += frontends/verilog/lexer.cc
|
||||
GENFILES += frontends/verilog/verilog_parser.tab.cc
|
||||
GENFILES += frontends/verilog/verilog_parser.tab.h
|
||||
GENFILES += frontends/verilog/verilog_parser.output
|
||||
GENFILES += frontends/verilog/verilog_lexer.cc
|
||||
|
||||
frontends/verilog/parser.tab.cc: frontends/verilog/parser.y
|
||||
$(P) bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y
|
||||
$(Q) mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc
|
||||
frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
|
||||
$(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser frontends/verilog/verilog_parser.y
|
||||
$(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc
|
||||
|
||||
frontends/verilog/parser.tab.h: frontends/verilog/parser.tab.cc
|
||||
frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc
|
||||
|
||||
frontends/verilog/lexer.cc: frontends/verilog/lexer.l
|
||||
$(P) flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
|
||||
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
|
||||
$(P) flex -o frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_lexer.l
|
||||
|
||||
OBJS += frontends/verilog/parser.tab.o
|
||||
OBJS += frontends/verilog/lexer.o
|
||||
OBJS += frontends/verilog/verilog_parser.tab.o
|
||||
OBJS += frontends/verilog/verilog_lexer.o
|
||||
OBJS += frontends/verilog/preproc.o
|
||||
OBJS += frontends/verilog/verilog_frontend.o
|
||||
OBJS += frontends/verilog/const2ast.o
|
||||
|
|
|
@ -132,8 +132,16 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
|
|||
}
|
||||
|
||||
// convert the verilog code for a constant to an AST node
|
||||
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
|
||||
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)
|
||||
{
|
||||
if (warn_z) {
|
||||
AstNode *ret = const2ast(code, case_type);
|
||||
if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
|
||||
log_warning("Yosys does not support tri-state logic at the moment. (%s:%d)\n",
|
||||
current_filename.c_str(), frontend_verilog_yyget_lineno());
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *str = code.c_str();
|
||||
|
||||
// Strings
|
||||
|
@ -174,7 +182,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
|
|||
if (str == endptr)
|
||||
len_in_bits = -1;
|
||||
|
||||
// The "<bits>'s?[bodh]<digits>" syntax
|
||||
// The "<bits>'s?[bodhBODH]<digits>" syntax
|
||||
if (*endptr == '\'')
|
||||
{
|
||||
std::vector<RTLIL::State> data;
|
||||
|
@ -186,15 +194,19 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
|
|||
switch (*(endptr+1))
|
||||
{
|
||||
case 'b':
|
||||
case 'B':
|
||||
my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
|
||||
break;
|
||||
case 'o':
|
||||
case 'O':
|
||||
my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -201,8 +201,8 @@ static void input_file(std::istream &f, std::string filename)
|
|||
insert_input("");
|
||||
auto it = input_buffer.begin();
|
||||
|
||||
input_buffer.insert(it, "`file_push " + filename + "\n");
|
||||
while ((rc = f.readsome(buffer, sizeof(buffer)-1)) > 0) {
|
||||
input_buffer.insert(it, "`file_push \"" + filename + "\"\n");
|
||||
while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) {
|
||||
buffer[rc] = 0;
|
||||
input_buffer.insert(it, buffer);
|
||||
}
|
||||
|
@ -221,7 +221,8 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
|
|||
input_buffer_charp = 0;
|
||||
|
||||
input_file(f, filename);
|
||||
defines_map["__YOSYS__"] = "1";
|
||||
defines_map["YOSYS"] = "1";
|
||||
defines_map["SYNTHESIS"] = "1";
|
||||
|
||||
while (!input_buffer.empty())
|
||||
{
|
||||
|
@ -422,7 +423,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
|
|||
if (tok == "(" || tok == "{" || tok == "[")
|
||||
level++;
|
||||
}
|
||||
for (size_t i = 0; i < args.size(); i++)
|
||||
for (int i = 0; i < GetSize(args); i++)
|
||||
defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i];
|
||||
} else {
|
||||
insert_input(tok);
|
||||
|
|
|
@ -54,6 +54,10 @@ struct VerilogFrontend : public Frontend {
|
|||
log(" enable support for SystemVerilog features. (only a small subset\n");
|
||||
log(" of SystemVerilog is supported)\n");
|
||||
log("\n");
|
||||
log(" -formal\n");
|
||||
log(" enable support for assert() and assume() statements\n");
|
||||
log(" (assert support is also enabled with -sv)\n");
|
||||
log("\n");
|
||||
log(" -dump_ast1\n");
|
||||
log(" dump abstract syntax tree (before simplification)\n");
|
||||
log("\n");
|
||||
|
@ -83,11 +87,20 @@ struct VerilogFrontend : public Frontend {
|
|||
log(" this can also be achieved by setting the 'nomem2reg'\n");
|
||||
log(" attribute on the respective module or register.\n");
|
||||
log("\n");
|
||||
log(" This is potentially dangerous. Usually the front-end has good\n");
|
||||
log(" reasons for converting an array to a list of registers.\n");
|
||||
log(" Prohibiting this step will likely result in incorrect synthesis\n");
|
||||
log(" results.\n");
|
||||
log("\n");
|
||||
log(" -mem2reg\n");
|
||||
log(" always convert memories to registers. this can also be\n");
|
||||
log(" achieved by setting the 'mem2reg' attribute on the respective\n");
|
||||
log(" module or register.\n");
|
||||
log("\n");
|
||||
log(" -nomeminit\n");
|
||||
log(" do not infer $meminit cells and instead convert initialized\n");
|
||||
log(" memories to registers directly in the front-end.\n");
|
||||
log("\n");
|
||||
log(" -ppdump\n");
|
||||
log(" dump verilog code after pre-processor\n");
|
||||
log("\n");
|
||||
|
@ -139,6 +152,7 @@ struct VerilogFrontend : public Frontend {
|
|||
bool flag_dump_ast2 = false;
|
||||
bool flag_dump_vlog = false;
|
||||
bool flag_nolatches = false;
|
||||
bool flag_nomeminit = false;
|
||||
bool flag_nomem2reg = false;
|
||||
bool flag_mem2reg = false;
|
||||
bool flag_ppdump = false;
|
||||
|
@ -154,6 +168,7 @@ struct VerilogFrontend : public Frontend {
|
|||
|
||||
frontend_verilog_yydebug = false;
|
||||
sv_mode = false;
|
||||
formal_mode = false;
|
||||
|
||||
log_header("Executing Verilog-2005 frontend.\n");
|
||||
|
||||
|
@ -166,6 +181,10 @@ struct VerilogFrontend : public Frontend {
|
|||
sv_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-formal") {
|
||||
formal_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dump_ast1") {
|
||||
flag_dump_ast1 = true;
|
||||
continue;
|
||||
|
@ -186,6 +205,10 @@ struct VerilogFrontend : public Frontend {
|
|||
flag_nolatches = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-nomeminit") {
|
||||
flag_nomeminit = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-nomem2reg") {
|
||||
flag_nomem2reg = true;
|
||||
continue;
|
||||
|
@ -257,7 +280,8 @@ struct VerilogFrontend : public Frontend {
|
|||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
log("Parsing Verilog input from `%s' to AST representation.\n", filename.c_str());
|
||||
log("Parsing %s%s input from `%s' to AST representation.\n",
|
||||
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
|
||||
|
||||
AST::current_filename = filename;
|
||||
AST::set_line_num = &frontend_verilog_yyset_lineno;
|
||||
|
@ -288,7 +312,7 @@ struct VerilogFrontend : public Frontend {
|
|||
child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
|
||||
}
|
||||
|
||||
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
|
||||
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
|
||||
|
||||
if (!flag_nopp)
|
||||
delete lexin;
|
||||
|
@ -300,22 +324,6 @@ struct VerilogFrontend : public Frontend {
|
|||
}
|
||||
} VerilogFrontend;
|
||||
|
||||
// the yyerror function used by bison to report parser errors
|
||||
void frontend_verilog_yyerror(char const *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[1024];
|
||||
char *p = buffer;
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
|
||||
AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
|
||||
va_start(ap, fmt);
|
||||
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
|
||||
va_end(ap);
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
|
||||
log_error("%s", buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct VerilogDefaults : public Pass {
|
||||
VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { }
|
||||
virtual void help()
|
||||
|
@ -376,3 +384,19 @@ struct VerilogDefaults : public Pass {
|
|||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
// the yyerror function used by bison to report parser errors
|
||||
void frontend_verilog_yyerror(char const *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[1024];
|
||||
char *p = buffer;
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
|
||||
YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
|
||||
va_start(ap, fmt);
|
||||
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
|
||||
va_end(ap);
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
|
||||
YOSYS_NAMESPACE_PREFIX log_error("%s", buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace VERILOG_FRONTEND
|
|||
extern struct AST::AstNode *current_ast;
|
||||
|
||||
// this function converts a Verilog constant to an AST_CONSTANT node
|
||||
AST::AstNode *const2ast(std::string code, char case_type = 0);
|
||||
AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
|
||||
|
||||
// state of `default_nettype
|
||||
extern bool default_nettype_wire;
|
||||
|
@ -51,6 +51,9 @@ namespace VERILOG_FRONTEND
|
|||
// running in SystemVerilog mode
|
||||
extern bool sv_mode;
|
||||
|
||||
// running in -formal mode
|
||||
extern bool formal_mode;
|
||||
|
||||
// lexer input stream
|
||||
extern std::istream *lexin;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#include "kernel/log.h"
|
||||
#include "verilog_frontend.h"
|
||||
#include "frontends/ast/ast.h"
|
||||
#include "parser.tab.h"
|
||||
#include "verilog_parser.tab.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
using namespace AST;
|
||||
|
@ -64,7 +64,7 @@ YOSYS_NAMESPACE_END
|
|||
return TOK_ID;
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
result = lexin->readsome(buf, max_size);
|
||||
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
|
||||
|
||||
%}
|
||||
|
||||
|
@ -85,6 +85,10 @@ YOSYS_NAMESPACE_END
|
|||
fn_stack.push_back(current_filename);
|
||||
ln_stack.push_back(frontend_verilog_yyget_lineno());
|
||||
current_filename = yytext+11;
|
||||
if (!current_filename.empty() && current_filename.front() == '"')
|
||||
current_filename = current_filename.substr(1);
|
||||
if (!current_filename.empty() && current_filename.back() == '"')
|
||||
current_filename = current_filename.substr(0, current_filename.size()-1);
|
||||
frontend_verilog_yyset_lineno(0);
|
||||
}
|
||||
|
||||
|
@ -112,6 +116,9 @@ YOSYS_NAMESPACE_END
|
|||
|
||||
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
|
||||
|
||||
"`celldefine"[^\n]* /* ignore `celldefine */
|
||||
"`endcelldefine"[^\n]* /* ignore `endcelldefine */
|
||||
|
||||
"`default_nettype"[ \t]+[^ \t\r\n/]+ {
|
||||
char *p = yytext;
|
||||
while (*p != 0 && *p != ' ' && *p != '\t') p++;
|
||||
|
@ -162,8 +169,9 @@ YOSYS_NAMESPACE_END
|
|||
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
|
||||
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
|
||||
|
||||
"assert" { SV_KEYWORD(TOK_ASSERT); }
|
||||
"property" { SV_KEYWORD(TOK_PROPERTY); }
|
||||
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
|
||||
"assume" { if (formal_mode) return TOK_ASSUME; return TOK_ID; }
|
||||
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
|
||||
"logic" { SV_KEYWORD(TOK_REG); }
|
||||
"bit" { SV_KEYWORD(TOK_REG); }
|
||||
|
||||
|
@ -177,12 +185,12 @@ YOSYS_NAMESPACE_END
|
|||
"genvar" { return TOK_GENVAR; }
|
||||
"real" { return TOK_REAL; }
|
||||
|
||||
[0-9]+ {
|
||||
[0-9][0-9_]* {
|
||||
frontend_verilog_yylval.string = new std::string(yytext);
|
||||
return TOK_CONST;
|
||||
}
|
||||
|
||||
[0-9]*[ \t]*\'s?[bodh][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
|
||||
[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
|
||||
frontend_verilog_yylval.string = new std::string(yytext);
|
||||
return TOK_CONST;
|
||||
}
|
||||
|
@ -240,7 +248,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
|
|||
supply0 { return TOK_SUPPLY0; }
|
||||
supply1 { return TOK_SUPPLY1; }
|
||||
|
||||
"$"(display|time|stop|finish) {
|
||||
"$"(display|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
|
||||
frontend_verilog_yylval.string = new std::string(yytext);
|
||||
return TOK_ID;
|
||||
}
|
||||
|
@ -254,8 +262,12 @@ supply1 { return TOK_SUPPLY1; }
|
|||
}
|
||||
|
||||
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
|
||||
log("Warning: Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n");
|
||||
log("It is strongly suggested to use `ifdef constructs instead!\n");
|
||||
static bool printed_warning = false;
|
||||
if (!printed_warning) {
|
||||
log_warning("Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n"
|
||||
"Yosys does support them but it is recommended to use `ifdef constructs instead!\n");
|
||||
printed_warning = true;
|
||||
}
|
||||
BEGIN(SYNOPSYS_TRANSLATE_OFF);
|
||||
}
|
||||
<SYNOPSYS_TRANSLATE_OFF>. /* ignore synopsys translate_off body */
|
||||
|
@ -266,13 +278,21 @@ supply1 { return TOK_SUPPLY1; }
|
|||
BEGIN(SYNOPSYS_FLAGS);
|
||||
}
|
||||
<SYNOPSYS_FLAGS>full_case {
|
||||
log("Warning: Found one of those horrible `(synopsys|synthesis) full_case' comments.\n");
|
||||
log("It is strongly suggested to use verilog x-values and default branches instead!\n");
|
||||
static bool printed_warning = false;
|
||||
if (!printed_warning) {
|
||||
log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n"
|
||||
"Yosys does support them but it is recommended to use verilog `full_case' attributes instead!\n");
|
||||
printed_warning = true;
|
||||
}
|
||||
return TOK_SYNOPSYS_FULL_CASE;
|
||||
}
|
||||
<SYNOPSYS_FLAGS>parallel_case {
|
||||
log("Warning: Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n");
|
||||
log("It is strongly suggested to use verilog `parallel_case' attributes instead!\n");
|
||||
static bool printed_warning = false;
|
||||
if (!printed_warning) {
|
||||
log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n"
|
||||
"Yosys does support them but it is recommended to use verilog `parallel_case' attributes instead!\n");
|
||||
printed_warning = true;
|
||||
}
|
||||
return TOK_SYNOPSYS_PARALLEL_CASE;
|
||||
}
|
||||
<SYNOPSYS_FLAGS>. /* ignore everything else */
|
||||
|
@ -342,7 +362,10 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
|
|||
[ \t\r\n] /* ignore whitespaces */
|
||||
\\[\r\n] /* ignore continuation sequence */
|
||||
"//"[^\r\n]* /* ignore one-line comments */
|
||||
"#"[$a-zA-Z_0-9\.]+ /* ignore simulation timings */
|
||||
|
||||
"#"\ *[0-9][0-9_]* /* ignore simulation timings */
|
||||
"#"\ *[0-9][0-9_]*\.[0-9][0-9_]* /* ignore simulation timings */
|
||||
"#"\ *[$a-zA-Z_\.][$a-zA-Z_0-9\.]* /* ignore simulation timings */
|
||||
|
||||
. { return *yytext; }
|
||||
|
|
@ -57,7 +57,7 @@ namespace VERILOG_FRONTEND {
|
|||
std::vector<char> case_type_stack;
|
||||
bool do_not_require_port_stubs;
|
||||
bool default_nettype_wire;
|
||||
bool sv_mode;
|
||||
bool sv_mode, formal_mode;
|
||||
std::istream *lexin;
|
||||
}
|
||||
YOSYS_NAMESPACE_END
|
||||
|
@ -111,7 +111,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
|||
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
|
||||
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
||||
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_PROPERTY
|
||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME TOK_PROPERTY
|
||||
|
||||
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
|
||||
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
||||
|
@ -139,10 +139,11 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
|||
%%
|
||||
|
||||
input: {
|
||||
ast_stack.clear();
|
||||
ast_stack.push_back(current_ast);
|
||||
} design {
|
||||
ast_stack.pop_back();
|
||||
log_assert(SIZE(ast_stack) == 0);
|
||||
log_assert(GetSize(ast_stack) == 0);
|
||||
for (auto &it : default_attr_list)
|
||||
delete it.second;
|
||||
default_attr_list.clear();
|
||||
|
@ -240,7 +241,7 @@ module:
|
|||
};
|
||||
|
||||
module_para_opt:
|
||||
'#' '(' module_para_list ')' | /* empty */;
|
||||
'#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */;
|
||||
|
||||
module_para_list:
|
||||
single_module_para |
|
||||
|
@ -249,11 +250,10 @@ module_para_list:
|
|||
|
||||
single_module_para:
|
||||
TOK_PARAMETER {
|
||||
if (astbuf1) delete astbuf1;
|
||||
astbuf1 = new AstNode(AST_PARAMETER);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
} param_signed param_integer param_range single_param_decl {
|
||||
delete astbuf1;
|
||||
};
|
||||
} param_signed param_integer param_range single_param_decl | single_param_decl;
|
||||
|
||||
module_args_opt:
|
||||
'(' ')' | /* empty */ | '(' module_args optional_comma ')';
|
||||
|
@ -310,10 +310,17 @@ module_arg:
|
|||
do_not_require_port_stubs = true;
|
||||
};
|
||||
|
||||
non_opt_delay:
|
||||
'#' '(' expr ')' { delete $3; } |
|
||||
'#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; };
|
||||
|
||||
delay:
|
||||
non_opt_delay | /* empty */;
|
||||
|
||||
wire_type:
|
||||
{
|
||||
astbuf3 = new AstNode(AST_WIRE);
|
||||
} wire_type_token_list {
|
||||
} wire_type_token_list delay {
|
||||
$$ = astbuf3;
|
||||
};
|
||||
|
||||
|
@ -449,7 +456,7 @@ task_func_decl:
|
|||
} opt_dpi_function_args ';' {
|
||||
current_function_or_task = NULL;
|
||||
} |
|
||||
attr TOK_TASK TOK_ID ';' {
|
||||
attr TOK_TASK TOK_ID {
|
||||
current_function_or_task = new AstNode(AST_TASK);
|
||||
current_function_or_task->str = *$3;
|
||||
append_attr(current_function_or_task, $1);
|
||||
|
@ -457,11 +464,11 @@ task_func_decl:
|
|||
ast_stack.push_back(current_function_or_task);
|
||||
current_function_or_task_port_id = 1;
|
||||
delete $3;
|
||||
} task_func_body TOK_ENDTASK {
|
||||
} task_func_args_opt ';' task_func_body TOK_ENDTASK {
|
||||
current_function_or_task = NULL;
|
||||
ast_stack.pop_back();
|
||||
} |
|
||||
attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' {
|
||||
attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID {
|
||||
current_function_or_task = new AstNode(AST_FUNCTION);
|
||||
current_function_or_task->str = *$5;
|
||||
append_attr(current_function_or_task, $1);
|
||||
|
@ -478,7 +485,7 @@ task_func_decl:
|
|||
current_function_or_task->children.push_back(outreg);
|
||||
current_function_or_task_port_id = 1;
|
||||
delete $5;
|
||||
} task_func_body TOK_ENDFUNCTION {
|
||||
} task_func_args_opt ';' task_func_body TOK_ENDFUNCTION {
|
||||
current_function_or_task = NULL;
|
||||
ast_stack.pop_back();
|
||||
};
|
||||
|
@ -512,6 +519,45 @@ opt_signed:
|
|||
$$ = false;
|
||||
};
|
||||
|
||||
task_func_args_opt:
|
||||
'(' ')' | /* empty */ | '(' {
|
||||
albuf = nullptr;
|
||||
astbuf1 = nullptr;
|
||||
astbuf2 = nullptr;
|
||||
} task_func_args optional_comma {
|
||||
delete astbuf1;
|
||||
if (astbuf2 != NULL)
|
||||
delete astbuf2;
|
||||
free_attr(albuf);
|
||||
} ')';
|
||||
|
||||
task_func_args:
|
||||
task_func_port | task_func_args ',' task_func_port;
|
||||
|
||||
task_func_port:
|
||||
attr wire_type range {
|
||||
if (albuf) {
|
||||
delete astbuf1;
|
||||
if (astbuf2 != NULL)
|
||||
delete astbuf2;
|
||||
free_attr(albuf);
|
||||
}
|
||||
albuf = $1;
|
||||
astbuf1 = $2;
|
||||
astbuf2 = $3;
|
||||
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
|
||||
if (astbuf2) {
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
} else {
|
||||
astbuf2 = new AstNode(AST_RANGE);
|
||||
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
|
||||
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true));
|
||||
}
|
||||
}
|
||||
if (astbuf2 && astbuf2->children.size() != 2)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
} wire_name | wire_name;
|
||||
|
||||
task_func_body:
|
||||
task_func_body behavioral_stmt |
|
||||
/* empty */;
|
||||
|
@ -568,6 +614,8 @@ param_decl_list:
|
|||
|
||||
single_param_decl:
|
||||
TOK_ID '=' expr {
|
||||
if (astbuf1 == nullptr)
|
||||
frontend_verilog_yyerror("syntax error");
|
||||
AstNode *node = astbuf1->clone();
|
||||
node->str = *$1;
|
||||
delete node->children[0];
|
||||
|
@ -609,27 +657,39 @@ wire_decl:
|
|||
}
|
||||
if (astbuf2 && astbuf2->children.size() != 2)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
} wire_name_list ';' {
|
||||
} wire_name_list {
|
||||
delete astbuf1;
|
||||
if (astbuf2 != NULL)
|
||||
delete astbuf2;
|
||||
free_attr(albuf);
|
||||
} |
|
||||
attr TOK_SUPPLY0 TOK_ID ';' {
|
||||
} ';' |
|
||||
attr TOK_SUPPLY0 TOK_ID {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
|
||||
ast_stack.back()->children.back()->str = *$3;
|
||||
append_attr(ast_stack.back()->children.back(), $1);
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)));
|
||||
ast_stack.back()->children.back()->children[0]->str = *$3;
|
||||
delete $3;
|
||||
} |
|
||||
attr TOK_SUPPLY1 TOK_ID ';' {
|
||||
} opt_supply_wires ';' |
|
||||
attr TOK_SUPPLY1 TOK_ID {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
|
||||
ast_stack.back()->children.back()->str = *$3;
|
||||
append_attr(ast_stack.back()->children.back(), $1);
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1)));
|
||||
ast_stack.back()->children.back()->children[0]->str = *$3;
|
||||
delete $3;
|
||||
} opt_supply_wires ';';
|
||||
|
||||
opt_supply_wires:
|
||||
/* empty */ |
|
||||
opt_supply_wires ',' TOK_ID {
|
||||
AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone();
|
||||
AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone();
|
||||
wire_node->str = *$3;
|
||||
assign_node->children[0]->str = *$3;
|
||||
ast_stack.back()->children.push_back(wire_node);
|
||||
ast_stack.back()->children.push_back(assign_node);
|
||||
delete $3;
|
||||
};
|
||||
|
||||
wire_name_list:
|
||||
|
@ -689,7 +749,7 @@ wire_name:
|
|||
};
|
||||
|
||||
assign_stmt:
|
||||
TOK_ASSIGN assign_expr_list ';';
|
||||
TOK_ASSIGN delay assign_expr_list ';';
|
||||
|
||||
assign_expr_list:
|
||||
assign_expr | assign_expr_list ',' assign_expr;
|
||||
|
@ -709,7 +769,7 @@ cell_stmt:
|
|||
} cell_parameter_list_opt cell_list ';' {
|
||||
delete astbuf1;
|
||||
} |
|
||||
attr tok_prim_wrapper {
|
||||
attr tok_prim_wrapper delay {
|
||||
astbuf1 = new AstNode(AST_PRIMITIVE);
|
||||
astbuf1->str = *$2;
|
||||
append_attr(astbuf1, $1);
|
||||
|
@ -874,27 +934,34 @@ opt_label:
|
|||
assert:
|
||||
TOK_ASSERT '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3));
|
||||
} |
|
||||
TOK_ASSUME '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
|
||||
};
|
||||
|
||||
assert_property:
|
||||
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4));
|
||||
} |
|
||||
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
|
||||
};
|
||||
|
||||
simple_behavioral_stmt:
|
||||
lvalue '=' expr {
|
||||
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
|
||||
lvalue '=' delay expr {
|
||||
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4);
|
||||
ast_stack.back()->children.push_back(node);
|
||||
} |
|
||||
lvalue OP_LE expr {
|
||||
AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $3);
|
||||
lvalue OP_LE delay expr {
|
||||
AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4);
|
||||
ast_stack.back()->children.push_back(node);
|
||||
};
|
||||
|
||||
// this production creates the obligatory if-else shift/reduce conflict
|
||||
behavioral_stmt:
|
||||
defattr | assert | wire_decl |
|
||||
simple_behavioral_stmt ';' |
|
||||
non_opt_delay behavioral_stmt |
|
||||
simple_behavioral_stmt ';' | ';' |
|
||||
hierarchical_id attr {
|
||||
AstNode *node = new AstNode(AST_TCALL);
|
||||
node->str = *$1;
|
||||
|
@ -1008,10 +1075,6 @@ opt_synopsys_attr:
|
|||
} |
|
||||
/* empty */;
|
||||
|
||||
behavioral_stmt_opt:
|
||||
behavioral_stmt |
|
||||
';' ;
|
||||
|
||||
behavioral_stmt_list:
|
||||
behavioral_stmt_list behavioral_stmt |
|
||||
/* empty */;
|
||||
|
@ -1040,7 +1103,7 @@ case_item:
|
|||
ast_stack.back()->children.push_back(block);
|
||||
ast_stack.push_back(block);
|
||||
case_type_stack.push_back(0);
|
||||
} behavioral_stmt_opt {
|
||||
} behavioral_stmt {
|
||||
case_type_stack.pop_back();
|
||||
ast_stack.pop_back();
|
||||
ast_stack.pop_back();
|
||||
|
@ -1211,7 +1274,7 @@ basic_expr:
|
|||
if ($4->substr(0, 1) != "'")
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
AstNode *bits = $2;
|
||||
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
|
||||
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
|
||||
if (val == NULL)
|
||||
log_error("Value conversion failed: `%s'\n", $4->c_str());
|
||||
$$ = new AstNode(AST_TO_BITS, bits, val);
|
||||
|
@ -1222,7 +1285,7 @@ basic_expr:
|
|||
frontend_verilog_yyerror("Syntax error.");
|
||||
AstNode *bits = new AstNode(AST_IDENTIFIER);
|
||||
bits->str = *$1;
|
||||
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
|
||||
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
|
||||
if (val == NULL)
|
||||
log_error("Value conversion failed: `%s'\n", $2->c_str());
|
||||
$$ = new AstNode(AST_TO_BITS, bits, val);
|
||||
|
@ -1230,14 +1293,14 @@ basic_expr:
|
|||
delete $2;
|
||||
} |
|
||||
TOK_CONST TOK_CONST {
|
||||
$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
|
||||
$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
|
||||
if ($$ == NULL || (*$2)[0] != '\'')
|
||||
log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
|
||||
delete $1;
|
||||
delete $2;
|
||||
} |
|
||||
TOK_CONST {
|
||||
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
|
||||
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
|
||||
if ($$ == NULL)
|
||||
log_error("Value conversion failed: `%s'\n", $1->c_str());
|
||||
delete $1;
|
||||
|
@ -1278,10 +1341,15 @@ basic_expr:
|
|||
'(' expr ')' {
|
||||
$$ = $2;
|
||||
} |
|
||||
'(' expr ':' expr ':' expr ')' {
|
||||
delete $2;
|
||||
$$ = $4;
|
||||
delete $6;
|
||||
} |
|
||||
'{' concat_list '}' {
|
||||
$$ = $2;
|
||||
} |
|
||||
'{' expr '{' expr '}' '}' {
|
||||
'{' expr '{' concat_list '}' '}' {
|
||||
$$ = new AstNode(AST_REPLICATE, $2, $4);
|
||||
} |
|
||||
'~' attr basic_expr %prec UNARY_OPS {
|
|
@ -20,14 +20,17 @@
|
|||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/log.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct Vhdl2verilogPass : public Pass {
|
||||
|
@ -120,11 +123,8 @@ struct Vhdl2verilogPass : public Pass {
|
|||
if (top_entity.empty())
|
||||
log_cmd_error("Missing -top option.\n");
|
||||
|
||||
char tempdir_name[] = "/tmp/yosys-vhdl2verilog-XXXXXX";
|
||||
char *p = mkdtemp(tempdir_name);
|
||||
log("Using temp directory %s.\n", tempdir_name);
|
||||
if (p == NULL)
|
||||
log_error("For some reason mkdtemp() failed!\n");
|
||||
std::string tempdir_name = make_temp_dir("/tmp/yosys-vhdl2verilog-XXXXXX");
|
||||
log("Using temp directory %s.\n", tempdir_name.c_str());
|
||||
|
||||
if (!out_file.empty() && out_file[0] != '/') {
|
||||
char pwd[PATH_MAX];
|
||||
|
@ -135,7 +135,7 @@ struct Vhdl2verilogPass : public Pass {
|
|||
out_file = pwd + ("/" + out_file);
|
||||
}
|
||||
|
||||
FILE *f = fopen(stringf("%s/files.list", tempdir_name).c_str(), "wt");
|
||||
FILE *f = fopen(stringf("%s/files.list", tempdir_name.c_str()).c_str(), "wt");
|
||||
while (argidx < args.size()) {
|
||||
std::string file = args[argidx++];
|
||||
if (file.empty())
|
||||
|
@ -156,38 +156,25 @@ struct Vhdl2verilogPass : public Pass {
|
|||
std::string command = "exec 2>&1; ";
|
||||
if (!vhdl2verilog_dir.empty())
|
||||
command += stringf("cd '%s'; . ./setup_env.sh; ", vhdl2verilog_dir.c_str());
|
||||
command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name,
|
||||
command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name.c_str(),
|
||||
out_file.empty() ? "vhdl2verilog_output.v" : out_file.c_str(), top_entity.c_str(), extra_opts.c_str());
|
||||
|
||||
log("Running '%s'..\n", command.c_str());
|
||||
|
||||
errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
|
||||
f = popen(command.c_str(), "r");
|
||||
if (f == NULL)
|
||||
log_error("Opening pipe to `%s' for reading failed: %s\n", command.c_str(), strerror(errno));
|
||||
|
||||
char logbuf[1024];
|
||||
while (fgets(logbuf, 1024, f) != NULL)
|
||||
log("%s", logbuf);
|
||||
|
||||
int ret = pclose(f);
|
||||
if (ret < 0)
|
||||
log_error("Closing pipe to `%s' failed: %s\n", command.c_str(), strerror(errno));
|
||||
if (WEXITSTATUS(ret) != 0)
|
||||
log_error("Execution of command \"%s\" failed: the shell returned %d\n", command.c_str(), WEXITSTATUS(ret));
|
||||
int ret = run_command(command, [](const std::string &line) { log("%s", line.c_str()); });
|
||||
if (ret != 0)
|
||||
log_error("Execution of command \"%s\" failed: return code %d.\n", command.c_str(), ret);
|
||||
|
||||
if (out_file.empty()) {
|
||||
std::ifstream ff;
|
||||
ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name).c_str());
|
||||
ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()).c_str());
|
||||
if (ff.fail())
|
||||
log_error("Can't open vhdl2verilog output file `vhdl2verilog_output.v'.\n");
|
||||
Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name), "verilog");
|
||||
Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()), "verilog");
|
||||
}
|
||||
|
||||
log_header("Removing temp directory `%s':\n", tempdir_name);
|
||||
if (system(stringf("rm -rf '%s'", tempdir_name).c_str()) != 0)
|
||||
log_error("Execution of \"rm -rf '%s'\" failed!\n", tempdir_name);
|
||||
|
||||
log_header("Removing temp directory `%s':\n", tempdir_name.c_str());
|
||||
remove_directory(tempdir_name);
|
||||
log_pop();
|
||||
}
|
||||
} Vhdl2verilogPass;
|
||||
|
|
|
@ -23,24 +23,46 @@
|
|||
#include "kernel/log.h"
|
||||
#include "kernel/rtlil.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct BitPatternPool
|
||||
{
|
||||
int width;
|
||||
typedef std::vector<RTLIL::State> bits_t;
|
||||
std::set<bits_t> pool;
|
||||
struct bits_t {
|
||||
std::vector<RTLIL::State> bitdata;
|
||||
unsigned int cached_hash;
|
||||
bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
|
||||
RTLIL::State &operator[](int index) {
|
||||
return bitdata[index];
|
||||
}
|
||||
const RTLIL::State &operator[](int index) const {
|
||||
return bitdata[index];
|
||||
}
|
||||
bool operator==(const bits_t &other) const {
|
||||
if (hash() != other.hash())
|
||||
return false;
|
||||
return bitdata == other.bitdata;
|
||||
}
|
||||
unsigned int hash() const {
|
||||
if (!cached_hash)
|
||||
((bits_t*)this)->cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata);
|
||||
return cached_hash;
|
||||
}
|
||||
};
|
||||
pool<bits_t> database;
|
||||
|
||||
BitPatternPool(RTLIL::SigSpec sig)
|
||||
{
|
||||
width = sig.size();
|
||||
if (width > 0) {
|
||||
std::vector<RTLIL::State> pattern(width);
|
||||
bits_t pattern(width);
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1)
|
||||
pattern[i] = sig[i].data;
|
||||
else
|
||||
pattern[i] = RTLIL::State::Sa;
|
||||
}
|
||||
pool.insert(pattern);
|
||||
database.insert(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,17 +70,18 @@ struct BitPatternPool
|
|||
{
|
||||
this->width = width;
|
||||
if (width > 0) {
|
||||
std::vector<RTLIL::State> pattern(width);
|
||||
bits_t pattern(width);
|
||||
for (int i = 0; i < width; i++)
|
||||
pattern[i] = RTLIL::State::Sa;
|
||||
pool.insert(pattern);
|
||||
database.insert(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
bits_t sig2bits(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits = sig.as_const().bits;
|
||||
for (auto &b : bits)
|
||||
bits_t bits;
|
||||
bits.bitdata = sig.as_const().bits;
|
||||
for (auto &b : bits.bitdata)
|
||||
if (b > RTLIL::State::S1)
|
||||
b = RTLIL::State::Sa;
|
||||
return bits;
|
||||
|
@ -66,8 +89,8 @@ struct BitPatternPool
|
|||
|
||||
bool match(bits_t a, bits_t b)
|
||||
{
|
||||
log_assert(int(a.size()) == width);
|
||||
log_assert(int(b.size()) == width);
|
||||
log_assert(int(a.bitdata.size()) == width);
|
||||
log_assert(int(b.bitdata.size()) == width);
|
||||
for (int i = 0; i < width; i++)
|
||||
if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i])
|
||||
return false;
|
||||
|
@ -77,7 +100,7 @@ struct BitPatternPool
|
|||
bool has_any(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits = sig2bits(sig);
|
||||
for (auto &it : pool)
|
||||
for (auto &it : database)
|
||||
if (match(it, bits))
|
||||
return true;
|
||||
return false;
|
||||
|
@ -86,13 +109,13 @@ struct BitPatternPool
|
|||
bool has_all(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits = sig2bits(sig);
|
||||
for (auto &it : pool)
|
||||
for (auto &it : database)
|
||||
if (match(it, bits)) {
|
||||
for (int i = 0; i < width; i++)
|
||||
if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1)
|
||||
goto next_pool_entry;
|
||||
goto next_database_entry;
|
||||
return true;
|
||||
next_pool_entry:;
|
||||
next_database_entry:;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -101,36 +124,38 @@ struct BitPatternPool
|
|||
{
|
||||
bool status = false;
|
||||
bits_t bits = sig2bits(sig);
|
||||
std::vector<bits_t> pattern_list;
|
||||
for (auto &it : pool)
|
||||
if (match(it, bits))
|
||||
pattern_list.push_back(it);
|
||||
for (auto pattern : pattern_list) {
|
||||
pool.erase(pattern);
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (pattern[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
|
||||
continue;
|
||||
bits_t new_pattern = pattern;
|
||||
new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
|
||||
pool.insert(new_pattern);
|
||||
}
|
||||
status = true;
|
||||
}
|
||||
for (auto it = database.begin(); it != database.end();)
|
||||
if (match(*it, bits)) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
if ((*it)[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
|
||||
continue;
|
||||
bits_t new_pattern;
|
||||
new_pattern.bitdata = it->bitdata;
|
||||
new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
|
||||
database.insert(new_pattern);
|
||||
}
|
||||
it = database.erase(it);
|
||||
status = true;
|
||||
continue;
|
||||
} else
|
||||
++it;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool take_all()
|
||||
{
|
||||
if (pool.empty())
|
||||
if (database.empty())
|
||||
return false;
|
||||
pool.clear();
|
||||
database.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return pool.empty();
|
||||
return database.empty();
|
||||
}
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -303,7 +303,7 @@ RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
|||
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
|
||||
{
|
||||
RTLIL::Const arg1_ext = arg1;
|
||||
extend_u0(arg1_ext, std::max(result_len, SIZE(arg1)), signed1);
|
||||
extend_u0(arg1_ext, std::max(result_len, GetSize(arg1)), signed1);
|
||||
return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,13 +27,13 @@ YOSYS_NAMESPACE_BEGIN
|
|||
struct CellType
|
||||
{
|
||||
RTLIL::IdString type;
|
||||
std::set<RTLIL::IdString> inputs, outputs;
|
||||
pool<RTLIL::IdString> inputs, outputs;
|
||||
bool is_evaluable;
|
||||
};
|
||||
|
||||
struct CellTypes
|
||||
{
|
||||
std::map<RTLIL::IdString, CellType> cell_types;
|
||||
dict<RTLIL::IdString, CellType> cell_types;
|
||||
|
||||
CellTypes()
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ struct CellTypes
|
|||
setup_stdcells_mem();
|
||||
}
|
||||
|
||||
void setup_type(RTLIL::IdString type, const std::set<RTLIL::IdString> &inputs, const std::set<RTLIL::IdString> &outputs, bool is_evaluable = false)
|
||||
void setup_type(RTLIL::IdString type, const pool<RTLIL::IdString> &inputs, const pool<RTLIL::IdString> &outputs, bool is_evaluable = false)
|
||||
{
|
||||
CellType ct = {type, inputs, outputs, is_evaluable};
|
||||
cell_types[ct.type] = ct;
|
||||
|
@ -63,7 +63,7 @@ struct CellTypes
|
|||
|
||||
void setup_module(RTLIL::Module *module)
|
||||
{
|
||||
std::set<RTLIL::IdString> inputs, outputs;
|
||||
pool<RTLIL::IdString> inputs, outputs;
|
||||
for (RTLIL::IdString wire_name : module->ports) {
|
||||
RTLIL::Wire *wire = module->wire(wire_name);
|
||||
if (wire->port_input)
|
||||
|
@ -96,82 +96,105 @@ struct CellTypes
|
|||
"$logic_and", "$logic_or", "$concat", "$macc"
|
||||
};
|
||||
|
||||
IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y";
|
||||
IdString P = "\\P", G = "\\G", C = "\\C", X = "\\X";
|
||||
IdString BI = "\\BI", CI = "\\CI", CO = "\\CO", EN = "\\EN";
|
||||
|
||||
for (auto type : unary_ops)
|
||||
setup_type(type, {"\\A"}, {"\\Y"}, true);
|
||||
setup_type(type, {A}, {Y}, true);
|
||||
|
||||
for (auto type : binary_ops)
|
||||
setup_type(type, {"\\A", "\\B"}, {"\\Y"}, true);
|
||||
setup_type(type, {A, B}, {Y}, true);
|
||||
|
||||
for (auto type : std::vector<RTLIL::IdString>({"$mux", "$pmux"}))
|
||||
setup_type(type, {"\\A", "\\B", "\\S"}, {"\\Y"}, true);
|
||||
setup_type(type, {A, B, S}, {Y}, true);
|
||||
|
||||
setup_type("$lcu", {"\\P", "\\G", "\\CI"}, {"\\CO"}, true);
|
||||
setup_type("$alu", {"\\A", "\\B", "\\CI", "\\BI"}, {"\\X", "\\Y", "\\CO"}, true);
|
||||
setup_type("$fa", {"\\A", "\\B", "\\C"}, {"\\X", "\\Y"}, true);
|
||||
setup_type("$lcu", {P, G, CI}, {CO}, true);
|
||||
setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
|
||||
setup_type("$fa", {A, B, C}, {X, Y}, true);
|
||||
|
||||
setup_type("$assert", {"\\A", "\\EN"}, std::set<RTLIL::IdString>(), true);
|
||||
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$equiv", {A, B}, {Y}, true);
|
||||
}
|
||||
|
||||
void setup_internals_mem()
|
||||
{
|
||||
setup_type("$sr", {"\\SET", "\\CLR"}, {"\\Q"});
|
||||
setup_type("$dff", {"\\CLK", "\\D"}, {"\\Q"});
|
||||
setup_type("$dffsr", {"\\CLK", "\\SET", "\\CLR", "\\D"}, {"\\Q"});
|
||||
setup_type("$adff", {"\\CLK", "\\ARST", "\\D"}, {"\\Q"});
|
||||
setup_type("$dlatch", {"\\EN", "\\D"}, {"\\Q"});
|
||||
setup_type("$dlatchsr", {"\\EN", "\\SET", "\\CLR", "\\D"}, {"\\Q"});
|
||||
IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN";
|
||||
IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA";
|
||||
IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN";
|
||||
IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA";
|
||||
IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT";
|
||||
|
||||
setup_type("$memrd", {"\\CLK", "\\ADDR"}, {"\\DATA"});
|
||||
setup_type("$memwr", {"\\CLK", "\\EN", "\\ADDR", "\\DATA"}, std::set<RTLIL::IdString>());
|
||||
setup_type("$mem", {"\\RD_CLK", "\\RD_ADDR", "\\WR_CLK", "\\WR_EN", "\\WR_ADDR", "\\WR_DATA"}, {"\\RD_DATA"});
|
||||
setup_type("$sr", {SET, CLR}, {Q});
|
||||
setup_type("$dff", {CLK, D}, {Q});
|
||||
setup_type("$dffe", {CLK, EN, D}, {Q});
|
||||
setup_type("$dffsr", {CLK, SET, CLR, D}, {Q});
|
||||
setup_type("$adff", {CLK, ARST, D}, {Q});
|
||||
setup_type("$dlatch", {EN, D}, {Q});
|
||||
setup_type("$dlatchsr", {EN, SET, CLR, D}, {Q});
|
||||
|
||||
setup_type("$fsm", {"\\CLK", "\\ARST", "\\CTRL_IN"}, {"\\CTRL_OUT"});
|
||||
setup_type("$memrd", {CLK, ADDR}, {DATA});
|
||||
setup_type("$memwr", {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>());
|
||||
setup_type("$meminit", {ADDR, DATA}, pool<RTLIL::IdString>());
|
||||
setup_type("$mem", {RD_CLK, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA});
|
||||
|
||||
setup_type("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT});
|
||||
}
|
||||
|
||||
void setup_stdcells()
|
||||
{
|
||||
setup_type("$_NOT_", {"\\A"}, {"\\Y"}, true);
|
||||
setup_type("$_AND_", {"\\A", "\\B"}, {"\\Y"}, true);
|
||||
setup_type("$_NAND_", {"\\A", "\\B"}, {"\\Y"}, true);
|
||||
setup_type("$_OR_", {"\\A", "\\B"}, {"\\Y"}, true);
|
||||
setup_type("$_NOR_", {"\\A", "\\B"}, {"\\Y"}, true);
|
||||
setup_type("$_XOR_", {"\\A", "\\B"}, {"\\Y"}, true);
|
||||
setup_type("$_XNOR_", {"\\A", "\\B"}, {"\\Y"}, true);
|
||||
setup_type("$_MUX_", {"\\A", "\\B", "\\S"}, {"\\Y"}, true);
|
||||
setup_type("$_AOI3_", {"\\A", "\\B", "\\C"}, {"\\Y"}, true);
|
||||
setup_type("$_OAI3_", {"\\A", "\\B", "\\C"}, {"\\Y"}, true);
|
||||
setup_type("$_AOI4_", {"\\A", "\\B", "\\C", "\\D"}, {"\\Y"}, true);
|
||||
setup_type("$_OAI4_", {"\\A", "\\B", "\\C", "\\D"}, {"\\Y"}, true);
|
||||
IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D", S = "\\S", Y = "\\Y";
|
||||
setup_type("$_BUF_", {A}, {Y}, true);
|
||||
setup_type("$_NOT_", {A}, {Y}, true);
|
||||
setup_type("$_AND_", {A, B}, {Y}, true);
|
||||
setup_type("$_NAND_", {A, B}, {Y}, true);
|
||||
setup_type("$_OR_", {A, B}, {Y}, true);
|
||||
setup_type("$_NOR_", {A, B}, {Y}, true);
|
||||
setup_type("$_XOR_", {A, B}, {Y}, true);
|
||||
setup_type("$_XNOR_", {A, B}, {Y}, true);
|
||||
setup_type("$_MUX_", {A, B, S}, {Y}, true);
|
||||
setup_type("$_AOI3_", {A, B, C}, {Y}, true);
|
||||
setup_type("$_OAI3_", {A, B, C}, {Y}, true);
|
||||
setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
|
||||
setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
|
||||
}
|
||||
|
||||
void setup_stdcells_mem()
|
||||
{
|
||||
IdString S = "\\S", R = "\\R", C = "\\C";
|
||||
IdString D = "\\D", Q = "\\Q", E = "\\E";
|
||||
|
||||
std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};
|
||||
|
||||
for (auto c1 : list_np)
|
||||
for (auto c2 : list_np)
|
||||
setup_type(stringf("$_SR_%c%c_", c1, c2), {"\\S", "\\R"}, {"\\Q"});
|
||||
setup_type(stringf("$_SR_%c%c_", c1, c2), {S, R}, {Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
setup_type(stringf("$_DFF_%c_", c1), {"\\C", "\\D"}, {"\\Q"});
|
||||
setup_type(stringf("$_DFF_%c_", c1), {C, D}, {Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
for (auto c2 : list_np)
|
||||
setup_type(stringf("$_DFFE_%c%c_", c1, c2), {C, D, E}, {Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
for (auto c2 : list_np)
|
||||
for (auto c3 : list_01)
|
||||
setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {"\\C", "\\R", "\\D"}, {"\\Q"});
|
||||
setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {C, R, D}, {Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
for (auto c2 : list_np)
|
||||
for (auto c3 : list_np)
|
||||
setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {"\\C", "\\S", "\\R", "\\D"}, {"\\Q"});
|
||||
setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {C, S, R, D}, {Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
setup_type(stringf("$_DLATCH_%c_", c1), {"\\E", "\\D"}, {"\\Q"});
|
||||
setup_type(stringf("$_DLATCH_%c_", c1), {E, D}, {Q});
|
||||
|
||||
for (auto c1 : list_np)
|
||||
for (auto c2 : list_np)
|
||||
for (auto c3 : list_np)
|
||||
setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {"\\E", "\\S", "\\R", "\\D"}, {"\\Q"});
|
||||
setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {E, S, R, D}, {Q});
|
||||
}
|
||||
|
||||
void clear()
|
||||
|
@ -261,6 +284,8 @@ struct CellTypes
|
|||
HANDLE_CELL_TYPE(neg)
|
||||
#undef HANDLE_CELL_TYPE
|
||||
|
||||
if (type == "$_BUF_")
|
||||
return arg1;
|
||||
if (type == "$_NOT_")
|
||||
return eval_not(arg1);
|
||||
if (type == "$_AND_")
|
||||
|
@ -300,7 +325,7 @@ struct CellTypes
|
|||
int width = cell->parameters.at("\\WIDTH").as_int();
|
||||
|
||||
std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits;
|
||||
while (SIZE(t) < (1 << width))
|
||||
while (GetSize(t) < (1 << width))
|
||||
t.push_back(RTLIL::S0);
|
||||
t.resize(1 << width);
|
||||
|
||||
|
@ -308,16 +333,16 @@ struct CellTypes
|
|||
RTLIL::State sel = arg1.bits.at(i);
|
||||
std::vector<RTLIL::State> new_t;
|
||||
if (sel == RTLIL::S0)
|
||||
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + SIZE(t)/2);
|
||||
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
|
||||
else if (sel == RTLIL::S1)
|
||||
new_t = std::vector<RTLIL::State>(t.begin() + SIZE(t)/2, t.end());
|
||||
new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
|
||||
else
|
||||
for (int j = 0; j < SIZE(t)/2; j++)
|
||||
new_t.push_back(t[j] == t[j + SIZE(t)/2] ? t[j] : RTLIL::Sx);
|
||||
for (int j = 0; j < GetSize(t)/2; j++)
|
||||
new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
|
||||
t.swap(new_t);
|
||||
}
|
||||
|
||||
log_assert(SIZE(t) == 1);
|
||||
log_assert(GetSize(t) == 1);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -360,6 +385,9 @@ struct CellTypes
|
|||
}
|
||||
};
|
||||
|
||||
// initialized by yosys_setup()
|
||||
extern CellTypes yosys_celltypes;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include "kernel/celltypes.h"
|
||||
#include "kernel/macc.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct ConstEval
|
||||
{
|
||||
RTLIL::Module *module;
|
||||
|
@ -72,7 +74,7 @@ struct ConstEval
|
|||
assign_map.apply(sig);
|
||||
#ifndef NDEBUG
|
||||
RTLIL::SigSpec current_val = values_map(sig);
|
||||
for (int i = 0; i < SIZE(current_val); i++)
|
||||
for (int i = 0; i < GetSize(current_val); i++)
|
||||
log_assert(current_val[i].wire != NULL || current_val[i] == value.bits[i]);
|
||||
#endif
|
||||
values_map.add(sig, RTLIL::SigSpec(value));
|
||||
|
@ -107,10 +109,10 @@ struct ConstEval
|
|||
|
||||
if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def())
|
||||
{
|
||||
RTLIL::Const coval(RTLIL::Sx, SIZE(sig_co));
|
||||
RTLIL::Const coval(RTLIL::Sx, GetSize(sig_co));
|
||||
bool carry = sig_ci.as_bool();
|
||||
|
||||
for (int i = 0; i < SIZE(coval); i++) {
|
||||
for (int i = 0; i < GetSize(coval); i++) {
|
||||
carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry);
|
||||
coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0;
|
||||
}
|
||||
|
@ -118,7 +120,7 @@ struct ConstEval
|
|||
set(sig_co, coval);
|
||||
}
|
||||
else
|
||||
set(sig_co, RTLIL::Const(RTLIL::Sx, SIZE(sig_co)));
|
||||
set(sig_co, RTLIL::Const(RTLIL::Sx, GetSize(sig_co)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -196,7 +198,7 @@ struct ConstEval
|
|||
{
|
||||
RTLIL::SigSpec sig_c = cell->getPort("\\C");
|
||||
RTLIL::SigSpec sig_x = cell->getPort("\\X");
|
||||
int width = SIZE(sig_c);
|
||||
int width = GetSize(sig_c);
|
||||
|
||||
if (!eval(sig_a, undef, cell))
|
||||
return false;
|
||||
|
@ -214,7 +216,7 @@ struct ConstEval
|
|||
RTLIL::Const t3 = const_and(sig_c.as_const(), t1, false, false, width);
|
||||
RTLIL::Const val_x = const_or(t2, t3, false, false, width);
|
||||
|
||||
for (int i = 0; i < SIZE(val_y); i++)
|
||||
for (int i = 0; i < GetSize(val_y); i++)
|
||||
if (val_y.bits[i] == RTLIL::Sx)
|
||||
val_x.bits[i] = RTLIL::Sx;
|
||||
|
||||
|
@ -245,13 +247,13 @@ struct ConstEval
|
|||
RTLIL::SigSpec sig_co = cell->getPort("\\CO");
|
||||
|
||||
bool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def());
|
||||
sig_a.extend_u0(SIZE(sig_y), signed_a);
|
||||
sig_b.extend_u0(SIZE(sig_y), signed_b);
|
||||
sig_a.extend_u0(GetSize(sig_y), signed_a);
|
||||
sig_b.extend_u0(GetSize(sig_y), signed_b);
|
||||
|
||||
bool carry = sig_ci[0] == RTLIL::S1;
|
||||
bool b_inv = sig_bi[0] == RTLIL::S1;
|
||||
|
||||
for (int i = 0; i < SIZE(sig_y); i++)
|
||||
for (int i = 0; i < GetSize(sig_y); i++)
|
||||
{
|
||||
RTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] };
|
||||
|
||||
|
@ -292,7 +294,7 @@ struct ConstEval
|
|||
return false;
|
||||
}
|
||||
|
||||
RTLIL::Const result(0, SIZE(cell->getPort("\\Y")));
|
||||
RTLIL::Const result(0, GetSize(cell->getPort("\\Y")));
|
||||
if (!macc.eval(result))
|
||||
log_abort();
|
||||
|
||||
|
@ -376,4 +378,6 @@ struct ConstEval
|
|||
}
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COST_H
|
||||
#define COST_H
|
||||
|
||||
#include <kernel/yosys.h>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr);
|
||||
|
||||
int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> ¶meters = dict<RTLIL::IdString, RTLIL::Const>(),
|
||||
RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
|
||||
{
|
||||
static dict<RTLIL::IdString, int> gate_cost = {
|
||||
{ "$_BUF_", 1 },
|
||||
{ "$_NOT_", 2 },
|
||||
{ "$_AND_", 4 },
|
||||
{ "$_NAND_", 4 },
|
||||
{ "$_OR_", 4 },
|
||||
{ "$_NOR_", 4 },
|
||||
{ "$_XOR_", 8 },
|
||||
{ "$_XNOR_", 8 },
|
||||
{ "$_AOI3_", 6 },
|
||||
{ "$_OAI3_", 6 },
|
||||
{ "$_AOI4_", 8 },
|
||||
{ "$_OAI4_", 8 },
|
||||
{ "$_MUX_", 4 }
|
||||
};
|
||||
|
||||
if (gate_cost.count(type))
|
||||
return gate_cost.at(type);
|
||||
|
||||
if (parameters.empty() && design && design->module(type))
|
||||
{
|
||||
RTLIL::Module *mod = design->module(type);
|
||||
|
||||
if (mod->attributes.count("\\cost"))
|
||||
return mod->attributes.at("\\cost").as_int();
|
||||
|
||||
dict<RTLIL::IdString, int> local_mod_cost_cache;
|
||||
if (mod_cost_cache == nullptr)
|
||||
mod_cost_cache = &local_mod_cost_cache;
|
||||
|
||||
if (mod_cost_cache->count(mod->name))
|
||||
return mod_cost_cache->at(mod->name);
|
||||
|
||||
int module_cost = 1;
|
||||
for (auto c : mod->cells())
|
||||
module_cost += get_cell_cost(c, mod_cost_cache);
|
||||
|
||||
(*mod_cost_cache)[mod->name] = module_cost;
|
||||
return module_cost;
|
||||
}
|
||||
|
||||
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
|
||||
{
|
||||
return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
390
kernel/driver.cc
390
kernel/driver.cc
|
@ -27,13 +27,98 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) || defined(__MINGW32__)
|
||||
# include <unistd.h>
|
||||
#else
|
||||
char *optarg;
|
||||
int optind = 1, optcur = 1;
|
||||
int getopt(int argc, char **argv, const char *optstring)
|
||||
{
|
||||
if (optind >= argc || argv[optind][0] != '-')
|
||||
return -1;
|
||||
|
||||
bool takes_arg = false;
|
||||
int opt = argv[optind][optcur];
|
||||
for (int i = 0; optstring[i]; i++)
|
||||
if (opt == optstring[i] && optstring[i + 1] == ':')
|
||||
takes_arg = true;
|
||||
|
||||
if (!takes_arg) {
|
||||
if (argv[optind][++optcur] == 0)
|
||||
optind++, optcur = 1;
|
||||
return opt;
|
||||
}
|
||||
|
||||
if (argv[optind][++optcur]) {
|
||||
optarg = argv[optind++] + optcur;
|
||||
optcur = 1;
|
||||
return opt;
|
||||
}
|
||||
|
||||
optarg = argv[++optind];
|
||||
optind++, optcur = 1;
|
||||
return opt;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
|
||||
extern "C" int main(int, char**);
|
||||
extern "C" void run(const char*);
|
||||
extern "C" const char *errmsg();
|
||||
extern "C" const char *prompt();
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
mkdir("/work", 0777);
|
||||
chdir("/work");
|
||||
log_files.push_back(stdout);
|
||||
log_error_stderr = true;
|
||||
yosys_banner();
|
||||
yosys_setup();
|
||||
}
|
||||
|
||||
void run(const char *command)
|
||||
{
|
||||
int selSize = GetSize(yosys_get_design()->selection_stack);
|
||||
try {
|
||||
log_last_error = "Internal error (see JavaScript console for details)";
|
||||
run_pass(command);
|
||||
log_last_error = "";
|
||||
} catch (...) {
|
||||
while (GetSize(yosys_get_design()->selection_stack) > selSize)
|
||||
yosys_get_design()->selection_stack.pop_back();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
const char *errmsg()
|
||||
{
|
||||
return log_last_error.c_str();
|
||||
}
|
||||
|
||||
const char *prompt()
|
||||
{
|
||||
const char *p = create_prompt(yosys_get_design(), 0);
|
||||
while (*p == '\n') p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
#else /* EMSCRIPTEN */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::string frontend_command = "auto";
|
||||
|
@ -47,6 +132,9 @@ int main(int argc, char **argv)
|
|||
bool print_banner = true;
|
||||
bool print_stats = true;
|
||||
bool call_abort = false;
|
||||
bool timing_details = false;
|
||||
bool mode_v = false;
|
||||
bool mode_q = false;
|
||||
|
||||
#ifdef YOSYS_ENABLE_READLINE
|
||||
int history_offset = 0;
|
||||
|
@ -58,11 +146,103 @@ int main(int argc, char **argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help")))
|
||||
{
|
||||
printf("\n");
|
||||
printf("Usage: %s [options] [<infile> [..]]\n", argv[0]);
|
||||
printf("\n");
|
||||
printf(" -Q\n");
|
||||
printf(" suppress printing of banner (copyright, disclaimer, version)\n");
|
||||
printf("\n");
|
||||
printf(" -T\n");
|
||||
printf(" suppress printing of footer (log hash, version, timing statistics)\n");
|
||||
printf("\n");
|
||||
printf(" -q\n");
|
||||
printf(" quiet operation. only write warnings and error messages to console\n");
|
||||
printf(" use this option twice to also quiet warning messages\n");
|
||||
printf("\n");
|
||||
printf(" -v <level>\n");
|
||||
printf(" print log headers up to level <level> to the console. (this\n");
|
||||
printf(" implies -q for everything except the 'End of script.' message.)\n");
|
||||
printf("\n");
|
||||
printf(" -t\n");
|
||||
printf(" annotate all log messages with a time stamp\n");
|
||||
printf("\n");
|
||||
printf(" -d\n");
|
||||
printf(" print more detailed timing stats at exit\n");
|
||||
printf("\n");
|
||||
printf(" -l logfile\n");
|
||||
printf(" write log messages to the specified file\n");
|
||||
printf("\n");
|
||||
printf(" -L logfile\n");
|
||||
printf(" like -l but open log file in line buffered mode\n");
|
||||
printf("\n");
|
||||
printf(" -o outfile\n");
|
||||
printf(" write the design to the specified file on exit\n");
|
||||
printf("\n");
|
||||
printf(" -b backend\n");
|
||||
printf(" use this backend for the output file specified on the command line\n");
|
||||
printf("\n");
|
||||
printf(" -f backend\n");
|
||||
printf(" use the specified front for the input files on the command line\n");
|
||||
printf("\n");
|
||||
printf(" -H\n");
|
||||
printf(" print the command list\n");
|
||||
printf("\n");
|
||||
printf(" -h command\n");
|
||||
printf(" print the help message for the specified command\n");
|
||||
printf("\n");
|
||||
printf(" -s scriptfile\n");
|
||||
printf(" execute the commands in the script file\n");
|
||||
printf("\n");
|
||||
printf(" -c tcl_scriptfile\n");
|
||||
printf(" execute the commands in the tcl script file (see 'help tcl' for details)\n");
|
||||
printf("\n");
|
||||
printf(" -p command\n");
|
||||
printf(" execute the commands\n");
|
||||
printf("\n");
|
||||
printf(" -m module_file\n");
|
||||
printf(" load the specified module (aka plugin)\n");
|
||||
printf("\n");
|
||||
printf(" -X\n");
|
||||
printf(" enable tracing of core data structure changes. for debugging\n");
|
||||
printf("\n");
|
||||
printf(" -M\n");
|
||||
printf(" will slightly randomize allocated pointer addresses. for debugging\n");
|
||||
printf("\n");
|
||||
printf(" -A\n");
|
||||
printf(" will call abort() at the end of the script. for debugging\n");
|
||||
printf("\n");
|
||||
printf(" -V\n");
|
||||
printf(" print version information and exit\n");
|
||||
printf("\n");
|
||||
printf("The option -S is an shortcut for calling the \"synth\" command, a default\n");
|
||||
printf("script for transforming the verilog input to a gate-level netlist. For example:\n");
|
||||
printf("\n");
|
||||
printf(" yosys -o output.blif -S input.v\n");
|
||||
printf("\n");
|
||||
printf("For more complex synthesis jobs it is recommended to use the read_* and write_*\n");
|
||||
printf("commands in a script file instead of specifying input and output files on the\n");
|
||||
printf("command line.\n");
|
||||
printf("\n");
|
||||
printf("When no commands, script files or input files are specified on the command\n");
|
||||
printf("line, yosys automatically enters the interactive command mode. Use the 'help'\n");
|
||||
printf("command to get information on the individual commands.\n");
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "AQTVSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1)
|
||||
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'M':
|
||||
memhasher_on();
|
||||
break;
|
||||
case 'X':
|
||||
yosys_xtrace++;
|
||||
break;
|
||||
case 'A':
|
||||
call_abort = true;
|
||||
break;
|
||||
|
@ -101,22 +281,32 @@ int main(int argc, char **argv)
|
|||
got_output_filename = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
log_files.push_back(fopen(optarg, "wt"));
|
||||
if (log_files.back() == NULL) {
|
||||
fprintf(stderr, "Can't open log file `%s' for writing!\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
if (opt == 'L')
|
||||
setvbuf(log_files.back(), NULL, _IOLBF, 0);
|
||||
break;
|
||||
case 'q':
|
||||
mode_q = true;
|
||||
if (log_errfile == stderr)
|
||||
log_quiet_warnings = true;
|
||||
log_errfile = stderr;
|
||||
break;
|
||||
case 'v':
|
||||
mode_v = true;
|
||||
log_errfile = stderr;
|
||||
log_verbose_level = atoi(optarg);
|
||||
break;
|
||||
case 't':
|
||||
log_time = true;
|
||||
break;
|
||||
case 'd':
|
||||
timing_details = true;
|
||||
break;
|
||||
case 's':
|
||||
scriptfile = optarg;
|
||||
scriptfile_tcl = false;
|
||||
|
@ -126,107 +316,19 @@ int main(int argc, char **argv)
|
|||
scriptfile_tcl = true;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Usage: %s [-V -S -Q -T -q] [-v <level>[-t] [-l <logfile>] [-o <outfile>] [-f <frontend>] [-h cmd] \\\n", argv[0]);
|
||||
fprintf(stderr, " %*s[{-s|-c} <scriptfile>] [-p <pass> [-p ..]] [-b <backend>] [-m <module_file>] [<infile> [..]]\n", int(strlen(argv[0])+1), "");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -Q\n");
|
||||
fprintf(stderr, " suppress printing of banner (copyright, disclaimer, version)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -T\n");
|
||||
fprintf(stderr, " suppress printing of footer (log hash, version, timing statistics)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -q\n");
|
||||
fprintf(stderr, " quiet operation. only write error messages to console\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -v <level>\n");
|
||||
fprintf(stderr, " print log headers up to level <level> to the console. (implies -q)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -t\n");
|
||||
fprintf(stderr, " annotate all log messages with a time stamp\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -l logfile\n");
|
||||
fprintf(stderr, " write log messages to the specified file\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -o outfile\n");
|
||||
fprintf(stderr, " write the design to the specified file on exit\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -b backend\n");
|
||||
fprintf(stderr, " use this backend for the output file specified on the command line\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -f backend\n");
|
||||
fprintf(stderr, " use the specified front for the input files on the command line\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -H\n");
|
||||
fprintf(stderr, " print the command list\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -h command\n");
|
||||
fprintf(stderr, " print the help message for the specified command\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -s scriptfile\n");
|
||||
fprintf(stderr, " execute the commands in the script file\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -c tcl_scriptfile\n");
|
||||
fprintf(stderr, " execute the commands in the tcl script file (see 'help tcl' for details)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -p command\n");
|
||||
fprintf(stderr, " execute the commands\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -m module_file\n");
|
||||
fprintf(stderr, " load the specified module (aka plugin)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -A\n");
|
||||
fprintf(stderr, " will call abort() at the end of the script. useful for debugging\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -V\n");
|
||||
fprintf(stderr, " print version information and exit\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "The option -S is an shortcut for calling the \"synth\" command, a default\n");
|
||||
fprintf(stderr, "script for transforming the verilog input to a gate-level netlist. For example:\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " yosys -o output.blif -S input.v\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "For more complex synthesis jobs it is recommended to use the read_* and write_*\n");
|
||||
fprintf(stderr, "commands in a script file instead of specifying input and output files on the\n");
|
||||
fprintf(stderr, "command line.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "When no commands, script files or input files are specified on the command\n");
|
||||
fprintf(stderr, "line, yosys automatically enters the interactive command mode. Use the 'help'\n");
|
||||
fprintf(stderr, "command to get information on the individual commands.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Run '%s -h' for help.\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (log_errfile == NULL)
|
||||
log_files.push_back(stderr);
|
||||
|
||||
if (print_banner) {
|
||||
log("\n");
|
||||
log(" /-----------------------------------------------------------------------------\\\n");
|
||||
log(" | |\n");
|
||||
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
|
||||
log(" | |\n");
|
||||
log(" | Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |\n");
|
||||
log(" | |\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(" | copyright notice and this permission notice appear in all copies. |\n");
|
||||
log(" | |\n");
|
||||
log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
|
||||
log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
|
||||
log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
|
||||
log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
|
||||
log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
|
||||
log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
|
||||
log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
|
||||
log(" | |\n");
|
||||
log(" \\-----------------------------------------------------------------------------/\n");
|
||||
log("\n");
|
||||
log(" %s\n", yosys_version_str);
|
||||
log("\n");
|
||||
if (log_errfile == NULL) {
|
||||
log_files.push_back(stdout);
|
||||
log_error_stderr = true;
|
||||
}
|
||||
|
||||
if (print_banner)
|
||||
yosys_banner();
|
||||
|
||||
if (print_stats)
|
||||
log_hasher = new SHA1;
|
||||
|
||||
|
@ -242,7 +344,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
while (optind < argc)
|
||||
run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
|
||||
run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
|
||||
|
||||
if (!scriptfile.empty()) {
|
||||
if (scriptfile_tcl) {
|
||||
|
@ -253,14 +355,14 @@ int main(int argc, char **argv)
|
|||
log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n");
|
||||
#endif
|
||||
} else
|
||||
run_frontend(scriptfile, "script", yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
|
||||
run_frontend(scriptfile, "script", output_filename == "-" ? &backend_command : NULL);
|
||||
}
|
||||
|
||||
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
|
||||
run_pass(*it, yosys_design);
|
||||
run_pass(*it);
|
||||
|
||||
if (!backend_command.empty())
|
||||
run_backend(output_filename, backend_command, yosys_design);
|
||||
run_backend(output_filename, backend_command);
|
||||
|
||||
if (print_stats)
|
||||
{
|
||||
|
@ -268,12 +370,37 @@ int main(int argc, char **argv)
|
|||
delete log_hasher;
|
||||
log_hasher = nullptr;
|
||||
|
||||
log_time = false;
|
||||
yosys_xtrace = 0;
|
||||
log_spacer();
|
||||
|
||||
if (mode_v && !mode_q)
|
||||
log_files.push_back(stderr);
|
||||
|
||||
#ifdef _WIN32
|
||||
log("End of script. Logfile hash: %s\n", hash.c_str());
|
||||
#else
|
||||
std::string meminfo;
|
||||
std::string stats_divider = ", ";
|
||||
# ifdef __linux__
|
||||
std::ifstream statm;
|
||||
statm.open(stringf("/proc/%lld/statm", (long long)getpid()));
|
||||
if (statm.is_open()) {
|
||||
int sz_total, sz_resident;
|
||||
statm >> sz_total >> sz_resident;
|
||||
meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident",
|
||||
sz_total * (getpagesize() / 1024.0 / 1024.0),
|
||||
sz_resident * (getpagesize() / 1024.0 / 1024.0));
|
||||
stats_divider = "\n";
|
||||
}
|
||||
# endif
|
||||
|
||||
struct rusage ru_buffer;
|
||||
getrusage(RUSAGE_SELF, &ru_buffer);
|
||||
log_spacer();
|
||||
log("End of script. Logfile hash: %s, CPU: user %.2fs system %.2fs\n", hash.c_str(),
|
||||
ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
|
||||
ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec);
|
||||
log("End of script. Logfile hash: %s%sCPU: user %.2fs system %.2fs%s\n", hash.c_str(),
|
||||
stats_divider.c_str(), ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
|
||||
ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec, meminfo.c_str());
|
||||
#endif
|
||||
log("%s\n", yosys_version_str);
|
||||
|
||||
int64_t total_ns = 0;
|
||||
|
@ -285,37 +412,49 @@ int main(int argc, char **argv)
|
|||
timedat.insert(make_tuple(it.second->runtime_ns + 1, it.second->call_counter, it.first));
|
||||
}
|
||||
|
||||
int out_count = 0;
|
||||
log("Time spent:");
|
||||
for (auto it = timedat.rbegin(); it != timedat.rend() && out_count < 4; it++, out_count++) {
|
||||
if (out_count >= 2 && (std::get<0>(*it) < 1000000000 || int(100*std::get<0>(*it) / total_ns) < 20)) {
|
||||
log(", ...");
|
||||
break;
|
||||
if (timing_details)
|
||||
{
|
||||
log("Time spent:\n");
|
||||
for (auto it = timedat.rbegin(); it != timedat.rend(); it++) {
|
||||
log("%5d%% %5d calls %8.3f sec %s\n", int(100*std::get<0>(*it) / total_ns),
|
||||
std::get<1>(*it), std::get<0>(*it) / 1000000000.0, std::get<2>(*it).c_str());
|
||||
}
|
||||
log("%s %d%% %dx %s (%d sec)", out_count ? "," : "", int(100*std::get<0>(*it) / total_ns),
|
||||
std::get<1>(*it), std::get<2>(*it).c_str(), int(std::get<0>(*it) / 1000000000));
|
||||
}
|
||||
log("%s\n", out_count ? "" : " no commands executed");
|
||||
else
|
||||
{
|
||||
int out_count = 0;
|
||||
log("Time spent:");
|
||||
for (auto it = timedat.rbegin(); it != timedat.rend() && out_count < 4; it++, out_count++) {
|
||||
if (out_count >= 2 && (std::get<0>(*it) < 1000000000 || int(100*std::get<0>(*it) / total_ns) < 20)) {
|
||||
log(", ...");
|
||||
break;
|
||||
}
|
||||
log("%s %d%% %dx %s (%d sec)", out_count ? "," : "", int(100*std::get<0>(*it) / total_ns),
|
||||
std::get<1>(*it), std::get<2>(*it).c_str(), int(std::get<0>(*it) / 1000000000));
|
||||
}
|
||||
log("%s\n", out_count ? "" : " no commands executed");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COVER_ACTIVE
|
||||
#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
|
||||
if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
|
||||
{
|
||||
char filename_buffer[4096];
|
||||
string filename;
|
||||
FILE *f;
|
||||
|
||||
if (getenv("YOSYS_COVER_DIR")) {
|
||||
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid());
|
||||
f = fdopen(mkstemps(filename_buffer, 4), "w");
|
||||
filename = stringf("%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid());
|
||||
filename = make_temp_file(filename);
|
||||
} else {
|
||||
snprintf(filename_buffer, 4096, "%s", getenv("YOSYS_COVER_FILE"));
|
||||
f = fopen(filename_buffer, "a+");
|
||||
filename = getenv("YOSYS_COVER_FILE");
|
||||
}
|
||||
|
||||
if (f == NULL)
|
||||
log_error("Can't create coverage file `%s'.\n", filename_buffer);
|
||||
f = fopen(filename.c_str(), "a+");
|
||||
|
||||
log("<writing coverage file \"%s\">\n", filename_buffer);
|
||||
if (f == NULL)
|
||||
log_error("Can't create coverage file `%s'.\n", filename.c_str());
|
||||
|
||||
log("<writing coverage file \"%s\">\n", filename.c_str());
|
||||
|
||||
for (auto &it : get_coverage_data())
|
||||
fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
|
||||
|
@ -324,6 +463,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
memhasher_off();
|
||||
if (call_abort)
|
||||
abort();
|
||||
|
||||
|
@ -347,3 +487,5 @@ int main(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif /* EMSCRIPTEN */
|
||||
|
||||
|
|
|
@ -0,0 +1,887 @@
|
|||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Written by Clifford Wolf <clifford@clifford.at> in 2014
|
||||
// -------------------------------------------------------
|
||||
|
||||
#ifndef HASHLIB_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hashlib {
|
||||
|
||||
const int hashtable_size_trigger = 2;
|
||||
const int hashtable_size_factor = 3;
|
||||
|
||||
// The XOR version of DJB2
|
||||
inline unsigned int mkhash(unsigned int a, unsigned int b) {
|
||||
return ((a << 5) + a) ^ b;
|
||||
}
|
||||
|
||||
// traditionally 5381 is used as starting value for the djb2 hash
|
||||
const unsigned int mkhash_init = 5381;
|
||||
|
||||
// The ADD version of DJB2
|
||||
// (usunsigned int mkhashe this version for cache locality in b)
|
||||
inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
|
||||
return ((a << 5) + a) + b;
|
||||
}
|
||||
|
||||
inline unsigned int mkhash_xorshift(unsigned int a) {
|
||||
if (sizeof(a) == 4) {
|
||||
a ^= a << 13;
|
||||
a ^= a >> 17;
|
||||
a ^= a << 5;
|
||||
} else if (sizeof(a) == 8) {
|
||||
a ^= a << 13;
|
||||
a ^= a >> 7;
|
||||
a ^= a << 17;
|
||||
} else
|
||||
throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
|
||||
return a;
|
||||
}
|
||||
|
||||
template<typename T> struct hash_ops {
|
||||
static inline bool cmp(const T &a, const T &b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(const T &a) {
|
||||
return a.hash();
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct hash_ops<int> {
|
||||
template<typename T>
|
||||
static inline bool cmp(T a, T b) {
|
||||
return a == b;
|
||||
}
|
||||
template<typename T>
|
||||
static inline unsigned int hash(T a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct hash_ops<std::string> {
|
||||
static inline bool cmp(const std::string &a, const std::string &b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(const std::string &a) {
|
||||
unsigned int v = 0;
|
||||
for (auto c : a)
|
||||
v = mkhash(v, c);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
|
||||
static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(std::pair<P, Q> a) {
|
||||
hash_ops<P> p_ops;
|
||||
hash_ops<Q> q_ops;
|
||||
return mkhash(p_ops.hash(a.first), q_ops.hash(a.second));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct hash_ops<std::vector<T>> {
|
||||
static inline bool cmp(std::vector<T> a, std::vector<T> b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(std::vector<T> a) {
|
||||
hash_ops<T> t_ops;
|
||||
unsigned int h = mkhash_init;
|
||||
for (auto k : a)
|
||||
h = mkhash(h, t_ops.hash(k));
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct hash_cstr_ops {
|
||||
static inline bool cmp(const char *a, const char *b) {
|
||||
for (int i = 0; a[i] || b[i]; i++)
|
||||
if (a[i] != b[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
static inline unsigned int hash(const char *a) {
|
||||
unsigned int hash = mkhash_init;
|
||||
while (*a)
|
||||
hash = mkhash(hash, *(a++));
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
struct hash_ptr_ops {
|
||||
static inline bool cmp(const void *a, const void *b) {
|
||||
return a == b;
|
||||
}
|
||||
static inline unsigned int hash(const void *a) {
|
||||
return (unsigned long)a;
|
||||
}
|
||||
};
|
||||
|
||||
struct hash_obj_ops {
|
||||
static inline bool cmp(const void *a, const void *b) {
|
||||
return a == b;
|
||||
}
|
||||
template<typename T>
|
||||
static inline unsigned int hash(const T *a) {
|
||||
return a->hash();
|
||||
}
|
||||
};
|
||||
|
||||
inline int hashtable_size(int min_size)
|
||||
{
|
||||
static std::vector<int> zero_and_some_primes = {
|
||||
0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
|
||||
853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
|
||||
12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
|
||||
120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
|
||||
897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
|
||||
5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
|
||||
25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
|
||||
121590311, 151987889, 189984863, 237481091, 296851369, 371064217
|
||||
};
|
||||
|
||||
for (auto p : zero_and_some_primes)
|
||||
if (p >= min_size) return p;
|
||||
|
||||
if (sizeof(int) == 4)
|
||||
throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
|
||||
|
||||
for (auto p : zero_and_some_primes)
|
||||
if (100129 * p > min_size) return 100129 * p;
|
||||
|
||||
throw std::length_error("hash table exceeded maximum size.");
|
||||
}
|
||||
|
||||
template<typename K, typename T, typename OPS = hash_ops<K>> class dict;
|
||||
template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
|
||||
template<typename K, typename OPS = hash_ops<K>> class pool;
|
||||
|
||||
template<typename K, typename T, typename OPS>
|
||||
class dict
|
||||
{
|
||||
struct entry_t
|
||||
{
|
||||
std::pair<K, T> udata;
|
||||
int next;
|
||||
|
||||
entry_t() { }
|
||||
entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { }
|
||||
entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { }
|
||||
};
|
||||
|
||||
std::vector<int> hashtable;
|
||||
std::vector<entry_t> entries;
|
||||
OPS ops;
|
||||
|
||||
#ifdef NDEBUG
|
||||
static inline void do_assert(bool) { }
|
||||
#else
|
||||
static inline void do_assert(bool cond) {
|
||||
if (!cond) throw std::runtime_error("dict<> assert failed.");
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_hash(const K &key) const
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
if (!hashtable.empty())
|
||||
hash = ops.hash(key) % (unsigned int)(hashtable.size());
|
||||
return hash;
|
||||
}
|
||||
|
||||
void do_rehash()
|
||||
{
|
||||
hashtable.clear();
|
||||
hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
|
||||
|
||||
for (int i = 0; i < int(entries.size()); i++) {
|
||||
do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
|
||||
int hash = do_hash(entries[i].udata.first);
|
||||
entries[i].next = hashtable[hash];
|
||||
hashtable[hash] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int do_erase(int index, int hash)
|
||||
{
|
||||
do_assert(index < int(entries.size()));
|
||||
if (hashtable.empty() || index < 0)
|
||||
return 0;
|
||||
|
||||
int k = hashtable[hash];
|
||||
do_assert(0 <= k && k < int(entries.size()));
|
||||
|
||||
if (k == index) {
|
||||
hashtable[hash] = entries[index].next;
|
||||
} else {
|
||||
while (entries[k].next != index) {
|
||||
k = entries[k].next;
|
||||
do_assert(0 <= k && k < int(entries.size()));
|
||||
}
|
||||
entries[k].next = entries[index].next;
|
||||
}
|
||||
|
||||
int back_idx = entries.size()-1;
|
||||
|
||||
if (index != back_idx)
|
||||
{
|
||||
int back_hash = do_hash(entries[back_idx].udata.first);
|
||||
|
||||
k = hashtable[back_hash];
|
||||
do_assert(0 <= k && k < int(entries.size()));
|
||||
|
||||
if (k == back_idx) {
|
||||
hashtable[back_hash] = index;
|
||||
} else {
|
||||
while (entries[k].next != back_idx) {
|
||||
k = entries[k].next;
|
||||
do_assert(0 <= k && k < int(entries.size()));
|
||||
}
|
||||
entries[k].next = index;
|
||||
}
|
||||
|
||||
entries[index] = std::move(entries[back_idx]);
|
||||
}
|
||||
|
||||
entries.pop_back();
|
||||
|
||||
if (entries.empty())
|
||||
hashtable.clear();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int do_lookup(const K &key, int &hash) const
|
||||
{
|
||||
if (hashtable.empty())
|
||||
return -1;
|
||||
|
||||
if (entries.size() * hashtable_size_trigger > hashtable.size()) {
|
||||
((dict*)this)->do_rehash();
|
||||
hash = do_hash(key);
|
||||
}
|
||||
|
||||
int index = hashtable[hash];
|
||||
|
||||
while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
|
||||
index = entries[index].next;
|
||||
do_assert(-1 <= index && index < int(entries.size()));
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int do_insert(const K &key, int &hash)
|
||||
{
|
||||
if (hashtable.empty()) {
|
||||
entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
|
||||
do_rehash();
|
||||
hash = do_hash(key);
|
||||
} else {
|
||||
entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
|
||||
hashtable[hash] = entries.size() - 1;
|
||||
}
|
||||
return entries.size() - 1;
|
||||
}
|
||||
|
||||
int do_insert(const std::pair<K, T> &value, int &hash)
|
||||
{
|
||||
if (hashtable.empty()) {
|
||||
entries.push_back(entry_t(value, -1));
|
||||
do_rehash();
|
||||
hash = do_hash(value.first);
|
||||
} else {
|
||||
entries.push_back(entry_t(value, hashtable[hash]));
|
||||
hashtable[hash] = entries.size() - 1;
|
||||
}
|
||||
return entries.size() - 1;
|
||||
}
|
||||
|
||||
public:
|
||||
class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
|
||||
{
|
||||
friend class dict;
|
||||
protected:
|
||||
const dict *ptr;
|
||||
int index;
|
||||
const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { }
|
||||
public:
|
||||
const_iterator() { }
|
||||
const_iterator operator++() { index--; return *this; }
|
||||
bool operator<(const const_iterator &other) const { return index > other.index; }
|
||||
bool operator==(const const_iterator &other) const { return index == other.index; }
|
||||
bool operator!=(const const_iterator &other) const { return index != other.index; }
|
||||
const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
|
||||
const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
|
||||
};
|
||||
|
||||
class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
|
||||
{
|
||||
friend class dict;
|
||||
protected:
|
||||
dict *ptr;
|
||||
int index;
|
||||
iterator(dict *ptr, int index) : ptr(ptr), index(index) { }
|
||||
public:
|
||||
iterator() { }
|
||||
iterator operator++() { index--; return *this; }
|
||||
bool operator<(const iterator &other) const { return index > other.index; }
|
||||
bool operator==(const iterator &other) const { return index == other.index; }
|
||||
bool operator!=(const iterator &other) const { return index != other.index; }
|
||||
std::pair<K, T> &operator*() { return ptr->entries[index].udata; }
|
||||
std::pair<K, T> *operator->() { return &ptr->entries[index].udata; }
|
||||
const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
|
||||
const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
|
||||
operator const_iterator() const { return const_iterator(ptr, index); }
|
||||
};
|
||||
|
||||
dict()
|
||||
{
|
||||
}
|
||||
|
||||
dict(const dict &other)
|
||||
{
|
||||
entries = other.entries;
|
||||
do_rehash();
|
||||
}
|
||||
|
||||
dict(dict &&other)
|
||||
{
|
||||
swap(other);
|
||||
}
|
||||
|
||||
dict &operator=(const dict &other) {
|
||||
entries = other.entries;
|
||||
do_rehash();
|
||||
return *this;
|
||||
}
|
||||
|
||||
dict &operator=(dict &&other) {
|
||||
clear();
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
dict(const std::initializer_list<std::pair<K, T>> &list)
|
||||
{
|
||||
for (auto &it : list)
|
||||
insert(it);
|
||||
}
|
||||
|
||||
template<class InputIterator>
|
||||
dict(InputIterator first, InputIterator last)
|
||||
{
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
template<class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
insert(*first);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
i = do_insert(key, hash);
|
||||
return std::pair<iterator, bool>(iterator(this, i), true);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const std::pair<K, T> &value)
|
||||
{
|
||||
int hash = do_hash(value.first);
|
||||
int i = do_lookup(value.first, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
i = do_insert(value, hash);
|
||||
return std::pair<iterator, bool>(iterator(this, i), true);
|
||||
}
|
||||
|
||||
int erase(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int index = do_lookup(key, hash);
|
||||
return do_erase(index, hash);
|
||||
}
|
||||
|
||||
iterator erase(iterator it)
|
||||
{
|
||||
int hash = do_hash(it->first);
|
||||
do_erase(it.index, hash);
|
||||
return ++it;
|
||||
}
|
||||
|
||||
int count(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i < 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
int count(const K &key, const_iterator it) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i < 0 || i > it.index ? 0 : 1;
|
||||
}
|
||||
|
||||
iterator find(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return end();
|
||||
return iterator(this, i);
|
||||
}
|
||||
|
||||
const_iterator find(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return end();
|
||||
return const_iterator(this, i);
|
||||
}
|
||||
|
||||
T& at(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
throw std::out_of_range("dict::at()");
|
||||
return entries[i].udata.second;
|
||||
}
|
||||
|
||||
const T& at(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
throw std::out_of_range("dict::at()");
|
||||
return entries[i].udata.second;
|
||||
}
|
||||
|
||||
T& operator[](const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
i = do_insert(std::pair<K, T>(key, T()), hash);
|
||||
return entries[i].udata.second;
|
||||
}
|
||||
|
||||
template<typename Compare = std::less<K>>
|
||||
void sort(Compare comp = Compare())
|
||||
{
|
||||
std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
|
||||
do_rehash();
|
||||
}
|
||||
|
||||
void swap(dict &other)
|
||||
{
|
||||
hashtable.swap(other.hashtable);
|
||||
entries.swap(other.entries);
|
||||
}
|
||||
|
||||
bool operator==(const dict &other) const {
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
for (auto &it : entries) {
|
||||
auto oit = other.find(it.udata.first);
|
||||
if (oit == other.end() || !(oit->second == it.udata.second))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const dict &other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
size_t size() const { return entries.size(); }
|
||||
bool empty() const { return entries.empty(); }
|
||||
void clear() { hashtable.clear(); entries.clear(); }
|
||||
|
||||
iterator begin() { return iterator(this, int(entries.size())-1); }
|
||||
iterator end() { return iterator(nullptr, -1); }
|
||||
|
||||
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
|
||||
const_iterator end() const { return const_iterator(nullptr, -1); }
|
||||
};
|
||||
|
||||
template<typename K, typename OPS>
|
||||
class pool
|
||||
{
|
||||
template<typename, int, typename> friend class idict;
|
||||
|
||||
protected:
|
||||
struct entry_t
|
||||
{
|
||||
K udata;
|
||||
int next;
|
||||
|
||||
entry_t() { }
|
||||
entry_t(const K &udata, int next) : udata(udata), next(next) { }
|
||||
};
|
||||
|
||||
std::vector<int> hashtable;
|
||||
std::vector<entry_t> entries;
|
||||
OPS ops;
|
||||
|
||||
#ifdef NDEBUG
|
||||
static inline void do_assert(bool) { }
|
||||
#else
|
||||
static inline void do_assert(bool cond) {
|
||||
if (!cond) throw std::runtime_error("pool<> assert failed.");
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_hash(const K &key) const
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
if (!hashtable.empty())
|
||||
hash = ops.hash(key) % (unsigned int)(hashtable.size());
|
||||
return hash;
|
||||
}
|
||||
|
||||
void do_rehash()
|
||||
{
|
||||
hashtable.clear();
|
||||
hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
|
||||
|
||||
for (int i = 0; i < int(entries.size()); i++) {
|
||||
do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
|
||||
int hash = do_hash(entries[i].udata);
|
||||
entries[i].next = hashtable[hash];
|
||||
hashtable[hash] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int do_erase(int index, int hash)
|
||||
{
|
||||
do_assert(index < int(entries.size()));
|
||||
if (hashtable.empty() || index < 0)
|
||||
return 0;
|
||||
|
||||
int k = hashtable[hash];
|
||||
if (k == index) {
|
||||
hashtable[hash] = entries[index].next;
|
||||
} else {
|
||||
while (entries[k].next != index) {
|
||||
k = entries[k].next;
|
||||
do_assert(0 <= k && k < int(entries.size()));
|
||||
}
|
||||
entries[k].next = entries[index].next;
|
||||
}
|
||||
|
||||
int back_idx = entries.size()-1;
|
||||
|
||||
if (index != back_idx)
|
||||
{
|
||||
int back_hash = do_hash(entries[back_idx].udata);
|
||||
|
||||
k = hashtable[back_hash];
|
||||
if (k == back_idx) {
|
||||
hashtable[back_hash] = index;
|
||||
} else {
|
||||
while (entries[k].next != back_idx) {
|
||||
k = entries[k].next;
|
||||
do_assert(0 <= k && k < int(entries.size()));
|
||||
}
|
||||
entries[k].next = index;
|
||||
}
|
||||
|
||||
entries[index] = std::move(entries[back_idx]);
|
||||
}
|
||||
|
||||
entries.pop_back();
|
||||
|
||||
if (entries.empty())
|
||||
hashtable.clear();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int do_lookup(const K &key, int &hash) const
|
||||
{
|
||||
if (hashtable.empty())
|
||||
return -1;
|
||||
|
||||
if (entries.size() * hashtable_size_trigger > hashtable.size()) {
|
||||
((pool*)this)->do_rehash();
|
||||
hash = do_hash(key);
|
||||
}
|
||||
|
||||
int index = hashtable[hash];
|
||||
|
||||
while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
|
||||
index = entries[index].next;
|
||||
do_assert(-1 <= index && index < int(entries.size()));
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int do_insert(const K &value, int &hash)
|
||||
{
|
||||
if (hashtable.empty()) {
|
||||
entries.push_back(entry_t(value, -1));
|
||||
do_rehash();
|
||||
hash = do_hash(value);
|
||||
} else {
|
||||
entries.push_back(entry_t(value, hashtable[hash]));
|
||||
hashtable[hash] = entries.size() - 1;
|
||||
}
|
||||
return entries.size() - 1;
|
||||
}
|
||||
|
||||
public:
|
||||
class const_iterator : public std::iterator<std::forward_iterator_tag, K>
|
||||
{
|
||||
friend class pool;
|
||||
protected:
|
||||
const pool *ptr;
|
||||
int index;
|
||||
const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { }
|
||||
public:
|
||||
const_iterator() { }
|
||||
const_iterator operator++() { index--; return *this; }
|
||||
bool operator==(const const_iterator &other) const { return index == other.index; }
|
||||
bool operator!=(const const_iterator &other) const { return index != other.index; }
|
||||
const K &operator*() const { return ptr->entries[index].udata; }
|
||||
const K *operator->() const { return &ptr->entries[index].udata; }
|
||||
};
|
||||
|
||||
class iterator : public std::iterator<std::forward_iterator_tag, K>
|
||||
{
|
||||
friend class pool;
|
||||
protected:
|
||||
pool *ptr;
|
||||
int index;
|
||||
iterator(pool *ptr, int index) : ptr(ptr), index(index) { }
|
||||
public:
|
||||
iterator() { }
|
||||
iterator operator++() { index--; return *this; }
|
||||
bool operator==(const iterator &other) const { return index == other.index; }
|
||||
bool operator!=(const iterator &other) const { return index != other.index; }
|
||||
K &operator*() { return ptr->entries[index].udata; }
|
||||
K *operator->() { return &ptr->entries[index].udata; }
|
||||
const K &operator*() const { return ptr->entries[index].udata; }
|
||||
const K *operator->() const { return &ptr->entries[index].udata; }
|
||||
operator const_iterator() const { return const_iterator(ptr, index); }
|
||||
};
|
||||
|
||||
pool()
|
||||
{
|
||||
}
|
||||
|
||||
pool(const pool &other)
|
||||
{
|
||||
entries = other.entries;
|
||||
do_rehash();
|
||||
}
|
||||
|
||||
pool(pool &&other)
|
||||
{
|
||||
swap(other);
|
||||
}
|
||||
|
||||
pool &operator=(const pool &other) {
|
||||
entries = other.entries;
|
||||
do_rehash();
|
||||
return *this;
|
||||
}
|
||||
|
||||
pool &operator=(pool &&other) {
|
||||
clear();
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pool(const std::initializer_list<K> &list)
|
||||
{
|
||||
for (auto &it : list)
|
||||
insert(it);
|
||||
}
|
||||
|
||||
template<class InputIterator>
|
||||
pool(InputIterator first, InputIterator last)
|
||||
{
|
||||
insert(first, last);
|
||||
}
|
||||
|
||||
template<class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
insert(*first);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const K &value)
|
||||
{
|
||||
int hash = do_hash(value);
|
||||
int i = do_lookup(value, hash);
|
||||
if (i >= 0)
|
||||
return std::pair<iterator, bool>(iterator(this, i), false);
|
||||
i = do_insert(value, hash);
|
||||
return std::pair<iterator, bool>(iterator(this, i), true);
|
||||
}
|
||||
|
||||
int erase(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int index = do_lookup(key, hash);
|
||||
return do_erase(index, hash);
|
||||
}
|
||||
|
||||
iterator erase(iterator it)
|
||||
{
|
||||
int hash = do_hash(*it);
|
||||
do_erase(it.index, hash);
|
||||
return ++it;
|
||||
}
|
||||
|
||||
int count(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i < 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
int count(const K &key, const_iterator it) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i < 0 || i > it.index ? 0 : 1;
|
||||
}
|
||||
|
||||
iterator find(const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return end();
|
||||
return iterator(this, i);
|
||||
}
|
||||
|
||||
const_iterator find(const K &key) const
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
return end();
|
||||
return const_iterator(this, i);
|
||||
}
|
||||
|
||||
bool operator[](const K &key)
|
||||
{
|
||||
int hash = do_hash(key);
|
||||
int i = do_lookup(key, hash);
|
||||
return i >= 0;
|
||||
}
|
||||
|
||||
template<typename Compare = std::less<K>>
|
||||
void sort(Compare comp = Compare())
|
||||
{
|
||||
std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
|
||||
do_rehash();
|
||||
}
|
||||
|
||||
void swap(pool &other)
|
||||
{
|
||||
hashtable.swap(other.hashtable);
|
||||
entries.swap(other.entries);
|
||||
}
|
||||
|
||||
bool operator==(const pool &other) const {
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
for (auto &it : entries)
|
||||
if (!other.count(it.udata))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const pool &other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
size_t size() const { return entries.size(); }
|
||||
bool empty() const { return entries.empty(); }
|
||||
void clear() { hashtable.clear(); entries.clear(); }
|
||||
|
||||
iterator begin() { return iterator(this, int(entries.size())-1); }
|
||||
iterator end() { return iterator(nullptr, -1); }
|
||||
|
||||
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
|
||||
const_iterator end() const { return const_iterator(nullptr, -1); }
|
||||
};
|
||||
|
||||
template<typename K, int offset, typename OPS>
|
||||
class idict
|
||||
{
|
||||
pool<K, OPS> database;
|
||||
|
||||
public:
|
||||
typedef typename pool<K, OPS>::const_iterator const_iterator;
|
||||
|
||||
int operator()(const K &key)
|
||||
{
|
||||
int hash = database.do_hash(key);
|
||||
int i = database.do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
i = database.do_insert(key, hash);
|
||||
return i + offset;
|
||||
}
|
||||
|
||||
int at(const K &key) const
|
||||
{
|
||||
int hash = database.do_hash(key);
|
||||
int i = database.do_lookup(key, hash);
|
||||
if (i < 0)
|
||||
throw std::out_of_range("idict::at()");
|
||||
return i + offset;
|
||||
}
|
||||
|
||||
int count(const K &key) const
|
||||
{
|
||||
int hash = database.do_hash(key);
|
||||
int i = database.do_lookup(key, hash);
|
||||
return i < 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
void expect(const K &key, int i)
|
||||
{
|
||||
int j = (*this)(key);
|
||||
if (i != j)
|
||||
throw std::out_of_range("idict::expect()");
|
||||
}
|
||||
|
||||
const K &operator[](int index) const
|
||||
{
|
||||
return database.entries.at(index - offset).udata;
|
||||
}
|
||||
|
||||
const_iterator begin() const { return database.begin(); }
|
||||
const_iterator end() const { return database.end(); }
|
||||
};
|
||||
|
||||
} /* namespace hashlib */
|
||||
|
||||
#endif
|
228
kernel/log.cc
228
kernel/log.cc
|
@ -21,7 +21,14 @@
|
|||
#include "libs/sha1/sha1.h"
|
||||
#include "backends/ilang/ilang_backend.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#if !defined(_WIN32) || defined(__MINGW32__)
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -37,17 +44,41 @@ FILE *log_errfile = NULL;
|
|||
SHA1 *log_hasher = NULL;
|
||||
|
||||
bool log_time = false;
|
||||
bool log_error_stderr = false;
|
||||
bool log_cmd_error_throw = false;
|
||||
bool log_quiet_warnings = false;
|
||||
int log_verbose_level;
|
||||
string log_last_error;
|
||||
|
||||
std::vector<int> header_count;
|
||||
std::list<std::string> string_buf;
|
||||
int string_buf_size = 0;
|
||||
vector<int> header_count;
|
||||
pool<RTLIL::IdString> log_id_cache;
|
||||
vector<string> string_buf;
|
||||
int string_buf_index = -1;
|
||||
|
||||
static struct timeval initial_tv = { 0, 0 };
|
||||
static bool next_print_log = false;
|
||||
static int log_newline_count = 0;
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// this will get time information and return it in timeval, simulating gettimeofday()
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
LARGE_INTEGER counter;
|
||||
LARGE_INTEGER freq;
|
||||
|
||||
QueryPerformanceFrequency(&freq);
|
||||
QueryPerformanceCounter(&counter);
|
||||
|
||||
counter.QuadPart *= 1000000;
|
||||
counter.QuadPart /= freq.QuadPart;
|
||||
|
||||
tv->tv_sec = long(counter.QuadPart / 1000000);
|
||||
tv->tv_usec = counter.QuadPart % 1000000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void logv(const char *format, va_list ap)
|
||||
{
|
||||
while (format[0] == '\n' && format[1] != 0) {
|
||||
|
@ -62,9 +93,9 @@ void logv(const char *format, va_list ap)
|
|||
|
||||
size_t nnl_pos = str.find_last_not_of('\n');
|
||||
if (nnl_pos == std::string::npos)
|
||||
log_newline_count += SIZE(str);
|
||||
log_newline_count += GetSize(str);
|
||||
else
|
||||
log_newline_count = SIZE(str) - nnl_pos - 1;
|
||||
log_newline_count = GetSize(str) - nnl_pos - 1;
|
||||
|
||||
if (log_hasher)
|
||||
log_hasher->update(str);
|
||||
|
@ -128,15 +159,43 @@ void logv_header(const char *format, va_list ap)
|
|||
log_files.pop_back();
|
||||
}
|
||||
|
||||
void logv_warning(const char *format, va_list ap)
|
||||
{
|
||||
if (log_errfile != NULL && !log_quiet_warnings)
|
||||
log_files.push_back(log_errfile);
|
||||
|
||||
log("Warning: ");
|
||||
logv(format, ap);
|
||||
log_flush();
|
||||
|
||||
if (log_errfile != NULL && !log_quiet_warnings)
|
||||
log_files.pop_back();
|
||||
}
|
||||
|
||||
void logv_error(const char *format, va_list ap)
|
||||
{
|
||||
#ifdef EMSCRIPTEN
|
||||
auto backup_log_files = log_files;
|
||||
#endif
|
||||
|
||||
if (log_errfile != NULL)
|
||||
log_files.push_back(log_errfile);
|
||||
|
||||
log("ERROR: ");
|
||||
logv(format, ap);
|
||||
if (log_error_stderr)
|
||||
for (auto &f : log_files)
|
||||
if (f == stdout)
|
||||
f = stderr;
|
||||
|
||||
log_last_error = vstringf(format, ap);
|
||||
log("ERROR: %s", log_last_error.c_str());
|
||||
log_flush();
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
log_files = backup_log_files;
|
||||
throw 0;
|
||||
#else
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void log(const char *format, ...)
|
||||
|
@ -155,6 +214,14 @@ void log_header(const char *format, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_warning(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
logv_warning(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_error(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -168,10 +235,10 @@ void log_cmd_error(const char *format, ...)
|
|||
va_start(ap, format);
|
||||
|
||||
if (log_cmd_error_throw) {
|
||||
log("ERROR: ");
|
||||
logv(format, ap);
|
||||
log_last_error = vstringf(format, ap);
|
||||
log("ERROR: %s", log_last_error.c_str());
|
||||
log_flush();
|
||||
throw log_cmd_error_expection();
|
||||
throw log_cmd_error_exception();
|
||||
}
|
||||
|
||||
logv_error(format, ap);
|
||||
|
@ -191,17 +258,112 @@ void log_push()
|
|||
void log_pop()
|
||||
{
|
||||
header_count.pop_back();
|
||||
log_id_cache.clear();
|
||||
string_buf.clear();
|
||||
string_buf_size = 0;
|
||||
string_buf_index = -1;
|
||||
log_flush();
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
void log_backtrace(const char *prefix, int levels)
|
||||
{
|
||||
if (levels <= 0) return;
|
||||
|
||||
Dl_info dli;
|
||||
void *p;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(0))) && dladdr(p, &dli)) {
|
||||
log("%sframe #1: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #1: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 1) return;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(1))) && dladdr(p, &dli)) {
|
||||
log("%sframe #2: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #2: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 2) return;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(2))) && dladdr(p, &dli)) {
|
||||
log("%sframe #3: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #3: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 3) return;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(3))) && dladdr(p, &dli)) {
|
||||
log("%sframe #4: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #4: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 4) return;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(4))) && dladdr(p, &dli)) {
|
||||
log("%sframe #5: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #5: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 5) return;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(5))) && dladdr(p, &dli)) {
|
||||
log("%sframe #6: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #6: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 6) return;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(6))) && dladdr(p, &dli)) {
|
||||
log("%sframe #7: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #7: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 7) return;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(7))) && dladdr(p, &dli)) {
|
||||
log("%sframe #8: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #8: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 8) return;
|
||||
|
||||
if ((p = __builtin_extract_return_addr(__builtin_return_address(8))) && dladdr(p, &dli)) {
|
||||
log("%sframe #9: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
|
||||
} else {
|
||||
log("%sframe #9: ---\n", prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels <= 9) return;
|
||||
}
|
||||
#else
|
||||
void log_backtrace(const char*, int) { }
|
||||
#endif
|
||||
|
||||
void log_reset_stack()
|
||||
{
|
||||
while (header_count.size() > 1)
|
||||
header_count.pop_back();
|
||||
log_id_cache.clear();
|
||||
string_buf.clear();
|
||||
string_buf_size = 0;
|
||||
string_buf_index = -1;
|
||||
log_flush();
|
||||
}
|
||||
|
||||
|
@ -223,22 +385,28 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
|
|||
std::stringstream buf;
|
||||
ILANG_BACKEND::dump_sigspec(buf, sig, autoint);
|
||||
|
||||
if (string_buf_size < 100)
|
||||
string_buf_size++;
|
||||
else
|
||||
string_buf.pop_front();
|
||||
string_buf.push_back(buf.str());
|
||||
|
||||
return string_buf.back().c_str();
|
||||
if (string_buf.size() < 100) {
|
||||
string_buf.push_back(buf.str());
|
||||
return string_buf.back().c_str();
|
||||
} else {
|
||||
if (++string_buf_index == 100)
|
||||
string_buf_index = 0;
|
||||
string_buf[string_buf_index] = buf.str();
|
||||
return string_buf[string_buf_index].c_str();
|
||||
}
|
||||
}
|
||||
|
||||
const char *log_id(RTLIL::IdString str)
|
||||
{
|
||||
log_id_cache.insert(str);
|
||||
const char *p = str.c_str();
|
||||
log_assert(RTLIL::IdString::global_refcount_storage_[str.index_] > 1);
|
||||
if (p[0] == '\\' && p[1] != '$' && p[1] != 0)
|
||||
return p+1;
|
||||
return p;
|
||||
if (p[0] != '\\')
|
||||
return p;
|
||||
if (p[1] == '$' || p[1] == '\\' || p[1] == 0)
|
||||
return p;
|
||||
if (p[1] >= '0' && p[1] <= '9')
|
||||
return p;
|
||||
return p+1;
|
||||
}
|
||||
|
||||
void log_cell(RTLIL::Cell *cell, std::string indent)
|
||||
|
@ -251,9 +419,9 @@ void log_cell(RTLIL::Cell *cell, std::string indent)
|
|||
// ---------------------------------------------------
|
||||
// This is the magic behind the code coverage counters
|
||||
// ---------------------------------------------------
|
||||
#ifdef COVER_ACTIVE
|
||||
#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
|
||||
|
||||
std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
|
||||
dict<std::string, std::pair<std::string, int>> extra_coverage_data;
|
||||
|
||||
void cover_extra(std::string parent, std::string id, bool increment) {
|
||||
if (extra_coverage_data.count(id) == 0) {
|
||||
|
@ -266,9 +434,9 @@ void cover_extra(std::string parent, std::string id, bool increment) {
|
|||
extra_coverage_data[id].second++;
|
||||
}
|
||||
|
||||
std::map<std::string, std::pair<std::string, int>> get_coverage_data()
|
||||
dict<std::string, std::pair<std::string, int>> get_coverage_data()
|
||||
{
|
||||
std::map<std::string, std::pair<std::string, int>> coverage_data;
|
||||
dict<std::string, std::pair<std::string, int>> coverage_data;
|
||||
|
||||
for (auto &it : pass_register) {
|
||||
std::string key = stringf("passes.%s", it.first.c_str());
|
||||
|
@ -278,14 +446,14 @@ std::map<std::string, std::pair<std::string, int>> get_coverage_data()
|
|||
|
||||
for (auto &it : extra_coverage_data) {
|
||||
if (coverage_data.count(it.first))
|
||||
log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str());
|
||||
log_warning("found duplicate coverage id \"%s\".\n", it.first.c_str());
|
||||
coverage_data[it.first].first = it.second.first;
|
||||
coverage_data[it.first].second += it.second.second;
|
||||
}
|
||||
|
||||
for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
|
||||
if (coverage_data.count(p->id))
|
||||
log("WARNING: found duplicate coverage id \"%s\".\n", p->id);
|
||||
log_warning("found duplicate coverage id \"%s\".\n", p->id);
|
||||
coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
|
||||
coverage_data[p->id].second += p->counter;
|
||||
}
|
||||
|
|
63
kernel/log.h
63
kernel/log.h
|
@ -23,8 +23,14 @@
|
|||
#define LOG_H
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
// from libs/sha1/sha1.h
|
||||
class SHA1;
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -32,30 +38,36 @@ YOSYS_NAMESPACE_BEGIN
|
|||
#define S__LINE__sub1(x) S__LINE__sub2(x)
|
||||
#define S__LINE__ S__LINE__sub1(__LINE__)
|
||||
|
||||
struct log_cmd_error_expection { };
|
||||
struct log_cmd_error_exception { };
|
||||
|
||||
extern std::vector<FILE*> log_files;
|
||||
extern std::vector<std::ostream*> log_streams;
|
||||
extern FILE *log_errfile;
|
||||
extern class SHA1 *log_hasher;
|
||||
extern SHA1 *log_hasher;
|
||||
|
||||
extern bool log_time;
|
||||
extern bool log_error_stderr;
|
||||
extern bool log_cmd_error_throw;
|
||||
extern bool log_quiet_warnings;
|
||||
extern int log_verbose_level;
|
||||
extern string log_last_error;
|
||||
|
||||
void logv(const char *format, va_list ap);
|
||||
void logv_header(const char *format, va_list ap);
|
||||
void logv_error(const char *format, va_list ap) __attribute__ ((noreturn));
|
||||
void logv_warning(const char *format, va_list ap);
|
||||
YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn);
|
||||
|
||||
void log(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
|
||||
void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
|
||||
void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
void log_header(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
|
||||
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
|
||||
|
||||
void log_spacer();
|
||||
void log_push();
|
||||
void log_pop();
|
||||
|
||||
void log_backtrace(const char *prefix, int levels);
|
||||
void log_reset_stack();
|
||||
void log_flush();
|
||||
|
||||
|
@ -68,36 +80,43 @@ template<typename T> static inline const char *log_id(T *obj) {
|
|||
|
||||
void log_cell(RTLIL::Cell *cell, std::string indent = "");
|
||||
|
||||
#define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
|
||||
#define log_assert(_assert_expr_) do { if (_assert_expr_) break; log_error("Assert `%s' failed in %s:%d.\n", #_assert_expr_, __FILE__, __LINE__); } while (0)
|
||||
#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#ifndef NDEBUG
|
||||
static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) {
|
||||
if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line);
|
||||
}
|
||||
# define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)
|
||||
#else
|
||||
# define log_assert(_assert_expr_)
|
||||
#endif
|
||||
|
||||
#define log_abort() YOSYS_NAMESPACE_PREFIX log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
|
||||
#define log_ping() YOSYS_NAMESPACE_PREFIX log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
|
||||
|
||||
// ---------------------------------------------------
|
||||
// This is the magic behind the code coverage counters
|
||||
// ---------------------------------------------------
|
||||
|
||||
#if defined(__linux__) && !defined(NDEBUG)
|
||||
#define COVER_ACTIVE
|
||||
#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
|
||||
|
||||
#define cover(_id) do { \
|
||||
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1))) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
|
||||
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
|
||||
__d.counter++; \
|
||||
} while (0)
|
||||
|
||||
struct CoverData {
|
||||
const char *file, *func, *id;
|
||||
int line, counter;
|
||||
} __attribute__ ((packed));
|
||||
} YS_ATTRIBUTE(packed);
|
||||
|
||||
// this two symbols are created by the linker for the "yosys_cover_list" ELF section
|
||||
extern "C" struct CoverData __start_yosys_cover_list[];
|
||||
extern "C" struct CoverData __stop_yosys_cover_list[];
|
||||
|
||||
extern std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
|
||||
extern dict<std::string, std::pair<std::string, int>> extra_coverage_data;
|
||||
|
||||
void cover_extra(std::string parent, std::string id, bool increment = true);
|
||||
std::map<std::string, std::pair<std::string, int>> get_coverage_data();
|
||||
dict<std::string, std::pair<std::string, int>> get_coverage_data();
|
||||
|
||||
#define cover_list(_id, ...) do { cover(_id); \
|
||||
std::string r = cover_list_worker(_id, __VA_ARGS__); \
|
||||
|
@ -151,6 +170,8 @@ struct PerformanceTimer
|
|||
t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL;
|
||||
t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;
|
||||
return t;
|
||||
#elif _WIN32
|
||||
return 0;
|
||||
#else
|
||||
#error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
|
||||
#endif
|
||||
|
@ -169,7 +190,7 @@ struct PerformanceTimer
|
|||
}
|
||||
|
||||
float sec() const {
|
||||
return total_ns * 1e-9;
|
||||
return total_ns * 1e-9f;
|
||||
}
|
||||
#else
|
||||
static int64_t query() { return 0; }
|
||||
|
@ -188,8 +209,10 @@ static inline void log_dump_val_worker(int v) { log("%d", v); }
|
|||
static inline void log_dump_val_worker(unsigned int v) { log("%u", v); }
|
||||
static inline void log_dump_val_worker(long int v) { log("%ld", v); }
|
||||
static inline void log_dump_val_worker(unsigned long int v) { log("%lu", v); }
|
||||
#ifndef _WIN32
|
||||
static inline void log_dump_val_worker(long long int v) { log("%lld", v); }
|
||||
static inline void log_dump_val_worker(unsigned long long int v) { log("%lld", v); }
|
||||
#endif
|
||||
static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); }
|
||||
static inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); }
|
||||
static inline void log_dump_val_worker(bool v) { log("%s", v ? "true" : "false"); }
|
||||
|
@ -198,7 +221,7 @@ static inline void log_dump_val_worker(char *v) { log("%s", v); }
|
|||
static inline void log_dump_val_worker(const char *v) { log("%s", v); }
|
||||
static inline void log_dump_val_worker(std::string v) { log("%s", v.c_str()); }
|
||||
static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); }
|
||||
static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); }
|
||||
static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { log_assert(*p == 0); }
|
||||
void log_dump_val_worker(RTLIL::SigSpec v);
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -42,17 +42,20 @@ struct Macc
|
|||
|
||||
for (auto &port : ports)
|
||||
{
|
||||
if (SIZE(port.in_a) == 0 && SIZE(port.in_b) == 0)
|
||||
if (GetSize(port.in_a) == 0 && GetSize(port.in_b) == 0)
|
||||
continue;
|
||||
|
||||
if (SIZE(port.in_a) == 1 && SIZE(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
|
||||
if (GetSize(port.in_a) < GetSize(port.in_b))
|
||||
std::swap(port.in_a, port.in_b);
|
||||
|
||||
if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
|
||||
bit_ports.append(port.in_a);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (port.in_a.is_fully_const() && port.in_b.is_fully_const()) {
|
||||
RTLIL::Const v = port.in_a.as_const();
|
||||
if (SIZE(port.in_b))
|
||||
if (GetSize(port.in_b))
|
||||
v = const_mul(v, port.in_b.as_const(), port.is_signed, port.is_signed, width);
|
||||
if (port.do_subtract)
|
||||
off = const_sub(off, v, port.is_signed, port.is_signed, width);
|
||||
|
@ -62,15 +65,15 @@ struct Macc
|
|||
}
|
||||
|
||||
if (port.is_signed) {
|
||||
while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == port.in_a[SIZE(port.in_a)-2])
|
||||
port.in_a.remove(SIZE(port.in_a)-1);
|
||||
while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == port.in_b[SIZE(port.in_b)-2])
|
||||
port.in_b.remove(SIZE(port.in_b)-1);
|
||||
while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == port.in_a[GetSize(port.in_a)-2])
|
||||
port.in_a.remove(GetSize(port.in_a)-1);
|
||||
while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2])
|
||||
port.in_b.remove(GetSize(port.in_b)-1);
|
||||
} else {
|
||||
while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == RTLIL::S0)
|
||||
port.in_a.remove(SIZE(port.in_a)-1);
|
||||
while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == RTLIL::S0)
|
||||
port.in_b.remove(SIZE(port.in_b)-1);
|
||||
while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == RTLIL::S0)
|
||||
port.in_a.remove(GetSize(port.in_a)-1);
|
||||
while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == RTLIL::S0)
|
||||
port.in_b.remove(GetSize(port.in_b)-1);
|
||||
}
|
||||
|
||||
new_ports.push_back(port);
|
||||
|
@ -102,10 +105,12 @@ struct Macc
|
|||
bit_ports = cell->getPort("\\B");
|
||||
|
||||
std::vector<RTLIL::State> config_bits = cell->getParam("\\CONFIG").bits;
|
||||
int config_width = cell->getParam("\\CONFIG_WIDTH").as_int();
|
||||
int config_cursor = 0;
|
||||
|
||||
log_assert(SIZE(config_bits) >= config_width);
|
||||
#ifndef NDEBUG
|
||||
int config_width = cell->getParam("\\CONFIG_WIDTH").as_int();
|
||||
log_assert(GetSize(config_bits) >= config_width);
|
||||
#endif
|
||||
|
||||
int num_bits = 0;
|
||||
if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1;
|
||||
|
@ -114,7 +119,7 @@ struct Macc
|
|||
if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8;
|
||||
|
||||
int port_a_cursor = 0;
|
||||
while (port_a_cursor < SIZE(port_a))
|
||||
while (port_a_cursor < GetSize(port_a))
|
||||
{
|
||||
log_assert(config_cursor + 2 + 2*num_bits <= config_width);
|
||||
|
||||
|
@ -143,7 +148,7 @@ struct Macc
|
|||
}
|
||||
|
||||
log_assert(config_cursor == config_width);
|
||||
log_assert(port_a_cursor == SIZE(port_a));
|
||||
log_assert(port_a_cursor == GetSize(port_a));
|
||||
}
|
||||
|
||||
void to_cell(RTLIL::Cell *cell) const
|
||||
|
@ -153,8 +158,8 @@ struct Macc
|
|||
int max_size = 0, num_bits = 0;
|
||||
|
||||
for (auto &port : ports) {
|
||||
max_size = std::max(max_size, SIZE(port.in_a));
|
||||
max_size = std::max(max_size, SIZE(port.in_b));
|
||||
max_size = std::max(max_size, GetSize(port.in_a));
|
||||
max_size = std::max(max_size, GetSize(port.in_b));
|
||||
}
|
||||
|
||||
while (max_size)
|
||||
|
@ -168,17 +173,17 @@ struct Macc
|
|||
|
||||
for (auto &port : ports)
|
||||
{
|
||||
if (SIZE(port.in_a) == 0)
|
||||
if (GetSize(port.in_a) == 0)
|
||||
continue;
|
||||
|
||||
config_bits.push_back(port.is_signed ? RTLIL::S1 : RTLIL::S0);
|
||||
config_bits.push_back(port.do_subtract ? RTLIL::S1 : RTLIL::S0);
|
||||
|
||||
int size_a = SIZE(port.in_a);
|
||||
int size_a = GetSize(port.in_a);
|
||||
for (int i = 0; i < num_bits; i++)
|
||||
config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0);
|
||||
|
||||
int size_b = SIZE(port.in_b);
|
||||
int size_b = GetSize(port.in_b);
|
||||
for (int i = 0; i < num_bits; i++)
|
||||
config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0);
|
||||
|
||||
|
@ -189,9 +194,9 @@ struct Macc
|
|||
cell->setPort("\\A", port_a);
|
||||
cell->setPort("\\B", bit_ports);
|
||||
cell->setParam("\\CONFIG", config_bits);
|
||||
cell->setParam("\\CONFIG_WIDTH", SIZE(config_bits));
|
||||
cell->setParam("\\A_WIDTH", SIZE(port_a));
|
||||
cell->setParam("\\B_WIDTH", SIZE(bit_ports));
|
||||
cell->setParam("\\CONFIG_WIDTH", GetSize(config_bits));
|
||||
cell->setParam("\\A_WIDTH", GetSize(port_a));
|
||||
cell->setParam("\\B_WIDTH", GetSize(bit_ports));
|
||||
}
|
||||
|
||||
bool eval(RTLIL::Const &result) const
|
||||
|
@ -205,25 +210,31 @@ struct Macc
|
|||
return false;
|
||||
|
||||
RTLIL::Const summand;
|
||||
if (SIZE(port.in_b) == 0)
|
||||
summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
|
||||
if (GetSize(port.in_b) == 0)
|
||||
summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result));
|
||||
else
|
||||
summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
|
||||
summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result));
|
||||
|
||||
if (port.do_subtract)
|
||||
result = const_sub(result, summand, port.is_signed, port.is_signed, SIZE(result));
|
||||
result = const_sub(result, summand, port.is_signed, port.is_signed, GetSize(result));
|
||||
else
|
||||
result = const_add(result, summand, port.is_signed, port.is_signed, SIZE(result));
|
||||
result = const_add(result, summand, port.is_signed, port.is_signed, GetSize(result));
|
||||
}
|
||||
|
||||
for (auto bit : bit_ports) {
|
||||
if (bit.wire)
|
||||
return false;
|
||||
result = const_add(result, bit.data, false, false, SIZE(result));
|
||||
result = const_add(result, bit.data, false, false, GetSize(result));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Macc(RTLIL::Cell *cell = nullptr)
|
||||
{
|
||||
if (cell != nullptr)
|
||||
from_cell(cell);
|
||||
}
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -33,6 +33,7 @@ struct ModIndex : public RTLIL::Monitor
|
|||
RTLIL::IdString port;
|
||||
int offset;
|
||||
|
||||
PortInfo() : cell(), port(), offset() { }
|
||||
PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { }
|
||||
|
||||
bool operator<(const PortInfo &other) const {
|
||||
|
@ -42,24 +43,44 @@ struct ModIndex : public RTLIL::Monitor
|
|||
return offset < other.offset;
|
||||
return port < other.port;
|
||||
}
|
||||
|
||||
bool operator==(const PortInfo &other) const {
|
||||
return cell == other.cell && port == other.port && offset == other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
|
||||
}
|
||||
};
|
||||
|
||||
struct SigBitInfo
|
||||
{
|
||||
bool is_input, is_output;
|
||||
std::set<PortInfo> ports;
|
||||
pool<PortInfo> ports;
|
||||
|
||||
SigBitInfo() : is_input(false), is_output(false) { }
|
||||
|
||||
bool operator==(const SigBitInfo &other) const {
|
||||
return is_input == other.is_input && is_output == other.is_output && ports == other.ports;
|
||||
}
|
||||
|
||||
void merge(const SigBitInfo &other)
|
||||
{
|
||||
is_input = is_input || other.is_input;
|
||||
is_output = is_output || other.is_output;
|
||||
ports.insert(other.ports.begin(), other.ports.end());
|
||||
}
|
||||
};
|
||||
|
||||
SigMap sigmap;
|
||||
RTLIL::Module *module;
|
||||
std::map<RTLIL::SigBit, SigBitInfo> database;
|
||||
int auto_reload_counter;
|
||||
bool auto_reload_module;
|
||||
|
||||
void port_add(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
|
||||
{
|
||||
for (int i = 0; i < SIZE(sig); i++) {
|
||||
for (int i = 0; i < GetSize(sig); i++) {
|
||||
RTLIL::SigBit bit = sigmap(sig[i]);
|
||||
if (bit.wire)
|
||||
database[bit].ports.insert(PortInfo(cell, port, i));
|
||||
|
@ -68,7 +89,7 @@ struct ModIndex : public RTLIL::Monitor
|
|||
|
||||
void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
|
||||
{
|
||||
for (int i = 0; i < SIZE(sig); i++) {
|
||||
for (int i = 0; i < GetSize(sig); i++) {
|
||||
RTLIL::SigBit bit = sigmap(sig[i]);
|
||||
if (bit.wire)
|
||||
database[bit].ports.erase(PortInfo(cell, port, i));
|
||||
|
@ -80,15 +101,17 @@ struct ModIndex : public RTLIL::Monitor
|
|||
return database[sigmap(bit)];
|
||||
}
|
||||
|
||||
void reload_module()
|
||||
void reload_module(bool reset_sigmap = true)
|
||||
{
|
||||
sigmap.clear();
|
||||
sigmap.set(module);
|
||||
if (reset_sigmap) {
|
||||
sigmap.clear();
|
||||
sigmap.set(module);
|
||||
}
|
||||
|
||||
database.clear();
|
||||
for (auto wire : module->wires())
|
||||
if (wire->port_input || wire->port_output)
|
||||
for (int i = 0; i < SIZE(wire); i++) {
|
||||
for (int i = 0; i < GetSize(wire); i++) {
|
||||
RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i));
|
||||
if (bit.wire && wire->port_input)
|
||||
database[bit].is_input = true;
|
||||
|
@ -99,31 +122,105 @@ struct ModIndex : public RTLIL::Monitor
|
|||
for (auto &conn : cell->connections())
|
||||
port_add(cell, conn.first, conn.second);
|
||||
|
||||
auto_reload_module = false;
|
||||
if (auto_reload_module) {
|
||||
if (++auto_reload_counter > 2)
|
||||
log_warning("Auto-reload in ModIndex -- possible performance bug!\n");
|
||||
auto_reload_module = false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE
|
||||
void check()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (auto_reload_module)
|
||||
reload_module();
|
||||
return;
|
||||
|
||||
for (auto it : database)
|
||||
log_assert(it.first == sigmap(it.first));
|
||||
|
||||
auto database_bak = std::move(database);
|
||||
reload_module(false);
|
||||
|
||||
if (!(database == database_bak))
|
||||
{
|
||||
for (auto &it : database_bak)
|
||||
if (!database.count(it.first))
|
||||
log("ModuleIndex::check(): Only in database_bak, not database: %s\n", log_signal(it.first));
|
||||
|
||||
for (auto &it : database)
|
||||
if (!database_bak.count(it.first))
|
||||
log("ModuleIndex::check(): Only in database, not database_bak: %s\n", log_signal(it.first));
|
||||
else if (!(it.second == database_bak.at(it.first)))
|
||||
log("ModuleIndex::check(): Different content for database[%s].\n", log_signal(it.first));
|
||||
|
||||
log_assert(database == database_bak);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
|
||||
{
|
||||
log_assert(module == cell->module);
|
||||
|
||||
if (auto_reload_module)
|
||||
return;
|
||||
|
||||
port_del(cell, port, old_sig);
|
||||
port_add(cell, port, sig);
|
||||
}
|
||||
|
||||
virtual void notify_connect(RTLIL::Module *mod, const RTLIL::SigSig&)
|
||||
virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE
|
||||
{
|
||||
log_assert(module == mod);
|
||||
|
||||
if (auto_reload_module)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < GetSize(sigsig.first); i++)
|
||||
{
|
||||
RTLIL::SigBit lhs = sigmap(sigsig.first[i]);
|
||||
RTLIL::SigBit rhs = sigmap(sigsig.second[i]);
|
||||
bool has_lhs = database.count(lhs);
|
||||
bool has_rhs = database.count(rhs);
|
||||
|
||||
if (!has_lhs && !has_rhs) {
|
||||
sigmap.add(lhs, rhs);
|
||||
} else
|
||||
if (!has_rhs) {
|
||||
SigBitInfo new_info = database.at(lhs);
|
||||
database.erase(lhs);
|
||||
sigmap.add(lhs, rhs);
|
||||
lhs = sigmap(lhs);
|
||||
if (lhs.wire)
|
||||
database[lhs] = new_info;
|
||||
} else
|
||||
if (!has_lhs) {
|
||||
SigBitInfo new_info = database.at(rhs);
|
||||
database.erase(rhs);
|
||||
sigmap.add(lhs, rhs);
|
||||
rhs = sigmap(rhs);
|
||||
if (rhs.wire)
|
||||
database[rhs] = new_info;
|
||||
} else {
|
||||
SigBitInfo new_info = database.at(lhs);
|
||||
new_info.merge(database.at(rhs));
|
||||
database.erase(lhs);
|
||||
database.erase(rhs);
|
||||
sigmap.add(lhs, rhs);
|
||||
rhs = sigmap(rhs);
|
||||
if (rhs.wire)
|
||||
database[rhs] = new_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE
|
||||
{
|
||||
log_assert(module == mod);
|
||||
auto_reload_module = true;
|
||||
}
|
||||
|
||||
virtual void notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&)
|
||||
{
|
||||
log_assert(module == mod);
|
||||
auto_reload_module = true;
|
||||
}
|
||||
|
||||
virtual void notify_blackout(RTLIL::Module *mod)
|
||||
virtual void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE
|
||||
{
|
||||
log_assert(module == mod);
|
||||
auto_reload_module = true;
|
||||
|
@ -131,6 +228,7 @@ struct ModIndex : public RTLIL::Monitor
|
|||
|
||||
ModIndex(RTLIL::Module *_m) : module(_m)
|
||||
{
|
||||
auto_reload_counter = 0;
|
||||
auto_reload_module = true;
|
||||
module->monitors.insert(this);
|
||||
}
|
||||
|
@ -168,9 +266,9 @@ struct ModIndex : public RTLIL::Monitor
|
|||
return info->is_output;
|
||||
}
|
||||
|
||||
std::set<PortInfo> &query_ports(RTLIL::SigBit bit)
|
||||
pool<PortInfo> &query_ports(RTLIL::SigBit bit)
|
||||
{
|
||||
static std::set<PortInfo> empty_result_set;
|
||||
static pool<PortInfo> empty_result_set;
|
||||
SigBitInfo *info = query(bit);
|
||||
if (info == nullptr)
|
||||
return empty_result_set;
|
||||
|
@ -193,6 +291,14 @@ struct ModWalker
|
|||
return port < other.port;
|
||||
return offset < other.offset;
|
||||
}
|
||||
|
||||
bool operator==(const PortBit &other) const {
|
||||
return cell == other.cell && port == other.port && offset == other.offset;
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
|
||||
}
|
||||
};
|
||||
|
||||
RTLIL::Design *design;
|
||||
|
@ -201,11 +307,11 @@ struct ModWalker
|
|||
CellTypes ct;
|
||||
SigMap sigmap;
|
||||
|
||||
std::map<RTLIL::SigBit, std::set<PortBit>> signal_drivers;
|
||||
std::map<RTLIL::SigBit, std::set<PortBit>> signal_consumers;
|
||||
std::set<RTLIL::SigBit> signal_inputs, signal_outputs;
|
||||
dict<RTLIL::SigBit, pool<PortBit>> signal_drivers;
|
||||
dict<RTLIL::SigBit, pool<PortBit>> signal_consumers;
|
||||
pool<RTLIL::SigBit> signal_inputs, signal_outputs;
|
||||
|
||||
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_outputs, cell_inputs;
|
||||
dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_outputs, cell_inputs;
|
||||
|
||||
void add_wire(RTLIL::Wire *wire)
|
||||
{
|
||||
|
@ -286,11 +392,11 @@ struct ModWalker
|
|||
// get_* methods -- single RTLIL::SigBit
|
||||
|
||||
template<typename T>
|
||||
inline bool get_drivers(std::set<PortBit> &result, RTLIL::SigBit bit) const
|
||||
inline bool get_drivers(pool<PortBit> &result, RTLIL::SigBit bit) const
|
||||
{
|
||||
bool found = false;
|
||||
if (signal_drivers.count(bit)) {
|
||||
const std::set<PortBit> &r = signal_drivers.at(bit);
|
||||
const pool<PortBit> &r = signal_drivers.at(bit);
|
||||
result.insert(r.begin(), r.end());
|
||||
found = true;
|
||||
}
|
||||
|
@ -298,11 +404,11 @@ struct ModWalker
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool get_consumers(std::set<PortBit> &result, RTLIL::SigBit bit) const
|
||||
inline bool get_consumers(pool<PortBit> &result, RTLIL::SigBit bit) const
|
||||
{
|
||||
bool found = false;
|
||||
if (signal_consumers.count(bit)) {
|
||||
const std::set<PortBit> &r = signal_consumers.at(bit);
|
||||
const pool<PortBit> &r = signal_consumers.at(bit);
|
||||
result.insert(r.begin(), r.end());
|
||||
found = true;
|
||||
}
|
||||
|
@ -310,7 +416,7 @@ struct ModWalker
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
|
||||
inline bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
|
||||
{
|
||||
bool found = false;
|
||||
if (signal_inputs.count(bit))
|
||||
|
@ -319,7 +425,7 @@ struct ModWalker
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
|
||||
inline bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
|
||||
{
|
||||
bool found = false;
|
||||
if (signal_outputs.count(bit))
|
||||
|
@ -330,12 +436,12 @@ struct ModWalker
|
|||
// get_* methods -- container of RTLIL::SigBit's (always by reference)
|
||||
|
||||
template<typename T>
|
||||
inline bool get_drivers(std::set<PortBit> &result, const T &bits) const
|
||||
inline bool get_drivers(pool<PortBit> &result, const T &bits) const
|
||||
{
|
||||
bool found = false;
|
||||
for (RTLIL::SigBit bit : bits)
|
||||
if (signal_drivers.count(bit)) {
|
||||
const std::set<PortBit> &r = signal_drivers.at(bit);
|
||||
const pool<PortBit> &r = signal_drivers.at(bit);
|
||||
result.insert(r.begin(), r.end());
|
||||
found = true;
|
||||
}
|
||||
|
@ -343,12 +449,12 @@ struct ModWalker
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool get_consumers(std::set<PortBit> &result, const T &bits) const
|
||||
inline bool get_consumers(pool<PortBit> &result, const T &bits) const
|
||||
{
|
||||
bool found = false;
|
||||
for (RTLIL::SigBit bit : bits)
|
||||
if (signal_consumers.count(bit)) {
|
||||
const std::set<PortBit> &r = signal_consumers.at(bit);
|
||||
const pool<PortBit> &r = signal_consumers.at(bit);
|
||||
result.insert(r.begin(), r.end());
|
||||
found = true;
|
||||
}
|
||||
|
@ -356,7 +462,7 @@ struct ModWalker
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool get_inputs(std::set<RTLIL::SigBit> &result, const T &bits) const
|
||||
inline bool get_inputs(pool<RTLIL::SigBit> &result, const T &bits) const
|
||||
{
|
||||
bool found = false;
|
||||
for (RTLIL::SigBit bit : bits)
|
||||
|
@ -366,7 +472,7 @@ struct ModWalker
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool get_outputs(std::set<RTLIL::SigBit> &result, const T &bits) const
|
||||
inline bool get_outputs(pool<RTLIL::SigBit> &result, const T &bits) const
|
||||
{
|
||||
bool found = false;
|
||||
for (RTLIL::SigBit bit : bits)
|
||||
|
@ -377,25 +483,25 @@ struct ModWalker
|
|||
|
||||
// get_* methods -- call by RTLIL::SigSpec (always by value)
|
||||
|
||||
bool get_drivers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
|
||||
bool get_drivers(pool<PortBit> &result, RTLIL::SigSpec signal) const
|
||||
{
|
||||
std::vector<RTLIL::SigBit> bits = sigmap(signal);
|
||||
return get_drivers(result, bits);
|
||||
}
|
||||
|
||||
bool get_consumers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
|
||||
bool get_consumers(pool<PortBit> &result, RTLIL::SigSpec signal) const
|
||||
{
|
||||
std::vector<RTLIL::SigBit> bits = sigmap(signal);
|
||||
return get_consumers(result, bits);
|
||||
}
|
||||
|
||||
bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
|
||||
bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
|
||||
{
|
||||
std::vector<RTLIL::SigBit> bits = sigmap(signal);
|
||||
return get_inputs(result, bits);
|
||||
}
|
||||
|
||||
bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
|
||||
bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
|
||||
{
|
||||
std::vector<RTLIL::SigBit> bits = sigmap(signal);
|
||||
return get_outputs(result, bits);
|
||||
|
@ -405,47 +511,47 @@ struct ModWalker
|
|||
|
||||
template<typename T>
|
||||
inline bool has_drivers(const T &sig) const {
|
||||
std::set<PortBit> result;
|
||||
pool<PortBit> result;
|
||||
return get_drivers(result, sig);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool has_consumers(const T &sig) const {
|
||||
std::set<PortBit> result;
|
||||
pool<PortBit> result;
|
||||
return get_consumers(result, sig);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool has_inputs(const T &sig) const {
|
||||
std::set<RTLIL::SigBit> result;
|
||||
pool<RTLIL::SigBit> result;
|
||||
return get_inputs(result, sig);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool has_outputs(const T &sig) const {
|
||||
std::set<RTLIL::SigBit> result;
|
||||
pool<RTLIL::SigBit> result;
|
||||
return get_outputs(result, sig);
|
||||
}
|
||||
|
||||
// has_* methods -- call by value
|
||||
|
||||
inline bool has_drivers(RTLIL::SigSpec sig) const {
|
||||
std::set<PortBit> result;
|
||||
pool<PortBit> result;
|
||||
return get_drivers(result, sig);
|
||||
}
|
||||
|
||||
inline bool has_consumers(RTLIL::SigSpec sig) const {
|
||||
std::set<PortBit> result;
|
||||
pool<PortBit> result;
|
||||
return get_consumers(result, sig);
|
||||
}
|
||||
|
||||
inline bool has_inputs(RTLIL::SigSpec sig) const {
|
||||
std::set<RTLIL::SigBit> result;
|
||||
pool<RTLIL::SigBit> result;
|
||||
return get_inputs(result, sig);
|
||||
}
|
||||
|
||||
inline bool has_outputs(RTLIL::SigSpec sig) const {
|
||||
std::set<RTLIL::SigBit> result;
|
||||
pool<RTLIL::SigBit> result;
|
||||
return get_outputs(result, sig);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/satgen.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -146,35 +148,39 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
|
|||
void Pass::call(RTLIL::Design *design, std::string command)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
char *s = strdup(command.c_str()), *sstart = s, *saveptr;
|
||||
s += strspn(s, " \t\r\n");
|
||||
if (*s == 0 || *s == '#') {
|
||||
free(sstart);
|
||||
|
||||
std::string cmd_buf = command;
|
||||
std::string tok = next_token(cmd_buf, " \t\r\n");
|
||||
|
||||
if (tok.empty())
|
||||
return;
|
||||
}
|
||||
if (*s == '!') {
|
||||
for (s++; *s == ' ' || *s == '\t'; s++) { }
|
||||
char *p = s + strlen(s) - 1;
|
||||
while (p >= s && (*p == '\r' || *p == '\n'))
|
||||
*(p--) = 0;
|
||||
log_header("Shell command: %s\n", s);
|
||||
int retCode = system(s);
|
||||
|
||||
if (tok[0] == '!') {
|
||||
cmd_buf = command.substr(command.find('!') + 1);
|
||||
while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' ||
|
||||
cmd_buf.back() == '\r' || cmd_buf.back() == '\n'))
|
||||
cmd_buf.resize(cmd_buf.size()-1);
|
||||
log_header("Shell command: %s\n", cmd_buf.c_str());
|
||||
int retCode = run_command(cmd_buf);
|
||||
if (retCode != 0)
|
||||
log_cmd_error("Shell command returned error code %d.\n", retCode);
|
||||
free(sstart);
|
||||
return;
|
||||
}
|
||||
for (char *p = strtok_r(s, " \t\r\n", &saveptr); p; p = strtok_r(NULL, " \t\r\n", &saveptr)) {
|
||||
std::string str = p;
|
||||
int strsz = str.size();
|
||||
if (str == "#")
|
||||
break;
|
||||
if (strsz > 0 && str[strsz-1] == ';') {
|
||||
|
||||
while (!tok.empty()) {
|
||||
if (tok == "#") {
|
||||
int stop;
|
||||
for (stop = 0; stop < GetSize(cmd_buf); stop++)
|
||||
if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n')
|
||||
break;
|
||||
cmd_buf = cmd_buf.substr(stop);
|
||||
} else
|
||||
if (tok.back() == ';') {
|
||||
int num_semikolon = 0;
|
||||
while (strsz > 0 && str[strsz-1] == ';')
|
||||
strsz--, num_semikolon++;
|
||||
if (strsz > 0)
|
||||
args.push_back(str.substr(0, strsz));
|
||||
while (!tok.empty() && tok.back() == ';')
|
||||
tok.resize(tok.size()-1), num_semikolon++;
|
||||
if (!tok.empty())
|
||||
args.push_back(tok);
|
||||
call(design, args);
|
||||
args.clear();
|
||||
if (num_semikolon == 2)
|
||||
|
@ -182,9 +188,22 @@ void Pass::call(RTLIL::Design *design, std::string command)
|
|||
if (num_semikolon == 3)
|
||||
call(design, "clean -purge");
|
||||
} else
|
||||
args.push_back(str);
|
||||
args.push_back(tok);
|
||||
bool found_nl = false;
|
||||
for (auto c : cmd_buf) {
|
||||
if (c == ' ' || c == '\t')
|
||||
continue;
|
||||
if (c == '\r' || c == '\n')
|
||||
found_nl = true;
|
||||
break;
|
||||
}
|
||||
if (found_nl) {
|
||||
call(design, args);
|
||||
args.clear();
|
||||
}
|
||||
tok = next_token(cmd_buf, " \t\r\n");
|
||||
}
|
||||
free(sstart);
|
||||
|
||||
call(design, args);
|
||||
}
|
||||
|
||||
|
@ -333,8 +352,8 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
|
|||
if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r'))
|
||||
break;
|
||||
}
|
||||
int indent = buffer.find_first_not_of(" \t\r\n");
|
||||
if (buffer.substr(indent, eot_marker.size()) == eot_marker)
|
||||
size_t indent = buffer.find_first_not_of(" \t\r\n");
|
||||
if (indent != std::string::npos && buffer.substr(indent, eot_marker.size()) == eot_marker)
|
||||
break;
|
||||
last_here_document += buffer;
|
||||
}
|
||||
|
@ -528,11 +547,10 @@ struct HelpPass : public Pass {
|
|||
}
|
||||
void escape_tex(std::string &tex)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = tex.find('_', pos)) != std::string::npos) {
|
||||
for (size_t pos = 0; (pos = tex.find('_', pos)) != std::string::npos; pos += 2)
|
||||
tex.replace(pos, 1, "\\_");
|
||||
pos += 2;
|
||||
}
|
||||
for (size_t pos = 0; (pos = tex.find('$', pos)) != std::string::npos; pos += 2)
|
||||
tex.replace(pos, 1, "\\$");
|
||||
}
|
||||
void write_tex(FILE *f, std::string cmd, std::string title, std::string text)
|
||||
{
|
||||
|
@ -676,5 +694,17 @@ struct EchoPass : public Pass {
|
|||
}
|
||||
} EchoPass;
|
||||
|
||||
SatSolver *yosys_satsolver_list;
|
||||
SatSolver *yosys_satsolver;
|
||||
|
||||
struct MinisatSatSolver : public SatSolver {
|
||||
MinisatSatSolver() : SatSolver("minisat") {
|
||||
yosys_satsolver = this;
|
||||
}
|
||||
virtual ezSAT *create() YS_OVERRIDE {
|
||||
return new ezMiniSAT();
|
||||
}
|
||||
} MinisatSatSolver;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -71,9 +71,9 @@ struct Frontend : Pass
|
|||
|
||||
std::string frontend_name;
|
||||
Frontend(std::string name, std::string short_help = "** document me **");
|
||||
virtual void run_register();
|
||||
virtual void run_register() YS_OVERRIDE;
|
||||
virtual ~Frontend();
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
|
||||
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
|
||||
|
||||
static std::vector<std::string> next_args;
|
||||
|
@ -87,9 +87,9 @@ struct Backend : Pass
|
|||
{
|
||||
std::string backend_name;
|
||||
Backend(std::string name, std::string short_help = "** document me **");
|
||||
virtual void run_register();
|
||||
virtual void run_register() YS_OVERRIDE;
|
||||
virtual ~Backend();
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
|
||||
|
||||
void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
|
||||
|
@ -100,6 +100,8 @@ struct Backend : Pass
|
|||
|
||||
// implemented in passes/cmds/select.cc
|
||||
extern void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design);
|
||||
extern RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *design);
|
||||
extern void eval_select_op(vector<RTLIL::Selection> &work, const string &op, RTLIL::Design *design);
|
||||
|
||||
extern std::map<std::string, Pass*> pass_register;
|
||||
extern std::map<std::string, Frontend*> frontend_register;
|
||||
|
|
490
kernel/rtlil.cc
490
kernel/rtlil.cc
File diff suppressed because it is too large
Load Diff
670
kernel/rtlil.h
670
kernel/rtlil.h
|
@ -76,18 +76,15 @@ namespace RTLIL
|
|||
{
|
||||
// the global id string cache
|
||||
|
||||
struct char_ptr_cmp {
|
||||
bool operator()(const char *a, const char *b) const {
|
||||
for (int i = 0; a[i] || b[i]; i++)
|
||||
if (a[i] != b[i])
|
||||
return a[i] < b[i];
|
||||
return false;
|
||||
}
|
||||
};
|
||||
static struct destruct_guard_t {
|
||||
bool ok; // POD, will be initialized to zero
|
||||
destruct_guard_t() { ok = true; }
|
||||
~destruct_guard_t() { ok = false; }
|
||||
} destruct_guard;
|
||||
|
||||
static std::vector<int> global_refcount_storage_;
|
||||
static std::vector<char*> global_id_storage_;
|
||||
static std::map<char*, int, char_ptr_cmp> global_id_index_;
|
||||
static dict<char*, int, hash_cstr_ops> global_id_index_;
|
||||
static std::vector<int> global_free_idx_list_;
|
||||
|
||||
static inline int get_reference(int idx)
|
||||
|
@ -98,6 +95,8 @@ namespace RTLIL
|
|||
|
||||
static inline int get_reference(const char *p)
|
||||
{
|
||||
log_assert(destruct_guard.ok);
|
||||
|
||||
if (p[0]) {
|
||||
log_assert(p[1] != 0);
|
||||
log_assert(p[0] == '$' || p[0] == '\\');
|
||||
|
@ -121,16 +120,38 @@ namespace RTLIL
|
|||
global_id_storage_.at(idx) = strdup(p);
|
||||
global_id_index_[global_id_storage_.at(idx)] = idx;
|
||||
global_refcount_storage_.at(idx)++;
|
||||
|
||||
// Avoid Create->Delete->Create pattern
|
||||
static IdString last_created_id;
|
||||
put_reference(last_created_id.index_);
|
||||
last_created_id.index_ = idx;
|
||||
get_reference(last_created_id.index_);
|
||||
|
||||
if (yosys_xtrace) {
|
||||
log("#X# New IdString '%s' with index %d.\n", p, idx);
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline void put_reference(int idx)
|
||||
{
|
||||
// put_reference() may be called from destructors after the destructor of
|
||||
// global_refcount_storage_ has been run. in this case we simply do nothing.
|
||||
if (!destruct_guard.ok)
|
||||
return;
|
||||
|
||||
log_assert(global_refcount_storage_.at(idx) > 0);
|
||||
|
||||
if (--global_refcount_storage_.at(idx) != 0)
|
||||
return;
|
||||
|
||||
if (yosys_xtrace) {
|
||||
log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
global_id_index_.erase(global_id_storage_.at(idx));
|
||||
free(global_id_storage_.at(idx));
|
||||
global_id_storage_.at(idx) = nullptr;
|
||||
|
@ -211,12 +232,16 @@ namespace RTLIL
|
|||
*this = IdString();
|
||||
}
|
||||
|
||||
unsigned int hash() const {
|
||||
return index_;
|
||||
}
|
||||
|
||||
// The following is a helper key_compare class. Instead of for example std::set<Cell*>
|
||||
// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the
|
||||
// set has an influence on the algorithm.
|
||||
|
||||
template<typename T> struct compare_ptr_by_name {
|
||||
bool operator()(const T *a, const T *b) {
|
||||
bool operator()(const T *a, const T *b) const {
|
||||
return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name);
|
||||
}
|
||||
};
|
||||
|
@ -225,14 +250,14 @@ namespace RTLIL
|
|||
// of cell types). the following functions helps with that.
|
||||
|
||||
template<typename T, typename... Args>
|
||||
bool in(T first, Args... rest) {
|
||||
bool in(T first, Args... rest) const {
|
||||
return in(first) || in(rest...);
|
||||
}
|
||||
|
||||
bool in(IdString rhs) { return *this == rhs; }
|
||||
bool in(const char *rhs) { return *this == rhs; }
|
||||
bool in(const std::string &rhs) { return *this == rhs; }
|
||||
bool in(const std::set<IdString> &rhs) { return rhs.count(*this) != 0; }
|
||||
bool in(IdString rhs) const { return *this == rhs; }
|
||||
bool in(const char *rhs) const { return *this == rhs; }
|
||||
bool in(const std::string &rhs) const { return *this == rhs; }
|
||||
bool in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }
|
||||
};
|
||||
|
||||
static inline std::string escape_id(std::string str) {
|
||||
|
@ -242,9 +267,15 @@ namespace RTLIL
|
|||
}
|
||||
|
||||
static inline std::string unescape_id(std::string str) {
|
||||
if (str.size() > 1 && str[0] == '\\' && str[1] != '$')
|
||||
return str.substr(1);
|
||||
return str;
|
||||
if (str.size() < 2)
|
||||
return str;
|
||||
if (str[0] != '\\')
|
||||
return str;
|
||||
if (str[1] == '$' || str[1] == '\\')
|
||||
return str;
|
||||
if (str[1] >= '0' && str[1] <= '9')
|
||||
return str;
|
||||
return str.substr(1);
|
||||
}
|
||||
|
||||
static inline std::string unescape_id(RTLIL::IdString str) {
|
||||
|
@ -323,8 +354,8 @@ namespace RTLIL
|
|||
template<typename T>
|
||||
struct ObjIterator
|
||||
{
|
||||
typename std::map<RTLIL::IdString, T>::iterator it;
|
||||
std::map<RTLIL::IdString, T> *list_p;
|
||||
typename dict<RTLIL::IdString, T>::iterator it;
|
||||
dict<RTLIL::IdString, T> *list_p;
|
||||
int *refcount_p;
|
||||
|
||||
ObjIterator() : list_p(nullptr), refcount_p(nullptr) {
|
||||
|
@ -388,7 +419,7 @@ namespace RTLIL
|
|||
template<typename T>
|
||||
struct ObjRange
|
||||
{
|
||||
std::map<RTLIL::IdString, T> *list_p;
|
||||
dict<RTLIL::IdString, T> *list_p;
|
||||
int *refcount_p;
|
||||
|
||||
ObjRange(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { }
|
||||
|
@ -399,8 +430,8 @@ namespace RTLIL
|
|||
return list_p->size();
|
||||
}
|
||||
|
||||
operator std::set<T>() const {
|
||||
std::set<T> result;
|
||||
operator pool<T>() const {
|
||||
pool<T> result;
|
||||
for (auto &it : *list_p)
|
||||
result.insert(it.second);
|
||||
return result;
|
||||
|
@ -414,7 +445,7 @@ namespace RTLIL
|
|||
return result;
|
||||
}
|
||||
|
||||
std::set<T> to_set() const { return *this; }
|
||||
pool<T> to_pool() const { return *this; }
|
||||
std::vector<T> to_vector() const { return *this; }
|
||||
};
|
||||
};
|
||||
|
@ -438,17 +469,249 @@ struct RTLIL::Const
|
|||
bool as_bool() const;
|
||||
int as_int(bool is_signed = false) const;
|
||||
std::string as_string() const;
|
||||
static Const from_string(std::string str);
|
||||
|
||||
std::string decode_string() const;
|
||||
|
||||
inline int size() const { return bits.size(); }
|
||||
|
||||
inline unsigned int hash() const {
|
||||
unsigned int h = mkhash_init;
|
||||
for (auto b : bits)
|
||||
mkhash(h, b);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct RTLIL::SigChunk
|
||||
{
|
||||
RTLIL::Wire *wire;
|
||||
std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
|
||||
int width, offset;
|
||||
|
||||
SigChunk();
|
||||
SigChunk(const RTLIL::Const &value);
|
||||
SigChunk(RTLIL::Wire *wire);
|
||||
SigChunk(RTLIL::Wire *wire, int offset, int width = 1);
|
||||
SigChunk(const std::string &str);
|
||||
SigChunk(int val, int width = 32);
|
||||
SigChunk(RTLIL::State bit, int width = 1);
|
||||
SigChunk(RTLIL::SigBit bit);
|
||||
|
||||
RTLIL::SigChunk extract(int offset, int length) const;
|
||||
|
||||
bool operator <(const RTLIL::SigChunk &other) const;
|
||||
bool operator ==(const RTLIL::SigChunk &other) const;
|
||||
bool operator !=(const RTLIL::SigChunk &other) const;
|
||||
};
|
||||
|
||||
struct RTLIL::SigBit
|
||||
{
|
||||
RTLIL::Wire *wire;
|
||||
union {
|
||||
RTLIL::State data; // used if wire == NULL
|
||||
int offset; // used if wire != NULL
|
||||
};
|
||||
|
||||
SigBit();
|
||||
SigBit(RTLIL::State bit);
|
||||
SigBit(bool bit);
|
||||
SigBit(RTLIL::Wire *wire);
|
||||
SigBit(RTLIL::Wire *wire, int offset);
|
||||
SigBit(const RTLIL::SigChunk &chunk);
|
||||
SigBit(const RTLIL::SigChunk &chunk, int index);
|
||||
SigBit(const RTLIL::SigSpec &sig);
|
||||
|
||||
bool operator <(const RTLIL::SigBit &other) const;
|
||||
bool operator ==(const RTLIL::SigBit &other) const;
|
||||
bool operator !=(const RTLIL::SigBit &other) const;
|
||||
unsigned int hash() const;
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpecIterator : public std::iterator<std::input_iterator_tag, RTLIL::SigSpec>
|
||||
{
|
||||
RTLIL::SigSpec *sig_p;
|
||||
int index;
|
||||
|
||||
inline RTLIL::SigBit &operator*() const;
|
||||
inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }
|
||||
inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
|
||||
inline void operator++() { index++; }
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpecConstIterator : public std::iterator<std::input_iterator_tag, RTLIL::SigSpec>
|
||||
{
|
||||
const RTLIL::SigSpec *sig_p;
|
||||
int index;
|
||||
|
||||
inline const RTLIL::SigBit &operator*() const;
|
||||
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
|
||||
inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
|
||||
inline void operator++() { index++; }
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpec
|
||||
{
|
||||
private:
|
||||
int width_;
|
||||
unsigned long hash_;
|
||||
std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
|
||||
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
|
||||
|
||||
void pack() const;
|
||||
void unpack() const;
|
||||
void updhash() const;
|
||||
|
||||
inline bool packed() const {
|
||||
return bits_.empty();
|
||||
}
|
||||
|
||||
inline void inline_unpack() const {
|
||||
if (!chunks_.empty())
|
||||
unpack();
|
||||
}
|
||||
|
||||
public:
|
||||
SigSpec();
|
||||
SigSpec(const RTLIL::SigSpec &other);
|
||||
SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
|
||||
const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
|
||||
|
||||
SigSpec(const RTLIL::Const &value);
|
||||
SigSpec(const RTLIL::SigChunk &chunk);
|
||||
SigSpec(RTLIL::Wire *wire);
|
||||
SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
|
||||
SigSpec(const std::string &str);
|
||||
SigSpec(int val, int width = 32);
|
||||
SigSpec(RTLIL::State bit, int width = 1);
|
||||
SigSpec(RTLIL::SigBit bit, int width = 1);
|
||||
SigSpec(std::vector<RTLIL::SigChunk> chunks);
|
||||
SigSpec(std::vector<RTLIL::SigBit> bits);
|
||||
SigSpec(pool<RTLIL::SigBit> bits);
|
||||
SigSpec(std::set<RTLIL::SigBit> bits);
|
||||
SigSpec(bool bit);
|
||||
|
||||
SigSpec(RTLIL::SigSpec &&other) {
|
||||
width_ = other.width_;
|
||||
hash_ = other.hash_;
|
||||
chunks_ = std::move(other.chunks_);
|
||||
bits_ = std::move(other.bits_);
|
||||
}
|
||||
|
||||
const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) {
|
||||
width_ = other.width_;
|
||||
hash_ = other.hash_;
|
||||
chunks_ = std::move(other.chunks_);
|
||||
bits_ = std::move(other.bits_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t get_hash() const {
|
||||
if (!hash_) hash();
|
||||
return hash_;
|
||||
}
|
||||
|
||||
inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
|
||||
inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
|
||||
|
||||
inline int size() const { return width_; }
|
||||
inline bool empty() const { return width_ == 0; }
|
||||
|
||||
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
|
||||
inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
|
||||
|
||||
inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
|
||||
inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
|
||||
|
||||
inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
|
||||
inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
|
||||
|
||||
void sort();
|
||||
void sort_and_unify();
|
||||
|
||||
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
|
||||
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
|
||||
|
||||
void replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules);
|
||||
void replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
|
||||
|
||||
void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);
|
||||
void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
|
||||
|
||||
void replace(int offset, const RTLIL::SigSpec &with);
|
||||
|
||||
void remove(const RTLIL::SigSpec &pattern);
|
||||
void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
|
||||
void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
|
||||
|
||||
void remove(const pool<RTLIL::SigBit> &pattern);
|
||||
void remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
|
||||
void remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
|
||||
|
||||
void remove(int offset, int length = 1);
|
||||
void remove_const();
|
||||
|
||||
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
|
||||
RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
|
||||
RTLIL::SigSpec extract(int offset, int length = 1) const;
|
||||
|
||||
void append(const RTLIL::SigSpec &signal);
|
||||
void append_bit(const RTLIL::SigBit &bit);
|
||||
|
||||
void extend_u0(int width, bool is_signed = false);
|
||||
|
||||
RTLIL::SigSpec repeat(int num) const;
|
||||
|
||||
bool operator <(const RTLIL::SigSpec &other) const;
|
||||
bool operator ==(const RTLIL::SigSpec &other) const;
|
||||
inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }
|
||||
|
||||
bool is_wire() const;
|
||||
bool is_chunk() const;
|
||||
|
||||
bool is_fully_const() const;
|
||||
bool is_fully_def() const;
|
||||
bool is_fully_undef() const;
|
||||
bool has_const() const;
|
||||
bool has_marked_bits() const;
|
||||
|
||||
bool as_bool() const;
|
||||
int as_int(bool is_signed = false) const;
|
||||
std::string as_string() const;
|
||||
RTLIL::Const as_const() const;
|
||||
RTLIL::Wire *as_wire() const;
|
||||
RTLIL::SigChunk as_chunk() const;
|
||||
|
||||
bool match(std::string pattern) const;
|
||||
|
||||
std::set<RTLIL::SigBit> to_sigbit_set() const;
|
||||
pool<RTLIL::SigBit> to_sigbit_pool() const;
|
||||
std::vector<RTLIL::SigBit> to_sigbit_vector() const;
|
||||
std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;
|
||||
dict<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_dict(const RTLIL::SigSpec &other) const;
|
||||
RTLIL::SigBit to_single_sigbit() const;
|
||||
|
||||
static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
|
||||
static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
|
||||
static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
|
||||
|
||||
operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
|
||||
operator std::vector<RTLIL::SigBit>() const { return bits(); }
|
||||
|
||||
unsigned int hash() const { if (!hash_) updhash(); return hash_; };
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check() const;
|
||||
#else
|
||||
void check() const { }
|
||||
#endif
|
||||
};
|
||||
|
||||
struct RTLIL::Selection
|
||||
{
|
||||
bool full_selection;
|
||||
std::set<RTLIL::IdString> selected_modules;
|
||||
std::map<RTLIL::IdString, std::set<RTLIL::IdString>> selected_members;
|
||||
pool<RTLIL::IdString> selected_modules;
|
||||
dict<RTLIL::IdString, pool<RTLIL::IdString>> selected_members;
|
||||
|
||||
Selection(bool full = true) : full_selection(full) { }
|
||||
|
||||
|
@ -476,6 +739,15 @@ struct RTLIL::Selection
|
|||
|
||||
struct RTLIL::Monitor
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
|
||||
Monitor() {
|
||||
static unsigned int hashidx_count = 123456789;
|
||||
hashidx_count = mkhash_xorshift(hashidx_count);
|
||||
hashidx_ = hashidx_count;
|
||||
}
|
||||
|
||||
virtual ~Monitor() { }
|
||||
virtual void notify_module_add(RTLIL::Module*) { }
|
||||
virtual void notify_module_del(RTLIL::Module*) { }
|
||||
|
@ -487,14 +759,17 @@ struct RTLIL::Monitor
|
|||
|
||||
struct RTLIL::Design
|
||||
{
|
||||
std::set<RTLIL::Monitor*> monitors;
|
||||
std::map<std::string, std::string> scratchpad;
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
|
||||
pool<RTLIL::Monitor*> monitors;
|
||||
dict<std::string, std::string> scratchpad;
|
||||
|
||||
int refcount_modules_;
|
||||
std::map<RTLIL::IdString, RTLIL::Module*> modules_;
|
||||
dict<RTLIL::IdString, RTLIL::Module*> modules_;
|
||||
|
||||
std::vector<RTLIL::Selection> selection_stack;
|
||||
std::map<RTLIL::IdString, RTLIL::Selection> selection_vars;
|
||||
dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
|
||||
std::string selected_active_module;
|
||||
|
||||
Design();
|
||||
|
@ -521,6 +796,7 @@ struct RTLIL::Design
|
|||
bool scratchpad_get_bool(std::string varname, bool default_value = false) const;
|
||||
std::string scratchpad_get_string(std::string varname, std::string default_value = std::string()) const;
|
||||
|
||||
void sort();
|
||||
void check();
|
||||
void optimize();
|
||||
|
||||
|
@ -531,6 +807,14 @@ struct RTLIL::Design
|
|||
bool selected_module(RTLIL::Module *mod) const;
|
||||
bool selected_whole_module(RTLIL::Module *mod) const;
|
||||
|
||||
RTLIL::Selection &selection() {
|
||||
return selection_stack.back();
|
||||
}
|
||||
|
||||
const RTLIL::Selection &selection() const {
|
||||
return selection_stack.back();
|
||||
}
|
||||
|
||||
bool full_selection() const {
|
||||
return selection_stack.back().full_selection;
|
||||
}
|
||||
|
@ -556,7 +840,7 @@ struct RTLIL::Design
|
|||
};
|
||||
|
||||
#define RTLIL_ATTRIBUTE_MEMBERS \
|
||||
std::map<RTLIL::IdString, RTLIL::Const> attributes; \
|
||||
dict<RTLIL::IdString, RTLIL::Const> attributes; \
|
||||
void set_bool_attribute(RTLIL::IdString id) { \
|
||||
attributes[id] = RTLIL::Const(1); \
|
||||
} \
|
||||
|
@ -568,31 +852,36 @@ struct RTLIL::Design
|
|||
|
||||
struct RTLIL::Module
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
|
||||
protected:
|
||||
void add(RTLIL::Wire *wire);
|
||||
void add(RTLIL::Cell *cell);
|
||||
|
||||
public:
|
||||
RTLIL::Design *design;
|
||||
std::set<RTLIL::Monitor*> monitors;
|
||||
pool<RTLIL::Monitor*> monitors;
|
||||
|
||||
int refcount_wires_;
|
||||
int refcount_cells_;
|
||||
|
||||
std::map<RTLIL::IdString, RTLIL::Wire*> wires_;
|
||||
std::map<RTLIL::IdString, RTLIL::Cell*> cells_;
|
||||
dict<RTLIL::IdString, RTLIL::Wire*> wires_;
|
||||
dict<RTLIL::IdString, RTLIL::Cell*> cells_;
|
||||
std::vector<RTLIL::SigSig> connections_;
|
||||
|
||||
RTLIL::IdString name;
|
||||
std::set<RTLIL::IdString> avail_parameters;
|
||||
std::map<RTLIL::IdString, RTLIL::Memory*> memories;
|
||||
std::map<RTLIL::IdString, RTLIL::Process*> processes;
|
||||
pool<RTLIL::IdString> avail_parameters;
|
||||
dict<RTLIL::IdString, RTLIL::Memory*> memories;
|
||||
dict<RTLIL::IdString, RTLIL::Process*> processes;
|
||||
RTLIL_ATTRIBUTE_MEMBERS
|
||||
|
||||
Module();
|
||||
virtual ~Module();
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
|
||||
virtual size_t count_id(RTLIL::IdString id);
|
||||
|
||||
virtual void sort();
|
||||
virtual void check();
|
||||
virtual void optimize();
|
||||
|
||||
|
@ -628,7 +917,7 @@ public:
|
|||
RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }
|
||||
|
||||
// Removing wires is expensive. If you have to remove wires, remove them all at once.
|
||||
void remove(const std::set<RTLIL::Wire*> &wires);
|
||||
void remove(const pool<RTLIL::Wire*> &wires);
|
||||
void remove(RTLIL::Cell *cell);
|
||||
|
||||
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
|
||||
|
@ -698,9 +987,11 @@ public:
|
|||
RTLIL::Cell* addConcat (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
|
||||
RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_i, RTLIL::SigSpec sig_o, RTLIL::Const lut);
|
||||
RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
|
||||
RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
|
||||
|
||||
RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true);
|
||||
RTLIL::Cell* addDff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
|
||||
RTLIL::Cell* addDffe (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_polarity = true);
|
||||
RTLIL::Cell* addDffsr (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
|
||||
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true);
|
||||
RTLIL::Cell* addAdff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
|
||||
|
@ -723,6 +1014,7 @@ public:
|
|||
RTLIL::Cell* addOai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y);
|
||||
|
||||
RTLIL::Cell* addDffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
|
||||
RTLIL::Cell* addDffeGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_polarity = true);
|
||||
RTLIL::Cell* addDffsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
|
||||
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true);
|
||||
RTLIL::Cell* addAdffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
|
||||
|
@ -795,6 +1087,9 @@ public:
|
|||
|
||||
struct RTLIL::Wire
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
|
||||
protected:
|
||||
// use module->addWire() and module->remove() to create or destroy wires
|
||||
friend struct RTLIL::Module;
|
||||
|
@ -815,6 +1110,9 @@ public:
|
|||
|
||||
struct RTLIL::Memory
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
|
||||
Memory();
|
||||
|
||||
RTLIL::IdString name;
|
||||
|
@ -824,6 +1122,9 @@ struct RTLIL::Memory
|
|||
|
||||
struct RTLIL::Cell
|
||||
{
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
|
||||
protected:
|
||||
// use module->addCell() and module->remove() to create or destroy cells
|
||||
friend struct RTLIL::Module;
|
||||
|
@ -837,8 +1138,8 @@ public:
|
|||
RTLIL::Module *module;
|
||||
RTLIL::IdString name;
|
||||
RTLIL::IdString type;
|
||||
std::map<RTLIL::IdString, RTLIL::SigSpec> connections_;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> parameters;
|
||||
dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
|
||||
dict<RTLIL::IdString, RTLIL::Const> parameters;
|
||||
RTLIL_ATTRIBUTE_MEMBERS
|
||||
|
||||
// access cell ports
|
||||
|
@ -846,7 +1147,12 @@ public:
|
|||
void unsetPort(RTLIL::IdString portname);
|
||||
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal);
|
||||
const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const;
|
||||
const std::map<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
|
||||
const dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
|
||||
|
||||
// information about cell ports
|
||||
bool known() const;
|
||||
bool input(RTLIL::IdString portname) const;
|
||||
bool output(RTLIL::IdString portname) const;
|
||||
|
||||
// access cell parameters
|
||||
bool hasParam(RTLIL::IdString paramname) const;
|
||||
|
@ -854,242 +1160,18 @@ public:
|
|||
void setParam(RTLIL::IdString paramname, RTLIL::Const value);
|
||||
const RTLIL::Const &getParam(RTLIL::IdString paramname) const;
|
||||
|
||||
void sort();
|
||||
void check();
|
||||
void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false);
|
||||
|
||||
bool has_keep_attr() const {
|
||||
return get_bool_attribute("\\keep") || (module && module->design && module->design->module(type) &&
|
||||
module->design->module(type)->get_bool_attribute("\\keep"));
|
||||
}
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T functor);
|
||||
};
|
||||
|
||||
struct RTLIL::SigChunk
|
||||
{
|
||||
RTLIL::Wire *wire;
|
||||
std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
|
||||
int width, offset;
|
||||
|
||||
SigChunk();
|
||||
SigChunk(const RTLIL::Const &value);
|
||||
SigChunk(RTLIL::Wire *wire);
|
||||
SigChunk(RTLIL::Wire *wire, int offset, int width = 1);
|
||||
SigChunk(const std::string &str);
|
||||
SigChunk(int val, int width = 32);
|
||||
SigChunk(RTLIL::State bit, int width = 1);
|
||||
SigChunk(RTLIL::SigBit bit);
|
||||
|
||||
RTLIL::SigChunk extract(int offset, int length) const;
|
||||
|
||||
bool operator <(const RTLIL::SigChunk &other) const;
|
||||
bool operator ==(const RTLIL::SigChunk &other) const;
|
||||
bool operator !=(const RTLIL::SigChunk &other) const;
|
||||
};
|
||||
|
||||
struct RTLIL::SigBit
|
||||
{
|
||||
RTLIL::Wire *wire;
|
||||
union {
|
||||
RTLIL::State data; // used if wire == NULL
|
||||
int offset; // used if wire != NULL
|
||||
};
|
||||
|
||||
SigBit() : wire(NULL), data(RTLIL::State::S0) { }
|
||||
SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
|
||||
SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }
|
||||
SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire); }
|
||||
SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
|
||||
SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
|
||||
SigBit(const RTLIL::SigSpec &sig);
|
||||
|
||||
bool operator <(const RTLIL::SigBit &other) const {
|
||||
if (wire == other.wire)
|
||||
return wire ? (offset < other.offset) : (data < other.data);
|
||||
if (wire != nullptr && other.wire != nullptr)
|
||||
return wire->name < other.wire->name;
|
||||
return wire < other.wire;
|
||||
}
|
||||
|
||||
bool operator ==(const RTLIL::SigBit &other) const {
|
||||
return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));
|
||||
}
|
||||
|
||||
bool operator !=(const RTLIL::SigBit &other) const {
|
||||
return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
|
||||
}
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpecIterator
|
||||
{
|
||||
RTLIL::SigSpec *sig_p;
|
||||
int index;
|
||||
|
||||
inline RTLIL::SigBit &operator*() const;
|
||||
inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }
|
||||
inline void operator++() { index++; }
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpecConstIterator
|
||||
{
|
||||
const RTLIL::SigSpec *sig_p;
|
||||
int index;
|
||||
|
||||
inline const RTLIL::SigBit &operator*() const;
|
||||
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
|
||||
inline void operator++() { index++; }
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpec
|
||||
{
|
||||
private:
|
||||
int width_;
|
||||
unsigned long hash_;
|
||||
std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
|
||||
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
|
||||
|
||||
void pack() const;
|
||||
void unpack() const;
|
||||
void hash() const;
|
||||
|
||||
inline bool packed() const {
|
||||
return bits_.empty();
|
||||
}
|
||||
|
||||
inline void inline_unpack() const {
|
||||
if (!chunks_.empty())
|
||||
unpack();
|
||||
}
|
||||
|
||||
public:
|
||||
SigSpec();
|
||||
SigSpec(const RTLIL::SigSpec &other);
|
||||
SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
|
||||
const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
|
||||
|
||||
SigSpec(const RTLIL::Const &value);
|
||||
SigSpec(const RTLIL::SigChunk &chunk);
|
||||
SigSpec(RTLIL::Wire *wire);
|
||||
SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
|
||||
SigSpec(const std::string &str);
|
||||
SigSpec(int val, int width = 32);
|
||||
SigSpec(RTLIL::State bit, int width = 1);
|
||||
SigSpec(RTLIL::SigBit bit, int width = 1);
|
||||
SigSpec(std::vector<RTLIL::SigChunk> chunks);
|
||||
SigSpec(std::vector<RTLIL::SigBit> bits);
|
||||
SigSpec(std::set<RTLIL::SigBit> bits);
|
||||
|
||||
SigSpec(RTLIL::SigSpec &&other) {
|
||||
width_ = other.width_;
|
||||
hash_ = other.hash_;
|
||||
chunks_ = std::move(other.chunks_);
|
||||
bits_ = std::move(other.bits_);
|
||||
}
|
||||
|
||||
const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) {
|
||||
width_ = other.width_;
|
||||
hash_ = other.hash_;
|
||||
chunks_ = std::move(other.chunks_);
|
||||
bits_ = std::move(other.bits_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
|
||||
inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
|
||||
|
||||
inline int size() const { return width_; }
|
||||
|
||||
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
|
||||
inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
|
||||
|
||||
inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
|
||||
inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
|
||||
|
||||
inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
|
||||
inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
|
||||
|
||||
void sort();
|
||||
void sort_and_unify();
|
||||
|
||||
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
|
||||
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
|
||||
|
||||
void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);
|
||||
void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
|
||||
|
||||
void replace(int offset, const RTLIL::SigSpec &with);
|
||||
|
||||
void remove(const RTLIL::SigSpec &pattern);
|
||||
void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
|
||||
void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
|
||||
|
||||
void remove(const std::set<RTLIL::SigBit> &pattern);
|
||||
void remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
|
||||
void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
|
||||
|
||||
void remove(int offset, int length = 1);
|
||||
void remove_const();
|
||||
|
||||
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
|
||||
RTLIL::SigSpec extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
|
||||
RTLIL::SigSpec extract(int offset, int length = 1) const;
|
||||
|
||||
void append(const RTLIL::SigSpec &signal);
|
||||
void append_bit(const RTLIL::SigBit &bit);
|
||||
|
||||
void extend(int width, bool is_signed = false);
|
||||
void extend_u0(int width, bool is_signed = false);
|
||||
|
||||
RTLIL::SigSpec repeat(int num) const;
|
||||
|
||||
bool operator <(const RTLIL::SigSpec &other) const;
|
||||
bool operator ==(const RTLIL::SigSpec &other) const;
|
||||
inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }
|
||||
|
||||
bool is_wire() const;
|
||||
bool is_chunk() const;
|
||||
|
||||
bool is_fully_const() const;
|
||||
bool is_fully_def() const;
|
||||
bool is_fully_undef() const;
|
||||
bool has_marked_bits() const;
|
||||
|
||||
bool as_bool() const;
|
||||
int as_int(bool is_signed = false) const;
|
||||
std::string as_string() const;
|
||||
RTLIL::Const as_const() const;
|
||||
RTLIL::Wire *as_wire() const;
|
||||
RTLIL::SigChunk as_chunk() const;
|
||||
|
||||
bool match(std::string pattern) const;
|
||||
|
||||
std::set<RTLIL::SigBit> to_sigbit_set() const;
|
||||
std::vector<RTLIL::SigBit> to_sigbit_vector() const;
|
||||
std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;
|
||||
RTLIL::SigBit to_single_sigbit() const;
|
||||
|
||||
static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
|
||||
static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
|
||||
static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
|
||||
|
||||
operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
|
||||
operator std::vector<RTLIL::SigBit>() const { return bits(); }
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check() const;
|
||||
#else
|
||||
inline void check() const { }
|
||||
#endif
|
||||
};
|
||||
|
||||
inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
|
||||
return (*sig_p)[index];
|
||||
}
|
||||
|
||||
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
|
||||
return (*sig_p)[index];
|
||||
}
|
||||
|
||||
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
|
||||
log_assert(sig.size() == 1 && sig.chunks().size() == 1);
|
||||
*this = SigBit(sig.chunks().front());
|
||||
}
|
||||
|
||||
struct RTLIL::CaseRule
|
||||
{
|
||||
std::vector<RTLIL::SigSpec> compare;
|
||||
|
@ -1138,6 +1220,50 @@ struct RTLIL::Process
|
|||
RTLIL::Process *clone() const;
|
||||
};
|
||||
|
||||
|
||||
inline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { }
|
||||
inline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
|
||||
inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? RTLIL::S1 : RTLIL::S0) { }
|
||||
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }
|
||||
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }
|
||||
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
|
||||
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
|
||||
|
||||
inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
|
||||
if (wire == other.wire)
|
||||
return wire ? (offset < other.offset) : (data < other.data);
|
||||
if (wire != nullptr && other.wire != nullptr)
|
||||
return wire->name < other.wire->name;
|
||||
return wire < other.wire;
|
||||
}
|
||||
|
||||
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
|
||||
return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));
|
||||
}
|
||||
|
||||
inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {
|
||||
return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
|
||||
}
|
||||
|
||||
inline unsigned int RTLIL::SigBit::hash() const {
|
||||
if (wire)
|
||||
return mkhash_add(wire->name.hash(), offset);
|
||||
return data;
|
||||
}
|
||||
|
||||
inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
|
||||
return (*sig_p)[index];
|
||||
}
|
||||
|
||||
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
|
||||
return (*sig_p)[index];
|
||||
}
|
||||
|
||||
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
|
||||
log_assert(sig.size() == 1 && sig.chunks().size() == 1);
|
||||
*this = SigBit(sig.chunks().front());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RTLIL::Module::rewrite_sigspecs(T functor)
|
||||
{
|
||||
|
|
282
kernel/satgen.h
282
kernel/satgen.h
|
@ -26,7 +26,40 @@
|
|||
#include "kernel/macc.h"
|
||||
|
||||
#include "libs/ezsat/ezminisat.h"
|
||||
typedef ezMiniSAT ezDefaultSAT;
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// defined in kernel/register.cc
|
||||
extern struct SatSolver *yosys_satsolver_list;
|
||||
extern struct SatSolver *yosys_satsolver;
|
||||
|
||||
struct SatSolver
|
||||
{
|
||||
string name;
|
||||
SatSolver *next;
|
||||
virtual ezSAT *create() = 0;
|
||||
|
||||
SatSolver(string name) : name(name) {
|
||||
next = yosys_satsolver_list;
|
||||
yosys_satsolver_list = this;
|
||||
}
|
||||
|
||||
virtual ~SatSolver() {
|
||||
auto p = &yosys_satsolver_list;
|
||||
while (*p) {
|
||||
if (*p == this)
|
||||
*p = next;
|
||||
else
|
||||
p = &(*p)->next;
|
||||
}
|
||||
if (yosys_satsolver == this)
|
||||
yosys_satsolver = yosys_satsolver_list;
|
||||
}
|
||||
};
|
||||
|
||||
struct ezSatPtr : public std::unique_ptr<ezSAT> {
|
||||
ezSatPtr() : unique_ptr<ezSAT>(yosys_satsolver->create()) { }
|
||||
};
|
||||
|
||||
struct SatGen
|
||||
{
|
||||
|
@ -35,6 +68,8 @@ struct SatGen
|
|||
std::string prefix;
|
||||
SigPool initial_state;
|
||||
std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en;
|
||||
std::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en;
|
||||
std::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals;
|
||||
bool ignore_div_by_zero;
|
||||
bool model_undef;
|
||||
|
||||
|
@ -49,23 +84,24 @@ struct SatGen
|
|||
this->prefix = prefix;
|
||||
}
|
||||
|
||||
std::vector<int> importSigSpecWorker(RTLIL::SigSpec &sig, std::string &pf, bool undef_mode, bool dup_undef)
|
||||
std::vector<int> importSigSpecWorker(RTLIL::SigSpec sig, std::string &pf, bool undef_mode, bool dup_undef)
|
||||
{
|
||||
log_assert(!undef_mode || model_undef);
|
||||
sigmap->apply(sig);
|
||||
|
||||
std::vector<int> vec;
|
||||
vec.reserve(SIZE(sig));
|
||||
vec.reserve(GetSize(sig));
|
||||
|
||||
for (auto &bit : sig)
|
||||
if (bit.wire == NULL) {
|
||||
if (model_undef && dup_undef && bit == RTLIL::State::Sx)
|
||||
vec.push_back(ez->frozen_literal());
|
||||
else
|
||||
vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->TRUE : ez->FALSE);
|
||||
vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->CONST_TRUE : ez->CONST_FALSE);
|
||||
} else {
|
||||
std::string name = pf + stringf(bit.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(bit.wire->name), bit.offset);
|
||||
std::string name = pf + (bit.wire->width == 1 ? stringf("%s", log_id(bit.wire)) : stringf("%s [%d]", log_id(bit.wire->name), bit.offset));
|
||||
vec.push_back(ez->frozen_literal(name));
|
||||
imported_signals[pf][bit] = vec.back();
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
@ -91,6 +127,34 @@ struct SatGen
|
|||
return importSigSpecWorker(sig, pf, true, false);
|
||||
}
|
||||
|
||||
int importSigBit(RTLIL::SigBit bit, int timestep = -1)
|
||||
{
|
||||
log_assert(timestep != 0);
|
||||
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
return importSigSpecWorker(bit, pf, false, false).front();
|
||||
}
|
||||
|
||||
int importDefSigBit(RTLIL::SigBit bit, int timestep = -1)
|
||||
{
|
||||
log_assert(timestep != 0);
|
||||
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
return importSigSpecWorker(bit, pf, false, true).front();
|
||||
}
|
||||
|
||||
int importUndefSigBit(RTLIL::SigBit bit, int timestep = -1)
|
||||
{
|
||||
log_assert(timestep != 0);
|
||||
std::string pf = "undef:" + prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
return importSigSpecWorker(bit, pf, true, false).front();
|
||||
}
|
||||
|
||||
bool importedSigBit(RTLIL::SigBit bit, int timestep = -1)
|
||||
{
|
||||
log_assert(timestep != 0);
|
||||
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
return imported_signals[pf].count(bit) != 0;
|
||||
}
|
||||
|
||||
void getAsserts(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)
|
||||
{
|
||||
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
|
@ -98,6 +162,13 @@ struct SatGen
|
|||
sig_en = asserts_en[pf];
|
||||
}
|
||||
|
||||
void getAssumes(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)
|
||||
{
|
||||
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
sig_a = assumes_a[pf];
|
||||
sig_en = assumes_en[pf];
|
||||
}
|
||||
|
||||
int importAsserts(int timestep = -1)
|
||||
{
|
||||
std::vector<int> check_bits, enable_bits;
|
||||
|
@ -112,6 +183,20 @@ struct SatGen
|
|||
return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));
|
||||
}
|
||||
|
||||
int importAssumes(int timestep = -1)
|
||||
{
|
||||
std::vector<int> check_bits, enable_bits;
|
||||
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
if (model_undef) {
|
||||
check_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_a[pf], timestep)), importDefSigSpec(assumes_a[pf], timestep));
|
||||
enable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_en[pf], timestep)), importDefSigSpec(assumes_en[pf], timestep));
|
||||
} else {
|
||||
check_bits = importDefSigSpec(assumes_a[pf], timestep);
|
||||
enable_bits = importDefSigSpec(assumes_en[pf], timestep);
|
||||
}
|
||||
return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));
|
||||
}
|
||||
|
||||
int signals_eq(RTLIL::SigSpec lhs, RTLIL::SigSpec rhs, int timestep_lhs = -1, int timestep_rhs = -1)
|
||||
{
|
||||
if (timestep_rhs < 0)
|
||||
|
@ -141,9 +226,9 @@ struct SatGen
|
|||
if (!forced_signed && cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters.count("\\B_SIGNED") > 0)
|
||||
is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool();
|
||||
while (vec_a.size() < vec_b.size() || vec_a.size() < y_width)
|
||||
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->FALSE);
|
||||
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);
|
||||
while (vec_b.size() < vec_a.size() || vec_b.size() < y_width)
|
||||
vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->FALSE);
|
||||
vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->CONST_FALSE);
|
||||
}
|
||||
|
||||
void extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false)
|
||||
|
@ -157,7 +242,7 @@ struct SatGen
|
|||
{
|
||||
bool is_signed = forced_signed || (cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool());
|
||||
while (vec_a.size() < vec_y.size())
|
||||
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->FALSE);
|
||||
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);
|
||||
while (vec_y.size() < vec_a.size())
|
||||
vec_y.push_back(ez->literal());
|
||||
}
|
||||
|
@ -207,7 +292,7 @@ struct SatGen
|
|||
|
||||
if (is_arith_compare) {
|
||||
for (size_t i = 1; i < undef_y.size(); i++)
|
||||
ez->SET(ez->FALSE, undef_y.at(i));
|
||||
ez->SET(ez->CONST_FALSE, undef_y.at(i));
|
||||
ez->SET(undef_y_bit, undef_y.at(0));
|
||||
} else {
|
||||
std::vector<int> undef_y_bits(undef_y.size(), undef_y_bit);
|
||||
|
@ -288,7 +373,7 @@ struct SatGen
|
|||
int a = importDefSigSpec(cell->getPort("\\A"), timestep).at(0);
|
||||
int b = importDefSigSpec(cell->getPort("\\B"), timestep).at(0);
|
||||
int c = importDefSigSpec(cell->getPort("\\C"), timestep).at(0);
|
||||
int d = three_mode ? (aoi_mode ? ez->TRUE : ez->FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0);
|
||||
int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0);
|
||||
int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0);
|
||||
int yy = model_undef ? ez->literal() : y;
|
||||
|
||||
|
@ -302,7 +387,7 @@ struct SatGen
|
|||
int undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep).at(0);
|
||||
int undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep).at(0);
|
||||
int undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep).at(0);
|
||||
int undef_d = three_mode ? ez->FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0);
|
||||
int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0);
|
||||
int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0);
|
||||
|
||||
if (aoi_mode)
|
||||
|
@ -414,14 +499,14 @@ struct SatGen
|
|||
std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
|
||||
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
|
||||
|
||||
int maybe_one_hot = ez->FALSE;
|
||||
int maybe_many_hot = ez->FALSE;
|
||||
int maybe_one_hot = ez->CONST_FALSE;
|
||||
int maybe_many_hot = ez->CONST_FALSE;
|
||||
|
||||
int sure_one_hot = ez->FALSE;
|
||||
int sure_many_hot = ez->FALSE;
|
||||
int sure_one_hot = ez->CONST_FALSE;
|
||||
int sure_many_hot = ez->CONST_FALSE;
|
||||
|
||||
std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->FALSE);
|
||||
std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->FALSE);
|
||||
std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
|
||||
std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
|
||||
|
||||
for (size_t i = 0; i < s.size(); i++)
|
||||
{
|
||||
|
@ -463,7 +548,7 @@ struct SatGen
|
|||
if (cell->type == "$pos") {
|
||||
ez->assume(ez->vec_eq(a, yy));
|
||||
} else {
|
||||
std::vector<int> zero(a.size(), ez->FALSE);
|
||||
std::vector<int> zero(a.size(), ez->CONST_FALSE);
|
||||
ez->assume(ez->vec_eq(ez->vec_sub(zero, a), yy));
|
||||
}
|
||||
|
||||
|
@ -505,7 +590,7 @@ struct SatGen
|
|||
if (cell->type == "$logic_not")
|
||||
ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0));
|
||||
for (size_t i = 1; i < y.size(); i++)
|
||||
ez->SET(ez->FALSE, yy.at(i));
|
||||
ez->SET(ez->CONST_FALSE, yy.at(i));
|
||||
|
||||
if (model_undef)
|
||||
{
|
||||
|
@ -527,7 +612,7 @@ struct SatGen
|
|||
log_abort();
|
||||
|
||||
for (size_t i = 1; i < undef_y.size(); i++)
|
||||
ez->SET(ez->FALSE, undef_y.at(i));
|
||||
ez->SET(ez->CONST_FALSE, undef_y.at(i));
|
||||
|
||||
undefGating(y, yy, undef_y);
|
||||
}
|
||||
|
@ -550,7 +635,7 @@ struct SatGen
|
|||
else
|
||||
ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0));
|
||||
for (size_t i = 1; i < y.size(); i++)
|
||||
ez->SET(ez->FALSE, yy.at(i));
|
||||
ez->SET(ez->CONST_FALSE, yy.at(i));
|
||||
|
||||
if (model_undef)
|
||||
{
|
||||
|
@ -573,7 +658,7 @@ struct SatGen
|
|||
log_abort();
|
||||
|
||||
for (size_t i = 1; i < undef_y.size(); i++)
|
||||
ez->SET(ez->FALSE, undef_y.at(i));
|
||||
ez->SET(ez->CONST_FALSE, undef_y.at(i));
|
||||
|
||||
undefGating(y, yy, undef_y);
|
||||
}
|
||||
|
@ -611,7 +696,7 @@ struct SatGen
|
|||
if (cell->type == "$gt")
|
||||
ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0));
|
||||
for (size_t i = 1; i < y.size(); i++)
|
||||
ez->SET(ez->FALSE, yy.at(i));
|
||||
ez->SET(ez->CONST_FALSE, yy.at(i));
|
||||
|
||||
if (model_undef && (cell->type == "$eqx" || cell->type == "$nex"))
|
||||
{
|
||||
|
@ -626,7 +711,7 @@ struct SatGen
|
|||
yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b));
|
||||
|
||||
for (size_t i = 0; i < y.size(); i++)
|
||||
ez->SET(ez->FALSE, undef_y.at(i));
|
||||
ez->SET(ez->CONST_FALSE, undef_y.at(i));
|
||||
|
||||
ez->assume(ez->vec_eq(y, yy));
|
||||
}
|
||||
|
@ -648,7 +733,7 @@ struct SatGen
|
|||
int undef_y_bit = ez->AND(undef_any, ez->NOT(masked_ne));
|
||||
|
||||
for (size_t i = 1; i < undef_y.size(); i++)
|
||||
ez->SET(ez->FALSE, undef_y.at(i));
|
||||
ez->SET(ez->CONST_FALSE, undef_y.at(i));
|
||||
ez->SET(undef_y_bit, undef_y.at(0));
|
||||
|
||||
undefGating(y, yy, undef_y);
|
||||
|
@ -670,7 +755,7 @@ struct SatGen
|
|||
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
|
||||
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
|
||||
|
||||
int extend_bit = ez->FALSE;
|
||||
int extend_bit = ez->CONST_FALSE;
|
||||
|
||||
if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
|
||||
extend_bit = a.back();
|
||||
|
@ -684,16 +769,16 @@ struct SatGen
|
|||
std::vector<int> shifted_a;
|
||||
|
||||
if (cell->type == "$shl" || cell->type == "$sshl")
|
||||
shifted_a = ez->vec_shift_left(a, b, false, ez->FALSE, ez->FALSE);
|
||||
shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
|
||||
|
||||
if (cell->type == "$shr")
|
||||
shifted_a = ez->vec_shift_right(a, b, false, ez->FALSE, ez->FALSE);
|
||||
shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
|
||||
|
||||
if (cell->type == "$sshr")
|
||||
shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE, ez->FALSE);
|
||||
shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
|
||||
|
||||
if (cell->type == "$shift" || cell->type == "$shiftx")
|
||||
shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
|
||||
shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
|
||||
|
||||
ez->assume(ez->vec_eq(shifted_a, yy));
|
||||
|
||||
|
@ -704,7 +789,7 @@ struct SatGen
|
|||
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
|
||||
std::vector<int> undef_a_shifted;
|
||||
|
||||
extend_bit = cell->type == "$shiftx" ? ez->TRUE : ez->FALSE;
|
||||
extend_bit = cell->type == "$shiftx" ? ez->CONST_TRUE : ez->CONST_FALSE;
|
||||
if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
|
||||
extend_bit = undef_a.back();
|
||||
|
||||
|
@ -714,19 +799,19 @@ struct SatGen
|
|||
undef_a.push_back(extend_bit);
|
||||
|
||||
if (cell->type == "$shl" || cell->type == "$sshl")
|
||||
undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->FALSE, ez->FALSE);
|
||||
undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
|
||||
|
||||
if (cell->type == "$shr")
|
||||
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->FALSE, ez->FALSE);
|
||||
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
|
||||
|
||||
if (cell->type == "$sshr")
|
||||
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->FALSE, ez->FALSE);
|
||||
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
|
||||
|
||||
if (cell->type == "$shift")
|
||||
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
|
||||
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
|
||||
|
||||
if (cell->type == "$shiftx")
|
||||
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->TRUE, ez->TRUE);
|
||||
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE);
|
||||
|
||||
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
|
||||
std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b);
|
||||
|
@ -745,10 +830,10 @@ struct SatGen
|
|||
|
||||
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
|
||||
|
||||
std::vector<int> tmp(a.size(), ez->FALSE);
|
||||
std::vector<int> tmp(a.size(), ez->CONST_FALSE);
|
||||
for (int i = 0; i < int(a.size()); i++)
|
||||
{
|
||||
std::vector<int> shifted_a(a.size(), ez->FALSE);
|
||||
std::vector<int> shifted_a(a.size(), ez->CONST_FALSE);
|
||||
for (int j = i; j < int(a.size()); j++)
|
||||
shifted_a.at(j) = a.at(j-i);
|
||||
tmp = ez->vec_ite(b.at(i), ez->vec_add(tmp, shifted_a), tmp);
|
||||
|
@ -772,25 +857,25 @@ struct SatGen
|
|||
Macc macc;
|
||||
macc.from_cell(cell);
|
||||
|
||||
std::vector<int> tmp(SIZE(y), ez->FALSE);
|
||||
std::vector<int> tmp(GetSize(y), ez->CONST_FALSE);
|
||||
|
||||
for (auto &port : macc.ports)
|
||||
{
|
||||
std::vector<int> in_a = importDefSigSpec(port.in_a, timestep);
|
||||
std::vector<int> in_b = importDefSigSpec(port.in_b, timestep);
|
||||
|
||||
while (SIZE(in_a) < SIZE(y))
|
||||
in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->FALSE);
|
||||
in_a.resize(SIZE(y));
|
||||
while (GetSize(in_a) < GetSize(y))
|
||||
in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->CONST_FALSE);
|
||||
in_a.resize(GetSize(y));
|
||||
|
||||
if (SIZE(in_b))
|
||||
if (GetSize(in_b))
|
||||
{
|
||||
while (SIZE(in_b) < SIZE(y))
|
||||
in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->FALSE);
|
||||
in_b.resize(SIZE(y));
|
||||
while (GetSize(in_b) < GetSize(y))
|
||||
in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->CONST_FALSE);
|
||||
in_b.resize(GetSize(y));
|
||||
|
||||
for (int i = 0; i < SIZE(in_b); i++) {
|
||||
std::vector<int> shifted_a(in_a.size(), ez->FALSE);
|
||||
for (int i = 0; i < GetSize(in_b); i++) {
|
||||
std::vector<int> shifted_a(in_a.size(), ez->CONST_FALSE);
|
||||
for (int j = i; j < int(in_a.size()); j++)
|
||||
shifted_a.at(j) = in_a.at(j-i);
|
||||
if (port.do_subtract)
|
||||
|
@ -808,8 +893,8 @@ struct SatGen
|
|||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < SIZE(b); i++) {
|
||||
std::vector<int> val(SIZE(y), ez->FALSE);
|
||||
for (int i = 0; i < GetSize(b); i++) {
|
||||
std::vector<int> val(GetSize(y), ez->CONST_FALSE);
|
||||
val.at(0) = b.at(i);
|
||||
tmp = ez->vec_add(tmp, val);
|
||||
}
|
||||
|
@ -823,7 +908,7 @@ struct SatGen
|
|||
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
|
||||
|
||||
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
|
||||
ez->assume(ez->vec_eq(undef_y, std::vector<int>(SIZE(y), ez->OR(undef_any_a, undef_any_b))));
|
||||
ez->assume(ez->vec_eq(undef_y, std::vector<int>(GetSize(y), ez->OR(undef_any_a, undef_any_b))));
|
||||
|
||||
undefGating(y, tmp, undef_y);
|
||||
}
|
||||
|
@ -852,14 +937,14 @@ struct SatGen
|
|||
}
|
||||
|
||||
std::vector<int> chain_buf = a_u;
|
||||
std::vector<int> y_u(a_u.size(), ez->FALSE);
|
||||
std::vector<int> y_u(a_u.size(), ez->CONST_FALSE);
|
||||
for (int i = int(a.size())-1; i >= 0; i--)
|
||||
{
|
||||
chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->FALSE);
|
||||
chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->CONST_FALSE);
|
||||
|
||||
std::vector<int> b_shl(i, ez->FALSE);
|
||||
std::vector<int> b_shl(i, ez->CONST_FALSE);
|
||||
b_shl.insert(b_shl.end(), b_u.begin(), b_u.end());
|
||||
b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->FALSE);
|
||||
b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->CONST_FALSE);
|
||||
|
||||
y_u.at(i) = ez->vec_ge_unsigned(chain_buf, b_shl);
|
||||
chain_buf = ez->vec_ite(y_u.at(i), ez->vec_sub(chain_buf, b_shl), chain_buf);
|
||||
|
@ -886,13 +971,13 @@ struct SatGen
|
|||
std::vector<int> div_zero_result;
|
||||
if (cell->type == "$div") {
|
||||
if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) {
|
||||
std::vector<int> all_ones(y.size(), ez->TRUE);
|
||||
std::vector<int> only_first_one(y.size(), ez->FALSE);
|
||||
only_first_one.at(0) = ez->TRUE;
|
||||
std::vector<int> all_ones(y.size(), ez->CONST_TRUE);
|
||||
std::vector<int> only_first_one(y.size(), ez->CONST_FALSE);
|
||||
only_first_one.at(0) = ez->CONST_TRUE;
|
||||
div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones);
|
||||
} else {
|
||||
div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->TRUE);
|
||||
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE);
|
||||
div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->CONST_TRUE);
|
||||
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
|
||||
}
|
||||
} else {
|
||||
int copy_a_bits = std::min(cell->getPort("\\A").size(), cell->getPort("\\B").size());
|
||||
|
@ -900,7 +985,7 @@ struct SatGen
|
|||
if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool())
|
||||
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back());
|
||||
else
|
||||
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE);
|
||||
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
|
||||
}
|
||||
ez->assume(ez->vec_eq(yy, ez->vec_ite(ez->expression(ezSAT::OpOr, b), y_tmp, div_zero_result)));
|
||||
}
|
||||
|
@ -920,44 +1005,44 @@ struct SatGen
|
|||
|
||||
std::vector<int> lut;
|
||||
for (auto bit : cell->getParam("\\LUT").bits)
|
||||
lut.push_back(bit == RTLIL::S1 ? ez->TRUE : ez->FALSE);
|
||||
while (SIZE(lut) < (1 << SIZE(a)))
|
||||
lut.push_back(ez->FALSE);
|
||||
lut.resize(1 << SIZE(a));
|
||||
lut.push_back(bit == RTLIL::S1 ? ez->CONST_TRUE : ez->CONST_FALSE);
|
||||
while (GetSize(lut) < (1 << GetSize(a)))
|
||||
lut.push_back(ez->CONST_FALSE);
|
||||
lut.resize(1 << GetSize(a));
|
||||
|
||||
if (model_undef)
|
||||
{
|
||||
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
|
||||
std::vector<int> t(lut), u(SIZE(t), ez->FALSE);
|
||||
std::vector<int> t(lut), u(GetSize(t), ez->CONST_FALSE);
|
||||
|
||||
for (int i = SIZE(a)-1; i >= 0; i--)
|
||||
for (int i = GetSize(a)-1; i >= 0; i--)
|
||||
{
|
||||
std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2);
|
||||
std::vector<int> t1(t.begin() + SIZE(t)/2, t.end());
|
||||
std::vector<int> t0(t.begin(), t.begin() + GetSize(t)/2);
|
||||
std::vector<int> t1(t.begin() + GetSize(t)/2, t.end());
|
||||
|
||||
std::vector<int> u0(u.begin(), u.begin() + SIZE(u)/2);
|
||||
std::vector<int> u1(u.begin() + SIZE(u)/2, u.end());
|
||||
std::vector<int> u0(u.begin(), u.begin() + GetSize(u)/2);
|
||||
std::vector<int> u1(u.begin() + GetSize(u)/2, u.end());
|
||||
|
||||
t = ez->vec_ite(a[i], t1, t0);
|
||||
u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0));
|
||||
}
|
||||
|
||||
log_assert(SIZE(t) == 1);
|
||||
log_assert(SIZE(u) == 1);
|
||||
log_assert(GetSize(t) == 1);
|
||||
log_assert(GetSize(u) == 1);
|
||||
undefGating(y, t, u);
|
||||
ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<int> t = lut;
|
||||
for (int i = SIZE(a)-1; i >= 0; i--)
|
||||
for (int i = GetSize(a)-1; i >= 0; i--)
|
||||
{
|
||||
std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2);
|
||||
std::vector<int> t1(t.begin() + SIZE(t)/2, t.end());
|
||||
std::vector<int> t0(t.begin(), t.begin() + GetSize(t)/2);
|
||||
std::vector<int> t1(t.begin() + GetSize(t)/2, t.end());
|
||||
t = ez->vec_ite(a[i], t1, t0);
|
||||
}
|
||||
|
||||
log_assert(SIZE(t) == 1);
|
||||
log_assert(GetSize(t) == 1);
|
||||
ez->assume(ez->vec_eq(y, t));
|
||||
}
|
||||
return true;
|
||||
|
@ -1008,7 +1093,7 @@ struct SatGen
|
|||
|
||||
std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co;
|
||||
|
||||
for (int i = 0; i < SIZE(co); i++)
|
||||
for (int i = 0; i < GetSize(co); i++)
|
||||
ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0])));
|
||||
|
||||
if (model_undef)
|
||||
|
@ -1049,12 +1134,12 @@ struct SatGen
|
|||
std::vector<int> def_x = model_undef ? ez->vec_var(x.size()) : x;
|
||||
std::vector<int> def_co = model_undef ? ez->vec_var(co.size()) : co;
|
||||
|
||||
log_assert(SIZE(y) == SIZE(x));
|
||||
log_assert(SIZE(y) == SIZE(co));
|
||||
log_assert(SIZE(ci) == 1);
|
||||
log_assert(SIZE(bi) == 1);
|
||||
log_assert(GetSize(y) == GetSize(x));
|
||||
log_assert(GetSize(y) == GetSize(co));
|
||||
log_assert(GetSize(ci) == 1);
|
||||
log_assert(GetSize(bi) == 1);
|
||||
|
||||
for (int i = 0; i < SIZE(y); i++)
|
||||
for (int i = 0; i < GetSize(y); i++)
|
||||
{
|
||||
int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0);
|
||||
ez->SET(def_x.at(i), ez->XOR(s1, s2));
|
||||
|
@ -1084,7 +1169,7 @@ struct SatGen
|
|||
all_inputs_undef.insert(all_inputs_undef.end(), undef_bi.begin(), undef_bi.end());
|
||||
int undef_any = ez->expression(ezSAT::OpOr, all_inputs_undef);
|
||||
|
||||
for (int i = 0; i < SIZE(undef_y); i++) {
|
||||
for (int i = 0; i < GetSize(undef_y); i++) {
|
||||
ez->SET(undef_y.at(i), undef_any);
|
||||
ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0)));
|
||||
ez->SET(undef_co.at(i), undef_any);
|
||||
|
@ -1144,6 +1229,25 @@ struct SatGen
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$_BUF_" || cell->type == "$equiv")
|
||||
{
|
||||
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
|
||||
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
|
||||
extendSignalWidthUnary(a, y, cell);
|
||||
|
||||
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
|
||||
ez->assume(ez->vec_eq(a, yy));
|
||||
|
||||
if (model_undef) {
|
||||
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
|
||||
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
|
||||
extendSignalWidthUnary(undef_a, undef_y, cell, false);
|
||||
ez->assume(ez->vec_eq(undef_a, undef_y));
|
||||
undefGating(y, yy, undef_y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$assert")
|
||||
{
|
||||
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
|
@ -1152,10 +1256,20 @@ struct SatGen
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$assume")
|
||||
{
|
||||
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
|
||||
assumes_a[pf].append((*sigmap)(cell->getPort("\\A")));
|
||||
assumes_en[pf].append((*sigmap)(cell->getPort("\\EN")));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unsupported internal cell types: $pow $lut
|
||||
// .. and all sequential cells except $dff and $_DFF_[NP]_
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,9 +29,10 @@ struct SigPool
|
|||
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
|
||||
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
|
||||
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
|
||||
unsigned int hash() const { return first->name.hash() + second; }
|
||||
};
|
||||
|
||||
std::set<bitDef_t> bits;
|
||||
pool<bitDef_t> bits;
|
||||
|
||||
void clear()
|
||||
{
|
||||
|
@ -66,8 +67,8 @@ struct SigPool
|
|||
|
||||
void expand(RTLIL::SigSpec from, RTLIL::SigSpec to)
|
||||
{
|
||||
log_assert(SIZE(from) == SIZE(to));
|
||||
for (int i = 0; i < SIZE(from); i++) {
|
||||
log_assert(GetSize(from) == GetSize(to));
|
||||
for (int i = 0; i < GetSize(from); i++) {
|
||||
bitDef_t bit_from(from[i]), bit_to(to[i]);
|
||||
if (bit_from.first != NULL && bit_to.first != NULL && bits.count(bit_from) > 0)
|
||||
bits.insert(bit_to);
|
||||
|
@ -122,13 +123,13 @@ struct SigPool
|
|||
|
||||
RTLIL::SigSpec export_all()
|
||||
{
|
||||
std::set<RTLIL::SigBit> sig;
|
||||
pool<RTLIL::SigBit> sig;
|
||||
for (auto &bit : bits)
|
||||
sig.insert(RTLIL::SigBit(bit.first, bit.second));
|
||||
return sig;
|
||||
}
|
||||
|
||||
size_t size()
|
||||
size_t size() const
|
||||
{
|
||||
return bits.size();
|
||||
}
|
||||
|
@ -140,9 +141,10 @@ struct SigSet
|
|||
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
|
||||
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
|
||||
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
|
||||
unsigned int hash() const { return first->name.hash() + second; }
|
||||
};
|
||||
|
||||
std::map<bitDef_t, std::set<T, Compare>> bits;
|
||||
dict<bitDef_t, std::set<T, Compare>> bits;
|
||||
|
||||
void clear()
|
||||
{
|
||||
|
@ -193,6 +195,15 @@ struct SigSet
|
|||
}
|
||||
}
|
||||
|
||||
void find(RTLIL::SigSpec sig, pool<T> &result)
|
||||
{
|
||||
for (auto &bit : sig)
|
||||
if (bit.wire != NULL) {
|
||||
auto &data = bits[bit];
|
||||
result.insert(data.begin(), data.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::set<T> find(RTLIL::SigSpec sig)
|
||||
{
|
||||
std::set<T> result;
|
||||
|
@ -214,6 +225,7 @@ struct SigMap
|
|||
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
|
||||
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
|
||||
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
|
||||
unsigned int hash() const { return first->name.hash() + second; }
|
||||
};
|
||||
|
||||
struct shared_bit_data_t {
|
||||
|
@ -221,7 +233,7 @@ struct SigMap
|
|||
std::set<bitDef_t> bits;
|
||||
};
|
||||
|
||||
std::map<bitDef_t, shared_bit_data_t*> bits;
|
||||
dict<bitDef_t, shared_bit_data_t*> bits;
|
||||
|
||||
SigMap(RTLIL::Module *module = NULL)
|
||||
{
|
||||
|
@ -346,9 +358,9 @@ struct SigMap
|
|||
|
||||
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
|
||||
{
|
||||
log_assert(SIZE(from) == SIZE(to));
|
||||
log_assert(GetSize(from) == GetSize(to));
|
||||
|
||||
for (int i = 0; i < SIZE(from); i++)
|
||||
for (int i = 0; i < GetSize(from); i++)
|
||||
{
|
||||
RTLIL::SigBit &bf = from[i];
|
||||
RTLIL::SigBit &bt = to[i];
|
||||
|
|
|
@ -25,21 +25,23 @@
|
|||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// ------------------------------------------------
|
||||
// A map-like container, but you can save and restore the state
|
||||
// ------------------------------------------------
|
||||
|
||||
template<typename Key, typename T, typename Compare = std::less<Key>>
|
||||
template<typename Key, typename T, typename OPS = hash_ops<Key>>
|
||||
struct stackmap
|
||||
{
|
||||
private:
|
||||
std::vector<std::map<Key, T*, Compare>> backup_state;
|
||||
std::map<Key, T, Compare> current_state;
|
||||
std::vector<dict<Key, T*, OPS>> backup_state;
|
||||
dict<Key, T, OPS> current_state;
|
||||
static T empty_tuple;
|
||||
|
||||
public:
|
||||
stackmap() { }
|
||||
stackmap(const std::map<Key, T, Compare> &other) : current_state(other) { }
|
||||
stackmap(const dict<Key, T, OPS> &other) : current_state(other) { }
|
||||
|
||||
template<typename Other>
|
||||
void operator=(const Other &other)
|
||||
|
@ -81,7 +83,7 @@ public:
|
|||
|
||||
void reset(const Key &k)
|
||||
{
|
||||
for (int i = SIZE(backup_state)-1; i >= 0; i--)
|
||||
for (int i = GetSize(backup_state)-1; i >= 0; i--)
|
||||
if (backup_state[i].count(k) != 0) {
|
||||
if (backup_state[i].at(k) == nullptr)
|
||||
current_state.erase(k);
|
||||
|
@ -92,7 +94,7 @@ public:
|
|||
current_state.erase(k);
|
||||
}
|
||||
|
||||
const std::map<Key, T, Compare> &stdmap()
|
||||
const dict<Key, T, OPS> &stdmap()
|
||||
{
|
||||
return current_state;
|
||||
}
|
||||
|
@ -126,12 +128,12 @@ public:
|
|||
// A simple class for topological sorting
|
||||
// ------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
template<typename T, typename C = std::less<T>>
|
||||
struct TopoSort
|
||||
{
|
||||
bool analyze_loops, found_loops;
|
||||
std::map<T, std::set<T>> database;
|
||||
std::set<std::set<T>> loops;
|
||||
std::map<T, std::set<T, C>, C> database;
|
||||
std::set<std::set<T, C>> loops;
|
||||
std::vector<T> sorted;
|
||||
|
||||
TopoSort()
|
||||
|
@ -143,7 +145,7 @@ struct TopoSort
|
|||
void node(T n)
|
||||
{
|
||||
if (database.count(n) == 0)
|
||||
database[n] = std::set<T>();
|
||||
database[n] = std::set<T, C>();
|
||||
}
|
||||
|
||||
void edge(T left, T right)
|
||||
|
@ -152,13 +154,13 @@ struct TopoSort
|
|||
database[right].insert(left);
|
||||
}
|
||||
|
||||
void sort_worker(const T &n, std::set<T> &marked_cells, std::set<T> &active_cells, std::vector<T> &active_stack)
|
||||
void sort_worker(const T &n, std::set<T, C> &marked_cells, std::set<T, C> &active_cells, std::vector<T> &active_stack)
|
||||
{
|
||||
if (active_cells.count(n)) {
|
||||
found_loops = true;
|
||||
if (analyze_loops) {
|
||||
std::set<T> loop;
|
||||
for (int i = SIZE(active_stack)-1; i >= 0; i--) {
|
||||
std::set<T, C> loop;
|
||||
for (int i = GetSize(active_stack)-1; i >= 0; i--) {
|
||||
loop.insert(active_stack[i]);
|
||||
if (active_stack[i] == n)
|
||||
break;
|
||||
|
@ -195,16 +197,18 @@ struct TopoSort
|
|||
sorted.clear();
|
||||
found_loops = false;
|
||||
|
||||
std::set<T> marked_cells;
|
||||
std::set<T> active_cells;
|
||||
std::set<T, C> marked_cells;
|
||||
std::set<T, C> active_cells;
|
||||
std::vector<T> active_stack;
|
||||
|
||||
for (auto &it : database)
|
||||
sort_worker(it.first, marked_cells, active_cells, active_stack);
|
||||
|
||||
log_assert(SIZE(sorted) == SIZE(database));
|
||||
log_assert(GetSize(sorted) == GetSize(database));
|
||||
return !found_loops;
|
||||
}
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
479
kernel/yosys.cc
479
kernel/yosys.cc
|
@ -18,26 +18,112 @@
|
|||
*/
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/celltypes.h"
|
||||
|
||||
#ifdef YOSYS_ENABLE_READLINE
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#ifdef YOSYS_ENABLE_PLUGINS
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
#elif defined(__APPLE__)
|
||||
# include <mach-o/dyld.h>
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <sys/stat.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
int autoidx = 1;
|
||||
int yosys_xtrace = 0;
|
||||
RTLIL::Design *yosys_design = NULL;
|
||||
CellTypes yosys_celltypes;
|
||||
|
||||
#ifdef YOSYS_ENABLE_TCL
|
||||
Tcl_Interp *yosys_tcl_interp = NULL;
|
||||
#endif
|
||||
|
||||
bool memhasher_active = false;
|
||||
uint32_t memhasher_rng = 123456;
|
||||
std::vector<void*> memhasher_store;
|
||||
|
||||
void memhasher_on()
|
||||
{
|
||||
#ifdef __linux__
|
||||
memhasher_rng += time(NULL) << 16 ^ getpid();
|
||||
#endif
|
||||
memhasher_store.resize(0x10000);
|
||||
memhasher_active = true;
|
||||
}
|
||||
|
||||
void memhasher_off()
|
||||
{
|
||||
for (auto p : memhasher_store)
|
||||
if (p) free(p);
|
||||
memhasher_store.clear();
|
||||
memhasher_active = false;
|
||||
}
|
||||
|
||||
void memhasher_do()
|
||||
{
|
||||
memhasher_rng ^= memhasher_rng << 13;
|
||||
memhasher_rng ^= memhasher_rng >> 17;
|
||||
memhasher_rng ^= memhasher_rng << 5;
|
||||
|
||||
int size, index = (memhasher_rng >> 4) & 0xffff;
|
||||
switch (memhasher_rng & 7) {
|
||||
case 0: size = 16; break;
|
||||
case 1: size = 256; break;
|
||||
case 2: size = 1024; break;
|
||||
case 3: size = 4096; break;
|
||||
default: size = 0;
|
||||
}
|
||||
if (index < 16) size *= 16;
|
||||
memhasher_store[index] = realloc(memhasher_store[index], size);
|
||||
}
|
||||
|
||||
void yosys_banner()
|
||||
{
|
||||
log("\n");
|
||||
log(" /----------------------------------------------------------------------------\\\n");
|
||||
log(" | |\n");
|
||||
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
|
||||
log(" | |\n");
|
||||
log(" | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> |\n");
|
||||
log(" | |\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(" | copyright notice and this permission notice appear in all copies. |\n");
|
||||
log(" | |\n");
|
||||
log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
|
||||
log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
|
||||
log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
|
||||
log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
|
||||
log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
|
||||
log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
|
||||
log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
|
||||
log(" | |\n");
|
||||
log(" \\----------------------------------------------------------------------------/\n");
|
||||
log("\n");
|
||||
log(" %s\n", yosys_version_str);
|
||||
log("\n");
|
||||
}
|
||||
|
||||
std::string stringf(const char *fmt, ...)
|
||||
{
|
||||
std::string string;
|
||||
|
@ -55,8 +141,22 @@ std::string vstringf(const char *fmt, va_list ap)
|
|||
std::string string;
|
||||
char *str = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
int sz = 64, rc;
|
||||
while (1) {
|
||||
va_list apc;
|
||||
va_copy(apc, ap);
|
||||
str = (char*)realloc(str, sz);
|
||||
rc = vsnprintf(str, sz, fmt, apc);
|
||||
va_end(apc);
|
||||
if (rc >= 0 && rc < sz)
|
||||
break;
|
||||
sz *= 2;
|
||||
}
|
||||
#else
|
||||
if (vasprintf(&str, fmt, ap) < 0)
|
||||
str = NULL;
|
||||
#endif
|
||||
|
||||
if (str != NULL) {
|
||||
string = str;
|
||||
|
@ -66,15 +166,264 @@ std::string vstringf(const char *fmt, va_list ap)
|
|||
return string;
|
||||
}
|
||||
|
||||
int SIZE(RTLIL::Wire *wire)
|
||||
int readsome(std::istream &f, char *s, int n)
|
||||
{
|
||||
int rc = f.readsome(s, n);
|
||||
|
||||
// f.readsome() sometimes returns 0 on a non-empty stream..
|
||||
if (rc == 0) {
|
||||
int c = f.get();
|
||||
if (c != EOF) {
|
||||
*s = c;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
std::string next_token(std::string &text, const char *sep)
|
||||
{
|
||||
size_t pos_begin = text.find_first_not_of(sep);
|
||||
|
||||
if (pos_begin == std::string::npos)
|
||||
pos_begin = text.size();
|
||||
|
||||
size_t pos_end = text.find_first_of(sep, pos_begin);
|
||||
|
||||
if (pos_end == std::string::npos)
|
||||
pos_end = text.size();
|
||||
|
||||
std::string token = text.substr(pos_begin, pos_end-pos_begin);
|
||||
text = text.substr(pos_end);
|
||||
return token;
|
||||
}
|
||||
|
||||
// this is very similar to fnmatch(). the exact rules used by this
|
||||
// function are:
|
||||
//
|
||||
// ? matches any character except
|
||||
// * matches any sequence of characters
|
||||
// [...] matches any of the characters in the list
|
||||
// [!..] matches any of the characters not in the list
|
||||
//
|
||||
// a backslash may be used to escape the next characters in the
|
||||
// pattern. each special character can also simply match itself.
|
||||
//
|
||||
bool patmatch(const char *pattern, const char *string)
|
||||
{
|
||||
if (*pattern == 0)
|
||||
return *string == 0;
|
||||
|
||||
if (*pattern == '\\') {
|
||||
if (pattern[1] == string[0] && patmatch(pattern+2, string+1))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*pattern == '?') {
|
||||
if (*string == 0)
|
||||
return false;
|
||||
return patmatch(pattern+1, string+1);
|
||||
}
|
||||
|
||||
if (*pattern == '*') {
|
||||
while (*string) {
|
||||
if (patmatch(pattern+1, string++))
|
||||
return true;
|
||||
}
|
||||
return pattern[1] == 0;
|
||||
}
|
||||
|
||||
if (*pattern == '[') {
|
||||
bool found_match = false;
|
||||
bool inverted_list = pattern[1] == '!';
|
||||
const char *p = pattern + (inverted_list ? 1 : 0);
|
||||
|
||||
while (*++p) {
|
||||
if (*p == ']') {
|
||||
if (found_match != inverted_list && patmatch(p+1, string+1))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p == '\\') {
|
||||
if (*++p == *string)
|
||||
found_match = true;
|
||||
} else
|
||||
if (*p == *string)
|
||||
found_match = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (*pattern == *string)
|
||||
return patmatch(pattern+1, string+1);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int run_command(const std::string &command, std::function<void(const std::string&)> process_line)
|
||||
{
|
||||
if (!process_line)
|
||||
return system(command.c_str());
|
||||
|
||||
FILE *f = popen(command.c_str(), "r");
|
||||
if (f == nullptr)
|
||||
return -1;
|
||||
|
||||
std::string line;
|
||||
char logbuf[128];
|
||||
while (fgets(logbuf, 128, f) != NULL) {
|
||||
line += logbuf;
|
||||
if (!line.empty() && line.back() == '\n')
|
||||
process_line(line), line.clear();
|
||||
}
|
||||
if (!line.empty())
|
||||
process_line(line);
|
||||
|
||||
int ret = pclose(f);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
#ifdef _WIN32
|
||||
return ret;
|
||||
#else
|
||||
return WEXITSTATUS(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string make_temp_file(std::string template_str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (template_str.rfind("/tmp/", 0) == 0) {
|
||||
# ifdef __MINGW32__
|
||||
char longpath[MAX_PATH + 1];
|
||||
char shortpath[MAX_PATH + 1];
|
||||
# else
|
||||
WCHAR longpath[MAX_PATH + 1];
|
||||
TCHAR shortpath[MAX_PATH + 1];
|
||||
# endif
|
||||
if (!GetTempPath(MAX_PATH+1, longpath))
|
||||
log_error("GetTempPath() failed.\n");
|
||||
if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1))
|
||||
log_error("GetShortPathName() failed.\n");
|
||||
std::string path;
|
||||
for (int i = 0; shortpath[i]; i++)
|
||||
path += char(shortpath[i]);
|
||||
template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5);
|
||||
}
|
||||
|
||||
size_t pos = template_str.rfind("XXXXXX");
|
||||
log_assert(pos != std::string::npos);
|
||||
|
||||
while (1) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
static uint32_t x = 314159265 ^ uint32_t(time(NULL));
|
||||
x ^= x << 13, x ^= x >> 17, x ^= x << 5;
|
||||
template_str[pos+i] = y[x % y.size()];
|
||||
}
|
||||
if (_access(template_str.c_str(), 0) != 0)
|
||||
break;
|
||||
}
|
||||
#else
|
||||
size_t pos = template_str.rfind("XXXXXX");
|
||||
log_assert(pos != std::string::npos);
|
||||
|
||||
int suffixlen = GetSize(template_str) - pos - 6;
|
||||
|
||||
char *p = strdup(template_str.c_str());
|
||||
close(mkstemps(p, suffixlen));
|
||||
template_str = p;
|
||||
free(p);
|
||||
#endif
|
||||
|
||||
return template_str;
|
||||
}
|
||||
|
||||
std::string make_temp_dir(std::string template_str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
template_str = make_temp_file(template_str);
|
||||
mkdir(template_str.c_str());
|
||||
return template_str;
|
||||
#else
|
||||
# ifndef NDEBUG
|
||||
size_t pos = template_str.rfind("XXXXXX");
|
||||
log_assert(pos != std::string::npos);
|
||||
|
||||
int suffixlen = GetSize(template_str) - pos - 6;
|
||||
log_assert(suffixlen == 0);
|
||||
# endif
|
||||
|
||||
char *p = strdup(template_str.c_str());
|
||||
p = mkdtemp(p);
|
||||
log_assert(p != NULL);
|
||||
template_str = p;
|
||||
free(p);
|
||||
|
||||
return template_str;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
bool check_file_exists(std::string filename, bool)
|
||||
{
|
||||
return _access(filename.c_str(), 0) == 0;
|
||||
}
|
||||
#else
|
||||
bool check_file_exists(std::string filename, bool is_exec)
|
||||
{
|
||||
return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_absolute_path(std::string filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return filename[0] == '/' || filename[0] == '\\' || (filename[0] != 0 && filename[1] == ':');
|
||||
#else
|
||||
return filename[0] == '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
void remove_directory(std::string dirname)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str()));
|
||||
#else
|
||||
struct stat stbuf;
|
||||
struct dirent **namelist;
|
||||
int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort);
|
||||
log_assert(n >= 0);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
|
||||
std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name);
|
||||
if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) {
|
||||
remove(buffer.c_str());
|
||||
} else
|
||||
remove_directory(buffer);
|
||||
}
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
rmdir(dirname.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
int GetSize(RTLIL::Wire *wire)
|
||||
{
|
||||
return wire->width;
|
||||
}
|
||||
|
||||
void yosys_setup()
|
||||
{
|
||||
// if there are already IdString objects then we have a global initialization order bug
|
||||
IdString empty_id;
|
||||
log_assert(empty_id.index_ == 0);
|
||||
IdString::get_reference(empty_id.index_);
|
||||
|
||||
Pass::init_register();
|
||||
yosys_design = new RTLIL::Design;
|
||||
yosys_celltypes.setup();
|
||||
log_push();
|
||||
}
|
||||
|
||||
|
@ -92,6 +441,7 @@ void yosys_shutdown()
|
|||
log_files.clear();
|
||||
|
||||
Pass::done_register();
|
||||
yosys_celltypes.clear();
|
||||
|
||||
#ifdef YOSYS_ENABLE_TCL
|
||||
if (yosys_tcl_interp != NULL) {
|
||||
|
@ -101,20 +451,33 @@ void yosys_shutdown()
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_ENABLE_PLUGINS
|
||||
for (auto &it : loaded_plugins)
|
||||
dlclose(it.second);
|
||||
|
||||
loaded_plugins.clear();
|
||||
loaded_plugin_aliases.clear();
|
||||
#endif
|
||||
|
||||
IdString empty_id;
|
||||
IdString::put_reference(empty_id.index_);
|
||||
}
|
||||
|
||||
RTLIL::IdString new_id(std::string file, int line, std::string func)
|
||||
{
|
||||
std::string str = "$auto$";
|
||||
#ifdef _WIN32
|
||||
size_t pos = file.find_last_of("/\\");
|
||||
#else
|
||||
size_t pos = file.find_last_of('/');
|
||||
str += pos != std::string::npos ? file.substr(pos+1) : file;
|
||||
str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++);
|
||||
return str;
|
||||
#endif
|
||||
if (pos != std::string::npos)
|
||||
file = file.substr(pos+1);
|
||||
|
||||
pos = func.find_last_of(':');
|
||||
if (pos != std::string::npos)
|
||||
func = func.substr(pos+1);
|
||||
|
||||
return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++);
|
||||
}
|
||||
|
||||
RTLIL::Design *yosys_get_design()
|
||||
|
@ -210,9 +573,9 @@ struct TclPass : public Pass {
|
|||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
std::string proc_self_dirname ()
|
||||
std::string proc_self_dirname()
|
||||
{
|
||||
char path [PATH_MAX];
|
||||
char path[PATH_MAX];
|
||||
ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path));
|
||||
if (buflen < 0) {
|
||||
log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno));
|
||||
|
@ -222,10 +585,9 @@ std::string proc_self_dirname ()
|
|||
return std::string(path, buflen);
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
std::string proc_self_dirname ()
|
||||
std::string proc_self_dirname()
|
||||
{
|
||||
char * path = NULL;
|
||||
char *path = NULL;
|
||||
uint32_t buflen = 0;
|
||||
while (_NSGetExecutablePath(path, &buflen) != 0)
|
||||
path = (char *) realloc((void *) path, buflen);
|
||||
|
@ -233,8 +595,32 @@ std::string proc_self_dirname ()
|
|||
buflen--;
|
||||
return std::string(path, buflen);
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
std::string proc_self_dirname()
|
||||
{
|
||||
int i = 0;
|
||||
# ifdef __MINGW32__
|
||||
char longpath[MAX_PATH + 1];
|
||||
char shortpath[MAX_PATH + 1];
|
||||
# else
|
||||
WCHAR longpath[MAX_PATH + 1];
|
||||
TCHAR shortpath[MAX_PATH + 1];
|
||||
# endif
|
||||
if (!GetModuleFileName(0, longpath, MAX_PATH+1))
|
||||
log_error("GetModuleFileName() failed.\n");
|
||||
if (!GetShortPathName(longpath, shortpath, MAX_PATH+1))
|
||||
log_error("GetShortPathName() failed.\n");
|
||||
while (shortpath[i] != 0)
|
||||
i++;
|
||||
while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\')
|
||||
shortpath[--i] = 0;
|
||||
std::string path;
|
||||
for (i = 0; shortpath[i]; i++)
|
||||
path += char(shortpath[i]);
|
||||
return path;
|
||||
}
|
||||
#elif defined(EMSCRIPTEN)
|
||||
std::string proc_self_dirname ()
|
||||
std::string proc_self_dirname()
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
@ -242,17 +628,33 @@ std::string proc_self_dirname ()
|
|||
#error Dont know how to determine process executable base path!
|
||||
#endif
|
||||
|
||||
std::string proc_share_dirname ()
|
||||
#ifdef EMSCRIPTEN
|
||||
std::string proc_share_dirname()
|
||||
{
|
||||
return "/share";
|
||||
}
|
||||
#else
|
||||
std::string proc_share_dirname()
|
||||
{
|
||||
std::string proc_self_path = proc_self_dirname();
|
||||
# ifdef _WIN32
|
||||
std::string proc_share_path = proc_self_path + "share\\";
|
||||
if (check_file_exists(proc_share_path, true))
|
||||
return proc_share_path;
|
||||
proc_share_path = proc_self_path + "..\\share\\";
|
||||
if (check_file_exists(proc_share_path, true))
|
||||
return proc_share_path;
|
||||
# else
|
||||
std::string proc_share_path = proc_self_path + "share/";
|
||||
if (access(proc_share_path.c_str(), X_OK) == 0)
|
||||
if (check_file_exists(proc_share_path, true))
|
||||
return proc_share_path;
|
||||
proc_share_path = proc_self_path + "../share/yosys/";
|
||||
if (access(proc_share_path.c_str(), X_OK) == 0)
|
||||
if (check_file_exists(proc_share_path, true))
|
||||
return proc_share_path;
|
||||
# endif
|
||||
log_error("proc_share_dirname: unable to determine share/ directory!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
bool fgetline(FILE *f, std::string &buffer)
|
||||
{
|
||||
|
@ -275,15 +677,15 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
|
|||
int pos = 0;
|
||||
std::string label;
|
||||
|
||||
while (pos < SIZE(command) && (command[pos] == ' ' || command[pos] == '\t'))
|
||||
while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t'))
|
||||
pos++;
|
||||
|
||||
while (pos < SIZE(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
|
||||
while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
|
||||
label += command[pos++];
|
||||
|
||||
if (label.back() == ':' && SIZE(label) > 1)
|
||||
if (label.back() == ':' && GetSize(label) > 1)
|
||||
{
|
||||
label = label.substr(0, SIZE(label)-1);
|
||||
label = label.substr(0, GetSize(label)-1);
|
||||
command = command.substr(pos);
|
||||
|
||||
if (label == run_from)
|
||||
|
@ -293,8 +695,11 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
|
|||
}
|
||||
}
|
||||
|
||||
void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
|
||||
void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design)
|
||||
{
|
||||
if (design == nullptr)
|
||||
design = yosys_design;
|
||||
|
||||
if (command == "auto") {
|
||||
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
|
||||
command = "verilog";
|
||||
|
@ -361,9 +766,9 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi
|
|||
Pass::call(design, command);
|
||||
}
|
||||
}
|
||||
catch (log_cmd_error_expection) {
|
||||
catch (...) {
|
||||
Frontend::current_script_file = backup_script_file;
|
||||
throw log_cmd_error_expection();
|
||||
throw;
|
||||
}
|
||||
|
||||
Frontend::current_script_file = backup_script_file;
|
||||
|
@ -386,15 +791,26 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi
|
|||
Frontend::frontend_call(design, NULL, filename, command);
|
||||
}
|
||||
|
||||
void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
|
||||
{
|
||||
run_frontend(filename, command, nullptr, nullptr, design);
|
||||
}
|
||||
|
||||
void run_pass(std::string command, RTLIL::Design *design)
|
||||
{
|
||||
log("\n-- Running pass `%s' --\n", command.c_str());
|
||||
if (design == nullptr)
|
||||
design = yosys_design;
|
||||
|
||||
log("\n-- Running command `%s' --\n", command.c_str());
|
||||
|
||||
Pass::call(design, command);
|
||||
}
|
||||
|
||||
void run_backend(std::string filename, std::string command, RTLIL::Design *design)
|
||||
{
|
||||
if (design == nullptr)
|
||||
design = yosys_design;
|
||||
|
||||
if (command == "auto") {
|
||||
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
|
||||
command = "verilog";
|
||||
|
@ -518,11 +934,16 @@ void shell(RTLIL::Design *design)
|
|||
char *command = NULL;
|
||||
#ifdef YOSYS_ENABLE_READLINE
|
||||
while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
|
||||
{
|
||||
#else
|
||||
char command_buffer[4096];
|
||||
while ((command = fgets(command_buffer, 4096, stdin)) != NULL)
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
fputs(create_prompt(design, recursion_counter), stdout);
|
||||
fflush(stdout);
|
||||
if ((command = fgets(command_buffer, 4096, stdin)) == NULL)
|
||||
break;
|
||||
#endif
|
||||
if (command[strspn(command, " \t\r\n")] == 0)
|
||||
continue;
|
||||
#ifdef YOSYS_ENABLE_READLINE
|
||||
|
@ -540,7 +961,7 @@ void shell(RTLIL::Design *design)
|
|||
try {
|
||||
log_assert(design->selection_stack.size() == 1);
|
||||
Pass::call(design, command);
|
||||
} catch (log_cmd_error_expection) {
|
||||
} catch (log_cmd_error_exception) {
|
||||
while (design->selection_stack.size() > 1)
|
||||
design->selection_stack.pop_back();
|
||||
log_reset_stack();
|
||||
|
@ -634,9 +1055,9 @@ struct ScriptPass : public Pass {
|
|||
if (args.size() < 2)
|
||||
log_cmd_error("Missing script file.\n");
|
||||
else if (args.size() == 2)
|
||||
run_frontend(args[1], "script", design, NULL, NULL);
|
||||
run_frontend(args[1], "script", design);
|
||||
else if (args.size() == 3)
|
||||
run_frontend(args[1], "script", design, NULL, &args[2]);
|
||||
run_frontend(args[1], "script", NULL, &args[2], design);
|
||||
else
|
||||
extra_args(args, 2, design, false);
|
||||
}
|
||||
|
|
177
kernel/yosys.h
177
kernel/yosys.h
|
@ -45,7 +45,11 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <initializer_list>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
@ -56,44 +60,164 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _YOSYS_
|
||||
# error It looks like you are trying to build Yosys without the config defines set. \
|
||||
When building Yosys with a custom make system, make sure you set all the \
|
||||
defines the Yosys Makefile would set for your build configuration.
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_ENABLE_TCL
|
||||
# include <tcl.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# undef NOMINMAX
|
||||
# define NOMINMAX 1
|
||||
# undef YY_NO_UNISTD_H
|
||||
# define YY_NO_UNISTD_H 1
|
||||
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <direct.h>
|
||||
|
||||
# define strtok_r strtok_s
|
||||
# define strdup _strdup
|
||||
# define snprintf _snprintf
|
||||
# define getcwd _getcwd
|
||||
# define mkdir _mkdir
|
||||
# define popen _popen
|
||||
# define pclose _pclose
|
||||
# define PATH_MAX MAX_PATH
|
||||
|
||||
# ifndef __MINGW32__
|
||||
# define isatty _isatty
|
||||
# define fileno _fileno
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define PRIVATE_NAMESPACE_BEGIN namespace {
|
||||
#define PRIVATE_NAMESPACE_END }
|
||||
|
||||
#if 0
|
||||
# define YOSYS_NAMESPACE_BEGIN namespace Yosys {
|
||||
# define YOSYS_NAMESPACE_END }
|
||||
# define YOSYS_NAMESPACE_PREFIX Yosys::
|
||||
# define USING_YOSYS_NAMESPACE using namespace Yosys;
|
||||
#else
|
||||
# define YOSYS_NAMESPACE_BEGIN
|
||||
# define YOSYS_NAMESPACE_END
|
||||
# define YOSYS_NAMESPACE_PREFIX
|
||||
# define USING_YOSYS_NAMESPACE
|
||||
#endif
|
||||
#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
|
||||
#define YOSYS_NAMESPACE_END }
|
||||
#define YOSYS_NAMESPACE_PREFIX Yosys::
|
||||
#define USING_YOSYS_NAMESPACE using namespace Yosys;
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
# define OVERRIDE override
|
||||
# define FINAL final
|
||||
# define YS_OVERRIDE override
|
||||
# define YS_FINAL final
|
||||
#else
|
||||
# define OVERRIDE
|
||||
# define FINAL
|
||||
# define YS_OVERRIDE
|
||||
# define YS_FINAL
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
|
||||
# define YS_NORETURN
|
||||
#elif defined(_MSC_VER)
|
||||
# define YS_ATTRIBUTE(...)
|
||||
# define YS_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
# define YS_ATTRIBUTE(...)
|
||||
# define YS_NORETURN
|
||||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
// Note: All headers included in hashlib.h must be included
|
||||
// outside of YOSYS_NAMESPACE before this or bad things will happen.
|
||||
#ifdef HASHLIB_H
|
||||
# undef HASHLIB_H
|
||||
# include "kernel/hashlib.h"
|
||||
#else
|
||||
# include "kernel/hashlib.h"
|
||||
# undef HASHLIB_H
|
||||
#endif
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::pair;
|
||||
|
||||
using hashlib::mkhash;
|
||||
using hashlib::mkhash_init;
|
||||
using hashlib::mkhash_add;
|
||||
using hashlib::mkhash_xorshift;
|
||||
using hashlib::hash_ops;
|
||||
using hashlib::hash_cstr_ops;
|
||||
using hashlib::hash_ptr_ops;
|
||||
using hashlib::hash_obj_ops;
|
||||
using hashlib::dict;
|
||||
using hashlib::idict;
|
||||
using hashlib::pool;
|
||||
|
||||
namespace RTLIL {
|
||||
struct IdString;
|
||||
struct Const;
|
||||
struct SigBit;
|
||||
struct SigSpec;
|
||||
struct Wire;
|
||||
struct Cell;
|
||||
struct Module;
|
||||
struct Design;
|
||||
struct Monitor;
|
||||
}
|
||||
|
||||
std::string stringf(const char *fmt, ...);
|
||||
namespace AST {
|
||||
struct AstNode;
|
||||
}
|
||||
|
||||
using RTLIL::IdString;
|
||||
using RTLIL::Const;
|
||||
using RTLIL::SigBit;
|
||||
using RTLIL::SigSpec;
|
||||
using RTLIL::Wire;
|
||||
using RTLIL::Cell;
|
||||
using RTLIL::Module;
|
||||
using RTLIL::Design;
|
||||
|
||||
namespace hashlib {
|
||||
template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
|
||||
|
||||
template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
|
||||
template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
|
||||
}
|
||||
|
||||
void memhasher_on();
|
||||
void memhasher_off();
|
||||
void memhasher_do();
|
||||
|
||||
extern bool memhasher_active;
|
||||
inline void memhasher() { if (memhasher_active) memhasher_do(); }
|
||||
|
||||
void yosys_banner();
|
||||
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
std::string vstringf(const char *fmt, va_list ap);
|
||||
template<typename T> int SIZE(const T &obj) { return obj.size(); }
|
||||
int SIZE(RTLIL::Wire *wire);
|
||||
int readsome(std::istream &f, char *s, int n);
|
||||
std::string next_token(std::string &text, const char *sep = " \t\r\n");
|
||||
bool patmatch(const char *pattern, const char *string);
|
||||
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
|
||||
std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX");
|
||||
std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
|
||||
bool check_file_exists(std::string filename, bool is_exec = false);
|
||||
bool is_absolute_path(std::string filename);
|
||||
void remove_directory(std::string dirname);
|
||||
|
||||
template<typename T> int GetSize(const T &obj) { return obj.size(); }
|
||||
int GetSize(RTLIL::Wire *wire);
|
||||
|
||||
extern int autoidx;
|
||||
extern int yosys_xtrace;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
@ -103,15 +227,19 @@ YOSYS_NAMESPACE_END
|
|||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
using RTLIL::State;
|
||||
|
||||
namespace hashlib {
|
||||
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
|
||||
}
|
||||
|
||||
void yosys_setup();
|
||||
void yosys_shutdown();
|
||||
|
||||
#ifdef YOSYS_ENABLE_TCL
|
||||
#include <tcl.h>
|
||||
Tcl_Interp *yosys_get_tcl_interp();
|
||||
#endif
|
||||
|
||||
extern int autoidx;
|
||||
extern RTLIL::Design *yosys_design;
|
||||
|
||||
RTLIL::IdString new_id(std::string file, int line, std::string func);
|
||||
|
@ -127,9 +255,10 @@ std::string proc_self_dirname();
|
|||
std::string proc_share_dirname();
|
||||
const char *create_prompt(RTLIL::Design *design, int recursion_counter);
|
||||
|
||||
void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label);
|
||||
void run_pass(std::string command, RTLIL::Design *design);
|
||||
void run_backend(std::string filename, std::string command, RTLIL::Design *design);
|
||||
void run_pass(std::string command, RTLIL::Design *design = nullptr);
|
||||
void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr);
|
||||
void run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
|
||||
void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
|
||||
void shell(RTLIL::Design *design);
|
||||
|
||||
// from kernel/version_*.o (cc source generated from Makefile)
|
||||
|
|
|
@ -27,7 +27,10 @@
|
|||
#include <stdint.h>
|
||||
#include <csignal>
|
||||
#include <cinttypes>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../minisat/Solver.h"
|
||||
#include "../minisat/SimpSolver.h"
|
||||
|
@ -37,8 +40,8 @@ ezMiniSAT::ezMiniSAT() : minisatSolver(NULL)
|
|||
minisatSolver = NULL;
|
||||
foundContradiction = false;
|
||||
|
||||
freeze(TRUE);
|
||||
freeze(FALSE);
|
||||
freeze(CONST_TRUE);
|
||||
freeze(CONST_FALSE);
|
||||
}
|
||||
|
||||
ezMiniSAT::~ezMiniSAT()
|
||||
|
@ -77,6 +80,7 @@ bool ezMiniSAT::eliminated(int idx)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
ezMiniSAT *ezMiniSAT::alarmHandlerThis = NULL;
|
||||
clock_t ezMiniSAT::alarmHandlerTimeout = 0;
|
||||
|
||||
|
@ -88,6 +92,7 @@ void ezMiniSAT::alarmHandler(int)
|
|||
} else
|
||||
alarm(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ezMiniSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
|
||||
{
|
||||
|
@ -174,6 +179,7 @@ contradiction:
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
struct sigaction sig_action;
|
||||
struct sigaction old_sig_action;
|
||||
int old_alarm_timeout = 0;
|
||||
|
@ -188,9 +194,11 @@ contradiction:
|
|||
sigaction(SIGALRM, &sig_action, &old_sig_action);
|
||||
alarm(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool foundSolution = minisatSolver->solve(assumps);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (solverTimeout > 0) {
|
||||
if (alarmHandlerTimeout == 0)
|
||||
solverTimoutStatus = true;
|
||||
|
@ -198,6 +206,7 @@ contradiction:
|
|||
sigaction(SIGALRM, &old_sig_action, NULL);
|
||||
alarm(old_alarm_timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!foundSolution) {
|
||||
#if !EZMINISAT_INCREMENTAL
|
||||
|
|
|
@ -51,9 +51,11 @@ private:
|
|||
std::set<int> cnfFrozenVars;
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
static ezMiniSAT *alarmHandlerThis;
|
||||
static clock_t alarmHandlerTimeout;
|
||||
static void alarmHandler(int);
|
||||
#endif
|
||||
|
||||
public:
|
||||
ezMiniSAT();
|
||||
|
|
|
@ -22,14 +22,28 @@
|
|||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
const int ezSAT::TRUE = 1;
|
||||
const int ezSAT::FALSE = 2;
|
||||
const int ezSAT::CONST_TRUE = 1;
|
||||
const int ezSAT::CONST_FALSE = 2;
|
||||
|
||||
static std::string my_int_to_string(int i)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
char buffer[64];
|
||||
snprintf(buffer, 64, "%d", i);
|
||||
return buffer;
|
||||
#else
|
||||
return std::to_string(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
ezSAT::ezSAT()
|
||||
{
|
||||
statehash = 5381;
|
||||
|
||||
flag_keep_cnf = false;
|
||||
flag_non_incremental = false;
|
||||
|
||||
|
@ -42,20 +56,25 @@ ezSAT::ezSAT()
|
|||
solverTimeout = 0;
|
||||
solverTimoutStatus = false;
|
||||
|
||||
literal("TRUE");
|
||||
literal("FALSE");
|
||||
literal("CONST_TRUE");
|
||||
literal("CONST_FALSE");
|
||||
|
||||
assert(literal("TRUE") == TRUE);
|
||||
assert(literal("FALSE") == FALSE);
|
||||
assert(literal("CONST_TRUE") == CONST_TRUE);
|
||||
assert(literal("CONST_FALSE") == CONST_FALSE);
|
||||
}
|
||||
|
||||
ezSAT::~ezSAT()
|
||||
{
|
||||
}
|
||||
|
||||
void ezSAT::addhash(unsigned int h)
|
||||
{
|
||||
statehash = ((statehash << 5) + statehash) ^ h;
|
||||
}
|
||||
|
||||
int ezSAT::value(bool val)
|
||||
{
|
||||
return val ? TRUE : FALSE;
|
||||
return val ? CONST_TRUE : CONST_FALSE;
|
||||
}
|
||||
|
||||
int ezSAT::literal()
|
||||
|
@ -101,15 +120,21 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
|
|||
myArgs.reserve(args.size());
|
||||
bool xorRemovedOddTrues = false;
|
||||
|
||||
addhash(__LINE__);
|
||||
addhash(op);
|
||||
|
||||
for (auto arg : args)
|
||||
{
|
||||
addhash(__LINE__);
|
||||
addhash(arg);
|
||||
|
||||
if (arg == 0)
|
||||
continue;
|
||||
if (op == OpAnd && arg == TRUE)
|
||||
if (op == OpAnd && arg == CONST_TRUE)
|
||||
continue;
|
||||
if ((op == OpOr || op == OpXor) && arg == FALSE)
|
||||
if ((op == OpOr || op == OpXor) && arg == CONST_FALSE)
|
||||
continue;
|
||||
if (op == OpXor && arg == TRUE) {
|
||||
if (op == OpXor && arg == CONST_TRUE) {
|
||||
xorRemovedOddTrues = !xorRemovedOddTrues;
|
||||
continue;
|
||||
}
|
||||
|
@ -131,29 +156,29 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
|
|||
{
|
||||
case OpNot:
|
||||
assert(myArgs.size() == 1);
|
||||
if (myArgs[0] == TRUE)
|
||||
return FALSE;
|
||||
if (myArgs[0] == FALSE)
|
||||
return TRUE;
|
||||
if (myArgs[0] == CONST_TRUE)
|
||||
return CONST_FALSE;
|
||||
if (myArgs[0] == CONST_FALSE)
|
||||
return CONST_TRUE;
|
||||
break;
|
||||
|
||||
case OpAnd:
|
||||
if (myArgs.size() == 0)
|
||||
return TRUE;
|
||||
return CONST_TRUE;
|
||||
if (myArgs.size() == 1)
|
||||
return myArgs[0];
|
||||
break;
|
||||
|
||||
case OpOr:
|
||||
if (myArgs.size() == 0)
|
||||
return FALSE;
|
||||
return CONST_FALSE;
|
||||
if (myArgs.size() == 1)
|
||||
return myArgs[0];
|
||||
break;
|
||||
|
||||
case OpXor:
|
||||
if (myArgs.size() == 0)
|
||||
return xorRemovedOddTrues ? TRUE : FALSE;
|
||||
return xorRemovedOddTrues ? CONST_TRUE : CONST_FALSE;
|
||||
if (myArgs.size() == 1)
|
||||
return xorRemovedOddTrues ? NOT(myArgs[0]) : myArgs[0];
|
||||
break;
|
||||
|
@ -161,15 +186,15 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
|
|||
case OpIFF:
|
||||
assert(myArgs.size() >= 1);
|
||||
if (myArgs.size() == 1)
|
||||
return TRUE;
|
||||
return CONST_TRUE;
|
||||
// FIXME: Add proper const folding
|
||||
break;
|
||||
|
||||
case OpITE:
|
||||
assert(myArgs.size() == 3);
|
||||
if (myArgs[0] == TRUE)
|
||||
if (myArgs[0] == CONST_TRUE)
|
||||
return myArgs[1];
|
||||
if (myArgs[0] == FALSE)
|
||||
if (myArgs[0] == CONST_FALSE)
|
||||
return myArgs[2];
|
||||
break;
|
||||
|
||||
|
@ -183,12 +208,18 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
|
|||
if (expressionsCache.count(myExpr) > 0) {
|
||||
id = expressionsCache.at(myExpr);
|
||||
} else {
|
||||
id = -(expressions.size() + 1);
|
||||
id = -(int(expressions.size()) + 1);
|
||||
expressionsCache[myExpr] = id;
|
||||
expressions.push_back(myExpr);
|
||||
}
|
||||
|
||||
return xorRemovedOddTrues ? NOT(id) : id;
|
||||
if (xorRemovedOddTrues)
|
||||
id = NOT(id);
|
||||
|
||||
addhash(__LINE__);
|
||||
addhash(id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void ezSAT::lookup_literal(int id, std::string &name) const
|
||||
|
@ -281,7 +312,7 @@ std::string ezSAT::to_string(int id) const
|
|||
int ezSAT::eval(int id, const std::vector<int> &values) const
|
||||
{
|
||||
if (id > 0) {
|
||||
if (id <= int(values.size()) && (values[id-1] == TRUE || values[id-1] == FALSE || values[id-1] == 0))
|
||||
if (id <= int(values.size()) && (values[id-1] == CONST_TRUE || values[id-1] == CONST_FALSE || values[id-1] == 0))
|
||||
return values[id-1];
|
||||
return 0;
|
||||
}
|
||||
|
@ -295,39 +326,39 @@ int ezSAT::eval(int id, const std::vector<int> &values) const
|
|||
case OpNot:
|
||||
assert(args.size() == 1);
|
||||
a = eval(args[0], values);
|
||||
if (a == TRUE)
|
||||
return FALSE;
|
||||
if (a == FALSE)
|
||||
return TRUE;
|
||||
if (a == CONST_TRUE)
|
||||
return CONST_FALSE;
|
||||
if (a == CONST_FALSE)
|
||||
return CONST_TRUE;
|
||||
return 0;
|
||||
case OpAnd:
|
||||
a = TRUE;
|
||||
a = CONST_TRUE;
|
||||
for (auto arg : args) {
|
||||
b = eval(arg, values);
|
||||
if (b != TRUE && b != FALSE)
|
||||
if (b != CONST_TRUE && b != CONST_FALSE)
|
||||
a = 0;
|
||||
if (b == FALSE)
|
||||
return FALSE;
|
||||
if (b == CONST_FALSE)
|
||||
return CONST_FALSE;
|
||||
}
|
||||
return a;
|
||||
case OpOr:
|
||||
a = FALSE;
|
||||
a = CONST_FALSE;
|
||||
for (auto arg : args) {
|
||||
b = eval(arg, values);
|
||||
if (b != TRUE && b != FALSE)
|
||||
if (b != CONST_TRUE && b != CONST_FALSE)
|
||||
a = 0;
|
||||
if (b == TRUE)
|
||||
return TRUE;
|
||||
if (b == CONST_TRUE)
|
||||
return CONST_TRUE;
|
||||
}
|
||||
return a;
|
||||
case OpXor:
|
||||
a = FALSE;
|
||||
a = CONST_FALSE;
|
||||
for (auto arg : args) {
|
||||
b = eval(arg, values);
|
||||
if (b != TRUE && b != FALSE)
|
||||
if (b != CONST_TRUE && b != CONST_FALSE)
|
||||
return 0;
|
||||
if (b == TRUE)
|
||||
a = a == TRUE ? FALSE : TRUE;
|
||||
if (b == CONST_TRUE)
|
||||
a = a == CONST_TRUE ? CONST_FALSE : CONST_TRUE;
|
||||
}
|
||||
return a;
|
||||
case OpIFF:
|
||||
|
@ -335,18 +366,18 @@ int ezSAT::eval(int id, const std::vector<int> &values) const
|
|||
a = eval(args[0], values);
|
||||
for (auto arg : args) {
|
||||
b = eval(arg, values);
|
||||
if (b != TRUE && b != FALSE)
|
||||
if (b != CONST_TRUE && b != CONST_FALSE)
|
||||
return 0;
|
||||
if (b != a)
|
||||
return FALSE;
|
||||
return CONST_FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
return CONST_TRUE;
|
||||
case OpITE:
|
||||
assert(args.size() == 3);
|
||||
a = eval(args[0], values);
|
||||
if (a == TRUE)
|
||||
if (a == CONST_TRUE)
|
||||
return eval(args[1], values);
|
||||
if (a == FALSE)
|
||||
if (a == CONST_FALSE)
|
||||
return eval(args[2], values);
|
||||
return 0;
|
||||
default:
|
||||
|
@ -375,6 +406,9 @@ bool ezSAT::eliminated(int)
|
|||
|
||||
void ezSAT::assume(int id)
|
||||
{
|
||||
addhash(__LINE__);
|
||||
addhash(id);
|
||||
|
||||
if (id < 0)
|
||||
{
|
||||
assert(0 < -id && -id <= int(expressions.size()));
|
||||
|
@ -417,6 +451,10 @@ void ezSAT::assume(int id)
|
|||
|
||||
void ezSAT::add_clause(const std::vector<int> &args)
|
||||
{
|
||||
addhash(__LINE__);
|
||||
for (auto arg : args)
|
||||
addhash(arg);
|
||||
|
||||
cnfClauses.push_back(args);
|
||||
cnfClausesCount++;
|
||||
}
|
||||
|
@ -490,13 +528,13 @@ int ezSAT::bound(int id) const
|
|||
|
||||
std::string ezSAT::cnfLiteralInfo(int idx) const
|
||||
{
|
||||
for (size_t i = 0; i < cnfLiteralVariables.size(); i++) {
|
||||
for (int i = 0; i < int(cnfLiteralVariables.size()); i++) {
|
||||
if (cnfLiteralVariables[i] == idx)
|
||||
return to_string(i+1);
|
||||
if (cnfLiteralVariables[i] == -idx)
|
||||
return "NOT " + to_string(i+1);
|
||||
}
|
||||
for (size_t i = 0; i < cnfExpressionVariables.size(); i++) {
|
||||
for (int i = 0; i < int(cnfExpressionVariables.size()); i++) {
|
||||
if (cnfExpressionVariables[i] == idx)
|
||||
return to_string(-i-1);
|
||||
if (cnfExpressionVariables[i] == -idx)
|
||||
|
@ -507,6 +545,10 @@ std::string ezSAT::cnfLiteralInfo(int idx) const
|
|||
|
||||
int ezSAT::bind(int id, bool auto_freeze)
|
||||
{
|
||||
addhash(__LINE__);
|
||||
addhash(id);
|
||||
addhash(auto_freeze);
|
||||
|
||||
if (id >= 0) {
|
||||
assert(0 < id && id <= int(literals.size()));
|
||||
cnfLiteralVariables.resize(literals.size());
|
||||
|
@ -516,9 +558,9 @@ int ezSAT::bind(int id, bool auto_freeze)
|
|||
}
|
||||
if (cnfLiteralVariables[id-1] == 0) {
|
||||
cnfLiteralVariables[id-1] = ++cnfVariableCount;
|
||||
if (id == TRUE)
|
||||
if (id == CONST_TRUE)
|
||||
add_clause(+cnfLiteralVariables[id-1]);
|
||||
if (id == FALSE)
|
||||
if (id == CONST_FALSE)
|
||||
add_clause(-cnfLiteralVariables[id-1]);
|
||||
}
|
||||
return cnfLiteralVariables[id-1];
|
||||
|
@ -549,10 +591,13 @@ int ezSAT::bind(int id, bool auto_freeze)
|
|||
while (args.size() > 1) {
|
||||
std::vector<int> newArgs;
|
||||
for (int i = 0; i < int(args.size()); i += 2)
|
||||
if (i+1 == int(args.size()))
|
||||
if (i+1 == int(args.size())) {
|
||||
newArgs.push_back(args[i]);
|
||||
else
|
||||
newArgs.push_back(OR(AND(args[i], NOT(args[i+1])), AND(NOT(args[i]), args[i+1])));
|
||||
} else {
|
||||
int sub1 = AND(args[i], NOT(args[i+1]));
|
||||
int sub2 = AND(NOT(args[i]), args[i+1]);
|
||||
newArgs.push_back(OR(sub1, sub2));
|
||||
}
|
||||
args.swap(newArgs);
|
||||
}
|
||||
idx = bind(args.at(0), false);
|
||||
|
@ -563,12 +608,16 @@ int ezSAT::bind(int id, bool auto_freeze)
|
|||
std::vector<int> invArgs;
|
||||
for (auto arg : args)
|
||||
invArgs.push_back(NOT(arg));
|
||||
idx = bind(OR(expression(OpAnd, args), expression(OpAnd, invArgs)), false);
|
||||
int sub1 = expression(OpAnd, args);
|
||||
int sub2 = expression(OpAnd, invArgs);
|
||||
idx = bind(OR(sub1, sub2), false);
|
||||
goto assign_idx;
|
||||
}
|
||||
|
||||
if (op == OpITE) {
|
||||
idx = bind(OR(AND(args[0], args[1]), AND(NOT(args[0]), args[2])), false);
|
||||
int sub1 = AND(args[0], args[1]);
|
||||
int sub2 = AND(NOT(args[0]), args[2]);
|
||||
idx = bind(OR(sub1, sub2), false);
|
||||
goto assign_idx;
|
||||
}
|
||||
|
||||
|
@ -638,7 +687,7 @@ std::vector<int> ezSAT::vec_const(const std::vector<bool> &bits)
|
|||
{
|
||||
std::vector<int> vec;
|
||||
for (auto bit : bits)
|
||||
vec.push_back(bit ? TRUE : FALSE);
|
||||
vec.push_back(bit ? CONST_TRUE : CONST_FALSE);
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
@ -646,7 +695,7 @@ std::vector<int> ezSAT::vec_const_signed(int64_t value, int numBits)
|
|||
{
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i < numBits; i++)
|
||||
vec.push_back(((value >> i) & 1) != 0 ? TRUE : FALSE);
|
||||
vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE);
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
@ -654,7 +703,7 @@ std::vector<int> ezSAT::vec_const_unsigned(uint64_t value, int numBits)
|
|||
{
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i < numBits; i++)
|
||||
vec.push_back(((value >> i) & 1) != 0 ? TRUE : FALSE);
|
||||
vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE);
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
@ -669,8 +718,9 @@ std::vector<int> ezSAT::vec_var(int numBits)
|
|||
std::vector<int> ezSAT::vec_var(std::string name, int numBits)
|
||||
{
|
||||
std::vector<int> vec;
|
||||
for (int i = 0; i < numBits; i++)
|
||||
vec.push_back(VAR(name + "[" + std::to_string(i) + "]"));
|
||||
for (int i = 0; i < numBits; i++) {
|
||||
vec.push_back(VAR(name + my_int_to_string(i)));
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
@ -679,7 +729,7 @@ std::vector<int> ezSAT::vec_cast(const std::vector<int> &vec1, int toBits, bool
|
|||
std::vector<int> vec;
|
||||
for (int i = 0; i < toBits; i++)
|
||||
if (i >= int(vec1.size()))
|
||||
vec.push_back(signExtend ? vec1.back() : FALSE);
|
||||
vec.push_back(signExtend ? vec1.back() : CONST_FALSE);
|
||||
else
|
||||
vec.push_back(vec1[i]);
|
||||
return vec;
|
||||
|
@ -807,7 +857,7 @@ std::vector<int> ezSAT::vec_add(const std::vector<int> &vec1, const std::vector<
|
|||
{
|
||||
assert(vec1.size() == vec2.size());
|
||||
std::vector<int> vec(vec1.size());
|
||||
int carry = FALSE;
|
||||
int carry = CONST_FALSE;
|
||||
for (int i = 0; i < int(vec1.size()); i++)
|
||||
fulladder(this, vec1[i], vec2[i], carry, carry, vec[i]);
|
||||
|
||||
|
@ -831,7 +881,7 @@ std::vector<int> ezSAT::vec_sub(const std::vector<int> &vec1, const std::vector<
|
|||
{
|
||||
assert(vec1.size() == vec2.size());
|
||||
std::vector<int> vec(vec1.size());
|
||||
int carry = TRUE;
|
||||
int carry = CONST_TRUE;
|
||||
for (int i = 0; i < int(vec1.size()); i++)
|
||||
fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, vec[i]);
|
||||
|
||||
|
@ -853,15 +903,15 @@ std::vector<int> ezSAT::vec_sub(const std::vector<int> &vec1, const std::vector<
|
|||
|
||||
std::vector<int> ezSAT::vec_neg(const std::vector<int> &vec)
|
||||
{
|
||||
std::vector<int> zero(vec.size(), FALSE);
|
||||
std::vector<int> zero(vec.size(), CONST_FALSE);
|
||||
return vec_sub(zero, vec);
|
||||
}
|
||||
|
||||
void ezSAT::vec_cmp(const std::vector<int> &vec1, const std::vector<int> &vec2, int &carry, int &overflow, int &sign, int &zero)
|
||||
{
|
||||
assert(vec1.size() == vec2.size());
|
||||
carry = TRUE;
|
||||
zero = FALSE;
|
||||
carry = CONST_TRUE;
|
||||
zero = CONST_FALSE;
|
||||
for (int i = 0; i < int(vec1.size()); i++) {
|
||||
overflow = carry;
|
||||
fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, sign);
|
||||
|
@ -954,11 +1004,11 @@ std::vector<int> ezSAT::vec_shl(const std::vector<int> &vec1, int shift, bool si
|
|||
for (int i = 0; i < int(vec1.size()); i++) {
|
||||
int j = i-shift;
|
||||
if (int(vec1.size()) <= j)
|
||||
vec.push_back(signExtend ? vec1.back() : FALSE);
|
||||
vec.push_back(signExtend ? vec1.back() : CONST_FALSE);
|
||||
else if (0 <= j)
|
||||
vec.push_back(vec1[j]);
|
||||
else
|
||||
vec.push_back(FALSE);
|
||||
vec.push_back(CONST_FALSE);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
@ -1005,10 +1055,10 @@ std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std:
|
|||
int vec2_bits = std::min(my_clog2(vec1.size()) + (vec2_signed ? 1 : 0), int(vec2.size()));
|
||||
|
||||
std::vector<int> overflow_bits(vec2.begin() + vec2_bits, vec2.end());
|
||||
int overflow_left = FALSE, overflow_right = FALSE;
|
||||
int overflow_left = CONST_FALSE, overflow_right = CONST_FALSE;
|
||||
|
||||
if (vec2_signed) {
|
||||
int overflow = FALSE;
|
||||
int overflow = CONST_FALSE;
|
||||
for (auto bit : overflow_bits)
|
||||
overflow = OR(overflow, XOR(bit, vec2[vec2_bits-1]));
|
||||
overflow_left = AND(overflow, NOT(vec2.back()));
|
||||
|
@ -1046,7 +1096,7 @@ std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std:
|
|||
std::vector<int> ezSAT::vec_shift_left(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right)
|
||||
{
|
||||
// vec2_signed is not implemented in vec_shift_left() yet
|
||||
assert(vec2_signed == false);
|
||||
if (vec2_signed) assert(vec2_signed == false);
|
||||
|
||||
int vec2_bits = std::min(my_clog2(vec1.size()), int(vec2.size()));
|
||||
|
||||
|
@ -1105,7 +1155,7 @@ int64_t ezSAT::vec_model_get_signed(const std::vector<int> &modelExpressions, co
|
|||
for (int i = 0; i < 64; i++) {
|
||||
int j = i < int(vec1.size()) ? i : vec1.size()-1;
|
||||
if (modelMap.at(vec1[j]))
|
||||
value |= 1 << i;
|
||||
value |= int64_t(1) << i;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -1119,7 +1169,7 @@ uint64_t ezSAT::vec_model_get_unsigned(const std::vector<int> &modelExpressions,
|
|||
modelMap[modelExpressions[i]] = modelValues[i];
|
||||
for (int i = 0; i < int(vec1.size()); i++)
|
||||
if (modelMap.at(vec1[i]))
|
||||
value |= 1 << i;
|
||||
value |= uint64_t(1) << i;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -1195,7 +1245,7 @@ void ezSAT::printDIMACS(FILE *f, bool verbose) const
|
|||
fprintf(f, "c mapping of variables to expressions:\n");
|
||||
for (int i = 0; i < int(cnfExpressionVariables.size()); i++)
|
||||
if (cnfExpressionVariables[i] != 0)
|
||||
fprintf(f, "c %*d: %s\n", digits, cnfExpressionVariables[i], to_string(-i-1).c_str());
|
||||
fprintf(f, "c %*d: %d\n", digits, cnfExpressionVariables[i], -i-1);
|
||||
|
||||
if (mode_keep_cnf()) {
|
||||
fprintf(f, "c\n");
|
||||
|
@ -1243,7 +1293,7 @@ static std::string expression2str(const std::pair<ezSAT::OpId, std::vector<int>>
|
|||
}
|
||||
text += ":";
|
||||
for (auto it : data.second)
|
||||
text += " " + std::to_string(it);
|
||||
text += " " + my_int_to_string(it);
|
||||
return text;
|
||||
}
|
||||
|
||||
|
@ -1330,7 +1380,7 @@ int ezSAT::manyhot(const std::vector<int> &vec, int min_hot, int max_hot)
|
|||
|
||||
for (int i = -1; i < N; i++)
|
||||
for (int j = -1; j < M; j++)
|
||||
x[std::pair<int,int>(i,j)] = j < 0 ? TRUE : i < 0 ? FALSE : literal();
|
||||
x[std::pair<int,int>(i,j)] = j < 0 ? CONST_TRUE : i < 0 ? CONST_FALSE : literal();
|
||||
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < M; j++) {
|
||||
|
@ -1358,7 +1408,7 @@ int ezSAT::manyhot(const std::vector<int> &vec, int min_hot, int max_hot)
|
|||
int ezSAT::ordered(const std::vector<int> &vec1, const std::vector<int> &vec2, bool allow_equal)
|
||||
{
|
||||
std::vector<int> formula;
|
||||
int last_x = FALSE;
|
||||
int last_x = CONST_FALSE;
|
||||
|
||||
assert(vec1.size() == vec2.size());
|
||||
for (size_t i = 0; i < vec1.size(); i++)
|
||||
|
@ -1366,7 +1416,7 @@ int ezSAT::ordered(const std::vector<int> &vec1, const std::vector<int> &vec2, b
|
|||
int a = vec1[i], b = vec2[i];
|
||||
formula.push_back(OR(NOT(a), b, last_x));
|
||||
|
||||
int next_x = i+1 < vec1.size() ? literal() : allow_equal ? FALSE : TRUE;
|
||||
int next_x = i+1 < vec1.size() ? literal() : allow_equal ? CONST_FALSE : CONST_TRUE;
|
||||
formula.push_back(OR(a, b, last_x, NOT(next_x)));
|
||||
formula.push_back(OR(NOT(a), NOT(b), last_x, NOT(next_x)));
|
||||
last_x = next_x;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class ezSAT
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ class ezSAT
|
|||
// the number zero is not used as valid token number and is used to encode
|
||||
// unused parameters for the functions.
|
||||
//
|
||||
// positive numbers are literals, with 1 = TRUE and 2 = FALSE;
|
||||
// positive numbers are literals, with 1 = CONST_TRUE and 2 = CONST_FALSE;
|
||||
//
|
||||
// negative numbers are non-literal expressions. each expression is represented
|
||||
// by an operator id and a list of expressions (literals or non-literals).
|
||||
|
@ -44,8 +45,8 @@ public:
|
|||
OpNot, OpAnd, OpOr, OpXor, OpIFF, OpITE
|
||||
};
|
||||
|
||||
static const int TRUE;
|
||||
static const int FALSE;
|
||||
static const int CONST_TRUE;
|
||||
static const int CONST_FALSE;
|
||||
|
||||
private:
|
||||
bool flag_keep_cnf;
|
||||
|
@ -82,6 +83,9 @@ public:
|
|||
ezSAT();
|
||||
virtual ~ezSAT();
|
||||
|
||||
unsigned int statehash;
|
||||
void addhash(unsigned int);
|
||||
|
||||
void keep_cnf() { flag_keep_cnf = true; }
|
||||
void non_incremental() { flag_non_incremental = true; }
|
||||
|
||||
|
@ -159,6 +163,7 @@ public:
|
|||
virtual void freeze(int id);
|
||||
virtual bool eliminated(int idx);
|
||||
void assume(int id);
|
||||
void assume(int id, int context_id) { assume(OR(id, NOT(context_id))); }
|
||||
int bind(int id, bool auto_freeze = true);
|
||||
int bound(int id) const;
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
-- Bruce Guenter <bruce@untroubled.org>
|
||||
Translation to simpler C++ Code
|
||||
-- Volker Grabsch <vog@notjusthosting.com>
|
||||
Fixing bugs and improving style
|
||||
-- Eugene Hopkinson <slowriot at voxelstorm dot com>
|
||||
*/
|
||||
|
||||
#include "sha1.h"
|
||||
|
@ -52,7 +54,7 @@ void SHA1::update(std::istream &is)
|
|||
|
||||
while (is)
|
||||
{
|
||||
uint32 block[BLOCK_INTS];
|
||||
uint32_t block[BLOCK_INTS];
|
||||
buffer_to_block(buffer, block);
|
||||
transform(block);
|
||||
read(is, buffer, BLOCK_BYTES);
|
||||
|
@ -67,7 +69,7 @@ void SHA1::update(std::istream &is)
|
|||
std::string SHA1::final()
|
||||
{
|
||||
/* Total number of hashed bits */
|
||||
uint64 total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
|
||||
uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
|
||||
|
||||
/* Padding */
|
||||
buffer += 0x80;
|
||||
|
@ -77,7 +79,7 @@ std::string SHA1::final()
|
|||
buffer += (char)0x00;
|
||||
}
|
||||
|
||||
uint32 block[BLOCK_INTS];
|
||||
uint32_t block[BLOCK_INTS];
|
||||
buffer_to_block(buffer, block);
|
||||
|
||||
if (orig_size > BLOCK_BYTES - 8)
|
||||
|
@ -89,7 +91,7 @@ std::string SHA1::final()
|
|||
}
|
||||
}
|
||||
|
||||
/* Append total_bits, split this uint64 into two uint32 */
|
||||
/* Append total_bits, split this uint64_t into two uint32_t */
|
||||
block[BLOCK_INTS - 1] = total_bits;
|
||||
block[BLOCK_INTS - 2] = (total_bits >> 32);
|
||||
transform(block);
|
||||
|
@ -137,14 +139,14 @@ void SHA1::reset()
|
|||
* Hash a single 512-bit block. This is the core of the algorithm.
|
||||
*/
|
||||
|
||||
void SHA1::transform(uint32 block[BLOCK_BYTES])
|
||||
void SHA1::transform(uint32_t block[BLOCK_BYTES])
|
||||
{
|
||||
/* Copy digest[] to working vars */
|
||||
uint32 a = digest[0];
|
||||
uint32 b = digest[1];
|
||||
uint32 c = digest[2];
|
||||
uint32 d = digest[3];
|
||||
uint32 e = digest[4];
|
||||
uint32_t a = digest[0];
|
||||
uint32_t b = digest[1];
|
||||
uint32_t c = digest[2];
|
||||
uint32_t d = digest[3];
|
||||
uint32_t e = digest[4];
|
||||
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
|
@ -241,9 +243,9 @@ void SHA1::transform(uint32 block[BLOCK_BYTES])
|
|||
}
|
||||
|
||||
|
||||
void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
|
||||
void SHA1::buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS])
|
||||
{
|
||||
/* Convert the std::string (byte buffer) to a uint32 array (MSB) */
|
||||
/* Convert the std::string (byte buffer) to a uint32_t array (MSB) */
|
||||
for (unsigned int i = 0; i < BLOCK_INTS; i++)
|
||||
{
|
||||
block[i] = (buffer[4*i+3] & 0xff)
|
||||
|
@ -254,11 +256,14 @@ void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
|
|||
}
|
||||
|
||||
|
||||
void SHA1::read(std::istream &is, std::string &s, int max)
|
||||
void SHA1::read(std::istream &is, std::string &s, size_t max)
|
||||
{
|
||||
char sbuf[max];
|
||||
char* sbuf = new char[max];
|
||||
|
||||
is.read(sbuf, max);
|
||||
s.assign(sbuf, is.gcount());
|
||||
|
||||
delete[] sbuf;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
-- Bruce Guenter <bruce@untroubled.org>
|
||||
Translation to simpler C++ Code
|
||||
-- Volker Grabsch <vog@notjusthosting.com>
|
||||
Fixing bugs and improving style
|
||||
-- Eugene Hopkinson <slowriot at voxelstorm dot com>
|
||||
*/
|
||||
|
||||
#ifndef SHA1_HPP
|
||||
|
@ -21,6 +23,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
class SHA1
|
||||
{
|
||||
|
@ -32,22 +35,19 @@ public:
|
|||
static std::string from_file(const std::string &filename);
|
||||
|
||||
private:
|
||||
typedef unsigned long int uint32; /* just needs to be at least 32bit */
|
||||
typedef unsigned long long uint64; /* just needs to be at least 64bit */
|
||||
|
||||
static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
|
||||
static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
|
||||
static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
|
||||
|
||||
uint32 digest[DIGEST_INTS];
|
||||
uint32_t digest[DIGEST_INTS];
|
||||
std::string buffer;
|
||||
uint64 transforms;
|
||||
uint64_t transforms;
|
||||
|
||||
void reset();
|
||||
void transform(uint32 block[BLOCK_BYTES]);
|
||||
void transform(uint32_t block[BLOCK_BYTES]);
|
||||
|
||||
static void buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES]);
|
||||
static void read(std::istream &is, std::string &s, int max);
|
||||
static void read(std::istream &is, std::string &s, size_t max);
|
||||
static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]);
|
||||
};
|
||||
|
||||
std::string sha1(const std::string &string);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
using namespace SubCircuit;
|
||||
|
||||
#ifndef _YOSYS_
|
||||
static std::string my_stringf(const char *fmt, ...)
|
||||
{
|
||||
std::string string;
|
||||
|
@ -52,6 +53,9 @@ static std::string my_stringf(const char *fmt, ...)
|
|||
|
||||
return string;
|
||||
}
|
||||
#else
|
||||
# define my_stringf YOSYS_NAMESPACE_PREFIX stringf
|
||||
#endif
|
||||
|
||||
SubCircuit::Graph::Graph(const Graph &other, const std::vector<std::string> &otherNodes)
|
||||
{
|
||||
|
|
|
@ -61,7 +61,7 @@ to easily create complex designs from small HDL code. It is the preferred
|
|||
method of design entry for many designers\footnote{The other half prefers VHDL,
|
||||
a very different but -- of course -- equally powerful language.}.
|
||||
|
||||
The Berkeley Logic Interchange Format (BLIF) is a simple file format for
|
||||
The Berkeley Logic Interchange Format (BLIF) \cite{blif} is a simple file format for
|
||||
exchanging sequential logic between programs. It is easy to generate and
|
||||
easy to parse and is therefore the preferred method of design entry for
|
||||
many authors of logic synthesis tools.
|
||||
|
@ -456,6 +456,10 @@ Conor Santifort. Amber ARM-compatible core. \\
|
|||
Berkeley Logic Synthesis and Verification Group. ABC: A System for Sequential Synthesis and Verification. \\
|
||||
\url{http://www.eecs.berkeley.edu/~alanmi/abc/}
|
||||
|
||||
\bibitem{blif}
|
||||
Berkeley Logic Interchange Format (BLIF) \\
|
||||
\url{http://vlsi.colorado.edu/~vis/blif.ps}
|
||||
|
||||
\end{thebibliography}
|
||||
|
||||
|
||||
|
|
|
@ -31,4 +31,4 @@ n5:e -> c11:p7:w [color="black", label=""];
|
|||
n6:e -> x0:s0:w [color="black", label=""];
|
||||
n6:e -> x1:s0:w [color="black", label=""];
|
||||
n6:e -> x2:s0:w [color="black", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,4 +20,4 @@ n5:e -> c12:p8:w [color="black", label=""];
|
|||
c15:p10:e -> n6:w [color="black", label=""];
|
||||
c14:p10:e -> n7:w [color="black", label=""];
|
||||
n7:e -> c15:p9:w [color="black", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,4 +20,4 @@ n7:e -> p1:w [color="black", label=""];
|
|||
p1:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
|
||||
n8:e -> p1:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v0:e -> c14:p9:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -30,4 +30,4 @@ n8:e -> c21:p19:w [color="black", label=""];
|
|||
n8:e -> x1:w:w [color="black", label=""];
|
||||
n9:e -> c18:p15:w [color="black", label=""];
|
||||
v0:e -> c21:p11:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,4 +17,4 @@ n5:e -> c17:p16:w [color="black", label=""];
|
|||
n6:e -> c15:p12:w [color="black", label=""];
|
||||
c15:p14:e -> n7:w [color="black", style="setlinewidth(3)", label=""];
|
||||
n7:e -> c17:p8:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,4 +8,4 @@ c4 [ shape=record, label="{{<p1> A|<p2> B}|$2\n$add|{<p3> Y}}" ];
|
|||
v0:e -> c4:p1:w [color="black", label=""];
|
||||
v1:e -> c4:p2:w [color="black", label=""];
|
||||
c4:p3:e -> v2:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -135,4 +135,4 @@ v6:e -> c47:p34:w [color="black", label=""];
|
|||
v7:e -> c48:p33:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v8:e -> c49:p33:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v9:e -> c50:p33:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,4 +26,4 @@ v0:e -> c13:p11:w [color="black", label=""];
|
|||
v1:e -> c14:p11:w [color="black", label=""];
|
||||
v2:e -> c15:p11:w [color="black", label=""];
|
||||
v3:e -> c19:p16:w [color="black", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -36,4 +36,4 @@ x1:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
|
|||
x3:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
|
||||
x3:s1:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
|
||||
x6:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -42,4 +42,4 @@ c21:p8:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
|
|||
n8:e -> c20:p8:w [color="black", style="setlinewidth(3)", label=""];
|
||||
c21:p9:e -> n9:w [color="black", style="setlinewidth(3)", label=""];
|
||||
n9:e -> c20:p9:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -84,4 +84,4 @@ v4:e -> c35:p24:w [color="black", style="setlinewidth(3)", label=""];
|
|||
v5:e -> c36:p24:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v6:e -> c37:p24:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v7:e -> c38:p24:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -30,4 +30,4 @@ n8:e -> c17:p12:w [color="black", style="setlinewidth(3)", label=""];
|
|||
n9:e -> x0:s0:w [color="black", label=""];
|
||||
n9:e -> x1:s0:w [color="black", label=""];
|
||||
n9:e -> x2:s0:w [color="black", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,4 +23,4 @@ x1:s1:e -> n5:w [color="black", style="setlinewidth(3)", label=""];
|
|||
n6:e -> x2:s1:w [color="black", style="setlinewidth(3)", label=""];
|
||||
n7:e -> x2:s0:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v0:e -> c13:p8:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,4 +15,4 @@ c4:p3:e -> v2:w [color="black", style="setlinewidth(3)", label=""];
|
|||
v3:e -> c5:p1:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v4:e -> c5:p2:w [color="black", style="setlinewidth(3)", label=""];
|
||||
c5:p3:e -> v5:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@ n2:e -> c9:p6:w [color="black", style="setlinewidth(3)", label=""];
|
|||
n3:e -> c9:p7:w [color="black", style="setlinewidth(3)", label=""];
|
||||
n4:e -> c10:p7:w [color="black", style="setlinewidth(3)", label=""];
|
||||
c10:p8:e -> n5:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@ digraph "sumprod" {
|
|||
rankdir="LR";
|
||||
remincross=true;
|
||||
n1 [ shape=octagon, label="prod", color="black", fontcolor="black" ];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,4 +8,4 @@ c5 [ shape=record, label="{{<p2> A|<p3> B}|$4\n$mul|{<p4> Y}}" ];
|
|||
c5:p4:e -> n1:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v0:e -> c5:p2:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v1:e -> c5:p3:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,4 +8,4 @@ n1 [ shape=diamond, label="$3_Y" ];
|
|||
n1:e -> c7:p4:w [color="black", style="setlinewidth(3)", label=""];
|
||||
n2:e -> c7:p5:w [color="black", style="setlinewidth(3)", label=""];
|
||||
c7:p6:e -> n3:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@ n2:e -> c8:p5:w [color="black", style="setlinewidth(3)", label=""];
|
|||
c8:p6:e -> n3:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v0:e -> c7:p4:w [color="black", style="setlinewidth(3)", label=""];
|
||||
v1:e -> c7:p5:w [color="black", style="setlinewidth(3)", label=""];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,11 +2,24 @@
|
|||
\chapter{Application Notes}
|
||||
\label{chapter:appnotes}
|
||||
|
||||
\begin{fixme}
|
||||
This appendix will cover some typical use-cases of Yosys in the form of application notes.
|
||||
\end{fixme}
|
||||
% \begin{fixme}
|
||||
% This appendix will cover some typical use-cases of Yosys in the form of application notes.
|
||||
% \end{fixme}
|
||||
%
|
||||
% \section{Synthesizing using a Cell Library in Liberty Format}
|
||||
% \section{Reverse Engeneering the MOS6502 from an NMOS Transistor Netlist}
|
||||
% \section{Reconfigurable Coarse-Grain Synthesis using Intersynth}
|
||||
|
||||
\section{Synthesizing using a Cell Library in Liberty Format}
|
||||
\section{Reverse Engeneering the MOS6502 from an NMOS Transistor Netlist}
|
||||
\section{Reconfigurable Coarse-Grain Synthesis using Intersynth}
|
||||
This appendix contains copies of the Yosys application notes.
|
||||
|
||||
\begin{itemize}
|
||||
\item Yosys AppNote 010: Converting Verilog to BLIF \dotfill Page \pageref{app:010} \hskip2cm\null
|
||||
\item Yosys AppNote 011: Interactive Design Investigation \dotfill Page \pageref{app:011} \hskip2cm\null
|
||||
\end{itemize}
|
||||
|
||||
\eject\label{app:010}
|
||||
\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_010_Verilog_to_BLIF.pdf}
|
||||
|
||||
\eject\label{app:011}
|
||||
\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_011_Design_Investigation.pdf}
|
||||
|
||||
|
|
|
@ -17,3 +17,9 @@ The {\tt yosys-filterlib} tool is a small utility that can be used to strip
|
|||
or extract information from a Liberty file. See Sec.~\ref{sec:techmap_extern}
|
||||
for details.
|
||||
|
||||
\section{yosys-abc}
|
||||
|
||||
This is a unmodified copy of ABC \citeweblink{ABC}. Not all versions of Yosys
|
||||
work with all versions of ABC. So Yosys comes with its own yosys-abc to avoid
|
||||
compatibility issues between the two.
|
||||
|
||||
|
|
|
@ -357,7 +357,7 @@ Add a brief description of the {\tt \$fsm} cell type.
|
|||
For gate level logic networks, fixed function single bit cells are used that do
|
||||
not provide any parameters.
|
||||
|
||||
Simulation models for these cells can be found in the file {\tt techlibs/common/stdcells\_sim.v} in the Yosys
|
||||
Simulation models for these cells can be found in the file {\tt techlibs/common/simcells.v} in the Yosys
|
||||
source tree.
|
||||
|
||||
\begin{table}[t]
|
||||
|
@ -417,7 +417,7 @@ pass. The combinatorial logic cells can be mapped to physical cells from a Liber
|
|||
using the {\tt abc} pass.
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$assert} cells.
|
||||
Add information about {\tt \$assert}, {\tt \$assume}, and {\tt \$equiv} cells.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
|
@ -428,6 +428,14 @@ Add information about {\tt \$slice} and {\tt \$concat} cells.
|
|||
Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cells.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$dffe}, {\tt \$dffsr}, {\tt \$dlatch}, and {\tt \$dlatchsr} cells.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
|
||||
\end{fixme}
|
||||
|
|
|
@ -2,16 +2,21 @@
|
|||
\chapter{Programming Yosys Extensions}
|
||||
\label{chapter:prog}
|
||||
|
||||
\begin{fixme}
|
||||
This chapter will contain a guided tour to the Yosys APIs and conclude
|
||||
with an example module.
|
||||
\end{fixme}
|
||||
This chapter contains some bits and pieces of information about programming
|
||||
yosys extensions. Also consult the section on programming in the ``Yosys
|
||||
Presentation'' (can be downloaded from the Yosys website as PDF) and don't
|
||||
be afraid to ask questions on the Yosys Subreddit.
|
||||
|
||||
\section{Programming with RTLIL}
|
||||
\section{Internal Utility Libraries}
|
||||
\section{Loadable Modules}
|
||||
\section{The ``CodingReadme'' File}
|
||||
|
||||
The following is an excerpt of the {\tt CodingReadme} file from the Yosys source tree.
|
||||
|
||||
\lstinputlisting[title=CodingReadme,rangeprefix=--,rangesuffix=--,includerangemarker=false,linerange=snip-snap,numbers=left,frame=single]{../CodingReadme}
|
||||
|
||||
\section{The ``stubsnets'' Example Module}
|
||||
|
||||
The following is the complete code of the ``stubsnets'' example module. It is included in the Yosys source distribution as {\tt manual/CHAPTER\_Prog/stubnets.cc}.
|
||||
|
||||
\section{Example Module}
|
||||
|
||||
\lstinputlisting[title=stubnets.cc,numbers=left,frame=single,language=C++]{CHAPTER_Prog/stubnets.cc}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
stubnets.so
|
||||
stubnets.d
|
||||
*.log
|
|
@ -5,15 +5,16 @@
|
|||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/log.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
// this function is called for each module in the design
|
||||
static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool report_bits)
|
||||
{
|
||||
|
@ -62,7 +63,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
|
|||
|
||||
// for each bit (unless it is a constant):
|
||||
// check if it is used at least two times and add to stub_bits otherwise
|
||||
for (int i = 0; i < SIZE(sig); i++)
|
||||
for (int i = 0; i < GetSize(sig); i++)
|
||||
if (sig[i].wire != NULL && (bit_usage_count[sig[i]] + usage_offset) < 2)
|
||||
stub_bits.insert(i);
|
||||
|
||||
|
@ -72,7 +73,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
|
|||
|
||||
// report stub bits and/or stub wires, don't report single bits
|
||||
// if called with report_bits set to false.
|
||||
if (SIZE(stub_bits) == SIZE(sig)) {
|
||||
if (GetSize(stub_bits) == GetSize(sig)) {
|
||||
log(" found stub wire: %s\n", RTLIL::id2cstr(wire->name));
|
||||
} else {
|
||||
if (!report_bits)
|
||||
|
@ -126,3 +127,4 @@ struct StubnetsPass : public Pass {
|
|||
}
|
||||
} StubnetsPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -790,7 +790,7 @@ Unwrap in {\tt test2}:
|
|||
|
||||
\hfil\begin{tikzpicture}
|
||||
\node at (0,0) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2d.pdf}};
|
||||
\node at (0,-4) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2e.pdf}};
|
||||
\node at (0,-4) {\includegraphics[width=8cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2e.pdf}};
|
||||
\node at (1,-1.7) {\begin{lstlisting}[linewidth=5.5cm, frame=single, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
|
||||
techmap -map macc_xilinx_unwrap_map.v ;;
|
||||
\end{lstlisting}};
|
||||
|
|
|
@ -13,7 +13,7 @@ module axis_master(aclk, aresetn, tvalid, tready, tdata);
|
|||
if (tvalid && tready)
|
||||
tvalid <= 0;
|
||||
if (!tvalid || !tready) begin
|
||||
// ^- should be not inverted!
|
||||
// ^- should not be inverted!
|
||||
state = state ^ state << 13;
|
||||
state = state ^ state >> 7;
|
||||
state = state ^ state << 17;
|
||||
|
|
|
@ -268,7 +268,7 @@ memory -nomap; techmap -map my_memory_map.v; memory_map
|
|||
\end{frame}
|
||||
|
||||
\begin{frame}[t, fragile]{\subsecname{} -- Example 1/2}
|
||||
\vbox to 0cm{\includegraphics[width=\linewidth,trim=0cm 0cm 0cm -10cm]{PRESENTATION_ExSyn/memory_01.pdf}\vss}
|
||||
\vbox to 0cm{\includegraphics[width=0.7\linewidth,trim=0cm 0cm 0cm -10cm]{PRESENTATION_ExSyn/memory_01.pdf}\vss}
|
||||
\vskip-1cm
|
||||
\begin{columns}
|
||||
\column[t]{5cm}
|
||||
|
@ -455,7 +455,7 @@ read_verilog -D WITH_MULT cpu_alu.v
|
|||
hierarchy -check -top cpu_top
|
||||
|
||||
# high-level synthesis
|
||||
proc; opt; memory -nomap;; fsm; opt
|
||||
proc; opt; fsm;; memory -nomap; opt
|
||||
|
||||
# substitute block rams
|
||||
techmap -map map_rams.v
|
||||
|
@ -497,7 +497,7 @@ the next part (Section 3, ``Advanced Synthesis'') of this presentation.}
|
|||
\item Yosys provides commands for each phase of the synthesis.
|
||||
\item Each command solves a (more or less) simple problem.
|
||||
\item Complex commands are often only front-ends to simple commands.
|
||||
\item {\tt proc; opt; memory; opt; fsm; opt; techmap; opt; abc;;}
|
||||
\item {\tt proc; opt; fsm; opt; memory; opt; techmap; opt; abc;;}
|
||||
\end{itemize}
|
||||
|
||||
\bigskip
|
||||
|
|
|
@ -277,7 +277,7 @@ Direct link to the files: \\ \footnotesize
|
|||
|
||||
\medskip
|
||||
{\color{YosysGreen}\# the high-level stuff}\\
|
||||
\boxalert<3>{proc}; \boxalert<4>{opt}; \boxalert<5>{memory}; \boxalert<6>{opt}; \boxalert<7>{fsm}; \boxalert<8>{opt}
|
||||
\boxalert<3>{proc}; \boxalert<4>{opt}; \boxalert<5>{fsm}; \boxalert<6>{opt}; \boxalert<7>{memory}; \boxalert<8>{opt}
|
||||
|
||||
\medskip
|
||||
{\color{YosysGreen}\# mapping to internal cell library}\\
|
||||
|
@ -308,9 +308,9 @@ Direct link to the files: \\ \footnotesize
|
|||
\only<2>{hierarchy -check -top counter}%
|
||||
\only<3>{proc}%
|
||||
\only<4>{opt}%
|
||||
\only<5>{memory}%
|
||||
\only<5>{fsm}%
|
||||
\only<6>{opt}%
|
||||
\only<7>{fsm}%
|
||||
\only<7>{memory}%
|
||||
\only<8>{opt}%
|
||||
\only<9>{techmap}%
|
||||
\only<10>{opt}%
|
||||
|
@ -333,13 +333,13 @@ Direct link to the files: \\ \footnotesize
|
|||
Perform some basic optimizations and cleanups.
|
||||
}%
|
||||
\only<5>{
|
||||
Analyze memories and create circuits to implement them.
|
||||
Analyze and optimize finite state machines.
|
||||
}%
|
||||
\only<6>{
|
||||
Perform some basic optimizations and cleanups.
|
||||
}%
|
||||
\only<7>{
|
||||
Analyze and optimize finite state machines.
|
||||
Analyze memories and create circuits to implement them.
|
||||
}%
|
||||
\only<8>{
|
||||
Perform some basic optimizations and cleanups.
|
||||
|
@ -398,7 +398,7 @@ hierarchy -check -top counter
|
|||
|
||||
\begin{frame}[t, fragile]{\subsecname{} -- Step 2/4}
|
||||
\begin{verbatim}
|
||||
proc; opt; memory; opt; fsm; opt
|
||||
proc; opt; fsm; opt; memory; opt
|
||||
\end{verbatim}
|
||||
|
||||
\vfill
|
||||
|
@ -411,7 +411,7 @@ techmap; opt
|
|||
\end{verbatim}
|
||||
|
||||
\vfill
|
||||
\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_Intro/counter_02.pdf}
|
||||
\includegraphics[width=\linewidth,trim=0 0cm 0 2cm]{PRESENTATION_Intro/counter_02.pdf}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[t, fragile]{\subsecname{} -- Step 4/4}
|
||||
|
@ -427,6 +427,48 @@ clean
|
|||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\subsection{The synth command}
|
||||
|
||||
\begin{frame}[fragile]{\subsecname{}}
|
||||
Yosys contains a default (recommended example) synthesis script in form of the
|
||||
{\tt synth} command. The following commands are executed by this synthesis command:
|
||||
|
||||
\begin{columns}
|
||||
\column[t]{5cm}
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
|
||||
begin:
|
||||
hierarchy -check [-top <top>]
|
||||
|
||||
coarse:
|
||||
proc
|
||||
opt
|
||||
wreduce
|
||||
alumacc
|
||||
share
|
||||
opt
|
||||
fsm
|
||||
opt -fast
|
||||
memory -nomap
|
||||
opt_clean
|
||||
\end{lstlisting}
|
||||
\column[t]{5cm}
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
|
||||
fine:
|
||||
opt -fast -full
|
||||
memory_map
|
||||
opt -full
|
||||
techmap
|
||||
opt -fast
|
||||
|
||||
abc:
|
||||
abc -fast
|
||||
opt -fast
|
||||
\end{lstlisting}
|
||||
\end{columns}
|
||||
\end{frame}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\subsection{Yosys Commands}
|
||||
|
||||
\begin{frame}[fragile]{\subsecname{} 1/3 \hspace{0pt plus 1 filll} (excerpt)}
|
||||
|
@ -500,6 +542,7 @@ Commands for writing the results:
|
|||
\bigskip
|
||||
Script-Commands for standard synthesis tasks:
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
|
||||
synth # generic synthesis script
|
||||
synth_xilinx # synthesis for Xilinx FPGAs
|
||||
\end{lstlisting}
|
||||
|
||||
|
@ -603,12 +646,8 @@ endmodule
|
|||
|
||||
\begin{frame}{\subsecname}
|
||||
\begin{itemize}
|
||||
\item Multi-dimensional arrays (memories)
|
||||
\item Writing to arrays using bit- and part-selects (todo for 0.4.0)
|
||||
\item The wor/wand wire types (maybe for 0.4.0)
|
||||
\item Tri-state logic
|
||||
|
||||
\bigskip
|
||||
\item The wor/wand wire types (maybe for 0.5)
|
||||
\item Latched logic (is synthesized as logic with feedback loops)
|
||||
\item Some non-synthesizable features that should be ignored in synthesis are not supported by the parser and cause a parser error (file a bug report if you encounter this problem)
|
||||
\end{itemize}
|
||||
|
@ -813,10 +852,12 @@ control logic because it is simpler than setting up a commercial flow.
|
|||
\item When building on other Linux distributions:
|
||||
\begin{itemize}
|
||||
\item Needs compiler with some C++11 support
|
||||
\item See README file for build instructions
|
||||
\item Post to the subreddit if you get stuck
|
||||
\end{itemize}
|
||||
\item Ported to OS X (Darwin) and OpenBSD
|
||||
\item No win32 support (yet)
|
||||
\item Native win32 build with VisualStudio
|
||||
\item Cross win32 build with MXE
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
|
|
|
@ -89,12 +89,13 @@ left with a much simpler version of RTLIL:
|
|||
\bigskip
|
||||
Many commands simply choose to only work on this simpler version:
|
||||
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
|
||||
if (module->processes.size() != 0 || module->memories.size() != 0)
|
||||
log_error("This command does not operate on modules with processes "
|
||||
"and/or memories! Run 'proc' and 'memory' first.\n");
|
||||
for (RTLIL::Module *module : design->selected_modules() {
|
||||
if (module->has_memories_warn() || module->has_processes_warn())
|
||||
continue;
|
||||
....
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\bigskip
|
||||
For simplicity we only discuss this version of RTLIL in this presentation.
|
||||
\end{frame}
|
||||
|
||||
|
@ -122,8 +123,9 @@ has been executed.
|
|||
\subsection{The RTLIL Data Structures}
|
||||
|
||||
\begin{frame}{\subsecname}
|
||||
The RTLIL data structures are simple structs utilizing C++ {\tt std::}
|
||||
containers.
|
||||
The RTLIL data structures are simple structs utilizing {\tt pool<>} and
|
||||
{\tt dict<>} containers (drop-in replacementments for {\tt
|
||||
std::unordered\_set<>} and {\tt std::unordered\_map<>}).
|
||||
|
||||
\bigskip
|
||||
\begin{itemize}
|
||||
|
@ -145,7 +147,9 @@ See {\tt yosys/kernel/rtlil.h} for details.
|
|||
\subsubsection{RTLIL::IdString}
|
||||
|
||||
\begin{frame}{\subsubsecname}{}
|
||||
{\tt RTLIL::IdString} is a simple wrapper for {\tt std::string}. It is used for names of RTLIL objects.
|
||||
{\tt RTLIL::IdString} in many ways behave like a {\tt std::string}. It is used
|
||||
for names of RTLIL objects. Internally a RTLIL::IdString object is only a
|
||||
single integer.
|
||||
|
||||
\medskip
|
||||
The first character of a {\tt RTLIL::IdString} specifies if the name is {\it public\/} or {\it private\/}:
|
||||
|
@ -168,25 +172,25 @@ Use the {\tt NEW\_ID} macro to create a new unique private name.
|
|||
|
||||
\begin{frame}[t, fragile]{\subsubsecname}
|
||||
The {\tt RTLIL::Design} and {\tt RTLIL::Module} structs are the top-level RTLIL
|
||||
data structures.
|
||||
|
||||
Yosys always operates on one active design, but can hold many designs in memory.
|
||||
data structures. Yosys always operates on one active design, but can hold many designs in memory.
|
||||
|
||||
\bigskip
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
|
||||
struct RTLIL::Design {
|
||||
std::map<RTLIL::IdString, RTLIL::Module*> modules;
|
||||
dict<RTLIL::IdString, RTLIL::Module*> modules_;
|
||||
...
|
||||
};
|
||||
|
||||
struct RTLIL::Module {
|
||||
RTLIL::IdString name;
|
||||
std::map<RTLIL::IdString, RTLIL::Wire*> wires;
|
||||
std::map<RTLIL::IdString, RTLIL::Cell*> cells;
|
||||
std::vector<RTLIL::SigSig> connections;
|
||||
dict<RTLIL::IdString, RTLIL::Wire*> wires_;
|
||||
dict<RTLIL::IdString, RTLIL::Cell*> cells_;
|
||||
std::vector<RTLIL::SigSig> connections_;
|
||||
...
|
||||
};
|
||||
\end{lstlisting}
|
||||
|
||||
(Use the various accessor functions instead of directly working with the {\tt *\_} members.)
|
||||
\end{frame}
|
||||
|
||||
\subsubsection{The RTLIL::Wire Structure}
|
||||
|
@ -251,21 +255,22 @@ constants are part of the RTLIL representation itself.
|
|||
|
||||
\begin{frame}[t, fragile]{\subsubsecname}
|
||||
The {\tt RTLIL::SigSpec} struct represents a signal vector. Each bit can either be a bit from a wire
|
||||
or a constant value. Consecutive bits from a wire or consecutive constant bits are consolidated into
|
||||
a {\tt RTLIL::SigChunk}:
|
||||
or a constant value.
|
||||
|
||||
\bigskip
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
|
||||
struct RTLIL::SigChunk {
|
||||
struct RTLIL::SigBit
|
||||
{
|
||||
RTLIL::Wire *wire;
|
||||
RTLIL::Const data; // only used if wire == NULL
|
||||
int width, offset;
|
||||
union {
|
||||
RTLIL::State data; // used if wire == NULL
|
||||
int offset; // used if wire != NULL
|
||||
};
|
||||
...
|
||||
};
|
||||
|
||||
struct RTLIL::SigSpec {
|
||||
std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
|
||||
int width;
|
||||
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
|
||||
...
|
||||
};
|
||||
\end{lstlisting}
|
||||
|
@ -289,8 +294,8 @@ instances:
|
|||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
|
||||
struct RTLIL::Cell {
|
||||
RTLIL::IdString name, type;
|
||||
std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
|
||||
std::map<RTLIL::IdString, RTLIL::Const> parameters;
|
||||
dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
|
||||
dict<RTLIL::IdString, RTLIL::Const> parameters;
|
||||
...
|
||||
};
|
||||
\end{lstlisting}
|
||||
|
@ -345,7 +350,7 @@ typedef std::pair<RTLIL::SigSpec, RTLIL::SigSpec> RTLIL::SigSig;
|
|||
|
||||
struct RTLIL::Module {
|
||||
...
|
||||
std::vector<RTLIL::SigSig> connections;
|
||||
std::vector<RTLIL::SigSig> connections_;
|
||||
...
|
||||
};
|
||||
\end{lstlisting}
|
||||
|
@ -354,8 +359,8 @@ struct RTLIL::Module {
|
|||
{\tt RTLIL::SigSig::first} is the driven signal and {\tt RTLIL::SigSig::second} is the driving signal.
|
||||
Example usage (setting wire {\tt foo} to value {\tt 42}):
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
|
||||
module->connections.push_back(RTLIL::SigSig(module->wires.at("\\foo"),
|
||||
RTLIL::SigSpec(42, module->wires.at("\\foo")->width)));
|
||||
module->connect(module->wire("\\foo"),
|
||||
RTLIL::SigSpec(42, module->wire("\\foo")->width));
|
||||
\end{lstlisting}
|
||||
\end{frame}
|
||||
|
||||
|
@ -378,17 +383,19 @@ endmodule
|
|||
RTLIL::Module *module = new RTLIL::Module;
|
||||
module->name = "\\absval";
|
||||
|
||||
RTLIL::Wire *a = module->new_wire(4, "\\a");
|
||||
RTLIL::Wire *a = module->addWire("\\a", 4);
|
||||
a->port_input = true;
|
||||
a->port_id = 1;
|
||||
|
||||
RTLIL::Wire *y = module->new_wire(4, "\\y");
|
||||
RTLIL::Wire *y = module->addWire("\\y", 4);
|
||||
y->port_output = true;
|
||||
y->port_id = 2;
|
||||
|
||||
RTLIL::Wire *a_inv = module->new_wire(4, NEW_ID);
|
||||
RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4);
|
||||
module->addNeg(NEW_ID, a, a_inv, true);
|
||||
module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y);
|
||||
|
||||
module->fixup_ports();
|
||||
\end{lstlisting}
|
||||
\end{frame}
|
||||
|
||||
|
@ -431,8 +438,8 @@ In this case {\tt a}, {\tt x}, and {\tt y} are all different names for the same
|
|||
|
||||
\smallskip
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
|
||||
RTLIL::SigSpec a(module->wires.at("\\a")), x(module->wires.at("\\x")),
|
||||
y(module->wires.at("\\y"));
|
||||
RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")),
|
||||
y(module->wire("\\y"));
|
||||
log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
|
||||
\end{lstlisting}
|
||||
|
||||
|
@ -462,9 +469,9 @@ log("Mapped signal x: %s\n", log_signal(sigmap(x)));
|
|||
\end{lstlisting}
|
||||
|
||||
\medskip
|
||||
Use {\tt RTLIL::id2cstr()} to create a C-string for an {\tt RTLIL::IdString}:
|
||||
Use {\tt log\_id()} to create a C-string for an {\tt RTLIL::IdString}:
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
|
||||
log("Name of this module: %s\n", RTLIL::id2cstr(module->name));
|
||||
log("Name of this module: %s\n", log_id(module->name));
|
||||
\end{lstlisting}
|
||||
|
||||
\medskip
|
||||
|
@ -513,9 +520,8 @@ a new yosys command:
|
|||
|
||||
\bigskip
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/yosys.h"
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
struct MyPass : public Pass {
|
||||
MyPass() : Pass("my_cmd", "just a simple test") { }
|
||||
|
@ -526,9 +532,9 @@ struct MyPass : public Pass {
|
|||
log(" %s\n", arg.c_str());
|
||||
|
||||
log("Modules in current design:\n");
|
||||
for (auto &mod : design->modules)
|
||||
log(" %s (%zd wires, %zd cells)\n", RTLIL::id2cstr(mod.first),
|
||||
mod.second->wires.size(), mod.second->cells.size());
|
||||
for (auto mod : design->modules())
|
||||
log(" %s (%d wires, %d cells)\n", log_id(mod),
|
||||
GetSize(mod->wires), GetSize(mod->cells));
|
||||
}
|
||||
} MyPass;
|
||||
\end{lstlisting}
|
||||
|
@ -549,6 +555,12 @@ yosys-config --exec --cxx --cxxflags --ldflags \
|
|||
-o my_cmd.so -shared my_cmd.cc --ldlibs
|
||||
\end{lstlisting}
|
||||
|
||||
\bigskip
|
||||
Or shorter:
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
|
||||
yosys-config --build my_cmd.so my_cmd.cc
|
||||
\end{lstlisting}
|
||||
|
||||
\bigskip
|
||||
Load the plugin using the yosys {\tt -m} option:
|
||||
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
|
||||
|
@ -566,7 +578,7 @@ yosys -m ./my_cmd.so -p 'my_cmd foo bar'
|
|||
\item \dots and even simpler if you don't need RTLIL::Memory or RTLIL::Process objects.
|
||||
|
||||
\bigskip
|
||||
\item Writing synthesis software? Consider learning the Yosys API and make your stuff
|
||||
\item Writing synthesis software? Consider learning the Yosys API and make your work
|
||||
part of the Yosys framework.
|
||||
\end{itemize}
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
my_cmd.so
|
||||
my_cmd.d
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue