One of my favourites in the standard library: numeric_limits. Sometimes, you want to initialize a number to something really big. Some code just uses magic numbers, but the proper way is to use numeric_limits<T>::max(), which does exactly what you expect.
Right, the reset gets optimized away. Since it’s forbidden to read a member from a deleted object, the compiler assumes that the member p can never be read again, and removes the write. Only with optimization disabled do we have the expected behaviour.
Morality: C++ is hard and workarounds rarely work as you would expect them to.
In the electronic industry, there is one common denominator to all the tools and all the teams. Whether we are doing ASIC design, programming FPGAs or formally verifying chips, there is one thing we all use in our software: it is the representation of the design, called the netlist.
The netlist is the representation of the connections of the design. Although it probably originated from physical design representations, it is now a common representation throughout the compiler, from the high-level code to the final physical layout.
This post is the first in a series on the netlist, to present the basic concepts. Next ones will go more in depth on the operations performed on a netlist, the APIs that are provided to access it, and the actual representation in a programming language.
What’s in a netlist
A netlist represents the connections between the components of a design. Here is what it looks like:
Let’s call the component “cells” and the connections “nets”. Each cell has an interface: each element of this interface is called a “port”. Note that everything has a name, and that the ports generally have a direction as well. For the computer scientists among us, this is a lot like a graph.
Now, imagine we reuse mod in another netlist. It might just be a cell among others. some of those cells may actually be complex components, containing other, smaller cells: this creates a hierarchy of nested cells, some of which may be reused.
For example, a toy CPU: core is defined once, but used twice, creating two “instances”, core1 and core2. Like in software design, reuse is encouraged: a “module” (core, ALU) will be instantiated several times (core1, core2, core1.ALU1, core1.ALU2…). This reuse is there to make the designers’ and tools’ jobs easier: once we create the chip, there will be one copy of core for each core1, core2….
We have seen that the netlist came from the physical design world, but at the same time its quirks are present in “high-level” languages like Verilog and VHDL.
The consequence is that a netlist is the go-to format for everyone working in EDA… but there are many different netlist representations. For example:
Netlists targeting physical design with representations of the actual wiring as polygons. Coriolis’ Hurricane is a good example
Netlists targeting logical optimization, with specialized bit-level representations. This is the case in ABC
Higher-level netlists for synthesis and verification, with high-level operators, like Yosys
Generic netlists, that provide a generic API without application-specific utilities, like GBL
Since they are central to all those tools, their design as a lot of impact. First, on the overall development of the tools: an easy-to-use API is a must. Second, on the performance, to process millions to billions of gates efficiently. But let’s keep those for the next post.