]> rtime.felk.cvut.cz Git - fpga/plasma.git/blob - kernel/ethernet.c
Local copy of Plasma MIPS project.
[fpga/plasma.git] / kernel / ethernet.c
1 /*--------------------------------------------------------------------
2  * TITLE: Plasma Ethernet MAC
3  * AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
4  * DATE CREATED: 1/12/08
5  * FILENAME: ethernet.c
6  * PROJECT: Plasma CPU core
7  * COPYRIGHT: Software placed into the public domain by the author.
8  *    Software 'as is' without warranty.  Author liable for nothing.
9  * DESCRIPTION:
10  *    Ethernet MAC implementation.
11  *    Data is received from the Ethernet PHY four bits at a time. 
12  *    After 32-bits are received they are written to 0x13ff0000 + N.  
13  *    The data is received LSB first for each byte which requires the
14  *    nibbles to be swapped.
15  *    Transmit data is read from 0x13fe0000.  Write length/4+1 to
16  *    ETHERNET_REG to start transfer.
17  *--------------------------------------------------------------------*/
18 #include "plasma.h"
19 #include "rtos.h"
20 #include "tcpip.h"
21
22 #define POLYNOMIAL  0x04C11DB7   //CRC bit 33 is truncated
23 #define TOPBIT      (1<<31)
24 #define BYTE_EMPTY  0xde         //Data copied into receive buffer
25 #define COUNT_EMPTY 16           //Count to decide there isn't data
26 #define INDEX_MASK  0xffff       //Size of receive buffer
27
28 //void dump(const unsigned char *data, int length);
29
30 static unsigned char gDestMac[]={0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
31 static unsigned int CrcTable[256];
32 static unsigned char reflect[256];
33 static unsigned char reflectNibble[256];
34 static OS_Semaphore_t *SemEthernet, *SemEthTransmit;
35 static int gIndex;          //byte index into 0x13ff0000 receive buffer
36 static int gCheckedBefore;
37 static int gEmptyBefore;
38
39
40 //Read received data from 0x13ff0000.  Data starts with 0x5d+MACaddress.
41 //Data is being received while processing the data.  Therefore,
42 //all errors require waiting and then re-processing the data
43 //to see if the error is fixed by receiving the rest of the packet.
44 int EthernetReceive(unsigned char *buffer, int length)
45 {
46    int count;
47    int start, i, j, shift, offset;
48    int byte, byteNext;
49    unsigned long crc;
50    int byteCrc;
51    volatile unsigned char *buf = (unsigned char*)ETHERNET_RECEIVE;
52    int countEmpty, countEmptyGoal, countOk, needWait;
53    int packetExpected;
54
55    //Find the start of a frame
56    countEmpty = 0;
57    countOk = 0;
58    needWait = 0;
59    countEmptyGoal = COUNT_EMPTY;
60    packetExpected = MemoryRead(IRQ_STATUS) & IRQ_ETHERNET_RECEIVE;
61    if(packetExpected && buf[gIndex] == BYTE_EMPTY && gEmptyBefore)
62    {
63       //printf("Check ");
64       countEmptyGoal = 1500;
65    }
66    MemoryRead(ETHERNET_REG);        //clear receive interrupt
67    for(i = 0; i < INDEX_MASK; ++i)
68    {
69       //Check if partial packet possibly received
70       if(needWait && gCheckedBefore == 0 && countOk != i && countEmpty != i)
71       {
72          gCheckedBefore = 1;
73          //printf("W(%d,%d,%d)", i, countOk, countEmpty);
74          return 0;                  //Wait for more data
75       }
76
77       //Detect start of frame
78       byte = buf[(gIndex + i) & INDEX_MASK];
79       if(byte == gDestMac[countOk] || (countOk && byte == 0xff))
80       {
81          if(++countOk == sizeof(gDestMac))
82          {
83             //Set bytes before 0x5d to BYTE_EMPTY
84             offset = i - (int)sizeof(gDestMac);
85             //if(offset > 3)
86             //   printf("es%d ", offset);
87             for(j = 0; j <= offset; ++j)
88             {
89                buf[gIndex] = BYTE_EMPTY;
90                gIndex = (gIndex + 1) & INDEX_MASK;
91             }
92             break;
93          }
94       }
95       else
96       {
97          //if(countOk)
98          //   printf("N%d ", countOk);
99          if(countOk == 3 && byte == BYTE_EMPTY)
100             needWait = 1;
101          if(byte == 0x5d)
102             countOk = 1;
103          else
104             countOk = 0;
105       }
106
107       //Check if remainder of buffer is empty
108       if(byte == BYTE_EMPTY)
109       {
110          if(++countEmpty >= countEmptyGoal)
111          {
112             //Set skiped bytes to BYTE_EMPTY
113             //if(i - countEmpty > 3)
114             //{
115             //   printf("eb%d \n", i - countEmpty);
116             //   //dump((char*)buf+gIndex, 0x200);
117             //}
118             for(j = 0; j <= i - countEmpty; ++j)
119             {
120                buf[gIndex] = BYTE_EMPTY;
121                gIndex = (gIndex + 1) & INDEX_MASK;
122             }
123             gCheckedBefore = 0;
124             if(countEmpty >= i && packetExpected)
125                gEmptyBefore = 1;
126             return 0;
127          }
128       }
129       else
130       {
131          if(countEmpty > 2 || (countEmpty > 0 && countEmpty == i))
132             needWait = 1;
133          countEmpty = 0;
134          gEmptyBefore = 0;
135       }
136    }
137
138    //Found start of frame.  Now find end of frame and check CRC.
139    start = gIndex;
140    gIndex = (gIndex + 1) & INDEX_MASK;           //skip 0x5d byte
141    crc = 0xffffffff;
142    for(count = 0; count < length; )
143    {
144       byte = buf[gIndex];
145       gIndex = (gIndex + 1) & INDEX_MASK;
146
147       byte = ((byte << 4) & 0xf0) | (byte >> 4); //swap nibbles
148       buffer[count++] = (unsigned char)byte;
149       byte = reflect[byte] ^ (crc >> 24);        //calculate CRC32
150       crc = CrcTable[byte] ^ (crc << 8);
151       if(count >= 40)
152       {
153          //Check if CRC matches to detect end of frame
154          byteCrc = reflectNibble[crc >> 24];
155          byteNext = buf[gIndex];
156          if(byteCrc == byteNext)
157          {
158             for(i = 1; i < 4; ++i)
159             {
160                shift = 24 - (i << 3);
161                byteCrc = reflectNibble[(crc >> shift) & 0xff];
162                byteNext = buf[(gIndex + i) & 0xffff];
163                if(byteCrc != byteNext)
164                {
165                   //printf("nope %d %d 0x%x 0x%x\n", count, i, byteCrc, byteNext);
166                   i = 99;
167                }
168             }
169             if(i == 4)
170             {
171                //Found end of frame -- set used bytes to BYTE_EMPTY
172                //printf("Found it! %d\n", count);
173                gIndex = (gIndex + 4) & INDEX_MASK;
174                for(i = 0; i < count+5; ++i)
175                   buf[(start + i) & INDEX_MASK] = BYTE_EMPTY;
176                while(gIndex & 3)
177                {
178                   buf[gIndex] = BYTE_EMPTY;
179                   gIndex = (gIndex + 1) & INDEX_MASK;
180                }
181                gCheckedBefore = 0;
182                return count;
183             }
184          }
185       }
186    }
187    gIndex = start;
188    if(gCheckedBefore)
189    {
190       //printf("CRC failure\n");
191       buf[gIndex] = BYTE_EMPTY;
192    }
193    gCheckedBefore = 1;
194    return 0;        //wait for more data
195 }
196
197
198 //Copy transmit data to 0x13fe0000 with preamble and CRC32
199 void EthernetTransmit(unsigned char *buffer, int length)
200 {
201    int i, byte, shift;
202    unsigned long crc;
203    volatile unsigned char *buf = (unsigned char*)ETHERNET_TRANSMIT;
204
205    OS_SemaphorePend(SemEthTransmit, OS_WAIT_FOREVER);
206
207    //Wait for previous transfer to complete
208    for(i = 0; i < 10000; ++i)
209    {
210       if(MemoryRead(IRQ_STATUS) & IRQ_ETHERNET_TRANSMIT)
211          break;
212    }
213    //if(i > 100)
214    //   printf("wait=%d ", i);
215
216    Led(2, 2);
217    while(length < 60 || (length & 3) != 0)
218       buffer[length++] = 0;
219
220    //Start of Ethernet frame
221    for(i = 0; i < 7; ++i)
222       buf[i] = 0x55;
223    buf[7] = 0x5d;
224
225    //Calculate CRC32
226    crc = 0xffffffff;
227    for(i = 0; i < length; ++i)
228    {
229       byte = buffer[i];
230       buf[i + 8] = (unsigned char)((byte << 4) | (byte >> 4)); //swap nibbles
231       byte = reflect[byte] ^ (crc >> 24);        //calculate CRC32
232       crc = CrcTable[byte] ^ (crc << 8);
233    }
234
235    //Output CRC32
236    for(i = 0; i < 4; ++i)
237    {
238       shift = 24 - (i << 3);
239       byte = reflectNibble[(crc >> shift) & 0xff];
240       buf[length + 8 + i] = (unsigned char)byte;
241    }
242
243    //Start transfer
244    length = (length + 12 + 4) >> 2;
245    MemoryWrite(ETHERNET_REG, length);
246    Led(2, 0);
247
248    OS_SemaphorePost(SemEthTransmit);
249 }
250
251
252 void EthernetThread(void *arg)
253 {
254    int length;
255    int rc;\r
256    unsigned int ticks, ticksLast=0;
257    IPFrame *ethFrame=NULL;\r
258    static int ethErrorCount=0;
259    (void)arg;
260
261    for(;;)
262    {\r
263       OS_InterruptMaskSet(IRQ_ETHERNET_RECEIVE);
264       OS_SemaphorePend(SemEthernet, 50);  //wait for interrupt\r
265
266       //Process all received packets
267       for(;;)
268       {
269          if(ethFrame == NULL)
270             ethFrame = IPFrameGet(FRAME_COUNT_RCV);
271          if(ethFrame == NULL)\r
272          {\r
273             OS_ThreadSleep(50);
274             break;\r
275          }
276          length = EthernetReceive(ethFrame->packet, PACKET_SIZE);
277          if(length == 0)\r
278          {\r
279 #if 1       //Disable this on quiet networks\r
280             //No Ethernet packets seen for 60 seconds?\r
281             if(++ethErrorCount >= 120)\r
282             {\r
283                printf("\nEthernetInit\n");\r
284                ethErrorCount = 0;\r
285                EthernetInit(NULL);  //Need to re-initialize\r
286             }\r
287 #endif\r
288             break;\r
289          }\r
290          ethErrorCount = 0;\r
291          Led(1, 1);
292          rc = IPProcessEthernetPacket(ethFrame, length);
293          Led(1, 0);
294          if(rc)
295             ethFrame = NULL;
296       }
297
298       ticks = OS_ThreadTime();
299       if(ticks - ticksLast >= 50)
300       {
301          IPTick();
302          ticksLast = ticks;
303       }
304    }
305 }
306
307
308 void EthernetIsr(void *arg)
309 {
310    (void)arg;\r
311    OS_InterruptMaskClear(IRQ_ETHERNET_TRANSMIT | IRQ_ETHERNET_RECEIVE);
312    OS_SemaphorePost(SemEthernet);\r
313 }
314
315
316 /******************* CRC32 calculations **********************
317  * The CRC32 code is modified from Michale Barr's article in 
318  * Embedded Systems Programming January 2000.
319  * A CRC is really modulo-2 binary division.  Substraction means XOR. */
320 static unsigned int Reflect(unsigned int value, int bits)
321 {
322    unsigned int num=0;
323    int i;
324    for(i = 0; i < bits; ++i)
325    {
326       num = (num << 1) | (value & 1);
327       value >>= 1;
328    }
329    return num;
330 }
331
332
333 static void CrcInit(void)
334 {
335    unsigned int remainder;
336    int dividend, bit, i;
337
338    //Compute the remainder of each possible dividend
339    for(dividend = 0; dividend < 256; ++dividend)
340    {
341       //Start with the dividend followed by zeros
342       remainder = dividend << 24;
343       //Perform modulo-2 division, a bit at a time
344       for(bit = 8; bit > 0; --bit)
345       {
346          //Try to divide the current data bit
347          if(remainder & TOPBIT)
348             remainder = (remainder << 1) ^ POLYNOMIAL;
349          else
350             remainder = remainder << 1;
351       }
352       CrcTable[dividend] = remainder;
353    }
354    for(i = 0; i < 256; ++i)
355    {
356       reflect[i] = (unsigned char)Reflect(i, 8);
357       reflectNibble[i] = (unsigned char)((Reflect((i >> 4) ^ 0xf, 4) << 4) | 
358          Reflect(i ^ 0xf, 4));
359    }
360 }
361
362
363 static void SpinWait(int clocks)
364 {
365    int value = *(volatile int*)COUNTER_REG + clocks;
366    while(*(volatile int*)COUNTER_REG - value < 0)
367       ;
368 }
369
370
371 void EthernetInit(unsigned char MacAddress[6])
372 {
373    //Format of SMI data: 0101 A4:A0 R4:R0 00 D15:D0
374    unsigned long data=0x5f800100; //SMI R0 = 10Mbps full duplex
375    //unsigned long data=0x5f800000; //SMI R0 = 10Mbps half duplex
376    int i, value;
377    volatile unsigned char *buf = (unsigned char*)ETHERNET_RECEIVE;
378
379    CrcInit();\r
380    if(MacAddress)\r
381    {
382       for(i = 0; i < 6; ++i)
383       {
384          value = MacAddress[i];
385          gDestMac[i+1] = (unsigned char)((value >> 4) | (value << 4));
386       }\r
387    }
388
389    //Configure Ethernet PHY for 10Mbps full duplex via SMI interface
390    MemoryWrite(GPIO0_OUT, ETHERNET_MDIO | ETHERNET_MDIO_WE | ETHERENT_MDC);
391    for(i = 0; i < 34; ++i)
392    {
393       MemoryWrite(GPIO0_OUT, ETHERENT_MDC);    //clock high
394       SpinWait(10);
395       MemoryWrite(GPIO0_CLEAR, ETHERENT_MDC);  //clock low
396       SpinWait(10);
397    }
398    for(i = 31; i >= 0; --i)
399    {
400       value = (data >> i) & 1;
401       if(value)
402          MemoryWrite(GPIO0_OUT, ETHERNET_MDIO);
403       else
404          MemoryWrite(GPIO0_CLEAR, ETHERNET_MDIO);
405       MemoryWrite(GPIO0_OUT, ETHERENT_MDC);    //clock high
406       SpinWait(10);
407       MemoryWrite(GPIO0_CLEAR, ETHERENT_MDC);  //clock low
408       SpinWait(10);
409    }
410    MemoryWrite(GPIO0_CLEAR, ETHERNET_MDIO_WE | ETHERNET_ENABLE);
411
412    //Clear receive buffer
413    for(i = 0; i <= INDEX_MASK; ++i)
414       buf[i] = BYTE_EMPTY;
415
416    if(SemEthernet == NULL)\r
417    {\r
418       SemEthernet = OS_SemaphoreCreate("eth", 0);
419       SemEthTransmit = OS_SemaphoreCreate("ethT", 1);
420       OS_ThreadCreate("eth", EthernetThread, NULL, 240, 0);
421    }
422
423    //Setup interrupts for receiving data
424    OS_InterruptRegister(IRQ_ETHERNET_RECEIVE, EthernetIsr);\r
425
426    //Start receive DMA
427    MemoryWrite(GPIO0_OUT, ETHERNET_ENABLE);
428 }