// // 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