summaryrefslogtreecommitdiffstats
path: root/zpu/hdl/zealot/devices/gpio.vhdl
blob: fc66bde0c74175b8767c6909d96983135eb24aa6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
--
-- this module desribes a simple GPIO interface
--
-- data on port_in is synhronized to clk_i and can be read at
-- address 0
--
-- any write to address 0 is mapped to port_out
--
-- at address 1 is a direction register (port_dir)
-- initialized with '1's, what mean direction = in
-- this register is useful for bidirectional pins, e.g. headers
--
--
-- some examples:
--
-- to connect 4 buttons:
-- port_in( 3 downto  0) <= gpio_button;
--
--
-- to connect 8 LEDs:
-- gpio_led <= port_out(7 downto 0); 
--
--
-- to connect 2 bidirectional header pins:
-- port_in(8)  <= gpio_pin(0);
-- gpio_pin(0) <= port_out(8) when port_dir(8) = '0' else 'Z';
--
-- port_in(9)  <= gpio_pin(1);
-- gpio_pin(1) <= port_out(9) when port_dir(9) = '0' else 'Z';
--

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity gpio is
    port(
        clk_i    : in  std_logic;
        reset_i  : in  std_logic;
        --
        we_i     : in  std_logic;
        data_i   : in  unsigned(31 downto 0);
        addr_i   : in  unsigned( 0 downto 0);
        data_o   : out unsigned(31 downto 0);
        --
        port_in  : in  std_logic_vector(31 downto 0);
        port_out : out std_logic_vector(31 downto 0);
        port_dir : out std_logic_vector(31 downto 0)
    );
end entity gpio;


architecture rtl of gpio is

    signal port_in_reg  : std_logic_vector(31 downto 0);
    signal port_in_sync : std_logic_vector(31 downto 0);
    --
    signal direction    : std_logic_vector(31 downto 0) := (others => '1');

begin

    process
    begin
        wait until rising_edge( clk_i);
        
        -- synchronize all inputs with two registers
        -- to avoid metastability
        port_in_reg  <= port_in;
        port_in_sync <= port_in_reg;

        -- write access to gpio
        if we_i = '1' then
            -- data
            if addr_i = "0" then
                port_out  <= std_logic_vector( data_i);
            end if;
            -- direction
            if addr_i = "1" then
                direction <= std_logic_vector( data_i);
            end if;
        end if;

        -- read access to gpio
        -- data
        if addr_i = "0" then
            data_o <= unsigned( port_in_sync);
        end if;
        -- direction
        if addr_i = "1" then
            data_o <= unsigned( direction);
        end if;

        -- outputs
        port_dir <= direction;

        -- sync reset
        if reset_i = '1' then
            direction    <= (others => '1');
            port_in_reg  <= (others => '0');
            port_in_sync <= (others => '0');
        end if;

    end process;


end architecture rtl;
OpenPOWER on IntegriCloud