init. Works on altera
This commit is contained in:
195
eth/ehtmac_rx.vhd
Normal file
195
eth/ehtmac_rx.vhd
Normal file
@@ -0,0 +1,195 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Title : Ethernet RX Core
|
||||
-- Project : EthMAC
|
||||
-------------------------------------------------------------------------------
|
||||
-- File : design/ethmac_rx.vhd
|
||||
-- Author : Mario Hüttel <mario.huettel@gmx.net>
|
||||
-- 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 <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
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;
|
217
eth/eth-fcs.vhd
Normal file
217
eth/eth-fcs.vhd
Normal file
@@ -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;
|
193
eth/smi.vhd
Normal file
193
eth/smi.vhd
Normal file
@@ -0,0 +1,193 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Title : SMI (MDIO)
|
||||
-- Project : EthMAC
|
||||
-------------------------------------------------------------------------------
|
||||
-- File : design/smi.vhd
|
||||
-- Author : Mario Hüttel <mario.huettel@gmx.net>
|
||||
-- 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 <http://www.gnu.org/licenses/>.
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
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;
|
Reference in New Issue
Block a user