• 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

Posted (edited)

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

37 answers to this question

  • 0

@electronicsdevices,

Leaving the Vivado SDK?  A good choice, IMHO.  ;)

But ... how do you modify inputs and get outputs out?  As you are discovering, it's not as easy as it sounds.  Debugging can be a challenge as well.  Your biggest problem: good engineering discipline and practice requires that no more than one component be under test at any given time.  While I see you've minimized the items you wish to place under test, you've still got a lot of things to work with that .. each may fail individually.  How you will isolate any broken component will be your challenge.

This leads me to a couple of thoughts:

  1. Simulate your design first, before running on the hardware.  I have found and love Verilator as a tool, and I've written a short tutorial on how to use it.
  2. Use a known working interface, one that isn't likely to suffer from electronic contact bounce (such as the switches), or need logic that needs to be debugged (the 7-segment display) to get yourself started.  I recently described building such an interface on the ZipCPU blog.  Indeed, I'm hoping to present measurements of button bounces later this week ... but that wasn't your question.  I have used this basic approach with the Basys3 with complete success--it depends only on a working serial port, although I tend to use a more sophisticated debugging bus, that uses compression as well.
  3. Using such a bus, you might run a C++ program and give it a command such as fpga->writei(R_MATRIX_A, sizeof(amatrix), amatrix);, and then repeat for your matrix B.  (The blog discusses how this interface works, and shows examples of how to build your own if you want.)
  4. The example code even comes with a scope that you can use to see what is going on within your design.  You can find a discussion of how to set it up here.
  5. Much against my own better judgment, the example code is all nicely licensed under the LGPL.  (I tend to use and like GPL)  If you improve upon it, please share your improvements with others.  :)

What makes all of this really unique is that a lot of new FPGA designers, such as yourself, will try what seems like a very simple project (like the one you outline above), only to have something about it not work ... at which point these new FPGA designers get frustrated and often give up.  I like to call this situation FPGA Hell, defined by when your logic isn't working and you have no idea why not, nor any trace giving you information about what went wrong.

Hopefully this gets you moving in the right direction.  If not, just holler,

Dan

electronicsdevices likes this

Share this post


Link to post
Share on other sites
  • 0

@D@n

Thank you for the link to Verilator. I was looking for something like this.

I will look the rest of you points at a later time, but you should know that my intention wasn't to leave Vivado SDK, but rather, build an IP that has a switch that uses the logic on-board the FPGA to multiply two matrices independently of Vivado SDK. Since it requires an AXI4 interface, I will still need to use VIvado SDK because I will be using it to change the values of the matrices during runtime. However, I also want to multiply the contents of A and B by flipping a switch and this is the part of the design that should not rely on Vivado SDK. Unfortunately, I know of no way to combine the two requirements, which is why I am asking for help.

Share this post


Link to post
Share on other sites
  • 0

@D@n It doesn't even have to be on one IP. I just need to figure out a block design to where the FPGA has an AXI4 interface where a user can use VIvado SDK to change values, but the matrix multiplication itself is triggered by flipping a switch, and preferably the switch is not being monitored by Vivado SDK. I'm interested in minimizing the time it takes for the user to hit a switch to start the multiplication and if I have Vivado SDK monitor the switch, then that adds extra time.

Share this post


Link to post
Share on other sites
  • 0

@electronicsdevices

Adding additional ports to an AXI IP goes something like this:

[LINE 16]
// Users to add ports here
input switch,
// User ports ends
// Do not modify the ports beyond this line

...

[LINE 73 ish]
// Add user logic here
mymodule module (
.clk(s_axi_aclk),
.axi_port(slv_reg0),
.sw_port(switch)
.out_port(out_bus)
);
// User logic ends

note that when adding ports, you need to make sure that you modify both AXI wrapper files.

Hope this helps,

Arthur

Share this post


Link to post
Share on other sites
  • 0

Adding that you can later group a set of ports as a bus interface in the IP packager, but you don't need to worry about that for the application you described.

Share this post


Link to post
Share on other sites
  • 0

Posted (edited)

@artvvb

