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

Subversion Repositories openrisc_me

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc
    from Rev 442 to Rev 443
    Reverse comparison

Rev 442 → Rev 443

/trunk/or1ksim/doc/or1ksim.texi
642,7 → 642,9
@section Trace Generation
@cindex trace generation of @value{OR1KSIM}
 
An execution trace can be generated at run time with options passed by the command line, or via the operating system's signal passing mechanism.
An execution trace can be generated at run time with options passed by
the command line, or via the operating system's signal passing
mechanism.
 
The following, passed at run time, can be used to create an execution dump.
 
656,15 → 658,23
after each instruction (one line per instruction).
@end table
 
Passing a signal @code{SIGUSR1} while the simulator is running toggles trace generation. This can be done with the following command, assuming @value{OR1KSIM}'s executable name is @code{or32-elf-sim}:
Passing a signal @code{SIGUSR1} while the simulator is running toggles
trace generation. This can be done with the following command, assuming
@value{OR1KSIM}'s executable name is @code{or32-elf-sim}:
 
@example
pkill -SIGUSR1 or32-elf-sim
@end example
 
This is useful in the case where trace output is desired after a significant amount of simulation time, where it would be inconvenient to generate trace up to that point.
This is useful in the case where trace output is desired after a
significant amount of simulation time, where it would be inconvenient to
generate trace up to that point.
 
If the @code{pkill} utility is not available, the @code{kill} utility can be used if @value{OR1KSIM}'s process number is known. Use the following to determine the process ID of the @code{or32-elf-sim} and then send the @code{SIGUSR1} command to toggle execution trace generation:
If the @code{pkill} utility is not available, the @code{kill} utility
can be used if @value{OR1KSIM}'s process number is known. Use the
following to determine the process ID of the @code{or32-elf-sim} and
then send the @code{SIGUSR1} command to toggle execution trace
generation:
 
@example
ps a | grep or32-elf-sim
/trunk/or1ksim/peripheral/eth.c
2,7 → 2,7
 
