Add read support to SMI

This commit is contained in:
Mario Hüttel 2020-08-09 23:14:44 +02:00
parent 27286cb32f
commit 6d7492a98d
2 changed files with 147 additions and 134 deletions

View File

@ -2,7 +2,7 @@
-- Title : LED Demo File -- Title : LED Demo File
-- Project : EthMAC -- Project : EthMAC
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- File : design/led-demo.vhd -- File : design/led-demo.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net> -- Author : Mario Hüttel <mario.huettel@gmx.net>
-- Standard : VHDL'93/02 -- Standard : VHDL'93/02
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -18,7 +18,7 @@
-- --
-- This code is distributed in the hope that it will be useful, -- This code is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of -- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details. -- GNU General Public License for more details.
-- --
-- You should have received a copy of the GNU General Public License -- You should have received a copy of the GNU General Public License
@ -33,54 +33,54 @@ use ieee.numeric_std.all;
entity leddemo is entity leddemo is
port( port(
clk_tx : in std_logic; clk_tx : in std_logic;
clk_rx : in std_logic; clk_rx : in std_logic;
data_in : in std_logic_vector(3 downto 0); data_in : in std_logic_vector(3 downto 0);
data_out : out std_logic_vector(3 downto 0); data_out : out std_logic_vector(3 downto 0);
rst_hw : in std_logic; rst_hw : in std_logic;
rmii_tx : out std_logic_vector(1 downto 0); rmii_tx : out std_logic_vector(1 downto 0);
rmii_txen : out std_logic; rmii_txen : out std_logic;
rmii_rx : in std_logic_vector(1 downto 0); rmii_rx : in std_logic_vector(1 downto 0);
rmii_rxen : in std_logic; rmii_rxen : in std_logic;
mdc : out std_logic_vector(1 downto 0); mdc : out std_logic_vector(1 downto 0);
mdio : out std_logic_vector(1 downto 0) mdio : out std_logic_vector(1 downto 0)
); );
end entity leddemo; end entity leddemo;
architecture RTL of leddemo is architecture RTL of leddemo is
constant DELAYCNTVAL : integer := 100000 constant DELAYCNTVAL : integer := 100000
-- pragma synthesis_off -- pragma synthesis_off
/50000 /50000
-- pragma synthesis_on -- pragma synthesis_on
; ;
type smisend_t is (IDLE, STROBE); type smisend_t is (IDLE, STROBE);
type rx_state_t is (RXSOFWAIT, RXDATA, RXCRCCHECK); type rx_state_t is (RXSOFWAIT, RXDATA, RXCRCCHECK);
type tx_state_t is (TXWAIT, TXSEND); type tx_state_t is (TXWAIT, TXSEND);
type smiinit_t is (RESET, INIT, DELAY, INIT_COMPLETE); type smiinit_t is (RESET, INIT, DELAY, INIT_COMPLETE);
signal rx_state : rx_state_t; signal rx_state : rx_state_t;
signal tx_state : tx_state_t; signal tx_state : tx_state_t;
signal sendstate : smisend_t; signal sendstate : smisend_t;
signal delaycounter : unsigned(19 downto 0); signal delaycounter : unsigned(19 downto 0);
signal regaddr_s : std_logic_vector(4 downto 0); signal regaddr_s : std_logic_vector(4 downto 0);
signal smi_data_s : std_logic_vector(15 downto 0); signal smi_data_s : std_logic_vector(15 downto 0);
signal smi_strb_s : std_logic; signal smi_strb_s : std_logic;
signal rst_rxtx : std_logic; signal rst_rxtx : std_logic;
signal rst : std_logic; signal rst : std_logic;
signal smi_busy_s : std_logic; signal smi_busy_s : std_logic;
signal initstate : smiinit_t; signal initstate : smiinit_t;
signal mdio_s : std_logic; signal mdio_s : std_logic;
signal mdc_s : std_logic; signal mdc_s : std_logic;
signal rx_crc : std_logic; signal rx_crc : std_logic;
signal rx_strb : std_logic; signal rx_strb : std_logic;
signal rx_data : std_logic_vector(7 downto 0); signal rx_data : std_logic_vector(7 downto 0);
signal rx_eof : std_logic; signal rx_eof : std_logic;
signal rx_sof : std_logic; signal rx_sof : std_logic;
signal rx_mem : std_logic_vector(3 downto 0); signal rx_mem : std_logic_vector(3 downto 0);
signal tx_ack : std_logic; signal tx_ack : std_logic;
signal tx_data : std_logic_vector(7 downto 0); signal tx_data : std_logic_vector(7 downto 0);
signal tx_eof : std_logic; signal tx_eof : std_logic;
signal tx_sof : std_logic; signal tx_sof : std_logic;
begin begin
rst <= not rst_hw; rst <= not rst_hw;
@ -92,26 +92,27 @@ begin
clockdiv => 30 clockdiv => 30
-- pragma synthesis_off -- pragma synthesis_off
/10 /10
-- pragma synthesis_on -- pragma synthesis_on
) )
port map( port map(
clk_i => clk_tx, clk_i => clk_tx,
rst_i => rst, rst_i => rst,
mdio_io => mdio_s, mdio_io => mdio_s,
mdc_o => mdc_s, mdc_o => mdc_s,
busy_o => smi_busy_s, busy_o => smi_busy_s,
data_o => open, data_o => open, -- ignore read outputs
phyaddr_i => "00001", data_o_strb => open, -- ignore read outputs
regaddr_i => regaddr_s, phyaddr_i => "00001",
data_i => smi_data_s, regaddr_i => regaddr_s,
strb_i => smi_strb_s, data_i => smi_data_s,
rw_i => '0' strb_i => smi_strb_s,
); rw_i => '0' -- Fix for write operation
);
initphy : process(clk_tx, rst) is initphy : process(clk_tx, rst) is
procedure sendsmi(regaddr : in std_logic_vector(4 downto 0); procedure sendsmi(regaddr : in std_logic_vector(4 downto 0);
data : in std_logic_vector(15 downto 0); data : in std_logic_vector(15 downto 0);
nextstate : in smiinit_t) is nextstate : in smiinit_t) is
begin begin
case sendstate is case sendstate is
when IDLE => when IDLE =>
@ -144,7 +145,7 @@ begin
sendsmi((others => '0'), x"8000", DELAY); sendsmi((others => '0'), x"8000", DELAY);
when DELAY => when DELAY =>
delaycounter <= delaycounter + 1; delaycounter <= delaycounter + 1;
if delaycounter = DELAYCNTVAL then -- Set to 100000 if delaycounter = DELAYCNTVAL then -- Set to 100000
initstate <= INIT; initstate <= INIT;
end if; end if;
when INIT => when INIT =>
@ -158,22 +159,22 @@ begin
ethmac_rx_inst : entity work.ethmac_rx ethmac_rx_inst : entity work.ethmac_rx
port map( port map(
clk_50 => clk_rx, clk_50 => clk_rx,
rst => rst, rst => rst,
rmii_rx => rmii_rx, rmii_rx => rmii_rx,
rmii_dv => rmii_rxen, rmii_dv => rmii_rxen,
start_of_frame => rx_sof, start_of_frame => rx_sof,
end_of_frame => rx_eof, end_of_frame => rx_eof,
data_out => rx_data, data_out => rx_data,
data_strb => rx_strb, data_strb => rx_strb,
crc_check_valid => rx_crc crc_check_valid => rx_crc
); );
receiver : process(clk_rx, rst) is receiver : process(clk_rx, rst) is
begin begin
if rst = '1' then if rst = '1' then
rx_state <= RXSOFWAIT; rx_state <= RXSOFWAIT;
rx_mem <= (others => '0'); rx_mem <= (others => '0');
data_out <= (others => '0'); data_out <= (others => '0');
elsif rising_edge(clk_rx) then elsif rising_edge(clk_rx) then
case rx_state is case rx_state is
@ -183,7 +184,7 @@ begin
end if; end if;
when RXDATA => when RXDATA =>
if rx_strb = '1' then if rx_strb = '1' then
rx_mem <= rx_data(3 downto 0); rx_mem <= rx_data(3 downto 0);
rx_state <= RXCRCCHECK; rx_state <= RXCRCCHECK;
end if; end if;
when RXCRCCHECK => when RXCRCCHECK =>
@ -199,17 +200,17 @@ begin
ethmac_tx_inst : entity work.ethmac_tx ethmac_tx_inst : entity work.ethmac_tx
port map( port map(
clk_50 => clk_tx, clk_50 => clk_tx,
rst => rst, rst => rst,
tx_ready => open, tx_ready => open,
start_of_frame => tx_sof, start_of_frame => tx_sof,
end_of_frame => tx_eof, end_of_frame => tx_eof,
data_in => tx_data, data_in => tx_data,
data_ack => tx_ack, data_ack => tx_ack,
abort => '0', abort => '0',
rmii_tx => rmii_tx, rmii_tx => rmii_tx,
rmii_txen => rmii_txen rmii_txen => rmii_txen
); );
sender : process(clk_tx, rst_rxtx) is sender : process(clk_tx, rst_rxtx) is
variable dummycnt : integer range 0 to 511 := 0; variable dummycnt : integer range 0 to 511 := 0;
@ -217,26 +218,26 @@ begin
begin begin
if rst_rxtx = '1' then if rst_rxtx = '1' then
tx_state <= TXWAIT; tx_state <= TXWAIT;
tx_sof <= '0'; tx_sof <= '0';
tx_eof <= '0'; tx_eof <= '0';
tx_data <= x"00"; tx_data <= x"00";
dummycnt := 0; dummycnt := 0;
elsif rising_edge(clk_tx) then elsif rising_edge(clk_tx) then
case tx_state is case tx_state is
when TXWAIT => when TXWAIT =>
tx_sof <= '1'; tx_sof <= '1';
tx_state <= TXSEND; tx_state <= TXSEND;
tx_data <= "0000" & data_in; tx_data <= "0000" & data_in;
dummycnt := 0; dummycnt := 0;
when TXSEND => when TXSEND =>
if tx_ack = '1' then if tx_ack = '1' then
tx_sof <= '0'; tx_sof <= '0';
dummycnt := dummycnt + 1; dummycnt := dummycnt + 1;
if dummycnt = 500 then if dummycnt = 500 then
tx_eof <= '1'; tx_eof <= '1';
end if; end if;
if dummycnt = 501 then if dummycnt = 501 then
tx_eof <= '0'; tx_eof <= '0';
tx_state <= TXWAIT; tx_state <= TXWAIT;
end if; end if;
end if; end if;

