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

Subversion Repositories uart_fifo_cpu_if_sv_testbench

[/] [uart_fifo_cpu_if_sv_testbench/] [trunk/] [rtl/] [uart.vhd] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 andrewbrid
----------------------------------------------------------------------
2
----                                                              ----
3
----  UART and FIFO cpu interface                                 ----
4
----                                                              ----
5
----  This file is part of the xxx project                        ----
6
----  http://www.opencores.org/cores/xxx/                         ----
7
----                                                              ----
8
----  Description                                                 ----
9
--             Serial UART with byte wide register interface for control/status, data, and baud rate.
10
--             Transmit(Tx) and Receive(Rx) data is FIFO buffered. Tx and Rx FIFO size configurable independently.
11
--             Currently only supports no parity, 8 data bits, 1 stop bit (N81).
12 3 andrewbrid
--             Data is sent least significant bit first.
13 2 andrewbrid
--             Baud rate divisor set via 16 bit register, allowing a wide range of baud rates and system clocks.
14
--
15
--             Future:
16
--              - insertion and checking of parity bit
17
--              - data bit order configurable
18
--              - number of data bits configurable
19
--              - cts/rts
20
--              - interrupt on rx data ready and/or tx fifo empty
21
--
22
--Registers: 0x00: Data:
23
--                    Write this register to push data into the transmit FIFO. The UART
24
--                    empties the FIFO and transmits data at the specified baud rate.
25
--                    If the FIFO is full, writes are ignored.
26
--                    Read this register to pull data from the receive FIFO. If the FIFO
27
--                    is empty, reading returns the previously read value.
28
--           0x01: Control/Status:
29
--                    bit0: Rx FIFO data ready:     High when data waiting in the rx FIFO.
30
--                    bit1: Rx FIFO overflow flag:  High if overflow occurs. Write 0 to clear.
31
--                    bit2: Rx stop bit error flag: High if invalid stop bit. Write 0 to clear.
32
--                    bit3: Tx FIFO full:           High when the tx FIFO is full.        
33
--                    bit4: Tx FIFO overflow flag:  High if overflow occurs. Write 0 to clear.
34
--                    bit5: unused
35
--                    bit6: Cpu interface facing loopback enable: loopback is at serial txd/rxd pins
36
--                    bit7: Txd/rxd pin facing loopback enable: loopback is at txd/rxd pins
37
--                          (both loopbacks can be enabled at the same time)
38
--
39
--           0x02: Baud Rate Divisor LSB: baud rate = System clock / (baud rate divisor+1)
40
--           0x03: Baud Rate Divisor MSB: e.g. set to 433 to get 115200 with a 50MHz
41
--                                        system clock. Error is < 0.01%. 
42
--
43
-- Fmax and resource use data:
44
--
45
----  To Do:                                                      ----
46
----   -                                                          ----
47
----                                                              ----
48
----  Author(s):                                                  ----
49
----      - Andrew Bridger, andrew.bridger@gmail.org              ----
50
----                                                              ----
51
----------------------------------------------------------------------
52
----                                                              ----
53
---- Copyright (C) 2001 Authors and OPENCORES.ORG                 ----
54
----                                                              ----
55
---- This source file may be used and distributed without         ----
56
---- restriction provided that this copyright statement is not    ----
57
---- removed from the file and that any derivative work contains  ----
58
---- the original copyright notice and the associated disclaimer. ----
59
----                                                              ----
60
---- This source file is free software; you can redistribute it   ----
61
---- and/or modify it under the terms of the GNU Lesser General   ----
62
---- Public License as published by the Free Software Foundation; ----
63
---- either version 2.1 of the License, or (at your option) any   ----
64
---- later version.                                               ----
65
----                                                              ----
66
---- This source is distributed in the hope that it will be       ----
67
---- useful, but WITHOUT ANY WARRANTY; without even the implied   ----
68
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ----
69
---- PURPOSE.  See the GNU Lesser General Public License for more ----
70
---- details.                                                     ----
71
----                                                              ----
72
---- You should have received a copy of the GNU Lesser General    ----
73
---- Public License along with this source; if not, download it   ----
74
---- from http://www.opencores.org/lgpl.shtml                     ----
75
----                                                              ----
76
----------------------------------------------------------------------
77
--
78
-- CVS Revision History
79
--
80
-- $Log$
81
--
82
 
83
library ieee;
84
use ieee.std_logic_1164.all;
85
use ieee.numeric_std.all;
86
 
87
entity uart is
88
  generic(
89
    BASE_ADDR           : natural := 0;                --Uart registers are offset from
90
                                                       -- this base address.
91
    TX_FIFO_ADDR_LENGTH : natural := 5;                --5 length addr => 32 byte deep FIFO
92
    RX_FIFO_ADDR_LENGTH : natural := 5
93
    );
94
  port(
95
    clk            : in  std_logic;                    --all inputs(except rxd) MUST be synchronous to clk.
96
    reset          : in  std_logic;                    --synchronous reset
97
    --Serial UART
98
    i_rxd          : in  std_logic;                    --receive serial data (asynchronous)
99
    o_txd          : out std_logic;                    --transmit serial data
100
    --Cpu register interface
101 4 andrewbrid
    i_addr         : in  std_logic_vector;             --highest index is msb of address.
102 2 andrewbrid
    i_write_enable : in  std_logic;                    --high for 1 clk period for a write
103
    i_read_enable  : in  std_logic;                    --high for 1 clk period for a read
104
    i_data         : in  std_logic_vector(7 downto 0);
105
    o_data         : out std_logic_vector(7 downto 0)  --data returned up to 2 clock cycles after read_enable
106
    );
107
end uart;
108
 
109
architecture rtl of uart is
110
 
111
  signal rxd_d1, rxd_clean : std_logic;
112
 
113
  --FIFO from/to main process communication.
114
  signal tx_fifo_write_data, tx_fifo_read_data       : std_logic_vector(7 downto 0);
115
  signal tx_fifo_write_request, tx_fifo_read_request : std_logic;
116
  signal rx_fifo_write_data, rx_fifo_read_data       : std_logic_vector(7 downto 0);
117
  signal rx_fifo_write_request, rx_fifo_read_request : std_logic;
118
  signal rx_fifo_read_request_d1                     : std_logic;
119
  signal tx_fifo_full_flag                           : std_logic;
120
  signal tx_fifo_overflow                            : std_logic;
121
  signal tx_fifo_empty, tx_fifo_data_waiting         : std_logic;
122
  signal rx_fifo_overflow                            : std_logic;
123
  signal rx_fifo_empty                               : std_logic;
124
  signal rx_fifo_data_ready_flag                     : std_logic;
125
 
126
  --Cpu regs/bits
127
  signal rx_fifo_overflow_flag    : std_logic;
128
  signal tx_fifo_overflow_flag    : std_logic;
129
  signal rx_stop_bit_invalid_flag : std_logic;
130
 
131
  signal cpu_facing_loopback_enable     : std_logic;
132
  signal serial_facing_loopback_enable  : std_logic;
133
  --Baud rate divisor for 50MHz system clock and 115200 baud rate.
134
  constant BAUD_RATE_DIVISOR_50M_115200 : std_logic_vector(15 downto 0) := std_logic_vector(to_unsigned(433, 16));
135
  signal baud_rate_divisor_slv          : std_logic_vector(15 downto 0);
136
  --cpu register addresses and bit indexes
137
  constant DATA_REG                     : std_logic_vector(1 downto 0)  := "00";
138
  constant CONTROL_STATUS_REG           : std_logic_vector(1 downto 0)  := "01";
139
  constant BAUD_RATE_DIVISOR_LSB_REG    : std_logic_vector(1 downto 0)  := "10";
140
  constant BAUD_RATE_DIVISOR_MSB_REG    : std_logic_vector(1 downto 0)  := "11";
