-- splink, ethernet-connected LED controller -- Copyright (C) 2022 xiretza -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU Affero General Public License for more details. -- -- You should have received a copy of the GNU Affero General Public License -- along with this program. If not, see . library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; use work.util.flip_endianness; entity arty_a7 is generic ( IS_SIMULATION : std_logic := '0' ); port ( n_reset : in std_logic; buttons : in std_logic_vector(3 downto 0); switches : in std_logic_vector(3 downto 0); leds_simple : out std_logic_vector(3 downto 0); led0, led1, led2, led3 : out std_logic_vector(2 downto 0); -- Pmod connectors - A+D standard, B+C high-speed. -- Defined as inputs by default for safety, change -- when necessary pmod_a : out std_logic_vector(7 downto 0); pmod_b : out std_logic_vector(7 downto 0); pmod_c : out std_logic_vector(7 downto 0); pmod_d : out std_logic_vector(7 downto 0); clock_100mhz : in std_logic; uart_rx : in std_logic; uart_tx : out std_logic; mii_clk_25mhz : out std_logic; mii_n_reset : out std_logic; mii_mdio : inout std_logic; mii_mdc : out std_logic; mii_rx_clk : in std_logic; mii_rx_er : in std_logic; mii_rx_dv : in std_logic; mii_rx_data : in std_logic_vector(3 downto 0); mii_tx_clk : in std_logic; mii_tx_en : out std_logic; mii_tx_data : out std_logic_vector(3 downto 0); mii_col : in std_logic; mii_crs : in std_logic; ck_dig_l : inout std_logic_vector(13 downto 0); ck_dig_h : inout std_logic_vector(41 downto 26) ); end arty_a7; architecture a of arty_a7 is constant NUM_STRANDS: positive := 24; signal drivers: std_logic_vector(NUM_STRANDS-1 downto 0); component liteeth_core is port ( sys_clock : in std_logic; sys_reset : in std_logic; mii_eth_clocks_tx : in std_logic; mii_eth_clocks_rx : in std_logic; mii_eth_rst_n : out std_logic; mii_eth_mdio : inout std_logic; mii_eth_mdc : out std_logic; mii_eth_rx_dv : in std_logic; mii_eth_rx_er : in std_logic; mii_eth_rx_data : in std_logic_vector(3 downto 0); mii_eth_tx_en : out std_logic; mii_eth_tx_data : out std_logic_vector(3 downto 0); mii_eth_col : in std_logic; mii_eth_crs : in std_logic; ip_address : in std_logic_vector(31 downto 0); --== WISHBONE PORT ==-- wishbone_adr : in std_logic_vector(29 downto 0); wishbone_dat_w : in std_logic_vector(31 downto 0); wishbone_dat_r : out std_logic_vector(31 downto 0); wishbone_sel : in std_logic_vector(3 downto 0); wishbone_cyc : in std_logic; wishbone_stb : in std_logic; wishbone_ack : out std_logic; wishbone_we : in std_logic; wishbone_cti : in std_logic_vector(2 downto 0); wishbone_bte : in std_logic_vector(1 downto 0); wishbone_err : out std_logic; interrupt : out std_logic; --== PIXEL DATA PORT ==-- pixel_bind_port : in std_logic_vector(15 downto 0); -- sink pixel_sink_dst_ip_address : in std_logic_vector(31 downto 0); pixel_sink_dst_port : in std_logic_vector(15 downto 0); pixel_sink_length : in std_logic_vector(15 downto 0); pixel_sink_valid : in std_logic; pixel_sink_last : in std_logic; pixel_sink_last_be : in std_logic_vector(3 downto 0); pixel_sink_ready : out std_logic; pixel_sink_data : in std_logic_vector(31 downto 0); -- source pixel_source_src_ip_address : out std_logic_vector(31 downto 0); pixel_source_src_port : out std_logic_vector(15 downto 0); pixel_source_length : out std_logic_vector(15 downto 0); pixel_source_valid : out std_logic; pixel_source_last : out std_logic; pixel_source_last_be : out std_logic_vector(3 downto 0); pixel_source_ready : in std_logic; pixel_source_data : out std_logic_vector(31 downto 0) ); end component; signal pixel_sink_length : std_logic_vector(15 downto 0); signal pixel_sink_valid : std_logic; signal pixel_sink_last : std_logic; signal pixel_sink_last_be : std_logic_vector(3 downto 0); signal pixel_sink_ready : std_logic; signal pixel_sink_data : std_logic_vector(31 downto 0); signal pixel_source_src_ip_address : std_logic_vector(31 downto 0); signal pixel_source_src_port : std_logic_vector(15 downto 0); signal pixel_source_length : std_logic_vector(15 downto 0); signal pixel_source_valid : std_logic; signal pixel_source_last : std_logic; signal pixel_source_data : std_logic_vector(31 downto 0); signal remote_ip_address : std_logic_vector(31 downto 0); signal remote_port : std_logic_vector(15 downto 0); component PLLE2_BASE generic ( CLKFBOUT_MULT : integer; DIVCLK_DIVIDE : integer; CLKIN1_PERIOD : real; CLKOUT0_DIVIDE : integer := 0; CLKOUT0_DUTY_CYCLE : real := 0.5; CLKOUT0_PHASE : real := 0.0; CLKOUT1_DIVIDE : integer := 0; CLKOUT1_DUTY_CYCLE : real := 0.5; CLKOUT1_PHASE : real := 0.0; CLKOUT2_DIVIDE : integer := 0; CLKOUT2_DUTY_CYCLE : real := 0.5; CLKOUT2_PHASE : real := 0.0; CLKOUT3_DIVIDE : integer := 0; CLKOUT3_DUTY_CYCLE : real := 0.5; CLKOUT3_PHASE : real := 0.0; CLKOUT4_DIVIDE : integer := 0; CLKOUT4_DUTY_CYCLE : real := 0.5; CLKOUT4_PHASE : real := 0.0; CLKOUT5_DIVIDE : integer := 0; CLKOUT5_DUTY_CYCLE : real := 0.5; CLKOUT5_PHASE : real := 0.0 ); port ( RST : in std_logic; PWRDWN : in std_logic; LOCKED : out std_logic; CLKIN1 : in std_logic; CLKFBIN : in std_logic; CLKFBOUT : out std_logic; CLKOUT0 : out std_logic; CLKOUT1 : out std_logic; CLKOUT2 : out std_logic; CLKOUT3 : out std_logic; CLKOUT4 : out std_logic; CLKOUT5 : out std_logic ); end component PLLE2_BASE; signal pll_feedback : std_logic; signal pll_locked : std_logic; signal unbuf_sys_clk : std_logic; signal sys_clk : std_logic; component BUFG port ( I : in std_logic; O : out std_logic ); end component BUFG; signal sys_reset : std_logic; signal frame_number : unsigned(31 downto 0); signal prev_frame_number : unsigned(31 downto 0); -- little-endian pixel sink data signal pixel_sink_data_le : std_logic_vector(31 downto 0); -- big-endian pixel source data signal pixel_source_data_be : std_logic_vector(31 downto 0); begin leds_simple <= (others => '0'); led0 <= (others => '0'); led1 <= (others => '0'); led2 <= (others => '0'); led3 <= (others => '0'); uart_tx <= '0'; ck_dig_l <= (others => 'Z'); ck_dig_h <= (others => 'Z'); liteeth_inst: liteeth_core port map ( sys_clock => sys_clk, sys_reset => sys_reset, mii_eth_clocks_tx => mii_tx_clk, mii_eth_clocks_rx => mii_rx_clk, mii_eth_rst_n => mii_n_reset, mii_eth_mdio => mii_mdio, mii_eth_mdc => mii_mdc, mii_eth_rx_dv => mii_rx_dv, mii_eth_rx_er => mii_rx_er, mii_eth_rx_data => mii_rx_data, mii_eth_tx_en => mii_tx_en, mii_eth_tx_data => mii_tx_data, mii_eth_col => mii_col, mii_eth_crs => mii_crs, ip_address => x"0a141e28", -- 10.20.30.40 --== WISHBONE PORT ==-- wishbone_adr => (others => '1'), wishbone_dat_w => (others => '1'), wishbone_sel => (others => '1'), wishbone_cyc => '1', wishbone_stb => '1', wishbone_we => '1', wishbone_cti => (others => '1'), wishbone_bte => (others => '1'), --== PIXEL DATA PORT ==-- pixel_bind_port => x"effd", -- port 61437 - "PIXEL" -- sink pixel_sink_dst_ip_address => remote_ip_address, pixel_sink_dst_port => remote_port, pixel_sink_length => pixel_sink_length, pixel_sink_valid => pixel_sink_valid, pixel_sink_last => pixel_sink_last, pixel_sink_last_be => pixel_sink_last_be, pixel_sink_ready => pixel_sink_ready, pixel_sink_data => pixel_sink_data_le, -- source pixel_source_src_ip_address => pixel_source_src_ip_address, pixel_source_src_port => pixel_source_src_port, pixel_source_length => pixel_source_length, pixel_source_valid => pixel_source_valid, pixel_source_last => pixel_source_last, pixel_source_last_be => open, pixel_source_ready => '1', pixel_source_data => pixel_source_data ); pixel_sink_data_le <= flip_endianness(pixel_sink_data); -- 800 MHz VCO -- 80 MHz system clock -- 25 MHz MII clock pll_inst: PLLE2_BASE generic map ( CLKFBOUT_MULT => 8, DIVCLK_DIVIDE => 1, CLKIN1_PERIOD => 10.0, CLKOUT0_DIVIDE => 10, CLKOUT1_DIVIDE => 32, CLKOUT2_DIVIDE => 10, CLKOUT3_DIVIDE => 10, CLKOUT4_DIVIDE => 10, CLKOUT5_DIVIDE => 10 ) port map ( RST => '0', PWRDWN => '0', LOCKED => pll_locked, CLKIN1 => clock_100mhz, CLKFBIN => pll_feedback, CLKFBOUT => pll_feedback, CLKOUT0 => unbuf_sys_clk, CLKOUT1 => mii_clk_25mhz ); bufg_sys_clk: BUFG port map ( I => unbuf_sys_clk, O => sys_clk ); sys_reset <= not pll_locked or not n_reset; pmod_a <= "00" & drivers(5 downto 0); pmod_b <= "00" & drivers(11 downto 6); pmod_c(7) <= '0'; pmod_c(6) <= '0'; pmod_c(5) <= drivers(17); pmod_c(4) <= drivers(16); pmod_c(3) <= drivers(15); pmod_c(2) <= drivers(14); -- workaround for https://github.com/gatecat/nextpnr-xilinx/issues/42#issuecomment-1183525828 pmod_c(1) <= drivers(12); pmod_c(0) <= drivers(13); pmod_d <= "00" & drivers(23 downto 18); sender: process(sys_clk) begin if rising_edge(sys_clk) then if sys_reset then prev_frame_number <= frame_number; else if pixel_source_valid then remote_ip_address <= pixel_source_src_ip_address; remote_port <= pixel_source_src_port; end if; if frame_number /= prev_frame_number then prev_frame_number <= frame_number; pixel_sink_length <= x"0004"; pixel_sink_data <= std_logic_vector(frame_number); pixel_sink_valid <= '1'; pixel_sink_last <= '1'; end if; if pixel_sink_ready and pixel_sink_valid then pixel_sink_valid <= '0'; end if; end if; end if; end process; pixel_sink_last_be <= (pixel_sink_last, others => '0'); splink: entity work.splink generic map ( NUM_STRANDS => NUM_STRANDS ) port map ( clk => sys_clk, reset => sys_reset, udp_length => pixel_source_length, udp_valid => pixel_source_valid, udp_last => pixel_source_last, udp_data => pixel_source_data_be, frame_number => frame_number, drivers => drivers ); pixel_source_data_be <= flip_endianness(pixel_source_data); end architecture;