Verilog Barrel Shifter

时间:2011-09-25 04:08:49

标签: rotation verilog bit-shift shift case-statement

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

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

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

主要问题:如果没有大量的案例陈述,有没有办法做到这一点?

2 个答案:

答案 0 :(得分:10)

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

声明

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

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

标识符[constant_expression:constant_expression]

但您的代码使用第一个表达式的变量。如您所见,这是不允许的,但您是正确的,因为有办法避免键入大型case语句。您可以使用的是索引部分选择。这些是

的形式

标识符[表达式+:constant_expression]

标识符[表达式 - :constant_expression]

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

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];

答案 1 :(得分:0)

我发现这样做的最好方法是找到一种模式。当你想向左旋转8位信号1位置(8&#39; b00001111&lt;&lt;&lt; 1)时,结果是= 8&#39; b00011110)当你想要向左旋转9个位置时(8&#39; b00001111&lt; ;&lt; 9)结果相同= 8&#39; b00011110,并且还旋转了17个位置,这减少了你对下一个表的可能性:

PATTERN_TABLE

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

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

所以你可以通过使所有其他位为零来应用一个掩码(8&#39; b00000111)来确定正确的移位数:

reg_out_temp&lt; = reg_in_1&lt;&lt; (reg_in_2&amp; 8&#39; h07);

reg_out_temp 必须是reg_in_1的两倍,在这种情况下,reg_out_temp 必须为16位且reg_in_1为8位,因此您可以将携带的位转换为另一个字节您可以移动数据,以便使用OR表达式组合它们:

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

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