5831f0571be84dc9b02543fa8535962f6a313d4b
[mw/milkymist.git] / cores / uart / rtl / uart.v
1 /*
2  * Milkymist VJ SoC
3  * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 module uart #(
19         parameter csr_addr = 4'h0,
20         parameter clk_freq = 100000000,
21         parameter baud = 115200
22 ) (
23         input sys_clk,
24         input sys_rst,
25         
26         input [13:0] csr_a,
27         input csr_we,
28         input [31:0] csr_di,
29         output reg [31:0] csr_do,
30
31         output rx_irq,
32         output tx_irq,
33
34         input uart_rxd,
35         output uart_txd
36 );
37
38 reg [15:0] divisor;
39
40 wire [7:0] rx_data;
41 wire rx_avail;
42 wire rx_error;
43 wire rx_ack;
44
45 wire [7:0] tx_data;
46 wire tx_wr;
47 wire tx_busy;
48
49 uart_transceiver transceiver(
50         .sys_clk(sys_clk),
51         .sys_rst(sys_rst),
52
53         .uart_rxd(uart_rxd),
54         .uart_txd(uart_txd),
55
56         .divisor(divisor),
57
58         .rx_data(rx_data),
59         .rx_avail(rx_avail),
60         .rx_error(rx_error),
61         .rx_ack(rx_ack),
62         
63         .tx_data(tx_data),
64         .tx_wr(tx_wr),
65         .tx_busy(tx_busy)
66 );
67
68 /* Generate tx_done signal */
69 wire tx_ack;
70 reg tx_busy_r;
71 reg tx_done;
72
73 always @(posedge sys_clk) begin
74         if(sys_rst) begin
75                 tx_busy_r <= 1'b0;
76                 tx_done <= 1'b0;
77         end else begin
78                 tx_busy_r <= tx_busy;
79                 if(tx_ack|tx_wr)
80                         tx_done <= 1'b0;
81                 if(tx_busy_r & ~tx_busy)
82                         tx_done <= 1'b1;
83         end
84 end
85
86 /* CSR interface */
87 wire csr_selected = csr_a[13:10] == csr_addr;
88
89 assign rx_ack = csr_selected & csr_we & (csr_a[1:0] == 2'b00) & csr_di[2];
90 assign tx_data = csr_di[7:0];
91 assign tx_wr = csr_selected & csr_we & (csr_a[1:0] == 2'b01);
92 assign tx_ack = csr_selected & csr_we & (csr_a[1:0] == 2'b00) & csr_di[5];
93
94 parameter default_divisor = clk_freq/baud/16;
95
96 always @(posedge sys_clk) begin
97         if(sys_rst) begin
98                 divisor <= default_divisor;
99                 csr_do <= 32'd0;
100         end else begin
101                 csr_do <= 32'd0;
102                 if(csr_selected) begin
103                         case(csr_a[1:0])
104                                 2'b00: csr_do <= {1'b0, tx_done, tx_busy, 1'b0, rx_error, rx_avail};
105                                 2'b01: csr_do <= rx_data;
106                                 2'b10: csr_do <= divisor;
107                         endcase
108                         if(csr_we) begin
109                                 if(csr_a[1:0] == 2'b10)
110                                         divisor <= csr_di[15:0];
111                         end
112                 end
113         end
114 end
115
116 /* IRQs */
117 assign rx_irq = rx_avail|rx_error;
118 assign tx_irq = tx_done;
119
120 endmodule