www.pudn.com > PICTCPIP.rar > ethmod.c


/*///////////////////////////////////////////////////////////////////// 
// REALTEK RTL8019AS DRIVER 
// PACKET WHACKER 
// Author: Fred Eady 
// Version: 1.0 
// Date: 10/13/01 
// Description: ARP, PING, ECHO and Control, TCP 
/////////////////////////////////////////////////////////////////////*/ 
 
/*#include <16f877.h> 
#include */ 
/*//#device PIC16F877 *=16*/ 
/*#include  
 
/*#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,WRT 
#use delay(clock=20000000) 
/*#use delay(clock=196620800)  /*PICDEM.net* 
#use rs232(baud=2400,xmit=PIN_C6, rcv=PIN_C7) 
 
#use fast_io(A) 
#use fast_io(B) 
#use fast_io(C) 
#use fast_io(D) 
#use fast_io(E)*/ 
 
/*#define  esc   0x1B 
/******************************************************************/ 
/*	FUNCTION PROTOTYPES*/ 
/******************************************************************/ 
 void show_aux_packet(); 
 void dump_header(); 
 void readwrite(); 
 void bin2hex(binchar); 
 void show_regs(); 
 void show_packet(); 
 void cls(); 
 void application_code(); 
 void tcp(); 
 
void assemble_ack(); 
void write_creg(int regaddr, int regdata); 
char read_creg(int regaddr); 
void get_packet(); 
void setipaddrs(); 
void cksum(); 
void echo_packet(); 
void send_tcp_packet(); 
void arp(); 
void icmp(); 
void udp(); 
/****************************************************************** 
//*	IP ADDRESS DEFINITION 
//*   This is the Ethernet Module IP address. 
//*   You may change this to any valid address. 
/******************************************************************/ 
const	unsigned	char MYIP[4] = { 192,168,254,100 }; 
/******************************************************************/ 
/*	HARDWARE (MAC) ADDRESS DEFINITION 
//*   This is the Ethernet Module hardware address. 
//*   You may change this to any valid address. 
//******************************************************************/ 
const	unsigned	char MYMAC[6] = { 0,'V','O','L','T','S' }; 
const	unsigned	char EDTP[23]={"\r\nEDTP Telnet Server>"}; 
/******************************************************************/ 
/*	Receive Ring Buffer Header Layout 
//*   This is the 4-byte header that resides infront of the 
//*   data packet in the receive buffer. 
/*****************************************************************/ 
sreg	unsigned	char  pageheader[4]; 
#define  enetpacketstatus     0x00 
#define  nextblock_ptr        0x01 
#define	enetpacketLenL			0x02 
#define	enetpacketLenH			0x03 
/****************************************************************** 
/*	Ethernet Header Layout 
******************************************************************/ 
sreg	unsigned	char  packet[96];                   /*//50 bytes of UDP data available*/ 
#define	enetpacketDest0	   0x00  /*//destination mac address*/ 
#define	enetpacketDest1	   0x01 
#define	enetpacketDest2	   0x02 
#define	enetpacketDest3	   0x03 
#define	enetpacketDest4	   0x04 
#define	enetpacketDest5	   0x05 
#define	enetpacketSrc0		   0x06  /*//source mac address*/ 
#define	enetpacketSrc1		   0x07 
#define	enetpacketSrc2		   0x08 
#define	enetpacketSrc3		   0x09 
#define	enetpacketSrc4		   0x0A 
#define	enetpacketSrc5		   0x0B 
#define	enetpacketType0	   0x0C  /*type/length field*/ 
#define	enetpacketType1	   0x0D 
#define  enetpacketData       0x0E  /*IP data area begins here*/ 
/****************************************************************** 
//*	ARP Layout 
//******************************************************************/ 
#define	arp_hwtype			   0x0E 
#define	arp_prtype			   0x10 
#define	arp_hwlen			   0x12 
#define	arp_prlen			   0x13 
#define	arp_op				   0x14 
#define	arp_shaddr			   0x16   /*arp source mac address*/ 
#define	arp_sipaddr			   0x1C   /*arp source ip address*/ 
#define	arp_thaddr			   0x20   /*arp target mac address*/ 
#define	arp_tipaddr			   0x26   /*arp target ip address*/ 
/****************************************************************** 
//*	IP Header Layout 
//******************************************************************/ 
#define	ip_vers_len			   0x0E	/*/IP version and header length*/ 
#define	ip_tos				   0x0F	/*/IP type of service*/ 
#define	ip_pktlen			   0x10	/*/packet length*/ 
#define	ip_id				      0x12	/*/datagram id*/ 
#define	ip_frag_offset			0x14	/*/fragment offset*/ 
#define	ip_ttl				   0x16	/*/time to live*/ 
#define	ip_proto			      0x17	/*/protocol (ICMP=1, TCP=6, UDP=11)*/ 
#define	ip_hdr_cksum			0x18	/*/header checksum*/ 
#define	ip_srcaddr			   0x1A	/*/IP address of source*/ 
#define	ip_destaddr			   0x1E	/*/IP addess of destination*/ 
#define	ip_data				   0x22	/*/IP data area*/ 
/****************************************************************** 
//*	TCP Header Layout 
//******************************************************************/ 
#define	TCP_srcport			   0x22	/*/TCP source port*/ 
#define	TCP_destport   	   0x24	/*/TCP destination port*/ 
#define	TCP_seqnum  	      0x26	/*/sequence number*/ 
#define	TCP_acknum	         0x2A	/*/acknowledgement number*/ 
#define	TCP_hdrflags			0x2E	/*/4-bit header len and flags*/ 
#define	TCP_window			   0x30	/*/window size*/ 
#define	TCP_cksum		      0x32	/*/TCP checksum*/ 
#define	TCP_urgentptr   		0x34	/*/urgent pointer*/ 
#define  TCP_data             0x36  /*option/data*/ 
/****************************************************************** 
//*	TCP Flags 
//*   IN flags represent incoming bits 
//*   OUT flags represent outgoing bits 
//******************************************************************/ 
#define  FIN_IN               packet[TCP_hdrflags+1].0 
#define  SYN_IN               packet[TCP_hdrflags+1].1 
#define  RST_IN               packet[TCP_hdrflags+1].2 
#define  PSH_IN               packet[TCP_hdrflags+1].3 
#define  ACK_IN               packet[TCP_hdrflags+1].4 
#define  URG_IN               packet[TCP_hdrflags+1].5 
#define  FIN_OUT              packet[TCP_hdrflags+1].0=1; 
#define  SYN_OUT              packet[TCP_hdrflags+1].1=1; 
#define  RST_OUT              packet[TCP_hdrflags+1].2=1; 
#define  PSH_OUT              packet[TCP_hdrflags+1].3=1; 
#define  ACK_OUT              packet[TCP_hdrflags+1].4=1; 
#define  URG_OUT              packet[TCP_hdrflags+1].5=1; 
/****************************************************************** 
//*	Port Definitions 
//*   This address is used by TCP and the Telnet function. 
//*   This can be changed to any valid port number as long as 
//*   you modify your code to recognize the new port number. 
//******************************************************************/ 
#define  MY_PORT_ADDRESS      0x1F98  /* 8088 DECIMAL*/ 
/****************************************************************** 
//*	IP Protocol Types 
//******************************************************************/ 
#define	PROT_ICMP			   0x01 
#define	PROT_TCP			      0x06 
#define	PROT_UDP			      0x11 
/****************************************************************** 
//*	ICMP Header 
//******************************************************************/ 
#define	ICMP_type			   ip_data 
#define	ICMP_code			   ICMP_type+1 
#define	ICMP_cksum			   ICMP_code+1 
#define	ICMP_id				   ICMP_cksum+2 
#define	ICMP_seqnum			   ICMP_id+2 
#define  ICMP_data            ICMP_seqnum+2 
/****************************************************************** 
//*	UDP Header 
//;******************************************************************/ 
#define	UDP_srcport			   ip_data 
#define	UDP_destport			UDP_srcport+2 
#define	UDP_len				   UDP_destport+2 
#define	UDP_cksum			   UDP_len+2 
#define	UDP_data			      UDP_cksum+2 
/****************************************************************** 
//*	REALTEK CONTROL REGISTER OFFSETS 
//*   All offsets in Page 0 unless otherwise specified 
//******************************************************************/ 
#define CR		 	0x00 
#define PSTART		0x01 
#define PAR0      0x01    /* Page 1*/ 
#define CR9346    0x01    /* Page 3*/ 
#define PSTOP		0x02 
#define BNRY		0x03 
#define TSR			0x04 
#define TPSR		0x04 
#define TBCR0		0x05 
#define NCR			0x05 
#define TBCR1		0x06 
#define ISR			0x07 
#define CURR		0x07   /* Page 1*/ 
#define RSAR0		0x08 
#define CRDA0		0x08 
#define RSAR1		0x09 
#define CRDAL		0x09 
#define RBCR0		0x0A 
#define RBCR1		0x0B 
#define RSR			0x0C 
#define RCR			0x0C 
#define TCR			0x0D 
#define CNTR0		0x0D 
#define DCR			0x0E 
#define CNTR1		0x0E 
#define IMR			0x0F 
#define CNTR2		0x0F 
#define RDMAPORT  0X10 
#define RSTPORT   0x18 
/****************************************************************** 
//*	RTL8019AS INITIAL REGISTER VALUES 
//******************************************************************/ 
#define rcrval		0x04 
#define tcrval		0x00 
#define dcrval		0x58    /* was 0x48*/ 
#define imrval		0x11    /* PRX and OVW interrupt enabled*/ 
#define txstart   0x40 
#define rxstart   0x46 
#define rxstop    0x60 
/****************************************************************** 
//*	RTL8019AS 9346 EEPROM PIN DEFINITIONS 
//******************************************************************/ 
#define  cregaddr    p0 
#define  cregdata    p2 
#define  tocreg      pm2=0x00; 
#define  fromcreg    pm2=0xFF; 
/****************************************************************** 
//*	RTL8019AS 9346 EEPROM PIN DEFINITIONS 
//******************************************************************/ 
/*#define  EESK        PORTB,5 
#define  EEDI        PORTB,6 
#define  EEDO        PORTA,0*/ 
/****************************************************************** 
//*	RTL8016AS PIN DEFINITIONS 
//******************************************************************/ 
#define  INT0        p3.0 
#define  ior_pin     p1.0 
#define  iow_pin     p1.1 
#define  rst_pin     p2.4 
/****************************************************************** 
//*	RTL8016AS ISR REGISTER DEFINITIONS 
//******************************************************************/ 
#define  RST         0x07 
#define  RDC         0x06 
#define  OVW         0x04 
#define  PRX         0x00 
/****************************************************************** 
//*	PIC16F87X RAM Definitions 
//******************************************************************/ 
sreg	unsigned	char aux_data[16];            /*//received data area*/ 
sreg	unsigned	char *addr; 
sreg	unsigned	char byte_read,data_H,data_L; 
sreg	unsigned	char high_nibble, low_nibble, high_char, low_char,resend; 
sreg	unsigned	int i,txlen,rxlen,chksum16,hdrlen,tcplen,tcpdatalen_in; 
sreg	unsigned	int tcpdatalen_out,ISN,portaddr,ip_packet_len; 
sreg	unsigned	long hdr_chksum,my_seqnum,client_seqnum,incoming_ack,expected_ack; 
sreg	unsigned	short synflag,finflag; 
 
