Line 1... |
Line 1... |
// ============================================================================
|
// ============================================================================
|
// __
|
// __
|
// \\__/ o\ (C) 2006-2016 Robert Finch, Stratford
|
// \\__/ o\ (C) 2006-2018 Robert Finch, Waterloo
|
// \ __ / All rights reserved.
|
// \ __ / All rights reserved.
|
// \/_// robfinch<remove>@finitron.ca
|
// \/_// robfinch<remove>@finitron.ca
|
// ||
|
// ||
|
//
|
//
|
|
// fpdivr2.v
|
|
// Radix 2 floating point divider primitive
|
|
//
|
|
//
|
// 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.
|
//
|
//
|
Line 16... |
Line 20... |
// 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/>.
|
//
|
//
|
// fpdivr2.v
|
|
// Radix 2 floating point divider primitive
|
|
//
|
|
// ============================================================================
|
// ============================================================================
|
//
|
|
module fpdivr2
|
|
#( parameter WID = 24 )
|
|
(
|
|
input clk,
|
|
input ld,
|
|
input [WID-1:0] a,
|
|
input [WID-1:0] b,
|
|
output reg [WID*2-1:0] q,
|
|
output [WID-1:0] r,
|
|
output done
|
|
);
|
|
localparam DMSB = WID-1;
|
|
|
|
reg [DMSB:0] rx [2:0]; // remainder holds
|
|
reg [DMSB:0] rxx;
|
|
reg [7:0] cnt; // iteration count
|
|
wire [DMSB:0] sdq;
|
|
wire [DMSB:0] sdr;
|
|
wire sdval = 1'b0;
|
|
wire sdbz;
|
|
reg willGo0;
|
|
|
|
//specialCaseDivider #(WID) u1 (.a(a), .b(b), .q(sdq), .r(sdr), .val(sdval), .dbz(sdbz) );
|
|
|
|
initial begin
|
module fpdivr2(clk4x, ld, a, b, q, r, done, lzcnt);
|
rx[0] = 0;
|
parameter WID = 112;
|
|
parameter RADIX = 2;
|
|
localparam WID1 = WID;//((WID+2)/3)*3; // make width a multiple of three
|
|
localparam DMSB = WID1-1;
|
|
input clk4x;
|
|
input ld;
|
|
input [WID1-1:0] a;
|
|
input [WID1-1:0] b;
|
|
output reg [WID1*2-1:0] q = 0;
|
|
output reg [WID1-1:0] r = 0;
|
|
output reg done = 1'b0;
|
|
output reg [7:0] lzcnt;
|
|
|
|
|
|
reg [8:0] cnt; // iteration count
|
|
reg [WID1*2-1:0] qi = 0;
|
|
reg [DMSB+1:0] ri = 0;
|
|
wire b0;
|
|
reg gotnz; // got a non-zero bit
|
|
|
|
reg done1;
|
|
wire [7:0] maxcnt;
|
|
assign b0 = b <= ri;
|
|
wire [DMSB+1:0] r1 = b0 ? ri - b : ri;
|
|
assign maxcnt = WID1*2;
|
|
|
|
// Done pulse for external circuit. Must span over 1 1x clock so that it's
|
|
// recognized.
|
|
always @(posedge clk4x)
|
|
if (ld)
|
|
done <= 1'b0;
|
|
else if (cnt==9'h1FE)
|
|
done <= 1'b1;
|
|
else if (cnt==9'h1F7)
|
|
done <= 1'b0;
|
|
|
|
// Internal done pulse
|
|
always @(posedge clk4x)
|
|
begin
|
|
done1 <= 1'b0;
|
|
if (ld)
|
|
done1 <= 1'b0;
|
|
else if (cnt==9'h1FF)
|
|
done1 <= 1'b1;
|
end
|
end
|
|
|
always @(posedge clk)
|
always @(posedge clk4x)
|
if (ld)
|
if (ld)
|
cnt <= sdval ? 8'b10000000 : WID*2-2;
|
cnt <= maxcnt;
|
else if (!done)
|
else if (cnt != 9'h1F7)
|
cnt <= cnt - 1;
|
cnt <= cnt - 8'd1;
|
|
|
|
always @(posedge clk4x)
|
always @(posedge clk)
|
if (ld)
|
if (ld) begin
|
gotnz <= 1'b0;
|
rxx <= 0;
|
else if (!cnt[8]) begin
|
if (sdval)
|
if (b0)
|
q <= {sdq,{WID{1'b0}}};
|
gotnz <= 1'b1;
|
else
|
|
q <= {a,{WID{1'b0}}};
|
|
end
|
|
else if (!done) begin
|
|
willGo0 = {rxx ,q[WID*2-1 ]} > b;
|
|
rx[0] = willGo0 ? {rxx ,q[WID*2-1 ]} - b : {rxx ,q[WID*2-1 ]};
|
|
q[WID*2-1:1] <= q[WID*2-1-1:0];
|
|
q[0] <= willGo0;
|
|
rxx <= rx[0];
|
|
end
|
end
|
|
|
// correct remainder
|
wire cnt81;
|
assign r = sdval ? sdr : rx[2][DMSB] ? rx[2] + b : rx[2];
|
delay1 #(1) u1 (clk4x, 1'b1, cnt[8], cnt81);
|
assign done = cnt[7];
|
|
|
|
endmodule
|
|
|
|
/*
|
|
module fpdivr2_tb();
|
|
|
|
reg rst;
|
always @(posedge clk4x)
|
reg clk;
|
if (ld)
|
reg ld;
|
lzcnt <= 8'h00;
|
reg [6:0] cnt;
|
else if (!cnt81) begin
|
|
if (b0==1'b0 && !gotnz)
|
wire ce = 1'b1;
|
lzcnt <= lzcnt + 8'd1;
|
wire [23:0] a = 24'h0_4000;
|
end
|
wire [23:0] b = 24'd101;
|
|
wire [45:0] q;
|
|
wire [23:0] r;
|
|
wire done;
|
|
|
|
initial begin
|
|
clk = 1;
|
|
rst = 0;
|
|
#100 rst = 1;
|
|
#100 rst = 0;
|
|
end
|
|
|
|
always #20 clk = ~clk; // 25 MHz
|
|
|
|
always @(posedge clk)
|
|
if (rst)
|
|
cnt <= 0;
|
|
else begin
|
|
ld <= 0;
|
|
cnt <= cnt + 1;
|
|
if (cnt == 3)
|
|
ld <= 1;
|
|
$display("ld=%b q=%h r=%h done=%b", ld, q, r, done);
|
|
end
|
|
|
|
|
always @(posedge clk4x)
|
|
if (ld)
|
|
qi <= {3'b0,a,{WID1{1'b0}}};
|
|
else if (!cnt81)
|
|
qi[WID1*2-1:0] <= {qi[WID1*2-1-1:0],b0};
|
|
|
fpdivr2 #(24) divu0(.clk(clk), .ld(ld), .a(a), .b(b), .q(q), .r(r), .done(done) );
|
always @(posedge clk4x)
|
|
if (ld)
|
|
ri <= 0;
|
|
else if (!cnt81)
|
|
ri <= {r1[DMSB:0],qi[WID1*2-1]};
|
|
|
|
always @(posedge clk4x)
|
|
if (done1)
|
|
q <= qi;
|
|
always @(posedge clk4x)
|
|
if (done1)
|
|
r <= ri;
|
|
|
endmodule
|
endmodule
|
*/
|
|
|
|
|
|
|
|
No newline at end of file
|
No newline at end of file
|