]> git.llucax.com Git - z.facultad/66.09/etherled.git/blobdiff - pruebas/keil/red_test_anda/etherdev.c
Adapto ejemplo básico que andaba a SDCC y funciona correctamente.
[z.facultad/66.09/etherled.git] / pruebas / keil / red_test_anda / etherdev.c
index 2b265b82d366a8bdb22cd27d3aa231657c77b0f1..93abcbf4198b9e38999ad673d520a5094296c521 100644 (file)
@@ -1,11 +1,17 @@
 // vim: set et sw=4 sts=4 :    
 
 // vim: set et sw=4 sts=4 :    
 
+#include "types.h"
 #include "etherdev.h"
 
 void sleep(unsigned char);
 
 #include "etherdev.h"
 
 void sleep(unsigned char);
 
-static xdata leds1 _at_ 0x0080;
-static xdata leds2 _at_ 0x00c0;
+#ifdef SDCC
+static xdata at 0x0080 byte leds1;
+static xdata at 0x00c0 byte leds2;
+#else
+static byte xdata leds1 _at_ 0x0080;
+static byte xdata leds2 _at_ 0x00c0;
+#endif
 
 unsigned char uip_buf[80] =
 {
 
 unsigned char uip_buf[80] =
 {
@@ -17,17 +23,6 @@ unsigned char uip_buf[80] =
 
 unsigned int uip_len = 14;
 
 
 unsigned int uip_len = 14;
 
-#define ETH_CPU_CLOCK      ETH_CPU_XTAL / 12    // 8051 clock rate (X1 mode)
-
-// Delay routine timing parameters
-#define ETH_DELAY_CONST    9.114584e-5          // Delay routine constant
-#define ETH_DELAY_MULTPLR  (unsigned char)(ETH_DELAY_CONST * ETH_CPU_CLOCK)
-
-// X1 CPU mode timing parameters
-#define ETH_T0_CLOCK             ETH_CPU_XTAL / 12 // Timer 0 mode 1 clock rate
-#define ETH_T0_INT_RATE          24                // Timer 0 intrupt rate (Hz)
-#define ETH_T0_RELOAD            65536 - (ETH_T0_CLOCK / ETH_T0_INT_RATE)
-
 // Packet transmit & receive buffer configuration
 #define ETH_TX_PAGE_START  0x40    // 0x4000 Tx buffer is  6 * 256 = 1536 bytes
 #define ETH_RX_PAGE_START  0x46    // 0x4600 Rx buffer is 26 * 256 = 6656 bytes
 // Packet transmit & receive buffer configuration
 #define ETH_TX_PAGE_START  0x40    // 0x4000 Tx buffer is  6 * 256 = 1536 bytes
 #define ETH_RX_PAGE_START  0x46    // 0x4600 Rx buffer is 26 * 256 = 6656 bytes
@@ -36,13 +31,11 @@ unsigned int uip_len = 14;
 #define ETH_ADDR_PORT_MASK 0x1F                 // 00011111y
 #define ETH_DATA_PORT_MASK 0xFF                 // 11111111y
 
 #define ETH_ADDR_PORT_MASK 0x1F                 // 00011111y
 #define ETH_DATA_PORT_MASK 0xFF                 // 11111111y
 
-#define ETH_MIN_PACKET_LEN 0x3C
+#define ETH_MIN_PACKET_LEN 0x3C                 // 60 bytes
 
 
 static void etherdev_reg_write(unsigned char reg, unsigned char wr_data);
 static unsigned char etherdev_reg_read(unsigned char reg);
 
 
 static void etherdev_reg_write(unsigned char reg, unsigned char wr_data);
 static unsigned char etherdev_reg_read(unsigned char reg);
-static void etherdev_delay_ms(unsigned int count);
-static unsigned int etherdev_poll(void);
 
 // Manipulate PS1 & PS0 in CR to select RTL8019AS register page. 
 #define ETHERDEV_SELECT_REG_PAGE(page)                                      \
 
 // Manipulate PS1 & PS0 in CR to select RTL8019AS register page. 
 #define ETHERDEV_SELECT_REG_PAGE(page)                                      \
@@ -52,8 +45,6 @@ static unsigned int etherdev_poll(void);
               etherdev_reg_write(CR, etherdev_reg_read(CR) | (page << 6));  \
           } while(0)
 
               etherdev_reg_write(CR, etherdev_reg_read(CR) | (page << 6));  \
           } while(0)
 
