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.
100 lines
3.4 KiB
VHDL
100 lines
3.4 KiB
VHDL
-- GPIO module for microwatt
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.wishbone_types.all;
|
|
|
|
entity gpio is
|
|
generic (
|
|
NGPIO : integer := 32
|
|
);
|
|
port (
|
|
clk : in std_ulogic;
|
|
rst : in std_ulogic;
|
|
|
|
-- Wishbone
|
|
wb_in : in wb_io_master_out;
|
|
wb_out : out wb_io_slave_out;
|
|
|
|
-- GPIO lines
|
|
gpio_in : in std_ulogic_vector(NGPIO - 1 downto 0);
|
|
gpio_out : out std_ulogic_vector(NGPIO - 1 downto 0);
|
|
-- 1 = output, 0 = input
|
|
gpio_dir : out std_ulogic_vector(NGPIO - 1 downto 0);
|
|
|
|
-- Interrupt
|
|
intr : out std_ulogic
|
|
);
|
|
end entity gpio;
|
|
|
|
architecture behaviour of gpio is
|
|
constant GPIO_REG_BITS : positive := 5;
|
|
|
|
-- Register addresses, matching addr downto 2, so 4 bytes per reg
|
|
constant GPIO_REG_DATA_OUT : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00000";
|
|
constant GPIO_REG_DATA_IN : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00001";
|
|
constant GPIO_REG_DIR : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00010";
|
|
constant GPIO_REG_DATA_SET : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00100";
|
|
constant GPIO_REG_DATA_CLR : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00101";
|
|
|
|
-- Current output value and direction
|
|
signal reg_data : std_ulogic_vector(NGPIO - 1 downto 0) := (others => '0');
|
|
signal reg_dirn : std_ulogic_vector(NGPIO - 1 downto 0) := (others => '0');
|
|
signal reg_in1 : std_ulogic_vector(NGPIO - 1 downto 0);
|
|
signal reg_in2 : std_ulogic_vector(NGPIO - 1 downto 0);
|
|
|
|
signal wb_rsp : wb_io_slave_out;
|
|
signal reg_out : std_ulogic_vector(NGPIO - 1 downto 0);
|
|
|
|
begin
|
|
|
|
-- No interrupt facility for now
|
|
intr <= '0';
|
|
|
|
gpio_out <= reg_data;
|
|
gpio_dir <= reg_dirn;
|
|
|
|
-- Wishbone response
|
|
wb_rsp.ack <= wb_in.cyc and wb_in.stb;
|
|
with wb_in.adr(GPIO_REG_BITS - 1 downto 0) select reg_out <=
|
|
reg_data when GPIO_REG_DATA_OUT,
|
|
reg_in2 when GPIO_REG_DATA_IN,
|
|
reg_dirn when GPIO_REG_DIR,
|
|
(others => '0') when others;
|
|
wb_rsp.dat(wb_rsp.dat'left downto NGPIO) <= (others => '0');
|
|
wb_rsp.dat(NGPIO - 1 downto 0) <= reg_out;
|
|
wb_rsp.stall <= '0';
|
|
|
|
regs_rw: process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
wb_out <= wb_rsp;
|
|
reg_in2 <= reg_in1;
|
|
reg_in1 <= gpio_in;
|
|
if rst = '1' then
|
|
reg_data <= (others => '0');
|
|
reg_dirn <= (others => '0');
|
|
wb_out.ack <= '0';
|
|
else
|
|
if wb_in.cyc = '1' and wb_in.stb = '1' and wb_in.we = '1' then
|
|
case wb_in.adr(GPIO_REG_BITS - 1 downto 0) is
|
|
when GPIO_REG_DATA_OUT =>
|
|
reg_data <= wb_in.dat(NGPIO - 1 downto 0);
|
|
when GPIO_REG_DIR =>
|
|
reg_dirn <= wb_in.dat(NGPIO - 1 downto 0);
|
|
when GPIO_REG_DATA_SET =>
|
|
reg_data <= reg_data or wb_in.dat(NGPIO - 1 downto 0);
|
|
when GPIO_REG_DATA_CLR =>
|
|
reg_data <= reg_data and not wb_in.dat(NGPIO - 1 downto 0);
|
|
when others =>
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end architecture behaviour;
|
|
|