Copyright (C) 2001 by Erez Volk, erez@opencores.org
Ivan Guzvinec, ivang@opencores.org
Copyright (C) 2008 Embecosm Limited
Copyright (C) 2008, 2001 Embecosm Limited
Copyright (C) 2010 ORSoC
 
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
63,315 → 63,513
#include "toplevel-support.h"
#include "sim-cmd.h"
 
 
/* Control debug messages */
#ifndef ETH_DEBUG
# define ETH_DEBUG 1
#endif
 
 
/* -------------------------------------------------------------------------- */
/*!Structure describing the Ethernet device */
/* -------------------------------------------------------------------------- */
struct eth_device
{
/* Is peripheral enabled */
int enabled;
/* Basic stuff about the device */
int enabled; /* Is peripheral enabled */
oraddr_t baseaddr; /* Base address in memory */
unsigned long int base_vapi_id; /* Start of VAPI ID block */
 
/* Base address in memory */
oraddr_t baseaddr;
 
/* Which DMA controller is this MAC connected to */
/* DMA controller this MAC is connected to, and associated channels */
unsigned dma;
unsigned tx_channel;
unsigned rx_channel;
 
/* Our address */
unsigned char mac_address[ETHER_ADDR_LEN];
/* Details of the hardware */
unsigned char mac_address[ETHER_ADDR_LEN]; /* Ext HW address */
unsigned long int phy_addr; /* Int HW address */
unsigned long int mac_int; /* interrupt line number */
int int_line_stat; /* interrupt line status */
 
/* interrupt line number */
unsigned long mac_int;
/* External interface deatils */
int rtx_type; /* Type of external i/f: FILE or TAP */
 
/* interrupt line status */
int int_line_stat;
 
/* VAPI ID */
unsigned long base_vapi_id;
 
/* Ethernet PHY address */
unsigned long phy_addr;
 
/* What sort of external I/F: FILE or TAP */
int rtx_type;
 
/* RX and TX file names and handles for FILE type connection. */
char *rxfile, *txfile;
int txfd;
int rxfd;
off_t loopback_offset;
char *rxfile; /* Rx filename */
char *txfile; /* Tx filename */
int txfd; /* Rx file handle */
int rxfd; /* Tx file handle */
off_t loopback_offset; /* Circular buffer offset */
 
/* Info for TAP type connections */
int rtx_fd;
char *tap_dev;
char *tap_dev; /* The TAP device */
int rtx_fd; /* TAP device handle */
 
/* Current TX state */
struct
{
unsigned long state;
unsigned long bd_index;
unsigned long bd;
unsigned long bd_addr;
unsigned working, waiting_for_dma, error;
long packet_length;
unsigned minimum_length, maximum_length;
unsigned add_crc;
unsigned crc_dly;
unsigned long crc_value;
long bytes_left, bytes_sent;
unsigned long int bd_index;
} tx;
 
/* Current RX state */
struct
{
unsigned long state;
unsigned long bd_index;
unsigned long bd;
unsigned long bd_addr;
int fd;
off_t *offset;
unsigned working, error, waiting_for_dma;
long packet_length, bytes_read, bytes_left;
enum {
ETH_RXSTATE_IDLE, /* Was set to 0 */
ETH_RXSTATE_WAIT4BD, /* Was set to 10 */
ETH_RXSTATE_RECV, /* Was set to 20 */
ETH_RXSTATE_WRITEFIFO, /* Was set to 30 */
} state;
unsigned long int bd_index;
unsigned long int bd;
unsigned long int bd_addr;
int fd;
off_t *offset;
unsigned int working;
unsigned int waiting_for_dma;
unsigned int error;
long int packet_length;
long int bytes_read;
long int bytes_left;
} rx;
 
/* Visible registers */
struct
{
unsigned long moder;
unsigned long int_source;
unsigned long int_mask;
unsigned long ipgt;
unsigned long ipgr1;
unsigned long ipgr2;
unsigned long packetlen;
unsigned long collconf;
unsigned long tx_bd_num;
unsigned long controlmoder;
unsigned long miimoder;
unsigned long miicommand;
unsigned long miiaddress;
unsigned long miitx_data;
unsigned long miirx_data;
unsigned long miistatus;
unsigned long hash0;
unsigned long hash1;
unsigned long int moder;
unsigned long int int_source;
unsigned long int int_mask;
unsigned long int ipgt;
unsigned long int ipgr1;
unsigned long int ipgr2;
unsigned long int packetlen;
unsigned long int collconf;
unsigned long int tx_bd_num;
unsigned long int controlmoder;
unsigned long int miimoder;
unsigned long int miicommand;
unsigned long int miiaddress;
unsigned long int miitx_data;
unsigned long int miirx_data;
unsigned long int miistatus;
unsigned long int hash0;
unsigned long int hash1;
 
/* Buffer descriptors */
unsigned long bd_ram[ETH_BD_SPACE / 4];
unsigned long int bd_ram[ETH_BD_SPACE / 4];
} regs;
 
unsigned char rx_buff[ETH_MAXPL];
unsigned char tx_buff[ETH_MAXPL];
unsigned char lo_buff[ETH_MAXPL];
unsigned char rx_buff[ETH_MAXPL];
unsigned char tx_buff[ETH_MAXPL];
unsigned char lo_buff[ETH_MAXPL];
};
 
 
/* simulator interface */
static void eth_vapi_read (unsigned long id, unsigned long data, void *dat);
/* register interface */
static void eth_write32 (oraddr_t addr, uint32_t value, void *dat);
static uint32_t eth_read32 (oraddr_t addr, void *dat);
/* clock */
static void eth_controller_tx_clock (void *);
static void eth_controller_rx_clock (void *);
/* utility functions */
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_rx_next_packet (struct eth_device *);
static void eth_write_tx_bd_num (struct eth_device *, unsigned long value);
static void eth_miim_trans (void *dat);
 
#define ETH_DEBUG 0
/* -------------------------------------------------------------------------- */
/*!Utility function to read from the ethernet RX file.
 
Helper function when using file I/O.
 
/* ========================================================================== */
/* Dummy socket routines. These are the points where we spoof an Ethernet */
/* network. */
This function moves the file pointer to the current place in the packet
before reading. The Ethernet device datastructure contains the file
descriptor and offset to use.
 
@param[in] eth Ethernet device datastruture.
@param[out] buf Buffer for read data.
@param[in] count Number of bytes to read.
 