-static unsigned char tick_count = 0;
-
 
 static void etherdev_reg_write(unsigned char reg, unsigned char wr_data)
 {
 
 static void etherdev_reg_write(unsigned char reg, unsigned char wr_data)
 {
@@ -71,9 +62,6 @@ static void etherdev_reg_write(unsigned char reg, unsigned char wr_data)
     IOW = 1;
     NICE = 1;
 
     IOW = 1;
     NICE = 1;
 
-    // Set register data port as input again.
-    ETH_DATA_PORT = ETH_DATA_PORT_MASK;
-
     return;
 } 
 
     return;
 } 
 
@@ -86,8 +74,11 @@ static unsigned char etherdev_reg_read(unsigned char reg)
     ETH_ADDR_PORT &= ~ETH_ADDR_PORT_MASK;
     ETH_ADDR_PORT |= reg;
 
     ETH_ADDR_PORT &= ~ETH_ADDR_PORT_MASK;
     ETH_ADDR_PORT |= reg;
 
+    // Set register data port as input.
+    ETH_DATA_PORT = ETH_DATA_PORT_MASK;
+
     // Enable register data output from RTL8019AS.
     // Enable register data output from RTL8019AS.
-       NICE = 0;
+    NICE = 0;
     IOR = 0;
 
     // Read register data from port.
     IOR = 0;
 
     // Read register data from port.
@@ -95,33 +86,12 @@ static unsigned char etherdev_reg_read(unsigned char reg)
 
     // Disable register data output from RTL8019AS.
     IOR = 1; 
 
     // Disable register data output from RTL8019AS.
     IOR = 1; 
-       NICE = 1;   
+    NICE = 1;   
 
     return rd_data;
 } 
 
 
 
     return rd_data;
 } 
 
 
-/* 
-                                                                     
-                           etherdev_timer0_isr()                     
-                                                                     
- This function is invoked each 1/24th of a second and updates a      
- 1/24th of a second tick counter.                                    
-                                                                     
- */
-static void etherdev_timer0_isr(void) interrupt 1 using 1
-{
-    // Reload timer/ counter 0 for 24Hz periodic interrupt.   
-    TH0 = ETH_T0_RELOAD >> 8;
-    TL0 = ETH_T0_RELOAD;
-
-    // Increment 24ths of a second counter.
-    tick_count++;
-
-    return;
-}
-
-
 /*
                                                                      
                             etherdev_init()                          
 /*
                                                                      
                             etherdev_init()                          
@@ -130,7 +100,7 @@ static void etherdev_timer0_isr(void) interrupt 1 using 1
   Refer to National Semiconductor DP8390 App Note 874, July 1993.    
                                                                      
  */
   Refer to National Semiconductor DP8390 App Note 874, July 1993.    
                                                                      
  */
-bit etherdev_init(void)
+bool etherdev_init(void)
 {
     // Set IOR & IOW as they're active low.
     IOR = 1;
 {
     // Set IOR & IOW as they're active low.
     IOR = 1;
@@ -155,11 +125,8 @@ bit etherdev_init(void)
         return 0;
     }
 
         return 0;
     }
 
-    // Select RTL8019AS register page 0.
-    ETHERDEV_SELECT_REG_PAGE(0);
-
     // Stop RTL8019AS, select page 0 and abort DMA operation.
     // Stop RTL8019AS, select page 0 and abort DMA operation.
-    etherdev_reg_write(CR, RD2 | STP);
+    etherdev_reg_write(CR, ABORT | STP);
 
     // Initialise data configuration register. 
     // FIFO threshold 8 bytes, no loopback, don't use auto send packet.
 
     // Initialise data configuration register. 
     // FIFO threshold 8 bytes, no loopback, don't use auto send packet.
