OpenCores
URL https://opencores.org/ocsvn/wbuart32/wbuart32/trunk

Subversion Repositories wbuart32

[/] [wbuart32/] [trunk/] [rtl/] [rxuartlite.v] - Blame information for rev 17

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 15 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    rxuartlite.v
4
//
5
// Project:     wbuart32, a full featured UART with simulator
6
//
7
// Purpose:     Receive and decode inputs from a single UART line.
8
//
9
//
10
//      To interface with this module, connect it to your system clock,
11
//      and a UART input.  Set the parameter to the number of clocks per
12
//      baud.  When data becomes available, the o_wr line will be asserted
13
//      for one clock cycle.
14
//
15
//      This interface only handles 8N1 serial port communications.  It does
16
//      not handle the break, parity, or frame error conditions.
17
//
18
//
19
// Creator:     Dan Gisselquist, Ph.D.
20
//              Gisselquist Technology, LLC
21
//
22
////////////////////////////////////////////////////////////////////////////////
23
//
24
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
25
//
26
// This program is free software (firmware): you can redistribute it and/or
27
// modify it under the terms of  the GNU General Public License as published
28
// by the Free Software Foundation, either version 3 of the License, or (at
29
// your option) any later version.
30
//
31
// This program is distributed in the hope that it will be useful, but WITHOUT
32
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
33
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
34
// for more details.
35
//
36
// You should have received a copy of the GNU General Public License along
37
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
38
// target there if the PDF file isn't present.)  If not, see
39
// <http://www.gnu.org/licenses/> for a copy.
40
//
41
// License:     GPL, v3, as defined and found on www.gnu.org,
42
//              http://www.gnu.org/licenses/gpl.html
43
//
44
//
45
////////////////////////////////////////////////////////////////////////////////
46
//
47
//
48 17 dgisselq
`default_nettype        none
49
//
50
`define RXUL_BIT_ZERO           4'h0
51
`define RXUL_BIT_ONE            4'h1
52
`define RXUL_BIT_TWO            4'h2
53
`define RXUL_BIT_THREE          4'h3
54
`define RXUL_BIT_FOUR           4'h4
55
`define RXUL_BIT_FIVE           4'h5
56
`define RXUL_BIT_SIX            4'h6
57
`define RXUL_BIT_SEVEN          4'h7
58
`define RXUL_STOP               4'h8
59
`define RXUL_IDLE               4'hf
60 15 dgisselq
 
61
module rxuartlite(i_clk, i_uart_rx, o_wr, o_data);
62
        parameter [23:0] CLOCKS_PER_BAUD = 24'd868;
63 17 dgisselq
        input   wire            i_clk;
64
        input   wire            i_uart_rx;
65 15 dgisselq
        output  reg             o_wr;
66
        output  reg     [7:0]    o_data;
67
 
68
 
69
        wire    [23:0]   clocks_per_baud, half_baud;
70
        reg     [3:0]    state;
71
 
72
        assign  half_baud = { 1'b0, CLOCKS_PER_BAUD[23:1] } - 24'h1;
73
        reg     [23:0]   baud_counter;
74
        reg             zero_baud_counter;
75
 
76
 
77
        // Since this is an asynchronous receiver, we need to register our
78
        // input a couple of clocks over to avoid any problems with 
79
        // metastability.  We do that here, and then ignore all but the
80
        // ck_uart wire.
81
        reg     q_uart, qq_uart, ck_uart;
82
        initial q_uart  = 1'b0;
83
        initial qq_uart = 1'b0;
84
        initial ck_uart = 1'b0;
85
        always @(posedge i_clk)
86
        begin
87
                q_uart <= i_uart_rx;
88
                qq_uart <= q_uart;
89
                ck_uart <= qq_uart;
90
        end
91
 
92
        // Keep track of the number of clocks since the last change.
93
        //
94
        // This is used to determine if we are in either a break or an idle
95
        // condition, as discussed further below.
96
        reg     [23:0]   chg_counter;
97
        initial chg_counter = 24'h00;
98
        always @(posedge i_clk)
99
                if (qq_uart != ck_uart)
100
                        chg_counter <= 24'h00;
101
                else
102
                        chg_counter <= chg_counter + 1;
103
 
104
        // Are we in the middle of a baud iterval?  Specifically, are we
105
        // in the middle of a start bit?  Set this to high if so.  We'll use
106
        // this within our state machine to transition out of the IDLE
107
        // state.
108
        reg     half_baud_time;
109
        initial half_baud_time = 0;
110
        always @(posedge i_clk)
111
                half_baud_time <= (~ck_uart)&&(chg_counter >= half_baud);
112
 
113
 
114 17 dgisselq
        initial state = `RXUL_IDLE;
