You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
7.7 KiB
VHDL
200 lines
7.7 KiB
VHDL
-- Sim GPIO, based on potato GPIO by
|
|
-- Kristian Klomsten Skordal.
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.sim_console.all;
|
|
|
|
|
|
--! @brief Generic Wishbone GPIO Module.
|
|
--!
|
|
--! The following registers are defined:
|
|
--! |---------|------------------------------------------------------------------|
|
|
--! | Address | Description |
|
|
--! |---------|------------------------------------------------------------------|
|
|
--! | 0x00 | Describes the port: (read-only) |
|
|
--! | | bits 0-5: The number of pins |
|
|
--! | 0x08 | Input values, one bit per pin (read/write), |
|
|
--! | | If the pin is set to output, writing 1 will toggle the pin |
|
|
--! | 0x10 | Output values, one bit per pin (read/write) |
|
|
--! | 0x18 | Set register, Output = Output | set register (write-only) |
|
|
--! | 0x20 | Clear register, Output = Output & ~(clear register) (write-only) |
|
|
--! | 0x28 | Type, 4 bits per pin (read/write), pins 0-15 |
|
|
--! | 0x30 | Type, 4 bits per pin (read/write), pins 16-31 |
|
|
--! | 0x38 | Type, 4 bits per pin (read/write), pins 32-47 |
|
|
--! | 0x40 | Type, 4 bits per pin (read/write), pins 48-63 |
|
|
--! | | Types: MSB LSB |
|
|
--! | | 0 0 0 0 Input, Interrupt disabled |
|
|
--! | | 0 0 1 0 Input, Interrupt when low |
|
|
--! | | 0 0 1 1 Input, Interrupt when high |
|
|
--! | | 0 1 0 0 Input, Interrupt when falling |
|
|
--! | | 0 1 0 1 Input, Interrupt when rising |
|
|
--! | | 0 1 1 1 Output |
|
|
--! | | others Undefined |
|
|
--! | 0x48 | Interrupt Triggered, one bit per pin (read/write) |
|
|
--! |---------|------------------------------------------------------------------|
|
|
--!
|
|
--! Writes to the output register for input pins are ignored.
|
|
entity pp_soc_gpio is
|
|
generic(
|
|
NUM_GPIOS : natural := 64
|
|
);
|
|
port(
|
|
clk : in std_logic;
|
|
reset : in std_logic;
|
|
irq : out std_logic;
|
|
|
|
-- GPIO interface:
|
|
gpio : inout std_logic_vector(NUM_GPIOS - 1 downto 0);
|
|
|
|
-- Wishbone interface:
|
|
wb_adr_in : in std_logic_vector(7 downto 0);
|
|
wb_dat_in : in std_logic_vector(63 downto 0);
|
|
wb_dat_out : out std_logic_vector(63 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
|
|
|
|
type type_array is array (natural range 0 to NUM_GPIOS - 1) of
|
|
std_logic_vector(3 downto 0);
|
|
|
|
signal input_buffer : std_logic_vector(NUM_GPIOS - 1 downto 0);
|
|
signal input_register_prev : std_logic_vector(NUM_GPIOS - 1 downto 0);
|
|
signal input_register : std_logic_vector(NUM_GPIOS - 1 downto 0);
|
|
signal output_register : std_logic_vector(NUM_GPIOS - 1 downto 0);
|
|
signal type_register : type_array;
|
|
signal irq_triggered_register : std_logic_vector(NUM_GPIOS - 1 downto 0);
|
|
|
|
signal ack : std_logic := '0';
|
|
|
|
begin
|
|
|
|
assert NUM_GPIOS > 0 and NUM_GPIOS <= 64
|
|
report "Only a number between 1 and 64 (inclusive) GPIOs are supported!"
|
|
severity FAILURE;
|
|
|
|
wb_ack_out <= ack and wb_cyc_in and wb_stb_in;
|
|
|
|
wishbone: process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
for i in 0 to NUM_GPIOS - 1 loop
|
|
gpio(i) <= output_register(i) when type_register(i) = b"0111" else 'Z';
|
|
input_register_prev(i) <= input_register(i);
|
|
input_register(i) <= input_buffer(i);
|
|
input_buffer(i) <= gpio(i) when type_register(i) /= b"0111";
|
|
|
|
case type_register(i) is
|
|
when b"0010" =>
|
|
if gpio(i) = '0' then
|
|
irq_triggered_register(i) <= '1';
|
|
irq <= '1';
|
|
end if;
|
|
when b"0011" =>
|
|
if gpio(i) = '1' then
|
|
irq_triggered_register(i) <= '1';
|
|
irq <= '1';
|
|
end if;
|
|
when b"0100" =>
|
|
if input_register(i) = '0' and input_register_prev(i) = '1' then
|
|
irq_triggered_register(i) <= '1';
|
|
irq <= '1';
|
|
end if;
|
|
when b"0101" =>
|
|
if input_register(i) = '1' and input_register_prev(i) = '0' then
|
|
irq_triggered_register(i) <= '1';
|
|
irq <= '1';
|
|
end if;
|
|
when others =>
|
|
end case;
|
|
end loop;
|
|
|
|
if reset = '1' then
|
|
input_register <= (others => '0');
|
|
output_register <= (others => '0');
|
|
wb_dat_out <= (others => '0');
|
|
for i in 0 to NUM_GPIOS - 1 loop
|
|
type_register(i) <= (others => '0');
|
|
end loop;
|
|
irq_triggered_register <= (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 x"08" => --! Input Value
|
|
output_register <= output_register xor wb_dat_in(NUM_GPIOS - 1 downto 0);
|
|
when x"10" => --! Output Value
|
|
output_register <= wb_dat_in(NUM_GPIOS - 1 downto 0);
|
|
when x"18" => --! Set
|
|
output_register <= output_register OR wb_dat_in(NUM_GPIOS - 1 downto 0);
|
|
when x"20" => --! Clear
|
|
output_register <= output_register AND NOT(wb_dat_in(NUM_GPIOS - 1 downto 0));
|
|
when x"28" => --! Type Pins 0-15
|
|
for i in 0 to MINIMUM(NUM_GPIOS - 1, 15) loop
|
|
type_register(i) <= (wb_dat_in((i + 1) * 4 - 1 downto i * 4));
|
|
end loop;
|
|
when x"30" => --! Type Pins 16-31
|
|
for i in 16 to MINIMUM(NUM_GPIOS - 1, 31) loop
|
|
type_register(i) <= (wb_dat_in((i - 16 + 1) * 4 - 1 downto (i - 16) * 4));
|
|
end loop;
|
|
when x"38" => --! Type Pins 32-47
|
|
for i in 32 to MINIMUM(NUM_GPIOS - 1, 47) loop
|
|
type_register(i) <= (wb_dat_in((i - 32 + 1) * 4 - 1 downto (i - 32) * 4));
|
|
end loop;
|
|
when x"40" => --! Type Pins 48-63
|
|
for i in 48 to MINIMUM(NUM_GPIOS - 1, 63) loop
|
|
type_register(i) <= (wb_dat_in((i - 48 + 1) * 4 - 1 downto (i - 48) * 4));
|
|
end loop;
|
|
when others =>
|
|
end case;
|
|
ack <= '1';
|
|
else
|
|
case wb_adr_in is
|
|
when x"00" => --! Description
|
|
wb_dat_out <= std_logic_vector(to_unsigned(NUM_GPIOS, wb_dat_out'length));
|
|
when x"08" => --! Input Value
|
|
wb_dat_out <= std_logic_vector(resize(unsigned(input_register), wb_dat_out'length));
|
|
when x"10" => --! Output value
|
|
wb_dat_out <= std_logic_vector(resize(unsigned(output_register), wb_dat_out'length));
|
|
when x"28" => --! Type Pins 0-15
|
|
for i in 0 to MINIMUM(NUM_GPIOS - 1, 15) loop
|
|
wb_dat_out((i + 1) * 4 - 1 downto i * 4) <= type_register(i);
|
|
end loop;
|
|
when x"30" => --! Type Pins 16-31
|
|
for i in 21 to MINIMUM(NUM_GPIOS - 1, 31) loop
|
|
wb_dat_out((i - 16 + 1) * 4 - 1 downto (i - 16) * 4) <= type_register(i);
|
|
end loop;
|
|
when x"38" => --! Type Pins 32-47
|
|
for i in 32 to MINIMUM(NUM_GPIOS - 1, 47) loop
|
|
wb_dat_out((i - 32 + 1) * 4 - 1 downto (i - 32) * 4) <= type_register(i);
|
|
end loop;
|
|
when x"40" => --! Type Pins 32-47
|
|
for i in 32 to MINIMUM(NUM_GPIOS - 1, 47) loop
|
|
wb_dat_out((i - 32 + 1) * 4 - 1 downto (i - 32) * 4) <= type_register(i);
|
|
end loop;
|
|
when x"48" => --! Interrupts triggered
|
|
wb_dat_out <= std_logic_vector(resize(unsigned(irq_triggered_register), wb_dat_out'length));
|
|
irq_triggered_register <= (others => '0');
|
|
irq <= '0';
|
|
when others =>
|
|
end case;
|
|
report "ack";
|
|
ack <= '1';
|
|
end if;
|
|
elsif wb_stb_in = '0' then
|
|
ack <= '0';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process wishbone;
|
|
|
|
end architecture behaviour; |