uart_interface.vhd 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. --+-----------------------------------+-------------------------------------+--
  2. --| ___ ___ | (c) 2013-2014 William R Sowerbutts |--
  3. --| ___ ___ ___ ___( _ ) / _ \ | will@sowerbutts.com |--
  4. --| / __|/ _ \ / __|_ / _ \| | | | | |--
  5. --| \__ \ (_) | (__ / / (_) | |_| | | A Z80 FPGA computer, just for fun |--
  6. --| |___/\___/ \___/___\___/ \___/ | |--
  7. --| | http://sowerbutts.com/ |--
  8. --+-----------------------------------+-------------------------------------+--
  9. --| Combine the UART with a receive FIFO and provide an interface to the |--
  10. --| microprocessor. |--
  11. --+-------------------------------------------------------------------------+--
  12. library IEEE;
  13. use IEEE.STD_LOGIC_1164.ALL;
  14. use IEEE.NUMERIC_STD.ALL;
  15. entity uart_interface is
  16. Generic ( watch_for_reset : integer := 0;
  17. clk_frequency : natural := (128*1000000);
  18. flow_control : integer := 0) ;
  19. Port ( clk : in std_logic;
  20. reset : in std_logic;
  21. -- rs232
  22. serial_in : in std_logic;
  23. serial_out : out std_logic;
  24. -- flow control (optional)
  25. serial_cts : in std_logic;
  26. serial_rts : out std_logic;
  27. -- memory interface
  28. cpu_address : in std_logic_vector (2 downto 0);
  29. cpu_data_in : in std_logic_vector (7 downto 0);
  30. cpu_data_out : out std_logic_vector (7 downto 0);
  31. reset_out : out std_logic;
  32. enable : in std_logic;
  33. interrupt : out std_logic;
  34. req_read : in std_logic;
  35. req_write : in std_logic);
  36. end uart_interface;
  37. architecture Behavioral of uart_interface is
  38. signal uart_data_in : std_logic_vector(7 downto 0);
  39. signal uart_data_out : std_logic_vector(7 downto 0);
  40. signal fifo_data_out : std_logic_vector(7 downto 0);
  41. signal fifo_data_ready : std_logic;
  42. signal uart_rx_ready : std_logic;
  43. signal uart_tx_busy : std_logic;
  44. signal uart_badbit : std_logic;
  45. signal uart_data_load : std_logic;
  46. signal fifo_data_ack : std_logic;
  47. signal uart_status_register : std_logic_vector(7 downto 0);
  48. signal rx_interrupt_enable : std_logic := '0';
  49. signal tx_interrupt_enable : std_logic := '0';
  50. signal rx_interrupt_signal : std_logic := '0';
  51. signal tx_interrupt_signal : std_logic := '0';
  52. signal uart_tx_was_busy : std_logic := '0';
  53. signal fifo_data_was_ready : std_logic := '0';
  54. signal cts_clk1 : std_logic;
  55. signal cts_clk2 : std_logic;
  56. signal fifo_nearly_full : std_logic;
  57. signal can_transmit : std_logic;
  58. type reset_seq_state is (
  59. st_idle,
  60. st_seen1,
  61. st_seen2,
  62. st_seen3,
  63. st_seen4,
  64. st_seen5
  65. );
  66. signal reset_seq : reset_seq_state := st_idle;
  67. signal reset_saw_byte0 : std_logic;
  68. signal reset_saw_byte1 : std_logic;
  69. begin
  70. -- this whole module could really do with a bit of a rethink.
  71. with cpu_address select
  72. cpu_data_out <=
  73. uart_status_register when "000",
  74. fifo_data_out when others;
  75. uart_data_in <= cpu_data_in;
  76. uart_status_register <= fifo_data_ready & uart_tx_busy & '0' & uart_badbit & rx_interrupt_enable & tx_interrupt_enable & rx_interrupt_signal & tx_interrupt_signal;
  77. interrupt <= (rx_interrupt_signal and rx_interrupt_enable) or (tx_interrupt_signal and tx_interrupt_enable);
  78. -- this decodes cpu_address="001" in a rather longwinded way.
  79. uart_data_load <= cpu_address(0) and (not cpu_address(1)) and (not cpu_address(2)) and enable and req_write;
  80. fifo_data_ack <= cpu_address(0) and (not cpu_address(1)) and (not cpu_address(2)) and enable and req_read;
  81. -- optional hardware flow control
  82. process(fifo_nearly_full, cts_clk2)
  83. begin
  84. if flow_control = 1 then
  85. serial_rts <= fifo_nearly_full;
  86. can_transmit <= (not cts_clk2);
  87. else
  88. serial_rts <= '0';
  89. can_transmit <= '1';
  90. end if;
  91. end process;
  92. -- optional reset on data sequence
  93. process(uart_data_out)
  94. begin
  95. if watch_for_reset = 1 then
  96. if uart_data_out = "00100001" then
  97. reset_saw_byte0 <= '1';
  98. reset_saw_byte1 <= '0';
  99. elsif uart_data_out = "01111110" then
  100. reset_saw_byte0 <= '0';
  101. reset_saw_byte1 <= '1';
  102. else
  103. reset_saw_byte0 <= '0';
  104. reset_saw_byte1 <= '0';
  105. end if;
  106. end if;
  107. end process;
  108. process(clk)
  109. begin
  110. if rising_edge(clk) then
  111. if reset = '1' then
  112. fifo_data_was_ready <= '0';
  113. rx_interrupt_enable <= '0';
  114. rx_interrupt_signal <= '0';
  115. tx_interrupt_enable <= '0';
  116. tx_interrupt_signal <= '0';
  117. uart_tx_was_busy <= '0';
  118. reset_out <= '0';
  119. reset_seq <= st_idle;
  120. cts_clk1 <= '0';
  121. cts_clk2 <= '0';
  122. else
  123. tx_interrupt_signal <= tx_interrupt_signal;
  124. rx_interrupt_signal <= rx_interrupt_signal;
  125. -- bring CTS into our clock domain
  126. if flow_control = 1 then
  127. cts_clk1 <= serial_cts;
  128. cts_clk2 <= cts_clk1;
  129. end if;
  130. -- handle writes to the status register
  131. if enable = '1' and req_write = '1' and cpu_address = "000" then
  132. rx_interrupt_enable <= cpu_data_in(3);
  133. tx_interrupt_enable <= cpu_data_in(2);
  134. rx_interrupt_signal <= cpu_data_in(1);
  135. tx_interrupt_signal <= cpu_data_in(0);
  136. end if;
  137. uart_tx_was_busy <= uart_tx_busy;
  138. fifo_data_was_ready <= fifo_data_ready;
  139. if uart_tx_was_busy = '1' and uart_tx_busy = '0' then
  140. tx_interrupt_signal <= '1';
  141. end if;
  142. if fifo_data_ready = '1' and fifo_data_was_ready = '0' then
  143. rx_interrupt_signal <= '1';
  144. end if;
  145. if watch_for_reset = 1 then
  146. if uart_rx_ready = '1' then
  147. reset_seq <= st_idle; -- end up here unless we match the conditions below
  148. reset_out <= '0';
  149. case reset_seq is
  150. when st_idle => if reset_saw_byte0 = '1' then reset_seq <= st_seen1; end if;
  151. when st_seen1 => if reset_saw_byte1 = '1' then reset_seq <= st_seen2; end if;
  152. when st_seen2 => if reset_saw_byte0 = '1' then reset_seq <= st_seen3; end if;
  153. when st_seen3 => if reset_saw_byte1 = '1' then reset_seq <= st_seen4; end if;
  154. when st_seen4 => if reset_saw_byte0 = '1' then reset_seq <= st_seen5; end if;
  155. when st_seen5 => if reset_saw_byte1 = '1' then reset_out <= '1'; end if;
  156. when others =>
  157. end case;
  158. else
  159. reset_seq <= reset_seq;
  160. reset_out <= '0';
  161. end if;
  162. end if;
  163. end if;
  164. end if;
  165. end process;
  166. fifo_instance: entity work.fifo
  167. PORT MAP(
  168. clk => clk,
  169. reset => reset,
  170. data_in => uart_data_out,
  171. data_out => fifo_data_out,
  172. read_ready => fifo_data_ready,
  173. read_en => fifo_data_ack,
  174. write_ready => open,
  175. write_en => uart_rx_ready,
  176. high_water_mark => fifo_nearly_full
  177. );
  178. uart_instance: entity work.uart
  179. GENERIC MAP(
  180. clk_frequency => clk_frequency
  181. )
  182. PORT MAP(
  183. clk => clk,
  184. serial_out => serial_out,
  185. serial_in => serial_in,
  186. data_in => uart_data_in,
  187. data_in_load => uart_data_load,
  188. data_out => uart_data_out,
  189. data_out_ready => uart_rx_ready,
  190. bad_bit => uart_badbit,
  191. transmitter_busy => uart_tx_busy,
  192. can_transmit => can_transmit
  193. );
  194. end Behavioral;