• 0
electronicsdevices

Create an IP that can Partly be Controlled with Vivado SDK and Partly be Controlled by a Physical Switch that Does Not Rely on Vivado SDK

Question

So far, I've been relying on this video if I want to make custom IP and control it with just the SDK

 

It's gotten me through many things so far, but now I want to implement a design like this:

 

5980d043bf5a1_Screenshotfrom2017-08-0114-01-55.png.3ca52dacb209356e931844d6994e2262.png

Previously, I had hardcoded the matrix entries for matrices A and B. What I want to do is to use Vivado SDK to write what the matrix entries of matrices A and B are. Then, I want to flip a physical switch on the BASYS 3 board and use the Verilog logic I have already got working on the Verilog-only implementation of this model to multiply matrices A and B together and store the contents in matrix Z. The results of the multiplication can be viewed by flipping another physical switch, at which point they will be displayed on the four 7-segment displays (for simplicity, the matrix entries are between 1 and 2, so the largest possible resultant entry is 8).

The matrix A, B, and Z entries I know how to read and write with Vivado SDK. The way I usually do this is to create an IP with an AXI4 interface. However, the twist is that I want to control a few switches and an LED WITHOUT using Vivado SDK. I know that I could use the LED and Switch IP's by drag-and-dropping them onto a block design, but I only know how to control them with Vivado SDK. How can I create an IP where during runtime, I can have the FPGA (not Vivado SDK) monitor whether a switch has been pushed while still being able to change the contents of matrices A and B with Vivado SDK. Also, what do I need to do to be able to implement the a,b,c,d,e,f,g,and dp parts of the 7-segment display in the design?

In other words, in the video, he has a simple interface, no physical LEDs or switches used:

 

module myAdder8bit(

input CLK,

input A,

input B,

output S

);

and in the AXI4 wrapper, the user logic was something like this:

