123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- //
- // 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).
- //
- // Currently there is no overrun checking or interrupt support, but that
- // can come later. A large FIFO makes that less of an issue anyway...
- //
- module tty (
- input rst_n,
- input sys_clk,
- input tty_clk,
- input valid,
- input [3:0] wstrb,
- input [31:0] wdata,
- input [0:0] addr,
- output tty_txd
- );
- `include "functions.sv" // For ModelSim
-
- //
- // Baud rate generator; produces a clock enable synchronous
- // with tty_clk
- //
- parameter [31:0] BAUDRATE = 115200;
- parameter [31:0] TTY_CLK = 48000000;
- localparam divisor_bits = 16;
-
- reg [divisor_bits-1:0] divisor_q = round_div(TTY_CLK, BAUDRATE << 4) - 1;
- wire [divisor_bits-1:0] divisor;
- reg [divisor_bits-1:0] clk_div;
- reg tty_clk_en; // tty clock tick (clock enable)
- always @(negedge rst_n or posedge tty_clk)
- if (~rst_n)
- begin
- clk_div <= 16; // Give enough time for synchronizer
- tty_clk_en <= 1'b0;
- end
- else
- begin
- if (~|clk_div)
- begin
- clk_div <= divisor;
- tty_clk_en <= 1'b1;
- end
- else
- begin
- clk_div <= clk_div - 1'b1;
- tty_clk_en <= 1'b0;
- end
- end // else: !if(~rst_n)
- //
- // Tx FIFO
- //
- reg tx_rdack;
- wire tx_wrreq;
- wire tx_rdempty;
- wire [7:0] tx_data;
-
- fifo txfifo (
- .aclr ( ~rst_n ),
- .data ( wdata ),
- .q ( tx_data ),
- .rdclk ( tty_clk ),
- .rdreq ( tx_rdack ),
- .wrclk ( sys_clk ),
- .wrreq ( tx_wrreq ),
- .rdempty ( tx_rdempty ),
- .rdusedw ( ),
- .wrfull ( ),
- .wrusedw ( )
- );
- //
- // CPU -> transmitter data. No wait state is needed nor expected.
- //
- // Data mask (if/when needed)
- wire [31:0] wmask = {{8{wstrb[3]}}, {8{wstrb[2]}},
- {8{wstrb[1]}}, {8{wstrb[0]}}};
- // Data (FIFO) register; normally addressed as byte
- // Protect against long pulses (edge detect)
- reg old_wstrb;
- always @(posedge sys_clk)
- old_wstrb <= wstrb[0];
- assign tx_wrreq = valid & wstrb[0] & ~old_wstrb & (addr == 0);
- // Divisor register
- always @(posedge sys_clk)
- if (wstrb[0] & valid & (addr == 1))
- divisor_q <= wdata[divisor_bits-1:0] & wmask;
- synchronizer #(.width(divisor_bits), .stages(2)) sync_divisor
- (
- .rst_n ( rst_n ),
- .clk ( tty_clk ),
- .d ( divisor_q ),
- .q ( divisor )
- );
- //
- // 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 tty_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)
- endmodule // tty
|