Here is my first attempt at implementing your suggestion. After putting this IP in a block design however, it does not prompt me to select pins for switches and LEDs. You had mentioned I need to edit both AXI files. I usually only edit the myipname_v1_0_S00_AXI.v. I tried to  copy and paste my changes from this AXI file to myiptest.v, but I get an error because myiptest.v does not have the slave registers I need, so I left that entire section blank. Where do I go from here?

MMultAXI4v

myiptest_v1_0_S00_AXI.v

myiptest.v

Edited by electronicsdevices

Share this post


Link to post
Share on other sites
  • 0

@electronicsdevices

You need to map the new ports you have created in myiptest_v1_0_S00_AXI when you instantiate it in myiptest. Just like when you instantiate your MMultAXI4 module, you need to make sure that you map all of the different ports available. Take a look around line 64-84 of myiptest.v to see what I am talking about.

At a glance, this looks close.

Hope this helps,

Arthur

Share this post


Link to post
Share on other sites
  • 0

@artvvb

Second attempt. I added signals to the already existing myiptest_v1_0_S00_AXI_inst and changed some names in myiptest of ports I got working in my original verilog design. The IP will synthesize, but I'm still not getting anything that is saying I need to specify a switch in the implementation phase. It is complaining about diff_clock_rtl_p not being implemented though.  MMultAXI4v remains unchanged.

myiptest_v1_0_S00_AXI.v

myiptest_v1_0.v

Share this post


Link to post
Share on other sites
  • 0

@electronicsdevices

Could you provide a screenshot of the block design which you have placed your IP in? seeing how the ports are laid out on the block, as well as how and what they are connected to may help.

Share this post


Link to post
Share on other sites
  • 0

Posted (edited)

@artvvb

All I really did is put mytestip and Microblaze on it. 59836781b3ddc_Screenshotfrom2017-08-0313-09-36.thumb.png.cd59680564271307f42a24f1f9764a4a.png

I'm wondering why it isn't complaining that I haven't assigned a switch to A,B,Z, and MMult_AB.

That's kinda what I don't get about it. I'm making a hybrid model of sorts. If instead I write it with just verilog, then when I go to implement the device, it asks me what switch I want to use (I didn't specify an .xdc file intentionally). In the past, if I wanted to use a switch, I could do that by adding the switch IP to the block design. I'm not really sure what to do if I want to combine the approaches.

Edited by electronicsdevices

Share this post


Link to post
Share on other sites
  • 0

Posted (edited)

@D@n

From reading your website, you seem to be a fan of simulation:

On 8/1/2017 at 3:28 PM, D@n said:

 

This leads me to a couple of thoughts:

  1. Simulate your design first, before running on the hardware.  I have found and love Verilator as a tool, and I've written a short tutorial on how to use it.

 

So I decided to simulate my design (even though I know it already works). I wrote the testbench and simulated it. What I want to happen is this: when the MMult_AB and Z switches are turned on (and A and B are off), the FPGA should multiply matrices A and B, check to see if the results are correct, and light an LED if they are. What the simulation says however, is that once MMult_AB and Z are both on, the LED automatically lights up (i.e. no delay). Of course, there must be some sort of delay, but this is not shown in the simulation. So how do you measure the delay?

59837c45b8a22_Screenshotfrom2017-08-0314-27-10.thumb.png.7658fa83277077bd708bc699837a5d7f.png

MMultAB_tb.v

MMultAB.v

Edited by electronicsdevices

Share this post


Link to post
Share on other sites
  • 0

@electronicsdevices,

Gosh, look what your simulation just revealed ... (I reviewed MMultAB.v only, not MMultAB_tb.v)

  1. Your design (MMultAB.v) takes no time at all, since none of the transitions take place on the positive edge of any clock.
  2. The synthesizer did all your logic for you, and only programmed the result into the resulting registers.  No operations actually took place.  A simple set of 4-input LUTs (A, B, C, and MultAB) can be used to select among four apriori known answers.  It's a memory lookup to the answer, rather than any computations taking place.

So, let me ask, are you sure your design actually does what you want it to?  And, since you hadn't simulated your design, you really only had a false sense of what your design was doing up until now.

