Indexing of original vector in a function in VHDL - 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.

Related

VHDL numeric_std function ("+")

everyone!
Please, can you explain me a strange thing.
The numeric_std library contains a function "+", addition. I inserted a description of the function.
-- Id: A.3
function "+" (L, R: UNSIGNED) return UNSIGNED;
-- Result subtype: UNSIGNED(MAX(L'LENGTH, R'LENGTH)-1 downto 0).
-- Result: Adds two UNSIGNED vectors that may be of different lengths.
For instance, we have:
a : in unsigned(2 downto 0);
b : in unsigned(1 downto 0);
result : out unsigned(2 downto 0);
So, If a is "111" and b is "01" the result will be "000". The reason is an overflow.
My question is why the library allows it, why it does not expand the results length? Why a compiler does not warn me about the overflow? Is it possible to add the values without the overflow? And how should I prevent or find to occur the overflow.
Thank you!
In hardware, we have incrementers and decrementers - which "roll over" as part of their normal operation, we have accumulators - which should never roll over, and we have math units which need to maintain full precision of the operation.
In VHDL, when we do an operation, it must produce an exact sized result. Incrementers, decrementers, and accumulators all need to keep the same size result, where as math units that need to maintain full precision of the operation need to increase in size.
Hence, the "+" can only meet one of these needs. The other part needs to be handled by code.
For numeric_std, the rule for "+" is as you state, the size of the result is the size of the largest array operand. What is interesting is that in ieee.fixed_pkg, the size of the result is the 1 + size of the largest array operand.
Lets take a look at how this impacts our math.
signal Co : std_logic ; -- to throw away carry out
signal Incrementer_unsigned : unsigned(3 downto 0) ;
signal Incrementer_ufixed : ufixed(3 downto 0) ;
signal Accumulator_unsigned : unsigned(3 downto 0) ;
signal Next_unsigned : unsigned(3 downto 0) ;
signal Accumulator_ufixed : ufixed(3 downto 0) ;
signal Next_ufixed : ufixed(3 downto 0) ;
signal Sum_unsigned : unsigned(8 downto 0) ;
signal A_unsigned : unsigned(7 downto 0) ;
signal B_unsigned : unsigned(7 downto 0) ;
signal Sum_ufixed : ufixed(8 downto 0) ;
signal A_ufixed : ufixed(7 downto 0) ;
signal B_ufixed : ufixed(7 downto 0) ;
. . .
process (Clk)
begin
if rising_edge(Clk) then
-- Incrementer / Decrementer with unsigned or ufixed. Result same size
Incrementer_unsigned <= Incrementer_unsigned + 1 ;
(Co, Incrementer_ufixed) <= Incrementer_ufixed + 1 ;
-- Accumulator with unsigned or ufixed. Result same size
Accumulate_unsigned <= Accumulate_unsigned + Next_unsigned ;
(Co, Accumulate_ufixed) <= Accumulate_unfixed + Next_ufixed ;
-- math unit with full precision. Result size increases
Sum_unsigned <= ('0' & A_unsigned) + ('0' & B_unsigned) ;
Sum_ufixed <= A_ufixed + B_ufixed ;
end if ;
end process ;
So for numeric_std, if we threw a warning for the incrementer, we would get numerous FALSE positive warnings and eventually ignore all warnings - that would be a mistake.
For numeric_std, the sizing rules work very well for the incrementer and accumulator. The size of results is what is expected. For the Sum_unsigned, we have to upsize one argument (if they are the same size), I chose to upsize both. There is a resize function that I chose not to use.
For fixed_pkg, for the incrementer and accumulator, we had to downsize the result by using an aggregate on the left hand side to remove the carry out (this code is VHDL-2008). There is also a resize that can handle this. For the Sum_ufixed, the size of the result matched our application.
One thing this demonstrates is that no matter which rule you pick, there is something the person writing the code must do.
For Sum_ufixed, the results get much more exciting if we have:
signal Sum_ufixed10 : ufixed(9 downto 0) ;
. . .
Sum_ufixed10 <= (A_ufixed + B_ufixed) + (C_ufixed + D_ufixed) ;
Because when you follow the rules, the size of the associativity identical expression ends up one bit bigger. While I have shown parentheses below, it is the same with them.
signal Sum_ufixed11 : ufixed(10 downto 0) ;
. . .
Sum_ufixed11 <= ((A_ufixed + B_ufixed) + C_ufixed) + D_ufixed ;
Also note that both packages support "+"[unsigned/ufixed, natural] return unsigned/ufixed, however, the natural argument does not influence the sizing. My take on this is 0 and 1 are simple to use, but other values must be scrutinized. If the integer is truncated, there is a warning, but in my mind maybe it should have been a failure instead (which would be consistent with what happens with array values). This certainly is open for discussion in the IEEE working group (see http://www.eda-twiki.org/cgi-bin/view.cgi/P1076/WebHome).
You're right, a warning about the use of this operator would be helpful. However, it is up to the developer to know if they need an addition operation that rolls over, or one in which and overflow will cause bad behavior.
When performing addition, and an overflow is undesired, the result needs to be 1 bit longer than the longest operand. Then you can check for overflow by seeing if the most significant bit is set to '1'.

bit_vector bounds violation by static constant

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.

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

Using Generate in Vhdl

I have following piece of code in Vhdl now I want to redirect this signal S1 conditionally to the output port, I will be gratful if someone can guide me through this.
Gen: for index in 0 to 4 generate
signal s1 : ARRAY_TYPE; --- array of (0 to 7) std_logic_vector (7 downto 0);
begin
process(CLK)
begin
if (rising_edge (CLK)) then
S1(counter_index) <= S_in((index*8+7) downto (index*8));
end if;
end if;
end process;
end generate Gen;
I know we can use a process inside generate loop but is otherway around also possible! If I declare S1 as global signal it complains of connected to multi driven net? How this is different?
I will be really grateful if someone can guide me through this
Your for-generate loop (from 0 to 4) will be unrolled at elaboration so that what you end up with, effectively, is (leaving out the process code for brevity):
for index = 0:
signal s1_0 : ARRAY_TYPE; --- array of (0 to 7) std_logic_vector (7 downto 0);
s1_0(counter_index) <= S_in(7 downto 0);
for index = 1:
signal s1_1 : ARRAY_TYPE; --- array of (0 to 7) std_logic_vector (7 downto 0);
s1_1(counter_index) <= S_in(15 downto 8);
etc.
You get "copies" because you declared the signal inside the generate loop, each of which is local to just that generate block. When you try to make s1 "global" (not really global, which has a different connotation; just declared for the whole architecture), you get:
for index = 0:
s1(counter_index) <= S_in(7 downto 0);
for index = 1:
s1(counter_index) <= S_in(15 downto 8);
See what happened there? Those statements are concurrent, and assigning to the same bits. That's why you have problems with multiple drivers.
The problem appears to be counter_index. Either you need to index s1 with some combination of your loop index with your other index, as QuantumRipple suggested, or you need to create some intermediate signal, or something.
Note that if you're handling 32-bit data a byte at a time, you probably meant 0 to 3, not 0 to 4.
Although fru1tbat covers the solution to your problem, I wanted to cover your other question:
I know we can use a process inside generate loop but is otherway
around also possible!
You can use a for ... loop inside of a process statement as well. It functions and gets unrolled similarly to a for... generate statement, but inside of a process. It can also be used to implement more complex logic by using variables or overwriting assignments. Here is a syntax reference for it: http://www.ics.uci.edu/~jmoorkan/vhdlref/for_loop.html

VHDL- vector slicing

I have input std_logic_vector of (0 to X).
Range of x is 0 to 1000 bytes and the code should support any value of X.
I would like to slice the input into 128 bit blocks, for further processing and operations.
a) how can it be done?
b) is there a way to make the following pseudo-code work? so i can adopt it for solving a)?
i need to use the loop index for naming the signals but i guess its not possible with VHDL (?)
for i in 0 to N loop
block_i <= input (X, X-127);
end loop;
Thanks in advance.
Something like this ?
library ieee;
use ieee.std_logic_1164.all;
entity slicer is
generic(X : natural:=1000);
port (input : in std_logic_vector(X*128-1 downto 0));
end entity;
architecture rtl of slicer is
type block_type is array(0 to X-1) of std_logic_vector(127 downto 0);
signal blocks : block_type;
begin
slicing:for i in 0 to X-1 generate
blocks(i) <= input(128*(i+1)-1 downto 128*i);
end generate;
end rtl;
You have a few options with how to accomplish this. One is to use the flattened 1-D array that is selectively sliced as demonstrated by #JCLL. Another option is to create a new type that is an array of an array.
subtype word is std_logic_vector(127 downto 0); -- Constrained subtype
type word_vec is array(natural range <>) of word; -- New unconstrained type
...
entity foo is
port (
X : in word_vec -- Get our constraint when instantiated
);
end entity;
...
for i in X'range loop
blocks(i) <= X(i);
end loop;
This solution skips the arithmetic needed for the 1-D slicing but is limited by the need for a constrained type for the elements of word_vec. This last limitation is lifted in VHDL-2008 where you can do the following:
-- Both unconstrained arrays
type word_vec is array(natural range <>) of std_logic_vector;
The best solution depends on what your task is and how much flexibility you need for size changes in the future.
A final less appealing option is to use a 2-D array but that gets ugly when you need more than bitwise access.
Yes, you can assign parts of a large logic vector to another smaller vector. I'm not sure about your specific implementation (you did not provide the signal types and sizes -- is the large vector 1000 bytes or 1000 bits?). However, If you know what X is at time of synthesis, use generics, like
entity foo is
generic(X : Natural);
port(input: in std_logic_vector(X-1 downto 0);
block_i: out std_logic_vector(127 downto 0));
end entity;
Otherwise you just need to pass in a size as well:
entity foo is
port(input: in std_logic_vector(X-1 downto 0);
block_i: out std_logic_vector(127 downto 0);
X : in Natural);
end entity;
And then use the size when you are assigning parts to block_i.
Note that you will need to either use the generic or a hard-coded constant (ie: 1000 for the worse case) for the loop. VHDL does not like variable loop ranges. You can work around this, but I usually don't need to (see: Using FOR loop in VHDL with a variable)

Resources