#define  set_packet32(d,s) packet[d] = make8(s,3); \ 
                           packet[d+1] = make8(s,2); \ 
                           packet[d+2] = make8(s,1); \ 
                           packet[d+3]= make8(s,0); \ 
/****************************************************************** 
//*	Application Code 
//*   Your application code goes here. 
//*   This particular code toggles the LED on PORT A bit 4 using 
//*   Telnet. 
//******************************************************************/ 
 
void application_code() 
{ 
   if(aux_data[0] != 0x0A) 
      tcpdatalen_out = tcpdatalen_in; 
   if(aux_data[0] == 0x0A) 
      tcpdatalen_out = 0x00; 
 
   if(aux_data[0] == '0') 
      /*;p3.0=1;/*bit_set(PORTA,4);*/ 
   if (aux_data[0] == '1') 
      /*;p3.0=0;/*bit_clear(PORTA,4);*/ 
   if (aux_data[0] == 0x0D) 
      { 
         /*strcpy(packet[TCP_data],"EDTP[0]\r\nEDTP Telnet Server>");/ 
         strcpy(packet[TCP_data],packet[4]);*/ 
         tcpdatalen_out = 21; 
      } 
 } 
/****************************************************************** 
//*	Perform ARP Response 
//*   This routine supplies a requesting computer with the 
//*   Ethernet modules's MAC (hardware) address. 
//******************************************************************/ 
void arp() 
{ 
   /*start the NIC*/ 
   write_creg(CR,0x22); 
 
   /*load beginning page for transmit buffer*/ 
   write_creg(TPSR,txstart); 
 
   /*set start address for remote DMA operation*/ 
   write_creg(RSAR0,0x00); 
   write_creg(RSAR1,0x40); 
 
   /*clear the Interrupts*/ 
   write_creg(ISR,0xFF); 
 
   /*load data byte count for remote DMA*/ 
   write_creg(RBCR0,0x3C); 
   write_creg(RBCR1,0x00); 
 
   /*do remote write operation*/ 
   write_creg(CR,0x12); 
 
   /*write destination MAC address*/ 
   for(i=0;i<6;++i) 
      write_creg(RDMAPORT,packet[enetpacketSrc0+i]); 
 
   /*write source MAC address*/ 
   for(i=0;i<6;++i) 
      write_creg(RDMAPORT,MYMAC[i]); 
 
   /*write typelen hwtype prtype hwlen prlen op:*/ 
   addr = &packet[enetpacketType0]; 
   packet[arp_op+1] = 0x02; 
   for(i=0;i<10;++i) 
      write_creg(RDMAPORT,*addr++); 
 
   /*write ethernet module MAC address*/ 
   for(i=0;i<6;++i) 
      write_creg(RDMAPORT,MYMAC[i]); 
 
   /*write ethernet module IP address*/ 
      for(i=0;i<4;++i) 
      write_creg(RDMAPORT,MYIP[i]); 
 
   /*write remote MAC address*/ 
   for(i=0;i<6;++i) 
      write_creg(RDMAPORT,packet[enetpacketSrc0+i]); 
 
   /*write remote IP address*/ 
   for(i=0;i<4;++i) 
      write_creg(RDMAPORT,packet[arp_sipaddr+i]); 
 
   /*write some pad characters to fill out the packet to*/ 
   /*the minimum length*/ 
   for(i=0;i<0x12;++i) 
      write_creg(RDMAPORT,0x00); 
 
   /*make sure the DMA operation has successfully completed*/ 
   byte_read = 0; 
   while(!bit_test(byte_read,RDC)) 
      read_creg(ISR); 
 
   /*load number of bytes to be transmitted*/ 
   write_creg(TBCR0,0x3C); 
   write_creg(TBCR1,0x00); 
 
   /*send the contents of the transmit buffer onto the network*/ 
   write_creg(CR,0x24); 
 } 