@return Number of bytes read, or zero on end-of-file or -1 on error. */
/* -------------------------------------------------------------------------- */
static ssize_t
eth_read_rx_file (struct eth_device *eth,
void *buf,
size_t count)
{
ssize_t result;
 
if (eth->rx.fd <= 0)
{
return 0;
}
 
/* ========================================================================= */
/* TX LOGIC */
/*---------------------------------------------------------------------------*/
if (eth->rx.offset)
{
if (lseek (eth->rx.fd, *(eth->rx.offset), SEEK_SET) == (off_t) - 1)
{
return 0;
}
}
 
/*
* TX clock
* Responsible for starting and finishing TX
*/
result = read (eth->rx.fd, buf, count);
 
if (eth->rx.offset && result >= 0)
{
*(eth->rx.offset) += result;
}
 
return result;
 
} /* eth_read_rx_file () */
 
 
/* -------------------------------------------------------------------------- */
/*!Skip bytes in the RX file.
 
Helper function when using file I/O.
 
This just updates the offset pointer in the ethernet device datastructure.
 
@param[in] eth Ethernet device datastruture.
@param[in] count Number of bytes to skip. */
/* -------------------------------------------------------------------------- */
static void
eth_controller_tx_clock (void *dat)
eth_skip_rx_file (struct eth_device *eth,
off_t count)
{
struct eth_device *eth = dat;
int bAdvance = 1;
long nwritten = 0;
unsigned long read_word;
eth->rx.offset += count;
 
switch (eth->tx.state)
{
case ETH_TXSTATE_IDLE:
eth->tx.state = ETH_TXSTATE_WAIT4BD;
break;
case ETH_TXSTATE_WAIT4BD:
/* Read buffer descriptor */
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_skip_rx_file () */
 
if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, READY))
{
/*****************/
/* initialize TX */
eth->tx.bytes_left = eth->tx.packet_length =
GET_FIELD (eth->tx.bd, ETH_TX_BD, LENGTH);
eth->tx.bytes_sent = 0;
 
/* Initialize error status bits */
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, RETRANSMIT);
CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, UNDERRUN);
CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, NO_CARRIER);
SET_FIELD (eth->tx.bd, ETH_TX_BD, RETRY, 0);
/* -------------------------------------------------------------------------- */
/* Move to next buffer descriptor in RX file.
 
/* Find out minimum length */
if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, PAD) ||
TEST_FLAG (eth->regs.moder, ETH_MODER, PAD))
eth->tx.minimum_length =
GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MINFL);
else
eth->tx.minimum_length = eth->tx.packet_length;
Helper function when using file I/O.
 
/* Find out maximum length */
if (TEST_FLAG (eth->regs.moder, ETH_MODER, HUGEN))
eth->tx.maximum_length = eth->tx.packet_length;
else
eth->tx.maximum_length =
GET_FIELD (eth->regs.packetlen, ETH_PACKETLEN, MAXFL);
Skip any remaining bytes in the Rx file for this transaction.
 
/* Do we need CRC on this packet? */
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, LAST)))
eth->tx.add_crc = 1;
else
eth->tx.add_crc = 0;
@param[in] eth Ethernet device datastruture. */
/* -------------------------------------------------------------------------- */
static void
eth_rx_next_packet (struct eth_device *eth)
{
/* Skip any possible leftovers */
if (eth->rx.bytes_left)
{
eth_skip_rx_file (eth, eth->rx.bytes_left);
}
} /* eth_rx_next_packet () */
 
if (TEST_FLAG (eth->regs.moder, ETH_MODER, DLYCRCEN))
eth->tx.crc_dly = 1;
else
eth->tx.crc_dly = 0;
/* XXX - For now we skip CRC calculation */
 