@@ -173,16 +140,41 @@ bit etherdev_init(void)
     etherdev_reg_write(RCR, MON);
 
     // Initialise transmit configuration register to loopback internally.
     etherdev_reg_write(RCR, MON);
 
     // Initialise transmit configuration register to loopback internally.
-    etherdev_reg_write(TCR, LB0);
+    etherdev_reg_write(TCR, MODE1);
 
     // Clear interrupt status register bits by writing 1 to each.
     etherdev_reg_write(ISR, 0xFF);
 
     // Mask all interrupts in mask register.
     etherdev_reg_write(IMR, 0x00);
 
     // Clear interrupt status register bits by writing 1 to each.
     etherdev_reg_write(ISR, 0xFF);
 
     // Mask all interrupts in mask register.
     etherdev_reg_write(IMR, 0x00);
+    
+    // Obtengo MAC de la placa
+    etherdev_reg_write(RBCR0, 0x0c); // Vamos a leer 12 bytes (2 x 6)
+    etherdev_reg_write(RBCR1, 0x00); 
+    etherdev_reg_write(RSAR0, 0x00); // En la dirección 0x0000
+    etherdev_reg_write(RSAR1, 0x00);
+    etherdev_reg_write(CR, READ | STA); // Comienza lectura
+    uip_buf[6] = etherdev_reg_read(RDMA);
+    etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
+    uip_buf[7] = etherdev_reg_read(RDMA);
+    etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
+    uip_buf[8] = etherdev_reg_read(RDMA);
+    etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
+    uip_buf[9] = etherdev_reg_read(RDMA);
+    etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
+    uip_buf[10] = etherdev_reg_read(RDMA);
+    etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
+    uip_buf[11] = etherdev_reg_read(RDMA);
+    etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
+
+    // Wait until remote DMA operation completes.
+    while(!(etherdev_reg_read(ISR) & RDC)) continue;
 
 
-    // TODO Obtengo MAC de la placa
-    //etherdev_reg_write(CR, 0x21);
+    // Abort/ complete DMA operation.
+    etherdev_reg_write(CR, ABORT | STP);
+
+    // Limpia ISR
+    etherdev_reg_write(ISR, RDC);
 
     // Set transmit page start.
     etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
 
     // Set transmit page start.
     etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
@@ -197,54 +189,31 @@ bit etherdev_init(void)
     etherdev_reg_write(PSTOP, ETH_RX_PAGE_STOP);
 
     // Select RTL8019AS register page 1.
     etherdev_reg_write(PSTOP, ETH_RX_PAGE_STOP);
 
     // Select RTL8019AS register page 1.
-    etherdev_reg_write(CR, RD2 | PS0 | STP);
+    etherdev_reg_write(CR, ABORT | PAGE1 | STP);
 
     // Initialise current packet receive buffer page pointer
 
     // Initialise current packet receive buffer page pointer
-    etherdev_reg_write(CURR, ETH_RX_PAGE_START+1);
+    etherdev_reg_write(CURR, ETH_RX_PAGE_START + 1);
 
     // Set physical address
 
     // Set physical address
-    etherdev_reg_write(PAR0, 0x00);
-    etherdev_reg_write(PAR1, 0x0c);
-    etherdev_reg_write(PAR2, 0x6e);
-    etherdev_reg_write(PAR3, 0x37);
-    etherdev_reg_write(PAR4, 0x19);
-    etherdev_reg_write(PAR5, 0xbe);
+    etherdev_reg_write(PAR0, uip_buf[6]);
+    etherdev_reg_write(PAR1, uip_buf[7]);
+    etherdev_reg_write(PAR2, uip_buf[8]);
+    etherdev_reg_write(PAR3, uip_buf[9]);
+    etherdev_reg_write(PAR4, uip_buf[10]);
+    etherdev_reg_write(PAR5, uip_buf[11]);
 
     // Select RTL8019AS register page 0 and abort DMA operation.
 
     // Select RTL8019AS register page 0 and abort DMA operation.
