Main Content

Verify the Combination of Hand-Written and Generated HDL Code

This example uses HDL cosimulation and FPGA-in-the-loop (FIL) simulation to verify an HDL design comprising generated and legacy HDL code. The term "legacy" is used here to indicate code that may have been hand-written, purchased from a third party or generated for another project and saved for reuse in this design.

The legacy code in this example implements a finite state machine (FSM) that is a sub-module of a Multiple Input - Multiple Output (MIMO) decoder intended for use in a wireless communications system. Most of the MIMO decoder has been developed in Simulink and the HDL code for it will be generated by HDL Coder. The FSM belongs inside that Simulink design. The legacy code for the FSM will be integrated with the Simulink model and incorporated into the FPGA implementation via the code generation process.

The example will show how the designer or verification engineer can use the HDL Verifier cosimulation wizard to integrate the legacy FSM with the Simulink model and verify it. HDL Cosimulation provides full visibility and control, enabling debugging and verification of the code.

After successful integration of the legacy FSM, the cosimulation block automatically incorporates the legacy code when HDL code is generated from the Simulink model, resulting in a complete FPGA implementation of the MIMO decoder. Finally, the entire design is verified on the actual FPGA using FPGA-in-the-loop.

Outline of the Example

  1. Use the cosimulation wizard to import legacy HDL code into a Simulink model

  2. Verify the legacy HDL code by cosimulating it and comparing results with a behavioral model

  3. Generate HDL code for the entire MIMO decoder using the cosimulation block in a Blackbox

  4. Validate the MIMO decoder with FPGA-in-the-loop

Requirements and Prerequisites

For cosimulation and FPGA-in-the-loop you'll need the following software and hardware:

  • One of the supported HDL simulators. For supported simulators see Cosimulation Requirements.

  • FPGA design software

  • One of the supported FPGA development boards. For supported hardware, see Supported FPGA Devices for FPGA Verification.

  • For connection using Ethernet: Gigabit Ethernet Adapter installed on host computer, Gigabit Ethernet crossover cable

  • For connection using JTAG: USB Blaster I or II cable and driver for Intel® FPGA boards. Digilent® JTAG cable and driver for AMD® FPGA boards.

MATLAB® and FPGA design software can either be locally installed on your computer or on a network accessible device. If you use software from the network you will need a second network adapter installed in your computer to provide a private network to the FPGA development board. Consult the hardware and networking guides for your computer to learn how to install the network adapter.

Note: The example includes code generation. If you do not have access to HDL Coder software you can skip the code generation step in this example and use the HDL files provided for you together with the FIL wizard to simulate them with FPGA-in-the-loop.

Create a Reference Model for the Finite State Machine

A reference model is a simulation model of the behavior expected of an implementation. It is typically used in HDL verification by instantiating it alongside the RTL implementation, giving the same inputs to both and comparing their outputs. The advantages of reference models in verification are that they can be developed independently of the implementation (often by a different person) providing an independent validation of the expected behavior, they are easier to create than the actual implementation (not requiring synthesis or actual device timing) and they usually run fast in simulation.

The first step in verifying the legacy HDL code in this example is to create a reference model for that part of the design. That has already been done for the FSM. Open the behavioral_mimo.slx model. Double-click into the MIMO Decoder subsystem and you'll see that the FSM subsystem contains a MATLAB function block that implements the behavior of the FSM. This reference model will be used to verify the legacy HDL code for the FSM.

1. Use Cosimulation Wizard to Import Legacy HDL Code

Invoke the cosimulation wizard by typing the following at the MATLAB command prompt:

cosimWizard

Select HDL cosimulation with Simulink and your preferred HDL simulator from the drop-down list. If the HDL simulator is not on your system path, provide the path and click Next.

Add FSMSubsystem.vhd, FSMSubsystem_pkg.vhd, and Embedded_Controller.vhd files (located in the "verify_legacy_hdlsrc" folder) using the cosimWizard's Add button and reorder the list to place FSMSubsystem.vhd at the bottom and FSMSubsystem_pkg.vhd at the top of the list, for correct compilation ordering. Then click Next.

Click Next on the following 2 panels to accept the default values and arrive at the Input/Output Ports panel. In the list of Input Ports, select the following Port Type values from the drop-down lists for the first 3 ports:

clk        : Port Type = clock
reset      : Port Type = reset
clk_enable : Port Type = reset

This identification of Port Types causes the cosimulation block to force those signals in the HDL simulator rather than require that they be driven in the Simulink diagram. In this example we treat the clk_enable port as another reset for cosimulation. Before you proceed to the next step similarly select "unused" for the ce_out, causing it to be omitted from the cosimulation block since it is not needed in Simulink.

