bit_vector bounds violation by static constant - vhdl

Posting this question on SO and not EE is because I am struggling with coding/software imperfections.
I am new to VHDL and going through "Free range VHDL" book. Playing around with bit_vector I found out that to access single wire in a bus syntax is following bus_name(0) (0 is just for example).
Keeping that in mind I wrote simple representation of 4 input multiplexer.
library ieee;
use ieee.std_logic_1164.all;
entity Multiplexer4_1 is
port
(
data : in bit_vector(3 to 0);
selector : in bit_vector(1 to 0);
output : out bit
);
end entity Multiplexer4_1;
architecture m4_1 of Multiplexer4_1 is
begin
output <= data(3) when (selector = "11") else
data(2) when (selector = "10") else
data(1) when (selector = "01") else
data(0) when (selector = "00") else
'0';
end architecture m4_1;
I am using ghdl to process VHDL under linux with the following command.
ghdl -a 4Multiplexer.vhdl
As a result I receive 4 error messages evidently because of data(0), data(1) and others, that are listed below.
4Multiplexer.vhdl:15:23: static constant violates bounds
4Multiplexer.vhdl:16:21: static constant violates bounds
4Multiplexer.vhdl:17:21: static constant violates bounds
4Multiplexer.vhdl:18:21: static constant violates bounds
ghdl: compilation error
The questions are:
How to solve that problem?
If bus_name(index) is a right syntax for that?
Update:
Not to make the same error I've made it's crucial to understand how arrays/ranges work in VHDL.
Difference between to and downto
VHDL constructs (arrays mentioned there)
Thanks for help!

The problem is with declaration.
You have defined data and selector as
data : in bit_vector(3 to 0);
selector : in bit_vector(1 to 0);
You should define it either as
data : in bit_vector(3 downto 0);
selector : in bit_vector(1 downto 0);
or
data : in bit_vector(0 to 3);
selector : in bit_vector(0 to 1);
Difference between to and downto:
The link already explains difference between to and downto. Any difference of "downto" and "to" appears when we want to use a bit-vector not just to represent an array of bits, where each bit has an independent behavior, but to represent an integer number. Then, there is a difference in bit significance, because of the way numbers are processed by circuits like adders, multipliers, etc.
I will give one more example
Lets say you want to assign your bit vector value = "0001"
if using "3 downto 0", assignment will be
data<=(0 => '1', others => '0')
and in "0 to 3" case, assignment will be
data<=(3=>'1',others => '0')
Importantly, one should always stick to either ascending or descending range. Programmer can use combination of both. However, it may be confusing and can throw some errors. Also, as far as I know, most buses are numbered using descending range. Hence, programmers favour descending range.

Related

Scaling down a 128 bit Xorshift. - PRNG in vhdl

