This is a simple exercise for a Hardware course that I am taking. We are required to use Altera Quartus II and ModelSim to test the implementation; tools that I've never used before, so I might be missing something, and my explanations, lacking.
The circuit has 3 inputs (Data, Clock and Reset) and 2 outputs (Locked, Error). The sequence used in this exercise is 10001.
The problem ask to design a circuit that will recognize a sequence of bits. When the correct sequence is entered, you are granted access (the circuit enters the "UNLOCK" state; Locked output is 0). Otherwise, if at any point you enter the wrong bit, you trigger an alarm and you're supposed to remain in the "ERROR" state until the circuit is manually reset.
"Locked" is always 1 unless it gets to the "UNLOCK" state. "Error" is always 0 unless it gets to the "ERROR" state.
The circuit is supposed to always start out in a "RESET" state. Once it gets in the "UNLOCK" state, it stays there as long as the bits provided are 1, or goes to "RESET" if a 0 is encountered.
This is the state diagram that I've worked out:
Any help or ideas are welcome!
It turned out that almost all the logic behind my implementation is correct, the problem was a misunderstanding in using the CLRNs on the flip-flops and a typo in one of the assignments. As such, most of the images were removed to get rid of the clutter.
-- EDIT 1
With the following code (which should be correct), the waveform is not as expected (at least the lock is not)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
entity dlock is
port
(
DATA : IN STD_LOGIC;
RESET : IN STD_LOGIC;
CLOCK : IN STD_LOGIC;
LOCK : OUT STD_LOGIC;
ALARM : OUT STD_LOGIC
);
end dlock;
architecture bdf_type of dlock is
type STATE_type is (S_RESET, S1, S2, S3, S4, UNLOCK, S_ALARM);
signal state : STATE_type := S_RESET;
begin
process (clock) is
begin
if (rising_edge(clock)) then
-- `reset` always puts us back in the reset state
if (RESET = '1') then
state <= S_RESET;
else
case state is
when S_RESET =>
-- Reset; lock active and alarm off
LOCK <= '1';
ALARM <= '0';
if (DATA = '1') then
-- Correct bit, proceed to next state
state <= S1;
else
-- Incorrect bit; ALARM
state <= S_ALARM;
end if;
when S1 =>
if (DATA = '0') then
state <= S2;
else
state <= S_ALARM;
end if;
when S2 =>
if (DATA = '0') then
state <= S3;
else
state <= S_ALARM;
end if;
when S3 =>
if (DATA = '0') then
state <= S4;
else
state <= S_ALARM;
end if;
when S4 =>
if (DATA = '1') then
state <= UNLOCK;
else
state <= S_ALARM;
end if;
when UNLOCK =>
-- Lock inactive!
LOCK <= '0';
if (data = '0') then
state <= S_RESET;
else
state <= UNLOCK;
end if;
when S_ALARM =>
-- Alarm active in ALARM state
ALARM <= '1';
end case;
end if;
end if;
end process;
end bdf_type;
Your reset, as written in the VHDL, is active low. This means you're holding the circuit in reset most of the time. Your data pattern looks like you thought your reset was active high.
Your error signal, insofar as I can see in the image of the waveform posted, is behaving correctly. Every time you exit reset for a cycle, your data is 0, which sends you to the error state. Of course this only persists for one cycle since you immediately reset again.
These are just glitches, if you zoom in you'll see that the phantom unlocks are happening for 0 time (or very small time periods depending on your gate models). This is one reason why the output of combinational logic isn't used for clocking data. Passing the value through a flip-flop will remove glitches.
EDIT:
Furthermore, your state assignment table and your state output table disagree with each other. One lists the Q values from Q2 downto Q0 and the other lists from Q0 to Q2, but both list the unlocked state as "110". This doesn't cause issues for the Error state since "111" reads the same forwards and backwards.
EDIT2:
As far as avoiding glitches... glitches are the nature of combinational logic.
You could have locked sourced directly from a flop without adding latency by having the input to a "locked" flop be dictated by the same preconditions of the unlocked state (i.e. locked_d = not((state=s4 or state=locked) and data=1) and use locked_q.
You could just avoiding having locked be a function of multiple state bits by converting the state machine machine encoding to a one-hot or hybrid one-hot (where there is a dedicated bit for the locked/error states because they drive output bits , but the other 5 states use 3 shared state bits).
Think of a state table like this:
Q4 Q3 Q2 Q1 Q0 State
0 1 0 0 0 Reset
0 1 0 0 1 S1
0 1 0 1 0 S2
0 1 0 1 1 S3
0 1 1 0 0 S4
0 0 X X X Unlock
1 1 X X X Error
1 0 X X X X
0 1 1 0 1 X
0 1 1 1 X X
Where Q4 is your error bit and Q3 is your locked bit
That said, avoiding glitches is usually not important because they don't cause problems when used in sequential logic as the D inputs or clock enables.
I would say you have made your life needlessly more difficult with your approach. You don't need these D and Q signals at all, just code the state machine exactly as you see it in the excellent diagram at the start of your question. I haven't written the full code, but this should show the basic approach that leads to a minimal, easy to read result:
type STATE_type is (S_RESET, S1, UNLOCK, ERROR);
signal state : STATE_type := S_RESET;
...
process (clock) is
begin
if (rising_edge(clock)) then
-- `reset` always puts us back in the reset state
if (reset = '1') then
state <= S_RESET;
else
case state is
when S_RESET =>
-- Reset; lock active and alarm off
lock <= '1';
alarm <= '0';
if (data = '1') then
-- Correct bit, proceed to next state
state <= S1;
else
-- Incorrect bit; error
state <= ERROR;
end if;
when S1 =>
if (data = '0') then
state <= UNLOCK;
else
state <= ERROR;
end if;
when UNLOCK =>
-- Lock inactive!
lock <= '0';
if (data = '0') then
state <= RESET;
end if;
when ERROR =>
-- Alarm active in error state
alarm <= '1';
end case;
end if;
end if;
end process;
You should easily be able to add the other states S2 and onward to this.
If you need the lock and alarm to change state as soon as reset is asserted, you should implement an asynchronous reset, instead of the synchronous reset in the example above:
if (reset = '1') then
state <= S_RESET;
alarm <= '0';
lock <= '1';
elsif (rising_edge(clock)) then
case state is
-- `when` statements
end case;
end if;
Another advantage of writing it this way is that you can easily make the required pattern a constant:
constant PATTERN : std_logic_vector(0 to 4) := "10001";
Then your data comparisons in the various states would look like:
when S_RESET =>
if (data = PATTERN(0)) then
...
when S1 =>
if (data = PATTERN(1)) then
etc. You can then alter the required pattern with a simple one-line change.
Related
I have a FSM consisting of 3 states: STATIC, UP and DOWN.
The FSM starts in the STATIC state and if I press the up arrow key, it will move to the UP state, thereafter returning to the STATIC state. Same thing for DOWN.
At first the FSM works well but suddenly after a random amount of key presses it will enter an unspecified state. The FSM consists of two processes:
type ALL_STATES is (STATIC, UP, DOWN);
signal STATE, NEXT_STATE: ALL_STATES;
signal posBarraYTOP, posBarraYBOT: std_logic_vector(11 downto 0);
signal movTeclado: std_logic_vector(1 downto 0);
-- ...
Keybd: keyboard port map (input, movTeclado); -- keyboard output
-- ...
bar_FSM_sincrono: process(CLK, RST) -- CLK is the FPGA's clock
begin
if RST='1' then
STATE <= STATIC;
elsif (CLK'event and CLK = '1') then
STATE <= NEXT_STATE; -- in each CLK cycle we move to the next state.
end if;
end process bar_FSM_sincrono;
bar_FSM_cambioest: process(STATE)
begin
case STATE is
when STATIC=>
seg <= "1001001";
if (movTeclado = "01" and posBarraYTOP > 20) then
NEXT_STATE <= UP;
elsif (movTeclado = "10" and posBarraYBOT < 980) then
NEXT_STATE <= DOWN;
else
NEXT_STATE <= STATIC;
end if;
when UP | DOWN =>
NEXT_STATE <= STATIC;
seg <= "1111110";
when others =>
NEXT_STATE <= STATIC;
seg <= "0110111";
end case;
end process bar_FSM_cambioest;
movTeclado is a 2-bit signal that shows when the user presses the up 01 or down 10 key. It's 00 if no key is pressed. movTeclado doesn't give me any problems.
posBarraYTOP and posBarraYBOT are two signals to describe a boundary, and these conditions are always met.
I use seg as a signal for the 7-segment display to debug and find out in what state the FSM is at. At first it always displays the STATIC seg, as it should since UP seg and DOWN seg are only displayed for one cycle. But then when the error happens it's when it starts displaying the others seg, as well as the STATIC seg. It's a back-and-forth between STATIC and others, which I don't understand since when STATE = STATIC, it should only transition to UP or DOWN.
Thank you for reading this far, does anyone know what's going on?
As other comments have suggested, you should never drive a signal from more than one process block. Personally I don't like writing state machines like this, with 2 process blocks, because I find it confusing.
But regardless, your 2nd process block (the combinational one) should only be assigning NEXT_STATE, it should never make an assignment to STATE since that's taken care of by the first process block.
One issue is that your bar_FSM_cambioest sensitivity list is incomplete. It needs to include all signals who's changes will affect the process's output.
bar_FSM_cambioest: process(STATE, movTeclado, posBarraYTOP, posBarraYBOT)
My next question would be how fast is your clock? Are you trying to go from the STATIC segment display to the UP/DOWN one and back faster than the 7-segment display can reliably update?
I am new to VHDL and I am attempting to implement the following state machine into VHDL (state diagram provided below). When I press a button on my Basys3 FPGA board( P input) the output is a random state. I suspect this is because the clock is going through many cycles during a single press so more than 1 input is being taken in from a single press but I am unsure. Is there anything I can do to fix this. I want to be able to press button P and the states change one at a time.
library IEEE;
USE ieee.std_logic_1164.all;
ENTITY trasher is
PORT (
clock : IN STD_LOGIC;
P : IN STD_LOGIC;
reset : IN STD_LOGIC;
LED3, LED1,LED2,LED0 : OUT STD_LOGIC);
END ENTITY;
-- Architecture definition for the SimpleFSM entity
Architecture RTL of trasher is
TYPE State_type IS (A, B, C, D); -- Define the states
SIGNAL State : State_Type; -- Create a signal that uses
-- the different states
BEGIN
PROCESS (clock, reset)
BEGIN
IF (reset = '1') THEN -- upon reset, set the state to A
State <= A;
ELSIF rising_edge(clock) THEN -- if there is a rising edge of the
-- clock, then do the stuff below
-- The CASE statement checks the value of the State variable,
-- and based on the value and any other control signals, changes
-- to a new state.
CASE State IS
-- If the current state is A and P is set to 1, then the
-- next state is B
WHEN A =>
IF P='1' THEN
State <= B;
END IF;
-- If the current state is B and P is set to 1, then the
-- next state is C
WHEN B =>
IF P='1' THEN
State <= C;
END IF;
-- If the current state is C and P is set to 1, then the
-- next state is D
WHEN C =>
IF P='1' THEN
State <= D;
END IF;
-- If the current state is D and P is set to 1, then the
-- next state is B.
-- If the current state is D and P is set to 0, then the
-- next state is A.
WHEN D=>
IF P='1' THEN
State <= B;
ELSE
State <= A;
END IF;
WHEN others =>
State <= A;
END CASE;
END IF;
END PROCESS;
-- Decode the current state to create the output
-- if the current state is D, R is 1 otherwise R is 0
LED0 <= '1' WHEN State=A ELSE '0';
LED1 <= '1' WHEN State=B ELSE '0';
LED2 <= '1' WHEN State=C ELSE '0';
LED3 <= '1' WHEN State=D ELSE '0';
END rtl;
Do not use directly the input from your press-button. What you need to feed your state machine is the output of a rising edge detector of P, not P itself.
Moreover P is not synchronous with your master clock and there is thus a risk of meta-stability. Last but not least, if it bounces, you will get several value changes instead of just one. To solve the meta-stability issue you need a re-synchronizer, which is just a shift register. And you can also use it to generate an intermediate signal that is asserted high during only one clock period when the button is pressed, that is, the rising edge detector you need for your state machine. Example with 3-stages:
signal sync: std_ulogic_vector(0 to 2);
signal button_pressed: std_ulogic;
...
process(clock, reset)
begin
if reset = '1' then
sync <= (others => '0');
elsif rising_edge(clock) then
sync <= P & sync(0 to 1);
end if;
end process;
button_pressed <= sync(1) and (not sync(2));
Stages 1 and 2 of sync are safe to use because they have already been resynchronized (assuming 2 stages are enough for your target technology and mean time between failures; read something about meta-stability, maybe, if you don't understand this).
When the button is pressed, ones are shifted in sync. After two clock periods sync = "110" so button_pressed is asserted high. One clock period later sync = "111" and button_pressed is de-asserted. button_pressed is thus a one-clock-period-only indicator that the button was pressed. You can use it as an input of your state machine.
The second problem comes from the way press-buttons work. If your prototyping board does not already debounce its press-buttons it can be that, when the button is pressed, your P input oscillates several times between 0 and 1 before stabilizing to 1. Same when the button is released. As this is sometimes not the case do some tests before implementing a debouncer. For instance, count the number of times button_pressed is asserted high and send this to your LEDs:
signal cnt: u_unsigned(3 downto 0);
...
process(clock, reset)
begin
if reset = '1' then
cnt <= (others => '0');
elsif rising_edge(clock) then
cnt <= cnt + button_pressed;
end if;
end process;
LED0 <= std_logic(cnt(0));
LED1 <= std_logic(cnt(1));
LED2 <= std_logic(cnt(2));
LED3 <= std_logic(cnt(3));
If your button bounces you should sometimes see more than one increment when you press it. It will be time to search a bit about debouncing and, if needed, to ask a new question.
I am making an FSM with VHDL. The simplest possible when valid = 1 change from stateA to stateB.
The confusing part is the rising edge selected by the blue rectangular. When valid = '1'. At the first rising edge, the state will be calculated to be B but it won't take effect until the next rising edge BUT what happened that it took effect at the FIRST rising edge.
Because the change in the state from A to B should affect other parts ( parallel process ) in the design in the NEXT cycle. From the waveform, If valid = '1' just before CLK_1.
At, CLK_1 all other processes should see state = A | waveform correct
output
state = A
enteredlastcycle = 0
At, CLK_2 all processes start seeing state = B. another parallel
process checks if state = B then it drives ENTERED_STATEB_LASTCYCLE to
be 1 waveform correct output
state = B
enteredlastcycle = 0
Then at CLK_3, waveform correct output
state = B
enteredlastcycle = 1
Do I misunderstand something?
Library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.KDlib.all;
entity nearestPoint is
generic ( ARRAY_WIDTH : integer := 8);
port (
clk: in std_logic;
reset: in std_logic;
inpoint: in kdvector;
valid: in std_logic;
finished: buffer std_logic
);
end nearestPoint;
architecture behave of nearestPoint is
signal state: two_state_type;
signal stateB_entered_lastCycle: std_logic;
begin
process ( clk )
begin
if ( reset = '1' ) then
elsif ( rising_edge(clk) ) then
case state is
when stateA =>
if ( valid = '1' ) then
state <= stateB;
end if;
when stateB =>
when others =>
end case;
end if;
end process;
process(clk)
begin
if ( reset = '1' ) then
elsif ( clk = '1' ) then
case state is
when stateA =>
when stateB =>
stateB_entered_lastCycle <= '1';
when others =>
end case;
end if;
end process;
end behave;
I will give you an explanation through a digital circuit prism. It is a way of thinking that you have to keep in mind when you develop VHDL.
Your valid is at 1 before the clock edge. You are in simulation so you can imagine that all your computations are instant. At the input of your flipflop the new value of your state is already calculated.
I am used to code with only one sequential process and one or more combinational process. Maybe you will understand better with this code with same functionnality than yours (a bit simplified) :
SEQ : process(clk, rst)
begin
if rst = '1' then
current_state <= '0';
elsif rising_edge(clk) then
current_state <= next_state;
end if;
end process SEQ;
Circuit corresponding to this code :
COMB : process(current_state, valid)
begin
next_state <= current_state; -- Default value to ensure that next_state will always be affected
if current_state = '0' and valid = '1' then
next_state <= '1';
end if;
end process COMB;
Circuit correspondint to this code :
If we consider that when valid changes next_state is refreshed instant, current_state (state in your code) goes high on the very next clock rising edge.
Hope you will understand, if you need more precision, don't hesitate to ask, I can edit my post or answer in comments.
Important note : If you have an asynchronous reset in your sequential process, it has to be in sensitivity list.
VHDL has no concept of blocking/non-blocking assignments. There are signals and variables and they are assigned differently.
In your case, you need to remember that simulation runs on a series of delta cycles. 1 delta is an infinitely small space of time, but they happen sequentially. A signal assignment doesn't take effect until the end of the delta, so state = B in the delta cycle after the rising edge of the clock. The 2nd process is sensitive only the clock, so it cannot update stateB_entered_lastcycle until the clock rises again.
I am working on a Program Counter that must be added 4 in each rising edge of a clk:
Code:
if_CounterSum <= MemAddr + 4;
process (Clk, Reset)
begin
if Reset = '1' then
MemAddr <= (OTHERS => '0');
elsif rising_edge(Clk) then
MemAddr <= if_CounterSum;
end if;
end process;
When simulating in ISIM,
After Reset is set to 0:
Initial state:
MemAddr = 0 (0000)
if_CounterSum = 4 (0100)
First CLK rising_edge:
MemAddr = X (0X00)
if_CounterSum = X (XXXX)
I have been working on this "simple" thing for some hours, I have tried:
Change the +4 line to synchronous too (Into the process) but problem kept.
Some other stuff that didn't worked.
How can I fix that X? I have tested other numbers instead of 4 and as I guessed all '1's in if_CounterSim where converted in 'X's after the assignment.
You have not included all of the code, so below is a guess.
The problem is probably a result of VHLD resolution of the signal, whereby multiple conflicting drivers of the same signals as for example both '0' and '1' will result in 'X', but where two drivers of '0' will result in '0'.
So look for all places in the module where MemAddr and if_CounterSum are assigned, and remove those unnecessary assigns.
When assigning a signal outside a process you literally connect it to the right side of the arrow.
When assigning a signal inside a synchronous process you implement flip flops to assign a value to your signal on clock edges.
In your case, I suggest you put if_CounterSum <= MemAddr + 4; in your process. This way, the increment will be done at each clock rising edge.
process (Clk, Reset)
begin
if Reset = '1' then
MemAddr <= (OTHERS => '0');
elsif rising_edge(Clk) then
MemAddr <= MemAddr + 4;
end if;
end process;
If you really need the if_CounterSum you can add if_CounterSum <= MemAddr outside the process this time (because it would be wired).
I have this signal that should be zero until another signal Start = 0. How can I accomplish this? Here is the relevant code:
din<=0;
wait until falling_edge(start);
for i in 0 to 63 loop
wait until clk = '1' and clk'event;
if i = 0 then
Start <= '1','0' after clk_period;
end if;
if (i < 24) then
din <= 255;
elsif (i > 40) then
din <= 255;
else
din <= 0;
end if;
end loop;
wait;
I thought I could just make din = 0 until the falling edge of start but it stops at the rising edge of start. I want to start reading the din values when start =0. Before that din = 0.
Here is a pic:
EDIT: Actually I got it to start at the correct signal values but the dout value always has an intermediate value that isn't necessary. In this case its 78450. I know this has to do with the testbench code but I can't get it to just calculate the correct value at the correct time. What changes can be made to the code below to get rid of the intermediate value?
din<=0;
for i in 0 to 63 loop
wait until clk = '1' and clk'event;
if i = 0 then
Start <= '1','0' after clk_period;
elsif (i < 24) then
din <= 255;
elsif (i > 40) then
din <= 255;
else
din <= 0;
end if;
end loop;
First of all I assume (and hope) you are writing a testbench. If not, you should avoid using wait statements, as these have very limited support in synthesis tools.
Even in a testbench, it is best to use time-based wait or after statements only to generate the clock, and make all other signals dependent on an event (e.g. rising_edge(clk)). This avoids the problem of having multiple signals changing during delta cycle 0 along with the clock.
Consider the following code for a typical register:
process(clk) begin
if(rising_edge(clk)) then
a <= b;
end if;
end process;
and assume that clk and b are generated in a testbench as follows:
clk <= not clock after 1 ns;
process begin
b <= '1', '0' after 10 ns;
wait;
end process;
At time 0 delta 0, clk changes to '1' and b would change to '1'.
At time 0 delta 1, the register process would run since clk changed, and a would change to '1'.
No further sensitivity exists, so time would update to the next event at 1 ns.
At time 1 delta 0, clk changes to '0'.
At time 1 delta 1, the register process is run since clk changed, but nothing happens because rising_edge(clk) is false.
The above repeats for time 2-9 ns.
At time 10 delta 0, clk changes to '1' and b changes to '0'. Note that clk and b change in the same delta cycle.
At time 10 delta 1, the register process runs and a changes to '0'! As far as the result is concerned, this means that b changed before the rising clock edge!
Even if this behavior is understandable in this simple system, it can lead to some incredibly difficult to find simulation bugs. It is therefore better to base all signals off of the appropriate clock.
process begin
-- Initialize b to 1.
b <= '1';
-- Wait for 5 cycles.
for i in 1 to 5 loop
wait for rising_edge(clk);
end loop;
-- Set b to 0.
b <= '0';
-- Done.
wait;
end process;
This avoids unexpected behavior, since all signals will change at least one delta cycle after the associated clock, meaning causality is maintained throughout all of your processes.
I have this signal that should be zero until another signal Start = 0. How can I accomplish this?
Maybe you can use a handshake signal and put it in the sensitive list of the process. It will behave like a reset signal.
process (handshake_s, ...)
begin
if (handshake_s = '1') then -- failing edge of start
din <= 0;
else
-- do something
end if;
end process;
Use another process to update handshake_s.
process (start, ...)
begin
if failing_edge(start) then
handshake_s <= '1', '0' after 10 ns; -- produce a pulse
end if;
-- do something
end process;
Would you mind post all your code here so that we could understand the waveform better?
Testbench or RTL code?
For a testbench, your coding style is mostly ok, however, your signal Start has a problem and will never be '1' during a rising edge of clock. It goes to '1' just after the rising edge of clock and will return to '0' either simultaneously with clock or 1 delta cycle before clock (depending on your clock setup). Either way, anything running on rising_edge clock, such as your design, will not see it as a '1'.
A simple way to avoid this is to use nominal delays (25% of tperiod_Clk) on all of your testbench outputs that go to the DUT (Device Under Test). The pattern for a pulse is as follows.
wait until clk = '1' ; -- I recommend using rising_edge(Clk) for readability
Start <= '1' after tpd, '0' after tpd + tperiod_clk ;
Alternately, you can avoid this issue by not using waveform assignments. Such as the following. In this case, you don't need the tpd, however, if it really is a testbench, I recommend using it.
wait until clk = '1' ;
if i = 0 then
Start <= '1' after tpd ;
else
Start <= '0' after tpd ;
end if ;
For RTL code, you need to explore a different approach. Very briefly one way to approach it is as follows. Note do not use any delays, waveform assignments, or loops.
-- Counter to count from 0 to 63. Use "+ 1". Use "mod 64" if using type integer.
-- Start logic = decoder (can be coded separately)
-- Din Logic = decoder (can be coded separately)