📄 ethernet.c
字号:
#include <reg167.h>
#include <CS8900.h>
#include <string.h>
#include <intrins.h>
/* hw & ip addresses */
#define ETH_ALEN 6
#define IP_LEN 4
BYTE own_hw_addr[ETH_ALEN] = { 00, 0x00, 0x00, 0x12, 0x34, 0x56 };
BYTE own_ip_addr[IP_LEN] = { 192, 168, 100, 210 };
/* extract the low or high byte out of a word16 */
#define HIGHBYTE(w) ((BYTE)(w>>8))
#define LOWBYTE(w) ((BYTE)(w&0x00ff))
// 48 bit IEEE OUI (Organizationally Unique Identifier)
#define MAC1 0x00
#define MAC2 0x00
#define MAC3 0x00
#define MAC4 0x12
#define MAC5 0x34
#define MAC6 0x56
BOOL CheckIOInterface(void) {
WORD pic, rev, iobadr;
// check product identification code and revision number
Ether.IO.PPP = cProductIdentificationCode | cAutoIncrement;
pic = Ether.IO.PPD;
rev = Ether.IO.PPD;
if (pic != 0x630E) return(FALSE); // chip not accessible
//if (rev != 0x0900) return(FALSE); // chip version may vary
Ether.IO.PPP = cIOBaseAddress;
iobadr = Ether.IO.PPD;
if (iobadr != 0x0300) return (FALSE); // must be 0x0300
// switch on the LINK LED
//Ether.IO.PPP = cSelfCTL;
//Ether.IO.PPD |= 0x5000;
return(TRUE);
}
BOOL EnableMemInterface(void) {
//DWORD volatile pic;
WORD volatile v1, v2;
Ether.IO.PPP = cMemBaseAddress | cAutoIncrement;
v1 = Ether.IO.PPP; // load low word of address
Ether.IO.PPD = 0x0000; // load low word of address
Ether.IO.PPD = 0x0000; // load high word of address
v1 = Ether.IO.PPP; // load low word of address
Ether.IO.PPP = cMemBaseAddress | cAutoIncrement;
v1 = Ether.IO.PPD; // load low word of address
v2 = Ether.IO.PPD; // load high word of address
Ether.IO.PPP = cBusCTL; // Select Bus Contol Register Reg17
Ether.IO.PPD |= 0x0400; // Set MemoryE Bit
Ether.IO.PPP = cMemBaseAddress | cAutoIncrement;
v1 = Ether.IO.PPD; // load low word of address
v2 = Ether.IO.PPD; // load high word of address
//if ((pic & 0x0000ffff) != 0x0000630E) // Read Product Ident Code (chip version may vary)
// return (FALSE);
return (TRUE); // Return successful
}
BOOL ResetChip(void) {
WORD i, rev, pic;
Ether.IO.PPP = cSelfCTL;
Ether.IO.PPD = SELF_CTL_RESET; //issue a reset to the chip
i = 0;
while(Ether.IO.PPD & SELF_CTL_RESET) i++; // wait until reset done
i = 0;
Ether.IO.PPP = cSelfST;
while(!(Ether.IO.PPD & SELF_ST_INIT_DONE)) i++; // wait until INITD bit set
Ether.IO.PPP = cProductIdentificationCode | cAutoIncrement;
pic = Ether.IO.PPD;
rev = Ether.IO.PPD;
if (pic != 0x630E) return(FALSE); // chip not accessible
//if (rev != 0x0900) return(FALSE); // chip version may vary
return(TRUE);
}
// Initializes the chip
BOOL InitChip(void) {
Ether.LineCTL = LINE_CTL_10BASET; // set to 10BaseT
Ether.TestCTL = TEST_CTL_FDX; // set to full duplex
Ether.RxCFG = RX_CFG_RX_OK_IE; // enable RxOK interrupt
Ether.RxCTL = (RX_CTL_RX_OK_A | RX_CTL_IND_A | RX_CTL_BCAST_A | RX_CTL_RUNT_A | RX_CTL_PROM_A);
Ether.TxCFG = TX_CFG_ALL_IE;
// Important: The IA needs to be byte reversed IA=aa:bb:cc:dd:ee:ff
Ether.IndividualAddress[0] = MAC1;
Ether.IndividualAddress[1] = MAC2;
Ether.IndividualAddress[2] = MAC3;
Ether.IndividualAddress[3] = MAC4;
Ether.IndividualAddress[4] = MAC5;
Ether.IndividualAddress[5] = MAC6;
Ether.InterruptNumber = 0x00; //INT is on INTRQ0
Ether.BusCTL |= BUS_CTL_INT_ENBL; // enable interrupt
Ether.LineCTL |= LINE_CTL_RX_ON | LINE_CTL_TX_ON; // set SerRxOn and SerTxOn
return(TRUE);
}
void error(void) {
while(1);
}
typedef union mac_a {
BYTE b[6];
WORD w[3];
} MAC_A;
typedef union ip_a {
BYTE b[4];
WORD w[2];
DWORD d;
} IP_A;
typedef struct ethernet_header {
MAC_A Dest;
MAC_A Sender;
WORD Protocol;
WORD Data[1]; // 46 - 1500 bytes of data
} ETHERNET_HEADER;
typedef struct arp_header {
WORD HardwAdrSpace; // usually 0x0001
WORD ProtocolAdrSpace; // usually 0x0800
BYTE HwLen; // usually 6 (MAC address len)
BYTE ProtLen; // usually 4 (IP addresws len)
WORD Opcode; // 1 request / 2 reply
MAC_A SenderHwAdr;
IP_A SenderProtAdr;
MAC_A DestHwAdr;
IP_A DestProtAdr;
} ARP_HEADER;
void SendARPReply(ARP_HEADER huge *pARP) {
ETHERNET_HEADER huge *pETH;
ARP_HEADER huge *pARPDest;
Ether.TxCMD2 = 0x00C9; /* start xmit after entire frame is in CS8900 */
Ether.TxLength = 42;
/* wait until ready for xmit */
while ((Ether.BusST & BUS_ST_RDY4TXNOW) == 0);
pETH = (ETHERNET_HEADER huge *)&Ether.TransmitFrameLocation[0];
/* copy the 6 byte dest hardware address */
xmemcpy(&pETH->Dest, &pARP->SenderHwAdr, ETH_ALEN);
/* copy the 6 byte source hardware address */
xmemcpy(&pETH->Sender, &own_hw_addr[0], ETH_ALEN);
/* copy the protocol 2 bytes, network order */
pETH->Protocol = 0x0608;
pARPDest = (ARP_HEADER huge *)pETH->Data;
pARPDest->HardwAdrSpace = 0x0100;
pARPDest->ProtocolAdrSpace = 0x0008;
pARPDest->HwLen = 0x0006;
pARPDest->ProtLen = 0x0004;
pARPDest->Opcode = 0x0200; //reply
xmemcpy(&pARPDest->SenderHwAdr, &own_hw_addr[0], ETH_ALEN);
xmemcpy(&pARPDest->SenderProtAdr, &own_ip_addr[0], IP_LEN);
xmemcpy(&pARPDest->DestHwAdr, &pARP->SenderHwAdr, ETH_ALEN);
xmemcpy(&pARPDest->DestProtAdr, &pARP->SenderProtAdr,IP_LEN);
}
void ProceedARP(ARP_HEADER huge *pARP) {
// check if ARP header is correct
if (pARP->HardwAdrSpace != 0x0100) return;
if (pARP->ProtocolAdrSpace != 0x0008) return;
if (pARP->HwLen != 0x0006) return;
if (pARP->ProtLen != 0x0004) return;
switch (pARP->Opcode) {
case 0x0100: //ToDo enter addresses into ARP table // ARP request
if (xmemcmp(own_ip_addr, &pARP->DestProtAdr, IP_LEN)) return; // is it me?
SendARPReply(pARP);
break;
case 0x0200: //ToDo enter addresses into ARP table // ARP reply
break;
default: // Ignore all other commands
break;
}
}
void AnalyzeEthernetHeader(ETHERNET_HEADER huge *pETH) {
switch (pETH->Protocol) { // Protocol in revers byte order
case 0x0008: // IP
break;
case 0x0608: ProceedARP((ARP_HEADER huge *)pETH->Data); // ARP
break;
case 0x3580: // RARP
break;
default: // Ignore all other protocols
break;
}
}
void EtherInt(void) interrupt 0x1F {
WORD IRQSource;
while ((IRQSource = Ether.ISQ) != 0) /* Read Interrupt Service Queue */
{
switch(IRQSource & 0x003F) {
case 0x04: // Receive Interrupt occured
// IRQSource contains the RxEvent Register contents
AnalyzeEthernetHeader((ETHERNET_HEADER huge *)&Ether.ReceiveFrameLocation[0]);
break;
case 0x08: // Transmit Interrupt occured
// IRQSource contains the TxEvent Register contents
break;
case 0x0C: // Buffer Interrupt occured
// IRQSource contains the BufEvent Register contents
break;
case 0x10: // Receive Buffer Miss Interrupt occured
// IRQSource contains the RxMISS Register contents
break;
case 0x12: // Transmit Collision Counter Interrupt occured
// IRQSource contains the TxCOLL Register contents
break;
default:
// This should never occur
break;
}
}
}
/******************************************************************************/
/*************************** MAIN PROGRAM ***************************/
/******************************************************************************/
void main ( void ) { /* main entry for program */
BYTE test_pkt[] = {"Hello, World\0"};
if (CheckIOInterface() == FALSE) error();
if (ResetChip() == FALSE) error();
if (EnableMemInterface() == FALSE) error();
if (InitChip() == FALSE) error();
P2 |= 0x8000; // Initialize external interrupt for ethernet controller
DP2 &= 0x7FFF;
CCM3 = 0x1000;
CC15IC = 0x44; // IE = 1, ILVL = 1, GLVL = 0
IEN = 1; // enable all interrupts
while(1) {
_nop_();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -