From 79e798a6417f4730ef5030680007ecf2b79270ac Mon Sep 17 00:00:00 2001 From: bbracker Date: Thu, 10 Jun 2021 09:53:48 -0400 Subject: [PATCH] UART improved and added more reg read side effects --- wally-pipelined/src/uncore/uartPC16550D.sv | 56 +++++++++++++--------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/wally-pipelined/src/uncore/uartPC16550D.sv b/wally-pipelined/src/uncore/uartPC16550D.sv index 0f539512..9261848c 100644 --- a/wally-pipelined/src/uncore/uartPC16550D.sv +++ b/wally-pipelined/src/uncore/uartPC16550D.sv @@ -94,7 +94,7 @@ module uartPC16550D( logic rxfifodmaready; logic [8:0] rxdata9; logic [7:0] rxdata; - logic [15:0] rxerrbit, rxfullbit; + logic [15:0] RXerrbit, rxfullbit; // transmit data logic [11:0] TXHR, txdata, nexttxdata, txsr; @@ -106,7 +106,9 @@ module uartPC16550D( logic fifoenabled, fifodmamodesel, evenparitysel; // interrupts - logic rxlinestatusintr, rxdataavailintr, modemstatusintr, intrpending, THRE, suppressTHREbecauseIIR, suppressTHREbecauseIIRtrig; + logic RXerr, RXerrIP, squashRXerrIP, prevSquashRXerrIP, setSquashRXerrIP, resetSquashRXerrIP; + logic THRE, THRE_IP, squashTHRE_IP, prevSquashTHRE_IP, setSquashTHRE_IP, resetSquashTHRE_IP; + logic rxdataavailintr, modemstatusintr, intrpending; logic [2:0] intrID; /////////////////////////////////////////// @@ -146,13 +148,15 @@ module uartPC16550D( 3'b111: SCR <= #1 Din; endcase 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 - if (RXBR[10]) LSR[1] <= #1 1; // overrun error - if (RXBR[9]) LSR[2] <= #1 1; // parity error - if (RXBR[8]) LSR[3] <= #1 1; // framing error - if (rxbreak) LSR[4] <= #1 1; // break indicator - LSR[5] <= #1 THRE & ~(suppressTHREbecauseIIR | suppressTHREbecauseIIRtrig); // THRE (suppress trigger included to avoid 2-cycle delay) + 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 @@ -162,7 +166,6 @@ module uartPC16550D( MSR[2] <= #1 MSR[2] | (~RIb2 & RIbsync); // Trailing Edge of Ring Indicator MSR[3] <= #1 MSR[3] | DCDb2 ^ DCDbsync; // Delta Data Carrier Detect end - always_comb if (~MEMRb) case (A) @@ -199,7 +202,6 @@ module uartPC16550D( /////////////////////////////////////////// // receive timing and control /////////////////////////////////////////// - always_ff @(posedge HCLK, negedge HRESETn) if (~HRESETn) begin rxoversampledcnt <= #1 0; @@ -260,7 +262,7 @@ module uartPC16550D( if (rxstate == UART_DONE) begin RXBR <= #1 {rxoverrunerr, rxparityerr, rxframingerr, rxdata}; // load recevive buffer register if (fifoenabled) begin - rxfifo[rxfifohead] <= #1 {rxoverrunerr, rxparityerr, rxframingerr, rxdata}; + rxfifo[rxfifohead] <= #1 {rxoverrunerr, rxparityerr, rxframingerr, rxdata}; rxfifohead <= #1 rxfifohead + 1; end rxdataready <= #1 1; @@ -287,14 +289,14 @@ module uartPC16550D( generate genvar i; for (i=0; i<16; i++) begin - assign rxerrbit[i] = |rxfifo[i][10:8]; // are any of the error conditions set? + assign RXerrbit[i] = |rxfifo[i][10:8]; // are any of the error conditions set? if (i > 0) assign rxfullbit[i] = ((rxfifohead==i) | rxfullbit[i-1]) & (rxfifotail != i); else assign rxfullbit[0] = ((rxfifohead==i) | rxfullbit[15]) & (rxfifotail != i); end endgenerate - assign rxfifohaserr = |(rxerrbit & rxfullbit); + assign rxfifohaserr = |(RXerrbit & rxfullbit); // receive buffer register and ready bit always_ff @(posedge HCLK, negedge HRESETn) // track rxrdy for DMA mode (FCR3 = FCR0 = 1) @@ -341,7 +343,6 @@ module uartPC16550D( /////////////////////////////////////////// // transmit holding register, shift register, FIFO /////////////////////////////////////////// - always_comb begin // compute value for parity and tx holding register nexttxdata = fifoenabled ? txfifo[txfifotail] : TXHR; // pick from FIFO or holding register case (LCR[1:0]) // compute parity from appropriate number of bits @@ -420,20 +421,22 @@ module uartPC16550D( /////////////////////////////////////////// // interrupts /////////////////////////////////////////// - assign rxlinestatusintr = |LSR[4:1]; // LS interrupt if any of the flags are true + assign RXerr = |LSR[4:1]; // LS interrupt if any of the flags are true + assign RXerrIP = RXerr & ~squashRXerrIP; // intr squashed upon reading LSR assign rxdataavailintr = fifoenabled ? rxfifotriggered : rxdataready; - assign THRE = fifoenabled ? txfifoempty : ~txhrfull; + assign THRE = fifoenabled ? txfifoempty : ~txhrfull; + assign THRE_IP = THRE & ~squashTHRE_IP; // THRE_IP squashed upon reading IIR assign modemstatusintr = |MSR[3:0]; // set interrupt when modem pins change // IIR: interrupt priority (Table 5) // set intrID based on highest priority pending interrupt source; otherwise, no interrupt is pending always_comb begin intrpending = 1; - if (rxlinestatusintr & IER[2]) intrID = 3'b011; - else if (rxdataavailintr & IER[0]) intrID = 3'b010; - else if (rxfifotimeout & fifoenabled & IER[0]) intrID = 3'b110; - else if (THRE & IER[1] & ~suppressTHREbecauseIIR) intrID = 3'b001; - else if (modemstatusintr & IER[3]) intrID = 3'b000; + if (RXerrIP & IER[2]) intrID = 3'b011; + else if (rxdataavailintr & IER[0]) intrID = 3'b010; + else if (rxfifotimeout & fifoenabled & IER[0]) intrID = 3'b110; + else if (THRE_IP & IER[1]) intrID = 3'b001; + else if (modemstatusintr & IER[3]) intrID = 3'b000; else begin intrID = 3'b000; intrpending = 0; @@ -441,9 +444,16 @@ module uartPC16550D( end always @(posedge HCLK) INTR <= #1 intrpending; // prevent glitches on interrupt pin - // Side effect of reading IIR is lowering THRE if most significant intr - assign suppressTHREbecauseIIRtrig = ~MEMRb & (A==3'b010) & (intrID==2'h1); - flopr #(1) suppressTHREreg(HCLK, (~HRESETn | (fifoenabled ? ~txfifoempty : txhrfull)), (suppressTHREbecauseIIRtrig | suppressTHREbecauseIIR), suppressTHREbecauseIIR); + // Side effect of reading LSR is lowering overrun, parity, framing, break intr's + assign setSquashRXerrIP = ~MEMRb & (A==3'b101); + assign resetSquashRXerrIP = (rxstate == UART_DONE); + assign squashRXerrIP = (prevSquashRXerrIP | setSquashRXerrIP) & ~resetSquashRXerrIP; + flopr #(1) squashRXerrIPreg(HCLK, ~HRESETn, squashRXerrIP, prevSquashRXerrIP); + // Side effect of reading IIR is lowering THRE_IP if most significant intr + assign setSquashTHRE_IP = ~MEMRb & (A==3'b010) & (intrID==2'h1); // there's a 1-cycle delay on set squash so that THRE_IP doesn't change during the process of reading IIR (otherwise combinational loop) + assign resetSquashTHRE_IP = ~THRE; + assign squashTHRE_IP = prevSquashTHRE_IP & ~resetSquashTHRE_IP; + flopr #(1) squashTHRE_IPreg(HCLK, ~HRESETn, squashTHRE_IP | setSquashTHRE_IP, prevSquashTHRE_IP); /////////////////////////////////////////// // modem control logic