Implement Cycle-Accuracy Simulation with NI 6581 FlexRIO Adapter Module

Updated Jun 1, 2023



  • NI-6581


  • LabVIEW
  • LabVIEW FPGA Module


  • FlexRIO

Operating System

  • Windows

LabVIEW 2010 introduced the capability to create a simulation export of your LabVIEW FPGA VI. This enables you to validate or debug your FPGA VI before you compile. If you will be simulating a VI for an NI FlexRIO target with adapter module, a few additional steps are required to simulate the adapter module. The purpose of this tutorial is to provide the additional details necessary to simulate NI FlexRIO adapter modules or FAMs. This tutorial expands upon the Cycle-Accurate Simulation with Mentor Graphics ModelSim  tutorial by simulating the NI 6581 adapter module and outputting the count on the digital output lines.

Create an FPGA VI and Project

To speed up the process of building our VI for debug, this tutorial leverages one of the example programs provided with the NI 6581 adapter module.

  1. Open NI 6581 Finite Acquisition and Generation – Simple.lvproj. You can locate this example by selecting Help » Find Examples to launch the NI Example Finder. Browse to Hardware Input and Output » FlexRIO » IO Modules » NI 6581 » NI 6581 Finite Acquisition and Generation – Simple.lvproj.
  2. To avoid inadvertently saving over this example, in the project window select File » Save As and Duplicate the project and dependencies.

    Select Continue, then select an appropriate location and file name to save your new project. Close the original example project and open the duplicate that you just saved.
  3. Make some simple modifications to the FPGA VI to optimize your simulation experience.

    The Modified VI, NI 6581 Acquisition and Generation Simple (FPGA) (Simulation).vi, is included in the file attached to this tutorial for download.

    If you wish to make the optimizations yourself, follow the steps below:
    1. Add a conditional disable structure from the Structures palette around the wait in the second frame. 
    2. Right-click the top of the frame to add a sub-diagram. Right-click on each of the cases and select Edit Condition For This Subdiagram to edit the conditions that allow execution for each sub-diagram. 
    3. The wait should execute when the FPGA_EXECUTION_MODE is equal to FPGA_TARGET and should not execute when it is THIRD_PARTY_SIMULATION. There no need to simulate the settling behavior of the NI 6581, and disabling this wait will speed up the simulation.

Configure the LabVIEW FPGA Module for Simulation

  1. Before you build a simulation export, configure the simulator. Go to Tools»Options»FPGA Module. Under Simulation, select ModelSim as the simulator. If ModelSim is installed correctly, LabVIEW should be able to find and populate the Simulator directory field. If it does not, you can set the value manually.
  2. Before creating simulation exports, you must also configure the FPGA simulation libraries. From the menu, select Tools»FPGA Module»Update FPGA Simulation Libraries. This compiles the VHDL libraries that the simulation model needs. You need to do this only once. Note: Updating the Simulation Libraries will take 5-10 Minutes.
  1. In LabVIEW 2011 and later, the FPGA Target must also be configured to execute on the third-party simulator before creating simulation exports. From the project view, right-click on the FPGA Target and select Execute VI on » Third-Party Simulator.


Verify or Add Simulation Support for the Adapter Module (CLIP Declaration Wizard)

To successfully simulate the VI, it is necessary to make sure the configured adapter module has simulation support. If the adapter module does not have a simulation model defined at the time of initiating the simulation export, an error will occur during code generation and you will not be able to simulate your VI. An error dialog is shown for reference in the figure below.

If a simulation model does not yet exist for the NI FlexRIO Adapter Module you want to simulate, then you must write a simulation model and use the CLIP declaration wizard to update the CLIP XML. The CLIP Declaration Wizard can be used to update the CLIP XML with new tags and version information required for simulation support. Once you have a simulation model in place for your adapter module you can continue with creating the simulation export. Creating a simulation model for any given FlexRIO Adapter Module requires detailed knowledge and understanding of the workings of the Adapter Module. 

