Libre Gates

A Libre VHDL framework for the static and dynamic analysis of mapped, gate-level circuits for FPGA and ASIC. Design For Test or nothing !

Similar projects worth following
As the project "VHDL library for gate-level verification" ( ) was progressing, more features and more abstraction were developed, such that libraries other than the ProASIC3 family could be implemented. ASIC libraries such as sxlib or wsclib are good candidates, and more will appear with the surge in DIY ASIC projects spurred by Google & Skywater.

This project brings its pure GHDL-driven code to more technologies, allowing users to check their circuit, verify BIST coverage and eventually generate test vectors with only a set of really Libre files in pure VHDL (thus avoiding expensive and restrictive license fees from niche proprietary vendors). Oh, did I mention how awesome GHDL is ? But you could use any simulator that is fully VHDL'93 compliant.

Import from, and export to other netlist formats are also in the air...

These files let you process VHDL files mapped to FPGA/ASIC gates, to:

  • Simulate the circuit
  • Perform static analysis of the netlist
  • Extract dynamic activity statistics
  • Verify that any internal state can be reached
  • Alter any boolean function, inject arbitrary errors and prove your BIST strategy
  • Extract logic traversal depth, detect unexpected logic chains and estimate speed/latency
  • Inspect logic cones
  • Ensure that the circuit is correctly initialised with the minimal amount of /RESET signals
  • Detect and break logic loops

Some day, it could be extended to

  • Pipeline a netlist and choose the appropriate strategy (will require detailed timing information)
  • Transcode/Transpile a netlist from one family/technology to another
  • Import/export to EDIF or others ?

The project started as #VHDL library for gate-level verification but the scope keeps extending and greatly surpasses the ProASIC3 domain. I also study the addition of the minimalist OSU FreePDK45. More unrelated libraries should be added in the near future, depending on applications : Skywater PDK and Alliance could follow. Contact me if you need something !


1. First upload
2. Second upload
3. Rewrite
4. More features ! (one day)
5. Another method to create the wrapper
6. inside out
7. OSU FreePDK45 and derivatives


copy from

gzip - 1.69 MB - 09/20/2020 at 18:38



Another interim : wrapper generator finally working ! but the VHDL side must be updated.

x-bzip-compressed-tar - 195.26 kB - 09/13/2020 at 00:44



interim release, not for normal use.

x-bzip-compressed-tar - 193.58 kB - 09/04/2020 at 23:21



moved directories around... no big deal but every step counts.

x-bzip-compressed-tar - 186.44 kB - 09/02/2020 at 20:10



