OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_52/] [or1ksim/] [peripheral/] [eth.c] - Diff between revs 849 and 867

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 849 Rev 867
/* ethernet.c -- Simulation of Ethernet MAC
/* ethernet.c -- Simulation of Ethernet MAC
   Copyright (C) 2001 by Erez Volk, erez@opencores.org
   Copyright (C) 2001 by Erez Volk, erez@opencores.org
                         Ivan Guzvinec, ivang@opencores.org
                         Ivan Guzvinec, ivang@opencores.org
 
 
   This file is part of OpenRISC 1000 Architectural Simulator.
   This file is part of OpenRISC 1000 Architectural Simulator.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
*/
 
 
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>   
#include <sys/stat.h>   
#include <fcntl.h>      
#include <fcntl.h>      
#include <sys/poll.h>   
#include <sys/poll.h>   
#include <sys/time.h>   
#include <sys/time.h>   
#include <unistd.h>     
#include <unistd.h>     
#include <errno.h>
#include <errno.h>
 
 
 
#include "config.h"
#include "abstract.h"
#include "abstract.h"
#include "ethernet_i.h"
#include "ethernet_i.h"
#include "dma.h"
#include "dma.h"
#include "sim-config.h"
#include "sim-config.h"
#include "fields.h"
#include "fields.h"
#include "crc32.h"
#include "crc32.h"
 
 
static struct eth_device eths[MAX_ETHERNETS];
static struct eth_device eths[MAX_ETHERNETS];
 
 
/* simulator interface */
/* simulator interface */
static void eth_reset_controller( struct eth_device *eth);
static void eth_reset_controller( struct eth_device *eth);
/* register interface */
/* register interface */
static void eth_write32( unsigned long addr, unsigned long value );
static void eth_write32( unsigned long addr, unsigned long value );
static unsigned long eth_read32( unsigned long addr );
static unsigned long eth_read32( unsigned long addr );
/* clock */
/* clock */
static void eth_controller_tx_clock( struct eth_device * );
static void eth_controller_tx_clock( struct eth_device * );
static void eth_controller_rx_clock( struct eth_device * );
static void eth_controller_rx_clock( struct eth_device * );
/* utility functions */
/* utility functions */
static int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr );
static int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr );
static ssize_t eth_read_rx_file( struct eth_device *, void *, size_t );
static ssize_t eth_read_rx_file( struct eth_device *, void *, size_t );
static void eth_skip_rx_file( struct eth_device *, off_t );
static void eth_skip_rx_file( struct eth_device *, off_t );
static void eth_rewind_rx_file( struct eth_device *, off_t );
static void eth_rewind_rx_file( struct eth_device *, off_t );
static void eth_rx_next_packet( struct eth_device * );
static void eth_rx_next_packet( struct eth_device * );
static void eth_write_tx_bd_num( struct eth_device *, unsigned long value );
static void eth_write_tx_bd_num( struct eth_device *, unsigned long value );
/* ========================================================================= */
/* ========================================================================= */
/*  TX LOGIC                                                                 */
/*  TX LOGIC                                                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
/*
/*
 * TX clock
 * TX clock
 * Responsible for starting and finishing TX
 * Responsible for starting and finishing TX
 */
 */
void eth_controller_tx_clock( struct eth_device *eth )
void eth_controller_tx_clock( struct eth_device *eth )
{
{
    int breakpoint = 0;
    int breakpoint = 0;
    int bAdvance   = 1;
    int bAdvance   = 1;
#ifdef HAVE_ETH_PHY
#if HAVE_ETH_PHY
    struct sockaddr_ll sll;
    struct sockaddr_ll sll;
#endif /* HAVE_ETH_PHY */
#endif /* HAVE_ETH_PHY */
    long nwritten;
    long nwritten;
    unsigned long read_word;
    unsigned long read_word;
 
 
    switch (eth->tx.state) {
    switch (eth->tx.state) {
        case ETH_TXSTATE_IDLE:
        case ETH_TXSTATE_IDLE:
        if ( TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) ) {
        if ( TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) ) {
 
 
            /* wait for TxBuffer to be ready */
            /* wait for TxBuffer to be ready */
                debug (3, "TX - entering state WAIT4BD (%d)\n", eth->tx.bd_index);
                debug (3, "TX - entering state WAIT4BD (%d)\n", eth->tx.bd_index);
            eth->tx.state = ETH_TXSTATE_WAIT4BD;
            eth->tx.state = ETH_TXSTATE_WAIT4BD;
        }
        }
        break;
        break;
    case ETH_TXSTATE_WAIT4BD:
    case ETH_TXSTATE_WAIT4BD:
        /* Read buffer descriptor */
        /* Read buffer descriptor */
        eth->tx.bd = eth->regs.bd_ram[eth->tx.bd_index];
        eth->tx.bd = eth->regs.bd_ram[eth->tx.bd_index];
        eth->tx.bd_addr = eth->regs.bd_ram[eth->tx.bd_index + 1];
        eth->tx.bd_addr = eth->regs.bd_ram[eth->tx.bd_index + 1];
 
 
        if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, READY ) ) {
        if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, READY ) ) {
            /*****************/
            /*****************/
            /* initialize TX */
            /* initialize TX */
            eth->tx.bytes_left = eth->tx.packet_length = GET_FIELD( eth->tx.bd, ETH_TX_BD, LENGTH );
            eth->tx.bytes_left = eth->tx.packet_length = GET_FIELD( eth->tx.bd, ETH_TX_BD, LENGTH );
            eth->tx.bytes_sent = 0;
            eth->tx.bytes_sent = 0;
 
 
            /*   Initialize error status bits */
            /*   Initialize error status bits */
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, DEFER );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, DEFER );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, COLLISION );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, COLLISION );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, RETRANSMIT );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, RETRANSMIT );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, UNDERRUN );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, UNDERRUN );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, NO_CARRIER );
            CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, NO_CARRIER );
            SET_FIELD ( eth->tx.bd, ETH_TX_BD, RETRY, 0 );
            SET_FIELD ( eth->tx.bd, ETH_TX_BD, RETRY, 0 );
 
 
            /* Find out minimum length */
            /* Find out minimum length */
            if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, PAD ) ||
            if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, PAD ) ||
                 TEST_FLAG( eth->regs.moder, ETH_MODER, PAD ) )
                 TEST_FLAG( eth->regs.moder, ETH_MODER, PAD ) )
                eth->tx.minimum_length = GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MINFL );
                eth->tx.minimum_length = GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MINFL );
            else
            else
                eth->tx.minimum_length = eth->tx.packet_length;
                eth->tx.minimum_length = eth->tx.packet_length;
 
 
            /* Find out maximum length */
            /* Find out maximum length */
            if ( TEST_FLAG( eth->regs.moder, ETH_MODER, HUGEN ) )
            if ( TEST_FLAG( eth->regs.moder, ETH_MODER, HUGEN ) )
                eth->tx.maximum_length = eth->tx.packet_length;
                eth->tx.maximum_length = eth->tx.packet_length;
            else
            else
                eth->tx.maximum_length = GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MAXFL );
                eth->tx.maximum_length = GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MAXFL );
 
 
            /* Do we need CRC on this packet? */
            /* Do we need CRC on this packet? */
            if ( TEST_FLAG( eth->regs.moder, ETH_MODER, CRCEN ) ||
            if ( TEST_FLAG( eth->regs.moder, ETH_MODER, CRCEN ) ||
                 (TEST_FLAG( eth->tx.bd, ETH_TX_BD, CRC) &&
                 (TEST_FLAG( eth->tx.bd, ETH_TX_BD, CRC) &&
                  TEST_FLAG( eth->tx.bd, ETH_TX_BD, LAST)) )
                  TEST_FLAG( eth->tx.bd, ETH_TX_BD, LAST)) )
                eth->tx.add_crc = 1;
                eth->tx.add_crc = 1;
            else
            else
                eth->tx.add_crc = 0;
                eth->tx.add_crc = 0;
 
 
            if ( TEST_FLAG( eth->regs.moder, ETH_MODER, DLYCRCEN ) )
            if ( TEST_FLAG( eth->regs.moder, ETH_MODER, DLYCRCEN ) )
                eth->tx.crc_dly = 1;
                eth->tx.crc_dly = 1;
            else
            else
                eth->tx.crc_dly = 0;
                eth->tx.crc_dly = 0;
            /* XXX - For now we skip CRC calculation */
            /* XXX - For now we skip CRC calculation */
 
 
            debug( 3, "Ethernet: Starting TX of %u bytes (min. %u, max. %u)\n", eth->tx.packet_length,
            debug( 3, "Ethernet: Starting TX of %u bytes (min. %u, max. %u)\n", eth->tx.packet_length,
                   eth->tx.minimum_length, eth->tx.maximum_length );
                   eth->tx.minimum_length, eth->tx.maximum_length );
 
 
            if (eth->rtx_type == ETH_RTX_FILE) {
            if (eth->rtx_type == ETH_RTX_FILE) {
                /* write packet length to file */
                /* write packet length to file */
                nwritten = write( eth->txfd, &(eth->tx.packet_length), sizeof(eth->tx.packet_length) );
                nwritten = write( eth->txfd, &(eth->tx.packet_length), sizeof(eth->tx.packet_length) );
            }
            }
 
 
            /************************************************/
            /************************************************/
            /* start transmit with reading packet into FIFO */
            /* start transmit with reading packet into FIFO */
                debug (3, "TX - entering state READFIFO\n");
                debug (3, "TX - entering state READFIFO\n");
            eth->tx.state = ETH_TXSTATE_READFIFO;
            eth->tx.state = ETH_TXSTATE_READFIFO;
        }
        }
        else if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) ) {
        else if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) ) {
            /* stop TX logic */
            /* stop TX logic */
                debug (3, "TX - entering state IDLE\n");
                debug (3, "TX - entering state IDLE\n");
            eth->tx.state = ETH_TXSTATE_IDLE;
            eth->tx.state = ETH_TXSTATE_IDLE;
        }
        }
 
 
        /* stay in this state if (TXEN && !READY) */
        /* stay in this state if (TXEN && !READY) */
        break;
        break;
    case ETH_TXSTATE_READFIFO:
    case ETH_TXSTATE_READFIFO:
