Radix 2 Integer division working (without signs or remainder)

This commit is contained in:
cturek 2022-07-05 21:34:49 +00:00
parent d73645944f
commit e7ac99a683
5 changed files with 205 additions and 157 deletions

BIN
pipelined/srt/inttestgen Executable file

Binary file not shown.

View File

@ -0,0 +1,83 @@
/* testgen.c */
/* Written 10/31/96 by David Harris
This program creates test vectors for mantissa component
of an IEEE floating point divider.
*/
/* #includes */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* Constants */
#define ENTRIES 10
#define RANDOM_VECS 500
/* Prototypes */
void output(FILE *fptr, long a, long b, long r, long rem);
void printhex(FILE *fptr, long x);
double random_input(void);
/* Main */
void main(void)
{
FILE *fptr;
long a, b, r, rem;
long list[ENTRIES] = {1, 3, 5, 18, 25, 33, 42, 65, 103, 255};
int i, j;
if ((fptr = fopen("inttestvectors","w")) == NULL) {
fprintf(stderr, "Couldn't write testvectors file\n");
exit(1);
}
for (i=0; i<ENTRIES; i++) {
b = list[i];
for (j=0; j<ENTRIES; j++) {
a = list[j];
r = a/b;
rem = a%b;
output(fptr, a, b, r, rem);
}
}
// for (i = 0; i< RANDOM_VECS; i++) {
// a = random_input();
// b = random_input();
// r = a/b;
// output(fptr, a, b, r);
// }
fclose(fptr);
}
/* Functions */
void output(FILE *fptr, long a, long b, long r, long rem)
{
printhex(fptr, a);
fprintf(fptr, "_");
printhex(fptr, b);
fprintf(fptr, "_");
printhex(fptr, r);
fprintf(fptr, "_");
printhex(fptr, rem);
fprintf(fptr, "\n");
}
void printhex(FILE *fptr, long m)
{
fprintf(fptr, "%016llx", m);
}
double random_input(void)
{
return 1.0 + rand()/32767.0;
}

View File

