Root/plasma/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
30static unsigned char gDestMac[]={0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
31static unsigned int CrcTable[256];
32static unsigned char reflect[256];
33static unsigned char reflectNibble[256];
34static OS_Semaphore_t *SemEthernet, *SemEthTransmit;
35static int gIndex; //byte index into 0x13ff0000 receive buffer
36static int gCheckedBefore;
37static 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.
44int 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
199void 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
252void EthernetThread(void *arg)
253{
254   int length;
255   int rc;
256   unsigned int ticks, ticksLast=0;
257   IPFrame *ethFrame=NULL;
258   (void)arg;
259
260   for(;;)
261   {
262      OS_InterruptMaskSet(IRQ_ETHERNET_RECEIVE);
263      OS_SemaphorePend(SemEthernet, 50); //wait for interrupt
264
265      //Process all received packets
266      for(;;)
267      {
268         if(ethFrame == NULL)
269            ethFrame = IPFrameGet(FRAME_COUNT_RCV);
270         if(ethFrame == NULL)
271         {
272            OS_ThreadSleep(50);
273            break;
274         }
275         length = EthernetReceive(ethFrame->packet, PACKET_SIZE);
276         if(length == 0)
277            break;
278         Led(1, 1);
279         rc = IPProcessEthernetPacket(ethFrame, length);
280         Led(1, 0);
281         if(rc)
282            ethFrame = NULL;
283      }
284
285      ticks = OS_ThreadTime();
286      if(ticks - ticksLast > 50)
287      {
288         IPTick();
289         ticksLast = ticks;
290      }
291   }
292}
293
294
295void EthernetIsr(void *arg)
296{
297   (void)arg;
298   OS_InterruptMaskClear(IRQ_ETHERNET_TRANSMIT | IRQ_ETHERNET_RECEIVE);
299   OS_SemaphorePost(SemEthernet);
300}
301
302
303/******************* CRC32 calculations **********************
304 * The CRC32 code is modified from Michale Barr's article in
305 * Embedded Systems Programming January 2000.
306 * A CRC is really modulo-2 binary division. Substraction means XOR. */
307static unsigned int Reflect(unsigned int value, int bits)
308{
309   unsigned int num=0;
310   int i;
311   for(i = 0; i < bits; ++i)
312   {
313      num = (num << 1) | (value & 1);
314      value >>= 1;
315   }
316   return num;
317}
318
319
320static void CrcInit(void)
321{
322   unsigned int remainder;
323   int dividend, bit, i;
324
325   //Compute the remainder of each possible dividend
326   for(dividend = 0; dividend < 256; ++dividend)
327   {
328      //Start with the dividend followed by zeros
329      remainder = dividend << 24;
330      //Perform modulo-2 division, a bit at a time
331      for(bit = 8; bit > 0; --bit)
332      {
333         //Try to divide the current data bit
334         if(remainder & TOPBIT)
335            remainder = (remainder << 1) ^ POLYNOMIAL;
336         else
337            remainder = remainder << 1;
338      }
339      CrcTable[dividend] = remainder;
340   }
341   for(i = 0; i < 256; ++i)
342   {
343      reflect[i] = (unsigned char)Reflect(i, 8);
344      reflectNibble[i] = (unsigned char)((Reflect((i >> 4) ^ 0xf, 4) << 4) |
345         Reflect(i ^ 0xf, 4));
346   }
347}
348
349
350static void SpinWait(int clocks)
351{
352   int value = *(volatile int*)COUNTER_REG + clocks;
353   while(*(volatile int*)COUNTER_REG - value < 0)
354      ;
355}
356
357
358void EthernetInit(unsigned char MacAddress[6])
359{
360   //Format of SMI data: 0101 A4:A0 R4:R0 00 D15:D0
361   unsigned long data=0x5f800100; //SMI R0 = 10Mbps full duplex
362   //unsigned long data=0x5f800000; //SMI R0 = 10Mbps half duplex
363   int i, value;
364   volatile unsigned char *buf = (unsigned char*)ETHERNET_RECEIVE;
365
366   CrcInit();
367   for(i = 0; i < 6; ++i)
368   {
369      value = MacAddress[i];
370      gDestMac[i+1] = (unsigned char)((value >> 4) | (value << 4));
371   }
372
373   //Configure Ethernet PHY for 10Mbps full duplex via SMI interface
374   MemoryWrite(GPIO0_OUT, ETHERNET_MDIO | ETHERNET_MDIO_WE | ETHERENT_MDC);
375   for(i = 0; i < 34; ++i)
376   {
377      MemoryWrite(GPIO0_OUT, ETHERENT_MDC); //clock high
378      SpinWait(10);
379      MemoryWrite(GPIO0_CLEAR, ETHERENT_MDC); //clock low
380      SpinWait(10);
381   }
382   for(i = 31; i >= 0; --i)
383   {
384      value = (data >> i) & 1;
385      if(value)
386         MemoryWrite(GPIO0_OUT, ETHERNET_MDIO);
387      else
388         MemoryWrite(GPIO0_CLEAR, ETHERNET_MDIO);
389      MemoryWrite(GPIO0_OUT, ETHERENT_MDC); //clock high
390      SpinWait(10);
391      MemoryWrite(GPIO0_CLEAR, ETHERENT_MDC); //clock low
392      SpinWait(10);
393   }
394   MemoryWrite(GPIO0_CLEAR, ETHERNET_MDIO_WE | ETHERNET_ENABLE);
395
396   //Clear receive buffer
397   for(i = 0; i <= INDEX_MASK; ++i)
398      buf[i] = BYTE_EMPTY;
399
400   //Start receive DMA
401   MemoryWrite(GPIO0_OUT, ETHERNET_ENABLE);
402
403   //Setup interrupts for receiving data
404   SemEthernet = OS_SemaphoreCreate("eth", 0);
405   SemEthTransmit = OS_SemaphoreCreate("ethT", 1);
406   OS_ThreadCreate("eth", EthernetThread, NULL, 240, 0);
407   OS_InterruptRegister(IRQ_ETHERNET_RECEIVE, EthernetIsr);
408}
409

Archive Download this file

Branches:
master



interactive