Mod for DIV/REM instruction and update to div.sv unit

This commit is contained in:
James E. Stine 2021-05-24 19:29:13 -05:00
parent 82a6ee4c0e
commit 1704fdc877
3 changed files with 104 additions and 15 deletions

View File

@ -31,12 +31,13 @@
`include "wally-config.vh"
module div (Qf, remf, done, divBusy, div0, N, D, clk, reset, start);
module div (Qf, remf, done, divBusy, div0, N, D, clk, reset, start, S);
input logic [63:0] N, D;
input logic clk;
input logic reset;
input logic start;
input logic S;
output logic [63:0] Qf;
output logic [63:0] remf;
@ -58,6 +59,24 @@ module div (Qf, remf, done, divBusy, div0, N, D, clk, reset, start);
logic shiftResult;
logic enablev, state0v, donev, divdonev, oftzerov, divBusyv, ulp;
logic [63:0] twoD;
logic [63:0] twoN;
logic SignD;
logic SignN;
logic [63:0] QT, remT;
logic D_NegOne;
logic Max_N;
// Check if negative (two's complement)
// If so, convert to positive
adder #(64) cpa1 ((D ^ {64{D[63]&S}}), {63'h0, D[63]&S}, twoD);
adder #(64) cpa2 ((N ^ {64{N[63]&S}}), {63'h0, N[63]&S}, twoN);
assign SignD = D[63];
assign SignN = N[63];
// Max N and D = -1 (Overflow)
assign Max_N = (~|N[62:0]) & N[63];
assign D_NegOne = &D;
// Divider goes the distance to 37 cycles
// (thanks the evil divisor for D = 0x1)
// but could theoretically be stopped when
@ -74,17 +93,14 @@ module div (Qf, remf, done, divBusy, div0, N, D, clk, reset, start);
// exception is given to FSM to tell the operation to
// quit gracefully.
// div0 produced output errors have untested results
// (it is assumed the OS would handle some output)
lz64 p1 (P, V, D);
shifter_l64 p2 (op2, D, P);
assign op1 = N;
lz64 p1 (P, V, twoD);
shifter_l64 p2 (op2, twoD, P);
assign op1 = twoN;
assign div0 = ~V;
// #iter: N = m+v+s = m+(s+2) = m+2+s (mod k = 0)
// v = 2 since \rho < 1 (add 4 to make sure its a ceil)
adder #(8) cpa1 ({2'b0, P},
adder #(8) cpa3 ({2'b0, P},
{5'h0, shiftResult, ~shiftResult, 1'b0},
Num);
@ -130,9 +146,23 @@ module div (Qf, remf, done, divBusy, div0, N, D, clk, reset, start);
// n ln(r)
shifter_r64 p4 (rem0, Rem5, RemShift);
// Adjust Q/Rem for Signed
assign tcQ = (SignN ^ SignD) & S;
assign tcR = SignN & S;
// Signed Divide
// - When N and D are negative: Remainder is negative (undergoes a two's complement).
// - When N is negative: Quotient and Remainder are both negative (undergo a two's complement).
// - When D is negative: Quotient is negative (undergoes a two's complement).
adder #(64) cpa4 ((rem0 ^ {64{tcR}}), {63'h0, tcR}, remT);
adder #(64) cpa5 ((Q ^ {64{tcQ}}), {63'h0, tcQ}, QT);
// RISC-V has exceptions for divide by 0 and overflow (see Table 6.1 of spec)
exception_int exc (QT, remT, N, S, div0, Max_N, D_NegOne, Qf, remf);
// Delete me if works
// RISC-V has exceptions for divide by 0 (Table 6.1 of SPEC)
mux2 #(64) exc1 (Q, {64{1'b1}}, div0, Qf);
mux2 #(64) exc2 (rem0, op1, div0, remf);
//mux2 #(64) exc1 (Q, {64{1'b1}}, div0, Qf);
//mux2 #(64) exc2 (rem0, op1, div0, remf);
endmodule // int32div
@ -1609,6 +1639,64 @@ module shift_left #(parameter WIDTH=8)
endmodule // shift_right
module exception_int (Q, rem, op1, S, div0, Max_N, D_NegOne, Qf, remf);
input logic [63:0] Q;
input logic [63:0] rem;
input logic [63:0] op1;
input logic S;
input logic div0;
input logic Max_N;
input logic D_NegOne;
output logic [63:0] Qf;
output logic [63:0] remf;
// Needs to be optimized
always_comb
case ({div0, S, Max_N, D_NegOne})
4'b0000 : Qf = Q;
4'b0001 : Qf = Q;
4'b0010 : Qf = Q;
4'b0011 : Qf = Q;
4'b0100 : Qf = Q;
4'b0101 : Qf = Q;
4'b0110 : Qf = Q;
4'b0111 : Qf = {1'b1, 31'h0};
4'b1000 : Qf = {64{1'b1}};
4'b1001 : Qf = {64{1'b1}};
4'b1010 : Qf = {64{1'b1}};
4'b1011 : Qf = {64{1'b1}};
4'b1100 : Qf = {64{1'b1}};
4'b1101 : Qf = {64{1'b1}};
4'b1110 : Qf = {64{1'b1}};
4'b1111 : Qf = {64{1'b1}};
default: Qf = Q;
endcase
always_comb
case ({div0, S, Max_N, D_NegOne})
4'b0000 : remf = rem;
4'b0001 : remf = rem;
4'b0010 : remf = rem;
4'b0011 : remf = rem;
4'b0100 : remf = rem;
4'b0101 : remf = rem;
4'b0110 : remf = rem;
4'b0111 : remf = 64'h0;
4'b1000 : remf = op1;
4'b1001 : remf = op1;
4'b1010 : remf = op1;
4'b1011 : remf = op1;
4'b1100 : remf = op1;
4'b1101 : remf = op1;
4'b1110 : remf = op1;
4'b1111 : remf = op1;
default: remf = rem;
endcase
endmodule // exception_int
/* verilator lint_on COMBDLY */
/* verilator lint_on IMPLICIT */

View File

@ -57,7 +57,8 @@ module muldiv (
logic gclk;
logic DivStartE;
logic startDivideE;
logic startDivideE;
logic signedDivide;
// Multiplier
mul mul(.*);
@ -76,8 +77,8 @@ module muldiv (
flopenrc #(`XLEN) reg_den (.d(SrcBE), .q(D),
.en(startDivideE), .clear(DivDoneE),
.reset(reset), .clk(~gclk));
div div (QuotE, RemE, DivDoneE, DivBusyE, div0error, N, D, gclk, reset, startDivideE);
assign signedDivide = (Funct3E[2]&~Funct3E[1]&~Funct3E[0]) | (Funct3E[2]&Funct3E[1]&~Funct3E[0]);
div div (QuotE, RemE, DivDoneE, DivBusyE, div0error, N, D, gclk, reset, startDivideE, signedDivide);
// Added for debugging of start signal for divide
assign startDivideE = MulDivE&DivStartE&~DivBusyE;

View File

@ -163,11 +163,11 @@ string tests32f[] = '{
"rv64m/I-MULHSU-01", "3000",
"rv64m/I-MULHU-01", "3000",
"rv64m/I-MULW-01", "3000",
//"rv64m/I-DIV-01", "3000",
"rv64m/I-DIV-01", "3000",
"rv64m/I-DIVU-01", "3000",
//"rv64m/I-DIVUW-01", "3000",
//"rv64m/I-DIVW-01", "3000",
//"rv64m/I-REM-01", "3000",
"rv64m/I-REM-01", "3000",
"rv64m/I-REMU-01", "3000"
//"rv64m/I-REMUW-01", "3000",
//"rv64m/I-REMW-01", "3000"