How can I make this VHDL code synthesizable? - vhdl

I have VHDL code that uses havily the fallowing syntax:
signal_1 <= (others => '0') when cau_state = st_idle else
signal_2 - signal_3 when cau_state = st_cycle_1 else
signal_4 when cau_state = st_cycle_2 else
signal_5 when cau_state = st_cycle_3 else
signal_6 when cau_state = st_cycle_4 else
signal_1;
Where cau_state is a signal that holds the current state. This syntax worked in simulation on Model-Sim and everything worked fine. But when I wanted to burn the code to an FPGA, the code didn't synthesize on Altera Quartus II 32-bit ver. 12.1 And I got the fallowing error messages:
Warning (13012): Latch CAU:uut|cross_3_sig[0][31] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal CAU:uut|cau_state.st_cycle_2
Warning (13012): Latch CAU:uut|cross_3_sig[0][30] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal CAU:uut|cau_state.st_cycle_2
I get these messages for many signals, but NOT for all the signals that are using this syntax. And for a signal that get this message I get it for all its bits: cross_3_sig[0][31] to cross_3_sig[0][0]. The syntax for the signal cross_3_sig(0) is:
constant WIDTH : integer := 32;
...
subtype scalar is std_logic_vector((WIDTH-1) downto 0);
type vector_nd is array (natural range <>) of scalar;
subtype vector_3d is vector_nd(2 downto 0);
...
signal cross_3_sig : vector_3d;
...
cross_3_sig(0) <= sum_mults_out_sig when cau_state = st_cycle_2 else
mult1_out_sig - mult2_out_sig when cau_state = st_cycle_9 else
cross_3_sig(0);
And there are some places where I assign cross_3_sig(0) into other signals, i.e.:
numer_sig <= C_ZERO - cross_3_sig(0) & (16 downto 0 => '0');
mult1_in2_sig <= (others => '0') when cau_state = st_idle else
...
cross_3_sig(0) when cau_state = st_cycle_11 else
...
What is the problem, and how can I fix it?

The problem is that this form of expression creates a latch (which is sensitive to glitches on its control signal) and furthermore it is a latch with multiple control signals, for which there is no direct equivalent in real hardware.
signal_1 <= (others => '0') when cau_state = st_idle else
...
signal_6 when cau_state = st_cycle_4 else
signal_1;
Any time you see (outside a clocked process) something like
signal_1 <= ... else signal_1;
you know you have a problem. This is a signal feeding itself directly, an attempt to use a simple wire as a memory.
The correct use for this pattern is as a multiplexer, not as memory,
output_1 <= input_1 when ... else
input_2 when ... else
input_n;
The correct way to remember the old value of signal1 is a clocked process, e.g.
process (clk)
begin
if rising_edge(clk) then
if cau_state = st_idle then signal_1 <= (others => '0')
...
elsif cau_state = st_cycle_4 then signal_1 <= signal_6;
end if;
end if;
end process;
With no assignment, signal_1 will maintain its current value.
Or a better alternative : use a case statement in the process:
process (clk)
begin
if rising_edge(clk) then
case cau_state is
when st_idle => signal_1 <= (others => '0')
...
when st_cycle_4 => signal_1 <= signal_6;
-- when others => some default action
end case;
end if;
end process;
This does change the semantics to a clocked design, but unclocked designs are troublesome in FPGA, to say the least!

Related

Please help me with VHDL compile error [duplicate]

