OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [uart.vhd] - Blame information for rev 3

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

Line No. Rev Author Line
1 3 howe.r.j.8
--------------------------------------------------------------------------------
2
--| @file uart.vhd
3
--| @brief implements a universal asynchronous receiver transmitter with
4
--| parameterisable baud rate. tested on a spartan 6 lx9 connected to a
5
--| silicon labs cp210 usb-uart bridge.
6
--|
7
--| @author         peter a bennett
8
--| @copyright      (c) 2012 peter a bennett
9
--| @license        Apache 2.0
10
--| @email          pab850@googlemail.com
11
--| @contact        www.bytebash.com
12
--|
13
--| See https://github.com/pabennett/uart
14
--|
15
--| There have been many changes to the original code, consult the git logs
16
--| for a full list of changes.
17
--|
18
--| @note Changes made to range to stop Xilinx warnings and with formatting,
19
--| the UART has also been wrapped up in a package and top level component
20
--| (called "uart_top") to make the interface easier to use and less confusing.
21
--| This has not be tested yet.
22
--|
23
--| @note Somewhere along the chain from the computer, to the Nexys3 board,
24
--| to the UART module, and finally to the H2 core, bytes are being lost in
25
--| transmission from the computer. This UART really should be buffered
26
--| as well.
27
--|
28
--|  START 0 1 2 3 4 5 6 7 STOP
29
--| ----\_/-|-|-|-|-|-|-|-|-|-------
30
--|
31
--------------------------------------------------------------------------------
32
library ieee;
33
use ieee.std_logic_1164.all;
34
 
35
package uart_pkg is
36
 
37
        component uart_top is
38
        generic (baud_rate: positive; clock_frequency: positive; fifo_depth: positive := 8);
39
        port (
40
                clk:                 in      std_ulogic;
41
                rst:                 in      std_ulogic;
42
 
43
                rx_data:             out     std_ulogic_vector(7 downto 0);
44
                rx_fifo_empty:       out     std_ulogic;
45
                rx_fifo_full:        out     std_ulogic;
46
                rx_data_re:          in      std_ulogic;
47
 
48
                tx_data:             in      std_ulogic_vector(7 downto 0);
49
                tx_fifo_full:        out     std_ulogic;
50
                tx_fifo_empty:       out     std_ulogic;
51
                tx_data_we:          in      std_ulogic;
52
 
53
                tx:                  out     std_ulogic;
54
                rx:                  in      std_ulogic);
55
 
56
        end component;
57
 
58
        component uart_core is
59
                generic (baud_rate: positive; clock_frequency: positive);
60
                port (
61
                        clk:       in      std_ulogic;
62
                        rst:       in      std_ulogic;
63
                        din:       in      std_ulogic_vector(7 downto 0);
64
                        din_stb:   in      std_ulogic;
65
                        din_ack:   out     std_ulogic := '0';
66
                        din_busy:  out     std_ulogic;
67
 
68
                        dout:      out     std_ulogic_vector(7 downto 0);
69
                        dout_stb:  out     std_ulogic;
70
                        dout_ack:  in      std_ulogic;
71
                        dout_busy: out     std_ulogic;
72
 
73
                        tx:        out     std_ulogic;
74
                        rx:        in      std_ulogic);
75
        end component;
76
 
77
end package;
78
 
79
---- UART Package --------------------------------------------------------------
80
 
81
---- UART Top ------------------------------------------------------------------
82
 
83
library ieee;
84
use ieee.std_logic_1164.all;
85
use ieee.numeric_std.all;
86
use work.util.fifo;
87
use work.uart_pkg.uart_core;
88
 
89
entity uart_top is
90
        generic (baud_rate: positive; clock_frequency: positive; fifo_depth: positive := 8);
91
        port (
92
                clk:                 in      std_ulogic;
93
                rst:                 in      std_ulogic;
94
 
95
                rx_data:             out     std_ulogic_vector(7 downto 0);
96
                rx_fifo_empty:       out     std_ulogic;
97
                rx_fifo_full:        out     std_ulogic;
98
                rx_data_re:          in      std_ulogic;
99
 
100
                tx_data:             in      std_ulogic_vector(7 downto 0);
101
                tx_fifo_full:        out     std_ulogic;
102
                tx_fifo_empty:       out     std_ulogic;
103
                tx_data_we:          in      std_ulogic;
104
 
105
                tx:                  out     std_ulogic;
106
                rx:                  in      std_ulogic);
