pp_uart: reformat

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
pull/118/head
Benjamin Herrenschmidt 4 years ago
parent 9620a76281
commit 559b3bcf2d

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

Loading…
Cancel
Save