123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- //
- // Serial port "snoop" of the console (otherwise sent via USB.)
- //
- // The only receive support is BREAK.
- //
- // 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 (
- input rst_n,
- input clk,
- input tx_valid,
- input [7:0] tx_data,
- input tty_rx,
- output tty_tx,
- output reg rx_break,
- output tx_full
- );
- `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 = 921600;
- parameter [31:0] TTY_CLK = 84000000;
- parameter NCO_BITS = 24;
- parameter BREAK_BITS = 19; // 2^19/(BAUDRATE*16) ~ 33 ms
- 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_out_data;
- reg tx_valid_q;
- always @(negedge rst_n or posedge clk)
- if (~rst_n)
- tx_valid_q <= 1'b0;
- else
- tx_valid_q <= tx_valid;
- fifo txfifo (
- .aclr ( ~rst_n ),
- .clock ( clk ),
- .data ( tx_data ),
- .rdreq ( tx_rdack ),
- .sclr ( 1'b0 ), // Flush FIFO command
- .wrreq ( tx_valid & ~tx_valid_q ),
- .empty ( tx_rdempty ),
- .full ( tx_full ),
- .q ( tx_out_data ),
- .usedw ( )
- );
- //
- // Transmitter
- //
- reg [3:0] tx_phase;
- reg [3:0] tx_bits;
- reg [9:0] tx_sr = ~10'b0; // Shift register
- assign tty_tx = 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_out_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)
- //
- // BREAK detect
- //
- 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
- begin
- rx_break_ctr <= rx_break_ctr_next[BREAK_BITS-1:0];
- 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)
-
- endmodule // serial
|