$ signal的算术移位在条件表达式中给出不同的结果,并始终阻止

时间:2017-06-02 13:56:18

标签: verilog iverilog

我正在为MIPS编写ALU。

我曾经把它写成顺序逻辑(或者总是阻止?我不知道为什么但c必须是reg所以我猜它是'顺序逻辑?)

似乎是组合逻辑

always @* begin
    case (op)
        4'b0000: c = mux_a + mux_b; 
        4'b0001: c = mux_a - mux_b;
        4'b0010: c = mux_b << mux_a[4:0];
        4'b0011: c = mux_b >> mux_a[4:0];
        4'b0100: c = $signed(mux_b) >>> mux_a[4:0]; 
        4'b0101: c = mux_a & mux_b;
        4'b0110: c = mux_a | mux_b;
        4'b0111: c = mux_a ^ mux_b;
        4'b1000: c = ~(mux_a | mux_b);    
        4'b1001: c = (mux_a < mux_b) ? 32'b1 : 32'b0; // sltu
        4'b1010: c = ($signed(mux_a) < $signed(mux_b)) ? 32'b1 : 32'b0; // slt
        4'b1011: c = mux_a + mux_b - 4;
        default: c = 0;
    endcase
end

效果很好,4'b0100: c = $signed(mux_b) >>> mux_a[4:0]可以得到正确的输出。但是由于某些原因,我决定使用组合逻辑条件表达式。

assign c =  (op == 4'b0000) ? (mux_a + mux_b) : 
            (op == 4'b0001) ? (mux_a - mux_b) : 
            (op == 4'b0010) ? (mux_b << mux_a[4:0]) : 
            (op == 4'b0011) ? (mux_b >> mux_a[4:0]) : 
            (op == 4'b0100) ? ($signed(mux_b) >>> mux_a[4:0]) : 
            (op == 4'b0101) ? (mux_a & mux_b) : 
            (op == 4'b0110) ? (mux_a | mux_b) : 
            (op == 4'b0111) ? (mux_a ^ mux_b) : 
            (op == 4'b1000) ? (~(mux_a | mux_b)) : 
            (op == 4'b1001) ? ((mux_a < mux_b) ? 32'b1 : 32'b0) : 
            (op == 4'b1010) ? (($signed(mux_a) < $signed(mux_b)) ? 32'b1 : 32'b0) : 
            (op == 4'b1011) ? (mux_a + mux_b - 4) : 
            0;

除了c wire之外几乎相同。

我运行此代码并告诉我,4294967280(FFFFFFF0)&gt;&gt;&gt; 8 = 33554431(1FFFFFF)这太荒谬了。

PC=        388, Fetched 00000000000100011001101000000011.
  Decoder done. alu=4294967280.
  ALUOP=0100 ALUMASK=10 Calc Result=  33554431
  rs=         0 rt=4294967280
  aluflag = 0000
  Written(0000) 01ffffff to RegAddr:19

但如果我改用(op == 4'b0100) ? ({ {31{mux_b[32]}}, mux_b} >> mux_a[4:0]) :,我可以得到正确的结果。

谁能告诉我原因?以下是这些变量的定义方式(对溢出标志使用33位)

input [31:0] a;
input [31:0] b;
input [31:0] imm1;
input [31:0] imm0;
input [3:0] op;
input [1:0] mask;

output [31:0] result;
output [3:0] flags;

wire [31:0] _mux_a;
wire [31:0] _mux_b;

wire [32:0] mux_a;
wire [32:0] mux_b;
wire [32:0] c;

assign _mux_a = mask[1] ? imm1 : a;
assign _mux_b = mask[0] ? imm0 : b;
assign mux_a = {_mux_a[31], _mux_a};
assign mux_b = {_mux_b[31], _mux_b};
assign result = c[31:0];

//zf of uf
assign flags = {c[31], result == 0,  c[32:31] == 2'b01,  c[32:31] == 2'b10};

1 个答案:

答案 0 :(得分:1)

这是iverilog中的一个错误。关于组合$signed和条件运算符?:的事情。如果使用连续赋值(assign语句)或始终阻塞,则无关紧要。

mux_b[32]为1时,$signed(mux_b) >>> mux_a[4:0]将提供正确的输出,而(1'b1) ? ($signed(mux_b) >>> mux_a[4:0]) : 33'h0将提供错误的输出。

如果需要,您可以提交错误herehere

解决方法是分开操作。例如:

assign op4 = $signed(mux_b) >>> mux_a[4:0];
assign c = (op == 4'b0000) ...
           (op == 4'b0100) ? op4 :
           (op == 4'b0101) ...

(op == 4'b0100) ? ({ {31{mux_b[32]}}, mux_b} >> mux_a[4:0]) :正如问题中已经指出的那样。

FYI :根据我的经验,即使4:1或其他多路复用类型更理想,条件运算符?:也经常合成一个明确的2:1多路复用器。您的经历可能有所不同一般情况下,我建议使用case语句来处理大于3:1的任何多路复用。