diff --git a/docs/db_dev_process/fuzzers/index.rst b/docs/db_dev_process/fuzzers/index.rst index fe6f8599..65a4183c 100644 --- a/docs/db_dev_process/fuzzers/index.rst +++ b/docs/db_dev_process/fuzzers/index.rst @@ -1,10 +1,11 @@ Fuzzers ======= -Fuzzers are things that generate a design, feed it to Vivado, and look at the resulting bitstream to make some conclusion. + +Fuzzers are a set of tests which generate a design, feed it to Vivado, and look at the resulting bitstream to make some conclusion. This is how the contents of the database are generated. The general idea behind fuzzers is to pick some element in the device (say a block RAM or IOB) to target. -If you picked the IOB (no one is working on that yet), you'd write a design that is implemented in a specific IOB. +If you picked the IOB, you'd write a design that is implemented in a specific IOB. Then you'd create a program that creates variations of the design (called specimens) that vary the design parameters, for example, changing the configuration of a single pin. A lot of this program is TCL that runs inside Vivado to change the design parameters, because it is a bit faster to load in one Verilog model and use TCL to replicate it with varying inputs instead of having different models and loading them individually. diff --git a/docs/db_dev_process/index.rst b/docs/db_dev_process/index.rst index 9fab0542..c66b5d45 100644 --- a/docs/db_dev_process/index.rst +++ b/docs/db_dev_process/index.rst @@ -7,6 +7,7 @@ Database Development Process readme contributing + new_fuzzer fuzzers/index minitests/index parts diff --git a/docs/db_dev_process/new_fuzzer.rst b/docs/db_dev_process/new_fuzzer.rst new file mode 100644 index 00000000..1e389726 --- /dev/null +++ b/docs/db_dev_process/new_fuzzer.rst @@ -0,0 +1,164 @@ +Adding New Fuzzer +================= + +This chapter describes how to create a new fuzzer using a DSP as an example target primitive. +The files that are generated with such fuzzer have been described in more detail in the :doc:`Database<../dev_database/index>` chapter. +The process of creating a new fuzzer consists of two elements, namely base address calculation and feature fuzzing. + +Base Address Calculation +------------------------ + +The base address calculation is based on segmatching (statistical +constraint solver) the base addresses. A similar technique is used in +most fuzzers for solving configuration bits. + +Methodology ++++++++++++ + +In this technique all IP blocks are changed in parallel. This means that +log(N, 2) bitstreams are required instead of N to get the same number of +base addresses. However, as part of this conversion, address propagation +is also generally discouraged. So it is also recommended to toggle bits +in all IP blocks in a column, not just one. In the CLB case, this means +that every single CLB tile gets one bit set to a random value. If there +are 4 CLB CMT columns in the ROI, this means we\'d randomly set 4 \* 50 +bits in every bitstream. With 200 bits, it takes minimum floor(log(200, +2)) =\> 8 bitstreams (specimens) to solve all of them. + +Calculating the base address +++++++++++++++++++++++++++++ + +#. Find a tilegrid fuzzer to copy, e.g. "dsp" + +#. Enter your copied directory + +#. Edit `top.py` + + a. Refer to the `Xilinx 7 Series Library guide `_ and/or Vivado layout to understand the primitive you need to instantiate + + b. Find a single bit parameter that can be easily toggled, such as a clock inverter or a bulk configuration bit + + c. Find the correct site type in gen_sites() + + d. Instantiate the correct verilog library macro in top + + e. LOC it, if necessary. It's necessary to LOC it if there is more than one + +#. Run make, and look at Vivado's output. Especially if you took shortcuts instantiating your macro (ex: not connecting critical ports) you may need to add DRC waivers to generate.tcl + +#. Inspect the ``build/segbits_tilegrid.tdb`` to observe bit addresses, for example ``DSP_L_X22Y0.DWORD:0.DFRAME:1b 0040171B_000_01`` + + #. The ``DFRAME`` etc entries are deltas to convert this feature offset to the base address for the tile + + #. We will fix them in the subsequent step + +#. Correct Makefile's ``GENERATE_ARGS`` to make it the section base address instead of a specific bit in that memory region + + #. Align address to 0x80: 0x0040171B => --dframe 1B to yield a base address of 0x00401700 + + #. Correct word offset. This is harder since it requires some knowledge of how and where the IP block memory is as a whole + + i. If there is only one tile of this type in the DSP column: + start by assuming it occupies the entire address range. + In this step add a delta to make the word offset 0 (--dword 0) and later indicate that it occupies 101 words (all of them) + + ii. If there are multiple: compare the delta between adjacent tiles to get the pitch. + This should give an upper bound on the address size. + Make a guess with that in mind and you may have to correct it later when you have better information. + + #. Align bits to 0: 1 => --dbit 1 + +#. Run ``make clean && make`` + +#. Verify ``build/segbits_tilegrid.tdb`` now looks resolved + + #. Ex: ``DSP_L_X22Y0.DWORD:0.DFRAME:1b 0040171B_000_01`` + + #. In this case there were several DSP48 sites per DSP column + +#. Find the number of frames for your tile + + #. Run ``$XRAY_BLOCKWIDTH build/specimen_001/design.bit`` + + #. Find the base address you used above i.e. we used ``0x00401700``, so use ``0x00401700: 0x1B`` (0x1C => 28) + + #. This information is in the part YAML file, but is not as easy to read + +#. Return to the main tilegrid directory + +#. Edit ``tilegrid/add_tdb.py`` dsd a + + #. Find ``tdb\_fns`` and add an entry for your tile type e.g. ``(dsp/build/segbits_tilegrid.tdb", 28, 10)`` + + #. This is declared to be 28 frames wide and occupy 10 words per tile in the DSP column + +#. Run ``make`` in the tilegrid directory + +#. Look at ``build/tilegrid.json`` + + #. Observe your base address(es) have been inserted (look for bits ``CLB_IO_CLK`` entry in the ``DSP_L_*`` tiles) + +Feature Fuzzing +--------------- + +The general idea behind fuzzers is to pick some element in the device (say a block RAM or IOB) to target and write a design that is implemented in a specific element. +Next, we need to create variations of the design (called specimens) that vary the design parameters, for example, changing the configuration of a single pin. +A lot of this program is TCL that runs inside Vivado to change the design parameters, because it is a bit faster to load in one Verilog model and use TCL to replicate it with varying inputs instead of having different models and loading them individually. + +By looking at all the resulting specimens, the information which bits in which frame correspond to a particular choice in the design can be correlated. +Looking at the implemented design in Vivado with "Show Routing Resources" turned on is quite helpful in understanding what all choices exist. + +Fuzzer structure +++++++++++++++++ + +Typically a fuzzer directory consists of a mixture of makefiles, bash, +python and tcl scripts. Many of the scripts are shared among fuzzers and +only some of them have to be modified when working on a new fuzzer. + +- Makefile and a number of sub-makefiles contain various targets that + have to be run in order to run the fuzzer and commit the results + to the final database. The most important ones are: + + - *run* - run the fuzzer to generate the netlist, create + bitstreams in Vivado, solve the bits and update the final + database with the newly calculated results. + + - *database -* run the fuzzer without updating the final database + +The changes usually done in the Makefile concern various script +parameters, like number of specimen, regular expressions for inclusion +or exclusion list of features to be calculated or maximal number of +iterations the fuzzer should try to solve the bits for. + +- *top.py* - Python script used to generate the verilog netlist which + will be used by the fuzzer for all Vivado runs. + +- *generate.tcl -* tcl script used by Vivado to read the base verilog + design, if necessary tweak some properties and write out the + specimen bitstreams + +- *generate.py -* Python script that reads the generated bitstream and + takes a parameterized description of the design (usually in the + form of a csv file) in order to produce a file with information + about which features are enabled and which are disabled in a given + segment. + +Creating the fuzzer ++++++++++++++++++++ + +1. Open the *top.py* script and modify the content of the top module by + instantiating a DSP primitive and specifying some parameters. Use + LOC and DONT\_TOUCH attributes to avoid some design optimization + since the netlists are in many cases very artificial. + +2. Make sure the *top.py* script generates apart from the top.v + netlist, a csv file with the values of parameters used in the + generated netlist. + +3. Modify the *generate.tcl* script to read the netlist generated in + step 1, apply, if necessary, some parameters from the csv file + generated in step 2 and write out the bitstream + +4. Modify the *generate.py* script to insert the tags, which signify + whether a feature is disabled or enabled in a site, based on the + csv parameters file generated in step 1