for generate with conditional logic - vhdl

I am implementing the following module:
library ieee;
use ieee.std_logic_1164.all;
entity Grant_Logic is
generic (
N : positive := 4
);
Port (
Priority_Logic0 : in std_logic_vector(N-1 downto 0);
Priority_Logic1 : in std_logic_vector(N-1 downto 0);
Priority_Logic2 : in std_logic_vector(N-1 downto 0);
Priority_Logic3 : in std_logic_vector(N-1 downto 0);
Gnt : out std_logic_vector (N-1 downto 0)
);
end Grant_Logic;
architecture Behavioral of Grant_Logic is
begin
gnt(0) <= Priority_Logic0(0) or Priority_Logic1(3) or Priority_Logic2(2) or Priority_Logic3(1);
gnt(1) <= Priority_Logic0(1) or Priority_Logic1(0) or Priority_Logic2(3) or Priority_Logic3(2);
gnt(2) <= Priority_Logic0(2) or Priority_Logic1(1) or Priority_Logic2(0) or Priority_Logic3(3);
gnt(3) <= Priority_Logic0(3) or Priority_Logic1(2) or Priority_Logic2(1) or Priority_Logic3(0);
end Behavioral;
I want to take advantage of for ... generate to implement the same circuit when N changes. I am using Xilinx so Vivado (vhdl'93) does not support custom types for ports in the IP generation.
However, for the architecture I would like to use for ... generate. The issue is that some logic is needed to generate each bit of gnt. What I have so far is:
gen_gnt_vertical: for y in 0 to N-1 generate
constant val, index : integer := 0;
begin
s_result <= '0';
gen_gnt_horizontal: for x in 0 to N-1 generate
begin
LOGIC BASED ON val, x and y to obtain the index
s_result <= s_result or s_Priority_Logic(x)(index);
end generate;
gnt(y) <= s_result;
end generate;
The logic to compute index is:
if(x>0)
{
val = y - x;
if (val < 0)
{
index = N + val;
}
else
index = val;
}
else
{
index = y;
}
I have a script that generates a vhdl file based on N but I would like to do it directly on vhdl. Is that possible?
Thanks for the help
EDIT: As #Tricky replied, a function did the trick. So, I have the following:
function index( N, x,y : natural) return natural is
variable val : integer;
variable index : integer := 0;
begin
if(x>0) then
val := y - x;
if(val < 0) then
index := N + val;
else
index := val;
end if;
else
index := y;
end if;
return index;
end function;
And the architecture:
architecture Behavioral of Grant_Logic is
signal s_Priority_Logic : t_Priority_logic;
signal s_result : std_logic_vector(N-1 downto 0) := (others=>'0');
begin
s_Priority_Logic(0) <= Priority_Logic0;
s_Priority_Logic(1) <= Priority_Logic1;
s_Priority_Logic(2) <= Priority_Logic2;
s_Priority_Logic(3) <= Priority_Logic3;
process(s_Priority_Logic)
variable result : std_logic;
begin
for y in 0 to N-1 loop
result := '0';
for x in 0 to N-1 loop
result := result or s_Priority_logic(x)(index(N, x, y));
end loop;
gnt_g(y) <= result;
end loop;
end process;
end Behavioral;

#Tricky using a function was the correct thing to get the index value. Alo for generate was not correct but for loop. I edited my question to show the final result

Related

Clock based 8 bit prime number detector

I am developing a 8 bit unsigned prime number detector in VHDL, synthesizable, for a project.The objective is to do not only avoiding to use any sort of loops or latches as well as restricting it to only the FPGA 50Mhz clock.
We tried a clock-based using successive divisions but such implementation does not meet the timing requirements in Quartus Timequest when we try to output the result.
When we comment the output it seems to work just fine, and we don't fully understand the why.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity primeChecker is
generic(NumCyclesWait :integer := 1000);
port( clock: in std_logic;
enable: in std_logic;
reset : in std_logic;
input : in std_logic_vector(7 downto 0);
output : out std_logic_vector(7 downto 0);
isPrime : out std_logic_vector(0 downto 0));
end primeChecker;
architecture arch of primeChecker is
signal count: integer := 0;
signal numToCheck : integer := 0;
signal prime, primeOut : integer := 1;
signal s_out: unsigned(7 downto 0);
signal div : integer := 2;
signal clockCount : unsigned(0 downto 0) := "0";
begin
numToCheck <= to_integer(unsigned(input));
process(clock)
begin
if(rising_edge(clock)) then
if(count = NumCyclesWait) then
if ((numToCheck = 1) OR (numToCheck = 0)) then
prime <= 0; --Not Prime
elsif(numToCheck > 2 and prime =1 and div < numToCheck) then
if (numToCheck rem div = 0) then
-- if the number is divisible
prime <= 0;
end if;
div <= div +1;
end if;
else
count <= count +1;
end if;
if(enable = '1') then
s_out <= to_unsigned(numToCheck,8);
count <= 0;
div <= 2;
primeOut <= prime;
prime <= 1;
else
s_out <= s_out;
end if;
end if;
end process;
isPrime <= std_logic_vector(to_unsigned(primeOut,1));
output <= std_logic_vector(s_out);
end arch ; -- arch
I expect for it not to trigger the "Timing requirement not met" error and for it to fully compile.
For fastest constant time response, I would take a different approach. Your task is to deal with eight bit numbers only and your FPGA probably has more than enough RAM to set up an 8-bit prime number lookup table where each table entry just indicates whether its index is a prime number or not:
type prime_numbers_type is array(0 to 255) of std_ulogic;
constant prime_numbers : prime_numbers_type :=
( '0', '0', '1', '1', '0', '1', ... );
This makes the vital part of your prime number detector overly simple:
is_prime <= prime_numbers(to_integer(unsigned(num_to_check)));
I would probably just write a small Tcl script to set up the lookup table.

Do I need increment pwm_count variable?

I'm learning VHDL language right now and I have some problems of understanding a part of the code in my course. I don't understand in process freq_counter this statement -> if(pwm_count < max_pwm_count), because we don't know the value of max_pwm_count and also I don't see any incrementation of variable pwm_count.
Thank you, guys!
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
entity PWM is
generic (
freq : integer := 50; --50Hz
INPUT_CLK : integer := 50000000; --50MHz
BITH_DEPTH : integer := 8
);
Port (
ENABLE : in std_logic;
CLK : in std_logic;
PWM_OUT : out std_logic;
DUTY_CYCLE : in std_logic_vector(BITH_DEPTH-1 downto 0)
);
end PWM;
architecture behavioral of PWM is
constant max_freq_count : integer:= INPUT_CLK/freq;
constant pwm_step : integer := max_freq_count/2**BITH_DEPTH;
signal PWM_value : std_logic := '0';
signal freq_count : integer range from 0 to max_freq_count := 0;
signal pwm_count : integer range from 0 to 2**BITH_DEPTH := 0;
signal max_pwm_count : integer range from 0 to 2**BITH_DEPTH := 0;
signal pwm_step_count : integer range from 0 to max_freq_count := 0;
begin
max_pwm_count <= TO_INTEGER(unsigned(DUTY_CYCLE));
PWM_OUT <= PWM_value;
freq_counter: process(CLK)
begin
if rising_edge(CLK) then
if(ENABLE='0') then
if(freq_count < max_freq_count) then
freq_count <= freq_count + 1;
if(pwm_count < max_pwm_count) then
PWM_value<='1';
if(pwm_step_count<pwm_step) then
pwm_step_count<=pwm_step_count+1;
else
pwm_step_count<=0;
pwm_count<=0;
end if;
else
pwm_value<='0';
end if;
else
freq_count <= 0;
pwm_count <= 0;
end if;
else
PWM_value <= '0';
end if;
end if;
end process freq_counter;
end PWM;
We DO know the value of max_pwm_count : it is initialised to 0 and never re-assigned. Therefore the IF can never be true and ... so on.
As far as incrementing PWM_Count is concerned, your understanding seems to be better than the author's, which puts you in a reasonable position for the necessary re-write.
I recommend first writing a testbench so you can observe its behaviour, and get it correct in simulation.

Assign 2d std_logic_vector with another 1d std_logic_vector in VHDL

I have this port
PORT (
A : IN STD_LOGIC_VECTOR(31 downto 0);
B : IN STD_LOGIC_VECTOR(31 downto 0);
C : IN STD_LOGIC_VECTOR(31 downto 0);
F : OUT STD_LOGIC_VECTOR(31 downto 0);
);
and this signal
SIGNAL data : std_logic_2d(31 downto 0, 2 downto 0);
I need to assign data(all,0) with A and data(all,1) with B and so on
like that
data(?,0) <= A;
data(?,1) <= B;
data(?,2) <= C;
what can I put instead of "?" in the code to perform it??
Solution 1 - process and for-loop:
A process is used to host a sequential for loop. You need to add all read signals to the sensitivity list: A, B, C.
process(A, B, C)
begin
for i in A'range loop
data(i, 0) <= A(i);
data(i, 1) <= B(i);
data(i, 2) <= C(i);
end loop;
end process;
Solution 2 - for-generate:
A generate loop is used to create lots of concurrent assignments.
gen: for i in A'range generate
data(i, 0) <= A(i);
data(i, 1) <= B(i);
data(i, 2) <= C(i);
end generate;
Solution 3 - a assignment procesdure:
A procedure is used to encapsulate the assignment to rows.
procedure assign_col(signal slm : out T_SLM; slv : std_logic_vector; constant ColIndex : natural) is
variable temp : std_logic_vector(slm'range(1));
begin
temp := slv;
for i in temp'range loop
slm(i, ColIndex) <= temp(i);
end loop;
end procedure;
Source: PoC.vectors.assign_col
Usage:
assign_col(data, A, 0);
assign_col(data, B, 1);
assign_col(data, C, 2);
The package PoC.vectors contains a lot of new types, functions and procedures to handle true std_logic based 2D arrays in VHDL.

Booth Multiplication Algorithm

I'm new to VHDL and am trying to code up Booth's Multiplication Algorithm. I'm using XILINX and when I synthesize my code, I end up with a lot of warnings:
Upper is assigned but never used,
Product is used but never assigned,
LowerPrevLSB is assigned but never used,
Lower is assigned but never used,
A_2sComp is assigned but never used,
Z has a constant value of 0,
Product has a constant value of 0.
I thought I assigned and wrote the code correctly, but evidently I am not. Any advice and help would be appreciated.
library IEEE;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_arith.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
-- X * Y = Z
entity BoothMultiplier is
generic
(
numBits_X : integer := 8;
numBits_Y : integer := 8
);
port
(
CLK : in std_logic;
X : in std_logic_vector((numBits_X - 1) downto 0);
Y : in std_logic_vector((numBits_Y - 1) downto 0);
Z : out std_logic_vector((numBits_X + numBits_Y - 1) downto 0)
);
end BoothMultiplier;
architecture Behavioral of BoothMultiplier is
-- Two's Complement Function
function TwosComplement(inputNum : std_logic_vector) return std_logic_vector;
function TwosComplement(inputNum : std_logic_vector) return std_logic_vector is
variable temp : std_logic_vector(inputNum'range);
begin
temp := (not inputNum) + 1;
return temp;
end TwosComplement;
-- End Two's Complement Function
-- MIN Function
function MIN(Left, Right : integer) return integer;
function MIN(Left, Right : integer) return integer is
begin
if Left < Right then return Left;
else return Right;
end if;
end Min;
-- End MIN Function
-- MAX Function
function MAX(Left, Right : integer) return integer;
function MAX(Left, Right : integer) return integer is
begin
if Left > Right then return Left;
else return Right;
end if;
end MAX;
-- End MAX Function
-- Signals
signal Upper : std_logic_vector(MAX(numBits_X, numBits_Y) - 1 downto 0)
:= (others => '0');
signal Lower : std_logic_vector(MIN(numBits_X, numBits_Y) - 1 downto 0)
:= (others => '0');
signal LowerPrevLSB : std_logic := '0';
signal Product : std_logic_vector(numBits_X + numBits_Y - 1 downto 0)
:= (others => '0');
signal A, A_2sComp : std_logic_vector(MAX(numBits_X, numBits_y) - 1 downto 0)
:= (others => '0');
signal counter : integer := 0;
-- End Signals
begin
assert Z'length = (X'length + Y'length) report "Bad Product Length" severity failure;
Lower <= X when (numBits_X <= numBits_Y) else Y;
A <= X when (numBits_X > numBits_Y) else Y;
A_2sComp <= TwosComplement(A);
process(CLK)
begin
if rising_edge(CLK) then
if (Lower(0) = '0' and LowerPrevLSB = '1') then
Upper <= Upper + A;
elsif (Lower(0) = '1' and LowerPrevLSB = '0') then
Upper <= Upper + A_2sComp;
end if;
LowerPrevLSB <= Lower(0);
Product <= Upper & Lower;
for i in 0 to Product'length - 2 loop
Product(i) <= Product(i+1);
end loop;
Product(Product'length-1) <= Product(Product'length-1);
Upper <= Product(Product'length - 1 downto MIN(numBits_X, numBits_Y));
Lower <= Product(MIN(numBits_X, numBits_Y) - 1 downto 0);
counter <= counter + 1;
if (counter = MIN(numBits_X, numBits_Y)) then
Z <= Product;
end if;
end if;
end process;
end Behavioral;
In VHDL, successive assignments to the same signal in a process overrides previous assignments, thus:
if (Lower(0) = '0' and LowerPrevLSB = '1') then
Upper <= Upper + A;
elsif (Lower(0) = '1' and LowerPrevLSB = '0') then
Upper <= Upper + A_2sComp;
end if;
...
Upper <= Product(Product'length - 1 downto MIN(numBits_X, numBits_Y));
The first assignments, in the if block, is completely ignored. If you look at your code, assignments to Product, Upper and Lower are overridden.
I suggest you simulate your design before synthesizing your design with Xilinx. It will be much easier to test and debug. For instance, your counter signal is never reset, and will count up to 2^31-1, then wrap to -2^31. What will happen to your design in those cases? Simulation would point out these error easily, leave synthesis for later!

Implementing an OR gate with for-generate

I have implemented an OR gate with generic parameters, but I am currently having some issues implementing it with a for-generate.
entity OR_gate is
generic( n : natural := 2);
port(x : in std_logic_vector(1 to n);
z : out std_logic);
end OR_gate;
architecture Behavioral of OR_gate is
begin
process(x)
variable temp : std_logic;
begin
temp := '0';
G1: for i in 1 to N loop
temp := temp or x(i);
end generate G1;
z <= temp;
end process;
end Behavioral;
I have the G1 parameter which indicates a loop, however as far as that goes, I am lost.
It is not a generate (concurrent) loop when made inside a process. In this case it is just a regular loop, with syntax without the generate, thus as:
process(x)
variable temp : std_logic;
begin
temp := '0';
G1 : for i in 1 to N loop
temp := temp or x(i);
end loop G1;
z <= temp;
end process;
An alternative to the process, is to create a function, and then make a concurrent function call in order to generate z, like:
architecture Behavioral of OR_gate is
function or_reduct(slv : in std_logic_vector) return std_logic is
variable res_v : std_logic;
begin
res_v := '0';
for i in slv'range loop
res_v := res_v or slv(i);
end loop;
return res_v;
end function;
begin
z <= or_reduct(x);
end Behavioral;
Finally, if the tools support the logical reduction operators defined VHDL-2008, then you can simplify it all to:
z <= or x;

Resources