rtl: div: timing optimization

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/1/head
liangkangnan 2020-09-12 14:17:34 +08:00
parent 90f57951e4
commit 8c3d7ac932
2 changed files with 407 additions and 131 deletions

View File

@ -40,166 +40,336 @@ module div(
); );
// //
localparam STATE_IDLE = 4'b0001; localparam STATE_IDLE = 5'b00001;
localparam STATE_START = 4'b0010; localparam STATE_START = 5'b00010;
localparam STATE_INVERT = 4'b0100; localparam STATE_CALC = 5'b00100;
localparam STATE_END = 4'b1000; localparam STATE_INVERT = 5'b01000;
localparam STATE_END = 5'b10000;
reg[`RegBus] dividend_temp; reg[4:0] state;
reg[`RegBus] divisor_temp; reg[4:0] next_state;
reg[3:0] state; reg[`RegBus] dividend_r;
reg[`RegBus] divisor_r;
reg[2:0] op_r;
reg[31:0] count; reg[31:0] count;
reg[`RegBus] div_result; reg[`RegBus] div_result;
reg[`RegBus] div_remain; reg[`RegBus] div_remain;
reg[`RegBus] minuend; reg[`RegBus] minuend;
reg invert_result; reg invert_result;
reg inst_div;
reg inst_divu;
wire[31:0] dividend_invert = -dividend_i; wire[31:0] dividend_invert = (-dividend_r);
wire[31:0] divisor_invert = -divisor_i; wire[31:0] divisor_invert = (-divisor_r);
wire[31:0] minuend_sub_res = minuend - divisor_temp; wire[31:0] minuend_sub_res = (minuend - divisor_r);
wire minuend_ge_divisor = minuend >= divisor_temp; wire minuend_ge_divisor = (minuend >= divisor_r);
wire op_div = (op_i == `INST_DIV); wire op_div = (op_r == `INST_DIV);
wire op_divu = (op_i == `INST_DIVU); wire op_divu = (op_r == `INST_DIVU);
wire op_rem = (op_i == `INST_REM); wire op_rem = (op_r == `INST_REM);
wire op_remu = (op_i == `INST_REMU); wire op_remu = (op_r == `INST_REMU);
wire is_divisor_zero = (divisor_r == `ZeroWord);
//
//
always @ (posedge clk) begin always @ (posedge clk) begin
if (rst == `RstEnable) begin if (rst == `RstEnable) begin
state <= STATE_IDLE; state <= STATE_IDLE;
ready_o <= `DivResultNotReady; end else begin
result_o <= `ZeroWord; state <= next_state;
div_result <= `ZeroWord; end
div_remain <= `ZeroWord; end
reg_waddr_o <= `ZeroWord;
dividend_temp <= `ZeroWord; //
divisor_temp <= `ZeroWord; always @ (*) begin
minuend <= `ZeroWord; if (start_i == `DivStart) begin
count <= `ZeroWord; case (state)
invert_result <= 1'b0; STATE_IDLE: begin
busy_o <= `False; next_state = STATE_START;
inst_div <= 1'b0; end
inst_divu <= 1'b0; 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 end else begin
case (state) case (state)
STATE_IDLE: begin STATE_IDLE: begin
busy_o <= `False;
if (start_i == `DivStart) begin if (start_i == `DivStart) begin
reg_waddr_o <= reg_waddr_i; dividend_r <= dividend_i;
inst_div <= op_div; end
inst_divu <= op_divu; end
STATE_START: begin
// 0
if (!is_divisor_zero) begin
// DIVREM
if ((op_div | op_rem) & dividend_r[31]) begin
//
dividend_r <= dividend_invert;
end
end
end
STATE_CALC: begin
if (|count) begin
dividend_r <= {dividend_r[30:0], 1'b0};
end
end
endcase
end
end
//
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
// DIVREM
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 // 0
if (divisor_i == `ZeroWord) begin if (is_divisor_zero) begin
ready_o <= `DivResultReady; ready_o <= `DivResultReady;
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 if (op_div | op_divu) begin
result_o <= 32'hffffffff; result_o <= 32'hffffffff;
end else begin end else begin
result_o <= dividend_i; result_o <= dividend_r;
end 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 // 0
end else begin if (!is_divisor_zero) begin
count <= 32'h80000000; count <= 32'h80000000;
state <= STATE_START;
// DIVREM
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 end
//
if (divisor_i[31] == 1'b1) begin
divisor_temp <= divisor_invert;
end else begin
divisor_temp <= divisor_i;
end end
end else begin STATE_CALC: begin
dividend_temp <= dividend_i; if (|count) begin
minuend <= dividend_i[31]; count <= {1'b0, count[31:1]};
divisor_temp <= divisor_i; end
end
endcase
end
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_i[31] ^ divisor_i[31] == 1'b1)) if (((op_div) && (dividend_r[31] ^ divisor_r[31] == 1'b1))
|| ((op_rem) && (dividend_i[31] == 1'b1))) begin || ((op_rem) && (dividend_r[31] == 1'b1))) begin
invert_result <= 1'b1; invert_result <= 1'b1;
end else begin end else begin
invert_result <= 1'b0; invert_result <= 1'b0;
end end
end end
end else begin end
ready_o <= `DivResultNotReady; endcase
result_o <= `ZeroWord;
end end
end end
//
always @ (posedge clk) begin
if (rst == `RstEnable) begin
minuend <= `ZeroWord;
end else begin
case (state)
STATE_START: begin STATE_START: begin
busy_o <= `True; // 0
if (start_i == `DivStart) begin if (!is_divisor_zero) begin
div_result <= {div_result[30:0], minuend_ge_divisor}; // DIVREM
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 (|count) begin
if (minuend_ge_divisor) begin if (minuend_ge_divisor) begin
minuend <= {minuend_sub_res[30:0], dividend_temp[31]}; minuend <= {minuend_sub_res[30:0], dividend_r[31]};
end else begin end else begin
minuend <= {minuend[30:0], dividend_temp[31]}; minuend <= {minuend[30:0], dividend_r[31]};
end end
count <= {1'b0, count[31:1]}; end
dividend_temp <= {dividend_temp[30:0], 1'b0}; end
endcase
end
end
//
always @ (posedge clk) begin
if (rst == `RstEnable) begin
div_result <= `ZeroWord;
end else begin end else begin
state <= STATE_INVERT; 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 if (minuend_ge_divisor) begin
div_remain <= minuend_sub_res; div_remain <= minuend_sub_res;
end else begin end else begin
div_remain <= minuend; div_remain <= minuend;
end end
end end
end else begin
ready_o <= `DivResultNotReady;
result_o <= `ZeroWord;
state <= STATE_IDLE;
end end
end
STATE_INVERT: begin STATE_INVERT: begin
busy_o <= `True;
if (start_i == `DivStart) begin
if (invert_result == 1'b1) begin if (invert_result == 1'b1) begin
div_result <= -div_result;
div_remain <= -div_remain; div_remain <= -div_remain;
end end
state <= STATE_END; end
end else begin endcase
ready_o <= `DivResultNotReady;
result_o <= `ZeroWord;
state <= STATE_IDLE;
end end
end end
STATE_END: begin // busyready
always @ (posedge clk) begin
if (rst == `RstEnable) begin
busy_o <= `False; busy_o <= `False;
if (start_i == `DivStart) begin
ready_o <= `DivResultReady;
if (inst_div | inst_divu) begin
result_o <= div_result;
end else begin end else begin
result_o <= div_remain; case (state)
STATE_CALC, STATE_INVERT: begin
busy_o <= `True;
end end
state <= STATE_IDLE; default: begin
end else begin busy_o <= `False;
state <= STATE_IDLE;
result_o <= `ZeroWord;
ready_o <= `DivResultNotReady;
end end
end
endcase endcase
end end
end end

View File

@ -14,7 +14,7 @@
limitations under the License. limitations under the License.
*/ */
// 线
module gen_pipe_dff #( module gen_pipe_dff #(
parameter DW = 32)( parameter DW = 32)(
@ -41,3 +41,109 @@ module gen_pipe_dff #(
assign qout = qout_r; assign qout = qout_r;
endmodule 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