myAdder8bit UIP ( .CLK(S_AXI_ACLK),  .A(slv_reg0[7:0], .B(slv_reg0[15:8], .S(adder_out   )  ;

all the parameters he needed, he found or made in the AXI4 wrapper verilog file.

 

If he amended the interface as follows:

module myAdder8bit(

input CLK,

input A,

input B,

input physicalSwitchOnTheBoard,

output S

);

and in the AXI4 wrapper, the user logic was something like this:

myAdder8bit UIP ( .CLK(S_AXI_ACLK),  .A(slv_reg0[7:0], .B(slv_reg0[15:8],  .physicalSwitchOnTheBoard( IDONTKNOWWHATTOPUTINHERE    )   ,  .S(adder_out   )  ;

 

what would I substitute in for "IDONTKNOWWHATTOPUTINHERE"?

 

Edited by electronicsdevices

Share this post


Link to post
Share on other sites

Recommended Posts

  • 0

Create a verilog module in the project manager. Once it is in the project, go into your block design, right click, and select "Add Module". This only works in Vivado 2016 and 2017. It's a relatively recent feature where Vivado is able to interpret verilog and vhdl source files as IP. Parameters to your modules will show up when you double click the "IP" to edit it's settings as well.

Share this post


Link to post
Share on other sites
  • 0

A few notes, I wouldn't use this in a project I was going to release, it would definitely be better to create a custom AXI IP, and I can go into how to edit the template later if you want (we have some tutorials, but they only really cover PS-PL data transfers). I find this method fantastic for prototyping something. Important addendum is that Vivado cannot package modules added like this into IP, at least in 2016.

Share this post


Link to post
Share on other sites
  • 0

I apologize if a lot of this is redundant with the tutorial.

First, create a new axi4 peripheral, this you probably know.

Spoiler

package.png.e41f3a55c3779c84ccb900bf6d8a6e10.png

You can edit the number of registers and size of them, in case you need more than 4x32 bits in your interface. I believe that adding more registers or making them wider does not affect your bandwidth over AXI, so this is just a convenience.

Spoiler

settings.png.8dd4c238f9c2d78115c5953bd3f2b845.png

MAKE SURE you select edit IP before finishing.

Spoiler

edit.png.2c19eae033dfc45427725429a96e24d9.png

More to come...

Share this post


Link to post
Share on other sites
  • 0

In the template, you can find a few relevant areas when it comes to customization:

First, the place to put any parameters you want to add.

//Users to add parameters here

Second, the place to put any additional ports you want to add. For instance, if you wanted to connect LEDs to your IP.

// Users to add ports here
output [3:0] led,

If you wanted to connect to switches.

input [3:0] sw,

If you want ports and/or parameters to the IP, you need to add them to the port maps of both <myip>_v1_0.v and <myip>_v1_0_S00_AXI_inst. Make sure to edit the instantiation of the "Axi Bus Interface S00_AXI" as well.

 

Relevant code in myip_v1_0_S00_AXI:

If you want to configure one of the register addresses to communicate from PL to PS, you will need to edit the synchronous process on lines 211-261 of this file. Comment out lines referring to the slv_reg# that you want to replace. If you want to change the name of the slv_reg#, make sure to replace it in lines 365-368 as well. The slave register can be replaced with a wire output of a verilog module you want to instantiate, for instance.

 

This is key to getting communication set up:

If you want a particular address to be written from the processor: use the slv_reg with the appropriate number (with 32 bit wide registers, slv_reg1 would be located at BASEADDR+4 when you are using Xil_Out32) in code added in the section at line 392 (Add user logic here).

If you want a particular address to be read from the processor: replace all instances of that slave register's name when it appears on the right hand side of an assignment in the _S00_AXI file with your own signal. Comment out all instances where that slave register appears on the left hand side of an assignment.

Do not touch any other predefined signals in either file, unless you really know what you are doing.

You can basically do whatever you want in the Add user logic here area, as long as you keep in mind how your IP will be communicating with the rest of your design. AXI lets you communicate with the processor (one bit at a time), additional ports let you communicate with other IP, instantiated modules in the block design, and external ports, parameters let you reconfigure the IP while designing, so that you don't need to edit the IP again later (hopefully), and so that you can reuse it in different situations.

Edited by artvvb
switches are inputs...

Share this post


Link to post
Share on other sites
  • 0

The packager itself can look scary, but you don't need to worry about nearly any of the options if you are just trying to get something simple up and running. At this point, just merge your changes and Re-package the IP.

Share this post


Link to post
Share on other sites
  • 0

An example of what I would do for this would be the two attached verilog source files. The attached image shows how to make the parameters visible in the customization GUI. In the IP Packager's Customization Parameters tab, double click on any parameter you want to be able to change from your block design and check the Visible in Customization GUI box.

The IP that these files would instantiate sets things up so that the following should always evaluate to true. (the IP just copies slv_reg0 onto slv_reg1's address).

Xil_Out32(BASEADDR, value);
newvalue = Xil_In32(BASEADDR+4);
return (value == newvalue);

The led and sw ports can be resized by customizing the IP in your block design. If you make those ports external in the block design and then properly constrain them, then Xil_Out32(BASEADDR+8, value); will set your boards leds, while Xil_In32(BASEADDR+12); will return the state of your boards switches.

myip_v1_0.v

myip_v1_0_S00_AXI.v

parameters.png

Share this post


Link to post
Share on other sites
  • 0

@artvvb

1) What was the reason behind not using slv_reg1 in your design? Also, I noticed you did not comment out the "slv_reg1 <= 0;" part on line 218 or the "slv_reg3 <=0" on line 220 of the AXI file. Why?

2) What was the reason behind dumping the contents of slv_reg0 in the case of 2'h1 in addition to 2'h0 (i.e. why twice)?

3) It looks like you chose slv_reg2 for the LEDs. So that means I should be able to do something like Xil_Out32(BASEADDR+8, 0x00001001) if I want to light the 1st and 4th LEDs then right? Suppose I want to turn on the LED if I flip a switch. Could I replace the user logic with

assign led = sw;

so that I could avoid using the SDK to set it if I wanted to?

 

 

Edited by electronicsdevices

Share this post


Link to post
Share on other sites
  • 0

1) slv_reg1 isn't being used because it's memory address is taken by the feedback from slv_reg0. I have that address configured as read only.

For line 218, good catch, I forgot, and didn't actually test this code, just knocked it together quickly to illustrate :).

2) As previously mentioned, this is intended to illustrate how to set up read-only and write-only registers. The assignment on line 369 is intended to show how to get data from PL to PS, the same as on line 371, but with the data flow coming from the processor instead of a port.

Lets assume that we treat each slave reg as a port of it's own, the code I posted was intended to map to something a little like the following pseudo code. I am thinking of the slv_reg# ports in this pseudocode block not as actual registers, but as what the processor will need to treat the associated addresses as.

module thing (
	//ports
    output [N-1:0] led,
    input  [M-1:0] sw,
    //implied bus to processor
    input [31:0] slv_reg0,
    output [31:0] slv_reg1,
    input [31:0] slv_reg2,
    output [31:0] slv_reg3
);
    parameter N=4;
    parameter M=4;
    assign led = slv_reg2;
    assign slv_reg3 = sw;
    assign slv_reg1 = slv_reg0;
endmodule

3) Absolutely, but if you aren't using SDK, there isn't much reason to include the AXI code. At that point you might just be better off with a pure-hdl project.

Something you could do that would be similar, but take advantage of the AXI bus would be:

assign led = sw | slv_reg2;

 

Share this post


Link to post
Share on other sites
  • 0

@artvvb

I feel like I'm learning a lot, but there are still some things I'm unclear about:

1) On line 369, I see 2'h1. Is that the address that slv_reg1 was using? Why use two addresses for the same slv_reg0? Also, I don't understand what you did that makes it read only.

