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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [eth.c] - Diff between revs 82 and 224

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

Rev 82 Rev 224
/* 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
   Copyright (C) 2008 Embecosm Limited
   Copyright (C) 2008 Embecosm Limited
 
 
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
 
 
   This program is free software; you can redistribute it and/or modify it
   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 the Free
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 3 of the License, or (at your option)
   Software Foundation; either version 3 of the License, or (at your option)
   any later version.
   any later version.
 
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
   more details.
 
 
   You should have received a copy of the GNU General Public License along
   You should have received a copy of the GNU General Public License along
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
/* This program is commented throughout in a fashion suitable for processing
/* This program is commented throughout in a fashion suitable for processing
   with Doxygen. */
   with Doxygen. */
 
 
 
 
/* Autoconf and/or portability configuration */
/* Autoconf and/or portability configuration */
#include "config.h"
#include "config.h"
#include "port.h"
#include "port.h"
 
 
/* System includes */
/* System includes */
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.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 <netinet/in.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if.h>
 
 
/* Package includes */
/* Package includes */
#include "arch.h"
#include "arch.h"
#include "config.h"
#include "config.h"
#include "abstract.h"
#include "abstract.h"
#include "eth.h"
#include "eth.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"
#include "vapi.h"
#include "vapi.h"
#include "pic.h"
#include "pic.h"
#include "sched.h"
#include "sched.h"
#include "toplevel-support.h"
#include "toplevel-support.h"
#include "sim-cmd.h"
#include "sim-cmd.h"
 
 
struct eth_device
struct eth_device
{
{
  /* Is peripheral enabled */
  /* Is peripheral enabled */
  int enabled;
  int enabled;
 
 
  /* Base address in memory */
  /* Base address in memory */
  oraddr_t baseaddr;
  oraddr_t baseaddr;
 
 
  /* Which DMA controller is this MAC connected to */
  /* Which DMA controller is this MAC connected to */
  unsigned dma;
  unsigned dma;
  unsigned tx_channel;
  unsigned tx_channel;
  unsigned rx_channel;
  unsigned rx_channel;
 
 
  /* Our address */
  /* Our address */
  unsigned char mac_address[ETHER_ADDR_LEN];
  unsigned char mac_address[ETHER_ADDR_LEN];
 
 
  /* interrupt line */
  /* interrupt line */
  unsigned long mac_int;
  unsigned long mac_int;
 
 
  /* VAPI ID */
  /* VAPI ID */
  unsigned long base_vapi_id;
  unsigned long base_vapi_id;
 
 
  /* RX and TX file names and handles */
  /* RX and TX file names and handles */
  char *rxfile, *txfile;
  char *rxfile, *txfile;
  int txfd;
  int txfd;
  int rxfd;
  int rxfd;
  off_t loopback_offset;
  off_t loopback_offset;
 
 
  /* Socket interface name */
  /* Socket interface name */
  char *sockif;
  char *sockif;
 
 
  int rtx_sock;
  int rtx_sock;
  int rtx_type;
  int rtx_type;
  struct ifreq ifr;
  struct ifreq ifr;
  fd_set rfds, wfds;
  fd_set rfds, wfds;
 
 
  /* Current TX state */
  /* Current TX state */
  struct
  struct
  {
  {
    unsigned long state;
    unsigned long state;
    unsigned long bd_index;
    unsigned long bd_index;
    unsigned long bd;
    unsigned long bd;
    unsigned long bd_addr;
    unsigned long bd_addr;
    unsigned working, waiting_for_dma, error;
    unsigned working, waiting_for_dma, error;
    long packet_length;
    long packet_length;
    unsigned minimum_length, maximum_length;
    unsigned minimum_length, maximum_length;
    unsigned add_crc;
    unsigned add_crc;
    unsigned crc_dly;
    unsigned crc_dly;
    unsigned long crc_value;
    unsigned long crc_value;
    long bytes_left, bytes_sent;
    long bytes_left, bytes_sent;
  } tx;
  } tx;
 
 
  /* Current RX state */
  /* Current RX state */
  struct
  struct
  {
  {
    unsigned long state;
    unsigned long state;
    unsigned long bd_index;
    unsigned long bd_index;
    unsigned long bd;
    unsigned long bd;
    unsigned long bd_addr;
    unsigned long bd_addr;
    int fd;
    int fd;
    off_t *offset;
    off_t *offset;
    unsigned working, error, waiting_for_dma;
    unsigned working, error, waiting_for_dma;
    long packet_length, bytes_read, bytes_left;
    long packet_length, bytes_read, bytes_left;
  } rx;
  } rx;
 
 
  /* Visible registers */
  /* Visible registers */
  struct
  struct
  {
  {
    unsigned long moder;
    unsigned long moder;
    unsigned long int_source;
    unsigned long int_source;
    unsigned long int_mask;
    unsigned long int_mask;
    unsigned long ipgt;
    unsigned long ipgt;
    unsigned long ipgr1;
    unsigned long ipgr1;
    unsigned long ipgr2;
    unsigned long ipgr2;
    unsigned long packetlen;
    unsigned long packetlen;
    unsigned long collconf;
    unsigned long collconf;
    unsigned long tx_bd_num;
    unsigned long tx_bd_num;
    unsigned long controlmoder;
    unsigned long controlmoder;
    unsigned long miimoder;
    unsigned long miimoder;
    unsigned long miicommand;
    unsigned long miicommand;
    unsigned long miiaddress;
    unsigned long miiaddress;
    unsigned long miitx_data;
    unsigned long miitx_data;
    unsigned long miirx_data;
    unsigned long miirx_data;
    unsigned long miistatus;
    unsigned long miistatus;
    unsigned long hash0;
    unsigned long hash0;
    unsigned long hash1;
    unsigned long hash1;
 
 
    /* Buffer descriptors */
    /* Buffer descriptors */
    unsigned long bd_ram[ETH_BD_SPACE / 4];
    unsigned long bd_ram[ETH_BD_SPACE / 4];
  } regs;
  } regs;
 
 
  unsigned char rx_buff[ETH_MAXPL];
  unsigned char rx_buff[ETH_MAXPL];
  unsigned char tx_buff[ETH_MAXPL];
  unsigned char tx_buff[ETH_MAXPL];
  unsigned char lo_buff[ETH_MAXPL];
  unsigned char lo_buff[ETH_MAXPL];
};
};
 
 
 
 
/* simulator interface */
/* simulator interface */
static void eth_vapi_read (unsigned long id, unsigned long data, void *dat);
static void eth_vapi_read (unsigned long id, unsigned long data, void *dat);
/* register interface */
/* register interface */
static void eth_write32 (oraddr_t addr, uint32_t value, void *dat);
static void eth_write32 (oraddr_t addr, uint32_t value, void *dat);
static uint32_t eth_read32 (oraddr_t addr, void *dat);
static uint32_t eth_read32 (oraddr_t addr, void *dat);
/* clock */
/* clock */
static void eth_controller_tx_clock (void *);
static void eth_controller_tx_clock (void *);
static void eth_controller_rx_clock (void *);
static void eth_controller_rx_clock (void *);
/* utility functions */
/* utility functions */
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_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
 */
 */
