我在访问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
答案 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) ;