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


von Rooney B. (rooney)


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?

von Ottmar (Gast)


Lesenswert?

Laut

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

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

von Rooney B. (rooney)


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.

von Rooney B. (rooney)


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.
1
for i in 0 to data'left loop
2
data(i) := data(data'left - i);
3
end loop;
4
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.

von PittyJ (Gast)


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.
1
library ieee;
2
use ieee.std_logic_1164.all;
3
4
entity crc is
5
  port (   
6
  Clock      : in std_logic;
7
  Reset      : in std_logic;
8
  DataIn       : in std_logic_vector (7 downto 0);
9
  CRCCalculationEnable    : in std_logic;
10
  CRCOut        : out std_logic_vector (31 downto 0);
11
  CRCOutInverted : out std_logic_vector (31 downto 0)
12
 );
13
end crc;
14
15
architecture imp_crc of crc is
16
17
signal lfsr_q: std_logic_vector (31 downto 0);
18
signal lfsr_c: std_logic_vector (31 downto 0);
19
20
begin
21
    CRCOut          <= lfsr_q;
22
23
   CRCOutInverted(31) <=  not(lfsr_q( 0)); -- bits swappen und invertieren
24
   CRCOutInverted(30) <=  not(lfsr_q( 1));
25
   CRCOutInverted(29) <=  not(lfsr_q( 2));
26
   CRCOutInverted(28) <=  not(lfsr_q( 3));
27
   CRCOutInverted(27) <=  not(lfsr_q( 4));
28
   CRCOutInverted(26) <=  not(lfsr_q( 5));
29
   CRCOutInverted(25) <=  not(lfsr_q( 6));
30
   CRCOutInverted(24) <=  not(lfsr_q( 7));
31
32
   CRCOutInverted(23) <=  not(lfsr_q( 8));
33
   CRCOutInverted(22) <=  not(lfsr_q( 9));
34
   CRCOutInverted(21) <=  not(lfsr_q(10));
35
   CRCOutInverted(20) <=  not(lfsr_q(11));
36
   CRCOutInverted(19) <=  not(lfsr_q(12));
37
   CRCOutInverted(18) <=  not(lfsr_q(13));
38
   CRCOutInverted(17) <=  not(lfsr_q(14));
39
   CRCOutInverted(16) <=  not(lfsr_q(15));
40
41
   CRCOutInverted(15) <=  not(lfsr_q(16));
42
   CRCOutInverted(14) <=  not(lfsr_q(17));
43
   CRCOutInverted(13) <=  not(lfsr_q(18));
44
   CRCOutInverted(12) <=  not(lfsr_q(19));
45
   CRCOutInverted(11) <=  not(lfsr_q(20));
46
   CRCOutInverted(10) <=  not(lfsr_q(21));
47
   CRCOutInverted( 9) <=  not(lfsr_q(22));
48
   CRCOutInverted( 8) <=  not(lfsr_q(23));
49
50
   CRCOutInverted( 7) <=  not(lfsr_q(24));
51
   CRCOutInverted( 6) <=  not(lfsr_q(25));
52
   CRCOutInverted( 5) <=  not(lfsr_q(26));
53
   CRCOutInverted( 4) <=  not(lfsr_q(27));
54
   CRCOutInverted( 3) <=  not(lfsr_q(28));
55
   CRCOutInverted( 2) <=  not(lfsr_q(29));
56
   CRCOutInverted( 1) <=  not(lfsr_q(30));
57
   CRCOutInverted( 0) <=  not(lfsr_q(31));
58
   
59
    lfsr_c(0)  <= lfsr_q(24) xor lfsr_q(30) xor DataIn(0) xor DataIn(6);
60
    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);
61
    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);
62
    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);
63
    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);
64
    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);
65
    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);
66
    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);
67
    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);
68
    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);
69
    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);
70
    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);
71
    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);
72
    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);
73
    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);
74
    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);
75
    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);
76
    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);
77
    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);
78
    lfsr_c(19) <= lfsr_q(11) xor lfsr_q(27) xor lfsr_q(31) xor DataIn(3) xor DataIn(7);
79
    lfsr_c(20) <= lfsr_q(12) xor lfsr_q(28) xor DataIn(4);
