Debug FPGA Hardware with System Console

ID 659642
Updated 10/9/2017
Version Latest
Public

author-image

By

Overview

This tutorial shows you how to use the System Console debugging tool to program a compiled FPGA design into an FPGA device, then access the hardware modules (i.e. peripherals) that are instantiated in that FPGA design. This System Console tutorial is based on the FPGA design created in the “Build a Custom Hardware System” tutorial. In that tutorial, you create this Qsys system:

Qsys System Block Diagram
Figure 1: Qsys System Block Diagram

In this tutorial, you will interact with the Qsys system through a JTAG cable connected to the FPGA, sending read and write transactions through the JTAG primary component to interact with the secondary peripherals connected to it.

Materials

Hardware

  • Windows* or Linux* development host PC
  • Intel® Cyclone® 10 LP FPGA Evaluation Kit
  • USB Type A to Mini-B cable

Software

  • Installed Intel® Quartus® Prime Software Suite. Either the Lite or Standard Edition, but not the Pro Edition. This was accomplished in the “How to Program Your First FPGA” tutorial.

  • A completed Quartus project from “Build a Custom Hardware System” tutorial. If you have not completed that tutorial you should go back and complete it now.

Step 1: Preparing the Board

This section describes how to prepare the Intel® Cyclone® 10 LP FPGA board for use in this tutorial.

  1. Plug the mini USB cable into the USB connector of the board. Then plug the other end of the USB cable to your host PC.

  2. Make sure DIP switch S1-4 (BYPASS) is in the default “OFF” position as shown in figure 2. This enables a JTAG connection to the board via USB. The other 3 switches are general user inputs and can be in any state.

Image of the Intel® Cyclone®  motherboard and USB connector
Figure 2: USB Connector

Step 2: Getting Started with System Console

