w11 - vhd 0.794
W11 CPU core and support modules
Loading...
Searching...
No Matches
serport_uart_rx.vhd
Go to the documentation of this file.
1-- $Id: serport_uart_rx.vhd 1181 2019-07-08 17:00:50Z mueller $
2-- SPDX-License-Identifier: GPL-3.0-or-later
3-- Copyright 2007-2016 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4--
5-- The uart expects CLKDIV+1 wide input bit symbols.
6-- This implementation counts the number of 1's in the first CLKDIV clock
7-- cycles, and checks in the last cycle of the symbol time whether the
8-- number of 1's was > CLKDIV/2. This supresses short glitches nicely,
9-- especially for larger clock dividers.
10--
11------------------------------------------------------------------------------
12-- Module Name: serport_uart_rx - syn
13-- Description: serial port UART - receiver
14--
15-- Dependencies: -
16-- Test bench: tb/tb_serport_uart_rxtx
17-- Target Devices: generic
18-- Tool versions: ise 8.2-14.7; viv 2014.4-2016.2; ghdl 0.18-0.33
19-- Revision History:
20-- Date Rev Version Comment
21-- 2016-05-22 767 2.0.4 don't init N_REGS (vivado fix for fsm inference)
22-- 2011-10-22 417 2.0.3 now numeric_std clean
23-- 2009-07-12 233 2.0.2 remove snoopers
24-- 2008-03-02 121 2.0.1 comment out snoopers
25-- 2007-10-21 91 2.0 re-designed and -implemented with state machine.
26-- allow CLKDIV=0 with 1 stop bit; allow max. CLKDIV
27-- (all 1's); aborts bad start bit after 1/2 cell;
28-- accepts stop bit after 1/2 cell, permits tx clock
29-- be ~3 percent faster than rx clock.
30-- for 3s1000ft256: 50 -> 58 slices for CDWIDTH=13
31-- 2007-10-14 89 1.1 almost full rewrite, handles now CLKDIV=0 properly
32-- for 3s1000ft256: 43 -> 50 slices for CDWIDTH=13
33-- 2007-10-12 88 1.0.1 avoid ieee.std_logic_unsigned, use cast to unsigned
34-- 2007-06-30 62 1.0 Initial version
35------------------------------------------------------------------------------
36-- NOTE: for test bench usage a copy of all serport_* entities, with _tb
37-- !!!! appended to the name, has been created in the /tb sub folder.
38-- !!!! Ensure to update the copy when this file is changed !!
39
40library ieee;
41use ieee.std_logic_1164.all;
42use ieee.numeric_std.all;
43
44use work.slvtypes.all;
45
46entity serport_uart_rx is -- serial port uart: receive part
47 generic (
48 CDWIDTH : positive := 13); -- clk divider width
49 port (
50 CLK : in slbit; -- clock
51 RESET : in slbit; -- reset
52 CLKDIV : in slv(CDWIDTH-1 downto 0); -- clock divider setting
53 RXSD : in slbit; -- receive serial data (uart view)
54 RXDATA : out slv8; -- receiver data out
55 RXVAL : out slbit; -- receiver data valid
56 RXERR : out slbit; -- receiver data error (frame error)
57 RXACT : out slbit -- receiver active
58 );
60
61
62architecture syn of serport_uart_rx is
63
64 type state_type is (
65 s_idle, -- s_idle: idle
66 s_colb0, -- s_colb0: collect b0 (start bit)
67 s_endb0, -- s_endb0: finish b0 (start bit)
68 s_colbx, -- s_colbx: collect bx
69 s_endbx, -- s_endbx: finish bx
70 s_colb9, -- s_colb9: collect bx (stop bit)
71 s_endb9 -- s_endb9: finish bx (stop bit)
72 );
73
74 type regs_type is record
75 state : state_type; -- state
76 ccnt : slv(CDWIDTH-1 downto 0); -- clock divider counter
77 dcnt : slv(CDWIDTH downto 0); -- data '1' counter
78 bcnt : slv4; -- bit counter
79 sreg : slv8; -- input shift register
80 end record regs_type;
81
82 constant ccntzero : slv(CDWIDTH-1 downto 0) := (others=>'0');
83 constant dcntzero : slv(CDWIDTH downto 0) := (others=>'0');
84 constant regs_init : regs_type := (
85 s_idle, -- state
86 ccntzero, -- ccnt
87 dcntzero, -- dcnt
88 (others=>'0'), -- bcnt
89 (others=>'0') -- sreg
90 );
91
93 signal N_REGS : regs_type; -- don't init (vivado fix for fsm infer)
94
95begin
96
97 proc_regs: process (CLK)
98 begin
99
100 if rising_edge(CLK) then
101 R_REGS <= N_REGS;
102 end if;
103
104 end process proc_regs;
105
106 proc_next: process (R_REGS, RESET, CLKDIV, RXSD)
107
108 variable r : regs_type := regs_init;
109 variable n : regs_type := regs_init;
110
111 variable dbit : slbit := '0';
112 variable ld_ccnt : slbit := '0';
113 variable tc_ccnt : slbit := '0';
114 variable tc_bcnt : slbit := '0';
115 variable ld_dcnt : slbit := '0';
116 variable ld_bcnt : slbit := '0';
117 variable ce_bcnt : slbit := '0';
118 variable iact : slbit := '0';
119 variable ival : slbit := '0';
120 variable ierr : slbit := '0';
121
122 begin
123
124 r := R_REGS;
125 n := R_REGS;
126
127 dbit := '0';
128 ld_ccnt := '0';
129 tc_ccnt := '0';
130 tc_bcnt := '0';
131 ld_dcnt := '0';
132 ld_bcnt := '0';
133 ce_bcnt := '0';
134 iact := '1';
135 ival := '0';
136 ierr := '0';
137
138 if unsigned(r.ccnt) = 0 then
139 tc_ccnt := '1';
140 end if;
141 if unsigned(r.bcnt) = 9 then
142 tc_bcnt := '1';
143 end if;
144
145 if unsigned(r.dcnt) > unsigned("00" & CLKDIV(CDWIDTH-1 downto 1)) then
146 dbit := '1';
147 end if;
148
149 case r.state is
150
151 when s_idle => -- s_idle: idle ----------------------
152 iact := '0';
153 ld_dcnt := '1'; -- always keep dcnt in reset
154 if RXSD = '0' then -- if start bit seen
155 if tc_ccnt = '1' then
156 n.state := s_endb0; -- finish b0
157 ld_ccnt := '1'; -- start next bit
158 ce_bcnt := '1';
159 else
160 n.state := s_colb0; -- collect b0
161 end if;
162 else -- otherwise
163 ld_ccnt := '1'; -- keep all counters in reset
164 ld_bcnt := '1';
165 end if;
166
167 when s_colb0 => -- s_colb0: collect b0 (start bit) ---
168 if tc_ccnt = '1' then -- last cycle of b0 ?
169 n.state := s_endb0; -- finish b0
170 ld_ccnt := '1'; -- "
171 ce_bcnt := '1';
172 else -- continue in b0 ?
173 if dbit='1' and RXSD='1' then -- too many 1's ?
174 n.state := s_idle; -- abort to idle
175 ld_dcnt := '1'; -- put counters in reset
176 ld_ccnt := '1';
177 ld_bcnt := '1';
178 end if;
179 end if;
180
181 when s_endb0 => -- s_endb0: finish b0 (start bit) ---
182 ld_dcnt := '1'; -- start next bit
183 if dbit = '1' then -- was it a 1 ?
184 n.state := s_idle; -- abort to idle
185 ld_ccnt := '1'; -- put counters in reset
186 ld_bcnt := '1';
187 else
188 if tc_ccnt = '1' then -- last cycle of bx ?
189 n.state := s_endbx; -- finish bx
190 ld_ccnt := '1';
191 ce_bcnt := '1';
192 else -- continue in b0 ?
193 n.state := s_colbx; -- collect bx
194 end if;
195 end if;
196
197 when s_colbx => -- s_colbx: collect bx ---------------
198 if tc_ccnt = '1' then -- last cycle of bx ?
199 n.state := s_endbx; -- finish bx
200 ld_ccnt := '1';
201 ce_bcnt := '1';
202 end if;
203
204 when s_endbx => -- s_endbx: finish bx ---------------
205 ld_dcnt := '1'; -- start next bit
206 n.sreg := dbit & r.sreg(7 downto 1);
207 if tc_ccnt = '1' then -- last cycle of bx ?
208 if tc_bcnt = '1' then
209 n.state := s_endb9; -- finish b9
210 ld_bcnt := '1'; -- and wrap bcnt
211 else
212 n.state := s_endbx; -- finish bx
213 ce_bcnt := '1';
214 end if;
215 ld_ccnt := '1';
216 else -- continue in bx ?
217 if tc_bcnt = '1' then
218 n.state := s_colb9; -- collect b9
219 else
220 n.state := s_colbx; -- collect bx
221 end if;
222 end if;
223
224 when s_colb9 => -- s_colb9: collect bx (stop bit) ----
225 if tc_ccnt = '1' then -- last cycle of b9 ?
226 n.state := s_endb9; -- finish b9
227 ld_ccnt := '1'; -- "
228 ld_bcnt := '1'; -- and wrap bcnt
229 else -- continue in b9 ?
230 if dbit='1' and RXSD='1' then -- already enough 1's ?
231 n.state := s_idle; -- finish to idle
232 ld_dcnt := '1'; -- put counters in reset
233 ld_ccnt := '1';
234 ld_bcnt := '1';
235 ival := '1';
236 end if;
237 end if;
238
239 when s_endb9 => -- s_endb9: finish bx (stop bit) ----
240 ld_dcnt := '1'; -- start next bit
241 if dbit = '1' then -- was it a valid stop bit ?
242 ival := '1';
243 else
244 ierr := '1';
245 end if;
246 if RXSD = '1' then -- line in idle state ?
247 n.state := s_idle; -- finish to idle state
248 ld_ccnt := '1'; -- and put counters in reset
249 ld_bcnt := '1'; -- "
250 else
251 if tc_ccnt = '1' then -- last cycle of b9 ?
252 n.state := s_endb0; -- finish b0
253 ld_ccnt := '1'; -- "
254 ce_bcnt := '1';
255 else -- continue in b0 ?
256 n.state := s_colb0; -- collect bx
257 end if;
258 end if;
259
260 when others => null; -- -----------------------------------
261
262 end case;
263
264 if RESET = '1' then -- RESET seen
265 ld_ccnt := '1'; -- keep all counters in reset
266 ld_dcnt := '1';
267 ld_bcnt := '1';
268 n.state := s_idle;
269 end if;
270
271 if ld_ccnt = '1' then -- implement ccnt
272 n.ccnt := CLKDIV;
273 else
274 n.ccnt := slv(unsigned(r.ccnt) - 1);
275 end if;
276
277 if ld_dcnt = '1' then -- implement dcnt
278 n.dcnt(CDWIDTH downto 1) := (others=>'0');
279 n.dcnt(0) := RXSD;
280 else
281 if RXSD = '1' then
282 n.dcnt := slv(unsigned(r.dcnt) + 1);
283 end if;
284 end if;
285
286 if ld_bcnt = '1' then -- implement bcnt
287 n.bcnt := (others=>'0');
288 else
289 if ce_bcnt = '1' then
290 n.bcnt := slv(unsigned(r.bcnt) + 1);
291 end if;
292 end if;
293
294 N_REGS <= n;
295
296 RXDATA <= r.sreg;
297 RXACT <= iact;
298 RXVAL <= ival;
299 RXERR <= ierr;
300
301 end process proc_next;
302
303end syn;
slv( CDWIDTH downto 0) :=( others => '0') dcntzero
regs_type := regs_init R_REGS
(s_idle,s_colb0,s_endb0,s_colbx,s_endbx,s_colb9,s_endb9) state_type
regs_type :=( s_idle, ccntzero, dcntzero,( others => '0'),( others => '0')) regs_init
slv( CDWIDTH- 1 downto 0) :=( others => '0') ccntzero
CDWIDTH positive := 13
in CLKDIV slv( CDWIDTH- 1 downto 0)
std_logic_vector( 3 downto 0) slv4
Definition: slvtypes.vhd:36
std_logic slbit
Definition: slvtypes.vhd:30
std_logic_vector( 7 downto 0) slv8
Definition: slvtypes.vhd:40
std_logic_vector slv
Definition: slvtypes.vhd:31