Verilog:三元运算符与算术右移一起导致意外行为

Fra*_* Li 4 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
Run Code Online (Sandbox Code Playgroud)

例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
Run Code Online (Sandbox Code Playgroud)

例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
Run Code Online (Sandbox Code Playgroud)

我的测试台:

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
Run Code Online (Sandbox Code Playgroud)

我认为上面的三个示例对于我的测试平台会有相同的输出,但实际上第二个具有意外行为,在第一个和第三个示例中输出“10000000 2 00100000”而不是“10000000 2 11100000”。请注意,第一个和第二个示例之间的唯一区别是使用了中间变量 arith_shift。

任何人都可以告诉我这里发生了什么? https://www.edaplayground.com/x/S9ec

PS1:我在“Icarus verilog”、“vcs”和“questasim”上测试过,都是一样的,所以奇怪的行为不太可能是由模拟器引起的

PS2:我在questasim中进一步检查了这三个例子生成的原理图,第一个和第三个生成正确在此处输入图片说明 但第二个产生了错误的 在此处输入图片说明

PS3:在Ex4中,即使我们先做signed转换,结果也和Ex2一样,是错误的。请注意,我明确地将 result 和 sign_data 声明为有符号变量并没有做出任何更改(更不用说我是否没有将它们声明为有符号变量)。

Ex4

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
Run Code Online (Sandbox Code Playgroud)

dav*_*_59 5

您看到此行为的原因是因为您在条件运算符的上下文中混合了有符号和无符号类型。LRM 说有符号类型通过以下规则转换为无符号类型。

11.8.1 表达式类型规则

如果任何操作数是无符号的,则无论运算符如何,结果都是无符号的。

11.8.2 计算表达式的步骤

将表达式(或自定子表达式)的类型和大小向下传播到表达式的上下文确定的操作数。通常,运算符的任何上下文确定的操作数都应与运算符的结果具有相同的类型和大小。

在示例 2 和示例 4 中,有符号操作数会立即转换回无符号操作数,因为它与另一个无符号操作数处于上下文中。如果您对两个操作数都进行签名,那么您将能够在单个语句中执行此操作。