www.mikrocontroller.net

Forum: FPGA, VHDL & Co. CRC Berechnung für Ethernet


Autor: Rooney Bob (rooney)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi!

Ich möchte zwei FPGA Boards über einen Switch miteinander verbinden. 
Damit die Daten im Switch nicht verworfen werden, schick ich einen 
Ethernet Frame im Format 802.3 inkl. FCS.

Blöderweise versuch ich schon seit Tagen eine korrekte CRC zu berechnen, 
aber es will einfach nicht funktionieren.

Ich hab mir mit dem Tool auf http://www.easics.com/webtools/crctool eine 
CRC als VHDL Funktion generieren lassen, aber die CRC stimmt einfach 
nicht.

Jetzt habe ich schon versucht die Bits umzudrehen, bevor ich die Daten 
der CRC Funktion übergebe. Ich habe versucht die ersten 32 Bit des 
Frames zu invertieren und ich habe versucht die Bits des Low und High 
Nibbles zu verdrehen.

Leider hat das absolut nichts gebracht.

Hat von euch schon jemand ähnliche Probleme gehabt und diese gelöst?

Autor: Ottmar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Laut

http://de.wikipedia.org/wiki/Ethernet

wird bei der CRC Prüfsumme jedes byte reverse übertragen.

Autor: Rooney Bob (rooney)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, das hätte ich ja eigentlich schon ausprobiert, aber ohne Erfolg.

An anderer Stelle habe ich gelesen, dass die ersten 32 Bit invertiert 
gehören... war aber auch nicht hilfreich.

Setzt ihr mit euren VHDL Designs auf einem höheren Level an? Kaum zu 
glauben, dass man im Netz nichts brauchbares findet.

Autor: Rooney Bob (rooney)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Nachdem ich jetzt haufenweise Kombination ausprobiert habe und das 
Ergebnis mit einem Packet Sniffer überprüft habe, weiß ich wie man die 
CRC richtig berechnet.

Hier eine kurze Einführung, falls jemand einmal vor selbigem Problem 
stehen sollte...