/****************************************************************** 
//*	Perform ICMP Function 
//*   This routine responds to a ping. 
//******************************************************************/ 
void icmp() 
{ 
   /*set echo reply*/ 
   packet[ICMP_type]=0x00; 
   packet[ICMP_code]=0x00; 
 
   /*clear the ICMP checksum*/ 
   packet[ICMP_cksum ]=0x00; 
   packet[ICMP_cksum+1]=0x00; 
 
   /*setup the IP header*/ 
   setipaddrs(); 
 
   /*calculate the ICMP checksum*/ 
   hdr_chksum =0; 
   hdrlen = (make16(packet[ip_pktlen],packet[ip_pktlen+1])) - ((packet[ip_vers_len] & 0x0F) * 4); 
   addr = &packet[ICMP_type]; 
   cksum(); 
   chksum16= ~(hdr_chksum + ((hdr_chksum & 0xFFFF0000) >> 16)); 
   packet[ICMP_cksum] = make8(chksum16,1); 
   packet[ICMP_cksum+1] = make8(chksum16,0); 
 
   /*send the ICMP packet along on its way*/ 
   echo_packet(); 
} 
/****************************************************************** 
//*	UDP Function 
//*   This function uses a Visual Basic UDP program to echo the 
//*   data back to the VB program and set or reset PORT A bit 4 
//*   under control of the VB program. 
//******************************************************************/ 
void udp() 
{ 
   /*port 7 is the well-known echo port*/ 
   if(packet[UDP_destport] == 0x00 && packet[UDP_destport+1] ==0x07) 
   { 
      /*build the IP header*/ 
      setipaddrs(); 
 
      /*swap the UDP source and destination ports*/ 
      data_L = packet[UDP_srcport]; 
      packet[UDP_srcport] = packet[UDP_destport]; 
      packet[UDP_destport] = data_L; 
 
      data_L = packet[UDP_srcport+1]; 
      packet[UDP_srcport+1] = packet[UDP_destport+1]; 
      packet[UDP_destport+1] = data_L; 
 
      /*calculate the UDP checksum*/ 
      packet[UDP_cksum] = 0x00; 
      packet[UDP_cksum+1] = 0x00; 
 
      hdr_chksum =0; 
      hdrlen = 0x08; 
      addr = &packet[ip_srcaddr]; 
      cksum(); 
      hdr_chksum = hdr_chksum + packet[ip_proto]; 
      hdrlen = 0x02; 
      addr = &packet[UDP_len]; 
      cksum(); 
      hdrlen = make16(packet[UDP_len],packet[UDP_len+1]); 
      addr = &packet[UDP_srcport]; 
      cksum(); 
      chksum16= ~(hdr_chksum + ((hdr_chksum & 0xFFFF0000) >> 16)); 
      packet[UDP_cksum] = make8(chksum16,1); 
      packet[UDP_cksum+1] = make8(chksum16,0); 
 
      /*echo the incoming data back to the VB program*/ 
      echo_packet(); 
   } 
 
   /*buttons on the VB GUI are pointed towards port address 5000 decimal*/ 
   else if(packet[UDP_destport] == 0x13 && packet[UDP_destport+1] == 0x88); 
	  { 
      if(packet[UDP_data]) 
         /*received a 0x00 from the VB program*/ 
         bit_set(PORTA,4); 
      else 
         /*received a 0xFF from the VB program*/ 
         bit_clear(PORTA,4); 
     } 
} 
/****************************************************************** 
//*	TCP Function 
//*   This function uses TCP protocol to act as a Telnet server on 
//*   port 8088 decimal.  The application function is called with 
//*   every incoming character. 
//******************************************************************/ 
  
