1 /*--------------------------------------------------------------------
2 * TITLE: Plasma Ethernet MAC
3 * AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
4 * DATE CREATED: 1/12/08
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.
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 *--------------------------------------------------------------------*/
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
28 //void dump(const unsigned char *data, int length);
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 static int gEmptyBefore;
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)
47 int start, i, j, shift, offset;
51 volatile unsigned char *buf = (unsigned char*)ETHERNET_RECEIVE;
52 int countEmpty, countEmptyGoal, countOk, needWait;
55 //Find the start of a frame
59 countEmptyGoal = COUNT_EMPTY;
60 packetExpected = MemoryRead(IRQ_STATUS) & IRQ_ETHERNET_RECEIVE;
61 if(packetExpected && buf[gIndex] == BYTE_EMPTY && gEmptyBefore)
64 countEmptyGoal = 1500;
66 MemoryRead(ETHERNET_REG); //clear receive interrupt
67 for(i = 0; i < INDEX_MASK; ++i)
69 //Check if partial packet possibly received
70 if(needWait && gCheckedBefore == 0 && countOk != i && countEmpty != i)
73 //printf("W(%d,%d,%d)", i, countOk, countEmpty);
74 return 0; //Wait for more data
77 //Detect start of frame
78 byte = buf[(gIndex + i) & INDEX_MASK];
79 if(byte == gDestMac[countOk] || (countOk && byte == 0xff))
81 if(++countOk == sizeof(gDestMac))
83 //Set bytes before 0x5d to BYTE_EMPTY
84 offset = i - (int)sizeof(gDestMac);
86 // printf("es%d ", offset);
87 for(j = 0; j <= offset; ++j)
89 buf[gIndex] = BYTE_EMPTY;
90 gIndex = (gIndex + 1) & INDEX_MASK;
98 // printf("N%d ", countOk);
99 if(countOk == 3 && byte == BYTE_EMPTY)
107 //Check if remainder of buffer is empty
108 if(byte == BYTE_EMPTY)
110 if(++countEmpty >= countEmptyGoal)
112 //Set skiped bytes to BYTE_EMPTY
113 //if(i - countEmpty > 3)
115 // printf("eb%d \n", i - countEmpty);
116 // //dump((char*)buf+gIndex, 0x200);
118 for(j = 0; j <= i - countEmpty; ++j)
120 buf[gIndex] = BYTE_EMPTY;
121 gIndex = (gIndex + 1) & INDEX_MASK;
124 if(countEmpty >= i && packetExpected)
131 if(countEmpty > 2 || (countEmpty > 0 && countEmpty == i))
138 //Found start of frame. Now find end of frame and check CRC.
140 gIndex = (gIndex + 1) & INDEX_MASK; //skip 0x5d byte
142 for(count = 0; count < length; )
145 gIndex = (gIndex + 1) & INDEX_MASK;
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);
153 //Check if CRC matches to detect end of frame
154 byteCrc = reflectNibble[crc >> 24];
155 byteNext = buf[gIndex];
156 if(byteCrc == byteNext)
158 for(i = 1; i < 4; ++i)
160 shift = 24 - (i << 3);
161 byteCrc = reflectNibble[(crc >> shift) & 0xff];
162 byteNext = buf[(gIndex + i) & 0xffff];
163 if(byteCrc != byteNext)
165 //printf("nope %d %d 0x%x 0x%x\n", count, i, byteCrc, byteNext);
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;
178 buf[gIndex] = BYTE_EMPTY;
179 gIndex = (gIndex + 1) & INDEX_MASK;
190 //printf("CRC failure\n");
191 buf[gIndex] = BYTE_EMPTY;
194 return 0; //wait for more data
198 //Copy transmit data to 0x13fe0000 with preamble and CRC32
199 void EthernetTransmit(unsigned char *buffer, int length)
203 volatile unsigned char *buf = (unsigned char*)ETHERNET_TRANSMIT;
205 OS_SemaphorePend(SemEthTransmit, OS_WAIT_FOREVER);
207 //Wait for previous transfer to complete
208 for(i = 0; i < 10000; ++i)
210 if(MemoryRead(IRQ_STATUS) & IRQ_ETHERNET_TRANSMIT)
214 // printf("wait=%d ", i);
217 while(length < 60 || (length & 3) != 0)
218 buffer[length++] = 0;
220 //Start of Ethernet frame
221 for(i = 0; i < 7; ++i)
227 for(i = 0; i < length; ++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);
236 for(i = 0; i < 4; ++i)
238 shift = 24 - (i << 3);
239 byte = reflectNibble[(crc >> shift) & 0xff];
240 buf[length + 8 + i] = (unsigned char)byte;
244 length = (length + 12 + 4) >> 2;
245 MemoryWrite(ETHERNET_REG, length);
248 OS_SemaphorePost(SemEthTransmit);
252 void EthernetThread(void *arg)
256 unsigned int ticks, ticksLast=0;
257 IPFrame *ethFrame=NULL;
\r
258 static int ethErrorCount=0;
263 OS_InterruptMaskSet(IRQ_ETHERNET_RECEIVE);
264 OS_SemaphorePend(SemEthernet, 50); //wait for interrupt
\r
266 //Process all received packets
270 ethFrame = IPFrameGet(FRAME_COUNT_RCV);
271 if(ethFrame == NULL)
\r
276 length = EthernetReceive(ethFrame->packet, PACKET_SIZE);
279 #if 1 //Disable this on quiet networks
\r
280 //No Ethernet packets seen for 60 seconds?
\r
281 if(++ethErrorCount >= 120)
\r
283 printf("\nEthernetInit\n");
\r
285 EthernetInit(NULL); //Need to re-initialize
\r
292 rc = IPProcessEthernetPacket(ethFrame, length);
298 ticks = OS_ThreadTime();
299 if(ticks - ticksLast >= 50)
308 void EthernetIsr(void *arg)
311 OS_InterruptMaskClear(IRQ_ETHERNET_TRANSMIT | IRQ_ETHERNET_RECEIVE);
312 OS_SemaphorePost(SemEthernet);
\r
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)
324 for(i = 0; i < bits; ++i)
326 num = (num << 1) | (value & 1);
333 static void CrcInit(void)
335 unsigned int remainder;
336 int dividend, bit, i;
338 //Compute the remainder of each possible dividend
339 for(dividend = 0; dividend < 256; ++dividend)
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)
346 //Try to divide the current data bit
347 if(remainder & TOPBIT)
348 remainder = (remainder << 1) ^ POLYNOMIAL;
350 remainder = remainder << 1;
352 CrcTable[dividend] = remainder;
354 for(i = 0; i < 256; ++i)
356 reflect[i] = (unsigned char)Reflect(i, 8);
357 reflectNibble[i] = (unsigned char)((Reflect((i >> 4) ^ 0xf, 4) << 4) |
358 Reflect(i ^ 0xf, 4));
363 static void SpinWait(int clocks)
365 int value = *(volatile int*)COUNTER_REG + clocks;
366 while(*(volatile int*)COUNTER_REG - value < 0)
371 void EthernetInit(unsigned char MacAddress[6])
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
377 volatile unsigned char *buf = (unsigned char*)ETHERNET_RECEIVE;
382 for(i = 0; i < 6; ++i)
384 value = MacAddress[i];
385 gDestMac[i+1] = (unsigned char)((value >> 4) | (value << 4));
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)
393 MemoryWrite(GPIO0_OUT, ETHERENT_MDC); //clock high
395 MemoryWrite(GPIO0_CLEAR, ETHERENT_MDC); //clock low
398 for(i = 31; i >= 0; --i)
400 value = (data >> i) & 1;
402 MemoryWrite(GPIO0_OUT, ETHERNET_MDIO);
404 MemoryWrite(GPIO0_CLEAR, ETHERNET_MDIO);
405 MemoryWrite(GPIO0_OUT, ETHERENT_MDC); //clock high
407 MemoryWrite(GPIO0_CLEAR, ETHERENT_MDC); //clock low
410 MemoryWrite(GPIO0_CLEAR, ETHERNET_MDIO_WE | ETHERNET_ENABLE);
412 //Clear receive buffer
413 for(i = 0; i <= INDEX_MASK; ++i)
416 if(SemEthernet == NULL)
\r
418 SemEthernet = OS_SemaphoreCreate("eth", 0);
419 SemEthTransmit = OS_SemaphoreCreate("ethT", 1);
420 OS_ThreadCreate("eth", EthernetThread, NULL, 240, 0);
423 //Setup interrupts for receiving data
424 OS_InterruptRegister(IRQ_ETHERNET_RECEIVE, EthernetIsr);
\r
427 MemoryWrite(GPIO0_OUT, ETHERNET_ENABLE);