This question already has an answer here:
VHDL: Unable to read output status
(1 answer)
Closed 4 years ago.
library IEEE;
use IEEE.std_logic_1164.all;
entity doorlock is
port( reset : in std_logic;
enable : in std_logic;
password : in std_logic_vector (7 downto 0);
door : out std_logic_vector (7 downto 0);
lock : out std_logic;
alarm : out std_logic;
turnoff : out std_logic);
end doorlock;
--password is 10(decimal no.) which is 00010000(binary no.)
architecture DDL of doorlock is
signal err_count : integer range 0 to 5 := 0;
begin
lock <= '0' when (reset = '0');
alarm <= '0' when (reset = '0');
turnoff <= '0' when (reset = '0');
door <= "00000000" when (reset = '0');
lock <= '0' when (enable <= '0');
process(password)
begin
if (password = "-------1") then
door <= "00000000";
elsif (password = "------10") then
door <= "00000001";
elsif (password = "-----100") then
door <= "00000011";
elsif (password = "----1000") then
door <= "00000111";
elsif (password = "---00000") then
door <= "00001111";
elsif (password = "--110000") then
door <= "00011111";
elsif (password = "-1010000") then
door <= "00111111";
elsif (password = "10010000") then
door <= "01111111";
elsif (password = "00010000") then
door <= "11111111";
end if;
err_count <= err_count + 1;
end process;
alarm <= '1' when (err_count = 3);
turnoff <= '1' when (err_count = 5);
lock <= '1' when (door = "11111111" and turnoff = '0' and alarm = '0');
end DDL;
I made this code for my homework making digital door lock.
And this line have error as I compile it.
lock <= '1' when (door = "11111111" and turnoff = '0' and alarm = '0');
Error is like this below
** Error: D:\modelsim\Door.vhd(53): Cannot read output "alarm".
VHDL 2008 allows reading outputs.
This facility is enabled by compiling with -2008.
** Error: D:\modelsim\Door.vhd(53): Cannot read output "door".
VHDL 2008 allows reading outputs.
This facility is enabled by compiling with -2008.
** Error: D:\modelsim\Door.vhd(53): Cannot read output "turnoff".
VHDL 2008 allows reading outputs.
This facility is enabled by compiling with -2008.
** Error: D:\modelsim\Door.vhd(55): VHDL Compiler exiting
I don't know why it happens please help me
First off: "Please help me" is not a good question. Better would be something like "Modelsim error "cannot read output" when compiling"
Second off: The error is quite descriptive. "Cannot read output "alarm"". alarm is declared as
alarm : out std_logic;
Thus it is an output port. In pre-2008 VHDL it was not allowed to read output ports. Next the compiler hints on how to fix it:
"VHDL 2008 allows reading outputs. This facility is enabled by compiling with -2008."
So do so!
In your modelsim compilation window select "default options"
And then set to VHDL-2008
Alternatively you can actually do what is described (add the -2008) on the command line:
vcom -reportprogress 300 -work work -2008 doorlock.vhd
Voila. Finished! Not?
No wait, still doesn't work!
You have a multiple driver error. In line 23 it states:
door <= "00000000" when (reset = '0');
This acts as a latch, effectively being the same as
process(reset) begin
if reset = '0' then
door <= "00000000";
end if;
end process;
Thus once reset='0' has occurred, the process will drive door to a fixed value. In the password-triggered process you again drive door! This will resolve badly. E.g. if (password = "------10"), then door <= "00000001". This will resolve:
resolve("00000000", "00000001") = "0000000X"
Because connecting '0' to '1' is equivalently a short-circuit.
So let's look at proper design. You're now triggering on a change of password. Not so nice, but it's possible. I would use another trigger, like the enable signal that is not being used. But anyhow: we introduce an extra signal to detect the change password_delay. But more importantly we introduce a clock. In digital hardware most systems use a clock. Finally, we use the new VHDL-2008 statement case? to decode the don't cares.
Together the VHDL-2008 code becomes:
library IEEE;
use IEEE.std_logic_1164.all;
entity doorlock is
port(
clk : in std_logic;
reset : in std_logic;
enable : in std_logic;
password : in std_logic_vector (7 downto 0);
door : out std_logic_vector (7 downto 0);
lock : out std_logic;
alarm : out std_logic;
turnoff : out std_logic
);
end doorlock;
--password is 10(decimal no.) which is 00010000(binary no.)
architecture DDL of doorlock is
signal password_delay : std_logic_vector(password'range) := password;
use ieee.numeric_std_unsigned.all;
signal err_count : integer range 0 to 5 := 0;
begin
clk_proc : process(clk) begin
if rising_edge(clk) then
if reset = '0' then
door <= (others => '0');
lock <= '0';
alarm <= '0';
turnoff <= '0';
err_count <= 0;
else -- no reset :)
if password /= password_delay then
case? password is
when "-------1" => door <= "00000000";
when "------10" => door <= "00000001";
when "-----100" => door <= "00000011";
when "----1000" => door <= "00000111";
when "---00000" => door <= "00001111";
when "--110000" => door <= "00011111";
when "-1010000" => door <= "00111111";
when "10010000" => door <= "01111111";
when "00010000" => door <= "11111111";
when others => null;
end case?;
err_count <= err_count + 1;
end if;
case err_count is
when 3 => alarm <= '1';
when 5 => turnoff <= '1';
when others => null;
end case;
if door = "11111111" and turnoff = '0' and alarm = '0' then
lock <= '1';
end if;
end if;
password_delay <= password;
end if;
end process;
end DDL;
That's something different, eh? I'm sorry, but I don't have time to write a test bench for you.
NOTE: The code gives a compiler warning
Warning: C:/HDL/doorlock/doorlock.vhd(20): (vcom-1013) Initial value of "password_delay" depends on value of signal "password".
Ignore this. This is required for simulation as else undefined initial value of password_delaywill cause a trigger of password /= password_delay.

