/* * Ben's attempt at doing a UART in verilog ... everybody hide ! * * 3 modules: * * - uart_clk : This provides the clock strobes for Tx and Rx * - uart_tx : Transmit side * - uart_rx : Receive side */ /* * Divided clock pulses * * The divider argument must be set so that sysclk/clkdiv is * 4x the bit clock. * * The output pulses are 1-sysclk wide pulses. */ module uart_clk(sysclk, reset, clkdiv, tick); parameter div_width = 16; input sysclk; input reset; input [div_width-1:0] clkdiv; output tick; /* sclk is our fastest clock enable, used to sample bits */ reg [div_width-1:0] cnt; assign tick = (cnt[div_width-1 : 0] == 0); always @(posedge reset or posedge sysclk) begin if (reset) begin cnt <= clkdiv; end else begin cnt <= cnt - 1; if (tick) begin cnt <= clkdiv; end end end endmodule /* * Tx side * * TODO: Add a tx_done that rises when stop bit is all the way out ? Right now * tx_busy goes down as soon as we start sending it, which mean we can latch the * next character and thus send back-to-back without delay, but some * applications might have some use for knowing when the send is really * complete */ module uart_tx(clk, reset, tick, tx, tx_byte, tx_kick, tx_busy ); input clk; input reset; input tick; output tx; output tx_busy; input [7:0] tx_byte; input tx_kick; /* Our tx state machine. We have a main state and a sample * counter */ reg tx_busy; reg [1:0] tx_scnt; reg [9:0] tx_shift; reg tx; /* Pulse every four clock to get our bit clock */ wire tx_strobe = (tick && tx_scnt == 2'b00); /* We are finished when the 10-bit shift register contains only * one '1' bit at the bottom, ie, the stop bit went all the way */ wire tx_done = (tx_shift == 10'b0_0000_0000_1); /* Sub-bit counter: for the sake of Rx, our clock is 4x the baud * rate so we use this counter to divide it by 4 */ always @(posedge reset or posedge clk) begin if (reset) begin tx_scnt <= 2'b00; end else if (tick) begin tx_scnt <= tx_scnt + 1; end end /* Busy bit. Goes up as soon as we sample data, goes down when * we have started sending the stop bit (ie, tx_done is 1 and * we have a bit strobe). We can latch a new byte one sys clock * after that. */ always @(posedge reset or posedge clk) begin if (reset) begin tx_busy <= 1'b0; end else if (!tx_busy && tx_kick) begin tx_busy <= 1'b1; end else if (tx_done && tx_strobe) begin tx_busy <= 1'b0; end end /* Shift register. We latch the incoming char with the start and * stop bit, and we feed 0's at the bottom */ always @(posedge reset or posedge clk) begin if (reset) begin tx_shift <= 10'b0_0000_0000_0; end else if (tx_strobe && tx_busy) begin tx_shift[9:0] <= { 1'b0, tx_shift[9:1] }; end else if (tx_kick && !tx_busy) begin tx_shift[9:0] <= { 1'b1, tx_byte[7:0], 1'b0 }; end end /* Tx line */ always @(posedge reset or posedge clk) begin if (reset) begin tx <= 1'b1; end else begin if (!tx_busy) begin tx <= 1'b1; end else if (tx_strobe) begin tx <= tx_shift[0]; end end end endmodule /* * Rx side * * Note: Initially oversampled by x16 but that wasn't terribly useful * since I really only did a half-bit stability check on the start * bit and then took a single sample at mid-bit. IE. No actual framing * error detection. * So I reduced that to x4, which is plenty enough for simple uses */ module uart_rx(clk, reset, tick, rx, rx_byte, rx_kick ); input clk; input reset; input tick; input rx; output [7:0] rx_byte; output rx_kick; /* Here's our 3 stage input buffer */ reg [2:0] rx_buf; always @(posedge(reset) or posedge clk) begin if (reset) begin rx_buf <= 3'b111; end else begin rx_buf[0] <= rx; rx_buf[1] <= rx_buf[0]; rx_buf[2] <= rx_buf[1]; end end /* Our rx state machine. We have a main state and a sample * counter */ reg [1:0] rx_state; parameter rx_state_idle = 2'b00; parameter rx_state_start = 2'b01; parameter rx_state_shift = 2'b10; reg [1:0] rx_scnt; reg [8:0] rx_shift; /* Set to 1 to shift a bit in */ wire rx_strobe = (tick && (rx_scnt == 2'b00)); /* Pulse when start bit reaches end of shift register */ wire rx_done = rx_strobe && !rx_shift[0]; /* Toplevel state machine */ always @(posedge reset or posedge clk) begin if (reset) begin rx_state <= rx_state_idle; end else if (rx_state == rx_state_idle) begin /* Wait for 1 -> 0 transition */ if (rx_buf[2] & !rx_buf[1]) begin rx_state <= rx_state_start; end end else if (rx_state == rx_state_start) begin /* Check for stable until half bit */ if (rx_buf[1]) begin rx_state <= rx_state_idle; end else if (rx_scnt[1]) begin rx_state <= rx_state_shift; end end else if (rx_state == rx_state_shift) begin if (rx_done) begin rx_state <= rx_state_idle; end end end /* Sub-bit counter */ always @(posedge reset or posedge clk) begin if (reset) begin rx_scnt <= 2'b00; end else if (rx_state == rx_state_idle || (rx_state == rx_state_start && rx_scnt[1])) begin rx_scnt <= 2'b00; end else if (tick) begin rx_scnt <= rx_scnt + 1; end end /* Shift register */ always @(posedge reset or posedge clk) begin if (reset) begin rx_shift <= 9'b1_1111_1111; end else if (rx_state != rx_state_shift) begin rx_shift <= 9'b1_1111_1111; end else if (rx_strobe && rx_shift[0]) begin rx_shift[8:0] <= { rx_buf[1], rx_shift[8:1]}; end end /* Output signals. rx_kick is strobed and delayed by 1 clk */ assign rx_byte[7:0] = rx_shift[8:1]; assign rx_kick = rx_done; endmodule