Note: NI does not provide simulation models for the NI FlexRIO Adapter Modules. The following steps walk through how to use the wizard to create a simulation model for the NI 6581. These steps also generically apply to creating simulation models for the NI 6583, NI 6584, and NI 6585 FlexRIO Adapter Modules.

  1. Before making any changes to the XML of the Socketed CLIP XML for your FlexRIO Adapter Module, you should create a backup which you can revert to if necessary. For the purposes of this tutorial we will actually modify the backup copy to avoid changing the original.
    1. Copy the NI6581Port folder from the following directory:

      32-bit Windows:
      C:\Program Files\National Instruments\Shared\FlexRIO\IO Modules\NI 6581\NI6581Port

      64-bit Windows:
      C:\Program Files (x86)\National Instruments\Shared\FlexRIO\IO Modules\NI 6581\NI6581Port
    2. To the user directory:

      Windows XP/2000:
      C:\Documents and Settings\All Users\Shared Documents\National Instruments\FlexRIO\IO Modules\NI6581 Port

      Windows 7/Vista:
      C:\Users\Public\Documents\National Instruments\FlexRIO\IO Modules\NI6581 Port
  1. Once you have copied the CLIP to your user directory, right-click your FPGA target and select Properties to bring up the FPGA Target Properties dialog window.
  2. Select the Component-Level IP category. Using the buttons on the right, add the component-level IP for the NI 6581 by selecting the Add file icon and loading the XML from the new location for your CLIP.
  3. To update the XML using the wizard, select Modify File. This will launch a series of windows to guide you through updating the XML. For more details, see the Using the Configure Component-Level IP Wizard  topic in the LabVIEW Help.

    Although you will need to complete all 8 steps of the wizard, only the first page is covered here, as it covers the options related to simulation. The first page covers the CLIP declaration name and the source files.
  4. For the NI 6581 Port, change the Declaration Name at the top to NI 6581 Port with Simulation. This will help to identify the CLIP in a later step.
  5. For each synthesis file you can individually set the simulation behavior. The options are:

  • Same as synthesis (default for vhd file extensions)
  • User-defined
  • Exclude from simulation model (default for non-simulatable file extensions such as .ngc).
Clicking Help will bring up more detailed information on these three options.
For any files that are pre-compiled or otherwise not able to be simulated, a new file must be created in order to allow simulation of that component of the CLIP. Once these simulation files are ready, the simulation behavior should be set to user-defined, and the simulation file(s) should be added.

For the NI 6581 Port CLIP, the synthesis files can be used directly for simulation, so keep the remaining default settings that the Wizard has selected, and click Next.
  1. Continue clicking Next to step your way through the wizard. On page 3, Generics and Syntax Check, the Next button will be grayed out. You will need to first click Check Syntax.

    This will take a few seconds to verify all of the files and enable the Next button for you to proceed. Click the Next button.
  1. Continue clicking Next to step your way through the wizard. Complete the Wizard on page 9, XML Export, by clicking Finish. This will create a new .XML file with all of the simulation tags populated.
  2. You may get a warning that the XML is a newer version. Click OK to continue.
  1. Click OK to allow the save to continue and to overwrite the existing file since you are already working with a backup copy.
  1. Now you should have a CLIP which includes simulation support. However, the project is still configured to use the original CLIP. In the FPGA Target Properties, remove the CLIP that you added by highlighting it in the list and clicking the Remove File icon. Click OK to return to the Project Explorer.
  2. Right-click the IO Module and select Properties to reconfigure the IO Module to use the new CLIP with simulation support.

    Ensure that the Enable IO Module checkbox is checked then select the NI 6581 from the list of available IO Modules. Under the Component Level IP list, change the selection from NI 6581 Port to NI 6581 Port with Simulation and click OK.