2) Sort of the same question. I'm still trying to make the connection as to how dumping the contents of slv_reg0 in the case of 2'h1 in addition to 2'h0 leads to setting up read-only and write-only registers

Share this post


Link to post
Share on other sites
  • 0

2'h1 is the offset from the base address in terms of the registers, so it would be offset by 4 when accessing from SDK.

Where I think you are getting confused is in thinking about memory addresses as seen by SDK as "registers", which has a different meaning in the context of the HDL. SDK accesses the HDL code you define based on memory addresses, the HDL converts these addresses into values it can use to select which slave register to write to, or which piece of logic to read from. The process starting at line 213 defines how addresses are translated into registers when SDK writes values into the slave registers, so commenting out cases here defines which addresses cannot be written to. With the 2'h1 case commented out, calling Xil_Out32(BASE_ADDRESS+4, ...); will not have any effect on the values that your HDL sees. The process starting at line 363 defines how addresses are translated into what data will be read back into SDK.

The way to think about this is that 213 defines what and where Xil_Out32(base_address + 4*HDL_address, data); will write into the slave registers. 363 defines what data will be selected when you call Xil_In32(base_address + 4*HDL_address);.

With this in mind, the address represented by the read 2'h1 case selects the data previously written into slv_reg0 by the write 2'h0 case.

Does that help?

 

Share this post


Link to post
Share on other sites
  • 0
On ‎08‎/‎11‎/‎2017 at 1:54 AM, artvvb said:

Lets assume that we treat each slave reg as a port of it's own, the code I posted was intended to map to something a little like the following pseudo code. I am thinking of the slv_reg# ports in this pseudocode block not as actual registers, but as what the processor will need to treat the associated addresses as.

 

 

Dear

I'm newbie to AXI core. I have reviewed all your replies and I have learned lots of things.

Actually I'm puzzled when I want to add some Verilog code under "Add User Logic here" section.

for example I  set slv_reg0 with a number in the SDK. (I have used Xil_Out32(add,0x2311))

the first 16 bits of slv_reg0 is dedicated to the Hours

and second 16 bits of slv_reg0 is dedicated to the Minuets

after that I will convert the HH and MM to a proper 7 seg code. (using a lookup)

now how should I write a module under "Add User Logic here"?

Actually in pure Verilog coding it's easy but here I'm very puzzled!

could you please help me? please.

Edited by xzsawq21

Share this post


Link to post
Share on other sites
  • 0

Hi @xzsawq21,

Can you be more specific on what your project is trying to accomplish? Are you trying to show hours and minutes on a seven segment display using microblaze and AXI4 IP cores? You might benefit from using the Add A Module function in the Vivado Block design as described in this forum thread. The add a module allows you to use a Verilog module with microblaze and the AXI bus.

thank you,

Jon

Share this post


Link to post
Share on other sites
  • 0
33 minutes ago, jpeyron said:

Hi @xzsawq21,

Can you be more specific on what your project is trying to accomplish? Are you trying to show hours and minutes on a seven segment display using microblaze and AXI4 IP cores? You might benefit from using the Add A Module function in the Vivado Block design as described in this forum thread. The add a module allows you to use a Verilog module with microblaze and the AXI bus.

thank you,

Jon

Actually I don't use Microblaze. I only use Cortex-A9 PS and PL side of Zynq7020

Share this post


Link to post
Share on other sites
  • 0

Hi @xzsawq21,

The add a module function works with the zynq processor as well. What zynq board are you using? Here is another tutorial for using the custom ip core if you would still prefer to use the custom ip core instead of the add a module function.

thank you,

Jon

Share this post


Link to post
Share on other sites
  • 0
3 minutes ago, jpeyron said:

Hi @xzsawq21,

The add a module function works with the zynq processor as well. What zynq board are you using? Here is another tutorial for using the custom ip core if you would still prefer to use the custom ip core instead of the add a module function.

thank you,

Jon

what difference is between adding a module and creating an AXI Custom IP? for these days I'm coding to learn creating AXI IP core but very soon I should crate some custom IP to work with a high speed ADC and DAC to save some big data on DDR3.

Share this post


Link to post
Share on other sites
  • 0