141
  constant BASE_ADDR_SLV                : std_logic_vector(i_addr'length-1 downto 0)
142
    := std_logic_vector(to_unsigned(BASE_ADDR, i_addr'length));
143
 
144
begin
145
 
146
  main : process(clk)
147
    type uart_state_t is (IDLE, START, DATA, STOP);
148
    variable tx_state, rx_state : uart_state_t;
149
    subtype baud_rate_t is natural range 0 to (2**16)-1;
150
    variable baud_rate_divisor  : baud_rate_t;
151
    variable tx_baud_rate_count : baud_rate_t;
152
    variable rx_baud_rate_count : baud_rate_t;
153
    variable tx_data_count      : natural range 0 to 7;
154
    variable rx_data_count      : natural range 0 to 7;
155
    variable rx_bit_enable      : boolean;
156
    variable tx_bit_enable      : boolean;
157
    variable chip_select        : boolean;
158
    variable rxd, txd           : std_logic;
159
    variable addr               : std_logic_vector(i_addr'length-1 downto 0);
160
  begin
161
    if rising_edge(clk) then
162
      if reset = '1' then
163
        --Keep uart serial lines high during reset. Don't want any glitches at startup.
164
        rxd_d1                        <= '1';
165
        rxd_clean                     <= '1';
166
        rxd                           := '1';
167
        txd                           := '1';
168
        o_txd                         <= '1';
169
        --Put UART rx/tx FSMs and counters into a known state at reset.
170
        tx_state                      := IDLE;
171
        rx_state                      := IDLE;
172
        tx_baud_rate_count            := 0;
173
        rx_baud_rate_count            := 0;
174
        tx_fifo_write_request         <= '0';
175
        tx_fifo_read_request          <= '0';
176
        rx_fifo_write_request         <= '0';
177
        rx_fifo_read_request          <= '0';
178
        --Power up state for registers
179
        baud_rate_divisor_slv         <= BAUD_RATE_DIVISOR_50M_115200;  --set default for 115200
180
        rx_fifo_overflow_flag         <= '0';
181
        rx_stop_bit_invalid_flag      <= '0';
182
        tx_fifo_overflow_flag         <= '0';
183
        cpu_facing_loopback_enable    <= '0';
184
        serial_facing_loopback_enable <= '0';
185
        --Check base addr on x4 byte boundary.
186
        --Only check during reset so no burden on sim speed. (Synplicity doesn't honour this assert unfortunately.)
187
        assert BASE_ADDR_SLV(1 downto 0) = "00" report "UART Base address must be 32 bit aligned. I.e. 2 LSBs must be 00"
188
          severity failure;
189
      else
190
        ------[CPU Interface]------
191
        --CPU interface side of rx and tx fifos. Including the registers directly within this module means
192
        --this is a self-contained module.
193
        addr        := i_addr;                                          --ensure addr is in "downto" form.
194
        chip_select := (addr(addr'high downto 2) = BASE_ADDR_SLV(BASE_ADDR_SLV'high downto 2));
195
        if chip_select then
196
          --Cpu register write.
197
          if i_write_enable = '1' then
198
            case i_addr(1 downto 0) is
199
              when DATA_REG =>
200
                tx_fifo_write_data    <= i_data;
201
                tx_fifo_write_request <= '1';
202
              when CONTROL_STATUS_REG =>
203
                --Some bits are only write zero to clear.
204
                if i_data(1) = '0' then
205
                  rx_fifo_overflow_flag <= '0';
206
                end if;
207
                if i_data(2) = '0' then
208
                  rx_stop_bit_invalid_flag <= '0';
209
                end if;
210
                if i_data(4) = '0' then
211
                  tx_fifo_overflow_flag <= '0';
212
                end if;
213
                --Standard read/write control bits
214
                cpu_facing_loopback_enable    <= i_data(6);
215
                serial_facing_loopback_enable <= i_data(7);
216
 
217
              when BAUD_RATE_DIVISOR_LSB_REG => baud_rate_divisor_slv(7 downto 0)  <= i_data;
218
              when BAUD_RATE_DIVISOR_MSB_REG => baud_rate_divisor_slv(15 downto 8) <= i_data;
219
              when others                    => null;
220
            end case;
221
          end if;
222
          --Cpu register read.
223
          if i_read_enable = '1' then
224
            case i_addr(1 downto 0) is
225
              when DATA_REG           => rx_fifo_read_request <= '1';
226
              when CONTROL_STATUS_REG => o_data               <= serial_facing_loopback_enable &
227
                                                                 cpu_facing_loopback_enable &
228
                                                                 '0' &  --unused
229
                                                                 tx_fifo_overflow_flag &
230
                                                                 tx_fifo_full_flag &
231
                                                                 rx_stop_bit_invalid_flag &
232
                                                                 rx_fifo_overflow_flag &
233
                                                                 rx_fifo_data_ready_flag;
234
              when BAUD_RATE_DIVISOR_LSB_REG => o_data <= baud_rate_divisor_slv(7 downto 0);
235
              when BAUD_RATE_DIVISOR_MSB_REG => o_data <= baud_rate_divisor_slv(15 downto 8);
236
              when others                    => null;
237
            end case;
238
          end if;
239
        end if;
240
        --Takes 1 clock to read data out of rx fifo.
241
        rx_fifo_read_request_d1 <= rx_fifo_read_request;
242
        if rx_fifo_read_request_d1 = '1' then
243
          o_data <= rx_fifo_read_data;
244
        end if;
245
        --type conversion for baud rate divisor.
246
        baud_rate_divisor := to_integer( unsigned( baud_rate_divisor_slv ));
247
 
248
        ------[UART Transmit (tx) FSM]------
249
        tx_fifo_read_request <= '0';    --default
250
        case tx_state is
251
          when IDLE =>
252
            txd := '1';
253
            if tx_fifo_data_waiting = '1' then
254
              tx_state             := START;
255
              tx_fifo_read_request <= '1';
256
            end if;
257
          --output 1 start bit
258
          when START =>
259
            if tx_bit_enable then
260
              txd           := '0';
261
              tx_state      := DATA;
262 3 andrewbrid
              tx_data_count := 0;
263 2 andrewbrid
            end if;
264 3 andrewbrid
          --output 8 data bits, least significant bit first.
265 2 andrewbrid
          when DATA =>
266
            if tx_bit_enable then
267
              txd := tx_fifo_read_data(tx_data_count);
268 3 andrewbrid
              if tx_data_count = 7 then
269 2 andrewbrid
                tx_state := STOP;
270
              else
271 3 andrewbrid
                tx_data_count := tx_data_count + 1;
272 2 andrewbrid
              end if;
273
            end if;
274
          --output 1 stop bit
275
          when STOP =>
276
            if tx_bit_enable then
277
              txd      := '1';
278
              tx_state := IDLE;
279
            end if;
280
        end case;
281
 
282
        --transmit baud rate "clk" (enable)
283
        if tx_baud_rate_count = 0 then
284
          tx_baud_rate_count := baud_rate_divisor;
285
          tx_bit_enable      := true;
286
        else
287
          tx_baud_rate_count := tx_baud_rate_count - 1;
288
          tx_bit_enable      := false;
289
        end if;
290
 
291
        ------[UART Receive (rx) FSM]------
292
        rx_fifo_write_request <= '0';
293
        case rx_state is
294
          when IDLE =>
295
            if rxd = '0' then
296
              rx_state           := START;
297
              rx_baud_rate_count := baud_rate_divisor/2;  --setup baud rate counter so we sample
298
                                                          --at middle of bit period
299
            end if;
300
          --look for a start bit that is continuously low for at least 1/2 the nominal bit
301
          --period. This helps to filter short duration glitches. And gets us sampling
302
          --rxd at the center of a bit period.
303
          when START =>
304
            if rxd /= '0' then
305
              --start bit has not stayed low for longer than 1/2 a bit period.
306
              rx_state := IDLE;
307
            elsif rx_bit_enable then
308
              rx_state      := DATA;
309 3 andrewbrid
              rx_data_count := 0;
310 2 andrewbrid
            end if;
311
          --read in 8 data bits.
312
          when DATA =>
313
            if rx_bit_enable then
314
              rx_fifo_write_data(rx_data_count) <= rxd;
315 3 andrewbrid
              if rx_data_count = 7 then
316 2 andrewbrid
                rx_state := STOP;
317
              else
318 3 andrewbrid
                rx_data_count := rx_data_count + 1;
319 2 andrewbrid
              end if;
320
            end if;
321
          --check stop bit is '1'. If not, set the rx error flag.
322
          when STOP =>
323
            if rx_bit_enable then
324
              if rxd = '1' then
325
                --Valid stop bit, so attempt to write the received byte to the rx fifo.
326
                rx_fifo_write_request <= '1';
327
              else
328
                --Invalid stop bit.
329
                rx_stop_bit_invalid_flag <= '1';
330
              end if;
331
              rx_state := IDLE;
332
            end if;
333
        end case;
334
 
335
        --receive baud rate "clk" (enable)
336
        if rx_baud_rate_count = 0 then
337
          rx_baud_rate_count := baud_rate_divisor;
338
          rx_bit_enable      := true;
339
        else
340
          rx_baud_rate_count := rx_baud_rate_count - 1;
341
          rx_bit_enable      := false;
342
        end if;
343
 
344
        ------[Latch FIFO overflow bits]------
345
        if tx_fifo_overflow = '1' then
346
          tx_fifo_overflow_flag <= '1';
347
        end if;
348
        if rx_fifo_overflow = '1' then
349
          rx_fifo_overflow_flag <= '1';
350
        end if;
351
 
352
        ------[Loopbacks and Rxd Retime]------
353
        --rxd is an asynchronous input so retime it onto the system clock domain.
354
        rxd_d1    <= i_rxd;
355
        rxd_clean <= rxd_d1;
356
        if cpu_facing_loopback_enable = '0' then
357
          --normal operation.
358
          rxd := rxd_clean;
359
        else
360
          --loopback enabled.
361
          rxd := txd;
362
        end if;
363
        if serial_facing_loopback_enable = '0' then
364
          --normal operation.
365
          o_txd <= txd;
366
        else
367
          --loopback enabled.
368
          o_txd <= rxd_clean;
369
        end if;
370
      end if;
371
    end if;
372
  end process;
373
 
374
  tx_fifo : entity work.synchronous_FIFO(rtl)
375
    generic map (
376
      ADDR_LENGTH => TX_FIFO_ADDR_LENGTH,
377
      DATA_WIDTH  => 8)
378
    port map (
379
      clk           => clk,
380
      reset         => reset,
381
      write_data    => tx_fifo_write_data,
382
      write_request => tx_fifo_write_request,
383
      full          => tx_fifo_full_flag,
384
      overflow      => tx_fifo_overflow,
385
      read_data     => tx_fifo_read_data,
386
      read_request  => tx_fifo_read_request,
387
      empty         => tx_fifo_empty,
388
      underflow     => open,
389
      half_full     => open);
390
 
391
  tx_fifo_data_waiting <= not tx_fifo_empty;
392
 
393
  rx_fifo : entity work.synchronous_FIFO(rtl)
394
    generic map (
395
      ADDR_LENGTH => RX_FIFO_ADDR_LENGTH,
396
      DATA_WIDTH  => 8)
397
    port map (
398
      clk           => clk,
399
      reset         => reset,
400
      write_data    => rx_fifo_write_data,
401
      write_request => rx_fifo_write_request,
402
      full          => open,
403
      overflow      => rx_fifo_overflow,
404
      read_data     => rx_fifo_read_data,
405
      read_request  => rx_fifo_read_request,
406
      empty         => rx_fifo_empty,
407
      underflow     => open,
408
      half_full     => open);
409
 
410
  rx_fifo_data_ready_flag <= not rx_fifo_empty;
411
end rtl;

powered by: WebSVN 2.1.0

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