我似乎无法弄清楚在case块中执行{c_out, result} = {a + b + c_in}
的正确语法是什么。 c_out
在我的测试平台上不起作用,如果我添加32'hffffffff + 1'b1
,我会c_out = 0, result = 32'b0
。这样做的正确方法是什么?
module verification_alu(
input c_in
input [W-1:0] a, b,
input [2:0] operation,
output reg [W-1:0] result
output reg c_out
);
parameter W = 32;
always@*
begin
case(operation)
0: result = a;
1: result = ~a;
2: {c_out, result} = {a + b + c_in};
3: {c_out, result} = {a - b + c_in};
4: result = a | b;
5: result = a & b;
default: {c_out, result} = {W-2'b0}; // will this line fill with zeros properly?
endcase
end
endmodule
另外,附带问题,32'b0 - 1'b1
的正确输出应该是什么?我应该32'hffffffff
吗?
答案 0 :(得分:2)
加法和减法操作不起作用的原因是因为您将计算包装在连接运算符({}
)中。 Verilog部分地根据表达式中的操作数以及该表达式的上下文确定操作的位大小。在您的情况下,表达式a + b + c_in
被评估为W位,因为该表达式中任何变量的最大长度为W
(即a
和b
是那个长度,因为Verilog将首先评估这个添加(或两个添加),然后再继续评估包装它的{}
运算符。通过删除此不需要的步骤,您应该获得a + b + c_in
的正确(W + 1)位评估;所以该行将是:3: {c_out, result} = a - b + c_in;
。有关详情,请参阅IEEE1800-2012,第11.6节。
回答其他两个问题:
不,表达式{W-2'b0}
不会为零填充,而是会导致值为W
,因为您告诉模拟器从2'b0
中减去W
。您正在考虑{(W-2){1'b0}}
,或专门针对零填充'0
(因为它非常常见,您也可以使用'1
,'x
或'z
来填充1,分别不关心或高Z)。 (注意{c_out, result}
的宽度为W+1
,而W-2
的宽度为32'b0 - 1'b1
最后,32'hffffffff
很可能会产生{{1}},但它受上述规则(以及签名扩展规则)的约束。
答案 1 :(得分:1)
修改后的说明:
module verification_alu #(parameter W=32) (
input wire c_in,
input wire [W-1:0] a,
input wire [W-1:0] b,
input wire [2:0] operation,
output reg [W-1:0] result,
output reg c_out
);
always @* begin
case(operation)
0: result = a;
1: result = ~a;
2: {c_out, result} = a + b + c_in;
3: {c_out, result} = a - b + c_in;
4: result = a | b;
5: result = a & b;
default: {c_out, result} = 0; // will this line fill with zeros properly?
endcase
end
endmodule
关键是要确保至少有一个操作数与你想要的结果大小相同,所以我在a和b之前加上一个0位。
我已经验证这可以用于远远超过普通整数大小的尺寸:
module tb;
reg c_in;
reg [127:0] a;
reg [127:0] b;
reg [2:0] op;
wire [127:0] res;
wire c_out;
verification_alu #(.W(128)) uut (c_in, a, b, op, res, c_out);
initial begin
c_in = 0;
a = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
b = 128'h00000000000000000000000000000001;
op = 3'd2;
#100;
$display ("RES = %H C_OUT = %d\n", res, c_out);
#100;
c_in = 0;
a = 128'h00000000000000000000000000000000;
b = 128'h00000000000000000000000000000001;
op = 3;
#100;
$display ("RES = %H C_OUT = %d\n", res, c_out);
#100;
op = 7;
#100;
$display ("RES = %H C_OUT = %d\n", res, c_out);
$finish;
end
endmodule
Chronologic VCS simulator copyright 1991-2014
Contains Synopsys proprietary information.
Compiler version J-2014.12-SP1-1; Runtime version J-2014.12-SP1-1; Oct 11 17:47 2015
RES = 00000000000000000000000000000000 C_OUT = 1
RES = ffffffffffffffffffffffffffffffff C_OUT = 1
RES = 00000000000000000000000000000000 C_OUT = 0
$finish called from file "testbench.sv", line 35.
$finish at simulation time 500
编辑和/或运行测试平台以及修订后的模块
编辑:哎哟!我没有意识到OP使用了连接运算符{}来包含三个操作数。是!你的代码更简单。我将在我的回答中编辑代码。
答案 2 :(得分:0)
首先,根据您的代码,输入端口中的参数定义将无法被编译器访问,并且会引发语法错误,您必须在i / o声明之前提及参数定义,因为它是在i /中访问的o声明,verilog带有一个语法,以避免这个
module module_name #(parameter W =value)
{}是一个与","一起使用的串联运算符。例如:a = 1bit b = 1bit c = 2bit所以我们可以给c={a,b};
所以正确的语法就像
2: {c_out, result} = a + b + c_in;
3: {c_out, result} = a - b + c_in;
用零填充它参数和花括号的混合将有助于解析(内部花括号将充当复制操作符)
default: {c_out, result} = {(W-2){1'b0}};