diff --git a/pipelined/src/uncore/uartPC16550D.sv b/pipelined/src/uncore/uartPC16550D.sv index 524a63454..89bdc837d 100644 --- a/pipelined/src/uncore/uartPC16550D.sv +++ b/pipelined/src/uncore/uartPC16550D.sv @@ -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 diff --git a/pipelined/srt/Makefile b/pipelined/srt/Makefile index 5d7898b17..ee249139d 100644 --- a/pipelined/srt/Makefile +++ b/pipelined/srt/Makefile @@ -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 diff --git a/pipelined/srt/exptestgen.c b/pipelined/srt/exptestgen.c index d6bebb774..61fe74aa4 100644 --- a/pipelined/srt/exptestgen.c +++ b/pipelined/srt/exptestgen.c @@ -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"); } diff --git a/pipelined/srt/inttestgen b/pipelined/srt/inttestgen index 2f7e68199..9e65cf4a0 100755 Binary files a/pipelined/srt/inttestgen and b/pipelined/srt/inttestgen differ diff --git a/pipelined/srt/inttestgen.c b/pipelined/srt/inttestgen.c index 17ec9299e..8c83d7963 100644 --- a/pipelined/srt/inttestgen.c +++ b/pipelined/srt/inttestgen.c @@ -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 +#include +#include + +/* 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= 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 \ No newline at end of file diff --git a/pipelined/srt/testbench.sv b/pipelined/srt/testbench.sv index 7a4e1897b..513305b26 100644 --- a/pipelined/srt/testbench.sv +++ b/pipelined/srt/testbench.sv @@ -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];