Create and Build Simulation Exports

  1. To create a simulation export, locate the build specification under FPGA Target. You use the build specification to create the simulation testbench and specify various options for it. To create the build specification, right-click Build Specifications under the FPGA Target and select New»Simulation Export.
  2. This opens a dialog box where you can configure simulation export settings. Notice that the build specification name is currently “My Simulation Export”. First, set the top-level VI to simulate by going to the Source Files tab, selecting NI 6581 Acquisition and Generation Simple (FPGA).vi, and clicking the Add Item button. Also, under the Source Files tab, you can specify different signals that will be automatically added to the simulation waveform. Leave these as the default value.

  3. Go back to the Information tab and see that the build specification name has changed to match the name of your VI. Note that, under the Information tab, you can also set the top-level simulation model name and Destination directory. The top-level simulation model name is the name of the VHDL file that will be generated for the VI. Leave this field as the default value. You can specify where to generate simulation files in the destination directory.

    Note: Ensure that the destination directory is not read-only. If the destination directory is read-only, it will prevent later steps of the tutorial from working correctly.

  4. The Model Fidelity tab contains information about the I/O fidelity level, bus model, and framework.
  5. Click Build to save the build specification and generate the testbench files. You should see a dialog window indicating when the simulation export has been successfully built. Click Done in that dialog window.
  6. Next, navigate to the simulation directory by right-clicking on the build specification and selecting Explore.
  7. Look at the folders generated in the simulation export directory.

    The ModelSim folder contains files used by the ModelSim simulation tool. You do not need to view or edit any files in this folder. The niFpga folder contains VHDL files generated by the LabVIEW FPGA Module to implement the simulation model. These files are regenerated each time the simulation export is built and should not be modified.

    The user directory contains files that you can edit, including the top-level testbench file. In this case, the file is named tb_NiFpgaSimulationModel.vhd. This file is a template to implement a testbench and will be described later. This file is only generated the first time the build specification is built and will not be overwritten by the LabVIEW FPGA Module. A copy of the template is generated on each build in the niFpga directory for reference.