80
    lfsr_c(21) <= lfsr_q(13) xor lfsr_q(29) xor DataIn(5);
81
    lfsr_c(22) <= lfsr_q(14) xor lfsr_q(24) xor DataIn(0);
82
    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);
83
    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);
84
    lfsr_c(25) <= lfsr_q(17) xor lfsr_q(26) xor lfsr_q(27) xor DataIn(2) xor DataIn(3);
85
    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);
86
    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);
87
    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);
88
    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);
89
    lfsr_c(30) <= lfsr_q(22) xor lfsr_q(28) xor lfsr_q(31) xor DataIn(4) xor DataIn(7);
90
    lfsr_c(31) <= lfsr_q(23) xor lfsr_q(29) xor DataIn(5);
91
92
    process (Clock,Reset) begin
93
      if rising_edge(Clock) then
94
      if (Reset = '1') then
95
        lfsr_q <= (others => '1');
96
      elsif (CRCCalculationEnable = '1') then
97
        lfsr_q <= lfsr_c;
98
         end if;
99
      end if;
100
    end process;
101
   
102
end architecture imp_crc; 
103
104
Die Berechnung erfolgt nur von den Datenbytes, die vorangestellte Präambel X"55555555555555D5" wird nicht mitgenommen.
105
Mit in der Berechnung sind allerdings die Pad-Nullen, falls das Paket auf 64 Datenbytes erweitert werden muss.
106
107
Die Datenbytes müssen vertauscht an die CRC-Funktion gegeben werden. 0 <-> 7 
108
  CRC_Calculator: crc
109
  port map
110
  (
111
    Clock      =>  Clock_125MHz,
112
    Reset      => CRCReset,
113
    DataIn(0)    => FifoData(7),  -- databits swappen
114
    DataIn(1)    => FifoData(6),
115
    DataIn(2)    => FifoData(5),
116
    DataIn(3)    => FifoData(4),
117
    DataIn(4)    => FifoData(3),
118
    DataIn(5)    => FifoData(2),
119
    DataIn(6)    => FifoData(1),
120
    DataIn(7)    => FifoData(0),
121
    CRCCalculationEnable   => CRCEnable,
122
    CRCOut       => open,
123
    CRCOutInverted    => CRCResultInverted
124
  );
125
126
127
Nach dem Daten wird der CRC gesendet, allerdings auch der vertauschte 31 <-> 0 und invertierte.
128
Dabei wird LSB-First gesendet.
129
130
when SendDataLastByte => 
131
  -- begin with the first crc datafield
132
  CRCEnable       <= '0';
133
  OutByte            <= CRCResultInverted( 7 downto 0);
134
  SendBufferState     <= SendCRC0;
135
when SendCRC0 =>
136
  OutByte            <= CRCResultInverted( 15 downto 8);
137
  SendBufferState     <= SendCRC1;
138
when SendCRC1 =>
139
  OutByte            <= CRCResultInverted( 23 downto 16);
140
  SendBufferState     <= SendCRC2;
141
when SendCRC2 =>
142
  OutByte            <= CRCResultInverted( 31 downto 24);
143
  SendBufferState     <= SendCRC3;
144
when SendCRC3 =>
145
  OutByte            <= (others => '0');
146
  TXOut              <= '0';
147
  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.

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


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"

von Robert K. (Firma: Medizintechnik) (robident)


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?

von Dosmo (Gast)


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.

von Robert K. (Firma: Medizintechnik) (robident)


Lesenswert?

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

von AndyK (Gast)


Lesenswert?

PittyJ schrieb:
> 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.

Die Erklärung warum er die MAC-Adresse nicht extra invertieren muß ist, 
sein Schieberegister in der CRC Berechnung wird vor jedem neuen 
Ethernet-Frame mit 0xFFFF initialisiert, das invertiert die ersten 32 
Bit!

von Edi M. (Gast)


Lesenswert?

Weiß jemand, wozu das so gemacht wird?

von VHDL hotline (Gast)


Lesenswert?

Edi M. schrieb:
> Weiß jemand, wozu das so gemacht wird?

Du meinst das Invertieren? Um führende und angehängte Nullen abbilden zu 
können. Siehe hier

https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Variations

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.