commit 4f4c36ffe85476ef9c3c5653c48983ebe48486c0 Author: Mario Hüttel Date: Fri Apr 6 17:37:39 2018 +0200 init. Works on altera diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3c51f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*~ +*.bak +*.ghw +*.o +temp diff --git a/bench/test.vhd b/bench/test.vhd new file mode 100644 index 0000000..42bb083 --- /dev/null +++ b/bench/test.vhd @@ -0,0 +1,118 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +entity test is + +end entity test; + +architecture bench of test is + + signal clk : std_logic; + signal rst : std_logic := '1'; + signal dv : std_logic; + signal rx : std_logic_vector(1 downto 0); + signal mdc : std_logic; + signal mdio : std_logic; + signal led : std_logic_vector(1 downto 0); + signal ws : std_logic; +begin -- architecture bench + + + top_1 : entity work.top + port map ( + clk => clk, + rst => rst, + mdio => mdio, + mdc => mdc, + rx => rx, + dv => dv, + led1 => led(0), + led2 => led(1), + ws_out => ws); + + + + clkgen : process is + begin + clk <= '0'; + wait for 10 ns; + clk <= '1'; + wait for 10 ns; + end process clkgen; + + + + + + sendphy : process is + procedure sendRMII(byte : in std_logic_vector(7 downto 0)) is + begin + wait until falling_edge(clk); + dv <= '1'; + rx <= byte(1 downto 0); + wait until falling_edge(clk); + rx <= byte(3 downto 2); + wait until falling_edge(clk); + rx <= byte(5 downto 4); + wait until falling_edge(clk); + rx <= byte(7 downto 6); + + end procedure sendRMII; + begin + dv <= '0'; + + wait for 35 ns; + rst <= '0'; + dv <= '0'; + rx <= "00"; + wait for 100 us; + sendRMII(x"55"); + sendRMII(x"55"); + sendRMII(x"55"); + sendRMII(x"55"); + sendRMII(x"55"); + sendRMII(x"55"); + sendRMII(x"55"); + sendRMII(x"55"); + sendRMII(x"D5"); + + sendRMII(x"00"); + sendRMII(x"DE"); + sendRMII(x"AD"); + sendRMII(x"BE"); + sendRMII(x"EF"); + sendRMII(x"00"); + + sendRMII(x"01"); + sendRMII(x"02"); + sendRMII(x"03"); + sendRMII(x"04"); + sendRMII(x"05"); + sendRMII(x"06"); + + sendRMII(x"01"); + sendRMII(x"02"); + + sendRMII(x"AA"); + + sendRMII(x"01"); + sendRMII(x"02"); + + + sendRMII(x"CC"); + sendRMII(x"AA"); + sendRMII(x"55"); + -- Send FCS + sendRMII(x"BD"); + sendRMII(x"9B"); + sendRMII(x"AC"); + sendRMII(x"54"); + + -- sendRMII(x"AB"); + + wait until falling_edge(clk); + wait for 10 ns; + dv <= '0'; + wait; + end process sendphy; +end architecture bench; diff --git a/eth/ehtmac_rx.vhd b/eth/ehtmac_rx.vhd new file mode 100644 index 0000000..3d67446 --- /dev/null +++ b/eth/ehtmac_rx.vhd @@ -0,0 +1,195 @@ +------------------------------------------------------------------------------- +-- Title : Ethernet RX Core +-- Project : EthMAC +------------------------------------------------------------------------------- +-- File : design/ethmac_rx.vhd +-- Author : Mario Hüttel +-- Standard : VHDL'93/02 +------------------------------------------------------------------------------- +-- Description: LED Demonstration for Ethernet RX + TX +------------------------------------------------------------------------------- +-- Copyright (c) 2016 +-- +-- This file is part of EthMAC. +-- +-- EthMAC is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, version 2 of the License. +-- +-- This code 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this code. If not, see . +-- +------------------------------------------------------------------------------- + + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity ethmac_rx is + port( + clk_50 : in std_logic; + rst : in std_logic; + rmii_rx : in std_logic_vector(1 downto 0); + rmii_dv : in std_logic; + start_of_frame : out std_logic; + end_of_frame : out std_logic; + data_out : out std_logic_vector(7 downto 0); + data_strb : out std_logic; + crc_check_valid : out std_logic + ); +end entity ethmac_rx; + +architecture RTL of ethmac_rx is + type ethstate_t is (ETH_INIT, ETH_PREAMBLE, ETH_DATA); + signal framestate : ethstate_t; + signal crc_data_in : std_logic_vector(7 downto 0); + signal crc_init : std_logic; + signal crc_calc_en : std_logic; + signal crc_data_valid : std_logic; + signal crc_valid : std_logic; + signal dibit_counter : integer range 0 to 3 := 0; + signal data_delay_in : std_logic_vector(7 downto 0); + signal data_delay_in_strb : std_logic; + signal data_delay_truncate : std_logic; + signal end_of_frame_s : std_logic; + type data_fifo_t is array (0 to 3) of std_logic_vector(7 downto 0); + + signal data_delay_fifo : data_fifo_t; + +-- signal datatype_reg: ethfield_t; +-- signal data : std_logic_vector( 7 downto 0); +begin + ethfcs_inst : entity work.ethfcs + port map( + CLOCK => clk_50, + RESET => rst, + DATA => crc_data_in, + LOAD_INIT => crc_init, + CALC => crc_calc_en, + D_VALID => crc_data_valid, + CRC => open, + CRC_REG => open, + CRC_VALID => crc_valid); + + rx_framefsm : process(clk_50, rst) is + variable recv_byte : std_logic_vector(7 downto 0) := (others => '0'); + + begin + if rst = '1' then + framestate <= ETH_INIT; + dibit_counter <= 0; + recv_byte := (others => '0'); + crc_calc_en <= '0'; + data_delay_truncate <= '0'; + data_delay_in_strb <= '0'; + data_delay_in <= (others => '0'); + crc_init <= '0'; + crc_data_in <= (others => '0'); + crc_data_valid <= '0'; + crc_calc_en <= '0'; + start_of_frame <= '0'; + end_of_frame_s <= '0'; + elsif rising_edge(clk_50) then + end_of_frame_s <= '0'; + crc_calc_en <= '0'; + start_of_frame <= '0'; + data_delay_truncate <= '0'; + data_delay_in_strb <= '0'; + crc_init <= '0'; + crc_data_valid <= '0'; + if dibit_counter = 3 then + dibit_counter <= 0; + else + dibit_counter <= dibit_counter + 1; + end if; + + -- input data shift register (LSB first) + recv_byte := rmii_rx & recv_byte(7 downto 2); + + case framestate is + when ETH_INIT => + if rmii_dv = '0' then -- Wait for inter frame gap for sync + crc_init <= '1'; + framestate <= ETH_PREAMBLE; + end if; + when ETH_PREAMBLE => + if rmii_dv = '1' and rmii_rx = "11" then -- Data valid and last dibit of preamble recieved + -- reset dibit counter + dibit_counter <= 0; + start_of_frame <= '1'; + framestate <= ETH_DATA; + -- crc_init <= '1'; + end if; + when ETH_DATA => + crc_calc_en <= '1'; + if rmii_dv = '1' then + if dibit_counter = 3 then -- Data word received + data_delay_in <= recv_byte; + data_delay_in_strb <= '1'; + crc_data_in <= recv_byte; + crc_data_valid <= '1'; + end if; + else + framestate <= ETH_INIT; + end_of_frame_s <= '1'; + crc_calc_en <= '0'; + data_delay_truncate <= '1'; + end if; + end case; + + end if; + end process rx_framefsm; + + data_delay : process(rst, clk_50) is -- This implements a four byte big delay buffer/FIFO used for removing the crc + variable data_count : integer range 0 to 4 := 0; + begin + if rst = '1' then + data_out <= (others => '0'); + data_strb <= '0'; + data_count := 0; + for i in 0 to 3 loop + data_delay_fifo(i) <= (others => '0'); + end loop; + + elsif rising_edge(clk_50) then + data_strb <= '0'; + if data_delay_truncate = '1' then + data_count := 0; -- resetting counter is enough. FIFO itself has not to be cleared + elsif data_delay_in_strb = '1' then + data_delay_fifo(0) <= data_delay_in; + for i in 3 downto 1 loop + data_delay_fifo(i) <= data_delay_fifo(i - 1); + end loop; + + if data_count < 4 then + data_count := data_count + 1; + else -- Enable output + data_out <= data_delay_fifo(3); + data_strb <= '1'; + end if; + end if; + end if; + end process data_delay; + + crc_valid_gen : process(crc_valid) is + begin + crc_check_valid <= crc_valid; + end process crc_valid_gen; + + eof_sync : process(clk_50, rst) is + begin + if rst = '1' then + end_of_frame <= '0'; + elsif rising_edge(clk_50) then + end_of_frame <= end_of_frame_s; + end if; + end process eof_sync; + +end architecture RTL; diff --git a/eth/eth-fcs.vhd b/eth/eth-fcs.vhd new file mode 100644 index 0000000..9e13f63 --- /dev/null +++ b/eth/eth-fcs.vhd @@ -0,0 +1,217 @@ +-------------------------------------------------------------------------------- +-- CRC GENERATOR +-- Computes the CRC32 (802.3) for the input byte stream. Assert D_VALID to load +-- each byte for calculation. LOAD_INIT should be asserted at the beginning of a +-- data stream in order to prime with CRC generator with 32'hFFFFFFFF +-- which will cause the initial 32 bits in to be complemented as per 802.3. +-- +-- IO DESCRIPTION +-- Clock: 100MHz Clock +-- Reset: Active high reset +-- Data: 8Bit Data In +-- Load Init: Asserted for one clock period, loads the CRC gen with 32'hFFFFFFFF +-- Calc: Asserted to enable calculation of the CRC. +-- D_valid: Asserted for one clock period, loads in the next byte on DATA. +-- +-- @author Peter A Bennett +-- @copyright (c) 2012 Peter A Bennett +-- @version $Rev: 2 $ +-- @lastrevision $Date: 2012-03-11 15:19:25 +0000 (Sun, 11 Mar 2012) $ +-- @license LGPL +-- @email pab850@googlemail.com +-- @contact www.bytebash.com +-- +-------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity ethfcs is + Port ( CLOCK : in std_logic; + RESET : in std_logic; + DATA : in std_logic_vector(7 downto 0); + LOAD_INIT : in std_logic; + CALC : in std_logic; + D_VALID : in std_logic; + CRC : out std_logic_vector(7 downto 0); + CRC_REG : out std_logic_vector(31 downto 0); + CRC_VALID : out std_logic + ); +end ethfcs; + +architecture RTL of ethfcs is + -- Block Diagram for Parallel CRC-32 generation. + -- (Based on Xilinx CRC App Note) + -- http://www.xilinx.com/support/documentation/application_notes/xapp209.pdf + -- Data In is byte reversed internally as per the requirements of the easics comb CRC block. + + -- + -- The "8-bit CRC Out" register always contains the bit-reversed and complimented most + -- significant bits of the "32-bit CRC" register. The final IEEE 802.3 FCS can be read from the + -- "8-bit CRC Out" register by asserting d_valid four times after the de-assertion of calc + -- + -- +--------------------------------------+-----------------------------------+ + -- | | _____ | + -- | comb_crc_gen next_crc(23:0) | | \ +--->CRC_REG(31:0) + -- | +---------------+ & x"FF" +-->|00 \ +-----+ | + -- +-->| Combinatorial |--------------------->|01 \__________|D Q|______| + --D(7:0) >--->| Next CRC Gen | xFFFFFFFF---->|10 / +--|---|En | + -- +---------------+ xFFFFFFFF---->|11 / | | +-----+ ____ +-----+ + -- (complements first |_____/ | +------------>| = |-->|D Q|--> VALID_REG + -- 32 bits of frame) | | | residue ---->|____| +-|En | + --load_init >----------------------+------------------+ | | xC704DD7B | +-----+ + --calc >-----------+ | | | | + --d_valid >-------+ | _ | | |-----------------------+ + -- | +---|x\____|____________________| | + -- +---|---|_/ | _ | + -- | | +---|+\_______________________| + -- +---|----------+---|_/ + -- | | + -- | +------------------------------------+ + -- | ________ ____ | +-----+ + -- | crc_reg (16:23)>-----|0 \ +--|En | + -- | ________ | \___|D Q|------>CRC(7:0) + -- | next_crc(24:31)>-----|1 / +-----+ + -- | |_____/ + -- | | + -- +------------------------------------------+ + + + -- First, the data stream and CRC of the received frame are sent through the circuit. + -- Then the value left in the CRC-32 registers can be compared with a constant, commonly + -- referred to as the residue. In this implementation, the value of the residue is 0xC704DD7B + -- when no CRC errors are detected. (Xilinx CRC App Note). + + -- CRC32 (Easics generator). + function comb_crc_gen + ( + data_in : std_logic_vector(7 downto 0); + crc_in : std_logic_vector(31 downto 0) + ) + return std_logic_vector is + + variable d: std_logic_vector(7 downto 0); + variable c: std_logic_vector(31 downto 0); + variable newcrc: std_logic_vector(31 downto 0); + + begin + d := data_in; + c := crc_in; + -- Easics + newcrc(0) := d(6) xor d(0) xor c(24) xor c(30); + newcrc(1) := d(7) xor d(6) xor d(1) xor d(0) xor c(24) xor c(25) xor c(30) xor c(31); + newcrc(2) := d(7) xor d(6) xor d(2) xor d(1) xor d(0) xor c(24) xor c(25) xor c(26) xor c(30) xor c(31); + newcrc(3) := d(7) xor d(3) xor d(2) xor d(1) xor c(25) xor c(26) xor c(27) xor c(31); + newcrc(4) := d(6) xor d(4) xor d(3) xor d(2) xor d(0) xor c(24) xor c(26) xor c(27) xor c(28) xor c(30); + newcrc(5) := d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(1) xor d(0) xor c(24) xor c(25) xor c(27) xor c(28) xor c(29) xor c(30) xor c(31); + newcrc(6) := d(7) xor d(6) xor d(5) xor d(4) xor d(2) xor d(1) xor c(25) xor c(26) xor c(28) xor c(29) xor c(30) xor c(31); + newcrc(7) := d(7) xor d(5) xor d(3) xor d(2) xor d(0) xor c(24) xor c(26) xor c(27) xor c(29) xor c(31); + newcrc(8) := d(4) xor d(3) xor d(1) xor d(0) xor c(0) xor c(24) xor c(25) xor c(27) xor c(28); + newcrc(9) := d(5) xor d(4) xor d(2) xor d(1) xor c(1) xor c(25) xor c(26) xor c(28) xor c(29); + newcrc(10) := d(5) xor d(3) xor d(2) xor d(0) xor c(2) xor c(24) xor c(26) xor c(27) xor c(29); + newcrc(11) := d(4) xor d(3) xor d(1) xor d(0) xor c(3) xor c(24) xor c(25) xor c(27) xor c(28); + newcrc(12) := d(6) xor d(5) xor d(4) xor d(2) xor d(1) xor d(0) xor c(4) xor c(24) xor c(25) xor c(26) xor c(28) xor c(29) xor c(30); + newcrc(13) := d(7) xor d(6) xor d(5) xor d(3) xor d(2) xor d(1) xor c(5) xor c(25) xor c(26) xor c(27) xor c(29) xor c(30) xor c(31); + newcrc(14) := d(7) xor d(6) xor d(4) xor d(3) xor d(2) xor c(6) xor c(26) xor c(27) xor c(28) xor c(30) xor c(31); + newcrc(15) := d(7) xor d(5) xor d(4) xor d(3) xor c(7) xor c(27) xor c(28) xor c(29) xor c(31); + newcrc(16) := d(5) xor d(4) xor d(0) xor c(8) xor c(24) xor c(28) xor c(29); + newcrc(17) := d(6) xor d(5) xor d(1) xor c(9) xor c(25) xor c(29) xor c(30); + newcrc(18) := d(7) xor d(6) xor d(2) xor c(10) xor c(26) xor c(30) xor c(31); + newcrc(19) := d(7) xor d(3) xor c(11) xor c(27) xor c(31); + newcrc(20) := d(4) xor c(12) xor c(28); + newcrc(21) := d(5) xor c(13) xor c(29); + newcrc(22) := d(0) xor c(14) xor c(24); + newcrc(23) := d(6) xor d(1) xor d(0) xor c(15) xor c(24) xor c(25) xor c(30); + newcrc(24) := d(7) xor d(2) xor d(1) xor c(16) xor c(25) xor c(26) xor c(31); + newcrc(25) := d(3) xor d(2) xor c(17) xor c(26) xor c(27); + newcrc(26) := d(6) xor d(4) xor d(3) xor d(0) xor c(18) xor c(24) xor c(27) xor c(28) xor c(30); + newcrc(27) := d(7) xor d(5) xor d(4) xor d(1) xor c(19) xor c(25) xor c(28) xor c(29) xor c(31); + newcrc(28) := d(6) xor d(5) xor d(2) xor c(20) xor c(26) xor c(29) xor c(30); + newcrc(29) := d(7) xor d(6) xor d(3) xor c(21) xor c(27) xor c(30) xor c(31); + newcrc(30) := d(7) xor d(4) xor c(22) xor c(28) xor c(31); + newcrc(31) := d(5) xor c(23) xor c(29); + return newcrc; + end comb_crc_gen; + + -- Reverse the input vector. + function reversed(slv: std_logic_vector) return std_logic_vector is + variable result: std_logic_vector(slv'reverse_range); + begin + for i in slv'range loop + result(i) := slv(i); + end loop; + return result; + end reversed; + + + -- Magic number for the CRC generator. + constant c_crc_residue : std_logic_vector(31 downto 0) := x"C704DD7B"; + signal s_next_crc : std_logic_vector(31 downto 0) := (others => '0'); + signal s_crc_reg : std_logic_vector(31 downto 0) := (others => '0'); + signal s_crc : std_logic_vector(7 downto 0) := (others => '0'); + signal s_reversed_byte : std_logic_vector(7 downto 0) := (others => '0'); + signal s_crc_valid : std_logic := '0'; + + begin + + CRC <= s_crc; + CRC_REG <= s_crc_reg; + CRC_VALID <= s_crc_valid; + + BYTE_REVERSE : process (DATA) + -- Nibble swapped and Bit reversed version of DATA + begin + --s_reversed_byte <= reversed(DATA(3 downto 0) & DATA(7 downto 4)); + s_reversed_byte <= reversed(DATA); + end process; + + COMB_NEXT_CRC_GEN : process (s_reversed_byte, s_crc_reg) + begin + s_next_crc <= comb_crc_gen(s_reversed_byte, s_crc_reg); + end process COMB_NEXT_CRC_GEN; + + CRC_GEN : process (CLOCK) + variable state : std_logic_vector(2 downto 0); + begin + if rising_edge(CLOCK) then + if RESET = '1' then + s_crc_reg <= (others => '0'); + s_crc <= (others => '0'); + s_crc_valid <= '0'; + state := (others => '0'); + else + state := LOAD_INIT & CALC & D_VALID; + case state is + when "000" => + -- No change. + when "001" => + s_crc_reg <= s_crc_reg(23 downto 0) & x"FF"; + s_crc <= not reversed(s_crc_reg(23 downto 16)); + when "010" => + -- No Change + when "011" => + s_crc_reg <= s_next_crc; + s_crc <= not reversed(s_next_crc(31 downto 24)); + when "100" => + s_crc_reg <= x"FFFFFFFF"; + when "101" => + s_crc_reg <= x"FFFFFFFF"; + s_crc <= not reversed(s_crc_reg(23 downto 16)); + when "110" => + s_crc_reg <= x"FFFFFFFF"; + when "111" => + s_crc_reg <= x"FFFFFFFF"; + s_crc <= not reversed(s_next_crc(31 downto 24)); + when others => + null; + end case; + if c_crc_residue = s_crc_reg then + s_crc_valid <= '1'; + else + s_crc_valid <= '0'; + end if; + end if; + end if; + end process CRC_GEN; +end RTL; diff --git a/eth/smi.vhd b/eth/smi.vhd new file mode 100644 index 0000000..545f53a --- /dev/null +++ b/eth/smi.vhd @@ -0,0 +1,193 @@ +------------------------------------------------------------------------------- +-- Title : SMI (MDIO) +-- Project : EthMAC +------------------------------------------------------------------------------- +-- File : design/smi.vhd +-- Author : Mario Hüttel +-- Standard : VHDL'93/02 +------------------------------------------------------------------------------- +-- Description: SMI/MDIO Implementation for Ethernet PHYs +------------------------------------------------------------------------------- +-- Copyright (c) 2016 +-- +-- This file is part of EthMAC. +-- +-- EthMAC is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, version 2 of the License. +-- +-- This code 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 General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this code. If not, see . +-- +------------------------------------------------------------------------------- + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- Implementation of the SMI +-- Only write Access implemented +-- I think i won't implement read access because.........IT'S FUCKING USELESS +entity smi is + generic( + clockdiv : integer := 64 + ); + port( + clk_i : in std_logic; + rst_i : in std_logic; + mdio_io : inout std_logic; + mdc_o : out std_logic; + busy_o : out std_logic; + data_o : out std_logic_vector(15 downto 0); + phyaddr_i : std_logic_vector(4 downto 0); + regaddr_i : std_logic_vector(4 downto 0); + data_i : in std_logic_vector(15 downto 0); + strb_i : in std_logic; + rw_i : in std_logic --Read/write. 0=write, 1=read + ); +end entity smi; + +architecture RTL of smi is + type smistate_t is (IDLE, PRE, SOF, OPC, PHYADDR, REGADDR, TURN, DATA, CONCL); + signal state_s : smistate_t; + signal fedge_strb_s : std_logic; + signal datashift_s : std_logic_vector(15 downto 0); + signal regaddr_s : std_logic_vector(4 downto 0); + signal phyaddr_s : std_logic_vector(4 downto 0); + signal bitcounter_s : integer range 0 to 32; + signal mdc_o_s : std_logic; +begin + mdc_o <= mdc_o_s; + + div : process(clk_i, rst_i) is + variable counter : integer := 0; + begin + if rst_i = '1' then + fedge_strb_s <= '0'; + counter := 0; + mdc_o_s <= '0'; + elsif rising_edge(clk_i) then + fedge_strb_s <= '0'; + counter := counter + 1; + if counter = clockdiv then + mdc_o_s <= not mdc_o_s; + counter := 0; + if mdc_o_s = '1' then + fedge_strb_s <= '1'; + end if; + end if; + end if; + end process div; + + smishift : process(clk_i, rst_i) is + begin + if rst_i = '1' then + mdio_io <= '1'; + state_s <= IDLE; + + busy_o <= '1'; + elsif rising_edge(clk_i) then + busy_o <= '1'; + if state_s = IDLE then + mdio_io <= '1'; + busy_o <= '0'; + bitcounter_s <= 0; + if (strb_i = '1') then + state_s <= PRE; + busy_o <= '1'; + --Load data + phyaddr_s <= phyaddr_i; + regaddr_s <= regaddr_i; + datashift_s <= data_i; + end if; + elsif state_s = CONCL then + mdio_io <= '1'; + busy_o <= '0'; + state_s <= IDLE; + bitcounter_s <= 0; + elsif fedge_strb_s = '1' then + mdio_io <= '1'; + bitcounter_s <= bitcounter_s + 1; + case state_s is + when PRE => + if fedge_strb_s = '1' then + --Mdio idle high for 32 cycles + if (bitcounter_s = 31) then + bitcounter_s <= 0; + state_s <= SOF; + end if; + end if; + when SOF => + if bitcounter_s = 0 then + mdio_io <= '0'; + elsif bitcounter_s = 1 then + bitcounter_s <= 0; + --Mdio idle high + state_s <= OPC; + end if; + when OPC => --Write OPCODE + if bitcounter_s = 0 then + if rw_i = '1' then + mdio_io <= '1'; + else + mdio_io <= '0'; + end if; + elsif bitcounter_s = 1 then + bitcounter_s <= 0; + if rw_i = '1' then + mdio_io <= '0'; + else + mdio_io <= '1'; + end if; + state_s <= PHYADDR; + end if; + when PHYADDR => + if bitcounter_s = 4 then + bitcounter_s <= 0; + state_s <= REGADDR; + end if; + mdio_io <= phyaddr_s(4); + phyaddr_s <= phyaddr_s(3 downto 0) & '0'; + when REGADDR => + if bitcounter_s = 4 then + bitcounter_s <= 0; + state_s <= TURN; + end if; + mdio_io <= regaddr_s(4); + regaddr_s <= regaddr_s(3 downto 0) & '0'; + when TURN => + if rw_i = '1' then + mdio_io <= 'Z'; + end if; + if bitcounter_s = 1 then + bitcounter_s <= 0; + state_s <= DATA; + end if; + when DATA => + if bitcounter_s = 15 then + bitcounter_s <= 0; + state_s <= CONCL; + end if; + if rw_i = '1' then + mdio_io <= 'Z'; + --Not implemented => => + else + mdio_io <= datashift_s(15); + datashift_s <= datashift_s(14 downto 0) & '0'; + end if; + when others => + null; -- This should not happen + end case; + end if; + end if; + end process smishift; + + data_o <= (others => '0'); + +end architecture RTL; diff --git a/fifo.vhd b/fifo.vhd new file mode 100644 index 0000000..a879d34 --- /dev/null +++ b/fifo.vhd @@ -0,0 +1,95 @@ +library IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +entity STD_FIFO is + Generic ( + constant DATA_WIDTH : positive := 8; + constant FIFO_DEPTH : positive := 256 + ); + Port ( + CLK : in STD_LOGIC; + RST : in STD_LOGIC; + WriteEn : in STD_LOGIC; + DataIn : in STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0); + ReadEn : in STD_LOGIC; + DataOut : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0); + Empty : out STD_LOGIC; + Full : out STD_LOGIC + ); +end STD_FIFO; + +architecture Behavioral of STD_FIFO is + +begin + + -- Memory Pointer Process + fifo_proc : process (CLK) + type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0); + variable Memory : FIFO_Memory; + + variable Head : natural range 0 to FIFO_DEPTH - 1; + variable Tail : natural range 0 to FIFO_DEPTH - 1; + + variable Looped : boolean; + begin + if rising_edge(CLK) then + if RST = '1' then + Head := 0; + Tail := 0; + + Looped := false; + + Full <= '0'; + Empty <= '1'; + else + if (ReadEn = '1') then + if ((Looped = true) or (Head /= Tail)) then + -- Update data output + DataOut <= Memory(Tail); + + -- Update Tail pointer as needed + if (Tail = FIFO_DEPTH - 1) then + Tail := 0; + + Looped := false; + else + Tail := Tail + 1; + end if; + + + end if; + end if; + + if (WriteEn = '1') then + if ((Looped = false) or (Head /= Tail)) then + -- Write Data to Memory + Memory(Head) := DataIn; + + -- Increment Head pointer as needed + if (Head = FIFO_DEPTH - 1) then + Head := 0; + + Looped := true; + else + Head := Head + 1; + end if; + end if; + end if; + + -- Update Empty and Full flags + if (Head = Tail) then + if Looped then + Full <= '1'; + else + Empty <= '1'; + end if; + else + Empty <= '0'; + Full <= '0'; + end if; + end if; + end if; + end process; + +end Behavioral; diff --git a/fifo_dc.vhd b/fifo_dc.vhd new file mode 100644 index 0000000..c60727e --- /dev/null +++ b/fifo_dc.vhd @@ -0,0 +1,125 @@ +-- VHDL netlist generated by SCUBA Diamond (64-bit) 3.10.0.111.2 +-- Module Version: 5.8 +--/usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n fifo_dc -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ebfifo -depth 256 -width 8 -rwidth 8 -no_enable -pe 10 -pf 250 + +-- Thu Apr 5 20:50:27 2018 + +library IEEE; +use IEEE.std_logic_1164.all; +-- synopsys translate_off +library MACHXO2; +use MACHXO2.components.all; +-- synopsys translate_on + +entity fifo_dc is + port ( + Data: in std_logic_vector(7 downto 0); + WrClock: in std_logic; + RdClock: in std_logic; + WrEn: in std_logic; + RdEn: in std_logic; + Reset: in std_logic; + RPReset: in std_logic; + Q: out std_logic_vector(7 downto 0); + Empty: out std_logic; + Full: out std_logic; + AlmostEmpty: out std_logic; + AlmostFull: out std_logic); +end fifo_dc; + +architecture Structure of fifo_dc is + + -- internal signal declarations + signal scuba_vhi: std_logic; + signal Empty_int: std_logic; + signal Full_int: std_logic; + signal scuba_vlo: std_logic; + + -- local component declarations + component VHI + port (Z: out std_logic); + end component; + component VLO + port (Z: out std_logic); + end component; + component FIFO8KB + generic (FULLPOINTER1 : in String; FULLPOINTER : in String; + AFPOINTER1 : in String; AFPOINTER : in String; + AEPOINTER1 : in String; AEPOINTER : in String; + ASYNC_RESET_RELEASE : in String; RESETMODE : in String; + GSR : in String; CSDECODE_R : in String; + CSDECODE_W : in String; REGMODE : in String; + DATA_WIDTH_R : in Integer; DATA_WIDTH_W : in Integer); + port (DI0: in std_logic; DI1: in std_logic; DI2: in std_logic; + DI3: in std_logic; DI4: in std_logic; DI5: in std_logic; + DI6: in std_logic; DI7: in std_logic; DI8: in std_logic; + DI9: in std_logic; DI10: in std_logic; DI11: in std_logic; + DI12: in std_logic; DI13: in std_logic; + DI14: in std_logic; DI15: in std_logic; + DI16: in std_logic; DI17: in std_logic; + CSW0: in std_logic; CSW1: in std_logic; + CSR0: in std_logic; CSR1: in std_logic; + FULLI: in std_logic; EMPTYI: in std_logic; + WE: in std_logic; RE: in std_logic; ORE: in std_logic; + CLKW: in std_logic; CLKR: in std_logic; RST: in std_logic; + RPRST: in std_logic; DO0: out std_logic; + DO1: out std_logic; DO2: out std_logic; + DO3: out std_logic; DO4: out std_logic; + DO5: out std_logic; DO6: out std_logic; + DO7: out std_logic; DO8: out std_logic; + DO9: out std_logic; DO10: out std_logic; + DO11: out std_logic; DO12: out std_logic; + DO13: out std_logic; DO14: out std_logic; + DO15: out std_logic; DO16: out std_logic; + DO17: out std_logic; EF: out std_logic; + AEF: out std_logic; AFF: out std_logic; FF: out std_logic); + end component; + attribute syn_keep : boolean; + attribute NGD_DRC_MASK : integer; + attribute NGD_DRC_MASK of Structure : architecture is 1; + +begin + -- component instantiation statements + scuba_vhi_inst: VHI + port map (Z=>scuba_vhi); + + scuba_vlo_inst: VLO + port map (Z=>scuba_vlo); + + fifo_dc_0_0: FIFO8KB + generic map (FULLPOINTER1=> "0b00111111110000", FULLPOINTER=> "0b01000000000000", + AFPOINTER1=> "0b00111110010000", AFPOINTER=> "0b00111110100000", + AEPOINTER1=> "0b00000010110000", AEPOINTER=> "0b00000010100000", + ASYNC_RESET_RELEASE=> "SYNC", GSR=> "DISABLED", RESETMODE=> "ASYNC", + REGMODE=> "NOREG", CSDECODE_R=> "0b11", CSDECODE_W=> "0b11", + DATA_WIDTH_R=> 18, DATA_WIDTH_W=> 18) + port map (DI0=>Data(0), DI1=>Data(1), DI2=>Data(2), DI3=>Data(3), + DI4=>Data(4), DI5=>Data(5), DI6=>Data(6), DI7=>Data(7), + DI8=>scuba_vlo, DI9=>scuba_vlo, DI10=>scuba_vlo, + DI11=>scuba_vlo, DI12=>scuba_vlo, DI13=>scuba_vlo, + DI14=>scuba_vlo, DI15=>scuba_vlo, DI16=>scuba_vlo, + DI17=>scuba_vlo, CSW0=>scuba_vhi, CSW1=>scuba_vhi, + CSR0=>scuba_vhi, CSR1=>scuba_vhi, FULLI=>Full_int, + EMPTYI=>Empty_int, WE=>WrEn, RE=>RdEn, ORE=>RdEn, + CLKW=>WrClock, CLKR=>RdClock, RST=>Reset, RPRST=>RPReset, + DO0=>open, DO1=>open, DO2=>open, DO3=>open, DO4=>open, + DO5=>open, DO6=>open, DO7=>open, DO8=>open, DO9=>Q(0), + DO10=>Q(1), DO11=>Q(2), DO12=>Q(3), DO13=>Q(4), DO14=>Q(5), + DO15=>Q(6), DO16=>Q(7), DO17=>open, EF=>Empty_int, + AEF=>AlmostEmpty, AFF=>AlmostFull, FF=>Full_int); + + Empty <= Empty_int; + Full <= Full_int; +end Structure; + +-- synopsys translate_off +library MACHXO2; +configuration Structure_CON of fifo_dc is + for Structure + for all:VHI use entity MACHXO2.VHI(V); end for; + for all:VLO use entity MACHXO2.VLO(V); end for; + for all:FIFO8KB use entity MACHXO2.FIFO8KB(V); end for; + end for; +end Structure_CON; + +-- synopsys translate_on diff --git a/top.vhd b/top.vhd new file mode 100644 index 0000000..9b08c6d --- /dev/null +++ b/top.vhd @@ -0,0 +1,372 @@ +------------------------------------------------------------------------------- +-- Title : Ethernet controlled WS2812b +-- Project : +------------------------------------------------------------------------------- +-- File : top.vhd +-- Author : Mario Hüttel +-- Company : +-- Created : 2018-04-05 +-- Last update: 2018-04-06 +-- 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; + constant DEFMAC : std_logic_vector(47 downto 0) := x"00DEADBEEF00"; + + type smi_state_t is (IDLE, STROBE); + type smi_init_state_t is (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 := RESET; + signal rst_rxtx : std_logic; + signal delaycounter : unsigned(19 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 + + rst <= not rst_hw; + + 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 => 256) + 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 <= RESET; + sendstate <= IDLE; + delaycounter <= (others => '0'); + elsif rising_edge(clk) then + smi_strb <= '0'; + rst_rxtx <= '1'; + case initstate is + when RESET => + 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; + rst_rxtx <= '0'; + 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; diff --git a/ws2812/ws2812bphy.vhd b/ws2812/ws2812bphy.vhd new file mode 100644 index 0000000..dacac7f --- /dev/null +++ b/ws2812/ws2812bphy.vhd @@ -0,0 +1,121 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity ws2812bphy is + generic( + constant HIGH1 : integer := 40; + constant LOW1 : integer := 23; + constant HIGH0 : integer := 20; + constant LOW0 : integer := 43); + port( + clk : in std_logic; + rst : in std_logic; + busy : out std_logic; + ws_out : out std_logic; + strb : in std_logic; + red : in unsigned(7 downto 0); + green : in unsigned(7 downto 0); + blue : in unsigned(7 downto 0)); +end entity ws2812bphy; + +architecture RTL of ws2812bphy is + + type ws_output_state_t is (IDLE, TRANSMITTING, INTERLEDDELAY); + signal ws_output_state : ws_output_state_t; + + type bitstate_t is (LOW, HIGH); + signal bitstate : bitstate_t; + +begin + ws_output : process(clk, rst) is + variable counter : integer range 0 to 255 := 0; + + variable color_vector : std_logic_vector(23 downto 0); + variable bitnum : integer range 0 to 23; + begin + if rst = '1' then + ws_output_state <= IDLE; + color_vector := (others => '0'); + counter := 0; + bitstate <= LOW; + bitnum := 0; + elsif rising_edge(clk) then + case ws_output_state is + when IDLE => + bitstate <= LOW; + if strb = '1' then + ws_output_state <= TRANSMITTING; + bitnum := 23; + color_vector := std_logic_vector(green) & std_logic_vector(red) & std_logic_vector(blue); + counter := 0; + bitstate <= HIGH; + end if; + when TRANSMITTING => + case bitstate is + when HIGH => + if color_vector(bitnum) = '1' then + if counter < HIGH1 - 1 then + counter := counter + 1; + else + bitstate <= LOW; + counter := 0; + end if; + else + if counter < HIGH0 -1 then + counter := counter + 1; + else + bitstate <= LOW; + counter := 0; + end if; + end if; + when LOW => + if color_vector(bitnum) = '1' then + if counter < LOW1 -1 then + counter := counter + 1; + else + bitstate <= HIGH; + counter := 0; + if bitnum = 0 then + ws_output_state <= INTERLEDDELAY; + counter := 0; + bitstate <= LOW; + else + bitnum := bitnum - 1; + end if; + end if; + else + if counter < LOW0 - 1 then + counter := counter + 1; + else + bitstate <= HIGH; + counter := 0; + + if bitnum = 0 then + ws_output_state <= INTERLEDDELAY; + counter := 0; + bitstate <= LOW; + else + bitnum := bitnum - 1; + end if; + + end if; + end if; + + end case; + + when INTERLEDDELAY => + if counter < HIGH1+LOW1+LOW1 then + counter := counter + 1; + else + counter := 0; + ws_output_state <= IDLE; + end if; + + end case; + end if; + end process ws_output; + busy <= '0' when ws_output_state = IDLE else '1'; + ws_out <= '1' when bitstate = HIGH else '0'; + +end architecture RTL;