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

Subversion Repositories leros

[/] [leros/] [trunk/] [vhdl/] [io/] [uart.vhd] - Blame information for rev 4

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

Line No. Rev Author Line
1 3 martin
--
2
--  Copyright 2000-2011 Martin Schoeberl <masca@imm.dtu.dk>,
3
--  All rights reserved.
4
--
5
-- Redistribution and use in source and binary forms, with or without
6
-- modification, are permitted provided that the following conditions are met:
7
-- 
8
--    1. Redistributions of source code must retain the above copyright notice,
9
--       this list of conditions and the following disclaimer.
10
-- 
11
--    2. Redistributions in binary form must reproduce the above copyright
12
--       notice, this list of conditions and the following disclaimer in the
13
--       documentation and/or other materials provided with the distribution.
14
-- 
15
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
16
-- OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
18
-- NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
19
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
-- 
26
-- The views and conclusions contained in the software and documentation are
27
-- those of the authors and should not be interpreted as representing official
28
-- policies, either expressed or implied, of the copyright holder.
29
-- 
30
 
31
 
32
--
33
--      This file is an adapted version of the SimpCon UART (from JOP).
34
--      Simplify to have a one cycle read.
35
--
36
--      uart.vhd
37
--
38
--      8-N/E/O-1 serial interface
39
--      
40
--      wr, rd should be one cycle long => trde, rdrf goes 0 one cycle later
41
--
42
--      Author: Martin Schoeberl        martin@jopdesign.com
43
--
44
 
45
--      2000-12-02      first working version
46
--  history deleted
47
--      2011-06-02      simplify for Leros
48
 
49
 
50
--
51
--      The FIFO for read and write buffers
52
--
53
library ieee;
54
use ieee.std_logic_1164.all;
55
 
56
entity fifo_elem is
57
 
58
generic (width : integer);
59
port (
60
        clk             : in std_logic;
61
        reset   : in std_logic;
62
 
63
        din             : in std_logic_vector(width-1 downto 0);
64
        dout    : out std_logic_vector(width-1 downto 0);
65
 
66
        rd              : in std_logic;
67
        wr              : in std_logic;
68
 
69
        rd_prev : out std_logic;
70
        full    : out std_logic
71
);
72
end fifo_elem;
73
 
74
architecture rtl of fifo_elem is
75
 
76
        signal buf              : std_logic_vector(width-1 downto 0);
77
        signal f                : std_logic;
78
 
79
begin
80
 
81
        dout <= buf;
82
 
83
process(clk, reset, f)
84
 
85
begin
86
 
87
        full <= f;
88
 
89
        if (reset='1') then
90
 
91
                buf <= (others => '0');
92
                f <= '0';
93
                rd_prev <= '0';
94
 
95
        elsif rising_edge(clk) then
96
 
97
                rd_prev <= '0';
98
                if f='0' then
99
                        if wr='1' then
100
                                rd_prev <= '1';
101
                                buf <= din;
102
                                f <= '1';
103
                        end if;
104
                else
105
                        if rd='1' then
106
                                f <= '0';
107
                        end if;
108
                end if;
109
 
110
        end if;
111
 
112
end process;
113
 
114
end rtl;
115
 
116
library ieee;
117
use ieee.std_logic_1164.all;
118
 
119
entity fifo is
120
 
121
generic (width : integer := 8; depth : integer := 4);
122
port (
123
        clk             : in std_logic;
124
        reset   : in std_logic;
125
 
126
        din             : in std_logic_vector(width-1 downto 0);
127
        dout    : out std_logic_vector(width-1 downto 0);
128
 
129
        rd              : in std_logic;
130
        wr              : in std_logic;
131
 
132
        empty   : out std_logic;
133
        full    : out std_logic
134
);
135
end fifo ;
136
 
137
architecture rtl of fifo is
138
 
139
component fifo_elem is
140
 
141
generic (width : integer);
142
port (
143
        clk             : in std_logic;
144
        reset   : in std_logic;
145
 
146
        din             : in std_logic_vector(width-1 downto 0);
147
        dout    : out std_logic_vector(width-1 downto 0);
148
 
149
        rd              : in std_logic;
150
        wr              : in std_logic;
151
 
152
        rd_prev : out std_logic;
153
        full    : out std_logic
154
);
155
end component;
156
 
157
        signal r, w, rp, f      : std_logic_vector(depth-1 downto 0);
158
        type d_array is array (0 to depth-1) of std_logic_vector(width-1 downto 0);
159
        signal di, do           : d_array;
160
 
161
begin
162
 
163
 
164
        g1: for i in 0 to depth-1 generate
165
 
166
                f1: fifo_elem generic map (width)
167
                        port map (clk, reset, di(i), do(i), r(i), w(i), rp(i), f(i));
168
 
169
                x: if i<depth-1 generate
170
                        r(i) <= rp(i+1);
171
                        w(i+1) <= f(i);
172
                        di(i+1) <= do(i);
173
                end generate;
174
 
175
        end generate;
176
 
177
        di(0) <= din;
178
        dout <= do(depth-1);
179
        w(0) <= wr;
180
        r(depth-1) <= rd;
181
 
182
        full <= f(0);
183
        empty <= not f(depth-1);
184
 
185
end rtl;
186
 
187
--
188
--      The UART
189
-- this UART consumes 104 LCs!!! The original version
190
-- was way smaller - let's get it down again.
191
--
192
 
193
library ieee;
194
use ieee.std_logic_1164.all;
195
use ieee.numeric_std.all;
196
 
197
entity uart is
198
 
199
        generic (clk_freq : integer;
200
                         baud_rate : integer;
201
                         txf_depth : integer;
202
                         rxf_depth : integer);
203
        port (
204
                clk             : in std_logic;
205
                reset   : in std_logic;
206
 
207
-- SimpCon interface
208
 
209
                address         : in std_logic;
210
                wr_data         : in std_logic_vector(15 downto 0);
211
                rd, wr          : in std_logic;
212
                rd_data         : out std_logic_vector(15 downto 0);
213
 
214
                txd             : out std_logic;
215
                rxd             : in std_logic
216
                );
217
end uart;
218
 
219
architecture rtl of uart is
220
 
221
        component fifo is
222
 
223
                generic (width : integer; depth : integer);
224
                port (
225
                        clk             : in std_logic;
226
                        reset   : in std_logic;
227
 
228
                        din             : in std_logic_vector(width-1 downto 0);
229
                        dout    : out std_logic_vector(width-1 downto 0);
230
 
231
                        rd              : in std_logic;
232
                        wr              : in std_logic;
233
 
234
                        empty   : out std_logic;
235
                        full    : out std_logic
236
                        );
237
        end component;
238
 
239
--
240
--      signals for uart connection
241
--
242
        signal ua_dout                  : std_logic_vector(7 downto 0);
243
        signal ua_wr, tdre              : std_logic;
244
        signal ua_rd, rdrf              : std_logic;
245
 
246
        type uart_tx_state_type         is (s0, s1);
247
        signal uart_tx_state            : uart_tx_state_type;
248
 
249
        signal tf_dout          : std_logic_vector(7 downto 0); -- fifo out
250
        signal tf_rd            : std_logic;
251
        signal tf_empty         : std_logic;
252
        signal tf_full          : std_logic;
253
 
254
        signal tsr                      : std_logic_vector(9 downto 0); -- tx shift register
255
 
256
        signal tx_clk           : std_logic;
257
 
258
 
259
        type uart_rx_state_type         is (s0, s1, s2);
260
        signal uart_rx_state            : uart_rx_state_type;
261
 
262
        signal rf_wr            : std_logic;
263
        signal rf_empty         : std_logic;
264
        signal rf_full          : std_logic;
265
 
266
        signal rxd_reg          : std_logic_vector(2 downto 0);
267
        signal rx_buf           : std_logic_vector(2 downto 0);  -- sync in, filter
268
        signal rx_d                     : std_logic;                                    -- rx serial data
269
 
270
        signal rsr                      : std_logic_vector(9 downto 0); -- rx shift register
271
 
272
        signal rx_clk           : std_logic;
273
        signal rx_clk_ena       : std_logic;
274
 
275
        constant clk16_cnt      : integer := (clk_freq/baud_rate+8)/16-1;
276
 
277
 
278
begin
279
 
280
        rd_data(15 downto 8) <= (others => '0');
281
 
282
-- This is a single cycle read, different from SimpCon  
283
process(address, rd, rdrf, tdre, ua_dout)
284
begin
285
        ua_rd <= '0';
286
        if address='0' then
287
                rd_data(7 downto 0) <= "000000" & rdrf & tdre;
288
        else
289
                rd_data(7 downto 0) <= ua_dout;
290
                if rd='1' then
291
                        ua_rd <= rd;
292
                end if;
293
        end if;
294
end process;
295
 
296
        -- write is on address offset 1 
297
        ua_wr <= wr and address;
298
 
299
--
300
--      serial clock
301
--
302
        process(clk, reset)
303
 
304
                variable clk16          : integer range 0 to clk16_cnt;
305
                variable clktx          : unsigned(3 downto 0);
306
                variable clkrx          : unsigned(3 downto 0);
307
 
308
        begin
309
                if (reset='1') then
310
                        clk16 := 0;
311
                        clktx := "0000";
312
                        clkrx := "0000";
313
                        tx_clk <= '0';
314
                        rx_clk <= '0';
315
                        rx_buf <= "111";
316
 
317
                elsif rising_edge(clk) then
318
 
319
                        rxd_reg(0) <= rxd;                       -- to avoid setup timing error in Quartus
320
                        rxd_reg(1) <= rxd_reg(0);
321
                        rxd_reg(2) <= rxd_reg(1);
322
 
323
                        if (clk16=clk16_cnt) then               -- 16 x serial clock
324
                                clk16 := 0;
325
--
326
--      tx clock
327
--
328
                                clktx := clktx + 1;
329
                                if (clktx="0000") then
330
                                        tx_clk <= '1';
331
                                else
332
                                        tx_clk <= '0';
333
                                end if;
334
--
335
--      rx clock
336
--
337
                                if (rx_clk_ena='1') then
338
                                        clkrx := clkrx + 1;
339
                                        if (clkrx="1000") then
340
                                                rx_clk <= '1';
341
                                        else
342
                                                rx_clk <= '0';
343
                                        end if;
344
                                else
345
                                        clkrx := "0000";
346
                                end if;
347
--
348
--      sync in filter buffer
349
--
350
                                rx_buf(0) <= rxd_reg(2);
351
                                rx_buf(2 downto 1) <= rx_buf(1 downto 0);
352
                        else
353
                                clk16 := clk16 + 1;
354
                                tx_clk <= '0';
355
                                rx_clk <= '0';
356
                        end if;
357
 
358
 
359
                end if;
360
 
361
        end process;
362
 
363
 
364
--
365
--      transmit fifo
366
--
367
        tf: fifo generic map (8, txf_depth)
368
                port map (clk, reset, wr_data(7 downto 0), tf_dout, tf_rd, ua_wr, tf_empty, tf_full);
369
 
370
--
371
--      state machine for actual shift out
372
--
373
        process(clk, reset)
374
 
375
                variable i : integer range 0 to 11;
376
 
377
        begin
378
 
379
 
380
                if (reset='1') then
381
                        uart_tx_state <= s0;
382
                        tsr <= "1111111111";
383
                        tf_rd <= '0';
384
 
385
                elsif rising_edge(clk) then
386
 
387
                        case uart_tx_state is
388
 
389
                                when s0 =>
390
 
391
                                        i := 0;
392
                                        if tf_empty='0' then
393
                                                uart_tx_state <= s1;
394
                                                -- is there a reason to start with a stop bit?
395
                                                tsr <= tf_dout & '0' & '1';
396
                                                tf_rd <= '1';
397
                                        end if;
398
 
399
                                when s1 =>
400
                                        tf_rd <= '0';
401
                                        if (tx_clk='1') then
402
                                                tsr(9) <= '1';
403
                                                tsr(8 downto 0) <= tsr(9 downto 1);
404
                                                i := i+1;
405
                                                if i=11 then
406
                                                        uart_tx_state <= s0;
407
                                                end if;
408
 
409
                                        end if;
410
 
411
                        end case;
412
 
413
                end if;
414
 
415
        end process;
416
 
417
        txd <= tsr(0);
418
        tdre <= not tf_full;
419
 
420
--
421
--      receive fifo
422
--
423
        rf: fifo generic map (8, rxf_depth)
424
                port map (clk, reset, rsr(8 downto 1), ua_dout, ua_rd, rf_wr, rf_empty, rf_full);
425
 
426
        rdrf <= not rf_empty;
427
 
428
--
429
--      filter rxd
430
--
431
-- TODO: this is not really needed and should go away
432
-- just do a dual FF synchronizer
433
--
434
        with rx_buf select
435
                rx_d <= '0' when "000",
436
                '0' when "001",
437
                '0' when "010",
438
                '1' when "011",
439
                '0' when "100",
440
                '1' when "101",
441
                '1' when "110",
442
                '1' when "111",
443
                'X' when others;
444
 
445
--
446
--      state machine for actual shift in
447
--
448
        process(clk, reset)
449
 
450
                variable i : integer range 0 to 10;
451
 
452
        begin
453
 
454
                if (reset='1') then
455
                        uart_rx_state <= s0;
456
                        rsr <= "0000000000";
457
                        rf_wr <= '0';
458
                        rx_clk_ena <= '0';
459
 
460
                elsif rising_edge(clk) then
461
 
462
                        case uart_rx_state is
463
 
464
 
465
                                when s0 =>
466
                                        i := 0;
467
                                        rf_wr <= '0';
468
                                        if (rx_d='0') then
469
                                                rx_clk_ena <= '1';
470
                                                uart_rx_state <= s1;
471
                                        else
472
                                                rx_clk_ena <= '0';
473
                                        end if;
474
 
475
                                when s1 =>
476
                                        if (rx_clk='1') then
477
                                                rsr(9) <= rx_d;
478
                                                rsr(8 downto 0) <= rsr(9 downto 1);
479
                                                i := i+1;
480
 
481
                                                if i=10 then
482
                                                        uart_rx_state <= s2;
483
                                                end if;
484
                                        end if;
485
 
486
                                when s2 =>
487
                                        rx_clk_ena <= '0';
488
 
489
                                        if rsr(0)='0' and rsr(9)='1' then
490
                                                if rf_full='0' then                              -- if full just drop it
491
                                                        rf_wr <= '1';
492
                                                end if;
493
                                        end if;
494
 
495
                                        uart_rx_state <= s0;
496
 
497
                        end case;
498
                end if;
499
 
500
        end process;
501
 
502
end rtl;

powered by: WebSVN 2.1.0

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