zygot

Tales from the Trenches ( with apologies to WWI veterans )

Recommended Posts

If, like me, you do any significant FPGA development and in particular designs for a wide variety of devices and more so using devices from most of the programmable logic vendors, you run into "quirks" with the devices and tools that are unexpected and not easily resolved without a bit of luck and determination. A naive view of software development is that if you use a particular language, such as C, then all of the confusion as to what exactly the language syntax implies as regards to behavior and expression of that behavior in all machine code has long been settled. I can assure you that this is not the case. So, as complex as the FPGA tools are it shouldn't be a surprise that you might come upon strange and unexplainable problems. Add to that the occasional bug in any particular toolset and it's not uncommon to run into a wall now or then that should be there.

Since I know of no other venue for having a discussion about this I thought that starting a thread here might be useful. If you are a newbie to FPGA development you might find information posted here useful as well. At least you might develop an appreciation for the complexity of what's behind translating your HDL into working logic.

My hope is that new postings to this thread restrict their scope to presenting out-of-band issues that they've come across and resolved. Mentioning specific devices and toolset versions is important.

I've been thinking about starting this thread about 4 issues ago so if there's any interest I can feed the pipeline for a while.

Share this post


Link to post
Share on other sites

I've been posting quite a few "tales from the trenches" on ZipCPU.com.  Perhaps you've seen some of them?  Here's an article telling of some of the times I've gotten stuck.  Another article discusses reasons why simulation might not match the hardware implementation.  You can read here about one of the uglier bugs I've come across, or here regarding about all the bugs I found, and have since fixed using formal methods, in the ZipCPU.  Another fun one was a student's response to one of the articles I'd written, telling his tale from the trenches.

In general, though, I embed most of my tales from the trenches stories into topical articles.  For example, here's a fun recent one on how to build an SPI controller--including a discussion of how I had to work through a timing issue with the final SB_IO pin controller in an ODDR type of mode.  (That vendor doesn't call it an ODDR, but that's the mode the I/O was placed within.)

Perhaps that'll get the discussion going for you?

Dan

Share this post


Link to post
Share on other sites

Tool: ISIM

ToolSet Version: P.20131013

Target Device: KC7K325T-2GFG200C

 

Sometimes, you find a problem with a tool, figure out a resolution, and many months later step back into the same sinkhole again, wasting a few hours, until you remember....


I'm a big proponent of simulation. Of course simulation is only a tool. You can do good (adequate) simulation, bad simulation, useless simulation and simulation that lies to you. It's a form of art as much as anything else; really. It's also, in my opinion essential not only for verification purposes but in developing and exercising your skills as an engineer.

Lately, I've been working with ISE 14.7 Application Version P.20131013, which as far as I know is the very last version published by Xilinx. The sinkhole in question is a quirk in ISE ISIM. My project targets the KC7K325T-2GFG200C device and the KC705 development board from Xilinx. Why would I want to use ISE for a new project? Because I am also using a third party PCIe core that uses ISE. Why create unnecessary problems when toolset versions present more than I care to handle?

My design uses the Ethernet PHY and is mostly a port of code that I've been using successfully on the Spartan 6 based ATLYS development board. I've had no end of nasty surprises doing what I expected to be a rather routine port. I have a considerable number of designs for both of these boards completed so I generally have a good feel for the expected issues. But this post is about ISE ISIM.

It is important to mention how I use FPGA vendor tools. I use my own text editor. I am aware of issues with tools not recognizing when source code has been updated, or worse yet sometimes recognizing when source code has been updated.

The quirk prompting this post has reveals itself when I change source code and relaunch a current simulation. This always initiates a recompile ( if you are observant you will notice that ISIM complies executables of your simulation; no doubt to speed up the actual simulation). Occasionally, I'll make small changes to the source ( either the design or the testbench ) and not see an expected change in logic behavior. If I'm lucky, this happens when I change the testbench and It's fairly obvious that ISIM is ignoring my change. If I'm unlucky, this happens when I change design sources and I can quickly find my way down the rabbit hole conversing with a strange creature. Mostly, this issue for me involves forgetting past experiences and having a general mindset that if things aren't working, it must be me not the tools. Thankfully, it's usually me.

What I keep forgetting, when I've been away from ISE for a while, is that when ISIM simulations stop conforming to a reasonable sense of reality I need to do the following:

  • stop using the Relaunch button in the simulator
  • exit the simulator
  • in The ISE Processes window right-click the 'Simulate the Behavorial Model' process and select Re-Run All.

 This usually restores my sanity, at least for a while.

Edited by zygot

Share this post


Link to post
Share on other sites
4 minutes ago, [email protected] said:

Perhaps you've seen some of them?

I should have known that you'd be around as I got this thread started. I'm thrilled to see a reply as I submit the first post.

To answer you question; no I haven't but I promise to check out what you've been up to.

If this venue fails to show interest I'd be happy to conspire with you to create one that does.

Share this post


Link to post
Share on other sites