void tcp() 
{ 
 
   /*assemble the destination port address from the incoming packet*/ 
   portaddr = make16(packet[TCP_destport],packet[TCP_destport+1]); 
 
   /*calculate the length of the data coming in with the packet*/ 
   /*tcpdatalen_in = incoming packet length - incoming ip header length - incoming tcp header length*/ 
   tcpdatalen_in = (make16(packet[ip_pktlen],packet[ip_pktlen+1])) - 
   ((packet[ip_vers_len] & 0x0F) * 4) - (((packet[TCP_hdrflags] & 0xF0) >> 4) * 4); 
 
   /*If an ACK is recieved and the destination port address is valid and no data is in the packet*/ 
   if(ACK_IN && portaddr == MY_PORT_ADDRESS && tcpdatalen_in == 0x00) 
   { 
      /*assemble the acknowledgment number from the incoming packet*/ 
      incoming_ack =make32(packet[TCP_acknum],packet[TCP_acknum+1],packet[TCP_acknum+2],packet[TCP_acknum+3]); 
 
      /*if the incoming packet is a result of session establishment*/ 
      if(synflag) 
      { 
         /*clear the SYN flag*/ 
         synflag = 0; 
 
         /*the incoming acknowledgment is my new sequence number*/ 
         my_seqnum = incoming_ack; 
 
         /*send the Telnet server banner*/ 
         /*limit the character count to 40 decimal*/ 
         strcpy(packet[TCP_data],"EASY ETHERNET\r\n1=LED ON\r\n0=LED OFF\r\n>"); 
         /*length of the banner message*/ 
         tcpdatalen_out = 37; 
 
         /*expect to get an acknowledgment of the banner message*/ 
         expected_ack = my_seqnum +tcpdatalen_out; 
 
         /*send the TCP/IP packet*/ 
         send_tcp_packet(); 
      } 
   } 
 
   /*if an ack is received and the port address is valid and there is data in the incoming packet*/ 
   if(ACK_IN && portaddr == MY_PORT_ADDRESS && tcpdatalen_in) 
   { 
      for(i=0;i> 16)); 
      packet[TCP_cksum] = make8(chksum16,1); 
      packet[TCP_cksum+1] = make8(chksum16,0); 
      echo_packet(); 
   } 
 
   /*this code segment processes a FIN from the Telnet client 
   /*and acknowledges the FIN and any incoming data.*/ 
   if(FIN_IN && portaddr == MY_PORT_ADDRESS) 
   { 
      if(tcpdatalen_in) 
      { 
         for(i=0;i> 16)); 
   packet[TCP_cksum] = make8(chksum16,1); 
   packet[TCP_cksum+1] = make8(chksum16,0); 
 
   txlen = ip_packet_len + 14; 
   if(txlen < 60) 
      txlen = 60; 
   data_L = make8(txlen,0); 
   data_H = make8(txlen,1); 
   write_creg(CR,0x22); 
   write_creg(TPSR,txstart); 
   write_creg(RSAR0,0x00); 
   write_creg(RSAR1,0x40); 
   write_creg(ISR,0xFF); 
   write_creg(RBCR0,data_L); 
   write_creg(RBCR1,data_H); 
   write_creg(CR,0x12); 
 
   for(i=0;i 0x09) 
      high_char = high_nibble + 0x37; 
   else 
      high_char = high_nibble + 0x30; 
 
   low_nibble = (binchar & 0x0F); 
   if(low_nibble > 0x09) 
      low_char = low_nibble + 0x37; 
   else 
      low_char = low_nibble + 0x30; 
} 
/****************************************************************** 
//*	Used with Tera Term to clear the screen (VT-100 command) 
//******************************************************************/ 
  
