------------------------------------------------------------------------------- -- Title : Ethernet controlled WS2812b -- Project : ------------------------------------------------------------------------------- -- File : top.vhd -- Author : Mario Hüttel -- Company : -- Created : 2018-04-05 -- Last update: 2018-04-13 -- Platform : -- Standard : VHDL'93/02 ------------------------------------------------------------------------------- -- Description: ------------------------------------------------------------------------------- -- Copyright (c) 2018 ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity top is port ( clk : in std_logic; rst_hw : in std_logic; mdio : inout std_logic; mdc : out std_logic; rx : in std_logic_vector(1 downto 0); dv : in std_logic; led1 : out std_logic; led2 : out std_logic; dat_cnt : out std_logic_vector(3 downto 0); ws_out : out std_logic); end entity top; architecture RTL of top is constant DELAYCNTVAL : integer := 100000; -- set to low value for -- simulation constant STARTUPDELAY : integer := 50000000; constant DEFMAC : std_logic_vector(47 downto 0) := x"00DEADBEEF00"; constant PIPE_PKG : std_logic_vector(15 downto 0) := x"AA00"; constant FIN_PKG : std_logic_vector(15 downto 0) := x"55AA"; type smi_state_t is (IDLE, STROBE); type smi_init_state_t is (SMI_POR, SMI_PORDELAY, RESET, INIT, DELAY, INIT_COMPLETE); type ws_send_t is (WS_READY, WS_SYNC, WS_RED, WS_GREEN, WS_BLUE, WS_PIPE, WS_POST); type receive_t is (PRE, DESTMAC, SRCMAC, TYPEFIELD, RECV, WAITFORACK); signal rst : std_logic; signal dat_cnt_s : unsigned(3 downto 0); signal sendstate : smi_state_t; signal initstate : smi_init_state_t := SMI_POR; signal rst_rxtx : std_logic; signal delaycounter : unsigned(26 downto 0); signal smi_reg : std_logic_vector(4 downto 0); signal smi_dat : std_logic_vector(15 downto 0); signal smi_strb : std_logic; signal smi_busy : std_logic; --- signal sof : std_logic; signal eof : std_logic; signal eth_dat : std_logic_vector(7 downto 0); signal eth_strb : std_logic; signal crc_valid : std_logic; -- signal fifo_in : std_logic_vector(7 downto 0); signal fifo_out : std_logic_vector(7 downto 0); signal fifo_wr : std_logic; signal fifo_rd : std_logic; signal fifo_rst : std_logic; signal fifo_full : std_logic; signal fifo_empty : std_logic; -- signal fifo_data_avail : std_logic; signal fifo_data_ack : std_logic; signal recv_state : receive_t; signal mac : std_logic_vector(47 downto 0); signal recv_cnt : integer range 0 to 15; signal pkg_type : std_logic_vector(15 downto 0); -- signal ws_busy : std_logic; signal ws_strb : std_logic; signal red : unsigned(7 downto 0); signal green : unsigned(7 downto 0); signal blue : unsigned(7 downto 0); -- signal ws_state : ws_send_t; begin -- architecture RTL reset_sync : process(clk, rst_hw) is begin if rst_hw = '0' then rst <= '1'; elsif rising_edge(clk) then if rst_hw = '1' then rst <= '0'; end if; end if; end process reset_sync; smi_1 : entity work.smi generic map ( clockdiv => 64) port map ( clk_i => clk, rst_i => rst, mdio_io => mdio, mdc_o => mdc, busy_o => smi_busy, data_o => open, phyaddr_i => "00001", regaddr_i => smi_reg, data_i => smi_dat, strb_i => smi_strb, rw_i => '0'); ethmac_rx_1 : entity work.ethmac_rx port map ( clk_50 => clk, rst => rst_rxtx, rmii_rx => rx, rmii_dv => dv, start_of_frame => sof, end_of_frame => eof, data_out => eth_dat, data_strb => eth_strb, crc_check_valid => crc_valid); -- fifo_dc_1 : entity work.fifo_dc -- port map ( -- Data => fifo_in, -- WrClock => clk, -- RdClock => clk, -- WrEn => fifo_wr, -- RdEn => fifo_rd, -- Reset => fifo_rst, -- RPReset => fifo_rst, -- Q => fifo_out, -- Empty => fifo_empty, -- Full => fifo_full, -- AlmostEmpty => open, -- AlmostFull => open); STD_FIFO_1 : entity work.STD_FIFO generic map ( DATA_WIDTH => 8, FIFO_DEPTH => 360*3) port map ( CLK => clk, RST => fifo_rst, WriteEn => fifo_wr, DataIn => fifo_in, ReadEn => fifo_rd, DataOut => fifo_out, Empty => fifo_empty, Full => fifo_full); wsphy1 : entity work.ws2812bphy generic map ( HIGH1 => 40, LOW1 => 23, HIGH0 => 20, LOW0 => 43) port map ( clk => clk, rst => rst, busy => ws_busy, ws_out => ws_out, strb => ws_strb, red => red, green => green, blue => blue); initphy : process(clk, rst) is procedure sendsmi(regaddr : in std_logic_vector(4 downto 0); data : in std_logic_vector(15 downto 0); nextstate : in smi_init_state_t) is begin case sendstate is when IDLE => smi_reg <= regaddr; smi_dat <= data; if smi_busy = '0' then smi_strb <= '1'; sendstate <= STROBE; end if; when STROBE => initstate <= nextstate; sendstate <= IDLE; end case; end procedure sendsmi; begin if rst = '1' then smi_reg <= (others => '0'); smi_dat <= (others => '0'); smi_strb <= '0'; rst_rxtx <= '1'; initstate <= SMI_POR; sendstate <= IDLE; delaycounter <= (others => '0'); elsif rising_edge(clk) then smi_strb <= '0'; rst_rxtx <= '1'; case initstate is when SMI_POR => delaycounter <= (others => '0'); initstate <= SMI_PORDELAY; when SMI_PORDELAY => delaycounter <= delaycounter + 1; if delaycounter = STARTUPDELAY then initstate <= RESET; end if; when RESET => delaycounter <= (others => '0'); sendsmi((others => '0'), x"8000", DELAY); when DELAY => delaycounter <= delaycounter + 1; if delaycounter = DELAYCNTVAL then -- Set to 100000 initstate <= INIT; end if; when INIT => sendsmi((others => '0'), "00" & '1' & '1' & "000" & '1' & "00000000", INIT_COMPLETE); when INIT_COMPLETE => initstate <= INIT_COMPLETE; if smi_busy = '0' then rst_rxtx <= '0'; end if; end case; end if; end process initphy; receive_fifo : process (clk, rst) is begin -- process receive_fifo if rst = '1' then -- asynchronous reset (active high) fifo_rst <= '1'; fifo_wr <= '0'; fifo_in <= (others => '0'); fifo_data_avail <= '0'; recv_state <= PRE; dat_cnt_s <= (others => '0'); led1 <= '1'; led2 <= '1'; recv_cnt <= 0; pkg_type <= (others => '0'); mac <= (others => '0'); elsif rising_edge(clk) then -- rising clock edge fifo_rst <= '0'; fifo_wr <= '0'; case recv_state is when PRE => if sof = '1' then recv_cnt <= 0; pkg_type <= (others => '0'); mac <= (others => '0'); recv_state <= DESTMAC; led1 <= '1'; led2 <= '1'; end if; when DESTMAC => if eof = '1' then recv_state <= PRE; elsif eth_strb = '1' then recv_cnt <= recv_cnt + 1; mac <= mac(39 downto 0) & eth_dat; if recv_cnt = 5 and (mac(39 downto 0) & eth_dat) = DEFMAC then recv_cnt <= 0; recv_state <= SRCMAC; end if; end if; when SRCMAC => if eof = '1' then recv_state <= PRE; elsif eth_strb = '1' then recv_cnt <= recv_cnt + 1; if recv_cnt 5 then -- SRC_MAC received recv_state <= TYPEFIELD recv_cnt <= 0; end if; end if; when TYPEFIELD => if eof = '1' then recv_state <= PRE; elsif eth_strb = '1' then recv_cnt <= recv_cnt + 1; pkg_type <= pkg_type(7 downto 0) & eth_dat; if recv_cnt = 1 then -- Type received recv_cnt <= 0; recv_state <= RECV; end if; end if; when RECV => led2 <= '0'; if eth_strb = '1' and fifo_full /= '1' then fifo_in <= eth_dat; fifo_wr <= '1'; dat_cnt_s <= dat_cnt_s +1; end if; if eof = '1' then if crc_valid = '1' then if pkg_type = PIPE_PKG then -- Wait for further frames -- This is also called with any -- undefined TYPEFIELD recv_state <= PRE; elsif pkg_type = FIN_PKG then fifo_data_avail <= '1'; recv_state <= WAITFORACK; else recv_state <= PRE; end if; else -- Eth Frame invalid. Discard fifo_rst <= '1'; recv_state <= PRE; end if; end if; when WAITFORACK => fifo_data_avail <= '1'; if fifo_data_ack = '1' then recv_state <= PRE; fifo_data_avail <= '0'; -- fifo_rst <= '1'; end if; when others => null; end case; end if; end process receive_fifo; ws_write : process (clk, rst) is -- variable ws_send_cnt : integer range 0 to 7 := 0; begin -- process ws_write if rst = '1' then -- asynchronous reset (active high) red <= (others => '0'); green <= (others => '0'); blue <= (others => '0'); ws_strb <= '0'; fifo_rd <= '0'; fifo_data_ack <= '0'; ws_state <= WS_READY; elsif rising_edge(clk) then -- rising clock edge ws_strb <= '0'; fifo_rd <= '0'; fifo_data_ack <= '0'; case ws_state is when WS_READY => if fifo_data_avail = '1' then if fifo_empty = '0' then ws_state <= WS_SYNC; fifo_rd <= '1'; -- read red else ws_state <= WS_POST; end if; end if; when WS_SYNC => if fifo_empty = '1' then ws_state <= WS_POST; else fifo_rd <= '1'; --read green ws_state <= WS_RED; end if; when WS_RED => if fifo_empty = '1' then ws_state <= WS_POST; else fifo_rd <= '1'; --read blue red <= unsigned(fifo_out); ws_state <= WS_GREEN; end if; when WS_GREEN => if fifo_empty = '1' then ws_state <= WS_POST; else green <= unsigned(fifo_out); ws_state <= WS_BLUE; end if; when WS_BLUE => blue <= unsigned(fifo_out); ws_state <= WS_PIPE; when WS_PIPE => if ws_busy = '0' and ws_strb = '0' then ws_strb <= '1'; if fifo_empty = '0' then ws_state <= WS_SYNC; fifo_rd <= '1'; -- read else ws_state <= WS_POST; end if; end if; when WS_POST => if ws_busy = '0' and fifo_data_ack = '0' then fifo_data_ack <= '1'; elsif fifo_data_ack = '1' and fifo_data_avail = '1' then ws_state <= WS_READY; end if; end case; end if; end process ws_write; dat_cnt <= std_logic_vector(dat_cnt_s); end architecture RTL;