107
end entity;
108
 
109
architecture behav of uart_top is
110
        signal rx_sync, rx_uart, tx_uart: std_ulogic := '0';
111
 
112
        signal din:       std_ulogic_vector(7 downto 0) := (others => '0');
113
        signal din_stb:   std_ulogic := '0';
114
        signal din_ack:   std_ulogic := '0';
115
        signal din_busy:  std_ulogic := '0';
116
 
117
        signal dout:      std_ulogic_vector(7 downto 0) := (others => '0');
118
        signal dout_stb:  std_ulogic := '0';
119
        signal dout_ack:  std_ulogic := '0';
120
        signal dout_busy: std_ulogic := '0';
121
 
122
        signal tx_fifo_re:             std_ulogic := '0';
123
        signal tx_fifo_empty_internal: std_ulogic := '1';
124
        signal tx_fifo_full_internal:  std_ulogic := '0';
125
 
126
        signal wrote_c, wrote_n: std_ulogic := '0';
127
 
128
begin
129
        uart_deglitch: process (clk, rst)
130
        begin
131
                if rst = '1' then
132
                        wrote_c <= '0';
133
                elsif rising_edge(clk) then
134
                        rx_sync <= rx;
135
                        rx_uart <= rx_sync;
136
                        tx      <= tx_uart;
137
                        wrote_c <= wrote_n;
138
                end if;
139
        end process;
140
 
141
        process(dout_stb, tx_fifo_empty_internal, tx_fifo_full_internal, din_ack, wrote_c, din_busy)
142
        begin
143
                        dout_ack    <= '0';
144
                        din_stb     <= '0';
145
                        tx_fifo_re  <= '0';
146
                        wrote_n     <= wrote_c;
147
 
148
                        if dout_stb = '1' then
149
                                dout_ack <= '1';
150
                        end if;
151
 
152
                        if tx_fifo_empty_internal = '0' and tx_fifo_full_internal = '0' and din_busy = '0' then
153
                                tx_fifo_re <= '1';
154
                                wrote_n    <= '1';
155
                        elsif din_ack = '0' and wrote_c = '1' then
156
                        --elsif wrote_c = '1' then
157
                                -- assert din_ack = '1' on the next cycle?
158
                                din_stb    <= '1';
159
                                wrote_n    <= '0';
160
                        end if;
161
        end process;
162
 
163
        rx_fifo: work.util.fifo
164
                generic map (
165
                        data_width => 8,
166
                        fifo_depth => fifo_depth)
167
                port map(
168
                        clk   => clk,
169
                        rst   => rst,
170
                        di    => dout,
171
                        we    => dout_stb,
172
                        re    => rx_data_re,
173
                        do    => rx_data,
174
                        full  => rx_fifo_full,
175
                        empty => rx_fifo_empty);
176
 
177
        tx_fifo: work.util.fifo
178
                generic map (
179
                        data_width => 8,
180
                        fifo_depth => fifo_depth)
181
                port map(
182
                        clk   => clk,
183
                        rst   => rst,
184
                        di    => tx_data,
185
                        we    => tx_data_we,
186
                        re    => tx_fifo_re,
187
                        do    => din,
188
                        full  => tx_fifo_full_internal,
189
                        empty => tx_fifo_empty_internal);
190
 
191
        tx_fifo_empty <= tx_fifo_empty_internal;
192
        -- @bug This is a hack, it should be just 'tx_fifo_full_internal', but
193
        -- it does not work correctly, so as a temporary hack the busy signal
194
        -- is or'd in so the data source can block until the FIFO is 'not full'
195
        -- and not lose any data thinking it has been transmitted.
196
        tx_fifo_full  <= '1' when tx_fifo_full_internal = '1' or din_busy = '1' else '0';
197
 
198
        uart: work.uart_pkg.uart_core
199
                generic map(
200
                        baud_rate => baud_rate,
201
                        clock_frequency => clock_frequency)
