diff --git a/fpga/pp_soc_uart.vhd b/fpga/pp_soc_uart.vhd index 1d5c629..879ea26 100644 --- a/fpga/pp_soc_uart.vhd +++ b/fpga/pp_soc_uart.vhd @@ -34,351 +34,353 @@ use ieee.numeric_std.all; --! - Bit 0: data received (receive buffer not empty) --! - Bit 1: ready to send data (transmit buffer empty) entity pp_soc_uart is - generic( - FIFO_DEPTH : natural := 64 --! Depth of the input and output FIFOs. + generic( + FIFO_DEPTH : natural := 64 --! Depth of the input and output FIFOs. ); - port( - clk : in std_logic; - reset : in std_logic; - - -- UART ports: - txd : out std_logic; - rxd : in std_logic; - - -- Interrupt signal: - irq : out std_logic; - - -- Wishbone ports: - wb_adr_in : in std_logic_vector(11 downto 0); - wb_dat_in : in std_logic_vector( 7 downto 0); - wb_dat_out : out std_logic_vector( 7 downto 0); - wb_we_in : in std_logic; - wb_cyc_in : in std_logic; - wb_stb_in : in std_logic; - wb_ack_out : out std_logic + port( + clk : in std_logic; + reset : in std_logic; + + -- UART ports: + txd : out std_logic; + rxd : in std_logic; + + -- Interrupt signal: + irq : out std_logic; + + -- Wishbone ports: + wb_adr_in : in std_logic_vector(11 downto 0); + wb_dat_in : in std_logic_vector( 7 downto 0); + wb_dat_out : out std_logic_vector( 7 downto 0); + wb_we_in : in std_logic; + wb_cyc_in : in std_logic; + wb_stb_in : in std_logic; + wb_ack_out : out std_logic ); end entity pp_soc_uart; architecture behaviour of pp_soc_uart is - subtype bitnumber is natural range 0 to 7; --! Type representing the index of a bit. + subtype bitnumber is natural range 0 to 7; --! Type representing the index of a bit. - -- UART sample clock signals: - signal sample_clk : std_logic; - signal sample_clk_divisor : std_logic_vector(7 downto 0); - signal sample_clk_counter : std_logic_vector(sample_clk_divisor'range); + -- UART sample clock signals: + signal sample_clk : std_logic; + signal sample_clk_divisor : std_logic_vector(7 downto 0); + signal sample_clk_counter : std_logic_vector(sample_clk_divisor'range); - -- UART receive process signals: - type rx_state_type is (IDLE, RECEIVE, STARTBIT, STOPBIT); - signal rx_state : rx_state_type; - signal rx_byte : std_logic_vector(7 downto 0); - signal rx_current_bit : bitnumber; + -- UART receive process signals: + type rx_state_type is (IDLE, RECEIVE, STARTBIT, STOPBIT); + signal rx_state : rx_state_type; + signal rx_byte : std_logic_vector(7 downto 0); + signal rx_current_bit : bitnumber; - subtype rx_sample_counter_type is natural range 0 to 15; - signal rx_sample_counter : rx_sample_counter_type; - signal rx_sample_value : rx_sample_counter_type; + subtype rx_sample_counter_type is natural range 0 to 15; + signal rx_sample_counter : rx_sample_counter_type; + signal rx_sample_value : rx_sample_counter_type; - subtype rx_sample_delay_type is natural range 0 to 7; - signal rx_sample_delay : rx_sample_delay_type; + subtype rx_sample_delay_type is natural range 0 to 7; + signal rx_sample_delay : rx_sample_delay_type; - -- UART transmit process signals: - type tx_state_type is (IDLE, TRANSMIT, STOPBIT); - signal tx_state : tx_state_type; - signal tx_byte : std_logic_vector(7 downto 0); - signal tx_current_bit : bitnumber; + -- UART transmit process signals: + type tx_state_type is (IDLE, TRANSMIT, STOPBIT); + signal tx_state : tx_state_type; + signal tx_byte : std_logic_vector(7 downto 0); + signal tx_current_bit : bitnumber; - -- UART transmit clock: - subtype uart_tx_counter_type is natural range 0 to 15; - signal uart_tx_counter : uart_tx_counter_type := 0; - signal uart_tx_clk : std_logic; + -- UART transmit clock: + subtype uart_tx_counter_type is natural range 0 to 15; + signal uart_tx_counter : uart_tx_counter_type := 0; + signal uart_tx_clk : std_logic; - -- Buffer signals: - signal send_buffer_full, send_buffer_empty : std_logic; - signal recv_buffer_full, recv_buffer_empty : std_logic; - signal send_buffer_input, send_buffer_output : std_logic_vector(7 downto 0); - signal recv_buffer_input, recv_buffer_output : std_logic_vector(7 downto 0); - signal send_buffer_push, send_buffer_pop : std_logic := '0'; - signal recv_buffer_push, recv_buffer_pop : std_logic := '0'; + -- Buffer signals: + signal send_buffer_full, send_buffer_empty : std_logic; + signal recv_buffer_full, recv_buffer_empty : std_logic; + signal send_buffer_input, send_buffer_output : std_logic_vector(7 downto 0); + signal recv_buffer_input, recv_buffer_output : std_logic_vector(7 downto 0); + signal send_buffer_push, send_buffer_pop : std_logic := '0'; + signal recv_buffer_push, recv_buffer_pop : std_logic := '0'; - -- IRQ enable signals: - signal irq_recv_enable, irq_tx_ready_enable : std_logic := '0'; + -- IRQ enable signals: + signal irq_recv_enable, irq_tx_ready_enable : std_logic := '0'; - -- Wishbone signals: - type wb_state_type is (IDLE, WRITE_ACK, READ_ACK); - signal wb_state : wb_state_type; + -- Wishbone signals: + type wb_state_type is (IDLE, WRITE_ACK, READ_ACK); + signal wb_state : wb_state_type; - signal wb_ack : std_logic; --! Wishbone acknowledge signal + signal wb_ack : std_logic; --! Wishbone acknowledge signal begin - irq <= (irq_recv_enable and (not recv_buffer_empty)) - or (irq_tx_ready_enable and send_buffer_empty); - - ---------- UART receive ---------- - - recv_buffer_input <= rx_byte; - - uart_receive: process(clk) - begin - if rising_edge(clk) then - if reset = '1' then - rx_state <= IDLE; - recv_buffer_push <= '0'; + irq <= (irq_recv_enable and (not recv_buffer_empty)) + or (irq_tx_ready_enable and send_buffer_empty); + + ---------- UART receive ---------- + + recv_buffer_input <= rx_byte; + + uart_receive: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + rx_state <= IDLE; + recv_buffer_push <= '0'; + else + case rx_state is + when IDLE => + if recv_buffer_push = '1' then + recv_buffer_push <= '0'; + end if; + + if sample_clk = '1' and rxd = '0' then + rx_sample_value <= rx_sample_counter; + rx_sample_delay <= 0; + rx_current_bit <= 0; + rx_state <= STARTBIT; + end if; + when STARTBIT => + if sample_clk = '1' then + if rx_sample_delay = 7 then + rx_state <= RECEIVE; + rx_sample_value <= rx_sample_counter; + rx_sample_delay <= 0; else - case rx_state is - when IDLE => - if recv_buffer_push = '1' then - recv_buffer_push <= '0'; - end if; - - if sample_clk = '1' and rxd = '0' then - rx_sample_value <= rx_sample_counter; - rx_sample_delay <= 0; - rx_current_bit <= 0; - rx_state <= STARTBIT; - end if; - when STARTBIT => - if sample_clk = '1' then - if rx_sample_delay = 7 then - rx_state <= RECEIVE; - rx_sample_value <= rx_sample_counter; - rx_sample_delay <= 0; - else - rx_sample_delay <= rx_sample_delay + 1; - end if; - end if; - when RECEIVE => - if sample_clk = '1' and rx_sample_counter = rx_sample_value then - if rx_current_bit /= 7 then - rx_byte(rx_current_bit) <= rxd; - rx_current_bit <= rx_current_bit + 1; - else - rx_byte(rx_current_bit) <= rxd; - rx_state <= STOPBIT; - end if; - end if; - when STOPBIT => - if sample_clk = '1' and rx_sample_counter = rx_sample_value then - rx_state <= IDLE; - - if recv_buffer_full = '0' then - recv_buffer_push <= '1'; - end if; - end if; - end case; + rx_sample_delay <= rx_sample_delay + 1; end if; - end if; - end process uart_receive; - - sample_counter: process(clk) - begin - if rising_edge(clk) then - if reset = '1' then - rx_sample_counter <= 0; - elsif sample_clk = '1' then - if rx_sample_counter = 15 then - rx_sample_counter <= 0; - else - rx_sample_counter <= rx_sample_counter + 1; - end if; + end if; + when RECEIVE => + if sample_clk = '1' and rx_sample_counter = rx_sample_value then + if rx_current_bit /= 7 then + rx_byte(rx_current_bit) <= rxd; + rx_current_bit <= rx_current_bit + 1; + else + rx_byte(rx_current_bit) <= rxd; + rx_state <= STOPBIT; end if; - end if; - end process sample_counter; - - ---------- UART transmit ---------- + end if; + when STOPBIT => + if sample_clk = '1' and rx_sample_counter = rx_sample_value then + rx_state <= IDLE; - tx_byte <= send_buffer_output; - - uart_transmit: process(clk) - begin - if rising_edge(clk) then - if reset = '1' then - txd <= '1'; - tx_state <= IDLE; - send_buffer_pop <= '0'; - tx_current_bit <= 0; - else - case tx_state is - when IDLE => - if send_buffer_empty = '0' and uart_tx_clk = '1' then - txd <= '0'; - send_buffer_pop <= '1'; - tx_current_bit <= 0; - tx_state <= TRANSMIT; - elsif uart_tx_clk = '1' then - txd <= '1'; - end if; - when TRANSMIT => - if send_buffer_pop = '1' then - send_buffer_pop <= '0'; - elsif uart_tx_clk = '1' and tx_current_bit = 7 then - txd <= tx_byte(tx_current_bit); - tx_state <= STOPBIT; - elsif uart_tx_clk = '1' then - txd <= tx_byte(tx_current_bit); - tx_current_bit <= tx_current_bit + 1; - end if; - when STOPBIT => - if uart_tx_clk = '1' then - txd <= '1'; - tx_state <= IDLE; - end if; - end case; + if recv_buffer_full = '0' then + recv_buffer_push <= '1'; end if; + end if; + end case; + end if; + end if; + end process uart_receive; + + sample_counter: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + rx_sample_counter <= 0; + elsif sample_clk = '1' then + if rx_sample_counter = 15 then + rx_sample_counter <= 0; + else + rx_sample_counter <= rx_sample_counter + 1; end if; - end process uart_transmit; - - uart_tx_clock_generator: process(clk) - begin - if rising_edge(clk) then - if reset = '1' then - uart_tx_counter <= 0; - uart_tx_clk <= '0'; - else - if sample_clk = '1' then - if uart_tx_counter = 15 then - uart_tx_counter <= 0; - uart_tx_clk <= '1'; - else - uart_tx_counter <= uart_tx_counter + 1; - uart_tx_clk <= '0'; - end if; - else - uart_tx_clk <= '0'; - end if; - end if; + end if; + end if; + end process sample_counter; + + ---------- UART transmit ---------- + + tx_byte <= send_buffer_output; + + uart_transmit: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + txd <= '1'; + tx_state <= IDLE; + send_buffer_pop <= '0'; + tx_current_bit <= 0; + else + case tx_state is + when IDLE => + if send_buffer_empty = '0' and uart_tx_clk = '1' then + txd <= '0'; + send_buffer_pop <= '1'; + tx_current_bit <= 0; + tx_state <= TRANSMIT; + elsif uart_tx_clk = '1' then + txd <= '1'; + end if; + when TRANSMIT => + if send_buffer_pop = '1' then + send_buffer_pop <= '0'; + elsif uart_tx_clk = '1' and tx_current_bit = 7 then + txd <= tx_byte(tx_current_bit); + tx_state <= STOPBIT; + elsif uart_tx_clk = '1' then + txd <= tx_byte(tx_current_bit); + tx_current_bit <= tx_current_bit + 1; + end if; + when STOPBIT => + if uart_tx_clk = '1' then + txd <= '1'; + tx_state <= IDLE; + end if; + end case; + end if; + end if; + end process uart_transmit; + + uart_tx_clock_generator: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + uart_tx_counter <= 0; + uart_tx_clk <= '0'; + else + if sample_clk = '1' then + if uart_tx_counter = 15 then + uart_tx_counter <= 0; + uart_tx_clk <= '1'; + else + uart_tx_counter <= uart_tx_counter + 1; + uart_tx_clk <= '0'; + end if; + else + uart_tx_clk <= '0'; end if; - end process uart_tx_clock_generator; - - ---------- Sample clock generator ---------- - - sample_clock_generator: process(clk) - begin - if rising_edge(clk) then - if reset = '1' then - sample_clk_counter <= (others => '0'); - sample_clk <= '0'; - else - if sample_clk_divisor /= x"00" then - if sample_clk_counter = sample_clk_divisor then - sample_clk_counter <= (others => '0'); - sample_clk <= '1'; - else - sample_clk_counter <= std_logic_vector(unsigned(sample_clk_counter) + 1); - sample_clk <= '0'; - end if; - end if; - end if; + end if; + end if; + end process uart_tx_clock_generator; + + ---------- Sample clock generator ---------- + + sample_clock_generator: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + sample_clk_counter <= (others => '0'); + sample_clk <= '0'; + else + if sample_clk_divisor /= x"00" then + if sample_clk_counter = sample_clk_divisor then + sample_clk_counter <= (others => '0'); + sample_clk <= '1'; + else + sample_clk_counter <= std_logic_vector(unsigned(sample_clk_counter) + 1); + sample_clk <= '0'; + end if; end if; - end process sample_clock_generator; - - ---------- Data Buffers ---------- - - send_buffer: entity work.pp_fifo - generic map( - DEPTH => FIFO_DEPTH, - WIDTH => 8 - ) port map( - clk => clk, - reset => reset, - full => send_buffer_full, - empty => send_buffer_empty, - data_in => send_buffer_input, - data_out => send_buffer_output, - push => send_buffer_push, - pop => send_buffer_pop + end if; + end if; + end process sample_clock_generator; + + ---------- Data Buffers ---------- + + send_buffer: entity work.pp_fifo + generic map( + DEPTH => FIFO_DEPTH, + WIDTH => 8 + ) port map( + clk => clk, + reset => reset, + full => send_buffer_full, + empty => send_buffer_empty, + data_in => send_buffer_input, + data_out => send_buffer_output, + push => send_buffer_push, + pop => send_buffer_pop ); - recv_buffer: entity work.pp_fifo - generic map( - DEPTH => FIFO_DEPTH, - WIDTH => 8 - ) port map( - clk => clk, - reset => reset, - full => recv_buffer_full, - empty => recv_buffer_empty, - data_in => recv_buffer_input, - data_out => recv_buffer_output, - push => recv_buffer_push, - pop => recv_buffer_pop + recv_buffer: entity work.pp_fifo + generic map( + DEPTH => FIFO_DEPTH, + WIDTH => 8 + ) port map( + clk => clk, + reset => reset, + full => recv_buffer_full, + empty => recv_buffer_empty, + data_in => recv_buffer_input, + data_out => recv_buffer_output, + push => recv_buffer_push, + pop => recv_buffer_pop ); - ---------- Wishbone Interface ---------- - - wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in; - - wishbone: process(clk) - begin - if rising_edge(clk) then - if reset = '1' then - wb_ack <= '0'; - wb_state <= IDLE; - send_buffer_push <= '0'; - recv_buffer_pop <= '0'; - sample_clk_divisor <= (others => '0'); - irq_recv_enable <= '0'; - irq_tx_ready_enable <= '0'; - else - case wb_state is - when IDLE => - if wb_cyc_in = '1' and wb_stb_in = '1' then - if wb_we_in = '1' then -- Write to register - if wb_adr_in = x"000" then - send_buffer_input <= wb_dat_in; - send_buffer_push <= '1'; - elsif wb_adr_in = x"018" then - sample_clk_divisor <= wb_dat_in; - elsif wb_adr_in = x"020" then - irq_recv_enable <= wb_dat_in(0); - irq_tx_ready_enable <= wb_dat_in(1); - end if; - - -- Invalid writes are acked and ignored. - - wb_ack <= '1'; - wb_state <= WRITE_ACK; - else -- Read from register - if wb_adr_in = x"008" then - recv_buffer_pop <= '1'; - elsif wb_adr_in = x"010" then - wb_dat_out <= x"0" & send_buffer_full & recv_buffer_full & send_buffer_empty & recv_buffer_empty; - wb_ack <= '1'; - elsif wb_adr_in = x"018" then - wb_dat_out <= sample_clk_divisor; - wb_ack <= '1'; - elsif wb_adr_in = x"020" then - wb_dat_out <= (0 => irq_recv_enable, 1 => irq_tx_ready_enable, others => '0'); - wb_ack <= '1'; - else - wb_dat_out <= (others => '0'); - wb_ack <= '1'; - end if; - wb_state <= READ_ACK; - end if; - end if; - when WRITE_ACK => - send_buffer_push <= '0'; - - if wb_stb_in = '0' then - wb_ack <= '0'; - wb_state <= IDLE; - end if; - when READ_ACK => - if recv_buffer_pop = '1' then - recv_buffer_pop <= '0'; - else - wb_dat_out <= recv_buffer_output; - wb_ack <= '1'; - end if; - - if wb_stb_in = '0' then - wb_ack <= '0'; - wb_state <= IDLE; - end if; - end case; + ---------- Wishbone Interface ---------- + + wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in; + + wishbone: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + wb_ack <= '0'; + wb_state <= IDLE; + send_buffer_push <= '0'; + recv_buffer_pop <= '0'; + sample_clk_divisor <= (others => '0'); + irq_recv_enable <= '0'; + irq_tx_ready_enable <= '0'; + else + case wb_state is + when IDLE => + if wb_cyc_in = '1' and wb_stb_in = '1' then + if wb_we_in = '1' then -- Write to register + if wb_adr_in = x"000" then + send_buffer_input <= wb_dat_in; + send_buffer_push <= '1'; + elsif wb_adr_in = x"018" then + sample_clk_divisor <= wb_dat_in; + elsif wb_adr_in = x"020" then + irq_recv_enable <= wb_dat_in(0); + irq_tx_ready_enable <= wb_dat_in(1); + end if; + + -- Invalid writes are acked and ignored. + wb_ack <= '1'; + wb_state <= WRITE_ACK; + else -- Read from register + if wb_adr_in = x"008" then + recv_buffer_pop <= '1'; + elsif wb_adr_in = x"010" then + wb_dat_out <= x"0" & send_buffer_full & recv_buffer_full & + send_buffer_empty & recv_buffer_empty; + wb_ack <= '1'; + elsif wb_adr_in = x"018" then + wb_dat_out <= sample_clk_divisor; + wb_ack <= '1'; + elsif wb_adr_in = x"020" then + wb_dat_out <= (0 => irq_recv_enable, + 1 => irq_tx_ready_enable, + others => '0'); + wb_ack <= '1'; + else + wb_dat_out <= (others => '0'); + wb_ack <= '1'; + end if; + wb_state <= READ_ACK; end if; - end if; - end process wishbone; + end if; + when WRITE_ACK => + send_buffer_push <= '0'; + + if wb_stb_in = '0' then + wb_ack <= '0'; + wb_state <= IDLE; + end if; + when READ_ACK => + if recv_buffer_pop = '1' then + recv_buffer_pop <= '0'; + else + wb_dat_out <= recv_buffer_output; + wb_ack <= '1'; + end if; + + if wb_stb_in = '0' then + wb_ack <= '0'; + wb_state <= IDLE; + end if; + end case; + end if; + end if; + end process wishbone; end architecture behaviour;