我为Uart接收器编写简单的vhdl代码。 模拟(iSIM)很好,但实施后我的阅读行为有误。 当合成的ISE告诉我在data_fill(x)上的状态机端有锁存器。 你有什么建议。
提前谢谢 吉安这里是代码
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;
答案 0 :(得分:0)
您需要了解何时生成锁存器。当组合逻辑中的分配不完整时,会生成锁存器。您的案例陈述是组合的。您没有完全分配数据信号和状态机的所有可能性。如果在组合过程中分配不完整,则始终会生成一个锁存器。闩锁很糟糕!
正确使用when others
在所有条件下分配所有信号。您的data_fill信号将始终生成锁存器,因为在所有情况下您都不会处理数据0:9的所有条件。
详细了解how to avoid latches in VHDL
编辑:您似乎也没有在VHDL中始终如一地创建顺序逻辑。您需要在组合过程中创建一个时钟进程或从敏感性列表中删除clk。
答案 1 :(得分:0)
(1) Xilinx XST不会将已实现的状态机识别为FSM。请参阅XST报告或* .syr文件。不会成为FSM部分。如果XST没有找到FSM,它就无法选择最好的&#34;状态编码并优化您的FSM。
您应该使用枚举作为状态类型并初始化状态信号:
type t_state is (st_idle, st_receive, st_stop);
signal state : t_state := st_idle;
signal nextstate : t_state;
您的FSM流程还需要默认分配(请参阅Russell的解释),如
nextstate <= state;
(2) 异步复位不是一个好的设计实践,并且使时序收敛计算变得复杂。
(3) 您正在处理来自FPGA外部的原始输入信号而没有任何时序信息。为了防止元稳定性问题,在rx_data路径上放置两个D触发器。您还应该将async-reg和no-srl-extract属性添加到这两个寄存器以防止XST优化
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);
让&#39; In&#39;是你的异步输入。现在,您可以在时钟域中使用I_sync。我选择在单行中描述这两个寄存器,你也可以使用经典的过程:)后缀&#39; _async&#39;允许您在* .xcf和* .ucf文件中定义匹配的计时规则。