static void
static void
eth_controller_tx_clock (void *dat)
eth_controller_tx_clock (void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  int bAdvance = 1;
  int bAdvance = 1;
#if 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 = 0;
  long nwritten = 0;
  unsigned long read_word;
  unsigned long read_word;
 
 
  switch (eth->tx.state)
  switch (eth->tx.state)
    {
    {
    case ETH_TXSTATE_IDLE:
    case ETH_TXSTATE_IDLE:
      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 =
          eth->tx.bytes_left = eth->tx.packet_length =
            GET_FIELD (eth->tx.bd, ETH_TX_BD, 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 =
            eth->tx.minimum_length =
              GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MINFL);
              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 =
            eth->tx.maximum_length =
              GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MAXFL);
              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 */
 
 
          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 =
              nwritten =
                write (eth->txfd, &(eth->tx.packet_length),
                write (eth->txfd, &(eth->tx.packet_length),
                       sizeof (eth->tx.packet_length));
                       sizeof (eth->tx.packet_length));
            }
            }
 
 
            /************************************************/
            /************************************************/
          /* start transmit with reading packet into FIFO */
          /* start transmit with reading packet into FIFO */
          eth->tx.state = ETH_TXSTATE_READFIFO;
          eth->tx.state = ETH_TXSTATE_READFIFO;
        }
        }
 
 
      /* 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 =
          read_word =
            eval_direct32 (eth->tx.bytes_sent + eth->tx.bd_addr, 0, 0);
            eval_direct32 (eth->tx.bytes_sent + eth->tx.bd_addr, 0, 0);
          eth->tx_buff[eth->tx.bytes_sent] =
          eth->tx_buff[eth->tx.bytes_sent] =
            (unsigned char) (read_word >> 24);
            (unsigned char) (read_word >> 24);
          eth->tx_buff[eth->tx.bytes_sent + 1] =
          eth->tx_buff[eth->tx.bytes_sent + 1] =
            (unsigned char) (read_word >> 16);
            (unsigned char) (read_word >> 16);
          eth->tx_buff[eth->tx.bytes_sent + 2] =
          eth->tx_buff[eth->tx.bytes_sent + 2] =
            (unsigned char) (read_word >> 8);
            (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] =
          eth->tx_buff[eth->tx.bytes_sent] =
            eval_direct8 (eth->tx.bytes_sent + eth->tx.bd_addr, 0, 0);
            eval_direct8 (eth->tx.bytes_sent + eth->tx.bd_addr, 0, 0);
          eth->tx.bytes_sent += 1;
          eth->tx.bytes_sent += 1;
        }
        }
#endif
#endif
      else
      else
        {
        {
          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;
#if 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 =
          nwritten =
            sendto (eth->rtx_sock, eth->tx_buff, eth->tx.packet_length, 0,
            sendto (eth->rtx_sock, eth->tx_buff, eth->tx.packet_length, 0,
                    (struct sockaddr *) &sll, sizeof (sll));
                    (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);
 
 
          eth->tx.state = ETH_TXSTATE_WAIT4BD;
          eth->tx.state = ETH_TXSTATE_WAIT4BD;
        }
        }
      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);
 
 
          eth->tx.state = ETH_TXSTATE_WAIT4BD;
          eth->tx.state = ETH_TXSTATE_WAIT4BD;
        }
        }
 
 
      eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd;
      eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd;
 
 
      /* 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))
        {
        {
          if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, IRQ))
          if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, IRQ))
            report_interrupt (eth->mac_int);
            report_interrupt (eth->mac_int);
        }
        }
 
 
      /* 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;
        }
        }
 
 
      break;
      break;
    }
    }
 
 
  /* Reschedule */
  /* Reschedule */
  SCHED_ADD (eth_controller_tx_clock, dat, 1);
  SCHED_ADD (eth_controller_tx_clock, dat, 1);
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/* ========================================================================= */
/* ========================================================================= */
/*  RX LOGIC                                                                 */
/*  RX LOGIC                                                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
/*
/*
 * RX clock
 * RX clock
 * Responsible for starting and finishing RX
 * Responsible for starting and finishing RX
 */
 */
