Library of reusable VHDL components
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.9 KiB

  1. -- Copyright (c) 2014 - 2022 by Torsten Meissner
  2. --
  3. -- Licensed under the Apache License, Version 2.0 (the "License");
  4. -- you may not use this file except in compliance with the License.
  5. -- You may obtain a copy of the License at
  6. --
  7. -- https://www.apache.org/licenses/LICENSE-2.0
  8. --
  9. -- Unless required by applicable law or agreed to in writing, software
  10. -- distributed under the License is distributed on an "AS IS" BASIS,
  11. -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. -- See the License for the specific language governing permissions and
  13. -- limitations under the License.
  14. library ieee;
  15. use ieee.std_logic_1164.all;
  16. use ieee.numeric_std.all;
  17. library libvhdl;
  18. use libvhdl.UtilsP.all;
  19. entity UartRx is
  20. generic (
  21. DATA_LENGTH : positive range 5 to 9 := 8;
  22. PARITY : boolean := true;
  23. CLK_DIV : natural := 10
  24. );
  25. port (
  26. reset_n_i : in std_logic; -- async reset
  27. clk_i : in std_logic; -- clock
  28. data_o : out std_logic_vector(DATA_LENGTH-1 downto 0); -- data output
  29. error_o : out std_logic; -- rx error
  30. valid_o : out std_logic; -- output data valid
  31. accept_i : in std_logic; -- output data accepted
  32. rx_i : in std_logic -- uart rx input
  33. );
  34. end entity UartRx;
  35. architecture rtl of UartRx is
  36. function to_integer (data : in boolean) return integer is
  37. begin
  38. if data then
  39. return 1;
  40. else
  41. return 0;
  42. end if;
  43. end function to_integer;
  44. type t_uart_state is (IDLE, RECEIVE, VALID);
  45. signal s_uart_state : t_uart_state;
  46. signal s_data : std_logic_vector(DATA_LENGTH+1+to_integer(PARITY) downto 0);
  47. signal s_clk_en : boolean;
  48. begin
  49. ClkDivP : process (clk_i, reset_n_i) is
  50. variable v_clk_cnt : natural range 0 to CLK_DIV-1;
  51. begin
  52. if (reset_n_i = '0') then
  53. s_clk_en <= false;
  54. v_clk_cnt := CLK_DIV-1;
  55. elsif (rising_edge(clk_i)) then
  56. s_clk_en <= false;
  57. if (s_uart_state = IDLE) then
  58. v_clk_cnt := CLK_DIV-2;
  59. elsif (s_uart_state = RECEIVE) then
  60. if (v_clk_cnt = 0) then
  61. v_clk_cnt := CLK_DIV-1;
  62. else
  63. v_clk_cnt := v_clk_cnt - 1;
  64. end if;
  65. if (v_clk_cnt = CLK_DIV/2-1) then
  66. s_clk_en <= true;
  67. end if;
  68. end if;
  69. end if;
  70. end process ClkDivP;
  71. RxP : process (clk_i, reset_n_i) is
  72. variable v_bit_cnt : natural range 0 to s_data'length-1;
  73. begin
  74. if (reset_n_i = '0') then
  75. s_uart_state <= IDLE;
  76. s_data <= (others => '0');
  77. valid_o <= '0';
  78. v_bit_cnt := 0;
  79. elsif (rising_edge(clk_i)) then
  80. FsmL : case s_uart_state is
  81. when IDLE =>
  82. valid_o <= '0';
  83. v_bit_cnt := s_data'length-1;
  84. if (rx_i = '0') then
  85. s_uart_state <= RECEIVE;
  86. end if;
  87. when RECEIVE =>
  88. if (s_clk_en) then
  89. s_data <= rx_i & s_data(s_data'length-1 downto 1);
  90. if (v_bit_cnt = 0) then
  91. valid_o <= '1';
  92. s_uart_state <= VALID;
  93. else
  94. v_bit_cnt := v_bit_cnt - 1;
  95. end if;
  96. end if;
  97. when VALID =>
  98. valid_o <= '1';
  99. if (valid_o = '1' and accept_i = '1') then
  100. valid_o <= '0';
  101. s_uart_state <= IDLE;
  102. end if;
  103. end case;
  104. end if;
  105. end process RxP;
  106. ParityG : if PARITY generate
  107. data_o <= s_data(s_data'length-3 downto 1);
  108. error_o <= '1' when odd_parity(s_data(s_data'length-3 downto 1)) /= s_data(s_data'length-2) or
  109. s_data(s_data'length-1) = '0' else
  110. '0';
  111. else generate
  112. data_o <= s_data(s_data'length-2 downto 1);
  113. error_o <= '1' when s_data(s_data'length-1) = '0' else '0';
  114. end generate ParityG;
  115. end architecture rtl;