OpenCores
URL https://opencores.org/ocsvn/potato/potato/trunk

Subversion Repositories potato

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /potato/trunk
    from Rev 6 to Rev 7
    Reverse comparison

Rev 6 → Rev 7

/soc/pp_soc_gpio.vhd
0,0 → 1,95
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
--! @brief Generic Wishbone GPIO Module.
--! The following registers are defined:
--! * 0: Input values, one bit per GPIO (read-only)
--! * 1: Output values, one bit per GPIO (read/write)
--! * 2: Direction register, 0 means input, 1 means output.
entity pp_soc_gpio is
generic(
NUM_GPIOS : natural := 32
);
port(
clk : in std_logic;
reset : in std_logic;
 
-- GPIO interface:
gpio : inout std_logic_vector(NUM_GPIOS - 1 downto 0);
 
-- Wishbone interface:
wb_adr_in : in std_logic_vector( 1 downto 0);
wb_dat_in : in std_logic_vector(31 downto 0);
wb_dat_out : out std_logic_vector(31 downto 0);
wb_cyc_in : in std_logic;
wb_stb_in : in std_logic;
wb_we_in : in std_logic;
wb_ack_out : out std_logic
);
end entity pp_soc_gpio;
 
architecture behaviour of pp_soc_gpio is
 
signal direction_register : std_logic_vector(NUM_GPIOS - 1 downto 0);
signal output_register : std_logic_vector(NUM_GPIOS - 1 downto 0);
signal input_register : std_logic_vector(NUM_GPIOS - 1 downto 0);
 
signal ack : std_logic := '0';
 
begin
 
assert NUM_GPIOS > 0 and NUM_GPIOS <= 32
report "Only a number between 1 and 32 (inclusive) GPIOs are supported!"
severity FAILURE;
 
io_setup: for i in 0 to NUM_GPIOS - 1 generate
gpio(i) <= 'Z' when direction_register(i) = '0' else output_register(i);
input_register(i) <= gpio(i) when direction_register(i) = '0' else '0';
end generate;
 
wb_ack_out <= ack and wb_cyc_in and wb_stb_in;
 
