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

Subversion Repositories xulalx25soc

[/] [xulalx25soc/] [trunk/] [rtl/] [txuart.v] - Blame information for rev 99

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

Line No. Rev Author Line
1 7 dgisselq
////////////////////////////////////////////////////////////////////////////////
2 2 dgisselq
//
3
// Filename:    txuart.v
4
//
5 7 dgisselq
// Project:     XuLA2 board
6 2 dgisselq
//
7
// Purpose:     Transmit outputs over a single UART line.
8
//
9
//      To interface with this module, connect it to your system clock,
10
//      pass it the 32 bit setup register (defined below) and the byte
11
//      of data you wish to transmit.  Strobe the i_wr line high for one
12
//      clock cycle, and your data will be off.  Wait until the 'o_busy'
13
//      line is low before strobing the i_wr line again--this implementation
14
//      has NO BUFFER, so strobing i_wr while the core is busy will just
15
//      cause your data to be lost.  The output will be placed on the o_txuart
16
//      output line.  If you wish to set/send a break condition, assert the
17
//      i_break line otherwise leave it low.
18
//
19
//      There is a synchronous reset line, logic high.
20
//
21
//      Now for the setup register.  The register is 32 bits, so that this
22
//      UART may be set up over a 32-bit bus.
23
//
24
//      i_setup[29:28]  Indicates the number of data bits per word.  This will
25
//      either be 2'b00 for an 8-bit word, 2'b01 for a 7-bit word, 2'b10
26
//      for a six bit word, or 2'b11 for a five bit word.
27
//
28
//      i_setup[27]     Indicates whether or not to use one or two stop bits.
29
//              Set this to one to expect two stop bits, zero for one.
30
//
31
//      i_setup[26]     Indicates whether or not a parity bit exists.  Set this
32
//              to 1'b1 to include parity.
33
//
34
//      i_setup[25]     Indicates whether or not the parity bit is fixed.  Set
35
//              to 1'b1 to include a fixed bit of parity, 1'b0 to allow the
36
//              parity to be set based upon data.  (Both assume the parity
37
//              enable value is set.)
38
//
39
//      i_setup[24]     This bit is ignored if parity is not used.  Otherwise,
40
//              in the case of a fixed parity bit, this bit indicates whether
41
//              mark (1'b1) or space (1'b0) parity is used.  Likewise if the
42
//              parity is not fixed, a 1'b1 selects even parity, and 1'b0
43
//              selects odd.
44
//
45
//      i_setup[23:0]   Indicates the speed of the UART in terms of clocks.
46
//              So, for example, if you have a 200 MHz clock and wish to
47
//              run your UART at 9600 baud, you would take 200 MHz and divide
48
//              by 9600 to set this value to 24'd20834.  Likewise if you wished
49
//              to run this serial port at 115200 baud from a 200 MHz clock,
50
//              you would set the value to 24'd1736
51
//
52
//      Thus, to set the UART for the common setting of an 8-bit word, 
53
//      one stop bit, no parity, and 115200 baud over a 200 MHz clock, you
54
//      would want to set the setup value to:
55
//
56
//      32'h0006c8              // For 115,200 baud, 8 bit, no parity
57
//      32'h005161              // For 9600 baud, 8 bit, no parity
58
//      
59 7 dgisselq
//
60
//
61
// Creator:     Dan Gisselquist, Ph.D.
62 2 dgisselq
//              Gisselquist Technology, LLC
63
//
64 7 dgisselq
////////////////////////////////////////////////////////////////////////////////
65 2 dgisselq
//
66 88 dgisselq
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
67 2 dgisselq
//
68 7 dgisselq
// This program is free software (firmware): you can redistribute it and/or
69
// modify it under the terms of  the GNU General Public License as published
70
// by the Free Software Foundation, either version 3 of the License, or (at
71
// your option) any later version.
72 2 dgisselq
//
73 7 dgisselq
// This program is distributed in the hope that it will be useful, but WITHOUT
74
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
75
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
76
// for more details.
77 2 dgisselq
//
78 99 dgisselq
// You should have received a copy of the GNU General Public License along
79
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
80
// target there if the PDF file isn't present.)  If not, see
81
// <http://www.gnu.org/licenses/> for a copy.
82
//
83 7 dgisselq
// License:     GPL, v3, as defined and found on www.gnu.org,
84
//              http://www.gnu.org/licenses/gpl.html
85 2 dgisselq
//
86 7 dgisselq
//
87
////////////////////////////////////////////////////////////////////////////////
88
//
89
//
90
//
91 2 dgisselq
`define TXU_BIT_ZERO    4'h0
92
`define TXU_BIT_ONE     4'h1
93
`define TXU_BIT_TWO     4'h2
94
`define TXU_BIT_THREE   4'h3
95
`define TXU_BIT_FOUR    4'h4
96
`define TXU_BIT_FIVE    4'h5
97
`define TXU_BIT_SIX     4'h6
98
`define TXU_BIT_SEVEN   4'h7
99
`define TXU_PARITY      4'h8    // Constant 1
100
`define TXU_STOP        4'h9    // Constant 1
101
`define TXU_SECOND_STOP 4'ha
102
// 4'hb // Unused
103
// 4'hc // Unused
104
// `define      TXU_START       4'hd    // An unused state
105
`define TXU_BREAK       4'he
106
`define TXU_IDLE        4'hf
107 99 dgisselq
//
108
//
109 2 dgisselq
module txuart(i_clk, i_reset, i_setup, i_break, i_wr, i_data, o_uart, o_busy);
110
        input                   i_clk, i_reset;
