输出保持相同的值

时间:2017-04-09 19:02:08

标签: vhdl fpga state-machine vivado

我的PRN-Generator无法正常工作。我想用线性反馈移位寄存器来做。

模拟和编译工作没有问题,但输出错误(lfsr_out ='0')并且没有改变。

代码:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

entity lfsr_counter is
  generic(
    WIDTH : integer := 10
  );
  port(
    clk      : in  std_logic;       --clock
    rst      : in  std_logic;       --positiv rst
    lfsr_out : out std_logic        --1 bit output of lfsr
  );
end lfsr_counter;

-------------------------------------------------------------------

architecture behavioral of lfsr_counter is
  type state_type is (state_rst, state_go); --rst: reset; go: lfsr 
shifts

  signal present_state : state_type;
  signal next_state    : state_type;
  signal lfsr          : std_logic_vector((WIDTH - 1) downto 0) := 
(others => '0');
  signal d0            : std_logic                              := '0'; 
--stores the current feedbackvalue

begin

  --sequencial logic:
  -------------------------------------------------------------------
  state_register : process(clk, rst)
  begin
    if (rst = '1') then
      present_state <= state_rst; --default state on reset.
    elsif (rising_edge(clk)) then
      present_state <= next_state; --state change
    end if;
  end process;

  --  combinatorial logic
  -------------------------------------------------------------------

  comb_logic : process(present_state, rst)
  begin
    case present_state is
      when state_rst =>
        if (rst = '1') then
          next_state <= state_rst;
        else
          next_state <= state_go;
        end if;
      when state_go =>
        if (rst = '1') then
          next_state <= state_rst;
        else
          next_state <= state_go;
        end if;
    end case;
  end process;

  output_logic : process(present_state)
  begin
    if (present_state = state_go) then
      --assert ((WIDTH >= 3) and (WIDTH <= 10))
      --report "Error: the LFSR width must be between 3 and 10" severity 
failure;
      case WIDTH is               --definitions for the feedback
        when 3      => d0 <= lfsr(2) xnor lfsr(1);
        when 4      => d0 <= lfsr(3) xnor lfsr(2);
        when 5      => d0 <= lfsr(4) xnor lfsr(2);
        when 6      => d0 <= lfsr(5) xnor lfsr(4);
        when 7      => d0 <= lfsr(6) xnor lfsr(5);
        when 8      => d0 <= lfsr(7) xnor lfsr(5) xnor lfsr(4) xnor 
lfsr(3);
        when 9      => d0 <= lfsr(8) xnor lfsr(4);
        when 10     => d0 <= lfsr(9) xnor lfsr(6);
        when others => null;
      end case;
      lfsr     <= std_logic_vector(unsigned(lfsr) sll 1); --shifting all 
bits to left by 1
      lfsr_out <= lfsr(WIDTH - 1); --MSB to output
      lfsr     <= lfsr(WIDTH - 1 downto 1) & d0; --concatenate the 
feedback to the lfsr
    else
      lfsr     <= (others => '0'); --reset state -> lfsr contains only 
'0'
      lfsr_out <= '0';
    end if;
  end process;
end architecture;

如果在output_logic中设置“lfsr_out&lt; ='1'”,则输出将保持为“1”。我的代码出了什么问题?

1 个答案:

答案 0 :(得分:3)

  

我的代码出了什么问题?

您的移位寄存器的值为全0和XNOR将产生输出d0为'1'。这就是'1'的来源。

您可以使用generate语句生成d0而不是带有case语句的process语句。

对lfsr的第一次分配不起作用,可以删除。任何预定时间只有一个预计输出波形。没有后延迟的分配将产生增量循环。同一个delta周期中的两个和最后一个将生效。因此,您不需要包std_logic_unsigned(Synopsys)或numeric_std(IEEE)。

合成结果

lfsr不是一个时钟寄存器,它是一个组合循环,总是在合成硬件中产生'1'。这是由于缺乏顺序转移造成的。

此外,您的模拟如何正常运行?进程output_logic仅对present_state上的事件恢复。

抛弃单独的状态机并实现一个定时的lfsr移位寄存器并使用generate语句:

library ieee;
use ieee.std_logic_1164.all;
-- use ieee.std_logic_unsigned.all;
-- use ieee.numeric_std.all;

entity lfsr_counter is
    generic (
        -- WIDTH: integer := 10
        WIDTH:  positive range 3 to 10 := 10
    );
    port (
        clk:       in  std_logic;
        rst:       in  std_logic;       -- positive rst
        lfsr_out:  out std_logic
    );
end entity lfsr_counter;

architecture behavioral of lfsr_counter is
    -- type state_type is (state_rst, state_go); 
    -- signal present_state:  state_type;
    -- signal next_state:     state_type;
    signal lfsr:    std_logic_vector((WIDTH - 1) downto 0) := (others => '0');
    signal d0:             std_logic := '0'; 
