uart_rx: ein prozessmodell. spart weitere 3 logic elements :P
[hwmod.git] / src / uart_rx.vhd
index e36b5c583b5b3e76afc6d924cb821a5ab1329ba7..550412cdb790f1e8f6e5e6980539a9bf7f22c6f2 100644 (file)
@@ -4,154 +4,88 @@ use ieee.numeric_std.all;
 use work.gen_pkg.all;
 
 entity uart_rx is
-port(
-       sys_clk : in std_logic;
-       sys_res : in std_logic;
-       txd : in std_logic; -- warning: this is asynchronous input!
-       tx_data : out std_logic_vector(7 downto 0); -- map this to a larger register with containing input
-       tx_new : out std_logic
-);
+       generic (
+               CLK_FREQ : integer := 33000000;
+               BAUDRATE : integer := 115200
+       );
+       port(
+               sys_clk : in std_logic;
+               sys_res_n : in std_logic;
+               rxd : in std_logic;
+               rx_data : out std_logic_vector(7 downto 0);
+               rx_new : out std_logic
+       );
 end entity uart_rx;
 
 architecture beh of uart_rx is
-       constant timer_max : integer := 35;
+       constant BAUD : integer := CLK_FREQ/BAUDRATE;
 
-       type STATE_UART_RX is (IDLE, BUSY, DONE);
+       type STATE_UART_RX is (IDLE, STARTBIT, DBITS, STOPBIT);
+       signal state : STATE_UART_RX;
 
-       signal timer, timer_next : integer range 0 to 65535;
-       signal counter, counter_next : integer range 0 to 15;
-       signal state, state_next : STATE_UART_RX;
-       signal tx_data_prev : std_logic_vector(7 downto 0); -- FIXME: this isnt named next so that the interface isn't called tx_data_next ...
-
-       -- these are internal signals that are actually used as in and output
-       signal tx_data_i : std_logic_vector(7 downto 0);
-       signal tx_new_i : std_logic;
+       signal startbitdetection : std_logic_vector(1 downto 0);
+       signal bitcnt : integer range 0 to 7;
+       signal baudcnt : integer range 0 to BAUD + 2;
+       signal rx_data_int : std_logic_vector(7 downto 0);
 begin
---FIXME:
-
-       tx_new <= tx_new_i;
-       tx_data <= tx_data_i;
-
-       process(sys_clk, sys_res)
+       rx_data <= rx_data_int;
+       process(sys_clk, sys_res_n)
        begin
-               if (sys_res = '0') then
-                       -- Set reset state
+               if (sys_res_n = '0') then
                        state <= IDLE;
-                       tx_data_prev <= X"00";
+                       rx_data_int <= (others => '0');
+                       rx_new <= '0';
+                       bitcnt <= 0;
+                       baudcnt <= 0;
+                       startbitdetection <= b"11";
                elsif rising_edge(sys_clk) then
-                       -- Store next state
-                       state <= state_next;
-                       tx_data_prev <= tx_data_i;
-               end if;
-       end process;
+                       startbitdetection <= startbitdetection(0) & rxd;
+                       rx_new <= '0';
+                       baudcnt <= baudcnt + 1;
+                       case state is
+                               when IDLE =>
+                                       baudcnt <= 0;
+                                       -- bei fallender flanke koennte starbit folgen
+                                       if startbitdetection = b"10" then
+                                               state <= STARTBIT;
+                                       end if;
+                               when STARTBIT =>
+                                       rx_data_int <= (others => '0');
 
-       process(state, txd, counter)
-       begin
-               state_next <= state;
-               case state is
-                       when IDLE =>
-                               if (txd = '0') then
-                                       state_next <= BUSY;
-                               else
-                                       state_next <= IDLE;
-                               end if;
-                       when BUSY =>
-                               if (counter = 9) then --FIXME: is this true?
-                                       state_next <= DONE;
-                               else
-                                       state_next <= BUSY;
-                               end if;
-                       when DONE =>
-                               state_next <= IDLE;
-               end case;
-       end process;
+                                       -- halbe BAUDTIME warten, um immer in der mitte abzutasten
+                                       -- vgl. http://upload.wikimedia.org/wikipedia/de/d/de/RS-232_timing.png
+                                       if baudcnt = BAUD/2 then
+                                               baudcnt <= 0;
+                                               if rxd = '0' then
+                                                       -- starbit (= '0')? dann kommen daten
+                                                       state <= DBITS;
+                                                       bitcnt <= 0;
+                                                       baudcnt <= 0;
+                                               else
+                                                       -- sonst war das nix...
+                                                       state <= IDLE;
+                                               end if;
+                                       end if;
+                               when DBITS =>
+                                       if baudcnt = BAUD then
+                                               baudcnt <= 0;
+                                               -- bitorder beachten
+                                               rx_data_int <= rxd & rx_data_int(7 downto 1);
 
-       process(state)
-       begin
-               -- Set default values
-               -- for the outputs
-               tx_new_i <= '0';
-
-               -- Calculate the outputs
-               -- based on the current
-               -- state
-               case state is
-                       when IDLE =>
-                               tx_new_i <= '0';
-                       when BUSY =>
-                               tx_new_i <= '0';
-                       when DONE =>
-                               tx_new_i <= '1';
-               end case;
-       end process;
--- END FIXME: do fill this out CORRECTLY
-
-       process (sys_clk, sys_res)
-       begin
-               if sys_res = '0' then
-                       counter <= 0;
-                       timer <= 0;
-               elsif rising_edge(sys_clk) then
-                       counter <= counter_next;
-                       timer <= timer_next;
+                                               if bitcnt = 7 then
+                                                       state <= STOPBIT;
+                                               else
+                                                       bitcnt <= bitcnt + 1;
+                                               end if;
+                                       end if;
+                               when STOPBIT =>
+                                       if baudcnt = BAUD then
+                                               state <= IDLE;
+                                               if rxd = '1' then
+                                                       rx_new <= '1';
+                                               end if;
+                                       end if;
+                       end case;
                end if;
        end process;
-
-       process (timer)
-       begin
-               if (timer = timer_max) then
-                       timer_next <= 0;
-               else
-                       timer_next <= timer + 1;
-               end if;
-       end process;
-
-       process (timer, counter, tx_new_i)
-       begin
-               if (tx_new_i = '1') then
-                       if (timer = timer_max) then
-                               if (counter > 10) then
-                                       counter_next <= 0;
-                               else
-                                       counter_next <= counter + 1;
-                               end if;
-                       else
-                                       counter_next <= counter;
-                       end if;
-               else
-                               counter_next <= 0;
-               end if;
-       end process;
-
-       process (counter, txd)
-       begin
-               tx_data_i <= tx_data_prev;
-               -- TODO: we probably want oversampling and averaging + failure!
-               -- FIXME: this is per se not synthesisable
-               case (counter) is
-                       when 0 => --start bit
-                               assert (txd = '0');
-                       when 1 =>
-                               tx_data_i(0) <= txd;
-                       when 2 =>
-                               tx_data_i(1) <= txd;
-                       when 3 =>
-                               tx_data_i(2) <= txd;
-                       when 4 =>
-                               tx_data_i(3) <= txd;
-                       when 5 =>
-                               tx_data_i(4) <= txd;
-                       when 6 =>
-                               tx_data_i(5) <= txd;
-                       when 7 =>
-                               tx_data_i(6) <= txd;
-                       when 8 =>
-                               tx_data_i(7) <= txd;
-                       when 9 => -- stop bit
-                               assert (txd = '1');
-                       when others => -- idle
-                               assert (txd = '1');
-               end case;
-       end process;
-
 end architecture beh;