From 8c3d7ac932b8943939b458d6a1002c9703e65ecc Mon Sep 17 00:00:00 2001 From: liangkangnan Date: Sat, 12 Sep 2020 14:17:34 +0800 Subject: [PATCH] rtl: div: timing optimization Signed-off-by: liangkangnan --- rtl/core/div.v | 430 ++++++++++++++++++++++++++++++-------------- rtl/utils/gen_dff.v | 108 ++++++++++- 2 files changed, 407 insertions(+), 131 deletions(-) diff --git a/rtl/core/div.v b/rtl/core/div.v index a2b3750..cbf1eac 100644 --- a/rtl/core/div.v +++ b/rtl/core/div.v @@ -40,166 +40,336 @@ module div( ); // 状态定义 - localparam STATE_IDLE = 4'b0001; - localparam STATE_START = 4'b0010; - localparam STATE_INVERT = 4'b0100; - localparam STATE_END = 4'b1000; + localparam STATE_IDLE = 5'b00001; + localparam STATE_START = 5'b00010; + localparam STATE_CALC = 5'b00100; + localparam STATE_INVERT = 5'b01000; + localparam STATE_END = 5'b10000; - reg[`RegBus] dividend_temp; - reg[`RegBus] divisor_temp; - reg[3:0] state; + reg[4:0] state; + reg[4:0] next_state; + reg[`RegBus] dividend_r; + reg[`RegBus] divisor_r; + reg[2:0] op_r; reg[31:0] count; reg[`RegBus] div_result; reg[`RegBus] div_remain; reg[`RegBus] minuend; 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; + wire[31:0] dividend_invert = (-dividend_r); + wire[31:0] divisor_invert = (-divisor_r); + wire[31:0] minuend_sub_res = (minuend - divisor_r); + wire minuend_ge_divisor = (minuend >= divisor_r); - 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); + wire op_div = (op_r == `INST_DIV); + wire op_divu = (op_r == `INST_DIVU); + wire op_rem = (op_r == `INST_REM); + wire op_remu = (op_r == `INST_REMU); + wire is_divisor_zero = (divisor_r == `ZeroWord); - // 状态机实现 + + // 当前状态切换 always @ (posedge clk) begin if (rst == `RstEnable) begin state <= STATE_IDLE; - ready_o <= `DivResultNotReady; - result_o <= `ZeroWord; - div_result <= `ZeroWord; - div_remain <= `ZeroWord; - 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 + state <= next_state; + end + end + + // 下一个状态切换 + always @ (*) begin + if (start_i == `DivStart) begin + case (state) + STATE_IDLE: begin + next_state = STATE_START; + end + STATE_START: begin + if (is_divisor_zero) begin + next_state = STATE_IDLE; + end else begin + next_state = STATE_CALC; + end + end + STATE_CALC: begin + if (count == `ZeroWord) begin + next_state = STATE_INVERT; + end else begin + next_state = STATE_CALC; + end + end + STATE_INVERT: begin + next_state = STATE_END; + end + STATE_END: begin + next_state = STATE_IDLE; + end + default: begin + next_state = STATE_IDLE; + end + endcase + end else begin + next_state = STATE_IDLE; + end + end + + // 具体操作 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + op_r <= 3'h0; + end else begin + if (start_i == `DivStart && state == STATE_IDLE) begin + op_r <= op_i; + end + end + end + + // 运算完后要写的寄存器地址 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + reg_waddr_o <= `ZeroReg; + end else begin + if (start_i == `DivStart && state == STATE_IDLE) begin + reg_waddr_o <= reg_waddr_i; + end + end + end + + // 被除数 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + dividend_r <= `ZeroWord; end else begin case (state) STATE_IDLE: begin - busy_o <= `False; if (start_i == `DivStart) begin - reg_waddr_o <= reg_waddr_i; - inst_div <= op_div; - inst_divu <= op_divu; - - // 除数为0 - if (divisor_i == `ZeroWord) begin - ready_o <= `DivResultReady; - if (op_div | op_divu) begin - result_o <= 32'hffffffff; - end else begin - result_o <= dividend_i; - end - // 除数不为0 - end else begin - count <= 32'h80000000; - state <= STATE_START; - - // DIV和REM这两条指令是有符号数运算 - if ((op_div) || (op_rem)) begin - // 被除数求补码 - if (dividend_i[31] == 1'b1) begin - dividend_temp <= dividend_invert; - minuend <= dividend_invert[31]; - end else begin - dividend_temp <= dividend_i; - minuend <= dividend_i[31]; - end - // 除数求补码 - if (divisor_i[31] == 1'b1) begin - divisor_temp <= divisor_invert; - end else begin - divisor_temp <= divisor_i; - end - end else begin - dividend_temp <= dividend_i; - minuend <= dividend_i[31]; - divisor_temp <= divisor_i; - end - - // 运算结束后是否要对结果取补码 - 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; - end - end - end else begin - ready_o <= `DivResultNotReady; - result_o <= `ZeroWord; + dividend_r <= dividend_i; end end - STATE_START: begin - busy_o <= `True; - if (start_i == `DivStart) begin - 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 - minuend <= {minuend[30:0], dividend_temp[31]}; - end - count <= {1'b0, count[31:1]}; - dividend_temp <= {dividend_temp[30:0], 1'b0}; - end else begin - state <= STATE_INVERT; - if (minuend_ge_divisor) begin - div_remain <= minuend_sub_res; - end else begin - div_remain <= minuend; - end + // 除数不为0 + if (!is_divisor_zero) begin + // DIV和REM这两条指令是有符号数运算 + if ((op_div | op_rem) & dividend_r[31]) begin + // 被除数求补码 + dividend_r <= dividend_invert; end - end else begin - ready_o <= `DivResultNotReady; - 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; - div_remain <= -div_remain; - end - state <= STATE_END; - end else begin - ready_o <= `DivResultNotReady; - result_o <= `ZeroWord; - state <= STATE_IDLE; + STATE_CALC: begin + if (|count) begin + dividend_r <= {dividend_r[30:0], 1'b0}; end end + endcase + end + end - STATE_END: begin - busy_o <= `False; + // 除数 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + divisor_r <= `ZeroWord; + end else begin + case (state) + STATE_IDLE: begin if (start_i == `DivStart) begin + divisor_r <= divisor_i; + end + end + STATE_START: begin + // 除数不为0 + if (!is_divisor_zero) begin + // DIV和REM这两条指令是有符号数运算 + if ((op_div | op_rem) & divisor_r[31]) begin + // 除数求补码 + divisor_r <= divisor_invert; + end + end + end + endcase + end + end + + // 运算结束 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + ready_o <= `DivResultNotReady; + end else begin + case (state) + STATE_IDLE: begin + ready_o <= `DivResultNotReady; + end + STATE_START: begin + // 除数为0 + if (is_divisor_zero) begin ready_o <= `DivResultReady; - 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; - ready_o <= `DivResultNotReady; end end + STATE_END: begin + ready_o <= `DivResultReady; + end + endcase + end + end + // 最终结果 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + result_o <= `ZeroWord; + end else begin + case (state) + STATE_IDLE: begin + result_o <= `ZeroWord; + end + STATE_START: begin + // 除数为0 + if (is_divisor_zero) begin + if (op_div | op_divu) begin + result_o <= 32'hffffffff; + end else begin + result_o <= dividend_r; + end + end + end + STATE_END: begin + if (op_div | op_divu) begin + result_o <= div_result; + end else begin + result_o <= div_remain; + end + end + endcase + end + end + + // bit计数 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + count <= `ZeroWord; + end else begin + case (state) + STATE_START: begin + // 除数不为0 + if (!is_divisor_zero) begin + count <= 32'h80000000; + end + end + STATE_CALC: begin + if (|count) begin + count <= {1'b0, count[31:1]}; + end + end + endcase + end + end + + // 结果是否取补码 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + invert_result <= 1'b0; + end else begin + case (state) + STATE_START: begin + // 除数不为0 + if (!is_divisor_zero) begin + // 运算结束后是否要对结果取补码 + if (((op_div) && (dividend_r[31] ^ divisor_r[31] == 1'b1)) + || ((op_rem) && (dividend_r[31] == 1'b1))) begin + invert_result <= 1'b1; + end else begin + invert_result <= 1'b0; + end + end + end + endcase + end + end + + // 被减数 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + minuend <= `ZeroWord; + end else begin + case (state) + STATE_START: begin + // 除数不为0 + if (!is_divisor_zero) begin + // DIV和REM这两条指令是有符号数运算 + if ((op_div | op_rem) & dividend_r[31]) begin + minuend <= dividend_invert[31]; + end else begin + minuend <= dividend_r[31]; + end + end + end + STATE_CALC: begin + if (|count) begin + if (minuend_ge_divisor) begin + minuend <= {minuend_sub_res[30:0], dividend_r[31]}; + end else begin + minuend <= {minuend[30:0], dividend_r[31]}; + end + end + end + endcase + end + end + + // 商 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + div_result <= `ZeroWord; + end else begin + case (state) + STATE_CALC: begin + div_result <= {div_result[30:0], minuend_ge_divisor}; + end + STATE_INVERT: begin + if (invert_result == 1'b1) begin + div_result <= -div_result; + end + end + endcase + end + end + + // 余数 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + div_remain <= `ZeroWord; + end else begin + case (state) + STATE_CALC: begin + if (count == `ZeroWord) begin + if (minuend_ge_divisor) begin + div_remain <= minuend_sub_res; + end else begin + div_remain <= minuend; + end + end + end + STATE_INVERT: begin + if (invert_result == 1'b1) begin + div_remain <= -div_remain; + end + end + endcase + end + end + + // busy信号要比ready信号提前一个时钟撤销 + always @ (posedge clk) begin + if (rst == `RstEnable) begin + busy_o <= `False; + end else begin + case (state) + STATE_CALC, STATE_INVERT: begin + busy_o <= `True; + end + default: begin + busy_o <= `False; + end endcase end end diff --git a/rtl/utils/gen_dff.v b/rtl/utils/gen_dff.v index 3ee48f8..4914387 100644 --- a/rtl/utils/gen_dff.v +++ b/rtl/utils/gen_dff.v @@ -14,7 +14,7 @@ limitations under the License. */ - +// 带默认值和控制信号的流水线触发器 module gen_pipe_dff #( parameter DW = 32)( @@ -41,3 +41,109 @@ module gen_pipe_dff #( assign qout = qout_r; endmodule + +// 复位后输出为0的触发器 +module gen_rst_0_dff #( + parameter DW = 32)( + + input wire clk, + input wire rst, + + input wire[DW-1:0] din, + output wire[DW-1:0] qout + + ); + + reg[DW-1:0] qout_r; + + always @ (posedge clk) begin + if (!rst) begin + qout_r <= {DW{1'b0}}; + end else begin + qout_r <= din; + end + end + + assign qout = qout_r; + +endmodule + +// 复位后输出为1的触发器 +module gen_rst_1_dff #( + parameter DW = 32)( + + input wire clk, + input wire rst, + + input wire[DW-1:0] din, + output wire[DW-1:0] qout + + ); + + reg[DW-1:0] qout_r; + + always @ (posedge clk) begin + if (!rst) begin + qout_r <= {DW{1'b1}}; + end else begin + qout_r <= din; + end + end + + assign qout = qout_r; + +endmodule + +// 复位后输出为默认值的触发器 +module gen_rst_def_dff #( + parameter DW = 32)( + + input wire clk, + input wire rst, + input wire[DW-1:0] def_val, + + input wire[DW-1:0] din, + output wire[DW-1:0] qout + + ); + + reg[DW-1:0] qout_r; + + always @ (posedge clk) begin + if (!rst) begin + qout_r <= def_val; + end else begin + qout_r <= din; + end + end + + assign qout = qout_r; + +endmodule + +// 带使能端、复位后输出为0的触发器 +module gen_en_dff #( + parameter DW = 32)( + + input wire clk, + input wire rst, + + input wire en, + input wire[DW-1:0] din, + output wire[DW-1:0] qout + + ); + + reg[DW-1:0] qout_r; + + always @ (posedge clk) begin + if (!rst) begin + qout_r <= {DW{1'b0}}; + end else if (en == 1'b1) begin + qout_r <= din; + end + end + + assign qout = qout_r; + +endmodule