166 lines
3.9 KiB
Verilog
166 lines
3.9 KiB
Verilog
/*
|
||
* Milkymist 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,
|
||
|
||
output reg break
|
||
);
|
||
|
||
//-----------------------------------------------------------------
|
||
// 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 uart_rx_r;
|
||
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;
|
||
break <= 1'b0;
|
||
uart_rx_r <= 1'b0;
|
||
end else begin
|
||
rx_done <= 1'b0;
|
||
break <= 1'b0;
|
||
|
||
if(enable16) begin
|
||
uart_rx_r <= uart_rx2;
|
||
if(~rx_busy) begin // look for start bit
|
||
if(~uart_rx2 & uart_rx_r) 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 else if(rx_reg == 8'h00) // break condition
|
||
break <= 1'b1;
|
||
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
|