forked from Github_Repos/cvw
		
	UART improved and added more reg read side effects
This commit is contained in:
		
							parent
							
								
									75257f2ab2
								
							
						
					
					
						commit
						79e798a641
					
				@ -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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user