I want to check if std_logic_vector contains negative integer - vhdl

How can I check with if (...) then ... end if; construction if std_logic_vector variable holds the bits of a negative number? If it is negative, I have to assign it a zero value.
I have :
signal sum : std_logic_vector (15 downto 0);
sum<= (...);
if (...) then
sum<=x"00";
end if;
Thank you!

You cannot add two STD_LOGIC_VECTORs, because the language does not know anything about the arithmetic that it should perform. This is because, to the synthesis tool, every signal/port/variable that's declared as STD_LOGIC_VECTOR is nothing more than an array of STD_LOGIC, the multi-valued logic type. Arithmetic on such a type does not make sense.
If you want to use arithmetic on types whose interface is similar to the one exposed by STD_LOGIC_VECTOR, you should use SIGNED (for signed arithmetic) and UNSIGNED (for unsigned arithmetic) types defined in IEEE.NUMERIC_STD. In order to convert between these types, just cast them using the type names explicitly, like this :
std_logic_vector_variable := STD_LOGIC_VECTOR(unsigned_variable);
unsigned_variable := UNSIGNED(std_logic_vector_variable);
So, summing it all up - the signal sum should be declared as SIGNED, since you're obviously going to perform arithmetic on it. Then, you can freely use the comparison and arithmetic operations that you need. The resulting code should look more or less like this :
use IEEE.NUMERIC_STD.ALL;
-- entity and architecture declarations...
signal sum : SIGNED (15 downto 0);
-- inside some process...
if (sum <= 0) then sum <= 0; end if;

