ignore /abc.history
[microwatt.git] / gpio.vhdl
1 -- GPIO module for microwatt
2 library ieee;
3 use ieee.std_logic_1164.all;
4 use ieee.numeric_std.all;
5
6 library work;
7 use work.wishbone_types.all;
8
9 entity gpio is
10 generic (
11 NGPIO : integer := 32
12 );
13 port (
14 clk : in std_ulogic;
15 rst : in std_ulogic;
16
17 -- Wishbone
18 wb_in : in wb_io_master_out;
19 wb_out : out wb_io_slave_out;
20
21 -- GPIO lines
22 gpio_in : in std_ulogic_vector(NGPIO - 1 downto 0);
23 gpio_out : out std_ulogic_vector(NGPIO - 1 downto 0);
24 -- 1 = output, 0 = input
25 gpio_dir : out std_ulogic_vector(NGPIO - 1 downto 0);
26
27 -- Interrupt
28 intr : out std_ulogic
29 );
30 end entity gpio;
31
32 architecture behaviour of gpio is
33 constant GPIO_REG_BITS : positive := 5;
34
35 -- Register addresses, matching addr downto 2, so 4 bytes per reg
36 constant GPIO_REG_DATA_OUT : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00000";
37 constant GPIO_REG_DATA_IN : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00001";
38 constant GPIO_REG_DIR : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00010";
39 constant GPIO_REG_DATA_SET : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00100";
40 constant GPIO_REG_DATA_CLR : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "00101";
41
42 constant GPIO_REG_INT_EN : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01000";
43 constant GPIO_REG_INT_STAT : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01001";
44 -- write 1 to clear
45 constant GPIO_REG_INT_CLR : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01100";
46 -- edge 0, level 1
47 constant GPIO_REG_INT_TYPE : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01101";
48 -- for edge: trigger on either edge = 1
49 constant GPIO_REG_INT_BOTH_EDGE : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01110";
50 -- for edge: rising 0, falling 1
51 -- for level: high 0, low 1
52 constant GPIO_REG_INT_LEVEL : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01111";
53
54 -- Current output value and direction
55 signal reg_data : std_ulogic_vector(NGPIO - 1 downto 0);
56 signal reg_dirn : std_ulogic_vector(NGPIO - 1 downto 0);
57 signal reg_in0 : std_ulogic_vector(NGPIO - 1 downto 0);
58 signal reg_in1 : std_ulogic_vector(NGPIO - 1 downto 0);
59 signal reg_in2 : std_ulogic_vector(NGPIO - 1 downto 0);
60
61 signal reg_intr_en : std_ulogic_vector(NGPIO - 1 downto 0);
62 signal reg_intr_hit : std_ulogic_vector(NGPIO - 1 downto 0);
63 signal reg_intr_type : std_ulogic_vector(NGPIO - 1 downto 0);
64 signal reg_intr_level : std_ulogic_vector(NGPIO - 1 downto 0);
65 signal reg_intr_both : std_ulogic_vector(NGPIO - 1 downto 0);
66
67 signal wb_rsp : wb_io_slave_out;
68 signal reg_out : std_ulogic_vector(NGPIO - 1 downto 0);
69
70 constant ZEROS : std_ulogic_vector(NGPIO-1 downto 0) := (others => '0');
71 begin
72 intr <= '0' when reg_intr_hit = ZEROS else '1';
73 gpio_out <= reg_data;
74 gpio_dir <= reg_dirn;
75
76 -- Wishbone response
77 wb_rsp.ack <= wb_in.cyc and wb_in.stb;
78 with wb_in.adr(GPIO_REG_BITS - 1 downto 0) select reg_out <=
79 reg_data when GPIO_REG_DATA_OUT,
80 reg_in1 when GPIO_REG_DATA_IN,
81 reg_dirn when GPIO_REG_DIR,
82 reg_intr_en when GPIO_REG_INT_EN,
83 reg_intr_hit when GPIO_REG_INT_STAT,
84 reg_intr_type when GPIO_REG_INT_TYPE,
85 reg_intr_both when GPIO_REG_INT_BOTH_EDGE,
86 reg_intr_level when GPIO_REG_INT_LEVEL,
87 (others => '0') when others;
88 wb_rsp.dat(wb_rsp.dat'left downto NGPIO) <= (others => '0');
89 wb_rsp.dat(NGPIO - 1 downto 0) <= reg_out;
90 wb_rsp.stall <= '0';
91
92 regs_rw: process(clk)
93 variable trig : std_logic_vector(0 to 2);
94 variable change : std_logic;
95 variable intr_hit : boolean;
96 begin
97 if rising_edge(clk) then
98 wb_out <= wb_rsp;
99 for i in NGPIO - 1 downto 0 loop
100 -- interrupt triggers. reg_in1 is current value
101 if reg_intr_type(i) = '0' then
102 -- edge
103 change := '0' when (reg_in1(i) = reg_in2(i)) else '1';
104 trig := change & reg_intr_both(i) & reg_intr_level(i);
105 case trig is
106 -- both
107 when "110" | "111" => intr_hit := true;
108 -- rising
109 when "100" => intr_hit := reg_in1(i) = '1';
110 -- falling
111 when "101" => intr_hit := reg_in1(i) = '0';
112 when others => intr_hit := false;
113 end case;
114 else
115 -- level
116 intr_hit := reg_in1(i) = not reg_intr_level(i);
117 end if;
118 reg_intr_hit(i) <= '1' when intr_hit and reg_intr_en(i) = '1';
119
120 end loop;
121
122 -- previous value for interrupt edge detection
123 reg_in2 <= reg_in1;
124 -- 2 flip flops to cross from async input to sys clock domain
125 reg_in1 <= reg_in0;
126 reg_in0 <= gpio_in;
127
128 if rst = '1' then
129 reg_data <= (others => '0');
130 reg_dirn <= (others => '0');
131 reg_intr_en <= (others => '0');
132 reg_intr_hit <= (others => '0');
133 reg_intr_type <= (others => '0');
134 reg_intr_both <= (others => '0');
135 reg_intr_level <= (others => '0');
136 wb_out.ack <= '0';
137 else
138 if wb_in.cyc = '1' and wb_in.stb = '1' and wb_in.we = '1' then
139 case wb_in.adr(GPIO_REG_BITS - 1 downto 0) is
140 when GPIO_REG_DATA_OUT =>
141 reg_data <= wb_in.dat(NGPIO - 1 downto 0);
142 when GPIO_REG_DIR =>
143 reg_dirn <= wb_in.dat(NGPIO - 1 downto 0);
144 when GPIO_REG_DATA_SET =>
145 reg_data <= reg_data or wb_in.dat(NGPIO - 1 downto 0);
146 when GPIO_REG_DATA_CLR =>
147 reg_data <= reg_data and not wb_in.dat(NGPIO - 1 downto 0);
148 when GPIO_REG_INT_EN =>
149 reg_intr_en <= wb_in.dat(NGPIO - 1 downto 0);
150 when GPIO_REG_INT_CLR =>
151 reg_intr_hit <= reg_intr_hit and not wb_in.dat(NGPIO - 1 downto 0);
152 when GPIO_REG_INT_TYPE =>
153 reg_intr_type <= wb_in.dat(NGPIO - 1 downto 0);
154 when GPIO_REG_INT_BOTH_EDGE =>
155 reg_intr_both <= wb_in.dat(NGPIO - 1 downto 0);
156 when GPIO_REG_INT_LEVEL =>
157 reg_intr_level <= wb_in.dat(NGPIO - 1 downto 0);
158 when others =>
159 end case;
160 end if;
161 end if;
162 end if;
163 end process;
164
165 end architecture behaviour;
166