uart.v
module uart #( parameter clk_freq = 50000000, parameter baud = 9600 ) ( input sys_clk, input sys_rst, output rx_irq, output tx_irq, input uart_rx, output uart_tx ); wire [7:0] rx_data; reg [7:0] tx_data; reg tx_wr; always @(posedge sys_clk) begin if (rx_irq) begin tx_data <= rx_data; tx_wr <= 1'b1; end else begin tx_wr <= 1'b0; end end uart_transceiver transceiver( .sys_clk(sys_clk), .sys_rst(sys_rst), .uart_rx(uart_rx), .uart_tx(uart_tx), .divisor(clk_freq/baud/16), .rx_data(rx_data), .rx_done(rx_irq), .tx_data(tx_data), .tx_wr(tx_wr), .tx_done(tx_irq) ); endmodule
uart_transceiver.v
/*
* Milkymist VJ SoC * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq * Copyright (C) 2007 Das Labor * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ module uart_transceiver( input sys_rst, input sys_clk, input uart_rx, output reg uart_tx, input [15:0] divisor, output reg [7:0] rx_data, output reg rx_done, input [7:0] tx_data, input tx_wr, output reg tx_done ); //----------------------------------------------------------------- // enable16 generator //----------------------------------------------------------------- reg [15:0] enable16_counter; wire enable16; assign enable16 = (enable16_counter == 16'd0); always @(posedge sys_clk) begin if(sys_rst) enable16_counter <= divisor - 16'b1; else begin enable16_counter <= enable16_counter - 16'd1; if(enable16) enable16_counter <= divisor - 16'b1; end end //----------------------------------------------------------------- // Synchronize uart_rx //----------------------------------------------------------------- reg uart_rx1; reg uart_rx2; always @(posedge sys_clk) begin uart_rx1 <= uart_rx; uart_rx2 <= uart_rx1; end //----------------------------------------------------------------- // UART RX Logic //----------------------------------------------------------------- reg rx_busy; reg [3:0] rx_count16; reg [3:0] rx_bitcount; reg [7:0] rx_reg; always @(posedge sys_clk) begin if(sys_rst) begin rx_done <= 1'b0; rx_busy <= 1'b0; rx_count16 <= 4'd0; rx_bitcount <= 4'd0; end else begin rx_done <= 1'b0; if(enable16) begin if(~rx_busy) begin // look for start bit if(~uart_rx2) begin // start bit found rx_busy <= 1'b1; rx_count16 <= 4'd7; rx_bitcount <= 4'd0; end end else begin rx_count16 <= rx_count16 + 4'd1; if(rx_count16 == 4'd0) begin // sample rx_bitcount <= rx_bitcount + 4'd1; if(rx_bitcount == 4'd0) begin // verify startbit if(uart_rx2) rx_busy <= 1'b0; end else if(rx_bitcount == 4'd9) begin rx_busy <= 1'b0; if(uart_rx2) begin // stop bit ok rx_data <= rx_reg; rx_done <= 1'b1; end // ignore RX error end else rx_reg <= {uart_rx2, rx_reg[7:1]}; end end end end end //----------------------------------------------------------------- // UART TX Logic //----------------------------------------------------------------- reg tx_busy; reg [3:0] tx_bitcount; reg [3:0] tx_count16; reg [7:0] tx_reg; always @(posedge sys_clk) begin if(sys_rst) begin tx_done <= 1'b0; tx_busy <= 1'b0; uart_tx <= 1'b1; end else begin tx_done <= 1'b0; if(tx_wr) begin tx_reg <= tx_data; tx_bitcount <= 4'd0; tx_count16 <= 4'd1; tx_busy <= 1'b1; uart_tx <= 1'b0; `ifdef SIMULATION $display("UART:Â %c", tx_data); `endif end else if(enable16 && tx_busy) begin tx_count16 <= tx_count16 + 4'd1; if(tx_count16 == 4'd0) begin tx_bitcount <= tx_bitcount + 4'd1; if(tx_bitcount == 4'd8) begin uart_tx <= 1'b1; end else if(tx_bitcount == 4'd9) begin uart_tx <= 1'b1; tx_busy <= 1'b0; tx_done <= 1'b1; end else begin uart_tx <= tx_reg[0]; tx_reg <= {1'b0, tx_reg[7:1]}; end end end end end endmodule