static void
static void
eth_controller_rx_clock (void *dat)
eth_controller_rx_clock (void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  long nread;
  long nread;
  unsigned long send_word;
  unsigned long send_word;
 
 
 
 
  switch (eth->rx.state)
  switch (eth->rx.state)
    {
    {
    case ETH_RXSTATE_IDLE:
    case ETH_RXSTATE_IDLE:
      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);
 
 
          /* 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;
            }
            }
          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))
        {
        {
          eth->rx.state = ETH_RXSTATE_IDLE;
          eth->rx.state = ETH_RXSTATE_IDLE;
        }
        }
      else
      else
        {
        {
          nread =
          nread =
            recv (eth->rtx_sock, eth->rx_buff, ETH_MAXPL, /*MSG_PEEK | */
            recv (eth->rtx_sock, eth->rx_buff, ETH_MAXPL, /*MSG_PEEK | */
                  MSG_DONTWAIT);
                  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
          if (eth_read_rx_file
              (eth, &(eth->rx.packet_length),
              (eth, &(eth->rx.packet_length),
               sizeof (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) */
              sim_done ();
              sim_done ();
              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 < ETHER_HDR_LEN)
          if (eth->rx.packet_length < ETHER_HDR_LEN)
            {
            {
              eth_rx_next_packet (eth);
              eth_rx_next_packet (eth);
 
 
              eth->rx.state = ETH_RXSTATE_WAIT4BD;
              eth->rx.state = ETH_RXSTATE_WAIT4BD;
              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)
            {
            {
              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;
 
 
          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)
                {
                {
                  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)
              if (TEST_FLAG (eth->regs.moder, ETH_MODER, IAM)
                  && (eth->rx_buff[0] & 1))
                  && (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;
 
 
          eth->rx.state = ETH_RXSTATE_WRITEFIFO;
          eth->rx.state = ETH_RXSTATE_WRITEFIFO;
 
 
          break;
          break;
        case ETH_RTX_VAPI:
        case ETH_RTX_VAPI:
          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_direct32 (eth->rx.bd_addr + eth->rx.bytes_read, send_word, 0, 0);
      set_direct32 (eth->rx.bd_addr + eth->rx.bytes_read, send_word, 0, 0);
      /* update counters */
      /* update counters */
      eth->rx.bytes_left -= 4;
      eth->rx.bytes_left -= 4;
      eth->rx.bytes_read += 4;
      eth->rx.bytes_read += 4;
#else
#else
      set_direct8 (eth->rx.bd_addr + eth->rx.bytes_read,
      set_direct8 (eth->rx.bd_addr + eth->rx.bytes_read,
                   eth->rx_buff[eth->rx.bytes_read], 0, 0);
                   eth->rx_buff[eth->rx.bytes_read], 0, 0);
      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);
 
 
          if (eth->rx.packet_length <
          if (eth->rx.packet_length <
              (GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MINFL) - 4))
              (GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MINFL) - 4))
            SET_FLAG (eth->rx.bd, ETH_RX_BD, TOOSHORT);
            SET_FLAG (eth->rx.bd, ETH_RX_BD, TOOSHORT);
          if (eth->rx.packet_length >
          if (eth->rx.packet_length >
              GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MAXFL))
              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)
          if (TEST_FLAG (eth->rx.bd, ETH_RX_BD, WRAP)
              || eth->rx.bd_index >= ETH_BD_COUNT)
              || eth->rx.bd_index >= ETH_BD_COUNT)
            eth->rx.bd_index = eth->regs.tx_bd_num << 1;
            eth->rx.bd_index = eth->regs.tx_bd_num << 1;
          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)) &&
              (TEST_FLAG (eth->rx.bd, ETH_RX_BD, IRQ)))
              (TEST_FLAG (eth->rx.bd, ETH_RX_BD, IRQ)))
            {
            {
              report_interrupt (eth->mac_int);
              report_interrupt (eth->mac_int);
            }
            }
 
 
          /* ready to receive next packet */
          /* ready to receive next packet */
          eth->rx.state = ETH_RXSTATE_IDLE;
          eth->rx.state = ETH_RXSTATE_IDLE;
        }
        }
      break;
      break;
    }
    }
 
 
  /* Reschedule */
  /* Reschedule */
  SCHED_ADD (eth_controller_rx_clock, dat, 1);
  SCHED_ADD (eth_controller_rx_clock, dat, 1);
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
/* Move to next RX BD */
/* Move to next RX BD */
static void
static void
eth_rx_next_packet (struct eth_device *eth)
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 */
static void
static void
eth_skip_rx_file (struct eth_device *eth, off_t count)
eth_skip_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
 */
 */
