// vim: set et sw=4 sts=4 :
+#include "types.h"
#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 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
#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_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) \
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)
{
IOW = 1;
NICE = 1;
- // Set register data port as input again.
- ETH_DATA_PORT = ETH_DATA_PORT_MASK;
-
return;
}
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.
- NICE = 0;
+ NICE = 0;
IOR = 0;
// Read register data from port.
// Disable register data output from RTL8019AS.
IOR = 1;
- NICE = 1;
+ NICE = 1;
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()
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;
return 0;
}
- // Select RTL8019AS register page 0.
- ETHERDEV_SELECT_REG_PAGE(0);
-
// 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.
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);
+
+ // 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);
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
- etherdev_reg_write(CURR, ETH_RX_PAGE_START);
+ etherdev_reg_write(CURR, ETH_RX_PAGE_START + 1);
// 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.
- etherdev_reg_write(CR, RD2 | STP);
+ etherdev_reg_write(CR, ABORT | STP);
// Restart RTL8019AS.
- etherdev_reg_write(CR, RD2 | STA);
+ etherdev_reg_write(CR, ABORT | STA);
// 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);
-
- // 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;
}
// 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;
- // Clear remote DMA complete interrupt status register bit.
- etherdev_reg_write(ISR, RDC);
-
// Set remote DMA start address registers to indicate where to load packet.
etherdev_reg_write(RSAR0, 0x00);
etherdev_reg_write(RSAR1, ETH_TX_PAGE_START);
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.
// Wait until remote DMA operation complete.
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);
+ etherdev_reg_write(CR, ABORT | STA);
// Set transmit page start to indicate packet start.
etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
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;
}
-/*
-
- 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;
+static void etherdev_reset()
+{
+ bit retransmit = etherdev_reg_read(CR) & TXP;
- tick_count = 0;
+ // 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.
- return bytes_read;
-}
+ // Stop RTL8019AS and abort DMA operation.
+ etherdev_reg_write(CR, ABORT | STP);
+ // Wait for controller to halt after any current tx completes.
+ while(!(etherdev_reg_read(ISR) & RST)) continue;
-/*
-
- etherdev_poll()
-
- Poll the RTL8019AS ethernet device for an available packet.
-
- */
-static unsigned int etherdev_poll(void)
-{
- unsigned int len = 0;
+ // Reset remote byte count registers.
+ etherdev_reg_write(RBCR0, 0x00);
+ etherdev_reg_write(RBCR1, 0x00);
- // Check if there is a packet in the rx buffer.
- if(etherdev_reg_read(ISR) & PRX)
+ // Check whether currently transmitting a packet.
+ if(retransmit)
{
- // Check if the rx buffer has overflowed.
- if(etherdev_reg_read(ISR) & OVW)
+ // 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))
{
- bit retransmit = 0;
+ retransmit = 0;
+ }
+ }
- // 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.
+ // Set transmit configuration register to loopback internally.
+ etherdev_reg_write(TCR, MODE1);
- // Stop RTL8019AS and abort DMA operation.
- etherdev_reg_write(CR, RD2 | STP);
+ // Restart the RTL8019AS.
+ etherdev_reg_write(CR, ABORT | STA);
- // Reset remote byte count registers.
- etherdev_reg_write(RBCR0, 0x00);
- etherdev_reg_write(RBCR1, 0x00);
+ // Re-initialise last receive buffer read pointer.
+ etherdev_reg_write(BNRY, ETH_RX_PAGE_START);
- // Wait for controller to halt after any current tx completes.
- while(!(etherdev_reg_read(ISR) & RST)) continue;
+ // Select RTL8019AS register page 1.
+ ETHERDEV_SELECT_REG_PAGE(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;
- }
- }
+ // Re-initialise current packet receive buffer page pointer.
+ etherdev_reg_write(CURR, ETH_RX_PAGE_START + 1);
- // Set transmit configuration register to loopback internally.
- etherdev_reg_write(TCR, LB0);
+ // Select RTL8019AS register page 0.
+ ETHERDEV_SELECT_REG_PAGE(0);
- // Restart the RTL8019AS.
- etherdev_reg_write(CR, RD2 | STA);
+ // Clear rx buffer overflow & packet received interrupt flags.
+ etherdev_reg_write(ISR, PRX | OVW);
- // Re-initialise last receive buffer read pointer.
- etherdev_reg_write(BNRY, ETH_RX_PAGE_START);
+ // Re-itialise transmit configuration reg for normal operation.
+ etherdev_reg_write(TCR, MODE0);
- // Select RTL8019AS register page 1.
- ETHERDEV_SELECT_REG_PAGE(1);
+ if(retransmit)
+ {
+ // Retransmit packet in RTL8019AS local tx buffer.
+ etherdev_reg_write(CR, ABORT | TXP | STA);
+ }
+}
- // Re-initialise current packet receive buffer page pointer.
- etherdev_reg_write(CURR, ETH_RX_PAGE_START);
- // Select RTL8019AS register page 0.
- ETHERDEV_SELECT_REG_PAGE(0);
+unsigned int etherdev_read(void)
+{
+ unsigned int len = 0;
- // Clear rx buffer overflow & packet received interrupt flags.
- etherdev_reg_write(ISR, PRX | OVW);
+ // Check if the rx buffer has overflowed.
+ if (etherdev_reg_read(ISR) & OVW)
+ {
+ unsigned char current;
- // 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.
+ // Select RTL8019AS register page 1.
+ ETHERDEV_SELECT_REG_PAGE(1);
+
+ // Retrieve current receive buffer page
+ current = etherdev_reg_read(CURR);
+
+ // Select RTL8019AS register page 1.
+ ETHERDEV_SELECT_REG_PAGE(0);
+
+ if (etherdev_reg_read(BNRY) == current)
{
- unsigned int i;
- unsigned char next_rx_packet;
- unsigned char current;
- // Retrieve packet header. (status, next_ptr, length_l, length_h)
+ 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;
+
+ // Retrieve packet header. (status, next_ptr, length_l, length_h)
- // Clear remote DMA complete interrupt status register bit.
- etherdev_reg_write(ISR, RDC);
+ // 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);
- // Set remote DMA start address registers to packet header.
- etherdev_reg_write(RSAR0, 0x00);
- etherdev_reg_write(RSAR1, etherdev_reg_read(BNRY));
+ // Select RTL8019AS register page 1.
+ ETHERDEV_SELECT_REG_PAGE(1);
- // Set remote DMA byte count registers to packet header length.
- etherdev_reg_write(RBCR0, 0x04);
- etherdev_reg_write(RBCR1, 0x00);
+ // Retrieve current receive buffer page
+ current = etherdev_reg_read(CURR);
- // Initiate DMA transfer of packet header.
- etherdev_reg_write(CR, RD0 | STA);
+ // Select RTL8019AS register page 1.
+ ETHERDEV_SELECT_REG_PAGE(0);
- // Drop packet status. We don't use it.
- 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;
+ }
- // Save next packet pointer.
- next_rx_packet = etherdev_reg_read(RDMA);
+ // Set remote DMA byte count registers to packet header length.
+ etherdev_reg_write(RBCR0, 0x04);
+ etherdev_reg_write(RBCR1, 0x00);
- // Retrieve packet data length and subtract CRC bytes.
- len = etherdev_reg_read(RDMA);
- len += etherdev_reg_read(RDMA) << 8;
- len -= 4;
+ // Clear remote DMA complete interrupt status register bit.
+ etherdev_reg_write(ISR, RDC);
- // Wait until remote DMA operation completes.
- while(!(etherdev_reg_read(ISR) & RDC)) continue;
+ // Initiate DMA transfer of packet header.
+ etherdev_reg_write(CR, READ | STA);
- // Abort/ complete DMA operation.
- etherdev_reg_write(CR, RD2 | STA);
+ // Packet status.
+ status = etherdev_reg_read(RDMA);
+ // Save next packet pointer.
+ next_rx_packet = etherdev_reg_read(RDMA);
- // Retrieve packet data.
+ // Retrieve packet data length and subtract CRC bytes.
+ len = etherdev_reg_read(RDMA);
+ len += etherdev_reg_read(RDMA) << 8;
+ len -= 4;
- // Check if incoming packet will fit into rx buffer.
- if(len <= sizeof(uip_buf))
- {
- // Clear remote DMA complete interrupt status register bit.
- etherdev_reg_write(ISR, RDC);
+ // Wait until remote DMA operation completes.
+ while(!(etherdev_reg_read(ISR) & RDC)) continue;
- // Set remote DMA start address registers to packet data.
- etherdev_reg_write(RSAR0, 0x04);
- etherdev_reg_write(RSAR1, etherdev_reg_read(BNRY));
+ // Abort/ complete DMA operation.
+ etherdev_reg_write(CR, ABORT | 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));
+ // Limpia ISR
+ etherdev_reg_write(ISR, RDC);
- // Initiate DMA transfer of packet data.
- etherdev_reg_write(CR, RD0 | STA);
+ // Si es un paquete inválido, lo dropeamos
+ if (len < 60 || len > 1518)
+ {
+ len = 0;
+ goto drop;
+ }
- // Read packet data directly into uip_buf.
- for(i = 0; i < len; i++)
- {
- *(uip_buf + i) = etherdev_reg_read(RDMA);
- }
+ // Si hubo un error, también lo dropeamos
+ if ((status & 0x0F) != RXSOK)
+ {
+ len = 0;
+ goto drop;
+ }
+
+ // 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))
+ {
- // Abort/ complete DMA operation.
- etherdev_reg_write(CR, RD2 | STA);
+ // Set remote DMA start address registers to packet data.
+ etherdev_reg_write(RSAR0, 0x04);
+ etherdev_reg_write(RSAR1, bnry);
+ // 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));
+
+ // 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);
-
- // Select RTL8019AS register page 1.
- ETHERDEV_SELECT_REG_PAGE(1);
+ // Wait until remote DMA operation complete.
+ while(!(etherdev_reg_read(ISR) & RDC)) continue;
- // Retrieve current receive buffer page
- current = etherdev_reg_read(CURR);
+ // Abort/ complete DMA operation.
+ etherdev_reg_write(CR, ABORT | STA);
- // Select RTL8019AS register page 0.
- ETHERDEV_SELECT_REG_PAGE(0);
+ // Clear remote DMA complete interrupt status register bit.
+ etherdev_reg_write(ISR, RDC);
- // Check if last packet has been removed from rx buffer.
- if(next_rx_packet == current)
- {
- // Clear packet received interrupt flag.
- etherdev_reg_write(ISR, PRX);
- }
}
+ 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;