#if 1
#if 1
        if ( eth->tx.bytes_sent < eth->tx.packet_length ) {
        if ( eth->tx.bytes_sent < eth->tx.packet_length ) {
            read_word = eval_mem32(eth->tx.bytes_sent + eth->tx.bd_addr, &breakpoint);
            read_word = eval_mem32(eth->tx.bytes_sent + eth->tx.bd_addr, &breakpoint);
            eth->tx_buff[eth->tx.bytes_sent]   = (unsigned char)(read_word >> 24);
            eth->tx_buff[eth->tx.bytes_sent]   = (unsigned char)(read_word >> 24);
            eth->tx_buff[eth->tx.bytes_sent+1] = (unsigned char)(read_word >> 16);
            eth->tx_buff[eth->tx.bytes_sent+1] = (unsigned char)(read_word >> 16);
            eth->tx_buff[eth->tx.bytes_sent+2] = (unsigned char)(read_word >> 8);
            eth->tx_buff[eth->tx.bytes_sent+2] = (unsigned char)(read_word >> 8);
            eth->tx_buff[eth->tx.bytes_sent+3] = (unsigned char)(read_word);
            eth->tx_buff[eth->tx.bytes_sent+3] = (unsigned char)(read_word);
            eth->tx.bytes_sent += 4;
            eth->tx.bytes_sent += 4;
        }
        }
#else
#else
        if ( eth->tx.bytes_sent < eth->tx.packet_length ) {
        if ( eth->tx.bytes_sent < eth->tx.packet_length ) {
            eth->tx_buff[eth->tx.bytes_sent] = eval_mem8(eth->tx.bytes_sent + eth->tx.bd_addr, &breakpoint);
            eth->tx_buff[eth->tx.bytes_sent] = eval_mem8(eth->tx.bytes_sent + eth->tx.bd_addr, &breakpoint);
            eth->tx.bytes_sent += 1;
            eth->tx.bytes_sent += 1;
        }
        }
#endif
#endif
        else {
        else {
            debug (3, "TX - entering state TRANSMIT\n");
            debug (3, "TX - entering state TRANSMIT\n");
            eth->tx.state = ETH_TXSTATE_TRANSMIT;
            eth->tx.state = ETH_TXSTATE_TRANSMIT;
        }
        }
        break;
        break;
    case ETH_TXSTATE_TRANSMIT:
    case ETH_TXSTATE_TRANSMIT:
        /* send packet */
        /* send packet */
        switch (eth->rtx_type) {
        switch (eth->rtx_type) {
        case ETH_RTX_FILE:
        case ETH_RTX_FILE:
            nwritten = write( eth->txfd, eth->tx_buff, eth->tx.packet_length );
            nwritten = write( eth->txfd, eth->tx_buff, eth->tx.packet_length );
            break;
            break;
#ifdef HAVE_ETH_PHY
#if HAVE_ETH_PHY
        case ETH_RTX_SOCK:
        case ETH_RTX_SOCK:
            memset(&sll, 0, sizeof(sll));
            memset(&sll, 0, sizeof(sll));
            sll.sll_ifindex = eth->ifr.ifr_ifindex;
            sll.sll_ifindex = eth->ifr.ifr_ifindex;
            nwritten = sendto(eth->rtx_sock, eth->tx_buff, eth->tx.packet_length, 0, (struct sockaddr *)&sll, sizeof(sll));
            nwritten = sendto(eth->rtx_sock, eth->tx_buff, eth->tx.packet_length, 0, (struct sockaddr *)&sll, sizeof(sll));
#endif /* HAVE_ETH_PHY */
#endif /* HAVE_ETH_PHY */
        }
        }
 
 
        /* set BD status */
        /* set BD status */
        if (nwritten == eth->tx.packet_length) {
        if (nwritten == eth->tx.packet_length) {
            CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY);
            CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY);
            SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB);
            SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB);
            debug (4, "ETH_INT_SOURCE = %0x\n", eth->regs.int_source);
            debug (4, "ETH_INT_SOURCE = %0x\n", eth->regs.int_source);
 
 
            debug (3, "TX - entering state IDLE\n");
            debug (3, "TX - entering state IDLE\n");
            eth->tx.state = ETH_TXSTATE_IDLE;
            eth->tx.state = ETH_TXSTATE_IDLE;
            debug (3, "send (%d)bytes OK\n", nwritten);
            debug (3, "send (%d)bytes OK\n", nwritten);
        }
        }
        else {
        else {
            /* XXX - implement retry mechanism here! */
            /* XXX - implement retry mechanism here! */
            CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY);
            CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY);
            CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, COLLISION);
            CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, COLLISION);
            SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXE);
            SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXE);
 
 
                debug (3, "TX - entering state IDLE\n");
                debug (3, "TX - entering state IDLE\n");
            eth->tx.state = ETH_TXSTATE_IDLE;
            eth->tx.state = ETH_TXSTATE_IDLE;
            debug (3, "send FAILED!\n");
            debug (3, "send FAILED!\n");
        }
        }
 
 
        eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd;
        eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd;
 
 
        /* advance to next BD */
        /* advance to next BD */
        if (bAdvance) {
        if (bAdvance) {
            if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, WRAP ) ||
            if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, WRAP ) ||
                            eth->tx.bd_index >= ETH_BD_COUNT )
                            eth->tx.bd_index >= ETH_BD_COUNT )
                eth->tx.bd_index = 0;
                eth->tx.bd_index = 0;
            else
            else
                eth->tx.bd_index += 2;
                eth->tx.bd_index += 2;
        }
        }
 
 
        /* generate OK interrupt */
        /* generate OK interrupt */
        if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, TXE_M) ||
        if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, TXE_M) ||
             TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, TXB_M) )
             TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, TXB_M) )
        {
        {
            report_interrupt( eth->mac_int );
            report_interrupt( eth->mac_int );
        }
        }
 
 
        break;
        break;
    }
    }
}
}
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/* ========================================================================= */
/* ========================================================================= */
/*  RX LOGIC                                                                 */
/*  RX LOGIC                                                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
/*
/*
 * RX clock
 * RX clock
 * Responsible for starting and finishing RX
 * Responsible for starting and finishing RX
 */
 */
