我想在 verilog 中创建一个 64 位桶形移位器(现在旋转)。我想知道是否有办法在不写 65 部分案例陈述的情况下做到这一点?有没有办法编写一些简单的代码,例如:
Y = {S[i - 1:0], S[63:i]};
我在 Xilinx 中尝试了上面的代码并得到一个错误:i is not a constant。
主要问题:有没有办法在没有大量案例陈述的情况下做到这一点?
我想在 verilog 中创建一个 64 位桶形移位器(现在旋转)。我想知道是否有办法在不写 65 部分案例陈述的情况下做到这一点?有没有办法编写一些简单的代码,例如:
Y = {S[i - 1:0], S[63:i]};
我在 Xilinx 中尝试了上面的代码并得到一个错误:i is not a constant。
主要问题:有没有办法在没有大量案例陈述的情况下做到这一点?
为了清楚起见,我简化了一些规则,但这里是细节。
在声明中
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];
我发现做到这一点的最好方法是找到一种模式。当您想向左旋转 8 位信号 1 位(8'b00001111 << 1)时,结果是 = 8'b00011110),当您想向左旋转 9 位(8'b00001111 << 9)时,结果是相同的= 8'b00011110,并且还旋转了 17 个位置,这减少了您下一张桌子的可能性:
所以如果你看,表上所有数字的树第一位相当于旋转 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应该是 reg_in_1 的双倍,在这种情况下 reg_out_temp应该是 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 位。