111
        input           [29:0]   i_setup;
112
        input                   i_break;
113
        input                   i_wr;
114
        input           [7:0]    i_data;
115 99 dgisselq
        output  reg             o_uart;
116
        output  wire            o_busy;
117 2 dgisselq
 
118
        wire    [27:0]   clocks_per_baud, break_condition;
119
        wire    [1:0]    data_bits;
120
        wire            use_parity, parity_even, dblstop, fixd_parity;
121
        reg     [29:0]   r_setup;
122
        assign  clocks_per_baud = { 4'h0, r_setup[23:0] };
123
        assign  break_condition = { r_setup[23:0], 4'h0 };
124
        assign  data_bits   = r_setup[29:28];
125
        assign  dblstop     = r_setup[27];
126
        assign  use_parity  = r_setup[26];
127
        assign  fixd_parity = r_setup[25];
128
        assign  parity_even = r_setup[24];
129
 
130
        reg     [27:0]   baud_counter;
131
        reg     [3:0]    state;
132
        reg     [7:0]    lcl_data;
133 99 dgisselq
        reg             calc_parity, r_busy, zero_baud_counter;
134 2 dgisselq
 
135
        initial o_uart = 1'b1;
136 99 dgisselq
        initial r_busy = 1'b1;
137 2 dgisselq
        initial state  = `TXU_IDLE;
138 99 dgisselq
        initial lcl_data= 8'h0;
139
        initial calc_parity = 1'b0;
140
        // initial      baud_counter = clocks_per_baud;//ILLEGAL--not constant
141 2 dgisselq
        always @(posedge i_clk)
142
        begin
143
                if (i_reset)
144
                begin
145
                        o_uart <= 1'b1;
146 99 dgisselq
                        r_busy <= 1'b1;
147 2 dgisselq
                        state <= `TXU_IDLE;
148
                        lcl_data <= 8'h0;
149
                        calc_parity <= 1'b0;
150
                end else if (i_break)
151
                begin
152
                        o_uart <= 1'b0;
153
                        state <= `TXU_BREAK;
154
                        calc_parity <= 1'b0;
155 99 dgisselq
                        r_busy <= 1'b1;
156
                end else if (~zero_baud_counter)
157
                begin // r_busy needs to be set coming into here
158
                        r_busy <= 1'b1;
159 2 dgisselq
                end else if (state == `TXU_BREAK)
160
                begin
161
                        state <= `TXU_IDLE;
162 99 dgisselq
                        r_busy <= 1'b1;
163 2 dgisselq
                        o_uart <= 1'b1;
164
                        calc_parity <= 1'b0;
165
                end else if (state == `TXU_IDLE)        // STATE_IDLE