The cosimulation wizard automatically identifies inputs and outputs in the HDL code and creates the cosimulation block for Simulink based on the ports it finds there. There are some details about the output ports that it cannot learn from the HDL code. In the HDL code the outputs are simply collections of bits with no indication of how you would like to interpret those bits in Simulink. You have to tell the cosimulation wizard whether you want those bits to be seen as signed or unsigned values and, if they are to be interpreted as fixed-point numbers, where to put the radix point.

In the Output Port Details panel refine the data type for each output. In the case of this design the output ports are to be interpreted as follows. Note that there are multiple scalar ports in the HDL code for the vector ports (out_1, out_6, out_9, out_10, out_11, out_12):

out_1  : Signed,   Fraction Length = 0 (4 scalar ports)
out_2  : Unsigned, Fraction Length = 0
out_3  : Unsigned, Fraction Length = 0
out_4  : Unsigned, Fraction Length = 0
out_5  : Signed,   Fraction Length = 10
out_6  : Signed,   Fraction Length = 10 (3 scalar ports)
out_7  : Signed,   Fraction Length = 2
out_8  : Unsigned, Fraction Length = 0
out_9  : Signed,   Fraction Length = 0 (4 scalar ports)
out_10 : Signed,   Fraction Length = 0 (4 scalar ports)
out_11 : Signed,   Fraction Length = 10 (4 scalar ports)
out_12 : Signed,   Fraction Length = 10 (4 scalar ports)
out_13 : Unsigned, Fraction Length = 0
out_14 : Signed,   Fraction Length = 0

On the Clock/Reset Details panel set the following values:

clk Period = 10 ns, Active Edge = Rising
reset Initial Value = 1, Duration = 27 ns
clk_enable Initial Value = 0, Duration = 37 ns

Click Next to proceed to the Start Time Alignment panel and set the "HDL time to start cosimulation (ns)" to 40.

Proceed to the final step and de-select the checkbox for "Automatically determine timescale at start of simulation". For this example we know that the timescale for cosimulation should be 1 second in Simulink corresponds to 10 ns in the HDL simulator. See HDL Verifier documentation for information on using the automatic timescale setting feature for other designs. Set the aforementioned timescale and click Finish.

The cosimulation block will be generated for importing the legacy HDL code into the Simulink model. You can drag and drop the newly generated cosimulation block and the 2 convenience command blocks into the Simulink model, inside the FSMSubsystem block and connect it to the output ports of the FSMSubsystem. A cosimulation model, with comparators and assertion blocks inside the MIMO Decoder subsystem, has been provided for this example. The comparators and assertion blocks have been added to alert you to any mismatches between the outputs of the reference model for the Embedded Controller and the legacy HDL implementation.

Use the following command to resize the generated cosimulation block to make it easier to insert it into the cosimulation model:

set_param('untitled/fsmsubsystem', 'Position', [0 0 165 852]);

Open the cosim_mimo.slx model. Drag the new block and convenience command blocks created by cosimWizard into the cosimulation model, replacing the placeholder subsystem inside the MIMODecoder subsystem.

2. Cosimulate to Verify the Legacy HDL Code

In your cosimulation model double-click the "Launch HDL Simulator" block to launch your chosen HDL simulator. Click the Play button in Simulink to start the cosimulation and observe that warning messages are displayed in the MATLAB window. These are indicating mismatches on the output signals because of a discrepancy between the reference FSM model and the HDL implementation.

Now you can use Simulink and HDL simulator debugging features to isolate the problem and fix the bug. In this case the errors arise because a state transition arc was missed in the HDL implementation. Notice in the HDL simulator's waveform display that the FSM state gets stuck very early in the simulation.

Fix the Hand-Written HDL Code and Rerun the Cosimulation

The corrected HDL code has been supplied for this example. Use the following command to copy the new code to your working directory, overwriting the bad version of Embedded_Controller.vhd:

copyfile(fullfile('verify_legacy_hdlsrc', 'fixed_hdl', 'Embedded_Controller.vhd'), 'verify_legacy_hdlsrc', 'f');

Recompile the Legacy HDL code by double-clicking the "Compile HDL Design" block. Exit the HDL simulator if it is still open following the previous execution of the cosimulation and relaunch the HDL simulator, then replay the cosimulation. You should observe no mismatches this time.

Now that you've debugged and verified the legacy HDL code for the Embedded Controller you can go on to verify the entire MIMODecoder with FPGA-in-the-loop.

Set FPGA Design Software Environment

Before using FPGA-in-the-loop, make sure your system environment is set up properly for accessing FPGA design software. You can use the function hdlsetuptoolpath to add FPGA design software to the system path for the current MATLAB session.

Prepare the Model for HDL Code Generation

