mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
using memread for quotent select
This commit is contained in:
parent
c41391e228
commit
e9f5778e2a
@ -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
|
||||
|
||||
|
@ -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
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user