verilog - Verilog:三元运算符与算术右移一起导致意外行为
问题描述
首先看一下设计右移位寄存器的三个代码示例,它允许用户在算术右移或逻辑右移之间进行选择:
例1:
module shiftr (data, shamt, arith, result);
input [8 - 1:0] data;
input [3 - 1:0] shamt;
input arith;
output [8 - 1:0] result;
wire [8 - 1:0] arith_shift;
assign arith_shift = $signed(data) >>> shamt;
assign result = arith ? arith_shift : (data >> shamt);
endmodule
例 2:
module shiftr (data, shamt, arith, result);
input [8 - 1:0] data;
input [3 - 1:0] shamt;
input arith;
output [8 - 1:0] result;
assign result = arith ? (($signed(data)) >>> shamt) : (data >> shamt);
endmodule
例 3:
module shiftr (data, shamt, arith, result);
input [8 - 1:0] data;
input [3 - 1:0] shamt;
input arith;
output reg [8 - 1:0] result;
wire [8 - 1:0] arith_shift;
always @(*) begin
if (arith) result = $signed(data) >>> shamt;
else result = data >> shamt;
end
endmodule
我的测试台:
module shiftr_tb;
reg [7:0] data;
reg [2:0] shamt;
reg arith;
wire [7:0] result;
shiftr dut (data, shamt, arith, result);
initial begin
$monitor("%b %d %b", data, shamt, result);
arith = 1'b1;
data = 8'b1000_0000;
shamt = 3'd2;
#10 $finish;
end
`ifdef FSDB_ON
initial begin
$fsdbDumpfile("trans.fsdb");
$fsdbDumpvars(0);
$fsdbDumpMDA();
end
`endif
endmodule
我认为上面的三个示例对我的测试台具有相同的输出,但实际上第二个示例具有意外行为,在第一个和第三个示例中输出“10000000 2 00100000”而不是“10000000 2 11100000”。请注意,第一个示例和第二个示例之间的唯一区别是使用了中间变量 arith_shift。
谁能告诉我这里发生了什么? https://www.edaplayground.com/x/S9ec
PS1:我在“Icarus verilog”、“vcs”和“questasim”上测试过,都是一样的,所以奇怪的行为不太可能是模拟器引起的
PS2:我在questasim中进一步检查了这三个示例生成的原理图,第一个和第三个生成正确 但第二个生成错误
PS3:在Ex4中,即使我们先做有符号转换,结果还是和Ex2一样,是错误的。请注意,我将 result 和 sign_data 显式声明为带符号变量不会进行更改(更不用说如果我不将它们声明为带符号变量)。
防爆4
module shiftr (data, shamt, arith, result);
input [8 - 1:0] data;
input [3 - 1:0] shamt;
input arith;
output signed [8 - 1:0] result;
wire signed [8 - 1:0] sign_data;
assign sign_data = $signed(data);
assign result = arith ? (sign_data >>> shamt) : (data >> shamt);
endmodule
解决方案
您看到此行为的原因是您在条件运算符的上下文中混合了有符号和无符号类型。LRM 说有符号类型通过以下规则转换为无符号类型。
11.8.1 表达式类型的规则
如果任何操作数是无符号的,则结果是无符号的,与运算符无关。
和
11.8.2 计算表达式的步骤
将表达式(或自确定的子表达式)的类型和大小向下传播到表达式的上下文确定的操作数。一般而言,运算符的任何上下文确定的操作数都应与运算符的结果具有相同的类型和大小。
在示例 2 和示例 4 中,有符号操作数立即被强制转换回无符号,因为它位于另一个无符号操作数的上下文中。如果您对两个操作数都进行了签名,那么您将能够在单个语句中执行此操作。
推荐阅读
- javascript - 循环时从对象中获取键值
- android - 如何通过 Ionic 中的 Cordova File 插件访问外部 USB 存储设备?
- r - R中的分组/计数/匹配数据
- csv - 在 Here Maps 中使用 csv 和 svg 创建基于位置的标记
- php - PHP 对象数组不包含正确的值
- python - 使用 python 发送邮件出错
- javascript - 盖茨比第二版布局模板
- javascript - 在 React 中深度克隆递归对象的正确方法(规范化状态)
- ios - 网页加载后活动指示器不隐藏
- javascript - 如果其他代码,我如何停止在此 JavaScript 中执行循环?