URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/orpsocv2/boards
- from Rev 480 to Rev 485
- ↔ Reverse comparison
Rev 480 → Rev 485
/actel/ordb1a3pe1500/rtl/verilog/orpsoc_top/orpsoc_top.v
1001,7 → 1001,7
wire [10:0] or1200_dbg_wp_o; |
wire or1200_dbg_bp_o; |
wire or1200_dbg_rst; |
|
|
wire or1200_clk, or1200_rst; |
wire sig_tick; |
|
/actel/ordb1a3pe1500/sw/Makefile.inc
8,7 → 8,8
# Figure out actual path the common software directory |
SW_ROOT=$(BOARD_SW_ROOT)/$(PROJ_ROOT)/sw |
|
# Set the BOARD_PATH to point to the root of this board build |
# Set the BOARD to be the path within the board/ path of the project that goes |
# to this project. |
BOARD=actel/ordb1a3pe1500 |
|
# Set RTL_VERILOG_INCLUDE_DIR so software |
/actel/ordb1a3pe1500/sw/board/include/board.h
15,11 → 15,14
// Uncomment the appropriate bootloader define. This will effect the bootrom.S |
// file, which is compiled and converted into Verilog for inclusion at |
// synthesis time. See bootloader/bootloader.S for details on each option. |
|
#ifndef PRELOAD_RAM |
#define BOOTROM_SPI_FLASH |
//#define BOOTROM_GOTO_RESET |
//#define BOOTROM_LOOP_AT_ZERO |
//#define BOOTROM_LOOP_IN_ROM |
#else |
#define BOOTROM_GOTO_RESET |
#endif |
|
// |
// Defines for each core (memory map base, OR1200 interrupt line number, etc.) |
91,4 → 94,18
// |
#define TICKS_PER_SEC 100 |
|
// |
// UART driver initialisation |
// |
#define UART_NUM_CORES 3 |
|
#define UART_BASE_ADDRESSES_CSV \ |
UART0_BASE, UART2_BASE, UART2_BASE |
|
#define UART_BAUD_RATES_CSV \ |
UART0_BAUD_RATE, UART1_BAUD_RATE, UART1_BAUD_RATE |
|
|
|
|
#endif |
/xilinx/ml501/bench/verilog/include/eth_stim.v
76,7 → 76,7
parameter eth_stim_num_rx_only_packet_size = 60; |
parameter eth_stim_num_rx_only_packet_size_change = 2'b01; // 2'b01: Increment |
parameter eth_stim_num_rx_only_packet_size_change_amount = 127; |
parameter eth_stim_num_rx_only_IPG = 180_000_000; // ps |
parameter eth_stim_num_rx_only_IPG = 800_000; // ps |
|
// Do call/response test |
reg eth_stim_do_rx_reponse_to_tx; |
95,7 → 95,7
|
// Use the smallest possible IPG |
parameter eth_stim_use_min_IPG = 0; |
parameter eth_stim_IPG_delay_max = 500_000_000; // Maximum 500uS ga |
parameter eth_stim_IPG_delay_max = 100_000_000; // Maximum 100 us |
//parameter eth_stim_IPG_delay_max = 100_000_000; // Maximum 100mS between packets |
parameter eth_stim_IPG_min_10mb = 9600_000; // 9.6 uS |
parameter eth_stim_IPG_min_100mb = 800_000; // 860+~100 = 960 nS 100MBit min IPG |
/xilinx/ml501/rtl/verilog/include/ethmac_defines.v
45,9 → 45,9
`define ETH_MBIST_CTRL_WIDTH 3 // width of MBIST control bus |
|
// Generic FIFO implementation - hopefully synthesizable with Synplify |
`define ETH_FIFO_GENERIC |
//`define ETH_FIFO_GENERIC |
// Ethernet implemented in Xilinx Chips (uncomment following lines) |
// `define ETH_FIFO_XILINX // Use Xilinx distributed ram for tx and rx fifo |
`define ETH_FIFO_XILINX // Use Xilinx distributed ram for tx and rx fifo |
// `define ETH_XILINX_RAMB4 // Selection of the used memory for Buffer descriptors |
// Core is going to be implemented in Virtex FPGA and contains Virtex |
// specific elements. |
186,9 → 186,10
|
// Defines for ethernet TX fifo size - impacts FPGA resource usage |
//`define ETH_TX_FULL_PACKET_FIFO // Full 1500 byte TX buffer - uncomment this |
//`define ETH_TX_256BYTE_FIFO // 256 byte TX buffer - uncomment this |
//`define ETH_TX_128BYTE_FIFO // 128 byte TX buffer - uncomment this |
`define ETH_TX_256BYTE_FIFO // 256 byte TX buffer - uncomment this |
//`define ETH_TX_512BYTE_FIFO // 512 byte TX buffer - uncomment this |
`define ETH_TX_1KBYTE_FIFO // 1024 byte TX buffer - uncomment this |
//`define ETH_TX_1KBYTE_FIFO // 1024 byte TX buffer - uncomment this |
|
`ifdef ETH_TX_FULL_PACKET_FIFO |
`define ETH_TX_FIFO_CNT_WIDTH 9 |
206,19 → 207,22
`define ETH_TX_FIFO_CNT_WIDTH 6 |
`define ETH_TX_FIFO_DEPTH 64 |
`else |
`ifdef ETH_TX_128BYTE_FIFO |
`define ETH_TX_FIFO_CNT_WIDTH 5 |
`define ETH_TX_FIFO_DEPTH 32 |
`else |
// Default is 64 bytes |
`define ETH_TX_FIFO_CNT_WIDTH 4 |
`define ETH_TX_FIFO_DEPTH 16 |
`define ETH_TX_FIFO_CNT_WIDTH 4 |
`define ETH_TX_FIFO_DEPTH 16 |
`endif |
`endif |
`endif |
`endif // !`ifdef ETH_TX_512BYTE_FIFO |
`endif // !`ifdef ETH_TX_512BYTE_FIFO |
`endif // !`ifdef ETH_TX_FULL_PACKET_FIFO |
|
|
|
// Settings for RX FIFO |
`define ETH_RX_FIFO_CNT_WIDTH 8 |
`define ETH_RX_FIFO_DEPTH 256 |
//`define ETH_RX_FIFO_CNT_WIDTH 8 |
//`define ETH_RX_FIFO_DEPTH 256 |
//`define ETH_RX_FIFO_CNT_WIDTH 7 |
//`define ETH_RX_FIFO_DEPTH 128 |
//`define ETH_RX_FIFO_CNT_WIDTH 6 |
225,8 → 229,8
//`define ETH_RX_FIFO_DEPTH 64 |
//`define ETH_RX_FIFO_CNT_WIDTH 5 |
//`define ETH_RX_FIFO_DEPTH 32 |
//`define ETH_RX_FIFO_CNT_WIDTH 4 |
//`define ETH_RX_FIFO_DEPTH 16 |
`define ETH_RX_FIFO_CNT_WIDTH 4 |
`define ETH_RX_FIFO_DEPTH 16 |
|
`define ETH_RX_FIFO_DATA_WIDTH 32 |
|
243,7 → 247,6
// Undefine this to enable bursting for RX (writing to memory) |
`define ETH_RX_BURST_EN |
|
|
// WISHBONE interface is Revision B3 compliant (uncomment when needed) |
`define ETH_WISHBONE_B3 |
|
252,4 → 255,4
|
// Define this to allow reading of the Wishbone control state machine on reg |
// address 0x58 |
`define WISHBONE_DEBUG |
//`define WISHBONE_DEBUG |
/xilinx/ml501/sw/tests/ethmac/sim/ethmac-rxtxcallresponse.c
0,0 → 1,681
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet MAC transmit test code //// |
//// //// |
//// Description //// |
//// Send packets while receiving packets //// |
//// //// |
//// Test data comes from pre-calculated array of random values, //// |
//// MAC TX buffer pointers are set to addresses in this array, //// |
//// saving copying the data around before transfers. //// |
//// //// |
//// Author(s): //// |
//// - jb, jb@orsoc.se, with parts taken from Linux kernel //// |
//// open_eth driver. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source 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 Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "cpu-utils.h" |
#include "board.h" |
#include "int.h" |
#include "ethmac.h" |
#include "eth-phy-mii.h" |
|
volatile unsigned tx_done; |
volatile unsigned rx_done; |
static int next_tx_buf_num; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
|
/* Let the ethernet packets use a space beginning here for buffering */ |
#define ETH_BUFF_BASE 0x01000000 |
|
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
//#undef RXBUFF_PREALLOC |
//#undef TXBUFF_PREALLOC |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
*/ |
#define OETH_RXBD_NUM 16 |
#define OETH_TXBD_NUM 16 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 0x600-4 |
#define OETH_TX_BUFF_SIZE 0x600-4 |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 1518 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
//struct sk_buff* rx_skbuff[OETH_RXBD_NUM]; |
//struct sk_buff* tx_skbuff[OETH_TXBD_NUM]; |
|
unsigned short tx_next; /* Next buffer to be sent */ |
unsigned short tx_last; /* Next buffer to be checked if packet sent */ |
unsigned short tx_full; /* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to be checked if packet |
received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
|
#define PHYNUM 7 |
|
// Data array of data to transmit, tx_data_array[] |
//#include "eth-rxtx-data.h" // Not used |
int tx_data_pointer; |
|
|
void |
eth_mii_write(char phynum, short regnum, short data) |
{ |
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE); |
regs->miiaddress = (regnum << 8) | phynum; |
regs->miitx_data = data; |
regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
} |
|
short |
eth_mii_read(char phynum, short regnum) |
{ |
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE); |
regs->miiaddress = (regnum << 8) | phynum; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
|
return regs->miirx_data; |
} |
|
|
|
// Wait here until all packets have been transmitted |
void |
wait_until_all_tx_clear(void) |
{ |
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
int some_tx_waiting = 1; |
|
while (some_tx_waiting) |
{ |
some_tx_waiting = 0; |
/* Go through the TX buffs, search for unused one */ |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
|
// Looking for buffer ready for transmit |
if((tx_bd[i].len_status & OETH_TX_BD_READY)) |
some_tx_waiting = 1; |
|
} |
} |
} |
|
|
void |
ethphy_set_10mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 10Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr &= ~BMCR_ANENABLE; // Clear auto negotiate bit |
cr &= ~BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void |
ethphy_set_100mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 100Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr |= BMCR_ANENABLE; // Clear auto negotiate bit |
cr |= BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void |
ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
regs->packet_len = 0x00400600; |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
|
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
// Setup TX Buffers |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
//tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[i].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
// Setup RX buffers |
for(i = 0; i < OETH_RXBD_NUM; i++) { |
rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ |
rx_bd[i].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps |
|
/* Enable RX and TX in MAC |
*/ |
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); |
regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN; |
|
next_tx_buf_num = 0; // init tx buffer pointer |
|
return; |
} |
|
// Enable RX in ethernet MAC |
void |
oeth_enable_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
regs->moder |= OETH_MODER_RXEN; |
} |
|
// Disable RX in ethernet MAC |
void |
oeth_disable_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
regs->moder &= ~(OETH_MODER_RXEN); |
} |
|
|
/* Setup buffer descriptors with data */ |
/* length is in BYTES */ |
void tx_packet(void* data, int length) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
volatile int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
/* Clear all of the status flags. |
*/ |
tx_bd->len_status &= ~OETH_TX_BD_STATS; |
|
/* If the frame is short, tell CPM to pad it. |
*/ |
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ |
if (length <= ETH_ZLEN) |
tx_bd->len_status |= OETH_TX_BD_PAD; |
else |
tx_bd->len_status &= ~OETH_TX_BD_PAD; |
|
#ifdef _ETH_RXTX_DATA_H_ |
// Set the address pointer to the place |
// in memory where the data is and transmit from there |
|
tx_bd->addr = (char*) &tx_data_array[tx_data_pointer&~(0x3)]; |
|
tx_data_pointer += length + 1; |
if (tx_data_pointer > (255*1024)) |
tx_data_pointer = 0; |
|
|
#else |
if (data){ |
//Copy the data into the transmit buffer, byte at a time |
char* data_p = (char*) data; |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<length;i++) |
{ |
data_b[i] = data_p[i]; |
} |
} |
#endif |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
/* Send it on its way. Tell controller its ready, interrupt when sent |
* and to put the CRC on the end. |
*/ |
tx_bd->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_CRC | OETH_TX_BD_IRQ); |
|
next_tx_buf_num = (next_tx_buf_num + 1) & OETH_TXBD_NUM_MASK; |
|
return; |
|
|
} |
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
serviced |= 0x2; |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
return; |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
bad=0; |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */ |
/* Check status for errors. |
*/ |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
report(0xbaad0001); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
report(0xbaad0002); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
report(0xbaad0003); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
report(0xbaad0004); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
report(0xbaad0005); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
report(0xbaad0006); |
} |
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
exit(0xbaaaaaad); |
|
continue; |
} |
else { |
/* Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
/* finish up */ |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */ |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */ |
rx_done++; |
} |
} |
} |
} |
|
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 0; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
/* set our test variable */ |
tx_done++; |
|
} |
} |
return; |
} |
|
// A function and defines to fill and transmit a packet |
#define MAX_TX_BUFFER 1532 |
static char tx_buffer[MAX_TX_BUFFER]; |
|
void |
fill_and_tx_call_packet(int size, int response_time) |
{ |
int i; |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (volatile oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
// Use rand() function to generate data for transmission |
// Assumption: ethernet buffer descriptors are 4byte aligned |
char* data_b = (char*) tx_bd->addr; |
// We will fill with words until there' less than a word to go |
int words_to_fill = size / sizeof(unsigned int); |
|
unsigned int* data_w = (unsigned int*) data_b; |
|
// Put first word as size of packet, second as response time |
data_w[0] = size; |
data_w[1] = response_time; |
|
for(i=2;i<words_to_fill;i++) |
data_w[i] = rand(); |
|
// Point data_b to offset wher word fills ended |
data_b += (words_to_fill * sizeof(unsigned int)); |
|
int leftover_size = size - (words_to_fill * sizeof(unsigned int)); |
|
for(i=0;i<leftover_size;i++) |
{ |
data_b[i] = rand() & 0xff; |
} |
|
tx_packet((void*)0, size); |
} |
|
// Send a packet, the very first byte of which will be read by the testbench |
// and used to indicate which test we'll use. |
void |
send_ethmac_rxtx_test_init_packet(char test) |
{ |
char cmd_tx_buffer[40]; |
cmd_tx_buffer[0] = test; |
tx_packet(cmd_tx_buffer, 40); // Smallest packet that can be sent (I think) |
} |
|
// Loop to check if a number is prime by doing mod divide of the number |
// to test by every number less than it |
int |
is_prime_number(unsigned long n) |
{ |
unsigned long c; |
if (n < 2) return 0; |
for(c=2;c<n;c++) |
if ((n % c) == 0) |
return 0; |
return 1; |
} |
|
|
int |
main () |
{ |
tx_data_pointer = 0; |
|
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(ETH0_IRQ, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
cpu_enable_user_interrupts(); |
|
/* Enable CPU timer */ |
cpu_enable_timer(); |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
/* clear tx_done, the tx interrupt handler will set it when it's been |
transmitted */ |
tx_done = 0; |
rx_done = 0; |
|
ethphy_set_100mbit(0); |
|
send_ethmac_rxtx_test_init_packet(0x0); // 0x0 - call response test |
|
#define ETH_TX_MIN_PACKET_SIZE 512 |
#define ETH_TX_NUM_PACKETS (ETH_TX_MIN_PACKET_SIZE + 20) |
|
//int response_time = 150000; // Response time before response packet it sent |
// back (should be in nanoseconds). |
int response_time = 0; |
|
unsigned long num_to_check; |
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
fill_and_tx_call_packet(num_to_check, response_time); |
|
|
// Wait a moment for the RX packet check to complete before switching off RX |
for(num_to_check=0;num_to_check=1000;num_to_check++); |
|
oeth_disable_rx(); |
|
// Now for 10mbit mode... |
ethphy_set_10mbit(0); |
|
oeth_enable_rx(); |
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
fill_and_tx_call_packet(num_to_check, response_time); |
|
oeth_disable_rx(); |
|
// Go back to 100-mbit mode |
ethphy_set_100mbit(0); |
|
oeth_enable_rx(); |
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
fill_and_tx_call_packet(num_to_check, response_time); |
|
exit(0x8000000d); |
|
} |
/xilinx/ml501/sw/tests/ethmac/sim/ethmac-rxtx.c
0,0 → 1,671
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet MAC transmit test code //// |
//// //// |
//// Description //// |
//// Send packets while receiving packets //// |
//// //// |
//// Test data comes from pre-calculated array of random values, //// |
//// MAC TX buffer pointers are set to addresses in this array, //// |
//// saving copying the data around before transfers. //// |
//// //// |
//// Author(s): //// |
//// - jb, jb@orsoc.se, with parts taken from Linux kernel //// |
//// open_eth driver. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source 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 Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "cpu-utils.h" |
#include "board.h" |
#include "int.h" |
#include "ethmac.h" |
#include "eth-phy-mii.h" |
|
volatile unsigned tx_done; |
volatile unsigned rx_done; |
static int next_tx_buf_num; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
|
/* Let the ethernet packets use a space beginning here for buffering */ |
#define ETH_BUFF_BASE 0x200000; |
|
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
//#undef RXBUFF_PREALLOC |
//#undef TXBUFF_PREALLOC |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
*/ |
#define OETH_RXBD_NUM 16 |
#define OETH_TXBD_NUM 16 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 0x600-4 |
#define OETH_TX_BUFF_SIZE 0x600-4 |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 1518 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
//struct sk_buff* rx_skbuff[OETH_RXBD_NUM]; |
//struct sk_buff* tx_skbuff[OETH_TXBD_NUM]; |
|
unsigned short tx_next; /* Next buffer to be sent */ |
unsigned short tx_last; /* Next buffer to be checked if packet sent */ |
unsigned short tx_full; /* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to be checked if packet |
received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
|
#define PHYNUM 7 |
|
// Data array of data to transmit, tx_data_array[] |
//#include "eth-rxtx-data.h" // Not used |
int tx_data_pointer; |
|
|
void |
eth_mii_write(char phynum, short regnum, short data) |
{ |
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE); |
regs->miiaddress = (regnum << 8) | phynum; |
regs->miitx_data = data; |
regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
} |
|
short |
eth_mii_read(char phynum, short regnum) |
{ |
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE); |
regs->miiaddress = (regnum << 8) | phynum; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
|
return regs->miirx_data; |
} |
|
|
|
// Wait here until all packets have been transmitted |
void |
wait_until_all_tx_clear(void) |
{ |
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
int some_tx_waiting = 1; |
|
while (some_tx_waiting) |
{ |
some_tx_waiting = 0; |
/* Go through the TX buffs, search for unused one */ |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
|
// Looking for buffer ready for transmit |
if((tx_bd[i].len_status & OETH_TX_BD_READY)) |
some_tx_waiting = 1; |
|
} |
} |
} |
|
|
void |
ethphy_set_10mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 10Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr &= ~BMCR_ANENABLE; // Clear auto negotiate bit |
cr &= ~BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void |
ethphy_set_100mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 100Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr |= BMCR_ANENABLE; // Clear auto negotiate bit |
cr |= BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void |
ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
regs->packet_len = 0x00400600; |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
|
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
// Setup TX Buffers |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
//tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[i].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
// Setup RX buffers |
for(i = 0; i < OETH_RXBD_NUM; i++) { |
rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ |
rx_bd[i].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps |
|
/* Enable RX and TX in MAC |
*/ |
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); |
regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN; |
|
next_tx_buf_num = 0; // init tx buffer pointer |
|
return; |
} |
|
// Enable RX in ethernet MAC |
void |
oeth_enable_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
regs->moder |= OETH_MODER_RXEN; |
} |
|
// Disable RX in ethernet MAC |
void |
oeth_disable_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
regs->moder &= ~(OETH_MODER_RXEN); |
} |
|
|
/* Setup buffer descriptors with data */ |
/* length is in BYTES */ |
void tx_packet(void* data, int length) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
volatile int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
/* Clear all of the status flags. |
*/ |
tx_bd->len_status &= ~OETH_TX_BD_STATS; |
|
/* If the frame is short, tell CPM to pad it. |
*/ |
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ |
if (length <= ETH_ZLEN) |
tx_bd->len_status |= OETH_TX_BD_PAD; |
else |
tx_bd->len_status &= ~OETH_TX_BD_PAD; |
|
#ifdef _ETH_RXTX_DATA_H_ |
// Set the address pointer to the place |
// in memory where the data is and transmit from there |
|
tx_bd->addr = (char*) &tx_data_array[tx_data_pointer&~(0x3)]; |
|
tx_data_pointer += length + 1; |
if (tx_data_pointer > (255*1024)) |
tx_data_pointer = 0; |
|
|
#else |
if (data){ |
//Copy the data into the transmit buffer, byte at a time |
char* data_p = (char*) data; |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<length;i++) |
{ |
data_b[i] = data_p[i]; |
} |
} |
#endif |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
/* Send it on its way. Tell controller its ready, interrupt when sent |
* and to put the CRC on the end. |
*/ |
tx_bd->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_CRC | OETH_TX_BD_IRQ); |
|
next_tx_buf_num = (next_tx_buf_num + 1) & OETH_TXBD_NUM_MASK; |
|
return; |
|
|
} |
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
serviced |= 0x2; |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
return; |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
bad=0; |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */ |
/* Check status for errors. |
*/ |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
report(0xbaad0001); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
report(0xbaad0002); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
report(0xbaad0003); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
report(0xbaad0004); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
report(0xbaad0005); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
report(0xbaad0006); |
} |
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
exit(0xbaaaaaad); |
|
continue; |
} |
else { |
/* Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
/* finish up */ |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */ |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */ |
rx_done++; |
} |
} |
} |
} |
|
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 0; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
/* set our test variable */ |
tx_done++; |
|
} |
} |
return; |
} |
|
// A function and defines to fill and transmit a packet |
#define MAX_TX_BUFFER 1532 |
static char tx_buffer[MAX_TX_BUFFER]; |
|
void |
fill_and_tx_packet(int size) |
{ |
int i; |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (volatile oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
// Use rand() function to generate data for transmission |
// Assumption: ethernet buffer descriptors are 4byte aligned |
char* data_b = (char*) tx_bd->addr; |
// We will fill with words until there' less than a word to go |
int words_to_fill = size / sizeof(unsigned int); |
|
unsigned int* data_w = (unsigned int*) data_b; |
|
for(i=0;i<words_to_fill;i++) |
data_w[i] = rand(); |
|
// Point data_b to offset wher word fills ended |
data_b += (words_to_fill * sizeof(unsigned int)); |
|
int leftover_size = size - (words_to_fill * sizeof(unsigned int)); |
|
for(i=0;i<leftover_size;i++) |
{ |
data_b[i] = rand() & 0xff; |
} |
|
tx_packet((void*)0, size); |
} |
|
// Send a packet, the very first byte of which will be read by the testbench |
// and used to indicate which test we'll use. |
void |
send_ethmac_rxtx_test_init_packet(char test) |
{ |
char cmd_tx_buffer[40]; |
cmd_tx_buffer[0] = test; |
tx_packet(cmd_tx_buffer, 40); // Smallest packet that can be sent (I think) |
} |
|
// Loop to check if a number is prime by doing mod divide of the number |
// to test by every number less than it |
int |
is_prime_number(unsigned long n) |
{ |
unsigned long c; |
if (n < 2) return 0; |
for(c=2;c<n;c++) |
if ((n % c) == 0) |
return 0; |
return 1; |
} |
|
|
int |
main () |
{ |
tx_data_pointer = 0; |
|
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(ETH0_IRQ, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
cpu_enable_user_interrupts(); |
|
/* Enable CPU timer */ |
cpu_enable_timer(); |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
/* clear tx_done, the tx interrupt handler will set it when it's been |
transmitted */ |
tx_done = 0; |
rx_done = 0; |
|
ethphy_set_100mbit(0); |
|
send_ethmac_rxtx_test_init_packet(0xff); // Test value of 0xFF |
|
//oeth_enable_rx(); |
|
#define ETH_TX_MIN_PACKET_SIZE 512 |
#define ETH_TX_NUM_PACKETS (ETH_TX_MIN_PACKET_SIZE + 32) |
|
unsigned long num_to_check; |
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
fill_and_tx_packet(num_to_check); |
|
oeth_disable_rx(); |
|
// Now for 10mbit mode... |
ethphy_set_10mbit(0); |
|
oeth_enable_rx(); |
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
fill_and_tx_packet(num_to_check); |
|
oeth_disable_rx(); |
|
// Go back to 100-mbit mode |
ethphy_set_100mbit(0); |
|
oeth_enable_rx(); |
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
fill_and_tx_packet(num_to_check); |
|
exit(0x8000000d); |
|
} |
/xilinx/ml501/sw/tests/ethmac/sim/ethmac-rx.c
0,0 → 1,470
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet MAC test code //// |
//// //// |
//// Description //// |
//// Do ethernet receive path testing //// |
//// Relies on testbench to provide simulus - expects at least //// |
//// 256 packets to be sent. //// |
//// //// |
//// Author(s): //// |
//// - Julius Baxter, julius@opencores.org //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source 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 Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "cpu-utils.h" |
#include "board.h" |
#include "int.h" |
#include "ethmac.h" |
#include "eth-phy-mii.h" |
|
volatile unsigned tx_done; |
volatile unsigned rx_done; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
void oeth_dump_bds(); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
/* Function to calculate checksum of ping responses we send */ |
unsigned short calculate_checksum(char* dats, unsigned int len) ; |
|
/* Let the ethernet packets use a space beginning here for buffering */ |
#define ETH_BUFF_BASE 0x200000; |
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
* Note: if changing these, must also change settings in eth_stim.v testbench |
* file! |
*/ |
#define OETH_RXBD_NUM 16 |
#define OETH_TXBD_NUM 16 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 0x600 |
#define OETH_TX_BUFF_SIZE 0x600 |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 1518 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
//struct sk_buff* rx_skbuff[OETH_RXBD_NUM]; |
//struct sk_buff* tx_skbuff[OETH_TXBD_NUM]; |
|
unsigned short tx_next; /* Next buffer to be sent */ |
unsigned short tx_last; /* Next buffer to be checked if packet sent */ |
unsigned short tx_full; /* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to be checked if packet received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
|
|
char CHECKSUM_BUFFER[OETH_RX_BUFF_SIZE]; // Big enough to hold a packet |
|
#define PHYNUM 7 |
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
regs->packet_len = 0x00400600; |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
|
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
// Setup TX Buffers |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
//tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[i].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
// Setup RX buffers |
for(i = 0; i < OETH_RXBD_NUM; i++) { |
rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ |
rx_bd[i].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps |
|
/* Enable just the receiver |
*/ |
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); |
regs->moder |= OETH_MODER_RXEN /* | OETH_MODER_TXEN*/; |
|
return; |
} |
|
void |
ethmac_halt(void) |
{ |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
// Disable receive and transmit |
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); |
|
} |
|
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
serviced |= 0x2; |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
return; |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
bad=0; |
/* Looking for buffer descriptors marked not empty */ |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ |
/* Check status for errors. |
*/ |
report(i); |
report(rx_bdp[i].len_status); |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
report(0xbaad0001); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
report(0xbaad0002); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
report(0xbaad0003); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
report(0xbaad0004); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
report(0xbaad0005); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
report(0xbaad0006); |
} |
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
//exit(0xbaaaaaad); |
|
continue; |
} |
else { |
/* |
* Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
// Do a bit of work - ie. copy it, process it |
memcpy(CHECKSUM_BUFFER, rx_bdp[i].addr, pkt_len); |
report(0xc4eccccc); |
report(calculate_checksum(CHECKSUM_BUFFER, pkt_len)); |
|
/* finish up */ |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */ |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */ |
rx_done++; |
report(rx_done); |
} |
} |
} |
} |
|
// Calculate checksum on received data. |
// From http://lkml.indiana.edu/hypermail/linux/kernel/9612.3/0060.html |
unsigned short calculate_checksum(char* dats, unsigned int len) |
{ |
unsigned int itr; |
unsigned long accum = 0; |
unsigned long longsum; |
|
// Sum all pairs of data |
for(itr=0;itr<(len & ~0x1);itr+=2) |
accum += (unsigned long)(((dats[itr]<<8)&0xff00)|(dats[itr+1]&0x00ff)); |
|
if (len & 0x1) // Do leftover |
accum += (unsigned long) ((dats[itr-1]<<8)&0xff00); |
|
longsum = (unsigned long) (accum & 0xffff); |
longsum += (unsigned long) (accum >> 16); // Sum the carries |
longsum += (longsum >> 16); |
return (unsigned short)((longsum ^ 0xffff) & 0xffff); |
|
} |
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 0; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
/* set our test variable */ |
tx_done = 1; |
|
} |
} |
return; |
} |
|
// Loop to check if a number is prime by doing mod divide of the number |
// to test by every number less than it |
int |
is_prime_number(unsigned long n) |
{ |
unsigned long c; |
if (n < 2) return 0; |
for(c=2;c<n;c++) |
if ((n % c) == 0) |
return 0; |
return 1; |
} |
|
int |
main () |
{ |
|
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(ETH0_IRQ, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
cpu_enable_user_interrupts(); |
|
/* Enable CPU timer */ |
cpu_enable_timer(); |
|
rx_done = 0; |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX in MODER */ |
|
#define NUM_PRIMES_TO_CHECK 1000 |
#define RX_TEST_LENGTH_PACKETS 12 |
|
char prime_check_results[NUM_PRIMES_TO_CHECK]; |
unsigned long num_to_check; |
|
for(num_to_check=2;num_to_check<NUM_PRIMES_TO_CHECK;num_to_check++) |
{ |
prime_check_results[num_to_check-2] |
= (char) is_prime_number(num_to_check); |
report(num_to_check | (0x1e<<24)); |
report(prime_check_results[num_to_check-2] | (0x2e<<24)); |
// Check number of packets received, testbench will hopefully send at |
// least this many packets |
if (rx_done >= (RX_TEST_LENGTH_PACKETS - 1)) |
exit(0x8000000d); |
} |
|
ethmac_halt(); |
|
exit(0x8000000d); |
|
return 0; |
} |
/xilinx/ml501/sw/tests/ethmac/sim/ethmac-tx.c
0,0 → 1,589
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet MAC transmit test code //// |
//// //// |
//// Description //// |
//// Transmits packets, testing both 100mbit and 10mbit modes. //// |
//// Expects testbench to be checking each packet sent. //// |
//// Define, ETH_TX_TEST_LENGTH, set further down, controls how //// |
//// many packets the test will send. //// |
//// //// |
//// Author(s): //// |
//// - jb, jb@orsoc.se, with parts taken from Linux kernel //// |
//// open_eth driver. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source 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 Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "cpu-utils.h" |
#include "board.h" |
#include "int.h" |
#include "ethmac.h" |
#include "eth-phy-mii.h" |
|
volatile unsigned tx_done; |
volatile unsigned rx_done; |
static int next_tx_buf_num; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
|
/* Let the ethernet packets use a space beginning here for buffering */ |
#define ETH_BUFF_BASE 0x200000; |
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
//#undef RXBUFF_PREALLOC |
//#undef TXBUFF_PREALLOC |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
*/ |
#define OETH_RXBD_NUM 16 |
#define OETH_TXBD_NUM 16 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 0x600 - 4 |
#define OETH_TX_BUFF_SIZE 0x600 - 4 |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 1518 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
|
unsigned short tx_next;/* Next buffer to be sent */ |
unsigned short tx_last;/* Next buffer to be checked if packet sent */ |
unsigned short tx_full;/* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to check if packet received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
|
|
// Data array of data to transmit, tx_data_array[] |
// Not included in ORPSoC - #include "eth-rxtx-data.h" |
//int tx_data_pointer; |
|
#define PHYNUM 7 |
|
void |
eth_mii_write(char phynum, short regnum, short data) |
{ |
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE); |
regs->miiaddress = (regnum << 8) | phynum; |
regs->miitx_data = data; |
regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
} |
|
short |
eth_mii_read(char phynum, short regnum) |
{ |
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE); |
regs->miiaddress = (regnum << 8) | phynum; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY); |
|
return regs->miirx_data; |
} |
|
|
// Wait here until all packets have been transmitted |
void wait_until_all_tx_clear(void) |
{ |
|
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
int some_tx_waiting = 1; |
|
while (some_tx_waiting) |
{ |
some_tx_waiting = 0; |
/* Go through the TX buffs, search for unused one */ |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
|
if((tx_bd[i].len_status & OETH_TX_BD_READY)) // Looking for buffer ready for transmit |
some_tx_waiting = 1; |
|
} |
} |
|
} |
|
|
void |
ethphy_set_10mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 10Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr &= ~BMCR_ANENABLE; // Clear auto negotiate bit |
cr &= ~BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void |
ethphy_set_100mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 100Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr |= BMCR_ANENABLE; // Clear auto negotiate bit |
cr |= BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
regs->packet_len = 0x00400600; |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
|
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
// Setup TX Buffers |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
//tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[i].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
// Setup RX buffers |
for(i = 0; i < OETH_RXBD_NUM; i++) { |
rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ |
rx_bd[i].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps |
|
/* Enable JUST the transmiter |
*/ |
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); |
regs->moder |= /*OETH_MODER_RXEN |*/ OETH_MODER_TXEN; |
|
next_tx_buf_num = 0; // init tx buffer pointer |
|
return; |
} |
|
|
|
/* Setup buffer descriptors with data */ |
/* length is in BYTES */ |
void tx_packet(void* data, int length) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
volatile int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
/* Clear all of the status flags. |
*/ |
tx_bd->len_status &= ~OETH_TX_BD_STATS; |
|
/* If the frame is short, tell CPM to pad it. |
*/ |
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ |
if (length <= ETH_ZLEN) |
tx_bd->len_status |= OETH_TX_BD_PAD; |
else |
tx_bd->len_status &= ~OETH_TX_BD_PAD; |
|
if (data){ |
//Copy the data into the transmit buffer, byte at a time |
char* data_p = (char*) data; |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<length;i++) |
{ |
data_b[i] = data_p[i]; |
} |
} |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
/* Send it on its way. Tell controller its ready, interrupt when sent |
* and to put the CRC on the end. |
*/ |
tx_bd->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_CRC | OETH_TX_BD_IRQ); |
|
next_tx_buf_num = (next_tx_buf_num + 1) & OETH_TXBD_NUM_MASK; |
|
return; |
|
} |
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
serviced |= 0x2; |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
return; |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
bad=0; |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */ |
/* Check status for errors. |
*/ |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
report(0xbaad0001); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
report(0xbaad0002); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
report(0xbaad0003); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
report(0xbaad0004); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
report(0xbaad0005); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
report(0xbaad0006); |
} |
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
exit(0xbaaaaaad); |
|
continue; |
} |
else { |
/* Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
/* Do something here with the data - copy it into userspace, perhaps*/ |
|
/* finish up */ |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */ |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */ |
rx_done++; |
} |
} |
} |
} |
|
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 0; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
/* set our test variable */ |
tx_done++; |
|
} |
} |
return; |
} |
|
// A function and defines to fill and transmit a packet |
#define MAX_TX_BUFFER 1532 |
static char tx_buffer[MAX_TX_BUFFER]; |
|
void |
fill_and_tx_packet(int size) |
{ |
int i; |
char tx_byte; |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
// Use rand() function to generate data for transmission |
// Assumption: ethernet buffer descriptors are 4byte aligned |
char* data_b = (char*) tx_bd->addr; |
// We will fill with words until there' less than a word to go |
int words_to_fill = size/ sizeof(unsigned int); |
unsigned int* data_w = (unsigned int*) data_b; |
|
for(i=0;i<words_to_fill;i++) |
data_w[i] = rand(); |
|
// Point data_b to offset wher word fills ended |
data_b += (words_to_fill * sizeof(unsigned int)); |
|
int leftover_size = size - (words_to_fill * sizeof(unsigned int)); |
|
for(i=0;i<leftover_size;i++) |
{ |
data_b[i] = rand()&0xff; |
} |
|
tx_packet((void*)0, size); |
} |
|
int |
main () |
{ |
int i; |
|
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(ETH0_IRQ, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
cpu_enable_user_interrupts(); |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
/* clear tx_done, the tx interrupt handler will set it when it's been transmitted */ |
tx_done = 0; |
rx_done = 0; |
|
ethphy_set_100mbit(0); |
|
#ifndef ETH_TX_TEST_LENGTH |
# define ETH_TX_START_LENGTH 40 |
# define ETH_TX_TEST_LENGTH 1024 |
# define ETH_TX_TEST_LENGTH_INCREMENT 21 |
//# define ETH_TX_TEST_LENGTH OETH_TX_BUFF_SIZE |
#endif |
|
for(i=ETH_TX_START_LENGTH;i<ETH_TX_TEST_LENGTH; |
i+=ETH_TX_TEST_LENGTH_INCREMENT) |
fill_and_tx_packet(i); |
|
ethphy_set_10mbit(0); |
|
for(i=ETH_TX_START_LENGTH;i<ETH_TX_TEST_LENGTH; |
i+=ETH_TX_TEST_LENGTH_INCREMENT) |
fill_and_tx_packet(i); |
|
exit(0x8000000d); |
|
|
} |
/xilinx/ml501/sw/tests/ethmac/sim/Makefile
0,0 → 1,14
# Set the path to our board's root directory |
BOARD_SW_ROOT=../../.. |
|
include $(BOARD_SW_ROOT)/Makefile.inc |
|
%.dis: %.elf |
$(Q)$(OR32_OBJDUMP) -d $< > $@ |
|
%.bin: %.elf |
$(Q)$(OR32_OBJCOPY) -O binary $< $@ |
|
clean: |
$(Q)rm -f *.elf *.bin *.vmem *.flashin *.dis |
|
/xilinx/ml501/sw/board/include/board.h
62,4 → 62,14
// |
#define TICKS_PER_SEC 100 |
|
|
|
// |
// UART driver configuration |
// |
#define UART_NUM_CORES 1 |
#define UART_BASE_ADDRESSES_CSV UART0_BASE |
#define UART_BAUD_RATES_CSV UART0_BAUD_RATE |
|
|
#endif |