166
                begin
167
                        // baud_counter <= 0;
168
                        r_setup <= i_setup;
169
                        calc_parity <= 1'b0;
170 99 dgisselq
                        if ((i_wr)&&(~r_busy))
171 2 dgisselq
                        begin   // Immediately start us off with a start bit
172
                                o_uart <= 1'b0;
173 99 dgisselq
                                r_busy <= 1'b1;
174 2 dgisselq
                                case(data_bits)
175
                                2'b00: state <= `TXU_BIT_ZERO;
176
                                2'b01: state <= `TXU_BIT_ONE;
177
                                2'b10: state <= `TXU_BIT_TWO;
178
                                2'b11: state <= `TXU_BIT_THREE;
179
                                endcase
180
                                lcl_data <= i_data;
181 99 dgisselq
                                // baud_counter <= clocks_per_baud-28'h01;
182 2 dgisselq
                        end else begin // Stay in idle
183
                                o_uart <= 1'b1;
184 99 dgisselq
                                r_busy <= 0;
185 2 dgisselq
                                // lcl_data is irrelevant
186
                                // state <= state;
187
                        end
188
                end else begin
189
                        // One clock tick in each of these states ...
190 99 dgisselq
                        // baud_counter <= clocks_per_baud - 28'h01;
191
                        r_busy <= 1'b1;
192 2 dgisselq
                        if (state[3] == 0) // First 8 bits
193
                        begin
194
                                o_uart <= lcl_data[0];
195
                                calc_parity <= calc_parity ^ lcl_data[0];
196
                                if (state == `TXU_BIT_SEVEN)
197
                                        state <= (use_parity)?`TXU_PARITY:`TXU_STOP;
198
                                else
199
                                        state <= state + 1;
200
                                lcl_data <= { 1'b0, lcl_data[7:1] };
201
                        end else if (state == `TXU_PARITY)
202
                        begin
203
                                state <= `TXU_STOP;
204
                                if (fixd_parity)
205
                                        o_uart <= parity_even;
206
                                else
207
                                        o_uart <= calc_parity^((parity_even)? 1'b1:1'b0);
208
                        end else if (state == `TXU_STOP)
209
                        begin // two stop bit(s)
210
                                o_uart <= 1'b1;
211
                                if (dblstop)
212
                                        state <= `TXU_SECOND_STOP;
213
                                else
214
                                        state <= `TXU_IDLE;
215
                                calc_parity <= 1'b0;
216
                        end else // `TXU_SECOND_STOP and default:
217
                        begin
218
                                state <= `TXU_IDLE; // Go back to idle
219
                                o_uart <= 1'b1;
220 99 dgisselq
                                // Still r_busy, since we need to wait
221 2 dgisselq
                                // for the baud clock to finish counting
222
                                // out this last bit.
223
                        end
224
                end
225
        end
226
 
227 99 dgisselq
        assign  o_busy = (r_busy);
228 2 dgisselq
 
229
 
230 99 dgisselq
        initial zero_baud_counter = 1'b0;
231
        always @(posedge i_clk)
232
        begin
233
                zero_baud_counter <= (baud_counter == 28'h01);
234
                if ((i_reset)||(i_break))
235
                        // Give ourselves 16 bauds before being ready
236
                        baud_counter <= break_condition;
237
                else if (~zero_baud_counter)
238
                        baud_counter <= baud_counter - 28'h01;
239
                else if (state == `TXU_BREAK)
240
                        // Give us two stop bits before becoming available
241
                        baud_counter <= clocks_per_baud<<2;
242
                else if (state == `TXU_IDLE)
243
                begin
244
                        if((i_wr)&&(~r_busy))
245
                                baud_counter <= clocks_per_baud - 28'h01;
246
                        else
247
                                zero_baud_counter <= 1'b1;
248
                end else
249
                        baud_counter <= clocks_per_baud - 28'h01;
250
        end
251
endmodule
252 2 dgisselq
 

powered by: WebSVN 2.1.0

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