using memread for quotent select

This commit is contained in:
Katherine Parry 2022-06-21 15:49:52 -07:00
parent c41391e228
commit e9f5778e2a
3 changed files with 86 additions and 106 deletions

View File

@ -17,7 +17,7 @@ if [file exists work] {
} }
vlib work vlib work
vlog +incdir+../config/rv64gc +incdir+../config/shared srt-radix4.sv testbench-radix4.sv qsel4.sv ../src/generic/flop/flop*.sv ../src/generic/mux.sv ../src/generic/lzc.sv vlog +incdir+../config/rv64gc +incdir+../config/shared srt-radix4.sv testbench-radix4.sv ../src/generic/flop/flop*.sv ../src/generic/mux.sv ../src/generic/lzc.sv
vopt +acc work.testbenchradix4 -o workopt vopt +acc work.testbenchradix4 -o workopt
vsim workopt vsim workopt

View File

@ -34,29 +34,24 @@
module srtradix4 ( module srtradix4 (
input logic clk, input logic clk,
input logic Start, input logic DivStart,
input logic Stall, // *** multiple pipe stages input logic XSgnE, YSgnE,
input logic Flush, // *** multiple pipe stages input logic [`NE-1:0] XExpE, YExpE,
// Floating Point Inputs
// later add exponents, signs, special cases
input logic XSign, YSign,
input logic [`NE-1:0] XExp, YExp,
input logic [`NF-1:0] XFrac, YFrac, input logic [`NF-1:0] XFrac, YFrac,
input logic [`XLEN-1:0] SrcA, SrcB, input logic [`XLEN-1:0] SrcA, SrcB,
input logic [1:0] Fmt, // Floats: 00 = 16 bit, 01 = 32 bit, 10 = 64 bit, 11 = 128 bit
input logic W64, // 32-bit ints on XLEN=64 input logic W64, // 32-bit ints on XLEN=64
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 DivDone,
output logic DivSgn,
output logic [`DIVLEN-1:0] Quot, Rem, // *** later handle integers output logic [`DIVLEN-1:0] Quot, Rem, // *** later handle integers
output logic [`NE-1:0] rExp, output logic [`NE-1:0] DivExp
output logic [3:0] Flags
); );
// logic qp, qz, qm; // quotient is +1, 0, or -1 // logic qp, qz, qm; // quotient is +1, 0, or -1
logic [3:0] q; logic [3:0] q;
logic [`NE-1:0] calcExp; logic [`NE-1:0] DivCalcExp;
logic calcSign; logic calcSign;
logic [`DIVLEN-1:0] X, Dpreproc; logic [`DIVLEN-1:0] X, Dpreproc;
logic [`DIVLEN+3:0] WS, WSA, WSN; logic [`DIVLEN+3:0] WS, WSA, WSN;
@ -65,7 +60,7 @@ module srtradix4 (
logic [$clog2(`XLEN+1)-1:0] intExp; logic [$clog2(`XLEN+1)-1:0] intExp;
logic intSign; logic intSign;
srtpreproc preproc(SrcA, SrcB, XFrac, YFrac, Fmt, W64, Signed, Int, Sqrt, X, Dpreproc, intExp, intSign); srtpreproc preproc(SrcA, SrcB, XFrac, YFrac, W64, Signed, Int, Sqrt, X, Dpreproc, intExp, 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.
@ -77,11 +72,11 @@ module srtradix4 (
// - otherwise load WSA into the flipflop // - otherwise load WSA into the flipflop
// *** what does N and A stand for? // *** what does N and A stand for?
// *** change shift amount for radix4 // *** change shift amount for radix4
mux2 #(`DIVLEN+4) wsmux({WSA[`DIVLEN+1:0], 2'b0}, {4'b0001, X}, Start, WSN); mux2 #(`DIVLEN+4) wsmux({WSA[`DIVLEN+1:0], 2'b0}, {4'b0001, X}, DivStart, WSN);
flop #(`DIVLEN+4) wsflop(clk, WSN, WS); flop #(`DIVLEN+4) wsflop(clk, WSN, WS);
mux2 #(`DIVLEN+4) wcmux({WCA[`DIVLEN+1:0], 2'b0}, {`DIVLEN+4{1'b0}}, Start, WCN); mux2 #(`DIVLEN+4) wcmux({WCA[`DIVLEN+1:0], 2'b0}, {`DIVLEN+4{1'b0}}, DivStart, WCN);
flop #(`DIVLEN+4) wcflop(clk, WCN, WC); flop #(`DIVLEN+4) wcflop(clk, WCN, WC);
flopen #(`DIVLEN+4) dflop(clk, Start, {4'b0001, Dpreproc}, D); flopen #(`DIVLEN+4) dflop(clk, DivStart, {4'b0001, Dpreproc}, D);
// 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)
@ -94,9 +89,9 @@ module srtradix4 (
// 0001 = -2 // 0001 = -2
qsel4 qsel4(.D, .WS, .WC, .q); qsel4 qsel4(.D, .WS, .WC, .q);
// Store the expoenent and sign until division is done // Store the expoenent and sign until division is DivDone
flopen #(`NE) expflop(clk, Start, calcExp, rExp); flopen #(`NE) expflop(clk, DivStart, DivCalcExp, DivExp);
flopen #(1) signflop(clk, Start, calcSign, rsign); flopen #(1) signflop(clk, DivStart, calcSign, DivSgn);
// Divisor Selection logic // Divisor Selection logic
// *** radix 4 change to choose -2 to 2 // *** radix 4 change to choose -2 to 2
@ -120,11 +115,13 @@ module srtradix4 (
csa #(`DIVLEN+4) csa(WS, WC, Dsel, |q[3:2], WSA, WCA); csa #(`DIVLEN+4) csa(WS, WC, Dsel, |q[3:2], WSA, WCA);
//*** change for radix 4 //*** change for radix 4
otfc4 #(`DIVLEN) otfc4(clk, Start, q, Quot); otfc4 #(`DIVLEN) otfc4(clk, DivStart, q, Quot);
expcalc expcalc(.XExp, .YExp, .calcExp); expcalc expcalc(.XExpE, .YExpE, .DivCalcExp);
signcalc signcalc(.XSign, .YSign, .calcSign); signcalc signcalc(.XSgnE, .YSgnE, .calcSign);
counter counter(clk, DivStart, DivDone);
endmodule endmodule
@ -132,13 +129,58 @@ endmodule
// Submodules // // Submodules //
//////////////// ////////////////
/////////////
// counter //
/////////////
module counter(input logic clk,
input logic DivStart,
output logic DivDone);
logic [5: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 == `DIVLEN/2+1) DivDone <= #1 1;
else if (DivDone | DivStart) DivDone <= #1 0;
if (DivStart) count <= #1 0;
else count <= #1 count+1;
end
endmodule
module qsel4 (
input logic [`DIVLEN+3:0] D,
input logic [`DIVLEN+3:0] WS, WC,
output logic [3:0] q
);
logic [6:0] Wmsbs;
logic [7:0] PreWmsbs;
logic [2:0] Dmsbs;
assign PreWmsbs = WC[`DIVLEN+3:`DIVLEN-4] + WS[`DIVLEN+3:`DIVLEN-4];
assign Wmsbs = PreWmsbs[7:1];
assign Dmsbs = D[`DIVLEN-1:`DIVLEN-3];
// D = 0001.xxx...
// Dmsbs = | |
// W = xxxx.xxx...
// Wmsbs = | |
logic [3:0] QSel4[1023:0];
initial $readmemh("qslc_r4a2b.tv", QSel4);
assign q = QSel4[{Dmsbs,Wmsbs}];
endmodule
/////////////////// ///////////////////
// Preprocessing // // Preprocessing //
/////////////////// ///////////////////
module srtpreproc ( module srtpreproc (
input logic [`XLEN-1:0] SrcA, SrcB, input logic [`XLEN-1:0] SrcA, SrcB,
input logic [`NF-1:0] XFrac, YFrac, input logic [`NF-1:0] XFrac, YFrac,
input logic [1:0] Fmt, // Floats: 00 = 16 bit, 01 = 32 bit, 10 = 64 bit, 11 = 128 bit
input logic W64, // 32-bit ints on XLEN=64 input logic W64, // 32-bit ints on XLEN=64
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
@ -173,48 +215,12 @@ module srtpreproc (
assign intSign = Signed & (SrcA[`XLEN - 1] ^ SrcB[`XLEN - 1]); assign intSign = Signed & (SrcA[`XLEN - 1] ^ SrcB[`XLEN - 1]);
endmodule endmodule
/////////////////////////////////
// Quotient Selection, Radix 2 //
/////////////////////////////////
module qsel2 ( // *** eventually just change to 4 bits
input logic [`DIVLEN+3:`DIVLEN] ps, pc,
output logic qp, qz, qm
);
logic [`DIVLEN+3:`DIVLEN] p, g;
logic magnitude, sign, cout;
// The quotient selection logic is presented for simplicity, not
// for efficiency. You can probably optimize your logic to
// select the proper divisor with less delay.
// Quotient equations from EE371 lecture notes 13-20
assign p = ps ^ pc;
assign g = ps & pc;
assign #1 magnitude = ~(&p[`DIVLEN+2:`DIVLEN]);
assign #1 cout = g[`DIVLEN+2] | (p[`DIVLEN+2] & (g[`DIVLEN+1] | p[`DIVLEN+1] & g[`DIVLEN]));
assign #1 sign = p[`DIVLEN+3] ^ cout;
/* assign #1 magnitude = ~((ps[54]^pc[54]) & (ps[53]^pc[53]) &
(ps[52]^pc[52]));
assign #1 sign = (ps[55]^pc[55])^
(ps[54] & pc[54] | ((ps[54]^pc[54]) &
(ps[53]&pc[53] | ((ps[53]^pc[53]) &
(ps[52]&pc[52]))))); */
// Produce quotient = +1, 0, or -1
assign #1 qp = magnitude & ~sign;
assign #1 qz = ~magnitude;
assign #1 qm = magnitude & sign;
endmodule
/////////////////////////////////// ///////////////////////////////////
// On-The-Fly Converter, Radix 2 // // On-The-Fly Converter, Radix 2 //
/////////////////////////////////// ///////////////////////////////////
module otfc4 #(parameter N=65) ( module otfc4 #(parameter N=65) (
input logic clk, input logic clk,
input logic Start, input logic DivStart,
input logic [3:0] q, input logic [3:0] q,
output logic [N-1:0] r output logic [N-1:0] r
); );
@ -234,8 +240,8 @@ module otfc4 #(parameter N=65) (
// discard the r most significant bits of Q and QM. // discard the r most significant bits of Q and QM.
logic [N:0] QR, QMR; logic [N:0] QR, QMR;
// if starting a new divison set Q to 0 and QM to -1 // if starting a new divison set Q to 0 and QM to -1
mux2 #(N+3) Qmux(QNext, {N+3{1'b0}}, Start, QMux); mux2 #(N+3) Qmux(QNext, {N+3{1'b0}}, DivStart, QMux);
mux2 #(N+3) QMmux(QMNext, {N+3{1'b1}}, Start, QMMux); mux2 #(N+3) QMmux(QMNext, {N+3{1'b1}}, DivStart, QMMux);
flop #(N+3) Qreg(clk, QMux, Q); flop #(N+3) Qreg(clk, QMux, Q);
flop #(N+3) QMreg(clk, QMMux, QM); flop #(N+3) QMreg(clk, QMMux, QM);
@ -287,7 +293,7 @@ module csa #(parameter N=69) (
// This block adds in1, in2, in3, and cin to produce // This block adds in1, in2, in3, and cin to produce
// a result out1 / out2 in carry-save redundant form. // a result out1 / out2 in carry-save redundant form.
// cin is just added to the least significant bit and // cin is just added to the least significant bit and
// is required to handle adding a negative divisor. // is Startuired to handle adding a negative divisor.
// Fortunately, the carry (out2) is shifted left by one // Fortunately, the carry (out2) is shifted left by one
// bit, leaving room in the least significant bit to // bit, leaving room in the least significant bit to
// insert cin. // insert cin.
@ -302,11 +308,11 @@ endmodule
// expcalc // // expcalc //
////////////// //////////////
module expcalc( module expcalc(
input logic [`NE-1:0] XExp, YExp, input logic [`NE-1:0] XExpE, YExpE,
output logic [`NE-1:0] calcExp output logic [`NE-1:0] DivCalcExp
); );
assign calcExp = XExp - YExp + (`NE)'(`BIAS); assign DivCalcExp = XExpE - YExpE + (`NE)'(`BIAS);
endmodule endmodule
@ -314,10 +320,10 @@ endmodule
// signcalc // // signcalc //
////////////// //////////////
module signcalc( module signcalc(
input logic XSign, YSign, input logic XSgnE, YSgnE,
output logic calcSign output logic calcSign
); );
assign calcSign = XSign ^ YSign; assign calcSign = XSgnE ^ YSgnE;
endmodule endmodule

View File

@ -2,30 +2,6 @@
`include "wally-config.vh" `include "wally-config.vh"
`define DIVLEN ((`NF<`XLEN) ? `XLEN : `NF) `define DIVLEN ((`NF<`XLEN) ? `XLEN : `NF)
/////////////
// counter //
/////////////
module counter(input logic clk,
input logic req,
output logic done);
logic [5: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 == `DIVLEN/2+1) done <= #1 1;
else if (done | req) done <= #1 0;
if (req) count <= #1 0;
else count <= #1 count+1;
end
endmodule
/////////// ///////////
// clock // // clock //
/////////// ///////////
@ -43,7 +19,7 @@ endmodule
module testbenchradix4; module testbenchradix4;
logic clk; logic clk;
logic req; logic req;
logic done; logic DivDone;
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;
@ -65,22 +41,20 @@ module testbenchradix4;
logic [MEM_WIDTH-1:0] Vec; // Verilog doesn't allow direct access to a logic [MEM_WIDTH-1:0] Vec; // Verilog doesn't allow direct access to a
// bit field of an array // bit field of an array
logic [63:0] correctr, nextr, diffn, diffp; logic [63:0] correctr, nextr, diffn, diffp;
logic [10:0] rExp; logic [10:0] DivExp;
logic rsign; logic DivSgn;
integer testnum, errors; integer testnum, errors;
// Divider // Divider
srtradix4 srtradix4(.clk, .Start(req), srtradix4 srtradix4(.clk, .DivStart(req),
.Stall(1'b0), .Flush(1'b0), .XExpE(aExp), .YExpE(bExp), .DivExp,
.XExp(aExp), .YExp(bExp), .rExp, .XSgnE(asign), .YSgnE(bsign), .DivSgn,
.XSign(asign), .YSign(bsign), .rsign,
.XFrac(afrac), .YFrac(bfrac), .XFrac(afrac), .YFrac(bfrac),
.SrcA('0), .SrcB('0), .Fmt(2'b00), .SrcA('0), .SrcB('0), .Fmt(2'b00),
.W64(1'b0), .Signed(1'b0), .Int(1'b0), .Sqrt(1'b0), .W64(1'b0), .Signed(1'b0), .Int(1'b0), .Sqrt(1'b0), .DivDone,
.Quot, .Rem(), .Flags()); .Quot, .Rem());
// Counter // Counter
counter counter(clk, req, done);
initial initial
@ -112,14 +86,14 @@ module testbenchradix4;
always @(posedge clk) always @(posedge clk)
begin begin
r = Quot[`DIVLEN-1:`DIVLEN - 52]; r = Quot[`DIVLEN-1:`DIVLEN - 52];
if (done) begin if (DivDone) begin
req <= 1; req <= 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 ((DivSgn !== correctr[63]) | (DivExp !== 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", DivExp, r, correctr, diffn, diffp);
$display("failed\n"); $display("failed\n");
$stop; $stop;
end end