@ -1,3 +1,5 @@
add wave -noupdate /testbench/* add wave -noupdate /testbench/*
add wave -noupdate /testbench/srt/* add wave -noupdate /testbench/srt/*
add wave -noupdate /testbench/srt/otfc2/* add wave -noupdate /testbench/srt/otfc2/*
add wave -noupdate /testbench/srt/preproc/*
add wave -noupdate /testbench/srt/divcounter/*

View File

@ -48,8 +48,8 @@ module srt (
input logic Signed, // Interpret integers as signed 2's complement input logic Signed, // Interpret integers as signed 2's complement
input logic Int, // Choose integer inputs input logic Int, // Choose integer inputs
input logic Sqrt, // perform square root, not divide input logic Sqrt, // perform square root, not divide
output logic rsign, output logic rsign, done,
output logic [`DIVLEN-1:0] Quot, Rem, QuotOTFC, // *** later handle integers output logic [`DIVLEN-1:0] Rem, Quot, // *** later handle integers
output logic [`NE-1:0] rExp, output logic [`NE-1:0] rExp,
output logic [3:0] Flags output logic [3:0] Flags
); );
@ -59,11 +59,10 @@ module srt (
logic calcSign; logic calcSign;
logic [`DIVLEN-1:0] X, Dpreproc; logic [`DIVLEN-1:0] X, Dpreproc;
logic [`DIVLEN+3:0] WS, WSA, WSN, WC, WCA, WCN, D, Db, Dsel; logic [`DIVLEN+3:0] WS, WSA, WSN, WC, WCA, WCN, D, Db, Dsel;
logic [`DIVLEN+2:0] rp, rm; logic [$clog2(`XLEN+1)-1:0] intExp, dur, calcDur;
logic [$clog2(`XLEN+1)-1:0] intExp;
logic intSign; logic intSign;
srtpreproc preproc(SrcA, SrcB, SrcXFrac, SrcYFrac, Fmt, W64, Signed, Int, Sqrt, X, Dpreproc, intExp, intSign); srtpreproc preproc(SrcA, SrcB, SrcXFrac, SrcYFrac, Fmt, W64, Signed, Int, Sqrt, X, Dpreproc, intExp, calcDur, intSign);
// Top Muxes and Registers // Top Muxes and Registers
// When start is asserted, the inputs are loaded into the divider. // When start is asserted, the inputs are loaded into the divider.
@ -78,25 +77,25 @@ module srt (
// Quotient Selection logic // Quotient Selection logic
// Given partial remainder, select quotient of +1, 0, or -1 (qp, qz, pm) // Given partial remainder, select quotient of +1, 0, or -1 (qp, qz, pm)
qsel2 qsel2(WS[`DIVLEN+3:`DIVLEN], WC[`DIVLEN+3:`DIVLEN], qp, qz, qm); qsel2 qsel2(WS[`DIVLEN+3:`DIVLEN], WC[`DIVLEN+3:`DIVLEN], qp, qz, qm);
// Accumulate quotient digits in a shift register (now done in OTFC)
qacc #(`DIVLEN+3) qacc(clk, Start, qp, qz, qm, rp, rm);
flopen #(`NE) expflop(clk, Start, calcExp, rExp); flopen #(`NE) expflop(clk, Start, calcExp, rExp);
flopen #(1) signflop(clk, Start, calcSign, rsign); flopen #(1) signflop(clk, Start, calcSign, rsign);
flopen #(7) durflop(clk, Start, calcDur, dur);
counter divcounter(clk, Start, dur, done);
// Divisor Selection logic // Divisor Selection logic
inv dinv(D, Db); assign Db = ~D;
mux3onehot #(`DIVLEN) divisorsel(Db, {(`DIVLEN+4){1'b0}}, D, qp, qz, qm, Dsel); mux3onehot #(`DIVLEN) divisorsel(Db, {(`DIVLEN+4){1'b0}}, D, qp, qz, qm, Dsel);
// Partial Product Generation // Partial Product Generation
csa #(`DIVLEN+4) csa(WS, WC, Dsel, qp, WSA, WCA); csa #(`DIVLEN+4) csa(WS, WC, Dsel, qp, WSA, WCA);
otfc2 #(`DIVLEN) otfc2(clk, Start, qp, qz, qm, QuotOTFC); otfc2 #(`DIVLEN) otfc2(clk, Start, qp, qz, qm, Quot);
expcalc expcalc(.XExp, .YExp, .calcExp); expcalc expcalc(.XExp, .YExp, .calcExp);
signcalc signcalc(.XSign, .YSign, .calcSign); signcalc signcalc(.XSign, .YSign, .calcSign);
srtpostproc postproc(rp, rm, Quot);
endmodule endmodule
//////////////// ////////////////
@ -115,7 +114,7 @@ module srtpreproc (
input logic Int, // Choose integer inputs input logic Int, // Choose integer inputs
input logic Sqrt, // perform square root, not divide input logic Sqrt, // perform square root, not divide
output logic [`DIVLEN-1:0] X, D, output logic [`DIVLEN-1:0] X, D,
output logic [$clog2(`XLEN+1)-1:0] intExp, // Quotient integer exponent output logic [$clog2(`XLEN+1)-1:0] intExp, dur, // Quotient integer exponent
output logic intSign // Quotient integer sign output logic intSign // Quotient integer sign
); );
@ -132,8 +131,8 @@ module srtpreproc (
assign ExtraA = {PosA, {`EXTRAINTBITS{1'b0}}}; assign ExtraA = {PosA, {`EXTRAINTBITS{1'b0}}};
assign ExtraB = {PosB, {`EXTRAINTBITS{1'b0}}}; assign ExtraB = {PosB, {`EXTRAINTBITS{1'b0}}};
assign PreprocA = ExtraA << zeroCntA; assign PreprocA = ExtraA << (zeroCntA + 1);
assign PreprocB = ExtraB << zeroCntB; assign PreprocB = ExtraB << (zeroCntB + 1);
assign PreprocX = {SrcXFrac, {`EXTRAFRACBITS{1'b0}}}; assign PreprocX = {SrcXFrac, {`EXTRAFRACBITS{1'b0}}};
assign PreprocY = {SrcYFrac, {`EXTRAFRACBITS{1'b0}}}; assign PreprocY = {SrcYFrac, {`EXTRAFRACBITS{1'b0}}};
@ -142,6 +141,8 @@ module srtpreproc (
assign D = Int ? PreprocB : PreprocY; assign D = Int ? PreprocB : PreprocY;
assign intExp = zeroCntB - zeroCntA + 1; assign intExp = zeroCntB - zeroCntA + 1;
assign intSign = Signed & (SrcA[`XLEN - 1] ^ SrcB[`XLEN - 1]); assign intSign = Signed & (SrcA[`XLEN - 1] ^ SrcB[`XLEN - 1]);
assign dur = Int ? (intExp & {7{~intExp[6]}}) : (`DIVLEN + 2);
endmodule endmodule
///////////////////////////////// /////////////////////////////////
@ -179,38 +180,10 @@ module qsel2 ( // *** eventually just change to 4 bits
assign #1 qm = magnitude & sign; assign #1 qm = magnitude & sign;
endmodule endmodule
//////////
// qacc //
//////////
// To be replaced by OTFC
module qacc #(parameter N=68) (
input logic clk,
input logic req,
input logic qp, qz, qm,
output logic [N-1:0] rp, rm
);
flopr #(N) rmreg(clk, req, {rm[N-2:0], qm}, rm);
flopr #(N) rpreg(clk, req, {rp[N-2:0], qp}, rp);
/* always @(posedge clk)
begin
if (req)
begin
rp <= #1 0;
rm <= #1 0;
end
else
begin
rm <= #1 {rm[54:0], qm};
rp <= #1 {rp[54:0], qp};
end
end */
endmodule
/////////////////////////////////// ///////////////////////////////////
// On-The-Fly Converter, Radix 2 // // On-The-Fly Converter, Radix 2 //
/////////////////////////////////// ///////////////////////////////////
module otfc2 #(parameter N=65) ( module otfc2 #(parameter N=64) (
input logic clk, input logic clk,
input logic Start, input logic Start,
input logic qp, qz, qm, input logic qp, qz, qm,
@ -254,13 +227,29 @@ module otfc2 #(parameter N=65) (
endmodule endmodule
///////// /////////////
// inv // // counter //
///////// /////////////
module inv(input logic [`DIVLEN+3:0] in, module counter(input logic clk,
output logic [`DIVLEN+3:0] out); input logic req,
input logic [$clog2(`XLEN+1)-1:0] dur,
output logic done);
assign #1 out = ~in; logic [$clog2(`XLEN+1)-1:0] count;
// This block of control logic sequences the divider
// through its iterations. You may modify it if you
// build a divider which completes in fewer iterations.
// You are not responsible for the (trivial) circuit
// design of the block.
always @(posedge clk)
begin
if (count == dur) done <= #1 1;
else if (done | req) done <= #1 0;
if (req) count <= #1 0;
else count <= #1 count+1;
end
endmodule endmodule
////////// //////////
@ -324,42 +313,3 @@ module signcalc(
assign calcSign = XSign ^ YSign; assign calcSign = XSign ^ YSign;
endmodule endmodule
////////////////////
// Postprocessing //
////////////////////
module srtpostproc (
input [`DIVLEN+2:0] rp, rm,
output [`DIVLEN-1:0] Quot
);
//assign Quot = rp - rm;
finaladd #(`DIVLEN+3) finaladd(rp, rm, Quot);
endmodule
//////////////
// finaladd //
//////////////
module finaladd #(parameter N=68) (
input logic [N-1:0] rp, rm,
output logic [N-4:0] r
);
logic [N-1:0] diff;
// this magic block performs the final addition for you
// to convert the positive and negative quotient digits
// into a normalized mantissa. It returns the 52 bit
// mantissa after shifting to guarantee a leading 1.
// You can assume this block operates in one cycle
// and do not need to budget it in your area and power
// calculations.
// Since no rounding is performed, the result may be too
// small by one unit in the least significant place (ulp).
// The checker ignores such an error.
assign #1 diff = rp - rm;
assign #1 r = diff[N-1] ? diff[N-2:2] : diff[N-3:1];
endmodule

