Arrays 获取最后512个值的最大值的更节省资源的方法
我编写了一些VHDL代码,用于存储输入信号的最后512个值,并计算存储值中的最大值。这段代码可以工作,但使用了我的FPGA的大量LUT资源。代码的目的是计算最后512个样本的最大值,是否有更节省资源的方法来实现这一点?(重要的是,它计算最后512个值中的最大值,而不是从该输入中观察到的最大值,后者可以通过存储单个数字轻松实现) 或者,我是否有办法编写VHDL代码,使合成器将阵列实现为块RAM(BRAM)而不是LUT 我使用的合成器是LabVIEW FPGA(我相信它在内部使用XilinX ISE来编译/合成VHDL) 我的当前代码如下所示: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
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个值