Simulating a Custom IP core using a Zynq processor


Prerequisites


Created in Vivado 2015.1 and SDK 2015.1

This demo is great for the ZYBO but is also applicable for any microblaze design. This tutorial simulates the custom IP core with a microblaze project to avoid the additional licenses associated with the ZYNQ BFM core and AXI BFM core. Unfortunately, this results in a significantly more complex setup for the simulation but provides a solution for simulation with built-in licenses for series-7 boards in Vivado.

We will be using the PWM core written in the Zybo Creating Custom IP Cores Guide


1. Open vivado and create a new project with Nexys4 DDR board

1.1) Create a new project with name: “ip_core_simulation”.

1.2) Click Next.

1.3) Select the Nexys4 DDR.

1.4) Click Finish.

2. Create Microblaze Block Design

2.1) Select Create block design.

2.2) Click OK.

2.3) Add microblaze IP block.

2.4) Add My_PWM_Core.

2.5) Run block automation and run connection automation.
2.6) Make PMW0, PWM1, PWM2 and PWM3 all external connections.

2.7) Change the source of the input clock to single ended clock.

2.8) Double-click the clocking wizard block and change the reset type to active low.

2.9) Create the HDL wrapper

3. Run Synthesis, Implementation and Export hardware design

3.1) Click Run Implementation.

3.2) Click File→Export→Export Hardware.

3.3) Click OK.

3.4) Launch the SDK.

4. Create program to test your IP core

4.1) Create new application.

4.2) Enter Project name “custom_ip_simulation” and click Next.

4.3) Select Empty Application and click Finish.

4.4) Add main.c
4.5) We are going to start with the program from the Creating a custom IP core tutorial and modifying it for simulation. The original code looks like this:
#include "xparameters.h"
#include "xil_io.h"

#define MY_PWM XPAR_MY_PWM_CORE_0_S00_AXI_BASEADDR

int main(){
    int num, i;

    while(1){
        if(num == 100)
             num = 0;
        else
             num++;

        Xil_Out32(MY_PWM, num);
        Xil_Out32((MY_PWM+4), num);
        Xil_Out32((MY_PWM+8), num);
        Xil_Out32((MY_PWM+12), num);

        for(i=0;i<300000; i++);
    }
}
4.6) A delay loop of 300000 is going to take a while to simulate so choosing a smaller number like 30 will speed up simulation. Change the delay loop to 30. Save the project and exit SDK.

5. Associate ELF created in SDK with microblaze design

5.1) Right Click Simulation Sources. Click Add Sources.

5.2) Select Add or create simulation sources. Click Next.

5.3) Click the green plus symbol. Select Add Files…

5.4) Navigate to “your work folder”/ip_core_simulation.sdk/custom_ip_core/Debug/. Add custom_ip_simulation.elf.

5.5) Click Finish.

5.6) Right click custom_ip_core.elf. Click Associate ELF File… NOTE: if Vivado asks to generate output products then click generate output products and repeat this step.

5.7) Click the button

5.8) Select custom_ip_simulation.elf. Click OK.

6. Create Test Fixture

6.1) Add a new simulation file named “test.v”.
6.2) Copy the following code into “test.v”:
`timescale 1ns / 1ps

module test();

wire PWM0_tb;
wire PWM1_tb;
wire PWM2_tb;
wire PWM3_tb;

reg clk = 0;

design_1_wrapper uut(
    .PWM0(PWM0_tb),
    .PWM1(PWM1_tb),
    .PWM2(PWM2_tb),
    .PWM3(PWM3_tb),
    .clk_in1(clk),
    .reset(1)
    );
    
always 
    #5 clk <= ~clk;    
    
endmodule

7. Run Simulation

Click Run behavioral simulation.

8. Celebrate

It works! We can now simulate IP cores