VHDL comparing non-constant part of std_logic_vector to zeros - vhdl

Suppose I have a vector :
action_complete: in std_logic_vector(n-1 downto 0)
How do I compare (inside the if statement) if PART of the vector is all zeros, where the comparison range depends on J (integer)? The integer is being changed inside the same process (state machine working with clock), but in other state.
Example code of what I want to do:
when s1 =>
J<=J+1;
when s2 =>
if action_complete(J-1 downto 0)=('all zeros') then ..

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

VHDL - custom shifter - concatenation input (in defined range) and remaining zeros

I am trying to write my own shifter. It all doesn't matter about the shifter, so please don't recommend me to do shifter by different way. The shifter is here only for demonstration my problem that I've reached.
Here is a piece of shifter description:
1: with operand_b select result <=
2: operand_a when "0000",
3: operand_a(14 downto 0) & '0' when "0001",
4: operand_a(13 downto 0) & "00" when "0010",
5: operand_a(12 downto 0) & "000" when "0011",
6: operand_a(11 downto 0) & "0000" when "0100",
7: operand_a(10 downto 0) & "00000" when "0101",
8: operand_a(9 downto 0) & "000000" when "0110",
9: operand_a(8 downto 0) & "0000000" when "0111",
10: operand_a(7 downto 0) & "00000000" when "1000",
11: operand_a(6 downto 0) & "000000000" when "1001",
12: operand_a(5 downto 0) & "0000000000" when "1010",
13: operand_a(4 downto 0) & "00000000000" when "1011",
14: operand_a(3 downto 0) & "000000000000" when "1100",
15: operand_a(2 downto 0) & "0000000000000" when "1101",
16: operand_a(1 downto 0) & "00000000000000" when "1110",
17: operand_a(0) & "000000000000000" when others;
Where operand_b is value used to be shifted by, result is output of the shifter.
As you can see, it is quite bottlenecking. What will happen when we have for instance 64 bit shifter - a lot of useless zeros. I was finding a lot on web how to write that more rationally, but every solution that I tried, like operand_a(13 downto 0) & (others => '0') when "0010" or (15 downto 2 => operand_a(13 downto 0), others => '0') when "0010" or (operand_a(13 downto 0), others => '0') when "0010" doesn't work. Everytime I got a report with some error.
Any solutions, please?
Sorry for my English.
EDIT:
When I replace operand_a(13 downto 0) & "00" when "0010", on the 4th line with:
operand_a(13 downto 0) & (others => '0') when "0010", it returns
Can not determine the "others" values in aggregate. (<= also for line 17)
Size of concat operation is different than size of the target.
(15 downto 2 => operand_a(13 downto 0), others => '0') when "0010", it returns
The type of the element in aggregate does not correspond to any array type.
(operand_a(13 downto 0), others => '0') when "0010", it returns
No array or record type can be found that has elements of types matching the aggregate.
operand_a(13 downto 0) & (1 downto 0 => '0') when "0010",
This one is working, but isn't here any way to use others?
Value expressions such as (operand_a(13 downto 0), others => '0') should work in IEEE Std 1076-2008.
Compare 9.3.3.3 Array aggregates, para 1 and 2:
For an aggregate of a one-dimensional array type, each choice shall specify values of the index type, and the expression of each element association shall be of either the element type or the type of the aggregate. If the type of the expression of an element association is the type of the aggregate, then either the element association shall be positional or the choice shall be a discrete range.
For an element association with a choice that is a discrete range and an expression of the element type of the aggregate, the value of the expression is the element at each index value in the range.
to IEEE Std 1076-1993 Array aggregates para 1:
For an aggregate of a one-dimensional array type, each choice must specify values of the index type, and the expression of each element association must be of the element type. An aggregate of an n-dimensional array type, where n is greater than 1, is written as a one-dimensional aggregate in which the index subtype of the aggregate is given by the first index position of the array type, and the expression specified for each element association is an (n-1)-dimensional array or array aggregate, which is called a subaggregate. A string or bit string literal is allowed as a subaggregate in the place of any aggregate of a one-dimensional array of a character type.
In -2008 we are allowed to have association elements that are the type of the aggregate (a one-dimensional array type). This allows association of slice names of the same type.
At the same time -2008 9.3.3.3 para 7 allows the use of the others choice:
e) As a value expression in an assignment statement, where the target is a declared object (or member thereof), and either the subtype of the target is a fully constrained array subtype or the target is a slice name
(And the target being a slice name has been added from previous revisions.) The rules for where you can use the others choice require you have context that supplies a subtype constraint.
So it tells us the VHDL implementation you are using is not -2008 compatible (or is not being used as -2008 compatible).
This feature is one of generally low priority for implementation in upgrading to -2008 compatibility.
Should you find your VHDL tool lacking support there are other ways to express your shifter such as:
SHIFTER:
process (operand_b, operand_a)
variable b: integer range 0 to operand_a'HIGH;
begin
result <= (others => '0');
if not is_x(operand_b) then -- culling meta-values
b := to_integer(unsigned(operand_b));
for i in result'range loop
if i = b then
result(result'high downto i) <=
operand_a (operand_a'high - i downto 0);
end if;
end loop;
end if;
end process;
This process is synthesis eligible, because the slice ranges depend on static values including the loop constant, loops are unrolled or parallelized for synthesis. There is an assignment statement for each binary value of operand_b and you rely on optimization in synthesis (which does amazingly well for things like multiplexers and shifters).
This method works by writing all of result as '0's then writing the portions of operand_a desired to result. It depends on sequential assignment inside the same process (and can be used with a sequential conditional signal assignment in a -2008 compatible implementation) and with if statement or a case statement. (But not a selected signal assignment which depends on same left hand side target).
The two assignment statements being executed in one process depends on there being a single driver and is supported by synthesis. The last written array element values overwrite earlier array element value writes, there is only one time slot for any particular simulation time in a projected output waveform.

VHDL multiple std_logic_vector to one large std_logic_vector

I have four std_logic_vectors (15 downto 0) and want to stack them into a std_logic_vector (63 downt 0) so fare I have found one way of doing it but is it the correct way or is there a more optimal and correct way to do it?
signal slv16_1,slv16_2,slv16_3,slv16_4 : std_logic_vector(15 downto 0);
signal slv64 : std_logic_vector(63 downto 0);
slv64(15 downto 0) <= slv16_1;
slv64(31 downto 16) <= slv16_2;
slv64(47 downto 32) <= slv16_3;
slv64(63 downto 48) <= slv16_4;
An easy way to accomplish this is to use the concatenation operator &. It achieves the same thing you did above, but with less code required.
slv64 <= slv16_4 & slv16_3 & slv16_2 & slv16_1;
Since the source vectors have unique names, I don't see a way to automate this. What you might be able to try is to never use the 16-bit vectors, and instead use slices of the larger 64 bit vector. So instead of an assignment like this:
slv16_1 <= "0101110000111010";
Use
slv64(15 downto 0) <= "0101110000111010";
Or instead of an entity instantiation where you connect slv16_2 like this:
output_port => slv16_2,
Use
output_port => slv64(31 downto 16),
I would really need to see more of your code to understand what might work best, but my basic answer is 'use the larger vector in the first place'.
If you can't do this for some reason, an alternative would be to declare your 16-bit vectors as an array of arrays:
type slv16_array_type is array (integer range <>) of std_logic_vector(15 downto 0);
signal slv16_array : slv16_array_type(3 downto 0);
You could then assign to the elements like this:
slv16_array(0) <= "0101";
You could combine the elements of this type with a generate loop:
slv16_combine : for i in 0 to 3 generate
slv64((16*(i+1))-1 downto 16*i) <= slv16_array(i);
end generate;
VHDL guide says that this one should work:
slv64 <= (slv16_4, slv16_3, slv16_2, slv16_1);

how to do zero padding al the lsb

I would like to add zero at the lsb (zero padding). my input is
m : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
and another vector (lets say a) that his length is changing all the time.
I didn't manage doing that by using bitwise "OR" because the length is always not the same.
Assuming you don't know the length of a, but want to zero pad the LSB of the resulting vector b it to length of b.
b(b'left downto b'left - a'left) <= a;
b(b'left - a'left - 1 downto 0) <= (others => '0');
I hope I didn't mix up the - 1.

Arithmetic mean vhdl

im trying to create element that would make an arithmetic mean. i have one input vector in all data should be written. and one clock input to change our input value. i looked in the internet but couldnt find result to help me to solve my problem. here is my code it works very espetial - it just works for first "some" results, and i could not understand the result. i work in Quartus 9.1. please help))
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
entity serArifmet is
generic ( r: integer :=8;
b: integer :=4);
port ( w: in signed (b-1 downto 0);
clk: in STD_LOGIC;
res: out signed (2*b-1 downto 0);
qqq: out signed(4*b-1 downto 0);
a: out signed (2*b-1 downto 0) );
end serArifmet;
architecture Arch_neuron_one of serArifmet is
type weights is array (1 to r) of signed (b-1 downto 0);
begin
process (clk, w)
variable weight: weights;
variable ost:signed(4*b-1 downto 0);
variable prod, acc, zzz: signed (2*b-1 downto 0);
variable prod2: signed (b-1 downto 0);
variable k:signed(7 downto 0);
variable eee: signed (3 downto 0);
begin
k:="00000001";
if (clk'event and clk='1') then
weight :=w & weight (1 to r-1);
end if;
acc := (others => '0');
for j in 1 to r loop
acc := acc + weight(j);
zzz:= (acc)/ k;
ost:=acc-zzz*k;
k:=k+1;
end loop;
a <= acc;
res<= zzz;
qqq<= ost;
end process;
end Arch_neuron_one;
You should remove 'w' from the sensitivity list and put the accum code inside the if (clk) statement.
Since 'w' and 'clk' are in the sensitivity list, the accum code will be evaluated each time w or clk changes. So it is probably being evaluated twice.
If you are actually trying to synthesize this, realize that the loop will unroll into a potentially deep and huge adder. As for the divide, it is an expensive operation that should ideally be avoided and may not even synthesize. If you must divide, it should be limited to powers of two, or be precomputed - calculate 1/N then implement it as a multiply. That is, x/4 = .25*x. If you have a bunch of N's, precompute them all then select the one you need.

Resources