2026/6/10 0:40:21
网站建设
项目流程
1688网站简介,中企动力公司,网页游戏网站源码,网站界面设计实训的意义写在前面 前面执行模块对于除法计算只做流水线控制和参数传递#xff0c;具体的除法计算由DIV除法模块来完成。该模块作者使用试商法实现#xff0c;所以在开始前先了解下试商法怎么进行除法计算。 有VIP的同学可以看一下这篇文章#xff0c;可能会讲解得更加详细#xff1…写在前面前面执行模块对于除法计算只做流水线控制和参数传递具体的除法计算由DIV除法模块来完成。该模块作者使用试商法实现所以在开始前先了解下试商法怎么进行除法计算。有VIP的同学可以看一下这篇文章可能会讲解得更加详细https://blog.csdn.net/m0_71078397/article/details/126610918试商法是一种用于除法运算的算法特别适用于硬件实现如FPGA、CPU等。它的核心思想是通过试探和修正的方式逐位确定商的值。基本公式被除数 ÷ 除数 商 … 余数基本思想从最高位开始每次确定商的一位。1、猜测当前位的商值2、用猜测值乘以除数3、比较乘积与被除数或当前余数4、根据比较结果调整商值十进制举例100 / 7二进制举例100 / 7call in作者为什么说除法至少需要33个时钟周期。这里试商法对于32位数的除法而言需要迭代处理32次即每一位都需要迭代一次。1、RISC-V32位除法指令DIV有符号除法商 DIVU无符号除法商 REM有符号取余余数 REMU无符号取余余数2、除法模块接口定义input wire clk,input wire rst,// from exinput wire[REG_BUS]dividend_i,// 被除数input wire[REG_BUS]divisor_i,// 除数input wire start_i,// 开始信号运算期间这个信号需要一直保持有效input wire[2:0]op_i,// 具体是哪一条指令input wire[REG_ADDR_BUS]reg_waddr_i,// 运算结束后需要写的寄存器// to exoutput reg[REG_BUS]result_o,// 除法结果高32位是余数低32位是商output reg ready_o,// 运算结束信号output reg busy_o,// 正在运算信号output reg[REG_ADDR_BUS]reg_waddr_o// 运算结束后需要写的寄存器该模块只和执行模块交换数据所以接口只用定义与执行模块数据交换即可。3、除法器状态机状态定义// 状态定义localparam STATE_IDLE4b0001;//空闲localparam STATE_START4b0010;//开始localparam STATE_CALC4b0100;//计算中localparam STATE_END4b1000;//结束4、中间运算变量reg[REG_BUS]dividend_r;//被除数reg[REG_BUS]divisor_r;//除数reg[2:0]op_r;//指令reg[3:0]state;//状态机状态reg[31:0]count;reg[REG_BUS]div_result;//除法结果reg[REG_BUS]div_remain;//除法结果余数reg[REG_BUS]minuend;//余数reg invert_result;//结果的补码形式wire op_div(op_rINST_DIV);wire op_divu(op_rINST_DIVU);wire op_rem(op_rINST_REM);wire op_remu(op_rINST_REMU);5、试商法除法的核心计算部分wire[31:0]dividend_invert(-dividend_r);//等价于dividend_invert ~dividend_r 32b1wire[31:0]divisor_invert(-divisor_r);//取二进制补码wire minuend_ge_divisorminuenddivisor_r;//比较部分余数 minuend 是否大于等于除数 divisor_rwire[31:0]minuend_sub_resminuend-divisor_r;//wire[31:0]div_result_tmpminuend_ge_divisor?({div_result[30:0],1b1}): ({div_result[30:0], 1b0});//若部分余数大于等于除数则余数更新为余数减除数的差值否则余数不变wire[31:0]minuend_tmpminuend_ge_divisor?minuend_sub_res[30:0]:minuend[30:0];div_result_tmp在余数大于等于除数时在对应位上商1否则商0。6、除法状态机1. 复位if(rstRESET_EN)begin stateSTATE_IDLE;ready_oDIV_RESULT_NOT_READY;//除法结果是否完成result_oZERO_WORD;//存储最终的除法结果商或余数div_resultZERO_WORD;//存储计算过程中的商div_remainZERO_WORD;op_r3h0;reg_waddr_oZERO_WORD;//除法结果-写地址dividend_rZERO_WORD;divisor_rZERO_WORD;minuendZERO_WORD;//存储当前的部分余数被减数invert_result1b0;// 结果取反标志busy_oFALSE;//除法器是否正在工作countZERO_WORD;//控制32次迭代的计数器end2. 空闲状态STATE_IDLE:beginif(start_iDIV_START)begin op_rop_i;dividend_rdividend_i;divisor_rdivisor_i;reg_waddr_oreg_waddr_i;stateSTATE_START;busy_oTRUE;endelsebegin op_r3h0;reg_waddr_oZERO_WORD;dividend_rZERO_WORD;divisor_rZERO_WORD;ready_oDIV_RESULT_NOT_READY;result_oZERO_WORD;busy_oFALSE;end end当接收到开始信号时将参与运算的变量进行初始化并对外发出“忙”信号busy_o后将状态机状态切换位开始状态。3、开始状态STATE_START:beginif(start_iDIV_START)begin// 除数为0if(divisor_rZERO_WORD)beginif(op_div|op_divu)begin result_o32hffffffff;//若指令为除法运算则返回全1--无限大endelsebegin result_odividend_r;//若为取余数运算则返回取余本身end ready_oDIV_RESULT_READY;//完成计算stateSTATE_IDLE;busy_oFALSE;// 除数不为0endelsebegin busy_oTRUE;count32h40000000;//计数器初始化--第31位为1右移32位后为0stateSTATE_CALC;//状态机切换为计算div_resultZERO_WORD;div_remainZERO_WORD;// DIV和REM这两条指令是有符号数运算指令if(op_div|op_rem)begin// 被除数求补码if(dividend_r[31]1b1)begin//被除数为负数时取二进制补码dividend_rdividend_invert;minuenddividend_invert[31];endelsebegin minuenddividend_r[31];end// 除数求补码if(divisor_r[31]1b1)begin divisor_rdivisor_invert;end endelsebegin minuenddividend_r[31];end// 运算结束后是否要对结果取补码if((op_div(dividend_r[31]^divisor_r[31]1b1))//异或运算若除数与被除数符号不同则为1标记结果符号为负号||(op_rem(dividend_r[31]1b1)))begin invert_result1b1;endelsebegin invert_result1b0;end end endelsebegin stateSTATE_IDLE;result_oZERO_WORD;ready_oDIV_RESULT_NOT_READY;busy_oFALSE;end end执行操作1、处理除数为0的情况除法计算返回全1取余运算返回本身。2、除数不为0初始化迭代计数器count 32’h40000000将状态切换为计算状态。3、对于操作数中存在负数情况时对其取补码。4、判断运算结果的符号并标记invert_result 。4、计算状态STATE_CALC:beginif(start_iDIV_START)begin dividend_r{dividend_r[30:0],1b0};//被除数左移一位div_resultdiv_result_tmp;//保存运算中间结果count{1b0,count[31:1]};//计数器右移if(|count)begin minuend{minuend_tmp[30:0],dividend_r[30]};endelsebegin stateSTATE_END;if(minuend_ge_divisor)begin div_remainminuend_sub_res;endelsebegin div_remainminuend;end end endelsebegin stateSTATE_IDLE;result_oZERO_WORD;ready_oDIV_RESULT_NOT_READY;busy_oFALSE;end end结合计算部分迭代32次完成计算。5、完成状态STATE_END:beginif(start_iDIV_START)begin ready_oDIV_RESULT_READY;stateSTATE_IDLE;busy_oFALSE;if(op_div|op_divu)beginif(invert_result)begin result_o(-div_result);endelsebegin result_odiv_result;end endelsebeginif(invert_result)begin result_o(-div_remain);endelsebegin result_odiv_remain;end end endelsebegin stateSTATE_IDLE;result_oZERO_WORD;ready_oDIV_RESULT_NOT_READY;busy_oFALSE;end end结合符号标记invert_result和指令为结果输出赋值并向执行模块发送完成信号。https://gitee.com/liangkangnan/tinyriscv