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?
Laut http://de.wikipedia.org/wiki/Ethernet wird bei der CRC Prüfsumme jedes byte reverse übertragen.
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.
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.
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.
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"
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?
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.
Wenn der CRC aber doch für Ethernet ausglegt war, sollte es doch von vorn herin gestimmt haben, oder?
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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.