Verilog 访问特定位

far*_*zin 6 verilog bit-manipulation

我在访问 Verilog 中的 32 个最高有效位和 32 个最低有效位时遇到问题。我编写了以下代码,但收到错误“非法部分选择表达式”这里的要点是我无权访问 64 位寄存器。能否请你帮忙。

`MLT: begin
  if (multState==0) begin
    {C,Res}<={A*B}[31:0];
    multState=1;
  end
  else
  begin
    {C,Res}<={A*B}[63:32];
    multState=2;  
  end
Run Code Online (Sandbox Code Playgroud)

Cli*_*nna 7

不幸的是,Verilog 的位选择和部分选择功能是表达式操作数的一部分。它们不是 Verilog 运算符(请参阅 Verilog 2005 标准文档 IEEE Std 1364-2005 的第 5.2.1 节),因此不能应用于任意表达式,而只能直接应用于寄存器或连线。

有多种方法可以完成您想要的操作,但我建议使用临时 64 位变量:

wire [31:0] A, B;
reg  [63:0] tmp;
reg  [31:0] ab_lsb, ab_msb;

always @(posedge clk) begin
  tmp = A*B;
  ab_lsb <= tmp[31:0];
  ab_msb <= tmp[63:32];
end
Run Code Online (Sandbox Code Playgroud)

(对 ab_lsb 和 ab_msb 的赋值可以是有条件的。否则,简单的“{ab_msb, ab_lsb} <= A*B;”当然也能达到目的。)

请注意,我使用阻塞分配来分配“tmp”,因为我需要以下两行中的值。这也意味着从该始终块外部访问“tmp”是不安全的。

另请注意,此处不需要串联 hack {A*B},因为 A*B 已分配给 64 位寄存器。这也符合 IEEE Std 1364-2005 第 5.4.1 节中的建议:

通过将结果分配给足够宽的东西来容纳它,可以在不丢失任何溢出位的情况下执行乘法。

然而,你说:“这里的重点是我无权访问 64 位寄存器”。

因此,我将描述一个不使用任何 Verilog 64 位寄存器的解决方案。然而,这不会对最终的硬件产生任何影响。它只会在 Verilog 代码中看起来有所不同。

这个想法是通过移位 A*B 的结果来访问 MSB 位。以下简单版本将不起作用:

ab_msb <= (A*B) >> 32;  // Don't do this -- it won't work!
Run Code Online (Sandbox Code Playgroud)

这不起作用的原因是 A*B 的宽度由赋值的左侧决定,即 32 位。因此A*B的结果将只包含结果的低32位。

使操作的位宽度自行确定的一种方法是使用串联运算符:

ab_msb <= {A*B} >> 32;  // Don't do this -- it still won't work!
Run Code Online (Sandbox Code Playgroud)

现在乘法的结果宽度是使用最大值确定的。其操作数的宽度。不幸的是,两个操作数都是 32 位,因此我们仍然有 32 位乘法。因此我们需要将一个操作数扩展为 64 位,例如通过附加零(我假设是无符号操作数):

ab_msb <= {{32'd0, A}*B} >> 32;
Run Code Online (Sandbox Code Playgroud)

访问 lsb 位很容易,因为无论如何这是默认行为:

ab_lsb <= A*B;
Run Code Online (Sandbox Code Playgroud)

所以我们最终得到以下替代代码:

wire [31:0] A, B;
reg  [31:0] ab_lsb, ab_msb;

always @(posedge clk) begin
  ab_lsb <= A*B;
  ab_msb <= {{32'd0, A}*B} >> 32;
end
Run Code Online (Sandbox Code Playgroud)

Xilinx XST 14.2 为两个版本生成相同的 RTL 网表。我强烈推荐第一个版本,因为它更容易阅读和理解。如果仅使用“ab_lsb”或“ab_msb”,综合工具将自动丢弃“tmp”未使用的位。所以真的没有什么区别。

如果这不是您要查找的信息,您可能应该澄清为什么以及如何“无法访问 64 位寄存器”。毕竟,您还尝试在代码中访问 64 位值的位 [63:32]。由于您无法在不执行低 32 位所需的几乎所有计算的情况下计算乘积 A*B 的高 32 位,因此您可能会要求一些不可能的东西。


Mor*_*gan 0

您在这里混合阻塞和非阻塞分配:

{C,Res}<={A*B}[63:32];  //< non-blocking
multState=2;            //< blocking
Run Code Online (Sandbox Code Playgroud)

这被认为是不好的做法。

不确定连接操作是否{A*B}有效。充其量它什么也不做。

您编码的方式看起来最终会得到 2 个硬件乘法器。是什么让你说你没有可用的 64 位注册表?reg 不一定意味着触发器。如果您有 2 个 32 位寄存器,那么您可以有 1 个 64 位寄存器。我个人会在 1 行上进行乘法,然后将结果拆分并输出为 2 个 32 位部分。

然而 :

x <= (a*b)[31:0]不幸的是不允许。如果 x 是 32 位,它将采用 LSB,所以您需要的是:

x <= (a*b)
Run Code Online (Sandbox Code Playgroud)

要获取 MSB,您可以尝试:

reg [31:0] throw_away;
{x, throw_away} <= (a*b) ;
Run Code Online (Sandbox Code Playgroud)