-    etherdev_reg_write(CR, RD2 | STP);
+    etherdev_reg_write(CR, ABORT | STP);
 
     // Restart RTL8019AS. 
 
     // Restart RTL8019AS. 
-    etherdev_reg_write(CR, RD2 | STA);
+    etherdev_reg_write(CR, ABORT | STA);
 
     // Initialise transmit configuration register for normal operation.
 
     // Initialise transmit configuration register for normal operation.
-    etherdev_reg_write(TCR, 0x00);
+    etherdev_reg_write(TCR, MODE0);
 
     // Receive configuration register to accept broadcast packets.
     etherdev_reg_write(RCR, AB);
 
 
     // Receive configuration register to accept broadcast packets.
     etherdev_reg_write(RCR, AB);
 
-
-    // Initialize Timer 0 to generate a periodic 24Hz interrupt. 
-
-    // Stop timer/ counter 0.                                         
-    TR0  = 0;          
-
-    // Set timer/ counter 0 as mode 1 16 bit timer.      
-    TMOD &= 0xF0;
-    TMOD |= 0x01;
-
-    // Preload for 24Hz periodic interrupt.    
-    TH0 = ETH_T0_RELOAD >> 8; 
-    TL0 = ETH_T0_RELOAD;
-
-    // Restart timer/ counter 0 running.
-    TR0 = 1;
-
-    // Enable timer/ counter 0 overflow interrupt.            
-    ET0 = 1;
-
-    // Enable global interrupt.
-    EA = 1;
-
     return 1;
 }
 
     return 1;
 }
 
@@ -264,7 +233,7 @@ void etherdev_send(void)
     // Setup for DMA transfer from uip_buf & uip_appdata buffers to RTL8019AS.
 
     // Select RTL8019AS register page 0 and abort DMA operation.
     // Setup for DMA transfer from uip_buf & uip_appdata buffers to RTL8019AS.
 
     // Select RTL8019AS register page 0 and abort DMA operation.
-    etherdev_reg_write(CR, RD2 | STA);
+    etherdev_reg_write(CR, ABORT | STA);
 
     // Wait until pending transmit operation completes.
     while(etherdev_reg_read(CR) & TXP) continue;
 
     // Wait until pending transmit operation completes.
     while(etherdev_reg_read(CR) & TXP) continue;
@@ -278,7 +247,7 @@ void etherdev_send(void)
     etherdev_reg_write(RBCR1, (unsigned char)(uip_len >> 8));
 
     // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
     etherdev_reg_write(RBCR1, (unsigned char)(uip_len >> 8));
 
     // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
-    etherdev_reg_write(CR, RD1 | STA);
+    etherdev_reg_write(CR, WRITE | STA);
 
     // DMA transfer packet from uip_buf & uip_appdata to RTL8019AS local
     // transmit buffer memory.
 
     // DMA transfer packet from uip_buf & uip_appdata to RTL8019AS local
     // transmit buffer memory.
@@ -294,7 +263,7 @@ void etherdev_send(void)
     etherdev_reg_write(ISR, RDC);
 
     // Abort/ complete DMA operation.
     etherdev_reg_write(ISR, RDC);
 
     // Abort/ complete DMA operation.
-    etherdev_reg_write(CR, RD2 | STA);
+    etherdev_reg_write(CR, ABORT | STA);
 
     // Set transmit page start to indicate packet start.
     etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
 
     // Set transmit page start to indicate packet start.
     etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
@@ -310,255 +279,234 @@ void etherdev_send(void)
     etherdev_reg_write(TBCR1, (unsigned char)(uip_len >> 8));
 
     // Issue command for RTL8019AS to transmit packet from it's local buffer.
     etherdev_reg_write(TBCR1, (unsigned char)(uip_len >> 8));
 
     // Issue command for RTL8019AS to transmit packet from it's local buffer.
-    etherdev_reg_write(CR, RD2 | TXP | STA);
+    etherdev_reg_write(CR, ABORT | TXP | STA);
 
     return;
 }
 
 
 
     return;
 }
 
 
