Verilog 桶形移位器

发布于 2024-12-06 21:43:22 字数 234 浏览 4 评论 0原文

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

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

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

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

I want to create a 64-bit barrel shifter in verilog (rotate right for now). I want to know if there is a way to do it without writing a 65 part case statement? Is there a way to write some simple code such as:

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

I tried the code above in Xilinx and get an error: i is not a constant.

Main Question: Is there a way to do this without a huge case statment?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

邮友 2024-12-13 21:43:22

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

在该语句中,

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

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

标识符[constant_expression:constant_expression]

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

identifier [ expression +:constant_expression ]

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

I've simplified some of the rules for clarity, but here are the details.

In the statement

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

you have a concatenation of two signals, each with a constant part select. A constant part select is of the form

identifier [ constant_expression : constant_expression ]

but your code uses a variable for the first expression. As you saw this isn't allowed, but you are correct in that there are ways to avoid typing a large case statement. What you can use instead is an indexed part select. These are of the form

identifier [ expression +: constant_expression ]

identifier [ expression -: constant_expression ]

These constructs enforce that the width of the resulting signal is constant, regardless of the variable on the left side.

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]

Rather than trying to build one signal out of two part selects, you can simply extend the input signal to 128 bits, and use a variable part select from that.

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

Another approach you could use is generate loops. This is a more general approach to replicating code based on a variable. It is much less efficient since it creates 4096 signals.

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];
同展鸳鸯锦 2024-12-13 21:43:22

我发现做到这一点的最好方法是找到一种模式。当您想要向左旋转 8 位信号 1 个位置 (8'b00001111 << 1) 时,结果为 = 8'b00011110),当您想要向左旋转 9 个位置 (8'b00001111 << 9) 时,结果为 = 8'b00011110)结果是相同的 = 8'b00011110,并且还旋转 17 个位置,这会减少您进入下一个的可能性表:

 PATTERN_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 是 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 位。

The best way I found to do this is finding a pattern. When you want to rotate left an 8 bit signal 1 position (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:

PATTERN_TABLE

so if you look, the tree first bits of all numbers on table equivalent to rotate 1 position (1,9,17,25...249) are equal to 001 (1)

the tree first bits of all numbers on table equivalent to rotate 6 positions (6,14,22,30...254) are equal to 110 (6)

so you can apply a mask (8'b00000111) to determine the correct shifting number by making zero all other bits:

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

reg_out_temp shall be the double of reg_in_1, in this case reg_out_temp shall be 16 bit and reg_in_1 8 bit, so you can get the carried bits to the other byte when you shift the data so you can combine them using an OR expression:

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

so by two clock cycles you have the result. For a 16 bit rotation, your mask shall be 8'b00011111 (8'h1F) because your shifts goes from 0 to 16, and your temporary register shall be of 32 bits.

找个人就嫁了吧 2024-12-13 21:43:22

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

reg [WIDTH-1:0] dumy; 
{dumy,out} = {in,in} >> shift_amount; 

I think the easiest solution to that problem is to replicate the input word using {} operator then shift right

reg [WIDTH-1:0] dumy; 
{dumy,out} = {in,in} >> shift_amount; 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文