Develop a Test Bench and Simulate the VI

  1. Familiarize yourself with the VHDL template that your testbench generated. From the root simulation directory, use a text editor to open tb_NiFpgaSimulationModel.vhd, located in the User directory.

    Scroll through the testbench and read the included comments to learn about the different components of the testbench. Note that the architecture block contains a block named MainStimulusBlock and an instantiation of the NiFpgaSimulationModel component.

    • MainStimulusBlock contains the host interface code. The existing code performs a download, open, run, and then close. Typically, user code to exercise the testbench is inserted between the run method and close method.
    • NiFpgaSimulationModel implements the VI simulation model. You should not have to modify this instantiation.
  2. Create a plant model for your adapter module and add it to your testbench. When you synthesize your code and run it, physical hardware will make connections between the external signals such as port A and port B and the interface to the FPGA module (signals aGPIO(0)- aGPIO(65) and aGPIO_n(0)- aGPIO_n(65). In simulation, this physical connection does not exist, so it is necessary to provide additional information to simulate the terminal block behavior.
    1. Open the NI 6581 Specifications by navigating to National Instruments»NI RIO»FlexRIO in your start menu or Navigating to your FlexRIO installation directory.

      C:\Program Files\National Instruments\NI-RIO\FlexRIO\NI_6581_Specs.pdf

      Expand the Pinout and Signal Information and locate Table 3 which lists the NI 6581 Connector signals and corresponding NI FlexRIO FPGA Module Signals. Note that there are 3 ports, 3 PFI lines and a clock per connector. Each of these signals additionally has an output enable. To simulate signals up to the connector(s), the plant model must implement the connections to the FPGA module as described in this table.

    2. A plant model for the NI 6581 has already been generated for the purposes of this tutorial and is included in the attached zip file, Download and save the attached Plant Model, Ni6581PlantModel.vhd, to the User directory that you explored to from your project. Open the Plant Model with a text editor. Note that there are two adapter module signal vectors. These are the finger connections between the adapter module and the fpga module. Also note there are external signals for each of the pins on the front panel of the adapter module.

      The simulated architecture within this model includes a simplified model of the adapter module, it does not attempt to simulate any signal delay within the adapter module. This model uses Table 3, NI 6581 Connector Signals and NI FlexRIO FPGA Module Signals, from the NI 6581 Specifications document and simulates the physical connection between the front panel and the fingers at the FPGA module. This includes an input signal for each of the ports and PFI lines as well as output signals for each of the ports, PFI lines and output clocks. The output signals are only driven to the connectors when the corresponding GPIO Output Enable (active low) signal is low (‘0’), otherwise a high impedance is set to enable the port as an input.

    3. Add the Plant Model to the Simulation Model section of your testbench by adding the following portmap above the existing simulation model.

      Ni6581PlantModel_Instance: entity work.Ni6581PlantModel
      port map (
      -- Adapter Module I/O
      -- External Signals
    4. Add declarations for each of the external signals in the plant model by pasting the following code into the testbench, after the existing signal declarations.

      -- External Signals
      signal DDCA_P0 : std_logic_vector(7 downto 0);
      signal DDCA_P1 : std_logic_vector(7 downto 0);
      signal DDCA_P2 : std_logic_vector(7 downto 0);
      signal DDCB_P0 : std_logic_vector(7 downto 0);
      signal DDCB_P1 : std_logic_vector(7 downto 0);
      signal DDCB_P2 : std_logic_vector(7 downto 0);
      signal DDCA_Pfi : std_logic_vector(3 downto 1);
      signal DDCB_Pfi : std_logic_vector(3 downto 1);
      signal DDCA_ClockOut: std_logic;
      signal DDCB_ClockOut: std_logic;
      signal DDCA_GlobalClk0: std_logic;
      signal DDCB_GlobalClk1: std_logic;
  3. Take a moment to familiarize yourself with the LabVIEW example. Before continuing to the next step, you should be familiar with each of the controls and have an idea of what signals you would expect to see on the NI 6581 when this VI is running.

    Hint: Use the context help (Ctrl+H) and scroll over the icon in the upper right corner to bring up a description of the intended function of the VI. A single cycle timed loop running at 20MHz alternates between writing to Port 0 of Connector B and reading from Port 0 of Connector A.

  4. Simulate the wrapback cable. When executed on the hardware, this example uses an external cable to connect the generated data on Port0 of connector B to Port 0 of connector A where data is acquired. This cable can easily be simulated in the testbench by adding the following line of code to the testbench architecture body, just after the begin keyword:

    • DDCA_P0<= DDCB_P0 after 1 ns;
  5. Modify the testbench to simulate the VI running with specific values for each of the controls. Read and Write procedures can be added to your testbench to interact with controls and indicators. Fifo procedures can be added to interact with FIFOs. Definitions of these procedures can be found in the VHDL packages in the niFpga directory. You should be familiar with the following packages:
    • PkgNiFpgaSimControlAndIndicatorProcedures.vhd contains control/indicator read/write procedure definitions.
    • PkgNiFpgaSimFifoProcedures.vhd contains FIFO method definitions, such as reading, writing, starting, and stopping FIFOs.
    • PkgNiFpgaSimMiscProcedures.vhd contains the other host interface procedure definitions, such as open, download, close, run, and reset.

    The following testbench modifications will allow you to simulate your VI with the “Trigger Mode” set to “Counter”, the “Num Samples” control set to “255”. It will also verify the signals generated and acquired on the two ports.

    Note that the controls in this example are U16 and U32 types, and the FIFO uses U8. The read and write procedures are overloaded to accommodate all of the datatypes. The Output mode is set via an Enum control. To get the enum value, look in PkgNiFpgaSimUserTypes.vhd.

    1. Set the “Trigger Mode” and “Num Samples”. Copy two calls of the NiFpga_Write procedure from the PkgNiFpgaSimControlAndIndicatorProcedures.vhd file and paste them before the NiFpgaRun procedure in the testbench file. Details on this procedure can be found in PkgNiFpgaSimControlAndIndicatorProcedures.vhd.

      Fill in the missing parameters including address and data.

      1. To fill in the address parameter, find the constants for control/indicator addresses in the /niFpga/PkgRegister.vhd file. You should see the following addresses in the file:
        • kGeneration_Mode_ctl_1k
        • Num_Samples_ctl_0
      2. To fill in the data parameter of the NiFPGA_Write call, use the variables declared at the beginning of the MainStimulusProcess statement.

        • variable Generation_Mode_ctl_1_Data: tGeneration_Mode;
        • variable Num_Samples_ctl_0_Data: tU32;
      3. Connect the parameters that begin with 'fi' to standard signals defined within the testbench. These communicate with the testbench framework defined in the simulation model. You only need to be familiar with ErrorStatus signals. Monitor the signal fiErrorStatus for warnings and errors.
      4. Set the Num_Samples_ctl_0_Data and Generation_Mode_ctl_1_Data variable values before writing them to the control. Insert the following lines before the calls to NiFpga_Write:
        • Num_Samples_ctl_0_Data:= to_unsigned(255,32);
        • Generation_Mode_ctl_1_Data:=Counter;
    2. Read the contents of the FIFO. This example reads data in from DCCA_Port0 and puts the result in a FIFO. Copy and Paste one call to the NiFpga_ReadFifo procedure to read back the result of the simulation. This call should be added between the NiFpgaRun and NiFpgaClose procedures. Details on this procedure can be found in PkgNiFpgaSimFifoProcedures.vhd.

      Fill in the missing parameters including the fifo name and data:

      1. To fill in the fifo name parameter, find the constants in the /niFpga/PkgNiFpgaSimulationModel.vhd file. You should see the following fifo constant in the file:
        • kAcquisition_FIFO_R_ChannelNumber
      2. To fill in the data parameter, use the variable declared at the beginning of the MainStimulusProcess statement.
        • Acquisition_FIFO_R_Data
      3. Set the timeout to be '5'.
        • timeout => 5
      4. Add a variable named “remaining” of type “natural” to the top of the Main Stimulus Process to hold the remaining samples in the FIFO value. Connect this variable to the “remaining” parameter in the NiFpga_ReadFifo procedure.
        • variable remaining: natural;
      5. Connect the parameters that begin with 'fi' to standard signals defined within the testbench. These communicate with the testbench framework defined in the simulation model. You only need to be familiar with ErrorStatus signals. Monitor the signal fiErrorStatus for warnings and errors.
      6. Change the size of the array initialized for the FIFO from 499 to 254. This variable is located in the list of variables for the Main Stimulus Process.
        • variable Acquisition_FIFO_R_Data: tU8_Array(254 downto 0);
    3. Add a 100 microsecond wait between niFpgaRun and niFpga_ReadFifo.
      • Wait for 100 us;

    The main stimulus process should now contain the following:

    variable Num_Samples_ctl_0_Data: tU32;
    variable remaining: natural;
    variable Acquisition_FIFO_R_Data: tU8_Array(254 downto 0);
    (attr => (kNiFpga_OpenAttribute_NoRun => '1', others => '0'),
    FiClock => FiClock,
    fiHostToTargetInterface => fiHostToTargetInterface,
    fiTargetToHostInterface => fiTargetToHostInterface,
    fiHostToTargetReady => fiHostToTargetReady,
    fiTargetToHostReady => fiTargetToHostReady,
    fiErrorStatusIn => fiErrorStatus,
    fiErrorStatusOut => fiErrorStatus);
    (Address => kGeneration_Mode_ctl_1,
    Data => Generation_Mode_ctl_1_Data,
    FiClock => FiClock,
    fiHostToTargetInterface => fiHostToTargetInterface,
    fiHostToTargetReady => fiHostToTargetReady,
    fiErrorStatusIn => fiErrorStatus,
    fiErrorStatusOut => fiErrorStatus);
    (Address => kNum_Samples_ctl_0,
    Data => Num_Samples_ctl_0_Data,
    FiClock => FiClock,
    fiHostToTargetInterface => fiHostToTargetInterface,
    fiHostToTargetReady => fiHostToTargetReady,
    fiErrorStatusIn => fiErrorStatus,
    fiErrorStatusOut => fiErrorStatus);
    (attr => (kNiFpga_RunAttribute_WaitUntilDone => '0',
    others => '0'),
    FiClock => FiClock,
    fiHostToTargetInterface => fiHostToTargetInterface,
    fiTargetToHostInterface => fiTargetToHostInterface,
    fiHostToTargetReady => fiHostToTargetReady,
    fiTargetToHostReady => fiTargetToHostReady,
    fiErrorStatusIn => fiErrorStatus,
    fiErrorStatusOut => fiErrorStatus);
    wait for 100 us;
    Data=> Acquisition_FIFO_R_Data,
    timeout => 5,
    remaining=> remaining,
    FiClock => FiClock,
    fiHostToTargetInterface=> fiHostToTargetInterface,
    fiTargetToHostInterface=> fiTargetToHostInterface,
    fiHostToTargetReady => fiHostToTargetReady,
    fiTargetToHostReady=> fiTargetToHostReady,
    fiErrorStatusIn => fiErrorStatus,
    fiErrorStatusOut => fiErrorStatus);
    NiFpga_Close (
    FiClock => FiClock,
    fiTargetToHostInterface => fiTargetToHostInterface,
    fiHostToTargetInterface => fiHostToTargetInterface,
    fiHostToTargetReady => fiHostToTargetReady,
    fiTargetToHostReady => fiTargetToHostReady,
    fiErrorStatusIn => fiErrorStatus,
    fiErrorStatusOut => fiErrorStatus);
    fiStopSim <= true;
    end process MainStimulusProcess;
  6. You are now ready to simulate. Make sure that you have saved the tb_NiFpgaSimulationModel.vhd file, and then launch the simulator by right-clicking the simulation export in the LabVIEW project and selecting Launch Simulator. This brings up the ModelSim tool with the NI 6581 project already loaded.
  7. Add the plant model to the project by first selecting Project » Add To Project » Existing File and then browsing to the Ni6581PlantModel.vhd file you downloaded earlier.
  8. Set the compile order to compile the plant model before the testbench. Right-click either of the files in the Project Window of ModelSim, and select Compile » Compile Order.

    Either manually reorder the files, or click the Auto Generate button. The Auto Generate button will proceed to compile the files for you, but this is not necessary as the files will be compiled in the following step.
  9. Next, compile the testbench file and put some useful debug information on the waveform. LabVIEW generated a script in the user directory that you can run to do this. Select Tools » Tcl » Execute Macro and select the .../user/ file.

    The macro should compile the testbench file successfully and list some control/indicator information and testbench status signals on the waveform.
  10. You can now run the testbench by typing “run –all” at the command line. You should see the following output:
  11. Now, examine the waveform signals. Zoom out to full by selecting Wave » Zoom » Zoom Full so that you can see the entire waveform. Then under Controls and Indicators, expand the “Generation Mode” and “Num Samples” headings in the waveform to see detailed information on the controls.
  12. There are several items under Generation Mode and Num Samples.
    • Clock is the clock signal that the registers implementing the controls are synchronous to.
    • Data is the register value for the controls.
    You can see in this waveform that the Generation Mode value begins with a default value of “Constant_2”, gets set to Counter, and then returns to the default value of Constant_2 when the VI resets during close. Num Samples begins with its default value of 0, gets set to 0x000000FF (255) as we programmed in the testbench, and goes back to the default value of 0 when the VI resets during close. You can change the representation of the value (Binary, Hexadecimal, Decimal) by right-clicking on Data and selecting Radix » <format>.

    Note: in the VI, the value was actually “Constant”, however this is a reserved word in VHDL, so the “_02” suffix was added.

  13. Expand the Host Interface Register Access Signals sections for Num Samples. The value of Host Data In becomes a 1 at around 3337 ns, when the Generation Mode is being written. However this data is not intended for the Num Samples control so the Host Write is not asserted at that time. Shortly after, around 3838 ns, the host data in becomes 255 and the Host Write signal goes true for one clock cycle. This corresponds to the second NiFpga_Write command issued in the testbench. For more detailed information on waveform signals refer to the “Using Waveform Viewer” help topic
  14. Next, examine the CLIP signals by expanding IO Module under the CLIP heading in the waveform. There are many signals in the CLIP, but this tutorial will focus on the ones relevant to this particular example.
    • DDCB_Port0_Write - This is the signal being written from the 6581
    • DDCA_Port0_Read - This is the signal being read back on the 6581
    Expand both of these signals to see the data being being written and read back through the simulated NI 5781 and simulated wrapback cable.