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

Subversion Repositories mlite

[/] [mlite/] [trunk/] [kernel/] [ethernet.c] - Blame information for rev 299

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

powered by: WebSVN 2.1.0

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