Problem with conversions.vhd

I am using a vhdl conversion package from freemodelfoundry.com, conversions.vhd. The function I am having a problem with is to_hex_str(slv,int). The simulation stops saying

Value 3 is out of valid range : 1 TO 2 of subtype of integer Simulation stopped when executing process: IRIG_TB.vhd:CTPControl on line 601 in file "C:/Arius/Boards/IRIG-B/FPGA/IRIG-B-X/ conversions.vhd"

function to_hex_str(x : std_logic_vector; rtn_len : natural := 0; justify : justify_side := right; basespec : b_spec := yes) return string is

When I look the error line, it is "ptr := ptr + 1;" which obviously could be running out of bounds. But looking at the code, the delclaration of ptr is based on the same information that controls the loop that is executing the statement, "ptr := ptr + 1;" I don't see any way for it to be assigning ptr out of bounds.

It gets trickier. I tried stripping my code down to the minimum that would cause the error and it very quickly went away. I am passing this function two parameters and allowing two to default. I don't see how anything in my code could cause a failure inside this function.

So now I am pretty stumped. I tried adding some debug statements, but they only told me that it was crapping out and the details that might actually tell me why can't be investigated... like what range is being assigned to ptr and why?

variable nxt : positive := nextmultof(x'length,4); variable int : std_logic_vector(1 to nxt):= (others => '0'); variable ptr : positive range 1 to (nxt/4)+1 := 1;

I can't "see" the value of x'length. The only way to explain the loop indexing ptr too high is that something is wrong with the initialization of the range of ptr. I added some debug statements to the function and got this...

at 150.000 ns(1): Note: nxt is d"8" (/IRIG_TB_vhd/). at 150.000 ns(1): Note: ptr is d"1" (/IRIG_TB_vhd/). at 150.000 ns(1): Note: rtn_len is d"2" (/IRIG_TB_vhd/). at 150.000 ns(1): Note: loop i d"1" (/IRIG_TB_vhd/). at 150.000 ns(1): Note: r string "0$" (/IRIG_TB_vhd/). at 150.000 ns(1): Note: ptr old d"1" (/IRIG_TB_vhd/).

Reply to
rickman
Loading thread data ...

I ran another test with interesting results. Let me recap...

I have three calls to to_int_str using an SLV. The first uses a 4 bit SLV, the second an 8 bit and the third a 16 bit SLV. In this order, I get an error on the second call saying ptr is out of range at 3 when 3 should be ok. If I remove the first call, the third call craps out with ptr being 4 when it should be ok at 5. Just for grins, I swapped the first and second calls. Sure enough, the third call craps out at

  1. The range of ptr is set in the variable declaration of the function to_int_str. I seem to recall reading recently that the declaration is only evaluated once before the function is run, not each time it is invoked. So that would make sense that the range of ptr does not change... which fits perfectly with the third case of it failing on the third call when the 8 bit SLV is used in the first call and the 4 bit SLV is used in the second. Then the third call fails at 4 as if the range of ptr was set by the initial call using an 8 bit SLV.

Did I find a bug in this code??? I can't believe I am the first to find this. This code has been around for a long time!

However, there is still the fact that if I change the code to remove the extraneous stuff outside of this procedure, it doesn't fail anymore. So clearly there is something else going on.

Anyone have a clue???

Reply to
rickman

At elaboration.

VHDL is not a dynamically typed language; you can't stretch and shrink subtypes e.g. ranges during run time.

So I am guessing that the first length (x'length) is statically determinable (i.e. without actually running the code) from initial conditions (e.g. an initial value of x).

It is a good idea to use constants to determine ranges; preventing this sort of error from happening. I had no idea that you could do it with the initial value of a variable; perhaps the Xilinx simulator is being incorrectly permissive here (and therefore hiding a subtle bug for you to find later).

In any case you have to adopt some design that allows the range to be the largest you will need, and derive any checking you require from the actual parameter x to your SLV function.

variable ptr : positive range 1 to largest_I_need; ... assert (nxt/4)+1 = (size_I_expect) report "Something wrong here" severity warning; -- if I am paranoid

- Brian

Reply to
Brian Drummond

I wrote: VHDL is not a dynamically typed language; you can't stretch and shrink subtypes e.g. ranges during run time.

Which makes sense if you think about its orientation as a hardware language; it is difficult to stretch and shrink registers or counters after synthesis.

But it does mean some unnecessary restrictions creating things like testbenches. VHDL 2006 suposedly relaxes some of these restrictions; but at a wild guess, not this one.

- Brian

Reply to
Brian Drummond

Yes, but subprograms (procedures and functions) are dynamically elaborated: all their arguments, and their local variables, are constructed dynamically at the moment of invocation. This is what allows you to handle unconstrained arguments so elegantly. For synthesis, the tool must convince itself that each subprogram call is in a context in which the tool can statically determine what will get elaborated; in other words, you effectively get a new static instance of each subprogram for each distinct invocation. That's what people mean when they say that functions represent combinational logic, and you get a new instance of the logic for each call to the function.

It sounds very much as though Rickman has encountered a tool bug. Is there any way you can run your test case in a second simulator? The free version of Simili, for example?

Alternatively, there may be other ways to get your type conversion, saving you the trouble of fighting a possibly buggy FMF package. Converting a SLV to its hex text representation is easy enough.

--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which 
are not the views of Doulos Ltd., unless specifically stated.
Reply to
Jonathan Bromley

I expected what you said. I don't see how subroutines could work (or make sense) in an HDL unless they are separately elaborated for each place in the code where they are invoked. We *are* describing hardware. I don't have the time right now, but later I will try again to boil this down to a simple test case that can be submitted to whoever "owns" the bug... including myself possibly.

Another very odd thing. I have replaced the calls to to_hex_str with to_int_str which is a different function with a different structure. The display shows the values d"x" with x being the value displayed... all except for the first invocation. Then it displays h"x"!!! This is the same line of code in my program in each case! I tried to debug this a bit by adding printouts and I found that there is a small bug for the case of x being 0. They have a default line of code to handle this with the base hardwired! I will report this one.

Rick

Reply to
rickman

Absolutely; I didn't mean anything different.

I possibly misread Rickman's post; that he was re-calling the function for a different value of the same variable in the same instance of the same process. Which is not clear is the case.

Otherwise, I agree, it looks like a bug.

I have found problems with ISE incorrectly synthesising different calls to a procedure in the same process so a similar bug in their simulator is credible.

That's why I was suggesting a static range, and using the parameter's length attribute to determine the number of digits.

- Brian

Reply to
Brian Drummond

That's a lot of sames... I'm not sure so here is the line that was causing the error, at least I think this is it.

report "Read " & " Addr " & to_hex_str(AddrWd, 2) & " Read data " & to_hex_str(DataWd, 4) & CR & LF severity NOTE;

As a work around I just converted the SLVs to ints like this, to_int(AddrWd) and a different function was invoked that works differently.

The function *does* use the parameter's length attribute to set the number of digits. Maybe I misunderstand what you mean. Here is the initial code of the function.

function to_hex_str(x : std_logic_vector; rtn_len : natural := 0; justify : justify_side := right; basespec : b_spec := yes) return string is -- will return x'length/4 variable nxt : positive := nextmultof(x'length,4); variable int : std_logic_vector(1 to nxt):= (others => '0'); variable ptr : positive range 1 to (nxt/4)+1 := 1; variable r : string(1 to nxt/4):=(others=>'$'); subtype slv4 is std_logic_vector(1 to 4); variable slv4_val : slv4; begin

The length of the input string 'x' is used to define nxt which in tern is used to define everything else.

I still don't have another simulator running, but I might later this week.

Rick

Reply to
rickman

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.