10BaseT-TX

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA Project allows an FPGA to send UDP packets without any additional hardware - just wire two pins a short UDP cable and plug into a switch!

Although it is based on http://www.fpga4fun.com/10BASE-T.html, I would like to think mine is better - the state machine is more explicit and the data to be sent is separated from the transmission logic.

It is a tricky project to test, as everything has to be just right for data to be received. It is also a good way to annoy a network admin with all sorts of 'physical' errors (like bad CRCs, framing errors, jabber...)

Source

Oh, I should mention that Clk must be 20MHz, and your cable short!

Phy.vhd

----------------------------------------------------------------------------------
-- Phy - transmit data out over 10baseT ethernet.
--
-- Written by Mike Field (hamster@snap.net.nz)
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Phy is
    Port ( Clk : in  STD_LOGIC;
           txp : out STD_LOGIC;
           txm : out STD_LOGIC);
end Phy;

architecture Behavioral of Phy is
   TYPE state IS (st_idle, st_nlp, st_preamble, st_startofframe, st_data, st_crc, st_trailer, st_interframe );
   SIGNAL output       : state;   
   SIGNAL counter    : STD_LOGIC_VECTOR(23 downto 0) := x"FFFFFD";
   SIGNAL endOfData  : STD_LOGIC := '0';
   SIGNAL data       : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL shiftReg    : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL CRC         : STD_LOGIC_VECTOR(31 downto 0);
   COMPONENT PacketData
   PORT(
      Addr           : IN  STD_LOGIC_VECTOR ( 7 downto 0);          
      IPsource       : in  STD_LOGIC_VECTOR (31 downto 0);
      IPdestination  : in  STD_LOGIC_VECTOR (31 downto 0);
      PhySource      : in  STD_LOGIC_VECTOR (47 downto 0);
      PhyDestination : in  STD_LOGIC_VECTOR (47 downto 0);
      Data           : OUT STD_LOGIC_VECTOR ( 7 downto 0);
      EndOfData      : OUT STD_LOGIC
      );
   END COMPONENT;
begin
   Inst_PacketData: PacketData PORT MAP(
      Addr => counter(11 downto 4),
      IPsource       => x"99633C99",
      IPdestination  => x"99633C63",
      PhySource      => x"001234567890",
      PhyDestination => x"C80AA9657F9A",
      Data => Data,
      endOfData => endOfData
   );
   
   process (clk)
   begin
      --- Set the output signals (txp and txm)
      if clk'event and Clk='1' then
         if output = st_preamble  then
            txp <=     counter(1) xor counter(0);
            txm <= not counter(1) xor counter(0);
         elsif output = st_startofframe  then
            txp <=     counter(0);
            txm <= not counter(0);
         elsif output = st_data  then
            txp <= not shiftReg(0) xor counter(0);
            txm <=     shiftReg(0) xor counter(0);
         elsif output = st_crc then
            -- push out the CRC onto the data lines         
            txp <=     CRC(31) xor counter(0);
            txm <= not CRC(31) xor counter(0);
         elsif output = st_trailer then
            txp <= '1';
            txm <= '0';
         elsif output = st_interframe then
            txm <= '1';
            txp <= '1';
         elsif output = st_nlp then
            txp <= '1';
            txm <= '0';
         else -- output = st_idle
            txp <= '1';
            txm <= '1';
         end if;
         
         --- Process the state
         counter <= counter+1; -- always increment, unless overridden later by state change
         
         if output = st_preamble  then
            if counter(6 downto 0) = "1111101" then
               output <= st_startofframe;
               counter <= x"000000";
            end if;
         elsif output = st_startofframe  then
            if counter(0) = '1' then
               -- This state is only two bits long. 
               -- reset the CRC to inital value
               -- load the shift register and change state
               -- Counter is offset by 16 cycles (one byte on the air), so that 
               -- state st_data loads the second byte when this one is sent (as
               -- the address used is counter(11 downto 4))
               crc <= x"FFFFFFFF";
               counter <= x"000010";
               output <= st_data;
               shiftReg <= data;
            end if;
            
         elsif output = st_data  then
            -- set the data lines, and update the CRC
            if counter(0) = '1' then 
               if (shiftReg(0) = crc(31)) then
                  crc <= crc(30 downto 0) & '0';
               else
                  crc <= (crc(30 downto 0)& '0') xor x"04C11DB7";
               end if;
            end if;
                        
            -- Are we at the end of the byte and need to load a new one into the shifter?
            if counter(3 downto 0) = "1111" then
               if endOfData = '1' then 
                  output <= st_crc;
                  counter <= x"000000";
               else
                  shiftReg <= data;
               end if;
            elsif counter(0) = '1' then
                        -- Move the shift register along during the second half of a bit time
               shiftReg <= "0" & shiftReg(7 downto 1);
            end if;

         elsif output = st_crc then
            -- shift the as it is sent onto the data lines         
            if counter(0) = '1' then
               crc <= CRC(30 downto 0) & "0";
            end if;
            
            -- Have we pushed out all the CRC bits?
            if counter(5 downto 0) = "111111" then
               output <= st_trailer;
               counter <= x"000000";
            end if;   
         elsif output = st_trailer then
            -- send out three one bits (not manchester encoded)
            if counter(2 downto 1) = "11" then
               output <= st_interframe;
               counter <= x"000000";
            end if;
         elsif output = st_interframe then
            -- interframe gap of 8 bytes = 64 bits = 128 clock cycles
            if counter(7 downto 0) = "1111111" then
               output <= st_idle;
               counter <= x"000000";
            end if;
         elsif output = st_nlp then
            output <= st_idle;
         else  -- output = st_idle
            if counter = x"FFFFFF" then
               output  <= st_preamble;
               counter <= x"000000";
            elsif counter(17 downto 0) = "11" & x"FFFF" then
               output <= st_nlp;
            end if;
         end if;
      end if;
   end process;
