397 lines
9.9 KiB
VHDL
397 lines
9.9 KiB
VHDL
-------------------------------------------------------------------------------
|
|
-- Title : Ethernet controlled WS2812b
|
|
-- Project :
|
|
-------------------------------------------------------------------------------
|
|
-- File : top.vhd
|
|
-- Author : Mario Hüttel <mario.huettel@gmx.net>
|
|
-- 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";
|
|
|
|
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, HEADER, 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 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;
|
|
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;
|
|
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 then
|
|
recv_cnt <= 0;
|
|
recv_state <= HEADER;
|
|
end if;
|
|
end if;
|
|
|
|
when HEADER =>
|
|
led1 <= '0';
|
|
if eof = '1' then
|
|
recv_state <= PRE;
|
|
elsif eth_strb = '1' then
|
|
recv_cnt <= recv_cnt + 1;
|
|
if recv_cnt = 7 then
|
|
if mac = DEFMAC then
|
|
recv_state <= RECV;
|
|
dat_cnt_s <= (others => '0');
|
|
else
|
|
recv_state <= PRE;
|
|
|
|
end if;
|
|
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 -- or crc_valid = '0' then
|
|
recv_state <= WAITFORACK;
|
|
fifo_data_avail <= '1';
|
|
--led2 <= '0';
|
|
else
|
|
--led2 <= '1';
|
|
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;
|