| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 | //// Very simple asynchronous tty. Not really a "UART" since it isn't// very "universal". It doesn't have to be.//// Currently only transmit is supported, 8-N-1, at a fixed speed.// The baud rate is tty_clk/((divisor+1)*16).//// The registers are as follows://// 0 - WO - data register (will be RW)// 1 - RW - baud rate register (binary fraction of TTY_CLK/16 - 1)// 2 - RO - status register//          0 - transmitter idle (FIFO and shift register empty)//          1 - transmit FIFO 3/4 empty//	    2 - transmit FIFO 1/2 empty//          3 - transmit FIFO 1/2 full (inverse of bit 2)//          4 - transmit FIFO 3/4 full// 3 - RW - interrupt enable register (status register mask)module tty (	    input 	      rst_n,	    input 	      clk,	    input 	      valid,	    input [3:0]       wstrb,	    input [31:0]      wdata,	    input [1:0]       addr,	    output reg [31:0] rdata,	    output reg	      irq,	    output 	      tty_txd	    );   `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.   //   parameter [31:0]	BAUDRATE = 115200;   parameter [31:0]	TTY_CLK  = 84000000;   parameter		NCO_BITS = 24;      reg  [NCO_BITS-1:0]  divisor			= round_div(BAUDRATE << NCO_BITS, TTY_CLK >> 4) - 1'b1;   reg  [NCO_BITS-1:0]  nco_q;   reg 			tty_clk_en; // tty clock tick (clock enable)   always @(posedge clk)	{ tty_clk_en, nco_q } <= nco_q + divisor + 1'b1;   //   // Tx FIFO   //   reg  tx_rdack;   wire tx_wrreq;   wire tx_rdempty;   wire [7:0] tx_data;   wire [8:0] tx_usedw;      fifo txfifo (		.aclr ( ~rst_n ),		.clock ( clk ),		.data ( wdata ),		.rdreq ( tx_rdack ),		.sclr ( 1'b0 ),	// Flush FIFO command		.wrreq ( tx_wrreq ),		.empty ( tx_rdempty ),		.full ( ),		.q ( tx_data ),		.usedw ( tx_usedw )		);   //   // Transmitter   //   reg [3:0]  tx_phase;   reg [3:0]  tx_bits;   reg [9:0]  tx_sr = ~10'b0;		// Shift register   assign tty_txd = tx_sr[0];   always @(negedge rst_n or posedge clk)     if (~rst_n)       begin	  tx_phase <= 4'h0;	  tx_bits  <= 4'd0;	  tx_sr    <= ~10'b0;	// Line idle	  tx_rdack <= 1'b0;       end     else       begin	  tx_rdack <= 1'b0;	  if ( tty_clk_en )	    begin	       tx_phase <= tx_phase + 1'b1; 	       if (tx_phase == 4'hF)		 begin		    tx_sr[8:0] <= tx_sr[9:1];		    tx_sr[9]   <= 1'b1; // Stop bit/idle		    		    if (tx_bits == 4'd0)		      begin			 if ( ~tx_rdempty )			   begin			      tx_sr[9:2] <= tx_data;			      tx_sr[1]   <= 1'b0; // Start bit			      // 10 = start bit + data + stop bit			      tx_bits    <= 4'd10;			      tx_rdack   <= 1'b1; // Remove from FIFO			   end		      end		    else		      begin			 tx_bits <= tx_bits - 1'b1;		      end // else: !if(tx_bits == 4'd0)		 end // if (tx_phase == 4'hF)	    end // if ( tty_clk_en )       end // else: !if(~rst_n)   //   // CPU interface   //   // Data (FIFO) register; normally addressed as byte   // Protect against long pulses (edge detect)   reg old_wstrb;   always @(posedge clk)     old_wstrb <= wstrb[0];   assign tx_wrreq = valid & wstrb[0] & ~old_wstrb & (addr == 2'b00);   // Status register definition   localparam status_bits = 5;   wire [status_bits-1:0] status;   assign status[0] = tx_rdempty & (tx_bits == 4'd0);   assign status[1] = tx_usedw[8:7] == 2'b00;   assign status[2] = ~tx_usedw[8];   assign status[3] = tx_usedw[8];   assign status[4] = tx_usedw[8:7] == 2'b11;      reg [status_bits-1:0]  irq_en;   //   // Control register writes.   // Only full word writes are supported.   //   always @(negedge rst_n or posedge clk)     if (~rst_n)       begin	  irq_en <= 5'b0;       end     else if (valid & (&wstrb))       case (addr)	 2'b01: divisor <= wdata[NCO_BITS-1:0];	 2'b11: irq_en  <= wdata[status_bits-1:0];       endcase // case (addr)   // Read MUX   always @(*)     begin	rdata = 32'b0;	case (addr)	  2'b01:   rdata[NCO_BITS-1:0]    = divisor;	  2'b10:   rdata[status_bits-1:0] = status;	  2'b11:   rdata[status_bits-1:0] = irq_en;	  default: rdata = 32'b0;	endcase // case (addr)     end   // Interrupt   always @(negedge rst_n or posedge clk)     if (~rst_n)       irq <= 1'b0;     else       irq <= |(status & irq_en);   endmodule // tty
 |