FPGA data logging
Minimal logic analyser
ECE 5760 Cornell University

Viewing the state of the FPGA

Debugging a FPGA design requires that you somehow view the internal state of the FPGA. Intel/Altera have some tools to do this

A simple Logic Analyzer (HOmebrew Logic Analyzer -- HOLA)

I wanted to build a very light-weight data logger that could be used as a logic analyser. The FPGA footprint should be minimal and the user interface completely determined by user code running on the HPS. Only the data aquisition and transfer to the HPS is defined. The data can be displayed as a text list, plotted as traces on the VGA, or exported to a spreadsheet.

To implement this, I used three state machines running at 100 MHz:

First implementations of HOLA

The HPS code transfers parameters, then just does a simple print out of 5 samples around the trigger. The verilog is set up with the data input to the logger being a 32 bit counter running at 100 MHz. The data input the analyzer is
data_input = {count[31:0]} .
The trigger input is

where KEY[3] is logic-low when pushed. If the HPS sends a trigger mask of 0h80000000, and a trigger word of 0h00000000 then the trigger will happen when the button is pushed. If the HPS sends a trigger mask of 0h0000ffff, and a trigger word of 0h00001000 then the trigger will happen when the count is 0h1000.
(HPS_code, verilog, Qsys_layout, ZIP) Address definition file.

A slight modification of the DUT verilog code sets up with the data input to the logger being 28 bits of a 32 bit counter running at 100 MHz, and 4 bits of counter state. The counter state merely sequences between 0,1,2 as a simple source. The data input the analyzer is
data_input = {DUT_state, count[27:0]} .
The trigger input is
The HPS code is modified to parse the 32 bit data into count and state and show 10 samples before/after the trigger. The first image below shows the program output with count and state with a trigger_mask=FFFF and trigger_value=1000. The second image shows program output with trigger_mask=8000FFFF and trigger_value=1000. The data capture occured when the count low 4 digits were 1000 and the button is pushed.
(HPS_code, verilog)

Modularized version of HOLA

Rearranging the hardware to separate the logic analyser from the device-under-test makes a cleaner interface.
The functionality is unchanged, as is the Qsys layout.
There are two connections to the DUT, connections to two SRAM modules on the Qsys bus, and a clock and reset.
The formatted verilog for DUT, analyser interface, and Qsys interfaces. (Verilog)
A modified version of the HPS code prints binary as well as the hex count and the state variable. (HPS_code)

Inserting HOLA into your design

There are just a few items to change to insert HOLA into your design:

As an example, insert HOLA into simplified version of
VGA display using a bus_master as a GPU for the HPS Display from SDRAM
project from the bus-master page.
The goal is to be able to use the VGA as a graphic output for the logic analyzer.

Adding waveform plotting to HOLA

Once the VGA interface is running, it is possible to add some graphics to HOLA. This example uses a DDS sinewave generator as the device-under-test. The clocked sine ROM adds a one cycle phase delay between the phase and the sine value. In the console image you can see the trigger condition was set to zero and masked to the low-order 8-bits. You can also see the one cycle sine delay. This mask isolates the phase value from the verilog data_input to HOLA. The data_input is parsed into 16-bits of sine and 8-bits of phase for display on the VGA. As seen below, the green line is at the trigger value of zero phase in the first image. Setting the trigger mask to 0xff and the trigger value to 0x40 produces a 90 degree phase shift at the trigger point, as seen in the second image.
(HPS_code, verilog, ZIP) (Qsys_layout)

Modularizing and simplifying the HPS interface to HOLA

To make the system easier to use for debugging, the low level functions on the HPS were abstracted to five functions:

The code for many applications will just call the start routine, plot some data, and end. The example queries for a trigger_mask, trigger_value, and zoom factor, the plots the phase of a DDS system, the individual bits of the phase, and the resulting sinewave. Two zoom levels are shown below. Zoom level 0 plots 1 pixel/horizontal pixel. Zoom level 2 plots 4 pixels/horizontal pixel. The phase and sine vectors are also printed.
(HPS_code, Verilog and zip is same as above)
(HPS_code with binary print)

As a template for testing the lab_1 ODE solver, this example plots four waveforms and the bit-wise expansion of one of the waveforms. The device-under-test (DUT) was a 3-phase DDS sinewave generator. Connections from the DUT to HOLA consisted of a data word and a trigger word. Phase angle and the phase bits are plotted in red, while the three phase sine waves are plotted in white, yellow, and cyan.
-- The first image has a trigger mask of 0x80000000 and trigger value of zero, so refering back to the connections, a trigger will occur when KEY3 is pushed.
-- The second image trigger mask is 0xff, which are the bits of the phase in the trigger word and a trigger value of zero. (Verilog, ZIP, C code)
-- A slightly modified DUT includes a DDS reset line from KEY[1], which is included in the external_trigger_source. If you now choose a trigger_mask of 0x40000000 and trigger_match_value of 0x40000000 in the C code, then when you press the KEY[1] DUT reset you get the third image. The phase stays at zero after the trigger because there is no way to remove your finger from the button in 5 microseconds. (Verilog)(Qsys_layout)

Adding table file write to HOLA

Using LINUX file-redirect it is easy to set up a utility that either prints a table to the terminal or saves it in a file. The utility allows you to format individual entries to produce a CSV or tabbed table. The routine print_table_HOLA outputs to stderr. By default the device stderr is the console screen. At the command line when you start the analysis program you can redirect stderr to a file using ./executable_name 2>file_name. Using ./la10 2>test.txt the table shown in the screen dump below is now in a file. The formatting code for the table gives the details of how to parse the logic_data vector read from the FPGA. The range of the sine functions is +/-63 because the verilog ROM table does not use the upper bit of the 16 bit table. The code uses the same Verilog as the example just above. (C code)

Adding real-time GPIO pin output for oscilloscope

Two multiplexers were added to the verilog design to allow real-time monotoring of two bits of the logic analyser data input word. The two bits are output on two GPIO_0 pins so you can hook up a scope. The the ALM use count is 4440, about 14% of the FPGA. Each mux uses about 13 ALMs. The HPS code and Qsys are unchanged (Verilog).

Below you can see a black jumper hooked to GPIO0_0 and a white jumper hooked to GPIO0_1. The top switches [10:5] chose bit 13 for channel 1 and switches [4:0] chose bit 14 for channel 2. The ringing on channel 1 is due to a misplaced ground connection. The screw-head in the lower right gives the better quality signal on channel 2.