I have this piece of code
function func (k1, k2 : in bit_vector) return bit_vector is
variable result : bit_vector(1 to 32);
begin
for i in 0 to 31 loop
result(i) <= k1(i);
end loop;
return result;
end func;
I get this error :
target (variable "result") is not a signal
I know I need to change the type of result but I don't know what it should be.
Thanks.
When assigning to a variable use := as:
result(i) := k1(i);
Assign with <= is for assign to signal.
The range of result (1 to 32) does not match the range in the loop (0 to 31), so first assign in the loop (result(0) := k1(0)) will cause in a range error. Fix this by changing either result or loop range.
Related
Hi guys i have the following package, defined by myself
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package util_pkg is
function log2c(n : natural) return natural;
end package util_pkg;
package body util_pkg is
function log2c(n : natural) return natural is
variable temp : natural := n;
variable ret_val : natural := 0;
begin
while temp > 1 loop
ret_val := ret_val + 1;
temp = temp/2;
end loop;
return ret_val;
end function log2c;
end package body util_pkg;
while my design is
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
use work.util_pkg.all;
entity ldz is
generic(n : natural); --i can assume n > 1
port(x : in std_logic_vector(n - 1 downto 0);
y : out std_logic_vector(log2c(n) - 1 downto 0));
end entity ldz;
-- Example
architecture ldz_arch of ldz is
function ldz_count(x : unsigned) return natural is
n_ldz : natural := 0;
begin
for i in x'high to 0 loop
if(x(i) = '1') then
return x'length - i - 1;
end if;
end loop;
return x'length - 1;
end function ldz_count;
begin
y <= std_logic_vector(to_unsigned(ldz_count(to_unsigned(x)));
end architecture ldz_arch;
When i try to verify the syntax with ncvhdl this is the error i get
unit (UTIL_PKG) not found in library (WORKLIB)
however such unit (package) is in the same library of the design.
the file is util_pkg.vhd while the design is ldz.vhd
What is wrong?
The tool complains because the package has not been analysed (compiled) before ldz. Compile it first and ldz next.
As mentioned in the comments, your code suffers several problems. The following code computes the log2 of a positive, rounded towards 0 or infinity:
function log2_down(n: positive) is
variable res: natural := 0;
begin
if n /= 1 then
res := 1 + log2_down(n / 2);
end if;
return res;
end function log2_down;
function log2_up(n: positive) is
variable res: natural := 0;
begin
if n /= 1 then
res := 1 + log2_up((n + 1) / 2);
end if;
return res;
end function log2_up;
Yes, VHDL supports recursion and most synthesisers too, at least when the number of iterations is statically computable.
The res variable could be avoided but it helps avoiding the warnings of some tools that warn you if the return statements of a function are all under control of a control structure. They do this because they cannot prove that the function will always return while a function shall always return. I always try to suppress the warnings such that any remaining warning is meaningful and cannot be ignored.
Declaring the parameter as positive is a simple way to deal with the log2(0) error. I always try to use the built-in features of the language to deal with errors.
With the same two principles (no warnings, let the built-in features of the language deal with errors), your leading zero counter ldz_count function could be written:
function ldz_count(x: unsigned) return natural is
constant n: positive := x'length;
constant v: unsigned(0 to n - 1) := x;
variable res: natural := n;
begin
for i in 0 to n - 1 loop
if v(i) = '1' then
res := i;
end if;
end if;
return res;
end function ldz_count;
Copying the x parameter with a chosen bit indexing will make your function usable with any x parameter whatever its declaration (7 to 35 or 9 downto 4) as long as it is at least one bit long. This is the third principle I like: if you make something generic, make it really generic.
So im trying to write a function that performs an AND gate, the intput is a vector of the gate inputs, and the number of inputs. But for some reason the compiler gives me an error that it doesn't recognize the "and" logic operator im using inside for some reason. can anyone spot the issue?
p.s this is all part of a bigger project that is a 16counter (0-15) thats made of 4 chained JK flip flops and 2 AND gates (using my "myand" function).
function myand (x: std_logic_vector; n : integer range 7 downto 0) return std_logic is
variable result: integer :=0;
begin
for i in 0 to n-1 loop
result:=result and x(i);
end loop;
return result;
end function;
The compiler error is:
Error (10327): VHDL error at counter16.vhd(16): can't determine definition of operator ""and"" -- found 0 possible definitions
I even tried using '+' instead of 'and' but its the same error.
The builtin libraries of VHDL don't define a operator and that takes a integer and std_logic.
How to fix this:
result should be a std_logic instead of an integer.
result should be initialized to '1' instead of 0.
The function interface can be simplified by removal of the ´n´ argument if the 'range attribute is used on x to get the index values. If a subrange of a std_logic_vector is used as argument, then the myand function can be called with that subrange only. Including sharth suggestions, the function is:
function myand (x : std_logic_vector) return std_logic is
variable result : std_logic := '1';
begin
for i in x'range loop
result := result and x(i);
end loop;
return result;
end function;
Is there a shorthand way to set a row of values in a matrix? I'm looking for a function/procedure type of solution.
Just to clarify, by matrix I don't mean an array of array but rather a 2D array.
I've managed to read a specific row using:
function extract_row(matrix : matrix_type; row_index : natural) return row_type is
variable res : row_type (matrix'range(2));
begin
for i in res'range loop
res(i) := matrix(row, i);
end loop;
return res;
end function;
And now I need a way to set a row in a fashion similar to how one can set a subarray in the array of arrays:
signal x : array_of_rows_type(range_a)(range_b);
signal y : row_type(range_b);
x(0) <= y;
I realise the shorthand isn't necessary and that one can work around it using loops and generates, but I have many places where I need to do this, and it's becoming increasingly difficult to keep legible code (and my sanity).
For those wondering, the reason why I'm using the matrix approach and not the array of arrays is because I need to reuse the type in multiple entities with different ranges.
Bonus points if the solution somehow allows me to use it in port mapping (although I realise this is impossible, unless I've misunderstood VHDL completely). i.e.:
port map (
row_type_outport => row_insert_solution(matrix, row)
)
I seem to recognize the code for the extract_row function. Perhaps you could adapt the function replace_matrix_column that is given in the same package?
function replace_matrix_column(
input_matrix: bit_matrix;
new_column: bit_vector;
column_index: integer
) return bit_matrix is
variable output: bit_matrix(input_matrix'range(1), input_matrix'range(2));
begin
for i in input_matrix'range(1) loop
for j in input_matrix'range(2) loop
if j = column_index then
output(i, j) := new_column(i);
else
output(i, j) := input_matrix(i, j);
end if;
end loop;
end loop;
return output;
end;
Then you could call it like this:
x <= replace_matrix_row(x, y, 0);
Or, for better clarity:
x <= replace_matrix_row(input_matrix => x, new_row => y, row_index => 0);
I don't have your types, so I can't compile this to make sure it works, but this might help get you close.
function row_insert_solution(matrix : matrix_type;
row_insert : row_type;
row_index : natural
) return matrix_type is
variable res : matrix_type := matrix;
begin
for i in row_insert'range loop
res(row_index, i) := row_insert(i);
end loop;
return res;
end function;
I have a simple question . Is it possible to write a VHDL for loop with step size not equal to 1 e.g 16
The loop should go like
0--> 16 --> 32--> 48.... to some value
any immediate help is appreciated
A possible solution is to use a range that is 1/16th of the desired range and unroll the loop inside it to generate the desired range:
for i in 0 to 3 -- Actually 0 to 48
loop
x(16*i) <= ...
x((16*i)+1) <= ...
(...)
x((16*i)+15) <= ...
end loop;
Another solution would be to use a while instead. Assuming your count variable is an integer:
while (i < 48)
loop
--Do something
i := count + 16;
end loop;
Edit: I haven't tested the code above, you might be unable to change the variable count inside the loop, I'm not sure. Maybe the first solution is the best one.
It is not possible to have a for loop with a step different then 1. You are not even allowed to change it inside the for, like this:
--THIS WILL NOT WORK
for i in 0 to 48 loop
--Do Something
i := i + 15; -- This will NOT increment the loop index by 16
end loop;
And finally, for steps of 2 or 3 you might use nested for's.
But anyway, What are you trying to accomplish? VHDL is a low-level hardware description language, you should be able to achieve whatever you are trying to without fancy for loops.
VHDL has no step parameter in for loop, so the step is always 1 for to
range direction and -1 for downto range direction.
So if you need loop with start and step value, you can do:
...
constant FOR_START : natural := 1;
constant FOR_STEP : natural := 2;
variable idx_v : natural; -- Support index variable
...
for idx_pre in 0 to 3 loop
idx_v := FOR_START + FOR_STEP * idx_pre;
z_o(idx_v) <= a_i(idx_v);
end loop;
A while loop can also be used as alternative:
constant FOR_START : natural := 1;
constant FOR_STEP : natural := 2;
constant FOR_MAX : natural := 7;
variable idx_v : natural;
...
idx_v := FOR_START;
while idx_v <= FOR_MAX loop
z_o(idx_v) <= a_i(idx_v);
idx_v := idx_v + FOR_STEP;
end loop;
How about looping over the entire range, but then using an 'if' statement to only act on every 16th value?
for i in start_thing to end_thing loop
if i mod 16 = 0 then
do things(i)
end if;
end loop; -- i
Or alternately use Next:
for i in start_thing to end_thing loop
next when i mod 16 /= 0 ;
do_things(i)
end loop; -- i
My research says no, but you can declare a second variable that acts as a multiple of your variable inside of your loop.
Yes, it is possible to "for loop" with a step size not equal to 1.
for i in range 1 downto 0 loop
foo(i) <= bar(1-i);
end
loop;
back:while (sub1_mantissa(52)='0') loop
sub1_mantissa := sub1_mantissa(51 downto 0) & '0';
count := count + "000000000001";
end loop back;
hi .i want to count leading zeros in vector...like if my result is 0001 so it will show 3 zeros..so my counter will be increment by 3..and when i will get the first 1 in msb then my loop will stop...
i m using the above code..but it is not working...counter value it takes is too large like 1100111...i am not getting where is d problem...guys plz help me...n reply soon
I would use a for loop to count this, something like this:
variable zero_count : natural := 0;
for i in sub1_mantissa'range loop
if sub1_mantissa(i) = '0' then
zero_count := zero_count + 1;
else
exit;
end if;
end loop;
NOTE: this will only count the leading zeros if sub1_mantissa is declared using DOWNTO notation.