library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity splink is generic ( NUM_STRANDS : positive; MAX_STRAND_LEN : positive := 256 ); port ( clk : in std_logic; reset : in std_logic; udp_valid : in std_logic; udp_last : in std_logic; udp_data : in std_logic_vector(31 downto 0); frame_done : out std_logic; drivers : out std_logic_vector(NUM_STRANDS-1 downto 0) ); end entity; architecture a of splink is constant BITS_PER_LED: natural := 24; subtype color_t is std_logic_vector(BITS_PER_LED-1 downto 0); type led_data_t is record addr : std_logic_vector(7 downto 0); current_color : color_t; was_written : std_logic; end record; type led_data_arr_t is array(0 to NUM_STRANDS-1) of led_data_t; signal led_data_arr : led_data_arr_t; begin driver_gen: for i in 0 to NUM_STRANDS-1 generate ws2812_inst: entity work.ws2812 generic map ( NUM_LEDS => MAX_STRAND_LEN, COLOR_ORDER => "GRB", T_CLK => 12.5 ns, T0H => 0.35 us, T0L => 0.8 us, T1H => 0.7 us, T1L => 0.6 us, T_RES => 80 us ) port map ( n_reset => not reset, clk => clk, led_addr => led_data_arr(i).addr, led_red => led_data_arr(i).current_color(23 downto 16), led_green => led_data_arr(i).current_color(15 downto 8), led_blue => led_data_arr(i).current_color(7 downto 0), dout => drivers(i) ); end generate; writer: process(clk) type strand_store_t is array(0 to MAX_STRAND_LEN-1) of color_t; type strand_stores_t is array(0 to NUM_STRANDS-1) of strand_store_t; variable strand_stores: strand_stores_t; variable active_strand: natural range 0 to NUM_STRANDS-1; variable packet_len: natural range 1 to MAX_STRAND_LEN; variable frame_number: unsigned(31 downto 0); variable store_counter: natural range 0 to MAX_STRAND_LEN-1; type receive_state_t is (FRAME_NUM, STRAND_NUM, DATA, DROP); variable receive_state : receive_state_t; begin if rising_edge(clk) then frame_done <= '0'; for i in 0 to NUM_STRANDS-1 loop led_data_arr(i).current_color <= strand_stores(i)(to_integer(unsigned(led_data_arr(i).addr))); end loop; if udp_valid then case receive_state is when STRAND_NUM => -- TODO udp_length, range check with MAX_STRAND_LEN packet_len := MAX_STRAND_LEN; -- FIXME bounds check active_strand := to_integer(unsigned(udp_data)); receive_state := FRAME_NUM; when FRAME_NUM => frame_number := unsigned(udp_data); store_counter := 0; receive_state := DATA; when DATA => strand_stores(active_strand)(store_counter) := udp_data(23 downto 0); if store_counter = packet_len then if udp_last then --led_data_arr(active_strand).was_written <= '1'; else -- packet too long receive_state := DROP; end if; else store_counter := store_counter + 1; end if; when DROP => -- wait until udp_last end case; if udp_last then receive_state := STRAND_NUM; end if; end if; end if; end process; end architecture;