Strange behavior of VHDL if statement - if-statement

I was stucked in a strange problem with VHDL if statement when I was working on my project. Although I fixed it, I still don't understand why it happened. I stimulated my code using ModelSPIM. Before I changed the code, I expected rd <= inst (20 downto 16); when RegDst = '1', but it gave me rd <= inst (15 downto 11);. I have checked RegDst was really equal to 0, but it gave me the wrong assignment. After I changed the code, everythings became normal. What is the difference between them ?
Before:
fetch: process(inst)
begin
if( inst = x"0000_0000" ) then -- end of program
endRun <= '1';
else
endRun <= '0';
opcode <= inst (31 downto 26);
rs <= inst (25 downto 21);
rt <= inst (20 downto 16);
if( RegDst = '1' ) then
rd <= inst (15 downto 11);
else
rd <= inst (20 downto 16);
end if;
funct <= inst (5 downto 0);
offset <= inst (15 downto 0);
jsec <= inst (25 downto 0);
end if;
end process fetch;
After:
fetch: process(inst)
begin
if( inst = x"0000_0000" ) then -- end of program
endRun <= '1';
else
endRun <= '0';
opcode <= inst (31 downto 26);
rs <= inst (25 downto 21);
rt <= inst (20 downto 16);
funct <= inst (5 downto 0);
offset <= inst (15 downto 0);
jsec <= inst (25 downto 0);
end if;
end process fetch;
rd <= inst (15 downto 11) when (RegDst = '1') else
inst(20 downto 16); -- RegDst mux

