Update uartPC16550D.sv

Program clean up
This commit is contained in:
Harshini Srinath 2023-06-15 10:20:29 -07:00 committed by GitHub
parent ae165b35f9
commit 53ad51ae54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -45,7 +45,7 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
output logic INTR, TXRDYb, RXRDYb, // interrupt and ready lines output logic INTR, TXRDYb, RXRDYb, // interrupt and ready lines
// Clocks // Clocks
output logic BAUDOUTb, // active low baud clock output logic BAUDOUTb, // active low baud clock
input logic RCLK, // usually BAUDOUTb tied to RCLK externally input logic RCLK, // usually BAUDOUTb tied to RCLK externally
// E1A Driver // E1A Driver
input logic SIN, DSRb, DCDb, CTSb, RIb, // UART external serial and flow-control inputs input logic SIN, DSRb, DCDb, CTSb, RIb, // UART external serial and flow-control inputs
output logic SOUT, RTSb, DTRb, OUT1b, OUT2b // UART external serial and flow-control outputs output logic SOUT, RTSb, DTRb, OUT1b, OUT2b // UART external serial and flow-control outputs
@ -71,9 +71,9 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
logic DLAB; // Divisor Latch Access Bit (LCR bit 7) logic DLAB; // Divisor Latch Access Bit (LCR bit 7)
// Baud and rx/tx timing // Baud and rx/tx timing
logic baudpulse, txbaudpulse, rxbaudpulse; // high one system clk cycle each baud/16 period logic baudpulse, txbaudpulse, rxbaudpulse; // high one system clk cycle each baud/16 period
logic [16+UART_PRESCALE-1:0] baudcount; logic [16+UART_PRESCALE-1:0] baudcount;
logic [3:0] rxoversampledcnt, txoversampledcnt; // count oversampled-by-16 logic [3:0] rxoversampledcnt, txoversampledcnt; // count oversampled-by-16
logic [3:0] rxbitsreceived, txbitssent; logic [3:0] rxbitsreceived, txbitssent;
statetype rxstate, txstate; statetype rxstate, txstate;
@ -122,6 +122,7 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
/////////////////////////////////////////// ///////////////////////////////////////////
// Input synchronization: 2-stage synchronizer // Input synchronization: 2-stage synchronizer
/////////////////////////////////////////// ///////////////////////////////////////////
always_ff @(posedge PCLK) begin always_ff @(posedge PCLK) begin
{SINd, DSRbd, DCDbd, CTSbd, RIbd} <= #1 {SIN, DSRb, DCDb, CTSb, RIb}; {SINd, DSRbd, DCDbd, CTSbd, RIbd} <= #1 {SIN, DSRb, DCDb, CTSb, RIb};
{SINsync, DSRbsync, DCDbsync, CTSbsync, RIbsync} <= #1 loop ? {SOUTbit, ~MCR[0], ~MCR[3], ~MCR[1], ~MCR[2]} : {SINsync, DSRbsync, DCDbsync, CTSbsync, RIbsync} <= #1 loop ? {SOUTbit, ~MCR[0], ~MCR[3], ~MCR[1], ~MCR[2]} :
@ -132,6 +133,7 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
/////////////////////////////////////////// ///////////////////////////////////////////
// Register interface (Table 1, note some are read only and some write only) // Register interface (Table 1, note some are read only and some write only)
/////////////////////////////////////////// ///////////////////////////////////////////
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) begin // Table 3 Reset Configuration if (~PRESETn) begin // Table 3 Reset Configuration
IER <= #1 4'b0; IER <= #1 4'b0;
@ -162,13 +164,13 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
if (~MEMWb & (A == 3'b101)) if (~MEMWb & (A == 3'b101))
LSR[6:1] <= #1 Din[6:1]; // recommended only for test, see 8.6.3 LSR[6:1] <= #1 Din[6:1]; // recommended only for test, see 8.6.3
else begin else begin
LSR[0] <= #1 rxdataready; // Data ready LSR[0] <= #1 rxdataready; // Data ready
LSR[1] <= #1 (LSR[1] | RXBR[10]) & ~squashRXerrIP;; // overrun error LSR[1] <= #1 (LSR[1] | RXBR[10]) & ~squashRXerrIP;; // overrun error
LSR[2] <= #1 (LSR[2] | RXBR[9]) & ~squashRXerrIP; // parity error LSR[2] <= #1 (LSR[2] | RXBR[9]) & ~squashRXerrIP; // parity error
LSR[3] <= #1 (LSR[3] | RXBR[8]) & ~squashRXerrIP; // framing error LSR[3] <= #1 (LSR[3] | RXBR[8]) & ~squashRXerrIP; // framing error
LSR[4] <= #1 (LSR[4] | rxbreak) & ~squashRXerrIP; // break indicator LSR[4] <= #1 (LSR[4] | rxbreak) & ~squashRXerrIP; // break indicator
LSR[5] <= #1 THRE; // THRE LSR[5] <= #1 THRE; // THRE
LSR[6] <= #1 ~txsrfull & THRE; // TEMT LSR[6] <= #1 ~txsrfull & THRE; // TEMT
if (rxfifohaserr) LSR[7] <= #1 1; // any bits in FIFO have error if (rxfifohaserr) LSR[7] <= #1 1; // any bits in FIFO have error
end end
@ -208,6 +210,7 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
/////////////////////////////////////////// ///////////////////////////////////////////
// Ross Thompson: Found a bug. If the baud rate dividers DLM, and DLL are reloaded // Ross Thompson: Found a bug. If the baud rate dividers DLM, and DLL are reloaded
// the baudcount is not reset to {DLM, DLL, UART_PRESCALE} // the baudcount is not reset to {DLM, DLL, UART_PRESCALE}
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) begin if (~PRESETn) begin
baudcount <= #1 1; baudcount <= #1 1;
@ -233,17 +236,18 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
/////////////////////////////////////////// ///////////////////////////////////////////
// receive timing and control // receive timing and control
/////////////////////////////////////////// ///////////////////////////////////////////
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) begin if (~PRESETn) begin
rxoversampledcnt <= #1 0; rxoversampledcnt <= #1 0;
rxstate <= #1 UART_IDLE; rxstate <= #1 UART_IDLE;
rxbitsreceived <= #1 0; rxbitsreceived <= #1 0;
rxtimeoutcnt <= #1 0; rxtimeoutcnt <= #1 0;
end else begin end else begin
if (rxstate == UART_IDLE & ~SINsync) begin // got start bit if (rxstate == UART_IDLE & ~SINsync) begin // got start bit
rxstate <= #1 UART_ACTIVE; rxstate <= #1 UART_ACTIVE;
rxoversampledcnt <= #1 0; rxoversampledcnt <= #1 0;
rxbitsreceived <= #1 0; rxbitsreceived <= #1 0;
if (~rxfifotimeout) rxtimeoutcnt <= #1 0; // reset timeout when new character is arriving. Jacob Pease: Only if the timeout was not already reached. p.16 PC16550D.pdf if (~rxfifotimeout) rxtimeoutcnt <= #1 0; // reset timeout when new character is arriving. Jacob Pease: Only if the timeout was not already reached. p.16 PC16550D.pdf
end else if (rxbaudpulse & (rxstate == UART_ACTIVE)) begin end else if (rxbaudpulse & (rxstate == UART_ACTIVE)) begin
rxoversampledcnt <= #1 rxoversampledcnt + 1; // 16x oversampled counter rxoversampledcnt <= #1 rxoversampledcnt + 1; // 16x oversampled counter
@ -260,13 +264,14 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
// ***explain why // ***explain why
if(QEMU) assign rxcentered = rxbaudpulse & (rxoversampledcnt[1:0] == 2'b10); // implies rxstate = UART_ACTIVE if(QEMU) assign rxcentered = rxbaudpulse & (rxoversampledcnt[1:0] == 2'b10); // implies rxstate = UART_ACTIVE
else assign rxcentered = rxbaudpulse & (rxoversampledcnt == 4'b1000); // implies rxstate = UART_ACTIVE else assign rxcentered = rxbaudpulse & (rxoversampledcnt == 4'b1000); // implies rxstate = UART_ACTIVE
assign rxbitsexpected = 4'd1 + (4'd5 + {2'b00, LCR[1:0]}) + {3'b000, LCR[3]} + 4'd1; // start bit + data bits + (parity bit) + stop bit assign rxbitsexpected = 4'd1 + (4'd5 + {2'b00, LCR[1:0]}) + {3'b000, LCR[3]} + 4'd1; // start bit + data bits + (parity bit) + stop bit
/////////////////////////////////////////// ///////////////////////////////////////////
// receive shift register, buffer register, FIFO // receive shift register, buffer register, FIFO
/////////////////////////////////////////// ///////////////////////////////////////////
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) rxshiftreg <= #1 10'b0000000001; // initialize so that there is a valid stop bit if (~PRESETn) rxshiftreg <= #1 10'b0000000001; // initialize so that there is a valid stop bit
else if (rxcentered) rxshiftreg <= #1 {rxshiftreg[8:0], SINsync}; // capture bit else if (rxcentered) rxshiftreg <= #1 {rxshiftreg[8:0], SINsync}; // capture bit
@ -282,11 +287,11 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
assign rxdata = LCR[3] ? rxdata9[7:0] : rxdata9[8:1]; // discard parity bit assign rxdata = LCR[3] ? rxdata9[7:0] : rxdata9[8:1]; // discard parity bit
// ERROR CONDITIONS // ERROR CONDITIONS
assign rxparity = ^rxdata; assign rxparity = ^rxdata;
assign rxparityerr = (rxparity ^ rxparitybit ^ ~evenparitysel) & LCR[3]; // 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 rxoverrunerr = fifoenabled ? (rxfifoentries == 15) : rxdataready; // overrun if FIFO or receive buffer register full
assign rxframingerr = ~rxstopbit; // framing error if no stop bit assign rxframingerr = ~rxstopbit; // framing error if no stop bit
assign rxbreak = rxframingerr & (rxdata9 == 9'b0); // break when 0 for start + data + parity + stop time assign rxbreak = rxframingerr & (rxdata9 == 9'b0); // break when 0 for start + data + parity + stop time
// receive FIFO and register // receive FIFO and register
always_ff @(posedge PCLK) always_ff @(posedge PCLK)
@ -298,7 +303,7 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
end else if (rxstate == UART_DONE) begin end else if (rxstate == UART_DONE) begin
RXBR <= #1 {rxoverrunerr, rxparityerr, rxframingerr, rxdata}; // load recevive buffer register RXBR <= #1 {rxoverrunerr, rxparityerr, rxframingerr, rxdata}; // load recevive buffer register
if (rxoverrunerr) $warning("UART RX Overrun Err\n"); if (rxoverrunerr) $warning("UART RX Overrun Err\n");
if (rxparityerr) $warning("UART RX Parity Err\n"); if (rxparityerr) $warning("UART RX Parity Err\n");
if (rxframingerr) $warning("UART RX Framing Err\n"); if (rxframingerr) $warning("UART RX Framing Err\n");
if (fifoenabled) begin if (fifoenabled) begin
rxfifo[rxfifohead] <= #1 {rxoverrunerr, rxparityerr, rxframingerr, rxdata}; rxfifo[rxfifohead] <= #1 {rxoverrunerr, rxparityerr, rxframingerr, rxdata};
@ -339,14 +344,14 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
else assign rxfullbitunwrapped[i] = ({1'b0,rxfifohead}==i | rxfullbitunwrapped[i-1]) & (rxfifotailunwrapped != i); else assign rxfullbitunwrapped[i] = ({1'b0,rxfifohead}==i | rxfullbitunwrapped[i-1]) & (rxfifotailunwrapped != i);
end end
for (i=0; i<16; i++) begin:rx for (i=0; i<16; i++) begin:rx
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?
assign rxfullbit[i] = rxfullbitunwrapped[i] | rxfullbitunwrapped[i+16]; assign rxfullbit[i] = rxfullbitunwrapped[i] | rxfullbitunwrapped[i+16];
/* if (i > 0) /* if (i > 0)
assign rxfullbit[i] = ((rxfifohead==i) | rxfullbit[i-1]) & (rxfifotail != i); assign rxfullbit[i] = ((rxfifohead==i) | rxfullbit[i-1]) & (rxfifotail != i);
else else
assign rxfullbit[0] = ((rxfifohead==i) | rxfullbit[15]) & (rxfifotail != i);*/ assign rxfullbit[0] = ((rxfifohead==i) | rxfullbit[15]) & (rxfifotail != i);*/
end end
assign rxfifohaserr = |(RXerrbit & rxfullbit); assign rxfifohaserr = |(RXerrbit & rxfullbit);
// receive buffer register and ready bit // receive buffer register and ready bit
always_ff @(posedge PCLK, negedge PRESETn) // track rxrdy for DMA mode (FCR3 = FCR0 = 1) always_ff @(posedge PCLK, negedge PRESETn) // track rxrdy for DMA mode (FCR3 = FCR0 = 1)
@ -361,22 +366,23 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
if (fifodmamodesel) RXRDYb = ~rxfifodmaready; if (fifodmamodesel) RXRDYb = ~rxfifodmaready;
else RXRDYb = rxfifoempty; else RXRDYb = rxfifoempty;
end else begin end else begin
RBR = RXBR; RBR = RXBR;
RXRDYb = ~rxdataready; RXRDYb = ~rxdataready;
end end
/////////////////////////////////////////// ///////////////////////////////////////////
// transmit timing and control // transmit timing and control
/////////////////////////////////////////// ///////////////////////////////////////////
always_ff @(posedge PCLK, negedge PRESETn) always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) begin if (~PRESETn) begin
txoversampledcnt <= #1 0; txoversampledcnt <= #1 0;
txstate <= #1 UART_IDLE; txstate <= #1 UART_IDLE;
txbitssent <= #1 0; txbitssent <= #1 0;
end else if ((txstate == UART_IDLE) & txsrfull) begin // start transmitting end else if ((txstate == UART_IDLE) & txsrfull) begin // start transmitting
txstate <= #1 UART_ACTIVE; txstate <= #1 UART_ACTIVE;
txoversampledcnt <= #1 1; txoversampledcnt <= #1 1;
txbitssent <= #1 0; txbitssent <= #1 0;
end else if (txbaudpulse & (txstate == UART_ACTIVE)) begin end else if (txbaudpulse & (txstate == UART_ACTIVE)) begin
txoversampledcnt <= #1 txoversampledcnt + 1; txoversampledcnt <= #1 txoversampledcnt + 1;
if (txnextbit) begin // transmit at end of phase if (txnextbit) begin // transmit at end of phase
@ -390,11 +396,12 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
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 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? // *** explain; is this necessary?
if (QEMU) assign txnextbit = txbaudpulse & (txoversampledcnt[1:0] == 2'b00); // implies txstate = UART_ACTIVE 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 else assign txnextbit = txbaudpulse & (txoversampledcnt == 4'b0000); // implies txstate = UART_ACTIVE
/////////////////////////////////////////// ///////////////////////////////////////////
// transmit holding register, shift register, FIFO // transmit holding register, shift register, FIFO
/////////////////////////////////////////// ///////////////////////////////////////////
always_comb begin // compute value for parity and tx holding register always_comb begin // compute value for parity and tx holding register
nexttxdata = fifoenabled ? txfifo[txfifotail] : TXHR; // pick from FIFO or holding register nexttxdata = fifoenabled ? txfifo[txfifotail] : TXHR; // pick from FIFO or holding register
case (LCR[1:0]) // compute parity from appropriate number of bits case (LCR[1:0]) // compute parity from appropriate number of bits
@ -426,9 +433,9 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
if (~MEMWb & A == 3'b000 & ~DLAB) begin // writing transmit holding register or fifo if (~MEMWb & A == 3'b000 & ~DLAB) begin // writing transmit holding register or fifo
if (fifoenabled) begin if (fifoenabled) begin
txfifo[txfifohead] <= #1 Din; txfifo[txfifohead] <= #1 Din;
txfifohead <= #1 txfifohead + 1; txfifohead <= #1 txfifohead + 1;
end else begin end else begin
TXHR <= #1 Din; TXHR <= #1 Din;
txhrfull <= #1 1; txhrfull <= #1 1;
end end
$write("%c",Din); // for testbench $write("%c",Din); // for testbench
@ -436,12 +443,12 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
if (txstate == UART_IDLE) begin // move data into tx shift register if available if (txstate == UART_IDLE) begin // move data into tx shift register if available
if (fifoenabled) begin if (fifoenabled) begin
if (~txfifoempty & ~txsrfull) begin if (~txfifoempty & ~txsrfull) begin
txsr <= #1 txdata; txsr <= #1 txdata;
txfifotail <= #1 txfifotail+1; txfifotail <= #1 txfifotail+1;
txsrfull <= #1 1; txsrfull <= #1 1;
end end
end else if (txhrfull) begin end else if (txhrfull) begin
txsr <= #1 txdata; txsr <= #1 txdata;
txhrfull <= #1 0; txhrfull <= #1 0;
txsrfull <= #1 1; txsrfull <= #1 1;
end end
@ -470,13 +477,13 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
HeadPointerLastMove <= 1'b0; HeadPointerLastMove <= 1'b0;
end end
assign txfifoempty = (txfifohead == txfifotail) & ~HeadPointerLastMove; assign txfifoempty = (txfifohead == txfifotail) & ~HeadPointerLastMove;
// verilator lint_off WIDTH // verilator lint_off WIDTH
assign txfifoentries = (txfifohead >= txfifotail) ? (txfifohead-txfifotail) : assign txfifoentries = (txfifohead >= txfifotail) ? (txfifohead-txfifotail) :
(txfifohead + 16 - txfifotail); (txfifohead + 16 - txfifotail);
// verilator lint_on WIDTH // verilator lint_on WIDTH
//assign txfifofull = (txfifoentries == 4'b1111); //assign txfifofull = (txfifoentries == 4'b1111);
assign txfifofull = (txfifohead == txfifotail) & HeadPointerLastMove; assign txfifofull = (txfifohead == txfifotail) & HeadPointerLastMove;
// transmit buffer ready bit // transmit buffer ready bit
always_ff @(posedge PCLK, negedge PRESETn) // track txrdy for DMA mode (FCR3 = FCR0 = 1) always_ff @(posedge PCLK, negedge PRESETn) // track txrdy for DMA mode (FCR3 = FCR0 = 1)
@ -490,11 +497,12 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
// Transmitter pin // Transmitter pin
assign SOUTbit = txsr[11]; // transmit most significant bit assign SOUTbit = txsr[11]; // transmit most significant bit
assign SOUT = loop ? 1 : (LCR[6] ? 0 : SOUTbit); // tied to 1 during loopback or 0 during break assign SOUT = loop ? 1 : (LCR[6] ? 0 : SOUTbit); // tied to 1 during loopback or 0 during break
/////////////////////////////////////////// ///////////////////////////////////////////
// interrupts // interrupts
/////////////////////////////////////////// ///////////////////////////////////////////
assign RXerr = |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 RXerrIP = RXerr & ~squashRXerrIP; // intr squashed upon reading LSR
assign rxdataavailintr = fifoenabled ? rxfifotriggered : rxdataready; assign rxdataavailintr = fifoenabled ? rxfifotriggered : rxdataready;
@ -533,15 +541,15 @@ module uartPC16550D #(parameter UART_PRESCALE, QEMU) (
// modem control logic // modem control logic
/////////////////////////////////////////// ///////////////////////////////////////////
assign loop = MCR[4]; assign loop = MCR[4];
assign DTRb = ~MCR[0] | loop; // disable modem signals in loopback mode assign DTRb = ~MCR[0] | loop; // disable modem signals in loopback mode
assign RTSb = ~MCR[1] | loop; assign RTSb = ~MCR[1] | loop;
assign OUT1b = ~MCR[2] | loop; assign OUT1b = ~MCR[2] | loop;
assign OUT2b = ~MCR[3] | loop; assign OUT2b = ~MCR[3] | loop;
assign DLAB = LCR[7]; assign DLAB = LCR[7];
assign evenparitysel = LCR[4]; assign evenparitysel = LCR[4];
assign fifoenabled = FCR[0]; assign fifoenabled = FCR[0];
assign fifodmamodesel = FCR[3]; assign fifodmamodesel = FCR[3];
always_comb always_comb
case (FCR[7:6]) case (FCR[7:6])