| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 | //// Simple serial port.//// The transmission rate is fixed to 1 Mbps.//// If the output FIFO is full, an output signal is asserted, which// is expected to be used together with DTR to provide blocking I/O// if desired.//module serial  #(    parameter logic  ENABLE_RX_DATA    = 1'b1,    parameter logic  ENABLE_RX_BREAK   = 1'b1,    parameter logic  ENABLE_TX_DATA    = 1'b1,    parameter logic  ENABLE_TX_BREAK   = 1'b1,    parameter logic  BAUDRATE_SETTABLE = 1'b0,    parameter [31:0] BAUDRATE          = 115200,    parameter [31:0] TTY_CLK           = 84000000,    parameter        NCO_BITS          = 24,    parameter        BREAK_BITS        = 16 // Bit times for BREAK detect    )   (    input tri1	  rst_n,    input	  clk,    output	  tty_tx,    input	  tty_rx,    input	  tx_wstrb,    input [7:0]   tx_data,    input	  tx_break, // BREAK is asserted as long as this is true    output	  tx_full,    output	  tx_empty,    input tri0	  tx_flush,    input	  rx_rstrb,    output [7:0]  rx_data,    output	  rx_break,    output	  rx_full,    output	  rx_empty,    input tri0	  rx_flush,    input [31:0]  divisor_wdata, // If divisor is settable    input tri0	  divisor_wstrb,    output [31:0] divisor    );   `include "functions.sv"	// For ModelSim   //   // Baud rate generator; produces a clock enable synchronous   // with clk.  This is based on a numerically controlled oscillator   // (NCO); the baudrate is given as a binary fraction of the input   // clock rate divided by the oversampling rate (16); for practical   // reasons represented minus one LSB so 0x0.ffffff -> 1   // and 0 -> 0x0.000001.   //   // The term "divisor" here is probably misleading, since it is   // actually a fixed-point *multiplier* which is <= 1.   //   localparam [NCO_BITS-1:0] default_divisor =		  round_div(BAUDRATE << NCO_BITS, TTY_CLK >> 4) - 1'b1;   reg  [NCO_BITS-1:0]	divisor_q = default_divisor;   reg  [NCO_BITS-1:0]  nco_q;   reg			tty_clk_en; // tty clock tick (clock enable)   assign divisor = divisor_q;   always @(posedge clk)     { tty_clk_en, nco_q } <= nco_q + divisor_q + 1'b1;   always @(negedge rst_n or posedge clk)     if (~rst_n)       divisor_q <= default_divisor;     else if ( BAUDRATE_SETTABLE & divisor_wstrb )       divisor_q <= divisor_wdata[NCO_BITS-1:0];   //   // **** Transmitter section ****   //   reg		tx_rdack;   wire [7:0]	tx_out_data;   //   // FIFO   //   generate if (ENABLE_TX_DATA)     begin	//	// Tx FIFO	//	reg tx_wstrb_q;	always @(negedge rst_n or posedge clk)	  if (~rst_n)	    tx_wstrb_q <= 1'b0;	  else	    tx_wstrb_q <= tx_wstrb;	fifo txfifo (		     .aclr ( ~rst_n ),		     .clock ( clk ),		     .data ( tx_data ),		     .wrreq ( tx_wstrb & ~tx_wstrb_q ),		     .sclr ( tx_flush ),		     .empty ( tx_empty ),		     .full ( tx_full ),		     .rdreq ( tx_rdack ),		     .q ( tx_out_data ),		     .usedw ( )		     );     end // if (ENABLE_TX_DATA)   else     begin	assign tx_empty    = 1'b1;	assign tx_full     = 1'b1;	assign tx_out_data = 8'hxx;     end   endgenerate   //   // Transmitter   //   generate if (ENABLE_TX_DATA | ENABLE_TX_BREAK)     begin	reg [3:0] tx_phase;	reg [3:0] tx_ctr;	reg [9:0] tx_sr = ~10'b0;	reg	  tx_sending_break;	always @(negedge rst_n or posedge clk)	  if (~rst_n)	    begin	       tx_phase <= 4'h0;	       tx_ctr  <= 'd0;	       tx_sr    <= 10'h3ff;	// Line idle	       tx_rdack <= 1'b0;	       tty_tx   <= 1'b1;	       tx_sending_break <= 1'b0;	    end	  else	    begin	       tx_rdack <= 1'b0;	       tty_tx   <= tx_sr[0] & ~tx_sending_break;	       if ( tty_clk_en )		 begin		    tx_phase <= tx_phase + 1'b1;		    if (&tx_phase)		      begin			 tx_sr[8:0] <= tx_sr[9:1];			 tx_sr[9]   <= 1'b1; // Stop bit/idle			 if (|tx_ctr)			   begin			      tx_ctr <= tx_ctr - 1'b1;			   end			 else if ( ENABLE_TX_BREAK &				   (tx_break | tx_sending_break) )			   begin			      // Make sure we get an idle bit after break			      tx_sending_break <= tx_break;			   end			 else if ( ~tx_empty )			   begin			      tx_sr[9:2] <= tx_out_data;			      tx_sr[1]   <= 1'b0; // Start bit			      // 10 = start bit + data + stop bit			      tx_ctr     <= 'd10;			      tx_rdack   <= 1'b1; // Remove from FIFO			   end		      end // if (tx_phase == 4'hF)		 end // if ( tty_clk_en )	    end // else: !if(~rst_n)     end // if (ENABLE_TX_DATA | ENABLE_TX_BREAK)   else     begin	assign tty_tx = 1'b1;     end // else: !if(ENABLE_TX_DATA | ENABLE_TX_BREAK)   endgenerate   //   // **** Receiver section ****   //   //   // Bit phase counter   //   generate if (ENABLE_RX_DATA | ENABLE_RX_BREAK)     begin	reg [3:0] rx_phase;	reg	  rx_phase_start = 1'b0;	always @(negedge rst_n or posedge clk)	  if (~rst_n)	    rx_phase <= 4'b0;	  else if ( rx_phase_start )	    rx_phase <= 4'h8;	// Start bit flank detected	  else	    rx_phase <= rx_phase + tty_clk_en;     end // if (ENABLE_RX_DATA | ENABLE_RX_BREAK)   endgenerate   //   // BREAK detect   //   generate if (ENABLE_RX_BREAK)     begin	reg  [BREAK_BITS-1:0] rx_break_ctr;	wire [BREAK_BITS:0]   rx_break_ctr_next = rx_break_ctr + 1'b1;	always @(negedge rst_n or posedge clk)	  if (~rst_n)	    begin	       rx_break_ctr <= 'b0;	       rx_break     <= 1'b0;	    end	  else	    begin	       if ( tty_clk_en )		 begin		    if ( tty_rx )		      begin			 // Rx high = not a break			 rx_break_ctr <= 'b0;			 rx_break     <= 1'b0;		      end		    else if ( &rx_phase )		      begin			 rx_break_ctr <= rx_break_ctr_next;			 rx_break     <= rx_break | rx_break_ctr_next[BREAK_BITS];		      end // else: !if(tty_rxd)		 end // if ( tty_clk_en )	    end // else: !if(~rst_n)     end // if (ENABLE_RX_BREAK)   else     begin	assign rx_break = 1'b0;     end   endgenerate   //   // Data receive   //   generate if (ENABLE_RX_DATA)     begin	reg rx_recv_strb;	reg rx_rstrb_q;	fifo rxfifo (		     .aclr ( ~rst_n ),		     .clock ( clk ),		     .rdreq ( ~rx_rstrb & rx_rstrb_q ), // Advance after read		     .q ( rx_data ),		     .sclr ( rx_flush ),		     .empty ( rx_empty ),		     .full ( rx_full ),		     .wrreq ( rx_recv_strb ),		     .data ( rx_sr ),		     .usedw ( )		     );	reg [3:0] rx_ctr;	reg [2:0] rx_bits;	reg [7:0] rx_sr;	reg	  tty_clk_en_q;	always @(negedge rst_n or posedge clk)	  if (~rst_n)	    begin	       rx_ctr         <= 4'b0;	       rx_bits        <= 3'b111;	       rx_sr          <= 8'hxx;	       tty_clk_en_q   <= 1'b0;	       rx_rstrb_q      <= 1'b0;	       rx_recv_strb    <= 1'b0;	       rx_phase_start <= 1'b0;	    end	  else	    begin	       rx_rstrb_q    <= rx_rstrb;	       tty_clk_en_q <= tty_clk_en;	       rx_recv_strb  <= 1'b0;	       if ( tty_clk_en )		 rx_bits <= { rx_bits[1:0], tty_rx };	       if ( tty_clk_en_q )		 begin		    if ( !rx_ctr )		      begin			 if ( rx_bits == 3'b100 )			   begin			      rx_ctr <= 4'd10;			      rx_phase_start <= 1'b1;			   end		      end		    else if ( !rx_phase )		      begin			 rx_sr[6:0] <= rx_sr[7:1];			 // Majority vote of three samples			 rx_sr[7] <= (rx_bits[1] & rx_bits[0]) |				     (rx_bits[2] & rx_bits[0]) |				     (rx_bits[2] & rx_bits[1]);			 rx_ctr <= rx_ctr - 1'b1;			 // Push to FIFO if this was the bit before stop			 rx_recv_strb <= rx_ctr == 4'd2;		      end // if ( &rx_phase )		 end // if ( tty_clk_en_q )	    end // else: !if(~rst_n)     end // if (ENABLE_RX_DATA)   endgenerateendmodule // serial
 |