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";
+ constant GPIO_REG_INT_EN : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01000";
+ constant GPIO_REG_INT_STAT : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01001";
+ -- write 1 to clear
+ constant GPIO_REG_INT_CLR : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01100";
+ -- edge 0, level 1
+ constant GPIO_REG_INT_TYPE : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01101";
+ -- for edge: trigger on either edge = 1
+ constant GPIO_REG_INT_BOTH_EDGE : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01110";
+ -- for edge: rising 0, falling 1
+ -- for level: high 0, low 1
+ constant GPIO_REG_INT_LEVEL : std_ulogic_vector(GPIO_REG_BITS-1 downto 0) := "01111";
+
-- Current output value and direction
signal reg_data : std_ulogic_vector(NGPIO - 1 downto 0);
signal reg_dirn : std_ulogic_vector(NGPIO - 1 downto 0);
+ signal reg_in0 : std_ulogic_vector(NGPIO - 1 downto 0);
signal reg_in1 : std_ulogic_vector(NGPIO - 1 downto 0);
signal reg_in2 : std_ulogic_vector(NGPIO - 1 downto 0);
+ signal reg_intr_en : std_ulogic_vector(NGPIO - 1 downto 0);
+ signal reg_intr_hit : std_ulogic_vector(NGPIO - 1 downto 0);
+ signal reg_intr_type : std_ulogic_vector(NGPIO - 1 downto 0);
+ signal reg_intr_level : std_ulogic_vector(NGPIO - 1 downto 0);
+ signal reg_intr_both : std_ulogic_vector(NGPIO - 1 downto 0);
+
signal wb_rsp : wb_io_slave_out;
signal reg_out : std_ulogic_vector(NGPIO - 1 downto 0);
+ constant ZEROS : std_ulogic_vector(NGPIO-1 downto 0) := (others => '0');
begin
-
- -- No interrupt facility for now
- intr <= '0';
-
+ intr <= '0' when reg_intr_hit = ZEROS else '1';
gpio_out <= reg_data;
gpio_dir <= reg_dirn;
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_in1 when GPIO_REG_DATA_IN,
reg_dirn when GPIO_REG_DIR,
+ reg_intr_en when GPIO_REG_INT_EN,
+ reg_intr_hit when GPIO_REG_INT_STAT,
+ reg_intr_type when GPIO_REG_INT_TYPE,
+ reg_intr_both when GPIO_REG_INT_BOTH_EDGE,
+ reg_intr_level when GPIO_REG_INT_LEVEL,
(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)
+ variable trig : std_logic_vector(0 to 2);
+ variable change : std_logic;
+ variable intr_hit : boolean;
begin
if rising_edge(clk) then
wb_out <= wb_rsp;
+ for i in NGPIO - 1 downto 0 loop
+ -- interrupt triggers. reg_in1 is current value
+ if reg_intr_type(i) = '0' then
+ -- edge
+ change := '0' when (reg_in1(i) = reg_in2(i)) else '1';
+ trig := change & reg_intr_both(i) & reg_intr_level(i);
+ case trig is
+ -- both
+ when "110" | "111" => intr_hit := true;
+ -- rising
+ when "100" => intr_hit := reg_in1(i) = '1';
+ -- falling
+ when "101" => intr_hit := reg_in1(i) = '0';
+ when others => intr_hit := false;
+ end case;
+ else
+ -- level
+ intr_hit := reg_in1(i) = not reg_intr_level(i);
+ end if;
+ reg_intr_hit(i) <= '1' when intr_hit and reg_intr_en(i) = '1';
+
+ end loop;
+
+ -- previous value for interrupt edge detection
reg_in2 <= reg_in1;
- reg_in1 <= gpio_in;
+ -- 2 flip flops to cross from async input to sys clock domain
+ reg_in1 <= reg_in0;
+ reg_in0 <= gpio_in;
+
if rst = '1' then
reg_data <= (others => '0');
reg_dirn <= (others => '0');
+ reg_intr_en <= (others => '0');
+ reg_intr_hit <= (others => '0');
+ reg_intr_type <= (others => '0');
+ reg_intr_both <= (others => '0');
+ reg_intr_level <= (others => '0');
wb_out.ack <= '0';
else
if wb_in.cyc = '1' and wb_in.stb = '1' and wb_in.we = '1' then
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 GPIO_REG_INT_EN =>
+ reg_intr_en <= wb_in.dat(NGPIO - 1 downto 0);
+ when GPIO_REG_INT_CLR =>
+ reg_intr_hit <= reg_intr_hit and not wb_in.dat(NGPIO - 1 downto 0);
+ when GPIO_REG_INT_TYPE =>
+ reg_intr_type <= wb_in.dat(NGPIO - 1 downto 0);
+ when GPIO_REG_INT_BOTH_EDGE =>
+ reg_intr_both <= wb_in.dat(NGPIO - 1 downto 0);
+ when GPIO_REG_INT_LEVEL =>
+ reg_intr_level <= wb_in.dat(NGPIO - 1 downto 0);
when others =>
end case;
end if;
end process;
end architecture behaviour;
-
+
#define XICS_ICP_BASE 0xc0004000 /* Interrupt controller */
#define XICS_ICS_BASE 0xc0005000 /* Interrupt controller */
#define SPI_FCTRL_BASE 0xc0006000 /* SPI flash controller registers */
+#define GPIO_BASE 0xc0007000 /* GPIO registers */
#define DRAM_CTRL_BASE 0xc8000000 /* LiteDRAM control registers */
#define LETH_CSR_BASE 0xc8020000 /* LiteEth CSR registers */
#define LETH_SRAM_BASE 0xc8030000 /* LiteEth MMIO space */
#define SPI_REG_AUTO_CFG_CSTOUT_SHIFT 24 /* CS timeout */
#define SPI_REG_AUTO_CFG_CSTOUT_MASK (0x3f << SPI_REG_AUTO_CFG_CSTOUT_SHIFT)
+/*
+ * Register definitions for GPIO
+ */
+#define GPIO_REG_DATA_OUT 0x00
+#define GPIO_REG_DATA_IN 0x04
+#define GPIO_REG_DIR 0x08
+#define GPIO_REG_DATA_SET 0x10
+#define GPIO_REG_DATA_CLR 0x14
+
+#define GPIO_REG_INT_EN 0x20
+#define GPIO_REG_INT_STAT 0x24
+#define GPIO_REG_INT_CLR 0x30
+#define GPIO_REG_INT_TYPE 0x34
+#define GPIO_REG_INT_BOTH_EDGE 0x38
+#define GPIO_REG_INT_LEVEL 0x3C
#endif /* __MICROWATT_SOC_H */