【发布时间】:2015-06-05 21:55:04
【问题描述】:
我正在为我编写的一些 VHDL 进行仿真测试,当我在 ModelSim 中运行它时,它会卡住。当我点击“break”时,它有一个箭头指向以下函数中的For 循环:
function MOD_3 (a, b, c : UNSIGNED (1023 downto 0)) return UNSIGNED is
VARIABLE x : UNSIGNED (1023 downto 0) := TO_UNSIGNED(1, 1024);
VARIABLE y : UNSIGNED (1023 downto 0) := a;
VARIABLE b_temp : UNSIGNED (1023 downto 0) := b;
begin
for I in 0 to 1024 loop
if b_temp > 0 then
if b_temp MOD 2 = 1 then
x := (x * y) MOD c;
end if;
y := (y * y) MOD c;
b_temp := b_temp / 2;
else
exit;
end if;
end loop;
return x MOD c;
end function;
我最初将此作为while 循环,我意识到它不适合合成。所以我将它转换为for 循环,条件是b_temp 大于0。b_temp 是1024 位unsigned,所以如果它是可以用1024 位表示并除以的最大数一半(我在每次迭代中都这样做)1024 次,不应该是 0 吗?
我觉得我的问题在于大乘法...如果我注释掉 x := (x * y) MOD c 和 y := (y * y) MOD c 然后它退出循环。所以我唯一能想到的是执行这些 1024 位乘法需要太长时间?如果是这种情况,是否有任何内置方法可以优化它以使其更快,或者是我实现 Karatsuba 乘法等的唯一选择......?
【问题讨论】:
-
在其中放置一个打印循环计数器的报告语句。循环的时间可能比您想象的要长。另外,你用的是哪个sim?可能值得尝试其他人。此外,C 的值是否有任何限制?如果你认为
*很慢,那么你还没有对mod进行基准测试...(不过不用担心mod 2,它应该被优化) -
我同意布赖恩的观点,
mod是通过除法执行的,这比乘法慢很多。如果你的目标是综合,那么你做错了。mod操作是不可合成的(可能除以 2),2 1024 位数字的乘法将占用大量的嵌入式乘法器并给出非常大的关键路径。更糟糕的是,你将这些乘法中的 1025 链接到 2 个不同的变量上,所以这些不敬的数量分别乘以 2050 和 1025!对于综合,您的算法需要位串行以重用相同的硬件。 -
次要修正:
mod通过小常数(不仅仅是 2,例如 28)是可综合的,至少使用 Xilinx XST。还有一个附加说明:这里的“位串行”可能意味着 1024 * 1 操作是可能的。我会更进一步并使用 1024*16 来充分利用乘数。我对实现mod的最佳方法没有明确的想法,除了注意到由于C 的唯一用途是用于大量的Mod 操作,您可以预先计算1/C 并除以倒数乘法。这需要测试其数值属性,您可能需要 2048 位精确的倒数以避免舍入错误。 -
@Brian 我是正确的,我不知道。不过我测试了它,对于
unsigned(7 downto 0) mod 3,甚至对于unsigned(7 downto 0) mod unsigned(2 downto 0),效果很好,但在unsigned(255 downto 0)上也是一样的失败(在等待1 小时的综合结果后不耐烦了)。我找不到关于 XST 的任何文档,但它似乎是作为一系列比较器和加法器/减法器实现的,并且具有可怕的关键路径。 -
感谢大家的投入,我确实提到了合成,但我要说的最远的是使用 ModelSim SE 进行仿真。 C 的唯一限制是它总是 1024 位并且可能是素数。我将尝试实现 C 的预计算,看看它是否有帮助。除此之外,听起来我真的别无选择,只能实现针对大比特大小优化的新 mod 和乘法算法?
标签: loops vhdl multiplication