X-Git-Url: https://git.llucax.com/z.facultad/66.09/etherled.git/blobdiff_plain/cbf2122a2f610a2b92f1dfcb0f554b4bf7c4757e..d6c5f7cf0e7f53c9251477b092e8b208a313e928:/src/dp8390.c?ds=sidebyside diff --git a/src/dp8390.c b/src/dp8390.c index 6392307..76d0c6d 100644 --- a/src/dp8390.c +++ b/src/dp8390.c @@ -1,26 +1,23 @@ // vim: set et sw=4 sts=4 : +#include "debug.h" #include "eth.h" #include "dp8390.h" -#ifdef DEBUG -void sleep(unsigned char); -#ifdef SDCC -static xdata at 0x0080 byte leds0; -static xdata at 0x00c0 byte leds1; -#else -static byte xdata leds0 _at_ 0x0080; -static byte xdata leds1 _at_ 0x00c0; -#endif -#endif - -/// Datos persistentes del módulo -static union +/** Tamaño del frame */ +byte netdev_len; + +// Próximo frame a obtener +static struct { - byte send_len; ///> Tamaño del frame que será enviado - byte next_pkt; ///> Próximo frame a obtener + byte next_buf; + byte curr_buf; + byte curr_off; } -persistent; +recv_state; + +/// Tamaño de la cabecera de los buffers de la placa de red +#define BUF_HDR_SIZE 4 /// Cambia de página sin modificar los demás bits del CR #define SELECT_REG_PAGE(page) \ @@ -43,6 +40,7 @@ persistent; static void write_reg(unsigned char reg, unsigned char wr_data) { + leds_lock(); // Select register address. ADDR_PORT &= ~ADDR_PORT_MASK; ADDR_PORT |= reg; @@ -59,11 +57,13 @@ static void write_reg(unsigned char reg, unsigned char wr_data) // Set register data port as input again. DATA_PORT = DATA_PORT_MASK; + leds_unlock(); } static unsigned char read_reg(unsigned char reg) { + leds_lock(); // Select register address. ADDR_PORT &= ~ADDR_PORT_MASK; ADDR_PORT |= reg; @@ -79,6 +79,7 @@ static unsigned char read_reg(unsigned char reg) IOR = 1; NICE = 1; + leds_unlock(); return reg; } @@ -149,6 +150,8 @@ static void reset() */ bool netdev_init() { + byte i; + // Set IOR & IOW as they're active low. IOR = 1; IOW = 1; @@ -201,18 +204,11 @@ bool netdev_init() write_reg(RSAR0, 0u); // En la dirección 0x0000 write_reg(RSAR1, 0u); write_reg(CR, READ); // Comienza lectura - eth_addr_local[0] = read_reg(RDMA); - read_reg(RDMA); // Ignoramos porque viene como un word - eth_addr_local[1] = read_reg(RDMA); - read_reg(RDMA); // Ignoramos porque viene como un word - eth_addr_local[2] = read_reg(RDMA); - read_reg(RDMA); // Ignoramos porque viene como un word - eth_addr_local[3] = read_reg(RDMA); - read_reg(RDMA); // Ignoramos porque viene como un word - eth_addr_local[4] = read_reg(RDMA); - read_reg(RDMA); // Ignoramos porque viene como un word - eth_addr_local[5] = read_reg(RDMA); - read_reg(RDMA); // Ignoramos porque viene como un word + for (i = 0; i < ETH_ADDR_SIZE; ++i) + { + eth_addr_local[i] = read_reg(RDMA); + read_reg(RDMA); // Ignoramos porque viene como un word + } // Abort/ complete DMA operation. ABORT_DMA(STOP); @@ -236,12 +232,8 @@ bool netdev_init() write_reg(CURR, RX_PAGE_START + 1); // Set physical address - write_reg(PAR0, eth_addr_local[0]); - write_reg(PAR1, eth_addr_local[1]); - write_reg(PAR2, eth_addr_local[2]); - write_reg(PAR3, eth_addr_local[3]); - write_reg(PAR4, eth_addr_local[4]); - write_reg(PAR5, eth_addr_local[5]); + for (i = 0; i < ETH_ADDR_SIZE; ++i) + write_reg(PAR_BASE + i, eth_addr_local[i]); // Restart RTL8019AS. write_reg(CR, START); @@ -256,34 +248,70 @@ bool netdev_init() } -/** Comienza el envío de un nuevo frame - * @param len Tamaño del frame a enviar - */ +/** Comienza el envío de un nuevo frame */ void netdev_send_start() { - persistent.send_len = 0; // Wait until pending transmit operation completes. - while(read_reg(CR) & TXP) continue; + while (read_reg(CR) & TXP) continue; + write_reg(ISR, PTX); // Limpio bit de interrupción // Set remote DMA start address registers to indicate where to load packet. write_reg(RSAR0, 0u); write_reg(RSAR1, TX_PAGE_START); +} + +/** Finaliza el envío del frame + * @precond netdev_send_start() debe haber sido ejecutada + * @precond se copiaron datos al dispositivo para enviar + * @param len Cantidad de bytes a transmitir + */ +void netdev_send_end(byte len) +{ + // Set transmit page start to indicate packet start. + write_reg(TPSR, TX_PAGE_START); + + // Ethernet packets must be > 60 bytes, otherwise are rejected as runts. + if (len < MIN_PACKET_LEN) + len = MIN_PACKET_LEN; + // Set transmit byte count registers to indicate packet length. + write_reg(TBCR0, len); + write_reg(TBCR1, 0u); + + // Issue command for RTL8019AS to transmit packet from it's local buffer. + write_reg(CR, START | TXP); +} + +void netdev_write_start(byte len) +{ // Set remote DMA byte count registers to indicate length of packet load. - write_reg(RBCR0, MAX_PACKET_LEN); // Tamaño máximo en principio + write_reg(RBCR0, len); write_reg(RBCR1, 0u); // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS. - write_reg(CR, WRITE | STA); + write_reg(CR, WRITE); +} + +void netdev_write_start_at(byte offset, byte len) +{ + // Set remote DMA start address registers to packet data. + write_reg(RSAR0, offset); + write_reg(RSAR1, TX_PAGE_START); + + // Set remote DMA byte count registers to indicate length of packet load. + write_reg(RBCR0, len); + write_reg(RBCR1, 0u); + + // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS. + write_reg(CR, WRITE); } /** Escribe un byte al buffer de la placa de red para ser enviado * @precond netdev_send_start() debe haber sido ejecutada * @param b Byte a enviar */ -void netdev_send_byte(byte b) +void netdev_write_byte(byte b) { - persistent.send_len++; write_reg(RDMA, b); } @@ -291,95 +319,57 @@ void netdev_send_byte(byte b) * @precond netdev_send_start() debe haber sido ejecutada * @param w Word a enviar */ -void netdev_send_word(uint16 w) +void netdev_write_word(uint16 w) { - persistent.send_len += 2; write_reg(RDMA, HIGH(w)); write_reg(RDMA, LOW(w)); } -/** Finaliza el envío del frame - * @precond netdev_send_start() debe haber sido ejecutada - */ -void netdev_send_end() +void netdev_write_end() { // Abort/ complete DMA operation. ABORT_DMA(START); - - // Set transmit page start to indicate packet start. - write_reg(TPSR, TX_PAGE_START); - - // Ethernet packets must be > 60 bytes, otherwise are rejected as runts. - if (persistent.send_len < MIN_PACKET_LEN) - { - persistent.send_len = MIN_PACKET_LEN; - } - - // Set transmit byte count registers to indicate packet length. - write_reg(TBCR0, LOW(persistent.send_len)); - write_reg(TBCR1, 0u); - - // Issue command for RTL8019AS to transmit packet from it's local buffer. - write_reg(CR, START | TXP); } /** Comienza la lectura de un nuevo frame - * @return Cantidad de bytes del frame leído + * @return Cantidad de bytes a recibir */ byte netdev_recv_start() -{ +{ // Check if the rx buffer has overflowed. if (read_reg(ISR) & OVW) { byte current; - // Select RTL8019AS register page 1. SELECT_REG_PAGE(1); - - // Retrieve current receive buffer page current = read_reg(CURR); - - // Select RTL8019AS register page 1. SELECT_REG_PAGE(0); + // Hack: a veces reporta mal el flag de OVW, así que verificamos que + // relamente haya habido overflow. if (read_reg(BNRY) == current) { -#ifdef DEBUG - leds1 = ~0x01; - leds2 = ~read_reg(ISR); - sleep(5); - leds1 = ~0x02; - leds2 = ~read_reg(BNRY); - sleep(5); - leds1 = ~0x04; - leds2 = ~current; - sleep(5); -#endif + printb(read_reg(ISR), 0x01); + printb(read_reg(BNRY), 0x02); + printb(current, 0x04); + printb(0x00, 0x00); reset(); } - return 0u; + return 0; } // Check if there is a packet in the rx buffer. else if (read_reg(ISR) & PRX) { - struct buf_hdr_t - { - byte status; // Estado del frame recibido - byte next; // Offset del próximo frame - uint16 len; // Tamaño del frame - } - buf_hdr; + byte status; + byte len; byte current; - byte bnry; // Retrieve packet header. (status, next_ptr, length_l, length_h) - // Set remote DMA start address registers to packet header. - bnry = read_reg(BNRY) + 1; - if (bnry >= RX_PAGE_STOP) - bnry = RX_PAGE_START; - write_reg(RSAR0, 0u); - write_reg(RSAR1, bnry); + // Obtiene el buffer a leer actualmente + recv_state.curr_buf = read_reg(BNRY) + 1; + if (recv_state.curr_buf >= RX_PAGE_STOP) + recv_state.curr_buf = RX_PAGE_START; // Select RTL8019AS register page 1. SELECT_REG_PAGE(1); @@ -391,65 +381,74 @@ byte netdev_recv_start() SELECT_REG_PAGE(0); // Check if last packet has been removed from rx buffer. - if(bnry == current) + if(recv_state.curr_buf == current) { // Clear packet received interrupt flag. write_reg(ISR, PRX | RXE); - return 0u; + return 0; } // Set remote DMA byte count registers to packet header length. - write_reg(RBCR0, sizeof(struct buf_hdr_t)); - write_reg(RBCR1, 0u); - - // Clear remote DMA complete interrupt status register bit. - write_reg(ISR, RDC); - - // Initiate DMA transfer of packet header. - write_reg(CR, READ); + recv_state.curr_off = 0; + netdev_read_start(BUF_HDR_SIZE); // Packet status. - buf_hdr.status = read_reg(RDMA); + status = netdev_read_byte(); // Save next packet pointer. - buf_hdr.next = persistent.next_pkt = read_reg(RDMA); + recv_state.next_buf = netdev_read_byte() - 1; // Retrieve packet data length and subtract CRC bytes. - buf_hdr.len = read_reg(RDMA) - sizeof(struct buf_hdr_t); + len = netdev_read_byte() - BUF_HDR_SIZE; // Si es muy grande, muy chico o hubo error, lo descartamos - if ((buf_hdr.len < MIN_PACKET_LEN) || (buf_hdr.len > MAX_PACKET_LEN) - || ((buf_hdr.status & 0x0F) != RXSOK) - || read_reg(RDMA)) // Parte alta del tamaño + if ((len < MIN_PACKET_LEN) || (len > MAX_PACKET_LEN) + || ((status & 0x0F) != RXSOK) + || netdev_read_byte()) // Parte alta del tamaño { - ABORT_DMA(START); // Termina DMA - write_reg(BNRY, buf_hdr.next - 1); // Pasa al próximo frame + // Terminamos DMA y pasamos al próximo frame + netdev_read_end(); + write_reg(BNRY, recv_state.next_buf); return 0; } // Abort/ complete DMA operation. - ABORT_DMA(START); + netdev_read_end(); - // Set remote DMA start address registers to packet data. - write_reg(RSAR0, sizeof(struct buf_hdr_t)); - write_reg(RSAR1, bnry); + return len; + } - // Set remote DMA byte count registers to packet data length. - write_reg(RBCR0, buf_hdr.len); - write_reg(RBCR1, 0u); + return 0; +} - // Initiate DMA transfer of packet data. - write_reg(CR, READ); +/** Finaliza la recepción del frame + * @precond netdev_recv_start() debe haber sido ejecutada + */ +void netdev_recv_end() +{ + // Pasa el próximo frame + write_reg(BNRY, recv_state.next_buf); +} - return buf_hdr.len; - } - return 0; +void netdev_read_start(byte len) +{ + // Set remote DMA start address registers to packet data. + write_reg(RSAR0, recv_state.curr_off); + write_reg(RSAR1, recv_state.curr_buf); + recv_state.curr_off += len; + + // Set remote DMA byte count registers to packet data length. + write_reg(RBCR0, len); + write_reg(RBCR1, 0); + + // Initiate DMA transfer of packet data. + write_reg(CR, READ); } /** Lee un byte del buffer de la placa de red * @precond netdev_recv_start() debe haber sido ejecutada */ -byte netdev_recv_byte() +byte netdev_read_byte() { return read_reg(RDMA); } @@ -457,21 +456,18 @@ byte netdev_recv_byte() /** Lee un word del buffer de la placa de red * @precond netdev_recv_start() debe haber sido ejecutada */ -uint16 netdev_recv_word() +uint16 netdev_read_word() { - uint16 w = netdev_recv_byte() << 8; - return w + netdev_recv_byte(); + uint16 w = read_reg(RDMA) << 8; + return w + read_reg(RDMA); } /** Finaliza la lectura del frame * @precond netdev_recv_start() debe haber sido ejecutada */ -void netdev_recv_end() +void netdev_read_end() { - // Abort/ complete DMA operation. + // Completa DMA ABORT_DMA(START); - - // Advance boundary pointer to next packet start. - write_reg(BNRY, persistent.next_pkt - 1); }