一个简单的UART.vhd
上传用户:easylife05
上传日期:2013-03-21
资源大小:42k
文件大小:10k
- ----------------------------------------------------------------
- --
- -- Copyright (c) 1992,1993,1994, Exemplar Logic Inc. All rights reserved.
- --
- ----------------------------------------------------------------
- --
- -- This design implements a UART.
- --
- --
- -- Version 1.1 : Original Creation
- -- Version 1.2 : Modified to std_logic types
- -- Version 2.1 : Extended reset to be more effective.
- -- Introduced OTHERS clause.
- -- download from: www.pld.com.cn & www.fpga.com.cn
- ----------------------------------------------------------------
- LIBRARY ieee;
- use ieee.std_logic_1164.all;
- use ieee.std_logic_arith.all;
- use ieee.std_logic_unsigned.all;
- ENTITY uart IS
- PORT (clkx16 : IN std_logic; -- Input clock. 16x bit clock
- read : IN std_logic; -- Received data read strobe
- write : IN std_logic; -- Transmit data write strobe
- rx : IN std_logic; -- Receive data line
- reset : IN std_logic; -- clear dependencies
- tx : OUT std_logic; -- Transmit data line
- rxrdy : OUT std_logic; -- Received data ready to be read
- txrdy : OUT std_logic; -- Transmitter ready for next byte
- parityerr : OUT std_logic; -- Receiver parity error
- framingerr : OUT std_logic; -- Receiver framing error
- overrun : OUT std_logic; -- Receiver overrun error
- data : INOUT std_logic_vector(0 TO 7)); -- Bidirectional data bus
- END uart;
- ARCHITECTURE exemplar OF uart IS
- -- Transmit data holding register
- SIGNAL txhold : std_logic_vector(0 TO 7);
- -- Transmit shift register bits
- SIGNAL txreg : std_logic_vector(0 TO 7);
- SIGNAL txtag2 : std_logic; -- tag bits for detecting
- SIGNAL txtag1 : std_logic; -- empty shift reg
- SIGNAL txparity : std_logic; -- Parity generation register
- -- Transmit clock and control signals
- SIGNAL txclk : std_logic; -- Transmit clock: 1/16th of clkx16
- SIGNAL txdone : std_logic; -- '1' when shifting of byte is done
- SIGNAL paritycycle : std_logic; -- '1' on next to last shift cycle
- SIGNAL txdatardy : std_logic; -- '1' when data is ready in txhold
- -- Receive shift register bits
- SIGNAL rxhold : std_logic_vector(0 TO 7);-- Holds received data for read
- SIGNAL rxreg : std_logic_vector(0 TO 7);-- Receive data shift register
- SIGNAL rxparity : std_logic; -- Parity bit of received data
- SIGNAL paritygen : std_logic; -- Generated parity of received data
- SIGNAL rxstop : std_logic; -- Stop bit of received data
- -- Receive clock and control signals
- SIGNAL rxclk : std_logic; -- Receive data shift clock
- SIGNAL rxidle : std_logic; -- '1' when receiver is idling
- SIGNAL rxdatardy : std_logic; -- '1' when data is ready to be read
- BEGIN
- make_txclk:
- PROCESS (reset, clkx16)
- VARIABLE cnt : std_logic_vector(2 DOWNTO 0);
- BEGIN
- -- Toggle txclk every 8 counts, which divides the clock by 16
- IF reset='1' THEN
- txclk <= '0' ;
- cnt := (OTHERS=>'0') ;
- ELSIF clkx16'event AND clkx16='1' THEN
- IF (cnt = "000") THEN
- txclk <= NOT txclk;
- END IF;
- cnt := cnt + "001"; -- Use the exemplar_1164 "+" on std_logic_vector
- END IF;
- END PROCESS;
- make_rxclk:
- PROCESS (reset, clkx16)
- VARIABLE rxcnt : std_logic_vector(0 TO 3); -- Count of clock cycles
- VARIABLE rx1 : std_logic; -- rx delayed one cycle
- VARIABLE hunt : boolean; -- Hunting for start bit
- BEGIN
- IF reset='1' THEN
- -- Reset all generated signals and variables
- hunt := FALSE ;
- rxcnt := (OTHERS=>'0') ;
- rx1 := '0' ;
- rxclk <= '0' ;
- ELSIF clkx16'EVENT AND clkx16 = '1' THEN
- -- rxclk = clkx16 divided by 16
- rxclk <= rxcnt(0);
- -- Hunt=TRUE when we are looking for a start bit:
- -- A start bit is eight clock times with rx=0 after a falling edge
- IF (rxidle = '1' AND rx = '0' AND rx1 = '1') THEN
- -- Start hunting when idle and falling edge is found
- hunt := TRUE;
- END IF ;
- IF rxidle = '0' OR rx = '1' THEN
- -- Stop hunting when shifting in data or a 1 is found on rx
- hunt := FALSE;
- END IF;
- rx1 := rx; -- rx delayed by one clock for edge detection
- -- (Must be assigned AFTER reference)
- -- Increment count when not idling or when hunting
- IF (rxidle = '0' OR hunt) THEN
- -- Count clocks when not rxidle or hunting for start bit
- rxcnt := rxcnt + "0001";
- ELSE
- -- hold at 1 when rxidle and waiting for falling edge
- rxcnt := "0001";
- END IF;
- END IF ;
- END PROCESS;
- -- transmit shift register:
- txshift:
- PROCESS (reset, txclk)
- BEGIN
- IF reset='1' THEN
- txreg <= (OTHERS=>'0') ;
- txtag1 <= '0' ;
- txtag2 <= '0' ;
- txparity <= '0' ;
- tx <= '0' ;
- ELSIF txclk'event AND txclk = '1' THEN
- IF (txdone AND txdatardy) = '1' THEN
- -- Initialize registers and load next byte of data
- txreg <= txhold; -- Load tx register from txhold
- txtag2 <= '1'; -- Tag bits for detecting
- txtag1 <= '1'; -- when shifting is done
- txparity <= '1'; -- Parity bit.Initializing to 1==odd parity
- tx <= '0'; -- Start bit
- ELSE
- -- Shift data
- txreg <= txreg(1 TO 7) & txtag1;
- txtag1 <= txtag2;
- txtag2 <= '0';
- -- Form parity as each bit goes by
- txparity <= txparity XOR txreg(0);
- -- Shift out data or parity bit or stop/idle bit
- IF txdone = '1' THEN
- tx <= '1'; -- stop/idle bit
- ELSIF paritycycle = '1' THEN
- tx <= txparity; -- Parity bit
- ELSE
- tx <= txreg(0); --Shift data bit
- END IF;
- END IF ;
- END IF;
- END PROCESS;
- -- paritycycle = 1 on next to last cycle (When txtag2 has reached txreg(1))
- -- (Enables putting the parity bit out on tx)
- paritycycle <= txreg(1) AND NOT (txtag2 OR txtag1 OR
- txreg(7) OR txreg(6) OR txreg(5) OR
- txreg(4) OR txreg(3) OR txreg(2));
- -- txdone = 1 when done shifting (When txtag2 has reached tx)
- txdone <= NOT (txtag2 OR txtag1 OR
- txreg(7) OR txreg(6) OR txreg(5) OR txreg(4) OR
- txreg(3) OR txreg(2) OR txreg(1) OR txreg(0));
- rx_proc: -- Shift data on each rxclk when not idling
- PROCESS (reset, rxclk)
- BEGIN
- IF reset='1' THEN
- rxreg <= (OTHERS=>'0') ;
- rxparity <= '0' ;
- paritygen <= '0' ;
- rxstop <= '0' ;
- ELSIF rxclk'event AND rxclk = '1' THEN
- IF rxidle = '1' THEN
- -- Load all ones when idling
- rxreg <= (OTHERS=>'1');
- rxparity <= '1';
- paritygen <= '1'; -- Odd parity
- rxstop <= '0';
- ELSE
- -- Shift data when not idling
- -- bug in assigning to slices
- -- rxreg (0 TO 6) <= rxreg (1 TO 7);
- -- rxreg(7) <= rxparity;
- rxreg <= rxreg (1 TO 7) & rxparity;
- rxparity <= rxstop;
- paritygen <= paritygen XOR rxstop;-- Form parity as data shifts by
- rxstop <= rx;
- END IF ;
- END IF;
- END PROCESS;
-
- async: -- rxidle requires async preset since it is clocked by rxclk and
- -- its value determines whether rxclk gets generated
- PROCESS ( reset, rxclk )
- BEGIN
- IF reset = '1' THEN
- rxidle <= '0';
- ELSIF rxclk'EVENT and rxclk = '1' THEN
- rxidle <= NOT rxidle AND NOT rxreg(0);
- END IF;
- END PROCESS async;
- txio: -- Load txhold and set txdatardy on falling edge of write
- -- Clear txdatardy on falling edge of txdone
- PROCESS (reset, clkx16)
- VARIABLE wr1,wr2: std_logic; -- write signal delayed 1 and 2 cycles
- VARIABLE txdone1: std_logic; -- txdone signal delayed one cycle
- BEGIN
- IF reset='1' THEN
- txdatardy <= '0' ;
- wr1 := '0' ;
- wr2 := '0' ;
- txdone1 := '0' ;
- ELSIF clkx16'event AND clkx16 = '1' THEN
- IF wr1 = '0' AND wr2= '1' THEN
- -- Falling edge on write signal. New data in txhold latches
- txdatardy <= '1';
- ELSIF txdone = '0' AND txdone1 = '1' THEN
- -- Falling edge on txdone signal. Txhold has been read.
- txdatardy <= '0';
- END IF;
- -- Delayed versions of write and txdone signals for edge detection
- wr2 := wr1;
- wr1 := write;
- txdone1 := txdone;
- END IF ;
- END PROCESS;
- rxio:
- PROCESS (reset, clkx16)
- VARIABLE rd1, rd2 : std_logic; -- Read input delayed 1 and 2 cycles
- VARIABLE rxidle1 : std_logic; -- rxidle signal delayed 1 cycle
- BEGIN
- IF reset='1' THEN
- overrun <= '0' ;
- rxhold <= (OTHERS=>'0') ;
- parityerr <= '0' ;
- framingerr <= '0' ;
- rxdatardy <= '0' ;
- rd1 := '0' ;
- rd2 := '0' ;
- rxidle1 := '0' ;
- ELSIF clkx16'event AND clkx16 = '1' THEN
- -- Look for rising edge on idle and update output registers
- IF rxidle = '1' AND rxidle1 = '0' THEN
- IF rxdatardy = '1' THEN
- -- Overrun error if previous data is still there
- overrun <= '1';
- ELSE
- -- No overrun error since holding register is empty
- overrun <= '0';
- -- Update holding register
- rxhold <= rxreg;
- -- paritygen = 1 if parity error
- parityerr <= paritygen;
- -- Framingerror if stop bit is not 1
- framingerr <= NOT rxstop;
- -- Signal that data is ready for reading
- rxdatardy <= '1';
- END IF;
- END IF;
- rxidle1 := rxidle; -- rxidle delayed 1 cycle for edge detect
- -- Clear error and data registers when data is read
- IF (NOT rd2 AND rd1) = '1' THEN
- rxdatardy <= '0';
- parityerr <= '0';
- framingerr <= '0';
- overrun <= '0';
- END IF;
- rd2 := rd1; -- Edge detect for read
- rd1 := read; -- (Must be assigned AFTER reference)
- IF reset = '1' THEN
- rxdatardy <= '0';
- END IF;
- END IF ;
- END PROCESS;
- -- Drive data bus only during read
- data <= rxhold WHEN read = '1' ELSE (OTHERS=>'Z') ;
- -- Latch data bus during write
- txhold <= data WHEN write = '1' ELSE txhold;
- -- Receive data ready output signal
- rxrdy <= rxdatardy;
- -- Transmitter ready for write when no data is in txhold
- txrdy <= NOT txdatardy;
- -- Run-time simulation check for transmit overrun
- ASSERT write = '0' OR txdatardy = '0'
- REPORT "Transmitter overrun error" SEVERITY WARNING;
- END exemplar;