View File

@ -3,26 +3,26 @@
///////////// /////////////
// counter // // counter //
///////////// /////////////
module counter(input logic clk, // module counter(input logic clk,
input logic req, // input logic req,
output logic done); // output logic done);
logic [7:0] count; // logic [7:0] count;
// This block of control logic sequences the divider // // This block of control logic sequences the divider
// through its iterations. You may modify it if you // // through its iterations. You may modify it if you
// build a divider which completes in fewer iterations. // // build a divider which completes in fewer iterations.
// You are not responsible for the (trivial) circuit // // You are not responsible for the (trivial) circuit
// design of the block. // // design of the block.
always @(posedge clk) // always @(posedge clk)
begin // begin
if (count == `DIVLEN + 2) done <= #1 1; // if (count == `DIVLEN + 2) done <= #1 1;
else if (done | req) done <= #1 0; // else if (done | req) done <= #1 0;
if (req) count <= #1 0; // if (req) count <= #1 0;
else count <= #1 count+1; // else count <= #1 count+1;
end // end
endmodule // endmodule
/////////// ///////////
// clock // // clock //
@ -42,21 +42,23 @@ module testbench;
logic clk; logic clk;
logic req; logic req;
logic done; logic done;
logic Int;
logic [63:0] a, b; logic [63:0] a, b;
logic [51:0] afrac, bfrac; logic [51:0] afrac, bfrac;
logic [10:0] aExp, bExp; logic [10:0] aExp, bExp;
logic asign, bsign; logic asign, bsign;
logic [51:0] r, rOTFC; logic [51:0] r;
logic [`DIVLEN-1:0] Quot, QuotOTFC; logic [63:0] rInt;
logic [54:0] rp, rm; // positive quotient digits logic [`DIVLEN-1:0] Quot;
// Test parameters // Test parameters
parameter MEM_SIZE = 40000; parameter MEM_SIZE = 40000;
parameter MEM_WIDTH = 64+64+64; parameter MEM_WIDTH = 64+64+64+64;
`define memr 63:0 `define memrem 63:0
`define memb 127:64 `define memr 127:64
`define mema 191:128 `define memb 191:128
`define mema 255:192
// Test logicisters // Test logicisters
logic [MEM_WIDTH-1:0] Tests [0:MEM_SIZE]; // Space for input file logic [MEM_WIDTH-1:0] Tests [0:MEM_SIZE]; // Space for input file
@ -67,18 +69,20 @@ module testbench;
logic rsign; logic rsign;
integer testnum, errors; integer testnum, errors;
assign Int = 1'b1;
// Divider // Divider
srt srt(.clk, .Start(req), srt srt(.clk, .Start(req),
.Stall(1'b0), .Flush(1'b0), .Stall(1'b0), .Flush(1'b0),
.XExp(aExp), .YExp(bExp), .rExp, .XExp(aExp), .YExp(bExp), .rExp,
.XSign(asign), .YSign(bsign), .rsign, .XSign(asign), .YSign(bsign), .rsign,
.SrcXFrac(afrac), .SrcYFrac(bfrac), .SrcXFrac(afrac), .SrcYFrac(bfrac),
.SrcA('0), .SrcB('0), .Fmt(2'b00), .SrcA(a), .SrcB(b), .Fmt(2'b00),
.W64(1'b0), .Signed(1'b0), .Int(1'b0), .Sqrt(1'b0), .W64(1'b1), .Signed(1'b0), .Int, .Sqrt(1'b0),
.Quot, .QuotOTFC, .Rem(), .Flags()); .Quot, .Rem(), .Flags(), .done);
// Counter // Counter
counter counter(clk, req, done); // counter counter(clk, req, done);
initial initial
@ -94,7 +98,7 @@ module testbench;
begin begin
testnum = 0; testnum = 0;
errors = 0; errors = 0;
$readmemh ("testvectors", Tests); $readmemh ("inttestvectors", Tests);
Vec = Tests[testnum]; Vec = Tests[testnum];
a = Vec[`mema]; a = Vec[`mema];
{asign, aExp, afrac} = a; {asign, aExp, afrac} = a;
@ -102,7 +106,7 @@ module testbench;
{bsign, bExp, bfrac} = b; {bsign, bExp, bfrac} = b;
nextr = Vec[`memr]; nextr = Vec[`memr];
r = Quot[(`DIVLEN - 1):(`DIVLEN - 52)]; r = Quot[(`DIVLEN - 1):(`DIVLEN - 52)];
rOTFC = QuotOTFC[(`DIVLEN - 1):(`DIVLEN - 52)]; rInt = Quot;
req <= #5 1; req <= #5 1;
end end
@ -111,45 +115,54 @@ module testbench;
always @(posedge clk) always @(posedge clk)
begin begin
r = Quot[(`DIVLEN - 1):(`DIVLEN - 52)]; r = Quot[(`DIVLEN - 1):(`DIVLEN - 52)];
rOTFC = QuotOTFC[(`DIVLEN - 1):(`DIVLEN - 52)]; rInt = Quot;
if (done) if (done) begin
begin if (~Int) begin
req <= #5 1; req <= #5 1;
diffp = correctr[51:0] - r; diffp = correctr[51:0] - r;
diffn = r - correctr[51:0]; diffn = r - correctr[51:0];
if ((rsign !== correctr[63]) | (rExp !== correctr[62:52]) | ($signed(diffn) > 1) | ($signed(diffp) > 1) | (diffn === 64'bx) | (diffp === 64'bx)) // check if accurate to 1 ulp if ((rsign !== correctr[63]) | (rExp !== correctr[62:52]) | ($signed(diffn) > 1) | ($signed(diffp) > 1) | (diffn === 64'bx) | (diffp === 64'bx)) // check if accurate to 1 ulp
begin begin
errors = errors+1; errors = errors+1;
$display("result was %h_%h, should be %h %h %h\n", rExp, r, correctr, diffn, diffp); $display("result was %h_%h, should be %h %h %h\n", rExp, r, correctr, diffn, diffp);
$display("failed\n"); $display("failed\n");
$stop; $stop;
end end
if (r !== rOTFC) // Check if OTFC works if (afrac === 52'hxxxxxxxxxxxxx)
begin begin
errors = errors+1; $display("%d Tests completed successfully", testnum);
$display("OTFC is %h, should be %h\n", rOTFC, r); $stop;
$display("failed\n"); end
// $stop; end else begin
req <= #5 1;
diffp = correctr[63:0] - rInt;
diffn = rInt - correctr[63:0];
if (($signed(diffn) > 1) | ($signed(diffp) > 1) | (diffn === 64'bx) | (diffp === 64'bx)) // check if accurate to 1 ulp
begin
errors = errors+1;
$display("result was %h, should be %h %h %h\n", rInt, correctr, diffn, diffp);
$display("failed\n");
$stop;
end
if (afrac === 52'hxxxxxxxxxxxxx)
begin
$display("%d Tests completed successfully", testnum);
$stop;
end
end
end end
if (afrac === 52'hxxxxxxxxxxxxx) if (req) begin
begin req <= #5 0;
$display("%d Tests completed successfully", testnum); correctr = nextr;
$stop; testnum = testnum+1;
end Vec = Tests[testnum];
end $display("a = %h b = %h",a,b);
if (req) a = Vec[`mema];
begin {asign, aExp, afrac} = a;
req <= #5 0; b = Vec[`memb];
correctr = nextr; {bsign, bExp, bfrac} = b;
testnum = testnum+1; nextr = Vec[`memr];
Vec = Tests[testnum]; end
$display("a = %h b = %h",a,b);
a = Vec[`mema];
{asign, aExp, afrac} = a;
b = Vec[`memb];
{bsign, bExp, bfrac} = b;
nextr = Vec[`memr];
end
end end
endmodule endmodule