Hi @xzsawq21,

Here is the Vivado Design Suite User Guide Creating and Packaging Custom IP and here is the Vivado Design Suite User Guide Designing IP Subsystems Using IP Integrator. My understanding is that the custom IP initially handles the AXI bus and through the process of creating the IP you will add in RTL to accomplish a desired result. The add a module allows an RTL module to connect to the AXI bus. The guides linked will be able to give a better explanation for each process.

thank you,

Jon

 

Share this post


Link to post
Share on other sites
  • 0

I really need your help. my time is very restricted

this is my sources

could you please check it?

1-the block design:

test1.PNG

 

I added the below ports in my AXI core:

		// Users to add ports here
            output [3:0] out_mux,
            output a, b, c, d, e, f, g, dp,

I have added my module as following: in my AXI core ( especially take a look from clk_100MHz to m0) is it right?

	// Add user logic here
	
	my_7seg_hdl U1(
	
	.clk_100MHz(S_AXI_ACLK), 
	.res(S_AXI_ARESETN),
	.h1(slv_reg0[15:12]),  
	.h0(slv_reg0[11:8]), 
	.m1(slv_reg0[7:4]), 
	.m0(slv_reg0[3:0]),  
	.a(a), 
	.b(b),  
	.c(c), 
	.d(d),  
	.e(e), 
	.f(f),  
	.g(g),  
	.dp(dp), 
	.out_mux(out_mux));


	// User logic ends

my module:

module my_7seg_hdl (clk_100MHz, res, h1, h0, m1, m0, a, b, c, d, e, f, g, dp, out_mux);

input clk_100MHz;
input res;

input [3:0] h1, h0, m1, m0;

output a, b, c, d, e, f, g, dp; 
output [3:0] out_mux;

reg [6:0] sseg;
reg [3:0] out_mux_temp;
reg reg_dp;

reg [19:0] refresh_counter;
wire [1:0] LED_activating_counter; 

always @(posedge clk_100MHz or posedge res)
    begin 
    if(res==1)
        refresh_counter <= 0;
    else
        refresh_counter <= refresh_counter + 1;
end 
assign LED_activating_counter = refresh_counter[19:18];



always @ (*)
    begin
        case(LED_activating_counter)
        
            2'b00 : 
            begin
            sseg = m0;
            out_mux_temp = 4'b1110;
            end
            
            2'b01:
            begin
            sseg = m1;
            out_mux_temp = 4'b1101;
            end
            
            2'b10:
            begin
            sseg = h0;
            out_mux_temp = 4'b1011;
            end
             
            2'b11:
            begin
            sseg = h1;
            out_mux_temp = 4'b0111;
            end
            
        endcase
    end
    assign out_mux = out_mux_temp;

reg [6:0] sseg_temp; 
always @ (*)
    begin
        case(sseg)
        4'd0 : sseg_temp = 7'b1000000;
        4'd1 : sseg_temp = 7'b1111001;
        4'd2 : sseg_temp = 7'b0100100;
        4'd3 : sseg_temp = 7'b0110000;
        4'd4 : sseg_temp = 7'b0011001;
        4'd5 : sseg_temp = 7'b0010010;
        4'd6 : sseg_temp = 7'b0000010;
        4'd7 : sseg_temp = 7'b1111000;
        4'd8 : sseg_temp = 7'b0000000;
        4'd9 : sseg_temp = 7'b0010000;
        default : sseg_temp = 7'b0111111; //dash
        endcase
    end
    assign {g, f, e, d, c, b, a} = sseg_temp; 
    assign dp = reg_dp;

endmodule

 

the SDK code to send a number 2314 (h1=2 and h0=3 and m1=1 and m0=4):

#include "stdio.h" //printf
#include "platform.h"
#include "xbasic_types.h"
//#include "xil_types.h"
#include "xparameters.h"
#include "xil_printf.h" //xin_printf
#include "xil_io.h" //xil_in32 , xil_out32
#include "sleep.h" //sleep()


u32 *BASEADDR_p = (u32 *)XPAR_AXI_MY_7SEG_0_S00_AXI_BASEADDR;


int main()
{
init_platform();

xil_printf("Project Started\n\r");

*(BASEADDR_p+0)=0x2314; //Write to register 0, Actually h1=2 and h0=3 and m1=1 and m0=4
sleep(2);


cleanup_platform();
return 0;
}

 

Edited by xzsawq21

Share this post


Link to post
Share on other sites
  • 0

There is a key point:

you don't have to comment any slv_reg#

After exporting hardware to SDK Launch on hardware(GDB) is not enough.

You have to program FPGA, then  Launch on hardware (System debugger) instead of (GDB) .

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now