用于环绕范围的Verilog模运算符

用于环绕范围的Verilog模运算符,verilog,system-verilog,hdl,caesar-cipher,Verilog,System Verilog,Hdl,Caesar Cipher,我的背景是软件,我是(系统)Verilog的新手,因此当我负责实现caesar移位器(将字符串中的每个字母移位N个字母,必要时环绕,例如ABCXYZ移位3变为DEFABC)时,我写了以下内容,希望能够减少代码重复,就像我在软件中所做的那样: /* every variable except 'direction' has the type 'byte' */ always_comb begin shifted_char = fresh_char; /* don't touch

我的背景是软件,我是(系统)Verilog的新手,因此当我负责实现caesar移位器(将字符串中的每个字母移位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;
新字母位置=字母位置+移位;
如果(新字母表位置>25)
新阿尔帕贝特位置-=26;
/*或者,对于倒档换档杆:*/
新字母位置=字母位置-移位;
如果(新字母表位置<0)
新阿尔帕贝特位置+=26;
…但我很好奇,想问这个问题,以及一个相关的问题(我希望更多的人能够回答):它可以用来制作一个正常的非2次幂计数器(例如。
count除非有专门的宏单元,否则2模的非幂将占用大量的门,并且具有相对较长的传播延迟,特别是如果作为纯战斗逻辑进行的话

请注意,根据您的合成器,变量“alphabet_start”、“alphabet_position”和“new_alphabet_position”将被推断为锁存器。您使用它们的方式是作为中间逻辑,因此,如果您不在该always块之外引用它们,并且您的合成器进行了适当的优化,那么它将不会是锁存器。为了保证它们不会丢失如果不是闩锁,则必须在if语句之外为其指定默认值

您声明除“方向”之外的所有变量都是“字节”类型,这意味着“移位方式”的值可能大于25或小于-25(“字节”默认为有符号值)。通过使用有符号值并添加三个值(
26+(字母表位置+移位方式)
)在使用模数之前,有一个不错的变化,即mod26将在10位有符号值上进行评估。这将比在8位值上使用更多的逻辑。有一个变化,您的合成器可能会进行一些优化,但可能不是很好

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

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

既然您使用System Verilog,您可能需要考虑{“代码”>“新鲜”字符在{[“a”):“z”} /代码>中,它的功能与“代码>”z“> =“新鲜”和“新鲜”,=“A”< /代码>。<代码>内< /COD> >关键字是可合成的,但我不知道它是否普遍支持。

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

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
始终\u梳
开始
shift_by_mod26=shift_by%26;如果保证asb(值)<26,则不需要/%26
字母表_start=(在{[“A”:“Z”]}内的新字符)?“A”:“A”;
if(在{[“A”:“Z”],[“A”:“Z”}内的新字符)
开始
如果(方向=“f”)
移位字符=新字符+移位字符(按26);
其他的
移位字符=新字符-移位字符(按26);
//如果移位字符大于127,则先减去26
//如果有符号(>127 unsigned为负符号),则返回正数
如果(8’(移位字符-26)>=字母表开始)
移位字符-=26;
else if(移位字符<字母表\u开始)
移位字符数+=26;
结束
其他的
开始
/*不要触摸非字母的字节*/
移位字符=新字符;
结束
结束
注意:如果“方向”不是“字节”类型,则对于每个匹配的“f”,其宽度必须至少为7位(无符号)或更大(符号不可知)



Cross post for a Cross post

即使从软件的角度来看,这也不是最有效的程序。至于硬件,你要求它合成几个全加器和除法器。可能会产生一个丑陋的结果,如果有的话。看起来你需要重新考虑整个算法。你还需要以某种方式将其与时钟同步。@Serge它在软件上的效率如何?关于硬件,合成工具不会找到逻辑上等价的东西并避免合成除法器吗?至于加法器,就是这样EEM对我来说是不可避免的,不是吗?我的意思是,因为你只使用ascii字母,你可能会找到一种不同的方法来解决这个问题,比如使用一个特殊的字母表,试图摆脱额外的+/-26操作,特别是模运算符。在软件中,你可以为程序提供额外的指令,以提高性能这并不意味着什么。在硬件方面,您开始浪费硅/LUT