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 =============== Outline of a Yosys command -------------------------- 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") { } void execute(vector, Design*) override { 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 and pool as main container classes. dict is essentially a replacement for std::unordered_map and pool is a replacement for std::unordered_set. The main characteristics are: - dict and pool are about 2x faster than the std containers - references to elements in a dict or pool are invalidated by insert and remove operations (similar to std::vector 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 and pool will have the same order of iteration across all compilers, standard libraries and architectures. In addition to dict and pool there is also an idict that creates a bijective map from K to the integers. For example: idict 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. Finally mfp implements a merge-find set data structure (aka. disjoint-set or union-find) over the type K ("mfp" = merge-find-promote). 2. Standard STL data types In Yosys we use std::vector and std::string whenever applicable. When dict and pool are not suitable then std::map and std::set are used instead. The types std::vector and std::string are also available as vector 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::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_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: 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 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. Coding Style ============ Formatting of code ------------------ - Yosys code is using tabs for indentation. Tabs are 8 characters. - A continuation of a statement in the following line is indented by two additional tabs. - Lines are as long as you want them to be. A good rule of thumb is to break lines at about column 150. - Opening braces can be put on the same or next line as the statement opening the block (if, switch, for, while, do). Put the opening brace on its own line for larger blocks, especially blocks that contains blank lines. - Otherwise stick to the Linux Kernel Coding Style: https://www.kernel.org/doc/Documentation/CodingStyle C++ Language ------------- Yosys is written in C++11. At the moment only constructs supported by gcc 4.8 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 "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 Project [ ] 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 ======================================== Things to do right away: - Add to kernel/celltypes.h (incl. eval() handling for non-mem cells) - Add to InternalCellChecker::check() in kernel/rtlil.cc - Add to techlibs/common/simlib.v - Add to techlibs/common/techmap.v Things to do after finalizing the cell interface: - Add support to kernel/satgen.h for the new cell type - Add to manual/CHAPTER_CellLib.tex (or just add a fixme to the bottom) - Maybe add support to the Verilog backend for dumping such cells as expression Checklist for creating Yosys releases ===================================== Update the CHANGELOG file: cd ~yosys gitk & vi CHANGELOG 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 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/examples/cmos bash testbench.sh cd ~yosys/examples/basys3 bash run.sh 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 - follow instructions cd frontends/verific ../../yosys test_navre.ys Finally run all tests with "make config-{clang,gcc,gcc-4.8}": cd ~yosys make clean make test make ystests 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: - set YOSYS_VER to x.y.z in Makefile - remove "bumpversion" target from Makefile - update version string in CHANGELOG git commit -am "Yosys x.y.z" - push tag to github - post changelog on github - post short release note on reddit Updating the website: cd ~yosys make manual make install - update pdf files on the website cd ~yosys-web make update_cmd make update_show git commit -am update make push Cross-Building for Windows with MXE =================================== Check http://mxe.cc/#requirements and install all missing requirements. As root (or other user with write access to /usr/local/src): cd /usr/local/src git clone https://github.com/mxe/mxe.git cd mxe make -j$(nproc) MXE_PLUGIN_DIRS="plugins/tcl.tk" \ MXE_TARGETS="i686-w64-mingw32.static" \ gcc tcl readline Then as regular user in some directory where you build stuff: git clone https://github.com/cliffordwolf/yosys.git yosys-win32 cd yosys-win32 make config-mxe make -j$(nproc) mxebin How to add unit test ==================== Unit test brings some advantages, briefly, we can list some of them (reference [1](https://en.wikipedia.org/wiki/Unit_testing)): * Tests reduce bugs in new features; * Tests reduce bugs in existing features; * Tests are good documentation; * Tests reduce the cost of change; * Tests allow refactoring; With those advantages in mind, it was required to choose a framework which fits well with C/C++ code. Hence, it was chosen (google test) [https://github.com/google/googletest], because it is largely used and it is relatively easy learn. Install and configure google test (manually) -------------------------------------------- In this section, you will see a brief description of how to install google test. However, it is strongly recommended that you take a look to the official repository (https://github.com/google/googletest) and refers to that if you have any problem to install it. Follow the steps below: * Install: cmake and pthread * Clone google test project from: https://github.com/google/googletest and enter in the project directory * Inside project directory, type: ``` cmake -DBUILD_SHARED_LIBS=ON . make ``` * After compilation, copy all "*.so" inside directory "googlemock" and "googlemock/gtest" to "/usr/lib/" * Done! Now you can compile your tests. If you have any problem, go to the official repository to find help. Ps.: Some distros already have googletest packed. If your distro supports it, you can use it instead of compile. Create new unit test -------------------- If you want to add new unit tests for Yosys, just follow the steps below: * Go to directory "yosys/test/unit/" * In this directory you can find something similar Yosys's directory structure. To create your unit test file you have to follow this pattern: fileNameToImplementUnitTest + Test.cc. E.g.: if you want to implement the unit test for kernel/celledges.cc, you will need to create a file like this: tests/unit/kernel/celledgesTest.cc; * Implement your unit test Run unit test ------------- To compile and run all unit tests, just go to yosys root directory and type: ``` make unit-test ``` If you want to remove all unit test files, type: ``` make clean-unit-test ```