2f321028aca6ceda92d3e24b6e891e642be8a40a
[hwmod.git] / src / uart_rx.vhd
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
4 use work.gen_pkg.all;
5
6 entity uart_rx is
7 port(
8         sys_clk : in std_logic;
9         sys_res : in std_logic;
10         txd : in std_logic; -- warning: this is asynchronous input!
11         tx_data : out std_logic_vector(7 downto 0); -- map this to a larger register with containing input
12         tx_new : out std_logic
13 );
14 end entity uart_rx;
15
16 architecture beh of uart_rx is
17         constant timer_max : integer := 35;
18         constant counter_max : integer := 9;
19         constant samples : integer := 8;
20
21         type STATE_UART_RX is (IDLE, BUSY, DONE);
22
23         signal timer, timer_next : integer range 0 to 65535;
24         signal counter, counter_next : integer range 0 to 15;
25         signal sample_counter, sample_counter_next : integer range 0 to counter_max-1;
26         signal state, state_next : STATE_UART_RX;
27         signal sync1, sync2, txd_next: std_logic; --synchronizers FIXME!
28
29         -- these are internal signals that are actually used as in and output
30         signal tx_data_prev : std_logic_vector(7 downto 0);
31         signal tx_new_i : std_logic;
32         signal shift, shift_value, shift_reset : std_logic;
33 begin
34
35         tx_new <= tx_new_i;
36
37         process(sys_clk, sys_res)
38         begin
39                 if (sys_res = '0') then
40                         -- Set reset state
41                         state <= IDLE;
42                         tx_data_prev <= X"00";
43
44                         txd_next <= '0'; --fixme: syncronizers!
45                         sync2 <= '0';
46                         sync1 <= '0';
47                         timer <= 0;
48                         counter <= 0;
49                 elsif rising_edge(sys_clk) then
50                         -- Store next state
51                         state <= state_next;
52                         if (shift = '1') then
53                                 tx_data(7 downto 1) <= tx_data_prev(6 downto 1);
54                                 tx_data(0) <= shift_value;
55                         elsif ( shift_reset = '1') then
56                                 tx_data <= X"00";
57                         end if;
58
59                         txd_next <= sync2; --fixme: syncronizers!
60                         sync2 <= sync1;
61                         sync1 <= txd;
62                         counter <= counter_next;
63                         sample_counter <= sample_counter_next;
64                         timer <= timer_next;
65                 end if;
66         end process;
67
68         process(state, txd, counter)
69         begin
70                 state_next <= state;
71
72                 shift <= '0';
73                 shift_reset <='0';
74                 shift_value <= '0';
75                 timer_next <= 0;
76                 counter_next <= 0;
77
78                 case state is
79                         when IDLE =>
80                                 if (txd = '0') then
81                                         state_next <= BUSY;
82                                         shift_reset <= '1';
83                                 end if;
84                         when BUSY =>
85                                 if (counter = counter_max) then --FIXME: is this true?
86                                         state_next <= DONE;
87                                 end if;
88
89                                 if (timer = timer_max) then
90                                         timer_next <= 0;
91                                         counter_next <= counter + 1;
92                                         if (sample_counter < samples/2) then
93                                                 shift_value <= '1';
94                                         else
95                                                 shift_value <= '0';
96                                         end if;
97                                         shift <= '1';
98                                 else
99                                         timer_next <= timer + 1;
100                                 end if;
101
102                                 if timer = timer_max/samples and txd_next = '1' then
103                                         sample_counter_next <= sample_counter + 1;
104                                 end if;
105                         when DONE =>
106                                 state_next <= IDLE;
107                 end case;
108         end process;
109
110 end architecture beh;