Skip to content

Instantly share code, notes, and snippets.

@mafice
Created February 27, 2012 14:59
Show Gist options
  • Save mafice/1924404 to your computer and use it in GitHub Desktop.
Save mafice/1924404 to your computer and use it in GitHub Desktop.
buggy NE2000 Ethernet NIC Driver

Simple NE2000 Ethernet NIC Driver

Keep in mind that this code is too buggy!

How to use it

  • Set NE2000_interruptHandler() as a interrupt handler of NE2000, and implement these functions.

    OUT instruction in assembly void asm_out8 (u16_t port, u8_t data);

    IN instruction in assembly u8_t asm_in8 (u16_t port);

  • Call NE2000_init(macaddr). NIC's MAC address is set in macaddr.

  • You can send frames from NE2000_send() with the frame header. if you want to receive data, replace code in NE2000_interruptHandler().

#define NE2000_PORT 0xc100
#define NE2000_CR NE2000_PORT+0
#define NE2000_PSTART NE2000_PORT+1
#define NE2000_PSTOP NE2000_PORT+2
#define NE2000_BNRY NE2000_PORT+3
#define NE2000_TPSR NE2000_PORT+4
#define NE2000_TBCR0 NE2000_PORT+5
#define NE2000_TBCR1 NE2000_PORT+6
#define NE2000_ISR NE2000_PORT+7
#define NE2000_CURR NE2000_PORT+7 // (!) Page:1
#define NE2000_RSAR0 NE2000_PORT+8
#define NE2000_RSAR1 NE2000_PORT+9
#define NE2000_RBCR0 NE2000_PORT+10
#define NE2000_RBCR1 NE2000_PORT+11
#define NE2000_RCR NE2000_PORT+12
#define NE2000_RSR NE2000_PORT+12
#define NE2000_TCR NE2000_PORT+13
#define NE2000_DCR NE2000_PORT+14
#define NE2000_IMR NE2000_PORT+15
#define NE2000_DATA_PORT NE2000_PORT+16
struct NE2000_RecvInfo{
u8_t status;
u8_t nextPacket;
u16_t length;
u32_t bnry;
u32_t curr;
};
#if 0
typedef unsigned char u8_t;
typedef unsigned short u16_t;
typedef unsigned long u32_t;
typedef unsigned char bool;
#define true 1
#define false 0
#endif
void NE2000_init (u8_t *MACAddress){
unsigned int i;
// initialize
asm_out8(NE2000_CR, 0x21);
asm_out8(NE2000_DCR, 0x5c);
asm_out8(NE2000_RBCR0, 0x00);
asm_out8(NE2000_RBCR1, 0x00);
asm_out8(NE2000_IMR, 0xff);
asm_out8(NE2000_ISR, 0xff);
asm_out8(NE2000_TCR, 0x02);
asm_out8(NE2000_RCR, 0x20);
asm_out8(NE2000_PSTART, 0x64);
asm_out8(NE2000_PSTOP, 0x80);
asm_out8(NE2000_BNRY, 0x46);
asm_out8(NE2000_CR, 0x61);
asm_out8(NE2000_CURR, 0x47);
asm_out8(NE2000_CR, 0x21);
asm_out8(NE2000_RSAR0, 0x00);
asm_out8(NE2000_RSAR1, 0x00);
asm_out8(NE2000_RBCR0, 12);
asm_out8(NE2000_RBCR1, 0x00);
asm_out8(NE2000_CR, 0x0a);
// get MAC address
for(i=0; i < 6; i++){
MACAddress[i] = asm_in8(NE2000_DATA_PORT);
// read unnecessary data
asm_in8(NE2000_DATA_PORT);
}
// re-initialize
asm_out8(NE2000_TCR, 0x00);
asm_out8(NE2000_RCR, 0x1c);
asm_out8(NE2000_DCR, 0x58);
return;
}
static void NE2000_writeBuffer (void* dataP, u16_t size, u16_t page){
int i;
u8_t *data = (u8_t *) dataP;
// clear RDC in ISR
asm_out8(NE2000_ISR, asm_in8(NE2000_ISR)&0xbf);
// write size of data to RBCR
asm_out8(NE2000_RBCR0, size & 0xff);
asm_out8(NE2000_RBCR1, (size>>8) & 0xff);
// write page to RSAR
asm_out8(NE2000_RSAR0, page & 0xff);
asm_out8(NE2000_RSAR1, (page>>8) & 0xff);
// set RD1 in CR
asm_out8(NE2000_CR, 0x12);
// write data to the buffer
for(i=0; i < size; i++){
asm_out8(NE2000_DATA_PORT, data[i]);
}
return;
}
static void NE2000_readBuffer (void *dataP, u16_t size, u16_t page){
int i;
u8_t *data = (u8_t *) dataP;
// write size of data to RBCR
asm_out8(NE2000_RBCR0, size & 0xff);
asm_out8(NE2000_RBCR1, (size>>8) & 0xff);
// write page to RSAR
asm_out8(NE2000_RSAR0, page & 0xff);
asm_out8(NE2000_RSAR1, (page>>8) & 0xff);
// set RD1 to CR
asm_out8(NE2000_CR, 0x0a);
// read data from the buffer
for(i=0; i < size; i++){
data[i] = asm_in8(NE2000_DATA_PORT);
}
return;
}
void NE2000_send (void *frame, u32 size){
// wait until transmission completed
while((asm_in8(NE2000_CR))&0x04);
// write frame to the buffer
NE2000_writeBuffer(frame, size, 0x4000);
// write origin address of written data to TPSR
asm_out8(NE2000_TPSR, 0x40);
// write size of frame to TBCR
asm_out8(NE2000_TBCR0, size & 0xff);
asm_out8(NE2000_TBCR1, (size>>8) & 0xff);
// send frame
asm_out8(NE2000_CR, asm_in8(NE2000_CR)|0x04);
return;
}
static bool NE2000_receive (struct NE2000_RecvInfo *RecvInfo){
u8 curr, bnry;
u8 status;
u16 length;
u8 nextPacket;
u8 buf[1024];
asm_out8(NE2000_CR, 0x4a);
curr = asm_in8(NE2000_CURR);
asm_out8(NE2000_CR, 0x0a);
bnry = asm_in8(NE2000_BNRY);
// if BNRY+1 is not CURR, there is no received frames.
if(curr == bnry+1)
return false;
asm_out8(NE2000_CR, 0x0a);
// read first 4 bytes in the BNRY+1 page
NE2000_readBuffer(buf, 4, (bnry+1)<<8);
// get status, etc.
status = *((u8 *) buf);
nextPacket = *((u8 *) ((void *) buf+1));
length = *((u16 *) ((void *) buf+2));
// check receive status
if((status&1) != 1)
return false;
// check length is valid
if((length < 64) || (length > 1518))
return false;
// update BNRY
asm_out8(NE2000_BNRY, curr-1);
// accept new interrupt (probably this code is not neccesary)
asm_out8(NE2000_ISR, 0xff);
RecvInfo->nextPacket = nextPacket;
RecvInfo->status = status;
RecvInfo->length = length;
RecvInfo->curr = curr;
RecvInfo->bnry = bnry+1;
return true;
}
void NE2000_interruptHandler (void){
char buf[1700];
unsigned int i;
struct NE2000_RecvInfo RecvInfo;
while(NE2000_receive(&RecvInfo)){
for(i=RecvInfo.bnry; (i < RecvInfo.nextPacket) && (i < RecvInfo.curr); i++){
NE2000_readBuffer((void *) &buf+((i-RecvInfo.bnry)*256), 256, ((i)<<8)+4);
}
//
//
//
// Received Packet is in "buf".
//
//
//
}
// accept new interrupt
asm_out8(NE2000_ISR, 0xff);
return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment