summaryrefslogtreecommitdiff
path: root/2004/n/fpga/src/portserie/uart/rxcver.vhd
blob: 6a6679a34d39fdc708c0c4e455e458a47ba1a5d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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;