初始化寄存器

Initializing registers

我有一个非常简单的同步电路,可以使 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;

进行此更改后,我看到 LED 开始在模拟器中闪烁。 [*]

负责模拟;但是我如何确保在真实板上有类似的复位信号呢?

[*] 当然,为了模拟,我将频率从 32,000,000 周期提高到仅 100 周期;否则我必须 运行 模拟器好久才能看到第一个转换。

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