static ssize_t
static ssize_t
eth_read_rx_file (struct eth_device *eth, void *buf, size_t count)
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)
    {
    {
      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)
      {
      {
        return 0;
        return 0;
      }
      }
 
 
  result = read (eth->rx.fd, buf, count);
  result = read (eth->rx.fd, buf, count);
  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.
*/
*/
static void
static void
eth_reset (void *dat)
eth_reset (void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
#if HAVE_ETH_PHY
#if HAVE_ETH_PHY
  int j;
  int j;
  struct sockaddr_ll sll;
  struct sockaddr_ll sll;
#endif /* HAVE_ETH_PHY */
#endif /* HAVE_ETH_PHY */
 
 
  if (eth->baseaddr != 0)
  if (eth->baseaddr != 0)
    {
    {
      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 */
          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",
            fprintf (stderr, "Cannot open Ethernet RX file \"%s\"\n",
                     eth->rxfile);
                     eth->rxfile);
          if ((eth->txfd = open (eth->txfile, O_RDWR | O_CREAT | O_APPEND
          if ((eth->txfd = open (eth->txfile, O_RDWR | O_CREAT | O_APPEND
#if defined(O_SYNC)             /* BSD / Mac OS X manual doesn't know about O_SYNC */
#if defined(O_SYNC)             /* BSD / Mac OS X manual doesn't know about O_SYNC */
                                 | O_SYNC
                                 | O_SYNC
#endif
#endif
                                 ,
                                 ,
                                 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",
            fprintf (stderr, "Cannot open Ethernet TX file \"%s\"\n",
                     eth->txfile);
                     eth->txfile);
          eth->loopback_offset = lseek (eth->txfd, 0, SEEK_END);
          eth->loopback_offset = lseek (eth->txfd, 0, SEEK_END);
 
 
          break;
          break;
#if 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;
 
 
          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 */
          memset (&(eth->ifr), 0, sizeof (eth->ifr));
          memset (&(eth->ifr), 0, sizeof (eth->ifr));
          strncpy (eth->ifr.ifr_name, eth->sockif, IFNAMSIZ);
          strncpy (eth->ifr.ifr_name, eth->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;
            }
            }
 
 
          /* Bind to interface... */
          /* Bind to interface... */
          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)) ==
          if (bind (eth->rtx_sock, (struct sockaddr *) &sll, sizeof (sll)) ==
              -1)
              -1)
            {
            {
              fprintf (stderr, "Error bind().\n");
              fprintf (stderr, "Error bind().\n");
              return;
              return;
            }
            }
 
 
          /* first, flush all received packets. */
          /* first, flush all received packets. */
          do
          do
            {
            {
              fd_set fds;
              fd_set fds;
              struct timeval t;
              struct timeval t;
 
 
              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);
 
 
          break;
          break;
#else /* HAVE_ETH_PHY */
#else /* HAVE_ETH_PHY */
        case ETH_RTX_SOCK:
        case ETH_RTX_SOCK:
          fprintf (stderr,
          fprintf (stderr,
                   "Ethernet phy not enabled in this configuration.  Configure with --enable-ethphy.\n");
                   "Ethernet phy not enabled in this configuration.  Configure with --enable-ethphy.\n");
          exit (1);
          exit (1);
          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 = 0x00000040;
      eth->regs.tx_bd_num = 0x00000040;
 
 
      /* 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 << 1;
      eth->rx.bd_index = eth->regs.tx_bd_num << 1;
 
 
      /* Initialize VAPI */
      /* Initialize VAPI */
      if (eth->base_vapi_id)
      if (eth->base_vapi_id)
        {
        {
          vapi_install_multi_handler (eth->base_vapi_id, ETH_NUM_VAPI_IDS,
          vapi_install_multi_handler (eth->base_vapi_id, ETH_NUM_VAPI_IDS,
                                      eth_vapi_read, dat);
                                      eth_vapi_read, dat);
        }
        }
    }
    }
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
  Print register values on stdout
  Print register values on stdout
*/
*/
static void
static void
eth_status (void *dat)
eth_status (void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  PRINTF ("\nEthernet MAC at 0x%" PRIxADDR ":\n", eth->baseaddr);
  PRINTF ("\nEthernet MAC at 0x%" PRIxADDR ":\n", 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);
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
  Read a register
  Read a register
*/
*/
static uint32_t
static uint32_t
eth_read32 (oraddr_t addr, void *dat)
eth_read32 (oraddr_t addr, void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  switch (addr)
  switch (addr)
    {
    {
    case ETH_MODER:
    case ETH_MODER:
      return eth->regs.moder;
      return eth->regs.moder;
    case ETH_INT_SOURCE:
    case ETH_INT_SOURCE:
      return eth->regs.int_source;
      return eth->regs.int_source;
    case ETH_INT_MASK:
    case ETH_INT_MASK:
      return eth->regs.int_mask;
      return eth->regs.int_mask;
    case ETH_IPGT:
    case ETH_IPGT:
      return eth->regs.ipgt;
      return eth->regs.ipgt;
    case ETH_IPGR1:
    case ETH_IPGR1:
      return eth->regs.ipgr1;
      return eth->regs.ipgr1;
    case ETH_IPGR2:
    case ETH_IPGR2:
      return eth->regs.ipgr2;
      return eth->regs.ipgr2;
    case ETH_PACKETLEN:
    case ETH_PACKETLEN:
      return eth->regs.packetlen;
      return eth->regs.packetlen;
    case ETH_COLLCONF:
    case ETH_COLLCONF:
      return eth->regs.collconf;
      return eth->regs.collconf;
    case ETH_TX_BD_NUM:
    case ETH_TX_BD_NUM:
      return eth->regs.tx_bd_num;
      return eth->regs.tx_bd_num;
    case ETH_CTRLMODER:
    case ETH_CTRLMODER:
      return eth->regs.controlmoder;
      return eth->regs.controlmoder;
    case ETH_MIIMODER:
    case ETH_MIIMODER:
      return eth->regs.miimoder;
      return eth->regs.miimoder;
    case ETH_MIICOMMAND:
    case ETH_MIICOMMAND:
      return eth->regs.miicommand;
      return eth->regs.miicommand;
    case ETH_MIIADDRESS:
    case ETH_MIIADDRESS:
      return eth->regs.miiaddress;
      return eth->regs.miiaddress;
    case ETH_MIITX_DATA:
    case ETH_MIITX_DATA:
      return eth->regs.miitx_data;
      return eth->regs.miitx_data;
    case ETH_MIIRX_DATA:
    case ETH_MIIRX_DATA:
      return eth->regs.miirx_data;
      return eth->regs.miirx_data;
    case ETH_MIISTATUS:
    case ETH_MIISTATUS:
      return eth->regs.miistatus;
      return eth->regs.miistatus;
    case ETH_MAC_ADDR0:
    case ETH_MAC_ADDR0:
      return (((unsigned long) eth->mac_address[3]) << 24) |
      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:
    case ETH_MAC_ADDR1:
      return (((unsigned long) eth->mac_address[5]) << 8) |
      return (((unsigned long) eth->mac_address[5]) << 8) |
        (unsigned long) eth->mac_address[4];
        (unsigned long) eth->mac_address[4];
    case ETH_HASH0:
    case ETH_HASH0:
      return eth->regs.hash0;
      return eth->regs.hash0;
    case ETH_HASH1:
    case ETH_HASH1:
      return eth->regs.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%" PRIxADDR " ): Illegal address\n",
  PRINTF ("eth_read32( 0x%" PRIxADDR " ): Illegal address\n",
          addr + eth->baseaddr);
          addr + eth->baseaddr);
  return 0;
  return 0;
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
  Write a register
  Write a register
*/
*/
static void
static void
eth_write32 (oraddr_t addr, uint32_t value, void *dat)
eth_write32 (oraddr_t addr, uint32_t value, void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  switch (addr)
  switch (addr)
    {
    {
    case ETH_MODER:
    case ETH_MODER:
 
 
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN) &&
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN) &&
          TEST_FLAG (value, ETH_MODER, RXEN))
          TEST_FLAG (value, ETH_MODER, RXEN))
        SCHED_ADD (eth_controller_rx_clock, dat, 1);
        SCHED_ADD (eth_controller_rx_clock, dat, 1);
      else if (!TEST_FLAG (value, ETH_MODER, RXEN))
      else if (!TEST_FLAG (value, ETH_MODER, RXEN))
        SCHED_FIND_REMOVE (eth_controller_rx_clock, dat);
        SCHED_FIND_REMOVE (eth_controller_rx_clock, dat);
 
 
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN) &&
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN) &&
          TEST_FLAG (value, ETH_MODER, TXEN))
          TEST_FLAG (value, ETH_MODER, TXEN))
        SCHED_ADD (eth_controller_tx_clock, dat, 1);
        SCHED_ADD (eth_controller_tx_clock, dat, 1);
      else if (!TEST_FLAG (value, ETH_MODER, TXEN))
      else if (!TEST_FLAG (value, ETH_MODER, TXEN))
        SCHED_FIND_REMOVE (eth_controller_tx_clock, dat);
        SCHED_FIND_REMOVE (eth_controller_tx_clock, dat);
 
 
      eth->regs.moder = value;
      eth->regs.moder = value;
 
 
      if (TEST_FLAG (value, ETH_MODER, RST))
      if (TEST_FLAG (value, ETH_MODER, RST))
        eth_reset (dat);
        eth_reset (dat);
      return;
      return;
    case ETH_INT_SOURCE:
    case ETH_INT_SOURCE:
      if (!(eth->regs.int_source & ~value) && eth->regs.int_source)
      if (!(eth->regs.int_source & ~value) && eth->regs.int_source)
        clear_interrupt (eth->mac_int);
        clear_interrupt (eth->mac_int);
      eth->regs.int_source &= ~value;
      eth->regs.int_source &= ~value;
      return;
      return;
    case ETH_INT_MASK:
    case ETH_INT_MASK:
      eth->regs.int_mask = value;
      eth->regs.int_mask = value;
      return;
      return;
    case ETH_IPGT:
    case ETH_IPGT:
      eth->regs.ipgt = value;
      eth->regs.ipgt = value;
      return;
      return;
    case ETH_IPGR1:
    case ETH_IPGR1:
      eth->regs.ipgr1 = value;
      eth->regs.ipgr1 = value;
      return;
      return;
    case ETH_IPGR2:
    case ETH_IPGR2:
      eth->regs.ipgr2 = value;
      eth->regs.ipgr2 = value;
      return;
      return;
    case ETH_PACKETLEN:
    case ETH_PACKETLEN:
      eth->regs.packetlen = value;
      eth->regs.packetlen = value;
      return;
      return;
    case ETH_COLLCONF:
    case ETH_COLLCONF:
      eth->regs.collconf = value;
      eth->regs.collconf = value;
      return;
      return;
    case ETH_TX_BD_NUM:
    case ETH_TX_BD_NUM:
      eth_write_tx_bd_num (eth, value);
      eth_write_tx_bd_num (eth, value);
      return;
      return;
    case ETH_CTRLMODER:
    case ETH_CTRLMODER:
      eth->regs.controlmoder = value;
      eth->regs.controlmoder = value;
      return;
      return;
    case ETH_MIIMODER:
    case ETH_MIIMODER:
      eth->regs.miimoder = value;
      eth->regs.miimoder = value;
      return;
      return;
    case ETH_MIICOMMAND:
    case ETH_MIICOMMAND:
      eth->regs.miicommand = value;
      eth->regs.miicommand = value;
      return;
      return;
    case ETH_MIIADDRESS:
    case ETH_MIIADDRESS:
      eth->regs.miiaddress = value;
      eth->regs.miiaddress = value;
      return;
      return;
    case ETH_MIITX_DATA:
    case ETH_MIITX_DATA:
      eth->regs.miitx_data = value;
      eth->regs.miitx_data = value;
      return;
      return;
    case ETH_MIIRX_DATA:
    case ETH_MIIRX_DATA:
      eth->regs.miirx_data = value;
      eth->regs.miirx_data = value;
      return;
      return;
    case ETH_MIISTATUS:
    case ETH_MIISTATUS:
      eth->regs.miistatus = value;
      eth->regs.miistatus = value;
      return;
      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:
    case ETH_HASH0:
      eth->regs.hash0 = value;
      eth->regs.hash0 = value;
      return;
      return;
    case ETH_HASH1:
    case ETH_HASH1:
      eth->regs.hash1 = value;
      eth->regs.hash1 = value;
      return;
      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%" PRIxADDR " ): Illegal address\n",
  PRINTF ("eth_write32( 0x%" PRIxADDR " ): Illegal address\n",
          addr + eth->baseaddr);
          addr + eth->baseaddr);
  return;
  return;
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/*
/*
 *   VAPI connection to outside
 *   VAPI connection to outside
 */
 */
