summaryrefslogtreecommitdiff
path: root/testsuite/gna/bug019/PoC/src/io/uart/uart_rx.vhdl
blob: 01383badea85e93b706eefe009b7717cd7d6c075 (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
163
164
165
166
167
168
169
170
171
172
173
174
-- EMACS settings: -*-  tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
-- 
-- ============================================================================
-- Authors:				 	Martin Zabel
--									Patrick Lehmann
-- 
-- Module:				 	UART Receiver
--
-- Description:
-- ------------------------------------
--	TODO
-- 
--	old comments:
--		Serial configuration: 8 data bits, 1 stop bit, no parity
--		
--		bclk_x8 = bit clock (defined by BAUD rate) times 8
--		dos       = data out strobe, signals that dout is valid, active high for one
--		            cycle 
--		dout      = data out = received byte
--		
--		OUT_REGS:
--		If disabled, then dos is a combinatorial output. Further merging of logic is
--		possible but timing constraints might fail. If enabled, 9 more registers are
--		required. But now, dout toggles only after receiving of full byte.
--
--
-- License:
-- ============================================================================
-- Copyright 2008-2015 Technische Universitaet Dresden - Germany
--										 Chair for VLSI-Design, Diagnostics and Architecture
-- 
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
-- 
--		http://www.apache.org/licenses/LICENSE-2.0
-- 
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- ============================================================================

library	IEEE;
use			IEEE.std_logic_1164.all;
use			IEEE.numeric_std.all;

library PoC;
use			PoC.components.all;


entity uart_rx is
	generic (
		OUT_REGS : boolean
	);
	port (
		clk       : in  std_logic;
		rst       : in  std_logic;
		bclk_x8 	: in  std_logic;
		rxd       : in  std_logic;
		dos       : out std_logic;
		dout      : out std_logic_vector(7 downto 0)
	);
end entity;


architecture rtl of uart_rx is
	type states is (IDLE, RDATA);
	signal state			: states	:= IDLE;
	signal next_state	: states;

	-- registers
	signal rxd_reg1			: std_logic											:= '1';
	signal rxd_reg2			: std_logic											:= '1';
	signal sr						: std_logic_vector(7 downto 0)	:= (others => '0');  -- data only
	signal bclk_cnt			: unsigned(2 downto 0)					:= to_unsigned(4, 3);
	signal shift_cnt		: unsigned(3 downto 0)					:= (others => '0');

	-- control signals
	signal rxd_falling    : std_logic;
	signal bclk_rising    : std_logic;
	signal start_bclk     : std_logic;
	signal shift_sr       : std_logic;
	signal shift_done     : std_logic;
	signal put_data       : std_logic;

begin

  rxd_falling    <= (not rxd_reg1) and rxd_reg2;
  bclk_rising    <= bclk_x8 when (comp_allone(bclk_cnt) = '1') else '0';

  -- shift_cnt count from 0 to 9 (1 start bit + 8 data bits)
	shift_cnt		<= upcounter_next(cnt => shift_cnt, rst => start_bclk, en => shift_sr) when rising_edge(clk);
  shift_done	<= upcounter_equal(cnt => shift_cnt, value => 9);

	bclk_cnt		<= upcounter_next(cnt => bclk_cnt, rst => start_bclk, en => bclk_x8, init => 4) when rising_edge(clk);
	
  process (state, rxd_falling, bclk_x8, bclk_rising, shift_done)
  begin
    next_state <= state;
    start_bclk <= '0';
    shift_sr   <= '0';
    put_data   <= '0';
    
    case state is
      when IDLE =>
        -- wait for start bit
        if (rxd_falling and bclk_x8) = '1' then
          next_state <= RDATA;
          start_bclk <= '1';            -- = rst_shift_cnt
        end if;

      when RDATA =>
        if bclk_rising = '1' then
          -- bit clock keeps running
          if shift_done = '1' then
            -- stop bit reached
            put_data   <= '1';
            next_state <= IDLE;
            
          else
            -- TODO: check start bit?
            shift_sr <= '1';
          end if;
        end if;
        
      when others => null;
    end case;
  end process;

  process (clk)
  begin
    if rising_edge(clk) then
      if rst = '1' then
        state <= IDLE;
      else
        state <= next_state;
      end if;

      rxd_reg1 <= rxd;

      if bclk_x8 = '1' then
        -- align to bclk_x8, so when we can easily check for
        -- the falling edge of the start bit
        rxd_reg2 <= rxd_reg1;
      end if;

      if shift_sr = '1' then
        -- shift into MSB
        sr <= rxd_reg2 & sr(sr'left downto 1);
      end if;
    end if;
  end process;

  -- output
  gOutRegs: if OUT_REGS = true generate
    process (clk)
    begin
      if rising_edge(clk) then
        dos  <= put_data and rxd_reg2;  -- check stop bit
        dout <= sr;
      end if;
    end process;
  end generate gOutRegs;

  gNoOutRegs: if OUT_REGS = false generate
    dos  <= put_data and rxd_reg2;      -- check stop bit
    dout <= sr;
  end generate gNoOutRegs;
  
end;