Arrays 获取最后512个值的最大值的更节省资源的方法

Arrays 获取最后512个值的最大值的更节省资源的方法,arrays,algorithm,vhdl,fpga,xilinx,Arrays,Algorithm,Vhdl,Fpga,Xilinx,我编写了一些VHDL代码,用于存储输入信号的最后512个值,并计算存储值中的最大值。这段代码可以工作,但使用了我的FPGA的大量LUT资源。代码的目的是计算最后512个样本的最大值,是否有更节省资源的方法来实现这一点?(重要的是,它计算最后512个值中的最大值,而不是从该输入中观察到的最大值,后者可以通过存储单个数字轻松实现) 或者,我是否有办法编写VHDL代码,使合成器将阵列实现为块RAM(BRAM)而不是LUT 我使用的合成器是LabVIEW FPGA(我相信它在内部使用XilinX ISE

我编写了一些VHDL代码,用于存储输入信号的最后512个值,并计算存储值中的最大值。这段代码可以工作,但使用了我的FPGA的大量LUT资源。代码的目的是计算最后512个样本的最大值,是否有更节省资源的方法来实现这一点?(重要的是,它计算最后512个值中的最大值,而不是从该输入中观察到的最大值,后者可以通过存储单个数字轻松实现)

或者,我是否有办法编写VHDL代码,使合成器将阵列实现为块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;
ieee库;
使用ieee.std_logic_1164.all;
使用ieee.numeric_std.all;
实体RecentMax是
港口(
clk:标准逻辑中;
复位:在标准逻辑中;
输入信号:标准逻辑向量(15到0);
最大值:输出标准逻辑向量(15到0)
);
结束当前最大值;
RecentMax的体系结构RTL是
--声明
Array512类型是有符号(15到0)的数组(0到511);
信号过去:阵列512;
Array256类型是有符号(15到0)的数组(0到255);
信号结果:Array256;
信号计算状态:无符号(1到0);
信号NLeftToCompute:无符号(8到0);
开始
--行为
过程(clk)
开始
如果(上升沿(clk)),则
如果(重置='1'),则
--重置值
对于PastVals'低到PastVals'高循环中的i
过去数(i)‘0’;
端环;
对于结果“从低到高”循环中的i
结果(i)‘0’;
端环;

计算状态你想要什么有两种可能

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

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;
dpram\u gen\p:过程(clk\u i)
开始
如果(上升沿(clk_i)),则
如果(wr_req_i='1'),则

mem(wr_add_s)对于这个特定的应用程序,只需每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;
ieee库;
使用ieee.std_logic_1164.all;
使用ieee.numeric_std.all;
实体RecentMax是
港口(
clk:标准逻辑中;
复位:在标准逻辑中;
输入信号:标准逻辑向量(15到0);
最大值:输出标准逻辑向量(15到0)
);
结束当前最大值;
RecentMax的体系结构RTL是
--声明
信号计数器:整数;
信号接收最大值:已签名(15至0);
开始
--行为
过程(clk)
开始
如果(上升沿(clk)),则
如果(重置='1'),则
--重置值

计数器您不能使用块RAM,因为您有512端口内存。您正在同一时钟周期中读取所有值,因此不可能进行存储优化。您还将得到一个大的比较器,因为您一次比较512个值乘以16位。您应该考虑创建一个比较器树,以切断关键路径,从而提高生成电路的频率。您的示例代码正在实现具有不同处理阶段的FSM。我认为您的实体应该提供握手端口,以便在准备接受新数据和保存数据以进行处理时发出信号。但这种行为与您的问题相矛盾,这意味着数据是连续的。因此,可以确定的是,数据是连续的,或者一个计算可以用512个周期来完成?数据是连续的,每个时钟周期都会采集一个新样本。如果每512个周期计算一个值是可以的,那么您可以这样做:使用双端口块RAM。端口A将新值作为环形缓冲区连续写入512个地址。这将保留最新的512个值。端口B用于扫描所有512个值,并将其与单个最大寄存器进行比较。512比较后,寄存器和读取指针复位。您可以通过分别使用256或128个entires的32或64位宽块RAM来改善循环时间。写入端口在进入下一个地址之前会将同一地址更新2或4倍。@MBo我们正在谈论的是可合成的VHDL代码,它会产生硬件:因此我们在FPGA中没有动态内存分配。此外,这篇文章是关于
O(n)
解决方案的,但问题是关于
O(1)
解决方案,这在硬件上是可能的,但会消耗大量资源。这不起作用,因为他在一个时钟周期内处理所有比较。这需要一个512端口的RAM。我是否可以将数组存储在BRAM中,并对BRAM进行排序,以便只需读取最终值即可获得最大值?例如,我是否可以向进程中添加排序算法,或者这是否意味着无法将其实现为BRAM?@Paebbels这是他目前正在做的事情,“但这不是他想要的,不是吗?”一些随机物理学家说,“不,你不能在RAM存储器中添加逻辑,因为你已经提出了这个理由。目前,RAM是简单的存储和获取组件。因此,对于订购,您需要执行大量的存储和获取操作。这需要一个额外的控制器加上大量的时钟周期来处理。在未来的FPGA中,我们希望能够进行内存操作,尽管这可能只适用于高端FPGA。您提供的代码不完整<代码>计数器
不会在任何地方声明。您不太可能找到使用更少资源和更少时钟周期的解决方案。您希望如何在不使用大量数据的情况下,在少于512个周期内找到最大512个值