From 45f502112a6012bfa62715e344ccc185f884d130 Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Tue, 29 Oct 2019 15:56:38 +1100 Subject: [PATCH] Add GPIO for Arty A7 Adds GPIO ports for all switches/leds/PMOD/ChipKit connectors on the Arty A7 Signed-off-by: Alastair D'Silva --- Makefile | 3 +- core_tb.vhdl | 8 +- fpga/arty_a7.vhdl | 82 ++++++++ fpga/arty_a7.xdc | 116 +++++++++++ fpga/pp_soc_gpio.vhdl | 200 ++++++++++++++++++ fpga/{toplevel.vhdl => toplevel_nogpio.vhdl} | 10 +- microwatt.core | 24 ++- sim_gpio.vhdl | 205 +++++++++++++++++++ soc.vhdl | 89 +++++++- 9 files changed, 716 insertions(+), 21 deletions(-) create mode 100644 fpga/arty_a7.vhdl create mode 100644 fpga/pp_soc_gpio.vhdl rename fpga/{toplevel.vhdl => toplevel_nogpio.vhdl} (89%) create mode 100644 sim_gpio.vhdl diff --git a/Makefile b/Makefile index 3056c53..11145b5 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,8 @@ simple_ram_behavioural_helpers.o: simple_ram_behavioural_tb.o: wishbone_types.o simple_ram_behavioural.o simple_ram_behavioural.o: wishbone_types.o simple_ram_behavioural_helpers.o sim_uart.o: wishbone_types.o sim_console.o -soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o simple_ram_behavioural.o dmi_dtm_xilinx.o wishbone_debug_master.o +sim_gpio.o: wishbone_types.o sim_console.o +soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o sim_gpio.o simple_ram_behavioural.o dmi_dtm_xilinx.o wishbone_debug_master.o wishbone_arbiter.o: wishbone_types.o wishbone_types.o: writeback.o: common.o crhelpers.o diff --git a/core_tb.vhdl b/core_tb.vhdl index 672b424..c4f3157 100644 --- a/core_tb.vhdl +++ b/core_tb.vhdl @@ -21,13 +21,17 @@ begin SIM => true, MEMORY_SIZE => 524288, RAM_INIT_FILE => "simple_ram_behavioural.bin", - RESET_LOW => false + RESET_LOW => false, + GPIO0_PINS => 1, + GPIO1_PINS => 1 ) port map( rst => rst, system_clk => clk, uart0_rxd => '0', - uart0_txd => open + uart0_txd => open, + gpio0 => open, + gpio1 => open ); clk_process: process diff --git a/fpga/arty_a7.vhdl b/fpga/arty_a7.vhdl new file mode 100644 index 0000000..415fa7b --- /dev/null +++ b/fpga/arty_a7.vhdl @@ -0,0 +1,82 @@ +library ieee; +use ieee.std_logic_1164.all; + +entity arty_a7 is + generic ( + MEMORY_SIZE : positive := 524288; + RAM_INIT_FILE : string := "firmware.hex"; + RESET_LOW : boolean := true; + CLK_INPUT : positive := 100000000; + CLK_FREQUENCY : positive := 100000000 + ); + port( + ext_clk : in std_ulogic; + ext_rst : in std_ulogic; + + -- UART0 signals: + uart0_txd : out std_ulogic; + uart0_rxd : in std_ulogic; + + -- GPIO signals: + gpio0 : inout std_logic_vector(55 downto 0); + gpio1 : inout std_logic_vector(36 downto 0) + ); +end entity arty_a7; + +architecture behaviour of arty_a7 is + + -- Reset signals: + signal soc_rst : std_ulogic; + signal pll_rst : std_ulogic; + + -- Internal clock signals: + signal system_clk : std_ulogic; + signal system_clk_locked : std_ulogic; + +begin + + reset_controller: entity work.soc_reset + generic map( + RESET_LOW => RESET_LOW + ) + port map( + ext_clk => ext_clk, + pll_clk => system_clk, + pll_locked_in => system_clk_locked, + ext_rst_in => ext_rst, + pll_rst_out => pll_rst, + rst_out => soc_rst + ); + + clkgen: entity work.clock_generator + generic map( + CLK_INPUT_HZ => CLK_INPUT, + CLK_OUTPUT_HZ => CLK_FREQUENCY + ) + port map( + ext_clk => ext_clk, + pll_rst_in => pll_rst, + pll_clk_out => system_clk, + pll_locked_out => system_clk_locked + ); + + -- Main SoC + soc0: entity work.soc + generic map( + MEMORY_SIZE => MEMORY_SIZE, + RAM_INIT_FILE => RAM_INIT_FILE, + RESET_LOW => RESET_LOW, + SIM => false, + GPIO0_PINS => 56, + GPIO1_PINS => 37 + ) + port map ( + system_clk => system_clk, + rst => soc_rst, + uart0_txd => uart0_txd, + uart0_rxd => uart0_rxd, + gpio0 => gpio0, + gpio1 => gpio1 + ); + +end architecture behaviour; diff --git a/fpga/arty_a7.xdc b/fpga/arty_a7.xdc index 481d8e4..45fecde 100644 --- a/fpga/arty_a7.xdc +++ b/fpga/arty_a7.xdc @@ -6,5 +6,121 @@ set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { ext_rs set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { uart0_txd }]; set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart0_rxd }]; +# Buttons 0-3 +set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { gpio0[0] }]; # BTN0 +set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { gpio0[1] }]; # BTN1 +set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { gpio0[2] }]; # BTN2 +set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { gpio0[3] }]; # BTN3 + +# Slide switches 0-3 +set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { gpio0[4] }]; # SW0 +set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { gpio0[5] }]; # SW1 +set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { gpio0[6] }]; # SW2 +set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { gpio0[7] }]; # SW3 + +# RGB LEDs 0-3 +set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { gpio0[8] }]; # LD0 Red +set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { gpio0[9] }]; # LD0 Green +set_property -dict { PACKAGE_PIN U1 IOSTANDARD LVCMOS33 } [get_ports { gpio0[10] }]; # LD0 Blue + +set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { gpio0[11] }]; # LD1 Red +set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { gpio0[12] }]; # LD1 Green +set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { gpio0[13] }]; # LD1 Blue + +set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { gpio0[14] }]; # LD2 Red +set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { gpio0[15] }]; # LD2 Green +set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { gpio0[16] }]; # LD2 Blue + +set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { gpio0[17] }]; # LD3 Red +set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { gpio0[18] }]; # LD3 Green +set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { gpio0[19] }]; # LD3 Blue + +# LEDs 4-7 +set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { gpio0[20] }]; # LD4 +set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { gpio0[21] }]; # LD5 +set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { gpio0[22] }]; # LD6 +set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { gpio0[23] }]; # LD7 + +# PMOD JA +set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { gpio0[24] }]; # PMOD JA Pin 1 +set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { gpio0[25] }]; # PMOD JA Pin 2 +set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { gpio0[26] }]; # PMOD JA Pin 3 +set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { gpio0[27] }]; # PMOD JA Pin 4 +set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { gpio0[28] }]; # PMOD JA Pin 7 +set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { gpio0[29] }]; # PMOD JA Pin 8 +set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { gpio0[30] }]; # PMOD JA Pin 9 +set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { gpio0[31] }]; # PMOD JA Pin 10 + +# PMOD JB +set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { gpio0[32] }]; # PMOD JB Pin 1 +set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { gpio0[33] }]; # PMOD JB Pin 2 +set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { gpio0[34] }]; # PMOD JB Pin 3 +set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { gpio0[35] }]; # PMOD JB Pin 4 +set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { gpio0[36] }]; # PMOD JB Pin 7 +set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { gpio0[37] }]; # PMOD JB Pin 8 +set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { gpio0[38] }]; # PMOD JB Pin 9 +set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { gpio0[39] }]; # PMOD JB Pin 10 + +# PMOD JC +set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { gpio0[40] }]; # PMOD JC Pin 1 +set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { gpio0[41] }]; # PMOD JC Pin 2 +set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { gpio0[42] }]; # PMOD JC Pin 3 +set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { gpio0[43] }]; # PMOD JC Pin 4 +set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { gpio0[44] }]; # PMOD JC Pin 7 +set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { gpio0[45] }]; # PMOD JC Pin 8 +set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { gpio0[46] }]; # PMOD JC Pin 9 +set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { gpio0[47] }]; # PMOD JC Pin 10 + +# PMOD JD +set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { gpio0[48] }]; # PMOD JD Pin 1 +set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { gpio0[49] }]; # PMOD JD Pin 2 +set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { gpio0[50] }]; # PMOD JD Pin 3 +set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { gpio0[51] }]; # PMOD JD Pin 4 +set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { gpio0[52] }]; # PMOD JD Pin 7 +set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { gpio0[53] }]; # PMOD JD Pin 8 +set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { gpio0[54] }]; # PMOD JD Pin 9 +set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { gpio0[55] }]; # PMOD JD Pin 10 + +# Chipkit +set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { gpio1[0] }]; # Chipkit IO0 +set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { gpio1[1] }]; # Chipkit IO1 +set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { gpio1[2] }]; # Chipkit IO2 +set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { gpio1[3] }]; # Chipkit IO3 +set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { gpio1[4] }]; # Chipkit IO4 +set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { gpio1[5] }]; # Chipkit IO5 +set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { gpio1[6] }]; # Chipkit IO6 +set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { gpio1[7] }]; # Chipkit IO7 +set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { gpio1[8] }]; # Chipkit IO8 +set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { gpio1[9] }]; # Chipkit IO9 +set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { gpio1[10] }]; # Chipkit IO10 +set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { gpio1[11] }]; # Chipkit IO11 +set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { gpio1[12] }]; # Chipkit IO12 +set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { gpio1[13] }]; # Chipkit IO13 + +set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { gpio1[14] }]; # Chipkit IO26 +set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { gpio1[15] }]; # Chipkit IO27 +set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { gpio1[16] }]; # Chipkit IO28 +set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { gpio1[17] }]; # Chipkit IO29 +set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { gpio1[18] }]; # Chipkit IO30 +set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { gpio1[19] }]; # Chipkit IO31 +set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { gpio1[20] }]; # Chipkit IO32 +set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { gpio1[21] }]; # Chipkit IO33 +set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { gpio1[22] }]; # Chipkit IO34 +set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { gpio1[23] }]; # Chipkit IO35 +set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { gpio1[24] }]; # Chipkit IO36 +set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { gpio1[25] }]; # Chipkit IO37 +set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { gpio1[26] }]; # Chipkit IO38 +set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { gpio1[27] }]; # Chipkit IO39 +set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { gpio1[28] }]; # Chipkit IO40 +set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { gpio1[29] }]; # Chipkit IO41 +set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { gpio1[30] }]; # Chipkit IO42 + +set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { gpio1[31] }]; # Chipkit I2C SCL +set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { gpio1[32] }]; # Chipkit I2C SDA +set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { gpio1[33] }]; # Chipkit SPI SS +set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { gpio1[34] }]; # Chipkit SPI CLK +set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { gpio1[35] }]; # Chipkit SPI MOSI +set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { gpio1[36] }]; # Chipkit SPI MISO + set_property CONFIG_VOLTAGE 3.3 [current_design] set_property CFGBVS VCCO [current_design] diff --git a/fpga/pp_soc_gpio.vhdl b/fpga/pp_soc_gpio.vhdl new file mode 100644 index 0000000..0b09999 --- /dev/null +++ b/fpga/pp_soc_gpio.vhdl @@ -0,0 +1,200 @@ +-- 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; \ No newline at end of file diff --git a/fpga/toplevel.vhdl b/fpga/toplevel_nogpio.vhdl similarity index 89% rename from fpga/toplevel.vhdl rename to fpga/toplevel_nogpio.vhdl index d73c802..f62ccd7 100644 --- a/fpga/toplevel.vhdl +++ b/fpga/toplevel_nogpio.vhdl @@ -1,7 +1,7 @@ library ieee; use ieee.std_logic_1164.all; -entity toplevel is +entity toplevel_nogpio is generic ( MEMORY_SIZE : positive := 524288; RAM_INIT_FILE : string := "firmware.hex"; @@ -17,9 +17,9 @@ entity toplevel is uart0_txd : out std_ulogic; uart0_rxd : in std_ulogic ); -end entity toplevel; +end entity toplevel_nogpio; -architecture behaviour of toplevel is +architecture behaviour of toplevel_nogpio is -- Reset signals: signal soc_rst : std_ulogic; @@ -62,7 +62,9 @@ begin MEMORY_SIZE => MEMORY_SIZE, RAM_INIT_FILE => RAM_INIT_FILE, RESET_LOW => RESET_LOW, - SIM => false + SIM => false, + GPIO0_PINS => 0, + GPIO1_PINS => 0 ) port map ( system_clk => system_clk, diff --git a/microwatt.core b/microwatt.core index 5fb9a7a..10255e8 100644 --- a/microwatt.core +++ b/microwatt.core @@ -51,11 +51,25 @@ filesets: - fpga/mw_soc_memory.vhdl - fpga/soc_reset.vhdl - fpga/pp_soc_uart.vhd + - fpga/pp_soc_gpio.vhdl - fpga/pp_utilities.vhd - fpga/toplevel.vhdl - fpga/firmware.hex : {copyto : firmware.hex, file_type : user} file_type : vhdlSource-2008 + fpga: + files: + - fpga/pp_fifo.vhd + - fpga/mw_soc_memory.vhdl + - fpga/soc_reset.vhdl + - fpga/pp_soc_uart.vhd + - fpga/pp_soc_gpio.vhdl + - fpga/pp_utilities.vhd + - fpga/toplevel_nogpio.vhdl + - fpga/arty_a7.vhdl + - fpga/firmware.hex : {copyto : firmware.hex, file_type : user} + file_type : vhdlSource-2008 + debug_xilinx: files: - dmi_dtm_xilinx.vhdl : {file_type : vhdlSource-2008} @@ -95,7 +109,7 @@ targets: - clk_frequency tools: vivado: {part : xc7a100tcsg324-1} - toplevel : toplevel + toplevel : toplevel_nogpio nexys_video: default_tool: vivado @@ -107,7 +121,7 @@ targets: - clk_frequency tools: vivado: {part : xc7a200tsbg484-1} - toplevel : toplevel + toplevel : toplevel_nogpio arty_a7-35: default_tool: vivado @@ -119,7 +133,7 @@ targets: - clk_frequency tools: vivado: {part : xc7a35ticsg324-1L} - toplevel : toplevel + toplevel : arty_a7 arty_a7-100: default_tool: vivado @@ -131,7 +145,7 @@ targets: - clk_frequency tools: vivado: {part : xc7a100ticsg324-1L} - toplevel : toplevel + toplevel : arty_a7 cmod_a7-35: default_tool: vivado @@ -144,7 +158,7 @@ targets: - clk_frequency tools: vivado: {part : xc7a35tcpg236-1} - toplevel : toplevel + toplevel : toplevel_nogpio synth: filesets: [core, soc] diff --git a/sim_gpio.vhdl b/sim_gpio.vhdl new file mode 100644 index 0000000..429006c --- /dev/null +++ b/sim_gpio.vhdl @@ -0,0 +1,205 @@ +-- 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, three bits per pin (read/write), pins 0-20 | +--! | 0x30 | Type, three bits per pin (read/write), pins 21-41 | +--! | 0x38 | Type, three bits per pin (read/write), pins 42-63 | +--! | | Types: MSB LSB | +--! | | 0 0 0 Input, Interrupt disabled | +--! | | 0 1 0 Input, Interrupt when low | +--! | | 0 1 1 Input, Interrupt when high | +--! | | 1 0 0 Input, Interrupt when falling | +--! | | 1 0 1 Input, Interrupt when rising | +--! | | 1 1 1 Output | +--! | | others Undefined | +--! | 0x40 | 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(2 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 0 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"111" 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"111"; + + case type_register(i) is + when b"010" => + if gpio(i) = '0' then + irq_triggered_register(i) <= '1'; + irq <= '1'; + end if; + when b"011" => + if gpio(i) = '1' then + irq_triggered_register(i) <= '1'; + irq <= '1'; + end if; + when b"100" => + if input_register(i) = '0' and input_register_prev(i) = '1' then + irq_triggered_register(i) <= '1'; + irq <= '1'; + end if; + when b"101" => + 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); + report "GPIO output " & to_hstring(output_register); + when x"10" => --! Output Value + output_register <= wb_dat_in(NUM_GPIOS - 1 downto 0); + report "GPIO output " & to_hstring(output_register); + when x"18" => --! Set + output_register <= output_register OR wb_dat_in(NUM_GPIOS - 1 downto 0); + report "GPIO output " & to_hstring(output_register); + when x"20" => --! Clear + output_register <= output_register AND NOT(wb_dat_in(NUM_GPIOS - 1 downto 0)); + report "GPIO output " & to_hstring(output_register); + when x"28" => --! Type Pins 0-20 + for i in 0 to MINIMUM(NUM_GPIOS - 1, 20) loop + type_register(i) <= (wb_dat_in((i + 1) * 3 - 1 downto i * 3)); + report "GPIO type for pin " & integer'image(i) & " is " & to_hstring((wb_dat_in((i + 1) * 3 - 1 downto i * 3))); + end loop; + when x"30" => --! Type Pins 21-41 + for i in 21 to MINIMUM(NUM_GPIOS - 1, 41) loop + type_register(i) <= (wb_dat_in((i - 21 + 1) * 3 - 1 downto (i - 21) * 3)); + report "GPIO type for pin " & integer'image(i) & " is " & to_hstring((wb_dat_in((i - 21 + 1) * 3 - 1 downto (i- 21) * 3))); + end loop; + when x"38" => --! Type Pins 42-63 + for i in 42 to MINIMUM(NUM_GPIOS - 1, 63) loop + type_register(i) <= (wb_dat_in((i - 42 + 1) * 3 - 1 downto (i - 42) * 3)); + report "GPIO type for pin " & integer'image(i) & " is " & to_hstring((wb_dat_in((i - 42 + 1) * 3 - 1 downto (i- 21) * 3))); + 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)); + report "Read GPIO Description register as " & to_hstring(wb_dat_out); + when x"08" => --! Input Value + wb_dat_out <= std_logic_vector(resize(unsigned(input_register), wb_dat_out'length)); + report "Read GPIO Input value as " & to_hstring(wb_dat_out); + when x"10" => --! Output value + wb_dat_out <= std_logic_vector(resize(unsigned(output_register), wb_dat_out'length)); + report "Read GPIO Output register as " & to_hstring(wb_dat_out); + when x"28" => --! Type Pins 0-20 + for i in 0 to MINIMUM(NUM_GPIOS - 1, 20) loop + wb_dat_out((i + 1) * 3 - 1 downto i * 3) <= type_register(i); + end loop; + report "Read GPIO Type register 0 as " & to_hstring(wb_dat_out); + when x"30" => --! Type Pins 21-41 + for i in 21 to MINIMUM(NUM_GPIOS - 1, 41) loop + wb_dat_out((i - 21 + 1) * 3 - 1 downto (i - 21) * 3) <= type_register(i); + end loop; + report "Read GPIO Type register 1 as " & to_hstring(wb_dat_out); + when x"38" => --! Type Pins 42-63 + for i in 21 to MINIMUM(NUM_GPIOS - 1, 41) loop + wb_dat_out((i - 21 + 1) * 3 - 1 downto (i - 21) * 3) <= type_register(i); + end loop; + report "Read GPIO Type register 2 as " & to_hstring(wb_dat_out); + when x"40" => --! Interrupts triggered + wb_dat_out <= std_logic_vector(resize(unsigned(irq_triggered_register), wb_dat_out'length)); + irq_triggered_register <= (others => '0'); + irq <= '0'; + report "Read IRQ Triggered register as " & to_hstring(wb_dat_out); + 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; \ No newline at end of file diff --git a/soc.vhdl b/soc.vhdl index 458a751..94aad18 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -17,7 +17,9 @@ entity soc is MEMORY_SIZE : positive; RAM_INIT_FILE : string; RESET_LOW : boolean; - SIM : boolean + SIM : boolean; + GPIO0_PINS : natural; + GPIO1_PINS : natural ); port( rst : in std_ulogic; @@ -28,6 +30,8 @@ entity soc is uart0_rxd : in std_ulogic; -- Misc (to use for things like LEDs) + gpio0 : inout std_logic_vector(GPIO0_PINS - 1 downto 0); + gpio1 : inout std_logic_vector(GPIO1_PINS - 1 downto 0); core_terminated : out std_ulogic ); end entity soc; @@ -51,6 +55,14 @@ architecture behaviour of soc is signal wb_uart0_out : wishbone_slave_out; signal uart_dat8 : std_ulogic_vector(7 downto 0); + -- GPIO0 signals: + signal wb_gpio0_in : wishbone_master_out; + signal wb_gpio0_out : wishbone_slave_out; + + -- GPIO1 signals: + signal wb_gpio1_in : wishbone_master_out; + signal wb_gpio1_out : wishbone_slave_out; + -- Main memory signals: signal wb_bram_in : wishbone_master_out; signal wb_bram_out : wishbone_slave_out; @@ -104,28 +116,46 @@ begin ); -- Wishbone slaves address decoder & mux - slave_intercon: process(wb_master_out, wb_bram_out, wb_uart0_out) + slave_intercon: process(wb_master_out, wb_bram_out, wb_uart0_out, wb_gpio0_out, wb_gpio1_out) -- Selected slave type slave_type is (SLAVE_UART_0, + SLAVE_GPIO_0, + SLAVE_GPIO_1, SLAVE_MEMORY, SLAVE_NONE); variable slave : slave_type; begin - -- Simple address decoder. - slave := SLAVE_NONE; - if wb_master_out.adr(31 downto 24) = x"00" then + -- Simple address decoder + case wb_master_out.adr(31 downto 24) is + when x"00" => slave := SLAVE_MEMORY; - elsif wb_master_out.adr(31 downto 24) = x"c0" then - if wb_master_out.adr(23 downto 12) = x"002" then + when x"c0" => + case wb_master_out.adr(23 downto 8) is + when x"0020" => slave := SLAVE_UART_0; - end if; - end if; + when others => + slave := SLAVE_NONE; + end case; + when x"c1" => + case wb_master_out.adr(23 downto 8) is + when x"0000" => + slave := SLAVE_GPIO_0; + when x"0001" => + slave := SLAVE_GPIO_1; + when others => + slave := SLAVE_NONE; + end case; + when others => + slave := SLAVE_NONE; + end case; -- Wishbone muxing. Defaults: wb_bram_in <= wb_master_out; wb_bram_in.cyc <= '0'; wb_uart0_in <= wb_master_out; wb_uart0_in.cyc <= '0'; + wb_gpio0_in <= wb_master_out; + wb_gpio0_in.cyc <= '0'; case slave is when SLAVE_MEMORY => wb_bram_in.cyc <= wb_master_out.cyc; @@ -133,6 +163,12 @@ begin when SLAVE_UART_0 => wb_uart0_in.cyc <= wb_master_out.cyc; wb_master_in <= wb_uart0_out; + when SLAVE_GPIO_0 => + wb_gpio0_in.cyc <= wb_master_out.cyc; + wb_master_in <= wb_gpio0_out; + when SLAVE_GPIO_1 => + wb_gpio1_in.cyc <= wb_master_out.cyc; + wb_master_in <= wb_gpio1_out; when others => wb_master_in.dat <= (others => '1'); wb_master_in.ack <= wb_master_out.stb and wb_master_out.cyc; @@ -165,6 +201,41 @@ begin ); wb_uart0_out.dat <= x"00000000000000" & uart_dat8; + -- GPIO + gpio_0: entity work.pp_soc_gpio + generic map( + NUM_GPIOS => GPIO0_PINS + ) + port map( + clk => system_clk, + reset => rst, + gpio => gpio0, + wb_adr_in => wb_gpio0_in.adr(7 downto 0), + wb_dat_in => wb_gpio0_in.dat(63 downto 0), + wb_dat_out => wb_gpio0_out.dat, + wb_cyc_in => wb_gpio0_in.cyc, + wb_stb_in => wb_gpio0_in.stb, + wb_we_in => wb_gpio0_in.we, + wb_ack_out => wb_gpio0_out.ack + ); + + gpio_1: entity work.pp_soc_gpio + generic map( + NUM_GPIOS => GPIO1_PINS + ) + port map( + clk => system_clk, + reset => rst, + gpio => gpio1, + wb_adr_in => wb_gpio1_in.adr(7 downto 0), + wb_dat_in => wb_gpio1_in.dat(63 downto 0), + wb_dat_out => wb_gpio1_out.dat, + wb_cyc_in => wb_gpio1_in.cyc, + wb_stb_in => wb_gpio1_in.stb, + wb_we_in => wb_gpio1_in.we, + wb_ack_out => wb_gpio1_out.ack + ); + -- BRAM Memory slave bram0: entity work.mw_soc_memory generic map(