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.
Related
I would like to implement a count min sketch with minimal update and access times.
Basically an input sample is hashed by multiple (d) hash functions and each of them increments a counter in the bucket that it hits. When querying for a sample, the counters of all the buckets corresponding to a sample are compared and the value of the smallest counter is returned as a result.
I am trying to find the minimum value of the counters in log_2(d) time with the following code:
entity main is
Port ( rst : in STD_LOGIC;
a_val : out STD_LOGIC_VECTOR(63 downto 0);
b_val : out STD_LOGIC_VECTOR(63 downto 0);
output : out STD_LOGIC_VECTOR(63 downto 0);
. .
. .
. .
CM_read_ready : out STD_LOGIC;
clk : in STD_LOGIC);
end main;
architecture Behavioral of main is
impure function min( LB, UB: in integer; sample: in STD_LOGIC_VECTOR(long_length downto 0)) return STD_LOGIC_VECTOR is
variable left : STD_LOGIC_VECTOR(long_length downto 0) := (others=>'0');
variable right : STD_LOGIC_VECTOR(long_length downto 0) := (others=>'0');
begin
if (LB < UB)
then
left := min(LB, ((LB + UB) / 2) - 1, sample);
right := min(((LB + UB) / 2) - 1, UB, sample);
if (to_integer(unsigned(left)) < to_integer(unsigned(right)))
then
return left;
else
return right;
end if;
elsif (LB = UB)
then
-- return the counter's value so that it can be compared further up in the stack.
return CM(LB, (to_integer(unsigned(hasha(LB)))*to_integer(unsigned(sample))
+ to_integer(unsigned(hashb(LB)))) mod width);
end if;
end min;
begin
CM_hashes_read_log_time: process (clk, rst)
begin
if (to_integer(unsigned(instruction)) = 2)
then
output <= min(0, depth - 1, sample);
end if;
end if;
end process;
end Behavioral;
When I run the above code, I get the following errors:
The simulator has terminated in an unexpected manner. Please review
the simulation log (xsim.log) for details.
[USF-XSim-62] 'compile' step failed with error(s). Please check the
Tcl console output or '/home/...sim/sim_1/behav/xsim/xvhdl.log' file
for more information.
[USF-XSim-62] 'elaborate' step failed with error(s). Please check the
Tcl console output or
'/home/...sim/sim_1/synth/func/xsim/elaborate.log' file for more
information.
I was not able to find any file called xsim.log and xvhdl.log was empty, but elaborate.log had some content:
Vivado Simulator 2018.2
Copyright 1986-1999, 2001-2018 Xilinx, Inc. All Rights Reserved.
Running: /opt/Xilinx/Vivado/2018.2/bin/unwrapped/lnx64.o/xelab -wto c199c4c74e8c44ef826c0ba56222b7cf --incr --debug typical --relax --mt 8 -L xil_defaultlib -L secureip --snapshot main_tb_behav xil_defaultlib.main_tb -log elaborate.log
Using 8 slave threads.
Starting static elaboration
Completed static elaboration
INFO: [XSIM 43-4323] No Change in HDL. Linking previously generated obj files to create kernel
Removing the following line solves the above errors:
output <= min(0, depth - 1, sample);
My questions:
Why am I not able to simulate this code?
Will this code be synthsizable once it is working?
Is there a better (and/or faster) way to obtain the minimum of all relevant hash buckets?
not that I was able to find any real world use for recursion, but just to surprise #EML (as requested in the comments above): you actually can define recursive hardware structures in VHDL.
In Quartus at least, this only works if you give the compiler a clear indication of the maximum recursion depth, otherwise it will try to unroll the recursion to any possible input, eventually dying from a stack overflow:
entity recursive is
generic
(
MAX_RECURSION_DEPTH : natural
);
port
(
clk : in std_ulogic;
n : in natural;
o : out natural
);
end recursive;
architecture Behavioral of recursive is
function fib(max_depth : natural; n : natural) return natural is
variable res : natural;
begin
if max_depth <= 1 then
res := 0;
return res;
end if;
if n = 0 then
res := 0;
elsif n = 1 or n = 2 then
res := 1;
else
res := fib(max_depth - 1, n - 1) + fib(max_depth - 1, n - 2);
end if;
return res;
end function fib;
begin
p_calc : process
begin
wait until rising_edge(clk);
o <= fib(MAX_RECURSION_DEPTH, n);
end process;
end Behavioral;
With a MAX_RECURSION_DEPTH of 6, this generates one single combinational circuit with more than 500 LEs (so the pracical use is probably very limited), but at least it works.
Is recursion possible in VHDL?
I would say, yes, but not recursion as we know it. That's the short answer. I have code (if anyone is interested that implements Quicksort) and it will synthesize quite happily. If anyone knows about Quicksort, it normally won't be anywhere near the context of synthesis. But I managed to do it.
The trick (which is vexatious and hard to follow) is to emulate recursion with a strange state machine that backtracks to the beginning state, after pushing a "state" onto a (hardware) stack. You can synthesize this sort of data structure quite easily if you want.
I recall some fascinating stuff written by Thatcher, Goguen and Wright about semantic transformations from one kind of coding domain to others (different models of computation, in short).
It does strike me that this is possibly a genesis point for actual recursive expressions in a more general sense. But do be warned, it's very difficult.
I used Xlinix ISE 14.1 to write the following code.
I found the syntax to be correct but the xilinx IDE shows errors at line 27 and 30.
I am trying to find the first partial derivatives of a matrix of numbers which is similar to finding the edges in an image.
The function by2i is used to convert the bytes (i.e. bits) to integer number.
In this VHDL code I am getting error messages:
"ERROR:HDLCompiler:806 B:/gxgyVHDL.vhd" Line 27: Syntax error near "return".
"ERROR:HDLCompiler:806 - "B:/gxgyVHDL.vhd" Line 30: Syntax error near ","".
I am unable to correct these errors as I know very little in VHDL. I learned basic programming in VHDL like implementing MUX, counters etc.
This is the first time I am writing a program for image processing And I'm not sure whether this program works like expected but it works well matlab and python.
Please help to correct these errors.
Here is vhdl code:
enter code here
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.numeric_std.ALL;
use IEEE.math_real.ALL;
entity getGxGy is
generic (width : natural := 66;
height : natural := 130); --width and height of the image window.
Port( pxl : in STD_LOGIC_VECTOR(7 downto 0);
clk : in bit;
fv : out real); --need to configure 'fv' signal properly to appropriate bit vector.
end getHOGfv;
architecture behave of getGxGy is
function by2i (b : STD_LOGIC_VECTOR(7 downto 0)) return natural is
variable num : natural;
begin
num := 0;
for i in b'Range loop
if b(i) = '1' then
num := num + 2**i;
end if;
end loop
return num
end by2i;
type bufarr is array (1 to height, 1 to width) of natural;
type gxgy is array (1 to height-2, 1 to width-2) of integer;
--signal tempfv : mat4;
process(clk, pxl)
variable buf: bufarr;
variable gx, gy: gxgy;
begin
--Buffer to store/create 64*128 pixels/widthindowidth
for h in 2 to height-1 loop
for w in 2 to width-1 loop
buf(h)(w) := by2i(pxl);
end loop;
end loop;
--1pixel padding
for w in 1 to width loop
buf(1)(w) := 0;
end loop;
for w in 1 to width loop
buf(height)(w) := 0;
end loop;
for h in 2 to height-1 loop
buf(h)(1) := 0;
end loop;
for h in 2 to height-1 loop
buf(h)(width) := 0;
end loop;
--compute gradients
for h in 2 to height-1 loop
for w in 2 to width-1 loop
gx(h)(w) := buf(h+1)(w)-buf(h-1)(w);
gy(h)(w) := buf(h)(w+1)-buf(h)(w-1);
mag(h)(w) := abs(gx(h)(w)+gy(h)(w));
ang(h)(w) := gy(h)(w)/gx(h)(w);
end loop;
end loop;
end process;
end behave;
Several problems:
Your entity names do not match. That is, entity getGxGy does not match end getHOGfv;
You are missing a trailing ; on the end loop in by2i
You are missing a trailing ; on the return in by2i
You are missing a begin statement in your architecture (between the type gxgy and the process(clk, pxl)
Your syntax for the use of multidimensional arrays is wrong. Rather than buf(1)(w), it should be buf(1, 2).
Neither mag nor ang are defined.
When you have a large number of errors, it can be difficult to track down the exact cause. Often the compilers get confused at reporting the errors. Start with the first one, fix it, and re-compile. Continue until things cleanup.
Also, a point of clarification. You don't need by2i. You can use numeric_std to do the converstion (thanks to scary_jeff for pointing this out). Use to_integer(unsigned(pxl)) to do the conversion.
And one further point. Do not use both std_logic_unsigned and numeric_std at the same time. numeric_std is the standard way to use signed and unsigned numbers. std_logic_unsigned was a vendor specific extension that is not standard.
Edit: You used the following syntax to define your arrays:
type bufarr is array (1 to height, 1 to width) of natural;
This is fine. And as I noted above you have to use the buf(h, w) syntax. But you could define it differently, such as:
type width_array is array(1 to width) of natural;
type bufarr is array(1 to height) of width_array;
Which you could then index using buf(h)(w).
I prefer the former.
In addition to the syntax items and missing declarations noted by PlayDough there are two superfluous context clauses for packages numeric_std (which should not be mixed with the Synopsys arithmetic pages std_logic_unsigned) and math_real (which isn't yet used).
After all the changes are edited in:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
-- use ieee.numeric_std.all;
-- use ieee.math_real.all;
entity getgxgy is
generic (width : natural := 66;
height : natural := 130); -- width and height of the image window.
port( pxl : in std_logic_vector(7 downto 0);
clk : in bit;
fv : out real); -- need to configure 'fv' signal properly to appropriate bit vector.
end getgxgy; -- WAS gethogfv;
architecture behave of getgxgy is
function by2i (b : std_logic_vector(7 downto 0)) return natural is
variable num : natural;
begin
num := 0;
for i in b'range loop
if b(i) = '1' then
num := num + 2 ** i;
end if;
end loop; -- MISSING ';'
return num; -- MISSING ';'
end function by2i;
type bufarr is array (1 to height, 1 to width) of natural;
type gxgy is array (1 to height - 2, 1 to width - 2) of integer;
--signal tempfv : mat4;
begin -- for architecture modiy WAS MISSING
process (clk, pxl)
variable buf: bufarr;
variable gx, gy: gxgy;
variable mag, ang: gxgy; -- MISSING DECLARATIONS
begin
--buffer to store/create 64*128 pixels/widthindowidth
for h in 2 to height - 1 loop
for w in 2 to width - 1 loop
buf(h, w) := by2i(pxl); -- WAS buf(h)(w)
end loop;
end loop;
--1pixel padding
for w in 1 to width loop
buf(1, w) := 0; -- WAS buf(1)(w)
end loop;
for w in 1 to width loop
buf(height, w) := 0; -- WAS buf(height)(w)
end loop;
for h in 2 to height - 1 loop
buf(h, 1) := 0; -- WAS buf(h)(1)
end loop;
for h in 2 to height - 1 loop
buf(h, width) := 0; -- WAS buf(h)(width)
end loop;
--compute gradients
for h in 2 to height - 1 loop
for w in 2 to width - 1 loop
gx(h, w) := buf(h + 1, w) - buf(h - 1, w); -- WAS gx(h)(w), buf(h+1)(w) and buf(h-1)(w)
gy(h, w) := buf(h, w + 1) - buf(h, w - 1); -- WAS gy(h)(w), buf(h)(w+1) and buf(h)(w-1)
mag(h, w) := abs(gx(h, w) + gy(h, w)); -- WAS mag(h)(w), x(h)(w) and gy(h)(w)
ang(h, w) := gy(h, w) / gx(h, w); --WAS ang(h)(w), gy(h)(w) and gx(h)(w)
end loop;
end loop;
end process;
end architecture behave;
your code analyzes and elaborates, noting there is no assignment to fv, type REAL is not synthesis eligible and there is no synthesis eligible use of clk.
If clk were std_logic (or std_ulogic) you could use the std_logic_1164 function rising_edge.
Adding a recognized sequential logic RTL construct for a clock edge gives:
process (clk) -- pxl NOT NEEDED , pxl)
variable buf: bufarr;
variable gx, gy: gxgy;
variable mag, ang: gxgy; -- MISSING DECLARATIONS
begin
if clk'event and clk = '1' then
--buffer to store/create 64*128 pixels/widthindowidth
for h in 2 to height - 1 loop
for w in 2 to width - 1 loop
buf(h, w) := conv_integer(pxl); -- WAS buf(h)(w)
end loop; -- CHANGED to use conv_integer
end loop;
--1pixel padding
for w in 1 to width loop
buf(1, w) := 0; -- WAS buf(1)(w)
end loop;
for w in 1 to width loop
buf(height, w) := 0; -- WAS buf(height)(w)
end loop;
for h in 2 to height - 1 loop
buf(h, 1) := 0; -- WAS buf(h)(1)
end loop;
for h in 2 to height - 1 loop
buf(h, width) := 0; -- WAS buf(h)(width)
end loop;
--compute gradients
for h in 2 to height - 1 loop
for w in 2 to width - 1 loop
gx(h, w) := buf(h + 1, w) - buf(h - 1, w); -- WAS gx(h)(w), buf(h+1)(w) and buf(h-1)(w)
gy(h, w) := buf(h, w + 1) - buf(h, w - 1); -- WAS gy(h)(w), buf(h)(w+1) and buf(h)(w-1)
mag(h, w) := abs(gx(h, w) + gy(h, w)); -- WAS mag(h)(w), x(h)(w) and gy(h)(w)
ang(h, w) := gy(h, w) / gx(h, w); --WAS ang(h)(w), gy(h)(w) and gx(h)(w)
end loop;
end loop;
end if;
end process;
also noting the switch to the package std_logic_unsigned function conv_integer from using function by2i.
So these changes along with deleting the function by2i analyzes.
Genning up a testbench to look for bounds errors:
library ieee;
use ieee.std_logic_1164.all;
entity getgxgy_tb is
end entity;
architecture foo of getgxgy_tb is
signal pxl: std_logic_vector(7 downto 0) := (others => '0');
signal clk: bit;
signal fv: real;
begin
DUT:
entity work.getgxgy
port map (
pxl => pxl,
clk => clk,
fv => fv
);
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if now > 120 ns then
wait;
end if;
end process;
end architecture;
And we elaborate and run the testbench and get a run time error!
The error is division by zero in the assignment to ang, so your algorithm needs a bit of work still.
Blocking that with an if statement and we find there's a bounds error in the assignment:
gx(h, w) := buf(h + 1, w) - buf(h - 1, w); -- WAS gx(h)(w), buf(h+1)(w) and buf(h-1)(w)
And that's caused by hitting w = 65 when
type gxgy is array (1 to height - 2, 1 to width - 2) of integer;
type gxgy's second dimension corresponding to w has a range to width - 2 while w reaches width - 1 which is out of bounds.
So a bit more algorithmic expression tuning still to do.
It isn't particularly clear what you intend to register. If it's just fv that could occur in a different process, with the current processes sensitivity list set to just pxl and gx, gy, mag and ang made into signals.
It's likely that all the abs, multiplies and divides may not fit in a target FPGA, requiring operations be spread over some number of clocks using common resources for arithmetic operations. VHDL describes hardware and every operator invocation or function call can imply it's own hardware.
In synthesis a loop statement has it's sequence of statements 'unrolled' and where no interdependencies are found produce separate hardware. For h in 2 to height - 1 and w in 2 to width - 1 ranges in your nested loops your generic values are implying 8001 subtracts for each of gx and gy, abs and addition for mag and divides for ang, all from changing the value of pxl. This tells us your hardware isn't going to fit in any FPGA without sharing resources over some number of clocks, a time and space tradeoff.
So not only does your algorithm need a bit work, you need to take implementation resources into account.
You don't program in VHDL you describe hardware.
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 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.