void eth_controller_rx_clock( struct eth_device *eth )
void eth_controller_rx_clock( struct eth_device *eth )
{
{
    int i;
    int i;
    int breakpoint = 0;
    int breakpoint = 0;
    long nread;
    long nread;
    unsigned long send_word;
    unsigned long send_word;
 
 
    fd_set rfds;
    fd_set rfds;
 
 
    switch (eth->rx.state) {
    switch (eth->rx.state) {
    case ETH_RXSTATE_IDLE:
    case ETH_RXSTATE_IDLE:
        if ( TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN) ) {
        if ( TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN) ) {
                debug (3, "RX - entering state WAIT4BD (%d)\n", eth->rx.bd_index);
                debug (3, "RX - entering state WAIT4BD (%d)\n", eth->rx.bd_index);
            eth->rx.state = ETH_RXSTATE_WAIT4BD;
            eth->rx.state = ETH_RXSTATE_WAIT4BD;
        }
        }
        break;
        break;
 
 
    case ETH_RXSTATE_WAIT4BD:
    case ETH_RXSTATE_WAIT4BD:
        eth->rx.bd = eth->regs.bd_ram[eth->rx.bd_index];
        eth->rx.bd = eth->regs.bd_ram[eth->rx.bd_index];
        eth->rx.bd_addr = eth->regs.bd_ram[eth->rx.bd_index + 1];
        eth->rx.bd_addr = eth->regs.bd_ram[eth->rx.bd_index + 1];
 
 
        if ( TEST_FLAG( eth->rx.bd, ETH_RX_BD, READY ) ) {
        if ( TEST_FLAG( eth->rx.bd, ETH_RX_BD, READY ) ) {
            /*****************/
            /*****************/
            /* Initialize RX */
            /* Initialize RX */
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, MISS );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, MISS );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, INVALID );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, INVALID );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, DRIBBLE );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, DRIBBLE );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, UVERRUN );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, UVERRUN );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, COLLISION );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, COLLISION );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, TOOBIG );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, TOOBIG );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, TOOSHORT );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, TOOSHORT );
 
 
            debug( 3,  "Ethernet: Starting RX\n" );
            debug( 3,  "Ethernet: Starting RX\n" );
 
 
            /* Setup file to read from */
            /* Setup file to read from */
            if ( TEST_FLAG( eth->regs.moder, ETH_MODER, LOOPBCK ) ) {
            if ( TEST_FLAG( eth->regs.moder, ETH_MODER, LOOPBCK ) ) {
                eth->rx.fd = eth->txfd;
                eth->rx.fd = eth->txfd;
                eth->rx.offset = &(eth->loopback_offset);
                eth->rx.offset = &(eth->loopback_offset);
            } else {
            } else {
                eth->rx.fd = eth->rxfd;
                eth->rx.fd = eth->rxfd;
                eth->rx.offset = 0;
                eth->rx.offset = 0;
            }
            }
                debug (3, "RX - entering state RECV\n");
                debug (3, "RX - entering state RECV\n");
            eth->rx.state = ETH_RXSTATE_RECV;
            eth->rx.state = ETH_RXSTATE_RECV;
        }
        }
        else if (!TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN)) {
        else if (!TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN)) {
          debug (3, "RX - entering state IDLE\n");
          debug (3, "RX - entering state IDLE\n");
          eth->rx.state = ETH_RXSTATE_IDLE;
          eth->rx.state = ETH_RXSTATE_IDLE;
        }
        }
        else {
        else {
            nread = recv(eth->rtx_sock, eth->rx_buff, ETH_MAXPL, /*MSG_PEEK | */MSG_DONTWAIT);
            nread = recv(eth->rtx_sock, eth->rx_buff, ETH_MAXPL, /*MSG_PEEK | */MSG_DONTWAIT);
            if (nread > 0) {
            if (nread > 0) {
                SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, BUSY);
                SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, BUSY);
                if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, BUSY_M) )
                if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, BUSY_M) )
                  report_interrupt(eth->mac_int);
                  report_interrupt(eth->mac_int);
            }
            }
        }
        }
        break;
        break;
 
 
    case ETH_RXSTATE_RECV:
    case ETH_RXSTATE_RECV:
        switch (eth->rtx_type) {
        switch (eth->rtx_type) {
        case ETH_RTX_FILE:
        case ETH_RTX_FILE:
            /* Read packet length */
            /* Read packet length */
            if ( eth_read_rx_file( eth, &(eth->rx.packet_length), sizeof(eth->rx.packet_length) )
            if ( eth_read_rx_file( eth, &(eth->rx.packet_length), sizeof(eth->rx.packet_length) )
                     < sizeof(eth->rx.packet_length) ) {
                     < sizeof(eth->rx.packet_length) ) {
                /* TODO: just do what real ethernet would do (some kind of error state) */
                /* TODO: just do what real ethernet would do (some kind of error state) */
                debug (4, "eth_start_rx(): File does not have a packet ready for RX (len = %d)\n", eth->rx.packet_length );
                debug (4, "eth_start_rx(): File does not have a packet ready for RX (len = %d)\n", eth->rx.packet_length );
                cont_run = 0;
                cont_run = 0;
                break;
                break;
            }
            }
 
 
            /* Packet must be big enough to hold a header */
            /* Packet must be big enough to hold a header */
            if ( eth->rx.packet_length < ETH_HLEN ){
            if ( eth->rx.packet_length < ETH_HLEN ){
                debug( 3,  "eth_start_rx(): Packet too small\n" );
                debug( 3,  "eth_start_rx(): Packet too small\n" );
                eth_rx_next_packet( eth );
                eth_rx_next_packet( eth );
 
 
                debug (3, "RX - entering state IDLE\n");
                debug (3, "RX - entering state IDLE\n");
                eth->rx.state = ETH_RXSTATE_IDLE;
                eth->rx.state = ETH_RXSTATE_IDLE;
                break;
                break;
            }
            }
 
 
            eth->rx.bytes_read = 0;
            eth->rx.bytes_read = 0;
            eth->rx.bytes_left = eth->rx.packet_length;
            eth->rx.bytes_left = eth->rx.packet_length;
 
 
            /* for now Read entire packet into memory */
            /* for now Read entire packet into memory */
            nread = eth_read_rx_file( eth, eth->rx_buff, eth->rx.bytes_left );
            nread = eth_read_rx_file( eth, eth->rx_buff, eth->rx.bytes_left );
            if ( nread < eth->rx.bytes_left ) {
            if ( nread < eth->rx.bytes_left ) {
                debug (3, "Read %d from %d. Error!\n", nread, eth->rx.bytes_left);
                debug (3, "Read %d from %d. Error!\n", nread, eth->rx.bytes_left);
                eth->rx.error = 1;
                eth->rx.error = 1;
                break;
                break;
            }
            }
 
 
            eth->rx.packet_length = nread;
            eth->rx.packet_length = nread;
            eth->rx.bytes_left = nread;
            eth->rx.bytes_left = nread;
            eth->rx.bytes_read = 0;
            eth->rx.bytes_read = 0;
 
 
            debug (3, "RX - entering state WRITEFIFO\n");
            debug (3, "RX - entering state WRITEFIFO\n");
            eth->rx.state = ETH_RXSTATE_WRITEFIFO;
            eth->rx.state = ETH_RXSTATE_WRITEFIFO;
 
 
            break;
            break;
 
 
        case ETH_RTX_SOCK:
        case ETH_RTX_SOCK:
            nread = recv(eth->rtx_sock, eth->rx_buff, ETH_MAXPL, MSG_DONTWAIT);
            nread = recv(eth->rtx_sock, eth->rx_buff, ETH_MAXPL, MSG_DONTWAIT);
 
 
            if (nread == 0)
            if (nread == 0)
                break;
                break;
            else if (nread < 0) {
            else if (nread < 0) {
                if ( errno != EAGAIN ) {
                if ( errno != EAGAIN ) {
                            debug (3, "recv() FAILED!\n");
                            debug (3, "recv() FAILED!\n");
                            break;
                            break;
                        }
                        }
                        else {
                        else {
                        break;
                        break;
                    }
                    }
            }
            }
            /* If not promiscouos mode, check the destination address */
            /* If not promiscouos mode, check the destination address */
            if (!TEST_FLAG(eth->regs.moder, ETH_MODER, PRO)) {
            if (!TEST_FLAG(eth->regs.moder, ETH_MODER, PRO)) {
                if (TEST_FLAG(eth->regs.moder, ETH_MODER, IAM) && (eth->rx_buff[0] & 1)) {
                if (TEST_FLAG(eth->regs.moder, ETH_MODER, IAM) && (eth->rx_buff[0] & 1)) {
                /* Nothing for now */
                /* Nothing for now */
                }
                }
 
 
                if (eth->mac_address[5] != eth->rx_buff[0] ||
                if (eth->mac_address[5] != eth->rx_buff[0] ||
                    eth->mac_address[4] != eth->rx_buff[1] ||
                    eth->mac_address[4] != eth->rx_buff[1] ||
                    eth->mac_address[3] != eth->rx_buff[2] ||
                    eth->mac_address[3] != eth->rx_buff[2] ||
                    eth->mac_address[2] != eth->rx_buff[3] ||
                    eth->mac_address[2] != eth->rx_buff[3] ||
                    eth->mac_address[1] != eth->rx_buff[4] ||
                    eth->mac_address[1] != eth->rx_buff[4] ||
                    eth->mac_address[0] != eth->rx_buff[5])
                    eth->mac_address[0] != eth->rx_buff[5])
                        break;
                        break;
            }
            }
 
 
            eth->rx.packet_length = nread;
            eth->rx.packet_length = nread;
            eth->rx.bytes_left = nread;
            eth->rx.bytes_left = nread;
            eth->rx.bytes_read = 0;
            eth->rx.bytes_read = 0;
 
 
            debug (3, "RX - entering state WRITEFIFO\n");
            debug (3, "RX - entering state WRITEFIFO\n");
            eth->rx.state = ETH_RXSTATE_WRITEFIFO;
            eth->rx.state = ETH_RXSTATE_WRITEFIFO;
 
 
            break;
            break;
        }
        }
        break;
        break;
 
 
    case ETH_RXSTATE_WRITEFIFO:
    case ETH_RXSTATE_WRITEFIFO:
