2

我正在为 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) >>> 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};
4

1 回答 1

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会给出错误的输出。

如果您愿意,您可以在此处此处提交错误

一种解决方法是将操作分开。例子:

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]) :正如问题中已经指出的那样。

仅供参考:根据我的经验,?:即使 4:1 或其他多路复用器类型更理想,条件运算符通常也会合成为显式 2:1 多路复用器。您的体验可能会有所不同。一般来说,我建议对任何大于 3:1 的复用使用 case 语句。

于 2017-06-06T20:04:25.753 回答