OpenCores
URL https://opencores.org/ocsvn/plasma/plasma/trunk

Subversion Repositories plasma

[/] [plasma/] [trunk/] [kernel/] [ethernet.c] - Blame information for rev 385

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 299 rhoads
/*--------------------------------------------------------------------
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 301 rhoads
#define COUNT_EMPTY 16           //Count to decide there isn't data
26 299 rhoads
#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 301 rhoads
static int gEmptyBefore;
38 299 rhoads
 
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 301 rhoads
   int countEmpty, countEmptyGoal, countOk, needWait;
53
   int packetExpected;
54 299 rhoads
 
55
   //Find the start of a frame
56
   countEmpty = 0;
57
   countOk = 0;
58
   needWait = 0;
59 301 rhoads
   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 299 rhoads
   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 301 rhoads
         if(++countEmpty >= countEmptyGoal)
111 299 rhoads
         {
112
            //Set skiped bytes to BYTE_EMPTY
113 301 rhoads
            //if(i - countEmpty > 3)
114 299 rhoads
            //{
115 301 rhoads
            //   printf("eb%d \n", i - countEmpty);
116 299 rhoads
            //   //dump((char*)buf+gIndex, 0x200);
117
            //}
118 301 rhoads
            for(j = 0; j <= i - countEmpty; ++j)
119 299 rhoads
            {
120
               buf[gIndex] = BYTE_EMPTY;
121
               gIndex = (gIndex + 1) & INDEX_MASK;
122
            }
123
            gCheckedBefore = 0;
124 301 rhoads
            if(countEmpty >= i && packetExpected)
125
               gEmptyBefore = 1;
126 299 rhoads
            return 0;
127
         }
128
      }
129
      else
130
      {
131
         if(countEmpty > 2 || (countEmpty > 0 && countEmpty == i))
132
            needWait = 1;
133
         countEmpty = 0;
134 301 rhoads
         gEmptyBefore = 0;
135 299 rhoads
      }
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 301 rhoads
      if(count >= 40)
152 299 rhoads
      {
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 368 rhoads
   Led(2, 2);
217 299 rhoads
   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 368 rhoads
   Led(2, 0);
247 299 rhoads
 
248
   OS_SemaphorePost(SemEthTransmit);
249
}
250
 
251
 
252
void EthernetThread(void *arg)
253
{
254
   int length;
255 375 rhoads
   int rc;
256 299 rhoads
   unsigned int ticks, ticksLast=0;
257 375 rhoads
   IPFrame *ethFrame=NULL;
258
   static int ethErrorCount=0;
259 299 rhoads
   (void)arg;
260
 
261
   for(;;)
262 375 rhoads
   {
263 299 rhoads
      OS_InterruptMaskSet(IRQ_ETHERNET_RECEIVE);
264 375 rhoads
      OS_SemaphorePend(SemEthernet, 50);  //wait for interrupt
265 299 rhoads
 
266
      //Process all received packets
267
      for(;;)
268
      {
269
         if(ethFrame == NULL)
270
            ethFrame = IPFrameGet(FRAME_COUNT_RCV);
271 375 rhoads
         if(ethFrame == NULL)
272
         {
273 323 rhoads
            OS_ThreadSleep(50);
274 375 rhoads
            break;
275 323 rhoads
         }
276 299 rhoads
         length = EthernetReceive(ethFrame->packet, PACKET_SIZE);
277 373 rhoads
         if(length == 0)
278 375 rhoads
         {
279
#if 1       //Disable this on quiet networks
280
            //No Ethernet packets seen for 60 seconds?
281
            if(++ethErrorCount >= 120)
282
            {
283
               printf("\nEthernetInit\n");
284
               ethErrorCount = 0;
285
               EthernetInit(NULL);  //Need to re-initialize
286
            }
287
#endif
288 373 rhoads
            break;
289 375 rhoads
         }
290
         ethErrorCount = 0;
291 368 rhoads
         Led(1, 1);
292 299 rhoads
         rc = IPProcessEthernetPacket(ethFrame, length);
293 368 rhoads
         Led(1, 0);
294 299 rhoads
         if(rc)
295
            ethFrame = NULL;
296
      }
297
 
298
      ticks = OS_ThreadTime();
299 373 rhoads
      if(ticks - ticksLast >= 50)
300 299 rhoads
      {
301
         IPTick();
302
         ticksLast = ticks;
303
      }
304
   }
305
}
306
 
307
 
308
void EthernetIsr(void *arg)
309
{
310 373 rhoads
   (void)arg;
311 299 rhoads
   OS_InterruptMaskClear(IRQ_ETHERNET_TRANSMIT | IRQ_ETHERNET_RECEIVE);
312 373 rhoads
   OS_SemaphorePost(SemEthernet);
313 299 rhoads
}
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 375 rhoads
   CrcInit();
380
   if(MacAddress)
381 299 rhoads
   {
382 375 rhoads
      for(i = 0; i < 6; ++i)
383
      {
384
         value = MacAddress[i];
385
         gDestMac[i+1] = (unsigned char)((value >> 4) | (value << 4));
386
      }
387 299 rhoads
   }
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 385 rhoads
   if(SemEthernet == NULL)
417
   {
418
      SemEthernet = OS_SemaphoreCreate("eth", 0);
419
      SemEthTransmit = OS_SemaphoreCreate("ethT", 1);
420
      OS_ThreadCreate("eth", EthernetThread, NULL, 240, 0);
421
   }
422 299 rhoads
 
423
   //Setup interrupts for receiving data
424 375 rhoads
   OS_InterruptRegister(IRQ_ETHERNET_RECEIVE, EthernetIsr);
425 385 rhoads
 
426
   //Start receive DMA
427
   MemoryWrite(GPIO0_OUT, ETHERNET_ENABLE);
428 299 rhoads
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.