From b6754f002ce5f2107b5839c9aebe674cb03f1c59 Mon Sep 17 00:00:00 2001 From: liangkangnan Date: Sun, 6 Sep 2020 23:17:56 +0800 Subject: [PATCH] rtl: div: optimization Signed-off-by: liangkangnan --- rtl/core/div.v | 112 +++++++++++++++++++++++++------------------ rtl/core/ex.v | 49 +++---------------- rtl/core/tinyriscv.v | 5 +- 3 files changed, 73 insertions(+), 93 deletions(-) diff --git a/rtl/core/div.v b/rtl/core/div.v index 0933e99..a2b3750 100644 --- a/rtl/core/div.v +++ b/rtl/core/div.v @@ -18,7 +18,7 @@ // 除法模块 // 试商法实现32位整数除法 -// 每次除法运算至少需要32个时钟周期才能完成 +// 每次除法运算需要33个时钟周期才能完成 module div( input wire clk, @@ -32,91 +32,104 @@ module div( input wire[`RegAddrBus] reg_waddr_i, // 运算结束后需要写的寄存器 // to ex - output reg[`DoubleRegBus] result_o, // 除法结果,高32位是余数,低32位是商 + output reg[`RegBus] result_o, // 除法结果 output reg ready_o, // 运算结束信号 - output wire busy_o, // 正在运算信号 - output reg[2:0] op_o, // 具体是哪一条指令 + output reg busy_o, // 正在运算信号 output reg[`RegAddrBus] reg_waddr_o // 运算结束后需要写的寄存器 ); // 状态定义 - localparam STATE_IDLE = 0; - localparam STATE_START = 1; - localparam STATE_INVERT = 2; - localparam STATE_END = 3; + localparam STATE_IDLE = 4'b0001; + localparam STATE_START = 4'b0010; + localparam STATE_INVERT = 4'b0100; + localparam STATE_END = 4'b1000; reg[`RegBus] dividend_temp; reg[`RegBus] divisor_temp; - reg[1:0] state; - reg[6:0] count; + reg[3:0] state; + reg[31:0] count; reg[`RegBus] div_result; reg[`RegBus] div_remain; reg[`RegBus] minuend; - reg[`RegBus] divisor_zero_result; reg invert_result; + reg inst_div; + reg inst_divu; + wire[31:0] dividend_invert = -dividend_i; + wire[31:0] divisor_invert = -divisor_i; + wire[31:0] minuend_sub_res = minuend - divisor_temp; + wire minuend_ge_divisor = minuend >= divisor_temp; - assign busy_o = (state != STATE_IDLE)? `True : `False; - + wire op_div = (op_i == `INST_DIV); + wire op_divu = (op_i == `INST_DIVU); + wire op_rem = (op_i == `INST_REM); + wire op_remu = (op_i == `INST_REMU); // 状态机实现 always @ (posedge clk) begin if (rst == `RstEnable) begin state <= STATE_IDLE; ready_o <= `DivResultNotReady; - result_o <= {`ZeroWord, `ZeroWord}; + result_o <= `ZeroWord; div_result <= `ZeroWord; div_remain <= `ZeroWord; - divisor_zero_result <= ~32'b00000001 + 1'b1; - op_o <= 3'h0; reg_waddr_o <= `ZeroWord; dividend_temp <= `ZeroWord; divisor_temp <= `ZeroWord; + minuend <= `ZeroWord; + count <= `ZeroWord; invert_result <= 1'b0; + busy_o <= `False; + inst_div <= 1'b0; + inst_divu <= 1'b0; end else begin case (state) STATE_IDLE: begin + busy_o <= `False; if (start_i == `DivStart) begin - op_o <= op_i; reg_waddr_o <= reg_waddr_i; + inst_div <= op_div; + inst_divu <= op_divu; // 除数为0 if (divisor_i == `ZeroWord) begin ready_o <= `DivResultReady; - result_o <= {dividend_i, divisor_zero_result}; + if (op_div | op_divu) begin + result_o <= 32'hffffffff; + end else begin + result_o <= dividend_i; + end // 除数不为0 end else begin - count <= 7'd31; + count <= 32'h80000000; state <= STATE_START; - div_result <= `ZeroWord; - div_remain <= `ZeroWord; // DIV和REM这两条指令是有符号数运算 - if ((op_i == `INST_DIV) || (op_i == `INST_REM)) begin + if ((op_div) || (op_rem)) begin // 被除数求补码 if (dividend_i[31] == 1'b1) begin - dividend_temp <= ~dividend_i + 1; - minuend <= ((~dividend_i + 1) >> 7'd31) & 1'b1; + dividend_temp <= dividend_invert; + minuend <= dividend_invert[31]; end else begin dividend_temp <= dividend_i; - minuend <= (dividend_i >> 7'd31) & 1'b1; + minuend <= dividend_i[31]; end // 除数求补码 if (divisor_i[31] == 1'b1) begin - divisor_temp <= ~divisor_i + 1; + divisor_temp <= divisor_invert; end else begin divisor_temp <= divisor_i; end end else begin dividend_temp <= dividend_i; - minuend <= (dividend_i >> 7'd31) & 1'b1; + minuend <= dividend_i[31]; divisor_temp <= divisor_i; end // 运算结束后是否要对结果取补码 - if (((op_i == `INST_DIV) && (dividend_i[31] ^ divisor_i[31] == 1'b1)) - || ((op_i == `INST_REM) && (dividend_i[31] == 1'b1))) begin + if (((op_div) && (dividend_i[31] ^ divisor_i[31] == 1'b1)) + || ((op_rem) && (dividend_i[31] == 1'b1))) begin invert_result <= 1'b1; end else begin invert_result <= 1'b0; @@ -124,60 +137,65 @@ module div( end end else begin ready_o <= `DivResultNotReady; - result_o <= {`ZeroWord, `ZeroWord}; + result_o <= `ZeroWord; end end STATE_START: begin + busy_o <= `True; if (start_i == `DivStart) begin - if (count >= 7'd1) begin - if (minuend >= divisor_temp) begin - div_result <= (div_result << 1'b1) | 1'b1; - minuend <= ((minuend - divisor_temp) << 1'b1) | ((dividend_temp >> (count - 1'b1)) & 1'b1); + div_result <= {div_result[30:0], minuend_ge_divisor}; + if (|count) begin + if (minuend_ge_divisor) begin + minuend <= {minuend_sub_res[30:0], dividend_temp[31]}; end else begin - div_result <= (div_result << 1'b1) | 1'b0; - minuend <= (minuend << 1'b1) | ((dividend_temp >> (count - 1'b1)) & 1'b1); + minuend <= {minuend[30:0], dividend_temp[31]}; end - count <= count - 1'b1; + count <= {1'b0, count[31:1]}; + dividend_temp <= {dividend_temp[30:0], 1'b0}; end else begin state <= STATE_INVERT; - if (minuend >= divisor_temp) begin - div_result <= (div_result << 1'b1) | 1'b1; - div_remain <= minuend - divisor_temp; + if (minuend_ge_divisor) begin + div_remain <= minuend_sub_res; end else begin - div_result <= (div_result << 1'b1) | 1'b0; div_remain <= minuend; end end end else begin ready_o <= `DivResultNotReady; - result_o <= {`ZeroWord, `ZeroWord}; + result_o <= `ZeroWord; state <= STATE_IDLE; end end STATE_INVERT: begin + busy_o <= `True; if (start_i == `DivStart) begin if (invert_result == 1'b1) begin - div_result <= ~div_result + 1'b1; - div_remain <= ~div_remain + 1'b1; + div_result <= -div_result; + div_remain <= -div_remain; end state <= STATE_END; end else begin ready_o <= `DivResultNotReady; - result_o <= {`ZeroWord, `ZeroWord}; + result_o <= `ZeroWord; state <= STATE_IDLE; end end STATE_END: begin + busy_o <= `False; if (start_i == `DivStart) begin ready_o <= `DivResultReady; - result_o <= {div_remain, div_result}; + if (inst_div | inst_divu) begin + result_o <= div_result; + end else begin + result_o <= div_remain; + end state <= STATE_IDLE; end else begin state <= STATE_IDLE; - result_o <= {`ZeroWord, `ZeroWord}; + result_o <= `ZeroWord; ready_o <= `DivResultNotReady; end end diff --git a/rtl/core/ex.v b/rtl/core/ex.v index 69e18eb..f3c7d91 100644 --- a/rtl/core/ex.v +++ b/rtl/core/ex.v @@ -44,9 +44,8 @@ module ex( // from div input wire div_ready_i, // 除法运算完成标志 - input wire[`DoubleRegBus] div_result_i, // 除法运算结果 + input wire[`RegBus] div_result_i, // 除法运算结果 input wire div_busy_i, // 除法运算忙标志 - input wire[2:0] div_op_i, // 具体是哪一条除法指令 input wire[`RegAddrBus] div_reg_waddr_i,// 除法运算结束后要写的寄存器地址 // to mem @@ -67,7 +66,7 @@ module ex( output wire[`MemAddrBus] csr_waddr_o, // 写CSR寄存器地址 // to div - output wire div_start_o, // 开始除法运算标志 + output wire div_start_o, // 开始除法运算标志 output reg[`RegBus] div_dividend_o, // 被除数 output reg[`RegBus] div_divisor_o, // 除数 output reg[2:0] div_op_o, // 具体是哪一条除法指令 @@ -251,23 +250,9 @@ module ex( div_start = `DivStop; div_hold_flag = `HoldDisable; if (div_ready_i == `DivResultReady) begin - case (div_op_i) - `INST_DIV, `INST_DIVU: begin - div_wdata = div_result_i[31:0]; - div_waddr = div_reg_waddr_i; - div_we = `WriteEnable; - end - `INST_REM, `INST_REMU: begin - div_wdata = div_result_i[63:32]; - div_waddr = div_reg_waddr_i; - div_we = `WriteEnable; - end - default: begin - div_wdata = `ZeroWord; - div_waddr = `ZeroWord; - div_we = `WriteDisable; - end - endcase + div_wdata = div_result_i; + div_waddr = div_reg_waddr_i; + div_we = `WriteEnable; end else begin div_we = `WriteDisable; div_wdata = `ZeroWord; @@ -822,7 +807,7 @@ module ex( end endcase end - `INST_JAL: begin + `INST_JAL, `INST_JALR: begin hold_flag = `HoldDisable; mem_wdata_o = `ZeroWord; mem_raddr_o = `ZeroWord; @@ -832,27 +817,7 @@ module ex( jump_addr = op1_jump_add_op2_jump_res; reg_wdata = op1_add_op2_res; end - `INST_JALR: begin - hold_flag = `HoldDisable; - mem_wdata_o = `ZeroWord; - mem_raddr_o = `ZeroWord; - mem_waddr_o = `ZeroWord; - mem_we = `WriteDisable; - jump_flag = `JumpEnable; - jump_addr = op1_jump_add_op2_jump_res; - reg_wdata = op1_add_op2_res; - end - `INST_LUI: begin - hold_flag = `HoldDisable; - mem_wdata_o = `ZeroWord; - mem_raddr_o = `ZeroWord; - mem_waddr_o = `ZeroWord; - mem_we = `WriteDisable; - jump_addr = `ZeroWord; - jump_flag = `JumpDisable; - reg_wdata = op1_add_op2_res; - end - `INST_AUIPC: begin + `INST_LUI, `INST_AUIPC: begin hold_flag = `HoldDisable; mem_wdata_o = `ZeroWord; mem_raddr_o = `ZeroWord; diff --git a/rtl/core/tinyriscv.v b/rtl/core/tinyriscv.v index b7dd6d6..81cc84d 100644 --- a/rtl/core/tinyriscv.v +++ b/rtl/core/tinyriscv.v @@ -124,10 +124,9 @@ module tinyriscv( wire[`InstAddrBus] ctrl_jump_addr_o; // div模块输出信号 - wire[`DoubleRegBus] div_result_o; + wire[`RegBus] div_result_o; wire div_ready_o; wire div_busy_o; - wire[2:0] div_op_o; wire[`RegAddrBus] div_reg_waddr_o; // clint模块输出信号 @@ -313,7 +312,6 @@ module tinyriscv( .div_ready_i(div_ready_o), .div_result_i(div_result_o), .div_busy_i(div_busy_o), - .div_op_i(div_op_o), .div_reg_waddr_i(div_reg_waddr_o), .div_start_o(ex_div_start_o), .div_dividend_o(ex_div_dividend_o), @@ -340,7 +338,6 @@ module tinyriscv( .result_o(div_result_o), .ready_o(div_ready_o), .busy_o(div_busy_o), - .op_o(div_op_o), .reg_waddr_o(div_reg_waddr_o) );