Verilog访问特定位

时间:2013-05-09 18:02:19

标签: bit-manipulation verilog

我在访问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

2 个答案:

答案 0 :(得分:3)

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

有多种方法可以做你想要的但我建议使用一个临时的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

(对ab_lsb和ab_msb的赋值可能是有条件的。否则一个简单的“{ab_msb,ab_lsb}&lt; = 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!

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

使操作的位宽自动确定的一种方法是使用连接运算符:

ab_msb <= {A*B} >> 32;  // Don't do this -- it still won't work!

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

ab_msb <= {{32'd0, A}*B} >> 32;

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

ab_lsb <= A*B;

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

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

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

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

答案 1 :(得分:0)

您正在混合阻止和非阻止分配:

{C,Res}<={A*B}[63:32];  //< non-blocking
multState=2;            //< blocking

这被认为是不好的做法。

不确定只有{A*B}的串联操作是否有效。充其量它什么都不做。

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

但是:

遗憾的是,不允许

x <= (a*b)[31:0]。如果x是32位,它将占用LSB,所以你只需要:

x <= (a*b)

您可以尝试使用MSB:

reg [31:0] throw_away;
{x, throw_away} <= (a*b) ;