static void
static void
eth_vapi_read (unsigned long id, unsigned long data, void *dat)
eth_vapi_read (unsigned long id, unsigned long data, void *dat)
{
{
  unsigned long which;
  unsigned long which;
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  which = id - eth->base_vapi_id;
  which = id - eth->base_vapi_id;
 
 
  if (!eth)
  if (!eth)
    {
    {
      return;
      return;
    }
    }
 
 
  switch (which)
  switch (which)
    {
    {
    case ETH_VAPI_DATA:
    case ETH_VAPI_DATA:
      break;
      break;
    case ETH_VAPI_CTRL:
    case ETH_VAPI_CTRL:
      break;
      break;
    }
    }
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
 
 
/* When TX_BD_NUM is written, also reset current RX BD index */
/* When TX_BD_NUM is written, also reset current RX BD index */
static void
static void
eth_write_tx_bd_num (struct eth_device *eth, unsigned long value)
eth_write_tx_bd_num (struct eth_device *eth, unsigned long value)
{
{
  eth->regs.tx_bd_num = value & 0xFF;
  eth->regs.tx_bd_num = value & 0xFF;
  eth->rx.bd_index = eth->regs.tx_bd_num << 1;
  eth->rx.bd_index = eth->regs.tx_bd_num << 1;
}
}
 
 
/* ========================================================================= */
/* ========================================================================= */
 
 
/*-----------------------------------------------[ Ethernet configuration ]---*/
/*-----------------------------------------------[ Ethernet configuration ]---*/
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Enable or disable the Ethernet interface
/*!Enable or disable the Ethernet interface
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_enabled (union param_val  val,
eth_enabled (union param_val  val,
             void            *dat)
             void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  eth->enabled = val.int_val;
  eth->enabled = val.int_val;
 
 
}       /* eth_enabled() */
}       /* eth_enabled() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet interface base address
/*!Set the Ethernet interface base address
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_baseaddr (union param_val  val,
eth_baseaddr (union param_val  val,
              void            *dat)
              void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  eth->baseaddr = val.addr_val;
  eth->baseaddr = val.addr_val;
 
 
}       /* eth_baseaddr() */
}       /* eth_baseaddr() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet DMA port
/*!Set the Ethernet DMA port
 
 
   This is not currently supported, so a warning message is printed.
   This is not currently supported, so a warning message is printed.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_dma (union param_val  val,
eth_dma (union param_val  val,
         void            *dat)
         void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported\n");
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported\n");
  eth->dma = val.addr_val;
  eth->dma = val.addr_val;
 
 
}       /* eth_dma() */
}       /* eth_dma() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet IRQ
/*!Set the Ethernet IRQ
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_irq (union param_val  val,
eth_irq (union param_val  val,
         void            *dat)
         void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  eth->mac_int = val.int_val;
  eth->mac_int = val.int_val;
 
 
}       /* eth_irq() */
}       /* eth_irq() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet interface type
/*!Set the Ethernet interface type
 
 
   Currently two types are supported, file and socket. Use of the socket
   Currently two types are supported, file and socket. Use of the socket
   requires a compile time option.
   requires a compile time option.
 
 
   @param[in] val  The value to use. 0 for file, 1 for socket.
   @param[in] val  The value to use. 0 for file, 1 for socket.
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_rtx_type (union param_val  val,
eth_rtx_type (union param_val  val,
              void            *dat)
              void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  if (val.int_val)
  if (val.int_val)
    {
    {
#ifndef HAVE_ETH_PHY
#ifndef HAVE_ETH_PHY
      fprintf (stderr, "Warning: Ethernet PHY socket not enabled in this "
      fprintf (stderr, "Warning: Ethernet PHY socket not enabled in this "
               "configuration (configure with --enable-ethphy): ignored\n");
               "configuration (configure with --enable-ethphy): ignored\n");
      return;
      return;
#endif
#endif
    }
    }
 
 
  eth->rtx_type = val.int_val;
  eth->rtx_type = val.int_val;
 
 
}       /* eth_rtx_type() */
}       /* eth_rtx_type() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet DMA Rx channel
/*!Set the Ethernet DMA Rx channel
 
 
   External DMA is not currently supported, so a warning message is printed.
   External DMA is not currently supported, so a warning message is printed.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_rx_channel (union param_val  val,
eth_rx_channel (union param_val  val,
                void            *dat)
                void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported: "
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported: "
           "Rx channel ignored\n");
           "Rx channel ignored\n");
  eth->rx_channel = val.int_val;
  eth->rx_channel = val.int_val;
 
 
}       /* eth_rx_channel() */
}       /* eth_rx_channel() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet DMA Tx channel
/*!Set the Ethernet DMA Tx channel
 
 
   External DMA is not currently supported, so a warning message is printed.
   External DMA is not currently supported, so a warning message is printed.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_tx_channel (union param_val  val,
eth_tx_channel (union param_val  val,
                void            *dat)
                void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported: "
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported: "
           "Tx channel ignored\n");
           "Tx channel ignored\n");
  eth->tx_channel = val.int_val;
  eth->tx_channel = val.int_val;
 
 
}       /* eth_tx_channel() */
}       /* eth_tx_channel() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet DMA Rx file
/*!Set the Ethernet DMA Rx file
 
 
   Free any previously allocated value.
   Free any previously allocated value.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_rxfile (union param_val  val,
eth_rxfile (union param_val  val,
            void            *dat)
            void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  if (NULL != eth->rxfile)
  if (NULL != eth->rxfile)
    {
    {
      free (eth->rxfile);
      free (eth->rxfile);
      eth->rxfile = NULL;
      eth->rxfile = NULL;
    }
    }
 
 
  if (!(eth->rxfile = strdup (val.str_val)))
  if (!(eth->rxfile = strdup (val.str_val)))
    {
    {
      fprintf (stderr, "Peripheral Ethernet: Run out of memory\n");
      fprintf (stderr, "Peripheral Ethernet: Run out of memory\n");
      exit (-1);
      exit (-1);
    }
    }
}       /* eth_rxfile() */
}       /* eth_rxfile() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet DMA Tx file
/*!Set the Ethernet DMA Tx file
 
 
   Free any previously allocated value.
   Free any previously allocated value.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_txfile (union param_val  val,
eth_txfile (union param_val  val,
            void            *dat)
            void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  if (NULL != eth->txfile)
  if (NULL != eth->txfile)
    {
    {
      free (eth->txfile);
      free (eth->txfile);
      eth->txfile = NULL;
      eth->txfile = NULL;
    }
    }
 
 
  if (!(eth->txfile = strdup (val.str_val)))
  if (!(eth->txfile = strdup (val.str_val)))
    {
    {
      fprintf (stderr, "Peripheral Ethernet: Run out of memory\n");
      fprintf (stderr, "Peripheral Ethernet: Run out of memory\n");
      exit (-1);
      exit (-1);
    }
    }
}       /* eth_txfile() */
}       /* eth_txfile() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the Ethernet socket interface
/*!Set the Ethernet socket interface
 
 
   Free any previously allocated value. This is only meaningful if the socket
   Free any previously allocated value. This is only meaningful if the socket
   interface is configured.
   interface is configured.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
eth_sockif (union param_val  val,
eth_sockif (union param_val  val,
            void            *dat)
            void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
#ifndef HAVE_ETH_PHY
#ifndef HAVE_ETH_PHY
  fprintf (stderr, "Warning: Ethernet PHY socket not enabled in this "
  fprintf (stderr, "Warning: Ethernet PHY socket not enabled in this "
           "configuration (configure with --enable-ethphy): "
           "configuration (configure with --enable-ethphy): "
           "sockif ignored\n");
           "sockif ignored\n");
  return;
  return;
#endif
#endif
 
 
  if (NULL != eth->sockif)
  if (NULL != eth->sockif)
    {
    {
      free (eth->sockif);
      free (eth->sockif);
      eth->sockif = NULL;
      eth->sockif = NULL;
    }
    }
 
 
  if (!(eth->sockif = strdup (val.str_val)))
  if (!(eth->sockif = strdup (val.str_val)))
    {
    {
      fprintf (stderr, "Peripheral Ethernet: Run out of memory\n");
      fprintf (stderr, "Peripheral Ethernet: Run out of memory\n");
      exit (-1);
      exit (-1);
    }
    }
}       /* eth_sockif() */
}       /* eth_sockif() */
 
 
 
 
static void
static void
eth_vapi_id (union param_val  val,
eth_vapi_id (union param_val  val,
             void            *dat)
             void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  eth->base_vapi_id = val.int_val;
  eth->base_vapi_id = val.int_val;
}
}
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Initialize a new Ethernet configuration
/*!Initialize a new Ethernet configuration
 
 
   ALL parameters are set explicitly to default values.                      */
   ALL parameters are set explicitly to default values.                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void *