View File

@ -2,7 +2,7 @@
-- Title : SMI (MDIO) -- Title : SMI (MDIO)
-- Project : EthMAC -- Project : EthMAC
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- File : design/smi.vhd -- File : design/smi.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net> -- Author : Mario Hüttel <mario.huettel@gmx.net>
-- Standard : VHDL'93/02 -- Standard : VHDL'93/02
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -18,7 +18,7 @@
-- --
-- This code is distributed in the hope that it will be useful, -- This code is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of -- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details. -- GNU General Public License for more details.
-- --
-- You should have received a copy of the GNU General Public License -- You should have received a copy of the GNU General Public License
@ -32,49 +32,49 @@ use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
-- Implementation of the SMI -- Implementation of the SMI
-- Only write Access implemented
-- I think i won't implement read access because.........IT'S FUCKING USELESS
entity smi is entity smi is
generic( generic(
clockdiv : integer := 64 clockdiv : integer := 64
); );
port( port(
clk_i : in std_logic; clk_i : in std_logic;
rst_i : in std_logic; rst_i : in std_logic;
mdio_io : inout std_logic; mdio_io : inout std_logic;
mdc_o : out std_logic; mdc_o : out std_logic;
busy_o : out std_logic; busy_o : out std_logic;
data_o : out std_logic_vector(15 downto 0); data_o : out std_logic_vector(15 downto 0);
phyaddr_i : std_logic_vector(4 downto 0); data_o_strb : out std_logic;
regaddr_i : std_logic_vector(4 downto 0); phyaddr_i : std_logic_vector(4 downto 0);
data_i : in std_logic_vector(15 downto 0); regaddr_i : std_logic_vector(4 downto 0);
strb_i : in std_logic; data_i : in std_logic_vector(15 downto 0);
rw_i : in std_logic --Read/write. 0=write, 1=read strb_i : in std_logic;
); rw_i : in std_logic --Read/write. 0=write, 1=read
);
end entity smi; end entity smi;
architecture RTL of smi is architecture RTL of smi is
type smistate_t is (IDLE, PRE, SOF, OPC, PHYADDR, REGADDR, TURN, DATA, CONCL); type smistate_t is (IDLE, PRE, SOF, OPC, PHYADDR, REGADDR, TURN, DATA, CONCL);
signal state_s : smistate_t; signal state_s : smistate_t;
signal fedge_strb_s : std_logic; signal fedge_strb_s : std_logic;
signal datashift_s : std_logic_vector(15 downto 0); signal datashift_s : std_logic_vector(15 downto 0);
signal regaddr_s : std_logic_vector(4 downto 0); signal regaddr_s : std_logic_vector(4 downto 0);
signal phyaddr_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 bitcounter_s : integer range 0 to 32;
signal mdc_o_s : std_logic; signal mdc_o_s : std_logic;
signal rw_latched : std_logic;
begin begin
mdc_o <= mdc_o_s; mdc_o <= mdc_o_s;
div : process(clk_i, rst_i) is div : process(clk_i, rst_i) is
variable counter : integer := 0; variable counter : integer := 0;
begin begin
if rst_i = '1' then if rst_i = '1' then
fedge_strb_s <= '0'; fedge_strb_s <= '0';
counter := 0; counter := 0;
mdc_o_s <= '0'; mdc_o_s <= '0';
elsif rising_edge(clk_i) then elsif rising_edge(clk_i) then
fedge_strb_s <= '0'; fedge_strb_s <= '0';
counter := counter + 1; counter := counter + 1;
if counter = clockdiv then if counter = clockdiv then
mdc_o_s <= not mdc_o_s; mdc_o_s <= not mdc_o_s;
counter := 0; counter := 0;
@ -88,39 +88,49 @@ begin
smishift : process(clk_i, rst_i) is smishift : process(clk_i, rst_i) is
begin begin
if rst_i = '1' then if rst_i = '1' then
mdio_io <= '1'; mdio_io <= '1';
state_s <= IDLE; state_s <= IDLE;
rw_latched <= '0';
busy_o <= '1'; phyaddr_s <= (others => '0');
regaddr_s <= (others => '0');
datashift_s <= (others => '0');
busy_o <= '1';
data_o_strb <= '0';
elsif rising_edge(clk_i) then elsif rising_edge(clk_i) then
busy_o <= '1'; busy_o <= '1';
data_o_strb <= '0';
if state_s = IDLE then if state_s = IDLE then
mdio_io <= '1'; mdio_io <= '1';
busy_o <= '0'; busy_o <= '0';
bitcounter_s <= 0; bitcounter_s <= 0;
if (strb_i = '1') then if (strb_i = '1') then
state_s <= PRE; state_s <= PRE;
busy_o <= '1'; busy_o <= '1';
--Load data --Load data
phyaddr_s <= phyaddr_i; phyaddr_s <= phyaddr_i;
regaddr_s <= regaddr_i; regaddr_s <= regaddr_i;
datashift_s <= data_i; datashift_s <= data_i;
rw_latched <= rw_i;
end if;
elsif state_s = CONCL then -- Wait for falling edge to
-- force output high after
-- read
if fedge_strb_s = '1' then
mdio_io <= '1';
busy_o <= '0';
state_s <= IDLE;
bitcounter_s <= 0;
end if; 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 elsif fedge_strb_s = '1' then
mdio_io <= '1'; mdio_io <= '1';
bitcounter_s <= bitcounter_s + 1; bitcounter_s <= bitcounter_s + 1;
case state_s is case state_s is
when PRE => when PRE =>
if fedge_strb_s = '1' then if fedge_strb_s = '1' then
--Mdio idle high for 32 cycles --Mdio idle high for 32 cycles
if (bitcounter_s = 31) then if (bitcounter_s = 31) then
bitcounter_s <= 0; bitcounter_s <= 0;
state_s <= SOF; state_s <= SOF;
end if; end if;
end if; end if;
when SOF => when SOF =>
@ -128,19 +138,19 @@ begin
mdio_io <= '0'; mdio_io <= '0';
elsif bitcounter_s = 1 then elsif bitcounter_s = 1 then
bitcounter_s <= 0; bitcounter_s <= 0;
--Mdio idle high --Mdio idle high
state_s <= OPC; state_s <= OPC;
end if; end if;
when OPC => --Write OPCODE when OPC => --Write OPCODE
if bitcounter_s = 0 then if bitcounter_s = 0 then
if rw_i = '1' then if rw_latched = '1' then
mdio_io <= '1'; mdio_io <= '1';
else else
mdio_io <= '0'; mdio_io <= '0';
end if; end if;
elsif bitcounter_s = 1 then elsif bitcounter_s = 1 then
bitcounter_s <= 0; bitcounter_s <= 0;
if rw_i = '1' then if rw_latched = '1' then
mdio_io <= '0'; mdio_io <= '0';
else else
mdio_io <= '1'; mdio_io <= '1';
@ -150,44 +160,46 @@ begin
when PHYADDR => when PHYADDR =>
if bitcounter_s = 4 then if bitcounter_s = 4 then
bitcounter_s <= 0; bitcounter_s <= 0;
state_s <= REGADDR; state_s <= REGADDR;
end if; end if;
mdio_io <= phyaddr_s(4); mdio_io <= phyaddr_s(4);
phyaddr_s <= phyaddr_s(3 downto 0) & '0'; phyaddr_s <= phyaddr_s(3 downto 0) & '0';
when REGADDR => when REGADDR =>
if bitcounter_s = 4 then if bitcounter_s = 4 then
bitcounter_s <= 0; bitcounter_s <= 0;
state_s <= TURN; state_s <= TURN;
end if; end if;
mdio_io <= regaddr_s(4); mdio_io <= regaddr_s(4);
regaddr_s <= regaddr_s(3 downto 0) & '0'; regaddr_s <= regaddr_s(3 downto 0) & '0';
when TURN => when TURN => -- Turn MDIO to input
if rw_i = '1' then if rw_latched = '1' then
mdio_io <= 'Z'; mdio_io <= 'Z';
end if; end if;
if bitcounter_s = 1 then if bitcounter_s = 1 then
bitcounter_s <= 0; bitcounter_s <= 0;
state_s <= DATA; state_s <= DATA;
end if; end if;
when DATA => when DATA =>
if bitcounter_s = 15 then if bitcounter_s = 15 then
bitcounter_s <= 0; bitcounter_s <= 0;
state_s <= CONCL; state_s <= CONCL;
if rw_latched = '1' then
data_o_strb <= '1';
end if;
end if; end if;
if rw_i = '1' then if rw_latched = '1' then -- read data
mdio_io <= 'Z'; mdio_io <= 'Z';
--Not implemented => => datashift_s <= datashift_s(14 downto 0) & mdio_io;
else else -- write data
mdio_io <= datashift_s(15); mdio_io <= datashift_s(15);
datashift_s <= datashift_s(14 downto 0) & '0'; datashift_s <= datashift_s(14 downto 0) & '0';
end if; end if;
when others => when others =>
null; -- This should not happen null; -- This should not happen
end case; end case;
end if; end if;
end if; end if;
end process smishift; end process smishift;
data_o <= (others => '0');
end architecture RTL; end architecture RTL;