Verilog 桶形移位器

问题描述 投票:0回答:3

我想用verilog创建一个64位桶形移位器(现在向右旋转)。我想知道是否有一种方法可以在不写 65 部分案例陈述的情况下做到这一点?有没有办法编写一些简单的代码,例如:

    Y = {S[i - 1:0], S[63:i]};

我在 Xilinx 中尝试了上面的代码并得到一个错误:i 不是常量。

主要问题:有没有办法在没有大量案例陈述的情况下做到这一点?

rotation verilog bit-shift shift case-statement
3个回答
17
投票

为了清晰起见,我简化了一些规则,但详细信息如下。

声明中

Y = {S[i - 1:0], S[63:i]};

您有两个信号的串联,每个信号都有一个恒定的部分选择。常数部分选择的形式为

标识符 [ 常量表达式 : 常量表达式 ]

但是您的代码使用变量作为第一个表达式。正如您所看到的,这是不允许的,但您是正确的,因为有一些方法可以避免键入大的 case 语句。您可以使用索引零件选择来代替。这些是以下形式

标识符[表达式+:常量表达式]

标识符[表达式-:常量_表达式]

这些构造强制结果信号的宽度是恒定的,无论左侧的变量如何。

wire [HIGH_BIT:LOW_BIT] signalAdd,signaSub;
signalAdd[some_expression +: some_range];
signalSub[some_expression -: some_range];
//Resolves to
signalAdd[some_expression + (some_range - 1) : some_expression];
signalSub[some_expression                    : some_expression - (some_range - 1)];

//The location of the high value depends on how the signal was declared:
wire [15: 0] a_vect;
wire [0 :15] b_vect;
a_vect[0 +: 8] // a_vect[7 : 0]
b_vect[0 +: 8] // b_vect[0 : 7]

您可以简单地将输入信号扩展到 128 位,并使用其中的可变部分选择,而不是尝试从两个部分选择中构建一个信号。

wire [63:0] data_in,data_out;
wire [127:0] data_in_double;
wire [5:0] select;

//Concatenate the input signal
assign data_in_double = {data_in,data_in};

//The same as signal[select + 63 : select]
assign data_out = data_in_double[select+63-:64];

您可以使用的另一种方法是生成循环。这是基于变量复制代码的更通用方法。它的效率要低得多,因为它创建了 4096 个信号。

wire [63:0] data_in,data_out;
wire [127:0] data_in_double;
wire [5:0] select;
wire [63:0] array [0:63];
genver i;

//Concatenate the input signal
assign data_in_double = {data_in,data_in};
for(i=0;i<64;i=i+1)
  begin : generate_loop
  //Allowed since i is constant when the loop is unrolled
  assign array[i] = data_in_double[63+i:i];
  /*
  Unrolls to 
  assign array[0] = data_in_double[63:0];
  assign array[1] = data_in_double[64:1];
  assign array[2] = data_in_double[65:2];
  ...
  assign array[63] = data_in_double[127:64];
  */
  end

//Select the shifted value
assign data_out = array[select];

0
投票

我发现做到这一点的最好方法是找到一种模式。当您想要向左旋转 8 位信号 1 位置时 (8'b00001111 << 1) the result is = 8'b00011110) also when you want to rotate left 9 positions (8'b00001111 << 9) the result is the same = 8'b00011110, and also rotating 17 positions, this reduce your possibilities to next table:

所以如果你看一下,表上所有数字的树第一位相当于旋转1个位置(1,9,17,25...249)等于001(1)

相当于旋转 6 个位置(6,14,22,30...254)的表上所有数字的树第一位等于 110 (6)

因此您可以应用掩码(8'b00000111)通过将所有其他位清零来确定正确的移位数:

reg_out_temp <= reg_in_1 << (reg_in_2 & 8'h07);

reg_out_temp shall 是 reg_in_1 的双倍,在这种情况下 reg_out_temp shall 是 16 位,而 reg_in_1 是 8 位,因此当您移位数据时,您可以将携带的位移至另一个字节,以便您可以使用 OR 将它们组合起来表达:

reg_out <= reg_out_temp[15:8] | reg_out_temp[7:0];

所以通过两个时钟周期你就得到了结果。对于 16 位旋转,您的掩码为 8'b00011111 (8'h1F),因为您的移位从 0 到 16,并且您的临时寄存器应为 32 位。


0
投票

我认为该问题最简单的解决方案是使用 {} 运算符复制输入单词,然后右移

reg [WIDTH-1:0] dumy; 
{dumy,out} = {in,in} >> shift_amount; 
© www.soinside.com 2019 - 2024. All rights reserved.