if (eth->rtx_type == ETH_RTX_FILE)
/* -------------------------------------------------------------------------- */
/*!Emulate MIIM transaction to ethernet PHY
 
@param[in] eth Ethernet device datastruture. */
/* -------------------------------------------------------------------------- */
static void
eth_miim_trans (struct eth_device *eth)
{
switch (eth->regs.miicommand)
{
case ((1 << ETH_MIICOMM_WCDATA_OFFSET)):
/* Perhaps something to emulate here later, but for now do nothing */
break;
case ((1 << ETH_MIICOMM_RSTAT_OFFSET)):
/*
printf("or1ksim: eth_miim_trans: phy %d\n",(int)
((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
ETH_MIIADDR_FIAD_MASK));
printf("or1ksim: eth_miim_trans: reg %d\n",(int)
((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
ETH_MIIADDR_RGAD_MASK));
*/
/*First check if it's the correct PHY to address */
if (((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
ETH_MIIADDR_FIAD_MASK) == eth->phy_addr)
{
/* Correct PHY - now switch based on the register address in the PHY*/
switch ((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
ETH_MIIADDR_RGAD_MASK)
{
/* write packet length to file */
nwritten =
write (eth->txfd, &(eth->tx.packet_length),
sizeof (eth->tx.packet_length));
case MII_BMCR:
eth->regs.miirx_data = BMCR_FULLDPLX;
break;
case MII_BMSR:
eth->regs.miirx_data = BMSR_LSTATUS | BMSR_ANEGCOMPLETE |
BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | BMSR_100FULL;
break;
case MII_PHYSID1:
eth->regs.miirx_data = 0x22; /* Micrel PHYID */
break;
case MII_PHYSID2:
eth->regs.miirx_data = 0x1613; /* Micrel PHYID */
break;
case MII_ADVERTISE:
eth->regs.miirx_data = ADVERTISE_FULL;
break;
case MII_LPA:
eth->regs.miirx_data = LPA_DUPLEX | LPA_100;
break;
case MII_EXPANSION:
eth->regs.miirx_data = 0;
break;
case MII_CTRL1000:
eth->regs.miirx_data = 0;
break;
case MII_STAT1000:
eth->regs.miirx_data = 0;
break;
case MII_ESTATUS:
eth->regs.miirx_data = 0;
break;
case MII_DCOUNTER:
eth->regs.miirx_data = 0;
break;
case MII_FCSCOUNTER:
eth->regs.miirx_data = 0;
break;
case MII_NWAYTEST:
eth->regs.miirx_data = 0;
break;
case MII_RERRCOUNTER:
eth->regs.miirx_data = 0;
break;
case MII_SREVISION:
eth->regs.miirx_data = 0;
break;
case MII_RESV1:
eth->regs.miirx_data = 0;
break;
case MII_LBRERROR:
eth->regs.miirx_data = 0;
break;
case MII_PHYADDR:
eth->regs.miirx_data = eth->phy_addr;
break;
case MII_RESV2:
eth->regs.miirx_data = 0;
break;
case MII_TPISTATUS:
eth->regs.miirx_data = 0;
break;
case MII_NCONFIG:
eth->regs.miirx_data = 0;
break;
default:
eth->regs.miirx_data = 0xffff;
break;
}
 
/************************************************/
/* start transmit with reading packet into FIFO */
eth->tx.state = ETH_TXSTATE_READFIFO;
}
else
{
eth->regs.miirx_data = 0xffff; /* PHY doesn't exist, read all 1's */
}
 
/* stay in this state if (TXEN && !READY) */
break;
case ETH_TXSTATE_READFIFO:
//if (eth->tx.bytes_sent < eth->tx.packet_length)
while (eth->tx.bytes_sent < eth->tx.packet_length)
 
case ((1 << ETH_MIICOMM_SCANS_OFFSET)):
/* From MAC's datasheet:
A host initiates the Scan Status Operation by asserting the SCANSTAT
signal. The MIIM performs a continuous read operation of the PHY
Status register. The PHY is selected by the FIAD[4:0] signals. The
link status LinkFail signal is asserted/deasserted by the MIIM module
and reflects the link status bit of the PHY Status register. The
signal NVALID is used for qualifying the validity of the LinkFail
signals and the status data PRSD[15:0]. These signals are invalid
until the first scan status operation ends. During the scan status
operation, the BUSY signal is asserted until the last read is
performed (the scan status operation is stopped).
 
So for now - do nothing, leave link status indicator as permanently
with link.
*/
 
break;
default:
break;
}
} /* eth_miim_trans () */
 
 
/* -------------------------------------------------------------------------- */
/*!Tx clock function.
 
The original version had 4 states, which allowed modeling the transfer of
data one byte per cycle.
 
For now we use only the one state for efficiency. When we find something in
a buffer descriptor, we transmit it. We should wake up for this every 10
cycles.
 
We also remove numerous calculations that are not needed here.
 
@todo We should eventually reinstate the one byte per cycle transfer.
 
Responsible for starting and completing any TX actions.
 
@param[in] dat The Ethernet data structure, passed as a void pointer. */
/* -------------------------------------------------------------------------- */
static void
eth_controller_tx_clock (void *dat)
{
struct eth_device *eth = dat;
 
/* First word of BD is flags and length, second is pointer to buffer */
unsigned long int bd_info = eth->regs.bd_ram[eth->tx.bd_index];
unsigned long int bd_addr = eth->regs.bd_ram[eth->tx.bd_index + 1];
 
/* If we have a buffer ready, get it and transmit it. */
if (TEST_FLAG (bd_info, ETH_TX_BD, READY))
{
long int packet_length;
long int bytes_sent;
long int nwritten = 0;
 
/* Get the packet length */
packet_length = GET_FIELD (bd_info, ETH_TX_BD, LENGTH);
 
/* Clear error status bits and retry count. */
CLEAR_FLAG (bd_info, ETH_TX_BD, DEFER);
CLEAR_FLAG (bd_info, ETH_TX_BD, COLLISION);
CLEAR_FLAG (bd_info, ETH_TX_BD, RETRANSMIT);
CLEAR_FLAG (bd_info, ETH_TX_BD, UNDERRUN);
CLEAR_FLAG (bd_info, ETH_TX_BD, NO_CARRIER);
 
SET_FIELD (bd_info, ETH_TX_BD, RETRY, 0);
 
/* Copy data from buffer descriptor address into our local tx_buff. */
for (bytes_sent = 0; bytes_sent < packet_length; bytes_sent +=4)
{
read_word =
eval_direct32 (eth->tx.bytes_sent + eth->tx.bd_addr, 0, 0);
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 + 2] =
(unsigned char) (read_word >> 8);
eth->tx_buff[eth->tx.bytes_sent + 3] = (unsigned char) (read_word);
eth->tx.bytes_sent += 4;
unsigned long int read_word =
eval_direct32 (bytes_sent + bd_addr, 0, 0);
 
eth->tx_buff[bytes_sent] = (unsigned char) (read_word >> 24);
eth->tx_buff[bytes_sent + 1] = (unsigned char) (read_word >> 16);
eth->tx_buff[bytes_sent + 2] = (unsigned char) (read_word >> 8);
eth->tx_buff[bytes_sent + 3] = (unsigned char) (read_word);
}
//else
// {
eth->tx.state = ETH_TXSTATE_TRANSMIT;
// }
break;
case ETH_TXSTATE_TRANSMIT:
/* send packet */
 
/* Send packet according to interface type. */
switch (eth->rtx_type)
{
case ETH_RTX_FILE:
nwritten = write (eth->txfd, eth->tx_buff, eth->tx.packet_length);
/* write packet length to file */
nwritten =
write (eth->txfd, &(packet_length),
sizeof (packet_length));
/* write data to file */
nwritten = write (eth->txfd, eth->tx_buff, packet_length);
break;
 
case ETH_RTX_TAP:
#if ETH_DEBUG
printf ("Writing TAP\n");
printf("packet %d bytes:",(int) eth->tx.packet_length );
int j; for (j=0;j<eth->tx.packet_length;j++)
{ if (j%16==0)printf("\n");
else if (j%8==0) printf(" ");
printf("%.2x ", eth->tx_buff[j]);
}
printf("\nend packet:\n");
{
int j;
 
printf ("Writing TAP\n");
printf (" packet %d bytes:", (int) packet_length);
 
for (j = 0; j < packet_length; j++)
{
if (0 == (j % 16))
{
printf ("\n");
}
else if (0 == (j % 8))
{
printf (" ");
}
 
printf ("%.2x ", eth->tx_buff[j]);
}
 
printf("\nend packet:\n");
}
#endif
nwritten = write (eth->rtx_fd, eth->tx_buff, eth->tx.packet_length);
nwritten = write (eth->rtx_fd, eth->tx_buff, packet_length);
break;
}
 
/* set BD status */
if (nwritten == eth->tx.packet_length)
/* Set BD status. If we didn't write the whole packet, then we retry. */
if (nwritten == packet_length)
{
CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY);
CLEAR_FLAG (bd_info, ETH_TX_BD, READY);
SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB);
 
eth->tx.state = ETH_TXSTATE_WAIT4BD;
}
else
{
/* XXX - implement retry mechanism here! */
CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY);
CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, COLLISION);
/* Does this retry mechanism really work? */
CLEAR_FLAG (bd_info, ETH_TX_BD, READY);
CLEAR_FLAG (bd_info, ETH_TX_BD, COLLISION);
SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXE);
 
