I'm building an MP3 decoder using VHDL and I want to make it synthesizable knowing that for loops of variable size and selecting a variable size from a variable position in std_logic_vector is also not synthesizable
so how do I get a loop to be synthesizable and how to make selecting a variable size from a std_logic_vector synthesizable
for j in 0 to switch_point_1-1 loop
bits:= data(ptr+current+scale_lengths(j)-1 downto ptr+current);
scalefac(j)(0) := to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
scalefac(j)(1) := to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
scalefac(j)(2) := to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
current := current+ scale_lengths(j);
end loop;
And another one
for j in switch_point_s-1 to cb_max loop
for k in 0 to 2 loop
-- window
bits:=data(ptr+current+scale_lengths(j)-1 downto ptr+current);
scalefac(j)(k) := to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
current := current+ scale_lengths(j);
end loop;
end loop;
This is one of the loops I have and there is a select in itbits:=data(ptr+current+scale_lengths(j)-1 downto ptr+current); is also not synthesizable how can I make them synthesizable ?
Full code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use ieee.numeric_std.all;
use std.textio.all;
use work.txt_util.all;
--use txt_util.all;
entity extract_main is
port(
data:in std_logic_vector(4095 downto 0);
en: in std_logic;
gr,clk:in std_logic;
enabled:in std_logic;
scsfi:in std_logic_vector(20 downto 0);
ptr: in integer;
windows_switching: in std_logic;
block_type: in std_logic_vector(1 downto 0);
mixed_block_flag: in std_logic;
part2_3_length: in std_logic_vector(11 downto 0);
slen1,slen2: in integer;
saved_scalefac_in: in integer;
saved_scalefac_out: out integer;
ptr_out: out integer;
enablenext:out std_logic
);
end extract_main;
architecture a of extract_main is
type intarr is array(20 downto 0) of integer;
type scalef is array(20 downto 0) of intarr;
begin
process(clk)
variable scalefac : scalef;
variable scale_lengths : intarr;
variable mainInfoBegin,mainInfoSize : integer;
variable blockType : integer;
variable part2_length :integer;
variable switch_point_1: integer;
variable switch_point_s: integer;
variable cb_max : integer;
variable current: integer:=0; -- iterator on data
variable it: integer;
variable bits: std_logic_vector(3 downto 0):="0000";
variable ptrout: integer;
begin
if enabled ='1' then
--size of main data
if falling_edge(clk) then
if en = '1' then
mainInfoSize := to_integer(UNSIGNED(part2_3_length));
if windows_switching = '0' then
blockType := 0;
else
blockType := to_integer(UNSIGNED(block_type));
end if;
if blockType = 2 and mixed_block_flag = '1' then
part2_length := 17 * slen1 + 18 * slen2;
scale_lengths(16) :=slen2;
scale_lengths(15) :=slen2;
scale_lengths(14) :=slen2;
scale_lengths(13) :=slen2;
scale_lengths(12) :=slen2;
scale_lengths(11) :=slen2;
scale_lengths(10) :=slen1;
scale_lengths(9) :=slen1;
scale_lengths(8) :=slen1;
scale_lengths(7) :=slen1;
scale_lengths(6) :=slen1;
scale_lengths(5) :=slen1;
scale_lengths(4) :=slen1;
scale_lengths(3) :=slen1;
scale_lengths(2) :=slen1;
scale_lengths(1) :=slen1;
scale_lengths(0) :=slen1;
cb_max := 16;
switch_point_1 := 8;
switch_point_s := 9;
elsif blockType = 2 and mixed_block_flag = '0' then
part2_length := 18 * slen1 + 18 * slen2;
scale_lengths(11) :=slen2;
scale_lengths(10) :=slen2;
scale_lengths(9) :=slen2;
scale_lengths(8) :=slen2;
scale_lengths(7) :=slen2;
scale_lengths(6) :=slen2;
scale_lengths(5) :=slen1;
scale_lengths(4) :=slen1;
scale_lengths(3) :=slen1;
scale_lengths(2) :=slen1;
scale_lengths(1) :=slen1;
scale_lengths(0) :=slen1;
switch_point_1 := 0;
switch_point_s := 1;
cb_max := 11;
else
part2_length := 11 * slen1 + 10 * slen2;
--scalefactor_bands(20 downto 11) <= slen2;
--scalefactor_bands(10 downto 0)<= slen1;
scale_lengths(20) :=slen2;
scale_lengths(19) :=slen2;
scale_lengths(18) :=slen2;
scale_lengths(17) :=slen2;
scale_lengths(16) :=slen2;
scale_lengths(15) :=slen2;
scale_lengths(14) :=slen2;
scale_lengths(13) :=slen2;
scale_lengths(12) :=slen2;
scale_lengths(11) :=slen2;
scale_lengths(10) :=slen1;
scale_lengths(9) :=slen1;
scale_lengths(8) :=slen1;
scale_lengths(7) :=slen1;
scale_lengths(6) :=slen1;
scale_lengths(5) :=slen1;
scale_lengths(4) :=slen1;
scale_lengths(3) :=slen1;
scale_lengths(2) :=slen1;
scale_lengths(1) :=slen1;
scale_lengths(0) :=slen1;
cb_max := 20;
end if;
if blockType = 2 and windows_switching = '1' then
for j in 0 to switch_point_1-1 loop
-- it:=0;
--for e in ptr+current to ptr+current+scale_lengths(j)-1 loop
-- bits(it) := ram(e)(0);
--it := it+1;
--end loop;
bits:= data(ptr+current+scale_lengths(j)-1 downto ptr+current);
scalefac(j)(0) := to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
scalefac(j)(1) := to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
scalefac(j)(2) := to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
current := current+ scale_lengths(j);
end loop;
for j in switch_point_s-1 to cb_max loop
for k in 0 to 2 loop
-- window
-- it:=0;
-- for e in ptr+current to ptr+current+scale_lengths(j)-1 loop
-- bits(it) := ram(e)(0);
-- it := it+1;
--end loop;
bits:=data(ptr+current+scale_lengths(j)-1 downto ptr+current);
scalefac(j)(k) := to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
current := current+ scale_lengths(j);
end loop;
end loop;
else
for j in 0 to 20 loop
if gr ='0' or scsfi(j) ='0' then
-- it:=0;
-- for e in ptr+current to ptr+current+scale_lengths(j)-1 loop
-- bits(it) := ram(e)(0);
-- it := it+1;
--end loop;
bits:=data(ptr+current+scale_lengths(j)-1 downto ptr+current);
scalefac(j)(0):= to_integer(UNSIGNED(bits(scale_lengths(j)-1 downto 0)));
current := current+ scale_lengths(j);
else
scalefac(j)(0):= saved_scalefac_in;
end if;
end loop;
if gr ='1' then
if scsfi(0) /= '0' or scsfi(6) /='0' or scsfi(11)/='0' or scsfi(16)/='0' then
saved_scalefac_out<=scalefac(0)(0);
end if;
end if;
end if;
ptrout:=ptr+current;
ptr_out<=ptrout;
enablenext<='1';
end if;
end if;
else enablenext<='0';
end if;
end process;
end;
With the necessary parts of the code, we can start to help.
It is now clear that there ARE upper bounds on the ranges of the loops, though the full code goes out of its way to hide them. However, the loop ranges must be bound by the fact that the loop variable is used to address a fixed size array.
First : is there a good reason to address your integer arrays in reverse? I am tentatively going to assume not, and simplify things a bit. Second, I am going to assume the length of intarr and scalef are dependent; again this may not be true but if it is, things get simpler.
And now I write the key declarations as:
subtype index is natural range 0 to 20;
type intarr is array(index) of integer;
type scalef is array(index) of intarr;
then
process(clk)
variable scalefac : scalef;
variable scale_lengths : intarr;
variable switch_point_1: index;
variable switch_point_s: index;
at which point the bounds on these variables is obvious...
if blockType = 2 and mixed_block_flag = '1' then
scale_lengths(11 to 16) := (others => slen2);
scale_lengths(0 to 10) := (others => slen1);
or scale_lengths(0 to 10) := (0 to 10 => slen1);
or scale_lengths := (0 to 10 => slen1, 11 to 16 => slen2, others => default_value);
depending what you want to do with the uninitialised entries.
Not because it's synthesisable but because it saves a lot of code...
And we can now work on those loops:
Make their bounds "locally static" i.e. constant and determinable from this unit alone.
And since we have a convenient and correct definition of the bounds,
for j in 0 to switch_point_1-1 loop
...
end loop;
now becomes
for j in index'range loop
if j <= switch_point_1-1 then
...
end if;
end loop;
which is potentially synthesisable, depending on the loop body actions.
Related
I have a design I've implemented using vhdl that is triggered based on a clock that sends an input signal to one of 8 output channels based on the sel input and also another 2 bit input. The elaborated design shows a lot of nesting due to the many if-else statements. So, I'm curious as to if there's a way to alleviate the nesting using case statements or some other method. I'm unfamiliar with doing this using case statements because I have two inputs that determine the output channel. The code that I currently have is displayed below.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--Inputs and outputs to entity
entity DSA_Worker is
Port ( DB_Select : in STD_LOGIC;
Atten : in STD_LOGIC_VECTOR ( 7 downto 0);
enable : in STD_LOGIC;
clk: in STD_LOGIC;
reset: in STD_LOGIC;
chip_select : in STD_LOGIC_VECTOR (1 downto 0);
DBA_TX1_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBA_TX2_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBA_RX1_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBA_RX2_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBB_TX1_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBB_TX2_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBB_RX1_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBB_RX2_DSA : out STD_LOGIC_VECTOR (7 downto 0));
end DSA_Worker;
architecture Behavioral of DSA_Worker is
begin
process(clk)
begin
if rising_edge(clk) then
--if reset is high, all outputs go to 0
if reset = '1'then
DBA_TX1_DSA <= (others =>'0');
DBA_TX2_DSA <= (others =>'0');
DBA_RX1_DSA <= (others =>'0');
DBA_RX2_DSA <= (others =>'0');
DBB_TX1_DSA <= (others =>'0');
DBB_TX2_DSA <= (others =>'0');
DBB_RX1_DSA <= (others =>'0');
DBB_RX2_DSA <= (others =>'0');
-- attenuation values sent to channels based on DB_select value(0/1) and chip select value
--DB_select - 0 is for DB-A and 1 for DB- B and chip_select determines the channel
elsif enable = '1'then
if(DB_Select='0' and chip_select = "00") then -- attenuation value sent to first channel
DBA_TX1_DSA(0) <= Atten(0);
DBA_TX1_DSA(1) <= Atten(1);
DBA_TX1_DSA(2) <= Atten(2);
DBA_TX1_DSA(3) <= Atten(3);
DBA_TX1_DSA(4) <= Atten(4);
DBA_TX1_DSA(5) <= Atten(5);
elsif (DB_Select='0' and chip_select = "01") then
DBA_TX2_DSA(0) <= Atten(0);
DBA_TX2_DSA(1) <= Atten(1);
DBA_TX2_DSA(2) <= Atten(2);
DBA_TX2_DSA(3) <= Atten(3);
DBA_TX2_DSA(4) <= Atten(4);
DBA_TX2_DSA(5) <= Atten(5);
elsif (DB_Select='0' and chip_select = "10") then
DBA_RX1_DSA(0) <= Atten(0);
DBA_RX1_DSA(1) <= Atten(1);
DBA_RX1_DSA(2) <= Atten(2);
DBA_RX1_DSA(3) <= Atten(3);
DBA_RX1_DSA(4) <= Atten(4);
DBA_RX1_DSA(5) <= Atten(5);
elsif (DB_Select='0' and chip_select = "11") then
DBA_RX2_DSA(0) <= Atten(0);
DBA_RX2_DSA(1) <= Atten(1);
DBA_RX2_DSA(2) <= Atten(2);
DBA_RX2_DSA(3) <= Atten(3);
DBA_RX2_DSA(4) <= Atten(4);
DBA_RX2_DSA(5) <= Atten(5);
-- Attenuation values being set for DB-B
elsif (DB_Select='1' and chip_select = "00") then
DBB_TX1_DSA(0) <= Atten(0);
DBB_TX1_DSA(1) <= Atten(1);
DBB_TX1_DSA(2) <= Atten(2);
DBB_TX1_DSA(3) <= Atten(3);
DBB_TX1_DSA(4) <= Atten(4);
DBB_TX1_DSA(5) <= Atten(5);
elsif (DB_Select='1' and chip_select = "01") then
DBB_TX2_DSA(0) <= Atten(0);
DBB_TX2_DSA(1) <= Atten(1);
DBB_TX2_DSA(2) <= Atten(2);
DBB_TX2_DSA(3) <= Atten(3);
DBB_TX2_DSA(4) <= Atten(4);
DBB_TX2_DSA(5) <= Atten(5);
elsif (DB_Select='1' and chip_select = "10") then
DBB_RX1_DSA(0) <= Atten(0);
DBB_RX1_DSA(1) <= Atten(1);
DBB_RX1_DSA(2) <= Atten(2);
DBB_RX1_DSA(3) <= Atten(3);
DBB_RX1_DSA(4) <= Atten(4);
DBB_RX1_DSA(5) <= Atten(5);
else
DBB_RX2_DSA(0) <= Atten(0);
DBB_RX2_DSA(1) <= Atten(1);
DBB_RX2_DSA(2) <= Atten(2);
DBB_RX2_DSA(3) <= Atten(3);
DBB_RX2_DSA(4) <= Atten(4);
DBB_RX2_DSA(5) <= Atten(5);
end if;
end if;
end if;
end process;
end Behavioral;
I did try to produce a simplified design using case statements as illustrated below
library IEEE;
use IEEE.STD_LOGIC_1164.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 leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity dsa_case is
Port (
DB_Select : in STD_LOGIC;
Atten : in STD_LOGIC_VECTOR ( 7 downto 0);
enable : in STD_LOGIC;
clk: in STD_LOGIC;
reset: in STD_LOGIC;
chip_select : in STD_LOGIC_VECTOR (1 downto 0);
DBA_TX1_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBA_TX2_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBA_RX1_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBA_RX2_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBB_TX1_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBB_TX2_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBB_RX1_DSA : out STD_LOGIC_VECTOR (7 downto 0);
DBB_RX2_DSA : out STD_LOGIC_VECTOR (7 downto 0));
end dsa_case;
architecture Behavioral of dsa_case is
begin
process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
DBA_TX1_DSA <= (others =>'0');
DBA_TX2_DSA <= (others =>'0');
DBA_RX1_DSA <= (others =>'0');
DBA_RX2_DSA <= (others =>'0');
DBB_TX1_DSA <= (others =>'0');
DBB_TX2_DSA <= (others =>'0');
DBB_RX1_DSA <= (others =>'0');
DBB_RX2_DSA <= (others =>'0');
elsif enable = '1'then
-- DB_Select <='0';
case chip_select is
when "00"=> -- attenuation value sent to first channel
DBA_TX1_DSA(0) <= Atten(0);
DBA_TX1_DSA(1) <= Atten(1);
DBA_TX1_DSA(2) <= Atten(2);
DBA_TX1_DSA(3) <= Atten(3);
DBA_TX1_DSA(4) <= Atten(4);
DBA_TX1_DSA(5) <= Atten(5);
when "01"=>
DBA_TX2_DSA(0) <= Atten(0);
DBA_TX2_DSA(1) <= Atten(1);
DBA_TX2_DSA(2) <= Atten(2);
DBA_TX2_DSA(3) <= Atten(3);
DBA_TX2_DSA(4) <= Atten(4);
DBA_TX2_DSA(5) <= Atten(5);
when "10"=>
DBA_RX1_DSA(0) <= Atten(0);
DBA_RX1_DSA(1) <= Atten(1);
DBA_RX1_DSA(2) <= Atten(2);
DBA_RX1_DSA(3) <= Atten(3);
DBA_RX1_DSA(4) <= Atten(4);
DBA_RX1_DSA(5) <= Atten(5);
when "11"=>
DBA_RX2_DSA(0) <= Atten(0);
DBA_RX2_DSA(1) <= Atten(1);
DBA_RX2_DSA(2) <= Atten(2);
DBA_RX2_DSA(3) <= Atten(3);
DBA_RX2_DSA(4) <= Atten(4);
DBA_RX2_DSA(5) <= Atten(5);
-- Attenuation values being set for DB-B
-- DB_Select <= '1';
when "00"=>
DBB_TX1_DSA(0) <= Atten(0);
DBB_TX1_DSA(1) <= Atten(1);
DBB_TX1_DSA(2) <= Atten(2);
DBB_TX1_DSA(3) <= Atten(3);
DBB_TX1_DSA(4) <= Atten(4);
DBB_TX1_DSA(5) <= Atten(5);
-- DB_Select <= '1';
when "01" =>
DBB_TX2_DSA(0) <= Atten(0);
DBB_TX2_DSA(1) <= Atten(1);
DBB_TX2_DSA(2) <= Atten(2);
DBB_TX2_DSA(3) <= Atten(3);
DBB_TX2_DSA(4) <= Atten(4);
DBB_TX2_DSA(5) <= Atten(5);
-- DB_Select <= '1';
when "10"=>
DBB_RX1_DSA(0) <= Atten(0);
DBB_RX1_DSA(1) <= Atten(1);
DBB_RX1_DSA(2) <= Atten(2);
DBB_RX1_DSA(3) <= Atten(3);
DBB_RX1_DSA(4) <= Atten(4);
DBB_RX1_DSA(5) <= Atten(5);
when others=>
DBB_RX2_DSA(0) <= Atten(0);
DBB_RX2_DSA(1) <= Atten(1);
DBB_RX2_DSA(2) <= Atten(2);
DBB_RX2_DSA(3) <= Atten(3);
DBB_RX2_DSA(4) <= Atten(4);
DBB_RX2_DSA(5) <= Atten(5);
end case;
end if;
end if;
end process;
end Behavioral;
However, it did fail to produce an elaborated design due to 5 errors, all like this
[Synth 8-517] overlapping choice 2'b00 in case statement ["/home/n310-osp/case_statement_design/case_statement_design.srcs/sources_1/new/dsa_case.vhd":108]
Personally I don't mind your if-else structure. I think you mostly have a readability issue, with a lot of redundancy (in this case the check on DB_Select inside each case) and inconsistent indentation.
This is how I'd improve the code inside the process:
process(clk)
begin
if rising_edge(clk) then
--if reset is high, all outputs go to 0
if reset = '1' then
DBA_TX1_DSA <= (others=>'0');
DBA_TX2_DSA <= (others=>'0');
DBA_RX1_DSA <= (others=>'0');
DBA_RX2_DSA <= (others=>'0');
DBB_TX1_DSA <= (others=>'0');
DBB_TX2_DSA <= (others=>'0');
DBB_RX1_DSA <= (others=>'0');
DBB_RX2_DSA <= (others=>'0');
-- attenuation values sent to channels based on DB_select value(0/1) and chip select value
-- DB_select - 0 is for DB-A and 1 for DB- B and chip_select determines the channel
elsif enable = '1'then
if DB_Select = '0' then
if chip_select = "00" then -- attenuation value sent to first channel
DBA_TX1_DSA(5 downto 0) <= Atten(5 downto 0);
elsif chip_select = "01" then
DBA_TX2_DSA(5 downto 0) <= Atten(5 downto 0);
elsif chip_select = "10" then
DBA_RX1_DSA(5 downto 0) <= Atten(5 downto 0);
else
DBA_RX2_DSA(5 downto 0) <= Atten(5 downto 0);
end if;
else -- Attenuation values being set for DB-B
if chip_select = "00" then
DBB_TX1_DSA(5 downto 0) <= Atten(5 downto 0);
elsif chip_select = "01" then
DBB_TX2_DSA(5 downto 0) <= Atten(5 downto 0);
elsif chip_select = "10" then
DBB_RX1_DSA(5 downto 0) <= Atten(5 downto 0);
else
DBB_RX2_DSA(5 downto 0) <= Atten(5 downto 0);
end if;
end if;
end if;
end if;
end process;
end Behavioral;
You could replace the if-else structure with when-else, but that's just a matter of preference.
The function of the code is given an opcode, it will perform a task at the rising edge of the clock. I'm a second year undergrad student, so any help/input will be appreciated
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ALU is Port (
X,Y :IN BIT_VECTOR(2 downto 0);
OPcode :IN BIT_VECTOR(2 downto 0);
Z :OUT BIT_VECTOR(5 downto 0);
CLK :IN BIT;
TempValX:INOUT BIT_VECTOR(5 downto 0));
end ALU;
architecture Circuit of ALU is signal g: BIT_VECTOR(3 downto 0);
signal C: BIT_VECTOR(3 downto 0);
signal p, u, r : bit_vector(2 downto 0);
signal s: Bit_vector(5 downto 0);
Component ThreeBitFA is
PORT (X,Y :IN BIT_VECTOR(2 downto 0);
C :INOUT BIT_VECTOR(3 downto 0));
end component; begin adder:ThreeBitFA port map(
X => X,
Y => Y,
C => C);
Process(X,Y,CLK,OPcode)
begin
IF OPcode = "000" THEN ----------------ADD OPcode
IF (CLK'EVENT AND CLK = '1') THEN
tempvalx <= "00" & C;
Z <= tempvalx;
end if;
ELSIF OPcode = "001" THEN ----------------MULT OPcode
IF (CLK'EVENT AND CLK = '1') THEN
IF Y(0) = '1' THEN P <= X; ELSE P <= "000"; END IF;
IF Y(1) = '1' THEN u <= X; ELSE u <= "000"; END IF;
IF Y(2) = '1' THEN R <= X; ELSE R <= "000"; END IF;
z(0) <= P(0);
z(1) <= P(1) XOR u(0); s(0) <= P(1) AND u(0);
z(2) <= P(2) XOR u(1) XOR R(0) XOR s(0); s(1) <= s(0) AND P(2); s(2) <= u(1) AND R(0);
z(3) <= u(2) XOR R(1) XOR s(1) XOR s(2); s(3) <= s(2) AND s(1); s(4) <= u(2) AND R(1);
z(4) <= R(2) XOR s(3) XOR s(4); s(5) <= s(3) AND s(4);
z(5) <= s(5);
end if;
ELSIF (OPcode = "010") THEN ------------AND OPcode
IF (CLK'EVENT AND CLK = '1') THEN
Z <= "000" & (X AND Y);
end IF;
ELSIF (OPcode = "011") THEN ------------OR Opcode
IF (CLK'EVENT AND CLK = '1') THEN
Z <= "000" & (X OR Y);
end IF;
ELSIF (OPcode = "100") THEN ------------XOR Opcode
IF (CLK'EVENT AND CLK = '1') THEN
Z <= "000" & (X XOR Y);
end IF;
ELSIF (OPcode = "101") THEN ------------NOT Opcode
IF (CLK'EVENT AND CLK = '1') THEN
Z <= "000" & (NOT X);
end IF;
ELSIF (OPcode = "110") THEN -----------Rshift OPcode
IF (CLK'EVENT AND CLK = '1') THEN
TempValX <= "000" & X;
Z <= '0' & TempValX(5 downto 1);
ELSIF (OPcode = "111") THEN -----------Lshift OPcode
IF (CLK'EVENT AND CLK = '1') THEN
TempValX <= "000" & X;
Z <= TempValX(4 downto 0) & '0';
end IF;
ELSE
Null;
END IF;
END IF; END Process; end Circuit;
Couple of things stand out.
If you only need to "perform a task at the rising edge of the clock", you only need 'CLK' in your process sensitivity list.
The order of precedence in your if-else inside the process is wrong. All of the opcode decoding logic should be inside the check for rising edge clock.
I am trying to develop an autonomous car. I have a sensor that counts the number of laps of our car's wheels. When the number of laps reaches a specific input number it should change states, but the if statement doesn't seem to be working. Instead of comparing the two numbers, it enters the else statement until the input vueltas is all '1'. If I change the code, and write if (vueltas < 15) it works. But I need the number to be changeable. This is the code, I want the program to stay in the same state until the number of lapsis this imput number. I have already proved that the input number is correct and is 15. The elsif(obst = '1') is in case the car detects an obstacle, but it doesn't matter with this problem.
Note: vueltas = laps in spanish
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
--use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Circuito is Port (
clk : in STD_LOGIC;
ir1 : in STD_LOGIC;
ir2 : in STD_LOGIC;
moverCoche : in STD_LOGIC;
angulo : in STD_LOGIC_VECTOR(4 downto 0);
vMaxCurva : in STD_LOGIC_VECTOR(4 downto 0);
posInicial : in STD_LOGIC_VECTOR(9 downto 0);
vueltasCurva : in STD_LOGIC_VECTOR(9 downto 0);
vueltasRecta : in STD_LOGIC_VECTOR(9 downto 0);
obst : in STD_LOGIC;
servoOut : out STD_LOGIC;
motorOut : out STD_LOGIC;
vueltasLed : out STD_LOGIC_VECTOR(9 downto 0);
vueltasDentroDeCircuito : out STD_LOGIC_VECTOR(11 downto 0);
revolucionesPorSeg : out STD_LOGIC_VECTOR(11 downto 0));
end Circuito;
architecture Behavioral of Circuito is
component motor_pwm_clk32kHz is Port (
clk : in STD_LOGIC;
entrada : in STD_LOGIC_VECTOR(4 downto 0);
salida : out STD_LOGIC);
end component;
component servo_pwm_clk32kHz is Port (
clk : in STD_LOGIC;
pos : in STD_LOGIC_VECTOR(4 downto 0);
servo : out STD_LOGIC);
end component;
component Contador_Vueltas is Port (
out1 : in STD_LOGIC; --Negro: 1 Blanco: 0
out2 : in STD_LOGIC; --Negro: 1 Blanco: 0
vueltas : out STD_LOGIC_VECTOR (9 downto 0);
rst : in STD_LOGIC;
clk : in STD_LOGIC);
end component;
component revoluciones is Port (
clk : in STD_LOGIC;
vueltasDentroDeCircuito : in STD_LOGIC_VECTOR(11 downto 0);
revoluciones : out STD_LOGIC_VECTOR(11 downto 0));
end component;
signal posServo, posMotor: STD_LOGIC_VECTOR(4 downto 0);
signal vueltas : STD_LOGIC_VECTOR(9 downto 0);
signal primeraVuelta : STD_LOGIC := '1';
signal sigReiniciarVueltas : STD_LOGIC;
signal sigVueltasDentroDeCircuito : STD_LOGIC_VECTOR(11 downto 0);
signal sigVueltasInicioEstado : STD_LOGIC_VECTOR(11 downto 0);
--signal sigVueltasRecta : unsigned := to_integer(unsigned(vueltasRecta));
--constant sigVueltasRecta : STD_LOGIC_VECTOR(9 downto 0) := "0000011110";
--constant sigVueltasCurva : STD_LOGIC_VECTOR(9 downto 0) := "0000011110";
signal flag : STD_LOGIC := '0';
signal Qt: STD_LOGIC_VECTOR(3 downto 0);
SUBTYPE STATE_TYPE IS STD_LOGIC_VECTOR(3 downto 0);
SIGNAL STATE: STATE_TYPE;
CONSTANT s0 : STATE_TYPE := "0000";
CONSTANT s1 : STATE_TYPE := "0001";
CONSTANT s2 : STATE_TYPE := "0010";
CONSTANT s3 : STATE_TYPE := "0011";
CONSTANT s4 : STATE_TYPE := "0100";
CONSTANT s5 : STATE_TYPE := "0101";
CONSTANT s6 : STATE_TYPE := "0110";
CONSTANT s7 : STATE_TYPE := "0111";
CONSTANT s8 : STATE_TYPE := "1000";
begin
UUT_Motor: motor_pwm_clk32kHz Port Map (
clk => clk,
entrada => posMotor,
salida => motorOut);
UUT_Servo: servo_pwm_clk32kHz Port Map (
clk => clk,
pos => posServo,
servo => servoOut);
UUT_ContadorVueltas: Contador_Vueltas Port Map (
clk => clk,
rst => sigReiniciarVueltas,
vueltas => vueltas,
out1 => ir1,
out2 => ir2);
UUT_Revoluciones: revoluciones Port Map(
clk => clk,
vueltasDentroDeCircuito => sigVueltasDentroDeCircuito,
revoluciones => revolucionesPorSeg
);
process(clk, moverCoche)
begin
if (moverCoche = '0') then
Qt <= s0;
sigReiniciarVueltas <= '1';
sigVueltasDentroDeCircuito <= (others => '0');
posServo <= "10000";
posMotor <= "10000";
elsif (clk'event and clk = '1') then
case Qt is
--Quieto
when s0 =>
posServo <= "10000";
posMotor <= "10000";
sigReiniciarVueltas <= '0';
Qt <= s1;
--Recta1
when s1 =>
sigReiniciarVueltas <= '0';
posServo <= "10000";
posMotor <= vMaxCurva; --Min: 10011
sigVueltasDentroDeCircuito <= ("00" & vueltas);
if (unsigned(vueltas) >= unsigned(vueltasRecta)) then
Qt <= s2;
sigReiniciarVueltas <= '1';
elsif (obst = '1') then
Qt <= s8;
else
-- sigVueltasRecta <= vueltasRecta;
Qt <= s1;
end if;
-- Curva1
when s2 =>
sigReiniciarVueltas <= '0';
posServo <= angulo;
posMotor <= vMaxCurva;
sigVueltasDentroDeCircuito <= posInicial + ("00" & vueltas);
if (unsigned(vueltas) >= unsigned(vueltasCurva)) then
sigReiniciarVueltas <= '1';
Qt <= s3;
elsif (obst = '1') then
Qt <= s8;
else
Qt <= s2;
end if;
--Recta2
when s3 =>
sigReiniciarVueltas <= '0';
posServo <= "10000";
posMotor <= vMaxCurva; --Min: 10011
sigVueltasDentroDeCircuito <= posInicial + vueltasCurva + ("00" & vueltas);
if (unsigned(vueltas) >= unsigned(vueltasRecta)) then
sigReiniciarVueltas <= '1';
Qt <= s4;
elsif (obst = '1') then
Qt <= s8;
else
Qt <= s3;
end if;
--Curva2
when s4 =>
sigReiniciarVueltas <= '0';
posServo <= angulo;
posMotor <= vMaxCurva;
sigVueltasDentroDeCircuito <= posInicial + vueltasCurva + vueltasRecta + ("00" & vueltas);
if (unsigned(vueltas) >= unsigned(vueltasCurva)) then
sigVueltasDentroDeCircuito <= (others => '0');
sigReiniciarVueltas <= '1';
Qt <= s4;
elsif (obst = '1') then
Qt <= s8;
else
Qt <= s1;
end if;
--Mantener Quieto
when s5 =>
posMotor <= "10000";
Qt <= s5;
when others =>
if(obst = '1') then
posMotor <= "00000";
--sigReiniciarVueltas <= '0';
Qt <= s8;
else
Qt <= s1;
end if;
end case;
vueltasDentroDeCircuito <= sigVueltasDentroDeCircuito;
vueltasLed <= vueltasRecta;
end if;
end process;
end Behavioral;
While it is possible to perform arithmetic comparison (in this case, <) on a std_logic_vector, it probably isn't best practice, as it is unknown whether the underlying value is signed or unsigned. If you need to do any arithmetic or comparisons, use unsigned or signed types from the numeric_std package.
A good discussion is found here.
So I am building a divider that divides unsigned 8 bit numbers by 53. It shows the quotient and the remainder as an output. I use one if/else statement to accomplish this task. I am getting syntax error near each if/elseif/else statements just declaring a syntax error, and I CANNOT find the error, where is my syntax error?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity divider is
Port ( input : in STD_LOGIC_VECTOR (7 downto 0);
output : out STD_LOGIC_VECTOR (7 downto 0);
r : out STD_LOGIC_VECTOR ( 7 downto 0));
end divider;
architecture Behavioral of divider is
signal input : unsigned(7 downto 0);
signal n : unsigned(7 downto 0);
signal quotient : unsigned(7 downto 0);
signal remainder : unsigned(7 downto 0);
signal a : unsigned(7 downto 0);
signal b : unsigned(7 downto 0);
signal c : unsigned(7 downto 0);
signal d : unsigned(7 downto 0);
signal zero : unsigned(7 downto 0);
signal one : unsigned(7 downto 0);
signal two : unsigned(7 downto 0);
signal three : unsigned(7 downto 0);
signal four : unsigned(7 downto 0);
signal x : unsigned(7 downto 0);
signal y : unsigned(7 downto 0);
signal z : unsigned(7 downto 0);
signal t : unsigned(7 downto 0);
begin
a <= "11010100"; -- 212
b <= "110011111"; -- 159
c <= "01101010"; -- 106
d <= "00110101"; -- 53
zero <= "0000000"; -- 0
one <= "00000001"; -- 1
two <= "00000010"; -- 2
three <= "00000011"; -- 3
four <= "00000100"; -- 4
x <= n - a; -- input - 212
y <= n - b; -- input - 159
z <= n - c; -- input - 106
t <= n - d; -- input - 53
input <= n;
if (x > zero) then
quotient <= four;
remainder <= n - a;
elsif (y = zero) then
quotient <= three;
remainder <= n - b;
elsif (z > zero) then
quotient <= two;
remainder <= n - c;
elsif (t > zero) then
quotient <= one;
remainder <= n - d;
else
quotient <= zero;
remainder <= n;
end if;
output <= quotient;
r <= remainder;
end behavioral;
This analyzes:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity divider is
port ( input: in std_logic_vector (7 downto 0);
output: out std_logic_vector (7 downto 0);
r: out std_logic_vector ( 7 downto 0)
);
end divider;
architecture behavioral of divider is
-- signal input: unsigned(7 downto 0);
signal n: unsigned(7 downto 0);
signal quotient: unsigned(7 downto 0);
signal remainder: unsigned(7 downto 0);
signal a: unsigned(7 downto 0);
signal b: unsigned(7 downto 0);
signal c: unsigned(7 downto 0);
signal d: unsigned(7 downto 0);
signal zero: unsigned(7 downto 0);
signal one: unsigned(7 downto 0);
signal two: unsigned(7 downto 0);
signal three: unsigned(7 downto 0);
signal four: unsigned(7 downto 0);
signal x: unsigned(7 downto 0);
signal y: unsigned(7 downto 0);
signal z: unsigned(7 downto 0);
signal t: unsigned(7 downto 0);
begin
a <= "11010100"; -- 212 -- get the lengths right
b <= "10011111"; -- 159 -- should these be constants?
c <= "01101010"; -- 106
d <= "00110101"; -- 53
zero <= "00000000"; -- 0
one <= "00000001"; -- 1
two <= "00000010"; -- 2
three <= "00000011"; -- 3
four <= "00000100"; -- 4
x <= n - a; -- input - 212
y <= n - b; -- input - 159
z <= n - c; -- input - 106
t <= n - d; -- input - 53
-- input <= n; -- can't assign inputs
process (x, zero, four, three, n, b, c, d) -- need a process
begin
if x > zero then
quotient <= four;
remainder <= n - a;
elsif y = zero then
quotient <= three;
remainder <= n - b;
elsif z > zero then
quotient <= two;
remainder <= n - c;
elsif t > zero then
quotient <= one;
remainder <= n - d;
else
quotient <= zero;
remainder <= n;
end if;
end process;
output <= std_logic_vector(quotient); -- need type conversion
r <= std_logic_vector(remainder); -- ditto
end architecture behavioral;
You had several string literals who's length did not match their assignment targets.
The if statement needed to be in a process.
There were some missing type conversions.
The rest of the changes are style and readability.
Haven't validated the algorithm it implements.
I am trying to write code to change the frequency of my clock. But the output is always zeroes...
signal cycle_counter : integer := 0;
signal HALFCYCLES : integer;
signal MY_CLK1, temporal : std_logic :='0';
frequency_divider: process (Clk,cycle_counter, HALFCYCLES)
begin
if rising_edge(Clk) then
cycle_counter <= cycle_counter + 1;
if cycle_counter = (HALFCYCLES-1) then
temporal <= NOT(temporal);
cycle_counter <= 0;
end if;
end if;
MY_CLK1 <= temporal;
end process frequency_divider;
When i put instead of HALFCYCLES-1 some integer value, all is working just fine, but i need this signal to be changeable.
I believe, that the problem is in comparing, but can't detect it.
I tried to make HALFCYCLES a variable, instead of signal, but compiler was against it :)
Full code (main goan - to put in the LED two different animations. Frequency and type of animation you should choose via switchers (input logic_vector S)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity LED2 is
generic (FIFT : std_logic_vector (15 downto 0) := "1111111111111111";
ZERO : std_logic_vector (15 downto 0) := "0000000000000000");
Port ( S : in STD_LOGIC_VECTOR (7 downto 0);
Clk : in STD_LOGIC;
R : in STD_LOGIC;
LED : out STD_LOGIC_VECTOR (7 downto 0));
end LED2;
architecture Behavioral of LED2 is
signal statement: std_logic_vector (7 downto 0);
signal cycle_counter : integer := 0;
signal CNT1, CNT2, CURCNT, CNT_NO : integer:= 0;
signal HALFCYCLES : integer;
signal MY_CLK1, MY_CLK2, temporal : std_logic :='0';
begin
frequency_divider: process (Clk,cycle_counter, HALFCYCLES) begin
if rising_edge(Clk) then
cycle_counter <= cycle_counter + 1;
if cycle_counter = (HALFCYCLES-1) then --(HALFCYCLES-1)
temporal <= NOT(temporal);
cycle_counter <= 0;
end if;
end if;
MY_CLK1 <= temporal;
MY_CLK2 <= temporal;
end process frequency_divider;
counter1: PROCESS (MY_CLK1, R)
BEGIN
IF (MY_CLK1 = '1' AND MY_CLK1'EVENT) THEN
IF (R='1') THEN
CNT1 <=0;
ELSIF (CNT1 = 15) THEN
CNT1 <= 0;
ELSE
CNT1 <= CNT1 + 1;
END IF;
END IF;
END PROCESS counter1;
counter2: PROCESS (MY_CLK2, R)
BEGIN
IF (MY_CLK2 = '1' AND MY_CLK2'EVENT) THEN
IF (R='1') THEN
CNT2 <=0;
ELSE
if (CNT2 = 15) then
CNT2 <= 0;
else
CNT2 <= CNT2 + 1;
end if;
END IF;
END IF;
END PROCESS counter2;
freq_changer: PROCESS (CNT1, CNT2, S)
BEGIN
IF (S(7) = '1')
THEN HALFCYCLES <= 50000000; CURCNT <= CNT1; CNT_NO <= 1;--1hz
ELSIF (S(6) = '1')
THEN HALFCYCLES <= 5000000; CURCNT <= CNT2; CNT_NO <= 2;--10hz
ELSIF (S(5) = '1')
THEN HALFCYCLES <= 500000; CURCNT <= CNT1; CNT_NO <= 1;--100hz
ELSIF (S(4) = '1')
THEN HALFCYCLES <= 50000; CURCNT <= CNT2; CNT_NO <= 2;--1khz
ELSIF (S(3) = '1')
THEN HALFCYCLES <= 5000; CURCNT <= CNT1; CNT_NO <= 1;--10khz
ELSIF (S(2) = '1')
THEN HALFCYCLES <= 500; CURCNT <= CNT2; CNT_NO <= 2;--100khz
ELSIF (S(1) = '1')
THEN HALFCYCLES <= 50; CURCNT <= CNT1; CNT_NO <= 1;--1mhz
ELSIF (S(0) = '1')
THEN HALFCYCLES <= 10; CURCNT <= CNT2; CNT_NO <= 2;--5mhz
ELSE HALFCYCLES <= 5; CURCNT <= CNT1; CNT_NO <= 1;--10mhz
END IF;
END PROCESS freq_changer;
main: PROCESS (CNT_NO, CURCNT)
BEGIN
c: CASE CNT_NO IS
WHEN 2 =>
counter2:CASE CURCNT IS
WHEN 0 => statement <= "00000001";
WHEN 1 => statement <= "00000010";
WHEN 2 => statement <= "00000100";
WHEN 3 => statement <= "00001000";
WHEN 4 => statement <= "00010000";
WHEN 5 => statement <= "00100000";
WHEN 6 => statement <= "01000000";
WHEN 7 => statement <= "10000000";
WHEN 8 => statement <= "10000000";
WHEN 9 => statement <= "01000000";
WHEN 10 => statement <= "00100000";
WHEN 11 => statement <= "00010000";
WHEN 12 => statement <= "00001000";
WHEN 13 => statement <= "00000100";
WHEN 14 => statement <= "00000010";
WHEN 15 => statement <= "00000001";
WHEN OTHERS => statement <= "00000000";
END CASE counter2;
WHEN OTHERS =>
counter1:CASE CURCNT IS
WHEN 0 => statement <= "10000001";
WHEN 1 => statement <= "01000010";
WHEN 2 => statement <= "00100100";
WHEN 3 => statement <= "00011000";
WHEN 4 => statement <= "00011000";
WHEN 5 => statement <= "00100100";
WHEN 6 => statement <= "01000010";
WHEN 7 => statement <= "10000001";
WHEN 8 => statement <= "00011000";
WHEN 9 => statement <= "00100100";
WHEN 10 => statement <= "01000010";
WHEN 11 => statement <= "10000001";
WHEN 12 => statement <= "10000001";
WHEN 13 => statement <= "01000010";
WHEN 14 => statement <= "00100100";
WHEN 15 => statement <= "00011000";
WHEN OTHERS => statement <= "00000000";
END CASE counter1;
END CASE c;
LED <= statement;
END PROCESS main;
end Behavioral;
testbench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.Numeric_Std.all;
ENTITY LED_controller_tb IS
END LED_controller_tb;
ARCHITECTURE behavior OF LED_controller_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT LED2
PORT(
S : IN std_logic_vector(7 downto 0);
Clk : IN std_logic;
R : IN std_logic;
LED : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
--Inputs
signal S : std_logic_vector(7 downto 0) := (others => '0');
signal Clk : std_logic := '0';
signal R : std_logic := '0';
--Outputs
signal LED : std_logic_vector(7 downto 0);
-- Clock period definitions
constant Clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: LED2 PORT MAP (
S => S,
Clk => Clk,
R => R,
LED => LED
);
-- Clock process definitions
Clk_process :process
begin
Clk <= '0';
wait for Clk_period/2;
Clk <= '1';
wait for Clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for Clk_period * 8;
S <= std_logic_vector(to_unsigned(to_integer(unsigned(S)) + 1, 8));
-- insert stimulus here
end process;
reset: PROCESS
BEGIN
WAIT FOR 1 us;
R <= '1';
WAIT FOR 500 ns;
R <= '0';
END PROCESS reset;
END;
I think you are changing S far too quickly in your testbench. I changed line in your testbench to wait for a much longer time and it seems to work OK.
As recommended by Andy, I would change line 26 of your design to
if cycle_counter >= (HALFCYCLES-1) then --(HALFCYCLES-1)
Here's the (modified) testbench in full. I have also added a process to stop the simulation; otherwise, it runs forever:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.Numeric_Std.all;
ENTITY LED_controller_tb IS
END LED_controller_tb;
ARCHITECTURE behavior OF LED_controller_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT LED2
PORT(
S : IN std_logic_vector(7 downto 0);
Clk : IN std_logic;
R : IN std_logic;
LED : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
--Inputs
signal S : std_logic_vector(7 downto 0) := (others => '0');
signal Clk : std_logic := '0';
signal R : std_logic := '0';
--Outputs
signal LED : std_logic_vector(7 downto 0);
-- Clock period definitions
constant Clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: LED2 PORT MAP (
S => S,
Clk => Clk,
R => R,
LED => LED
);
-- Clock process definitions
Clk_process :process
begin
Clk <= '0';
wait for Clk_period/2;
Clk <= '1';
wait for Clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for Clk_period * 800; -- WAIT MUCH LONGER BEFORE CHANGING S !
S <= std_logic_vector(to_unsigned(to_integer(unsigned(S)) + 1, 8));
-- insert stimulus here
end process;
reset: PROCESS
BEGIN
WAIT FOR 1 us;
R <= '1';
WAIT FOR 500 ns;
R <= '0';
END PROCESS reset;
STOP_SIM: process -- OTHERWISE THE SIM RUNS FOREVER
begin
wait for Clk_period * 4000;
assert FALSE severity FAILURE;
end process;
END;
http://www.edaplayground.com/x/7XS