begin
-- state_register:
--     process (clk, rst)
--         begin
--         if rst = '1' then
--             present_state <= state_rst;
--         elsif rising_edge(clk) then
--             present_state <= next_state;
--         end if;
--     end process;

-- comb_logic:  
    -- process (present_state, rst)
    -- begin
    --     case present_state is
    --         when state_rst =>
    --             if rst = '1' then
    --                 next_state <= state_rst;
    --             else
    --                 next_state <= state_go;
    --             end if;
    --         when state_go =>
    --             if rst = '1' then
    --                 next_state <= state_rst;
    --             else
    --                 next_state <= state_go;
    --             end if;
    --     end case;
    -- end process;

-- Using VHDL -2008 you could use a case generate or elsif
WIDTH3:
    if WIDTH = 3 generate
        d0 <= lfsr(2) xnor lfsr(1);
    end generate;
WIDTH4:
    if WIDTH = 4 generate
        d0 <= lfsr(3) xnor lfsr(2);
    end generate;
WIDTH5:
    if WIDTH = 5 generate
        d0 <= lfsr(4) xnor lfsr(2);
    end generate;
WIDTH6:
    if WIDTH = 6 generate
        d0 <= lfsr(5) xnor lfsr(4);
    end generate;
WIDTH7:
    if WIDTH = 7 generate
        d0 <= lfsr(6) xnor lfsr(5);
    end generate;
WIDTH8:
    if WIDTH = 8 generate
        d0 <= lfsr(7) xnor lfsr(5) xnor lfsr(4) xnor lfsr(3);
    end generate;
WIDTH9:
    if WIDTH = 9 generate
        d0 <= lfsr(8) xnor lfsr(4);
    end generate;
WIDTH10:
    if WIDTH = 10 generate
        d0 <= lfsr(9) xnor lfsr(6);
    end generate;
-- output_logic:
--     process (present_state)
--     begin
--     if present_state = state_go then
--         case WIDTH is
--             when 3   =>
--                 d0 <= lfsr(2) xnor lfsr(1);
--             when 4   =>
--                 d0 <= lfsr(3) xnor lfsr(2);
--             when 5   =>
--                 d0 <= lfsr(4) xnor lfsr(2);
--             when 6   =>
--                 d0 <= lfsr(5) xnor lfsr(4);
--             when 7   =>
--                 d0 <= lfsr(6) xnor lfsr(5);
--             when 8   =>
--                 d0 <= lfsr(7) xnor lfsr(5) xnor lfsr(4) xnor lfsr(3);
--             when 9   =>
--                 d0 <= lfsr(8) xnor lfsr(4);
--             when 10  =>
--                 d0 <= lfsr(9) xnor lfsr(6);
--             when others =>
--                 null;
--         end case;
--         -- lfsr     <= lfsr sll 1;
--         lfsr_out <= lfsr(WIDTH - 1);
--         lfsr     <= lfsr(WIDTH - 1 downto 1) & d0;
--     else
--         lfsr     <= (others => '0');
--         lfsr_out <= '0';
--         end if;
--     end process;
lfsr_reg:
    process (rst, clk)
    begin
        if rst = '1' then
            lfsr <= (others =>'0');
        elsif rising_edge(clk) then
            lfsr <= lfsr(WIDTH - 2 downto 0) & d0;  -- WAS WIDTH - 1 downto 1
        end if;
    end process;

    lfsr_out <= lfsr(WIDTH - 1);  -- not separately registered

end architecture;

带有generate语句的位没有任何意义,但是从合成中卸载工作,这必须在case语句多路复用器中使用所有这些赋值。

还有一个添加的测试平台来创建Minimal, Complete and Verifiable example,我们看到lfsr实际上并没有向左移动。修复程序显示在上面的代码中并涉及更改:

lfsr <= lfsr(WIDTH - 2 downto 0) & d0;  -- WAS WIDTH - 1 downto 1

测试平台:

library ieee;
use ieee.std_logic_1164.all;

entity lfsr_counter_tb is  -- a testbench
end entity;

architecture foo of lfsr_counter_tb is
    constant WIDTH:   positive range 1 to 10 := 10;  -- test full length
    signal clk:       std_logic := '1';
    signal rst:       std_logic := '0';
    signal lfsr_out:  std_logic;
begin
DUT:
    entity work.lfsr_counter
        generic map (
            WIDTH => WIDTH
        )
        port map (
            clk => clk,
            rst => rst,
            lfsr_out => lfsr_out
        );
CLOCK:
    process
    begin
        wait for 10 ns;
        clk <= not clk;
        if now > 550 ns then
            wait;
        end if;
    end process;
STIMULUS:
    process
    begin
        wait for 11 ns;
        rst <= '1';
        wait for 99 ns;
        rst <= '0';
        wait;
    end process;
end architecture;

模拟:

lfsr_counter_tb.png