void cls(void) 
{ 
   printf("%c[2J",esc); 
} 
/****************************************************************** 
//* show_packet   
//*	This routine is for diagnostic purposes and displays 
//*   the Packet Buffer memory in the PIC. 
//******************************************************************/ 
  
void show_packet() 
{ 
   cls(); 
   printf("\r\n"); 
   data_L = 0x00; 
   for(i=0;i<96;++i) 
   { 
      bin2hex(packet[i]); 
      printf(" %c%c",high_char,low_char); 
      if(++data_L == 0x10) 
         { 
            data_L = 0x00; 
            printf("\r\n"); 
         } 
   } 
} 
/****************************************************************** 
//*   show_aux_packet 
//*	This routine is a diagnostic that displays Auxillary 
//*   Packet Buffer buffer memory in the PIC. 
//******************************************************************/ 
  
void show_aux_packet() 
{ 
   cls(); 
   printf("\r\n"); 
   data_L = 0x00; 
   for(i=0;i<80;++i) 
   { 
      bin2hex(aux_data[i]); 
      printf(" %c%c",high_char,low_char); 
      if(++data_L == 0x10) 
         { 
            data_L = 0x00; 
            printf("\r\n"); 
         } 
   } 
} 
 
/****************************************************************** 
//*	Write to NIC Control Register 
//******************************************************************/ 
void write_creg(int regaddr, int regdata) 
{ 
    cregaddr = regaddr; 
    cregdata = regdata; 
    tocreg; 
    iow_pin=0;/*bit_clear(iow_pin);*/ 
    delay_cycles(1); 
    iow_pin=1;/*bit_set(iow_pin);*/ 
    fromcreg; 
} 
/****************************************************************** 
//*	Read From NIC Control Register 
//******************************************************************/ 
char read_creg(int regaddr) 
{ 
   fromcreg; 
   cregaddr = regaddr; 
   ior_pin=0;/*bit_clear(ior_pin);*/ 
   byte_read = input_d(); 
   ior_pin=1;/*bit_set(ior_pin);*/ 
   return(byte_read); 
} 
/****************************************************************** 
//*	Detect EEPROM Clock from RTL8019AS 
//******************************************************************/ 
void clock_9346() 
{ 
#asm 
chk_is_lo: 
   btfss EESK 
   goto  chk_is_lo 
chk_is_hi: 
   btfsc EESK 
   goto  chk_is_hi 
#endasm 
} 
/****************************************************************** 
//*	Emulate the presence of a 9346 EEPROM 
//******************************************************************/ 
void fakeout_9346() 
{ 
char reps,clocks,datum; 
 
#asm 
movlw 0x02 
movwf reps 
reload: 
bcf   EEDO 
movlw 0x03     /*0x03=half duplex 0x07=full duplex*/ 
movwf datum 
#endasm 
 
start_bit: 
clock_9346(); 
#asm 
btfss EEDI 
goto  start_bit 
#endasm 
clock_9346(); 
#asm 
btfss EEDI 
goto  start_bit 
#endasm 
clock_9346(); 
#asm 
btfsc EEDI 
goto  start_bit 
movlw 0x06 
movwf clocks 
#endasm 
addr: 
clock_9346(); 
#asm 
decfsz clocks,1 
goto  addr 
movlw 0x10 
movwf clocks 
bcf   C 
#endasm 
send: 
clock_9346(); 
#asm 
movf  datum,0 
movwf PORTA 
rrf   datum,1 
decfsz clocks,1 
goto  send 
decfsz reps,1 
goto  reload 
bcf   EEDO 
#endasm 
} 
/****************************************************************** 
//*	Handle Receive Ring Buffer Overrun 
//*   No packets are recovered 
//******************************************************************/ 
void overrun() 
{ 
   read_creg(CR); 
   data_L = byte_read; 
   write_creg(CR,0x21); 
   delay_ms(2); 
   write_creg(RBCR0,0x00); 
   write_creg(RBCR1,0x00); 
   if(!bit_test(data_L,2)) 
      resend = 0; 
   else if(bit_test(data_L,2)) 
      { 
         read_creg(ISR); 
         data_L = byte_read; 
         if(bit_test(data_L,1) || bit_test(data_L,3)) 
            resend = 0; 
         else 
            resend = 1; 
      } 
 
   write_creg(TCR,0x02); 
   write_creg(CR,0x22); 
   write_creg(BNRY,rxstart); 
   write_creg(CR,0x62); 
   write_creg(CURR,rxstart); 
   write_creg(CR,0x22); 
   write_creg(ISR,0x10); 
   write_creg(TCR,tcrval); 
} 
/****************************************************************** 
//*	Echo Packet Function 
//*   This routine does not modify the incoming packet size and 
//*   thus echoes the original packet structure. 
//******************************************************************/ 
void echo_packet() 
{ 
   write_creg(CR,0x22); 
   write_creg(TPSR,txstart); 
   write_creg(RSAR0,0x00); 
   write_creg(RSAR1,0x40); 
   write_creg(ISR,0xFF); 
   write_creg(RBCR0,pageheader[enetpacketLenL] - 4 ); 
   write_creg(RBCR1,pageheader[enetpacketLenH]); 
   write_creg(CR,0x12); 
 
   txlen = make16(pageheader[enetpacketLenH],pageheader[enetpacketLenL]) - 4; 
   for(i=0;i> 16)); 
   packet[ip_hdr_cksum] = make8(chksum16,1); 
   packet[ip_hdr_cksum+1] = make8(chksum16,0); 
 } 
