-- The Potato Processor - A simple processor for FPGAs
|
-- The Potato Processor - A simple processor for FPGAs
|
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
|
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
|
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
|
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
|
|
--! @brief Simple UART module.
|
--! @brief Simple UART module.
|
--! The following registers are defined:
|
--! The following registers are defined:
|
--! 0 - Transmit data register (write-only)
|
--! 0 - Transmit data register (write-only)
|
--! 1 - Receive data register (read-only)
|
--! 1 - Receive data register (read-only)
|
--! 2 - Status register; (read-only)
|
--! 2 - Status register; (read-only)
|
--! - Bit 0: data in receive buffer
|
--! - Bit 0: no data in receive buffer
|
--! - Bit 1: no data in transmit buffer
|
--! - Bit 1: no data in transmit buffer
|
--! - Bit 2: receive buffer full
|
--! - Bit 2: receive buffer full
|
--! - Bit 3: transmit buffer full
|
--! - Bit 3: transmit buffer full
|
--! 3 - Control register, currently unused.
|
--! 3 - Control register, currently unused.
|
entity pp_soc_uart is
|
entity pp_soc_uart is
|
generic(
|
generic(
|
FIFO_DEPTH : natural := 64; --! Depth of the input and output FIFOs.
|
FIFO_DEPTH : natural := 64; --! Depth of the input and output FIFOs.
|
SAMPLE_CLK_DIVISOR : natural := 54 --! Divisor used to obtain the sample clock, f_clk / (16 * baudrate).
|
SAMPLE_CLK_DIVISOR : natural := 54 --! Divisor used to obtain the sample clock, f_clk / (16 * baudrate).
|
);
|
);
|
port(
|
port(
|
clk : in std_logic;
|
clk : in std_logic;
|
reset : in std_logic;
|
reset : in std_logic;
|
|
|
-- UART ports:
|
-- UART ports:
|
txd : out std_logic;
|
txd : out std_logic;
|
rxd : in std_logic;
|
rxd : in std_logic;
|
|
|
-- Interrupt signals:
|
-- Interrupt signals:
|
irq_send_buffer_empty : out std_logic;
|
irq_send_buffer_empty : out std_logic;
|
irq_data_received : out std_logic;
|
irq_data_received : out std_logic;
|
|
|
-- Wishbone ports:
|
-- Wishbone ports:
|
wb_adr_in : in std_logic_vector(1 downto 0);
|
wb_adr_in : in std_logic_vector(1 downto 0);
|
wb_dat_in : in std_logic_vector(7 downto 0);
|
wb_dat_in : in std_logic_vector(7 downto 0);
|
wb_dat_out : out std_logic_vector(7 downto 0);
|
wb_dat_out : out std_logic_vector(7 downto 0);
|
wb_we_in : in std_logic;
|
wb_we_in : in std_logic;
|
wb_cyc_in : in std_logic;
|
wb_cyc_in : in std_logic;
|
wb_stb_in : in std_logic;
|
wb_stb_in : in std_logic;
|
wb_ack_out : out std_logic
|
wb_ack_out : out std_logic
|
);
|
);
|
end entity pp_soc_uart;
|
end entity pp_soc_uart;
|
|
|
architecture behaviour of pp_soc_uart is
|
architecture behaviour of pp_soc_uart is
|
|
|
subtype bitnumber is natural range 0 to 7;
|
subtype bitnumber is natural range 0 to 7;
|
|
|
-- UART sample clock signals:
|
-- UART sample clock signals:
|
signal sample_clk : std_logic;
|
signal sample_clk : std_logic;
|
|
|
subtype sample_clk_counter_type is natural range 0 to SAMPLE_CLK_DIVISOR - 1;
|
subtype sample_clk_counter_type is natural range 0 to SAMPLE_CLK_DIVISOR - 1;
|
signal sample_clk_counter : sample_clk_counter_type := 0;
|
signal sample_clk_counter : sample_clk_counter_type := 0;
|
|
|
-- UART receive process signals:
|
-- UART receive process signals:
|
type rx_state_type is (IDLE, RECEIVE, STOPBIT);
|
type rx_state_type is (IDLE, RECEIVE, STOPBIT);
|
signal rx_state : rx_state_type;
|
signal rx_state : rx_state_type;
|
signal rx_byte : std_logic_vector(7 downto 0);
|
signal rx_byte : std_logic_vector(7 downto 0);
|
signal rx_current_bit : bitnumber;
|
signal rx_current_bit : bitnumber;
|
|
|
subtype rx_sample_counter_type is natural range 0 to 15;
|
subtype rx_sample_counter_type is natural range 0 to 15;
|
signal rx_sample_counter : rx_sample_counter_type;
|
signal rx_sample_counter : rx_sample_counter_type;
|
signal rx_sample_value : rx_sample_counter_type;
|
signal rx_sample_value : rx_sample_counter_type;
|
|
|
-- UART transmit process signals:
|
-- UART transmit process signals:
|
type tx_state_type is (IDLE, TRANSMIT, STOPBIT);
|
type tx_state_type is (IDLE, TRANSMIT, STOPBIT);
|
signal tx_state : tx_state_type;
|
signal tx_state : tx_state_type;
|
signal tx_byte : std_logic_vector(7 downto 0);
|
signal tx_byte : std_logic_vector(7 downto 0);
|
signal tx_current_bit : bitnumber;
|
signal tx_current_bit : bitnumber;
|
|
|
-- UART transmit clock:
|
-- UART transmit clock:
|
subtype uart_tx_counter_type is natural range 0 to 15;
|
subtype uart_tx_counter_type is natural range 0 to 15;
|
signal uart_tx_counter : uart_tx_counter_type := 0;
|
signal uart_tx_counter : uart_tx_counter_type := 0;
|
signal uart_tx_clk : std_logic;
|
signal uart_tx_clk : std_logic;
|
|
|
-- Buffer signals:
|
-- Buffer signals:
|
signal send_buffer_full, send_buffer_empty : std_logic;
|
signal send_buffer_full, send_buffer_empty : std_logic;
|
signal recv_buffer_full, recv_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 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 recv_buffer_input, recv_buffer_output : std_logic_vector(7 downto 0);
|
signal send_buffer_push, send_buffer_pop : std_logic := '0';
|
signal send_buffer_push, send_buffer_pop : std_logic := '0';
|
signal recv_buffer_push, recv_buffer_pop : std_logic := '0';
|
signal recv_buffer_push, recv_buffer_pop : std_logic := '0';
|
|
|
-- Wishbone signals:
|
-- Wishbone signals:
|
type wb_state_type is (IDLE, WRITE_ACK, READ_ACK);
|
type wb_state_type is (IDLE, WRITE_ACK, READ_ACK);
|
signal wb_state : wb_state_type;
|
signal wb_state : wb_state_type;
|
|
|
signal wb_ack : std_logic; --! Wishbone acknowledge signal
|
signal wb_ack : std_logic; --! Wishbone acknowledge signal
|
|
|
begin
|
begin
|
|
|
irq_send_buffer_empty <= send_buffer_empty;
|
irq_send_buffer_empty <= send_buffer_empty;
|
irq_data_received <= not recv_buffer_empty;
|
irq_data_received <= not recv_buffer_empty;
|
|
|
---------- UART receive ----------
|
---------- UART receive ----------
|
|
|
recv_buffer_input <= rx_byte;
|
recv_buffer_input <= rx_byte;
|
|
|
uart_receive: process(clk)
|
uart_receive: process(clk)
|
begin
|
begin
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if reset = '1' then
|
if reset = '1' then
|
rx_state <= IDLE;
|
rx_state <= IDLE;
|
else
|
else
|
case rx_state is
|
case rx_state is
|
when IDLE =>
|
when IDLE =>
|
if sample_clk = '1' and rxd = '0' then
|
if sample_clk = '1' and rxd = '0' then
|
rx_sample_value <= rx_sample_counter;
|
rx_sample_value <= rx_sample_counter;
|
rx_current_bit <= 0;
|
rx_current_bit <= 0;
|
rx_state <= RECEIVE;
|
rx_state <= RECEIVE;
|
end if;
|
end if;
|
when RECEIVE =>
|
when RECEIVE =>
|
if sample_clk = '1' and rx_sample_counter = rx_sample_value then
|
if sample_clk = '1' and rx_sample_counter = rx_sample_value then
|
if rx_current_bit /= 7 then
|
if rx_current_bit /= 7 then
|
rx_byte(rx_current_bit) <= rxd;
|
rx_byte(rx_current_bit) <= rxd;
|
rx_current_bit <= rx_current_bit + 1;
|
rx_current_bit <= rx_current_bit + 1;
|
else
|
else
|
rx_byte(rx_current_bit) <= rxd;
|
rx_byte(rx_current_bit) <= rxd;
|
rx_state <= STOPBIT;
|
rx_state <= STOPBIT;
|
|
|
if recv_buffer_full = '0' then
|
if recv_buffer_full = '0' then
|
recv_buffer_push <= '1';
|
recv_buffer_push <= '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
when STOPBIT =>
|
when STOPBIT =>
|
recv_buffer_push <= '0';
|
recv_buffer_push <= '0';
|
|
|
if sample_clk = '1' and rx_sample_counter = rx_sample_value then
|
if sample_clk = '1' and rx_sample_counter = rx_sample_value then
|
rx_state <= IDLE;
|
rx_state <= IDLE;
|
end if;
|
end if;
|
end case;
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process uart_receive;
|
end process uart_receive;
|
|
|
sample_counter: process(clk)
|
sample_counter: process(clk)
|
begin
|
begin
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if reset = '1' then
|
if reset = '1' then
|
rx_sample_counter <= 0;
|
rx_sample_counter <= 0;
|
elsif sample_clk = '1' then
|
elsif sample_clk = '1' then
|
if rx_sample_counter = 15 then
|
if rx_sample_counter = 15 then
|
rx_sample_counter <= 0;
|
rx_sample_counter <= 0;
|
else
|
else
|
rx_sample_counter <= rx_sample_counter + 1;
|
rx_sample_counter <= rx_sample_counter + 1;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process sample_counter;
|
end process sample_counter;
|
|
|
---------- UART transmit ----------
|
---------- UART transmit ----------
|
|
|
tx_byte <= send_buffer_output;
|
tx_byte <= send_buffer_output;
|
|
|
uart_transmit: process(clk)
|
uart_transmit: process(clk)
|
begin
|
begin
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if reset = '1' then
|
if reset = '1' then
|
txd <= '1';
|
txd <= '1';
|
tx_state <= IDLE;
|
tx_state <= IDLE;
|
send_buffer_pop <= '0';
|
send_buffer_pop <= '0';
|
tx_current_bit <= 0;
|
tx_current_bit <= 0;
|
else
|
else
|
case tx_state is
|
case tx_state is
|
when IDLE =>
|
when IDLE =>
|
if send_buffer_empty = '0' and uart_tx_clk = '1' then
|
if send_buffer_empty = '0' and uart_tx_clk = '1' then
|
txd <= '0';
|
txd <= '0';
|
send_buffer_pop <= '1';
|
send_buffer_pop <= '1';
|
tx_current_bit <= 0;
|
tx_current_bit <= 0;
|
tx_state <= TRANSMIT;
|
tx_state <= TRANSMIT;
|
elsif uart_tx_clk = '1' then
|
elsif uart_tx_clk = '1' then
|
txd <= '1';
|
txd <= '1';
|
end if;
|
end if;
|
when TRANSMIT =>
|
when TRANSMIT =>
|
if send_buffer_pop = '1' then
|
if send_buffer_pop = '1' then
|
send_buffer_pop <= '0';
|
send_buffer_pop <= '0';
|
elsif uart_tx_clk = '1' and tx_current_bit = 7 then
|
elsif uart_tx_clk = '1' and tx_current_bit = 7 then
|
txd <= tx_byte(tx_current_bit);
|
txd <= tx_byte(tx_current_bit);
|
tx_state <= STOPBIT;
|
tx_state <= STOPBIT;
|
elsif uart_tx_clk = '1' then
|
elsif uart_tx_clk = '1' then
|
txd <= tx_byte(tx_current_bit);
|
txd <= tx_byte(tx_current_bit);
|
tx_current_bit <= tx_current_bit + 1;
|
tx_current_bit <= tx_current_bit + 1;
|
end if;
|
end if;
|
when STOPBIT =>
|
when STOPBIT =>
|
if uart_tx_clk = '1' then
|
if uart_tx_clk = '1' then
|
txd <= '1';
|
txd <= '1';
|
tx_state <= IDLE;
|
tx_state <= IDLE;
|
end if;
|
end if;
|
end case;
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process uart_transmit;
|
end process uart_transmit;
|
|
|
uart_tx_clock_generator: process(clk)
|
uart_tx_clock_generator: process(clk)
|
begin
|
begin
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if reset = '1' then
|
if reset = '1' then
|
uart_tx_counter <= 0;
|
uart_tx_counter <= 0;
|
uart_tx_clk <= '0';
|
uart_tx_clk <= '0';
|
else
|
else
|
if sample_clk = '1' then
|
if sample_clk = '1' then
|
if uart_tx_counter = 15 then
|
if uart_tx_counter = 15 then
|
uart_tx_counter <= 0;
|
uart_tx_counter <= 0;
|
uart_tx_clk <= '1';
|
uart_tx_clk <= '1';
|
else
|
else
|
uart_tx_counter <= uart_tx_counter + 1;
|
uart_tx_counter <= uart_tx_counter + 1;
|
uart_tx_clk <= '0';
|
uart_tx_clk <= '0';
|
end if;
|
end if;
|
else
|
else
|
uart_tx_clk <= '0';
|
uart_tx_clk <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process uart_tx_clock_generator;
|
end process uart_tx_clock_generator;
|
|
|
---------- Sample clock generator ----------
|
---------- Sample clock generator ----------
|
|
|
sample_clock_generator: process(clk)
|
sample_clock_generator: process(clk)
|
begin
|
begin
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if reset = '1' then
|
if reset = '1' then
|
sample_clk_counter <= 0;
|
sample_clk_counter <= 0;
|
sample_clk <= '0';
|
sample_clk <= '0';
|
else
|
else
|
if sample_clk_counter = SAMPLE_CLK_DIVISOR - 1 then
|
if sample_clk_counter = SAMPLE_CLK_DIVISOR - 1 then
|
sample_clk_counter <= 0;
|
sample_clk_counter <= 0;
|
sample_clk <= '1';
|
sample_clk <= '1';
|
else
|
else
|
sample_clk_counter <= sample_clk_counter + 1;
|
sample_clk_counter <= sample_clk_counter + 1;
|
sample_clk <= '0';
|
sample_clk <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process sample_clock_generator;
|
end process sample_clock_generator;
|
|
|
---------- Data Buffers ----------
|
---------- Data Buffers ----------
|
|
|
send_buffer: entity work.pp_fifo
|
send_buffer: entity work.pp_fifo
|
generic map(
|
generic map(
|
DEPTH => FIFO_DEPTH,
|
DEPTH => FIFO_DEPTH,
|
WIDTH => 8
|
WIDTH => 8
|
) port map(
|
) port map(
|
clk => clk,
|
clk => clk,
|
reset => reset,
|
reset => reset,
|
full => send_buffer_full,
|
full => send_buffer_full,
|
empty => send_buffer_empty,
|
empty => send_buffer_empty,
|
data_in => send_buffer_input,
|
data_in => send_buffer_input,
|
data_out => send_buffer_output,
|
data_out => send_buffer_output,
|
push => send_buffer_push,
|
push => send_buffer_push,
|
pop => send_buffer_pop
|
pop => send_buffer_pop
|
);
|
);
|
|
|
recv_buffer: entity work.pp_fifo
|
recv_buffer: entity work.pp_fifo
|
generic map(
|
generic map(
|
DEPTH => FIFO_DEPTH,
|
DEPTH => FIFO_DEPTH,
|
WIDTH => 8
|
WIDTH => 8
|
) port map(
|
) port map(
|
clk => clk,
|
clk => clk,
|
reset => reset,
|
reset => reset,
|
full => recv_buffer_full,
|
full => recv_buffer_full,
|
empty => recv_buffer_empty,
|
empty => recv_buffer_empty,
|
data_in => recv_buffer_input,
|
data_in => recv_buffer_input,
|
data_out => recv_buffer_output,
|
data_out => recv_buffer_output,
|
push => recv_buffer_push,
|
push => recv_buffer_push,
|
pop => recv_buffer_pop
|
pop => recv_buffer_pop
|
);
|
);
|
|
|
---------- Wishbone Interface ----------
|
---------- Wishbone Interface ----------
|
|
|
wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in;
|
wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in;
|
|
|
wishbone: process(clk)
|
wishbone: process(clk)
|
begin
|
begin
|
if rising_edge(clk) then
|
if rising_edge(clk) then
|
if reset = '1' then
|
if reset = '1' then
|
wb_ack <= '0';
|
wb_ack <= '0';
|
wb_state <= IDLE;
|
wb_state <= IDLE;
|
send_buffer_push <= '0';
|
send_buffer_push <= '0';
|
else
|
else
|
case wb_state is
|
case wb_state is
|
when IDLE =>
|
when IDLE =>
|
if wb_cyc_in = '1' and wb_stb_in = '1' then
|
if wb_cyc_in = '1' and wb_stb_in = '1' then
|
if wb_we_in = '1' then -- Write to register
|
if wb_we_in = '1' then -- Write to register
|
if wb_adr_in = b"00" then
|
if wb_adr_in = b"00" then
|
send_buffer_input <= wb_dat_in;
|
send_buffer_input <= wb_dat_in;
|
send_buffer_push <= '1';
|
send_buffer_push <= '1';
|
wb_ack <= '1';
|
wb_ack <= '1';
|
wb_state <= WRITE_ACK;
|
wb_state <= WRITE_ACK;
|
else -- Invalid write, just ack and ignore
|
else -- Invalid write, just ack and ignore
|
wb_ack <= '1';
|
wb_ack <= '1';
|
wb_state <= WRITE_ACK;
|
wb_state <= WRITE_ACK;
|
end if;
|
end if;
|
else -- Read from register
|
else -- Read from register
|
if wb_adr_in = b"01" then
|
if wb_adr_in = b"01" then
|
recv_buffer_pop <= '1';
|
recv_buffer_pop <= '1';
|
wb_state <= READ_ACK;
|
wb_state <= READ_ACK;
|
elsif wb_adr_in = b"10" then
|
elsif wb_adr_in = b"10" then
|
wb_dat_out <= x"0" & send_buffer_full & recv_buffer_full & send_buffer_empty & not recv_buffer_empty;
|
wb_dat_out <= x"0" & send_buffer_full & recv_buffer_full & send_buffer_empty & recv_buffer_empty;
|
wb_ack <= '1';
|
wb_ack <= '1';
|
wb_state <= READ_ACK;
|
wb_state <= READ_ACK;
|
else
|
else
|
wb_dat_out <= (others => '0');
|
wb_dat_out <= (others => '0');
|
wb_ack <= '1';
|
wb_ack <= '1';
|
wb_state <= READ_ACK;
|
wb_state <= READ_ACK;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
when WRITE_ACK =>
|
when WRITE_ACK =>
|
send_buffer_push <= '0';
|
send_buffer_push <= '0';
|
|
|
if wb_stb_in = '0' then
|
if wb_stb_in = '0' then
|
wb_ack <= '0';
|
wb_ack <= '0';
|
wb_state <= IDLE;
|
wb_state <= IDLE;
|
end if;
|
end if;
|
when READ_ACK =>
|
when READ_ACK =>
|
if recv_buffer_pop = '1' then
|
if recv_buffer_pop = '1' then
|
wb_ack <= '1';
|
wb_ack <= '1';
|
recv_buffer_pop <= '0';
|
recv_buffer_pop <= '0';
|
wb_dat_out <= recv_buffer_output;
|
wb_dat_out <= recv_buffer_output;
|
end if;
|
end if;
|
|
|
if wb_stb_in = '0' then
|
if wb_stb_in = '0' then
|
wb_ack <= '0';
|
wb_ack <= '0';
|
wb_state <= IDLE;
|
wb_state <= IDLE;
|
end if;
|
end if;
|
end case;
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process wishbone;
|
end process wishbone;
|
|
|
end architecture behaviour;
|
end architecture behaviour;
|
|
|