eth->tx.state = ETH_TXSTATE_WAIT4BD;
#if ETH_DEBUG
printf ("Transmit retry request.\n");
#endif
}
 
eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd;
/* Update the flags in the buffer descriptor */
eth->regs.bd_ram[eth->tx.bd_index] = bd_info;
 
/* This looks erroneous. Surely it will conflict with the retry flag */
SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB);
 
/* generate OK interrupt */
if (TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXE_M) ||
TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXB_M))
/* Generate interrupt to indicate transfer complete, under the
following criteria all being met:
- either INT_MASK flag for Tx (OK or error) is set
- the bugger descriptor has its IRQ flag set
- there is no interrupt in progress.
 
@todo We ought to warn if we get here and fail to set an IRQ. */
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 (bd_info, ETH_TX_BD, IRQ) &&
!eth->int_line_stat)
{
if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, IRQ) && !eth->int_line_stat)
{
#if ETH_DEBUG
printf ("ETH_TXSTATE_TRANSMIT interrupt\n");
printf ("TRANSMIT interrupt\n");
#endif
report_interrupt (eth->mac_int);
eth->int_line_stat = 1;
}
report_interrupt (eth->mac_int);
eth->int_line_stat = 1;
}
else
{
#if ETH_DEBUG
printf ("Failed to send TRANSMIT interrupt\n");
#endif
}
 
