1f6fda0330076c285313c2a6cc38bc89b1bab0e0
[mw/milkymist.git] / cores / uart / rtl / uart_transceiver.v
1 /*
2  * Milkymist VJ SoC
3  * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
4  * Copyright (C) 2007 Das Labor
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 3 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 module uart_transceiver(
20         input sys_rst,
21         input sys_clk,
22
23         input uart_rxd,
24         output reg uart_txd,
25
26         input [15:0] divisor,
27
28         output reg [7:0] rx_data,
29         output reg rx_avail,
30         output reg rx_error,
31         input rx_ack,
32         input [7:0] tx_data,
33         input tx_wr,
34         output reg tx_busy
35 );
36
37 //-----------------------------------------------------------------
38 // enable16 generator
39 //-----------------------------------------------------------------
40 reg [15:0] enable16_counter;
41
42 wire    enable16;
43 assign  enable16 = (enable16_counter == 16'd0);
44
45 always @(posedge sys_clk) begin
46         if(sys_rst)
47                 enable16_counter <= divisor - 16'b1;
48         else begin
49                 enable16_counter <= enable16_counter - 16'd1;
50                 if(enable16)
51                         enable16_counter <= divisor - 16'b1;
52         end
53 end
54
55 //-----------------------------------------------------------------
56 // Synchronize uart_rxd
57 //-----------------------------------------------------------------
58 reg uart_rxd1;
59 reg uart_rxd2;
60
61 always @(posedge sys_clk) begin
62         uart_rxd1 <= uart_rxd;
63         uart_rxd2 <= uart_rxd1;
64 end
65
66 //-----------------------------------------------------------------
67 // UART RX Logic
68 //-----------------------------------------------------------------
69 reg       rx_busy;
70 reg [3:0] rx_count16;
71 reg [3:0] rx_bitcount;
72 reg [7:0] rxd_reg;
73
74 always @(posedge sys_clk) begin
75         if(sys_rst) begin
76                 rx_busy     <= 1'd0;
77                 rx_count16  <= 4'd0;
78                 rx_bitcount <= 4'd0;
79                 rx_avail    <= 1'd0;
80                 rx_error    <= 1'd0;
81         end else begin
82                 if(rx_ack) begin
83                         rx_avail <= 1'd0;
84                         rx_error <= 1'd0;
85                 end
86
87                 if(enable16) begin
88                         if(!rx_busy) begin // look for start bit
89                                 if(!uart_rxd2) begin // start bit found
90                                         rx_busy     <= 1'd1;
91                                         rx_count16  <= 4'd7;
92                                         rx_bitcount <= 4'd0;
93                                 end
94                         end else begin
95                                 rx_count16 <= rx_count16 + 4'd1;
96
97                                 if(rx_count16 == 4'd0) begin // sample
98                                         rx_bitcount <= rx_bitcount + 4'd1;
99
100                                         if(rx_bitcount == 4'd0) begin // verify startbit
101                                                 if(uart_rxd2)
102                                                         rx_busy <= 1'd0;
103                                         end else if(rx_bitcount == 4'd9) begin // look for stop bit
104                                                 rx_busy <= 1'd0;
105                                                 if(uart_rxd2) begin // stop bit ok
106                                                         rx_data  <= rxd_reg;
107                                                         rx_avail <= 4'd1;
108                                                         rx_error <= 1'd0;
109                                                 end else begin // bad stop bit
110                                                         rx_error <= 1'd1;
111                                                 end
112                                         end else begin
113                                                 rxd_reg <= {uart_rxd2, rxd_reg[7:1]};
114                                         end
115                                 end
116                         end 
117                 end
118         end
119 end
120
121 //-----------------------------------------------------------------
122 // UART TX Logic
123 //-----------------------------------------------------------------
124 reg [3:0] tx_bitcount;
125 reg [3:0] tx_count16;
126 reg [7:0] txd_reg;
127
128 always @(posedge sys_clk) begin
129         if(sys_rst) begin
130                 tx_busy     <= 1'd0;
131                 uart_txd    <= 1'd1;
132         end else begin
133                 if(tx_wr && !tx_busy) begin
134                         txd_reg     <= tx_data;
135                         tx_bitcount <= 4'd0;
136                         tx_count16  <= 4'd1;
137                         tx_busy     <= 1'd1;
138                         uart_txd    <= 1'd0;
139 `ifdef SIMULATION
140                         $display("UART: %c", tx_data);
141 `endif
142                 end else if(enable16 && tx_busy) begin
143                         tx_count16  <= tx_count16 + 4'd1;
144
145                         if(tx_count16 == 4'd0) begin
146                                 tx_bitcount <= tx_bitcount + 4'd1;
147                                 
148                                 if(tx_bitcount == 4'd8) begin
149                                         uart_txd <= 1'b1;
150                                 end else if(tx_bitcount == 4'd9) begin
151                                         uart_txd <= 1'b1;
152                                         tx_busy  <= 1'b0;
153                                 end else begin
154                                         uart_txd <= txd_reg[0];
155                                         txd_reg  <= {1'b0, txd_reg[7:1]};
156                                 end
157                         end
158                 end
159         end
160 end
161
162 endmodule