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

Subversion Repositories plasma

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

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

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

powered by: WebSVN 2.1.0

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