Jump to content
  • 0

How do you use verilator with Xilinix unimacro elements?


Avogadro

Question

Hello,

I was having problems using verilator for a design thats using BRAM_SINGLE_MACRO for single port RAM. I have found the instantiation template from https://www.xilinx.com/support/documentation/sw_manuals/xilinx2012_2/ug953-vivado-7series-libraries.pdf

I decided to make a module with just the macro and try to get it working with verilator (I attached the .v file).

When running the command:

Verilator -Wall -cc BRAM_test.v

Im getting a lot of errors(I attached a txt with errors). Im not sure how to fix this or if Im doing something wrong. Im pretty new at this and at using the verilator.

Any help would be appreciated.

BRAM_test.v Error.txt

Link to comment
Share on other sites

21 answers to this question

Recommended Posts

I realize that more than a few readers of this thread don't care about what I think. So I say don't take my word for it, take Einstein's advice on FPGA ( and a lot of similar ) development:

Loosely paraphrased: "Things should be as simple as they can possibly be, but now simpler. Things should be as complicated as they have to be but no more complicated".

Einstein was a pretty smart fellow wasn't he?

Link to comment
Share on other sites

3 minutes ago, zygot said:

Who, in there right mind would do an HDL design using overly complicated bus structures when it doesn't have added value and overly complicates a design?

Someone who didn't have to pay for the hardware they were selling, of course!  ??

Link to comment
Share on other sites

6 minutes ago, D@n said:

They have an AXI based block RAM IP block that gets horrendous throughput performance, whereas you could get nice one write per cycle performance from simply inferring a block RAM.

I always use native, not AXI, interfaces when using the memory Wizards for ram or FIFOs. Who, in there right mind would do an HDL design using overly complicated bus structures when it doesn't have added value and overly complicates a design? I don't want to offend anyone but i feel the same way about Wishbone and all the other bus standards.

Link to comment
Share on other sites

@Avogadro,

7 minutes ago, zygot said:

For FPGA memory resources you can use the wizards to implement various kinds of structures and select either distributed (LUT) ram or block ram.

Be aware when or if you do this that Vivado's block RAM controller is not the same as their block RAM.  They have an AXI based block RAM IP block that gets horrendous throughput performance, whereas you could get nice one write per cycle performance from simply inferring a block RAM. 

What do I mean by horrendous?  Horrendous = N+3 clocks per burst transfer for a burst of N beats, with a worst case performance of one transfer every 4 cycles for random access.  Worse, it only allows either a read burst or a write burst but never both at the same time--their actual block RAM is much better than their AXI block RAM IP controller.

Personally, I think the problem is AXI ... but that's really another debate for another forum topic.

Dan

Link to comment
Share on other sites

For FPGA memory resources you can use the wizards to implement various kinds of structures and select either distributed (LUT) ram or block ram. The second approach is to use the primitive macros in you HDL and do basically the same thing. The third approach is to write HDL that follows the guidelines that every FPGA vendor supplies to infer a particular memory structure.

The third approach is the most portable; or as portable as can be given that block ram is organized and works differently between vendors and devices. The easiest is the first approach but you may have to go through the process every time Xilinx decides to break it's own IP ( such as Vivado 2019.x ). At least you get some help with constraints. The second approach is self-documenting.

Which of these do I use? All of them. How do I choose? It depends.

Do pursue the documentation provided by your FPGA vendor to learn how to use all three approaches successfully and know how to decide which is best for any particular project.

[edit] One thing that I forgot to mention about using wizards is that they are happy to waste resources if that's fine with you. If you are concerned with resource management then the other two options might force you do work out a non-straight forward plan. Of course you have to be thinking about what you are doing and what the costs are in the first place; and the point of Wizards is to allow you to be lazy and let someone else do the thinking. Just understand that Xilinx sells silicon so there's a price for letting them think for you. Even so, there's plenty of times where wizards work out in your favor as long as you understand what's going on behind the backdrop.

Link to comment
Share on other sites

@Avogadro,

If it's any help, you are more than welcome to look at my own Arty design.  I infer all of my block RAMs, and even include Verilator-based emulators for the serial port, DDR3 SDRAM (it's an AXI based emulator, rather than a true DDR3 SDRAM emulator), and the on-board flash.  Further, the design also includes Verilator-based emulators for an SD card and an OLEDrgb.