So, yeah, I am a big fan of simulation.  This is a wonderful example of why.

Were I to redo this, I'd rebuild the module so that the FPGA inputs could be set externally.  That would keep the synthesizer from optimizing away your logic.  It would also fail timing, forcing you to put the clocks back in that you need.  As for setting it externally, may I recommend using a debugging bus?  I like to use that to read/write an FPGA's data from software.  I consider the debugging bus interface to be more reliable than buttons and switches, but you may need to read the next several blog posts to know why.  (Or read the wikipedia paragraph on contact bouncing, and take a look at what buttons can do that you aren't expecting here)

Dan

electronicsdevices likes this

Share this post


Link to post
Share on other sites
  • 0

@electronicsdevices

And look at what your block design revealed, your ip should have additional ports for the inputs and outputs in your "Stuff I Added" section of myiptest_v1_0.

Have you merged file changes into the IP packager and re-packaged your IP since you added these ports? After doing so you will need to Refresh your IP repo and Upgrade the myiptest IP. "Refresh" should show up in a pop-up after you re-package, and you can do the Upgrade by doing Tools -> Reports -> Report IP Status, and then clicking Upgrade All.

Share this post


Link to post
Share on other sites
  • 0

Posted (edited)

@D@n

So for whatever reason, the matrix multiplication from the prior version would return the zero matrix in simulation. So I decided to scrap the design and start over.

I started off with the most basic part (the matrix multiplication) and got that working. I didn't hardcode the values like I did before. I put them in the testbench instead.

When I ran the simulation, I get the correct result, but again, no delay.

5988e9f0a579b_Screenshotfrom2017-08-0717-23-47.thumb.png.f6d22c8ed010c4317ae3d5417bdb58aa.png

 

Is it even possible to get some sort of delay in a simulation without using physical parts? You mentioned clocks. I tried that with a prior simulation, but I still got no delay

5988e99d3e44f_Screenshotfrom2017-08-0314-27-10.thumb.png.f7f4ed4bc66ee4f33eccac851f4d40ec.png

 

I also tried your debugging bus and ran into some issues as I followed your tutorial:

http://zipcpu.com/blog/2017/06/29/sw-dbg-interface.html

The big one is that there is no makefile in ~/filepath/dbgbus. I ended up compiling each individual makefile and got it to work, but still, what you say in the tutorial doesn't work when you try it.

5988eb8fa3525_Screenshotfrom2017-08-0716-56-45.thumb.png.1ec782a0a2f7de913be6554c24f2cd4e.png

 

I also tried writing to the BRAM named "MEM," but that register wasn't recognized. I think it's because earlier on in the tutorial there was source code I need to have written prior to testing it.

5988ebd535455_Screenshotfrom2017-08-0717-13-52.thumb.png.52bc25e3133809b60285787a8107e37f.png

 

How do I build a design where I can get some sort of delay that would be comparable to real life? The issue seems to be the compiler makes it so the design doesn't need to do the calculation, so you mentioned externally feeding the FPGA values, but how is that possible in a simulation? I can do it with Vivado SDK easily, but that's in realtime. The simulation is important, but how can I get reasonable data if the compiler is preventing the very behavior I want to examine?

Verilog files are attached.

 

 

Mult_AB_tb.v

Mult_AB.v

Edited by electronicsdevices

Share this post


Link to post
Share on other sites
  • 0

@electronicsdevices,

Your design takes no time at all, because that was what you told it to do.

If you want logic to take place "instantaneously" in a simulator, use an "assign" statement, or use an always statement that doesn't depend upon a clock.  "always @(posedge clk)" will require that the logic take a clock to take place.  Further, your test bench file itself will need to "create" the clock.  A little google turned up this article which discusses how to make a clock within your testbench. 

The simulator, though, doesn't match reality and in reality all logic takes time.  Your goal as a designer is to make sure that the time required by your logic is a touch less than the time between clock ticks.  Multiplies and adds take time.  I'm going to wager that "a0*b0+a1*b2" takes 2 DSP's and 20ns to do.  (It could be as fast as 10ns ... might be worth measuring.) 

Thank you for pointing out the issues with the debugging bus.  I think I've now fixed all of them.  Try going into the debugging bus directory, running "git pull" and then "make" from the main directory.  There's now a makefile there.  I also fixed the oversight of not having a register named "MEM" in regdefs.cpp.  That's now been fixed.

As for a design with a delay that would be comparable to real life ... I've only ever managed to do that by working back and forth with Vivado to implement my design.  Once my design implements, I know the delays within it are close to real life.  Use the clock, though ... Vivado is going to measure your design against the constraint that logic created on one clock must be completed before the next clock.  Vivado can only make that measurement when your logic starts on one clock and has to complete by the next.

Is it possible to externally feed an FPGA values in a simulation?  Yes.  I do it all the time.  The dbgbus simulation is doing that with the UART (it's just a C++ program ...).  However, that simulation isn't connected to the amount of time an operation requires.  To get that, I both simulate and build my design.  When building it, I check that it meets any timing requirements, etc.

Dan

Share this post


Link to post
Share on other sites
  • 0

@jpeyron, @D@n, @artvvb

I have this register in verilog code called usb_uart

598b943a00372_Screenshotfrom2017-08-0917-59-03.png.0db9969179bf888606ecd67a35f47dbf.png

 

and I have a UART IP that maps to something called usb_uart

598b946c63463_Screenshotfrom2017-08-0917-59-53.thumb.png.2db9d80f6a85be9377a82cde47a26b7c.png

Is there a way to use Vivado SDK or some other software to read/write the value of this register?

 

Share this post


Link to post
Share on other sites
  • 0

Do you mean the register or the port out of your block design?

3 minutes ago, electronicsdevices said:

Is there a way to use Vivado SDK or some other software to read/write the value of this register?

 

Share this post


Link to post
Share on other sites
  • 0

Creating an AXI wrapper for a module is the (xilinx suggested) way to communicate from PS to PL.

You can also connect ports of modules you have added to your block design to GPIO controllers, though this is hacky (I occasionally use it to prototype an AXI IP).

 

If you are having trouble putting what you want to do in words, an MS Paint drawing of the block design you want to create might help...

Share this post


Link to post
Share on other sites
  • 0

What I want is to create a design where the matrix multiplication is implemented in verilog code (i.e. the FPGA itself does the calculation), but the values of the matrices can be read/written from/to a register (e.g. the register I named "usb_uart) in realtime (i.e. after the bitstream has been written to the FPGA) with some sort of software.

Share this post


Link to post
Share on other sites
  • 0

Is the register named USB_UART for a reason? Do you want to read the values from Microblaze or your PC? The name makes things a little confusing...

Share this post


Link to post
Share on other sites
  • 0

I was hoping that the port called "usb_uart" could somehow tie into the register in the verilog code I want to read from. So I named it "usb_uart" wiith the hope that the two would somehow communicate. I would like to read and write values to this register I named "usb_uart" using software on my PC. I just don't know what interface I can use to accomplish this. Vivado SDK and @D@n's debug bus seem to be two ways to do it.

Share this post


Link to post
Share on other sites
  • 0

@electronicsdevices,

There's another way to do it, I just don't have the experience from having done it.  The other way is to create your own IP that interacts with the AXI bus.  Vivado's SDK will then connect to that IP.  You can then read and write your registers from the on-board processor (ARM or uBlaze).

Dan

Share this post


Link to post
Share on other sites
  • 0

@electronicsdevices

I'd suggest trying to tie a verilog module to your processor by connecting it's ports (other than stuff like clock) to an AXI GPIO controller. It's a little slower and uses a bit more resources than fully creating your own IP, but can be done fairly quickly. An example below:

 

ex.png

Share this post


Link to post
Share on other sites
  • 0

@D@nI've created my own IP before, so that's not an issue. What I would like is for this IP to interact with some Verilog code I have written (for instance, use AXI4 to read/write to a register in the Verilog code I wrote). I know that I can use xparameters.h to find registers in my custom IP I can read/write using Xil_Out/Xil_In. Maybe there's a way to feed that into a register in Verilog. I mean that gets turned into something on the FPGA anyways. I just don't know how to write/read to it.

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