end Behavioral;

Packet.vhd

----------------------------------------------------------------------------------
-- PacketData - the data to be sent out over the LAN
--
-- Written by Mike Field (hamster@snap.net.nz)
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity PacketData is
    Port ( Addr           : in  STD_LOGIC_VECTOR (7 downto 0);
           IPsource       : in  STD_LOGIC_VECTOR (31 downto 0);
           IPdestination  : in  STD_LOGIC_VECTOR (31 downto 0);
           PhyDestination : in  STD_LOGIC_VECTOR (47 downto 0);
           PhySource      : in  STD_LOGIC_VECTOR (47 downto 0);
           Data           : out STD_LOGIC_VECTOR (7 downto 0);
           EndOfData      : out STD_LOGIC);
end PacketData;

architecture Behavioral of PacketData is

   -- "Physical Address" - put the address of the PC you want to send to
   SIGNAL PhyDestination_1 : STD_LOGIC_VECTOR(7 downto 0);   
   SIGNAL PhyDestination_2 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL PhyDestination_3 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL PhyDestination_4 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL PhyDestination_5 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL PhyDestination_6 : STD_LOGIC_VECTOR(7 downto 0);

   -- "Physical Address" - put the address of the PC you want to send to
   SIGNAL PhySource_1 : STD_LOGIC_VECTOR(7 downto 0);   
   SIGNAL PhySource_2 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL PhySource_3 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL PhySource_4 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL PhySource_5 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL PhySource_6 : STD_LOGIC_VECTOR(7 downto 0);

   --"IP source" - put an unused IP - if unsure, see comment below after the source code
   SIGNAL IPsource_1 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL IPsource_2 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL IPsource_3 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL IPsource_4 : STD_LOGIC_VECTOR(7 downto 0);

   SIGNAL IPdestination_1 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL IPdestination_2 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL IPdestination_3 : STD_LOGIC_VECTOR(7 downto 0);
   SIGNAL IPdestination_4 : STD_LOGIC_VECTOR(7 downto 0);

   SIGNAL IPchecksum1 : STD_LOGIC_VECTOR(31 downto 0);
   SIGNAL IPchecksum2 : STD_LOGIC_VECTOR(31 downto 0);
   SIGNAL IPchecksum3 : STD_LOGIC_VECTOR(31 downto 0); 

