How to determine direction of a vector in VHDL (downto vs to)? - vhdl

I need to write a function that will shift data into an input vector. The input could be of type signed or unsigned. In order to make the function robust, I need to know the direction of the input vector i.e range declared using downto vs to. This information will be used to determine what index has the least significant bit.
How do I find out how the range has been declared and choose the correct least significant and most significant bit based on that information?

Array types have the default attributes 'ascending and 'descending which are both functions that return true/false depending on whether the range is actually to (ascending) or downto (descending). Hence, you will likely need to have the following coding style if you explicitly need to investigate the direction:
if p'ascending then
-- do code for to direction
else
-- do code for downto direction
end if;
Alternatively, you can use an alias to "normalise" the direction inside the function, which means an if/else is not needed depending on direction, as you know the direction inside the function:
function do_something( p : bit_vector ) return bit_vector is
alias p_a : bit_vector(p'length-1 downto 0) is p; -- normalise p
variable r : p_a'subtype;
begin
-- use p_a as a downto vector
return r;
end function;

Related

VHDL pass range to procedure

I'm writing my own package to deal with generic matrix-like objects due to unavailability of VHDL-2008 (I'm only concerned with compilation and simulation for the time being).
My aim is getting a matrix M_out from a matrix M_in such that:
M_out(i downto 0, j downto 0) <= M_in(k+i downto k, l+j downto l);
using a subroutine of sort. For, let's say, semantic convenience and analogy with software programming languages my subroutine prototype should ideally look something like this:
type matrix is array(natural range <>, natural range <>) of std_logic;
...
procedure slice_matrix(signal m_out: out matrix;
constant rows: natural range<>;
constant cols: natural range<>;
signal m_in: in matrix);
The compiler does however regard this as an error:
** Error: custom_types.vhd(9): near "<>": syntax error
** Error: custom_types.vhd(9): near "<>": syntax error
Is it possible to pass a range as an argument in some way or shall I surrender and pass 4 separate indexes to calculate it locally?
An unconstrained index range natural range <> is not a VHDL object of class signal, variable, constant, or file. Thus it can not be passed into a subprogram. I wouldn't implement a slice operations as a procedure, because it's a function like behavior.
An implementation for working with matrices and slices thereof is provided by the PoC-Library. The implementation is provided in the vectors package.
function slm_slice(slm : T_SLM; RowIndex : natural; ColIndex : natural; Height : natural; Width : natural) return T_SLM is
variable Result : T_SLM(Height - 1 downto 0, Width - 1 downto 0) := (others => (others => '0'));
begin
for i in 0 to Height - 1 loop
for j in 0 to Width - 1 loop
Result(i, j) := slm(RowIndex + i, ColIndex + j);
end loop;
end loop;
return Result;
end function;
More specialized functions to slice off a row or column can be found in that file too. It also provides procedures to assign parts of a matrix.
This package works in simulation and synthesis.
Unfortunately, slicing multi dimensional arrays will not be part of VHDL-2017. I'll make sure it's discuss for VHDL-202x again.
Passing ranges into a subprogram will be allowed in VHDL-2017. The language change LCS 2016-099 adds this capability.

VHDL - Do Functions used only in the architecture header take up FPGA logic?

