Edge sensitive IRQ on UART
[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_done,
30
31         input [7:0] tx_data,
32         input tx_wr,
33         output reg tx_done
34 );
35
36 //-----------------------------------------------------------------
37 // enable16 generator
38 //-----------------------------------------------------------------
39 reg [15:0] enable16_counter;
40
41 wire enable16;
42 assign enable16 = (enable16_counter == 16'd0);
43
44 always @(posedge sys_clk) begin
45         if(sys_rst)
46                 enable16_counter <= divisor - 16'b1;
47         else begin
48                 enable16_counter <= enable16_counter - 16'd1;
49                 if(enable16)
50                         enable16_counter <= divisor - 16'b1;
51         end
52 end
53
54 //-----------------------------------------------------------------
55 // Synchronize uart_rxd
56 //-----------------------------------------------------------------
57 reg uart_rxd1;
58 reg uart_rxd2;
59
60 always @(posedge sys_clk) begin
61         uart_rxd1 <= uart_rxd;
62         uart_rxd2 <= uart_rxd1;
63 end
64
65 //-----------------------------------------------------------------
66 // UART RX Logic
67 //-----------------------------------------------------------------
68 reg rx_busy;
69 reg [3:0] rx_count16;
70 reg [3:0] rx_bitcount;
71 reg [7:0] rxd_reg;
72
73 always @(posedge sys_clk) begin
74         if(sys_rst) begin
75                 rx_done <= 1'b0;
76                 rx_busy <= 1'b0;
77                 rx_count16  <= 4'd0;
78                 rx_bitcount <= 4'd0;
79         end else begin
80                 rx_done <= 1'b0;
81
82                 if(enable16) begin
83                         if(~rx_busy) begin // look for start bit
84                                 if(~uart_rxd2) begin // start bit found
85                                         rx_busy <= 1'b1;
86                                         rx_count16 <= 4'd7;
87                                         rx_bitcount <= 4'd0;
88                                 end
89                         end else begin
90                                 rx_count16 <= rx_count16 + 4'd1;
91
92                                 if(rx_count16 == 4'd0) begin // sample
93                                         rx_bitcount <= rx_bitcount + 4'd1;
94
95                                         if(rx_bitcount == 4'd0) begin // verify startbit
96                                                 if(uart_rxd2)
97                                                         rx_busy <= 1'b0;
98                                         end else if(rx_bitcount == 4'd9) begin
99                                                 rx_busy <= 1'b0;
100                                                 if(uart_rxd2) begin // stop bit ok
101                                                         rx_data <= rxd_reg;
102                                                         rx_done <= 1'b1;
103                                                 end // ignore RX error
104                                         end else
105                                                 rxd_reg <= {uart_rxd2, rxd_reg[7:1]};
106                                 end
107                         end
108                 end
109         end
110 end
111
112 //-----------------------------------------------------------------
113 // UART TX Logic
114 //-----------------------------------------------------------------
115 reg tx_busy;
116 reg [3:0] tx_bitcount;
117 reg [3:0] tx_count16;
118 reg [7:0] txd_reg;
119
120 always @(posedge sys_clk) begin
121         if(sys_rst) begin
122                 tx_done <= 1'b0;
123                 tx_busy <= 1'b0;
124                 uart_txd <= 1'b1;
125         end else begin
126                 if(tx_wr) begin
127                         txd_reg <= tx_data;
128                         tx_bitcount <= 4'd0;
129                         tx_count16 <= 4'd1;
130                         tx_busy <= 1'b1;
131                         uart_txd <= 1'b0;
132 `ifdef SIMULATION
133                         $display("UART: %c", tx_data);
134 `endif
135                 end else if(enable16 && tx_busy) begin
136                         tx_count16  <= tx_count16 + 4'd1;
137
138                         if(tx_count16 == 4'd0) begin
139                                 tx_bitcount <= tx_bitcount + 4'd1;
140                                 
141                                 if(tx_bitcount == 4'd8) begin
142                                         uart_txd <= 1'b1;
143                                 end else if(tx_bitcount == 4'd9) begin
144                                         uart_txd <= 1'b1;
145                                         tx_busy  <= 1'b0;
146                                 end else begin
147                                         uart_txd <= txd_reg[0];
148                                         txd_reg  <= {1'b0, txd_reg[7:1]};
149                                 end
150                         end
151                 end
152         end
153 end
154
155 endmodule