First release - was to be VHDL library v2.10 but ... (don't bother the wrong month number)

x-compressed-tar - 201.40 kB - 09/01/2020 at 05:38


  • OSU FreePDK45 and derivatives

    Yann Guidon / YGDES09/20/2020 at 18:07 0 comments

    One easy library to add to the collection is OSU's FreePDK45, found at (direct download link : : only 1.7MB, mirroredhere)

    It's a good candidate because it's a really surprisingly tiny library : 33 cells only !

    FILL (no logic input or output)


    AND2X1 AND2X2 HAX1 NAND2X1 OR2X1 OR2X2 NOR2X1 XNOR2X1 XOR2X1 (2 inputs)

    AOI21X1 FAX1 MUX2X1 NAND3X1 NOR3X1 OAI21X1 (3 inputs)

    AOI22X1 OAI22X1 (4 inputs)


    This is close to the minimum described at but should be enough for basic circuits. In fact we have the 1st order and most of the 2nd order gates, which I covered in log 31. v2.9 : introducing 4-input gates. OAI211 and AOI211 are missing, which are very useful for incrementers and adders...

    The site also provides these same basic standard cells for AMI 0.6um, AMI 0.35um, TSMC 0.25um, and TSMC 0.18um released in 2005 at A single bundle packages 4 technologies ! The library seems to have evolved to reach v2.7 and included a LEON example project: (but the latest archive looks broken)

    I love how minimal, compact and simple these gates are, accessible to beginners and targeting from 45nm to .5µm. It looks like a "RISC" approach to VLSI ;-) Note also that there are only 2 gates with two output drives and 2 inputs : AND and OR, which are 2nd order gates, merging a NAND/NOR with a X1 or X2 inverter. The rest of the fanout issues are solved by inserting INVX gates at critical fanout points. This means that physical mapping/synthesis should start by examining the fanouts, inserting the inverters/buffers and then deducing which logic function to bubble-push.

    I'm not sure how to create the files but I can easily derive them from the A3P files in 3 ways:

    • Modify the file generator
    • Modify the generated files
    • Create a "wrapper" file

    Furthermore the sequential gates are not yet clear about the precedence of the inputs.

    Extracting the logical functions was as simple as a grep and some sed :

    grep -r '>Y=' * |sed 's/.*data//'|sed 's/<tr.*FFF//'|sed 's/<.*//'|sed 's/[.]html.*Y/: Y/'
    CLKBUF2: Y=A
    AND2X2: Y=(A&B)
    NAND3X1: Y=!(A&B&C)
    NOR3X1: Y=!(A|B|C)
    XOR2X1: Y=(A^B)
    BUFX4: Y=A
    MUX2X1: Y=!(S?(A:B))
    OR2X1: Y=(A|B)
    AND2X1: Y=(A&B)
    TBUFX2: Y=(EN?!A:'BZ)
    /INVX8: Y=!A
    /CLKBUF3: Y=A
    INVX1: Y=!A
    AOI21X1: Y=!((A&B)|C)
    XNOR2X1: Y=!(A^B)
    BUFX2: Y=A
    OAI22X1: Y=!((C|D)&(A|B))
    TBUFX1: Y=(EN?!A:'BZ)
    OR2X2: Y=(A|B)
    OAI21X1: Y=!((A|B)&C)
    NAND2X1: Y=!(A&B)
    AOI22X1: Y=!((C&D)|(A&B))
    CLKBUF1: Y=A
    NOR2X1: Y=!(A|B)
    INVX4: Y=!A
    INVX2: Y=!A

    For the VHDL version, only a few more simple substitutions are required:

    $ grep -r '>Y=' * |sed 's/.*data[/]/"/'|sed 's/<tr.*FFF//'|sed 's/<.*//'|sed 's/[.]html.*Y=/": /' |sed 's/[!]/not /g'  |sed 's/[|]/ or /g'  |sed 's/[&]/ and /g' |sed 's/\^/ xor /g' |sort
    "AND2X1": (A and B)
    "AND2X2": (A and B)
    "AOI21X1": not ((A and B) or C)
    "AOI22X1": not ((C and D) or (A and B))
    "BUFX2": A
    "BUFX4": A
    "CLKBUF1": A
    "CLKBUF2": A
    "CLKBUF3": A
    "INVX1": not A
    "INVX2": not A
    "INVX4": not A
    "INVX8": not A
    "MUX2X1": not (S?(A:B))
    "NAND2X1": not (A and B)
    "NAND3X1": not (A and B and C)
    "NOR2X1": not (A or B)
    "NOR3X1": not (A or B or C)
    "OAI21X1": not ((A or B) and C)
    "OAI22X1": not ((C or D) and (A or B))
    "OR2X1": (A or B)
    "OR2X2": (A or B)
    "TBUFX1": (EN?not A:'BZ)
    "TBUFX2": (EN?not A:'BZ)
    "XNOR2X1": not (A xor B)
    "XOR2X1": (A xor B)

    Notice that MUX2 should be called MUXI. Some other corner cases are easily translated by hand as well. The TBUFs however fall outside of the purely boolean realm...

    Some gates have 2 outputs :

    YC=A and B
    YS=A xor B
    Read more »

  • inside out

    Yann Guidon / YGDES09/14/2020 at 17:51 0 comments

    The log 5. Another method to create the wrapper has successfully implemented the automatic wrapper that I intended to design one year ago. This is a relief, even though for now it forces bit vectors to use the SLV package of wrapper types. This could be solved later and it's not a great problem because the units I test have a fixed size, genericity has gone out of the window since the netlists are synthesised.

    Now this forces me to re-architect the whole code because now the wrapper is the top level. The previous choice has been discussed in the log 24. Hierarchy problems and solutions and we're back to the initial version:

    The bash script now knows the size of the vectors and can also "plug" the generator or driver but the rest of the code must be turned upside down like a sock. I have to rewrite/restructure the code from scratch, but the modifications are minor.

    The new structure has the wrapper containing the "driver" so the wrapper has no I/O ports, which are replaced by internal signals. Another change is that the driver is made of procedures and functions and it would be weird to encapsulate them in another entity. A main procedure with in and out arguments would work better and reduce the semantic complexity : in VHDL a procedure can work like an entity so let's exploit this trick :-) And the procedure can be nicely packaged in a separate library.

    Some more typing and I get the following example out of the ALU:

    -- Wrapper.vhdl
    -- Generated on 20200915-07:57
    -- Do not modify
    Library ieee;
        use ieee.std_logic_1164.all;
    Library work;
        use work.all;
    Library LibreGates;
        use LibreGates.Gates_lib.all;
        use LibreGates.Netlist_lib.all;
    entity Wrapper is
      generic (
        WrapperWidthIn : integer := 22;
        WrapperWidthOut: integer := 17;
        main_delay : time := 1 sec;
        filename : string := ""; -- file of exclude vectors
        verbose : string := ""
    end Wrapper;
    architecture Wrap of Wrapper is
      signal VectIn : std_logic_vector(WrapperWidthIn -1 downto 0);
      signal VectOut: std_logic_vector(WrapperWidthOut-1 downto 0);
      signal VectClk: std_logic := 'X';
      -- force the registration of the gates.
      -- must be placed at the very beginning!
      update_select_gate( -- called only once at start
        0, -- show gate listing when < 1
       -1, -- no alteration
        2, -- probe mode
        verbose, filename);
      Drive_DUT(VectIn, VectOut, VectClk, main_delay);
      -- Finally we "wire" the unit to the ports:
      tb: entity alu8 port map (
        cin => VectIn(0),
        neg => VectIn(1),
        passmask => VectIn(2),
        orxor => VectIn(3),
        rop2mx => VectIn(4),
        cmps => VectIn(5),
        sri => VectIn(13 downto 6),
        snd => VectIn(21 downto 14),
        rop2 => VectOut(7 downto 0),
        sum => VectOut(15 downto 8),
        cout => VectOut(16));
    end Wrap; 

    The line use LibreGates.Gates_lib.all; is required because update_select_gate() is used. Drive_DUT() is defined is defined in the new package Netlist_lib where all the netlist management functions are moved, from Vectgen.vhdl which will soon be obsolete.
    So now all the "fun stuff" is going to happen in Netlist_lib.vhdl, in which the size of the vectors is very easy to get, with the 'LENGTH attribute:

    package body Netlist_lib is
      procedure Drive_DUT(
        signal VectIn :   out std_logic_vector;
        signal VectOut: in    std_logic_vector;
        signal VectClk: inout std_logic;
              Interval: in    time) is
        report   "VectIn: "  & integer'image(VectIn'length)
             & ", VectOut: " & integer'image(VectOut'length)
             & ", CLK: "     & std_logic'image(VectClk) ;
      end Drive_DUT;
    end Netlist_lib;

    There, it's solved. And I can even sense if the clock signal is connected, by setting it to 'X' or 'U' in the wrapper.

    Well no, it's not totally and definitively solved because it's a hack and it can't catch the std_logic_vectors. It works but it's not scalable.

    Unai did some code at for his project and there is hope that libghdl will be more and better used in the future. I didn't want to add more...

    Read more »

  • Another method to create the wrapper

    Yann Guidon / YGDES09/09/2020 at 23:12 0 comments

    For now I manually create the "wrapper" unit that maps the inputs and outputs to a pair of unified vectors.

    In private, Tristan told me there was some sort of Python thing that could do what I need but I'd rather avoid Python and experimental (like, less than 5 years old) features.

    But there could be another way to extract the inputs and outputs from the compiled design : with the trace dumps ! GTKwave knows the type and direction of each port so maybe I can parse the trace dump to extract the info I want.

    I'll have to test this ASAP, as I am currently contemplating how to make GetVectorsSize better.

    Trying to play with GHDL in the LibreGates/tests/test2_INC8 directory:

    > PA3="-P../../LibreGates -P../../LibreGates/proasic3"
    > ghdl -a $PA3 INC8_ASIC.vhdl
    > ghdl -e $PA3 INC8
    > ./inc8 --vcd=inc8.vcd
    > less inc8.vcd
      Sat Sep 12 05:18:00 2020
      GHDL v0
      1 fs
    $var reg 8 ! a[7:0] $end
    $var reg 8 " y[7:0] $end
    $var reg 1 # v $end
    $var reg 8 $ ab[7:0] $end
    $var reg 1 % a012 $end
    $var reg 1 & a012a $end
    $var reg 1 ' a012b $end
    $var reg 1 ( a34 $end
    $var reg 1 ) a345 $end
    $var reg 1 * a3456 $end
    $scope module (0) $end
    $scope module x4 $end
    $var reg 1 + a $end
    $var reg 1 , y $end
    $var reg 1 - t $end
    $scope module e $end


    I get a dump of signals but NO indication of type (which can only be assumed), direction or hierarchy...

    From the doc:

    "Currently, there is no way to select signals to be dumped: all signals are dumped, which can generate big files."

    There could be more hope with the ./inc8 --wave=inc8.ghw command but that would require more efforts because the dump is in binary, undocumented and subject to change...

    Another approach uses another underrated feature of GHDL :

    ghdl --file-to-xml $PA3  INC8_ASIC.vhdl

    The -a command is replaced here with --file-to-xml command which, as you can infer from the name, dumps a XML stream...

    Here we find the definitions of the ports. This is contained in the "port_chain" tag :

      <el kind="interface_signal_declaration" identifier="a" mode="in">
        <subtype_indication identifier="slv8"></subtype_indication>
      <el kind="interface_signal_declaration" identifier="y" mode="out">
        <subtype_indication identifier="slv8"></subtype_indication>
      <el kind="interface_signal_declaration" identifier="v" mode="out">
        <subtype_indication identifier="sl"></subtype_indication>

    I have removed a LOT of text to get only what is required.

    This allows the use of the wrapper types SLVx and SL, but now we need XML processing software to list and extract only the needed information...

    Well, this is where it's getting interesting : at first I'd thought that using the wrapping types would make thing harder but looking at the XML, it looks like a great way to simplify the parsing because the std_logic_vectors use a complex system to define the bounds. OTOH the type SLV8 makes a static statement about the type and size, which is not flexible or generics-configurable but much more direct to extract.

    Well, thanks to some unexpected hack found on StackOverflow, it seems that XML can be crudely parsed with some dirty-as-ever bash script.

    # LibreGates/
    # created sam. sept. 12 09:29:47 CEST 2020
    ReadTag () {
      IFS=\> read -d \< ENTITY
    GetAttribute () {      #input list in $1
      LIST=($ATTRIBUTES)   # split string into array
      for i in $(seq "${#LIST[@]}") ; do  # scan the list
        IFS='"' read -a ATTRIBUTE <<< "${LIST[$i]}"  # split the individual parameter in a sub-string
        #echo "  $ATTRIBUTE   -   ${ATTRIBUTE[1]}"
        if [[ $ATTRIBUTE = "$1" ]] ; then   # found the key
          echo -n "${ATTRIBUTE[1]}"         # return the value
    FlushPort () {
      if [[ "$PORT_TYPE" != "" ]] ; then
        case "$INOUT" in
          "in")  ;;
          "out") ;;
          *) echo "wrong port direction for signal $PORTNAME"
        echo "$PORTNAME $PORT_TYPE $INOUT...
    Read more »

  • More features ! (one day)

    Yann Guidon / YGDES09/08/2020 at 16:40 0 comments

    While replying to Pat in comments in I’m Sorry Dave, You Shouldn’t Write Verilog, I realised that this little library could perform more functions, in particular "auto-pipeline" (the automatic insertion of DFF in the middle of a circuit to increase its clock speed). This requires the new function that re-exports a (modified) netlist. And from there, it's "all the way down on the slippery slope", with the possibility to modify the netlist in whatever other ways we might desire (extract a logic cone, strip DFFs to de-pipeline, you name it). It would become like a sort of sed for netlists ;-)

    I don't think it will be hard to re-export a netlist, based on the depthlist. I'd love to visualise the graphs however !

    Another possible funny application would be "de-synthesising" because the PA3 files contain a symbolic/algebraic representation of the boolean function of each gate, in text format ! Just substitute the operands with the net name and you get source code. So, given a netlist of gates with 3 inputs each, finding the corresponding reverse boolean function/name is quite easy and the netlist can be decompiled into a higher-level description, that is easier to read. You don't even need to know the name of the gate or function, the 8 bits of the LUT are enough (as found in some EDIF dumps), and applying permutations to the inputs will compress the 256 cases down to the known non-degenerate cases. I don't know if/how that will be useful in practice but it opens the perspective to transcode a library into another (when I'll have integrated other libraries). Can you imagine being able to port a design to another technology with a simple run of a program and not bother with the gates naming ? This means you can start your design on whatever platform you like and not being locked into it.

  • Rewrite

    Yann Guidon / YGDES09/03/2020 at 16:17 0 comments

    As I try to integrate the Backwards component, I see no place where I could easily change a few lines of code to make it work (although the principle itself is quite simple, right ?). Instead I am facing a big plate of spaghetti, not with the code itself (which is rather good, thanks) but with the data structures that are interwoven and the naming that might not be reflecting the function (which has certainly evolved since their creation). Oh and I didn't log much about the internals, so that genius pile of code is hard to re-architect easily.

    Of course there are good and great things that I want to keep. However I see that my initial technique for netlist extraction is quite under-efficient in the case of large designs : it works for small systems but I'm evaluating how it will scale to much larger circuits and I face a O(n²) vs O(n×log(n)) problem. If I ever have one million gates, the setup phase will be ... loooong.

    So I have to redesign some parts. This affects only 2 files : VectGen.vhdl and Gates_lib.vhdl, but the data structure depend a lot on the algorithms and I'm going to significantly change the latter. I must re-engineer the former... And this time I must document them ! In essence, I must rewrite just after the first routine :

    -- the main sequence of VectGen.vhdl:
    GetVectorsSize; -- probing the inputs and outputs
    GetNetList;     -- actively probing the gates
    FixSinklist;    -- post-processing, no gate activity

    GetVectorsSize is alright so far (though it might be re-designed one day, but it's another story). GetNetList however is a big offender and needs a replacement, and the change in algorithm could lead to a change in data structures, that will affect the next procedures : FixSinklist and FixDepthList. This is where I can check for "zombies" and/or take Backwards into account. Changing GetNetList will probably lead to the redesign of FixSinklist and others as well...

    The basic idea is that of drivers and sinks, as anywhere. A net is all the connections between the driver and all the sinks, so the "net" is practically described by the driver (we don't play with tristates here). So a "netlist" is just a list of drivers, with sublists of respective sinks.

    But a complete digital circuit must have input ports and output ports, not just logic gates, so the main database is (as already described in 1. First upload):

    • A list of gates, each with one output and an array of inputs. The array is indexed with gates numbers >= 1
      Gates_lib.vhdl :
      type Gate_Desc_Array is array(integer range <>) of Gate_Descriptor;
      type Gate_Desc_Access is access Gate_Desc_Array;
      shared variable GateList : Gate_Desc_Access;
      GateList := new Gate_Desc_Array(1 to gate_instance_counter);

      The size is known after the elaboration phase, after all the gates have called their respective census function, but before the very first clock cycle. update_select_gate must be called by the very first component in the hierarchy list.

    • A list of input ports, which is an array of  drivers. The std_logic_vector is "downto 0" but the signals are mapped to gates numbers < 1 (range "-x to 0"). Note that these numbers are valid when found in a sink port.
      shared variable input_records : output_record_access; 
    • A list of output ports, the reverse of the input ports : this is an array of sinks, with positive indexes for the std_logic_vector, but mapped to the negative ( < 1) gate numbers found on drivers.
      shared variable output_records : input_records_access;

    The port sizes are determined by GetVectorsSize after a number of clock cycles.

    -- allocate some memory for the descriptors
    output_records := new input_records_array(0 to VectOutMax);
     input_records := new output_record_array(0 to VectInMax);

    And this is only now that I realise I shouldn't have called it "input_records_array" but "sink_records_array" because it adds to the confusion...

    So what are those...

    Read more »

  • Second upload

    Yann Guidon / YGDES09/02/2020 at 19:24 0 comments

    Today I moved things again. The proasic3 directory is now inside the LibreGates directory to ease inclusion with other projects, with a single entry point for the paths (a single symlink would be enough and the other directories will be relative to this base). I'm considering updating the #YGREC8 soon but for now there are other more pressing issues, such as (finally) integrating the Backwards gates (they don't work yet), and changing the probing algorithm (introduced in log 36. An even faster and easier algorithm to map the netlist). That's 2 things to be done simultaneously and the second seems more daunting, the Backwards gates will integrate nicely when I rewrite some parts of VectGen.vhdl.

  • First upload

    Yann Guidon / YGDES09/01/2020 at 14:39 0 comments

    LibreGates_20200801.tgz is online !

    This is what should have been #VHDL library for gate-level verification's v2.10 but the scope of the change cascaded into a big structural change, which is necessary anyway to get the Backwards gates working.

    All the previous unit tests work and indeed have been instrumental to get the new version right. They took time to develop and fix but they are priceless because without them, the archive would not be as right so fast (it only took some hours to get things back to relatively bugless and working status).

    Unit tests are invaluable and also serve as examples, tutorials and showcase the functions and usefulness of the library. More tests should follow...

    But for now I must focus on getting the Backwards gates working, and I have added a new enum :

      type enum_gate_kind is (

    I don't want to break any part of the code, which is quite sophisticated... So I keep the gates numbering system :

    • gate numbers > 0 are library gates. Now it is possible to specify the "kind" (either boolean, register or backwards)
    • gate numbers < 1 are ports
      • If the number appears on an output, the port is an input
      • conversely, if the number appears on an input, the port is an output

    This reduces the amount of modifications, compared to the bolder plan I had but that would be much more harder to get right and fast. I get my feet wet again by adding support for Backwards and then I'll see how I can manage to get a useful, accurate and reliable model for the DFFs and latches.

View all 7 project logs

  • 1

    Get the latest package version from

  • 2

    Execute the script.

    This will build the libraries and run many self-tests.

    These examples in the tests directory also show you the various ways to use this library.

  • 3

    You can directly use this library with all the ProASIC3 standard files, either without the analytics system ("simple" version) or the full analytics system (the standard version).


    In the "simple" case, at full simulation speed and no analysis, your VHDL source code contains these lines :

    Library proasic3;
        use proasic3.all;

    Then you point GHDL to the right library with this command line:

    ghdl -Psomepath/LibreGates/proasic3/simple my_file.vhdl

    If you need full analysis, then use the standard version and add these invocations to the VHDL testbench:

    Library LibreGates;    use LibreGates.all;    use LibreGates.Gates_lib.all;

    Then you modify the inclusion path :

    ghdl -Psomepath/LibreGates/proasic3 my_file.vhdl

View all 4 instructions

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates