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

Subversion Repositories marca

[/] [marca/] [tags/] [INITIAL/] [vhdl/] [sc_uart.vhd] - Blame information for rev 2

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

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

powered by: WebSVN 2.1.0

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