If you look through Xilinx's doc's, you'll find a description of how to write your RAM so that it gets properly inferred.  It's much easier to do that way.  I have my own rules, which are somewhat stricter--mostly because I like to infer RAM across multiple architectures.  For example,

  1. Any RAM accesses should be in their own always block (their own process, for you VHDL types)
  2. RAM can only be iniitalized once.  (This seems to be a common misperception.  Re-initializing RAM doesn't work though.)
  3. Don't place a RAM into a cascaded if statement.  (This once kept my FFT from using block RAM.)
  4. Don't try to place a RAM in a port list.
  5. Don't place a RAM block in a process with other things

Even then I sometimes get surprised.  For example, on one architecture, my RAM wasn't inferred because the register I read from RAM into was given an initial value.

Xilinx allows some things other chips don't.  For example, you don't need a clock to read from a block RAM.  It is possible to read from block RAM and do something on the same cycle, just ... not necessarily recommended for timing reasons.  There's also a way of writing to RAM in a way that it they new value can be read out on the same clock cycle.  I've never done it, and just examining the prototype code makes it look like it might work in hardware but fail in simulation--another reason for not trying harder.

You can read more about my "rules" for block RAM usage in lesson 8 of my tutorial.

Dan

Link to comment
Share on other sites

>> I see that Vivado will use that block ram if I describe the memory as its written in the document he linked on page 106. Im I understanding this correctly?

Yes but you should check the logs carefully (utilization), and dig into the implemented schematic from time to time. Try to verify your assumptions - this can be full of surprises. Hint, go at least to the timing report and review where the critical paths are passing through.

For example, RAM in "logic" (FFs) is the worst-case option when nothing else can be done but very expensive. Before that comes "distributed" RAM which is a special operating mode of the LUT hardware.

But, feel free to instantiate BRAM - there is no simple right or wrong.

Link to comment
Share on other sites

Hey @D@n,

Yes there were quite a few errors but ignored all those ?. I read the documentation a bit better and now I see that .SRVAL and .INIT is expecting a 72 bit hex value. My mistake was assuming that it needs a number of bits equal to the READ_WIDTH. After fixing that Im just getting the "Little bit endian vector" warning (whats the proper way of dealing with this warning?) and  "Cannot find file containing module: 'RAMB36E1'" (I had the same problem with BRAM_SINGLE_MACRO.v file which I just copy-pasted into the project folder. Is there a better way to link these files?)

For your question, Im designing something for the Arty board I have and macro seemed easier to use than to write my logic. Also I assumed that describing memory with something like reg [W-1:0] mem [0:((1<<AW)-1)]; would create that memory using logic instead of using the actual block RAM on Artix7 chip which I want to use. But after reading the @xc6lx45's comment I see that Vivado will use that block ram if I describe the memory as its written in the document he linked on page 106. Im I understanding this correctly?

Link to comment
Share on other sites

If I weren't so lazy, I would have quoted this:

3 hours ago, D@n said:

So, let me ask you the question, why are you designing at the device-dependent level instead of using the (mostly) device-independent Verilog language to describe your design?  Memory can just as easily be described as, reg [W-1:0] mem [0:((1<<AW)-1)];, and operated on as such.  You don't need to use the vendor macros to do this and indeed, I would recommend against doing so since it will hinder your design from being implemented on other hardware at a later time.

what I meant is the keyword to search for is "inference". For example page 106 shows how to code a RAM in plain Verilog so it will be recognized by Xilinx tools as block RAM or distributed RAM.

Link to comment
Share on other sites

1 hour ago, D@n said:

I look forward to being able to sit down with you and discuss these differences one day.  At this point, I expect I will have a lot to learn, but I doubt the conversation would fit within these forums easily.

Discussing differences in viewpoint and perspective can (should) always be mutually beneficial and enlightening; not only in understanding external realities but more importantly that of our own reality. Gaining insight as to how we come to identify concepts that we associate as true is often more important than being exposed to new ideas. Rarely, can we do this from within our own framework.

Link to comment
Share on other sites

2 hours ago, D@n said:

So, let me ask you the question, why are you designing at the device-dependent level instead of using the (mostly) device-independent Verilog language to describe your design?  Memory can just as easily be described as, reg [W-1:0] mem [0:((1<<AW)-1)];, and operated on as such.  You don't need to use the vendor macros to do this and indeed, I would recommend against doing so since it will hinder your design from being implemented on other hardware at a later time.

I didn't have the time to address this earlier. Portability is an ideal this is much chased and never quite achieved. The simple truth is that different FPGA vendors have different primitives that reflect the actual hardware for a particular device family. Sometimes primitives from different vendors that appear to have identical functionality are, on the surface, quite similar; often they are not. Sometimes there simply is no corresponding primitive between vendors or devices from the same vendor because of inherent differences in how the hardware works. Users can exacerbate the problem and often find ways to deal with it more efficiently but can't cure it.

I sometimes use macros and primitives and sometimes vendor wizards. There is a place for both if you know what you ( and the tools ) are doing. Either way, the burden of knowing is always on the designer.

Link to comment
Share on other sites

1 hour ago, zygot said:

Don't confuse the two as being interchangeable. Be suspicious of claims by people who haven't mastered both tools.

I look forward to being able to sit down with you and discuss these differences one day.  At this point, I expect I will have a lot to learn, but I doubt the conversation would fit within these forums easily.

Dan

Link to comment
Share on other sites

3 minutes ago, D@n said:

Verilator is the fastest simulator on the market

An ant, pound for pound is stronger than a man but I wouldn't hire an ant to transport my belongings during a relo. Vivado simulator and Verilator are two different tools. Using Verilator as a secondary simulator tool when simplifying a problem to a cycle based problem is acceptable and you need a quick result is fine. Don't confuse the two as being interchangeable. Be suspicious of claims by people who haven't mastered both tools.

 

10 minutes ago, D@n said:

I hate Vivado's warnings.  They are too useless

This isn't a problem of Xilinx simulators alone. I'm frequently mystified by the synthesis and implementation warnings depending on the tool version. You have to learn how to interpret Xilinx ISIM behavior in order to use it effectively. 

Link to comment
Share on other sites

10 minutes ago, zygot said:

You already have a proper simulator in Vivado. Learn how to write a testbench. Where's the Verilator evangelist when a potential convert needs him?

My web page froze when I tried to write example code into the forum.  Not sure why, but the <> button seems to be hanging my browser.

Dan

Link to comment
Share on other sites

@Avogadro,

As someone who uses Verilator religiously, you can ignore the comments by the others here.  :D  The fact that Verilator is the fastest simulator on the market today bar none keeps me interested in it.  Likewise, the fact that I can easily integrate my Verilator simulations with O/S calls is also useful.  Indeed, I was just "booting" a Verilated design from an SD-Card yesterday--starting from scratch, I ran the simulation through firing up the SD card, reading a file from it, copying the file to memory, and then jumping to that address in memory ... but I digress.

Another reason why I like Verilator is because I hate Vivado's warnings.  They are too useless.  It is next to impossible to generate a design, using Vivado, that will pass without warnings.  This can make it a challenge when trying to use the warnings to find bugs since there's so much noise to search through in order to find a valid bug--if one is revealed by design warnings at all.  With Verilator, on the other hand, it is not only possible but very doable to create a design without warnings and I do it regularly.  Xilinx seems to have picked a different road where they just ignore their warnings altogether.

I tried your files and I was able to repeat your test, with ... similar results.  (You didn't mention the number of warnings you received.)  Most of the warnings seem to be centered around parameters comparing strings of different length.  For example, if "SPARTAN6" == "VIRTEX5", then Verilator is generating an warning.  Vivado code uses this idiom often.  If you dig a bit further, though, you'll discover that your .INIT and .SRVAL values don't have the width the BRAM_SINGLE_MACRO is expecting.  Internal to the macro, the unisim library is attempting to access bits much larger than the width you've given from those numbers.  Expanding their width will get you past these errors--while still leaving a whole mess of useless warnings.

This isn't a problem I normally deal with, mostly because I don't normally use Verilator to instantiate low-level primitives.   (I have done it with the iCE40 to create a simulation from just a bitstream, but haven't done it yet with any Xilinx parts or components.)  Such lower level primitives can typically be left to the synthesis tool to instantiate, leaving no reason for me in my code to use them.  In the rare cases where I need to use them (PLLs, MMCMs, etc), I typically leave them outside of the Verilated portion of my design.

So, let me ask you the question, why are you designing at the device-dependent level instead of using the (mostly) device-independent Verilog language to describe your design?  Memory can just as easily be described as, reg [W-1:0] mem [0:((1<<AW)-1)];, and operated on as such.  You don't need to use the vendor macros to do this and indeed, I would recommend against doing so since it will hinder your design from being implemented on other hardware at a later time.

Dan

 

 

Link to comment
Share on other sites

Correct - and it's probably the easiest way with Xilinx blocks.

I'm a big fan of Verilator but actually know too little about it to become a missionary. I have once used, long ago, in a not-for-fun project to write drivers while waiting for an ASIC, and it worked as advertised.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...