Quartus 15.0.0 Build 145 04/22/2015 SJ Web Edition
Device: Cyclone V 5CGTFD9E5F35C7

Here's the code snippet:

entity AN_ENTITY is
generic (
  num_crtl_regs    : integer := 1 -- the number of 64-bit read/write control registers

------------------
  signal  ctrl_offset         : integer; -- Quartus can't figure out what to do with this
--  signal  ctrl_offset         : integer range 0 to (num_crtl_regs*64)-1; --  to make Quartus happy
  signal  icontrol            : std_logic_vector((num_crtl_regs*64)-1 downto 0);

------------------

  CTRL_DATA_OFFSET_PROC : process(clk, hard_reset)
  begin
    if hard_reset = '1' then
      ctrl_offset   <= 8;
    elsif rising_edge(clk) then
      if current_state = IDLE then
        ctrl_offset   <= 8;
      elsif current_state = RDATA and ctrl_offset < max_offset then
        ctrl_offset <= ctrl_offset + 8;
      else
        ctrl_offset   <= ctrl_offset;
      end if;  
    end if;
  end process CTRL_DATA_OFFSET_PROC;

------------------
340  CONTROL_REG_PROC : process (clk, hard_reset)
341  begin  
342    if hard_reset)= '1' then         
343      icontrol  <= (others => '0');
344    elsif rising_edge(clk) then
345      if current_state = RDATA and ctrl_write_mask(7) = '1' then
346        icontrol(ctrl_offset-1 downto ctrl_offset-8)  <= phy_data_in;
347      end if;  
348    end if;
349  end process CONTROL_REG_PROC;

------------------  

The error as reported by Quartus:
Quartus Error: Error (10386): VHDL error at NODE_N_SINK_INF.vhd(346): non-constant index is always outside the range (63 downto 0) of object "icontrol"
------------------  

The discussion:     
I love to parameterize my IP because it can make instantiating custom version of it for different requirements of new projects easy. Of course with the flexibility of using GENERICS often comes added complexity. I also love to reuse HDL sources that have been reliable for past projects. You'd think that the same HDL code that works flawlessly** for one device would work for other devices, especially newer devices with better resources. This has not been my experience as a general rule. This has not been my experience especially when it involves devices and tools from different FPGA vendors.

This post is about basic VHDL constructs and how the synthesis tools from different vendors evaluate and implement the same constructs differently. If it's not obvious what the code snippets above are trying to accomplish, here's the idea.

I have an 8-bit input data stream. I have a variable sized output std_logic_vector that uses a variable number of bytes form that data stream to set it's value. Really, it's a variable width shift register that is loaded from an input, which in this case is 8 bits wide. The width of the output is in increments of 64. It should be obvious that this shift register is controlled by a state machine that understands the width of the signal icontrol.  The shift register is a fundamental logic construct that's been around since well before programmable logic. Most synthesis tools will automatically identify this construct in your code, if you allow it to, and synthesize the optimum implementation for the resources of a particular device.

The behavior of the synthesis tools often forms our coding style, for better or worse. A synthesis tool that overlooks our tendency to be lazy and type as few words as possible can also encourage poor HDL coding styles. Really, we don't care if our source is pristine, just that in the end our logic does what we think that it should ( in the limited scope that we bother to care or verify how it does indeed work ). Let's face it most of the time we are behind schedule for a number of things that need to get done..now.

I've used this code for many many Xilinx devices and target boards without issue. The Xilinx synthesis tools evaluate the code and know what it is that I want to do. When I recently tried using the same source for an Intel (aka ALTERA) device I was not pleased to see the error reported above. Curiously, I have previously used the same source for a different device (Cyclone V GX) and didn't get this error.
 
If I explicitly constrain the declaration of the signal ctrl_offset with a range specifier as shown in the commented out line that follows Quartus is happy to synthesize and create a working bitstream for me. 

It took me a while to post this because the error that I remember is one of an unconstrained integer ( well actually I remember my reaction rather than the actual error). Anyway, I wasn't able to find my notes about the details so I just recreated the one above.

Some companies believe that the Xilinx synthesis tools promote bad VHDL coding styles and insist that all designs be "compiled" using Synplicity ( the expensive version ) as part of the verification process. If you want to see Synplicity in action ( a cheaper version ) you can look into ACTEL ( aka Microsemi, aka NXP as of late ???) which has traditionally chosen to use third party synthesis tools.

SIDE NOTE:

works flawlessly**

One definition, the one that I favour, of 'working software' is 'software which hasn't been subjected to the particular testing that exposes a particular flaw. Don't trust anyone who tells you that a piece of software works. At best it works good enough under certain conditions as far as anyone has noticed when concentrating on a limited number of metrics. For FPGA development this premiss is even more true.

Edited by zygot

Share this post


Link to post
Share on other sites
Posted (edited)
5 hours ago, Pradeep KM said:

If you want to see Synplicity in action ( a cheaper version ) you can look into ACTEL ( aka Microsemi, aka NXP as of late ???) which has traditionally chosen to use third party synthesis tools

I've used Synplicity in the past when it was available to me. Yes, the ACTEL toolset has always used a 'version' of Synplicity. Unfortunately, I don't have many projects needing ACTEL devices and the tools for the ACTEL boards that I do have have  long since passed their 1 year license evaluation period.  Evaluation of 'free' versions of Synplicity isn't cheap.

At this point I probably should point out that the version of ISE that I referred to is no longer the last version of ISE. The newer version is less useful.

Edited by zygot

Share this post


Link to post
Share on other sites

In my experience the efforts to parameterize a design rarely pay off. A byte is going to be 8 bits for a long time.  There is readability lost in the parameterization.

I will stick with straight code with an emphasis on readability.

Just my $0.0256 worth.

Share this post


Link to post
Share on other sites
Posted (edited)
1 hour ago, Clyde said:

In my experience the efforts to parameterize a design rarely pay off

I guess that we have had different experiences. I certainly don't parameterize all of my design entities, or even start off assuming that I'd want to. On the other hand there are instances where parameterization is almost demanded. Sometimes it's more useful to add inputs to an entity to make them flexible. Sometimes generics just makes more sense. I address this on a case by case basis. Rarely, do I feel a need to remove parameterization.

1 hour ago, Clyde said:

here is readability lost in the parameterization.

Gee, I'd go with the opposite thinking. But you can write code that's 'readable' or 'unreadable' regardless. Usually, this is more important to people trying to figure out if code written by someone else is good for your application or needs substantial alteration. It's true that sometimes using parameterization incurs additional complexity and care. It's also true that sometimes parameterization makes the rest of the coding more streamlined and easy to follow. There is no rule to cover all cases.

1 hour ago, Clyde said:

I will stick with straight code with an emphasis on readability.

Everyone should stick with coding guidelines that work best for themselves. Unless they work in a company or situation in which designs are team sports or specifically for use by a large number of users. Then they should follow corporate coding styles, or try to improve any style guides that exist where appropriate.

What you consider to be readable might conflict with what I consider to be readable. What I considered to be readable when starting off in my FPGA development career is different than what I find readable now. I don't know of a perfect definition for what's readable code that applies to everyone.

Edited by zygot

Share this post


Link to post
Share on other sites
1 hour ago, Clyde said:

In my experience the efforts to parameterize a design rarely pay off. A byte is going to be 8 bits for a long time.  There is readability lost in the parameterization.

I think I'm also going to have to disagree here.

I've written several FIFO's  over the course of the years.  Rather than trying to maintain several FIFOs, each with slightly and subtly diffeent purposes, it helps to parameterize them.  I will agree that you can go overboard with parameterization--such as Xilinx whose FIFO generator has nearly 100 parameters--but I haven't gotten near that point.

Another example: Having built several designs, each with a wonderful purpose, I often want to get those same designs to run on multiple pieces of hardware.  Even with RTL coding, there are hardware differences.  For example, iCE40's don't have distributed RAM and require all RAM reads to be registered--unlike Xilinx.  To be able to use the same design across both iCE40s as well as Xilinx chips, therefore, I need to have subtle changes between the two designs.

Another example: Some hardware has more logic, other chips  have less.  Building a CPU that will run on both a Spartan 6LX4 as well as an Artix-7 200T requires either that the CPU be limited by the extremely few resources of the Spartan 6, or be parameterized so that it can support both the Spartan 6 (no caches, no pipelining) as well as an Artix-7 where I have lots of logic to spare.  Being able to adjust a design for the hardware space you have available is a productive use of parameters.

There is a challenge when using parameters, however: Verification.  If you have 20 boolean parameters, that roughly means you need a million test benches to check all combinations of them to know they work.  So ... it's a trade off.  Still, I find them quite valuable.

Dan

Share this post


Link to post
Share on other sites

To each his own.  I have had to work with parameterized code (not mine)  which is almost unusable and unreadable, and for me, readability is king.  Properly done, I will agree with you.

Clyde

Share this post


Link to post
Share on other sites
Posted (edited)

Everyone's had to work with source code that's undecipherable. Sometimes it's because the idea behind the code is a total mess. Sometimes it's a result of sloppiness, or lack of discipline. Sometimes, it a deliberate attempt to obfuscate the design, occasionally for understandable reasons, almost always for nefarious reasons. Most often it's because of poor coding styles. I think that @[email protected]and I are in agreement that parameterization and readability are just two different, though perhaps overlapping,  topics.

When coding for yourself do whatever floats your boat; you're the only one who has to read it. When coding for others either follow style guidelines or at least be considerate.

Readability is not a necessarily a static thing. As your coding skills evolve you don't have trouble with uncommon or exotic HDL constructs. Things that are obvious to one person might be confusing to another. I'm making no judgements here. We're all different. Bad coding styles and construction are easier to identify in general.

Edited by zygot

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