Initial import
[litex.git] / verilog / uart / uart.v
1 /*
2 * Milkymist SoC
3 * Copyright (C) 2007, 2008, 2009, 2010 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 parameter break_en_default = 1'b0
23 ) (
24 input sys_clk,
25 input sys_rst,
26
27 input [13:0] csr_a,
28 input csr_we,
29 input [31:0] csr_di,
30 output reg [31:0] csr_do,
31
32 output irq,
33
34 input uart_rx,
35 output uart_tx,
36
37 output break
38 );
39
40 reg [15:0] divisor;
41 wire [7:0] rx_data;
42 wire [7:0] tx_data;
43 wire tx_wr;
44
45 wire uart_tx_transceiver;
46
47 uart_transceiver transceiver(
48 .sys_clk(sys_clk),
49 .sys_rst(sys_rst),
50
51 .uart_rx(uart_rx),
52 .uart_tx(uart_tx_transceiver),
53
54 .divisor(divisor),
55
56 .rx_data(rx_data),
57 .rx_done(rx_done),
58
59 .tx_data(tx_data),
60 .tx_wr(tx_wr),
61 .tx_done(tx_done),
62
63 .break(break_transceiver)
64 );
65
66 assign uart_tx = thru_en ? uart_rx : uart_tx_transceiver;
67 assign break = break_en & break_transceiver;
68
69 /* CSR interface */
70 wire csr_selected = csr_a[13:10] == csr_addr;
71
72 assign irq = (tx_event & tx_irq_en) | (rx_event & rx_irq_en);
73
74 assign tx_data = csr_di[7:0];
75 assign tx_wr = csr_selected & csr_we & (csr_a[2:0] == 3'b000);
76
77 parameter default_divisor = clk_freq/baud/16;
78
79 reg thru_en;
80 reg break_en;
81 reg tx_irq_en;
82 reg rx_irq_en;
83 reg rx_event;
84 reg tx_event;
85 reg thre;
86
87 always @(posedge sys_clk) begin
88 if(sys_rst) begin
89 divisor <= default_divisor;
90 csr_do <= 32'd0;
91 thru_en <= 1'b0;
92 break_en <= break_en_default;
93 rx_irq_en <= 1'b0;
94 tx_irq_en <= 1'b0;
95 tx_event <= 1'b0;
96 rx_event <= 1'b0;
97 thre <= 1'b1;
98 end else begin
99 csr_do <= 32'd0;
100 if(break)
101 break_en <= 1'b0;
102 if(tx_done) begin
103 tx_event <= 1'b1;
104 thre <= 1'b1;
105 end
106 if(tx_wr)
107 thre <= 1'b0;
108 if(rx_done) begin
109 rx_event <= 1'b1;
110 end
111 if(csr_selected) begin
112 case(csr_a[2:0])
113 3'b000: csr_do <= rx_data;
114 3'b001: csr_do <= divisor;
115 3'b010: csr_do <= {tx_event, rx_event, thre};
116 3'b011: csr_do <= {thru_en, tx_irq_en, rx_irq_en};
117 3'b100: csr_do <= {break_en};
118 endcase
119 if(csr_we) begin
120 case(csr_a[2:0])
121 3'b000:; /* handled by transceiver */
122 3'b001: divisor <= csr_di[15:0];
123 3'b010: begin
124 /* write one to clear */
125 if(csr_di[1])
126 rx_event <= 1'b0;
127 if(csr_di[2])
128 tx_event <= 1'b0;
129 end
130 3'b011: begin
131 rx_irq_en <= csr_di[0];
132 tx_irq_en <= csr_di[1];
133 thru_en <= csr_di[2];
134 end
135 3'b100: break_en <= csr_di[0];
136 endcase
137 end
138 end
139 end
140 end
141
142 endmodule