Line 39... |
Line 39... |
//// Public License along with this source; if not, download it ////
|
//// Public License along with this source; if not, download it ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
|
|
#include "or32-utils.h"
|
#include "cpu-utils.h"
|
#include "spr-defs.h"
|
|
#include "board.h"
|
#include "board.h"
|
#include "int.h"
|
#include "int.h"
|
//#include "uart.h" // comment this out, UART uses simulation putc()
|
#include "ethmac.h"
|
#include "open-eth.h"
|
|
#include "printf.h"
|
|
#include "eth-phy-mii.h"
|
#include "eth-phy-mii.h"
|
|
|
volatile unsigned tx_done;
|
volatile unsigned tx_done;
|
volatile unsigned rx_done;
|
volatile unsigned rx_done;
|
static int next_tx_buf_num;
|
static int next_tx_buf_num;
|
Line 59... |
Line 56... |
/* Interrupt functions */
|
/* Interrupt functions */
|
void oeth_interrupt(void);
|
void oeth_interrupt(void);
|
static void oeth_rx(void);
|
static void oeth_rx(void);
|
static void oeth_tx(void);
|
static void oeth_tx(void);
|
|
|
/* Defining RTLSIM turns off use of real printf'ing to save time in simulation */
|
|
#define RTLSIM
|
|
|
|
#ifdef RTLSIM
|
|
#define printk
|
|
#else
|
|
#define printk printf
|
|
#endif
|
|
/* Let the ethernet packets use a space beginning here for buffering */
|
/* Let the ethernet packets use a space beginning here for buffering */
|
#define ETH_BUFF_BASE 0x01000000
|
#define ETH_BUFF_BASE 0x01000000
|
|
|
|
|
#define RXBUFF_PREALLOC 1
|
#define RXBUFF_PREALLOC 1
|
Line 92... |
Line 81... |
/* Buffer size
|
/* Buffer size
|
*/
|
*/
|
#define OETH_RX_BUFF_SIZE 0x600-4
|
#define OETH_RX_BUFF_SIZE 0x600-4
|
#define OETH_TX_BUFF_SIZE 0x600-4
|
#define OETH_TX_BUFF_SIZE 0x600-4
|
|
|
/* OR32 Page size def */
|
|
#define PAGE_SHIFT 13
|
|
#define PAGE_SIZE (1UL << PAGE_SHIFT)
|
|
|
|
/* How many buffers per page
|
|
*/
|
|
#define OETH_RX_BUFF_PPGAE (PAGE_SIZE/OETH_RX_BUFF_SIZE)
|
|
#define OETH_TX_BUFF_PPGAE (PAGE_SIZE/OETH_TX_BUFF_SIZE)
|
|
|
|
/* How many pages is needed for buffers
|
|
*/
|
|
#define OETH_RX_BUFF_PAGE_NUM (OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE)
|
|
#define OETH_TX_BUFF_PAGE_NUM (OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE)
|
|
|
|
/* Buffer size (if not XXBUF_PREALLOC
|
/* Buffer size (if not XXBUF_PREALLOC
|
*/
|
*/
|
#define MAX_FRAME_SIZE 1518
|
#define MAX_FRAME_SIZE 1518
|
|
|
/* The buffer descriptors track the ring buffers.
|
/* The buffer descriptors track the ring buffers.
|
Line 132... |
Line 107... |
};
|
};
|
|
|
#define PHYNUM 7
|
#define PHYNUM 7
|
|
|
// Data array of data to transmit, tx_data_array[]
|
// Data array of data to transmit, tx_data_array[]
|
#include "eth-rxtx-data.h"
|
//#include "eth-rxtx-data.h" // Not used
|
int tx_data_pointer;
|
int tx_data_pointer;
|
|
|
/* Scan the MIIM bus for PHYs */
|
|
void scan_ethphys(void)
|
|
{
|
|
unsigned int phynum,regnum, i;
|
|
|
|
volatile oeth_regs *regs;
|
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
|
|
|
regs->miitx_data = 0;
|
|
|
|
for(phynum=0;phynum<32;phynum++)
|
|
{
|
|
for (regnum=0;regnum<8;regnum++)
|
|
{
|
|
printk("scan_ethphys: phy %d r%d ",phynum, regnum);
|
|
|
|
/* Now actually perform the read on the MIIM bus*/
|
|
regs->miiaddress = (regnum << 8) | phynum;
|
|
regs->miicommand = OETH_MIICOMMAND_RSTAT;
|
|
/* Wait for command to be registered*/
|
|
while(!(regs->miistatus & OETH_MIISTATUS_BUSY));
|
|
|
|
regs->miicommand = 0;
|
|
|
|
while(regs->miistatus & OETH_MIISTATUS_BUSY);
|
|
|
|
printk("%x\n",regs->miirx_data);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ethmac_scanstatus(void)
|
|
{
|
|
volatile oeth_regs *regs;
|
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
|
|
|
|
|
printk("Oeth: regs->miistatus %x regs->miirx_data %x\n",regs->miistatus, regs->miirx_data);
|
|
regs->miiaddress = 0;
|
|
regs->miitx_data = 0;
|
|
regs->miicommand = OETH_MIICOMMAND_SCANSTAT;
|
|
printk("Oeth: regs->miiaddress %x regs->miicommand %x\n",regs->miiaddress, regs->miicommand);
|
|
//regs->miicommand = 0;
|
|
volatile int i; for(i=0;i<1000;i++);
|
|
while(regs->miistatus & OETH_MIISTATUS_BUSY) ;
|
|
//spin_cursor();
|
|
//printk("\r");
|
|
//or32_exit(0);
|
|
}
|
|
|
|
void
|
void
|
eth_mii_write(char phynum, short regnum, short data)
|
eth_mii_write(char phynum, short regnum, short data)
|
{
|
{
|
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE);
|
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE);
|
Line 213... |
Line 137... |
}
|
}
|
|
|
|
|
|
|
// Wait here until all packets have been transmitted
|
// Wait here until all packets have been transmitted
|
void wait_until_all_tx_clear(void)
|
void
|
|
wait_until_all_tx_clear(void)
|
{
|
{
|
|
|
int i;
|
int i;
|
volatile oeth_bd *tx_bd;
|
volatile oeth_bd *tx_bd;
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/
|
|
|
int some_tx_waiting = 1;
|
int some_tx_waiting = 1;
|
Line 228... |
Line 152... |
{
|
{
|
some_tx_waiting = 0;
|
some_tx_waiting = 0;
|
/* Go through the TX buffs, search for unused one */
|
/* Go through the TX buffs, search for unused one */
|
for(i = 0; i < OETH_TXBD_NUM; i++) {
|
for(i = 0; i < OETH_TXBD_NUM; i++) {
|
|
|
if((tx_bd[i].len_status & OETH_TX_BD_READY)) // Looking for buffer ready for transmit
|
// Looking for buffer ready for transmit
|
|
if((tx_bd[i].len_status & OETH_TX_BD_READY))
|
some_tx_waiting = 1;
|
some_tx_waiting = 1;
|
|
|
}
|
}
|
}
|
}
|
}
|
}
|
Line 260... |
Line 185... |
cr |= BMCR_SPEED100; // Clear fast eth. bit
|
cr |= BMCR_SPEED100; // Clear fast eth. bit
|
eth_mii_write(phynum, MII_BMCR, cr);
|
eth_mii_write(phynum, MII_BMCR, cr);
|
}
|
}
|
|
|
|
|
void ethmac_setup(void)
|
void
|
|
ethmac_setup(void)
|
{
|
{
|
// from arch/or32/drivers/open_eth.c
|
// from arch/or32/drivers/open_eth.c
|
volatile oeth_regs *regs;
|
volatile oeth_regs *regs;
|
|
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
Line 369... |
Line 295... |
rx_bd[i].addr = mem_addr;
|
rx_bd[i].addr = mem_addr;
|
mem_addr += OETH_RX_BUFF_SIZE;
|
mem_addr += OETH_RX_BUFF_SIZE;
|
}
|
}
|
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps
|
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps
|
|
|
/* Enable JUST the transmiter
|
/* Enable RX and TX in MAC
|
*/
|
*/
|
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);
|
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);
|
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
|
next_tx_buf_num = 0; // init tx buffer pointer
|
|
|
return;
|
return;
|
}
|
}
|
Line 526... |
Line 452... |
int pkt_len, i;
|
int pkt_len, i;
|
int bad = 0;
|
int bad = 0;
|
|
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
|
|
|
printk("r");
|
|
|
|
|
|
/* Find RX buffers marked as having received data */
|
/* Find RX buffers marked as having received data */
|
for(i = 0; i < OETH_RXBD_NUM; i++)
|
for(i = 0; i < OETH_RXBD_NUM; i++)
|
{
|
{
|
bad=0;
|
bad=0;
|
Line 604... |
Line 528... |
/* Probably good to check for TX errors here */
|
/* Probably good to check for TX errors here */
|
|
|
/* set our test variable */
|
/* set our test variable */
|
tx_done++;
|
tx_done++;
|
|
|
printk("T%d",i);
|
|
|
|
}
|
}
|
}
|
}
|
return;
|
return;
|
}
|
}
|
|
|
// A function and defines to fill and transmit a packet
|
// A function and defines to fill and transmit a packet
|
#define MAX_TX_BUFFER 1532
|
#define MAX_TX_BUFFER 1532
|
static char tx_buffer[MAX_TX_BUFFER];
|
static char tx_buffer[MAX_TX_BUFFER];
|
static unsigned long tx_data = 0x26fab2f2;
|
|
static inline char gen_next_tx_byte(void)
|
|
{
|
|
// Bit of LFSR action
|
|
tx_data = ((~(((((tx_data&(1<<25))>>25)^((tx_data&(1<<13))>>13))^((tx_data&(1<<2))>>2)))&0x01) | (tx_data<<1));
|
|
//tx_data =(!((tx_data>>26) ^ (tx_data>>14) ^ (tx_data>>5) ^ (tx_data>>3)) & 0x1) | (tx_data<<1);
|
|
return (char) tx_data & 0xff;
|
|
}
|
|
|
|
void
|
void
|
fill_and_tx_packet(int size)
|
fill_and_tx_packet(int size)
|
{
|
{
|
int i;
|
int i;
|
char tx_byte;
|
|
|
|
|
|
volatile oeth_regs *regs;
|
volatile oeth_regs *regs;
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
|
|
volatile oeth_bd *tx_bd;
|
volatile oeth_bd *tx_bd;
|
|
|
//tx_bd = (volatile oeth_bd *)OETH_BD_BASE;
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE;
|
tx_bd = (volatile oeth_bd*) &tx_bd[next_tx_buf_num];
|
tx_bd = (volatile oeth_bd*) &tx_bd[next_tx_buf_num];
|
|
|
|
|
// If it's in use - wait
|
// If it's in use - wait
|
while ((tx_bd->len_status & OETH_TX_BD_IRQ));
|
while ((tx_bd->len_status & OETH_TX_BD_IRQ));
|
|
|
#ifndef _ETH_RXTX_DATA_H_
|
// Use rand() function to generate data for transmission
|
/* Copy the data into the transmit buffer, byte at a time */
|
// Assumption: ethernet buffer descriptors are 4byte aligned
|
char* data_b = (char*) tx_bd->addr;
|
char* data_b = (char*) tx_bd->addr;
|
for(i=0;i<size;i++)
|
// 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] = gen_next_tx_byte();
|
data_b[i] = rand() & 0xff;
|
}
|
}
|
#endif
|
|
|
|
tx_packet((void*)0, size);
|
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
|
// Loop to check if a number is prime by doing mod divide of the number
|
// to test by every number less than it
|
// to test by every number less than it
|
int
|
int
|
is_prime_number(unsigned long n)
|
is_prime_number(unsigned long n)
|
Line 669... |
Line 601... |
return 0;
|
return 0;
|
return 1;
|
return 1;
|
}
|
}
|
|
|
|
|
//#define WAIT_PACKET_TX(x) while(tx_done<x)
|
int
|
#define WAIT_PACKET_TX(x)
|
main ()
|
|
|
int main ()
|
|
{
|
{
|
tx_data_pointer = 0;
|
tx_data_pointer = 0;
|
|
|
/* Initialise handler vector */
|
/* Initialise handler vector */
|
int_init();
|
int_init();
|
|
|
/* Install ethernet interrupt handler, it is enabled here too */
|
/* Install ethernet interrupt handler, it is enabled here too */
|
int_add(ETH0_IRQ, oeth_interrupt, 0);
|
int_add(ETH0_IRQ, oeth_interrupt, 0);
|
|
|
/* Enable interrupts in supervisor register */
|
/* Enable interrupts in supervisor register */
|
mtspr (SPR_SR, mfspr (SPR_SR) | SPR_SR_IEE);
|
cpu_enable_user_interrupts();
|
|
|
|
/* Enable CPU timer */
|
|
cpu_enable_timer();
|
|
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */
|
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
|
/* clear tx_done, the tx interrupt handler will set it when it's been
|
transmitted */
|
transmitted */
|
tx_done = 0;
|
tx_done = 0;
|
rx_done = 0;
|
rx_done = 0;
|
|
|
printf("Start of large txdata buffer: 0x%x\n",
|
|
(unsigned long)&tx_data_array[0]);
|
|
printf("Slut of large txdata buffer: 0x%x\n",
|
|
(unsigned long)&tx_data_array[262144]);
|
|
|
|
|
|
ethphy_set_100mbit(0);
|
ethphy_set_100mbit(0);
|
|
|
oeth_enable_rx();
|
send_ethmac_rxtx_test_init_packet(0xff); // Test value of 0xFF
|
|
|
|
//oeth_enable_rx();
|
|
|
#define ETH_TX_MIN_PACKET_SIZE 512
|
#define ETH_TX_MIN_PACKET_SIZE 512
|
#define ETH_TX_NUM_PACKETS (ETH_TX_MIN_PACKET_SIZE + 32)
|
#define ETH_TX_NUM_PACKETS (ETH_TX_MIN_PACKET_SIZE + 32)
|
|
|
#define CALCULATE_PRIMES 0
|
|
|
|
char prime_check_results[2048];
|
|
unsigned long num_to_check;
|
unsigned long num_to_check;
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE;
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE;
|
num_to_check<ETH_TX_NUM_PACKETS;
|
num_to_check<ETH_TX_NUM_PACKETS;
|
num_to_check++)
|
num_to_check++)
|
{
|
|
fill_and_tx_packet(num_to_check);
|
fill_and_tx_packet(num_to_check);
|
#if CALCULATE_PRIMES==1
|
|
prime_check_results[num_to_check-5]
|
|
= (char) is_prime_number(num_to_check);
|
|
report(num_to_check | (0x1e<<24));
|
|
report(prime_check_results[num_to_check-5] | (0x2e<<24));
|
|
#endif
|
|
}
|
|
|
|
oeth_disable_rx();
|
oeth_disable_rx();
|
|
|
// Now for 10mbit mode...
|
// Now for 10mbit mode...
|
ethphy_set_10mbit(0);
|
ethphy_set_10mbit(0);
|
Line 731... |
Line 650... |
oeth_enable_rx();
|
oeth_enable_rx();
|
|
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE;
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE;
|
num_to_check<ETH_TX_NUM_PACKETS;
|
num_to_check<ETH_TX_NUM_PACKETS;
|
num_to_check++)
|
num_to_check++)
|
{
|
|
fill_and_tx_packet(num_to_check);
|
fill_and_tx_packet(num_to_check);
|
#if CALCULATE_PRIMES==1
|
|
prime_check_results[num_to_check+(OETH_TX_BUFF_SIZE-5)]
|
|
= (char) is_prime_number(num_to_check+OETH_TX_BUFF_SIZE);
|
|
report(num_to_check | (0x1e<<24));
|
|
report(prime_check_results[num_to_check+(OETH_TX_BUFF_SIZE-5)]
|
|
| (0x2e<<24)
|
|
);
|
|
#endif
|
|
}
|
|
|
|
oeth_disable_rx();
|
oeth_disable_rx();
|
|
|
// Go back to 100-mbit mode
|
// Go back to 100-mbit mode
|
ethphy_set_100mbit(0);
|
ethphy_set_100mbit(0);
|
Line 753... |
Line 662... |
oeth_enable_rx();
|
oeth_enable_rx();
|
|
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE;
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE;
|
num_to_check<ETH_TX_NUM_PACKETS;
|
num_to_check<ETH_TX_NUM_PACKETS;
|
num_to_check++)
|
num_to_check++)
|
{
|
|
fill_and_tx_packet(num_to_check);
|
fill_and_tx_packet(num_to_check);
|
#if CALCULATE_PRIMES==1
|
|
prime_check_results[num_to_check+(OETH_TX_BUFF_SIZE-5)]
|
|
= (char) is_prime_number(num_to_check+OETH_TX_BUFF_SIZE);
|
|
report(num_to_check | (0x1e<<24));
|
|
report(prime_check_results[num_to_check+(OETH_TX_BUFF_SIZE-5)]
|
|
| (0x2e<<24)
|
|
);
|
|
#endif
|
|
}
|
|
|
|
|
|
exit(0x8000000d);
|
exit(0x8000000d);
|
|
|
|
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|