📄 uart.vhd
字号:
----------------------------------------------------------------
--
-- 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
rx : IN std_logic; -- Receive data line
reset : IN std_logic; -- clear dependencies
rxrdy : OUT std_logic; -- Received data ready to be read
parityerr : OUT std_logic; -- Receiver parity error
framingerr : OUT std_logic; -- Receiver framing error
overrun : OUT std_logic; -- Receiver overrun error
data : out std_logic_vector(7 downto 0)); -- Bidirectional data bus
END uart;
ARCHITECTURE exemplar OF uart IS
-- 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_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:
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;
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
-- Receive data ready output signal
rxrdy <= rxdatardy;
-- Transmitter ready for write when no data is in txhold
-- Run-time simulation check for transmit overrun
END exemplar;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -