I want an approximation of the Tanh function by saving the values in a LUT (by this I am doing a quantization). I want to choose the Number of entries in the LUT.
As an not-correct example, I imagine a code like
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use ieee.fixed_pkg.all;
entity tanh_lut is
generic (
MIN_RANGE: real := 0.0; -- Minimum value of x
MAX_RANGE: real := 5.0; -- Maximum value of x
DATA_RANGE_int: positive:= 8;
DATA_RANGE_frac: positive:= 8;
);
Port ( DIN : in sfixed(DATA_RANGE_int-1 downto -(DATA_RANGE_frac-1));
DOUT : out sfixed(DATA_RANGE_int-1 downto -(DATA_RANGE_frac-1))
end tanh_lut;
architecture Behavioral of tanh_lut is
begin
lut_gen: for i in 0 to LUT_SIZE-1 generate
constant x_val : real := MIN_RANGE + (MAX_RANGE - MIN_RANGE) * i / (LUT_SIZE-1);
constant x_val_next : real := MIN_RANGE + (MAX_RANGE - MIN_RANGE) * (i+1) / (LUT_SIZE-1);
constant y_val : real := tanh(x_val);
if DIN>=x_val_previous AND DIN<x_val then
DOUT <= to_sfixed(tanh(y_val),DOUT ) ;
END IF
end generate;
end Behavioral;
Per example, if I want 4 entries in the range 0 to 3, I want that it is synthesizing a code like:
if DIN>0 AND DIN<=1 then
DOUT <= to_sfixed(0, DOUT);
else DIN>1 AND DIN<=2 then
DOUT <= to_sfixed(0.76159415595, DOUT);
else DIN>2 AND DIN<=3 then
DOUT <= to_sfixed(0.96402758007, DOUT);
else DIN>3 AND DIN<=4 then
DOUT <= to_sfixed(0.99505475368, DOUT);
End if
Is there any way that a code like this or a code which implements the idea behind this is possible?
A simple LUT with addresses is not possible because the addresses are always integer and DIN is fixed point, e.g., 1.5
The other possibility would be two LUTs, one for mapping the Input to an address, another for mapping the address to the LUT entry, e.g., LUT1: 1.5=> address 5, LUT2: address 5 => 0.90. But by this I would double the amount of resources what I dont want
My requirements: things like the tanh(x) should not be synthesized, only the final value of tanh(x). It shoudl also be hardware efficient
It does not matter if you use a nested „if-elsif“ construct or if you use a new „if“ construct for each check.
So you can create a loop like this:
for i in 0 to c_number_of_checks-1 loop
if c_boundaries(i)<DIN and DIN<=c_boundaries(i+1) then
DOUT <= c_output_values(i);
end if;
end loop;
Of course you must provide the constants c_number_of_checks and c_boundaries, c_output_values. This can be done by:
constant c_number_of_checks : natural := 4;
type array_of_your_data_type is array (natural range <>) of your_data_type;
constant c_boundaries : array_of_your_data_type(c_number_of_checks downto 0) := init_c_boundaries(c_number_of_checks);
constant c_output_values : array_of_your_data_type(c_number_of_checks-1 downto 0) := init_c_output_values(c_number_of_checks);
This means you will need the functions init_c_boundaries, init_c_output_values, which create arrays of values, which can initialize the constant c_boundaries and c_output_values.
But this is not complicated (you can use from ieee.math_real the function TANH), as the functions need not to be synthesizable, as they are called only during compile time.
As you see, you will have some effort. So perhaps it is easier to follow the other suggestions. If you do so (value as address of a LUT) you should think about automatic ROM inference, which is provided by several tool chains and will give you a very efficient (small) hardware.
I'm currently working on writing a simple counter in VHDL, trying to genericize it as much as possible. Ideally I end up with a counter that can pause, count up/down, and take just two integer (min, max) values to determine the appropriate bus widths.
As far as I can tell, in order to get an integer of a given range, I just need to delcare
VARIABLE cnt: INTEGER RANGE min TO max := 0
Where min and max are defined as generics (both integers) in the entity. My understanding of this is that if min is 0, max is 5, for example, it will create an integer variable of 3 bits.
My problem is that I actually want to output this integer. So, naturally, I write
counterOut : OUT INTEGER RANGE min TO max
But this does not appear to be doing what I need. I'm generating a schematic block in Quartus Prime from this, and it creates a bus output from [min...max]. For example, if min = 0, max = 65, it outputs a 66 bit bus. Instead of the seven bit bus it should.
If I restricted the counter to unsigned values I might be able to just math out the output bus size, but I'd like to keep this as flexible as possible, and of course I'd like to know what I'm actually doing wrong and how to do it properly.
TL;DR: I want a VHDL entity to take generic min,max values, and generate an integer output bus of the required width to hold the range of values. How do?
If it matters, I'm using Quartus Prime Lite Edition V20.1.0 at the moment.
Note: I know I can use STD_LOGIC_VECTOR instead, but it is going to simulate significantly slower and is less easy to use than the integer type as far as I have read. I can provide more of my code if necessary, but it's really this one line that's the problem as far as I can tell.
I originally posted this on Stackexchange, but I think Stackoverflow might be a better place since it's more of a programming than a hardware problem.
EDIT: Complete code shown below
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
USE ieee.std_logic_signed.all;
ENTITY Counter IS
GENERIC (modulo : INTEGER := 32;
min : INTEGER := 0;
max : INTEGER := 64);
PORT( pause : IN STD_LOGIC;
direction : IN STD_LOGIC; -- 1 is up, 0 is down
clk : IN STD_LOGIC;
counterOut : OUT INTEGER RANGE min TO max --RANGE 0 TO 32 -- THIS line is the one generating an incorrect output bus width
);
END ENTITY Counter;
-- or entity
ARCHITECTURE CounterArch OF Counter IS
BEGIN
PROCESS(direction, pause, clk)
VARIABLE cnt : INTEGER RANGE min TO max := 0;
VARIABLE dir : INTEGER;
BEGIN
IF direction = '1' THEN
dir := 1;
ELSE
dir := -1;
END IF;
IF clk'EVENT AND clk = '1' THEN
IF pause = '0'THEN
IF (cnt = modulo AND direction = '1') THEN
cnt := min; -- If we're counting up and hit modulo, reset to min value.
ELSIF (cnt = min AND direction = '0') THEN
cnt := modulo; --Counting down hit 0, go back to modulo.
ELSE
cnt := cnt + dir;
END IF;
END IF;
END IF;
counterOut <= cnt;
END PROCESS;
END ARCHITECTURE CounterArch;
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.
I would like to compute a random value with a multimodal distribution composed of N normal distributions.
I have an array with N elements of normal distribution parameters (std deviation, mean).
My language (VHDL) and my library allow me to calculate the following basic distributions:
- uniform distribution [-1.0; 1.0]
- normal distribution (Box Muller transformation)
- Poisson distribution
How can I calculate random values so that the histogram looks like N overlapping normal distributions?
Types and helpers:
type T_NORMAL_DIST_PARAM is record
StdDev : REAL;
Mean : REAL;
end record;
type T_JITTER_DIST is array(NATURAL range <>) of T_NORMAL_DIST_PARAM;
constant JitterDistribution : T_JITTER_DIST := (
0 => (0.2, -0.4),
1 => (0.2, 0.4)
);
The problems core:
procedure getMultiModalDistributedRandomNumber(Seed : T_SIM_SEED; Value : REAL; JitterDistribution : T_JITTER_DIST) is
variable rand : REAL;
variable Result : REAL;
begin
-- ...
for i in JitterDistribution'range loop
getNormalDistributedRandomValue(Seed, rand, JitterDistribution(i).StdDev, JitterDistribution(i).Mean);
-- how to accumulate rand?
end loop;
Value := Result;
end procedure;
It's used in:
procedure genClock(signal Clock : out STD_LOGIC; Period : TIME) is
constant TimeHigh : TIME := Period / 2;
constant TimeLow : TIME := Period - TimeHigh;
variable rand : REAL;
begin
initializeSeed(Seed);
while (not isStopped) loop
getMultiModalDistributedRandomNumber(Seed, rand, JitterDistribution);
Clock <= '1';
wait for TimeHigh + (Period * rand);
Clock <= '0';
wait for TimeLow;
end loop;
end procedure;
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.