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_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;
dividend_r <= dividend_i;
end
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
if (divisor_i == `ZeroWord) begin
if (is_divisor_zero) begin
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
result_o <= 32'hffffffff;
end else begin
result_o <= dividend_i;
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
end else begin
if (!is_divisor_zero) begin
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
//
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;
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_i[31] ^ divisor_i[31] == 1'b1))
|| ((op_rem) && (dividend_i[31] == 1'b1))) 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 else begin
ready_o <= `DivResultNotReady;
result_o <= `ZeroWord;
end
endcase
end
end
//
always @ (posedge clk) begin
if (rst == `RstEnable) begin
minuend <= `ZeroWord;
end else begin
case (state)
STATE_START: begin
busy_o <= `True;
if (start_i == `DivStart) begin
div_result <= {div_result[30:0], minuend_ge_divisor};
// 0
if (!is_divisor_zero) begin
// 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 (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
minuend <= {minuend[30:0], dividend_temp[31]};
minuend <= {minuend[30:0], dividend_r[31]};
end
count <= {1'b0, count[31:1]};
dividend_temp <= {dividend_temp[30:0], 1'b0};
end
end
endcase
end
end
//
always @ (posedge clk) begin
if (rst == `RstEnable) begin
div_result <= `ZeroWord;
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
div_remain <= minuend_sub_res;
end else begin
div_remain <= minuend;
end
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;
end
endcase
end
end
STATE_END: begin
// busyready
always @ (posedge clk) begin
if (rst == `RstEnable) begin
busy_o <= `False;
if (start_i == `DivStart) begin
ready_o <= `DivResultReady;
if (inst_div | inst_divu) begin
result_o <= div_result;
end else begin
result_o <= div_remain;
case (state)
STATE_CALC, STATE_INVERT: begin
busy_o <= `True;
end
state <= STATE_IDLE;
end else begin
state <= STATE_IDLE;
result_o <= `ZeroWord;
ready_o <= `DivResultNotReady;
default: begin
busy_o <= `False;
end
end
endcase
end
end

View File

@ -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