static void *
eth_sec_start (void)
eth_sec_start (void)
{
{
  struct eth_device *new = malloc (sizeof (struct eth_device));
  struct eth_device *new = malloc (sizeof (struct eth_device));
 
 
  if (!new)
  if (!new)
    {
    {
      fprintf (stderr, "Peripheral Eth: Run out of memory\n");
      fprintf (stderr, "Peripheral Eth: Run out of memory\n");
      exit (-1);
      exit (-1);
    }
    }
 
 
  memset (new, 0, sizeof (struct eth_device));
  memset (new, 0, sizeof (struct eth_device));
 
 
  new->enabled      = 1;
  new->enabled      = 1;
  new->baseaddr     = 0;
  new->baseaddr     = 0;
  new->dma          = 0;
  new->dma          = 0;
  new->mac_int      = 0;
  new->mac_int      = 0;
  new->rtx_type     = 0;
  new->rtx_type     = 0;
  new->rx_channel   = 0;
  new->rx_channel   = 0;
  new->tx_channel   = 0;
  new->tx_channel   = 0;
  new->rxfile       = strdup ("eth_rx");
  new->rxfile       = strdup ("eth_rx");
  new->txfile       = strdup ("eth_tx");
  new->txfile       = strdup ("eth_tx");
  new->sockif       = strdup ("or1ksim_eth");
  new->sockif       = strdup ("or1ksim_eth");
  new->base_vapi_id = 0;
  new->base_vapi_id = 0;
 
 
  return new;
  return new;
}
}
 
 
static void
static void
eth_sec_end (void *dat)
eth_sec_end (void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  struct mem_ops ops;
  struct mem_ops ops;
 
 
  if (!eth->enabled)
  if (!eth->enabled)
    {
    {
      free (eth->rxfile);
      free (eth->rxfile);
      free (eth->txfile);
      free (eth->txfile);
      free (eth->sockif);
      free (eth->sockif);
      free (eth);
      free (eth);
      return;
      return;
    }
    }
 
 
  memset (&ops, 0, sizeof (struct mem_ops));
  memset (&ops, 0, sizeof (struct mem_ops));
 
 
  ops.readfunc32 = eth_read32;
  ops.readfunc32 = eth_read32;
  ops.writefunc32 = eth_write32;
  ops.writefunc32 = eth_write32;
  ops.read_dat32 = dat;
  ops.read_dat32 = dat;
  ops.write_dat32 = dat;
  ops.write_dat32 = dat;
 
 
  /* FIXME: Correct delay? */
  /* FIXME: Correct delay? */
  ops.delayr = 2;
  ops.delayr = 2;
  ops.delayw = 2;
  ops.delayw = 2;
  reg_mem_area (eth->baseaddr, ETH_ADDR_SPACE, 0, &ops);
  reg_mem_area (eth->baseaddr, ETH_ADDR_SPACE, 0, &ops);
  reg_sim_stat (eth_status, dat);
  reg_sim_stat (eth_status, dat);
  reg_sim_reset (eth_reset, dat);
  reg_sim_reset (eth_reset, dat);
}
}
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Register a new Ethernet configuration                                     */
/*!Register a new Ethernet configuration                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
reg_ethernet_sec ()
reg_ethernet_sec ()
{
{
  struct config_section *sec =
  struct config_section *sec =
    reg_config_sec ("ethernet", eth_sec_start, eth_sec_end);
    reg_config_sec ("ethernet", eth_sec_start, eth_sec_end);
 
 
  reg_config_param (sec, "enabled",    paramt_int,  eth_enabled);
  reg_config_param (sec, "enabled",    PARAMT_INT,  eth_enabled);
  reg_config_param (sec, "baseaddr",   paramt_addr, eth_baseaddr);
  reg_config_param (sec, "baseaddr",   PARAMT_ADDR, eth_baseaddr);
  reg_config_param (sec, "dma",        paramt_int,  eth_dma);
  reg_config_param (sec, "dma",        PARAMT_INT,  eth_dma);
  reg_config_param (sec, "irq",        paramt_int,  eth_irq);
  reg_config_param (sec, "irq",        PARAMT_INT,  eth_irq);
  reg_config_param (sec, "rtx_type",   paramt_int,  eth_rtx_type);
  reg_config_param (sec, "rtx_type",   PARAMT_INT,  eth_rtx_type);
  reg_config_param (sec, "rx_channel", paramt_int,  eth_rx_channel);
  reg_config_param (sec, "rx_channel", PARAMT_INT,  eth_rx_channel);
  reg_config_param (sec, "tx_channel", paramt_int,  eth_tx_channel);
  reg_config_param (sec, "tx_channel", PARAMT_INT,  eth_tx_channel);
  reg_config_param (sec, "rxfile",     paramt_str,  eth_rxfile);
  reg_config_param (sec, "rxfile",     PARAMT_STR,  eth_rxfile);
  reg_config_param (sec, "txfile",     paramt_str,  eth_txfile);
  reg_config_param (sec, "txfile",     PARAMT_STR,  eth_txfile);
  reg_config_param (sec, "sockif",     paramt_str,  eth_sockif);
  reg_config_param (sec, "sockif",     PARAMT_STR,  eth_sockif);
  reg_config_param (sec, "vapi_id",    paramt_int,  eth_vapi_id);
  reg_config_param (sec, "vapi_id",    PARAMT_INT,  eth_vapi_id);
 
 
}       /* reg_ethernet_sec() */
}       /* reg_ethernet_sec() */
 
 
 
 

powered by: WebSVN 2.1.0

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