|
发表于 2003-8-28 17:05:08
|
显示全部楼层
请问UART是什么?
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;
|
|