#if 1
#if 1
        send_word = ((unsigned long)eth->rx_buff[eth->rx.bytes_read]   << 24) |
        send_word = ((unsigned long)eth->rx_buff[eth->rx.bytes_read]   << 24) |
                    ((unsigned long)eth->rx_buff[eth->rx.bytes_read+1] << 16) |
                    ((unsigned long)eth->rx_buff[eth->rx.bytes_read+1] << 16) |
                    ((unsigned long)eth->rx_buff[eth->rx.bytes_read+2] << 8)  |
                    ((unsigned long)eth->rx_buff[eth->rx.bytes_read+2] << 8)  |
                    ((unsigned long)eth->rx_buff[eth->rx.bytes_read+3] );
                    ((unsigned long)eth->rx_buff[eth->rx.bytes_read+3] );
        set_mem32( eth->rx.bd_addr + eth->rx.bytes_read, send_word, &breakpoint);
        set_mem32( eth->rx.bd_addr + eth->rx.bytes_read, send_word, &breakpoint);
        /* update counters */
        /* update counters */
        debug (3, "Write %d, left %d - %08lXd\n", eth->rx.bytes_read, eth->rx.bytes_left, send_word);
        debug (3, "Write %d, left %d - %08lXd\n", eth->rx.bytes_read, eth->rx.bytes_left, send_word);
        eth->rx.bytes_left -= 4;
        eth->rx.bytes_left -= 4;
        eth->rx.bytes_read += 4;
        eth->rx.bytes_read += 4;
#else
#else
        set_mem8( eth->rx.bd_addr + eth->rx.bytes_read, eth->rx_buff[eth->rx.bytes_read], &breakpoint);
        set_mem8( eth->rx.bd_addr + eth->rx.bytes_read, eth->rx_buff[eth->rx.bytes_read], &breakpoint);
        eth->rx.bytes_left -= 1;
        eth->rx.bytes_left -= 1;
        eth->rx.bytes_read += 1;
        eth->rx.bytes_read += 1;
#endif
#endif
 
 
        if ( eth->rx.bytes_left <= 0 ) {
        if ( eth->rx.bytes_left <= 0 ) {
            /* Write result to bd */
            /* Write result to bd */
            SET_FIELD( eth->rx.bd, ETH_RX_BD, LENGTH, eth->rx.packet_length );
            SET_FIELD( eth->rx.bd, ETH_RX_BD, LENGTH, eth->rx.packet_length );
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, READY);
            CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, READY);
            SET_FLAG( eth->regs.int_source, ETH_INT_SOURCE, RXB);
            SET_FLAG( eth->regs.int_source, ETH_INT_SOURCE, RXB);
            debug (4, "ETH_INT_SOURCE = %0x\n", eth->regs.int_source);
            debug (4, "ETH_INT_SOURCE = %0x\n", eth->regs.int_source);
 
 
            if ( eth->rx.packet_length < GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MINFL ) )
            if ( eth->rx.packet_length < GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MINFL ) )
                SET_FLAG( eth->rx.bd, ETH_RX_BD, TOOSHORT);
                SET_FLAG( eth->rx.bd, ETH_RX_BD, TOOSHORT);
            if ( eth->rx.packet_length > GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MAXFL ) )
            if ( eth->rx.packet_length > GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MAXFL ) )
                SET_FLAG( eth->rx.bd, ETH_RX_BD, TOOBIG);
                SET_FLAG( eth->rx.bd, ETH_RX_BD, TOOBIG);
 
 
            eth->regs.bd_ram[eth->rx.bd_index] = eth->rx.bd;
            eth->regs.bd_ram[eth->rx.bd_index] = eth->rx.bd;
 
 
            /* advance to next BD */
            /* advance to next BD */
            if ( TEST_FLAG( eth->rx.bd, ETH_RX_BD, WRAP ) || eth->rx.bd_index >= ETH_BD_COUNT )
            if ( TEST_FLAG( eth->rx.bd, ETH_RX_BD, WRAP ) || eth->rx.bd_index >= ETH_BD_COUNT )
                eth->rx.bd_index = eth->regs.tx_bd_num;
                eth->rx.bd_index = eth->regs.tx_bd_num;
            else
            else
                eth->rx.bd_index += 2;
                eth->rx.bd_index += 2;
 
 
            if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, RXB_M) ) {
            if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, RXB_M) ) {
                report_interrupt( eth->mac_int );
                report_interrupt( eth->mac_int );
            }
            }
 
 
            /* ready to receive next packet */
            /* ready to receive next packet */
                debug (3, "RX - entering state IDLE\n");
                debug (3, "RX - entering state IDLE\n");
            eth->rx.state = ETH_RXSTATE_IDLE;
            eth->rx.state = ETH_RXSTATE_IDLE;
        }
        }
        break;
        break;
    }
    }
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
/* Move to next RX BD */
/* Move to next RX BD */
void eth_rx_next_packet( struct eth_device *eth )
void eth_rx_next_packet( struct eth_device *eth )
{
{
    /* Skip any possible leftovers */
    /* Skip any possible leftovers */
    if ( eth->rx.bytes_left )
    if ( eth->rx.bytes_left )
        eth_skip_rx_file( eth, eth->rx.bytes_left );
        eth_skip_rx_file( eth, eth->rx.bytes_left );
}
}
/* "Skip" bytes in RX file */
/* "Skip" bytes in RX file */
void eth_skip_rx_file( struct eth_device *eth, off_t count )
void eth_skip_rx_file( struct eth_device *eth, off_t count )
{
{
    eth->rx.offset += count;
    eth->rx.offset += count;
}
}
 
 
/* Move RX file position back */
/* Move RX file position back */
void eth_rewind_rx_file( struct eth_device *eth, off_t count )
void eth_rewind_rx_file( struct eth_device *eth, off_t count )
{
{
    eth->rx.offset -= count;
    eth->rx.offset -= count;
}
}
/*
/*
 * Utility function to read from the ethernet RX file
 * Utility function to read from the ethernet RX file
 * This function moves the file pointer to the current place in the packet before reading
 * This function moves the file pointer to the current place in the packet before reading
 */
 */