Im trying to figure out a way of generating random values (pseudo random will do) in vhdl using vivado (meaning that I can't use the math_real library).
These random values will determine the number of counts a prescaler will run for which will then in turn generate random timing used for the application.
This means that the values generated do not need to have a very specific value as I can always tweak the speed the prescaler runs at. Generally speaking I am looking for values between 1000 - 10,000, but a bit larger might do as well.
I found following code online which implements a 128 bit xorshift and does seem to work very well. The only problem is that the values are way too large and converting to an integer is pointless as the max value for an unsigned integer is 2^32.
This is the code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity XORSHIFT_128 is
port (
CLK : in std_logic;
RESET : in std_logic;
OUTPUT : out std_logic_vector(127 downto 0)
);
end XORSHIFT_128;
architecture Behavioral of XORSHIFT_128 is
signal STATE : unsigned(127 downto 0) := to_unsigned(1, 128);
begin
OUTPUT <= std_logic_vector(STATE);
Update : process(CLK) is
variable tmp : unsigned(31 downto 0);
begin
if(rising_edge(CLK)) then
if(RESET = '1') then
STATE <= (others => '0');
end if;
tmp := (STATE(127 downto 96) xor (STATE(127 downto 96) sll 11));
STATE <= STATE(95 downto 0) &
((STATE(31 downto 0) xor (STATE(31 downto 0) srl 19)) xor (tmp xor (tmp srl 8)));
end if;
end process;
end Behavioral;
For the past couple of hours I have been trying to downscale this 128 bit xorshift PRNG to an 8 bit, 16 bit or even 32 bit PRNG but every time again I get either no output or my simulation (testbench) freezes after one cycle.
I've tried just dividing the value which does work in a way, but the size of the output of the 128 bit xorshift is so large that it makes it a very unwieldy way of going about the situation.
Any ideas or pointers would be very welcome.
To reduce the range of your RNG to a smaller power of two range, simply ignore some of the bits. I guess that's something like OUTPUT(15 downto 0) but I don't know VHDL at all.
The remaining bits represent working state for the generator and cannot be eliminated from the design even if you don't use them.
If you mean that the generator uses too many gates, then you'll need to find a different algorithm. Wikipedia gives an example 32-bit xorshift generator in C which you might be able to adapt.
Table 3 in the old Xilinx Application Note has the information you need to make such random generator circuit for 8-bit as you mention.
https://www.xilinx.com/support/documentation/application_notes/xapp052.pdf

Indexing of original vector in a function in VHDL

I want to write a function in VHDL which is given the top few bits of a std_logic_vector and does stuff to them but it seems to be that the indexing of my function still starts counting at the bottom of the whole vector.
I can get around this by first assigning my vector to a temporary signal and using that but I'm worried that I don't understand what's going on here.
Could someone explain why a and b don't get the same output in the below?
architecture rtl of inds is
function top_bit (c : std_logic_vector) return std_logic is
begin
return c(c'length-1);
end top_bit;
signal temp : std_logic_vector(2 downto 0);
begin
temp <= input(3 downto 1);
a <= top_bit(temp);
b <= top_bit(input(3 downto 1));
end rtl;
If you give them the input "0100", you get a='0', b='1'.
If you give them the input "1000", you get a='1', b='0'.
So a=temp(2)=input(3) and b=input(2) which is input("length of c" -1).
I don't think this makes sense, can someone justify it for me.
Edit: if you replace the declaration line with:
function top_bit (c : std_logic_vector(2 downto 0)) return std_logic is
then it works as I'd expect.
I suppose the vector c takes it's indexing from the vector it's given.
I'd like to see a function which takes an arbitrary slice of a vector and returns the top bit of that slice.
You are using the 'length attribute, where you could be using 'high. I think this would do what you're asking for.
I've got a print out on my wall of the table here http://www.csee.umbc.edu/portal/help/VHDL/attribute.html as a reference for what attributes are available.
The issue, is that c'length returns the length of the vector which is not necessarily a valid index. For example, say I declared the following signal:
signal temp : std_logic_vector(7 downto 4);
This would cause a range error calling top_bit. As you note in your comment on scary_jeff's answer, not all vectors are x downto 0. They could be x downto y. Or they could even by 0 to x or x to y. Assuming that c'length-1 is the top bit is only true if c is declared as std_logic_vector(N-1 downto 0) (which you discovered in your answer).
Just as a clarification. scary_jeff's answer is the correct way. However, you need to resolve what is meant by "top_bit". What if you are given a to vector, such as:
signal temp : std_logic_vector(4 to 7)
What is top bit? Bit 4 or bit 7? If you use 'high, you'll get bit 7. Is this the top bit? If you want bit 4 to be the top bit, you'll need to use 'low.

What's the right way to cast a sfixed to std_logic_vector in vhdl?

I am trying to cast a sfixed (from ieee.fixed_pkg) to std_logic_vector and I wonder what the correct syntax is and why the following is (appearently wrong). I tried compiling the following 3 architectures:
library ieee;
use ieee.std_logic_1164.all;
use ieee.fixed_pkg.all;
entity test is
port (input: in sfixed(0 downto -7) := x"00";
output: out std_logic_vector(7 downto 0) := x"00");
end;
Architecture a:
architecture a of test is begin
output <= std_logic_vector(input);
end;
Architecture b:
architecture b of test is begin
proc: process (input) begin
output <= std_logic_vector(input);
end process;
end;
Architecture c:
architecture c of test is begin
proc: process (input) begin
if ('1' and '1') then
output <= std_logic_vector(input);
end if;
end process;
end;
The compiler I've used was "ModelSim ALTERA vcom 10.3d Compiler 2014.10 Oct 7 2014".
Architectures a and b don't compile with the error message:
Error: [...] Index value -7 (of type std.STANDARD.NATURAL) is out of range 0 to 2147483647.
But architecture c compiles, while still giving me the warning message:
Warning: [...] Index value -7 (of type std.STANDARD.NATURAL) is out of range 0 to 2147483647.
So my question is: what is the correct way to cast this, and why is there any difference between the three architectures posted above?
The range issues resulting for type casting an sfixed that has negative indices to std_logic_vector that #BrianDrmmond discusses was an issue identified during the development of the standard. It is a real issue for simulators other than GHDL as well.
Hence, the package provides type conversion functions to handle this. To convert from either sfixed or ufixed to std_logic_vector use either to_slv and to_std_logic_vector:
output <= to_slv(input);
To convert from std_logic_vector to sfixed / ufixed use one of the flavors of to_sfixed/to_ufixed. There is one that takes the indices as a parameter and another that takes the object.
signal a_sfixed : sfixed(0 downto -7) := x"00";
signal a_slv : std_logic_vector(7 downto 0) := x"00";
a_sfixed <= to_sfixed(a_slv, 0, -7);
. . .
a_sfixed <= to_sfixed(a_slv, a_sfixed);
Yes, you can use a type conversion (aka casting) for an assignment instead of the above, however, if you wanted to then use the converted value in an expression, the range of the result would be incorrect since it is determined by the range of the inputs.
signal a_sfixed : sfixed(0 downto -7) := x"00";
signal a_slv : std_logic_vector(7 downto 0) := x"00";
signal y_sfixed : sfixed(1 downto -7) := x"00";
y_sfixed <= a_sfixed + to_sfixed(a_slv, 0, -7);
Funnily enough, this might actually be a grey area in the specification of the VHDL language itself. The same problematic conversion has been discussed as a possible "bug" against the open-source simulator, ghdl.
The essence of the problem is that input is declared as sfixed(0 downto -7) while the definition of std_logic_vector requires its index to be natural, i.e. a positive integer or 0.
Thus a type conversion to an unconstrained std_logic_vector
output <= std_logic_vector(input);
inherits the bounds of the source vector, (0 and -7) and fails because one bound is out of range.
There is a simple workaround, however : type conversion to a constrained std_logic_vector ... such as std_logic_vector (input'length-1 downto 0) ... which by using the 'length attribute is guaranteed to be the right size. The semantics of this conversion keep the indexes valid, so the conversion succeeds, transferring leftmost bit to leftmost bit, and so on.
In a bit more detail, the code looks like:
-- declarations
subtype result_type is std_logic_vector (input'length-1 downto 0);
signal output : result_type;
-- assignment
output <= result_type (arg);
I cannot guarantee Altera will accept the same workaround, but I'm reasonably confident that it will, it's more clearly valid VHDL. I also haven't tried declaring output as a port as you need.
As far as we can tell, ghdl (which is usually rigorous in its interpretation of VHDL) is correct in rejecting this construct according to the letter of the VHDL language reference manual (LRM) and the "bug" report has accordingly been closed.
However, further clarification has been sought from the VHDL standards committee - and possibly a future relaxation of the rule - IF - it can be shown to be completely proof against the sort of array bounds errors and buffer overruns that plague some other languages.
I found this post facing the same error in GHDL 0.35 (mcode, windows) using David Bishop's fixed_pkg_c (FPHDL, on github).
Note, while the answer here appears correct; I had to add to the following in fixed_pkg_c in order to get GHDL to compile and simulate:
function to_sulv (
arg : UNRESOLVED_sfixed) -- fixed point vector
return STD_ULOGIC_VECTOR is
variable result : STD_ULOGIC_VECTOR (arg'length-1 downto 0);
-- This was added
subtype result_type is STD_ULOGIC_VECTOR (arg'length-1 downto 0);
begin
if arg'length < 1 then
return NSLV;
end if;
-- originally: result := STD_ULOGIC_VECTOR (arg)
result := result_type (arg);
return result;
end function to_sulv;
The same change was needed to the to_sulv function for ufixed types.
I'm not sure why the previous 'type conversion' using STD_ULOGIC_VECTOR did not work, and I haven't spent more thought on this.
If others find this, please update on whether the original fixed_pkg_c file works in its original implementation.
The fixed package conversion function is not the solution to the OP's reported error, see posting of the function to convert to std_ulogic_vector below. Note that 'result' is a std_ulogic_vector and is obtained by performing a type cast of the operand 'arg', exactly the same as the OP did (except OP used std_logic_vector). The fixed point package will produce the same error as reported by the OP.
-- Conversion functions. These are needed for synthesis where typically
-- the only input and output type is a std_logic_vector.
function to_sulv (
arg : UNRESOLVED_ufixed) -- fixed point vector
return STD_ULOGIC_VECTOR is
variable result : STD_ULOGIC_VECTOR (arg'length-1 downto 0);
begin
if arg'length < 1 then
return NSLV;
end if;
result := STD_ULOGIC_VECTOR (arg);
return result;
end function to_sulv;
KJ

synthesis of dynamic mux on std_logic_vector bytes

I have a FIFO who's size is determined according to a parameter in the package:
signal fifo : std_logic_vector(FIFO_SIZE*8 -1 downto 0);
I also have a 4 bit vector (numOfBytes) saying how many bytes are in the FIFO at any given time (up to 8).
I want the data out (a single byte) from the FIFO to be determined according the numOfBytes signal:
Do <= fifo(to_integer(unsigned(numOfBytes)*8 -1 downto to_integer(unsigned(numOfBytes)*8 -8) when numOfBytes /= x"0" else (others => '0');
when simulating, this works well, however when I try to synthesis it (using Synopsys DC) I get an elaboration error upon linking the design saying "Constant value required (ELAB-922)".
The ELAB code means "This error message occurs because an expression in the indicated line of your RTL description does not evaluate to a constant value, as required by the language."
How else can I make the output mux so it will undergo synthesis?
if not for the parameter i'd change the Do line to a regular mux, but it can't work with the parameters. (I can't call fifo(63 downto 54) when fifo is 4 byte...)
p.s.
I tried working with conv_integer in the beginning, but changed to to_integer(unsigned())due to answers found on the web.
Signal indexes used to construct a range have to be compile-time constants for synthesis to accept them.
There are two ways to solve this problem:
1) Change your FIFO to use an array. This is the standard way of declaring any form of memory, such as a FIFO.
type fifo_type is array(0 to FIFO_SIZE-1) of std_logic_vector(8-1 downto 0);
signal fifo : fifo_type;
...
Do <= fifo(to_integer(unsigned(numOfBytes))-1) when(numOfBytes/=0) else (others=>'0');
2) Use a loop to convert the variable into a constant. This is a common way to code a generic mux.
Do <= (others=>'0');
for i in 0 to FIFO_SIZE-1 loop
if(numOfBytes=i+1) then
Do <= fifo((i+1)*8-1 downto i*8);
end if;
end loop;
I would recommend the first approach for larger, memory-based FIFOs, and the second for smaller, register-based ones.
If the FIFO created with a number of bytes, instead of combining it into the same std_logic_vector then Synopsys DC may be able to handle it. Code could look like:
library ieee;
use ieee.numeric_std.all;
architecture syn of mdl is
... Declaration of FIFO_SIZE natural constant
type fifo_t is array(natural range <>) of std_logic_vector(7 downto 0);
signal fifo : fifo_t(FIFO_SIZE - 1 downto 0);
begin
... Handling FIFO insert and remove
Do <= fifo(to_integer(unsigned(numOfBytes))) when numOfBytes /= x"0" else (others => '0');
end architecture;
If you don't need a runtime-dynamic size to the FIFO, use a generic on your entity.
If you truly need a dynamic sized FIFO, you'll have to use a loop in a process as someone else said. But be very careful how you use such a FIFO, as if you change the size of it while someone is reading or writing, bad things may happen!

Comparing a long std_logic_vector to zeros

In simulation this works perfect. Is this is the best way of checking for
zeros for a synthesisable code. What would be the resources generated?
signal vector_slv : std_logic_vector(2048 downto 0);
...
if (vector_slv = (vector_slv'range => '0')) then
-- do something...
Is there any other optimal way to implement this solution considering h/w mapping (with optimal resource utilization).
I would be more interested in understanding the resources used.
There's no way that makes more or less sense for synthesis. Write the code that best expresses your intention.
If you are comparing a vector for all zeros, the following should all produce the same results, or you should file a serious bug against the tool!
signal vector_slv : std_logic_vector(2048 downto 0);
constant zeros : std_logic_vector(vector_slv'range) := (others => '0');
...
if vector_slv = (vector_slv'range => '0') then
-- do something...
if vector_slv = zeros then
-- do something...
if unsigned(vector_slv) = to_unsigned(0, vector_slv'length) then
-- do something...
and indeed for shorter vectors which fit in an integer:
if intvar = 0 then
will be exactly the same as any 32-bit vector comparison.
(BTW, note there is no need for parentheses around the if condition - VHDL is not C :)
If the range is available, as in your example code, then the suggestion
solution looks fine, and I would expect that synthesis tools are made to handle
constructions like this.
If the range is not available, then compare with zero can be made like:
library ieee;
use ieee.numeric_std.all;
...
if unsigned( {std_logic_vector expression of any length} ) = 0 then
-- do something...
I would expect that synthesis tools handle this the same was as for compare
with (vector_slv'range => '0').
As far as synthesis is concerned, yes, such simple constructs are usually optimized fairly well by the tool. The exact hardware layout of course depends on what your target is (FPGA, ASIC, ...).
My suggestion is to take a look at the synthesis result (e.g. Technology Map Viewer for Altera FPGAs). If synthesis clobbers it, you can manually convert it into a binary tree of comparisons with zero, taking into account the technology primitives you have available. This can be a lot more tricky than it sounds, though, especially for FPGAs (there's more than LUTs to play with there), and shouldn't be necessary with a decent tool.
You can also separate predicate and assignment by doing this :
signal is_zero : boolean;
signal vector_slv : std_logic_vector(2048 downto 0);
...
process(clk)
begin
if rising_edge(clk) then
is_zero <= vector_slv = (vector_slv'range => '0');
if is_zero then
...
end if;
end if;
end process;
This should improve your Timing very much. Take into account that the predicate 'is_zero' is now a delayed version of your original comparison !
You could use the unary operators, e.g.:
and
nand
or
nor
signal vector_slv: std_logic_vector(2048 downto 0);
...
if and vector_slv then
-- Do something for all 1...
elsif nand vector_slv then
-- Do something for at least one 0...
elsif or vector_slv then
-- Do something for at least one 1...
elsif nor vector_slv then
-- Do something for all 0...
end if;
Or you could use the functions defined in std_logic_1164, e.g.:
function "and" (l : STD_ULOGIC_VECTOR) return STD_ULOGIC;
function "nand" (l : STD_ULOGIC_VECTOR) return STD_ULOGIC;
function "or" (l : STD_ULOGIC_VECTOR) return STD_ULOGIC;
function "nor" (l : STD_ULOGIC_VECTOR) return STD_ULOGIC;
use ieee.std_logic_1164.all;
...
signal vector_slv: std_logic_vector(2048 downto 0);
...
if and(vector_slv) then
-- Do something for all 1...
elsif nand(vector_slv) then
-- Do something for at least one 0...
elsif or(vector_slv) then
-- Do something for at least one 1...
elsif nor(vector_slv) then
-- Do something for all 0...
end if;

Resources