一个简单的UART.vhd
上传用户:easylife05
上传日期:2013-03-21
资源大小:42k
文件大小:10k
源码类别:

VHDL/FPGA/Verilog

开发平台:

C/C++

  1. ----------------------------------------------------------------
  2. --
  3. -- Copyright (c) 1992,1993,1994, Exemplar Logic Inc. All rights reserved.
  4. --
  5. ----------------------------------------------------------------
  6. --
  7. -- This design implements a UART. 
  8. --
  9. -- 
  10. --     Version 1.1 : Original Creation
  11. --     Version 1.2 : Modified to std_logic types
  12. --     Version 2.1 : Extended reset to be more effective.
  13. --                   Introduced OTHERS clause.
  14. -- download from: www.pld.com.cn & www.fpga.com.cn 
  15. ----------------------------------------------------------------
  16. LIBRARY ieee;
  17. use ieee.std_logic_1164.all;
  18. use ieee.std_logic_arith.all;
  19. use ieee.std_logic_unsigned.all;
  20. ENTITY uart IS
  21.     PORT (clkx16 : IN    std_logic; -- Input clock. 16x bit clock
  22.             read : IN    std_logic; -- Received data read strobe
  23.            write : IN    std_logic; -- Transmit data write strobe
  24.       rx : IN    std_logic; -- Receive  data line
  25.    reset : IN    std_logic; -- clear dependencies
  26.       tx : OUT   std_logic; -- Transmit data line
  27.            rxrdy : OUT   std_logic; -- Received data ready to be read
  28.            txrdy : OUT   std_logic; -- Transmitter ready for next byte
  29.        parityerr : OUT   std_logic; -- Receiver parity error
  30.       framingerr : OUT   std_logic; -- Receiver framing error
  31.          overrun : OUT   std_logic; -- Receiver overrun error 
  32.     data : INOUT std_logic_vector(0 TO 7)); -- Bidirectional data bus
  33. END uart;
  34. ARCHITECTURE exemplar OF uart IS
  35.     -- Transmit data holding register
  36.     SIGNAL      txhold : std_logic_vector(0 TO 7);
  37.     -- Transmit shift register bits
  38.     SIGNAL       txreg : std_logic_vector(0 TO 7);
  39.     SIGNAL      txtag2 : std_logic; -- tag bits for detecting 
  40.     SIGNAL      txtag1 : std_logic; --    empty shift reg
  41.     SIGNAL    txparity : std_logic; -- Parity generation register
  42.     -- Transmit clock and control signals
  43.     SIGNAL       txclk : std_logic;     -- Transmit clock: 1/16th of clkx16
  44.     SIGNAL      txdone : std_logic; -- '1' when shifting of byte is done
  45.     SIGNAL paritycycle : std_logic; -- '1' on next to last shift cycle
  46.     SIGNAL   txdatardy : std_logic;     -- '1' when data is ready in txhold
  47.     -- Receive shift register bits
  48.     SIGNAL      rxhold : std_logic_vector(0 TO 7);-- Holds received data for read
  49.     SIGNAL       rxreg : std_logic_vector(0 TO 7);-- Receive data shift register
  50.     SIGNAL    rxparity : std_logic; -- Parity bit of received data
  51.     SIGNAL   paritygen : std_logic; -- Generated parity of received data
  52.     SIGNAL      rxstop : std_logic; -- Stop bit of received data
  53.     -- Receive clock and control signals
  54.     SIGNAL       rxclk : std_logic; -- Receive data shift clock
  55.     SIGNAL      rxidle : std_logic;     -- '1' when receiver is idling
  56.     SIGNAL   rxdatardy : std_logic;     -- '1' when data is ready to be read
  57. BEGIN 
  58. make_txclk:
  59.     PROCESS (reset, clkx16)
  60. VARIABLE cnt  : std_logic_vector(2 DOWNTO 0);
  61.     BEGIN
  62. -- Toggle txclk every 8 counts, which divides the clock by 16
  63. IF reset='1' THEN
  64.     txclk <= '0' ;
  65.     cnt := (OTHERS=>'0') ;
  66. ELSIF clkx16'event AND clkx16='1' THEN
  67.     IF (cnt = "000") THEN 
  68.         txclk <= NOT txclk; 
  69.     END IF;
  70.     cnt := cnt + "001"; -- Use the exemplar_1164 "+" on std_logic_vector
  71. END IF;
  72.     END PROCESS;
  73. make_rxclk:
  74.     PROCESS  (reset, clkx16) 
  75. VARIABLE rxcnt : std_logic_vector(0 TO 3); -- Count of clock cycles
  76. VARIABLE rx1   : std_logic; -- rx delayed one cycle
  77. VARIABLE hunt  : boolean; -- Hunting for start bit 
  78.     BEGIN
  79. IF reset='1' THEN
  80.     -- Reset all generated signals and variables
  81.     hunt := FALSE ;
  82.     rxcnt := (OTHERS=>'0') ;
  83.     rx1 := '0' ;
  84.     rxclk <= '0' ;
  85. ELSIF clkx16'EVENT AND clkx16 = '1' THEN
  86.     -- rxclk = clkx16 divided by 16 
  87.     rxclk <= rxcnt(0);
  88.     -- Hunt=TRUE when we are looking for a start bit:
  89.     --  A start bit is eight clock times with rx=0 after a falling edge
  90.     IF (rxidle = '1' AND rx = '0' AND rx1 = '1') THEN
  91.                 -- Start hunting when idle and falling edge is found
  92.         hunt := TRUE;
  93.     END IF ;
  94.     IF rxidle = '0' OR rx = '1' THEN
  95.         -- Stop hunting when shifting in data or a 1 is found on rx
  96.         hunt := FALSE;
  97.     END IF;
  98.     rx1 := rx; -- rx delayed by one clock for edge detection
  99. -- (Must be assigned AFTER reference)
  100.     -- Increment count when not idling or when hunting
  101.     IF (rxidle = '0' OR hunt) THEN
  102.         -- Count clocks when not rxidle or hunting for start bit
  103.         rxcnt := rxcnt + "0001";
  104.     ELSE
  105.         -- hold at 1 when rxidle and waiting for falling edge
  106.         rxcnt := "0001";
  107.     END IF;
  108. END IF ;
  109.     END PROCESS;
  110. -- transmit shift register:
  111. txshift:
  112.     PROCESS (reset, txclk)
  113.     BEGIN
  114. IF reset='1' THEN
  115.     txreg <= (OTHERS=>'0') ; 
  116.     txtag1 <= '0' ;
  117.     txtag2 <= '0' ;
  118.             txparity <= '0' ;
  119.     tx <= '0' ;
  120. ELSIF txclk'event AND txclk = '1' THEN 
  121.     IF (txdone AND txdatardy) = '1'  THEN
  122.         -- Initialize registers and load next byte of data
  123.         txreg    <= txhold; -- Load tx register from txhold
  124.         txtag2   <= '1';    -- Tag bits for detecting 
  125.         txtag1   <= '1';    --    when shifting is done
  126.         txparity <= '1';    -- Parity bit.Initializing to 1==odd parity
  127.         tx       <= '0';    -- Start bit
  128.     ELSE
  129.         -- Shift data
  130.         txreg <= txreg(1 TO 7) & txtag1;
  131.         txtag1        <= txtag2;
  132.         txtag2    <= '0';
  133.         -- Form parity as each bit goes by
  134.         txparity      <= txparity XOR txreg(0);
  135.         -- Shift out data or parity bit or stop/idle bit
  136.         IF txdone = '1' THEN
  137.     tx <= '1'; -- stop/idle bit
  138.         ELSIF paritycycle = '1' THEN
  139.     tx <= txparity; -- Parity bit
  140.         ELSE
  141.          tx <= txreg(0); --Shift data bit
  142.         END IF;
  143.     END IF ;
  144. END IF;
  145.     END PROCESS;
  146.     -- paritycycle = 1 on next to last cycle (When txtag2 has reached txreg(1))
  147.     --   (Enables putting the parity bit out on tx)
  148.     paritycycle <= txreg(1) AND NOT (txtag2 OR txtag1 OR 
  149.      txreg(7) OR txreg(6) OR txreg(5) OR 
  150.      txreg(4) OR txreg(3) OR txreg(2));
  151.     -- txdone = 1 when done shifting (When txtag2 has reached tx)
  152.     txdone <= NOT (txtag2 OR txtag1 OR
  153.   txreg(7) OR txreg(6) OR txreg(5) OR txreg(4) OR 
  154.   txreg(3) OR txreg(2) OR txreg(1) OR txreg(0));
  155. rx_proc:  -- Shift data on each rxclk when not idling
  156.     PROCESS (reset, rxclk) 
  157.     BEGIN
  158. IF reset='1' THEN
  159.     rxreg <= (OTHERS=>'0') ;
  160.             rxparity <= '0' ;
  161.             paritygen <= '0' ;
  162.             rxstop <= '0' ;
  163. ELSIF rxclk'event AND rxclk = '1' THEN
  164.     IF rxidle = '1' THEN 
  165.         -- Load all ones when idling
  166.         rxreg <= (OTHERS=>'1');
  167.         rxparity <= '1';
  168.         paritygen <= '1'; -- Odd parity
  169.         rxstop <= '0';
  170.     ELSE
  171.         -- Shift data when not idling
  172.         -- bug in assigning to slices
  173.         -- rxreg (0 TO 6) <= rxreg (1 TO 7);
  174.         -- rxreg(7) <= rxparity;
  175.         rxreg <= rxreg (1 TO 7) & rxparity;
  176.         rxparity <= rxstop;
  177.         paritygen <= paritygen XOR rxstop;-- Form parity as data shifts by
  178.         rxstop <= rx;
  179.     END IF ;
  180.         END IF;
  181.     END PROCESS;
  182.     
  183. async:  -- rxidle requires async preset since it is clocked by rxclk and  
  184.         -- its value determines whether rxclk gets generated 
  185.     PROCESS ( reset, rxclk )
  186.     BEGIN
  187.         IF reset = '1' THEN
  188.            rxidle <= '0';
  189.         ELSIF rxclk'EVENT and rxclk = '1' THEN
  190.            rxidle <= NOT rxidle AND NOT rxreg(0);
  191.         END IF;
  192.     END PROCESS async;
  193. txio: -- Load txhold and set txdatardy on falling edge of write
  194. -- Clear txdatardy on falling edge of txdone
  195.     PROCESS (reset, clkx16)
  196. VARIABLE wr1,wr2: std_logic; -- write signal delayed 1 and 2 cycles
  197. VARIABLE txdone1: std_logic;        -- txdone signal delayed one cycle
  198.     BEGIN
  199. IF reset='1' THEN
  200.     txdatardy <= '0' ;
  201.     wr1 := '0' ;
  202.     wr2 := '0' ;
  203.     txdone1 := '0' ;
  204. ELSIF clkx16'event AND clkx16 = '1' THEN
  205.     IF wr1 = '0' AND wr2= '1' THEN
  206.         -- Falling edge on write signal. New data in txhold latches
  207.         txdatardy  <= '1';
  208.     ELSIF txdone = '0' AND txdone1 = '1' THEN
  209.         -- Falling edge on txdone signal. Txhold has been read.
  210.         txdatardy  <= '0';
  211.     END IF;
  212.     -- Delayed versions of write and txdone signals for edge detection
  213.          wr2 := wr1;
  214.     wr1 := write;
  215.     txdone1 := txdone;
  216. END IF ;
  217.     END PROCESS;
  218. rxio:
  219.     PROCESS (reset, clkx16)
  220. VARIABLE rd1, rd2 : std_logic; -- Read input delayed 1 and 2 cycles
  221. VARIABLE rxidle1  : std_logic; -- rxidle signal delayed 1 cycle
  222.     BEGIN
  223. IF reset='1' THEN
  224.     overrun <= '0' ;
  225.     rxhold <= (OTHERS=>'0') ;
  226.     parityerr <= '0' ;
  227.             framingerr <= '0' ;
  228.     rxdatardy <= '0' ;
  229.     rd1 := '0' ;
  230.             rd2 := '0' ;
  231.     rxidle1 := '0' ;
  232. ELSIF clkx16'event AND clkx16 = '1' THEN
  233.     -- Look for rising edge on idle and update output registers
  234.     IF rxidle = '1' AND rxidle1 = '0' THEN
  235.         IF rxdatardy = '1' THEN
  236.          -- Overrun error if previous data is still there
  237.     overrun <= '1';
  238.         ELSE
  239.     -- No overrun error since holding register is empty
  240.     overrun <= '0';
  241.     -- Update holding register
  242.     rxhold <= rxreg;
  243.     -- paritygen = 1 if parity error
  244.     parityerr <= paritygen;
  245.     -- Framingerror if stop bit is not 1
  246.     framingerr <= NOT rxstop;
  247.     -- Signal that data is ready for reading
  248.     rxdatardy <= '1';
  249.         END IF;
  250.     END IF;
  251.     rxidle1 := rxidle; -- rxidle delayed 1 cycle for edge detect
  252.     --  Clear error and data registers when data is read
  253.     IF (NOT rd2 AND rd1) = '1' THEN
  254.         rxdatardy  <= '0';
  255.         parityerr  <= '0';
  256.         framingerr <= '0';
  257.         overrun    <= '0';
  258.     END IF;
  259.     rd2 := rd1; -- Edge detect for read
  260.     rd1 := read; -- (Must be assigned AFTER reference)
  261.     IF reset = '1' THEN 
  262.         rxdatardy <= '0'; 
  263.     END IF;
  264. END IF ;
  265.     END PROCESS;
  266.     -- Drive data bus only during read
  267.     data <= rxhold WHEN read = '1' ELSE (OTHERS=>'Z') ;
  268.     -- Latch data bus during write
  269.     txhold <= data WHEN write = '1' ELSE txhold;
  270.     -- Receive data ready output signal
  271.     rxrdy <= rxdatardy;
  272.     -- Transmitter ready for write when no data is in txhold
  273.     txrdy <= NOT txdatardy;
  274.     -- Run-time simulation check for transmit overrun
  275.     ASSERT write = '0' OR txdatardy = '0'
  276. REPORT "Transmitter overrun error" SEVERITY WARNING;
  277. END exemplar;