代码之家  ›  专栏  ›  技术社区  ›  Cactus

初始化寄存器

  •  2
  • Cactus  · 技术社区  · 6 年前

    我有一个非常简单的同步电路,它可以让LED闪烁:

    module Blinker where
    
    import Clash.Prelude
    import Data.Word
    
    {-# NOINLINE topEntity #-}
    {-# ANN topEntity
      (Synthesize
        { t_name   = "blinkerTop"
        , t_inputs = [PortName "CLK_32MHZ", PortName "RESET"]
        , t_output = PortName "LED"
        }) #-}
    topEntity
      :: Clock System Source
      -> Reset System Asynchronous
      -> Signal System Bit
    topEntity = exposeClockReset $ tickTock 32000000
    
    tickTock :: (HiddenClockReset domain gated synchronous) => Word32 -> Signal domain Bit
    tickTock n = mealy step (False, 0) (pure ())
      where
        step (s, k) () =
            let k' = k + 1
                finished = k' == n
                s' = if finished then not s else s
                k'' = if finished then 0 else k'
            in ((s', k''), if s' then high else low)
    

    因为当我把它上传到一个真正的FPGA板上时,它不起作用,所以我想我可以在Xilinx的模拟器中用下面的测试台来测试它:

    LIBRARY ieee;
    USE ieee.std_logic_1164.ALL;
    
    ENTITY testbench IS
    END testbench;
    
    ARCHITECTURE behavior OF testbench IS 
        COMPONENT blinkerTop
        PORT(
             CLK_32MHZ : IN  std_logic;
             RESET : IN  std_logic;
             LED : OUT  std_logic
            );
        END COMPONENT;
    
       signal CLK_32MHZ : std_logic := '0';
       signal RESET : std_logic := '0';
       signal LED : std_logic;
       constant CLK_32MHZ_period : time := 31.2 ns;
    
    BEGIN 
       uut: blinkerTop PORT MAP (
              CLK_32MHZ => CLK_32MHZ,
              RESET => RESET,
              LED => LED
            );
    
       CLK_32MHZ_process :process
       begin
            CLK_32MHZ <= '0';
            wait for CLK_32MHZ_period/2;
            CLK_32MHZ <= '1';
            wait for CLK_32MHZ_period/2;
       end process;
    END;
    

    在模拟器中,这与现实生活中的FPGA板的行为相匹配: LED 信号保持低。

    我查看了生成的VHDL,它是这样的:

    -- Automatically generated VHDL-93
    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;
    use IEEE.MATH_REAL.ALL;
    use std.textio.all;
    use work.all;
    use work.blinkertop_types.all;
    
    entity blinkerTop is
      port(-- clock
           CLK_32MHZ : in std_logic;
           -- asynchronous reset: active high
           RESET     : in std_logic;
           LED       : out std_logic);
    end;
    
    architecture structural of blinkerTop is
      signal \#tup_app_arg\       : unsigned(31 downto 0);
      signal \s'\                 : boolean;
      signal \#s'_case_alt\       : boolean;
      signal s                    : boolean;
      signal \#finished_case_alt\ : boolean;
      signal \#k'_case_alt\       : unsigned(31 downto 0);
      signal ds                   : blinkertop_types.tup2;
      signal \#finished_app_arg\  : signed(63 downto 0);
      signal x                    : unsigned(63 downto 0);
      signal x_0                  : blinkertop_types.tup2;
      signal \x#\                 : unsigned(63 downto 0);
      signal k                    : unsigned(31 downto 0);
      signal \#w\                 : unsigned(63 downto 0);
    begin
      LED <= '1' when \s'\ else
             '0';
    
      \#tup_app_arg\ <= resize(to_unsigned(0,64),32) when \#finished_case_alt\ else
                        \#k'_case_alt\;
    
      \s'\ <= \#s'_case_alt\ when \#finished_case_alt\ else
              s;
    
      \#s'_case_alt\ <= false when s else
                        true;
    
      s <= ds.tup2_sel0;
    
      \#finished_case_alt\ <= tagToEnum(\#finished_app_arg\);
    
      \#w\ <= (\x#\ + to_unsigned(1,64));
    
      \#k'_case_alt\ <= resize((resize(\#w\(31 downto 0),64)),32);
    
      -- register begin 
      blinkertop_register : process(CLK_32MHZ,RESET)
      begin
        if RESET = '1' then
          ds <= ( tup2_sel0 => false, tup2_sel1 => resize(to_unsigned(0,64),32) )
          -- pragma translate_off
          after 1 ps
          -- pragma translate_on
          ;
        elsif rising_edge(CLK_32MHZ) then
          ds <= x_0
          -- pragma translate_off
          after 1 ps
          -- pragma translate_on
          ;
        end if;
      end process;
      -- register end
    
      \#finished_app_arg\ <= to_signed(1,64) when x = to_unsigned(32000000,64) else to_signed(0,64);
    
      x <= resize(\#k'_case_alt\,64);
    
      x_0 <= ( tup2_sel0 => \s'\
             , tup2_sel1 => \#tup_app_arg\ );
    
      \x#\ <= resize(k,64);
    
      k <= ds.tup2_sel1;
    end;
    

    我注意到内部状态不是初始化的,只是在重置时分配的。所以这给了我一个在测试台上添加重置过程的想法:

    stim_proc: process
    begin       
       RESET <= '1';  
       wait for 100 ns; 
       RESET <= '0';
       wait;
    end process;
    

    有了这些变化,我明白了 发光二极管 在模拟器中开始闪烁。[*]

    这需要模拟;但我如何确保在实际板上有类似的复位信号?

    [*]当然,对于模拟,我将频率从32000000个周期增加到了100个周期;否则,我将不得不运行模拟器很长时间,以便看到第一个过渡。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Ola Grøttvik    6 年前

    一种解决方案是在您的FPGA逻辑中创建上电复位序列。这可以实现为一个计数器,只要计数器值低于某个常量,就断言重置。当计数器超过定值时,解除重置。