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 Database 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.
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
Refer to the Xilinx 7 Series Library guide and/or Vivado layout to understand the primitive you need to instantiate
Find a single bit parameter that can be easily toggled, such as a clock inverter or a bulk configuration bit
Find the correct site type in gen_sites()
Instantiate the correct verilog library macro in top
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
build/segbits_tilegrid.tdbto observe bit addresses, for example
DFRAMEetc entries are deltas to convert this feature offset to the base address for the tile
We will fix them in the subsequent step
GENERATE_ARGSto 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
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)
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
make clean && make
build/segbits_tilegrid.tdbnow looks resolved
In this case there were several DSP48 sites per DSP column
Find the number of frames for your tile
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
tdb_fnsand 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
makein the tilegrid directory
Observe your base address(es) have been inserted (look for bits
CLB_IO_CLKentry in the
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 and process them in Vivado in order to obtain the respective bitstreams. Finally, 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.
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¶
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.
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.
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
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