202
                port map(
203
                        clk      => clk,
204
                        rst      => rst,
205
                        din      => din,
206
                        din_stb  => din_stb,
207
                        din_ack  => din_ack,
208
                        din_busy => din_busy,
209
                        dout     => dout,
210
                        dout_stb => dout_stb,
211
                        dout_ack => dout_ack,
212
                        dout_busy=> dout_busy,
213
                        rx       => rx_uart,
214
                        tx       => tx_uart);
215
 
216
end;
217
 
218
---- UART Top ------------------------------------------------------------------
219
 
220
---- UART Core -----------------------------------------------------------------
221
 
222
library ieee;
223
use ieee.std_logic_1164.all;
224
use ieee.numeric_std.all;
225
 
226
entity uart_core is
227
        generic(baud_rate: positive; clock_frequency: positive);
228
        port(
229
                clk:       in      std_ulogic;
230
                rst:       in      std_ulogic;
231
                din:       in      std_ulogic_vector(7 downto 0);
232
                din_stb:   in      std_ulogic;
233
                din_ack:   out     std_ulogic := '0';
234
                din_busy:  out     std_ulogic;
235
 
236
                dout:      out     std_ulogic_vector(7 downto 0);
237
                dout_stb:  out     std_ulogic;
238
                dout_ack:  in      std_ulogic;
239
                dout_busy: out     std_ulogic;
240
 
241
                tx:        out     std_ulogic;
242
                rx:        in      std_ulogic);
243
end entity;
244
 
245
architecture behav of uart_core is
246
 
247
        constant uart_tx_count_max: positive := 7;
248
        constant uart_rx_count_max: positive := 7;
249
        ----------------------------------------------------------------------------
250
        -- baud generation
251
        ----------------------------------------------------------------------------
252
        constant c_tx_divider_val: integer := clock_frequency / baud_rate;
253
        constant c_rx_divider_val: integer := clock_frequency / (baud_rate * 16);
254
 
255
        signal baud_counter:            integer range 0 to c_tx_divider_val;
256
        signal baud_tick:               std_ulogic := '0';
257
        signal oversample_baud_counter: integer range 0 to c_rx_divider_val := 0;
258
        signal oversample_baud_tick:    std_ulogic := '0';
259
 
260
        ----------------------------------------------------------------------------
261
        -- transmitter signals
262
        ----------------------------------------------------------------------------
263
        type    uart_tx_states is (idle,
264
                                wait_for_tick,
265
                                send_start_bit,
266
                                transmit_data,
267
                                send_stop_bit);
268
 
269
        signal  uart_tx_state: uart_tx_states := idle;
270
 
271
        signal  uart_tx_data_block:  std_ulogic_vector(7 downto 0) := (others => '0');
272
        signal  uart_tx_data:        std_ulogic := '1';
273
        signal  uart_tx_count:       integer range 0 to uart_tx_count_max := 0;
274
        signal  uart_rx_data_in_ack: std_ulogic := '0';
275
        ----------------------------------------------------------------------------
276
        -- receiver signals
277
        ----------------------------------------------------------------------------
278
        type    uart_rx_states is (rx_wait_start_synchronise,
279
                                    rx_get_start_bit,
280
                                    rx_get_data,
281
                                    rx_get_stop_bit,
282
                                    rx_send_block);
283
 
284
        signal  uart_rx_state:        uart_rx_states := rx_get_start_bit;
285
        signal  uart_rx_bit:          std_ulogic := '1'; -- @note should the be 0 or 1?
286
        signal  uart_rx_data_block:   std_ulogic_vector(7 downto 0) := (others => '0');
287
        signal  uart_rx_data_vec:     std_ulogic_vector(1 downto 0) := (others => '0');
288
        signal  uart_rx_filter:       unsigned(1 downto 0)  := (others => '1');
289
        signal  uart_rx_count:        integer range 0 to uart_rx_count_max  := 0;
290
        signal  uart_rx_data_out_stb: std_ulogic := '0';
291
        signal  uart_rx_bit_spacing:  unsigned (3 downto 0) := (others => '0');
292
        signal  uart_rx_bit_tick:     std_ulogic := '0';
293
begin
294
 
295
        din_ack  <= uart_rx_data_in_ack;
