--! - 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;