我在下面的代码中遇到了for循环的问题 - 在模拟中它显示了循环的唯一最后一个增量,例如:
在我给出的输入上(显然在w0,w1,w2的8位SIGNED中):
x1 = 1; x2 = 1; w0 = -32; w1 = 63; w2 = 63
并在输出上我收到 u = 31
而不是 u = 94.
所以似乎方程是:
u = (x2 * w2) - w0
代替:
u = (x1 * w1) + (x2 * w2) - w0
我知道VHDL中的循环与C中的循环不同,但变量的使用应该可以解决问题 . 不幸的是,我错过了一些东西 . 它可能是什么?
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
ENTITY NeuronBehavioral IS
GENERIC ( n: INTEGER := 1;
m: INTEGER := 2;
b: INTEGER := 8);
PORT ( x1 : in STD_LOGIC;
x2 : in STD_LOGIC;
w0 : in SIGNED (b-1 downto 0); --11100000 (-32)
w1 : in SIGNED (b-1 downto 0); --00111111 (63)
w2 : in SIGNED (b-1 downto 0); --00111111 (63)
u : out STD_LOGIC_VECTOR (b-1 downto 0));
END NeuronBehavioral;
ARCHITECTURE Behavioral OF NeuronBehavioral IS
TYPE weights IS ARRAY (1 TO n*m) OF SIGNED(b-1 DOWNTO 0);
TYPE inputs IS ARRAY (1 TO m) OF SIGNED(b-1 DOWNTO 0);
TYPE outputs IS ARRAY (1 TO n) OF SIGNED(b-1 DOWNTO 0);
BEGIN
PROCESS (w0, w1, w2, x1, x2)
VARIABLE weight: weights;
VARIABLE input: inputs;
VARIABLE output: outputs;
VARIABLE prod, acc: SIGNED(b-1 DOWNTO 0);
BEGIN
input(1) := "0000000" & x1;
input(2) := "0000000" & x2;
weight(1) := w1;
weight(2) := w2;
L1: FOR i IN 1 TO n LOOP
acc := (OTHERS => '0');
L2: FOR j IN 1 TO m LOOP
prod := input(j)*weight(m*(i-1)+j);
acc := acc + prod;
END LOOP L2;
output(i) := acc + w0;
END LOOP L1;
u <= STD_LOGIC_VECTOR(output(1));
END PROCESS;
END Behavioral;
试验台:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
ENTITY NeuronTB IS
END NeuronTB;
ARCHITECTURE behavior OF NeuronTB IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT NeuronBehavioral
PORT(
x1 : IN std_logic;
x2 : IN std_logic;
w0 : IN SIGNED(7 downto 0);
w1 : IN SIGNED(7 downto 0);
w2 : IN SIGNED(7 downto 0);
u : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
--Inputs
signal x1 : std_logic := '0';
signal x2 : std_logic := '0';
signal w0 : SIGNED(7 downto 0) := (others => '0');
signal w1 : SIGNED(7 downto 0) := (others => '0');
signal w2 : SIGNED(7 downto 0) := (others => '0');
--Outputs
signal u : std_logic_vector(7 downto 0);
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: NeuronBehavioral PORT MAP (
x1 => x1,
x2 => x2,
w0 => w0,
w1 => w1,
w2 => w2,
u => u
);
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
x1 <= '1';
x2 <= '1';
w0 <= "11100000";
w1 <= "00111111";
w2 <= "00111111";
wait for 100 ns;
x1 <= '1';
x2 <= '0';
w0 <= "11100000";
w1 <= "00111111";
w2 <= "00111111";
wait for 100 ns;
x1 <= '0';
x2 <= '1';
w0 <= "11100000";
w1 <= "00111111";
w2 <= "00111111";
wait for 100 ns;
x1 <= '0';
x2 <= '0';
w0 <= "11100000";
w1 <= "00111111";
w2 <= "00111111";
wait;
end process;
END;
1 回答
该问题最初没有提供Minimal, Complete and Verifiable example,缺乏复制错误的方法,远远低于预期的结果 . 这不是实际问题的总障碍 .
有一个超出界限的错误
signed的类型的右 Watch 达式将具有被乘数(
input(j)
)和乘数(weight( m * (i - 1) + j)
)的长度之和的长度 .检测通过从赋值语句中的右 Watch 达式评估投影输出波形而产生的最终有效值,标准需要针对目标的每个元素的匹配元素(参见IEEE Std 1076-2008 14.7.3.4信号更新, - 1993年至2002年12.6.2信号值的传播) .
(当工具允许通过命令行标志或配置暂停执行此检查时,期望它在某个时刻完成,并且在消除它时性能会提高 . )
关于不需要MCVe,一些模拟器允许运行具有顶级端口的模型 . 通过为所有输入提供默认值可以识别此问题 . 根据VHDL修订版,带有to_string的报告语句(output(1)可以显示原始引用的答案 .
当使用ghdl运行时,设计规范在循环L2中产生了边界失败 .
在未标记的过程中更改prod的声明:
并赋予acc:
允许计算完成,生成
在流程中添加了最后一条语句:
对于非VHDL-2008兼容的模拟器,可以将to_string函数添加到process语句的声明性区域:
请注意,报告值是94的8位有符号值 .
还应检查prod,acc和u的声明,以确保设计能够在w0,w1和w2的输入值范围内产生结果 .
VHDL不仅强类型,而且特别关注数学意义 . 如果结果不正确,则会出错,因此“*”运算符的乘积具有足以产生有效数学结果的长度 . 这可以在numeric_std包体中看到 .
通过上述设计规范的补丁,测试平台可以生成:
因为
input(j)
只能是基于输入x1
和x2
的"00000000"或"000000001",所以可以替代上述更改:乘法器结果可以调整大小(取最低有效b长度位) . 最左边的乘数是0或1 .
因为
input(j)
的值为0或1(作为8位有符号值),所以可以消除第一个乘法:对于计算
weight
的索引的第二个乘数,观察所有变量是通用常量或在循环语句中隐式声明 . 虽然后者在VHDL中的执行时动态详细说明,但在遍历每个循环语句中的顺序语句期间,它们的值被认为是静态的 .循环语句中的语句序列在综合中展开 . 并发语句中的等价物是通过使用for语句将各种语句复制为并发语句 . 请注意,这将需要信号(共享变量不可移植,也不保证不同的供应商工具链支持) .
并发语句版本看起来像:
没有使用乘法且所有静态索引元素都是积累在两个地方 . MONITOR过程中的
wait for 0 ns;
语句是通过连续信号克服0延迟分配中的delta延迟 . (某处有某些事情正在进行离散事件,对于x1
和x2
,如果没有其他目的 . )这给出了与上面相同的答案:
并代表相同的硬件 .