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

Subversion Repositories s6soc

[/] [s6soc/] [trunk/] [rtl/] [rxuartlite.v] - Blame information for rev 51

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 51 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
`define RXU_BIT_ZERO            4'h0
49
`define RXU_BIT_ONE             4'h1
50
`define RXU_BIT_TWO             4'h2
51
`define RXU_BIT_THREE           4'h3
52
`define RXU_BIT_FOUR            4'h4
53
`define RXU_BIT_FIVE            4'h5
54
`define RXU_BIT_SIX             4'h6
55
`define RXU_BIT_SEVEN           4'h7
56
// `define      RXU_PARITY              4'h8    // Unused in RXUARTLITE
57
`define RXU_STOP                4'h8
58
// `define      RXU_SECOND_STOP         4'ha    // Unused in RXUARTLITE
59
// Unused 4'hb
60
// Unused 4'hc
61
// `define      RXU_BREAK               4'hd    // Unused in RXUARTLITE
62
// `define      RXU_RESET_IDLE          4'he    // Unused in RXUARTLITE
63
`define RXU_IDLE                4'hf
64
 
65
module rxuartlite(i_clk, i_uart_rx, o_wr, o_data);
66
        parameter [23:0] CLOCKS_PER_BAUD = 24'd868;
67
        input                   i_clk;
68
        input                   i_uart_rx;
69
        output  reg             o_wr;
70
        output  reg     [7:0]    o_data;
71
 
72
 
73
        wire    [23:0]   clocks_per_baud, half_baud;
74
        reg     [3:0]    state;
75
 
76
        assign  half_baud = { 1'b0, CLOCKS_PER_BAUD[23:1] } - 24'h1;
77
        reg     [23:0]   baud_counter;
78
        reg             zero_baud_counter;
79
 
80
 
81
        // Since this is an asynchronous receiver, we need to register our
82
        // input a couple of clocks over to avoid any problems with 
83
        // metastability.  We do that here, and then ignore all but the
84
        // ck_uart wire.
85
        reg     q_uart, qq_uart, ck_uart;
86
        initial q_uart  = 1'b0;
87
        initial qq_uart = 1'b0;
88
        initial ck_uart = 1'b0;
89
        always @(posedge i_clk)
90
        begin
91
                q_uart <= i_uart_rx;
92
                qq_uart <= q_uart;
93
                ck_uart <= qq_uart;
94
        end
95
 
96
        // Keep track of the number of clocks since the last change.
97
        //
98
        // This is used to determine if we are in either a break or an idle
99
        // condition, as discussed further below.
100
        reg     [23:0]   chg_counter;
101
        initial chg_counter = 24'h00;
102
        always @(posedge i_clk)
103
                if (qq_uart != ck_uart)
104
                        chg_counter <= 24'h00;
105
                else
106
                        chg_counter <= chg_counter + 1;
107
 
108
        // Are we in the middle of a baud iterval?  Specifically, are we
109
        // in the middle of a start bit?  Set this to high if so.  We'll use
110
        // this within our state machine to transition out of the IDLE
111
        // state.
112
        reg     half_baud_time;
113
        initial half_baud_time = 0;
114
        always @(posedge i_clk)
115
                half_baud_time <= (~ck_uart)&&(chg_counter >= half_baud);
116
 
117
 
118
        initial state = `RXU_IDLE;
119
        always @(posedge i_clk)
120
        begin
121
                if (state == `RXU_IDLE)
122
                begin // Idle state, independent of baud counter
123
                        // By default, just stay in the IDLE state
124
                        state <= `RXU_IDLE;
125
                        if ((~ck_uart)&&(half_baud_time))
126
                                // UNLESS: We are in the center of a valid
127
                                // start bit
128
                                state <= `RXU_BIT_ZERO;
129
                end else if (zero_baud_counter)
130
                begin
131
                        if (state < `RXU_STOP)
132
                                // Data arrives least significant bit first.
133
                                // By the time this is clocked in, it's what
134
                                // you'll have.
135
                                state <= state + 1;
136
                        else // Wait for the next character
137
                                state <= `RXU_IDLE;
138
                end
139
        end
140
 
141
        // Data bit capture logic.
142
        //
143
        // This is drastically simplified from the state machine above, based
144
        // upon: 1) it doesn't matter what it is until the end of a captured
145
        // byte, and 2) the data register will flush itself of any invalid
146
        // data in all other cases.  Hence, let's keep it real simple.
147
        reg     [7:0]    data_reg;
148
        always @(posedge i_clk)
149
                if (zero_baud_counter)
150
                        data_reg <= { ck_uart, data_reg[7:1] };
151
 
152
        // Our data bit logic doesn't need nearly the complexity of all that
153
        // work above.  Indeed, we only need to know if we are at the end of
154
        // a stop bit, in which case we copy the data_reg into our output
155
        // data register, o_data, and tell others (for one clock) that data is
156
        // available.
157
        //
158
        initial o_data = 8'h00;
159
        reg     pre_wr;
160
        initial pre_wr = 1'b0;
161
        always @(posedge i_clk)
162
                if ((zero_baud_counter)&&(state == `RXU_STOP))
163
                begin
164
                        o_wr   <= 1'b1;
165
                        o_data <= data_reg;
166
                end else
167
                        o_wr   <= 1'b0;
168
 
169
        // The baud counter
170
        //
171
        // This is used as a "clock divider" if you will, but the clock needs
172
        // to be reset before any byte can be decoded.  In all other respects,
173
        // we set ourselves up for clocks_per_baud counts between baud
174
        // intervals.
175
        always @(posedge i_clk)
176
                if ((zero_baud_counter)|||(state == `RXU_IDLE))
177
                        baud_counter <= CLOCKS_PER_BAUD-1'b1;
178
                else
179
                        baud_counter <= baud_counter-1'b1;
180
 
181
        // zero_baud_counter
182
        //
183
        // Rather than testing whether or not (baud_counter == 0) within our
184
        // (already too complicated) state transition tables, we use
185
        // zero_baud_counter to pre-charge that test on the clock
186
        // before--cleaning up some otherwise difficult timing dependencies.
187
        initial zero_baud_counter = 1'b0;
188
        always @(posedge i_clk)
189
                if (state == `RXU_IDLE)
190
                        zero_baud_counter <= 1'b0;
191
                else
192
                        zero_baud_counter <= (baud_counter == 24'h01);
193
 
194
 
195
endmodule
196
 
197
 

powered by: WebSVN 2.1.0

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