296
        dout     <= uart_rx_data_block;
297
        dout_stb <= uart_rx_data_out_stb;
298
        tx       <= uart_tx_data;
299
 
300
        din_busy  <= '0' when uart_tx_state = idle else '1';
301
        dout_busy <= '0' when uart_rx_state = rx_get_start_bit or uart_rx_state = rx_send_block else '1';
302
 
303
        -- the input clk is 100MHz, this needs to be divided down to the
304
        -- rate dictated by the baud_rate. for example, if 115200 baud is selected
305
        -- (115200 baud = 115200 bps - 115.2kbps) a tick must be generated once
306
        -- every 1/115200
307
        tx_clk_divider: process (clk, rst)
308
        begin
309
                if rst = '1' then
310
                        baud_counter <= 0;
311
                        baud_tick    <= '0';
312
                elsif rising_edge (clk) then
313
                        if baud_counter = c_tx_divider_val then
314
                                baud_counter <= 0;
315
                                baud_tick    <= '1';
316
                        else
317
                                baud_counter <= baud_counter + 1;
318
                                baud_tick    <= '0';
319
                        end if;
320
                end if;
321
        end process;
322
 
323
        -- get data from din and send it one bit at a time
324
        -- upon each baud tick. lsb first.
325
        -- wait 1 tick, send start bit (0), send data 0-7, send stop bit (1)
326
        uart_send_data: process(clk, rst)
327
        begin
328
                if rst = '1' then
329
                        uart_tx_data        <= '1';
330
                        uart_tx_data_block  <= (others => '0');
331
                        uart_tx_count       <= 0;
332
                        uart_tx_state       <= idle;
333
                        uart_rx_data_in_ack <= '0';
334
                elsif rising_edge(clk) then
335
                        uart_rx_data_in_ack <= '0';
336
                        case uart_tx_state is
337
                        when idle =>
338
                                if din_stb = '1' then
339
                                        uart_tx_data_block  <= din;
340
                                        uart_rx_data_in_ack <= '1';
341
                                        uart_tx_state       <= wait_for_tick;
342
                                end if;
343
                        when wait_for_tick =>
344
                                if baud_tick = '1' then
345
                                        uart_tx_state    <= send_start_bit;
346
                                end if;
347
                        when send_start_bit =>
348
                                if baud_tick = '1' then
349
                                        uart_tx_data  <= '0';
350
                                        uart_tx_state <= transmit_data;
351
                                        uart_tx_count <= 0;
352
                                end if;
353
                        when transmit_data =>
354
                                if baud_tick = '1' then
355
                                        if uart_tx_count < uart_tx_count_max then
356
                                                uart_tx_data  <= uart_tx_data_block(uart_tx_count);
357
                                                uart_tx_count <= uart_tx_count + 1;
358
                                        else
359
                                                uart_tx_data  <= uart_tx_data_block(7);
360
                                                uart_tx_count <= 0;
361
                                                uart_tx_state <= send_stop_bit;
362
                                        end if;
363
                                end if;
364
                        when send_stop_bit =>
365
                                if baud_tick = '1' then
366
                                        uart_tx_data <= '1';
367
                                        uart_tx_state <= idle;
368
                                end if;
369
                        when others =>
370
                                uart_tx_data  <= '1';
371
                                uart_tx_state <= idle;
372
                        end case;
373
                end if;
374
        end process;
375
 
376
        -- generate an oversampled tick (baud * 16)
377
        oversample_clk_divider: process (clk, rst)
378
        begin
379
                if rst = '1' then
380
                        oversample_baud_counter <= 0;
381
                        oversample_baud_tick    <= '0';
382
                elsif rising_edge (clk) then
383
                        if oversample_baud_counter = c_rx_divider_val then
384
                                oversample_baud_counter <= 0;
385
                                oversample_baud_tick    <= '1';
386
                        else
387
                                oversample_baud_counter <= oversample_baud_counter + 1;
388
                                oversample_baud_tick    <= '0';
389
                        end if;
390
                end if;
391
        end process;
392
 
393
        -- synchronise rxd to the oversampled baud
394
        rxd_synchronise: process(clk, rst)
395
        begin
396
                if rst = '1' then
