In my waveform diagram, I am wondering why my "rdy" value does not change to 1 after 400ns.
And why does my "d" value not output anything after the first two outputs? I've tried finding the error for hours but to no avail. Please help, thank you in advance.
Here is my waveform diagram:
And here is my main code.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
entity GCD is
port(st , clk: in std_logic; --clk temporarily taken out
d1, d2 : in std_logic_vector(7 downto 0);
dout : out std_logic_vector(7 downto 0);
rdy : out std_logic);
end GCD;
architecture behav of GCD is
type state is (S0, S1, S2, S3, S4, S5, S6, S7);
--temporary clk
--signal clk : std_logic;
signal new_state : state;
signal eq : boolean;
signal eq1 : boolean;
signal lt : boolean;
begin
--State transition
process is
variable curr_state : state:= S0;
begin
if clk = '1' then
case curr_state is
when S0 =>
if st = '1' then curr_state := S1;
end if;
when S1 =>
curr_state := S2;
when S2 =>
if eq and not lt then curr_state := S7;
elsif lt and not eq then curr_state := S4;
elsif not eq and not lt then curr_state := S3;
end if;
when S3 =>
curr_state := S4;
when S4 =>
curr_state := S5;
when S5 =>
if eq1 = true then curr_state := S7;
else curr_state := S6;
end if;
when S6 =>
curr_state := S1;
when S7 =>
if st = '0' then curr_state := S0;
end if;
end case;
new_state <= curr_state;
end if;
wait on clk;
end process;
--Asserted Output Process
process is
variable M, N, dout_val, tmp: std_logic_vector(7 downto 0);
variable rdy_val : std_logic;
variable lt_val, eq_val, eq1_val : boolean;
begin
rdy_val := '0';
case new_state is
when S0 =>
M := d1;
N := d2;
when S1 =>
if (to_integer(M) = to_integer(N)) then eq_val := true;
elsif (to_integer(M) < to_integer(N)) then lt_val := true;
end if;
when S2 =>
when S3 =>
M := N;
N := M;
when S4 =>
if (to_integer(M) = 1) then eq1_val := true;
end if;
when S5 =>
when S6 =>
N := (N - M);
when S7 =>
rdy_val := '1';
dout_val := M;
end case;
dout <= dout_val;
rdy <= rdy_val;
lt <= lt_val;
eq <= eq_val;
eq1 <= eq1_val;
wait on new_state;
end process;
end behav;
And here is my testbench:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use work.all;
entity test_GCD is
end test_GCD;
architecture testbench of test_GCD is
signal m, n ,d: std_logic_vector(7 downto 0);
signal clk, st, rdy : std_logic;
begin
--Component Instantiation
device : GCD
port map( clk => clk, st => st, d1 => m,
d2 => n, dout => d, rdy => rdy);
--Process to Generate Test Data
process is
begin
st <= '0';
wait for 10ns;
m <= "00001001"; --9 , 15
n <= "00001111";
wait for 10ns;
st <= '1';
wait until rdy = '1';
wait for 10ns;
st <= '0';
wait for 10ns;
m <= "00001111"; --15, 9
n <= "00001001";
wait for 10ns;
st <= '1';
wait until rdy = '1';
wait for 10ns;
st <= '0';
wait for 10ns; --15 , 14
m <= "00001111";
n <= "00001110";
wait for 10ns;
st <= '1';
wait until rdy = '1';
wait for 10ns;
st <= '0';
wait for 10ns;
m <= "00010010"; --18 , 36
n <= "00100100";
wait for 30ns;
st <= '1';
wait until rdy = '1';
wait for 10ns;
st <= '0';
wait for 10ns;
m <= "01011011"; --91 = 01011011 , 39 = 00100111
n <= "00100111";
wait for 10ns;
st <= '1';
--wait for 10ns;
wait until rdy = '1';
wait for 10ns;
st <= '0';
wait for 10ns;
m <= "01111111"; --127, 127
n <= "01111111";
wait for 10ns;
st <= '1';
wait until rdy = '1';
wait for 10ns;
wait;
end process;
process is
begin
clk <= '0', '1' after 15ns;
wait for 30ns;
end process;
end testbench;
You're the second one to ask a question here today with the same assignment.
In the third st/rdy set you've upset the timing relation:
st <= '0';
wait for 10ns;
m <= "00010010"; --18 , 36
n <= "00100100";
wait for 30ns;
st <= '1';
wait until rdy = '1';
wait for 10ns;
The previous two sets have wait for 10 ns. This one has 30 ns. What does that do?
You're state machine in the unlabelled state transition process is missing the st <= '1', because it's not looking for it when it occurs, add waveforms down in GCD, try new_state.
There's a fine balance between helping someone and doing their assignment for them.
addendum
Can you elaborate what you mean by I am missing the st<='1' in my state transition? I've declared st as a std_logic so I can't use the "<=" assignment for it. Do you mean I am missing the st<='1' in my testbench?
The idea was to get you to look at the operation of the state machine spread across two unlabelled processes.
Your state machine is operating on the positive clock edge even though your code is not written to be synthesis eligible. The process is driven by only one event, clk and the expression clk = '1'is evaluated in the first if statement condition.
if you add new_state to your waveform dump (show it in the waveform display):
(you can open the image in a separate tab or window, it's a link to itself)
(And notice the first GCD 'answer' is all U's. The second 'answer' also doesn't appear to be the greatest common denominator between 15 and 9, either.)
You'll see your state machine quits transitioning, remaining stuck in S2 which evaluates ltand eqbut doesn't modify them in the Asserted Output Process (and you could use labels instead of comments, any statement can be labelled in VHDL).
We look to the previous state S1, where eq_val and lt_val are assigned. They are dependent on M and N, which are assigned from d1 and d2 in S0.
Back in S2 notice:
when S2 =>
if eq and not lt then
curr_state := S7;
elsif lt and not eq then
curr_state := S4;
elsif not eq and not lt then
curr_state := S3;
end if;
And if you look at eq and lt in the above waveform you see they are both true. How can that be? There is to transition condition for that, you stick in S2.
So how can both conditions be true at the same time?
when S1 =>
if (to_integer(M) = to_integer(N)) then
eq_val := true;
elsif (to_integer(M) < to_integer(N)) then
lt_val := true;
end if;
You are only assigning one of them.
However, the other one remains in it's previous state, latched by new_state.
As a short term demonstration I assigned eq_val and lt_val both false right before they are evaluated. That will leave at most only one true.
Unfortunately that reveals another flaw in your design:
And that's not the subject of your question.
You appear to use a Euclid (GCD) algorithm shown in the flow chart (figure 1) in the PDF found in the link. The Boolean types appears to be an assignment requirement (the other student used them as well). The resulting VHDL expresses this algorithm with at least one more error.
You use N as an accumulator in finding the GCD, and you also change the contents of M. N has three sources, d2, the result of N-M in S6 and swappingMandNinS3(which has the effect of assigningNtoM, andN` to itself, variable assignment is immediate). M and N should be signals, or you need an intermediary value to swap through. (They should be signals).
You can use your waveform display to troubleshoot your design. You should also be aware when you are inferring latches, which occur when you have conditional assignments without the equivalent of an 'else'.
The open source tools I used looking at your design (ghdl and gtkwave) don't capture variables in waveform dumps. I'd suspect DesignWorks 5 doesn't either (and could be wrong).
The impact of this is you can't see what the data is doing during the simulation. Your design is small enough you could have used signals throughout without impacting simulation time significantly. Assigning to eq and lt directly in S1 would require else assignments (false). If you're required to use variables for the assignment you can assign them to signals so they are visible, should DesignWorks 5 not display variables. Once you're done you can remove the signals.
The answer to Why doesn't my “rdy” value change to 1? is that you have inferred latches creating a case you don't detect for branching out of S2.
Once you straighten out the M and N swap in S3 it looks like it may have a good chance or working (there could be another gotcha or two in there).
And when you use tmp to hold the value of M (not using signals):
when S3 =>
tmp := M;
M := N;
N := tmp;
You start getting the right answers:
Without seeing the handout you were given for your project I'd anticipate you worked from pseudo code like found in the linked PDF's figure 1. It may have been written in the anticipation of the use of signals.
Related
While implementing a state machine on VHDL I was wondering how can I set the output / current state initial condition. I read on one of the questions on here.
One of the answers said we do the initialization before the case structure:
process(currentstate, a)
begin
b <= '1';
c <= '1';
case currentstate is
when s1 =>
if (a = '1') then
c <= '0';
end if;
nextstate <= s2;
However doesn't that make us automatically set b<='1' and c<='1' whenever we get into the process? So if we are at a state say A and we are at the conditions of moving to B whenever we enter the process this directly puts b<='1' and c<='1' isn't that true ?
Or does it actually just run once we start the program and then gets bounded in the case structure ?
Also check this link.
In their FSM implementation they did not specify the initial state how does the compiler or FPGA determine the start state ?
The lines you are looking at are not performing initialization.
b <= '1';
c <= '1';
Remember that VHDL is a hardware description language, not a programming language. What those two assignments do is to set a default assignment for those signals, unless something else contradicts these assignments later in the process. You can assign to the same signal several times in one process, and whichever assignment happens last will take priority. This saves having to write code like:
case State is
when s1 =>
a <= '0';
b <= '1';
c <= '1';
when s2 =>
a <= '1';
b <= '0';
c <= '1';
when s2 =>
a <= '1';
b <= '1';
c <= '0';
end case;
It can end up being quite repetitive and error prone to have the same assignments in many states, so default assignments can really tidy it up:
a <= '1';
b <= '1';
c <= '1';
case State is
when s1 =>
a <= '0';
when s2 =>
b <= '0';
when s2 =>
c <= '0';
end case;
The same pattern works for if statements where you don't want to cover every output signal in every logical branch.
If you want an initial state, there are two approaches that may be applicable depending on the scenario. Here you would assert reset at start-up to set the initial state. Note that the case statement is inside a clocked process:
process (clk)
begin
if (rising_edge(clk)) then
if (reset = '1') then
State <= s1;
else
case State is
when s1 =>
State <= s2;
when s2 =>
State <= s1;
end case;
end if;
end if;
end process;
The other option is to define your state signal with an initial value:
signal State : state_type := s1;
I won't go into the pros and cons of using initial values as there are existing questions that explore this.
Right now i'm working on a project concerning the use of D Flip Flop on Falling Edge, with x and y being the inputs and z being the output.
The Circuit will only give z ='1' only if x and y are both 0 and also if they were both 0 in a previous clock cycle, and the transitions only occurring in the clock's falling edge.
Variables a and b will represent states Q0(a) and Q1(b).
The Mealy machine is of two states : Q0 and Q1, and the transations are as follow:
Q0
x y z
0 0 1
0 1 x
1 0 0 --> goes to next state (Q1)
1 1 x
Q1
x y z
0 0 0 --> goes to next state (Q0) only this time z='0'
0 1 x
1 0 x
1 1 0 --> stays in current state (Q1)
The problem is that when the transition from Q1 to Q0 happens, z is still '1' instead of '0'.
Is there any advice on how could i manage to get around that fast transition?
Here is the code so far:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Mealys is
Port (
inicio: in std_logic;
clk: in std_logic;
x: in std_logic;
y: in std_logic;
z: out std_logic;
a: out std_logic;
b: out std_logic
);
end Mealys;
architecture behavior of Mealys is
type nombres_estados is (Q0, Q1);
signal estado: nombres_estados;
signal entrada_aux: std_logic_vector (1 downto 0);
begin
entrada_aux <= x & y;
FF_D: process (clk)
begin
if (inicio = '1') then
estado <= Q0;
elsif falling_edge(clk) then
case estado is
when Q0 =>
case entrada_aux is
when "00" => estado<=Q0;
when "10" => estado<=Q1;
when others => estado<=Q0;
end case;
when Q1 =>
case entrada_aux is
when "00" => estado<=Q0;
when "11" => estado<=Q1;
when others => estado<=Q1;
end case;
when others => estado<=Q0;
end case;
end if;
end process;
next_decode: process(estado, entrada_aux)
begin
case (estado) is
when Q0 =>
a <= '1';
b <= '0';
if entrada_aux <= "00" then
z<='1';
elsif entrada_aux <= "10" then
z<='0';
end if;
when Q1 =>
a <= '0';
b <= '1';
if entrada_aux <= "00" then
z<='0';
elsif entrada_aux <= "11" then
z<='0';
end if;
end case;
end process;
end behavior;
And here is the state diagram
Thank you for you time.
I assume that you are learning VHDL, that you are starting with the VHDL subset for synthesis and that the final goal is to synthesize your design.
Your design comprises two processes: a synchronous one and a combinatorial one. Both are bogus for synthesis.
Your synchronous process does not correctly handle the reset. If your reset is asynchronous (that is, is taken into account immediately when asserted), it should be in the sensitivity list:
process(clk, inicio)
begin
if inicio = '1' then
<initialize things>
elsif falling_edge(clk) then
<do things>
end if;
end process;
And if it is synchronous (that is taken into account only on the clock falling edge), it should not be in the sensitivity list but the reset part of your process should be under the scope of the clock edge test:
process(clk)
begin
if falling_edge(clk) then
if inicio = '1' then
<initialize things>
else
<do things>
end if;
end if;
end process;
Your combinatorial process has 3 outputs: a, band z. They must all be assigned a value during any execution of the process. This is what combinatorial means: each time an input changes, the signals propagate and all outputs finally get a new value. The new value can be the same as the previous one but this must be by accident, not because the output has not been assigned. Else, it would mean to a synthesizer: "keep the previous value", which usually leads to the inference of latches to store the previous value... Not what you want in a true combinatorial process. In your process, when estado or entrada_aux change, a and b are assigned but not always z (I let you understand why).
There is another problem in this process: the equality test operator is =, not <= which is the less or equal test operator. Note that your code should not even compile as it is.
It is not easy to propose a fixed version of this process because your specification is not 100% clear. What do these x mean in the transition table? For instance, what happens to z if we are in state Q0 and xy is 01 or 11? If the answer is "z does not change", then its computation must involve a memory element and you must describe this in your synchronous process. Else, if it means "z takes any value" (we don't care), then you must decide yourself before coding and add this to your combinatorial process (for instance with an else statement).
I will assume that it means "z does not change". So, you need a memory element (a D-flip-flop) to store the previous value. Add another signal (previous_z) and assign it in your synchronous process:
signal previous_z: std_logic:
...
process(clk, inicio)
begin
if inicio = '1' then
previous_z <= '0';
<initialize other things>
elsif falling_edge(clk) then
previous_z <= z;
<do other things>
end if;
end process;
There is a potential problem here because we are reading the value of z which is an output port of your entity. In VHDL versions previous 2008 this was forbidden. If you are using a pre-2008 version of VHDL you must declare another internal signal (local_z) that you can read and assign, use it everywhere, and assign it to the output z, for instance in a concurrent signal assignment (outside any process):
signal previous_z: std_logic:
signal local_z: std_logic:
...
process(clk, inicio)
begin
if inicio = '1' then
previous_z <= '0';
<initialize other things>
elsif falling_edge(clk) then
previous_z <= local_z;
<do other things>
end if;
end process;
z <= local_z;
Now, you can use this previous_z signal in your combinatorial process to compute local_z (or z in VHDL 2008):
next_decode: process(estado, entrada_aux, previous_z)
begin
case estado is
when Q0 =>
a <= '1';
b <= '0';
if entrada_aux = "00" then
local_z <= '1';
elsif entrada_aux = "10" then
local_z <= '0';
else
local_z <= previous_z;
end if;
when Q1 =>
a <= '0';
b <= '1';
if entrada_aux = "00" then
local_z <= '0';
elsif entrada_aux = "11" then
local_z <= '0';
else
local_z <= previous_z;
end if;
end case;
end process;
Note that previous_z must be added to the sensitivity list. Do you see now how the local_z output of the process will always be assigned?
There is an even better option which consists in assigning a default value to each output, unconditionally, at the beginning of the process and change this if and only if needed:
next_decode: process(estado, entrada_aux, previous_z)
begin
a <= '0':
b <= '0';
local_z <= previous_z;
case estado is
when Q0 =>
a <= '1';
if entrada_aux = "00" then
local_z <= '1';
elsif entrada_aux = "10" then
local_z <= '0';
end if;
when Q1 =>
b <= '1';
if entrada_aux = "00" then
local_z <= '0';
elsif entrada_aux = "11" then
local_z <= '0';
end if;
end case;
end process;
This works because, in a combinatorial process, when a signal is assigned several times, it is the last assignment that wins. And this coding style has a good property: you cannot forget to assign an output.
There is another good option: concurrent signal assignments (outside any process):
a <= '1' when estado = Q0 else '0';
b <= '1' when estado = Q1 else '0';
local_z <= '1' when estado = Q0 and entrada_aux = "00" else
'0' when estado = Q0 and entrada_aux = "10" else
'0' when estado = Q1 and entrada_aux = "00" else
'0' when estado = Q1 and entrada_aux = "11" else
previous_z;
Concurrent signal assignments, when the logic is simple enough, are maybe even better than the two other options because there is no need to worry about sensitivity lists and always assigning the outputs. Probably very good points, at least for beginners.
One last remark: you use the std_logic resolved type without any good reason. This is unfortunate and error prone. You should use std_ulogic, its unresolved parent type instead (u for Unresolved). But this is out of scope your question.
I am developing a state machine in VHDL and it doesn't' seem to be functioning properly. The design is shown below:
SHARED VARIABLE XM_INDEX : NATURAL RANGE 0 TO 99 := 0;
SIGNAL XM_STATE_INDICATOR : STD_LOGIC_VECTOR (7 DOWNTO 0) := "00000000";
TYPE XM_STATE_TYPE IS (EMPTY, IDLE, POWER_UP, POWER_UP_CONFIRM,
CHANNEL_SELECT, CHANNEL_SELECT_CONFIRM, VOLUME_CHANGE,
VOLUME_CHANGE_CONFIRM, TRANSMIT_CHAR, TRANSMIT_CHAR_CONFIRM,
COMPLETED);
SIGNAL XM_CURRENT_STATE : XM_STATE_TYPE := EMPTY;
SIGNAL XM_NEXT_STATE : XM_STATE_TYPE := EMPTY;
XMStateMachineClock: PROCESS (CLK25, SYS_RST) IS
BEGIN
IF (SYS_RST = '1') THEN
XM_CURRENT_STATE <= EMPTY;
ELSIF (RISING_EDGE(CLK25)) THEN
XM_CURRENT_STATE <= XM_NEXT_STATE;
END IF;
END PROCESS XMStateMachineClock;
XMStateMachine: PROCESS (XM_CURRENT_STATE) IS
BEGIN
-- Pend on current XM state
CASE XM_CURRENT_STATE IS
-- Empty: Debug only
WHEN EMPTY =>
XM_NEXT_STATE <= IDLE;
XM_STATE_INDICATOR <= "00000001";
-- Idle: Idle state
WHEN IDLE =>
IF XM_POWER_UP = '1' THEN
XM_INDEX := 0;
XM_NEXT_STATE <= POWER_UP;
XM_STATE_INDICATOR <= "00000010";
ELSE
-- Remain in idle
XM_NEXT_STATE <= IDLE;
XM_STATE_INDICATOR <= "00000001";
END IF;
WHEN POWER_UP =>
XM_NEXT_STATE <= TRANSMIT_CHAR;
XM_STATE_INDICATOR <= "00000100";
WHEN TRANSMIT_CHAR =>
IF (XM_INDEX < 11) THEN
XM_NEXT_STATE <= TRANSMIT_CHAR_CONFIRM;
XM_STATE_INDICATOR <= "00001000";
ELSE
XM_NEXT_STATE <= COMPLETED;
XM_STATE_INDICATOR <= "00000000";
END IF;
WHEN TRANSMIT_CHAR_CONFIRM =>
XM_INDEX := XM_INDEX + 1;
XM_NEXT_STATE <= TRANSMIT_CHAR;
XM_STATE_INDICATOR <= "00000100";
WHEN COMPLETED =>
XM_NEXT_STATE <= COMPLETED;
XM_STATE_INDICATOR <= "00000000";
-- Default
WHEN OTHERS =>
END CASE;
END PROCESS XMStateMachine;
The state machine is being clocked at 25 MHz. Per my understanding, my state machine should progress between the states as follows:
However, what I see when I hook up my logic analyzer is the following:
It seems as if the state machine is only alternating between the transmit and transmit confirm states once, as opposed to the 11 times that is should, and I cannot figure out why.
If you make XM_INDEX a signal have an XM_INDEX_NEXT that is latched in your XMStateMachineClock process and then change XM_INDEX := XM_INDEX + 1 to XM_INDEX_NEXT <= XM_INDEX + 1. I believe that this will fix your issue. XMStateMachine will also need to be sensitive to XM_INDEX.
The example code isn't compete and there's some chance chaning xm_index from a shared variable might upset some plans for it's use, should more than one process write to it. You could note that the user is responsible for controlling exclusive access in -1993 shared variables.
Creating a MCVE by providing a complete entity and architecture pair:
library ieee;
use ieee.std_logic_1164.all;
entity xm_sm is
port (
clk25: in std_logic;
sys_rst: in std_logic;
xm_power_up: in std_logic
);
end entity;
architecture foo of xm_sm is
-- shared variable xm_index: natural range 0 to 99 := 0;
signal xm_index: natural range 0 to 99 := 0; -- CHANGED to SIGNAL
signal xm_index_nxt: natural range 0 to 99; -- ADDED
signal xm_state_indicator: std_logic_vector (7 downto 0) := "00000000";
type xm_state_type is (EMPTY, IDLE, POWER_UP, POWER_UP_CONFIRM,
CHANNEL_SELECT, CHANNEL_SELECT_CONFIRM,
VOLUME_CHANGE, VOLUME_CHANGE_CONFIRM,
TRANSMIT_CHAR, TRANSMIT_CHAR_CONFIRM,
COMPLETED);
signal xm_current_state: xm_state_type := EMPTY;
signal xm_next_state: xm_state_type := EMPTY;
begin
xmstatemachineclock:
process (clk25, sys_rst) is
begin
if sys_rst = '1' then
xm_current_state <= EMPTY;
xm_index <= 0; -- ADDED
elsif rising_edge(clk25) then
xm_current_state <= xm_next_state;
xm_index <= xm_index_nxt; -- ADDED
end if;
end process xmstatemachineclock;
xmstatemachine:
process (xm_current_state, xm_power_up) is
begin
-- pend on current xm state
case xm_current_state is
-- empty: debug only
when EMPTY =>
xm_next_state <= IDLE;
xm_state_indicator <= "00000001";
-- idle: idle state
when IDLE =>
if xm_power_up = '1' then
xm_index_nxt <= 0;
xm_next_state <= POWER_UP;
xm_state_indicator <= "00000010";
else
-- remain in idle
xm_next_state <= IDLE;
xm_state_indicator <= "00000001";
end if;
when POWER_UP =>
xm_next_state <= TRANSMIT_CHAR;
xm_state_indicator <= "00000100";
when TRANSMIT_CHAR =>
if xm_index < 11 then
xm_next_state <= TRANSMIT_CHAR_CONFIRM;
xm_state_indicator <= "00001000";
else
xm_next_state <= COMPLETED;
xm_state_indicator <= "00000000";
end if;
when TRANSMIT_CHAR_CONFIRM =>
if xm_index = 99 then -- protect again overflow -- ADDED
xm_index_nxt <= 0;
else
xm_index_nxt <= xm_index + 1; -- CHANGED
end if;
-- xm_index_nxt <= xm_index + 1;
xm_next_state <= TRANSMIT_CHAR;
xm_state_indicator <= "00000100";
when COMPLETED =>
xm_next_state <= COMPLETED;
xm_state_indicator <= "00000000";
-- default
when others =>
end case;
end process xmstatemachine;
end architecture;
This changes xm_index to a signal and including a next value as suggested by Alden in his answer. This works as long as there's only one process that writes to it. xm_index is also now set to 0 during reset. Additionally in the TRANSMIT_CHAR_CONFIRM of the xm_currrent_state case statement xm_index is protected against overflow as a matter of course. The range of xm_index (0 to 99) can be limited to the maximum value (11). It raises suspicions that we're not seeing all of the design.
Adding a test bench:
library ieee;
use ieee.std_logic_1164.all;
entity xm_sm_tb is
end entity;
architecture foo of xm_sm_tb is
signal clk25: std_logic := '0';
signal sys_rst: std_logic := '0';
signal xm_power_up: std_logic := '0';
begin
DUT:
entity work.xm_sm
port map (
clk25 => clk25,
sys_rst => sys_rst,
xm_power_up => xm_power_up
);
CLOCK:
process
begin
wait for 50 ns;
clk25 <= not clk25;
if now > 3.1 us then
wait;
end if;
end process;
STIMULI:
process
begin
wait for 100 ns;
sys_rst <= '1';
wait for 100 ns;
sys_rst <= '0';
wait for 200 ns;
xm_power_up <= '1';
wait for 100 ns;
xm_power_up <= '0';
wait;
end process;
end architecture;
and we get:
Where we see we go through all the index values before finishing.
The original code successfully simulated but appears to have not synthesized to a working design due to the combinatorical loop:
XM_INDEX := XM_INDEX + 1;
where xm_loop is latched by a presumably one hot state representation for state TRANSMIT_CHAR_CONFIRM as a latch enable.
In simulation the sensitivity list being devoid of xm_index would prevent the adder from ripple incrementing xm_index. If xm_index had been in the process sensitivity list it would caused a bounds check violation on assignment after reaching 100. (Integer types aren't modular, they don't wrap and aren't proofed against overflow).
In synthesis without seeing the console output we might presume that the ripply time is sufficient to push the value of xm_index above 11 reliably in one clock time without wrapping to less than 11.
My VHDL-Code is functionaly correct, in ModelSim every thing works fine. I tested it with many variations and the code is functionaly correct.
But when I put it on the Altera board it displays a "3" on the 7-segment display, but it should show "0".
If I put RESET to "1" it breaks completly and displays only a line in the top segment.
My Inputs X, CLK, RESET are connected to the switches.
LOAD ist connected to a button and DIGIT to the 7-segment display.
It should have a clock signal as I swtich the CLK-switch.
Here my full code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY seqdec IS
PORT ( X: IN std_logic_vector(15 DOWNTO 0);
CLK: IN std_logic;
RESET: IN std_logic;
LOAD: IN std_logic;
DIGIT: OUT std_logic_vector(6 DOWNTO 0) := "1111110";
Y: OUT std_logic);
END seqdec;
ARCHITECTURE SEQ OF seqdec IS
TYPE statetype IS (s0, s1, s2, s3, s4);
SIGNAL state: statetype:=s0;
SIGNAL next_state: statetype;
SIGNAL counter: std_logic_vector(2 DOWNTO 0) :="000" ;
SIGNAL temp: std_logic_vector(15 DOWNTO 0):= (OTHERS => '0');
SIGNAL so: std_logic := 'U';
-------------------Aktualisierung des Zustandes--------------------------------
BEGIN
STATE_AKT: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
state <= s0;
ELSIF CLK = '1' AND CLK'event THEN
state <= next_state ;
END IF;
END PROCESS STATE_AKT;
---------------------Counter---------------------------------------------------
COUNT: PROCESS (state, RESET)
BEGIN
IF (RESET = '1') THEN
counter <= (OTHERS => '0');
ELSIF (state = s4) THEN
counter <= counter + '1';
END IF;
END PROCESS COUNT;
-------------------PiSo für die Eingabe des zu Prüfenden Vektors---------------
PISO: PROCESS (CLK, LOAD, X)
BEGIN
IF (LOAD = '1') THEN
temp(15 DOWNTO 0) <= X(15 DOWNTO 0);
ELSIF (CLK'event and CLK='1') THEN
so <= temp(15);
temp(15 DOWNTO 1) <= temp(14 DOWNTO 0);
temp(0) <= '0';
END IF;
END PROCESS PISO;
-------------------Zustandsabfrage und Berechnung------------------------------
STATE_CAL: PROCESS (so,state)
BEGIN
next_state <= state;
Y <= '0';
CASE state IS
WHEN s0 =>
IF so = '1' THEN
next_state <= s0 ;
END IF;
WHEN s1 =>
IF so = '1' THEN
next_state <= s1;
END IF;
WHEN s2 =>
IF so = '0' THEN
next_state <= s3 ;
END IF;
WHEN s3 =>
IF so = '0' THEN
next_state <= s0 ;
ELSE
next_state <= s4 ;
END IF;
WHEN s4 =>
Y <= '1';
IF so = '0' THEN
next_state <= s0;
ELSE
next_state <= s2 ;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS STATE_CAL;
-------------------7 Segment---------------------------------------------------
SEVEN_SEG: PROCESS (counter)
BEGIN
CASE counter IS
WHEN "000" => DIGIT <= "1111110";
WHEN "001" => DIGIT <= "0110000";
WHEN "010" => DIGIT <= "1101101";
WHEN "011" => DIGIT <= "1111001";
WHEN "100" => DIGIT <= "0110011";
WHEN "101" => DIGIT <= "1011011";
WHEN OTHERS => NULL;
END CASE;
END PROCESS SEVEN_SEG;
END SEQ;
I am pretty new to VHDL and am pretty sure it hase to do something with the timings, cause the functional part should be fine, as already said.
Hope for some hints, tips or even solutions.
EDIT: new code without LOAD, is this a valid idea? (non the less the whole code is not working on the FPGA....)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY seqdec IS
PORT ( X: IN std_logic_vector(15 DOWNTO 0);
CLK: IN std_logic;
RESET: IN std_logic;
LOAD: IN std_logic;
DIGIT: OUT std_logic_vector(0 TO 6) := "0000001";
Y: OUT std_logic);
END seqdec;
ARCHITECTURE SEQ OF seqdec IS
TYPE statetype IS (s0, s1, s2, s3, s4);
SIGNAL state: statetype:=s0;
SIGNAL next_state: statetype;
SIGNAL counter: std_logic_vector(2 DOWNTO 0) :="000" ;
SIGNAL temp: std_logic_vector(15 DOWNTO 0):= (OTHERS => '0');
SIGNAL so: std_logic := 'U';
-------------------Aktualisierung des Zustandes--------------------------------
BEGIN
STATE_AKT: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
state <= s0;
ELSIF CLK = '1' AND CLK'event THEN
state <= next_state ;
END IF;
END PROCESS STATE_AKT;
---------------------Counter---------------------------------------------------
COUNT: PROCESS (state, RESET)
BEGIN
IF (RESET = '1') THEN
counter <= (OTHERS => '0');
ELSIF (state = s4) THEN
counter <= counter + '1';
END IF;
END PROCESS COUNT;
-------------------PiSo für die Eingabe des zu Prüfenden Vektors---------------
PISO: PROCESS (CLK, LOAD, X)
BEGIN
IF (CLK'event and CLK='1') THEN
IF (LOAD = '1') THEN
temp(15 DOWNTO 0) <= X(15 DOWNTO 0);
ELSE
so <= temp(15);
temp(15 DOWNTO 1) <= temp(14 DOWNTO 0);
temp(0) <= '0';
END IF;
END IF;
END PROCESS PISO;
-------------------Zustandsabfrage und Berechnung------------------------------
STATE_CAL: PROCESS (so,state)
BEGIN
next_state <= state;
Y <= '0';
CASE state IS
WHEN s0 =>
IF so = '1' THEN
next_state <= s1 ;
END IF;
WHEN s1 =>
IF so = '1' THEN
next_state <= s2;
END IF;
WHEN s2 =>
IF so = '0' THEN
next_state <= s3 ;
END IF;
WHEN s3 =>
IF so = '0' THEN
next_state <= s0 ;
ELSE
next_state <= s4 ;
END IF;
WHEN s4 =>
Y <= '1';
IF so = '0' THEN
next_state <= s0;
ELSE
next_state <= s2 ;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS STATE_CAL;
-------------------7 Segment---------------------------------------------------
SEVEN_SEG: PROCESS (counter)
BEGIN
CASE counter IS
WHEN "000" => DIGIT <= "0000001";
WHEN "001" => DIGIT <= "1001111";
WHEN "010" => DIGIT <= "0010010";
WHEN "011" => DIGIT <= "0000110";
WHEN "100" => DIGIT <= "1001100";
WHEN "101" => DIGIT <= "0100100";
WHEN OTHERS => DIGIT <= "0000001";
END CASE;
END PROCESS SEVEN_SEG;
END SEQ;
EDIT: This is now my version.
It will still show a "0" no matter what I do.
I would assume it has to do with the COUNT and counter.
should i realize this as synchronous too?
Is the numeric and unsigned really that big of a problem? We did it that way at university.
And will it work when i put LOAD onto a slide switch???
Best regards
Adrian
Your code has several problems. Btw. a running simulation does not mean your design is correct, because you can simulate actions which can not be implemented in hardware.
Here is a list of problems:
You can not use a switch button as a clock signal. Buttons are no clock source! Either you implement a signal cleanup circuit (at least a debounce circuit, which requires another clock) or you use you clk signal as an enable.
Moreover, each of your signals needs a debounce circuit if connected to external switch buttons or toggle buttons unless your test board has debounced buttons...
Your state machine has an init state (that's OK), but you must assign the state to state instead of next_state.
Your code uses std_logic_unsigned, which is obsolete. You should use numeric_std and the type unsigned for your counter signal.
Your code intoduces an additional register for COUT is this intended?
Your PISO process uses an asynchronous LOAD signal this is not supported in hardware (assuming an FPGA as target device).
Depending on your synthesis tool it's possible that it will not recognize a FSM because your case statement does not fit the pattern for FSMs.
Seeing a fixed output pattern can be causes by an FSM fault. If your synthesizer recognizes a FSM, you can go to the state diagram and identify false edges or false terminal states.
More ...
Your 7-segment decoder is a combinatorical process. It can not be reset.
Moreover, this process is not sensitive to CLK, just to counter. This cause a mismatch between simulation and hardware. (Synthesis ignores sensitivity lists)
If you fix this, your simulation should have another behavior and, if fixed, work as your hardware :).
The FSM
STATE_CAL : process(state, so)
begin
-- Standardzuweisungen
next_state <= state; -- Bleib im Zustand falls in CASE nichts abweichendes bestimmt wird
Y <= '0';
-- Zustandswechsel
CASE state IS
WHEN s0 =>
IF (so = '1' THEN
next_state <= s1;
END IF;
WHEN s1 =>
IF (so = '1') THEN
next_state <= s2;
END IF;
WHEN s2 =>
IF (so = '0') THEN
next_state <= s3;
END IF;
WHEN s3 =>
IF (so = '0') THEN
next_state <= s0;
else
next_state <= s4;
END IF;
WHEN s4 =>
Y <= '1'; -- Moore-Ausgabe
IF (so = '0') THEN
next_state <= s0;
else
next_state <= s2;
END IF;
END CASE;
END PROCESS;
Paebbels already described many issues of your code. Please check also the warnings of your synthesis tool. They often indicate where the synthesizer actually outputs different logic than you have described in VHDL.
I suspect you have made another two mistakes which are not directly related to VHDL:
Your 7-segment display control lines seem to be low-active because you see only one active segment when you press RESET. This matches the only zero in the vector "1111110" you assigned in this case (via reseting counter to "000").
But even in this case, the enlighted segment should be in the middle instead on the top. Thus, your pin assignments seem to be in the reverse order.
This project is about adding user's custom peripheral core to MicroBlaze project on FPGA board "spartan 6 lx9". Using ISE Design Suite 14.6 and EDK.
My problem is being not enough experienced in writing VHDL code. I'm still getting 1-bit unintentional latches on signals: "data_bits" and "latest_value" from <0> til <15>, even though I have used recommended coding style for signal's assignment. I have set default values, but no success... Assignment of signal in each branch of case statement is not an option, since I want to retain value especially for "data_bits" since this vector is being build from several clock cycles. I'm trying to solve this problem for several days.
My questions are:
How I can fixed latches problem in this finite-state machine design? --Answered
I would like to get feedback on my state-machine design, styling etc. --Answered, but there is new code
Any design advice for staying on one state for several clocks cycles, using counters or there is a better technique? --Still expecting some advice
Initial Source Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity adc_16bit is
port(
clk : in std_logic;
rst : in std_logic;
data_reg_out : out std_logic_vector(31 downto 0);
control_reg : in std_logic_vector(31 downto 0);
SDO : in std_logic;
SCK : out std_logic;
CONV : out std_logic
);
end adc_16bit;
architecture Behavioral of adc_16bit is
type adc_states is (idle, conversation, clocking_low, clocking_high, receiving_bit, update_data);
signal State, NextState : adc_states;
signal data_bits : std_logic_vector(15 downto 0) := (others => '0');
signal latest_value : std_logic_vector(15 downto 0) := (others => '0');
signal conv_cnt : integer range 0 to 501 := 0;
signal clk_cnt : integer range 0 to 14 := 0;
signal bit_cnt : integer range 0 to 17 := 0;
begin
----------------------------------------------------------------------------------------
-- State Machine Register
----------------------------------------------------------------------------------------
StateReg:
process(clk, rst)
begin
if(clk'event and clk = '1') then
if(rst = '0') then
State <= idle;
else
State <= NextState;
end if;
end if;
end process StateReg;
----------------------------------------------------------------------------------------
-- Signals Register
----------------------------------------------------------------------------------------
TimerReg:
process(clk, rst)
begin
if(clk'event and clk = '1') then
--!default
conv_cnt <= conv_cnt;
clk_cnt <= clk_cnt;
bit_cnt <= bit_cnt;
--latest_value <= latest_value;
--data_bits <= data_bits;
case State is
when idle =>
conv_cnt <= 0;
clk_cnt <= 0;
bit_cnt <= 0;
when conversation =>
if(conv_cnt = 501) then
conv_cnt <= 0;
else
conv_cnt <= conv_cnt + 1;
end if;
when clocking_low =>
if(clk_cnt = 14) then
clk_cnt <= 0;
else
clk_cnt <= clk_cnt + 1;
end if;
when clocking_high =>
if(clk_cnt = 14) then
clk_cnt <= 0;
else
clk_cnt <= clk_cnt + 1;
end if;
when receiving_bit =>
if(bit_cnt = 16) then
bit_cnt <= 0;
else
bit_cnt <= bit_cnt + 1;
end if;
when update_data =>
end case;
end if;
end process TimerReg;
----------------------------------------------------------------------------------------
-- FSM Logic
----------------------------------------------------------------------------------------
FSM_Proc:
process(State, control_reg, conv_cnt, clk_cnt, bit_cnt )
begin
case State is
when idle =>
if(control_reg(0) = '1') then
NextState <= conversation;
else
NextState <= idle;
end if;
when conversation =>
if(conv_cnt = 500) then
NextState <= clocking_low;
else
NextState <= conversation;
end if;
when clocking_low =>
if(clk_cnt = 13) then
NextState <= clocking_high;
else
NextState <= clocking_low;
end if;
when clocking_high =>
if(clk_cnt = 13) then
NextState <= receiving_bit;
else
NextState <= clocking_high;
end if;
when receiving_bit =>
if(bit_cnt = 15) then
NextState <= update_data;
else
NextState <= clocking_low;
end if;
when update_data =>
if(control_reg(0) = '1') then
NextState <= conversation;
else
NextState <= idle;
end if;
end case;
end process FSM_Proc;
----------------------------------------------------------------------------------------
-- FSM Output
----------------------------------------------------------------------------------------
FSM_Output:
process(NextState, latest_value, data_bits, bit_cnt, SDO )
begin
--!default
CONV <= '0';
SCK <= '0';
data_reg_out(31 downto 16) <= (others => '0');
data_reg_out(15 downto 0) <= latest_value;
--data_bits <= data_bits;
--latest_value <= latest_value;
case NextState is
when idle =>
latest_value <= (others => '0');
data_bits <= (others => '0');
when conversation =>
CONV <= '1';
when clocking_low =>
SCK <= '0';
when clocking_high =>
SCK <= '1';
when receiving_bit =>
SCK <= '1';
--data_bits <= data_bits;
data_bits(bit_cnt) <= SDO;
when update_data =>
latest_value <= data_bits;
when others =>
--latest_value <= latest_value;
--data_bits <= data_bits;
end case;
end process FSM_Output;
end Behavioral;
EDIT
Thank you for all your responses! I decided to rewrite my FSM on single process and to add more information regarding my problem in order to make it more understandable for others who has similar problems!
Block Diagram of system:
http://i.stack.imgur.com/odCwR.png
Note: that right now I just want to simulate and verify stand alone adc_core itself without MicroBlaze and AXI interconnection block.
FSM Diagram:
http://i.stack.imgur.com/5qFdN.png
Single process source code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity adc_chip_driver is
port(
clk : in std_logic;
rst : in std_logic;
data_reg_out : out std_logic_vector(31 downto 0);
control_reg : in std_logic_vector(31 downto 0);
SDO : in std_logic;
SCK : out std_logic;
CONV : out std_logic
);
end adc_chip_driver;
architecture Behavioral of adc_chip_driver is
type states is (idle, conversation, clocking_low, clocking_high, receiving_bit, update_data);
signal state : states;
signal data_bits : std_logic_vector(0 to 15) := (others => '0');
signal latest_value : std_logic_vector(15 downto 0) := (others => '0');
signal conv_cnt : integer range 0 to 500 := 0;
signal clk_cnt : integer range 0 to 13 := 0;
signal bit_cnt : integer range 0 to 15 := 0;
begin
process(clk, rst, control_reg)
begin
if(rst = '0') then
state <= idle;
data_bits <= (others => '0');
latest_value <= (others => '0');
data_reg_out <= (others => '0');
elsif(clk'event and clk = '1') then
--!Default Values
data_reg_out(31 downto 16) <= (others => '0'); --unused bits of register
data_reg_out(15 downto 0) <= latest_value; --data_reg_out is always tided to latast_value;
latest_value <= latest_value; --latest_value is being updated only once
data_bits <= data_bits; --has to retain value
conv_cnt <= conv_cnt;
clk_cnt <= clk_cnt;
bit_cnt <= bit_cnt;
case state is
when idle =>
--signals
conv_cnt <= 0;
clk_cnt <= 0;
bit_cnt <= 0;
--outputs
SCK <= '0';
CONV <= '0';
--logic
if(control_reg(0) = '1') then
state <= conversation;
else
state <= idle;
end if;
when conversation =>
--output
SCK <= '0';
CONV <= '1';
--logic
if(conv_cnt = 500) then
state <= clocking_low;
conv_cnt <= 0;
else
state <= conversation;
conv_cnt <= conv_cnt + 1;
end if;
when clocking_low =>
--ouput
SCK <= '0';
CONV <= '0';
--logic
if(clk_cnt = 13) then
clk_cnt <= 0;
state <= clocking_high;
else
clk_cnt <= clk_cnt + 1;
state <= clocking_low;
end if;
when clocking_high =>
--ouput
SCK <= '1';
CONV <= '0';
--logic
if(clk_cnt = 13) then
clk_cnt <= 0;
state <= receiving_bit;
else
clk_cnt <= clk_cnt + 1;
state <= clocking_high;
end if;
when receiving_bit =>
--signal
data_bits(bit_cnt) <= SDO;
--ouput
SCK <= '1';
CONV <= '0';
--logic
if(bit_cnt = 15) then
bit_cnt <= 0;
state <= update_data;
else
bit_cnt <= bit_cnt + 1;
state <= clocking_low;
end if;
when update_data =>
--signal
latest_value(15 downto 0) <= data_bits(0 to 15);
--ouput
SCK <= '0';
CONV <= '0';
--logic
if(control_reg(0) = '1') then
state <= conversation;
else
state <= idle;
end if;
end case;
end if;
end process;
end Behavioral;
Maybe I could receive some new feedback on single process design?
Also I still do you have unanswered question regarding usage of counters in specific FSM states. I have noticed that usually during second cycle on "clocking_low" and "clocking_high" counter actually starts at 1 instead of 0, I know that in this situation it's not a problem, but I can easily imagine where it could be important. I was thinking about after reset set counters to '-1', but maybe there is better solution?
Your code has a number of problems. To illustrate some of them, I tried to sketch your finite state machine in Figs. 1 and 2 below, based on the VHDL code that you provided.
First and most importantly, the design should begin with a top-level block diagram, showing the circuit ports (as in Fig. 1), followed by a detailed state transition diagram (as in Fig. 2 – incomplete here). Recall, for example, that the circuit outputs (data_reg_out, SCK, and CONV – Fig. 1) are the signals that the FSM is supposed to produce, so it is indispensable that these values be specified in all states (shown inside the state circles in Fig. 2). Once the diagram of Fig. 2 is fixed and completed, writing a corresponding VHDL code should be relatively straightforward (except for the timer - see comments below).
Other problems can be seen directly in the code. Some comments on the four processes follow.
The first process (StateReg), which stores the FSM state, is fine.
The second process (TimerReg) is also registered (under clk’event), which is necessary to build the timer. However, dealing with timers is one of the trickiest parts of any timed FSM, because you MUST devise a correct strategy for stopping/running the timer and also for zeroing it. For this, I suggest that you check reference 1 below, which deals with all possible kinds of FSM implementations from a hardware perspective, including an extensive study of timed FSMs.
The third process (FSM_Proc) defines the next state. It is not registered, which is as it should be. However, to check it, it is necessary to complete first the state transition diagram of Fig. 2.
The last process (FSM_Output) defines the machine outputs. It is not registered, which is as it should be in general. However, the list of outputs is not the same in all states, in spite of the default values. Note, for example, the existence of latest_value and data_bits in state idle, which do not appear in all states, thus causing the inference of latches. Additionally, this process is based on NextState instead of PresentState, which (besides being awkward) might reduce the circuit’s maximum speed.
I hope these comments motivate you to restart from the beginning.
1 V. A. Pedroni, Finite State Machines in Hardware: Theory and Design (with VHDL and SystemVerilog), MIT Press, Dec. 2013.
You get a latch if a signal is not assigned to on all possible paths, as it then becomes stateful.
To avoid the problem, make sure you always assign a value to the signal (one way is to assign a "default" value at the top of the process).
since I want to retain value especially for "data_bits" since this vector is being build from several clock cycles.
"Retaining a value" means state, not purely combinatorial logic. In which case, it should not be in your output process. It should be in your state-update process.
My solution to this has been to always use clocked processes for everything. There is no need to have a separate clocked process for the state register and a separate process for the state transitions. That's a style which was required years ago. In my opinion, you are better off putting everything into a single clocked process and then you cannot get latches.
If you must use two processes then get a VHDL 2008 compiler and use process(all) to ensure that all your signals are correctly in the sensitivity list, and then carefully ensure that every signal you assign to gets an assignment for every logical path through the process. The easiest way to achieve this is often to assign them all some 'default' values at the start of the process.
In a combinational process (like FSM_Output), you should never read a signal and write to the same signal. That is exactly what is going on here, for latest_value and data_bits.
Either create new signals latest_value_r and data_bits_r and copy the values in the clocked process, or stick to a single clocked process with no separate combinational process.
What hardware do you want for data_bits and latest_value? If you want to build a vector over several clock cycles, then you need a storage device. Your choices are: latch (level sensitive storage) and flip-flop (edge sensitive storage). If you don't want latches, then you must code flip-flops.
To code flip-flops use the "if clk='1' and clk'event then", just like you did in TimerReg process. You can alternatively use "if rising_edge(Clk) then" - I like this better for readablity, but the tools don't care either way.
I think where you went wrong is in your planning process. Code is just design capture. What is important is that you plan with a block diagram and know where your design requires flip-flops and where it requires combinational logic. Get this right and the rest is just applying coding templates. So make sure you understand this before you start coding.
It does not matter whether you code with only clocked processes or use a mix of clocked and combinational logic processes. I think the most important thing you do in your coding is make it readable. If you collect opinions, you will see they vary, #Martin and #Brian prefer a single clocked process. I prefer a 2 process statemachine - flip-flop and combinational (present state to next state and ouput decode). You used a 3 process statemachine - for me that is like drawing a bubble diagram to show state transitions and a separate one to show the output transitions. However at the end of the day, they all capture the same intent. As long it is clear to someone reading your code long after you have left, it should be ok.