我想访问矢量的特定元素,并在一个时钟中添加它们的值。缓存输入已在此计算之前写入,因此可以立即访问它们。
type cache_type is array (89 downto 0) of std_logic_vector(14 downto 0);
signal input_cache : cache_type := (others => (others => '0'));
signal cluster_square_sum : integer := 0;
calc: process (clk)
begin
if rising_edge(clk) and cache_ready then
cluster_square_sum <= conv_integer(input_cache(5)) +
conv_integer(input_cache(6)) + conv_integer(input_cache(7)) +
conv_integer(input_cache(12)) + conv_integer(input_cache(13)) +
conv_integer(input_cache(14)) + conv_integer(input_cache(15)) + ...
end if;
end process;
如果没有在添加中明确写出所有需要的元素,我如何实现此行为?我已经考虑过程中的变量迭代器,但由于单个时钟计算它不起作用。
实际上,我首先不需要进程,我可以使用“when语句”直接在架构中编写我的总和
cluster_square_sum <= conv_integer(input_cache(5)) +
conv_integer(input_cache(6)) + conv_integer(input_cache(7)) +
conv_integer(input_cache(12)) + conv_integer(input_cache(13)) +
conv_integer(input_cache(14)) + conv_integer(input_cache(15)) + ...
when cache_ready <= '1';
不幸的是,我不知道如何以一种方式实现我的行为。
答案 0 :(得分:2)
关于你的问题的一些事情尚不清楚,但关于这个问题的一件事是明确的:更好的设计会让你使用类型系统,而不是每一行都对抗它。
有一点不清楚:你在缓存中存储了什么?它是专门为数字保留的,还是可以存储数字,文本,指令等的CPU缓存?
如果它专门用于数字数据,那么
type cache_type is array (89 downto 0) of natural range 0 to 2**14 - 1;
会简化你的总和。或等效的有符号整数范围,以适合您的应用程序为准。这也使设计意图清晰。或者您可以使用signed
中的unsigned
或numeric_std
。
cluster_square_sum <= input_cache(5) + input_cache(6) + input_cache(7) + ...
when cache_ready <= '1';
它还不清楚你正在总结的缓存子集,特别是因为它不是[MCVE]并且似乎覆盖了非连续范围。所以我只需要猜测它是一个固定的连续子集;你可以使用一个循环。
calc: process (clk)
variable running_total : natural;
begin
if rising_edge(clk) then
if cache_ready then
running_total := 0;
for i in lower_bound to upper_bound loop
running_total := running_total + input_cache(6)(i);
end loop;
cluster_square_sum <= running_total;
end if;
end if;
end process;
该变量允许即时赋值(变量赋值语义)而不是推迟赋值(信号赋值语义),因此您可以获得运行总计。
如果边界不是常数(或泛型),或者范围不是连续的,则此策略需要进行一些修改。
另一个不明确的事情是你的速度(延迟和吞吐量)和逻辑大小目标。这将在单个周期中执行每次添加,但该周期可能相当慢。如果您可能需要每个时钟周期输出一个具有真实时钟频率的输出,那么您必须对其进行流水线操作。
或者如果在需要输出之前cache_ready
之后有足够的周期,则将循环和计算嵌入由cache_ready
触发的状态机中。这可以在每个时钟周期执行一次加法(和循环迭代),允许input_cache
成为块Ram而不是单独可访问的寄存器,用于非常小且快速的时钟设计。 (在这种情况下,每个时钟只添加一个,您可以安全地使用running_total
的变量或信号。
答案 1 :(得分:1)
在所有情况下,我建议使用一个函数。
在你想要添加的元素中似乎没有任何逻辑,所以我让函数接受一组元素索引。
“最小”示例:
library IEEE;
use IEEE.std_logic_1164.all;
entity e is
port(clk: in std_logic);
end entity;
architecture a of e is
use IEEE.numeric_std.all;
type cache_type is array(0 to 89) of std_logic_vector(14 downto 0);
signal input_cache : cache_type := (
5 => "000010101010101",
6 => "000001010101010",
7 => "000000101010101",
12 => "000000010101010",
13 => "000000001010101",
14 => "000000000101010",
15 => "000000000010101",
others => (others => '0'));
type integer_array is array(natural range <>) of integer;
constant elements_to_add : integer_array := (5, 6, 7, 12, 13, 14, 15);
signal cluster_square_sum : integer := 0;
function add_elements(input_array : cache_type; element_idxs: integer_array) return integer is
variable output : integer := 0;
begin
for idx in element_idxs'low to element_idxs'high loop
output := output + to_integer(unsigned(input_array(element_idxs(idx))));
end loop;
return output;
end;
begin
calc: process(clk)
begin
if rising_edge(clk) then
cluster_square_sum <= add_elements(input_cache, elements_to_add);
end if;
end process;
end architecture;
请注意,您也可以使用此功能进行无处理/直接分配。
Plus testbench:
entity e_tb is end entity;
library IEEE;
architecture a of e_tb is
use IEEE.std_logic_1164.all;
signal clk : std_logic := '0';
begin
UUT : entity work.e port map (clk => clk);
test: process begin
wait for 1 ns;
clk <= '1';
wait for 1 ns;
clk <= '0';
wait;
end process;
end architecture;
请注意,如果要在FPGA中实现此功能,则需要相当多的资源并且会失去性能。管道设计会更好:使用多个时钟周期来添加元素。