This commit is contained in:
Daniel Torres 2022-07-21 20:59:01 -07:00
commit f1578936b8
12 changed files with 219 additions and 90 deletions

View File

@ -165,6 +165,7 @@ module uartPC16550D(
SCR <= #1 8'b0; // not strictly necessary to reset
end else begin
if (~MEMWb) begin
/* verilator lint_off CASEINCOMPLETE */
case (A)
/* -----\/----- EXCLUDED -----\/-----
3'b000: if (DLAB) DLL <= #1 Din; // else TXHR <= #1 Din; // TX handled in TX register/FIFO section
@ -177,34 +178,40 @@ module uartPC16550D(
// freq /baud / 16 = div
//3'b000: if (DLAB) DLL <= #1 8'd38; //else TXHR <= #1 Din; // TX handled in TX register/FIFO section
//3'b000: if (DLAB) DLL <= #1 8'd11; //else TXHR <= #1 Din; // TX handled in
3'b000: if (DLAB) DLL <= #1 8'd8; //else TXHR <= #1 Din; // TX handled in
3'b000: if (DLAB) DLL <= #1 8'd8; //else TXHR <= #1 Din; // TX handled in
3'b001: if (DLAB) DLM <= #1 8'b0; else IER <= #1 Din[3:0];
3'b010: FCR <= #1 {Din[7:6], 2'b0, Din[3], 2'b0, Din[0]}; // Write only FIFO Control Register; 4:5 reserved and 2:1 self-clearing
3'b011: LCR <= #1 Din;
3'b100: MCR <= #1 Din[4:0];
3'b101: LSR[6:1] <= #1 Din[6:1]; // recommended only for test, see 8.6.3
3'b110: MSR <= #1 Din[3:0];
3'b111: SCR <= #1 Din;
endcase
/* verilator lint_on CASEINCOMPLETE */
end
// Line Status Register (8.6.3)
// Ben 6/9/21 I don't like how this is a register. A lot of the individual bits have clocked components, so this just adds unecessary delay.
LSR[0] <= #1 rxdataready; // Data ready
LSR[1] <= #1 (LSR[1] | RXBR[10]) & ~squashRXerrIP;; // overrun error
LSR[2] <= #1 (LSR[2] | RXBR[9]) & ~squashRXerrIP; // parity error
LSR[3] <= #1 (LSR[3] | RXBR[8]) & ~squashRXerrIP; // framing error
LSR[4] <= #1 (LSR[4] | rxbreak) & ~squashRXerrIP; // break indicator
LSR[5] <= #1 THRE; // THRE
LSR[6] <= #1 ~txsrfull & THRE; // TEMT
if (rxfifohaserr) LSR[7] <= #1 1; // any bits in FIFO have error
// Ben 6/9/21 I don't like how this is a register. A lot of the individual bits have clocked components, so this just adds unecessary delay.
if (~MEMWb & (A == 3'b101))
LSR[6:1] <= #1 Din[6:1]; // recommended only for test, see 8.6.3
else begin
LSR[0] <= #1 rxdataready; // Data ready
LSR[1] <= #1 (LSR[1] | RXBR[10]) & ~squashRXerrIP;; // overrun error
LSR[2] <= #1 (LSR[2] | RXBR[9]) & ~squashRXerrIP; // parity error
LSR[3] <= #1 (LSR[3] | RXBR[8]) & ~squashRXerrIP; // framing error
LSR[4] <= #1 (LSR[4] | rxbreak) & ~squashRXerrIP; // break indicator
LSR[5] <= #1 THRE; // THRE
LSR[6] <= #1 ~txsrfull & THRE; // TEMT
if (rxfifohaserr) LSR[7] <= #1 1; // any bits in FIFO have error
end
// Modem Status Register (8.6.8)
MSR[0] <= #1 MSR[0] | CTSb2 ^ CTSbsync; // Delta Clear to Send
MSR[1] <= #1 MSR[1] | DSRb2 ^ DSRbsync; // Delta Data Set Ready
MSR[2] <= #1 MSR[2] | (~RIb2 & RIbsync); // Trailing Edge of Ring Indicator
MSR[3] <= #1 MSR[3] | DCDb2 ^ DCDbsync; // Delta Data Carrier Detect
if (~MEMWb & (A == 3'b110))
MSR <= #1 Din[3:0];
else begin
MSR[0] <= #1 MSR[0] | CTSb2 ^ CTSbsync; // Delta Clear to Send
MSR[1] <= #1 MSR[1] | DSRb2 ^ DSRbsync; // Delta Data Set Ready
MSR[2] <= #1 MSR[2] | (~RIb2 & RIbsync); // Trailing Edge of Ring Indicator
MSR[3] <= #1 MSR[3] | DCDb2 ^ DCDbsync; // Delta Data Carrier Detect
end
end
always_comb
if (~MEMRb)
@ -215,7 +222,8 @@ module uartPC16550D(
3'b011: Dout = LCR;
3'b100: Dout = {3'b000, MCR};
3'b101: Dout = LSR;
3'b110: Dout = {~CTSbsync, ~DSRbsync, ~RIbsync, ~DCDbsync, MSR[3:0]};
// 3'b110: Dout = {~CTSbsync, ~DSRbsync, ~RIbsync, ~DCDbsync, MSR[3:0]};
3'b110: Dout = {~DCDbsync, ~RIbsync, ~DSRbsync, ~CTSbsync, MSR[3:0]};
3'b111: Dout = SCR;
endcase
else Dout = 8'b0;
@ -304,7 +312,7 @@ module uartPC16550D(
// ERROR CONDITIONS
assign rxparity = ^rxdata;
assign rxparityerr = rxparity ^ rxparitybit ^ ~evenparitysel; // Check even/odd parity (*** check if LCR needs to be inverted)
assign rxparityerr = (rxparity ^ rxparitybit ^ ~evenparitysel) & LCR[3]; // Check even/odd parity (*** check if LCR needs to be inverted)
assign rxoverrunerr = fifoenabled ? (rxfifoentries == 15) : rxdataready; // overrun if FIFO or receive buffer register full
assign rxframingerr = ~rxstopbit; // framing error if no stop bit
assign rxbreak = rxframingerr & (rxdata9 == 9'b0); // break when 0 for start + data + parity + stop time
@ -405,7 +413,7 @@ module uartPC16550D(
txstate <= #1 UART_IDLE;
end
assign txbitsexpected = 4'd1 + (4'd5 + {2'b00, LCR[1:0]}) + {3'b000, LCR[3]} + 4'd1 + {3'b000, LCR[2]} - 4'd1; // start bit + data bits + (parity bit) + stop bit(s)
assign txbitsexpected = 4'd1 + (4'd5 + {2'b00, LCR[1:0]}) + {3'b000, LCR[3]} + 4'd1 + {3'b000, LCR[2]} - 4'd1; // start bit + data bits + (parity bit) + stop bit(s) - 1
// *** explain; is this necessary?
if (`QEMU) assign txnextbit = txbaudpulse & (txoversampledcnt[1:0] == 2'b00); // implies txstate = UART_ACTIVE
else assign txnextbit = txbaudpulse & (txoversampledcnt == 4'b0000); // implies txstate = UART_ACTIVE

View File

@ -1,4 +1,4 @@
all: exptestgen testgen qslc_r4a2 qslc_r4a2b qslc_sqrt_r4a2 sqrttestgen
all: exptestgen testgen qslc_r4a2 qslc_r4a2b qslc_sqrt_r4a2 sqrttestgen modtestgen
sqrttestgen: sqrttestgen.c
gcc sqrttestgen.c -o sqrttestgen -lm
@ -28,6 +28,10 @@ inttestgen: inttestgen.c
gcc -lm -o inttestgen inttestgen.c
./inttestgen
modtestgen: modtestgen.c
gcc -lm -o modtestgen modtestgen.c
./modtestgen
clean:
rm -f testgen exptestgen qslc_r4a2 qslc_r4a2b qslc_sqrt_r4a2 sqrttestgen
rm -f testgen exptestgen qslc_r4a2 qslc_r4a2b qslc_sqrt_r4a2 sqrttestgen modtestgen

View File

@ -96,10 +96,6 @@ void output(FILE *fptr, int aSign, int aExp, double aFrac, int bSign, int bExp,
// Print r in standard double format
fprintf(fptr, "%03x", rExp|(rSign<<11));
printhex(fptr, rFrac);
fprintf(fptr, "_");
// Spacing for testbench, value doesn't matter
fprintf(fptr, "%016x", 0);
fprintf(fptr, "\n");
}

Binary file not shown.

View File

@ -1,9 +1,8 @@
/* testgen.c */
/* Written 10/31/96 by David Harris
/* Written 7/21/2022 by Cedar Turek
This program creates test vectors for mantissa component
of an IEEE floating point divider.
This program creates test vectors for integer divide.
*/
/* #includes */
@ -19,7 +18,7 @@
/* Prototypes */
void output(FILE *fptr, long a, long b, long r, long rem);
void output(FILE *fptr, long a, long b, long r);
void printhex(FILE *fptr, long x);
double random_input(void);
@ -28,7 +27,7 @@ double random_input(void);
void main(void)
{
FILE *fptr;
long a, b, r, rem;
long a, b, r;
long list[ENTRIES] = {1, 3, 5, 18, 25, 33, 42, 65, 103, 255};
int i, j;
@ -42,32 +41,22 @@ void main(void)
for (j=0; j<ENTRIES; j++) {
a = list[j];
r = a/b;
rem = a%b;
output(fptr, a, b, r, rem);
output(fptr, a, b, r);
}
}
// 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)
void output(FILE *fptr, long a, long b, long r)
{
printhex(fptr, a);
fprintf(fptr, "_");
printhex(fptr, b);
fprintf(fptr, "_");
printhex(fptr, r);
fprintf(fptr, "_");
printhex(fptr, rem);
fprintf(fptr, "\n");
}

BIN
pipelined/srt/modtestgen Executable file

Binary file not shown.

View File

@ -0,0 +1,73 @@
/* testgen.c */
/* Written 7/21/2022 by Cedar Turek
This program creates test vectors for modulo
calculation from integer divide.
*/
/* #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 rem);
void printhex(FILE *fptr, long x);
double random_input(void);
/* Main */
void main(void)
{
FILE *fptr;
long a, b, rem;
long list[ENTRIES] = {1, 3, 5, 18, 25, 33, 42, 65, 103, 255};
int i, j;
if ((fptr = fopen("modtestvectors","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];
rem = a%b;
output(fptr, a, b, rem);
}
}
fclose(fptr);
}
/* Functions */
void output(FILE *fptr, long a, long b, long rem)
{
printhex(fptr, a);
fprintf(fptr, "_");
printhex(fptr, b);
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;
}

Binary file not shown.

View File

@ -86,10 +86,6 @@ void output(FILE *fptr, int aExp, double aFrac, int rExp, double rFrac)
// Print r in standard double format
fprintf(fptr, "%03x", rExp);
printhex(fptr, rFrac);
fprintf(fptr, "_");
// Spacing for testbench, value doesn't matter
fprintf(fptr, "%016x", 0);
fprintf(fptr, "\n");
}

View File

@ -2,4 +2,5 @@ add wave -noupdate /testbench/*
add wave -noupdate /testbench/srt/*
add wave -noupdate /testbench/srt/sotfc2/*
add wave -noupdate /testbench/srt/preproc/*
add wave -noupdate /testbench/srt/postproc/*
add wave -noupdate /testbench/srt/divcounter/*

View File

@ -35,33 +35,36 @@ module srt (
input logic Start,
input logic Stall, // *** multiple pipe stages
input logic Flush, // *** multiple pipe stages
// Floating Point Inputs
// later add exponents, signs, special cases
// Floating Point
input logic XSign, YSign,
input logic [`NE-1:0] XExp, YExp,
input logic [`NF-1:0] SrcXFrac, SrcYFrac,
// Integer
input logic [`XLEN-1:0] SrcA, SrcB,
// Customization
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
// Selection
input logic Signed, // Interpret integers as signed 2's complement
input logic Int, // Choose integer inputs
input logic Mod, // perform remainder calculation (modulo) instead of divide
input logic Sqrt, // perform square root, not divide
output logic rsign, done,
output logic [`DIVLEN-2:0] Rem, Quot, // *** later handle integers
output logic [`DIVLEN-1:0] Result,
output logic [`NE-1:0] rExp,
output logic [3:0] Flags
);
logic qp, qz, qn; // quotient is +1, 0, or -1
logic qp, qz, qn; // result bits are +1, 0, or -1
logic [`NE-1:0] calcExp;
logic calcSign;
logic [`DIVLEN+3:0] X, Dpreproc, C, F, S, SM, AddIn;
logic [`DIVLEN+3:0] WS, WSA, WSN, WC, WCA, WCN, D, Db, Dsel;
logic [$clog2(`XLEN+1)-1:0] intExp, dur, calcDur;
logic [$clog2(`XLEN+1)-1:0] zeroCntD, intExp, dur, calcDur;
logic intSign;
logic cin;
srtpreproc preproc(SrcA, SrcB, SrcXFrac, SrcYFrac, XExp, Fmt, W64, Signed, Int, Sqrt, X, Dpreproc, intExp, calcDur, intSign);
srtpreproc preproc(SrcA, SrcB, SrcXFrac, SrcYFrac, XExp, Fmt, W64, Signed, Int, Mod, Sqrt, X, Dpreproc, zeroCntD, intExp, calcDur, intSign);
// Top Muxes and Registers
// When start is asserted, the inputs are loaded into the divider.
@ -91,7 +94,7 @@ module srt (
// otfc2 #(`DIVLEN) otfc2(clk, Start, qp, qz, qn, Quot);
// otherwise use sotfc
creg sotfcC(clk, Start, Sqrt, C);
sotfc2 sotfc2(clk, Start, qp, qn, Sqrt, C, Quot, S, SM);
sotfc2 sotfc2(clk, Start, qp, qn, Sqrt, C, S, SM);
fsel2 fsel(qp, qn, C, S, SM, F);
// Adder input selection
@ -103,7 +106,7 @@ module srt (
expcalc expcalc(.XExp, .YExp, .calcExp, .Sqrt);
signcalc signcalc(.XSign, .YSign, .calcSign);
srtpostproc postproc(.WS, .WC, .X, .D, .S, .SM, .dur, .zeroCntD, .XSign, .YSign, .Signed, .Int, .Mod, .Result, .calcSign);
endmodule
////////////////
@ -121,13 +124,14 @@ module srtpreproc (
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 Mod, // perform remainder calculation (modulo) instead of divide
input logic Sqrt, // perform square root, not divide
output logic [`DIVLEN+3:0] X, D,
output logic [$clog2(`XLEN+1)-1:0] intExp, dur, // Quotient integer exponent
output logic [$clog2(`XLEN+1)-1:0] zeroCntB, intExp, dur, // Quotient integer exponent
output logic intSign // Quotient integer sign
);
logic [$clog2(`XLEN+1)-1:0] zeroCntA, zeroCntB;
logic [$clog2(`XLEN+1)-1:0] zeroCntA;
logic [`XLEN-1:0] PosA, PosB;
logic [`DIVLEN-1:0] ExtraA, ExtraB, PreprocA, PreprocB, PreprocX, PreprocY, DivX;
logic [`NF+4:0] SqrtX;
@ -159,7 +163,7 @@ module srtpreproc (
assign D = {4'b0001, Int ? PreprocB : PreprocY};
// Integer exponent and sign calculations
assign intExp = zeroCntB - zeroCntA + 1;
assign intExp = zeroCntB - zeroCntA - Mod + (PreprocA >= PreprocB);
assign intSign = Signed & (SrcA[`XLEN - 1] ^ SrcB[`XLEN - 1]);
// Number of cycles of divider
@ -235,7 +239,7 @@ module otfc2 #(parameter N=66) (
input logic clk,
input logic Start,
input logic qp, qz, qn,
output logic [N-3:0] r
output logic [N-3:0] Result
);
// The on-the-fly converter transfers the quotient
// bits to the quotient as they come.
@ -261,7 +265,7 @@ module otfc2 #(parameter N=66) (
QMNext = {QMR, 1'b0};
end
end
assign r = Q[N] ? Q[N-1:2] : Q[N-2:1];
assign Result = Q[N] ? Q[N-1:2] : Q[N-2:1];
endmodule
@ -274,7 +278,6 @@ module sotfc2(
input logic sp, sn,
input logic Sqrt,
input logic [`DIVLEN+3:0] C,
output logic [`DIVLEN-2:0] Sq,
output logic [`DIVLEN+3:0] S, SM
);
// The on-the-fly converter transfers the square root
@ -298,7 +301,6 @@ module sotfc2(
SMNext = SM | (C & ~(C << 1));
end
end
assign Sq = S[`DIVLEN] ? S[`DIVLEN-1:1] : S[`DIVLEN-2:0];
endmodule
//////////////////////////
@ -395,14 +397,76 @@ module expcalc(
endmodule
//////////////
// signcalc //
//////////////
module signcalc(
input logic XSign, YSign,
module srtpostproc(
input logic [`DIVLEN+3:0] WS, WC, X, D, S, SM,
input logic [$clog2(`XLEN+1)-1:0] dur, zeroCntD,
input logic XSign, YSign, Signed, Int, Mod,
output logic [`DIVLEN-1:0] Result,
output logic calcSign
);
logic [`DIVLEN+3:0] W, shiftRem, intRem, intS;
logic [`DIVLEN-1:0] floatRes, intRes;
logic WSign;
assign W = WS + WC;
assign WSign = W[`DIVLEN+3];
// Remainder handling
always_comb begin
if (zeroCntD == ($clog2(`XLEN+1))'(`XLEN)) begin
intRem = X;
intS = -1;
end
else if (~Signed) begin
if (WSign) begin
intRem = W + D;
intS = SM;
end else begin
intRem = W;
intS = S;
end
end
else case ({YSign, XSign, WSign})
3'b000: begin
intRem = W;
intS = S;
end
3'b001: begin
intRem = W + D;
intS = SM;
end
3'b010: begin
intRem = W - D;
intS = ~S;
end
3'b011: begin
intRem = W;
intS = ~SM;
end
3'b100: begin
intRem = W;
intS = ~SM;
end
3'b101: begin
intRem = W + D;
intS = ~SM + 1;
end
3'b110: begin
intRem = W - D;
intS = S + 1;
end
3'b111: begin
intRem = W;
intS = S;
end
endcase
end
assign floatRes = S[`DIVLEN] ? S[`DIVLEN:1] : S[`DIVLEN-1:0];
assign intRes = intS[`DIVLEN] ? intS[`DIVLEN:1] : intS[`DIVLEN-1:0];
assign shiftRem = (intRem >>> (`DIVLEN - dur + 2));
always_comb
if (Int) Result = intRes >> (`DIVLEN - dur);
else if (Mod) Result = shiftRem[`DIVLEN-1:0];
else Result = floatRes;
assign calcSign = XSign ^ YSign;
endmodule
endmodule

View File

@ -42,24 +42,23 @@ module testbench;
logic clk;
logic req;
logic done;
logic Int;
logic Int, Sqrt, Mod;
logic [`XLEN-1:0] a, b;
logic [`NF-1:0] afrac, bfrac;
logic [`NE-1:0] aExp, bExp;
logic asign, bsign;
logic [`NF-1:0] r;
logic [`XLEN-1:0] rInt;
logic [`DIVLEN-2:0] Quot;
logic [`DIVLEN-1:0] Quot;
// Test parameters
parameter MEM_SIZE = 40000;
parameter MEM_WIDTH = 64+64+64+64;
// Test sizes
`define memrem 63:0
`define memr 127:64
`define memb 191:128
`define mema 255:192
`define memr 63:0
`define memb 127:64
`define mema 191:128
// Test logicisters
logic [MEM_WIDTH-1:0] Tests [0:MEM_SIZE]; // Space for input file
@ -70,8 +69,9 @@ module testbench;
logic rsign;
integer testnum, errors;
// Equip Int test or Sqrt test
assign Int = 1'b0;
// Equip Int, Sqrt, or IntMod test
assign Int = 1'b1;
assign Mod = 1'b0;
assign Sqrt = 1'b0;
// Divider
@ -81,8 +81,8 @@ module testbench;
.XSign(asign), .YSign(bsign), .rsign,
.SrcXFrac(afrac), .SrcYFrac(bfrac),
.SrcA(a), .SrcB(b), .Fmt(2'b00),
.W64(1'b1), .Signed(1'b0), .Int, .Sqrt,
.Quot, .Rem(), .Flags(), .done);
.W64(1'b1), .Signed(1'b0), .Int, .Mod, .Sqrt,
.Result(Quot), .Flags(), .done);
// Counter
// counter counter(clk, req, done);
@ -101,7 +101,7 @@ module testbench;
begin
testnum = 0;
errors = 0;
$readmemh ("testvectors", Tests);
$readmemh ("inttestvectors", Tests);
Vec = Tests[testnum];
a = Vec[`mema];
{asign, aExp, afrac} = a;
@ -109,7 +109,7 @@ module testbench;
{bsign, bExp, bfrac} = b;
nextr = Vec[`memr];
r = Quot[(`DIVLEN - 2):(`DIVLEN - `NF - 1)];
rInt = {1'b1, Quot};
rInt = Quot;
req <= #5 1;
end
@ -117,9 +117,9 @@ module testbench;
always @(posedge clk) begin
r = Quot[(`DIVLEN - 2):(`DIVLEN - `NF - 1)];
rInt = {1'b1, Quot};
rInt = Quot;
if (done) begin
if (~Int & ~Sqrt) begin
if (~Int & ~Sqrt) begin // This test case checks floating point division
req <= #5 1;
diffp = correctr[51:0] - r;
diffn = r - correctr[51:0];
@ -135,23 +135,21 @@ module testbench;
$display("%d Tests completed successfully", testnum);
$stop;
end
end else if (~Sqrt) begin
end else if (~Sqrt) begin // This test case works for both integer divide and integer modulo
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
if (($signed(diffp) != 0) | (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("result was %h, should be %h %h\n", rInt, correctr, diffp);
$display("failed\n");
$stop;
end
if (afrac === 52'hxxxxxxxxxxxxx)
begin
$display("%d Tests completed successfully", testnum);
$display("%d Tests completed successfully", testnum - errors);
$stop;
end
end else begin
end else begin // This test case verifies square root
req <= #5 1;
diffp = correctr[51:0] - r;
diffn = r - correctr[51:0];