// ============================================================================
|
// ============================================================================
|
// __
|
// __
|
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
|
// \\__/ o\ (C) 2013,2015 Robert Finch, Stratford
|
// \ __ / All rights reserved.
|
// \ __ / All rights reserved.
|
// \/_// robfinch<remove>@finitron.ca
|
// \/_// robfinch<remove>@finitron.ca
|
// ||
|
// ||
|
//
|
//
|
// This source file is free software: you can redistribute it and/or modify
|
// This source file is free software: you can redistribute it and/or modify
|
// it under the terms of the GNU Lesser General Public License as published
|
// it under the terms of the GNU Lesser General Public License as published
|
// by the Free Software Foundation, either version 3 of the License, or
|
// by the Free Software Foundation, either version 3 of the License, or
|
// (at your option) any later version.
|
// (at your option) any later version.
|
//
|
//
|
// This source file is distributed in the hope that it will be useful,
|
// This source file is distributed in the hope that it will be useful,
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
//
|
//
|
//
|
//
|
// Thor Superscaler
|
// Thor Superscaler
|
// Thor_divider.v
|
// Thor_divider.v
|
// - 64 bit divider
|
// - 64 bit divider
|
//
|
//
|
// ============================================================================
|
// ============================================================================
|
//
|
//
|
module Thor_divider(rst, clk, ld, abort, sgn, isDivi, a, b, imm, qo, ro, dvByZr, done, idle);
|
module Thor_divider(rst, clk, ld, abort, sgn, isDivi, a, b, imm, qo, ro, dvByZr, done, idle);
|
parameter WID=64;
|
parameter WID=64;
|
parameter DIV=3'd3;
|
parameter DIV=3'd3;
|
parameter IDLE=3'd4;
|
parameter IDLE=3'd4;
|
parameter DONE=3'd5;
|
parameter DONE=3'd5;
|
input clk;
|
input clk;
|
input rst;
|
input rst;
|
input ld;
|
input ld;
|
input abort;
|
input abort;
|
input sgn;
|
input sgn;
|
input isDivi;
|
input isDivi;
|
input [WID-1:0] a;
|
input [WID-1:0] a;
|
input [WID-1:0] b;
|
input [WID-1:0] b;
|
input [WID-1:0] imm;
|
input [WID-1:0] imm;
|
output [WID-1:0] qo;
|
output [WID-1:0] qo;
|
reg [WID-1:0] qo;
|
reg [WID-1:0] qo;
|
output [WID-1:0] ro;
|
output [WID-1:0] ro;
|
reg [WID-1:0] ro;
|
reg [WID-1:0] ro;
|
output done;
|
output done;
|
output idle;
|
output idle;
|
output dvByZr;
|
output dvByZr;
|
reg dvByZr;
|
reg dvByZr;
|
|
|
reg [WID-1:0] aa,bb;
|
reg [WID-1:0] aa,bb;
|
reg so;
|
reg so;
|
reg [2:0] state;
|
reg [2:0] state;
|
reg [7:0] cnt;
|
reg [7:0] cnt;
|
wire cnt_done = cnt==8'd0;
|
wire cnt_done = cnt==8'd0;
|
assign done = state==DONE;
|
assign done = state==DONE||(state==IDLE && !ld);
|
assign idle = state==IDLE;
|
assign idle = state==IDLE;
|
reg ce1;
|
reg ce1;
|
reg [WID-1:0] q;
|
reg [WID-1:0] q;
|
reg [WID:0] r;
|
reg [WID:0] r;
|
wire b0 = bb <= r;
|
wire b0 = bb <= r;
|
wire [WID-1:0] r1 = b0 ? r - bb : r;
|
wire [WID-1:0] r1 = b0 ? r - bb : r;
|
|
|
initial begin
|
initial begin
|
q = 64'd0;
|
q = 64'd0;
|
r = 64'd0;
|
r = 64'd0;
|
qo = 64'd0;
|
qo = 64'd0;
|
ro = 64'd0;
|
ro = 64'd0;
|
end
|
end
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
if (rst) begin
|
if (rst) begin
|
aa <= {WID{1'b0}};
|
aa <= {WID{1'b0}};
|
bb <= {WID{1'b0}};
|
bb <= {WID{1'b0}};
|
q <= {WID{1'b0}};
|
q <= {WID{1'b0}};
|
r <= {WID{1'b0}};
|
r <= {WID{1'b0}};
|
qo <= {WID{1'b0}};
|
qo <= {WID{1'b0}};
|
ro <= {WID{1'b0}};
|
ro <= {WID{1'b0}};
|
cnt <= 8'd0;
|
cnt <= 8'd0;
|
|
dvByZr <= 1'b0;
|
state <= IDLE;
|
state <= IDLE;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (abort)
|
if (abort)
|
cnt <= 8'd00;
|
cnt <= 8'd00;
|
else if (!cnt_done)
|
else if (!cnt_done)
|
cnt <= cnt - 8'd1;
|
cnt <= cnt - 8'd1;
|
|
|
case(state)
|
case(state)
|
IDLE:
|
IDLE:
|
if (ld) begin
|
if (ld) begin
|
if (sgn) begin
|
if (sgn) begin
|
q <= a[WID-1] ? -a : a;
|
q <= a[WID-1] ? -a : a;
|
bb <= isDivi ? (imm[WID-1] ? -imm : imm) :(b[WID-1] ? -b : b);
|
bb <= isDivi ? (imm[WID-1] ? -imm : imm) :(b[WID-1] ? -b : b);
|
so <= isDivi ? a[WID-1] ^ imm[WID-1] : a[WID-1] ^ b[WID-1];
|
so <= isDivi ? a[WID-1] ^ imm[WID-1] : a[WID-1] ^ b[WID-1];
|
end
|
end
|
else begin
|
else begin
|
q <= a;
|
q <= a;
|
bb <= isDivi ? imm : b;
|
bb <= isDivi ? imm : b;
|
so <= 1'b0;
|
so <= 1'b0;
|
$display("bb=%d", isDivi ? imm : b);
|
$display("bb=%d", isDivi ? imm : b);
|
end
|
end
|
dvByZr <= isDivi ? imm=={WID{1'b0}} : b=={WID{1'b0}};
|
dvByZr <= isDivi ? imm=={WID{1'b0}} : b=={WID{1'b0}};
|
r <= {WID{1'b0}};
|
r <= {WID{1'b0}};
|
cnt <= WID+1;
|
cnt <= WID+1;
|
state <= DIV;
|
state <= DIV;
|
end
|
end
|
DIV:
|
DIV:
|
if (!cnt_done) begin
|
if (!cnt_done) begin
|
$display("cnt:%d r1=%h q[63:0]=%h", cnt,r1,q);
|
$display("cnt:%d r1=%h q[63:0]=%h", cnt,r1,q);
|
q <= {q[WID-2:0],b0};
|
q <= {q[WID-2:0],b0};
|
r <= {r1,q[WID-1]};
|
r <= {r1,q[WID-1]};
|
end
|
end
|
else begin
|
else begin
|
$display("cnt:%d r1=%h q[63:0]=%h", cnt,r1,q);
|
$display("cnt:%d r1=%h q[63:0]=%h", cnt,r1,q);
|
if (sgn) begin
|
if (sgn) begin
|
if (so) begin
|
if (so) begin
|
qo <= -q;
|
qo <= -q;
|
ro <= -r[WID:1];
|
ro <= -r[WID:1];
|
end
|
end
|
else begin
|
else begin
|
qo <= q;
|
qo <= q;
|
ro <= r[WID:1];
|
ro <= r[WID:1];
|
end
|
end
|
end
|
end
|
else begin
|
else begin
|
qo <= q;
|
qo <= q;
|
ro <= r[WID:1];
|
ro <= r[WID:1];
|
end
|
end
|
state <= DONE;
|
state <= DONE;
|
end
|
end
|
DONE:
|
DONE:
|
state <= IDLE;
|
state <= IDLE;
|
endcase
|
endcase
|
end
|
end
|
|
|
endmodule
|
endmodule
|
|
|
module Thor_divider_tb();
|
module Thor_divider_tb();
|
parameter WID=64;
|
parameter WID=64;
|
reg rst;
|
reg rst;
|
reg clk;
|
reg clk;
|
reg ld;
|
reg ld;
|
wire done;
|
wire done;
|
wire [WID-1:0] qo,ro;
|
wire [WID-1:0] qo,ro;
|
|
|
initial begin
|
initial begin
|
clk = 1;
|
clk = 1;
|
rst = 0;
|
rst = 0;
|
#100 rst = 1;
|
#100 rst = 1;
|
#100 rst = 0;
|
#100 rst = 0;
|
#100 ld = 1;
|
#100 ld = 1;
|
#150 ld = 0;
|
#150 ld = 0;
|
end
|
end
|
|
|
always #10 clk = ~clk; // 50 MHz
|
always #10 clk = ~clk; // 50 MHz
|
|
|
|
|
Thor_divider #(WID) u1
|
Thor_divider #(WID) u1
|
(
|
(
|
.rst(rst),
|
.rst(rst),
|
.clk(clk),
|
.clk(clk),
|
.ld(ld),
|
.ld(ld),
|
.sgn(1'b1),
|
.sgn(1'b1),
|
.isDivi(1'b0),
|
.isDivi(1'b0),
|
.a(64'd10005),
|
.a(64'd10005),
|
.b(64'd27),
|
.b(64'd27),
|
.imm(64'd123),
|
.imm(64'd123),
|
.qo(qo),
|
.qo(qo),
|
.ro(ro),
|
.ro(ro),
|
.dvByZr(),
|
.dvByZr(),
|
.done(done)
|
.done(done)
|
);
|
);
|
|
|
endmodule
|
endmodule
|
|
|
|
|