begin
   IPsource_1 <= IPsource(31 downto 24);
   IPsource_2 <= IPsource(23 downto 16);
   IPsource_3 <= IPsource(15 downto 8);
   IPsource_4 <= IPsource( 7 downto 0);

   PhyDestination_1 <= PhyDestination(47 downto 40);
   PhyDestination_2 <= PhyDestination(39 downto 32);
   PhyDestination_3 <= PhyDestination(31 downto 24);
   PhyDestination_4 <= PhyDestination(23 downto 16);
   PhyDestination_5 <= PhyDestination(15 downto  8);
   PhyDestination_6 <= PhyDestination( 7 downto  0);

   PhySource_1 <= PhySource(47 downto 40);
   PhySource_2 <= PhySource(39 downto 32);
   PhySource_3 <= PhySource(31 downto 24);
   PhySource_4 <= PhySource(23 downto 16);
   PhySource_5 <= PhySource(15 downto  8);
   PhySource_6 <= PhySource( 7 downto  0);

   IPdestination_1 <= IPdestination(31 downto 24);
   IPdestination_2 <= IPdestination(23 downto 16);
   IPdestination_3 <= IPdestination(15 downto 8);
   IPdestination_4 <= IPdestination( 7 downto 0);

   IPchecksum1 <= x"0000C53F" 
       + (IPsource_1 & x"00") + IPsource_2
       + (IPsource_3 & x"00") + IPsource_4
       + (IPdestination_1 & x"00") + IPdestination_2  
       + (IPdestination_3 & x"00") + IPdestination_4;

   IPchecksum2 <=      (x"0000" & IPchecksum1(31 downto 16)) + (x"0000" & IPchecksum1(15 downto 0));   
   IPchecksum3 <= NOT ((x"0000" & IPchecksum2(31 downto 16)) + (x"0000" & IPchecksum2(15 downto 0)));


   process (addr)
   begin
      endOfData <= '0';
      case addr is
         --a Ethernet header
         when x"00" => data <= PhyDestination_1;
         when x"01" => data <= PhyDestination_2;
         when x"02" => data <= PhyDestination_3;
         when x"03" => data <= PhyDestination_4;
         when x"04" => data <= PhyDestination_5;
         when x"05" => data <= PhyDestination_6;   
         when x"06" => data <= PhySource_1;
         when x"07" => data <= PhySource_2;
         when x"08" => data <= PhySource_3;
         when x"09" => data <= PhySource_4;
         when x"0A" => data <= PhySource_5;
         when x"0B" => data <= PhySource_6;
         
         --a IP header
         when x"0C" => data <= x"08";
         when x"0D" => data <= x"00";
         when x"0E" => data <= x"45";
         when x"0F" => data <= x"00";
         when x"10" => data <= x"00";
         when x"11" => data <= x"2E";
         when x"12" => data <= x"00";
         when x"13" => data <= x"00";
         when x"14" => data <= x"00";
         when x"15" => data <= x"00";
         when x"16" => data <= x"80";
         when x"17" => data <= x"11";
         when x"18" => data <= IPchecksum3(15 downto 8);
         when x"19" => data <= IPchecksum3(7 downto 0);
         when x"1A" => data <= IPsource_1;
         when x"1B" => data <= IPsource_2;
         when x"1C" => data <= IPsource_3;
         when x"1D" => data <= IPsource_4;
         when x"1E" => data <= IPdestination_1;
         when x"1F" => data <= IPdestination_2;
         when x"20" => data <= IPdestination_3;
         when x"21" => data <= IPdestination_4;
         --a UDP header
         when x"22" => data <= x"04";
         when x"23" => data <= x"00";
         when x"24" => data <= x"04";
         when x"25" => data <= x"00";
         when x"26" => data <= x"00";
         when x"27" => data <= x"1A";
         when x"28" => data <= x"00";
         when x"29" => data <= x"00";
         
         --   a payload
         when x"2A" => data <= x"00"; --a put here the data that you want to send
         when x"2B" => data <= x"01"; --a put here the data that you want to send
         when x"2C" => data <= x"02"; --a put here the data that you want to send
         when x"2D" => data <= x"03"; --a put here the data that you want to send
         when x"2E" => data <= x"04"; --a put here the data that you want to send
         when x"2F" => data <= x"05"; --a put here the data that you want to send
         when x"30" => data <= x"06"; --a put here the data that you want to send
         when x"31" => data <= x"07"; --a put here the data that you want to send
         when x"32" => data <= x"08"; --a put here the data that you want to send
         when x"33" => data <= x"09"; --a put here the data that you want to send
         when x"34" => data <= x"0A"; --a put here the data that you want to send
         when x"35" => data <= x"0B"; --a put here the data that you want to send
         when x"36" => data <= x"0C"; --a put here the data that you want to send
         when x"37" => data <= x"0D"; --a put here the data that you want to send
         when x"38" => data <= x"0E"; --a put here the data that you want to send
         when x"39" => data <= x"0F"; --a put here the data that you want to send
         when x"3A" => data <= x"10"; --a put here the data that you want to send
         when x"3B" => data <= x"11"; --a put here the data that you want to send
         when others => data <= x"00";
                        endOfData <= '1';
      end case;
   end process;
end Behavioral;


Personal tools