If I have some code like so:
...
architecture behaviour of ExampleEntity is
-- type definitions
type Matrix is array(0 to 1,0 to 1) of signed(NumOfBitsForSignals_1 downto 0);
-- function definitions
function TransposeMatrix(MatrixArg : Matrix) return Matrix is
-- variable decleration
variable Result : Matrix;
begin
-- behaviour
for columnNo in Result'range loop
for rowNo in Result'range loop
Result(columnNo, rowNo) := MatrixArg(rowNo, columnNo);
end loop;
end loop;
return Result;
end function;
-- constant definitions
constant A00 : std_logic_vector(NumOfBitsForSignals_1 downto 0) := "A00Value";
constant A01 : std_logic_vector(NumOfBitsForSignals_1 downto 0) := "A01Value";
constant A10 : std_logic_vector(NumOfBitsForSignals_1 downto 0) := "A10Value";
constant A11 : std_logic_vector(NumOfBitsForSignals_1 downto 0) := "A11Value";
constant A : Matrix := ((signed(A00), signed(A01)),
constant A_Transpose : Matrix := TransposeMatrix(A);
...
And the TransposeMatrix function is only used once in this place is this function still synthesised or will the compiler assign the appropriate value to A_Transpose and remove this function from the synthesis? If this isn't the case and it synthesised the transpose function would it be better to remove this function and transpose the matrix manually and enter it?
As a general rule, a synthesis tool will try it's very best to reduce the complexity of the generated net list. This includes working out the results of functions that have constant inputs, even if these inputs are themselves generated by other functions, depend on generic parameters, etc. The tools are so good at this process, that a simple mistake in your code can lead to whole parts of your design being optimised away.
That being the case, it doesn't actually matter whether the function is only called in a declarative region; no matter where a function is called, any simplifications or optimisations possible will be carried out by the synthesis tool.
Some tools do have limitations, for example if your function reads from files, or in some scenarios if it contains a loop with bounds that are determined by parameters. However, this will tend to result in either an error or a warning, as opposed to extra logic in the net list.

Number of bits to represent an integer in VHDL

I have to convert an integer to find how many bits are required to represent that integer.
Let say, integer value is 22. I know 5 bits are required to represent this integer.
Is there any attribute in VHDL to do this?
Important: The result should also be an integer, which should represent number of bits.
There is no VHDL attribute or function, but you can create a function like:
-- Returns number of bits required to represent val in binary vector
function bits_req(val : natural) return natural is
variable res_v : natural; -- Result
variable remain_v : natural; -- Remainder used in iteration
begin
res_v := 0;
remain_v := val;
while remain_v > 0 loop -- Iteration for each bit required
res_v := res_v + 1;
remain_v := remain_v / 2;
end loop;
return res_v;
end function;
However, sometimes a ceil_log2 function is also useful, since that gives the number of required address bits based on entries in a memory map, and ceil_log2(val) = bits_req(val - 1).
Use the math_real library. It's not for synthesis, but works great between the architecture and begin statements.
use ieee.math_real.all;
constant nbits : natural := integer(ceil(log2(real(n))));
I use math_real a lot for in-line generating sin/cos tables... again it's between architecture and begin... again, don't try to use math_real in synthesis.
I've used this in Quartus, ISE, Vivado, Modelsim successfully; it might not be supported by everything out there.

How can I check if a VHDL Integer is even or odd?

What is the easiest or simplest way to check if an integer signal is even or odd in VHDL?
if (A mod 2) = 0 then
-- it's even
else
-- it's odd
end if;
As a side note if the signal is a vector, then you can do the following:
if (A(0)) then
-- it's odd
else
-- it's even
function is_even(val : integer) return boolean is
constant vec: signed(31 downto 0) := to_signed(val, 32);
begin
return vec(0) = '0';
end;
or
function is_even(val : integer) return boolean is
begin
return val mod 2 = 0;
end;
depending on whether your synthesiser is bright enough to figure out mod 2
Another way if you are not storing as an integer * is to register the LSB from the standard logic vector holding the value and check if it is 0 or 1.
EDIT: Re-storing integers
removed * (which can be a problem on many FPGA's)
My mistake here, I was thinking along two different paths and mixed the two up. I have had trouble before passing character and string types between components when coding on FPGA's. While I cannot list the error messages off hand, I took a mental note to use std logic vectors instead of the pre-compile types. I found that they always seemed to work in simulation but never on the board.

Unsigned logic, vector and addition - How?

I'm creating a program counter that is supposed to use only unsigned numbers.
I have 2 STD_LOGIC_VECTOR and a couple of STD_LOGIC. Is there anything I need to do so that they only use unsigned? At the moment I only have library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
I also need to increase one of the binary vectors by 1 under certain conditions (as you probably have guessed by now). Would you be so kind to explain how to perform such actions (using unsigned and adding up one) considering one of the vectors is output with 32 bits.
I'm guessing (I tried) Output <= Output + 1; won't do. Oh and I'm using a process.
In brief, you can add the ieee.numeric_std package to your architecture (library ieee; use ieee.numeric_std.all;) and then do the addition using:
Output <= std_logic_vector(unsigned(Output) + 1);
to convert your std_logic_vector to an unsigned vector, increment it, and finally convert the result back to an std_logic_vector.
Note that if Output is an output port, this won't work because you can't access the value of an output port within the same block. If that is the case, you need to add a new signal and then assign Output from that signal, outside your process.
If you do need to add a signal, it might be simpler to make that signal a different type than std_logic_vector. For example, you could use an integer or the unsigned type above. For example:
architecture foo of bar is
signal Output_int : integer range 0 to (2**Output'length)-1;
begin
PR: process(clk, resetn)
begin
if resetn='0' then
Output_int <= 0;
elsif clk'event and clk='1' then
Output_int <= Output_int + 1;
end if;
end process;
Output <= std_logic_vector(to_unsigned(Output_int, Output'length));
end foo;
Output_int is declared with a range of valid values so that tools will be able to determine both the size of the integer as well as the range of valid values for simulation.
In the declaration of Output_int, Output'length is the width of the Output vector (as an integer), and the "**" operator is used for exponentiation, so the expression means "all unsigned integers that can be expressed with as many bits as Output has".
For example, for an Output defined as std_logic_vector(31 downto 0), Output'length is 32. 232-1 is the highest value that can be expressed with an unsigned 32-bit integer. Thus, in the example case, the range 0 to (2**Output'length)-1 resolves to the range 0...4294967295 (232=4294967296), i.e. the full unsigned range that can be expressed with 32 bits.
Note that you'll need to add any wrapping logic manually: VHDL simulators will produce an error when you've reached the maximum value and try to increment by one, even if the synthesized logic will cleanly wrap around to 0.

Resources