tinyriscv/rtl/core/div.v

149 lines
6.0 KiB
Coq
Raw Normal View History

/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.v"
module div (
input wire clk,
input wire rst,
input wire[`RegBus] dividend_i,
input wire[`RegBus] divisor_i,
input wire start_i,
output reg[`DoubleRegBus] result_o,
output reg ready_o
);
parameter STATE_IDLE = 0;
parameter STATE_START = 1;
parameter STATE_REVERT = 2;
parameter STATE_END = 3;
reg[`RegBus] dividend_temp;
reg[`RegBus] divisor_temp;
reg[1:0] state;
reg[6:0] count;
reg[`RegBus] div_result;
reg[`RegBus] div_remain;
reg[`RegBus] minuend;
reg[`RegBus] divisor_zero_result;
always @ (posedge clk) begin
if (rst == `RstEnable) begin
state <= STATE_IDLE;
ready_o <= `DivResultNotReady;
result_o <= {`ZeroWord, `ZeroWord};
div_result <= `ZeroWord;
div_remain <= `ZeroWord;
divisor_zero_result <= ~32'b00000001 + 1'b1;
end else begin
case (state)
STATE_IDLE: begin
if (start_i == `DivStart) begin
if (divisor_i == `ZeroWord) begin
ready_o <= `DivResultReady;
result_o <= {`ZeroWord, divisor_zero_result};
end else begin
count <= 7'd31;
state <= STATE_START;
if (dividend_i[31] == 1'b1) begin
dividend_temp <= ~dividend_i + 1;
minuend <= ((~dividend_i + 1) >> 7'd31) & 1'b1;
end else begin
dividend_temp <= dividend_i;
minuend <= (dividend_i >> 7'd31) & 1'b1;
end
if (divisor_i[31] == 1'b1) begin
divisor_temp <= ~divisor_i + 1;
end else begin
divisor_temp <= divisor_i;
end
div_result <= `ZeroWord;
div_remain <= `ZeroWord;
end
end else begin
ready_o <= `DivResultNotReady;
result_o <= {`ZeroWord, `ZeroWord};
end
end
STATE_START: begin
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);
end else begin
div_result <= (div_result << 1'b1) | 1'b0;
minuend <= (minuend << 1'b1) | ((dividend_temp >> (count - 1'b1)) & 1'b1);
end
count <= count - 1'b1;
end else begin
state <= STATE_REVERT;
if (minuend >= divisor_temp) begin
div_result <= (div_result << 1'b1) | 1'b1;
div_remain <= minuend - divisor_temp;
end else begin
div_result <= (div_result << 1'b1) | 1'b0;
div_remain <= minuend;
end
end
end else begin
ready_o <= `DivResultReady;
result_o <= {`ZeroWord, `ZeroWord};
state <= STATE_IDLE;
end
end
STATE_REVERT: begin
if (start_i == `DivStart) begin
if (dividend_i[31] ^ divisor_i[31] == 1'b1) begin
div_result <= ~div_result + 1'b1;
end
if (((dividend_i[31] == 1'b1) && (div_remain >= 0)) || ((dividend_i[31] == 1'b0) && (div_remain < 0))) begin
div_remain <= ~div_remain + 1'b1;
end
state <= STATE_END;
end else begin
ready_o <= `DivResultReady;
result_o <= {`ZeroWord, `ZeroWord};
state <= STATE_IDLE;
end
end
STATE_END: begin
if (start_i == `DivStart) begin
ready_o <= `DivResultReady;
result_o <= {div_remain, div_result};
state <= STATE_IDLE;
end else begin
state <= STATE_IDLE;
ready_o <= `DivResultNotReady;
end
end
endcase
end
end
endmodule