-/*
-                                                                     
-                           etherdev_read()                           
-                                                                     
- This function will read an entire IP packet into the uip_buf.       
- If it must wait for more than 0.5 seconds, it will return with      
- the return value 0. Otherwise, when a full packet has been read     
- into the uip_buf buffer, the length of the packet is returned.      
-                                                                     
- */
-unsigned int etherdev_read(void)
-{    
-    unsigned int bytes_read;
-
-    /* tick_count threshold should be 12 for 0.5 sec bail-out
-       One second (24) worked better for me, but socket recycling
-       is then slower. I set UIP_TIME_WAIT_TIMEOUT 60 in uipopt.h
-       to counter this. Retransmission timing etc. is affected also. */
-    while ((!(bytes_read = etherdev_poll())) && (tick_count < 12)) continue;
-
-    tick_count = 0;
+static void etherdev_reset()
+{
+    bit retransmit = etherdev_reg_read(CR) & TXP;
 
 
-    return bytes_read;
-}
+    // If the receive buffer ring has overflowed we dump the whole
+    // thing and start over. There is no way of knowing whether the
+    // data it contains is uncorrupted, or will cause us grief.
 
 
+    // Stop RTL8019AS and abort DMA operation.
+    etherdev_reg_write(CR, ABORT | STP);
 
 
-/*
-                                                                     
-                           etherdev_poll()                           
-                                                                     
- Poll the RTL8019AS ethernet device for an available packet.         
-                                                                     
- */
-static unsigned int etherdev_poll(void)
-{
-    unsigned int len = 0;
+    // Wait for controller to halt after any current tx completes.
+    while(!(etherdev_reg_read(ISR) & RST)) continue;
 
 
-    leds1 = ~0x01;
-    leds2 = ~etherdev_reg_read(ISR);
-    sleep(0);
+    // Reset remote byte count registers.
+    etherdev_reg_write(RBCR0, 0x00);
+    etherdev_reg_write(RBCR1, 0x00);
 
 
-    if(etherdev_reg_read(ISR) & OVW)
+    // Check whether currently transmitting a packet.
+    if(retransmit)
     {
     {
-        leds1 = ~0x02;
-        leds2 = ~etherdev_reg_read(BNRY);
-        sleep(5);
-        leds1 = ~0x04;
-        leds2 = ~etherdev_reg_read(CURR);
-        sleep(5);
+        // If neither a successful transmission nor a tx abort error 
+        // has occured, then flag current tx packet for resend.
+        if(etherdev_reg_read(ISR) & (PTX | TXE))
+        {
+            retransmit = 0;
+        }
     }
 
     }
 
-    // Check if there is a packet in the rx buffer.
-    if(etherdev_reg_read(ISR) & PRX)
-    {
-        // Check if the rx buffer has overflowed.
-        if(etherdev_reg_read(ISR) & OVW)
-        {
-            bit retransmit = 0;
+    // Set transmit configuration register to loopback internally.
+    etherdev_reg_write(TCR, MODE1);
 
 
-            // If the receive buffer ring has overflowed we dump the whole
-            // thing and start over. There is no way of knowing whether the
-            // data it contains is uncorrupted, or will cause us grief.
+    // Restart the RTL8019AS.
+    etherdev_reg_write(CR, ABORT | STA);
 
 
-            // Stop RTL8019AS and abort DMA operation.
-            etherdev_reg_write(CR, RD2 | STP);
+    // Re-initialise last receive buffer read pointer.
+    etherdev_reg_write(BNRY, ETH_RX_PAGE_START);
 
 
-            // Reset remote byte count registers.
-            etherdev_reg_write(RBCR0, 0x00);
-            etherdev_reg_write(RBCR1, 0x00);
+    // Select RTL8019AS register page 1.
+    ETHERDEV_SELECT_REG_PAGE(1);
 
 
-            // Wait for controller to halt after any current tx completes.
-            while(!(etherdev_reg_read(ISR) & RST)) continue;
+    // Re-initialise current packet receive buffer page pointer.
+    etherdev_reg_write(CURR, ETH_RX_PAGE_START + 1);
 
 
-            // Check whether currently transmitting a packet.
-            if(etherdev_reg_read(CR) & TXP)
-            {
-                // If neither a successful transmission nor a tx abort error 
-                // has occured, then flag current tx packet for resend.
-                if(!((etherdev_reg_read(ISR) & PTX)
-                                          || (etherdev_reg_read(ISR) & TXE)))
-                {
-                    retransmit = 1;
-                }
-            }
+    // Select RTL8019AS register page 0.
+    ETHERDEV_SELECT_REG_PAGE(0);
 
 
-            // Set transmit configuration register to loopback internally.
-            etherdev_reg_write(TCR, LB0);
+    // Clear rx buffer overflow & packet received interrupt flags.
+    etherdev_reg_write(ISR, PRX | OVW);
 
 
-            // Restart the RTL8019AS.
-            etherdev_reg_write(CR, RD2 | STA);
+    // Re-itialise transmit configuration reg for normal operation.
+    etherdev_reg_write(TCR, MODE0);
 
 
-            // Re-initialise last receive buffer read pointer.
-            etherdev_reg_write(BNRY, ETH_RX_PAGE_START);
+    if(retransmit)
+    {
+        // Retransmit packet in RTL8019AS local tx buffer.
+        etherdev_reg_write(CR, ABORT | TXP | STA);
+    }
+}
 
 
-            // Select RTL8019AS register page 1.
-            ETHERDEV_SELECT_REG_PAGE(1);
 
 
-            // Re-initialise current packet receive buffer page pointer.
-            etherdev_reg_write(CURR, ETH_RX_PAGE_START+1);
+unsigned int etherdev_read(void)
+{    
+    unsigned int len = 0;
 
 
-            // Select RTL8019AS register page 0.
-            ETHERDEV_SELECT_REG_PAGE(0);
+    // Check if the rx buffer has overflowed.
+    if (etherdev_reg_read(ISR) & OVW)
+    {
+        unsigned char current;
 
 
-            // Clear rx buffer overflow & packet received interrupt flags.
-            etherdev_reg_write(ISR, PRX | OVW);
+        // Select RTL8019AS register page 1.
+        ETHERDEV_SELECT_REG_PAGE(1);
 
 
-            // Re-itialise transmit configuration reg for normal operation.
-            etherdev_reg_write(TCR, 0x00);
-        
-            if(retransmit)
-            {
-                // Retransmit packet in RTL8019AS local tx buffer.
-                etherdev_reg_write(CR, RD2 | TXP | STA);
-            }
-        }
-        else // Rx buffer has not overflowed, so read a packet into uip_buf.
-        {
-            unsigned int i;
-            unsigned char next_rx_packet;
-            unsigned char current;
-            unsigned char bnry;
-            unsigned char status;
-
-            // Retrieve packet header. (status, next_ptr, length_l, length_h)
-
-            // Set remote DMA start address registers to packet header.
-            bnry = etherdev_reg_read(BNRY) + 1;
-            if (bnry >= ETH_RX_PAGE_STOP)
-                bnry = ETH_RX_PAGE_START;
-            etherdev_reg_write(RSAR0, 0x00);
-            etherdev_reg_write(RSAR1, bnry);
+        // Retrieve current receive buffer page
+        current = etherdev_reg_read(CURR);
 
 
-            // Select RTL8019AS register page 1.
-            ETHERDEV_SELECT_REG_PAGE(1);
+        // Select RTL8019AS register page 1.
+        ETHERDEV_SELECT_REG_PAGE(0);
 
 
-            // Retrieve current receive buffer page
-            current = etherdev_reg_read(CURR);
+        if (etherdev_reg_read(BNRY) == current)
+        {
 
 
-            // Select RTL8019AS register page 1.
-            ETHERDEV_SELECT_REG_PAGE(0);
+            leds1 = ~0x01;
+            leds2 = ~etherdev_reg_read(ISR);
+            sleep(5);
+            leds1 = ~0x02;
+            leds2 = ~etherdev_reg_read(BNRY);
+            sleep(5);
+            leds1 = ~0x04;
+            leds2 = ~current;
+            sleep(5);
+
+            etherdev_reset();
+        }
+    }
+    // Check if there is a packet in the rx buffer.
+    else if (etherdev_reg_read(ISR) & PRX)
+    {
+        unsigned int i;
+        unsigned char next_rx_packet;
+        unsigned char current;
+        unsigned char bnry;
+        unsigned char status;
 
 
-            // Check if last packet has been removed from rx buffer.
-            if(bnry == current)
-            {
-                // Clear packet received interrupt flag.
-                etherdev_reg_write(ISR, PRX);
-                return 0;
-            }
+        // Retrieve packet header. (status, next_ptr, length_l, length_h)
 
 
-            // Set remote DMA byte count registers to packet header length.
-            etherdev_reg_write(RBCR0, 0x04);
-            etherdev_reg_write(RBCR1, 0x00);
+        // Set remote DMA start address registers to packet header.
+        bnry = etherdev_reg_read(BNRY) + 1;
+        if (bnry >= ETH_RX_PAGE_STOP)
+            bnry = ETH_RX_PAGE_START;
+        etherdev_reg_write(RSAR0, 0x00);
+        etherdev_reg_write(RSAR1, bnry);
 
 
-            // Clear remote DMA complete interrupt status register bit.
-            etherdev_reg_write(ISR, RDC);
+        // Select RTL8019AS register page 1.
+        ETHERDEV_SELECT_REG_PAGE(1);
 
 
-            // Initiate DMA transfer of packet header.
-            etherdev_reg_write(CR, RD0 | STA);
+        // Retrieve current receive buffer page
+        current = etherdev_reg_read(CURR);
 
 
-            // Packet status.
-            status = etherdev_reg_read(RDMA);
+        // Select RTL8019AS register page 1.
+        ETHERDEV_SELECT_REG_PAGE(0);
 
 
-            // Save next packet pointer.
-            next_rx_packet = etherdev_reg_read(RDMA);
+        // Check if last packet has been removed from rx buffer.
+        if(bnry == current)
+        {
+            // Clear packet received interrupt flag.
+            etherdev_reg_write(ISR, PRX | RXE);
+            return 0;
+        }
 
 
-            // Retrieve packet data length and subtract CRC bytes.
-            len =  etherdev_reg_read(RDMA);
-            len += etherdev_reg_read(RDMA) << 8;
-            len -= 4;
+        // Set remote DMA byte count registers to packet header length.
+        etherdev_reg_write(RBCR0, 0x04);
+        etherdev_reg_write(RBCR1, 0x00);
 
 
-            // Wait until remote DMA operation completes.
-            while(!(etherdev_reg_read(ISR) & RDC)) continue;
+        // Clear remote DMA complete interrupt status register bit.
+        etherdev_reg_write(ISR, RDC);
 
 
-            // Abort/ complete DMA operation.
-            etherdev_reg_write(CR, RD2 | STA);
+        // Initiate DMA transfer of packet header.
+        etherdev_reg_write(CR, READ | STA);
 
 
-            // Limpia ISR
-            etherdev_reg_write(ISR, RDC);
+        // Packet status.
+        status = etherdev_reg_read(RDMA);
 
 
-            if (len < 60 || len > 1518) // XXX DROP!!!
-            {
-                leds1 = ~0xff;
-                leds2 = ~0x01;
-                while(1);
-            }
+        // Save next packet pointer.
+        next_rx_packet = etherdev_reg_read(RDMA);
 
 
-            if ((status & 0x0F) != RXSOK) // XXX DROP!!!
-            {
-                leds1 = ~0xff;
-                leds2 = ~0x02;
-                while(1);
-            }
+        // Retrieve packet data length and subtract CRC bytes.
+        len =  etherdev_reg_read(RDMA);
+        len += etherdev_reg_read(RDMA) << 8;
+        len -= 4;
 
 
-            // Retrieve packet data.
+        // Wait until remote DMA operation completes.
+        while(!(etherdev_reg_read(ISR) & RDC)) continue;
 
 
-            // Check if incoming packet will fit into rx buffer.
-            if(len <= sizeof(uip_buf))
-            {
+        // Abort/ complete DMA operation.
+        etherdev_reg_write(CR, ABORT | STA);
 
 
-                // Set remote DMA start address registers to packet data.
-                etherdev_reg_write(RSAR0, 0x04);
-                etherdev_reg_write(RSAR1, bnry);
+        // Limpia ISR
+        etherdev_reg_write(ISR, RDC);
 
 
-                // Set remote DMA byte count registers to packet data length.
-                etherdev_reg_write(RBCR0, (unsigned char)(len & 0xFF));
-                etherdev_reg_write(RBCR1, (unsigned char)(len >> 8));
+        // Si es un paquete inválido, lo dropeamos
+        if (len < 60 || len > 1518)
+        {
+            len = 0;
+            goto drop;
+        }
 
 
-                // Initiate DMA transfer of packet data.
-                etherdev_reg_write(CR, RD0 | STA);
+        // Si hubo un error, también lo dropeamos
+        if ((status & 0x0F) != RXSOK)
+        {
+            len = 0;
+            goto drop;
+        }
 
 
-                // Read packet data directly into uip_buf.
-                uip_len = len;
-                for(i = 0; i < 14; i++)
-                {
-                    etherdev_reg_read(RDMA); // XXX descarto cabecera eth
-                }
-                for(i = 14; i < len; i++)
-                {
-                    uip_buf[i] = etherdev_reg_read(RDMA); // XXX copio el resto
-                }
+        // Retrieve packet data.
 
 
-                // Wait until remote DMA operation complete.
-                while(!(etherdev_reg_read(ISR) & RDC)) continue;
+        // Check if incoming packet will fit into rx buffer.
+        if(len <= sizeof(uip_buf))
+        {
+
+            // Set remote DMA start address registers to packet data.
+            etherdev_reg_write(RSAR0, 0x04);
+            etherdev_reg_write(RSAR1, bnry);
 
 
-                // Abort/ complete DMA operation.
-                etherdev_reg_write(CR, RD2 | STA);
+            // Set remote DMA byte count registers to packet data length.
+            etherdev_reg_write(RBCR0, (unsigned char)(len & 0xFF));
+            etherdev_reg_write(RBCR1, (unsigned char)(len >> 8));
 
 
-                // Clear remote DMA complete interrupt status register bit.
-                etherdev_reg_write(ISR, RDC);
+            // Initiate DMA transfer of packet data.
+            etherdev_reg_write(CR, READ | STA);
 
 
+            // Read packet data directly into uip_buf.
+            uip_len = len;
+            for(i = 0; i < 14; i++)
+            {
+                etherdev_reg_read(RDMA); // XXX descarto cabecera eth
             }
             }
-            else
+            for(i = 14; i < len; i++)
             {
             {
-                // Incoming packet too big, so dump it.
-                len = 0;
+                uip_buf[i] = etherdev_reg_read(RDMA); // XXX copio el resto
             }
 
             }
 
-            // Advance boundary pointer to next packet start.
-            etherdev_reg_write(BNRY, next_rx_packet - 1);
+            // Wait until remote DMA operation complete.
+            while(!(etherdev_reg_read(ISR) & RDC)) continue;
+
+            // Abort/ complete DMA operation.
+            etherdev_reg_write(CR, ABORT | STA);
+
+            // Clear remote DMA complete interrupt status register bit.
+            etherdev_reg_write(ISR, RDC);
 
 
-            // Select RTL8019AS register page 0.
-            ETHERDEV_SELECT_REG_PAGE(0);
         }
         }
+        else
+        {
+            // Incoming packet too big, so dump it.
+            len = 0;
+        }
+
+drop:
+        // Advance boundary pointer to next packet start.
+        etherdev_reg_write(BNRY, next_rx_packet - 1);
+
     }
 
     return len;
     }
 
     return len;