Uart Vhdl,模拟还可以,但在fpga中无法正常工作

时间:2014-07-08 18:20:03

标签: vhdl uart receiver

我为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;

2 个答案:

答案 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文件中定义匹配的计时规则。