【问题标题】:Verilog modulus operator for wrapping around a range用于环绕范围的 Verilog 模数运算符
【发布时间】:2017-11-22 02:06:22
【问题描述】:

我的背景是软件,我是 (System)Verilog 的新手,所以当我负责实现一个凯撒移位器时(将字符串中的每个字母移位 N 个字母,必要时环绕,例如 ABCXYZ 移位 3 变为 DEFABC),我写了以下内容,希望能够减少代码重复,就像我在软件中一样:

  /* every variable except 'direction' has the type 'byte' */
  always_comb
  begin
    shifted_char = fresh_char; /* don't touch bytes that aren't letters */
    is_lower_case = "z" >= fresh_char && fresh_char >= "a";
    is_upper_case = "Z" >= fresh_char && fresh_char >= "A";
    if (is_lower_case || is_upper_case)
      begin
        unique if (is_lower_case)
          alphabet_start = "a";
        else if (is_upper_case)
          alphabet_start = "A";
        alphabet_position = fresh_char - alphabet_start;
        if (direction == "f") /* direction is a module parameter: f for forwards results in a shifter, any other value results in an 'unshifter' */
          new_alphabet_position = (26 + (alphabet_position + shift_by)) % 26;
        else
          new_alphabet_position = (26 + (alphabet_position - shift_by)) % 26;
        shifted_char = new_alphabet_position + alphabet_start;
      end
  end

我的问题是(假设它是一个前移器):关于“% 26”部分,我是否可以期望合成器推断出它在该点获得的可能值的范围是 [26, 26+25+ 25] ([26, 76]) 所以只有两种情况逻辑需要区分(> 26和> 52),而不是[处理所有可能的256个不同输入时的智能调用是什么-(会是考虑>26、>52、>78 等案例...?还是有更好的方法?我跑题了...)]?

我总是可以做到以下几点:

new_alphabet_position = alphabet_position + shift_by;
if (new_alphabet_position > 25)
  new_alpahbet_position -= 26;

/* Or, for the reverse shifter: */

new_alphabet_position = alphabet_position - shift_by;
if (new_alphabet_position < 0)
  new_alpahbet_position += 26;

...但是很好奇并想问这个问题,以及一个相关的问题(我希望更多人能够回答):它可以用来制作普通的非 2 次幂计数器吗(例如。 计数 https://forums.xilinx.com/t5/Synthesis/Modulus-synthesizable-or-non-synthesizable/td-p/747493

【问题讨论】:

  • 即使从软件的角度来看,这也不是最有效的程序。至于硬件,您要求它合成几个全加器和除法器(%)。如果有的话,可能会产生丑陋的结果。看起来你需要一起重新考虑算法。此外,您还需要以某种方式将其与时钟同步。
  • @Serge 它在软件中的效率如何?关于硬件,综合工具不会找到逻辑上等效的东西并避免合成分频器吗?至于加法器,这对我来说似乎是不可避免的;不是吗?
  • 我的意思是,由于您只使用 ascii 字母,您可能能够找到一种不同的方法来解决问题,例如使用特殊字母表来尝试摆脱额外的 +/- 26 操作和特别是模运算符。在软件中,您可以为性能并不重要的程序提供额外的指令。在硬件中,您开始浪费硅片/lut,这可能会显着影响性能、功耗、面积、成本……

标签: verilog system-verilog hdl caesar-cipher


【解决方案1】:

除非有一个专门的宏单元,否则非 2 模数的幂将占用大量门并且具有相对较长的传播延迟,尤其是在作为纯组合逻辑完成时。

请注意,根据您的合成器,变量“alphabet_start”、“alphabet_position”和“new_alphabet_position”可能会被推断为锁存器。你使用它们的方式是作为中间逻辑,所以如果你不在这个总是块之外引用它们并且你的合成器有不错的优化,那么它就不会是一个锁存器。为保证它们不会成为闩锁,必须在 if 语句之外为其赋予默认值。

您声明除 'direction' 之外的所有变量都是 'byte' 类型,这意味着 'shift_by' 的值可能大于 25 或小于 -25(默认情况下,'byte' 是有符号值)。通过在使用模数之前使用有符号值并添加三个值 (26 + (alphabet_position + shift_by)),mod26 将在 10 位有符号值上进行评估,这是一个不错的变化。这将比在 8 位值上使用更多的逻辑。您的合成器可能会进行一些优化,但可能不是很好。

如果您可以保证 'shift_by' 小于 26 且大于 -26(如果无符号则大于或等于 0),那么您不需要 'alphabet_position' 或 'new_alphabet_position'。只需添加或减去“shift_by”并计算是否超出范围。对于范围检查,首先检查8'(shifted_char-26) &gt;= alphabet_start。这样做的原因是为了确保我们比较的是正数。 "z"+25 是 147,对于有符号的 8 位值来说是负数。 8'() 将其转换为 8 位无符号值,以修剪任何非零中间第 9 位以上。如果不需要调整,则检查 hifted_char &lt; alphabet_start 是否已经处理了溢出到负数的可能性。

如果你不能保证'shift_by'在范围内,那么你没有选择修改它。幸运的是,这是一个 8 位有符号值,比原来的 10 位有符号值更糟糕。这不是理想的,但我能提供的最好的。让“shift_by”的驱动程序分配一个合法的值然后添加更多的逻辑来修改它是更理想的。

由于您使用的是 SystemVerilog,您可能需要考虑使用fresh_char inside { ["A":"Z"] },它在功能上与"Z" &gt;= fresh_char &amp;&amp; fresh_char &gt;= "A" 相同。 inside is 关键字是为了可合成,但不知道是否普遍支持。

考虑以下代码。它可能不是最优化的,但比您的原始代码更优化:

always_comb
begin
  shift_by_mod26 = shift_by % 26; // %26 is not need if guaranteed asb(value) < 26
  alphabet_start = (fresh_char inside { ["A":"Z"] }) ? "A" : "a";
  if ( fresh_char inside { ["A":"Z"], ["a":"z"] } )
  begin
     if (direction == "f")
       shifted_char = fresh_char + shift_by_mod26;
     else
       shifted_char = fresh_char - shift_by_mod26;

     // subtract 26 first in case shifted_char is >127
     // bring back to a positive if signed (>127 unsigned is negative signed)
     if (8'(shifted_char-26) >= alphabet_start)
       shifted_char -= 26;
     else if (shifted_char < alphabet_start)
       shifted_char += 26;
  end
  else
  begin
    /* don't touch bytes that aren't letters */
    shifted_char = fresh_char;
  end
end

注意:如果'direction'不是'byte'类型,那么对于每个匹配“f”,它必须至少为7位(无符号)或更大(符号不可知)


转帖answer 转帖question

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-14
    • 2011-05-09
    • 2011-01-21
    • 1970-01-01
    • 2010-09-09
    • 1970-01-01
    • 2013-05-24
    相关资源
    最近更新 更多