可惜的位选和部分选择功能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位所需的几乎所有计算,您可能会要求一些不可能的事情。
它不混合非阻塞和阻塞任务是问题。 AIUI的问题来自于使用阻塞分配来在不同的硬件块之间进行通信。 http://www.sigasi.com/content/verilogs-major-flaw – 2013-05-10 11:04:00
@MartinThompson我曾看过,但没有完整阅读。我所拿走的所有东西都是'对于同步设计,这使它们无害',但我从来没有在Verilog中遇到过这个问题,尽管VHDL用户有时确实指出这个错误在VHDL中绝不会发生;) – Morgan 2013-05-10 11:58:15
从我的关键位(坦率地说,非Verilogger)的观点是,你必须从不*使用*阻塞*赋值*通信*。其他任何东西都很好......而且VHDL通过不允许在进程之外访问变量(具有阻塞语义)来强制执行。 – 2013-05-10 12:12:19