1. CRC Modul mit http://www.easics.com/webtools/crctool generieren.
2. Bevor die Daten an das CRC Modul übergeben werden (in meinem Fall 
über den Funktionsaufruf nextCRC32_D8), müssen die Bits vertauscht 
werden.
Übergeben werden Daten von Target MAC bis letztes Byte der Payload, MSB 
zuerst.
Die ersten 32Bit der Target MAC müssen invertiert werden.
for i in 0 to data'left loop
data(i) := data(data'left - i);
end loop;
crc <=nextCRC32_D8(data, crc);  

3. Am Ende der Payload muss der komplette CRC Wert invertiert werden und 
die Bits anschließend wieder vertauscht werden.

4. Die CRC wird mit dem LSB Byte zuerst an das Ende des Frames gestellt.

Autor: PittyJ (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachdem ich auch mehrere Tage am CRC gesessen habe, hier die Schritte, 
wie es bei mit geklappt hat.

Die CRC Funktion habe ich mir bei OutputLogic.com generieren lassen. 
Allerdings habe ich sie erweitert, so dass sie auch gleich das Inverse 
berechnet, weil das später benutzt wird.
library ieee;
use ieee.std_logic_1164.all;

entity crc is
  port (   
  Clock      : in std_logic;
  Reset      : in std_logic;
  DataIn       : in std_logic_vector (7 downto 0);
  CRCCalculationEnable    : in std_logic;
  CRCOut        : out std_logic_vector (31 downto 0);
  CRCOutInverted : out std_logic_vector (31 downto 0)
 );
end crc;

architecture imp_crc of crc is

signal lfsr_q: std_logic_vector (31 downto 0);
signal lfsr_c: std_logic_vector (31 downto 0);

begin
    CRCOut          <= lfsr_q;

   CRCOutInverted(31) <=  not(lfsr_q( 0)); -- bits swappen und invertieren
   CRCOutInverted(30) <=  not(lfsr_q( 1));
   CRCOutInverted(29) <=  not(lfsr_q( 2));
   CRCOutInverted(28) <=  not(lfsr_q( 3));
   CRCOutInverted(27) <=  not(lfsr_q( 4));
   CRCOutInverted(26) <=  not(lfsr_q( 5));
   CRCOutInverted(25) <=  not(lfsr_q( 6));
   CRCOutInverted(24) <=  not(lfsr_q( 7));

   CRCOutInverted(23) <=  not(lfsr_q( 8));
   CRCOutInverted(22) <=  not(lfsr_q( 9));
   CRCOutInverted(21) <=  not(lfsr_q(10));
   CRCOutInverted(20) <=  not(lfsr_q(11));
   CRCOutInverted(19) <=  not(lfsr_q(12));
   CRCOutInverted(18) <=  not(lfsr_q(13));
   CRCOutInverted(17) <=  not(lfsr_q(14));
   CRCOutInverted(16) <=  not(lfsr_q(15));

   CRCOutInverted(15) <=  not(lfsr_q(16));
   CRCOutInverted(14) <=  not(lfsr_q(17));
   CRCOutInverted(13) <=  not(lfsr_q(18));
   CRCOutInverted(12) <=  not(lfsr_q(19));
   CRCOutInverted(11) <=  not(lfsr_q(20));
   CRCOutInverted(10) <=  not(lfsr_q(21));
   CRCOutInverted( 9) <=  not(lfsr_q(22));
   CRCOutInverted( 8) <=  not(lfsr_q(23));

   CRCOutInverted( 7) <=  not(lfsr_q(24));
   CRCOutInverted( 6) <=  not(lfsr_q(25));
   CRCOutInverted( 5) <=  not(lfsr_q(26));
   CRCOutInverted( 4) <=  not(lfsr_q(27));
   CRCOutInverted( 3) <=  not(lfsr_q(28));
   CRCOutInverted( 2) <=  not(lfsr_q(29));
   CRCOutInverted( 1) <=  not(lfsr_q(30));
   CRCOutInverted( 0) <=  not(lfsr_q(31));
   
    lfsr_c(0)  <= lfsr_q(24) xor lfsr_q(30) xor DataIn(0) xor DataIn(6);
    lfsr_c(1)  <= lfsr_q(24) xor lfsr_q(25) xor lfsr_q(30) xor lfsr_q(31) xor DataIn(0) xor DataIn(1) xor DataIn(6) xor DataIn(7);
    lfsr_c(2)  <= lfsr_q(24) xor lfsr_q(25) xor lfsr_q(26) xor lfsr_q(30) xor lfsr_q(31) xor DataIn(0) xor DataIn(1) xor DataIn(2) xor DataIn(6) xor DataIn(7);
    lfsr_c(3)  <= lfsr_q(25) xor lfsr_q(26) xor lfsr_q(27) xor lfsr_q(31) xor DataIn(1) xor DataIn(2) xor DataIn(3) xor DataIn(7);
    lfsr_c(4)  <= lfsr_q(24) xor lfsr_q(26) xor lfsr_q(27) xor lfsr_q(28) xor lfsr_q(30) xor DataIn(0) xor DataIn(2) xor DataIn(3) xor DataIn(4) xor DataIn(6);
    lfsr_c(5)  <= lfsr_q(24) xor lfsr_q(25) xor lfsr_q(27) xor lfsr_q(28) xor lfsr_q(29) xor lfsr_q(30) xor lfsr_q(31) xor DataIn(0) xor DataIn(1) xor DataIn(3) xor DataIn(4) xor DataIn(5) xor DataIn(6) xor DataIn(7);
    lfsr_c(6)  <= lfsr_q(25) xor lfsr_q(26) xor lfsr_q(28) xor lfsr_q(29) xor lfsr_q(30) xor lfsr_q(31) xor DataIn(1) xor DataIn(2) xor DataIn(4) xor DataIn(5) xor DataIn(6) xor DataIn(7);
    lfsr_c(7)  <= lfsr_q(24) xor lfsr_q(26) xor lfsr_q(27) xor lfsr_q(29) xor lfsr_q(31) xor DataIn(0) xor DataIn(2) xor DataIn(3) xor DataIn(5) xor DataIn(7);
    lfsr_c(8)  <= lfsr_q(0) xor lfsr_q(24) xor lfsr_q(25) xor lfsr_q(27) xor lfsr_q(28) xor DataIn(0) xor DataIn(1) xor DataIn(3) xor DataIn(4);
    lfsr_c(9)  <= lfsr_q(1) xor lfsr_q(25) xor lfsr_q(26) xor lfsr_q(28) xor lfsr_q(29) xor DataIn(1) xor DataIn(2) xor DataIn(4) xor DataIn(5);
    lfsr_c(10) <= lfsr_q(2) xor lfsr_q(24) xor lfsr_q(26) xor lfsr_q(27) xor lfsr_q(29) xor DataIn(0) xor DataIn(2) xor DataIn(3) xor DataIn(5);
    lfsr_c(11) <= lfsr_q(3) xor lfsr_q(24) xor lfsr_q(25) xor lfsr_q(27) xor lfsr_q(28) xor DataIn(0) xor DataIn(1) xor DataIn(3) xor DataIn(4);
    lfsr_c(12) <= lfsr_q(4) xor lfsr_q(24) xor lfsr_q(25) xor lfsr_q(26) xor lfsr_q(28) xor lfsr_q(29) xor lfsr_q(30) xor DataIn(0) xor DataIn(1) xor DataIn(2) xor DataIn(4) xor DataIn(5) xor DataIn(6);
    lfsr_c(13) <= lfsr_q(5) xor lfsr_q(25) xor lfsr_q(26) xor lfsr_q(27) xor lfsr_q(29) xor lfsr_q(30) xor lfsr_q(31) xor DataIn(1) xor DataIn(2) xor DataIn(3) xor DataIn(5) xor DataIn(6) xor DataIn(7);
    lfsr_c(14) <= lfsr_q(6) xor lfsr_q(26) xor lfsr_q(27) xor lfsr_q(28) xor lfsr_q(30) xor lfsr_q(31) xor DataIn(2) xor DataIn(3) xor DataIn(4) xor DataIn(6) xor DataIn(7);
    lfsr_c(15) <= lfsr_q(7) xor lfsr_q(27) xor lfsr_q(28) xor lfsr_q(29) xor lfsr_q(31) xor DataIn(3) xor DataIn(4) xor DataIn(5) xor DataIn(7);
    lfsr_c(16) <= lfsr_q(8) xor lfsr_q(24) xor lfsr_q(28) xor lfsr_q(29) xor DataIn(0) xor DataIn(4) xor DataIn(5);
    lfsr_c(17) <= lfsr_q(9) xor lfsr_q(25) xor lfsr_q(29) xor lfsr_q(30) xor DataIn(1) xor DataIn(5) xor DataIn(6);
    lfsr_c(18) <= lfsr_q(10) xor lfsr_q(26) xor lfsr_q(30) xor lfsr_q(31) xor DataIn(2) xor DataIn(6) xor DataIn(7);
    lfsr_c(19) <= lfsr_q(11) xor lfsr_q(27) xor lfsr_q(31) xor DataIn(3) xor DataIn(7);
    lfsr_c(20) <= lfsr_q(12) xor lfsr_q(28) xor DataIn(4);
    lfsr_c(21) <= lfsr_q(13) xor lfsr_q(29) xor DataIn(5);
    lfsr_c(22) <= lfsr_q(14) xor lfsr_q(24) xor DataIn(0);
    lfsr_c(23) <= lfsr_q(15) xor lfsr_q(24) xor lfsr_q(25) xor lfsr_q(30) xor DataIn(0) xor DataIn(1) xor DataIn(6);
    lfsr_c(24) <= lfsr_q(16) xor lfsr_q(25) xor lfsr_q(26) xor lfsr_q(31) xor DataIn(1) xor DataIn(2) xor DataIn(7);
    lfsr_c(25) <= lfsr_q(17) xor lfsr_q(26) xor lfsr_q(27) xor DataIn(2) xor DataIn(3);
    lfsr_c(26) <= lfsr_q(18) xor lfsr_q(24) xor lfsr_q(27) xor lfsr_q(28) xor lfsr_q(30) xor DataIn(0) xor DataIn(3) xor DataIn(4) xor DataIn(6);
    lfsr_c(27) <= lfsr_q(19) xor lfsr_q(25) xor lfsr_q(28) xor lfsr_q(29) xor lfsr_q(31) xor DataIn(1) xor DataIn(4) xor DataIn(5) xor DataIn(7);
    lfsr_c(28) <= lfsr_q(20) xor lfsr_q(26) xor lfsr_q(29) xor lfsr_q(30) xor DataIn(2) xor DataIn(5) xor DataIn(6);
    lfsr_c(29) <= lfsr_q(21) xor lfsr_q(27) xor lfsr_q(30) xor lfsr_q(31) xor DataIn(3) xor DataIn(6) xor DataIn(7);
    lfsr_c(30) <= lfsr_q(22) xor lfsr_q(28) xor lfsr_q(31) xor DataIn(4) xor DataIn(7);
    lfsr_c(31) <= lfsr_q(23) xor lfsr_q(29) xor DataIn(5);

    process (Clock,Reset) begin
      if rising_edge(Clock) then
      if (Reset = '1') then
        lfsr_q <= (others => '1');
      elsif (CRCCalculationEnable = '1') then
        lfsr_q <= lfsr_c;
         end if;
      end if;
    end process;
   
end architecture imp_crc; 

Die Berechnung erfolgt nur von den Datenbytes, die vorangestellte Präambel X"55555555555555D5" wird nicht mitgenommen.
Mit in der Berechnung sind allerdings die Pad-Nullen, falls das Paket auf 64 Datenbytes erweitert werden muss.

Die Datenbytes müssen vertauscht an die CRC-Funktion gegeben werden. 0 <-> 7 
  CRC_Calculator: crc
  port map
  (
    Clock      =>  Clock_125MHz,
    Reset      => CRCReset,
    DataIn(0)    => FifoData(7),  -- databits swappen
    DataIn(1)    => FifoData(6),
    DataIn(2)    => FifoData(5),
    DataIn(3)    => FifoData(4),
    DataIn(4)    => FifoData(3),
    DataIn(5)    => FifoData(2),
    DataIn(6)    => FifoData(1),
    DataIn(7)    => FifoData(0),
    CRCCalculationEnable   => CRCEnable,
    CRCOut       => open,
    CRCOutInverted    => CRCResultInverted
  );


Nach dem Daten wird der CRC gesendet, allerdings auch der vertauschte 31 <-> 0 und invertierte.
Dabei wird LSB-First gesendet.

when SendDataLastByte => 
  -- begin with the first crc datafield
  CRCEnable       <= '0';
  OutByte            <= CRCResultInverted( 7 downto 0);
  SendBufferState     <= SendCRC0;
when SendCRC0 =>
  OutByte            <= CRCResultInverted( 15 downto 8);
  SendBufferState     <= SendCRC1;
when SendCRC1 =>
  OutByte            <= CRCResultInverted( 23 downto 16);
  SendBufferState     <= SendCRC2;
when SendCRC2 =>
  OutByte            <= CRCResultInverted( 31 downto 24);
  SendBufferState     <= SendCRC3;
when SendCRC3 =>
  OutByte            <= (others => '0');
  TXOut              <= '0';
  SendBufferState     <= Idle;

Es gibt noch den Hinweis, dass die ersten 32 Bit der MAC-Adresse 
invertiert werden müssen.
Das hat bei mir damit nicht geklappt. Ich habe sie normal in den CRC 
geschoben.

Vielleicht hilft das ja jemanden.
Ich kann jedenfalls damit die Pakete über RGMII und einen Marvel 88E1111 
verschicken.
Entwickelt wurde alles auf einem DE2-115 Board mit einem Cyclone 4.

Autor: René D. (Firma: www.dossmatik.de) (dose)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier wurde die CRC schon mal gelöst. Der Code des Anfangspostings hat 
noch ein paar kleine Fehler die im Thread gelöst werden. Es ist eine 
GMII Interface, der CRC ist der Gleiche.


Beitrag "Ethernet GMII"

Autor: Robert Kuhn (Firma: Medizintechnik) (robident)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verständnisfrage dazu: Warum müssen die Bits gedreht werden, wie 
beschrieben steht? Inwiefern gehen Ethernet-Implementierung und CRC-Tool 
da von verdrehten Bits aus?

Autor: Dosmo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert K. schrieb:
> Verständnisfrage dazu: Warum müssen die Bits gedreht werden, wie
> beschrieben steht?

Beim Ethernet kommt das LSB zuerst (im Gegensatz zu z.B. I2C).
D.h. das Byte 0x12 (b00010010) kommt als Datenstrom "01001000" rein. 
Daher muß man swappen.

Autor: Robert Kuhn (Firma: Medizintechnik) (robident)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn der CRC aber doch für Ethernet ausglegt war, sollte es doch von 
vorn herin gestimmt haben, oder?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.