ssize_t eth_read_rx_file( struct eth_device *eth, void *buf, size_t count )
ssize_t eth_read_rx_file( struct eth_device *eth, void *buf, size_t count )
{
{
    ssize_t result;
    ssize_t result;
 
 
    if ( eth->rx.fd <= 0 ) {
    if ( eth->rx.fd <= 0 ) {
        debug( 3,  "Ethernet: No RX file\n" );
        debug( 3,  "Ethernet: No RX file\n" );
        return 0;
        return 0;
    }
    }
 
 
    if ( eth->rx.offset )
    if ( eth->rx.offset )
        if ( lseek( eth->rx.fd, *(eth->rx.offset), SEEK_SET ) == (off_t)-1 ) {
        if ( lseek( eth->rx.fd, *(eth->rx.offset), SEEK_SET ) == (off_t)-1 ) {
            debug( 3,  "Ethernet: Error seeking RX file\n" );
            debug( 3,  "Ethernet: Error seeking RX file\n" );
            return 0;
            return 0;
        }
        }
 
 
    result = read( eth->rx.fd, buf, count );
    result = read( eth->rx.fd, buf, count );
    debug (4, "Ethernet: read result = %d \n", result);
    debug (4, "Ethernet: read result = %d \n", result);
    if ( eth->rx.offset && result >= 0 )
    if ( eth->rx.offset && result >= 0 )
        *(eth->rx.offset) += result;
        *(eth->rx.offset) += result;
 
 
    return result;
    return result;
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
/*
/*
  Reset. Initializes all registers to default and places devices in
  Reset. Initializes all registers to default and places devices in
         memory address space.
         memory address space.
*/
*/
void eth_reset()
void eth_reset()
{
{
    static int first_time = 1;
    static int first_time = 1;
    unsigned i;
    unsigned i;
 
 
    if (!config.nethernets)
    if (!config.nethernets)
        return;
        return;
 
 
    if ( first_time )
    if ( first_time )
        memset( eths, 0, sizeof(eths) );
        memset( eths, 0, sizeof(eths) );
 
 
    for ( i = 0; i < MAX_ETHERNETS; ++ i ) {
    for ( i = 0; i < MAX_ETHERNETS; ++ i ) {
        struct eth_device *eth = &(eths[i]);
        struct eth_device *eth = &(eths[i]);
 
 
        if (!HAVE_ETH_PHY && eth->rtx_type == ETH_RTX_SOCK) {
        if (!HAVE_ETH_PHY && eth->rtx_type == ETH_RTX_SOCK) {
          fprintf (stderr, "Ethernet phy not enabled in this configuration.  Configure with --enable-ethphy.\n");
          fprintf (stderr, "Ethernet phy not enabled in this configuration.  Configure with --enable-ethphy.\n");
          exit (1);
          exit (1);
        }
        }
        eth->eth_number = i;
        eth->eth_number = i;
        eth_reset_controller( eth );
        eth_reset_controller( eth );
        if ( eth->baseaddr && first_time )
        if ( eth->baseaddr && first_time )
            register_memoryarea( eth->baseaddr, ETH_ADDR_SPACE, 4, eth_read32, eth_write32 );
            register_memoryarea( eth->baseaddr, ETH_ADDR_SPACE, 4, eth_read32, eth_write32 );
    }
    }
 
 
    if ( first_time )
    if ( first_time )
        first_time = 0;
        first_time = 0;
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
static void eth_reset_controller(struct eth_device *eth)
static void eth_reset_controller(struct eth_device *eth)
{
{
    int i = eth->eth_number;
    int i = eth->eth_number;
    int j;
    int j;
#ifdef HAVE_ETH_PHY
#if HAVE_ETH_PHY
    struct sockaddr_ll sll;
    struct sockaddr_ll sll;
#endif /* HAVE_ETH_PHY */
#endif /* HAVE_ETH_PHY */
 
 
    eth->baseaddr = config.ethernets[i].baseaddr;
    eth->baseaddr = config.ethernets[i].baseaddr;
 
 
    if ( eth->baseaddr != 0 ) {
    if ( eth->baseaddr != 0 ) {
        /* Mark which DMA controller and channels */
        /* Mark which DMA controller and channels */
        eth->dma        = config.ethernets[i].dma;
        eth->dma        = config.ethernets[i].dma;
        eth->mac_int    = config.ethernets[i].irq;
        eth->mac_int    = config.ethernets[i].irq;
        eth->tx_channel = config.ethernets[i].tx_channel;
        eth->tx_channel = config.ethernets[i].tx_channel;
        eth->rx_channel = config.ethernets[i].rx_channel;
        eth->rx_channel = config.ethernets[i].rx_channel;
        eth->rtx_type   = config.ethernets[i].rtx_type;
        eth->rtx_type   = config.ethernets[i].rtx_type;
 
 
        switch (eth->rtx_type) {
        switch (eth->rtx_type) {
        case ETH_RTX_FILE:
        case ETH_RTX_FILE:
            /* (Re-)open TX/RX files */
            /* (Re-)open TX/RX files */
            eth->rxfile = config.ethernets[i].rxfile;
            eth->rxfile = config.ethernets[i].rxfile;
            eth->txfile = config.ethernets[i].txfile;
            eth->txfile = config.ethernets[i].txfile;
 
 
            if ( eth->rxfd > 0 )
            if ( eth->rxfd > 0 )
                close( eth->rxfd );
                close( eth->rxfd );
            if ( eth->txfd > 0 )
            if ( eth->txfd > 0 )
                close( eth->txfd );
                close( eth->txfd );
            eth->rxfd = eth->txfd = -1;
            eth->rxfd = eth->txfd = -1;
 
 
            if ( (eth->rxfd = open( eth->rxfile, O_RDONLY )) < 0 )
            if ( (eth->rxfd = open( eth->rxfile, O_RDONLY )) < 0 )
                fprintf( stderr, "Cannot open Ethernet RX file \"%s\"\n", eth->rxfile );
                fprintf( stderr, "Cannot open Ethernet RX file \"%s\"\n", eth->rxfile );
            if ( (eth->txfd = open( eth->txfile,
            if ( (eth->txfd = open( eth->txfile,
                                    O_RDWR | O_CREAT | O_APPEND | O_SYNC,
                                    O_RDWR | O_CREAT | O_APPEND | O_SYNC,
                                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )) < 0 )
                                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )) < 0 )
                fprintf( stderr, "Cannot open Ethernet TX file \"%s\"\n", eth->txfile );
                fprintf( stderr, "Cannot open Ethernet TX file \"%s\"\n", eth->txfile );
            eth->loopback_offset = lseek( eth->txfd, 0, SEEK_END );
            eth->loopback_offset = lseek( eth->txfd, 0, SEEK_END );
 
 
            break;
            break;
#ifdef HAVE_ETH_PHY
#if HAVE_ETH_PHY
        case ETH_RTX_SOCK:
        case ETH_RTX_SOCK:
            /* (Re-)open TX/RX sockets */
            /* (Re-)open TX/RX sockets */
            if (eth->rtx_sock != 0)
            if (eth->rtx_sock != 0)
                break;
                break;
 
 
            debug (3, "RTX oppening socket...\n");
            debug (3, "RTX oppening socket...\n");
            eth->rtx_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
            eth->rtx_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
            if (eth->rtx_sock == -1) {
            if (eth->rtx_sock == -1) {
                fprintf( stderr, "Cannot open rtx_sock.\n");
                fprintf( stderr, "Cannot open rtx_sock.\n");
                return;
                return;
            }
            }
 
 
            /* get interface index number */
            /* get interface index number */
            debug (3, "RTX getting interface...\n");
            debug (3, "RTX getting interface...\n");
            memset(&(eth->ifr), 0, sizeof(eth->ifr));
            memset(&(eth->ifr), 0, sizeof(eth->ifr));
            strncpy(eth->ifr.ifr_name, config.ethernets[i].sockif, IFNAMSIZ);
            strncpy(eth->ifr.ifr_name, config.ethernets[i].sockif, IFNAMSIZ);
            if (ioctl(eth->rtx_sock, SIOCGIFINDEX, &(eth->ifr)) == -1) {
            if (ioctl(eth->rtx_sock, SIOCGIFINDEX, &(eth->ifr)) == -1) {
                fprintf( stderr, "SIOCGIFINDEX failed!\n");
                fprintf( stderr, "SIOCGIFINDEX failed!\n");
                return;
                return;
            }
            }
            debug (3, "RTX Socket Interface : %d\n", eth->ifr.ifr_ifindex);
            debug (3, "RTX Socket Interface : %d\n", eth->ifr.ifr_ifindex);
 
 
            /* Bind to interface... */
            /* Bind to interface... */
            debug (3, "Binding to the interface ifindex=%d\n", eth->ifr.ifr_ifindex);
            debug (3, "Binding to the interface ifindex=%d\n", eth->ifr.ifr_ifindex);
            memset(&sll, 0xff, sizeof(sll));
            memset(&sll, 0xff, sizeof(sll));
            sll.sll_family = AF_PACKET;    /* allways AF_PACKET */
            sll.sll_family = AF_PACKET;    /* allways AF_PACKET */
            sll.sll_protocol = htons(ETH_P_ALL);
            sll.sll_protocol = htons(ETH_P_ALL);
            sll.sll_ifindex = eth->ifr.ifr_ifindex;
            sll.sll_ifindex = eth->ifr.ifr_ifindex;
            if (bind(eth->rtx_sock, (struct sockaddr *)&sll, sizeof(sll)) == -1) {
            if (bind(eth->rtx_sock, (struct sockaddr *)&sll, sizeof(sll)) == -1) {
                fprintf( stderr, "Error bind().\n");
                fprintf( stderr, "Error bind().\n");
                return;
                return;
            }
            }
 
 
            /* first, flush all received packets. */
            /* first, flush all received packets. */
            debug (3, "Flush");
            debug (3, "Flush");
            do {
            do {
                fd_set fds;
                fd_set fds;
                struct timeval t;
                struct timeval t;
 
 
                debug( 3, ".");
                debug( 3, ".");
                FD_ZERO(&fds);
                FD_ZERO(&fds);
                FD_SET(eth->rtx_sock, &fds);
                FD_SET(eth->rtx_sock, &fds);
                memset(&t, 0, sizeof(t));
                memset(&t, 0, sizeof(t));
                j = select(FD_SETSIZE, &fds, NULL, NULL, &t);
                j = select(FD_SETSIZE, &fds, NULL, NULL, &t);
                if (j > 0)
                if (j > 0)
                    recv(eth->rtx_sock, eth->rx_buff, j, 0);
                    recv(eth->rtx_sock, eth->rx_buff, j, 0);
            } while (j);
            } while (j);
            debug (3, "\n");
            debug (3, "\n");
 
 
            break;
            break;
#endif /* HAVE_ETH_PHY */
#endif /* HAVE_ETH_PHY */
        }
        }
 
 
        /* Set registers to default values */
        /* Set registers to default values */
        memset( &(eth->regs), 0, sizeof(eth->regs) );
        memset( &(eth->regs), 0, sizeof(eth->regs) );
        eth->regs.moder = 0x0000A000;
        eth->regs.moder = 0x0000A000;
        eth->regs.ipgt = 0x00000012;
        eth->regs.ipgt = 0x00000012;
        eth->regs.ipgr1 = 0x0000000C;
        eth->regs.ipgr1 = 0x0000000C;
        eth->regs.ipgr2 = 0x00000012;
        eth->regs.ipgr2 = 0x00000012;
        eth->regs.packetlen = 0x003C0600;
        eth->regs.packetlen = 0x003C0600;
        eth->regs.collconf = 0x000F003F;
        eth->regs.collconf = 0x000F003F;
        eth->regs.miimoder = 0x00000064;
        eth->regs.miimoder = 0x00000064;
        eth->regs.tx_bd_num = 0x00000080;
        eth->regs.tx_bd_num = 0x00000080;
 
 
        /* Initialize TX/RX status */
        /* Initialize TX/RX status */
        memset( &(eth->tx), 0, sizeof(eth->tx) );
        memset( &(eth->tx), 0, sizeof(eth->tx) );
        memset( &(eth->rx), 0, sizeof(eth->rx) );
        memset( &(eth->rx), 0, sizeof(eth->rx) );
        eth->rx.bd_index = eth->regs.tx_bd_num;
        eth->rx.bd_index = eth->regs.tx_bd_num;
    }
    }
}
}
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
  Print register values on stdout
  Print register values on stdout
*/
*/
void eth_status( void )
void eth_status( void )
{
{
    unsigned i;
    unsigned i;
 
 
    for ( i = 0; i < MAX_ETHERNETS; ++ i ) {
    for ( i = 0; i < MAX_ETHERNETS; ++ i ) {
        struct eth_device *eth = &(eths[i]);
        struct eth_device *eth = &(eths[i]);
 
 
        if ( eth->baseaddr == 0 )
        if ( eth->baseaddr == 0 )
            continue;
            continue;
 
 
        printf( "\nEthernet MAC %u at 0x%08X:\n", i, eth->baseaddr );
        printf( "\nEthernet MAC %u at 0x%08X:\n", i, eth->baseaddr );
        printf( "MODER        : 0x%08lX\n", eth->regs.moder );
        printf( "MODER        : 0x%08lX\n", eth->regs.moder );
        printf( "INT_SOURCE   : 0x%08lX\n", eth->regs.int_source );
        printf( "INT_SOURCE   : 0x%08lX\n", eth->regs.int_source );
        printf( "INT_MASK     : 0x%08lX\n", eth->regs.int_mask );
        printf( "INT_MASK     : 0x%08lX\n", eth->regs.int_mask );
        printf( "IPGT         : 0x%08lX\n", eth->regs.ipgt );
        printf( "IPGT         : 0x%08lX\n", eth->regs.ipgt );
        printf( "IPGR1        : 0x%08lX\n", eth->regs.ipgr1 );
        printf( "IPGR1        : 0x%08lX\n", eth->regs.ipgr1 );
        printf( "IPGR2        : 0x%08lX\n", eth->regs.ipgr2 );
        printf( "IPGR2        : 0x%08lX\n", eth->regs.ipgr2 );
        printf( "PACKETLEN    : 0x%08lX\n", eth->regs.packetlen );
        printf( "PACKETLEN    : 0x%08lX\n", eth->regs.packetlen );
        printf( "COLLCONF     : 0x%08lX\n", eth->regs.collconf );
        printf( "COLLCONF     : 0x%08lX\n", eth->regs.collconf );
        printf( "TX_BD_NUM    : 0x%08lX\n", eth->regs.tx_bd_num );
        printf( "TX_BD_NUM    : 0x%08lX\n", eth->regs.tx_bd_num );
        printf( "CTRLMODER    : 0x%08lX\n", eth->regs.controlmoder );
        printf( "CTRLMODER    : 0x%08lX\n", eth->regs.controlmoder );
        printf( "MIIMODER     : 0x%08lX\n", eth->regs.miimoder );
        printf( "MIIMODER     : 0x%08lX\n", eth->regs.miimoder );
        printf( "MIICOMMAND   : 0x%08lX\n", eth->regs.miicommand );
        printf( "MIICOMMAND   : 0x%08lX\n", eth->regs.miicommand );
        printf( "MIIADDRESS   : 0x%08lX\n", eth->regs.miiaddress );
        printf( "MIIADDRESS   : 0x%08lX\n", eth->regs.miiaddress );
        printf( "MIITX_DATA   : 0x%08lX\n", eth->regs.miitx_data );
        printf( "MIITX_DATA   : 0x%08lX\n", eth->regs.miitx_data );
        printf( "MIIRX_DATA   : 0x%08lX\n", eth->regs.miirx_data );
        printf( "MIIRX_DATA   : 0x%08lX\n", eth->regs.miirx_data );
        printf( "MIISTATUS    : 0x%08lX\n", eth->regs.miistatus );
        printf( "MIISTATUS    : 0x%08lX\n", eth->regs.miistatus );
        printf( "MAC Address  : %02X:%02X:%02X:%02X:%02X:%02X\n",
        printf( "MAC Address  : %02X:%02X:%02X:%02X:%02X:%02X\n",
                eth->mac_address[0], eth->mac_address[1], eth->mac_address[2],
                eth->mac_address[0], eth->mac_address[1], eth->mac_address[2],
                eth->mac_address[3], eth->mac_address[4], eth->mac_address[5] );
                eth->mac_address[3], eth->mac_address[4], eth->mac_address[5] );
        printf( "HASH0        : 0x%08lX\n", eth->regs.hash0 );
        printf( "HASH0        : 0x%08lX\n", eth->regs.hash0 );
        printf( "HASH1        : 0x%08lX\n", eth->regs.hash1 );
        printf( "HASH1        : 0x%08lX\n", eth->regs.hash1 );
    }
    }
}
}
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
  Simulation hook. Must be called every clock cycle to simulate Ethernet MAC.
  Simulation hook. Must be called every clock cycle to simulate Ethernet MAC.
*/
*/
void eth_clock()
void eth_clock()
{
{
    unsigned i;
    unsigned i;
 
 
    for ( i = 0; i < config.nethernets; ++ i ) {
    for ( i = 0; i < config.nethernets; ++ i ) {
        eth_controller_tx_clock( &(eths[i]) );
        eth_controller_tx_clock( &(eths[i]) );
        eth_controller_rx_clock( &(eths[i]) );
        eth_controller_rx_clock( &(eths[i]) );
    }
    }
}
}
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
  Read a register
  Read a register
*/
*/
unsigned long eth_read32( unsigned long addr )
unsigned long eth_read32( unsigned long addr )
{
{
    struct eth_device *eth;
    struct eth_device *eth;
    if ( !eth_find_controller( addr, &eth, &addr ) )    {
    if ( !eth_find_controller( addr, &eth, &addr ) )    {
        printf( "eth_read32( 0x%08lX ): Not in registered range(s)\n", addr );
        printf( "eth_read32( 0x%08lX ): Not in registered range(s)\n", addr );
        return 0;
        return 0;
    }
    }
 
 
    switch( addr ) {
    switch( addr ) {
    case ETH_MODER: return eth->regs.moder;
    case ETH_MODER: return eth->regs.moder;
    case ETH_INT_SOURCE: return eth->regs.int_source;
    case ETH_INT_SOURCE: return eth->regs.int_source;
    case ETH_INT_MASK: return eth->regs.int_mask;
    case ETH_INT_MASK: return eth->regs.int_mask;
    case ETH_IPGT: return eth->regs.ipgt;
    case ETH_IPGT: return eth->regs.ipgt;
    case ETH_IPGR1: return eth->regs.ipgr1;
    case ETH_IPGR1: return eth->regs.ipgr1;
    case ETH_IPGR2: return eth->regs.ipgr2;
    case ETH_IPGR2: return eth->regs.ipgr2;
    case ETH_PACKETLEN: return eth->regs.packetlen;
    case ETH_PACKETLEN: return eth->regs.packetlen;
    case ETH_COLLCONF: return eth->regs.collconf;
    case ETH_COLLCONF: return eth->regs.collconf;
    case ETH_TX_BD_NUM: return eth->regs.tx_bd_num;
    case ETH_TX_BD_NUM: return eth->regs.tx_bd_num;
    case ETH_CTRLMODER: return eth->regs.controlmoder;
    case ETH_CTRLMODER: return eth->regs.controlmoder;
    case ETH_MIIMODER: return eth->regs.miimoder;
    case ETH_MIIMODER: return eth->regs.miimoder;
    case ETH_MIICOMMAND: return eth->regs.miicommand;
    case ETH_MIICOMMAND: return eth->regs.miicommand;
    case ETH_MIIADDRESS: return eth->regs.miiaddress;
    case ETH_MIIADDRESS: return eth->regs.miiaddress;
    case ETH_MIITX_DATA: return eth->regs.miitx_data;
    case ETH_MIITX_DATA: return eth->regs.miitx_data;
    case ETH_MIIRX_DATA: return eth->regs.miirx_data;
    case ETH_MIIRX_DATA: return eth->regs.miirx_data;
    case ETH_MIISTATUS: return eth->regs.miistatus;
    case ETH_MIISTATUS: return eth->regs.miistatus;
    case ETH_MAC_ADDR0: return (((unsigned long)eth->mac_address[3]) << 24) |
    case ETH_MAC_ADDR0: return (((unsigned long)eth->mac_address[3]) << 24) |
                               (((unsigned long)eth->mac_address[2]) << 16) |
                               (((unsigned long)eth->mac_address[2]) << 16) |
                               (((unsigned long)eth->mac_address[1]) << 8) |
                               (((unsigned long)eth->mac_address[1]) << 8) |
                                 (unsigned long)eth->mac_address[0];
                                 (unsigned long)eth->mac_address[0];
    case ETH_MAC_ADDR1: return (((unsigned long)eth->mac_address[5]) << 8) |
    case ETH_MAC_ADDR1: return (((unsigned long)eth->mac_address[5]) << 8) |
                                 (unsigned long)eth->mac_address[4];
                                 (unsigned long)eth->mac_address[4];
    case ETH_HASH0: return eth->regs.hash0;
    case ETH_HASH0: return eth->regs.hash0;
    case ETH_HASH1: return eth->regs.hash1;
    case ETH_HASH1: return eth->regs.hash1;
    /*case ETH_DMA_RX_TX: return eth_rx( eth );*/
    /*case ETH_DMA_RX_TX: return eth_rx( eth );*/
    }
    }
 
 
    if ( (addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE) )
    if ( (addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE) )
        return eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4];
        return eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4];
 
 
    printf( "eth_read32( 0x%08lX ): Illegal address\n", addr + eth->baseaddr );
    printf( "eth_read32( 0x%08lX ): Illegal address\n", addr + eth->baseaddr );
    cont_run = 0;
    cont_run = 0;
    return 0;
    return 0;
}
}
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
  Write a register
  Write a register
*/
*/
void eth_write32( unsigned long addr, unsigned long value )
void eth_write32( unsigned long addr, unsigned long value )
{
{
    struct eth_device *eth;
    struct eth_device *eth;
    if ( !eth_find_controller( addr, &eth, &addr ) )    {
    if ( !eth_find_controller( addr, &eth, &addr ) )    {
        printf( "eth_write32( 0x%08lX ): Not in registered range(s)\n", addr );
        printf( "eth_write32( 0x%08lX ): Not in registered range(s)\n", addr );
    return;
    return;
    }
    }
 
 
    switch( addr ) {
    switch( addr ) {
    case ETH_MODER: eth->regs.moder = value; if (TEST_FLAG(value, ETH_MODER, RST)) eth_reset(); return;
    case ETH_MODER: eth->regs.moder = value; if (TEST_FLAG(value, ETH_MODER, RST)) eth_reset(); return;
    case ETH_INT_SOURCE: eth->regs.int_source &= ~value; return;
    case ETH_INT_SOURCE: eth->regs.int_source &= ~value; return;
    case ETH_INT_MASK: eth->regs.int_mask = value; return;
    case ETH_INT_MASK: eth->regs.int_mask = value; return;
    case ETH_IPGT: eth->regs.ipgt = value; return;
    case ETH_IPGT: eth->regs.ipgt = value; return;
    case ETH_IPGR1: eth->regs.ipgr1 = value; return;
    case ETH_IPGR1: eth->regs.ipgr1 = value; return;
    case ETH_IPGR2: eth->regs.ipgr2 = value; return;
    case ETH_IPGR2: eth->regs.ipgr2 = value; return;
    case ETH_PACKETLEN: eth->regs.packetlen = value; return;
    case ETH_PACKETLEN: eth->regs.packetlen = value; return;
    case ETH_COLLCONF: eth->regs.collconf = value; return;
    case ETH_COLLCONF: eth->regs.collconf = value; return;
    case ETH_TX_BD_NUM: eth_write_tx_bd_num( eth, value ); return;
    case ETH_TX_BD_NUM: eth_write_tx_bd_num( eth, value ); return;
    case ETH_CTRLMODER: eth->regs.controlmoder = value; return;
    case ETH_CTRLMODER: eth->regs.controlmoder = value; return;
    case ETH_MIIMODER: eth->regs.miimoder = value; return;
    case ETH_MIIMODER: eth->regs.miimoder = value; return;
    case ETH_MIICOMMAND: eth->regs.miicommand = value; return;
    case ETH_MIICOMMAND: eth->regs.miicommand = value; return;
    case ETH_MIIADDRESS: eth->regs.miiaddress = value; return;
    case ETH_MIIADDRESS: eth->regs.miiaddress = value; return;
    case ETH_MIITX_DATA: eth->regs.miitx_data = value; return;
    case ETH_MIITX_DATA: eth->regs.miitx_data = value; return;
    case ETH_MIIRX_DATA: eth->regs.miirx_data = value; return;
    case ETH_MIIRX_DATA: eth->regs.miirx_data = value; return;
    case ETH_MIISTATUS: eth->regs.miistatus = value; return;
    case ETH_MIISTATUS: eth->regs.miistatus = value; return;
    case ETH_MAC_ADDR0:
    case ETH_MAC_ADDR0:
        eth->mac_address[0] = value & 0xFF;
        eth->mac_address[0] = value & 0xFF;
        eth->mac_address[1] = (value >> 8) & 0xFF;
        eth->mac_address[1] = (value >> 8) & 0xFF;
        eth->mac_address[2] = (value >> 16) & 0xFF;
        eth->mac_address[2] = (value >> 16) & 0xFF;
        eth->mac_address[3] = (value >> 24) & 0xFF;
        eth->mac_address[3] = (value >> 24) & 0xFF;
        return;
        return;
    case ETH_MAC_ADDR1:
    case ETH_MAC_ADDR1:
        eth->mac_address[4] = value & 0xFF;
        eth->mac_address[4] = value & 0xFF;
        eth->mac_address[5] = (value >> 8) & 0xFF;
        eth->mac_address[5] = (value >> 8) & 0xFF;
        return;
        return;
    case ETH_HASH0: eth->regs.hash0 = value; return;
    case ETH_HASH0: eth->regs.hash0 = value; return;
    case ETH_HASH1: eth->regs.hash1 = value; return;
    case ETH_HASH1: eth->regs.hash1 = value; return;
 
 
    /*case ETH_DMA_RX_TX: eth_tx( eth, value ); return;*/
    /*case ETH_DMA_RX_TX: eth_tx( eth, value ); return;*/
    }
    }
 
 
    if ( (addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE) ) {
    if ( (addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE) ) {
        eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value;
        eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value;
        return;
        return;
    }
    }
 
 
    printf( "eth_write32( 0x%08lX ): Illegal address\n", addr + eth->baseaddr );
    printf( "eth_write32( 0x%08lX ): Illegal address\n", addr + eth->baseaddr );
    cont_run = 0;
    cont_run = 0;
    return;
    return;
}
}
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/* When TX_BD_NUM is written, also reset current RX BD index */
/* When TX_BD_NUM is written, also reset current RX BD index */
void eth_write_tx_bd_num( struct eth_device *eth, unsigned long value )
void eth_write_tx_bd_num( struct eth_device *eth, unsigned long value )
{
{
    eth->rx.bd_index = eth->regs.tx_bd_num = value & 0xFF;
    eth->rx.bd_index = eth->regs.tx_bd_num = value & 0xFF;
}
}
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
  Convert a memory address to a oontroller struct and relative address.
  Convert a memory address to a oontroller struct and relative address.
  Return nonzero on success
  Return nonzero on success
*/
*/
int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr )
int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr )
{
{
    unsigned i;
    unsigned i;
    *eth = NULL;
    *eth = NULL;
 
 
    for ( i = 0; i < MAX_ETHERNETS && *eth == NULL; ++ i ) {
    for ( i = 0; i < MAX_ETHERNETS && *eth == NULL; ++ i ) {
        if ( (addr >= eths[i].baseaddr) && (addr < eths[i].baseaddr + ETH_ADDR_SPACE) )
        if ( (addr >= eths[i].baseaddr) && (addr < eths[i].baseaddr + ETH_ADDR_SPACE) )
            *eth = &(eths[i]);
            *eth = &(eths[i]);
        }
        }
 
 
    /* verify we found a controller */
    /* verify we found a controller */
    if ( *eth == NULL )
    if ( *eth == NULL )
        return 0;
        return 0;
 
 
    /* Verify legal address */
    /* Verify legal address */
    if ( (addr - (*eth)->baseaddr) % 4 != 0 )
    if ( (addr - (*eth)->baseaddr) % 4 != 0 )
        return 0;
        return 0;
 
 
    *reladdr = addr - (*eth)->baseaddr;
    *reladdr = addr - (*eth)->baseaddr;
    return 1;
    return 1;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.