To prepare the model for FPGA-in-the-loop incorporating the legacy HDL code and generating new HDL code for the remainder of the MIMO Decoder you need to do 2 things to complete the FPGA implementation:

  1. edit the cosimulation model to remove the FSM reference design

  2. use the HDL Coder Blackbox to incorporate the legacy HDL into the model for code generation

If you want to follow all steps to prepare the model for HDL code generation using the HDL Blackbox, save the cosimulation model with a different name and proceed with the rest of model preparation as follows:

1. edit the cosimulation model to remove the FSM reference design

  • inside the MIMO Decoder subsystem delete the Embedded_Controller function block

  • delete the "from" blocks that drive Embedded_Controller inputs with the exception of the enablecoder input

  • delete the comparators and assertion blocks on the outputs

  • reconnect the cosimulation block outputs to the inputs of DelaySubsystem1

2. use the HDL Coder Blackbox to incorporate the legacy HDL into the model for code generation

  • select the cosimulation block and type control-G to create a subsystem

  • right-click on the new cosimulation subsystem and select HDL Code and HDL Block Properties

  • select Architecture = BlackBox

  • enter FSMSubsystem in the EntityName parameter

  • enter 0 in the ImplementationLatency parameter

  • OK the HDL Block properties dialog

3. rerun the simulation to update the diagram.

  • double-click the "Launch HDL Simulator" block to launch the HDL simulator

  • click the Play button in Simulink to start the cosimulation

  • save the model

3. Generate HDL Code and FPGA-in-the-Loop

This step requires HDL Coder. If you do not have this software, you can use pre-generated HDL files for FIL simulation. Jump directly to step 5. FIL Simulation Using filWizard.

If you want to follow the process to generate the HDL files yourself return to the top level of the model, right click on the MIMODecoder subsystem and under "HDL Code" launch the HDL Coder Workflow Advisor.

  • Step 1.1: select FPGA-in-the-loop Target Workflow, select your preferred FPGA development board from the drop-down list, and identify a writeable directory to hold the generated HDL code.

  • Step 4.1: in Set FPGA Options select "Add" and use the browser to navigate to the EmbeddedController HDL files you copied to your working folder in Step 1 and modified with the fixed HDL code in Step 3.

  • Step 4.2: Right-click on step 4.2 of the workflow in the left-hand navigation tree and select "Run to this task". This step may take several minutes because it includes the steps to synthesize, map, and route the design for the FPGA device.

The result will be an FPGA programming file for FPGA-in-the-loop simulation of the MIMO Decoder subsystem and a new model containing the original model (including the legacy HDL for the FSM) of the decoder alongside the FPGA-in-the-loop block. It will also have comparators with assertion blocks to identify mismatching signals similar to those we saw in the cosimulation model.

4. Verify the Design with FPGA-in-the-Loop Simulation

Since the generated verification model includes the cosimulation for the FSMSubsystem you will need to use the HDL simulator to run the entire FIL model. Make sure that the HDL simulator from your previous cosimulation is shut down and relaunch the HDL simulator.

In the FPGA-in-the-loop model generated in Step 3, open the FIL block.

Select "Load" to download the FPGA programming file to the device on your board.

Click Play in the Simulink model to run FPGA-in-the-loop simulation.

Observe the results in the comparison scopes and the ErrorRate Calculation in the model. Your FIL simulation results should exactly match the reference model.

5. FIL Simulation Using FIL Wizard

This step is the alternative to Step 4 for those who do not have HDL Coder software. If you've completed Step 4 you need not continue with this step.

The pre-generated HDL files are located in the "verify_legacy_gen_hdlsrc" folder. You can create the FPGA programming file for FPGA-in-the-loop using the FIL wizard. the FIL wizard will also create a FIL block which you can discard because the FIL model provided for this example already contains the FIL block.

Open the FIL wizard by entering the following command:

filWizard
  • In FIL Options select your FPGA development board from the list.

  • In Source Files select Add and choose all of the files in the folder verify_legacy_gen_hdlsrc and identify MIMODecoder.vhd as the top level file.

  • Accept the default values for the remainder of the filWizard options

  • Wait for the FIl block and FPGA programming file to be created. This may take several minutes due to the time required to synthesize and route the FPGA implementation.

  • Open the gm_fil_codegen_mimo_fil.slx model and drag the newly generated FIL block into the model at the location indicated.

  • Open the FIL block mask, click on the Signal Attributes tab. Change the data type for each rx_decoded output to fixdt(1,6,0) to match the data type of the behavioral block.

  • Open the FIL block mask, click on the Main tab, select Load and wait for the FPGA programming file to be downloaded to the device.

  • Press Play in the Simulink model to run FPGA-in-the-loop.

Observe the results in the comparison scopes and the ErrorRate Calculation in the model. Your FIL simulation results should exactly match the reference model.

This concludes the example of Using HDL Cosimulation and FPGA-in-the-loop to Verify HDL Designs.