This section describes how to use System Console to download the FPGA design into the FPGA device, and then interact with the JTAG primary IP core inside the Qsys system to read from, and write to the attached seconday peripherals. It also demonstrates JTAG link debug and Qsys system health observability provided by System Console.

  1. Launch the Intel® Quartus® software and open the blink project you created in the “Build a Custom Hardware System” tutorial by selecting File > Open Project, navigating to your project folder, and selecting the blink.qpf file.

  2. Launch System Console from the Tools > System Debugging Tools > System Console menu.

    Screenshot of system console menu
    Figure 3: System Console Menu

  3. The System Console tool looks for devices connected to the JTAG cable. To list the available devices, locate the TCL Console pane at the bottom right corner of the System Console window, and type the following command, then press ENTER:
    get_service_paths device


    Figure 4: System Console’s TCL Console

  4. You can use tab completion to finish commands as you type them, and even show you what possible commands can complete from the prefix you type. For instance, type get on the command line and then press TAB, to see a pop-up list of all commands that begin with get. You can use the up and down arrows on the keyboard to scroll up and down the list to select one of the commands. Press Enter to select a command from the pop-up menu.


    Figure 5: Command Line Before Pressing Tab


    Figure 6: Command Line After Pressing Tab

    The TCL console history buffer can also be scrolled backward and forward using the up and down arrows on the keyboard, letting you easily recall previously executed command lines.

  5. All commands provide help if you pass them into the help command. At the tcl prompt type:
    help get_service_paths


    Figure 7: Getting Help for Commands

    Type help help to see a list of commands.

    Step 3: Program the FPGA

    1. To program the FPGA device, we first need to get a service path to the device. We will assign that path to a variable called d_path by typing the following command:
      set d_path [lindex [get_service_paths device] 0 ]

    2. Download the SOF file to the device by typing the following command:
      device_download_sof $d_path output_files/blink.sof
      The amber D5 CONFIG LED should be illuminated once the commands above complete

    Step 4: Using the JTAG Debug Service

    Exercise the JTAG DEBUG service path provided by the JTAG primary component.

    1. Locate the JTAG DEBUG service path of the JTAG primary and store it in a new variable called jd_path by typing the following command:
      set jd_path [lindex [get_service_paths jtag_debug] 0]

    2. Exercise the JTAG interface by sending a list of values through a loopback at tdi and tdo of a system-level debug node (SLD). This command checks the physical interface of the board and JTAG TAP controller pins of the FPGA device. Type the following command and observe the values returned:
      jtag_debug_loop $jd_path [list 1 2 4 8 15 16]

    3. Check the clock connected to the JTAG primary component in the Qsys system. This command senses whether the clock is active, and returns a 1 if it is, and a 0 if it is not. Type the following command:
      jtag_debug_sense_clock $jd_path

    4. Sample the “state” of the clock connected to the JTAG primary component. Repeatedly sample the clock until you catch it in both the high (1) and low (0) state. Type the following command and press ENTER to observe the clock state. Repeat the command by pressing the up arrow followed by ENTER:
      jtag_debug_sample_clock $jd_path

    5. Sample the reset signal connected to the JTAG primary component inside the Qsys system. The S3 push button on the board is connected to the Qsys system reset input (active low). To sample the reset signal type the following command:
      jtag_debug_sample_reset $jd_path

    6. To see the reset signal change, press and hold the S3 push button and resample the reset, then release the S3 push button and resample the reset.

    Intel® Cyclone® motherboard image
    Figure 8: Location of Push Button S3

    Step 5: Using the JTAG Primary Service

    Next, we will exercise the primary service path provided by the JTAG primary. This will require us to recall the address map produced in the previous “Build a Custom Hardware System” tutorial. Remember that we used the sopc-create- header-files in that tutorial to create the master_0.h header file, and then dumped the base address macros from that file. To refresh your memory, here is what those addresses are:

    # define OCRAM_64K_BASE 0x0
    # define LED PIO BASE 0x10000
    # define BUTTON PIO BASE 0x10010
    # define SWITCH_PIO_BASE 0x10020
    # define SYSTEM_ID_BASE 0x10030
    
    1. First, set several TCL variables to allow us to more easily recall these base addresses in the rest of this tutorial. Execute each of the following commands to setup these variables:

      set ocram 0x0
      set led 0x10000
      set button 0x10010 
      set switch 0x10020 
      set sysid 0x10030 
      
    2. To communicate with the peripherals in the device, we are going to use the “primary” service. Locate the service path to the JTAG Primary component and save it to the tcl variable m_path by typing the following command:
      set m_path [lindex [get_service_paths master] 0 ]
      Claim the primary service path so that we can interact with the JTAG Primary component, and save it to the tcl variable c_path by typing the following command:
      set c_path [claim_service master $m_path ""]

    3. Now that we can send commands to the JTAG Primary, let’s interact with the on-chip RAM component by reading a single word from its base address. Type the following command and press ENTER:
      master_read_32 $c_path $ocram 1

      Now write a word to the base address by typing the following command and pressing ENTER:
      master_write_32 $c_path $ocram 0x1234de10

      Finally, let’s verify the word was written by reading from the on-chip RAM once more:
      master_read_32 $c_path $ocram 1

    4. Next we'll use the JTAG Primary to interact with the LED PIO component. First, turn on every other LED by typing the following command and pressing ENTER:
      master_write_32 $c_path $led 0x55

      Now turn those LEDs off and turn the other ones on by typing the following command:
      master_write_32 $c_path $led 0xaa

      New can also create a loop to toggle LED0 and LED1 every half second for 10 times by typing the following commands (or cutting and pasting into the Tcl Console):

      set COUNT 0
      while {$COUNT < 10} {
      master_write_32 $c_path $led 0x01
      after 500
      master_write_32 $c_path $led 0x02
      after 500
      set COUNT [expr $COUNT + 1]
      }
      

      Finally, let’s turn off all the user LEDs with the following command:
      master_write_32 $c_path $led 0xff

    5. Exercise the JTAG DEBUG service reset functionality. Now that we have some LEDs illuminated, let’s look at one more JTAG DEBUG service provided by the JTAG primary component. We can assert the reset signal connected to the Qsys system by the JTAG primary component. To do that we use the following command:
      jtag_debug_reset_system $jd_path

      After executing that command, the LEDs should all turn ON, returned to their reset state. You can trigger the same reset effect by pressing the S3 push button like we did before. Turn OFF some LEDs again and try pressing S3 to prove that as well.

    6. Interact with the button PIO component by reading the status of the S4 Push Button.

      First, read it before pressing the button with the following command:
      master_read_32 $c_path $button 1

      Next, press and hold S4 and repeat the command.

    7. Interact with the switch PIO component. There are 4 slide switches in DIP switch SW1, but only 3 of them are for GPIO use. We will use SW1-1 through SW1-3; avoid changing SW1-4 which causes the device JTAG link to be bypassed.

      First, set SW1-1 through SW1-3 to the ON position and read the switches with the following command:
      master_read_32 $c_path $switch 1

      Now, one by one, set SW1-3 through SW1-1 to the OFF position and read the switches again.

    8. Interact with the system ID component. This component contains two 32-bit words. The first word is the ID value that we set to 0xde10de10 in the previous hardware portion of this tutorial, and the second word that represents the Unix second time value when the Qsys system was generated.
      master_read_32 $c_path $sysid 2

    9. Exercise the default seconday peripheral. Here we will demonstrate what happens when we read and write to unmapped addresses.

      Our peripherals are mapped into addresses 0x0000_0000 thru 0x0001_0038. By reading an address outside that range, we will read instead from the default secondary peripheral (which was initialized at device configuration to 0x0000_0000). Read from an unmapped address with the following command:
      master_read_32 $c_path 0x01000000 4

      The read operation should return the following data:
      0x00000000 0x00000000 0x00000000 0x00000000

      Let’s write to that same address 4 words with a specific incrementing pattern.
      master_write_32 $c_path 0x01000000 [list 0x0badf00d 0x1badf00d 0x2badf00d 0x3badf00d]

      Now verify that pattern repeats every 4 words
      master_read_32 $c_path 0x01000000 8

      The read operation should return the data shown below:
      0x0badf00d 0x1badf00d 0x2badf00d 0x3badf00d 0x0badf00d 0x1badf00d 0x2badf00d 0x3badf00d

      Let’s write to a secondary that has no write interface, like the system ID peripheral. That write will not be decoded by any secondary in the system and will be directed into the default secondary.
      master_write_32 $c_path $sysid 0xfacecafe

      Now verify that this write operation was sent to the default secondary.

      master_read_32 $c_path 0x01000000 4
      The read operation should return the data shown below. Since only a single word was written (0xfacecafe), only the first word of the default secondary was changed.
      0xfacecafe 0x1badf00d 0x2badf00d 0x3badf00d

    10. Close the primary service by typing the following command:
      close_service master $c_path

    That’s it, you’ve used System Console to debug and test the FPGA hardware system.

    As you have seen, System Console is useful for low-level, scripted or interactive testing and debugging of IP cores. In this exercise, we communicated with the device over a JTAG link, but you can also use other communication channels, such as TCP/IP making the tool useful for remote debug as well. For more details on using System Console check out the dedicated web page here.

System Console