LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.std_logic_unsigned.ALL; entity RXCVER is port ( MCLKX16 : in std_logic; -- input clock, 16x baudrate clock used for synchronization READ : in std_logic; -- Read Strobe RX : in std_logic; -- Receive Input Line RESET : in std_logic; -- Global Reset RXRDY : out std_logic; -- Receiver data ready to read PARITY_ERR : out std_logic; -- Receiver parity error flag FRAMING_ERR : out std_logic; -- Receiver framing error flag OVERRUN : out std_logic; -- Receiver overrun error flag DATA : out std_logic_vector(7 downto 0) -- 8 bit output data bus ); end RXCVER; architecture RTL of RXCVER is signal RXCNT : std_logic_vector(3 downto 0); -- clock cycle count signal RX1 : std_logic; -- delayed versions of rx, read, idle signal READ1 : std_logic; signal READ2 : std_logic; signal IDLE1 : std_logic; signal HUNT : std_logic; -- hunting for start bit flag signal RHR : std_logic_vector(7 downto 0); -- Receiver hold register signal RSR : std_logic_vector(7 downto 0); -- Receiver serial -> parallel 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 constant PARITYMODE : std_logic := '1'; -- initializing to 1 = odd parity, 0 = even parity signal RXCLK : std_logic; -- Receive data shift clock signal IDLE : std_logic; -- = '1' when receiver is idling signal RXDATARDY : std_logic; -- = '1' when data is ready to be read begin -- Idle requires async preset since it is clocked by rxclk, and it's -- value determines whether rxclk gets generated or not. -- Idle goes low when shifting in data. This is ensured because all bits -- of rsr are preset to all 1's when idle is high. Idle goes high again -- when rsr[0] = 0, i.e. when the low "rxstop" bit reach rsr[0]. -- Next rising edge of rxclk preset idle to high again, and generation of -- rxclk is disabled. IDLE_PRESET : process (RXCLK, RESET) begin if (RESET = '1') then IDLE <= '1'; elsif (RXCLK'event and RXCLK = '1') then IDLE <= (not IDLE) and (not RSR(0)); end if; end process; -- Synchronizing rxclk to the centerpoint of low leading startbit. -- always @(posedge mclkx16) -- begin -- -- A start bit is eight clock times with rx=0 after a falling edge of rx. RXCLK_SYNC : process (MCLKX16, RESET) begin if (RESET = '1') then HUNT <= '0'; RXCNT <= "0001"; RX1 <= '1'; RXCLK <= '0'; elsif (MCLKX16'event and MCLKX16 = '1') then if (IDLE = '1' and RX = '0' and RX1 = '1') then HUNT <= '1'; else if (IDLE = '0' or RX = '1') then HUNT <= '0'; end if; if (IDLE = '0' or HUNT = '1') then RXCNT <= RXCNT + 1; else RXCNT <= "0001"; end if; end if; RX1 <= RX; RXCLK <= RXCNT(3); end if; end process; -- When not idling, sample data at the rx input, and generate parity. SAMPLE_DATA : process (RXCLK, RESET) begin if (RESET = '1') then -- Idle_reset RSR <= "11111111"; -- All 1's ensure that idle stays low during data shifting. RXPARITY <= '1'; -- Preset to high to ensure idle = 0 during data shifting. PARITYGEN <= PARITYMODE; -- Preset paritygen to parity mode. RXSTOP <= '0'; elsif (RXCLK'event and RXCLK = '1') then if (IDLE = '1') then -- Idle_reset RSR <= "11111111"; -- All 1's ensure that idle stays low during data shifting. RXPARITY <= '1'; -- Preset to high to ensure idle = 0 during data shifting. PARITYGEN <= PARITYMODE; -- Preset paritygen to parity mode. RXSTOP <= '0'; else -- Shift_data RSR <= '0' & RSR(7 downto 1); -- Right shift receive shift register. RSR(7) <= RXPARITY; -- Load rsr[7] with rxparity. RXPARITY <= RXSTOP; -- Load rxparity with rxstop. RXSTOP <= RX; -- Load rxstop with rx. At 1'st shift rxstop gets low "start bit". PARITYGEN <= PARITYGEN xor RXSTOP; -- Generate parity as data are shifted. end if; end if; end process; -- Generate status & error flags. GENERATE_FLAG : process (MCLKX16, RESET) begin if (RESET = '1') then RHR <= "00000000"; RXDATARDY <= '0'; OVERRUN <= '0'; PARITY_ERR <= '0'; FRAMING_ERR <= '0'; IDLE1 <= '1'; READ2 <= '1'; READ1 <= '1'; elsif (MCLKX16'event and MCLKX16 = '1') then if (IDLE = '1' and IDLE1 = '0') then if (RXDATARDY = '1') then OVERRUN <= '1'; else OVERRUN <= '0'; -- No overrun error, since holding register is empty. RHR <= RSR; -- Update holding register with contens of shift register. PARITY_ERR <= PARITYGEN; -- Paritygen = 1, if parity error. FRAMING_ERR <= not RXSTOP; -- Framingerror, if stop bit is not 1. RXDATARDY <= '1'; -- Data is ready for reading flag. end if; end if; if (READ2 = '0' and READ1 = '1') then RXDATARDY <= '0'; PARITY_ERR <= '0'; FRAMING_ERR <= '0'; OVERRUN <= '0'; end if; IDLE1 <= IDLE; -- Idle delayed 1 cycle for edge detect. READ2 <= READ1; -- 2 cycle delayed version of read, used for edge detection. READ1 <= READ; -- 1 cycle delayed version of read, used for edge detection. end if; end process; RXRDY <= RXDATARDY; DATA <= RHR; end RTL;