lfsr_counter也应该合成并运行。

  

Uhhm。我们的数字设计课程从未听说过有关生成声明的任何内容!在某些情况下,这可能非常有用。谢谢你这个例子。我理解你的代码。它非常简单,自我解释。您还可以避免组合循环。但是,这是一种不同的方法。我仍然希望将其作为FSM来实现并理解FSM的机制。现在,我知道output_logic部分没有计时,这会导致梳理。环。此外,只执行lfsr的最后一个语句。我需要编辑什么才能使其正常工作?

他们说这是一个不同的问题。两个特别的,今天只有。

您的代码显示编程语言思维,而VHDL是硬件描述语言。例如,当任何进程尚未在当前模拟周期中恢复或随后暂停时,不会发生信号更新。这意味着d0不希望成为信号,或者它的分配想要处于单独的过程中。

信号在进程之间进行通信。对于仅在进程内使用的对象,如果在赋值后计算值,则应使用变量。

还有使用WIDTH分配d0的多路复用器。它代表了在合成过程中会被吃掉的硬件,因为WIDTH是不变的,作为通用常量传递。

泛型常量可以有一个定义的标量范围:

library ieee;
use ieee.std_logic_1164.all;
-- use ieee.std_logic_unsigned.all;
-- use ieee.numeric_std.all;

entity lfsr_counter is
    generic (
        -- WIDTH: integer := 10
        WIDTH:  positive range 3 to 10 := 10
    );
    port (
        clk:       in  std_logic;
        rst:       in  std_logic;       -- positive rst
        lfsr_out:  out std_logic
    );
end entity lfsr_counter;

这允许编写VHDL设计描述,而不必处理您使用的值之外的值。所有额外的逻辑都被吃掉了,但你可能会引入错误。

所以d0做了一个变量,WIDTH约束了,lsfr_out赋值转移到了一个并发语句:

architecture behave of lfsr_counter is
    type state_type is (state_rst, state_go);
    signal present_state:  state_type;
    signal next_state:     state_type;
    signal lfsr:    std_logic_vector((WIDTH - 1) downto 0) := (others => '0');
    -- signal d0:             std_logic := '0'; 
begin
state_register:
    process (clk, rst)
        begin
        if rst = '1' then
            present_state <= state_rst;
        elsif rising_edge(clk) then
            present_state <= next_state;
        end if;
    end process;

comb_logic:
    process (present_state, rst)
    begin
        case present_state is
            when state_rst =>
                if rst = '1' then
                    next_state <= state_rst;
                else
                    next_state <= state_go;
                end if;
            when state_go =>
                if rst = '1' then
                    next_state <= state_rst;
                else
                    next_state <= state_go;
                end if;
        end case;
    end process;

output_logic:
    process  (clk)  -- (present_state)
        variable d0: std_logic;
    begin
        if rising_edge(clk) then
            if present_state = state_go then
                case WIDTH is
                    when 3   =>
                        d0 := lfsr(2) xnor lfsr(1);
                    when 4   =>
                        d0 := lfsr(3) xnor lfsr(2);
                    when 5   =>
                        d0 := lfsr(4) xnor lfsr(2);
                    when 6   =>
                        d0 := lfsr(5) xnor lfsr(4);
                    when 7   =>
                        d0 := lfsr(6) xnor lfsr(5);
                    when 8   =>
                        d0 := lfsr(7) xnor lfsr(5) xnor lfsr(4) xnor lfsr(3);
                    when 9   =>
                        d0 := lfsr(8) xnor lfsr(4);
                    when 10  =>
                        d0 := lfsr(9) xnor lfsr(6);
                    -- when others =>
                    --     null;
                end case;
                -- lfsr     <= lfsr sll 1;
                -- lfsr_out <= lfsr(WIDTH - 1);
                -- lfsr     <= lfsr(WIDTH - 1 downto 1) & d0;
                lfsr <= lfsr(WIDTH - 2 downto 0) & d0;
            else
                lfsr     <= (others => '0');  -- a synchronous reset
                -- lfsr_out <= '0';
            end if;
        end if;
    end process;

    lfsr_out <= lfsr(WIDTH - 1);  -- not separately registered, a mux

end architecture behave;

显示第一个架构的所有更改,原始代码已注释掉。这使用相同的测试平台进行分析,详细说明和模拟,并产生相同的结果。

移动lfsr_out分配的原因基于与d0相同的问题,另一个观察结果。 output_logic进程只有在找到敏感列表的信号上有事件时才会恢复执行。

这意味着你会错过lfsr_out上的转换来模拟你的第一个设计,或者意味着使用一个带时钟的lfsr寄存器的半时钟延迟(对于下一个clk边缘),就像上面的行为架构一样。

您可以注意到lsfr赋值更改实际上提供了移位,如顶部代码示例中的lfsr_reg进程中所示。你会注意到lfsr的第一次分配仍然被注释掉了。