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

Subversion Repositories plasma

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

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

powered by: WebSVN 2.1.0

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