The quick and simple hack is to check if the most-significant-bit is 1, indicating a negative number:
result <= (others=>'0') when sum(sum'left)='1' else sum;
Or you can coerce the std_logic_vector into an appropriate type and see if it is negative:
result <= (others=>'0') when signed(sum) < 0 else sum;
Or inside of a process use an if statement instead of a selected signal assignment:
if signed(sum) < 0 then
result <= (others=>'0');
else
result <= sum;
end if;

signal sum : std_logic_vector (15 downto 0);
sum<= x"E8";
if (sum(15)='1') then
sum<=x"00";
end if;
Just check the MSB..
If MSB is 1, that means the number is negative else positive.

Related

Combining `others` expression with `signed` cast

Let var stand for a signed vector (library IEEE.NUMERIC_STD.ALL) of size m.
Let foo be another variable of type std_logic_vector(n-1 downto 0), where n is smaller than m.
I want to concatenate a '0' left of foo, then pad it with zeroes in its right until it size is m and then store the result in var.
I tried
rdsor <= signed('0' & divisor & others=>'0');
But Xilinx complains with the following message on synthesis:
Syntax error near "others".
How do I do what I want?
Assuming rdsor is equivalent to your theoretical var and divisor equivalent to foo you could use two assignments in a process statement:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity jsevillamol is
end entity;
architecture fum of jsevillamol is
constant M: natural := 42;
constant N: natural := 23;
signal rdsor: signed (M - 1 downto 0);
signal divisor: std_logic_vector (N - 1 downto 0);
begin
-- rdsor <= signed('0' & divisor & others=>'0');
process (divisor)
begin
rdsor <= (others => '0');
rdsor (rdsor'LEFT downto rdsor'LEFT - divisor'LENGTH)
<= signed('0' & divisor);
end process;
end architecture;
This works because each element of rdsor is a separate signal and there is only one value for any particular time in a projected output waveform. By not providing an after time_expression in the waveform element of the second assignment the elements of rdsor slice will be assigned the second assignments expression values. (The elements of the first assignment are supplanted by the second). This method of overwriting the projected output waveform is commonly used in providing default values prior to incomplete condition coverage with if statements.
This example analyzes, elaborates and simulates, while doing nothing interesting it demonstrates index ranges are constructed properly.
Notice it avoids the issue of concatenation versus aggregation brought up by Matthew Taylor's answer.
For a single signal assignment in a method not sensitive to tool VHDL revision:
architecture fie of jsevillamol is
constant M: natural := 42;
constant N: natural := 23;
signal rdsor: signed (M - 1 downto 0);
signal divisor: std_logic_vector (N - 1 downto 0);
subtype other is signed (rdsor'LEFT - divisor'LENGTH - 1 downto 0);
begin
-- rdsor <= signed('0' & divisor & others=>'0');
rdsor <= '0' & signed(divisor) & other'(others => '0');
end architecture;
This uses concatenation and subsumes the others into an aggregate. There's a subtype declaration for the trailing '0's portion to allow the aggregate expression to be the target of a qualified expression.
This architecture also analyzes, elaborates and simulates proving index arithmetic is correct.
You would need to use others as part of an aggregate not part of a concatenation. Here's a solution using an aggregate and attributes (which relies on you using VHDL 2008):
rdsor <= (rdsor'LEFT => '0', (rdsor'LEFT-1) downto (rdsor'LEFT-divisor'LENGTH) => signed(divisor), others => '0');
https://www.edaplayground.com/x/5Yuw

cross total of a std_logic_vector

My purpose of this code is a cross total of a std_logic_vector.
I have the following code:
generic(
lowPass_len : integer := 4;
...
signal inputbuffer : std_logic_vector(lowPass_len-1 downto 0);
signal sum: integer range 0 to lowPass_len;
signal lowpass_alarm_tog : std_logic;
...
inputbuffer <= inputbuffer(lowPass_len-1 downto 1) & alarm_tog_d2_meta;
for i in (lowPass_len-1) downto 1 loop
sum <= to_integer(unsigned(inputbuffer(i-1)) + unsigned(inputbuffer(i)));
end loop;
because inputbuffer is a std_logic_vector, I wanted to cast it to unsigned to make the addition. then convert it to integer, as sum has this kind of type.
ghdl gives me the following mistake for two times in this line
conversion not allowed between not closely related types
The expression inputbuffer(i-1) just returns a single bit of type std_logic. This cannot be directly casted to unsigned because the latter is an array of std_logic.
You have to extend the single bit to a vector of the required length first. The length depends on the highest number which could be encountered in the addition.

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

AND all elements of an n-bit array in VHDL

lets say I have an n-bit array. I want to AND all elements in the array. Similar to wiring each element to an n-bit AND gate.
How do I achieve this in VHDL?
Note: I am trying to use re-usable VHDL code so I want to avoid hard coding something like
result <= array(0) and array(1) and array(2)....and array(n);
Thanks
Oshara
Solution 1: With unary operator
VHDL-2008 defines unary operators, like these:
outp <= and "11011";
outp <= xor "11011";
outp <= and inp; --this would be your case
However, they might not be supported yet by your compiler.
Solution 2: With pure combinational (and traditional) code
Because in concurrent code you cannot assign a value to a signal more than once, your can create a temp signal with an "extra" dimension. In your case, the output is one-bit, so the temp signal should be a 1D array, as shown below.
-------------------------------------------
entity unary_AND IS
generic (N: positive := 8); --array size
port (
inp: in bit_vector(N-1 downto 0);
outp: out bit);
end entity;
-------------------------------------------
architecture unary_AND of unary_AND is
signal temp: bit_vector(N-1 downto 0);
begin
temp(0) <= inp(0);
gen: for i in 1 to N-1 generate
temp(i) <= temp(i-1) and inp(i);
end generate;
outp <= temp(N-1);
end architecture;
-------------------------------------------
The inferred circuit is shown in the figure below.
Solution 3: With sequential code
This is simpler than solution 2, though you are now using sequential code to solve a purely combinational problem (but the hardware will be the same). You can either write a code similar to that in solution 2, but with a process and loop (the latter, in place of generate) or using a function. Because in sequential code you are allowed to assign a value to a signal more than once, the temp signal of solution 2 is not needed here.
If you have VHDL-2008 available, then reduction and is build into the
language as David Koontz and Pedroni have explained.
If you only have VHDL-2003 and prior available, then you can use a function
like:
function and_reduct(slv : in std_logic_vector) return std_logic is
variable res_v : std_logic := '1'; -- Null slv vector will also return '1'
begin
for i in slv'range loop
res_v := res_v and slv(i);
end loop;
return res_v;
end function;
You can then use the function both inside and outside functions with:
signal arg : std_logic_vector(7 downto 0);
signal res : std_logic;
...
res <= and_reduct(arg);
My favorite, non-VHDL-2008 solution is:
use ieee.std_logic_unsigned.all ; -- assuming not VHDL-2008
. . .
result <= '1' when not MyArray = 0 else '0' ;
With VHDL-2008, I recommend that you use the "and" reduction built-in (see Pedroni's post) and use the IEEE standard package "ieee.numeric_std_unsigned.all" instead of the shareware package "std_logic_unsigned".

convert integer to std_logic

Suppose you have a loop
for i in 1 downto 0 loop
for j in 1 downto 0 loop
tS0 <= i;
But I need to convert the integer (which is natural) to std_logic. tS0 is declared as std_logic. I am only doing it one bit (0 or 1). That is, my i and j can only represent the value {0,1}.
I think I am heading to the wrong approach here. Can someone please tell me what should I do instead?
I don't think std_logic has to_unsigned method. i tried letting tS0 to be a vector (1 down to 0), and assigned like tS0(0) <= i, and etc. But it still didn't work out.
Thank you very much!
There is no need to convert from integers. You can just iterate over the std_logic datatype:
for i in std_logic range '0' to '1' loop
ts0 <= i;
end loop;
I'd write a function:
function to_std_logic(i : in integer) return std_logic is
begin
if i = 0 then
return '0';
end if;
return '1';
end function;
then use:
ts0 <= to_std_logic(i);
You will need to use a vector, either unsigned or std_logic, but it can be one bit long. ie:
signal tS0 : unsigned (0 downto 0);
...
tS0 <= to_unsigned(i, tS0'length);
...or...
signal tS0: std_logic_vector(0 downto 0);
...
tS0 <= std_logic_vector(to_unsigned(i,tS0'length);
You can do it like this. It looks a little simplier.
ts0 <= std_logic(to_unsigned(i, 1)(0));
You will build a unsigned vector by using the to_unsigned function. Then you grap the lowest bit and convert it to std_logic and then you assign it to the signal.
This is how it works fine :-).
Improving on a previous answer, you could write:
ts0 <= to_unsigned(i, 1)(0);
Provided you include the "numeric_std" library, in which that function is defined:
library IEEE;
use IEEE.numeric_std.all;
You can skip the explicit cast to "std_logic" type because the return type of "to_unsigned()" is an array of "std_logic" itself:
type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;

Resources