/* advance to next BD */
if (bAdvance)
/* Advance to next BD, wrapping around if appropriate. */
if (TEST_FLAG (bd_info, ETH_TX_BD, WRAP) ||
eth->tx.bd_index >= ETH_BD_COUNT)
{
if (TEST_FLAG (eth->tx.bd, ETH_TX_BD, WRAP) ||
eth->tx.bd_index >= ETH_BD_COUNT)
eth->tx.bd_index = 0;
else
eth->tx.bd_index += 2;
eth->tx.bd_index = 0;
}
 
break;
else
{
eth->tx.bd_index += 2;
}
}
 
/* Reschedule */
/* Wake up again after 1 ticks (was 10, changed by Julius). */
SCHED_ADD (eth_controller_tx_clock, dat, 1);
}
 
} /* eth_controller_tx_clock () */
 
 
/* -------------------------------------------------------------------------- */
/*!Rx clock function.
 
NEEDS WRITING
 
The original version had 4 states, which allowed modeling the transfer of
data one byte per cycle.
 
For now we use only the one state for efficiency. When we find something in
a buffer descriptor, we transmit it. We should wake up for this every 10
cycles.
 
We also remove numerous calculations that are not needed here.
 
@todo We should eventually reinstate the one byte per cycle transfer.
 
Responsible for starting and completing any TX actions.
 
@param[in] dat The Ethernet data structure, passed as a void pointer. */
/* -------------------------------------------------------------------------- */
 
/* ========================================================================= */
 
 
685,57 → 883,41
break;
}
 
/* Reschedule */
/* Reschedule. Was 10 ticks when waiting (ETH_RXSTATE_RECV). Now always 1
tick. */
SCHED_ADD (eth_controller_rx_clock, dat, 1);
}
 
/* ========================================================================= */
/* Move to next RX BD */
static void
eth_rx_next_packet (struct eth_device *eth)
{
/* Skip any possible leftovers */
if (eth->rx.bytes_left)
eth_skip_rx_file (eth, eth->rx.bytes_left);
}
 
