【问题标题】:VHDL simulation stuck in for loopVHDL模拟卡在for循环中
【发布时间】: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 cy := (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


【解决方案1】:

我认为在 numeric_std 函数调用中实现蒙哥马利乘数可能不会像您希望的那样改善模拟(同时提供综合资格)。

问题在于动态详细的子程序调用的数量与它们的操作数大小与适合您的 CPU-running-Modelsim 的 L1/L2/L3 缓存的情况。

它确实为在 FPGA 或 SIMD GPU 实现中的目标合成创造了奇迹。

请参阅Subversion Repositories BasicRSA 文件 modmult.vhd(具有通用大小)。我成功地将其转换为使用 numeric_std[_unsigned]。

如果我没记错的话,这似乎受到了启发 David Narh Amanor 在 2005 年的硕士论文 (Efficient Hardware Architectures for Modular Multiplication) 概述了各种字长的 Java 和 VHDL 实现。

我找到了 Stackoverflow 问题 (Montgomery multiplication VHDL Implementation) 中提到的 OpenCores 实现,并在 SVN 存储库中找到了通用大小的版本(可下载的版本是 16 位),并在 A 1024 – Bit Implementation of the Faster Montgomery Multiplier Using VHDL 中提到了论文(作者 David Narh Anamor,原始链接已过期)。请注意引用的 42 微秒以下的 FPGA 实现性能。

请注意,由泛型指定的长度为 1024 的版本仍会使用长度为 1024 的操作数(尽管不是“*”、“mod”或“/”)执行动态详细的函数调用。你仍然会使用动态详细(在表达式堆栈上传递)1024 位参数进行数百万次函数调用。我们只是更改了数百万次大参数子例程调用以及它们可以花费的时间。

这也带来了在 VHDL 中实现整数向量(bignum 等效项)的可能性,这可能会进一步提高仿真性能(您可能处于未知领域)。

使用可变参数的 OpenCores 模型的基于子程序的版本会说明问题。 (无论你是否可以让任何人向他们展示正在执行的仿真模型,或者是否有这种长时间的停顿被每个人偷偷看一眼挂钟并看起来很无聊而打断)。

【讨论】:

    猜你喜欢
    • 2021-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多