rtl: div: fix error

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/1/head
liangkangnan 2020-09-14 22:22:42 +08:00
parent 045f482fe1
commit 29623c8d2a
1 changed files with 131 additions and 295 deletions

View File

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