2013-05-09 204 views
4

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

`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 

回答

0

你混合阻塞这里非阻塞赋值:

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

这被认为是不好的做法。

不确定只有{A*B}的连接操作是否有效。最好它什么都不做。

你编码的方式看起来像你最终会得到2个硬件乘法器。是什么让你说你没有64位的reg,可用? reg不一定要暗示人字拖。如果你有2个32位寄存器,那么你可以有1个64位寄存器。我会亲自做1行的乘法运算,然后将结果拆分并输出为2个32位段。

但是:

x <= (a*b)[31:0]不幸不允许的。如果x是32位的,将采取最低有效位,因此,所有你需要的是:

x <= (a*b) 

采取的MSB你可以尝试:

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

它不混合非阻塞和阻塞任务是问题。 AIUI的问题来自于使用阻塞分配来在不同的硬件块之间进行通信。 http://www.sigasi.com/content/verilogs-major-flaw – 2013-05-10 11:04:00

+0

@MartinThompson我曾看过,但没有完整阅读。我所拿走的所有东西都是'对于同步设计,这使它们无害',但我从来没有在Verilog中遇到过这个问题,尽管VHDL用户有时确实指出这个错误在VHDL中绝不会发生;) – Morgan 2013-05-10 11:58:15

+0

从我的关键位(坦率地说,非Verilogger)的观点是,你必须从不*使用*阻塞*赋值*通信*。其他任何东西都很好......而且VHDL通过不允许在进程之外访问变量(具有阻塞语义)来强制执行。 – 2013-05-10 12:12:19

3

可惜的位选和部分选择功能Verilog是表达式操作数的一部分。它们不是Verilog运算符(参见Verilog 2005标准文档的第5.2.1节,IEEE标准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 } < = A * B;“当然也会这样做的。”)

请注意,我使用阻塞赋值来分配'tmp',因为我需要下面两行中的值。这也意味着从外部 访问'tmp'是不安全的。

另请注意,这里不需要连接hack {A * B},因为A * B被分配给64位寄存器。这也符合IEEE标准2064至05年的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

请注意,ab_msb <= {{32'd0,A} * B} >> 32'中的外部级联不是必需的;内部一个足以进行乘法和64位下移。 – EML 2013-05-14 11:06:47