/****************************************************************** 
//*	CHECKSUM CALCULATION ROUTINE 
//******************************************************************/ 
void cksum() 
{ 
      while(hdrlen > 1) 
      { 
         data_H=*addr++; 
         data_L=*addr++; 
         chksum16=make16(data_H,data_L); 
         hdr_chksum = hdr_chksum + chksum16; 
         hdrlen -=2; 
      } 
      if(hdrlen > 0) 
      { 
         data_H=*addr; 
         data_L=0x00; 
         chksum16=make16(data_H,data_L); 
         hdr_chksum = hdr_chksum + chksum16; 
      } 
} 
/****************************************************************** 
//*	Initialize the RTL8019AS 
//******************************************************************/ 
void init_RTL8019AS() 
{ 
  	ADCON1 = 0x06;		                  /*00000110	all digital to start*/ 
	ADCON0 = 0; 
   set_tris_C(0x85); 
   set_tris_A(0x00); 
   bit_clear(EEDO); 
   set_tris_B(0xE0);                   /* setup address lines*/ 
   cregaddr = 0x00;                    /* clear address lines*/ 
   fromcreg;                           /* address lines = input*/ 
   set_tris_E(0x00);                   /* setup IOW, IOR, RESET*/ 
 
   iow_pin=1;/*bit_set(iow_pin);                    disable IOW*/ 
   ior_pin=1;/*bit_set(ior_pin);                    disable IOR*/ 
   rst_pinb=1;/*it_set(rst_pin);                    put NIC in reset*/ 
   delay_ms(2);                        /* delay at least 1.6ms*/ 
   rst_pinb=0;/*bit_clear(rst_pin);                 /* disable reset line*/ 
   read_creg(RSTPORT);                 /* read contents of reset port*/ 
   write_creg(RSTPORT,byte_read);      /* do soft reset*/ 
   delay_ms(10);                       /* give it time*/ 
   read_creg(ISR);                     /* check for good soft reset*/ 
   if(!bit_test(byte_read,RST)){ 
      while(1){ 
      printf("INIT FAILED\n\r"); 
      } 
   } 
 
   write_creg(CR,0x21);       /*stop the NIC, abort DMA, page 0*/ 
   delay_ms(2);               /*make sure nothing is coming in or going out*/ 
   write_creg(DCR,dcrval);    /*0x58*/ 
   write_creg(RBCR0,0x00);    /*clear the DMA byte counters*/ 
   write_creg(RBCR1,0x00); 
   write_creg(RCR,0x04);      /*accept broadcast packets  */ 
   write_creg(TPSR,txstart);  /*set transmit buffer start page */  
   write_creg(TCR,0x02); 
   write_creg(PSTART,rxstart);//set receive buffer start page*/ 
   write_creg(BNRY,rxstart);  /*initialize the boundary  */ 
   write_creg(PSTOP,rxstop);  /*set receive buffer stop page  */ 
   write_creg(CR,0x61);       /*stop NIC and change control register page */ 
   delay_ms(2); 
   write_creg(CURR,rxstart);  /*write NIC MAC (hardware) address  */ 
   for(i=0;i<6;++i) 
      write_creg(PAR0+i, MYMAC[i]); 
 
   write_creg(CR,0xC1);      /*prepare to emulate 9346 EEPROM*/ 
   write_creg(CR9346,0xC0); 
   write_creg(CR9346,0x40); 
 
   fakeout_9346();           /*emulate the 9348 */ 
   delay_ms(10); 
 
   write_creg(CR,0x21);      /*stop the NIC and go to home page */ 
   write_creg(DCR,dcrval);   /*set FIFO threshold, enable Send Packet Command, */ 
   write_creg(CR,0x22);      /*start NIC  */ 
   write_creg(ISR,0xFF);     /*clear interrupts*/ 
   write_creg(IMR,imrval);   /*unmask interrupts */ 
   write_creg(TCR,tcrval);   /*normal operation and enable CRC */ 
} 
/****************************************************************** 
//*	MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN 
//******************************************************************/ 
void main() 
{ 
   init_RTL8019AS(); 
   synflag = 0; 
   finflag = 0; 
/****************************************************************** 
//*	Look for a packet in the receive buffer ring 
//******************************************************************/ 
   while(1) 
   { 
      /*start the NIC*/ 
      write_creg(CR,0x22); 
 
      /*wait for a good packet*/ 
      while(!bit_test(INT0)); 
 
      /*read the interrupt status register*/ 
      read_creg(ISR); 
 
      /*if the receive buffer has been overrun*/ 
      if(bit_test(byte_read,OVW)) 
         overrun(); 
 
      /*if the receive buffer holds a good packet*/ 
      if(bit_test(byte_read,PRX)) 
         get_packet(); 
 
      /*make sure the receive buffer ring is empty*/ 
      /*if BNRY = CURR, the buffer is empty*/ 
         read_creg(BNRY); 
         data_L = byte_read; 
         write_creg(CR,0x62); 
         read_creg(CURR); 
         data_H = byte_read; 
         write_creg(CR,0x22); 
      /*buffer is not empty.. get next packet*/ 
         if(data_L != data_H) 
            get_packet(); 
 
      /*reset the interrupt bits*/ 
      write_creg(ISR,0xFF); 
   } 
}