trashernet-soc/fpga/hdl/generics/uart_rx.vhd

100 lines
2.6 KiB
VHDL

-- -------------------------------------------------------------------------- --
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
-- -------------------------------------------------------------------------- --
-- TODO
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- License : Mozilla Public License (MPL) Version 2
-- -------------------------------------------------------------------------- --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity uart_rx is
generic(
F_CLK : natural := 50_000_000; -- System clock speed
BAUD_RATE : natural := 115_200 -- Desired baudrate
);
port(
clk : in std_logic; -- System clock @ F_CLK
rst_a : in std_logic; -- Asynchronous reset
data : out std_logic_vector; -- Receive payload word (width determines width of UART payload)
data_valid : out std_logic; -- Data is valid
serial_in_a : in std_logic -- UART RX line (asynchronous) @ BAUDRATE
);
end entity uart_rx;
architecture rtl of uart_rx is
signal serial_in : std_logic;
constant BITCLK_MAX : integer := integer(real(F_CLK) / real(BAUD_RATE));
constant BITCLK_START : integer := BITCLK_MAX / 2;
signal bitclk_cnt : integer range 0 to BITCLK_MAX;
signal bit_stb : std_logic;
constant BITCNT_MAX : integer := 10;
signal cnt : integer range 0 to BITCNT_MAX;
signal busy : std_logic;
begin
synchronizer_rx_inst : entity work.synchronizer
generic map(
init_value => '1'
)
port map(
clk => clk,
rst => rst_a,
data_in_a(0) => serial_in_a,
data_out(0) => serial_in
);
rx : process(clk, rst_a) is
begin
if rst_a then
cnt <= 0;
data_valid <= '0';
elsif rising_edge(clk) then
data_valid <= '0';
if (cnt = 0 and serial_in = '0') or bit_stb = '1' then
if cnt = BITCNT_MAX then
cnt <= 0;
data_valid <= '1';
else
data <= serial_in & data(7 downto 1);
cnt <= cnt + 1;
end if;
end if;
end if;
end process rx;
busy <= '1' when cnt /= 0 else '0';
bitclk : process(clk, rst_a) is
begin
if rst_a then
bit_stb <= '0';
bitclk_cnt <= 0;
elsif rising_edge(clk) then
bit_stb <= '0';
if not busy then
bitclk_cnt <= BITCLK_START;
else
if bitclk_cnt = 0 then
bitclk_cnt <= BITCLK_MAX;
bit_stb <= '1';
else
bitclk_cnt <= bitclk_cnt - 1;
end if;
end if;
end if;
end process bitclk;
end architecture rtl;