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

Subversion Repositories simpcon

[/] [simpcon/] [trunk/] [vhdl/] [sc_uart.vhd] - Blame information for rev 29

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 12 martin
--
2 29 martin
--
3
--  This file is a part of JOP, the Java Optimized Processor
4
--
5
--  Copyright (C) 2001-2008, Martin Schoeberl (martin@jopdesign.com)
6
--
7
--  This program is free software: you can redistribute it and/or modify
8
--  it under the terms of the GNU General Public License as published by
9
--  the Free Software Foundation, either version 3 of the License, or
10
--  (at your option) any later version.
11
--
12
--  This program is distributed in the hope that it will be useful,
13
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
--  GNU General Public License for more details.
16
--
17
--  You should have received a copy of the GNU General Public License
18
--  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
--
20
 
21
 
22
--
23 12 martin
--      sc_uart.vhd
24
--
25
--      8-N-1 serial interface
26
--      
27
--      wr, rd should be one cycle long => trde, rdrf goes 0 one cycle later
28
--
29
--      Author: Martin Schoeberl        martin@jopdesign.com
30
--
31
--
32
--      resources on ACEX1K30-3
33
--
34
--              100 LCs, max 90 MHz
35
--
36
--      resetting rts with fifo_full-1 works with C program on pc
37
--      but not with javax.comm: sends some more bytes after deassert
38
--      of rts (16 byte blocks regardless of rts).
39
--      Try to stop with half full fifo.
40
--
41
--      todo:
42
--
43
--
44
--      2000-12-02      first working version
45
--      2002-01-06      changed tdr and rdr to fifos.
46
--      2002-05-15      changed clkdiv calculation
47
--      2002-11-01      don't wait if read fifo is full, just drop the byte
48
--      2002-11-03      use threshold in fifo to reset rts 
49
--                              don't send if cts is '0'
50
--      2002-11-08      rx fifo to 20 characters and stop after 4
51
--      2003-07-05      new IO standard, change cts/rts to neg logic
52
--      2003-09-19      sync ncts in!
53
--      2004-03-23      two stop bits
54
--      2005-11-30      change interface to SimpCon
55 18 martin
--      2006-08-07      rxd input register with clk to avoid Quartus tsu violation
56
--      2006-08-13      use 3 FFs for the rxd input at clk
57 12 martin
--
58
 
59
 
60
library ieee;
61
use ieee.std_logic_1164.all;
62
use ieee.numeric_std.all;
63
 
64
entity sc_uart is
65
 
66
generic (addr_bits : integer;
67
        clk_freq : integer;
68
        baud_rate : integer;
69
        txf_depth : integer; txf_thres : integer;
70
        rxf_depth : integer; rxf_thres : integer);
71
port (
72
        clk             : in std_logic;
73
        reset   : in std_logic;
74
 
75
-- SimpCon interface
76
 
77
        address         : in std_logic_vector(addr_bits-1 downto 0);
78
        wr_data         : in std_logic_vector(31 downto 0);
79
        rd, wr          : in std_logic;
80
        rd_data         : out std_logic_vector(31 downto 0);
81
        rdy_cnt         : out unsigned(1 downto 0);
82
 
83
        txd             : out std_logic;
84
        rxd             : in std_logic;
85
        ncts    : in std_logic;
86
        nrts    : out std_logic
87
);
88
end sc_uart;
89
 
90
architecture rtl of sc_uart is
91
 
92
component fifo is
93
 
94
generic (width : integer; depth : integer; thres : integer);
95
port (
96
        clk             : in std_logic;
97
        reset   : in std_logic;
98
 
99
        din             : in std_logic_vector(width-1 downto 0);
100
        dout    : out std_logic_vector(width-1 downto 0);
101
 
102
        rd              : in std_logic;
103
        wr              : in std_logic;
104
 
105
        empty   : out std_logic;
106
        full    : out std_logic;
107
        half    : out std_logic
108
);
109
end component;
110
 
111
--
112
--      signals for uart connection
113
--
114
        signal ua_dout                  : std_logic_vector(7 downto 0);
115
        signal ua_wr, tdre              : std_logic;
116
        signal ua_rd, rdrf              : std_logic;
117
 
118
        type uart_tx_state_type         is (s0, s1);
119
        signal uart_tx_state            : uart_tx_state_type;
120
 
121
        signal tf_dout          : std_logic_vector(7 downto 0); -- fifo out
122
        signal tf_rd            : std_logic;
123
        signal tf_empty         : std_logic;
124
        signal tf_full          : std_logic;
125
        signal tf_half          : std_logic;
126
 
127
        signal ncts_buf         : std_logic_vector(2 downto 0);  -- sync in
128
 
129
        signal tsr                      : std_logic_vector(9 downto 0); -- tx shift register
130
 
131
        signal tx_clk           : std_logic;
132
 
133
 
134
        type uart_rx_state_type         is (s0, s1, s2);
135
        signal uart_rx_state            : uart_rx_state_type;
136
 
137
        signal rf_wr            : std_logic;
138
        signal rf_empty         : std_logic;
139
        signal rf_full          : std_logic;
140
        signal rf_half          : std_logic;
141
 
142 18 martin
        signal rxd_reg          : std_logic_vector(2 downto 0);
143 12 martin
        signal rx_buf           : std_logic_vector(2 downto 0);  -- sync in, filter
144
        signal rx_d                     : std_logic;                                    -- rx serial data
145
 
146
        signal rsr                      : std_logic_vector(9 downto 0); -- rx shift register
147
 
148
        signal rx_clk           : std_logic;
149
        signal rx_clk_ena       : std_logic;
150
 
151
        constant clk16_cnt      : integer := (clk_freq/baud_rate+8)/16-1;
152
 
153
 
154
begin
155
 
156
        rdy_cnt <= "00";        -- no wait states
157
        rd_data(31 downto 8) <= std_logic_vector(to_unsigned(0, 24));
158
--
159
--      The registered MUX is all we need for a SimpCon read.
160
--      The read data is stored in registered rd_data.
161
--
162
process(clk, reset)
163
begin
164
 
165
        if (reset='1') then
166
                rd_data(7 downto 0) <= (others => '0');
167
        elsif rising_edge(clk) then
168
 
169
                ua_rd <= '0';
170
                if rd='1' then
171
                        -- that's our very simple address decoder
172
                        if address(0)='0' then
173
                                rd_data(7 downto 0) <= "000000" & rdrf & tdre;
174
                        else
175
                                rd_data(7 downto 0) <= ua_dout;
176
                                ua_rd <= rd;
177
                        end if;
178
                end if;
179
        end if;
180
 
181
end process;
182
 
183
        -- write is on address offest 1
184
        ua_wr <= wr and address(0);
185
 
186
--
187
--      serial clock
188
--
189
process(clk, reset)
190
 
191
        variable clk16          : integer range 0 to clk16_cnt;
192
        variable clktx          : unsigned(3 downto 0);
193
        variable clkrx          : unsigned(3 downto 0);
194
 
195
begin
196
        if (reset='1') then
197
                clk16 := 0;
198
                clktx := "0000";
199
                clkrx := "0000";
200
                tx_clk <= '0';
201
                rx_clk <= '0';
202
                rx_buf <= "111";
203
 
204
        elsif rising_edge(clk) then
205
 
206 18 martin
                rxd_reg(0) <= rxd;                       -- to avoid setup timing error in Quartus
207
                rxd_reg(1) <= rxd_reg(0);
208
                rxd_reg(2) <= rxd_reg(1);
209
 
210 12 martin
                if (clk16=clk16_cnt) then               -- 16 x serial clock
211
                        clk16 := 0;
212
--
213
--      tx clock
214
--
215
                        clktx := clktx + 1;
216
                        if (clktx="0000") then
217
                                tx_clk <= '1';
218
                        else
219
                                tx_clk <= '0';
220
                        end if;
221
--
222
--      rx clock
223
--
224
                        if (rx_clk_ena='1') then
225
                                clkrx := clkrx + 1;
226
                                if (clkrx="1000") then
227
                                        rx_clk <= '1';
228
                                else
229
                                        rx_clk <= '0';
230
                                end if;
231
                        else
232
                                clkrx := "0000";
233
                        end if;
234
--
235
--      sync in filter buffer
236
--
237 18 martin
                        rx_buf(0) <= rxd_reg(2);
238 12 martin
                        rx_buf(2 downto 1) <= rx_buf(1 downto 0);
239
                else
240
                        clk16 := clk16 + 1;
241
                        tx_clk <= '0';
242
                        rx_clk <= '0';
243
                end if;
244
 
245
 
246
        end if;
247
 
248
end process;
249
 
250
--
251
--      transmit fifo
252
--
253
        cmp_tf: fifo generic map (8, txf_depth, txf_thres)
254
                        port map (clk, reset, wr_data(7 downto 0), tf_dout, tf_rd, ua_wr, tf_empty, tf_full, tf_half);
255
 
256
--
257
--      state machine for actual shift out
258
--
259
process(clk, reset)
260
 
261
        variable i : integer range 0 to 11;
262
 
263
begin
264
 
265
        if (reset='1') then
266
                uart_tx_state <= s0;
267
                tsr <= "1111111111";
268
                tf_rd <= '0';
269
                ncts_buf <= "111";
270
 
271
        elsif rising_edge(clk) then
272
 
273
                ncts_buf(0) <= ncts;
274
                ncts_buf(2 downto 1) <= ncts_buf(1 downto 0);
275
 
276
                case uart_tx_state is
277
 
278
                        when s0 =>
279
                                i := 0;
280
                                if (tf_empty='0' and ncts_buf(2)='0') then
281
                                        uart_tx_state <= s1;
282
                                        tsr <= tf_dout & '0' & '1';
283
                                        tf_rd <= '1';
284
                                end if;
285
 
286
                        when s1 =>
287
                                tf_rd <= '0';
288
                                if (tx_clk='1') then
289
                                        tsr(9) <= '1';
290
                                        tsr(8 downto 0) <= tsr(9 downto 1);
291
                                        i := i+1;
292
                                        if (i=11) then                          -- two stop bits
293
                                                uart_tx_state <= s0;
294
                                        end if;
295
                                end if;
296
 
297
                end case;
298
        end if;
299
 
300
end process;
301
 
302
        txd <= tsr(0);
303
        tdre <= not tf_full;
304
 
305
 
306
--
307
--      receive fifo
308
--
309
        cmp_rf: fifo generic map (8, rxf_depth, rxf_thres)
310
                        port map (clk, reset, rsr(8 downto 1), ua_dout, ua_rd, rf_wr, rf_empty, rf_full, rf_half);
311
 
312
        rdrf <= not rf_empty;
313
        nrts <= rf_half;                        -- glitches even on empty fifo!
314
 
315
--
316
--      filter rxd
317
--
318
        with rx_buf select
319
                rx_d <= '0' when "000",
320
                                '0' when "001",
321
                                '0' when "010",
322
                                '1' when "011",
323
                                '0' when "100",
324
                                '1' when "101",
325
                                '1' when "110",
326
                                '1' when "111",
327
                                'X' when others;
328
 
329
--
330
--      state machine for actual shift in
331
--
332
process(clk, reset)
333
 
334
        variable i : integer range 0 to 10;
335
 
336
begin
337
 
338
        if (reset='1') then
339
                uart_rx_state <= s0;
340
                rsr <= "0000000000";
341
                rf_wr <= '0';
342
                rx_clk_ena <= '0';
343
 
344
        elsif rising_edge(clk) then
345
 
346
                case uart_rx_state is
347
 
348
 
349
                        when s0 =>
350
                                i := 0;
351
                                rf_wr <= '0';
352
                                if (rx_d='0') then
353
                                        rx_clk_ena <= '1';
354
                                        uart_rx_state <= s1;
355
                                else
356
                                        rx_clk_ena <= '0';
357
                                end if;
358
 
359
                        when s1 =>
360
                                if (rx_clk='1') then
361
                                        rsr(9) <= rx_d;
362
                                        rsr(8 downto 0) <= rsr(9 downto 1);
363
                                        i := i+1;
364
                                        if (i=10) then
365
                                                uart_rx_state <= s2;
366
                                        end if;
367
                                end if;
368
 
369
                        when s2 =>
370
                                rx_clk_ena <= '0';
371
                                if rsr(0)='0' and rsr(9)='1' then
372
                                        if rf_full='0' then                              -- if full just drop it
373
                                                rf_wr <= '1';
374
                                        end if;
375
                                end if;
376
                                uart_rx_state <= s0;
377
 
378
                end case;
379
        end if;
380
 
381
end process;
382
 
383
end rtl;

powered by: WebSVN 2.1.0

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