基于VHDL设计的一个简单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;
 

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GJZGRB

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值