Edit - Can't Infer Register Because It's Behavior Does Not Match Any Supported Register Model VHDL

This is a branch off of a separate question I asked. I am going to explain more in depth on what I am trying to do and what it is not liking. This is a school project and doesn't need to follow standards.
I am attempting to make the SIMON game. Right now, what I am trying to do is use a switch case for levels and each level is supposed to be faster (hence different frequency dividers). The first level is supposed to be the first frequency and a pattern of LEDs is supposed to light up and disappear. Before I put in a switch case, the first level was by itself (no second level stuff) and it lit up and disappeared like it should. I also used compare = 0 in order to compare in output to an input. (The user is supposed to flip up the switches in the light pattern they saw). This worked when the first level was by itself but now that it is in a switch case, it doesn't like compare. I'm not sure how to get around that in order to compare an output to an input.
The errors I am getting are similar to before:
Error (10821): HDL error at FP.vhd(75): can't infer register for "compare" because its behavior does not match any supported register model
Error (10821): HDL error at FP.vhd(75): can't infer register for "count[0]" because its behavior does not match any supported register model
Error (10821): HDL error at FP.vhd(75): can't infer register for "count[1]" because its behavior does not match any supported register model
Error (10821): HDL error at FP.vhd(75): can't infer register for "count[2]" because its behavior does not match any supported register model
Error (10822): HDL error at FP.vhd(80): couldn't implement registers for assignments on this clock edge
Error (10822): HDL error at FP.vhd(102): couldn't implement registers for assignments on this clock edge
Error (12153): Can't elaborate top-level user hierarchy
I also understand that it doesn't like the rising_edge(toggle) but I need that in order to make the LED pattern light up and disappear.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
entity FP is
port(
clk, reset : in std_logic;
QF : out std_logic_vector (3 downto 0);
checkbtn : in std_logic;
Switch : in std_logic_vector(3 downto 0);
sel : in std_logic_vector (1 downto 0);
score : out std_logic_vector (6 downto 0)
);
end FP;
architecture behavior of FP is
signal time_count: integer:=0;
signal toggle : std_logic;
signal toggle1 : std_logic;
signal count : std_logic_vector (2 downto 0);
signal seg : std_logic_vector (3 downto 0);
signal compare : integer range 0 to 1:=0;
type STATE_TYPE is (level1, level2);
signal level : STATE_TYPE;
--signal input : std_logic_vector (3 downto 0);
--signal sev : std_logic_vector (6 downto 0);
begin
process (clk, reset, sel)
begin
if (reset = '0') then
time_count <= 0;
toggle <= '0';
elsif rising_edge (clk) then
case sel is
when "00" =>
if (time_count = 1249999) then
toggle <= not toggle;
time_count <= 0;
else
time_count <= time_count+1;
end if;
when "01" =>
if (time_count = 2499999) then
toggle1 <= not toggle1;
time_count <= 0;
else
time_count <= time_count+1;
end if;
when "10" =>
if (time_count = 4999999) then
toggle <= not toggle;
time_count <= 0;
else
time_count <= time_count+1;
end if;
when "11" =>
if (time_count = 12499999) then
toggle <= not toggle;
time_count <= 0;
else
time_count <= time_count+1;
end if;
end case;
end if;
end process;
Process (toggle, compare, switch)
begin
case level is
when level1 =>
if sel = "00" then
count <= "001";
seg <= "1000";
elsif (rising_edge (toggle)) then
count <= "001";
compare <= 0;
if (count = "001") then
count <= "000";
else
count <= "000";
end if;
end if;
if (switch = "1000") and (compare = 0) and (checkbtn <= '0') then
score <= "1111001";
level <= level2;
else
score <= "1000000";
level <= level1;
end if;
when level2 =>
if sel = "01" then
count <= "010";
seg <= "0100";
elsif (rising_edge (toggle1)) then
count <= "010";
compare <= 1;
if (count = "010") then
count <= "000";
else
count <= "000";
end if;
end if;
if (switch = "0100") and (compare = 1) and (checkbtn <= '0') then
score <= "0100100";
else
score <= "1000000";
level <= level1;
end if;
end case;
case count is
when "000"=>seg<="0000";
when "001"=>seg<="1000";
when "010"=>seg<="0100";
when "011"=>seg<="0110";
when "100"=>seg<="0011";
when others=>seg<="0000";
end case;
end process;
QF <= seg;
end behavior;
Thanks again in advance!
Well... it is hard to tell what is wrong, because this state machine is written in wrong way. You should look for references about proper modeling of FSM in VHDL. One good example is here.
If you use Quartus, you could also look for Altera's description on how to model FSM specifically for their compiler.
I will now give you just two advices. First is that you shouldn't (or mabye even you can't) use is two
if rising_edge (clk)
checks in one process. If your process is supposed to be sensitive on clock edge, write it once at the beginning.
Second thing is that if you want to model FSM with one process with synchronous reset, then put just clk on sensitivity list.
EDIT after question and code edit:
Ok, much better now. But another few things:
Your FSM is still not like it should. Look again at the example in the source I gave you above and edit it to be like there, or make it one process FSM like in example in this link.
Intends! Very important. I couldn't spot some of obvious errors, before I made proper intendation in your code. This leads me to...
Look at the places, there you assign values to count, in particular the if statements. No mater what, you assign the same value of "000".
Similar story with another signal - seg. You assign to it some value in the process, and then at the end of this process there is case statement in which you assign to it some other value, making this previous assignments irrelevant.
Use rising_edge only once in the process, only to clock, and only at the very beginning of the process, or in the way you did in the first process, that has asynchronous reset. In second process you did all this three things.
In sequential process with rising_edge, like the first one, you don't have to put to sensitivity list anything more than clock, and reset if it is asynchronous, like in your case.
Sensitivity list in second process. It is parallel process, so you should put there signals, that you check in a process, and can change outside of it. It is not the case for compare. But there should be signals: level, sel and toggle1.
As I'm still not sure what are you trying to achieve, I will not tell you what exactly to do. Fix your code according to points above, then maybe it will just work.

Error(10820) and (10822) VHDL

i am trying to write a code but i get error, i dont understand that, i am new to vhdl, any help would be appreciated.
code:
entity counter is
port
(
upp_down : in std_logic;
rst : in std_logic;
pressed : in std_logic;
count : out std_logic_vector(3 downto 0)
);
end entity;
architecture rtl of counter is
signal count_value: std_logic_vector(3 downto 0);
begin
process (rst,pressed,upp_down)
begin
if(rst'event and rst = '0') then
count <= "0000";
else
if(pressed'event and pressed = '0' ) then
if(upp_down = '1') then
count_value <= count_value + 1;
elsif(upp_down = '0') then
count_value <= count_value - 1;
end if;
end if;
end if;
end process;
count <= count_value;
end rtl;
Errors:
Error (10820): Netlist error at counter.vhd(28): can't infer register for count_value[1] because its behavior depends on the edges of multiple distinct clocks
Error (10822): HDL error at counter.vhd(28): couldn't implement registers for assignments on this clock edge
The first problem is that you're trying to use the edge of two different 'clocks' in one process. A particular process can only respond to one clock.
The second problem is that your code does not translate into any real-world hardware. There's nothing in the FPGA that can respond to there not being an edge of a clock, which is what you have described with your if(rst'event and rst = '0') then else structure.
Nicolas pointed out another problem (which your compiler didn't get as far as), which is that you're assigning count both inside and outside a process; this is not allowed, as signals can only be assigned in one process.
Generally the type of reset it looks like you're trying to implement would be written as in the example below:
process (rst,pressed,upp_down)
begin
if(rst = '0') then
count_value <= "0000";
elsif(pressed'event and pressed = '0' ) then
if(upp_down = '1') then
count_value <= count_value + 1;
elsif(upp_down = '0') then
count_value <= count_value - 1;
end if;
end if;
end process;
count <= count_value;
The reason for changing the reset to affect count_value, is that without this, the effect of your reset would only last one clock cycle, after which the count would resume from where it left off (Thanks #Jim Lewis for this suggestion).
In addition to your compile errors, you should try to use the rising_edge() or falling_edge() functions for edge detection, as they behave better than the 'event style.
The reset can be more easily implemented using count_value <= (others => '0'); this makes all elements '0', no matter how long count is.
Lastly, it looks like you're using the std_logic_arith package. There are many other answers discouraging the use of this package. Instead, you should use the numeric_std package, and have your counter of type unsigned. If your output must be of type std_logic_vector, you can convert to this using a cast: count <= std_logic_vector(count_value);.
One more thing, I just noticed that your counter is not initialised; this can be done in the same way as I suggested for the reset function, using the others syntax.
"count" can't be assigned inside and outside a process.
count <= "0000"; <-- inside process
count <= count_value; <-- outside process.
You should do "count <= count_value;" inside your process :
entity counter is
port
(
upp_down : in std_logic;
rst : in std_logic;
pressed : in std_logic;
count : out std_logic_vector(3 downto 0)
);
end entity;
architecture rtl of counter is
signal count_value: std_logic_vector(3 downto 0);
begin
process (rst,pressed,upp_down)
begin
if(rst'event and rst = '0') then
count <= "0000";
else
if(pressed'event and pressed = '0' ) then
if(upp_down = '1') then
count_value <= count_value + 1;
elsif(upp_down = '0') then
count_value <= count_value - 1;
end if;
count <= count_value;
end if;
end if;
end process;
end rtl;

Uart Vhdl, simulation is ok but in fpga not work

I write simple vhdl code for Uart receiver.
Simulation (iSIM) is fine but when implemented I have wrong reading behavior.
When synthetized ISE tell me there are latches on state machine end on data_fill(x).
have you any suggestion.
thanks in advance
gian
here the code
library ieee;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
entity rx_uart is
port (
clk : in STD_LOGIC;
rst : in STD_LOGIC;
rx_data : in STD_LOGIC;
data_out: out STD_LOGIC_VECTOR(7 downto 0)
);
end rx_uart;
architecture fizzim of rx_uart is
-- state bits
subtype state_type is STD_LOGIC_VECTOR(2 downto 0);
constant idle: state_type:="000"; -- receive_en=0 load_en=0 cnt_en=0
constant receive: state_type:="101"; -- receive_en=1 load_en=0 cnt_en=1
constant stop_load: state_type:="010"; -- receive_en=0 load_en=1 cnt_en=0
signal state,nextstate: state_type;
signal cnt_en_internal: STD_LOGIC;
signal load_en_internal: STD_LOGIC;
signal receive_en_internal: STD_LOGIC;
signal count : integer range 0 to 54686:=0;
signal cnt_en : STD_LOGIC;
signal load_en : STD_LOGIC;
signal receive_en : STD_LOGIC;
signal data_fill : STD_LOGIC_VECTOR(9 downto 0);
-- comb always block
begin
COUNTER_EN : process(clk,rst,cnt_en) begin
if (rst ='1') then
count <= 0;
elsif rising_edge(clk) then
if (cnt_en ='1') then
count <= count+1;
else
count <= 0;
end if;
end if;
end process;
LOADER: process(clk,rst,load_en) begin
if (rst='1') then
data_out <= (others =>'0');
elsif (rising_edge(clk) and load_en='1')then
data_out <= data_fill(8 downto 1);
end if;
end process;
ASSIGNATION : process(clk,rst,receive_en) begin
if (rst ='1') then
data_fill <= (others =>'0');
elsif (receive_en='1') then
case count is
when 7812 =>
data_fill(1) <= rx_data;
when 13020 =>
data_fill(2) <= rx_data;
when 18228 =>
data_fill(3) <= rx_data;
when 23436 =>
data_fill(4) <= rx_data;
when 28664 =>
data_fill(5) <= rx_data;
when 33852 =>
data_fill(6) <= rx_data;
when 39060 =>
data_fill(7) <= rx_data;
when 44268 =>
data_fill(8) <= rx_data;
when 49476 =>
data_fill(9) <= rx_data;
when others =>
data_fill(0) <= '0';
end case;
end if;
end process;
COMB: process(state,clk,count,rst,rx_data) begin
case state is
when idle =>
if (rx_data='0') then
nextstate <= receive;
elsif (rx_data='1') then
nextstate <= idle;
end if;
when receive =>
if (count<=54685) then
nextstate <= receive;
elsif (count>54685) then
nextstate <= stop_load;
end if;
when stop_load =>
nextstate <= idle;
when others =>
end case;
end process;
-- Assign reg'd outputs to state bits
cnt_en_internal <= state(0);
load_en_internal <= state(1);
receive_en_internal <= state(2);
-- Port renames for vhdl
cnt_en <= cnt_en_internal;
load_en <= load_en_internal;
receive_en <= receive_en_internal;
-- sequential always block
FF: process(clk,rst,nextstate) begin
if (rst='1') then
state <= idle;
elsif (rising_edge(clk)) then
state <= nextstate;
end if;
end process;
end fizzim;
You need to understand when latches are generated. Latches are generated when you have an incomplete assignment in combinational logic. Your case statements are combinational. You do not completely assign all possibilities of your data signal and your state machine. When you have an incomplete assignment in a combinational process you will always generate a latch. Latches are bad!
Use your when others properly to assign all of your signals under all conditions. Your data_fill signal will always generate a latch because you don't handle all conditions for data 0:9 on all cases.
Read more about how to avoid latches in VHDL
Edit: It seems too that you don't consistently create sequential logic in VHDL. You need to be creating a clocked process or remove clk from your sensitivity list in a combinational process.
your design has several bad code sites besides your latch problem. I'll number them for better reference.
(1)
Xilinx XST won't recognize the implemented state machine as a FSM. See your XST report or the *.syr file. There won't be a FSM section. If XST finds no FSM it's not able to choose "the best" state encoding and optimize your FSM.
You should use an enum as a state-type and also initialize your state signal:
type t_state is (st_idle, st_receive, st_stop);
signal state : t_state := st_idle;
signal nextstate : t_state;
Your FSM process also needs default assignments (see Russell's explanation) like
nextstate <= state;
(2)
asynchronous resets are no good design practice and complicate timing closure calculations.
(3)
you are handling raw input signals from outside you FPGA without any timing information. to prevent meta stability problems place two D-flip-flops on the rx_data path. you should also add the async-reg and no-srl-extract attribute to these 2 registers to prevent XST optimizations
SIGNAL I_async : STD_LOGIC := '0';
SIGNAL I_sync : STD_LOGIC := '0';
-- Mark register "I_async" as asynchronous
ATTRIBUTE ASYNC_REG OF I_async : SIGNAL IS "TRUE";
-- Prevent XST from translating two FFs into SRL plus FF
ATTRIBUTE SHREG_EXTRACT OF I_async : SIGNAL IS "NO";
ATTRIBUTE SHREG_EXTRACT OF I_sync : SIGNAL IS "NO";
[...]
BEGIN
[...]
I_async <= In WHEN rising_edge(Clock);
I_sync <= I_async WHEN rising_edge(Clock);
Let 'In' be your asynchronous input. Now you can use I_sync in your clock domain. I choose to describe these 2 registers in a one-liner, you can also use a classic process :) The suffix '_async' allows you to define a matching timing rule in your *.xcf and *.ucf files.

Unintentional latches in finite state machine (VHDL) + feedback

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.

Resources