/* "Skip" bytes in RX file */
static void
eth_skip_rx_file (struct eth_device *eth, off_t count)
{
eth->rx.offset += count;
}
/* ========================================================================= */
 
 
/*
* Utility function to read from the ethernet RX file
* This function moves the file pointer to the current place in the packet before reading
* VAPI connection to outside
*/
static ssize_t
eth_read_rx_file (struct eth_device *eth, void *buf, size_t count)
static void
eth_vapi_read (unsigned long id, unsigned long data, void *dat)
{
ssize_t result;
unsigned long which;
struct eth_device *eth = dat;
 
if (eth->rx.fd <= 0)
which = id - eth->base_vapi_id;
 
if (!eth)
{
return 0;
return;
}
 
if (eth->rx.offset)
if (lseek (eth->rx.fd, *(eth->rx.offset), SEEK_SET) == (off_t) - 1)
{
return 0;
}
 
result = read (eth->rx.fd, buf, count);
if (eth->rx.offset && result >= 0)
*(eth->rx.offset) += result;
 
return result;
switch (which)
{
case ETH_VAPI_DATA:
break;
case ETH_VAPI_CTRL:
break;
}
}
 
/* ========================================================================= */
 
 
/* -------------------------------------------------------------------------- */
/*!Reset the Ethernet.
 
1095,7 → 1277,9
eth->regs.collconf = value;
return;
case ETH_TX_BD_NUM:
eth_write_tx_bd_num (eth, value);
/* When TX_BD_NUM is written, also reset current RX BD index */
eth->regs.tx_bd_num = value & 0xFF;
eth->rx.bd_index = eth->regs.tx_bd_num << 1;
return;
case ETH_CTRLMODER:
eth->regs.controlmoder = value;
1106,7 → 1290,7
case ETH_MIICOMMAND:
eth->regs.miicommand = value;
/* Perform MIIM transaction, if required */
eth_miim_trans(dat);
eth_miim_trans (eth);
return;
case ETH_MIIADDRESS:
eth->regs.miiaddress = value;
1159,41 → 1343,9
/* ========================================================================= */
 
 
/*
* VAPI connection to outside
*/
static void
eth_vapi_read (unsigned long id, unsigned long data, void *dat)
{
unsigned long which;
struct eth_device *eth = dat;
 
which = id - eth->base_vapi_id;
 
if (!eth)
{
return;
}
 
switch (which)
{
case ETH_VAPI_DATA:
break;
case ETH_VAPI_CTRL:
break;
}
}
 
/* ========================================================================= */
 
 
/* When TX_BD_NUM is written, also reset current RX BD index */
static void
eth_write_tx_bd_num (struct eth_device *eth, unsigned long value)
{
eth->regs.tx_bd_num = value & 0xFF;
eth->rx.bd_index = eth->regs.tx_bd_num << 1;
}
 
/* ========================================================================= */
 