397
                        uart_rx_data_vec <= (others => '0');
398
                elsif rising_edge(clk) then
399
                        if oversample_baud_tick = '1' then
400
                                uart_rx_data_vec(0) <= rx;
401
                                uart_rx_data_vec(1) <= uart_rx_data_vec(0);
402
                        end if;
403
                end if;
404
        end process;
405
 
406
        -- filter rxd with a 2 bit counter.
407
        rxd_filter: process(clk, rst)
408
        begin
409
                if rst = '1' then
410
                        uart_rx_filter <= (others => '1');
411
                        uart_rx_bit    <= '1';
412
                elsif rising_edge(clk) then
413
                        if oversample_baud_tick = '1' then
414
                                -- filter rxd.
415
                                if uart_rx_data_vec(1) = '1' and uart_rx_filter < 3 then
416
                                        uart_rx_filter <= uart_rx_filter + 1;
417
                                elsif uart_rx_data_vec(1) = '0' and uart_rx_filter > 0 then
418
                                        uart_rx_filter <= uart_rx_filter - 1;
419
                                end if;
420
                                -- set the rx bit.
421
                                if uart_rx_filter = 3 then
422
                                        uart_rx_bit <= '1';
423
                                elsif uart_rx_filter = 0 then
424
                                        uart_rx_bit <= '0';
425
                                end if;
426
                        end if;
427
                end if;
428
        end process;
429
 
430
        rx_bit_spacing: process (clk, rst)
431
        begin
432
                if rising_edge(clk) then
433
                        uart_rx_bit_tick <= '0';
434
                        if oversample_baud_tick = '1' then
435
                                if uart_rx_bit_spacing = 15 then
436
                                        uart_rx_bit_tick <= '1';
437
                                        uart_rx_bit_spacing <= (others => '0');
438
                                else
439
                                        uart_rx_bit_spacing <= uart_rx_bit_spacing + 1;
440
                                end if;
441
                                if uart_rx_state = rx_get_start_bit then
442
                                        uart_rx_bit_spacing <= (others => '0');
443
                                end if;
444
                        end if;
445
                end if;
446
        end process;
447
 
448
        uart_receive_data: process(clk, rst)
449
        begin
450
                if rst = '1' then
451
                        uart_rx_state        <= rx_get_start_bit;
452
                        uart_rx_data_block   <= (others => '0');
453
                        uart_rx_count        <= 0;
454
                        uart_rx_data_out_stb <= '0';
455
                elsif rising_edge(clk) then
456
                        case uart_rx_state is
457
                        when rx_get_start_bit =>
458
                                if oversample_baud_tick = '1' and uart_rx_bit = '0' then
459
                                        uart_rx_state <= rx_get_data;
460
                                end if;
461
                        when rx_get_data =>
462
                                if uart_rx_bit_tick = '1' then
463
                                        if uart_rx_count < uart_rx_count_max then
464
                                                uart_rx_data_block(uart_rx_count) <= uart_rx_bit;
465
                                                uart_rx_count <= uart_rx_count + 1;
466
                                        else
467
                                                uart_rx_data_block(7) <= uart_rx_bit;
468
                                                uart_rx_count <= 0;
469
                                                uart_rx_state <= rx_get_stop_bit;
470
                                        end if;
471
                                end if;
472
                        when rx_get_stop_bit =>
473
                                if uart_rx_bit_tick = '1' then
474
                                        if uart_rx_bit = '1' then
475
                                                uart_rx_state        <= rx_send_block;
476
                                                uart_rx_data_out_stb <= '1';
477
                                        end if;
478
                                end if;
479
                        when rx_send_block =>
480
                                if dout_ack = '1' then
481
                                        uart_rx_data_out_stb  <= '0';
482
                                        uart_rx_data_block    <= (others => '0');
483
                                        uart_rx_state         <= rx_get_start_bit;
484
                                else
485
                                        uart_rx_data_out_stb  <= '1';
486
                                end if;
487
                        when others =>
488
                                uart_rx_state <= rx_get_start_bit;
489
                        end case;
490
                end if;
491
        end process;
492
end;
493
 
494
---- UART Core -----------------------------------------------------------------

powered by: WebSVN 2.1.0

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