http://home.eeworld.com.cn/my/space-uid-210489-blogid-66899.html
- 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