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
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
vsim workopt

View File

@ -34,29 +34,24 @@
module srtradix4 (
input logic clk,
input logic Start,
input logic Stall, // *** multiple pipe stages
input logic Flush, // *** multiple pipe stages
// Floating Point Inputs
// later add exponents, signs, special cases
input logic XSign, YSign,
input logic [`NE-1:0] XExp, YExp,
input logic DivStart,
input logic XSgnE, YSgnE,
input logic [`NE-1:0] XExpE, YExpE,
input logic [`NF-1:0] XFrac, YFrac,
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 Signed, // Interpret integers as signed 2's complement
input logic Int, // Choose integer inputs
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 [`NE-1:0] rExp,
output logic [3:0] Flags
output logic [`NE-1:0] DivExp
);
// logic qp, qz, qm; // quotient is +1, 0, or -1
logic [3:0] q;
logic [`NE-1:0] calcExp;
logic [`NE-1:0] DivCalcExp;
logic calcSign;
logic [`DIVLEN-1:0] X, Dpreproc;
logic [`DIVLEN+3:0] WS, WSA, WSN;
@ -65,7 +60,7 @@ module srtradix4 (
logic [$clog2(`XLEN+1)-1:0] intExp;
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
// When start is asserted, the inputs are loaded into the divider.
@ -77,11 +72,11 @@ module srtradix4 (
// - otherwise load WSA into the flipflop
// *** what does N and A stand for?
// *** 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);
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);
flopen #(`DIVLEN+4) dflop(clk, Start, {4'b0001, Dpreproc}, D);
flopen #(`DIVLEN+4) dflop(clk, DivStart, {4'b0001, Dpreproc}, D);
// Quotient Selection logic
// Given partial remainder, select quotient of +1, 0, or -1 (qp, qz, pm)
@ -94,9 +89,9 @@ module srtradix4 (
// 0001 = -2
qsel4 qsel4(.D, .WS, .WC, .q);
// Store the expoenent and sign until division is done
flopen #(`NE) expflop(clk, Start, calcExp, rExp);
flopen #(1) signflop(clk, Start, calcSign, rsign);
// Store the expoenent and sign until division is DivDone
flopen #(`NE) expflop(clk, DivStart, DivCalcExp, DivExp);
flopen #(1) signflop(clk, DivStart, calcSign, DivSgn);
// Divisor Selection logic
// *** 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);
//*** 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
@ -132,13 +129,58 @@ endmodule
// 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 //
///////////////////
module srtpreproc (
input logic [`XLEN-1:0] SrcA, SrcB,
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 Signed, // Interpret integers as signed 2's complement
input logic Int, // Choose integer inputs
@ -173,48 +215,12 @@ module srtpreproc (
assign intSign = Signed & (SrcA[`XLEN - 1] ^ SrcB[`XLEN - 1]);
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 //
///////////////////////////////////
module otfc4 #(parameter N=65) (
input logic clk,
input logic Start,
input logic DivStart,
input logic [3:0] q,
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.
logic [N:0] QR, QMR;
// 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) QMmux(QMNext, {N+3{1'b1}}, Start, QMMux);
mux2 #(N+3) Qmux(QNext, {N+3{1'b0}}, DivStart, QMux);
mux2 #(N+3) QMmux(QMNext, {N+3{1'b1}}, DivStart, QMMux);
flop #(N+3) Qreg(clk, QMux, Q);
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
// a result out1 / out2 in carry-save redundant form.
// 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
// bit, leaving room in the least significant bit to
// insert cin.
@ -302,11 +308,11 @@ endmodule
// expcalc //
//////////////
module expcalc(
input logic [`NE-1:0] XExp, YExp,
output logic [`NE-1:0] calcExp
input logic [`NE-1:0] XExpE, YExpE,
output logic [`NE-1:0] DivCalcExp
);
assign calcExp = XExp - YExp + (`NE)'(`BIAS);
assign DivCalcExp = XExpE - YExpE + (`NE)'(`BIAS);
endmodule
@ -314,10 +320,10 @@ endmodule
// signcalc //
//////////////
module signcalc(
input logic XSign, YSign,
input logic XSgnE, YSgnE,
output logic calcSign
);
assign calcSign = XSign ^ YSign;
assign calcSign = XSgnE ^ YSgnE;
endmodule

View File

@ -2,30 +2,6 @@
`include "wally-config.vh"
`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 //
///////////
@ -43,7 +19,7 @@ endmodule
module testbenchradix4;
logic clk;
logic req;
logic done;
logic DivDone;
logic [63:0] a, b;
logic [51:0] afrac, bfrac;
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
// bit field of an array
logic [63:0] correctr, nextr, diffn, diffp;
logic [10:0] rExp;
logic rsign;
logic [10:0] DivExp;
logic DivSgn;
integer testnum, errors;
// Divider
srtradix4 srtradix4(.clk, .Start(req),
.Stall(1'b0), .Flush(1'b0),
.XExp(aExp), .YExp(bExp), .rExp,
.XSign(asign), .YSign(bsign), .rsign,
srtradix4 srtradix4(.clk, .DivStart(req),
.XExpE(aExp), .YExpE(bExp), .DivExp,
.XSgnE(asign), .YSgnE(bsign), .DivSgn,
.XFrac(afrac), .YFrac(bfrac),
.SrcA('0), .SrcB('0), .Fmt(2'b00),
.W64(1'b0), .Signed(1'b0), .Int(1'b0), .Sqrt(1'b0),
.Quot, .Rem(), .Flags());
.W64(1'b0), .Signed(1'b0), .Int(1'b0), .Sqrt(1'b0), .DivDone,
.Quot, .Rem());
// Counter
counter counter(clk, req, done);
initial
@ -112,14 +86,14 @@ module testbenchradix4;
always @(posedge clk)
begin
r = Quot[`DIVLEN-1:`DIVLEN - 52];
if (done) begin
if (DivDone) begin
req <= 1;
diffp = correctr[51:0] - r;
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
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");
$stop;
end