1452,136 → 1604,6
 
 
/*---------------------------------------------------------------------------*/
/*!Emulate MIIM transaction to ethernet PHY
 
@param[in] dat The config data structure */
/*---------------------------------------------------------------------------*/
static void
eth_miim_trans (void *dat)
{
struct eth_device *eth = dat;
switch (eth->regs.miicommand)
{
case ((1 << ETH_MIICOMM_WCDATA_OFFSET)):
/* Perhaps something to emulate here later, but for now do nothing */
break;
case ((1 << ETH_MIICOMM_RSTAT_OFFSET)):
/*
printf("or1ksim: eth_miim_trans: phy %d\n",(int)
((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
ETH_MIIADDR_FIAD_MASK));
printf("or1ksim: eth_miim_trans: reg %d\n",(int)
((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
ETH_MIIADDR_RGAD_MASK));
*/
/*First check if it's the correct PHY to address */
if (((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
ETH_MIIADDR_FIAD_MASK) == eth->phy_addr)
{
/* Correct PHY - now switch based on the register address in the PHY*/
switch ((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
ETH_MIIADDR_RGAD_MASK)
{
case MII_BMCR:
eth->regs.miirx_data = BMCR_FULLDPLX;
break;
case MII_BMSR:
eth->regs.miirx_data = BMSR_LSTATUS | BMSR_ANEGCOMPLETE |
BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | BMSR_100FULL;
break;
case MII_PHYSID1:
eth->regs.miirx_data = 0x22; /* Micrel PHYID */
break;
case MII_PHYSID2:
eth->regs.miirx_data = 0x1613; /* Micrel PHYID */
break;
case MII_ADVERTISE:
eth->regs.miirx_data = ADVERTISE_FULL;
break;
case MII_LPA:
eth->regs.miirx_data = LPA_DUPLEX | LPA_100;
break;
case MII_EXPANSION:
eth->regs.miirx_data = 0;
break;
case MII_CTRL1000:
eth->regs.miirx_data = 0;
break;
case MII_STAT1000:
eth->regs.miirx_data = 0;
break;
case MII_ESTATUS:
eth->regs.miirx_data = 0;
break;
case MII_DCOUNTER:
eth->regs.miirx_data = 0;
break;
case MII_FCSCOUNTER:
eth->regs.miirx_data = 0;
break;
case MII_NWAYTEST:
eth->regs.miirx_data = 0;
break;
case MII_RERRCOUNTER:
eth->regs.miirx_data = 0;
break;
case MII_SREVISION:
eth->regs.miirx_data = 0;
break;
case MII_RESV1:
eth->regs.miirx_data = 0;
break;
case MII_LBRERROR:
eth->regs.miirx_data = 0;
break;
case MII_PHYADDR:
eth->regs.miirx_data = eth->phy_addr;
break;
case MII_RESV2:
eth->regs.miirx_data = 0;
break;
case MII_TPISTATUS:
eth->regs.miirx_data = 0;
break;
case MII_NCONFIG:
eth->regs.miirx_data = 0;
break;
default:
eth->regs.miirx_data = 0xffff;
break;
}
}
else
eth->regs.miirx_data = 0xffff; /* PHY doesn't exist, read all 1's */
break;
 
case ((1 << ETH_MIICOMM_SCANS_OFFSET)):
/* From MAC's datasheet:
A host initiates the Scan Status Operation by asserting the SCANSTAT
signal. The MIIM performs a continuous read operation of the PHY
Status register. The PHY is selected by the FIAD[4:0] signals. The
link status LinkFail signal is asserted/deasserted by the MIIM module
and reflects the link status bit of the PHY Status register. The
signal NVALID is used for qualifying the validity of the LinkFail
signals and the status data PRSD[15:0]. These signals are invalid
until the first scan status operation ends. During the scan status
operation, the BUSY signal is asserted until the last read is
performed (the scan status operation is stopped).
 
So for now - do nothing, leave link status indicator as permanently
with link.
*/
 
break;
default:
break;
}
 
}
 
/*---------------------------------------------------------------------------*/
/*!Initialize a new Ethernet configuration
 
ALL parameters are set explicitly to default values. */
/trunk/or1ksim/peripheral/eth.h
243,16 → 243,6
/*
* Implementatino of Ethernet MAC Registers and State
*/
#define ETH_TXSTATE_IDLE 0
#define ETH_TXSTATE_WAIT4BD 10
#define ETH_TXSTATE_READFIFO 20
#define ETH_TXSTATE_TRANSMIT 30
 
#define ETH_RXSTATE_IDLE 0
#define ETH_RXSTATE_WAIT4BD 10
#define ETH_RXSTATE_RECV 20
#define ETH_RXSTATE_WRITEFIFO 30
 
#define ETH_RTX_FILE 0
#define ETH_RTX_TAP 1
#define ETH_RTX_VAPI 2
/trunk/or1ksim/toplevel-support.c
96,6 → 96,7
 
} /* ctrl_c() */
 
 
/*---------------------------------------------------------------------------*/
/*!Signal handler for SIGUSR1
 
/trunk/or1ksim/brstart.sh
30,7 → 30,6
 
# - <bridge> is the bridge interface to use, e.g. br0
# - <eth> is the hardware ethernet interface to use, e.g. eth0
# - <mac> is the MAC of the Or1ksim Linux instance
# - <tap> is/are the persistent TAP interface(s)
 
# The tap interfaces must have been previously set up persistently by the

powered by: WebSVN 2.1.0

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