URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 345 to Rev 346
- ↔ Reverse comparison
Rev 345 → Rev 346
/trunk/or1ksim/peripheral/ethernet.c
29,7 → 29,7
#include <unistd.h> |
#include <errno.h> |
|
#include "ethernet.h" |
#include "ethernet_i.h" |
#include "dma.h" |
#include "trace.h" |
#include "sim-config.h" |
43,17 → 43,27
static unsigned long eth_read32( unsigned long addr ); |
static void eth_controller_tx_clock( struct eth_device * ); |
static void eth_controller_rx_clock( struct eth_device * ); |
static void eth_start_tx( struct eth_device * ); |
static void eth_finish_tx( struct eth_device * ); |
static void eth_start_rx( struct eth_device * ); |
static void eth_finish_rx( struct eth_device * ); |
|
static void eth_write_rx_bd_adr( struct eth_device *, unsigned long value ); |
static unsigned long eth_rx( struct eth_device * ); |
static void eth_tx( struct eth_device *, unsigned long ); |
static void eth_rx_next_packet( struct eth_device * ); |
|
static ssize_t eth_initialize_tx_crc( struct eth_device * ); |
static ssize_t eth_write_tx_file_and_accumulate_crc( struct eth_device *, const 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_rewind_rx_file( struct eth_device *, off_t ); |
|
static int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr ); |
static void eth_close_files( struct eth_device *eth ); |
|
|
|
/* Reset. Initializes all registers to default and places devices in memory address space. */ |
void eth_reset() |
{ |
125,7 → 135,6
eth->rxfd = eth->txfd = -1; |
} |
|
|
/* Print register values on stdout */ |
void eth_status( void ) |
{ |
154,8 → 163,9
printf( "MIITX_DATA : 0x%08lX\n", eth->regs.miitx_data ); |
printf( "MIIRX_DATA : 0x%08lX\n", eth->regs.miirx_data ); |
printf( "MIISTATUS : 0x%08lX\n", eth->regs.miistatus ); |
printf( "MAC_ADDR0 : 0x%08lX\n", eth->regs.mac_addr0 ); |
printf( "MAC_ADDR1 : 0x%08lX\n", eth->regs.mac_addr1 ); |
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[3], eth->mac_address[4], eth->mac_address[5] ); |
} |
} |
|
212,9 → 222,12
case ETH_MIITX_DATA: return eth->regs.miitx_data; |
case ETH_MIIRX_DATA: return eth->regs.miirx_data; |
case ETH_MIISTATUS: return eth->regs.miistatus; |
case ETH_MAC_ADDR0: return eth->regs.mac_addr0; |
case ETH_MAC_ADDR1: return eth->regs.mac_addr1; |
|
case ETH_MAC_ADDR0: return (((unsigned long)eth->mac_address[3]) << 24) | |
(((unsigned long)eth->mac_address[2]) << 16) | |
(((unsigned long)eth->mac_address[1]) << 8) | |
(unsigned long)eth->mac_address[0]; |
case ETH_MAC_ADDR1: return (((unsigned long)eth->mac_address[5]) << 8) | |
(unsigned long)eth->mac_address[4]; |
case ETH_DMA_RX_TX: return eth_rx( eth ); |
} |
|
253,8 → 266,16
case ETH_MIITX_DATA: eth->regs.miitx_data = value; return; |
case ETH_MIIRX_DATA: eth->regs.miirx_data = value; return; |
case ETH_MIISTATUS: eth->regs.miistatus = value; return; |
case ETH_MAC_ADDR0: eth->regs.mac_addr0 = value; return; |
case ETH_MAC_ADDR1: eth->regs.mac_addr1 = value; return; |
case ETH_MAC_ADDR0: |
eth->mac_address[0] = value & 0xFF; |
eth->mac_address[1] = (value >> 8) & 0xFF; |
eth->mac_address[2] = (value >> 16) & 0xFF; |
eth->mac_address[3] = (value >> 24) & 0xFF; |
return; |
case ETH_MAC_ADDR1: |
eth->mac_address[4] = value & 0xFF; |
eth->mac_address[5] = (value >> 8) & 0xFF; |
return; |
|
case ETH_DMA_RX_TX: eth_tx( eth, value ); return; |
} |
352,7 → 373,7
bytes[3] = (unsigned char)((data ) & 0xFF); |
|
/* And "transmit" */ |
written = write( eth->txfd, bytes, send_count ); |
written = eth_write_tx_file_and_accumulate_crc( eth, bytes, send_count ); |
if ( written > 0 ) { |
eth->tx.bytes_left -= written; |
eth->tx.bytes_sent += written; |
375,7 → 396,7
send_count = eth->tx.minimum_length - eth->tx.packet_length; |
bytes[0] = 0; |
while ( send_count -- ) |
if ( write( eth->txfd, bytes, 1 ) < 1 ) { |
if ( eth_write_tx_file_and_accumulate_crc( eth, bytes, 1 ) < 1 ) { |
printf( "Ethernet: Error writing padding to \"%s\"\n", send_count, eth->txfile ); |
eth->tx.error = 1; |
cont_run = 0; |
397,6 → 418,10
} |
|
|
/* |
* TX clock |
* Responsible for starting and finishing TX |
*/ |
void eth_controller_tx_clock( struct eth_device *eth ) |
{ |
if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) || |
407,94 → 432,135
return; |
|
/* If this is the first time, initialize TX state */ |
if ( !eth->tx.working ) { |
/* Read buffer descriptor */ |
eth->tx.bd = eth->regs.bd_ram[eth->tx.bd_index]; |
if ( !eth->tx.working ) |
eth_start_tx( eth ); |
|
if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, READY ) ) { |
eth->tx.bytes_left = eth->tx.packet_length = GET_FIELD( eth->tx.bd, ETH_TX_BD, LENGTH ); |
eth->tx.bytes_sent = 0; |
/* Check for end of transmission */ |
if ( eth->tx.working && (eth->tx.error || eth->tx.bytes_sent >= eth->tx.packet_length) ) |
eth_finish_tx( eth ); |
} |
|
/* 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 ); |
|
/* 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; |
/* Initialize state for packet transmission */ |
void eth_start_tx( struct eth_device *eth ) |
{ |
unsigned long length_with_crc; |
|
/* Read buffer descriptor */ |
eth->tx.bd = eth->regs.bd_ram[eth->tx.bd_index]; |
|
/* 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 ); |
if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, READY ) ) { |
eth->tx.bytes_left = eth->tx.packet_length = GET_FIELD( eth->tx.bd, ETH_TX_BD, LENGTH ); |
eth->tx.bytes_sent = 0; |
|
/* 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.crc = 1; |
else |
eth->tx.crc = 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 ); |
|
dprintf(( "Ethernet: Starting TX of %u bytes (min. %u, max. %u)\n", eth->tx.packet_length, |
eth->tx.minimum_length, eth->tx.maximum_length )); |
/* 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; |
|
/* Write "header" to file */ |
write( eth->txfd, &(eth->tx.packet_length), sizeof(eth->tx.packet_length) ); |
/* 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 ); |
|
/* Tell DMA to start work */ |
set_dma_req_i( eth->dma, eth->tx_channel ); |
/* 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; |
eth_initialize_tx_crc( eth ); |
|
/* Signal to ourselves */ |
eth->tx.working = 1; |
eth->tx.waiting_for_ack = 0; |
} |
dprintf(( "Ethernet: Starting TX of %u bytes (min. %u, max. %u)\n", eth->tx.packet_length, |
eth->tx.minimum_length, eth->tx.maximum_length )); |
|
/* Write "header" to file */ |
length_with_crc = eth->tx.add_crc ? (eth->tx.packet_length + 4) : eth->tx.packet_length; |
write( eth->txfd, &length_with_crc, sizeof(length_with_crc) ); |
|
/* Tell DMA to start work */ |
set_dma_req_i( eth->dma, eth->tx_channel ); |
|
/* Signal to ourselves */ |
eth->tx.working = 1; |
eth->tx.waiting_for_ack = 0; |
} |
} |
|
/* Check for end of transmission */ |
if ( eth->tx.working && (eth->tx.error || eth->tx.bytes_sent >= eth->tx.packet_length) ) { |
/* |
|
/* Handle termination of sent packet */ |
void eth_finish_tx( struct eth_device *eth ) |
{ |
/* |
* TODO: |
* handle error state! |
* somehow notify user (or does DMA take care of that?) |
*/ |
|
if ( !eth->tx.waiting_for_ack ) { |
dprintf(( "Ethernet: TX of %u bytes: %s\n", eth->tx.packet_length, |
eth->tx.error ? "Error" : "Done" )); |
if ( !eth->tx.waiting_for_ack ) { |
dprintf(( "Ethernet: TX of %u bytes: %s\n", eth->tx.packet_length, |
eth->tx.error ? "Error" : "Done" )); |
|
/* Add CRC if needed */ |
if ( eth->tx.add_crc ) |
write( eth->txfd, &(eth->tx.crc_value), sizeof(eth->tx.crc_value) ); |
|
/* Write result to bd */ |
eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd; |
/* Write result to bd */ |
eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd; |
|
/* DMA flow control */ |
set_dma_nd_i( eth->dma, eth->tx_channel ); |
eth->tx.waiting_for_ack = 1; |
} |
else if ( check_dma_ack_o( eth->dma, eth->tx_channel ) ) { |
clear_dma_nd_i( eth->dma, eth->tx_channel ); |
clear_dma_req_i( eth->dma, eth->tx_channel ); |
/* DMA flow control */ |
set_dma_nd_i( eth->dma, eth->tx_channel ); |
eth->tx.waiting_for_ack = 1; |
} |
else if ( check_dma_ack_o( eth->dma, eth->tx_channel ) ) { |
clear_dma_nd_i( eth->dma, eth->tx_channel ); |
clear_dma_req_i( eth->dma, eth->tx_channel ); |
|
eth->tx.working = eth->tx.waiting_for_ack = 0; |
eth->tx.working = eth->tx.waiting_for_ack = 0; |
|
/* advance to next BD */ |
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; |
} |
/* advance to next BD */ |
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; |
} |
} |
|
|
/* Initialize calculation of packet CRC */ |
ssize_t eth_initialize_tx_crc( struct eth_device *eth ) |
{ |
eth->tx.crc_value = 0xFFFFFFFF; |
} |
|
/* Write to TX file and update CRC value */ |
ssize_t eth_write_tx_file_and_accumulate_crc( struct eth_device *eth, const void *buf, size_t count ) |
{ |
ssize_t written = write( eth->txfd, buf, count ); |
if ( written > 0 ) { |
/* TODO: Calculate CRC */ |
} |
return written; |
} |
|
|
/* |
* Clock for RX |
* Responsible for starting and finisihing RX |
*/ |
void eth_controller_rx_clock( struct eth_device *eth ) |
{ |
if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN ) || |
505,81 → 571,19
return; |
|
/* If this is the first time, initialize RX state */ |
if ( !eth->rx.working ) { |
/* Read buffer descriptor */ |
eth->rx.bd = eth->regs.bd_ram[eth->rx.bd_index]; |
if ( !eth->rx.working ) |
eth_start_rx( eth ); |
|
if ( TEST_FLAG( eth->rx.bd, ETH_TX_BD, READY ) ) { |
/* Initialize error status bits */ |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, DEFER ); |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, COLLISION ); |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, RETRANSMIT ); |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, UNDERRUN ); |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, NO_CARRIER ); |
SET_FIELD( eth->rx.bd, ETH_TX_BD, RETRY, 0 ); |
|
dprintf(( "Ethernet: Starting RX\n" )); |
|
/* Setup file to read from */ |
if ( TEST_FLAG( eth->regs.moder, ETH_MODER, LOOPBCK ) ) { |
eth->rx.fd = eth->txfd; |
eth->rx.offset = &(eth->loopback_offset); |
} else { |
eth->rx.fd = eth->rxfd; |
eth->rx.offset = 0; |
} |
|
/* Read packet length */ |
if ( eth_read_rx_file( eth, &(eth->rx.packet_length), sizeof(eth->rx.packet_length) ) |
< sizeof(eth->rx.packet_length) ) { |
/* TODO: just do what real ethernet would do */ |
printf( "eth_controller_rx_clock(): File does not have a packet ready for RX\n" ); |
cont_run = 0; |
} |
eth->rx.bytes_read = 0; |
eth->rx.bytes_left = eth->rx.packet_length; |
|
/* Tell DMA to start work */ |
set_dma_req_i( eth->dma, eth->rx_channel ); |
|
/* Signal to ourselves */ |
eth->rx.working = 1; |
eth->rx.waiting_for_ack = 0; |
} |
} |
|
/* Check for end of packet */ |
if ( eth->rx.working && (eth->rx.error || eth->rx.bytes_read >= eth->rx.packet_length) ) { |
if ( !eth->rx.waiting_for_ack ) { |
dprintf(( "Ethernet: RX of %u bytes: %s\n", eth->rx.packet_length, |
eth->rx.error ? "Error" : "Done" )); |
|
/* Write result to bd */ |
SET_FIELD( eth->rx.bd, ETH_RX_BD, LENGTH, eth->rx.packet_length ); |
eth->regs.bd_ram[eth->rx.bd_index] = eth->rx.bd; |
|
/* DMA flow control */ |
set_dma_nd_i( eth->dma, eth->rx_channel ); |
eth->rx.waiting_for_ack = 1; |
} |
else if ( check_dma_ack_o( eth->dma, eth->rx_channel ) ) { |
clear_dma_nd_i( eth->dma, eth->rx_channel ); |
clear_dma_req_i( eth->dma, eth->rx_channel ); |
|
eth->rx.working = eth->rx.waiting_for_ack = 0; |
|
/* advance to next BD */ |
if ( TEST_FLAG( eth->rx.bd, ETH_TX_BD, WRAP ) || |
eth->rx.bd_index >= ETH_BD_COUNT ) |
eth->rx.bd_index = eth->regs.rx_bd_adr; |
else |
++ eth->rx.bd_index; |
} |
} |
if ( eth->rx.working && (eth->rx.error || eth->rx.bytes_read >= eth->rx.packet_length) ) |
eth_finish_rx( eth ); |
} |
|
|
|
|
/* |
* Utility function to read from the ethernet RX file |
* This function moves the file pointer to the current place in the packet before reading |
*/ |
ssize_t eth_read_rx_file( struct eth_device *eth, void *buf, size_t count ) |
{ |
ssize_t result; |
602,3 → 606,141
|
return result; |
} |
|
|
/* "Skip" bytes in RX file */ |
void eth_skip_rx_file( struct eth_device *eth, off_t count ) |
{ |
eth->rx.offset += count; |
} |
|
/* Move RX file position back */ |
void eth_rewind_rx_file( struct eth_device *eth, off_t count ) |
{ |
eth->rx.offset -= count; |
} |
|
|
/* Initialize RX */ |
void eth_start_rx( struct eth_device *eth ) |
{ |
struct ether_header header; |
static const unsigned char bcast_address[ETH_HLEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
|
/* Read buffer descriptor */ |
eth->rx.bd = eth->regs.bd_ram[eth->rx.bd_index]; |
|
if ( TEST_FLAG( eth->rx.bd, ETH_TX_BD, READY ) ) { |
/* Initialize error status bits */ |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, DEFER ); |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, COLLISION ); |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, RETRANSMIT ); |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, UNDERRUN ); |
CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, NO_CARRIER ); |
SET_FIELD( eth->rx.bd, ETH_TX_BD, RETRY, 0 ); |
|
dprintf(( "Ethernet: Starting RX\n" )); |
|
/* Setup file to read from */ |
if ( TEST_FLAG( eth->regs.moder, ETH_MODER, LOOPBCK ) ) { |
eth->rx.fd = eth->txfd; |
eth->rx.offset = &(eth->loopback_offset); |
} else { |
eth->rx.fd = eth->rxfd; |
eth->rx.offset = 0; |
} |
|
/* Read packet length */ |
if ( eth_read_rx_file( eth, &(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) */ |
printf( "eth_start_rx(): File does not have a packet ready for RX\n" ); |
cont_run = 0; |
return; |
} |
|
/* Packet must be big enough to hold a header */ |
if ( eth->rx.packet_length < ETH_HLEN ){ |
dprintf(( "eth_start_rx(): Packet too small\n" )); |
eth_rx_next_packet( eth ); |
return; |
} |
|
if ( eth_read_rx_file( eth, &header, ETH_HLEN ) < ETH_HLEN ) { |
printf( "eth_start_rx(): Error reading packet header\n" ); |
cont_run = 0; |
return; |
} |
|
/* We haven't formally "received" the header yet */ |
eth_rewind_rx_file( eth, ETH_HLEN ); |
|
eth->rx.bytes_read = 0; |
eth->rx.bytes_left = eth->rx.packet_length; |
|
/* Unless promiscous, don't accept all packets */ |
if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, PRO ) ) { |
int for_us = (memcmp( header.ether_dhost, eth->mac_address, ETH_HLEN ) == 0); |
int for_all = (memcmp( header.ether_dhost, bcast_address, ETH_HLEN ) == 0); |
int good = for_us || (for_all && !TEST_FLAG( eth->regs.moder, ETH_MODER, BRO ) ); |
if ( !good ) { |
dprintf(( "eth_start_rx(): Packet destination is %02X:%02X:%02X:%02X:%02X:%02x, rejecting\n", |
header.ether_dhost[0], header.ether_dhost[1], header.ether_dhost[2], |
header.ether_dhost[3], header.ether_dhost[4], header.ether_dhost[5] )); |
eth_rx_next_packet( eth ); |
return; |
} |
} |
|
/* TODO: Check CRC */ |
|
/* Tell DMA to start work */ |
set_dma_req_i( eth->dma, eth->rx_channel ); |
|
/* Signal to ourselves */ |
eth->rx.working = 1; |
eth->rx.waiting_for_ack = 0; |
} |
} |
|
|
/* Finish RX */ |
void eth_finish_rx( struct eth_device *eth ) |
{ |
if ( !eth->rx.waiting_for_ack ) { |
dprintf(( "Ethernet: RX of %u bytes: %s\n", eth->rx.packet_length, |
eth->rx.error ? "Error" : "Done" )); |
|
/* Write result to bd */ |
SET_FIELD( eth->rx.bd, ETH_RX_BD, LENGTH, eth->rx.packet_length ); |
eth->regs.bd_ram[eth->rx.bd_index] = eth->rx.bd; |
|
/* DMA flow control */ |
set_dma_nd_i( eth->dma, eth->rx_channel ); |
eth->rx.waiting_for_ack = 1; |
} |
else if ( check_dma_ack_o( eth->dma, eth->rx_channel ) ) { |
clear_dma_nd_i( eth->dma, eth->rx_channel ); |
clear_dma_req_i( eth->dma, eth->rx_channel ); |
|
eth->rx.working = eth->rx.waiting_for_ack = 0; |
|
eth_rx_next_packet( eth ); |
} |
} |
|
|
/* Move to next RX BD */ |
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 ); |
|
/* advance to next BD */ |
if ( TEST_FLAG( eth->rx.bd, ETH_TX_BD, WRAP ) || |
eth->rx.bd_index >= ETH_BD_COUNT ) |
eth->rx.bd_index = eth->regs.rx_bd_adr; |
else |
++ eth->rx.bd_index; |
} |
/trunk/or1ksim/peripheral/ethernet.h
18,6 → 18,9
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
*/ |
|
#ifndef __OR1KSIM_PERIPHERAL_ETHERNET_H |
#define __OR1KSIM_PERIPHERAL_ETHERNET_H |
|
/* Exported function prototypes */ |
void eth_reset( void ); |
void eth_clock( void ); |
130,72 → 133,5
|
|
|
/* Implementatino of Ethernet MAC Registers and State */ |
struct eth_device |
{ |
/* Base address in memory */ |
unsigned long baseaddr; |
|
/* Which Ethernet MAC is this? */ |
unsigned eth_number; |
|
/* Which DMA controller is this MAC connected to */ |
unsigned dma; |
unsigned tx_channel; |
unsigned rx_channel; |
|
/* RX and TX file names and handles */ |
const char *rxfile, *txfile; |
int txfd; |
int rxfd; |
off_t loopback_offset; |
|
/* Current TX state */ |
struct |
{ |
unsigned long bd_index; |
unsigned long bd; |
unsigned working, waiting_for_ack, error; |
unsigned packet_length; |
unsigned minimum_length, maximum_length; |
unsigned crc; |
unsigned bytes_left, bytes_sent; |
} tx; |
|
/* Current RX state */ |
struct |
{ |
unsigned long bd_index; |
unsigned long bd; |
int fd; |
off_t *offset; |
unsigned working, error, waiting_for_ack; |
unsigned packet_length, bytes_read, 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 rx_bd_adr; |
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 mac_addr0; |
unsigned long mac_addr1; |
|
/* Buffer descriptors */ |
unsigned long bd_ram[ETH_BD_SPACE / 4]; |
} regs; |
}; |
#endif /* __OR1KSIM_PERIPHERAL_ETHERNET_H */ |
/trunk/or1ksim/peripheral/ethernet_i.h
0,0 → 1,158
/* ethernet_i.h -- Definition of internal types and structures for Ethernet MAC |
Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org |
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
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 Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
*/ |
|
#ifndef __OR1KSIM_PERIPHERAL_ETHERNET_I_H |
#define __OR1KSIM_PERIPHERAL_ETHERNET_I_H |
|
#include "ethernet.h" |
#include "config.h" |
|
/* |
* Ethernet protocol definitions |
*/ |
#if HAVE_NET_ETHERNET_H |
# include <net/ethernet.h> |
#else /* !HAVE_NET_ETHERNET_H -*/ |
|
#include <sys/types.h> |
|
#define ETH_ALEN 6 |
|
struct ether_addr |
{ |
u_int8_t ether_addr_octet[ETH_ALEN]; |
}; |
|
struct ether_header |
{ |
u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ |
u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ |
u_int16_t ether_type; /* packet type ID field */ |
}; |
|
/* Ethernet protocol ID's */ |
#define ETHERTYPE_PUP 0x0200 /* Xerox PUP */ |
#define ETHERTYPE_IP 0x0800 /* IP */ |
#define ETHERTYPE_ARP 0x0806 /* Address resolution */ |
#define ETHERTYPE_REVARP 0x8035 /* Reverse ARP */ |
|
#define ETHER_ADDR_LEN ETH_ALEN /* size of ethernet addr */ |
#define ETHER_TYPE_LEN 2 /* bytes in type field */ |
#define ETHER_CRC_LEN 4 /* bytes in CRC field */ |
#define ETHER_HDR_LEN ETH_HLEN /* total octets in header */ |
#define ETHER_MIN_LEN (ETH_ZLEN + ETHER_CRC_LEN) /* min packet length */ |
#define ETHER_MAX_LEN (ETH_FRAME_LEN + ETHER_CRC_LEN) /* max packet length */ |
|
/* make sure ethenet length is valid */ |
#define ETHER_IS_VALID_LEN(foo) \ |
((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) |
|
/* |
* The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have |
* (type-ETHERTYPE_TRAIL)*512 bytes of data followed |
* by an ETHER type (as given above) and then the (variable-length) header. |
*/ |
#define ETHERTYPE_TRAIL 0x1000 /* Trailer packet */ |
#define ETHERTYPE_NTRAILER 16 |
|
#define ETHERMTU ETH_DATA_LEN |
#define ETHERMIN (ETHER_MIN_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) |
|
#endif /* HAVE_NET_ETHERNET_H */ |
|
|
/* |
* Implementatino of Ethernet MAC Registers and State |
*/ |
struct eth_device |
{ |
/* Base address in memory */ |
unsigned long baseaddr; |
|
/* Which Ethernet MAC is this? */ |
unsigned eth_number; |
|
/* Which DMA controller is this MAC connected to */ |
unsigned dma; |
unsigned tx_channel; |
unsigned rx_channel; |
|
/* Our address */ |
unsigned char mac_address[ETH_ALEN]; |
|
/* RX and TX file names and handles */ |
const char *rxfile, *txfile; |
int txfd; |
int rxfd; |
off_t loopback_offset; |
|
/* Current TX state */ |
struct |
{ |
unsigned long bd_index; |
unsigned long bd; |
unsigned working, waiting_for_ack, error; |
unsigned packet_length; |
unsigned minimum_length, maximum_length; |
unsigned add_crc; |
unsigned long crc_value; |
unsigned bytes_left, bytes_sent; |
} tx; |
|
/* Current RX state */ |
struct |
{ |
unsigned long bd_index; |
unsigned long bd; |
int fd; |
off_t *offset; |
unsigned working, error, waiting_for_ack; |
unsigned packet_length, bytes_read, 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 rx_bd_adr; |
unsigned long controlmoder; |
unsigned long miimoder; |
unsigned long miicommand; |
unsigned long miiaddress; |
unsigned long miitx_data; |
unsigned long miirx_data; |
unsigned long miistatus; |
|
/* Buffer descriptors */ |
unsigned long bd_ram[ETH_BD_SPACE / 4]; |
} regs; |
}; |
|
|
|
|
#endif /* __OR1KSIM_PERIPHERAL_ETHERNET_I_H */ |