从零开始设计riscv cpu记录之五

一、在测试mulhsu不通过,其余的mul 、mulh、 mul都通过,这是为什么?

指令含义
mulh有符号 × 有符号,取高 32 位
mulhsu有符号 × 无符号,取高 32 位
mulhu无符号 × 无符号,取高 32 位
mul有符号/无符号 × 有符号/无符号,取低 32 位

二、对我来说,是认知之外的原因

三、ex.v中乘法的实现,分成散步

第一步,先取到操作数的有符号格式:

wiresigned[`DW-1:0]op1_signed=$signed(op1_i);wiresigned[`DW-1:0]op2_signed=$signed(op2_i);

第二步,按照表格中规定的计算乘积,比如mul,无符号相乘,就是op1_i * op2_i,其他的方法也一样:

wire[`DW*2-1:0]mul_result=op1_i*op2_i;wire[`DW*2-1:0]mulh_result=op1_signed*op2_signed;wire[`DW*2-1:0]mulhsu_result=op1_signed*op2_i

第三步,取32位,高32位或低32位

`INST_MUL:begin reg_wdata_o=mul_result[31:0];end `INST_MULH:begin reg_wdata_o=mulh_result[63:32];end `INST_MULHSU:begin reg_wdata_o=mulhsu_result[63:32];end `INST_MULHU:begin reg_wdata_o=mul_result[63:32];

四、思路清晰,感觉不会出错,但是忽略了verilog的乘法规则

五、mulhsu的错误原因:mulhsu要求的是有符号数 × 无符号数,但op1_signed * op2_i这种写法在 Verilog 里会被当成无符号 × 无符号来算。

六、Verilog 的混合符号乘法规则

Verilog 规定:一个表达式里只要有一个操作数是无符号的,整个表达式就按无符号运算处理。

七、正确做法:

wire[`DW*2-1:0]mulhsu_result=$signed({{32{op1_i[31]}},op1_i})*$signed({32'b0,op2_i});

含义:

  • {{32{op1_i[31]}}, op1_i}
    op1_i按有符号数符号扩展到 64 位。

  • {32'b0, op2_i}
    op2_i按无符号数零扩展到 64 位。

  • 两个 64 位数相乘,取高 32 位,就是mulhsu的正确结果。

八、改完之后测试结果PASS