RISC-V MCU中文社区

【分享】 乘法和除法指令的仿真方法与流程

发表于 开源蜂鸟E203 2023-05-26 10:43:58
0
2022
2

报名编号:CICC1014    团队名称:华芯极客

    本文首先将原蜂鸟E203 SoC中乘法和除法指令的实现模块进行了更改,使其运行周期缩短,之后需要对其进行仿真验证,本文将分享一下仿真验证的方法。

    在仿真前先使用vivado对整个工程进行综合执行,之后需要修改仿真文件tb_top.v中的.verilog文件路径,如下图绕圈中所示,该文件由.elf文件转换生成,转换方法见后文,而.elf文件正是由c程序生成的用于下载到开发板中的二进制代码,下面将对用于功能验证的c程序进行设计和介绍。

    RISC-V架构一共有4条乘法相关指令和4条除法相关指令,4条乘法指令为mul、mulh、mulhu和mulhsu,其中带h的指令读取乘法结果的高32位,带u表示将操作数当作无符号数,带su表示将rs1和rs2中的操作数分别当作有符号数和无符号数,如果希望得到完整的64位结果,可以使用两条连续的乘法指令"mulh[[s]u] rdh,rs1,rs2;mul rdl,rs1,rs2",其中[]表示可选,如果两条指令的源操作数索引和顺序完全相同,并且rdh和源操作数索引不同,则蜂鸟E203处理器会将其融合成一指令执行,即进入b2b(back to back)模式,因为第一条指令已经生成了64位的乘法结果并保存到了寄存器中,当执行mul指令时可以直接从寄存器中获取结果,而不需要重新计算。4条除法指令为div、divu、rem、remu,div表示取商,rem表示取余数,当执行两条连续的指令"div[u] rdq,rs1,rs2; rem[u] rdr,rs1,rs2"时,蜂鸟E203处理器同样会进行b2b模式,从而提高性能。下面给出本文用于乘法指令和除法指令测试的c程序代码:

#include
#include
#include "hbird_sdk_soc.h"


__STATIC_FORCEINLINE void mul_test(int a,int b){

    int begin_cycle,end_cycle,cycle;
    int res_h,res_l;
    begin_cycle = __get_rv_cycle();
    asm volatile("mulh %0,%1,%2":"=r"(res_h):"r"(a),"r"(b));
    asm volatile("mul %0,%1,%2":"=r"(res_l):"r"(a),"r"(b));    //这两条指令会进入b2b模式
    end_cycle = __get_rv_cycle();
    cycle=end_cycle-begin_cycle;        //用于计算花费的时钟周期
    printf("%d*%d=%d_%d,used %d cyclesrn",a,b,res_h,res_l,cycle);

}

__STATIC_FORCEINLINE void div_test(int a,int b){
    int begin_cycle,end_cycle,cycle;
    int quotient,remainder;
    begin_cycle = __get_rv_cycle();
    asm volatile("div %0,%1,%2":"=r"(quotient):"r"(a),"r"(b));
    asm volatile("rem %0,%1,%2":"=r"(remainder):"r"(a),"r"(b));     //这两条指令会进入b2b模式
    end_cycle = __get_rv_cycle();
    cycle=end_cycle-begin_cycle;
    printf("%d/%d=%d...%d,used %d cyclesrn",a,b,quotient,remainder,cycle);
}

int main(void)
{
    __RV_CSR_WRITE(CSR_MSTATUS, MSTATUS_XS);
    __enable_mcycle_counter();
    //结果为负数的测试
    int a=-92,b=10;
    mul_test(a,b);
    div_test(a,b);
     //结果为正数的测试
    a=92,b=10;
    mul_test(a,b);
    div_test(a,b);
    return 0;
}

    这里仅对带符号数进行测试,无符号数测试类似,之后可以按照帖子https://www.rvmcu.com/community-topic-id-386.html那样用nuclei studio生成.verilog文件,或者直接在对应代码文件夹中打开终端并输入make dasm生成,具体请参考https://doc.nucleisys.com/hbirdv2/quick_start/sdk.html,这两种方式本质上都是使用了命令 riscv-nuclei-elf-objcopy ".elf" -O verilog ".verilog"来生成.verilog文件。本文采用了第二种方式,但要注意的是,用make dasm命令生成的.verilog代码的默认起始地址为0x80000000,如下图,需要修改为0x00000000,后面的地址标记也要改为@0开始。最后进行仿真与测试,可参考帖子https://www.rvmcu.com/community-topic-id-386.html。

    下图为本文的仿真结果,代码中的printf打印结果在Tcl Console窗口中显示,将乘除法指令实现模块中的信号添加到波形件中,点击感兴趣的信号,并点击"||"符号进行定位(下图红圈所示),即可快速查看感兴趣信号的仿真波形。

喜欢2
用户评论
wwww

wwww 实名认证

懒的都不写签名

积分
问答
粉丝
关注
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板