115 15 dgisselq
        always @(posedge i_clk)
116
        begin
117 17 dgisselq
                if (state == `RXUL_IDLE)
118 15 dgisselq
                begin // Idle state, independent of baud counter
119
                        // By default, just stay in the IDLE state
120 17 dgisselq
                        state <= `RXUL_IDLE;
121 15 dgisselq
                        if ((~ck_uart)&&(half_baud_time))
122
                                // UNLESS: We are in the center of a valid
123
                                // start bit
124 17 dgisselq
                                state <= `RXUL_BIT_ZERO;
125 15 dgisselq
                end else if (zero_baud_counter)
126
                begin
127 17 dgisselq
                        if (state < `RXUL_STOP)
128 15 dgisselq
                                // Data arrives least significant bit first.
129
                                // By the time this is clocked in, it's what
130
                                // you'll have.
131
                                state <= state + 1;
132
                        else // Wait for the next character
133 17 dgisselq
                                state <= `RXUL_IDLE;
134 15 dgisselq
                end
135
        end
136
 
137
        // Data bit capture logic.
138
        //
139
        // This is drastically simplified from the state machine above, based
140
        // upon: 1) it doesn't matter what it is until the end of a captured
141
        // byte, and 2) the data register will flush itself of any invalid
142
        // data in all other cases.  Hence, let's keep it real simple.
143
        reg     [7:0]    data_reg;
144
        always @(posedge i_clk)
145
                if (zero_baud_counter)
146
                        data_reg <= { ck_uart, data_reg[7:1] };
147
 
148
        // Our data bit logic doesn't need nearly the complexity of all that
149
        // work above.  Indeed, we only need to know if we are at the end of
150
        // a stop bit, in which case we copy the data_reg into our output
151
        // data register, o_data, and tell others (for one clock) that data is
152
        // available.
153
        //
154
        initial o_data = 8'h00;
155
        reg     pre_wr;
156
        initial pre_wr = 1'b0;
157
        always @(posedge i_clk)
158 17 dgisselq
                if ((zero_baud_counter)&&(state == `RXUL_STOP))
159 15 dgisselq
                begin
160
                        o_wr   <= 1'b1;
161
                        o_data <= data_reg;
162
                end else
163
                        o_wr   <= 1'b0;
164
 
165
        // The baud counter
166
        //
167
        // This is used as a "clock divider" if you will, but the clock needs
168
        // to be reset before any byte can be decoded.  In all other respects,
169
        // we set ourselves up for clocks_per_baud counts between baud
170
        // intervals.
171
        always @(posedge i_clk)
172 17 dgisselq
                if ((zero_baud_counter)|||(state == `RXUL_IDLE))
173 15 dgisselq
                        baud_counter <= CLOCKS_PER_BAUD-1'b1;
174
                else
175
                        baud_counter <= baud_counter-1'b1;
176
 
177
        // zero_baud_counter
178
        //
179
        // Rather than testing whether or not (baud_counter == 0) within our
180
        // (already too complicated) state transition tables, we use
181
        // zero_baud_counter to pre-charge that test on the clock
182
        // before--cleaning up some otherwise difficult timing dependencies.
183
        initial zero_baud_counter = 1'b0;
184
        always @(posedge i_clk)
185 17 dgisselq
                if (state == `RXUL_IDLE)
186 15 dgisselq
                        zero_baud_counter <= 1'b0;
187
                else
188
                        zero_baud_counter <= (baud_counter == 24'h01);
189
 
190
 
191
endmodule
192
 
193
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.