获得最后512个值的最大资源的方法

时间:2017-09-12 11:35:11

标签: arrays algorithm vhdl fpga xilinx

我编写了一些VHDL代码,用于存储输入信号的最后512个值,并计算存储值的最大值。此代码有效,但使用了FPGA的许多LUT资源。代码的目的是计算最后512个样本的最大值,是否有更有效的方法来实现这一目标? (重要的是它计算最后512个值中的最大值,而不是从该输入中观察到的最大值,后者可以很容易地实现存储单个数字)。

或者在某种程度上,我可以对VHDL进行编码,使得合成器将阵列实现为Block RAM(BRAM)而不是LUT?

我使用的合成器是LabVIEW FPGA(我相信在内部使用XilinX ISE来编译/合成VHDL)。

我目前的代码如下所示:

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

entity RecentMax is
  port (
    clk : in std_logic;
    reset : in std_logic;
    InputSignal : in std_logic_vector(15 downto 0);
    Max : out std_logic_vector(15 downto 0)
    );
end RecentMax;

architecture RTL of RecentMax is
-- declarations
  type Array512 is array(0 to 511) of signed(15 downto 0);
  signal PastVals : Array512;
  type Array256 is array(0 to 255) of signed(15 downto 0);
  signal result : Array256;

  signal CalculationState : unsigned(1 downto 0);
  signal NLeftToCompute : unsigned(8 downto 0);
begin
-- behaviour
  process(clk)
  begin
    if(rising_edge(clk)) then
      if(reset = '1') then
        -- reset values
        for i in PastVals'low to PastVals'high loop
          PastVals(i) <= (others => '0');
        end loop;
        for i in result'low to result'high loop
          result(i) <= (others => '0');
        end loop;
        CalculationState <= to_unsigned(0, 2);
        Max <= std_logic_vector(to_signed(0, 16));
        NLeftToCompute <= to_unsigned(256, 9);
      else
        -- do stuff
        case to_integer(CalculationState) is
          when 0 =>
            for i in PastVals'low to PastVals'high-1 loop
              PastVals(i+1) <= PastVals(i);
            end loop;
            PastVals(0) <= signed(InputSignal);
            Max <= std_logic_vector(result(0));
            NLeftToCompute <= to_unsigned(256, 9);
            CalculationState <= to_unsigned(1, 2);
          when 1 =>
            for i in 0 to 255 loop
              if (i <= to_integer(NLeftToCompute)-1) then
                if PastVals(i*2) > PastVals(i*2+1) then
                  result(i) <= PastVals(i*2);
                else
                  result(i) <= PastVals(i*2+1);
                end if;
              end if;
            end loop;
            NLeftToCompute <= shift_right(NLeftToCompute, 1);
            CalculationState <= to_unsigned(2, 2);
          when 2 =>;
            for i in 0 to 127 loop
              if (i <= to_integer(NLeftToCompute)-1) then
                if result(i*2) > result(i*2+1) then
                  result(i) <= result(i*2);
                else
                  result(i) <= result(i*2+1);
                end if;
              end if;
            end loop;
            if NLeftToCompute > 2 then
              NLeftToCompute <= shift_right(NLeftToCompute, 1);
            else
              CalculationState <= to_unsigned(0, 2);
            end if;
          when others =>
            --- do nothing - shouldn't get here
        end case;
    end if;
  end if;
end process;
end RTL;

2 个答案:

答案 0 :(得分:1)

你想要的东西有两种可能性。

首先,您可以选择通过创建专用进程和数组来实例化BRAM,以便合成器选择使用块ram而不是512 luts。

CONSTANT DATA_WIDTH     : integer := 16;
CONSTANT ADD_WIDTH      : integer := 9; -- 512 addresses
CONSTANT DPRAM_DEPTH    : integer := 2**ADD_WIDTH; -- depth of the memory

TYPE dpram IS ARRAY (0 TO DPRAM_DEPTH - 1) OF std_logic_vector(DATA_WIDTH - 1 DOWNTO 0);
SIGNAL mem              : dpram;

然后是过程:

dpram_gen_p : PROCESS (clk_i)
BEGIN
    IF (rising_edge(clk_i)) THEN
        IF (wr_req_i = '1') THEN
            mem(wr_add_s) <= wr_data_i;
        END IF;
        rd_data_s <= mem(rd_add_s);
    END IF;
END PROCESS;

对于主合成器,此语法将实现为Block RAM。 然后,您需要使用RAM的数据端口,而不是PastVals信号。请注意读取周期,因为您需要一个时钟周期来更改读取接口的地址(rd_add_s),并且需要一个时钟来实际读取数据(rd_data_s)。

第二个选项(根据我的说法,它是最简单和最快的)只是为了实现512字大小的fifo内存(你可以使用Xilinx IP内核生成器)。

https://www.xilinx.com/support/documentation/ip_documentation/fifo_generator/v13_1/pg057-fifo-generator.pdf

然后你只需要写入fifo直到它已满,最后逐字逐字地读取数据,直到它为空并注册最高值,就像你在设计中所做的那样。

答案 1 :(得分:0)

对于这个特定的应用程序,只需每512个时钟周期更新一次就足够了。我的更新代码解决方案如下所示。我仍然对这个问题的答案感兴趣,关于是否有一种资源效率更高的方法可以在很少的时钟周期内工作。

代码解决方案:

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

entity RecentMax is
  port (
    clk : in std_logic;
    reset : in std_logic;
    InputSignal : in std_logic_vector(15 downto 0);
    Max : out std_logic_vector(15 downto 0)
    );
end RecentMax;

architecture RTL of RecentMax is
-- declarations
signal counter : integer;
signal RecentMax : signed(15 downto 0);

begin
-- behaviour
  process(clk)
  begin
    if(rising_edge(clk)) then
      if(reset = '1') then
        -- reset values
        counter <= 0;
        RecentMax <= to_signed(0, 16);
      else
      -- do stuff
      if counter = 0 then
        Max <= std_logic_vector(RecentMax);
        counter <= counter + 1;
        RecentMax <= to_signed(0, 16);
      else
        if signed(InputSignal) > RecentMax then
          RecentMax <= signed(InputSignal);
        end if;
        if counter >= 511 then
          counter <= 0;
        else
          counter <= counter + 1;
        end if;
      end if;  
    end if;
  end if;
end process;
end RTL;