wishbone: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
direction_register <= (others => '0');
output_register <= (others => '0');
wb_dat_out <= (others => '0');
ack <= '0';
else
if wb_cyc_in = '1' and wb_stb_in = '1' and ack = '0' then
if wb_we_in = '1' then
case wb_adr_in is
when b"01" =>
output_register <= wb_dat_in(NUM_GPIOS - 1 downto 0);
when b"10" =>
direction_register <= wb_dat_in(NUM_GPIOS - 1 downto 0);
when others =>
end case;
ack <= '1';
else
case wb_adr_in is
when b"00" =>
wb_dat_out <= std_logic_vector(resize(unsigned(input_register), wb_dat_out'length));
when b"01" =>
wb_dat_out <= std_logic_vector(resize(unsigned(output_register), wb_dat_out'length));
when b"10" =>
wb_dat_out <= std_logic_vector(resize(unsigned(direction_register), wb_dat_out'length));
when others =>
end case;
ack <= '1';
end if;
elsif wb_stb_in = '0' then
ack <= '0';
end if;
end if;
end if;
end process wishbone;
 
end architecture behaviour;
/soc/pp_soc_timer.vhd
0,0 → 1,99
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
--! @brief Simple timer module for generating periodic interrupts.
--! The following registers are defined:
--! * 0: Control register. The bits are:
--! - 0: Run - set to '1' to enable the counter
--! - 1: Clear - set to '1' to clear the counter after a comparison match or just to reset it
--! * 1: Compare register, set this to the value where an interrupt should be generated.
--! * 2: Counter register, should only be read, but can be written if you want to.
entity pp_soc_timer is
port(
clk : in std_logic;
reset : in std_logic;
 
-- Timer interrupt:
irq : out std_logic;
 
-- Wishbone interface:
wb_adr_in : in std_logic_vector( 1 downto 0);
wb_dat_in : in std_logic_vector(31 downto 0);
wb_dat_out : out std_logic_vector(31 downto 0);
wb_cyc_in : in std_logic;
wb_stb_in : in std_logic;
wb_we_in : in std_logic;
wb_ack_out : out std_logic
);
end entity;
 
architecture behaviour of pp_soc_timer is
signal ctrl_run : std_logic;
 
signal counter : std_logic_vector(31 downto 0);
signal compare : std_logic_vector(31 downto 0);
 
-- Wishbone acknowledge signal:
signal ack : std_logic;
begin
 
wb_ack_out <= ack and wb_cyc_in and wb_stb_in;
irq <= '1' when counter = compare else '0';
 
timer: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
wb_dat_out <= (others => '0');
ack <= '0';
 
ctrl_run <= '0';
counter <= (others => '0');
compare <= (others => '1');
else
if ctrl_run = '1' and counter /= compare then
counter <= std_logic_vector(unsigned(counter) + 1);
end if;
 
if wb_cyc_in = '1' and wb_stb_in = '1' and ack = '0' then
if wb_we_in = '1' then
case wb_adr_in is
when b"00" => -- Write control register
ctrl_run <= wb_dat_in(0);
if wb_dat_in(1) = '1' then
counter <= (others => '0');
end if;
when b"01" => -- Write compare register
compare <= wb_dat_in;
when b"10" => -- Write count register
counter <= wb_dat_in;
when b"11" => -- Unused register
when others =>
end case;
ack <= '1';
else
case wb_adr_in is
when b"00" => -- Read control register
wb_dat_out <= (0 => ctrl_run, others => '0');
when b"01" => -- Read compare register
wb_dat_out <= compare;
when b"10" => -- Read count register
wb_dat_out <= counter;
when b"11" => -- Unused register
when others =>
end case;
ack <= '1';
end if;
elsif wb_stb_in = '0' then
ack <= '0';
end if;
end if;
end if;
end process timer;
 
end architecture behaviour;
/soc/pp_soc_dummy.vhd
0,0 → 1,56
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
 
library ieee;
use ieee.std_logic_1164.all;
 
--! @brief Dummy module for an SoC implementation.
--! Reads returns whatever was last written into the module.
entity pp_soc_dummy is
port(
clk : in std_logic;
reset : in std_logic;
 
-- Wishbone signals:
wb_dat_in : in std_logic_vector(31 downto 0);
wb_dat_out : out std_logic_vector(31 downto 0);
wb_cyc_in : in std_logic;
wb_stb_in : in std_logic;
wb_we_in : in std_logic;
wb_ack_out : out std_logic
);
end entity pp_soc_dummy;
 
architecture behaviour of pp_soc_dummy is
 
signal reg : std_logic_vector(31 downto 0);
signal ack : std_logic;
 
begin
 
wb_ack_out <= ack and wb_cyc_in and wb_stb_in;
 
wishbone: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
reg <= (others => '0');
ack <= '0';
else
if wb_cyc_in = '1' and wb_stb_in = '1' and ack = '0' then
if wb_we_in = '1' then
reg <= wb_dat_in;
ack <= '1';
else
wb_dat_out <= reg;
ack <= '1';
end if;
elsif wb_stb_in = '0' then
ack <= '0';
end if;
end if;
end if;
end process wishbone;
 
end architecture behaviour;
/soc/pp_soc_uart.vhd
0,0 → 1,333
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
 
library ieee;
use ieee.std_logic_1164.all;
 
--! @brief Simple UART module.
--! The following registers are defined:
--! 0 - Transmit data register (write-only)
--! 1 - Receive data register (read-only)
--! 2 - Status register; (read-only)
--! - Bit 0: data in receive buffer
--! - Bit 1: no data in transmit buffer
--! - Bit 2: receive buffer full
--! - Bit 3: transmit buffer full
--! 3 - Control register, currently unused.
entity pp_soc_uart is
generic(
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).
);
port(
clk : in std_logic;
reset : in std_logic;
 
-- UART ports:
txd : out std_logic;
rxd : in std_logic;
 
-- Interrupt signals:
irq_send_buffer_empty : out std_logic;
irq_data_received : out std_logic;
 
-- Wishbone ports:
wb_adr_in : in std_logic_vector(1 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;
 
-- UART sample clock signals:
signal sample_clk : std_logic;
 
subtype sample_clk_counter_type is natural range 0 to SAMPLE_CLK_DIVISOR - 1;
signal sample_clk_counter : sample_clk_counter_type := 0;
 
-- UART receive process signals:
type rx_state_type is (IDLE, RECEIVE, 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;
 
-- 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;
 
-- 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';
 
-- 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
 
begin
 
irq_send_buffer_empty <= send_buffer_empty;
irq_data_received <= not recv_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;
else
case rx_state is
when IDLE =>
if sample_clk = '1' and rxd = '0' then
rx_sample_value <= rx_sample_counter;
rx_current_bit <= 0;
rx_state <= RECEIVE;
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;
 
if recv_buffer_full = '0' then
recv_buffer_push <= '1';
end if;
end if;
end if;
when STOPBIT =>
recv_buffer_push <= '0';
 
if sample_clk = '1' and rx_sample_counter = rx_sample_value then
rx_state <= IDLE;
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 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 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 <= 0;
sample_clk <= '0';
else
if sample_clk_counter = SAMPLE_CLK_DIVISOR - 1 then
sample_clk_counter <= 0;
sample_clk <= '1';
else
sample_clk_counter <= sample_clk_counter + 1;
sample_clk <= '0';
end if;
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
);
 
---------- 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';
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 = b"00" then
send_buffer_input <= wb_dat_in;
send_buffer_push <= '1';
wb_ack <= '1';
wb_state <= WRITE_ACK;
else -- Invalid write, just ack and ignore
wb_ack <= '1';
wb_state <= WRITE_ACK;
end if;
else -- Read from register
if wb_adr_in = b"01" then
recv_buffer_pop <= '1';
wb_state <= READ_ACK;
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_ack <= '1';
wb_state <= READ_ACK;
else
wb_dat_out <= (others => '0');
wb_ack <= '1';
wb_state <= READ_ACK;
end if;
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
wb_ack <= '1';
recv_buffer_pop <= '0';
wb_dat_out <= recv_buffer_output;
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;
/testbenches/tb_soc_uart.vhd
0,0 → 1,95
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
 
library ieee;
use ieee.std_logic_1164.all;
 
entity tb_soc_uart is
end entity tb_soc_uart;
 
architecture testbench of tb_soc_uart is
 
-- Clock signal:
signal clk : std_logic := '0';
constant clk_period : time := 10 ns;
 
-- Reset signal:
signal reset : std_logic := '1';
 
-- UART ports:
signal txd : std_logic;
signal rxd : std_logic := '1';
 
-- interrupt signals:
signal irq_send_buffer_empty : std_logic;
signal irq_data_received : std_logic;
 
-- Wishbone ports:
signal wb_adr_in : std_logic_vector(1 downto 0) := (others => '0');
signal wb_dat_in : std_logic_vector(7 downto 0) := (others => '0');
signal wb_dat_out : std_logic_vector(7 downto 0);
signal wb_we_in : std_logic := '0';
signal wb_cyc_in : std_logic := '0';
signal wb_stb_in : std_logic := '0';
signal wb_ack_out : std_logic;
 
begin
 
uut: entity work.pp_soc_uart
port map(
clk => clk,
reset => reset,
txd => txd,
rxd => rxd,
irq_send_buffer_empty => irq_send_buffer_empty,
irq_data_received => irq_data_received,
wb_adr_in => wb_adr_in,
wb_dat_in => wb_dat_in,
wb_dat_out => wb_dat_out,
wb_we_in => wb_we_in,
wb_cyc_in => wb_cyc_in,
wb_stb_in => wb_stb_in,
wb_ack_out => wb_ack_out
);
 
-- Set up an internal loopback:
rxd <= txd;
 
clock: process
begin
clk <= '1';
wait for clk_period / 2;
clk <= '0';
wait for clk_period / 2;
end process clock;
 
stimulus: process
begin
wait for clk_period * 2;
reset <= '0';
 
-- Write a 'P' (for Potato the Processor) to the UART:
wb_adr_in <= b"00";
wb_dat_in <= x"50";
wb_we_in <= '1';
wb_cyc_in <= '1';
wb_stb_in <= '1';
 
wait until wb_ack_out = '1';
wait for clk_period;
wb_stb_in <= '0';
wait for clk_period;
 
-- Write an 'o':
wb_dat_in <= x"6f";
wb_stb_in <= '1';
wait until wb_ack_out = '1';
wait for clk_period;
wb_stb_in <= '0';
wait for clk_period;
 
wait;
end process stimulus;
 
end architecture testbench;
/testbenches/tb_soc_gpio.vhd
0,0 → 1,91
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
 
library ieee;
use ieee.std_logic_1164.all;
 
entity tb_soc_gpio is
end entity tb_soc_gpio;
 
architecture testbench of tb_soc_gpio is
 
-- Clock signal:
signal clk : std_logic := '0';
constant clk_period : time := 10 ns;
 
-- Reset signal:
signal reset : std_logic := '1';
 
-- GPIOs:
signal gpio : std_logic_vector(31 downto 0);
 
-- Wishbone bus:
signal wb_adr_in : std_logic_vector( 1 downto 0) := (others => '0');
signal wb_dat_in : std_logic_vector(31 downto 0) := (others => '0');
signal wb_dat_out : std_logic_vector(31 downto 0);
signal wb_cyc_in : std_logic := '0';
signal wb_stb_in : std_logic := '0';
signal wb_we_in : std_logic := '0';
signal wb_ack_out : std_logic;
begin
 
uut: entity work.pp_soc_gpio
generic map(
NUM_GPIOS => 32
) port map(
clk => clk,
reset => reset,
gpio => gpio,
wb_adr_in => wb_adr_in,
wb_dat_in => wb_dat_in,
wb_dat_out => wb_dat_out,
wb_cyc_in => wb_cyc_in,
wb_stb_in => wb_stb_in,
wb_we_in => wb_we_in,
wb_ack_out => wb_ack_out
);
 
clock: process
begin
clk <= '1';
wait for clk_period / 2;
clk <= '0';
wait for clk_period / 2;
end process clock;
 
stimulus: process
begin
wait for clk_period * 2;
reset <= '0';
 
-- Set the upper half of the GPIOs as inputs, the rest as outputs:
wb_dat_in <= x"0000ffff";
wb_adr_in <= b"10";
wb_we_in <= '1';
wb_cyc_in <= '1';
wb_stb_in <= '1';
wait until wb_ack_out = '1';
wait for clk_period;
wb_stb_in <= '0';
wb_cyc_in <= '0';
wb_we_in <= '0';
wait for clk_period;
 
-- Set the outputs to aa, see if the upper half gets ignored correctly:
wb_dat_in <= x"aaaaaaaa";
wb_adr_in <= b"01";
wb_we_in <= '1';
wb_cyc_in <= '1';
wb_stb_in <= '1';
wait until wb_ack_out = '1';
wait for clk_period;
wb_stb_in <= '0';
wb_cyc_in <= '0';
wb_we_in <= '0';
wait for clk_period;
 
wait;
end process stimulus;
 
end architecture testbench;
/testbenches/tb_soc_timer.vhd
0,0 → 1,108
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
 
library ieee;
use ieee.std_logic_1164.all;
 
entity tb_soc_timer is
end entity tb_soc_timer;
 
architecture behaviour of tb_soc_timer is
 
-- Clock signal:
signal clk : std_logic := '0';
constant clk_period : time := 10 ns;
-- Reset signal:
signal reset : std_logic := '1';
 
-- IRQ signal:
signal irq : std_logic;
 
-- Wishbone interface:
signal wb_adr_in : std_logic_vector(1 downto 0) := (others => '0');
signal wb_dat_in : std_logic_vector(31 downto 0) := (others => '0');
signal wb_dat_out : std_logic_vector(31 downto 0);
signal wb_cyc_in : std_logic := '0';
signal wb_stb_in : std_logic := '0';
signal wb_we_in : std_logic := '0';
signal wb_ack_out : std_logic;
 
begin
 
uut: entity work.pp_soc_timer
port map(
clk => clk,
reset => reset,
irq => irq,
wb_adr_in => wb_adr_in,
wb_dat_in => wb_dat_in,
wb_dat_out => wb_dat_out,
wb_cyc_in => wb_cyc_in,
wb_stb_in => wb_stb_in,
wb_we_in => wb_we_in,
wb_ack_out => wb_ack_out
);
 
clock: process
begin
clk <= '1';
wait for clk_period / 2;
clk <= '0';
wait for clk_period / 2;
end process clock;
 
stimulus: process
begin
wait for clk_period * 2;
reset <= '0';
 
wait for clk_period;
 
-- Set the compare register to 50:
wb_cyc_in <= '1';
wb_stb_in <= '1';
wb_adr_in <= b"01";
wb_dat_in <= x"00000032";
wb_we_in <= '1';
wait until wb_ack_out = '1';
wait for clk_period;
 
wb_stb_in <= '0';
wait for clk_period;
 
-- Start the timer:
wb_stb_in <= '1';
wb_adr_in <= b"00";
wb_dat_in <= x"00000003";
wait until wb_ack_out = '1';
wait for clk_period;
 
wb_stb_in <= '0';
wb_cyc_in <= '0';
wb_we_in <= '0';
wait for clk_period;
 
-- Wait for the interrupt:
wait until irq = '1';
wait for clk_period;
 
-- Reset the interrupt:
wb_cyc_in <= '1';
wb_stb_in <= '1';
wb_we_in <= '1';
wb_adr_in <= b"00";
wb_dat_in <= x"00000003";
wait until wb_ack_out = '1';
wait for clk_period;
 
wb_stb_in <= '0';
wb_cyc_in <= '0';
wb_we_in <= '0';
wait for clk_period;
 
wait;
end process stimulus;
 
end architecture behaviour;
/example/imem_wrapper.vhd
0,0 → 1,68
-- Practical Test Application for the Potato Processor
-- (c) Kristian Klomsten Skordal 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato-test/issues>
 
library ieee;
use ieee.std_logic_1164.all;
 
entity imem_wrapper is
port(
clk : in std_logic;
reset : in std_logic;
 
-- Wishbone interface:
wb_adr_in : in std_logic_vector(12 downto 0);
wb_dat_out : out std_logic_vector(31 downto 0);
wb_cyc_in : in std_logic;
wb_stb_in : in std_logic;
wb_ack_out : out std_logic
);
end entity imem_wrapper;
 
architecture behaviour of imem_wrapper is
 
type wb_state is (IDLE, READ_ACK);
signal state : wb_state := IDLE;
 
signal address : std_logic_vector(10 downto 0);
signal data : std_logic_vector(31 downto 0);
 
signal ack : std_logic := '0';
 
begin
 
imem: entity work.instruction_rom
port map(
clka => clk,
addra => address,
douta => wb_dat_out
);
 
wb_ack_out <= ack and wb_cyc_in and wb_stb_in;
 
wishbone: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
ack <= '0';
state <= IDLE;
else
case state is
when IDLE =>
if wb_cyc_in = '1' and wb_stb_in = '1' then
address <= wb_adr_in(12 downto 2);
state <= READ_ACK;
end if;
when READ_ACK =>
if ack = '0' then
ack <= '1';
elsif wb_stb_in = '0' then
ack <= '0';
state <= IDLE;
end if;
end case;
end if;
end if;
end process wishbone;
 
end architecture behaviour;
/example/toplevel.vhd
0,0 → 1,370
-- Practical Test Application for the Potato Processor
-- (c) Kristian Klomsten Skordal 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <https://github.com/skordal/potato-test/issues>
 
library ieee;
use ieee.std_logic_1164.all;
 
entity toplevel is
port(
clk : in std_logic; -- System clock, 100 MHz
reset_n : in std_logic; -- CPU reset signal, active low
 
-- External interrupt input:
external_interrupt : in std_logic;
 
-- GPIO pins, must be inout to use with the GPIO module:
switches : inout std_logic_vector(15 downto 0);
leds : inout std_logic_vector(15 downto 0);
 
-- UART1 (host) pins:
uart_txd : out std_logic;
uart_rxd : in std_logic
);
end entity toplevel;
 
architecture behaviour of toplevel is
signal system_clk : std_logic;
signal timer_clk : std_logic;
 
-- Active high reset signal:
signal reset : std_logic;
 
-- IRQs:
signal irq : std_logic_vector(7 downto 0);
signal uart_irq_rts, uart_irq_recv : std_logic;
signal timer_irq : std_logic;
 
-- Processor wishbone interface:
signal p_adr_out : std_logic_vector(31 downto 0);
signal p_dat_out : std_logic_vector(31 downto 0);
signal p_dat_in : std_logic_vector(31 downto 0);
signal p_sel_out : std_logic_vector( 3 downto 0);
signal p_we_out : std_logic;
signal p_cyc_out, p_stb_out : std_logic;
signal p_ack_in : std_logic;
 
-- Instruction memory wishbone interface:
signal imem_adr_in : std_logic_vector(12 downto 0);
signal imem_dat_out : std_logic_vector(31 downto 0);
signal imem_cyc_in, imem_stb_in : std_logic;
signal imem_ack_out : std_logic;
 
-- Data memory wishbone interface:
signal dmem_adr_in : std_logic_vector(12 downto 0);
signal dmem_dat_in : std_logic_vector(31 downto 0);
signal dmem_dat_out : std_logic_vector(31 downto 0);
signal dmem_sel_in : std_logic_vector( 3 downto 0);
signal dmem_we_in : std_logic;
signal dmem_cyc_in, dmem_stb_in : std_logic;
signal dmem_ack_out : std_logic;
 
-- GPIO module I (switches) wishbone interface:
signal gpio1_adr_in : std_logic_vector(1 downto 0);
signal gpio1_dat_in : std_logic_vector(31 downto 0);
signal gpio1_dat_out : std_logic_vector(31 downto 0);
signal gpio1_we_in : std_logic;
signal gpio1_cyc_in, gpio1_stb_in : std_logic;
signal gpio1_ack_out : std_logic;
 
-- GPIO module II (LEDs) wishbone interface:
signal gpio2_adr_in : std_logic_vector(1 downto 0);
signal gpio2_dat_in : std_logic_vector(31 downto 0);
signal gpio2_dat_out : std_logic_vector(31 downto 0);
signal gpio2_we_in : std_logic;
signal gpio2_cyc_in, gpio2_stb_in : std_logic;
signal gpio2_ack_out : std_logic;
 
-- UART module wishbone interface:
signal uart_adr_in : std_logic_vector(1 downto 0);
signal uart_dat_in : std_logic_vector(7 downto 0);
signal uart_dat_out : std_logic_vector(7 downto 0);
signal uart_we_in : std_logic;
signal uart_cyc_in, uart_stb_in : std_logic;
signal uart_ack_out : std_logic;
 
-- Timer module wishbone interface:
signal timer_adr_in : std_logic_vector(1 downto 0);
signal timer_dat_in : std_logic_vector(31 downto 0);
signal timer_dat_out : std_logic_vector(31 downto 0);
signal timer_we_in : std_logic;
signal timer_cyc_in, timer_stb_in : std_logic;
signal timer_ack_out : std_logic;
 
-- Dummy module interface:
signal dummy_dat_in : std_logic_vector(31 downto 0);
signal dummy_dat_out : std_logic_vector(31 downto 0);
signal dummy_we_in : std_logic;
signal dummy_cyc_in, dummy_stb_in : std_logic;
signal dummy_ack_out : std_logic;
 
-- Address decoder signals:
type ad_state_type is (IDLE, BUSY);
signal ad_state : ad_state_type;
 
type module_name is (
MODULE_IMEM, MODULE_DMEM, -- Memory modules
MODULE_GPIO1, MODULE_GPIO2, -- GPIO modules
MODULE_UART, -- UART module
MODULE_TIMER, -- Timer module
MODULE_DUMMY, -- Dummy module, used for invalid addresses
MODULE_NONE -- Boring no-module mode, uses the dummy module
);
signal active_module : module_name;
 
begin
 
reset <= not reset_n;
irq <= (
0 => external_interrupt,
1 => uart_irq_rts, 2 => uart_irq_recv,
5 => timer_irq, others => '0'
);
 
clkgen: entity work.clock_generator
port map(
clk => clk,
system_clk => system_clk,
timer_clk => timer_clk
);
 
processor: entity work.pp_potato
port map(
clk => system_clk,
reset => reset,
irq => irq,
fromhost_data => (others => '0'),
fromhost_updated => '0',
tohost_data => open,
tohost_updated => open,
wb_adr_out => p_adr_out,
wb_dat_out => p_dat_out,
wb_dat_in => p_dat_in,
wb_sel_out => p_sel_out,
wb_we_out => p_we_out,
wb_cyc_out => p_cyc_out,
wb_stb_out => p_stb_out,
wb_ack_in => p_ack_in
);
 
imem: entity work.imem_wrapper
port map(
clk => system_clk,
reset => reset,
wb_adr_in => imem_adr_in,
wb_dat_out => imem_dat_out,
wb_cyc_in => imem_cyc_in,
wb_stb_in => imem_stb_in,
wb_ack_out => imem_ack_out
);
 
dmem: entity work.pp_soc_memory
generic map(
MEMORY_SIZE => 8192
) port map(
clk => system_clk,
reset => reset,
wb_adr_in => dmem_adr_in,
wb_dat_in => dmem_dat_in,
wb_dat_out => dmem_dat_out,
wb_sel_in => dmem_sel_in,
wb_we_in => dmem_we_in,
wb_cyc_in => dmem_cyc_in,
wb_stb_in => dmem_stb_in,
wb_ack_out => dmem_ack_out
);
 
gpio1: entity work.pp_soc_gpio
generic map(
NUM_GPIOS => 16
) port map(
clk => system_clk,
reset => reset,
gpio => switches,
wb_adr_in => gpio1_adr_in,
wb_dat_in => gpio1_dat_in,
wb_dat_out => gpio1_dat_out,
wb_cyc_in => gpio1_cyc_in,
wb_stb_in => gpio1_stb_in,
wb_we_in => gpio1_we_in,
wb_ack_out => gpio1_ack_out
);
 
gpio2: entity work.pp_soc_gpio
generic map(
NUM_GPIOS => 16
) port map(
clk => system_clk,
reset => reset,
gpio => leds,
wb_adr_in => gpio2_adr_in,
wb_dat_in => gpio2_dat_in,
wb_dat_out => gpio2_dat_out,
wb_cyc_in => gpio2_cyc_in,
wb_stb_in => gpio2_stb_in,
wb_we_in => gpio2_we_in,
wb_ack_out => gpio2_ack_out
);
 
uart1: entity work.pp_soc_uart
generic map(
FIFO_DEPTH => 64,
SAMPLE_CLK_DIVISOR => 27
) port map(
clk => system_clk,
reset => reset,
txd => uart_txd,
rxd => uart_rxd,
irq_send_buffer_empty => uart_irq_rts,
irq_data_received => uart_irq_recv,
wb_adr_in => uart_adr_in,
wb_dat_in => uart_dat_in,
wb_dat_out => uart_dat_out,
wb_cyc_in => uart_cyc_in,
wb_stb_in => uart_stb_in,
wb_we_in => uart_we_in,
wb_ack_out => uart_ack_out
);
 
timer1: entity work.pp_soc_timer
port map(
clk => system_clk,
reset => reset,
irq => timer_irq,
wb_adr_in => timer_adr_in,
wb_dat_in => timer_dat_in,
wb_dat_out => timer_dat_out,
wb_cyc_in => timer_cyc_in,
wb_stb_in => timer_stb_in,
wb_we_in => timer_we_in,
wb_ack_out => timer_ack_out
);
 
dummy: entity work.pp_soc_dummy
port map(
clk => system_clk,
reset => reset,
wb_dat_in => dummy_dat_in,
wb_dat_out => dummy_dat_out,
wb_cyc_in => dummy_cyc_in,
wb_stb_in => dummy_stb_in,
wb_we_in => dummy_we_in,
wb_ack_out => dummy_ack_out
);
 
imem_cyc_in <= p_cyc_out when active_module = MODULE_IMEM else '0';
dmem_cyc_in <= p_cyc_out when active_module = MODULE_DMEM else '0';
gpio1_cyc_in <= p_cyc_out when active_module = MODULE_GPIO1 else '0';
gpio2_cyc_in <= p_cyc_out when active_module = MODULE_GPIO2 else '0';
uart_cyc_in <= p_cyc_out when active_module = MODULE_UART else '0';
timer_cyc_in <= p_cyc_out when active_module = MODULE_TIMER else '0';
dummy_cyc_in <= p_cyc_out when active_module = MODULE_DUMMY else '0';
 
imem_stb_in <= p_stb_out when active_module = MODULE_IMEM else '0';
dmem_stb_in <= p_stb_out when active_module = MODULE_DMEM else '0';
gpio1_stb_in <= p_stb_out when active_module = MODULE_GPIO1 else '0';
gpio2_stb_in <= p_stb_out when active_module = MODULE_GPIO2 else '0';
uart_stb_in <= p_stb_out when active_module = MODULE_UART else '0';
timer_stb_in <= p_stb_out when active_module = MODULE_TIMER else '0';
dummy_stb_in <= p_stb_out when active_module = MODULE_DUMMY else '0';
 
imem_adr_in <= p_adr_out(12 downto 0);
dmem_adr_in <= p_adr_out(12 downto 0);
gpio1_adr_in <= p_adr_out(3 downto 2);
gpio2_adr_in <= p_adr_out(3 downto 2);
uart_adr_in <= p_adr_out(3 downto 2);
timer_adr_in <= p_adr_out(3 downto 2);
 
dmem_dat_in <= p_dat_out;
gpio1_dat_in <= p_dat_out;
gpio2_dat_in <= p_dat_out;
uart_dat_in <= p_dat_out(7 downto 0);
timer_dat_in <= p_dat_out;
dummy_dat_in <= p_dat_out;
 
dmem_sel_in <= p_sel_out;
 
gpio1_we_in <= p_we_out;
gpio2_we_in <= p_we_out;
dmem_we_in <= p_we_out;
uart_we_in <= p_we_out;
timer_we_in <= p_we_out;
dummy_we_in <= p_we_out;
 
address_decoder: process(system_clk)
begin
if rising_edge(system_clk) then
if reset = '1' then
ad_state <= IDLE;
active_module <= MODULE_NONE;
else
case ad_state is
when IDLE =>
if p_cyc_out = '1' and p_stb_out = '1' then
if p_adr_out(31 downto 13) = b"0000000000000000000" then
active_module <= MODULE_IMEM;
ad_state <= BUSY;
elsif p_adr_out(31 downto 13) = b"0000000000000000001" then -- 0x2000
active_module <= MODULE_DMEM;
ad_state <= BUSY;
elsif p_adr_out(31 downto 11) = b"000000000000000001000" then -- 0x4000
active_module <= MODULE_GPIO1;
ad_state <= BUSY;
elsif p_adr_out(31 downto 11) = b"000000000000000001001" then -- 0x4800
active_module <= MODULE_GPIO2;
ad_state <= BUSY;
elsif p_adr_out(31 downto 11) = b"000000000000000001010" then -- 0x5000
active_module <= MODULE_UART;
ad_state <= BUSY;
elsif p_adr_out(31 downto 11) = b"000000000000000001011" then -- 0x5800
active_module <= MODULE_TIMER;
ad_state <= BUSY;
else
--active_module <= MODULE_NONE;
active_module <= MODULE_DUMMY;
ad_state <= BUSY;
end if;
end if;
when BUSY =>
if p_cyc_out = '0' then
active_module <= MODULE_NONE;
ad_state <= IDLE;
end if;
end case;
end if;
end if;
end process address_decoder;
 
module_mux: process(active_module, imem_ack_out, imem_dat_out, dmem_ack_out, dmem_dat_out,
gpio1_ack_out, gpio1_dat_out, gpio2_ack_out, gpio2_dat_out, uart_ack_out, uart_dat_out,
timer_ack_out, timer_dat_out, dummy_ack_out, dummy_dat_out)
begin
case active_module is
when MODULE_IMEM =>
p_ack_in <= imem_ack_out;
p_dat_in <= imem_dat_out;
when MODULE_DMEM =>
p_ack_in <= dmem_ack_out;
p_dat_in <= dmem_dat_out;
when MODULE_GPIO1 =>
p_ack_in <= gpio1_ack_out;
p_dat_in <= gpio1_dat_out;
when MODULE_GPIO2 =>
p_ack_in <= gpio2_ack_out;
p_dat_in <= gpio2_dat_out;
when MODULE_UART =>
p_ack_in <= uart_ack_out;
p_dat_in <= (31 downto 8 => '0') & uart_dat_out;
when MODULE_TIMER =>
p_ack_in <= timer_ack_out;
p_dat_in <= timer_dat_out;
when MODULE_DUMMY =>
p_ack_in <= dummy_ack_out;
p_dat_in <= dummy_dat_out;
when MODULE_NONE =>
p_ack_in <= '0';
p_dat_in <= (others => '0');
end case;
end process module_mux;
 
end architecture behaviour;
/example/README
0,0 → 1,33
# Demo design for the Nexys 4 board
 
This folder contains a design for a simple demo design using the Potato
processor. It has been tested using Vivado 2014.4.
 
## Quick Start
 
In order to use the design, first import all source files from the folders
`src/`, `soc/` and `example/` into your project.
 
### Clocking
 
Then add a clock generator using the Clocking Wizard. To seamlessly integrate
it into the design, name it "clock_generator". Choose the following options:
 
* Frequency Synthesis
* Safe Clock Startup
 
Set up two output clocks, `clk_out1` with frequency 50 MHz, and `clk_out2` with
a frequency of 10 MHz. Rename the corresponding ports to `system_clk` and
`timer_clk` respectively. Name the input clock `clk`.
 
### Instruction memory
 
Add a block RAM to use as instruction ROM using the Block Memory Generator.
Choose "Single Port ROM" as memory type, set port A width to 32 bits and
port A depth to 2048. Initialize it with your application binary and,
optionally, fill the remaining memory locations with 0x00000013.
 
### Test it!
 
Now you can test it and hopefully it works :-)
 
/example/nexys4_constraints.xdc
0,0 → 1,94
# Practical Test Application for the Potato Processor
# (c) Kristian Klomsten Skordal 2015 <kristian.skordal@wafflemail.net>
# Report bugs and issues on <https://github.com/skordal/potato-test/issues>
 
# Operating conditions:
set_operating_conditions -airflow 0
set_operating_conditions -heatsink low
 
# Clock:
set_property PACKAGE_PIN E3 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]
 
# Reset:
set_property PACKAGE_PIN C12 [get_ports reset_n]
set_property IOSTANDARD LVCMOS33 [get_ports reset_n]
 
# External interrupt button:
set_property PACKAGE_PIN E16 [get_ports external_interrupt]
set_property IOSTANDARD LVCMOS33 [get_ports external_interrupt]
 
# UART (to host) lines:
set_property PACKAGE_PIN C4 [get_ports uart_rxd]
set_property IOSTANDARD LVCMOS33 [get_ports uart_rxd]
set_property PACKAGE_PIN D4 [get_ports uart_txd]
set_property IOSTANDARD LVCMOS33 [get_ports uart_txd]
 
# Switches:
set_property PACKAGE_PIN U9 [get_ports {switches[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[0]}]
set_property PACKAGE_PIN U8 [get_ports {switches[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[1]}]
set_property PACKAGE_PIN R7 [get_ports {switches[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[2]}]
set_property PACKAGE_PIN R6 [get_ports {switches[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[3]}]
set_property PACKAGE_PIN R5 [get_ports {switches[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[4]}]
set_property PACKAGE_PIN V7 [get_ports {switches[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[5]}]
set_property PACKAGE_PIN V6 [get_ports {switches[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[6]}]
set_property PACKAGE_PIN V5 [get_ports {switches[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[7]}]
set_property PACKAGE_PIN U4 [get_ports {switches[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[8]}]
set_property PACKAGE_PIN V2 [get_ports {switches[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[9]}]
set_property PACKAGE_PIN U2 [get_ports {switches[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[10]}]
set_property PACKAGE_PIN T3 [get_ports {switches[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[11]}]
set_property PACKAGE_PIN T1 [get_ports {switches[12]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[12]}]
set_property PACKAGE_PIN R3 [get_ports {switches[13]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[13]}]
set_property PACKAGE_PIN P3 [get_ports {switches[14]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[14]}]
set_property PACKAGE_PIN P4 [get_ports {switches[15]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[15]}]
 
# LEDs:
set_property PACKAGE_PIN T8 [get_ports {leds[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[0]}]
set_property PACKAGE_PIN V9 [get_ports {leds[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[1]}]
set_property PACKAGE_PIN R8 [get_ports {leds[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[2]}]
set_property PACKAGE_PIN T6 [get_ports {leds[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[3]}]
set_property PACKAGE_PIN T5 [get_ports {leds[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[4]}]
set_property PACKAGE_PIN T4 [get_ports {leds[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[5]}]
set_property PACKAGE_PIN U7 [get_ports {leds[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[6]}]
set_property PACKAGE_PIN U6 [get_ports {leds[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[7]}]
set_property PACKAGE_PIN V4 [get_ports {leds[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[8]}]
set_property PACKAGE_PIN U3 [get_ports {leds[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[9]}]
set_property PACKAGE_PIN V1 [get_ports {leds[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[10]}]
set_property PACKAGE_PIN R1 [get_ports {leds[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[11]}]
set_property PACKAGE_PIN P5 [get_ports {leds[12]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[12]}]
set_property PACKAGE_PIN U1 [get_ports {leds[13]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[13]}]
set_property PACKAGE_PIN R2 [get_ports {leds[14]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[14]}]
set_property PACKAGE_PIN P2 [get_ports {leds[15]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[15]}]

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.