It is a problem with your sensitivity list. The sensitivity list is the list of signal in the parentheses after process. A process is executed when an event occurs on any signal in it's sensitivity list.
In your case, only inst was in your sensitivity list. Thus, when regDst would change from '0' to '1', the process would not be executed (if inst didn't change) and rd would not update.
In your second approach, the statement is not in a process, thus is not affected by sensitivity list (to be exact, all signals involved in an out of process statement are considered it it's sensitivity list). Should you add redDst in the sensitivity list, you would have the same results:
process(inst, regDst)
Note that missing signals in sensitivity list is a very common source of mismatch between simulation and implementation since all tools I know ignore them for implementation. If you use VHDL-2008, you can use the keyword all in your sensitivity list, which implies exactly what you think.

Related

if statement inside counter in VHDL

I have a 3 bit counter that counts upwards from "000". Every time "101" is reached, I want the o_en signal to be HIGH.
I have the following VHDL file.
The behaviour is unfortunately different.
The o_en signal is HIGH, when "110" is reached (delayed by one clock cycle).
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity special_counter is
port(
i_clk : in std_logic;
i_en : in std_logic;
i_rst : in std_logic;
o_data : out std_logic_vector(2 downto 0);
o_en : out std_logic
);
end entity;
architecture behave of special_counter is
signal w_data : std_logic_vector(2 downto 0);
signal w_en : std_logic;
begin
process(i_clk, i_rst) begin
if i_rst = '1' then
w_data <= "000";
elsif rising_edge(i_clk) then
if i_en = '1' then
if w_data = "101" then
w_en <= '1';
w_data <= w_data + 1;
else
w_en <= '0';
w_data <= w_data + 1;
end if;
end if;
end if;
end process;
o_data <= w_data;
o_en <= w_en;
end architecture;
How can I change my program to perform the expected behaviour ?
That is exactly correct and that is what you have coded.
To put it into words:
"At the rising edge of the clock, when the counter has the value 101 then the w_en will be set high."
Thus the w_en signal from which o_en is derived, will be high after the rising edge of the clock.
In the same time as the w_data changes and after the rising clock becomes "110".
There are two solutions:
Test for "100" (so one cycle sooner)
Make w_en (and thus o_en) combinatorial.
For the latter you must move the assignment outside the 'clocked' section
and use e.g.
w_en <= '1' when w_data = "101" else '0';

How to/Can you use if statement to an Assert Report Severity Statement in VHDL Testbench?

Okay. So to say why I'm asking this question. We have been told to develop the system that can work out the system that can resolve the formula:
O <= (A*3 + B*C)/D + C +5
There is a two cycle propagation delay in the system as it currently stands. However as it gets more complicated as we develop it, so I'm using a constant propagation_delay to represent how the delay can change.
There is a much simpler way to make a self checking test bench for this system, have two processes, one that inputs the test vectors, and one that waits for the delay, and then starts checking. However we were told that there was a more tricky way of doing it which involved only one process. I have decided to attempt this way as I enjoy VHDL a whole deal so I want to explore it as much I can!
Another constraint from the lecturer was that there had to be change every clock cycle.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY algorith_TB IS
END algorith_TB;
ARCHITECTURE behavior OF algorith_TB IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT algorithm
PORT(
A : IN std_logic_vector(15 downto 0);
B : IN std_logic_vector(15 downto 0);
C : IN std_logic_vector(15 downto 0);
D : IN std_logic_vector(15 downto 0);
O : OUT std_logic_vector(31 downto 0);
clk : IN std_logic;
rst : IN std_logic
);
END COMPONENT;
--Inputs
signal A : std_logic_vector(15 downto 0); --:= (others => '0');
signal B : std_logic_vector(15 downto 0); --:= (others => '0');
signal C : std_logic_vector(15 downto 0); --:= (others => '0');
signal D : std_logic_vector(15 downto 0); --:= (others => '0');
signal clk : std_logic; --:= '0';
signal rst : std_logic; --:= '0';
--Outputs
signal O : std_logic_vector(31 downto 0);
-- Delay Constants Definition
constant propagation_delay : integer := 2;
constant num_vectors : integer := 5;
-- Clock period definitions
constant clk_period : time := 120 ns;
type test_vector is record
A : STD_LOGIC_VECTOR(15 downto 0);
B : STD_LOGIC_VECTOR(15 downto 0);
C : STD_LOGIC_VECTOR(15 downto 0);
D : STD_LOGIC_VECTOR(15 downto 0);
O : STD_LOGIC_VECTOR(31 downto 0);
end record;
type test_vector_array is array
(natural range<>) of test_vector;
constant test_vectors : test_vector_array := (
-- A B C D O
(x"0001", x"0002", x"0003", x"0004", x"0000000A") ,
(x"AAAA", x"0202", x"4131", x"4123", x"00004340") ,
(x"0001", x"0003", x"0005", x"0007", x"0000000C") ,
(x"AAAA", x"0202", x"4131", x"4123", x"00004340") ,
(x"0001", x"0003", x"0005", x"0007", x"0000000C") );
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: algorithm PORT MAP (
A => A,
B => B,
C => C,
D => D,
O => O,
clk => clk,
rst => rst
);
-- 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 500 ns;
rst <= '1'; -- initial reset
wait for clk_period;
rst <= '0';
wait for clk_period*10; -- warm up period
wait until falling_edge(clk); -- resynchronise with falling edge
for i in 0 to 4 loop -- cycle through test vectors
if (i < num_vectors) then
A <= test_vectors(i).A;
B <= test_vectors(i).B;
C <= test_vectors(i).C;
D <= test_vectors(i).D;
wait for clk_period;
end if; -- end input loop if
if (i > propagation_delay) then -- pause for 2
assert (O = test_vectors(i-propagation_delay).O)
report "Test vector " & integer'image(i-propagation_delay) &
" failed for input A = " & integer'image(to_integer(unsigned(a))) &
"and b = " & integer'image(to_integer(unsigned(b))) &
" and C = " & integer'image(to_integer(unsigned(c))) &
"and D = " & integer'image(to_integer(unsigned(d)))
severity error;
end if; -- end assert check if
end loop; -- end for loop
wait;
end process;
END;
This works, in terms of simulation output. There is a two cycle delay between inputs and outputs.
However I am having a problem with the printing to console as it allows that i = 2,3,4 are all correct. But says that i = 0 , 1 are incorrect. Which are the two input vectors where i < propogation_delay. I understand I'm facing a problem here but just can't figure out how to fix it.
One way I've thought of fixing it but I get a syntax error I can't fix is:
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 500 ns;
rst <= '1'; -- initial reset
wait for clk_period;
rst <= '0';
wait for clk_period*10; -- warm up period
wait until falling_edge(clk); -- resynchronise with falling edge
for i in 0 to 4 loop -- cycle through test vectors
if (i < num_vectors) then
A <= test_vectors(i).A;
B <= test_vectors(i).B;
C <= test_vectors(i).C;
D <= test_vectors(i).D;
wait for clk_period;
end if; -- end input loop if
if (i > propagation_delay) then -- pause for 2
assert (O = test_vectors(i-propagation_delay).O)
end if; -- end assert check if
if (i - propagation_delay < 0) then
report "Test vector " & integer'image(i) &
" failed for input A = " & integer'image(to_integer(unsigned(a))) &
"and b = " & integer'image(to_integer(unsigned(b))) &
" and C = " & integer'image(to_integer(unsigned(c))) &
"and D = " & integer'image(to_integer(unsigned(d)))
severity error;
else
report "Test vector " & integer'image(i-propagation_delay) &
" failed for input A = " & integer'image(to_integer(unsigned(a))) &
"and b = " & integer'image(to_integer(unsigned(b))) &
" and C = " & integer'image(to_integer(unsigned(c))) &
"and D = " & integer'image(to_integer(unsigned(d)))
severity error;
end if; -- end report if
end loop; -- end for loop
wait;
end process;
END;
But I get a syntax error on the line
end if; -- end assert check if
I am trying to say if it is smaller then prop delay then check what is now, otherwise check i-prop.
Any ideas on how to work with this syntax or can you not split up the assert/report/severity?
Thanks for taking time to read guys!

VHDL if statement error

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity mux is
port (sel: in std_logic;
s0,s1: in std_logic_vector (3 downto 0) ;
sout : out std_logic_vector (3 downto 0));
end mux;
architecture Behavioral of mux is
begin
if sel = '0' then
sout <= s0;
else
sout <= s1;
end if;
end Behavioral;
-- I'm Trying to make a mux for a four bit serial adder output. If the cin is 0 then it will take the
-- sum from the first adder which has cin 0 and if cin is 1 then it will take the sum from the second -- adder which i've fed with cin 1. However there is an error with the if somewhere I can't figure --out. the compiler says error near if else and end if statement
Use the if-else construct within a process with the proper sensitivity list.
`
process(sel)
begin
(
if sel = '0' then
sout <= s0;
else
sout <= s1;
end if;
);
end process;
else use theWhen Else construct
The if is a sequential statement, so it only goes inside a process. Replace if with when, since that is a concurrent statement thus can be used directly in the architecture:
sout <= s0 when (sel = '0') else s1;

nbit Bitslice ALU with For/IF Generate in VHDL

I'm designing a n-bit bitslice ALU with GENERATE and I wrote this code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
ENTITY ALU IS
GENERIC (n : integer := 8);
PORT (A,B : IN std_logic_vector(n-1 DOWNTO 0);
funct : IN std_logic_vector (2 DOWNTO 0);
clk,nrst : IN std_logic;
Z : OUT std_logic_vector (n-1 DOWNTO 0);
ov,cout : OUT std_logic);
END ALU;
ARCHITECTURE bitSlice OF ALU IS
SIGNAL C : std_logic_vector (0 TO n);
SIGNAL temp : std_logic_vector (n-1 DOWNTO 0);
BEGIN
L1:IF nrst = '1' GENERATE
L2:IF funct = "000" GENERATE Z <= A;
END GENERATE L2;
L3:IF funct = "001" GENERATE Z <= B;
END GENERATE L3;
L4:IF funct = "010" GENERATE
c(0) <= '0';
cout <= C(n);
ov <= C(n);
L5: FOR i IN 0 TO n-1 GENERATE
Z(i) <= (A(i) XOR B(i) XOR C(i));
C(i+1) <= (A(i) AND B(i)) OR
(A(i) AND C(i)) OR
(B(i) AND C(i));
END GENERATE L5;
END GENERATE L4;
L6:IF funct = "011" GENERATE
c(0) <= '0';
cout <= C(n);
ov <= C(n);
temp <= std_logic_vector(signed(NOT(b))+1);
L7: FOR i IN 0 TO n-1 GENERATE
Z(i) <= (A(i) XOR temp(i) XOR C(i));
C(i+1) <= (A(i) AND temp(i)) OR
(A(i) AND C(i)) OR
(B(i) AND C(i));
END GENERATE L7;
END GENERATE L6;
L8:IF funct = "100" GENERATE Z <= A(n-1 DOWNTO 0) & '0';
END GENERATE L8;
L9:IF funct = "101" GENERATE Z <= B(n-1 DOWNTO 0) & '0';
END GENERATE L9;
L10:IF funct = "110" GENERATE Z <= '0' & a(n DOWNTO 1);
END GENERATE L10;
L11:IF funct = "111" GENERATE Z <= '0' & b(n DOWNTO 1);
END GENERATE L11;
END GENERATE L1;
END bitSlice;
It compiles alright but it doesn't work, although there are a bunch of warnings in generate blocks that says IF statement must be static. I wonder where I made a mistake.
You are asking the tools to generate different hardware according to a port whose input value is unknown till runtime. That won't work!
Making "funct" a generic input will allow you to use the Generates successfully, but the functionality will be fixed at elaborationtime.
Generating ALL the hardware and using "funct" to multiplex between different generated results is probably closer to what you want.
Generate is used to choose between different bits of hardware being "made". Your funct is an input, which can therefore change during operation. There is no way to change the actual hardware you've make at that point.
You need to choose between different sets of results from all the hardware based on funct - wrap your if..generates in a clocked process and change them to if..thens - and go from there.
You could use the WHEN or SELECT statement instead of GENERATE in this kind of implementation.
Your code has another problem: You are implementing a combinational circuit but you didn't specify the complete LUTs, which will cause the inference of latches. For example, you didn't specify the output values for nrst='0' (among several other signals/cases).

Holding an action in VHDL

I want to create a project with Quartus II and its function is to enable three different leds deppending on a code. When you are entering the code, the first led will be ON. Depending on the code entered, the second or the third will be ON. My problem is, when the code is correct I want the second led to be ON 3 seconds, and if it's incorrect, the third led will be ON during 2 seconds. It would be great if you help me.
Thank you!
Notes: leds are declared as a Logic Vector and the numbers of the code are declared as interrup from 0 to 7.
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
ENTITY programa IS
PORT
(
interrup : in Std_Logic_Vector (7 downto 0);
clk, rst: in Std_Logic;
led : out Std_Logic_Vector (2 downto 0)
);
END programa;
ARCHITECTURE arch_programa OF programa IS
type state is (zero, one, two, three, four, five, six);
signal pr_state, nx_state : state;
signal A : Std_Logic_Vector (3 downto 0);
BEGIN
process(interrup, pr_state)
begin
case pr_state is
when zero =>
led <= "100";
A(0) <= interrup(7);
nx_state <= one;
when one =>
led <= "100";
A(1) <= interrup(6);
nx_state <= two;
when two =>
led <= "100";
A(2) <= interrup(5);
nx_state <= three;
when three =>
led <= "100";
A(3) <= interrup(3);
nx_state <= four;
when four =>
led <= "100";
if(A = "1111") then nx_state <= five;
else nx_state <= six;
end if;
when five =>
led <= "010";
nx_state <=zero;
when six =>
led <= "001";
nx_state <=zero;
end case;
end process;
process(rst,clk)
begin
if(rst='1') then
pr_state <= zero;
elsif (clk'event and clk = '1') then
pr_state <= nx_state;
end if;
end process;
end arch_programa;
As for the first question, you will need to count either 3 or 2 seconds worth of clock pulses, so you need to know the clock frequency.
For example, start the counter when you turn the LED on, turn the led and counter off when you have counted the correct number of pulses. It is often easier to count down from that value and stop when the counter reaches zero.
As for the second, the button has to be connected via an input port, which you can use as an input to one of your processes.
There is probably a very large number of ways to solve this, but without changing your code, much, here is one (note, not fully tested).
Give each state a count output that depends on the clock rate.
Establish a counter register big enough to hold the largest count.
Decrement the count on each clock, reload it when it's zero.
The reload value comes from the new state.
Switch states on the last count before zero.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
ENTITY programa IS
PORT
(
interrup : in Std_Logic_Vector (7 downto 0);
clk, rst: in Std_Logic;
led : out Std_Logic_Vector (2 downto 0)
);
END programa;
ARCHITECTURE arch_programa OF programa IS
type state is (zero, one, two, three, four, five, six);
signal pr_state, nx_state : state;
signal A : Std_Logic_Vector (3 downto 0);
signal count,pr_count:integer; --NOTE: Synthisizing integers is very unpredictable, should use unsigned
BEGIN
assign_counts:process(pr_state)
begin
--no idea what states need what delay, this is just an example
case pr_state is
when zero | one | two =>
pr_count<=10;
when four =>
pr_count<=20;
when others =>
pr_count<=50;
end case;
end process;
process(interrup, pr_state)
begin
case pr_state is
when zero =>
led <= "100";
A(0) <= interrup(7);
nx_state <= one;
when one =>
led <= "100";
A(1) <= interrup(6);
nx_state <= two;
when two =>
led <= "100";
A(2) <= interrup(5);
nx_state <= three;
when three =>
led <= "100";
A(3) <= interrup(3);
nx_state <= four;
when four =>
led <= "100";
if(A = "1111") then nx_state <= five;
else nx_state <= six;
end if;
when five =>
led <= "010";
nx_state <=zero;
when six =>
led <= "001";
nx_state <=zero;
end case;
end process;
process(rst,clk)
begin
if(rst='1') then
pr_state <= zero;
count<=pr_count;
elsif (clk'event and clk = '1') then
if count=0 then
count<=pr_count;
elsif count=1 then
pr_state <= nx_state;
count<=count-1;
else
count<=count-1;
end if;
end if;
end process;
end architecture;
--Test bench
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity bench is
end bench;
architecture bench of bench is
component programa IS
PORT (
interrup : in Std_Logic_Vector (7 downto 0);
clk, rst: in Std_Logic;
led : out Std_Logic_Vector (2 downto 0));
END component;
signal clk:std_logic:='1';
signal interrup:std_logic_vector (7 downto 0);
signal rst:std_logic;
constant freq:real:=1.0e6;
begin
do_reset:process
begin
rst<='1';
wait for 10 us;
rst<='0';
wait;
end process;
clk<=not clk after 0.5 sec / freq;
UUT:programa port map (
interrup => interrup,
clk => clk,
rst => rst);
end architecture;