URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 43 to Rev 44
- ↔ Reverse comparison
Rev 43 → Rev 44
/openrisc/trunk/orpsocv2/bench/sysc/include/Or1200MonitorSC.h
5,6 → 5,7
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com> |
|
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com> |
// Contributor Julius Baxter <jb@orsoc.se> |
|
// This file is part of the cycle accurate model of the OpenRISC 1000 based |
// system-on-chip, ORPSoC, built using Verilator. |
29,6 → 30,9
#ifndef OR1200_MONITOR_SC__H |
#define OR1200_MONITOR_SC__H |
|
#include <fstream> |
#include <ctime> |
|
#include "systemc.h" |
|
#include "OrpsocAccess.h" |
52,11 → 56,18
// Method to check instructions |
void checkInstruction(); |
|
// Methods to setup and output state of processor to a file |
void init_displayState(int argc,char *argv[]); |
void displayState(); |
|
// The ports |
sc_in<bool> clk; |
|
private: |
|
// Function to calculate performance of the sim |
void perfSummary(); |
|
// Special NOP instructions |
static const uint32_t NOP_NOP = 0x15000000; //!< Normal nop instruction |
static const uint32_t NOP_EXIT = 0x15000001; //!< End of simulation |
64,6 → 75,15
static const uint32_t NOP_PRINTF = 0x15000003; //!< Simprintf instruction |
static const uint32_t NOP_PUTC = 0x15000004; //!< Putc instruction |
|
// Variables for processor status output |
ofstream statusFile; |
int logging_enabled; |
int exit_perf_summary_enabled; |
int insn_count; |
|
// Time measurement variables - for calculating performance of the sim |
clock_t start; |
|
//! The accessor for the Orpsoc instance |
OrpsocAccess *accessor; |
|
/openrisc/trunk/orpsocv2/bench/sysc/include/OrpsocAccess.h
35,6 → 35,8
class Vorpsoc_top; |
class Vorpsoc_top_orpsoc_top; |
class Vorpsoc_top_or1200_ctrl; |
class Vorpsoc_top_or1200_except; |
class Vorpsoc_top_or1200_sprs; |
class Vorpsoc_top_or1200_dpram; |
|
|
53,13 → 55,24
// Accessor functions |
bool getWbFreeze (); |
uint32_t getWbInsn (); |
uint32_t getWbPC (); |
bool getExceptFlushpipe (); |
bool getExDslot (); |
// Get a specific GPR from the register file |
uint32_t getGpr (uint32_t regNum); |
//SPR accessessors |
uint32_t getSprSr (); |
uint32_t getSprEpcr (); |
uint32_t getSprEear (); |
uint32_t getSprEsr (); |
|
private: |
|
// Pointers to modules with accessor functions |
Vorpsoc_top_or1200_ctrl *or1200_ctrl; |
Vorpsoc_top_or1200_dpram *rf_a; |
Vorpsoc_top_or1200_ctrl *or1200_ctrl; |
Vorpsoc_top_or1200_except *or1200_except; |
Vorpsoc_top_or1200_sprs *or1200_sprs; |
Vorpsoc_top_or1200_dpram *rf_a; |
|
}; // OrpsocAccess () |
|
/openrisc/trunk/orpsocv2/bench/sysc/src/Or1200MonitorSC.cpp
5,6 → 5,7
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com> |
|
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com> |
// Contributor Julius Baxter <jb@orsoc.se> |
|
// This file is part of the cycle accurate model of the OpenRISC 1000 based |
// system-on-chip, ORPSoC, built using Verilator. |
28,8 → 29,12
|
#include <iostream> |
#include <iomanip> |
#include <fstream> |
|
using namespace std; |
|
#include "Or1200MonitorSC.h" |
#include "OrpsocMain.h" |
|
|
SC_HAS_PROCESS( Or1200MonitorSC ); |
47,6 → 52,14
SC_METHOD (checkInstruction); |
sensitive << clk.pos(); |
dont_initialize(); |
|
SC_METHOD (displayState); |
logging_enabled = 0; // Default is logging disabled |
exit_perf_summary_enabled = 1; // Simulation exit performance summary is on by default. Turn off with "-q" on the cmd line |
sensitive << clk.pos(); |
dont_initialize(); |
|
start = clock(); |
|
} // Or1200MonitorSC () |
|
78,6 → 91,8
ts = sc_time_stamp().to_seconds() * 1000000000.0; |
std::cout << std::fixed << std::setprecision (2) << ts; |
std::cout << " ns: Exiting (" << r3 << ")" << std::endl; |
if (exit_perf_summary_enabled) perfSummary(); |
if (logging_enabled != 0) statusFile.close(); |
sc_stop(); |
break; |
|
106,3 → 121,120
|
} // checkInstruction() |
|
//! Method to setup the files for outputting the state of the processor |
|
//! This function will setup the output file, if enabled. |
|
void |
Or1200MonitorSC::init_displayState(int argc, char *argv[]) |
{ |
|
string logfileDefault("vlt-executed.log"); |
string logfileNameString; |
|
// Parse the command line options |
int cmdline_name_found=0; |
if (argc > 1) |
{ |
// Search through the command line parameters for the "-log" option |
for(int i=1; i < argc; i++) |
{ |
if (strcmp(argv[i], "-log")==0) |
{ |
logfileNameString = (argv[i+1]); |
cmdline_name_found=1; |
break; |
} |
} |
// Search through the command line parameters for the "-q","--no-perf-summary" option |
for(int i=1; i < argc; i++) |
{ |
if ((strcmp(argv[i], "-q")==0)||(strcmp(argv[i], "--no-perf-summary")==0)) |
{ |
exit_perf_summary_enabled = 0; |
break; |
} |
} |
|
|
} |
|
if(cmdline_name_found==0) // No -log option specified so don't turn on logging |
return; |
|
statusFile.open(logfileNameString.c_str(), ios::out ); // open file to write to it |
|
if(statusFile.is_open()) |
{ |
// If we could open the file then turn on logging |
logging_enabled = 1; |
cout << "Processor execution logged to file: " << logfileNameString << endl; |
} |
|
return; |
|
} |
|
//! Method to output the state of the processor |
|
//! This function will output to a file, if enabled, the status of the processor |
//! For now, it's just the PPC and instruction. |
|
void |
Or1200MonitorSC::displayState() |
{ |
uint32_t wbinsn; |
|
// Calculate how many instructions we've actually calculated by ignoring cycles where we're frozen, delay slots and flushpipe cycles |
if ((!accessor->getWbFreeze()) && !(accessor->getExceptFlushpipe() && accessor->getExDslot())) |
// Increment instruction counter |
insn_count++; |
|
if (logging_enabled == 0) |
return; // If we didn't inialise a file, then just return. |
|
// Output the state if we're not frozen and not flushing during a delay slot |
if ((!accessor->getWbFreeze()) && !(accessor->getExceptFlushpipe() && accessor->getExDslot())) |
{ |
// Print PC, instruction |
statusFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << insn_count << "): " << std::setfill('0') << hex << std::setw(8) << accessor->getWbPC() << ": " << hex << accessor->getWbInsn() << endl; |
|
// Print general purpose register contents |
for (int i=0; i<32; i++) |
{ |
if ((i%4 == 0)&&(i>0)) statusFile << endl; |
statusFile << std::setfill('0'); |
statusFile << "GPR" << dec << std::setw(2) << i << ": " << hex << std::setw(8) << (uint32_t) accessor->getGpr(i) << " "; |
} |
statusFile << endl; |
|
statusFile << "SR : " << hex << std::setw(8) << (uint32_t) accessor->getSprSr() << " "; |
statusFile << "EPCR0: " << hex << std::setw(8) << (uint32_t) accessor->getSprEpcr() << " "; |
statusFile << "EEAR0: " << hex << std::setw(8) << (uint32_t) accessor->getSprEear() << " "; |
statusFile << "ESR0 : " << hex << std::setw(8) << (uint32_t) accessor->getSprEsr() << endl; |
|
} |
|
return; |
|
} // displayState() |
|
//! Function to calculate the number of instructions performed and the time taken |
void |
Or1200MonitorSC::perfSummary() |
{ |
double ts; |
ts = sc_time_stamp().to_seconds() * 1000000000.0; |
int cycles = ts / (BENCH_CLK_HALFPERIOD*2); // Number of clock cycles we had |
|
clock_t finish = clock(); |
double elapsed_time = (double(finish)-double(start))/CLOCKS_PER_SEC; |
// It took elapsed_time seconds to do insn_count instructions. Divide insn_count by the time to get instructions/second. |
double ips = (insn_count/elapsed_time); |
double mips = (insn_count/elapsed_time)/1000000; |
std::cout << "Or1200Monitor: real time elapsed: " << elapsed_time << " seconds" << endl; |
std::cout << "Or1200Monitor: simulated " << dec << cycles << " clock cycles, executed " << insn_count << " instructions" << endl; |
std::cout << "Or1200Monitor: simulated insn/sec = " << ips << ", simulator mips = " << mips << endl; |
return; |
} // calculateMips() |
|
/openrisc/trunk/orpsocv2/bench/sysc/src/TraceSC.cpp
49,18 → 49,27
|
// Setup the name of the VCD dump file |
string dumpNameDefault("vlt-dump.vcd"); |
string dumpSuffix("-vlt.vcd"); |
string dumpDir("../results/"); // Note: hardcoded to store all VCDs in the ../results dir |
string testNameString; |
string vcdDumpFile; |
|
if (argc > 1) // If we were passed a name on the command line, use it |
|
// Search through the command line parameters for the "-vcd" option |
int cmdline_name_found=0; |
if (argc > 1) |
{ |
for(int i=1; i<argc; i++) |
{ |
testNameString = (argv[1]); |
vcdDumpFile = dumpDir + testNameString + dumpSuffix; |
if (strcmp(argv[i], "-vcd")==0) |
{ |
testNameString = (argv[i+1]); |
vcdDumpFile = testNameString; |
cmdline_name_found=1; |
break; |
} |
} |
else // otherwise use our default VCD dump file name |
vcdDumpFile = dumpDir + dumpNameDefault; |
} |
|
if(cmdline_name_found==0) // otherwise use our default VCD dump file name |
vcdDumpFile = dumpNameDefault; |
|
Verilated::traceEverOn (true); |
|
/openrisc/trunk/orpsocv2/bench/sysc/src/OrpsocAccess.cpp
5,6 → 5,7
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com> |
|
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com> |
// Contributor Julius Baxter <jb@orsoc.se> |
|
// This file is part of the cycle accurate model of the OpenRISC 1000 based |
// system-on-chip, ORPSoC, built using Verilator. |
34,6 → 35,8
#include "Vorpsoc_top_or1200_top.h" |
#include "Vorpsoc_top_or1200_cpu.h" |
#include "Vorpsoc_top_or1200_ctrl.h" |
#include "Vorpsoc_top_or1200_except.h" |
#include "Vorpsoc_top_or1200_sprs.h" |
#include "Vorpsoc_top_or1200_rf.h" |
#include "Vorpsoc_top_or1200_dpram.h" |
|
47,6 → 50,8
OrpsocAccess::OrpsocAccess (Vorpsoc_top *orpsoc_top) |
{ |
or1200_ctrl = orpsoc_top->v->i_or1k->i_or1200_top->or1200_cpu->or1200_ctrl; |
or1200_except = orpsoc_top->v->i_or1k->i_or1200_top->or1200_cpu->or1200_except; |
or1200_sprs = orpsoc_top->v->i_or1k->i_or1200_top->or1200_cpu->or1200_sprs; |
rf_a = orpsoc_top->v->i_or1k->i_or1200_top->or1200_cpu->or1200_rf->rf_a; |
|
} // OrpsocAccess () |
63,7 → 68,39
|
} // getWbFreeze () |
|
//! Access for the except_flushpipe signal |
|
//! @return The value of the or1200_except.except_flushpipe signal |
|
bool |
OrpsocAccess::getExceptFlushpipe () |
{ |
return or1200_except->except_flushpipe; |
|
} // getExceptFlushpipe () |
|
//! Access for the ex_dslot signal |
|
//! @return The value of the or1200_except.ex_dslot signalfac |
|
bool |
OrpsocAccess::getExDslot () |
{ |
return or1200_except->ex_dslot; |
|
} // getExDslot () |
|
//! Access for the wb_pc register |
|
//! @return The value of the or1200_except.wb_insn register |
|
uint32_t |
OrpsocAccess::getWbPC () |
{ |
return (or1200_except->get_wb_pc) (); |
|
} // getWbPC () |
|
//! Access for the wb_insn register |
|
//! @return The value of the or1200_ctrl.wb_insn register |
90,3 → 127,49
return (rf_a->get_gpr) (regNum); |
|
} // getGpr () |
|
|
//! Access for the sr register |
|
//! @return The value of the or1200_sprs.sr register |
|
uint32_t |
OrpsocAccess::getSprSr () |
{ |
return (or1200_sprs->get_sr) (); |
|
} // getSprSr () |
|
//! Access for the epcr register |
|
//! @return The value of the or1200_sprs.epcr register |
|
uint32_t |
OrpsocAccess::getSprEpcr () |
{ |
return (or1200_sprs->get_epcr) (); |
|
} // getSprEpcr () |
|
//! Access for the eear register |
|
//! @return The value of the or1200_sprs.eear register |
|
uint32_t |
OrpsocAccess::getSprEear () |
{ |
return (or1200_sprs->get_eear) (); |
|
} // getSprEear () |
|
//! Access for the esr register |
|
//! @return The value of the or1200_sprs.esr register |
|
uint32_t |
OrpsocAccess::getSprEsr () |
{ |
return (or1200_sprs->get_esr) (); |
|
} // getSprEsr () |
|
/openrisc/trunk/orpsocv2/bench/sysc/src/OrpsocMain.cpp
160,6 → 160,9
// Init the UART function |
uart->initUart(25000000, 115200); |
|
// Turn on logging by setting the "-log logfilename" option on the command line |
monitor->init_displayState(argc, argv); |
|
// Execute until we stop |
sc_start (); |
|
/openrisc/trunk/orpsocv2/bench/verilog/eth_stim.v
0,0 → 1,625
////////////////////////////////////////////////////////////////////// |
//// //// |
//// ORPSoC Testbench - Ethernet MAC Stimulus //// |
//// //// |
//// Description //// |
//// Ethernet MAC stimulus tasks. Taken from the project //// |
//// testbench in the ethmac core. //// |
//// //// |
//// To Do: //// |
//// //// |
//// //// |
//// Author(s): //// |
//// - Tadej Markovic, tadej@opencores.org //// |
//// - Igor Mohor, igorM@opencores.org //// |
//// - jb, jb@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
|
reg [15:0] rx_packet_length; |
reg [7:0] st_data; |
parameter Tp = 1; |
initial |
begin |
|
repeat(30000) @(posedge eth_clk); |
|
rx_packet_length = 16'd96; // Bytes |
|
st_data = 8'h0F; |
set_rx_packet(0, rx_packet_length, 1'b0, 48'h0012_3456_789a, 48'h0708_090A_0B0C, 16'h0D0E, st_data); // length without CRC |
set_rx_addr_type(0, 48'h0102_0304_0506, 48'h0708_090A_0B0C, 16'h0D0E); |
append_rx_crc(0, rx_packet_length, 1'b0, 1'b0); |
|
// write to phy's control register for 10Mbps |
#Tp eth_phy0.control_bit14_10 = 5'b00000; // bit 13 reset - speed 10 |
#Tp eth_phy0.control_bit8_0 = 9'h1_00; // bit 6 reset - (10/100), bit 8 set - FD |
//#Tp eth_phy0.carrier_sense_tx_fd_detect(1); // Full duplex CRS detect normally off |
|
/* |
from eth_phy.v: |
task send_rx_packet; |
input [(8*8)-1:0] preamble_data; // preamble data to be sent - correct is 64'h0055_5555_5555_5555 |
input [3:0] preamble_len; // length of preamble in bytes - max is 4'h8, correct is 4'h7 |
input [7:0] sfd_data; // SFD data to be sent - correct is 8'hD5 |
input [31:0] start_addr; // start address |
input [31:0] len; // length of frame in Bytes (without preamble and SFD) |
input plus_drible_nibble; // if length is longer for one nibble |
|
*/ |
#100000 eth_phy0.send_rx_packet(64'h0055_5555_5555_5555, 4'h7, 8'hD5, 0, rx_packet_length, 1'b0); |
|
|
/* TODO: Some checking here that the packet's contents actually ended up in RAM correctly */ |
|
end |
/* |
TASKS for set and check RX packets: |
----------------------------------- |
set_rx_packet |
(rxpnt[31:0], len[15:0], plus_nibble, d_addr[47:0], s_addr[47:0], type_len[15:0], start_data[7:0]); |
check_rx_packet |
(rxpnt_phy[31:0], rxpnt_wb[31:0], len[15:0], plus_nibble, successful_nibble, failure[31:0]); |
*/ |
task set_rx_packet; |
input [31:0] rxpnt; // pointer to place in in the phy rx buffer we'll start at |
input [15:0] len; |
input plus_dribble_nibble; // if length is longer for one nibble |
input [47:0] eth_dest_addr; |
input [47:0] eth_source_addr; |
input [15:0] eth_type_len; |
input [7:0] eth_start_data; |
integer i, sd; |
reg [47:0] dest_addr; |
reg [47:0] source_addr; |
reg [15:0] type_len; |
reg [21:0] buffer; |
reg delta_t; |
begin |
buffer = rxpnt[21:0]; |
dest_addr = eth_dest_addr; |
source_addr = eth_source_addr; |
type_len = eth_type_len; |
sd = eth_start_data; |
delta_t = 0; |
for(i = 0; i < len; i = i + 1) |
begin |
if (i < 6) |
begin |
eth_phy0.rx_mem[buffer] = dest_addr[47:40]; |
dest_addr = dest_addr << 8; |
end |
else if (i < 12) |
begin |
eth_phy0.rx_mem[buffer] = source_addr[47:40]; |
source_addr = source_addr << 8; |
end |
else if (i < 14) |
begin |
eth_phy0.rx_mem[buffer] = type_len[15:8]; |
type_len = type_len << 8; |
end |
else |
begin |
eth_phy0.rx_mem[buffer] = sd[7:0]; |
sd = sd + 1; |
end |
buffer = buffer + 1; |
end |
delta_t = !delta_t; |
if (plus_dribble_nibble) |
eth_phy0.rx_mem[buffer] = {4'h0, 4'hD /*sd[3:0]*/}; |
delta_t = !delta_t; |
end |
endtask // set_rx_packet |
|
|
|
|
task set_rx_addr_type; |
input [31:0] rxpnt; |
input [47:0] eth_dest_addr; |
input [47:0] eth_source_addr; |
input [15:0] eth_type_len; |
integer i; |
reg [47:0] dest_addr; |
reg [47:0] source_addr; |
reg [15:0] type_len; |
reg [21:0] buffer; |
reg delta_t; |
begin |
buffer = rxpnt[21:0]; |
dest_addr = eth_dest_addr; |
source_addr = eth_source_addr; |
type_len = eth_type_len; |
delta_t = 0; |
for(i = 0; i < 14; i = i + 1) |
begin |
if (i < 6) |
begin |
eth_phy0.rx_mem[buffer] = dest_addr[47:40]; |
dest_addr = dest_addr << 8; |
end |
else if (i < 12) |
begin |
eth_phy0.rx_mem[buffer] = source_addr[47:40]; |
source_addr = source_addr << 8; |
end |
else // if (i < 14) |
begin |
eth_phy0.rx_mem[buffer] = type_len[15:8]; |
type_len = type_len << 8; |
end |
buffer = buffer + 1; |
end |
delta_t = !delta_t; |
end |
endtask // set_rx_addr_type |
|
/* |
task check_rx_packet; |
input [31:0] rxpnt_phy; // source |
input [31:0] rxpnt_wb; // destination |
input [15:0] len; |
input plus_dribble_nibble; // if length is longer for one nibble |
input successful_dribble_nibble; // if additional nibble is stored into memory |
output [31:0] failure; |
integer i, data_wb, data_phy; |
reg [31:0] addr_wb, addr_phy; |
reg [31:0] failure; |
reg [21:0] buffer; |
reg delta_t; |
begin |
addr_phy = rxpnt_phy; |
addr_wb = rxpnt_wb; |
delta_t = 0; |
failure = 0; |
|
// First write might not be word allign. |
if(addr_wb[1:0] == 1) |
begin |
wb_slave.rd_mem(addr_wb[21:0] - 1, data_wb, 4'h7); |
data_phy[31:24] = 0; |
data_phy[23:16] = eth_phy0.rx_mem[addr_phy[21:0]]; |
data_phy[15: 8] = eth_phy0.rx_mem[addr_phy[21:0] + 1]; |
data_phy[ 7: 0] = eth_phy0.rx_mem[addr_phy[21:0] + 2]; |
i = 3; |
if (data_phy[23:0] !== data_wb[23:0]) |
begin |
//`TIME; |
//$display(" addr_phy = %h, addr_wb = %h", rxpnt_phy, rxpnt_wb); |
//$display("*E Wrong 1. word (3 bytes) of RX packet! phy = %h, wb = %h", data_phy[23:0], data_wb[23:0]); |
failure = 1; |
end |
end |
else if (addr_wb[1:0] == 2) |
begin |
wb_slave.rd_mem(addr_wb[21:0] - 2, data_wb, 4'h3); |
data_phy[31:16] = 0; |
data_phy[15: 8] = eth_phy0.rx_mem[addr_phy[21:0]]; |
data_phy[ 7: 0] = eth_phy0.rx_mem[addr_phy[21:0] + 1]; |
i = 2; |
if (data_phy[15:0] !== data_wb[15:0]) |
begin |
//`TIME; |
//$display(" addr_phy = %h, addr_wb = %h", rxpnt_phy, rxpnt_wb); |
//$display("*E Wrong 1. word (2 bytes) of RX packet! phy = %h, wb = %h", data_phy[15:0], data_wb[15:0]); |
failure = 1; |
end |
end |
else if (addr_wb[1:0] == 3) |
begin |
wb_slave.rd_mem(addr_wb[21:0] - 3, data_wb, 4'h1); |
data_phy[31: 8] = 0; |
data_phy[ 7: 0] = eth_phy0.rx_mem[addr_phy[21:0]]; |
i = 1; |
if (data_phy[7:0] !== data_wb[7:0]) |
begin |
//`TIME; |
//$display(" addr_phy = %h, addr_wb = %h", rxpnt_phy, rxpnt_wb); |
//$display("*E Wrong 1. word (1 byte) of RX packet! phy = %h, wb = %h", data_phy[7:0], data_wb[7:0]); |
failure = 1; |
end |
end |
else |
i = 0; |
delta_t = !delta_t; |
|
for(i = i; i < (len - 4); i = i + 4) // Last 0-3 bytes are not checked |
begin |
wb_slave.rd_mem(addr_wb[21:0] + i, data_wb, 4'hF); |
data_phy[31:24] = eth_phy0.rx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy0.rx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy0.rx_mem[addr_phy[21:0] + i + 2]; |
data_phy[ 7: 0] = eth_phy0.rx_mem[addr_phy[21:0] + i + 3]; |
if (data_phy[31:0] !== data_wb[31:0]) |
begin |
//`TIME; |
//if (i == 0) |
// $display(" addr_phy = %h, addr_wb = %h", rxpnt_phy, rxpnt_wb); |
//$display("*E Wrong %0d. word (4 bytes) of RX packet! phy = %h, wb = %h", ((i/4)+1), data_phy[31:0], data_wb[31:0]); |
failure = failure + 1; |
end |
end |
delta_t = !delta_t; |
|
// Last word |
if((len - i) == 3) |
begin |
wb_slave.rd_mem(addr_wb[21:0] + i, data_wb, 4'hF); |
data_phy[31:24] = eth_phy0.rx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy0.rx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy0.rx_mem[addr_phy[21:0] + i + 2]; |
if (plus_dribble_nibble) |
data_phy[ 7: 0] = eth_phy0.rx_mem[addr_phy[21:0] + i + 3]; |
else |
data_phy[ 7: 0] = 0; |
if (data_phy[31:8] !== data_wb[31:8]) |
begin |
//`TIME; |
//$display("*E Wrong %0d. word (3 bytes) of RX packet! phy = %h, wb = %h", ((i/4)+1), data_phy[31:8], data_wb[31:8]); |
failure = failure + 1; |
end |
if (plus_dribble_nibble && successful_dribble_nibble) |
begin |
if (data_phy[3:0] !== data_wb[3:0]) |
begin |
//`TIME; |
//$display("*E Wrong dribble nibble in %0d. word (3 bytes) of RX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
else if (plus_dribble_nibble && !successful_dribble_nibble) |
begin |
if (data_phy[3:0] === data_wb[3:0]) |
begin |
//`TIME; |
//$display("*E Wrong dribble nibble in %0d. word (3 bytes) of RX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
end |
else if((len - i) == 2) |
begin |
wb_slave.rd_mem(addr_wb[21:0] + i, data_wb, 4'hE); |
data_phy[31:24] = eth_phy0.rx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy0.rx_mem[addr_phy[21:0] + i + 1]; |
if (plus_dribble_nibble) |
data_phy[15: 8] = eth_phy0.rx_mem[addr_phy[21:0] + i + 2]; |
else |
data_phy[15: 8] = 0; |
data_phy[ 7: 0] = 0; |
if (data_phy[31:16] !== data_wb[31:16]) |
begin |
//`TIME; |
//$display("*E Wrong %0d. word (2 bytes) of RX packet! phy = %h, wb = %h", ((i/4)+1), data_phy[31:16], data_wb[31:16]); |
failure = failure + 1; |
end |
if (plus_dribble_nibble && successful_dribble_nibble) |
begin |
if (data_phy[11:8] !== data_wb[11:8]) |
begin |
//`TIME; |
//$display("*E Wrong dribble nibble in %0d. word (2 bytes) of RX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
else if (plus_dribble_nibble && !successful_dribble_nibble) |
begin |
if (data_phy[11:8] === data_wb[11:8]) |
begin |
//`TIME; |
//$display("*E Wrong dribble nibble in %0d. word (2 bytes) of RX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
end |
else if((len - i) == 1) |
begin |
wb_slave.rd_mem(addr_wb[21:0] + i, data_wb, 4'hC); |
data_phy[31:24] = eth_phy0.rx_mem[addr_phy[21:0] + i]; |
if (plus_dribble_nibble) |
data_phy[23:16] = eth_phy0.rx_mem[addr_phy[21:0] + i + 1]; |
else |
data_phy[23:16] = 0; |
data_phy[15: 8] = 0; |
data_phy[ 7: 0] = 0; |
if (data_phy[31:24] !== data_wb[31:24]) |
begin |
//`TIME; |
//$display("*E Wrong %0d. word (1 byte) of RX packet! phy = %h, wb = %h", ((i/4)+1), data_phy[31:24], data_wb[31:24]); |
failure = failure + 1; |
end |
if (plus_dribble_nibble && successful_dribble_nibble) |
begin |
if (data_phy[19:16] !== data_wb[19:16]) |
begin |
//`TIME; |
//$display("*E Wrong dribble nibble in %0d. word (1 byte) of RX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
else if (plus_dribble_nibble && !successful_dribble_nibble) |
begin |
if (data_phy[19:16] === data_wb[19:16]) |
begin |
//`TIME; |
//$display("*E Wrong dribble nibble in %0d. word (1 byte) of RX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
end |
else if((len - i) == 4) |
begin |
wb_slave.rd_mem(addr_wb[21:0] + i, data_wb, 4'hF); |
data_phy[31:24] = eth_phy0.rx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy0.rx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy0.rx_mem[addr_phy[21:0] + i + 2]; |
data_phy[ 7: 0] = eth_phy0.rx_mem[addr_phy[21:0] + i + 3]; |
if (data_phy[31:0] !== data_wb[31:0]) |
begin |
//`TIME; |
//$display("*E Wrong %0d. word (4 bytes) of RX packet! phy = %h, wb = %h", ((i/4)+1), data_phy[31:0], data_wb[31:0]); |
failure = failure + 1; |
end |
if (plus_dribble_nibble) |
begin |
wb_slave.rd_mem(addr_wb[21:0] + i + 4, data_wb, 4'h8); |
data_phy[31:24] = eth_phy0.rx_mem[addr_phy[21:0] + i + 4]; |
if (successful_dribble_nibble) |
begin |
if (data_phy[27:24] !== data_wb[27:24]) |
begin |
//`TIME; |
//$display("*E Wrong dribble nibble in %0d. word (0 bytes) of RX packet!", ((i/4)+2)); |
failure = failure + 1; |
end |
end |
else |
begin |
if (data_phy[27:24] === data_wb[27:24]) |
begin |
//`TIME; |
//$display("*E Wrong dribble nibble in %0d. word (0 bytes) of RX packet!", ((i/4)+2)); |
failure = failure + 1; |
end |
end |
end |
end |
else |
$display("(%0t)(%m) ERROR", $time); |
delta_t = !delta_t; |
end |
endtask // check_rx_packet |
*/ |
|
////////////////////////////////////////////////////////////// |
// Ethernet CRC Basic tasks |
////////////////////////////////////////////////////////////// |
|
task append_rx_crc; |
input [31:0] rxpnt_phy; // source |
input [15:0] len; // length in bytes without CRC |
input plus_dribble_nibble; // if length is longer for one nibble |
input negated_crc; // if appended CRC is correct or not |
reg [31:0] crc; |
reg [7:0] tmp; |
reg [31:0] addr_phy; |
reg delta_t; |
begin |
addr_phy = rxpnt_phy + len; |
delta_t = 0; |
// calculate CRC from prepared packet |
paralel_crc_phy_rx(rxpnt_phy, {16'h0, len}, plus_dribble_nibble, crc); |
if (negated_crc) |
crc = ~crc; |
delta_t = !delta_t; |
|
if (plus_dribble_nibble) |
begin |
tmp = eth_phy0.rx_mem[addr_phy]; |
eth_phy0.rx_mem[addr_phy] = {crc[27:24], tmp[3:0]}; |
eth_phy0.rx_mem[addr_phy + 1] = {crc[19:16], crc[31:28]}; |
eth_phy0.rx_mem[addr_phy + 2] = {crc[11:8], crc[23:20]}; |
eth_phy0.rx_mem[addr_phy + 3] = {crc[3:0], crc[15:12]}; |
eth_phy0.rx_mem[addr_phy + 4] = {4'h0, crc[7:4]}; |
end |
else |
begin |
eth_phy0.rx_mem[addr_phy] = crc[31:24]; |
eth_phy0.rx_mem[addr_phy + 1] = crc[23:16]; |
eth_phy0.rx_mem[addr_phy + 2] = crc[15:8]; |
eth_phy0.rx_mem[addr_phy + 3] = crc[7:0]; |
end |
end |
endtask // append_rx_crc |
|
task append_rx_crc_delayed; |
input [31:0] rxpnt_phy; // source |
input [15:0] len; // length in bytes without CRC |
input plus_dribble_nibble; // if length is longer for one nibble |
input negated_crc; // if appended CRC is correct or not |
reg [31:0] crc; |
reg [7:0] tmp; |
reg [31:0] addr_phy; |
reg delta_t; |
begin |
addr_phy = rxpnt_phy + len; |
delta_t = 0; |
// calculate CRC from prepared packet |
paralel_crc_phy_rx(rxpnt_phy+4, {16'h0, len}-4, plus_dribble_nibble, crc); |
if (negated_crc) |
crc = ~crc; |
delta_t = !delta_t; |
|
if (plus_dribble_nibble) |
begin |
tmp = eth_phy0.rx_mem[addr_phy]; |
eth_phy0.rx_mem[addr_phy] = {crc[27:24], tmp[3:0]}; |
eth_phy0.rx_mem[addr_phy + 1] = {crc[19:16], crc[31:28]}; |
eth_phy0.rx_mem[addr_phy + 2] = {crc[11:8], crc[23:20]}; |
eth_phy0.rx_mem[addr_phy + 3] = {crc[3:0], crc[15:12]}; |
eth_phy0.rx_mem[addr_phy + 4] = {4'h0, crc[7:4]}; |
end |
else |
begin |
eth_phy0.rx_mem[addr_phy] = crc[31:24]; |
eth_phy0.rx_mem[addr_phy + 1] = crc[23:16]; |
eth_phy0.rx_mem[addr_phy + 2] = crc[15:8]; |
eth_phy0.rx_mem[addr_phy + 3] = crc[7:0]; |
end |
end |
endtask // append_rx_crc_delayed |
|
|
// paralel CRC calculating for PHY RX |
task paralel_crc_phy_rx; |
input [31:0] start_addr; // start address |
input [31:0] len; // length of frame in Bytes without CRC length |
input plus_dribble_nibble; // if length is longer for one nibble |
output [31:0] crc_out; |
reg [21:0] addr_cnt; // only 22 address lines |
integer word_cnt; |
integer nibble_cnt; |
reg [31:0] load_reg; |
reg delta_t; |
reg [31:0] crc_next; |
reg [31:0] crc; |
reg crc_error; |
reg [3:0] data_in; |
integer i; |
begin |
#1 addr_cnt = start_addr[21:0]; |
word_cnt = 24; // 27; // start of the frame - nibble granularity (MSbit first) |
crc = 32'hFFFF_FFFF; // INITIAL value |
delta_t = 0; |
// length must include 4 bytes of ZEROs, to generate CRC |
// get number of nibbles from Byte length (2^1 = 2) |
if (plus_dribble_nibble) |
nibble_cnt = ((len + 4) << 1) + 1'b1; // one nibble longer |
else |
nibble_cnt = ((len + 4) << 1); |
// because of MAGIC NUMBER nibbles are swapped [3:0] -> [0:3] |
load_reg[31:24] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15: 8] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[ 7: 0] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
while (nibble_cnt > 0) |
begin |
// wait for delta time |
delta_t = !delta_t; |
// shift data in |
|
if(nibble_cnt <= 8) // for additional 8 nibbles shift ZEROs in! |
data_in[3:0] = 4'h0; |
else |
|
data_in[3:0] = {load_reg[word_cnt], load_reg[word_cnt+1], load_reg[word_cnt+2], load_reg[word_cnt+3]}; |
crc_next[0] = (data_in[0] ^ crc[28]); |
crc_next[1] = (data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29]); |
crc_next[2] = (data_in[2] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[30]); |
crc_next[3] = (data_in[3] ^ data_in[2] ^ data_in[1] ^ crc[29] ^ crc[30] ^ crc[31]); |
crc_next[4] = (data_in[3] ^ data_in[2] ^ data_in[0] ^ crc[28] ^ crc[30] ^ crc[31]) ^ crc[0]; |
crc_next[5] = (data_in[3] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[31]) ^ crc[1]; |
crc_next[6] = (data_in[2] ^ data_in[1] ^ crc[29] ^ crc[30]) ^ crc[ 2]; |
crc_next[7] = (data_in[3] ^ data_in[2] ^ data_in[0] ^ crc[28] ^ crc[30] ^ crc[31]) ^ crc[3]; |
crc_next[8] = (data_in[3] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[31]) ^ crc[4]; |
crc_next[9] = (data_in[2] ^ data_in[1] ^ crc[29] ^ crc[30]) ^ crc[5]; |
crc_next[10] = (data_in[3] ^ data_in[2] ^ data_in[0] ^ crc[28] ^ crc[30] ^ crc[31]) ^ crc[6]; |
crc_next[11] = (data_in[3] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[31]) ^ crc[7]; |
crc_next[12] = (data_in[2] ^ data_in[1] ^ data_in[0] ^ crc[28] ^ crc[29] ^ crc[30]) ^ crc[8]; |
crc_next[13] = (data_in[3] ^ data_in[2] ^ data_in[1] ^ crc[29] ^ crc[30] ^ crc[31]) ^ crc[9]; |
crc_next[14] = (data_in[3] ^ data_in[2] ^ crc[30] ^ crc[31]) ^ crc[10]; |
crc_next[15] = (data_in[3] ^ crc[31]) ^ crc[11]; |
crc_next[16] = (data_in[0] ^ crc[28]) ^ crc[12]; |
crc_next[17] = (data_in[1] ^ crc[29]) ^ crc[13]; |
crc_next[18] = (data_in[2] ^ crc[30]) ^ crc[14]; |
crc_next[19] = (data_in[3] ^ crc[31]) ^ crc[15]; |
crc_next[20] = crc[16]; |
crc_next[21] = crc[17]; |
crc_next[22] = (data_in[0] ^ crc[28]) ^ crc[18]; |
crc_next[23] = (data_in[1] ^ data_in[0] ^ crc[29] ^ crc[28]) ^ crc[19]; |
crc_next[24] = (data_in[2] ^ data_in[1] ^ crc[30] ^ crc[29]) ^ crc[20]; |
crc_next[25] = (data_in[3] ^ data_in[2] ^ crc[31] ^ crc[30]) ^ crc[21]; |
crc_next[26] = (data_in[3] ^ data_in[0] ^ crc[31] ^ crc[28]) ^ crc[22]; |
crc_next[27] = (data_in[1] ^ crc[29]) ^ crc[23]; |
crc_next[28] = (data_in[2] ^ crc[30]) ^ crc[24]; |
crc_next[29] = (data_in[3] ^ crc[31]) ^ crc[25]; |
crc_next[30] = crc[26]; |
crc_next[31] = crc[27]; |
|
crc = crc_next; |
crc_error = crc[31:0] != 32'hc704dd7b; // CRC not equal to magic number |
case (nibble_cnt) |
9: crc_out = {!crc[24], !crc[25], !crc[26], !crc[27], !crc[28], !crc[29], !crc[30], !crc[31], |
!crc[16], !crc[17], !crc[18], !crc[19], !crc[20], !crc[21], !crc[22], !crc[23], |
!crc[ 8], !crc[ 9], !crc[10], !crc[11], !crc[12], !crc[13], !crc[14], !crc[15], |
!crc[ 0], !crc[ 1], !crc[ 2], !crc[ 3], !crc[ 4], !crc[ 5], !crc[ 6], !crc[ 7]}; |
default: crc_out = crc_out; |
endcase |
// wait for delta time |
delta_t = !delta_t; |
// increment address and load new data |
if ((word_cnt+3) == 7)//4) |
begin |
// because of MAGIC NUMBER nibbles are swapped [3:0] -> [0:3] |
load_reg[31:24] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15: 8] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[ 7: 0] = eth_phy0.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
end |
// set new load bit position |
if((word_cnt+3) == 31) |
word_cnt = 16; |
else if ((word_cnt+3) == 23) |
word_cnt = 8; |
else if ((word_cnt+3) == 15) |
word_cnt = 0; |
else if ((word_cnt+3) == 7) |
word_cnt = 24; |
else |
word_cnt = word_cnt + 4;// - 4; |
// decrement nibble counter |
nibble_cnt = nibble_cnt - 1; |
// wait for delta time |
delta_t = !delta_t; |
end // while |
#1; |
end |
endtask // paralel_crc_phy_rx |
|
/openrisc/trunk/orpsocv2/bench/verilog/eth_phy_defines.v
0,0 → 1,91
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name: eth_phy_defines.v //// |
//// //// |
//// This file is part of the Ethernet IP core project //// |
//// http://www.opencores.org/projects/ethmac/ //// |
//// //// |
//// Author(s): //// |
//// - Tadej Markovic, tadej@opencores.org //// |
//// //// |
//// All additional information is available in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2002, Authors //// |
//// //// |
//// 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.1 2002/09/13 11:57:20 mohor |
// New testbench. Thanks to Tadej M - "The Spammer". |
// |
// |
// |
|
// Address of PHY device (LXT971A) |
`define ETH_PHY_ADDR 5'h00 //Changed to 0 -jb |
|
// LED/Configuration pins on PHY device - see the specification, page 26, table 8 |
// Initial set of bits 13, 12 and 8 of Control Register |
`define LED_CFG1 1'b0 |
`define LED_CFG2 1'b0 |
`define LED_CFG3 1'b1 |
|
|
// Supported speeds and physical ports - see the specification, page 67, table 41 |
// Set bits 15 to 9 of Status Register |
`define SUPPORTED_SPEED_AND_PORT 7'h3F |
|
// Extended status register (address 15) |
// Set bit 8 of Status Register |
`define EXTENDED_STATUS 1'b0 |
|
// Default status bits - see the specification, page 67, table 41 |
// Set bits 6 to 0 of Status Register |
`define DEFAULT_STATUS 7'h09 |
|
// PHY ID 1 number - see the specification, page 68, table 42 |
// Set bits of Phy Id Register 1 |
`define PHY_ID1 16'h0013 |
|
// PHY ID 2 number - see the specification, page 68, table 43 |
// Set bits 15 to 10 of Phy Id Register 2 |
`define PHY_ID2 6'h1E |
|
// Manufacturer MODEL number - see the specification, page 68, table 43 |
// Set bits 9 to 4 of Phy Id Register 2 |
`define MAN_MODEL_NUM 6'h0E |
|
// Manufacturer REVISION number - see the specification, page 68, table 43 |
// Set bits 3 to 0 of Phy Id Register 2 |
`define MAN_REVISION_NUM 4'h2 |
|
|
|
|
/openrisc/trunk/orpsocv2/bench/verilog/eth_phy.v
0,0 → 1,1481
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name: eth_phy.v //// |
//// //// |
//// This file is part of the Ethernet IP core project //// |
//// http://www.opencores.org/projects/ethmac/ //// |
//// //// |
//// Author(s): //// |
//// - Tadej Markovic, tadej@opencores.org //// |
//// //// |
//// All additional information is available in the README.txt //// |
//// file. //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2002 Authors //// |
//// //// |
//// 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.7 2002/10/18 13:58:22 tadejm |
// Some code changed due to bug fixes. |
// |
// Revision 1.6 2002/10/09 13:16:51 tadejm |
// Just back-up; not completed testbench and some testcases are not |
// wotking properly yet. |
// |
// Revision 1.5 2002/09/18 17:55:08 tadej |
// Bug repaired in eth_phy device |
// |
// Revision 1.3 2002/09/13 14:50:15 mohor |
// Bug in MIIM fixed. |
// |
// Revision 1.2 2002/09/13 12:29:14 mohor |
// Headers changed. |
// |
// Revision 1.1 2002/09/13 11:57:20 mohor |
// New testbench. Thanks to Tadej M - "The Spammer". |
// |
// |
// |
|
`include "timescale.v" |
`include "eth_phy_defines.v" |
|
// ORPSoCv2 testbench include |
// Will enable verbose if eth test |
`ifdef TEST_DEFINE_FILE |
`include "test_define.v" |
`endif |
|
|
`define MULTICAST_XFR 0 |
`define UNICAST_XFR 1 |
`define BROADCAST_XFR 2 |
`define UNICAST_WRONG_XFR 3 |
|
|
//`define ETH_PHY_VERBOSE 1 |
|
module eth_phy // This PHY model simulate simplified Intel LXT971A PHY |
( |
// COMMON |
m_rst_n_i, |
|
// MAC TX |
mtx_clk_o, |
mtxd_i, |
mtxen_i, |
mtxerr_i, |
|
// MAC RX |
mrx_clk_o, |
mrxd_o, |
mrxdv_o, |
mrxerr_o, |
|
mcoll_o, |
mcrs_o, |
|
// MIIM |
mdc_i, |
md_io, |
speed_o, |
link_o, |
duplex_o |
); |
|
////////////////////////////////////////////////////////////////////// |
// |
// Input/output signals |
// |
////////////////////////////////////////////////////////////////////// |
|
// MAC miscellaneous signals |
input m_rst_n_i; |
// MAC TX signals |
output mtx_clk_o; |
input [3:0] mtxd_i; |
input mtxen_i; |
input mtxerr_i; |
// MAC RX signals |
output mrx_clk_o; |
output [3:0] mrxd_o; |
output mrxdv_o; |
output mrxerr_o; |
// MAC common signals |
output mcoll_o; |
output mcrs_o; |
// MAC management signals |
input mdc_i; |
inout md_io; |
// Sideband signals for SMII -- jb |
output link_o; |
output speed_o; |
output duplex_o; |
|
|
////////////////////////////////////////////////////////////////////// |
// |
// PHY management (MIIM) REGISTER definitions |
// |
////////////////////////////////////////////////////////////////////// |
// |
// Supported registers: |
// |
// Addr | Register Name |
//-------------------------------------------------------------------- |
// 0 | Control reg. | |
// 1 | Status reg. #1 |--> normal operation |
// 2 | PHY ID reg. 1 | |
// 3 | PHY ID reg. 2 | |
//---------------------- |
// Addr | Data MEMORY |--> for testing |
// |
//-------------------------------------------------------------------- |
// |
// Control register |
reg control_bit15; // self clearing bit |
reg [14:10] control_bit14_10; |
reg control_bit9; // self clearing bit |
reg [8:0] control_bit8_0; |
// Status register |
wire [15:9] status_bit15_9 = `SUPPORTED_SPEED_AND_PORT; |
wire status_bit8 = `EXTENDED_STATUS; |
wire status_bit7 = 1'b0; // reserved |
reg [6:0] status_bit6_0; |
// PHY ID register 1 |
wire [15:0] phy_id1 = `PHY_ID1; |
// PHY ID register 2 |
wire [15:0] phy_id2 = {`PHY_ID2, `MAN_MODEL_NUM, `MAN_REVISION_NUM}; |
//-------------------------------------------------------------------- |
// |
// Data MEMORY |
reg [15:0] data_mem [0:31]; // 32 locations of 16-bit data width |
// |
////////////////////////////////////////////////////////////////////// |
|
|
////////////////////////////////////////////////////////////////////// |
// |
// PHY clocks - RX & TX |
// |
////////////////////////////////////////////////////////////////////// |
|
reg mtx_clk_o; |
reg mrx_clk_o; |
|
// random generator for a RX period when link is down |
real rx_link_down_halfperiod; |
|
always@(status_bit6_0[2]) |
begin |
if (!status_bit6_0[2]) // Link is down |
begin |
#1 rx_link_down_halfperiod = ({$random} % 243) + 13; |
`ifdef ETH_PHY_VERBOSE |
#1 $display( " (%0t)(%m)MAC RX clock is %f MHz while ethernet link is down!", |
$time, (1000/(rx_link_down_halfperiod*2)) ); |
`endif |
end |
end |
|
`ifdef ETH_PHY_VERBOSE |
always@(status_bit6_0[2]) |
begin |
if (!status_bit6_0[2]) // Link is down |
#1 $display( " (%0t)(%m)Ethernet link is down!", $time); |
else |
#1 $display( " (%0t)(%m)Ethernet link is up!", $time); |
end |
`endif |
|
// speed selection signal eth_speed: 1'b1 - 100 Mbps, 1'b0 - 10 Mbps |
wire eth_speed; |
|
assign eth_speed = ( (control_bit14_10[13]) && !((`LED_CFG1) && (`LED_CFG2)) ); |
|
`ifdef ETH_PHY_VERBOSE |
always@(eth_speed) |
begin |
if (eth_speed) |
#1 $display( " (%0t)(%m)PHY configured to 100 Mbps!", $time); |
else |
#1 $display( " (%0t)(%m)PHY configured tp 10 Mbps!", $time); |
end |
`endif |
|
// different clock calculation between RX and TX, so that there is alsways a litle difference |
/*initial |
begin |
set_mrx_equal_mtx = 1; // default |
end*/ |
|
always |
begin |
mtx_clk_o = 0; |
#7; |
forever |
begin |
if (eth_speed) // 100 Mbps - 25 MHz, 40 ns |
begin |
#20 mtx_clk_o = ~mtx_clk_o; |
end |
else // 10 Mbps - 2.5 MHz, 400 ns |
begin |
#200 mtx_clk_o = ~mtx_clk_o; |
end |
end |
end |
|
always |
begin |
// EQUAL mrx_clk to mtx_clk |
mrx_clk_o = 0; |
#7; |
forever |
begin |
if (eth_speed) // 100 Mbps - 25 MHz, 40 ns |
begin |
#20 mrx_clk_o = ~mrx_clk_o; |
end |
else // 10 Mbps - 2.5 MHz, 400 ns |
begin |
#200 mrx_clk_o = ~mrx_clk_o; |
end |
end |
// DIFFERENT mrx_clk than mtx_clk |
/* mrx_clk_diff_than_mtx = 1; |
#3; |
forever |
begin |
if (status_bit6_0[2]) // Link is UP |
begin |
if (eth_speed) // 100 Mbps - 25 MHz, 40 ns |
begin |
//#(((1/0.025001)/2)) |
#19.99 mrx_clk_diff_than_mtx = ~mrx_clk_diff_than_mtx; // period is calculated from frequency in GHz |
end |
else // 10 Mbps - 2.5 MHz, 400 ns |
begin |
//#(((1/0.0024999)/2)) |
#200.01 mrx_clk_diff_than_mtx = ~mrx_clk_diff_than_mtx; // period is calculated from frequency in GHz |
end |
end |
else // Link is down |
begin |
#(rx_link_down_halfperiod) mrx_clk_diff_than_mtx = ~mrx_clk_diff_than_mtx; // random frequency between 2 MHz and 40 MHz |
end |
end*/ |
// // set output mrx_clk |
// if (set_mrx_equal_mtx) |
// mrx_clk_o = mrx_clk_equal_to_mtx; |
// else |
// mrx_clk_o = mrx_clk_diff_than_mtx; |
end |
|
// set output mrx_clk |
//assign mrx_clk_o = set_mrx_equal_mtx ? mrx_clk_equal_to_mtx : mrx_clk_diff_than_mtx ; |
|
////////////////////////////////////////////////////////////////////// |
// |
// PHY management (MIIM) interface |
// |
////////////////////////////////////////////////////////////////////// |
reg respond_to_all_phy_addr; // PHY will respond to all phy addresses |
reg no_preamble; // PHY responds to frames without preamble |
|
integer md_transfer_cnt; // counter countes the value of whole data transfer |
reg md_transfer_cnt_reset; // for reseting the counter |
reg md_io_reg; // registered input |
reg md_io_output; // registered output |
reg md_io_rd_wr; // op-code latched (read or write) |
reg md_io_enable; // output enable |
reg [4:0] phy_address; // address of PHY device |
reg [4:0] reg_address; // address of a register |
reg md_get_phy_address; // for shifting PHY address in |
reg md_get_reg_address; // for shifting register address in |
reg [15:0] reg_data_in; // data to be written in a register |
reg md_get_reg_data_in; // for shifting data in |
reg md_put_reg_data_in; // for storing data into a selected register |
reg [15:0] reg_data_out; // data to be read from a register |
reg md_put_reg_data_out; // for registering data from a selected register |
|
wire [15:0] register_bus_in; // data bus to a selected register |
reg [15:0] register_bus_out; // data bus from a selected register |
|
initial |
begin |
md_io_enable = 1'b0; |
respond_to_all_phy_addr = 1'b0; |
no_preamble = 1'b0; |
end |
|
// tristate output |
assign #1 md_io = (m_rst_n_i && md_io_enable) ? md_io_output : 1'bz ; |
|
// registering input |
always@(posedge mdc_i or negedge m_rst_n_i) |
begin |
if (!m_rst_n_i) |
md_io_reg <= #1 0; |
else |
md_io_reg <= #1 md_io; |
end |
|
// getting (shifting) PHY address, Register address and Data in |
// putting Data out and shifting |
always@(posedge mdc_i or negedge m_rst_n_i) |
begin |
if (!m_rst_n_i) |
begin |
phy_address <= 0; |
reg_address <= 0; |
reg_data_in <= 0; |
reg_data_out <= 0; |
md_io_output <= 0; |
end |
else |
begin |
if (md_get_phy_address) |
begin |
phy_address[4:1] <= phy_address[3:0]; // correct address is `ETH_PHY_ADDR |
phy_address[0] <= md_io; |
end |
if (md_get_reg_address) |
begin |
reg_address[4:1] <= reg_address[3:0]; |
reg_address[0] <= md_io; |
end |
if (md_get_reg_data_in) |
begin |
reg_data_in[15:1] <= reg_data_in[14:0]; |
reg_data_in[0] <= md_io; |
end |
if (md_put_reg_data_out) |
begin |
reg_data_out <= register_bus_out; |
end |
if (md_io_enable) |
begin |
md_io_output <= reg_data_out[15]; |
reg_data_out[15:1] <= reg_data_out[14:0]; |
reg_data_out[0] <= 1'b0; |
end |
end |
end |
|
assign #1 register_bus_in = reg_data_in; // md_put_reg_data_in - allows writing to a selected register |
|
// counter for transfer to and from MIIM |
always@(posedge mdc_i or negedge m_rst_n_i) |
begin |
if (!m_rst_n_i) |
begin |
if (no_preamble) |
md_transfer_cnt <= 33; |
else |
md_transfer_cnt <= 1; |
end |
else |
begin |
if (md_transfer_cnt_reset) |
begin |
if (no_preamble) |
md_transfer_cnt <= 33; |
else |
md_transfer_cnt <= 1; |
end |
else if (md_transfer_cnt < 64) |
begin |
md_transfer_cnt <= md_transfer_cnt + 1'b1; |
end |
else |
begin |
if (no_preamble) |
md_transfer_cnt <= 33; |
else |
md_transfer_cnt <= 1; |
end |
end |
end |
|
// MIIM transfer control |
always@(m_rst_n_i or md_transfer_cnt or md_io_reg or md_io_rd_wr or |
phy_address or respond_to_all_phy_addr or no_preamble) |
begin |
#1; |
while ((m_rst_n_i) && (md_transfer_cnt <= 64)) |
begin |
// reset the signal - put registered data in the register (when write) |
// check preamble |
if (md_transfer_cnt < 33) |
begin |
#4 md_put_reg_data_in = 1'b0; |
if (md_io_reg !== 1'b1) |
begin |
#1 md_transfer_cnt_reset = 1'b1; |
end |
else |
begin |
#1 md_transfer_cnt_reset = 1'b0; |
end |
end |
|
// check start bits |
else if (md_transfer_cnt == 33) |
begin |
if (no_preamble) |
begin |
#4 md_put_reg_data_in = 1'b0; |
if (md_io_reg === 1'b0) |
begin |
#1 md_transfer_cnt_reset = 1'b0; |
end |
else |
begin |
#1 md_transfer_cnt_reset = 1'b1; |
//if ((md_io_reg !== 1'bz) && (md_io_reg !== 1'b1)) |
if (md_io_reg !== 1'bz) |
begin |
// ERROR - start ! |
`ifdef ETH_PHY_VERBOSE |
$display( "*E (%0t)(%m)MIIM - wrong first start bit (without preamble)", $time); |
`endif |
#10 $stop; |
end |
end |
end |
else // with preamble |
begin |
#4 ; |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m)MIIM - 32-bit preamble received", $time); |
`endif |
// check start bit only if md_transfer_cnt_reset is inactive, because if |
// preamble suppression was changed start bit should not be checked |
if ((md_io_reg !== 1'b0) && (md_transfer_cnt_reset == 1'b0)) |
begin |
// ERROR - start ! |
`ifdef ETH_PHY_VERBOSE |
$display( "*E (%0t)(%m)MIIM - wrong first start bit", $time); |
`endif |
#10 $stop; |
end |
end |
end |
|
else if (md_transfer_cnt == 34) |
begin |
#4; |
if (md_io_reg !== 1'b1) |
begin |
// ERROR - start ! |
#1; |
`ifdef ETH_PHY_VERBOSE |
if (no_preamble) |
$display( "*E (%0t)(%m)MIIM - wrong second start bit (without preamble)", $time); |
else |
$display( "*E (%0t)(%m)MIIM - wrong second start bit", $time); |
`endif |
#10 $stop; |
end |
else |
begin |
`ifdef ETH_PHY_VERBOSE |
if (no_preamble) |
#1 $display( " (%0t)(%m)MIIM - 2 start bits received (without preamble)", $time); |
else |
#1 $display( " (%0t)(%m)MIIM - 2 start bits received", $time); |
`endif |
end |
end |
|
// register the op-code (rd / wr) |
else if (md_transfer_cnt == 35) |
begin |
#4; |
if (md_io_reg === 1'b1) |
begin |
#1 md_io_rd_wr = 1'b1; |
end |
else |
begin |
#1 md_io_rd_wr = 1'b0; |
end |
end |
|
else if (md_transfer_cnt == 36) |
begin |
#4; |
if ((md_io_reg === 1'b0) && (md_io_rd_wr == 1'b1)) |
begin |
#1 md_io_rd_wr = 1'b1; // reading from PHY registers |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m)MIIM - op-code for READING from registers", $time); |
`endif |
end |
else if ((md_io_reg === 1'b1) && (md_io_rd_wr == 1'b0)) |
begin |
#1 md_io_rd_wr = 1'b0; // writing to PHY registers |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m)MIIM - op-code for WRITING to registers", $time); |
`endif |
end |
else |
begin |
// ERROR - wrong opcode ! |
`ifdef ETH_PHY_VERBOSE |
#1 $display( "*E (%0t)(%m)MIIM - wrong OP-CODE", $time); |
`endif |
#10 $stop; |
end |
// set the signal - get PHY address |
begin |
#1 md_get_phy_address = 1'b1; |
end |
end |
|
// reset the signal - get PHY address |
else if (md_transfer_cnt == 41) |
begin |
#4 md_get_phy_address = 1'b0; |
// set the signal - get register address |
#1 md_get_reg_address = 1'b1; |
end |
|
// reset the signal - get register address |
// set the signal - put register data to output register |
else if (md_transfer_cnt == 46) |
begin |
#4 md_get_reg_address = 1'b0; |
#1 md_put_reg_data_out = 1'b1; |
end |
|
// reset the signal - put register data to output register |
// set the signal - enable md_io as output when read |
else if (md_transfer_cnt == 47) |
begin |
#4 md_put_reg_data_out = 1'b0; |
if (md_io_rd_wr) //read |
begin |
if (md_io_reg !== 1'bz) |
begin |
// ERROR - turn around ! |
`ifdef ETH_PHY_VERBOSE |
#1 $display( "*E (%0t)(%m)MIIM - wrong turn-around cycle before reading data out", $time); |
`endif |
#10 $stop; |
end |
if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address |
begin |
#1 md_io_enable = 1'b1; |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m)MIIM - received correct PHY ADDRESS: %x", $time, phy_address); |
`endif |
end |
else |
begin |
`ifdef ETH_PHY_VERBOSE |
#1 $display( "*W (%0t)(%m)MIIM - received different PHY ADDRESS: %x", $time, phy_address); |
`endif |
end |
end |
else // write |
begin |
#1 md_io_enable = 1'b0; |
// check turn around cycle when write on clock 47 |
if (md_io_reg !== 1'b1) |
begin |
// ERROR - turn around ! |
`ifdef ETH_PHY_VERBOSE |
#1 $display( "*E (%0t)(%m)MIIM - wrong 1. turn-around cycle before writing data in", |
$time); |
`endif |
#10 $stop; |
end |
end |
end |
|
// set the signal - get register data in when write |
else if (md_transfer_cnt == 48) |
begin |
#4; |
if (!md_io_rd_wr) // write |
begin |
#1 md_get_reg_data_in = 1'b1; |
// check turn around cycle when write on clock 48 |
if (md_io_reg !== 1'b0) |
begin |
// ERROR - turn around ! |
`ifdef ETH_PHY_VERBOSE |
#1 $display( "*E (%0t)(%m)MIIM - wrong 2. turn-around cycle before writing data in", |
$time); |
`endif |
#10 $stop; |
end |
end |
else // read |
begin |
#1 md_get_reg_data_in = 1'b0; |
end |
end |
|
// reset the signal - enable md_io as output when read |
// reset the signal - get register data in when write |
// set the signal - put registered data in the register when write |
else if (md_transfer_cnt == 64) |
begin |
#1 md_io_enable = 1'b0; |
#4 md_get_reg_data_in = 1'b0; |
if (!md_io_rd_wr) // write |
begin |
if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address |
begin |
#1 md_put_reg_data_in = 1'b1; |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m)MIIM - received correct PHY ADDRESS: %x", $time, phy_address); |
$display( " (%0t)(%m)MIIM - WRITING to register %x COMPLETED!", $time, reg_address); |
`endif |
end |
else |
begin |
`ifdef ETH_PHY_VERBOSE |
#1 $display( "*W (%0t)(%m)MIIM - received different PHY ADDRESS: %x", $time, phy_address); |
$display( "*W (%0t)(%m)MIIM - NO WRITING to register %x !", $time, reg_address); |
`endif |
end |
end |
else // read |
begin |
`ifdef ETH_PHY_VERBOSE |
if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address |
#1 $display( " (%0t)(%m)MIIM - READING from register %x COMPLETED!", |
$time, reg_address); |
else |
#1 $display( "*W (%0t)(%m)MIIM - NO READING from register %x !", $time, reg_address); |
`endif |
end |
end |
|
// wait for one clock period |
@(posedge mdc_i) |
#1; |
end |
end |
|
//==================================================================== |
// |
// PHY management (MIIM) REGISTERS |
// |
//==================================================================== |
// |
// Supported registers (normal operation): |
// |
// Addr | Register Name |
//-------------------------------------------------------------------- |
// 0 | Control reg. |
// 1 | Status reg. #1 |
// 2 | PHY ID reg. 1 |
// 3 | PHY ID reg. 2 |
//---------------------- |
// Addr | Data MEMORY |--> for testing |
// |
//-------------------------------------------------------------------- |
// |
// Control register |
// reg control_bit15; // self clearing bit |
// reg [14:10] control_bit14_10; |
// reg control_bit9; // self clearing bit |
// reg [8:0] control_bit8_0; |
// Status register |
// wire [15:9] status_bit15_9 = `SUPPORTED_SPEED_AND_PORT; |
// wire status_bit8 = `EXTENDED_STATUS; |
// wire status_bit7 = 1'b0; // reserved |
// reg [6:0] status_bit6_0 = `DEFAULT_STATUS; |
// PHY ID register 1 |
// wire [15:0] phy_id1 = `PHY_ID1; |
// PHY ID register 2 |
// wire [15:0] phy_id2 = {`PHY_ID2, `MAN_MODEL_NUM, `MAN_REVISION_NUM}; |
//-------------------------------------------------------------------- |
// |
// Data MEMORY |
// reg [15:0] data_mem [0:31]; // 32 locations of 16-bit data width |
// |
//==================================================================== |
|
////////////////////////////////////////////////////////////////////// |
// |
// PHY management (MIIM) REGISTER control |
// |
////////////////////////////////////////////////////////////////////// |
|
// wholy writable registers for walking ONE's on data, phy and reg. addresses |
reg registers_addr_data_test_operation; |
|
// Non writable status registers |
initial // always |
begin |
#1 status_bit6_0[6] = no_preamble; |
status_bit6_0[5] = 1'b0; |
status_bit6_0[3] = 1'b1; |
status_bit6_0[0] = 1'b1; |
end |
always@(posedge mrx_clk_o) |
begin |
status_bit6_0[4] <= #1 1'b0; |
status_bit6_0[1] <= #1 1'b0; |
end |
initial |
begin |
status_bit6_0[2] = 1'b1; |
registers_addr_data_test_operation = 0; |
end |
|
// Reading from a selected registers |
always@(reg_address or registers_addr_data_test_operation or md_put_reg_data_out or |
control_bit15 or control_bit14_10 or control_bit9 or control_bit8_0 or |
status_bit15_9 or status_bit8 or status_bit7 or status_bit6_0 or |
phy_id1 or phy_id2) |
begin |
if (registers_addr_data_test_operation) // test operation |
begin |
if (md_put_reg_data_out) // read enable |
begin |
register_bus_out = #1 data_mem[reg_address]; |
end |
end |
else // normal operation |
begin |
if (md_put_reg_data_out) // read enable |
begin |
case (reg_address) |
5'h0: register_bus_out = #1 {control_bit15, control_bit14_10, control_bit9, control_bit8_0}; |
5'h1: register_bus_out = #1 {status_bit15_9, status_bit8, status_bit7, status_bit6_0}; |
5'h2: register_bus_out = #1 phy_id1; |
5'h3: register_bus_out = #1 phy_id2; |
default: register_bus_out = #1 16'hDEAD; |
endcase |
end |
end |
end |
|
// Self clear control signals |
reg self_clear_d0; |
reg self_clear_d1; |
reg self_clear_d2; |
reg self_clear_d3; |
// Self clearing control |
always@(posedge mdc_i or negedge m_rst_n_i) |
begin |
if (!m_rst_n_i) |
begin |
self_clear_d0 <= #1 0; |
self_clear_d1 <= #1 0; |
self_clear_d2 <= #1 0; |
self_clear_d3 <= #1 0; |
end |
else |
begin |
self_clear_d0 <= #1 md_put_reg_data_in; |
self_clear_d1 <= #1 self_clear_d0; |
self_clear_d2 <= #1 self_clear_d1; |
self_clear_d3 <= #1 self_clear_d2; |
end |
end |
|
// Writing to a selected register |
always@(posedge mdc_i or negedge m_rst_n_i) |
begin |
if ((!m_rst_n_i) || (control_bit15)) |
begin |
if (!registers_addr_data_test_operation) // normal operation |
begin |
control_bit15 <= #1 0; |
control_bit14_10 <= #1 {1'b0, (`LED_CFG1 || `LED_CFG2), `LED_CFG1, 2'b0}; |
control_bit9 <= #1 0; |
control_bit8_0 <= #1 {`LED_CFG3, 8'b0}; |
end |
end |
else |
begin |
if (registers_addr_data_test_operation) // test operation |
begin |
if (md_put_reg_data_in) |
begin |
data_mem[reg_address] <= #1 register_bus_in[15:0]; |
end |
end |
else // normal operation |
begin |
// bits that are normaly written |
if (md_put_reg_data_in) |
begin |
case (reg_address) |
5'h0: |
begin |
control_bit14_10 <= #1 register_bus_in[14:10]; |
control_bit8_0 <= #1 register_bus_in[8:0]; |
end |
default: |
begin |
end |
endcase |
end |
// self cleared bits written |
if ((md_put_reg_data_in) && (reg_address == 5'h0)) |
begin |
control_bit15 <= #1 register_bus_in[15]; |
control_bit9 <= #1 register_bus_in[9]; |
end |
else if (self_clear_d3) // self cleared bits cleared |
begin |
control_bit15 <= #1 1'b0; |
control_bit9 <= #1 1'b0; |
end |
end |
end |
end |
|
////////////////////////////////////////////////////////////////////// |
// |
// PHY <-> MAC control (RX and TX clocks are at the begining) |
// |
////////////////////////////////////////////////////////////////////// |
|
// CARRIER SENSE & COLLISION |
|
// MAC common signals |
reg mcoll_o; |
reg mcrs_o; |
// Internal signals controling Carrier sense & Collision |
// MAC common signals generated when appropriate transfer |
reg mcrs_rx; |
reg mcrs_tx; |
// delayed mtxen_i signal for generating delayed tx carrier sense |
reg mtxen_d1; |
reg mtxen_d2; |
reg mtxen_d3; |
reg mtxen_d4; |
reg mtxen_d5; |
reg mtxen_d6; |
// collision signal set or rest within task for controling collision |
reg task_mcoll; |
// carrier sense signal set or rest within task for controling carrier sense |
reg task_mcrs; |
reg task_mcrs_lost; |
// do not generate collision in half duplex - not normal operation |
reg no_collision_in_half_duplex; |
// generate collision in full-duplex mode also - not normal operation |
reg collision_in_full_duplex; |
// do not generate carrier sense in half duplex mode - not normal operation |
reg no_carrier_sense_in_tx_half_duplex; |
reg no_carrier_sense_in_rx_half_duplex; |
// generate carrier sense during TX in full-duplex mode also - not normal operation |
reg carrier_sense_in_tx_full_duplex; |
// do not generate carrier sense during RX in full-duplex mode - not normal operation |
reg no_carrier_sense_in_rx_full_duplex; |
// on RX: delay after carrier sense signal; on TX: carrier sense delayed (delay is one clock period) |
reg real_carrier_sense; |
|
initial |
begin |
mcrs_rx = 0; |
mcrs_tx = 0; |
task_mcoll = 0; |
task_mcrs = 0; |
task_mcrs_lost = 0; |
no_collision_in_half_duplex = 0; |
collision_in_full_duplex = 0; |
no_carrier_sense_in_tx_half_duplex = 0; |
no_carrier_sense_in_rx_half_duplex = 0; |
carrier_sense_in_tx_full_duplex = 0; |
no_carrier_sense_in_rx_full_duplex = 0; |
real_carrier_sense = 0; |
end |
|
// Collision |
always@(m_rst_n_i or control_bit8_0 or collision_in_full_duplex or |
mcrs_rx or mcrs_tx or task_mcoll or no_collision_in_half_duplex |
) |
begin |
if (!m_rst_n_i) |
mcoll_o = 0; |
else |
begin |
if (control_bit8_0[8]) // full duplex |
begin |
if (collision_in_full_duplex) // collision is usually not asserted in full duplex |
begin |
mcoll_o = ((mcrs_rx && mcrs_tx) || task_mcoll); |
`ifdef ETH_PHY_VERBOSE |
if (mcrs_rx && mcrs_tx) |
$display( " (%0t)(%m) Collision set in FullDuplex!", $time); |
if (task_mcoll) |
$display( " (%0t)(%m) Collision set in FullDuplex from TASK!", $time); |
`endif |
end |
else |
begin |
mcoll_o = task_mcoll; |
`ifdef ETH_PHY_VERBOSE |
if (task_mcoll) |
$display( " (%0t)(%m) Collision set in FullDuplex from TASK!", $time); |
`endif |
end |
end |
else // half duplex |
begin |
mcoll_o = ((mcrs_rx && mcrs_tx && !no_collision_in_half_duplex) || |
task_mcoll); |
`ifdef ETH_PHY_VERBOSE |
if (mcrs_rx && mcrs_tx) |
$display( " (%0t)(%m) Collision set in HalfDuplex!", $time); |
if (task_mcoll) |
$display( " (%0t)(%m) Collision set in HalfDuplex from TASK!", $time); |
`endif |
end |
end |
end |
|
// Carrier sense |
always@(m_rst_n_i or control_bit8_0 or carrier_sense_in_tx_full_duplex or |
no_carrier_sense_in_rx_full_duplex or |
no_carrier_sense_in_tx_half_duplex or |
no_carrier_sense_in_rx_half_duplex or |
mcrs_rx or mcrs_tx or task_mcrs or task_mcrs_lost |
) |
begin |
if (!m_rst_n_i) |
mcrs_o = 0; |
else |
begin |
if (control_bit8_0[8]) // full duplex |
begin |
if (carrier_sense_in_tx_full_duplex) // carrier sense is usually not asserted during TX in full duplex |
mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_full_duplex) || |
mcrs_tx || task_mcrs) && !task_mcrs_lost; |
else |
mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_full_duplex) || |
task_mcrs) && !task_mcrs_lost; |
end |
else // half duplex |
begin |
mcrs_o = ((mcrs_rx && !no_carrier_sense_in_rx_half_duplex) || |
(mcrs_tx && !no_carrier_sense_in_tx_half_duplex) || |
task_mcrs) && !task_mcrs_lost; |
end |
end |
end |
|
// MAC TX CONTROL (RECEIVING AT PHY) |
|
// storage memory for TX data received from MAC |
reg [7:0] tx_mem [0:4194303]; // 4194304 locations (22 address lines) of 8-bit data width |
reg [31:0] tx_mem_addr_in; // address for storing to TX memory |
reg [7:0] tx_mem_data_in; // data for storing to TX memory |
reg [31:0] tx_cnt; // counts nibbles |
|
// control data of a TX packet for upper layer of testbench |
reg tx_preamble_ok; |
reg tx_sfd_ok; |
// if there is a drible nibble, then tx packet is not byte aligned! |
reg tx_byte_aligned_ok; |
// complete length of TX packet (Bytes) received (without preamble and SFD) |
reg [31:0] tx_len; |
// complete length of TX packet (Bytes) received (without preamble and SFD) untill MTxErr signal was set first |
reg [31:0] tx_len_err; |
|
// TX control |
always@(posedge mtx_clk_o) |
begin |
// storing data and basic checking of frame |
if (!m_rst_n_i) |
begin |
tx_cnt <= 0; |
tx_preamble_ok <= 0; |
tx_sfd_ok <= 0; |
tx_len <= 0; |
tx_len_err <= 0; |
end |
else |
begin |
if (!mtxen_i) |
begin |
tx_cnt <= 0; |
end |
else |
begin |
// tx nibble counter |
tx_cnt <= tx_cnt + 1; |
// set initial values and check first preamble nibble |
if (tx_cnt == 0) |
begin |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m) TX frame started with tx_en set!", $time); |
`endif |
if (mtxd_i == 4'h5) |
tx_preamble_ok <= 1; |
else |
tx_preamble_ok <= 0; |
tx_sfd_ok <= 0; |
tx_byte_aligned_ok <= 0; |
tx_len <= 0; |
tx_len_err <= 0; |
// tx_mem_addr_in <= 0; |
end |
|
// check preamble |
if ((tx_cnt > 0) && (tx_cnt <= 13)) |
begin |
if ((tx_preamble_ok != 1) || (mtxd_i != 4'h5)) |
tx_preamble_ok <= 0; |
end |
// check SFD |
if (tx_cnt == 14) |
begin |
`ifdef ETH_PHY_VERBOSE |
if (tx_preamble_ok == 1) |
$display( " (%0t)(%m) TX frame preamble OK!", $time); |
else |
$display( "*E (%0t)(%m) TX frame preamble NOT OK!", $time); |
`endif |
if (mtxd_i == 4'h5) |
tx_sfd_ok <= 1; |
else |
tx_sfd_ok <= 0; |
end |
if (tx_cnt == 15) |
begin |
if ((tx_sfd_ok != 1) || (mtxd_i != 4'hD)) |
tx_sfd_ok <= 0; |
end |
|
// control for storing addresses, type/length, data and FCS to TX memory |
if (tx_cnt > 15) |
begin |
if (tx_cnt == 16) |
begin |
`ifdef ETH_PHY_VERBOSE |
if (tx_sfd_ok == 1) |
$display( " (%0t)(%m) TX frame SFD OK!", $time); |
else |
$display( "*E (%0t)(%m) TX frame SFD NOT OK!", $time); |
`endif |
end |
|
if (tx_cnt[0] == 0) |
begin |
tx_mem_data_in[3:0] <= mtxd_i; // storing LSB nibble |
tx_byte_aligned_ok <= 0; // if transfer will stop after this, then there was drible nibble |
end |
else |
begin |
tx_mem[tx_mem_addr_in[21:0]] <= {mtxd_i, tx_mem_data_in[3:0]}; // storing data into tx memory |
tx_len <= tx_len + 1; // enlarge byte length counter |
tx_byte_aligned_ok <= 1; // if transfer will stop after this, then transfer is byte alligned |
tx_mem_addr_in <= tx_mem_addr_in + 1'b1; |
end |
|
if (mtxerr_i) |
tx_len_err <= tx_len; |
end |
end |
end |
|
// generating CARRIER SENSE for TX with or without delay |
if (!m_rst_n_i) |
begin |
mcrs_tx <= 0; |
mtxen_d1 <= 0; |
mtxen_d2 <= 0; |
mtxen_d3 <= 0; |
mtxen_d4 <= 0; |
mtxen_d5 <= 0; |
mtxen_d6 <= 0; |
end |
else |
begin |
mtxen_d1 <= mtxen_i; |
mtxen_d2 <= mtxen_d1; |
mtxen_d3 <= mtxen_d2; |
mtxen_d4 <= mtxen_d3; |
mtxen_d5 <= mtxen_d4; |
mtxen_d6 <= mtxen_d5; |
if (real_carrier_sense) |
mcrs_tx <= mtxen_d6; |
else |
mcrs_tx <= mtxen_i; |
end |
end |
|
`ifdef ETH_PHY_VERBOSE |
reg frame_started; |
|
initial |
begin |
frame_started = 0; |
end |
always@(posedge mtxen_i) |
begin |
frame_started <= 1; |
end |
always@(negedge mtxen_i) |
begin |
if (frame_started) |
begin |
$display( " (%0t)(%m) TX frame ended with tx_en reset!", $time); |
frame_started <= 0; |
end |
end |
|
always@(posedge mrxerr_o) |
begin |
$display( " (%0t)(%m) RX frame ERROR signal was set!", $time); |
end |
`endif |
|
////////////////////////////////////////////////////////////////////// |
// |
// Tasks for PHY <-> MAC transactions |
// |
////////////////////////////////////////////////////////////////////// |
|
initial |
begin |
tx_mem_addr_in = 0; |
end |
|
// setting the address of tx_mem, to set the starting point of tx packet |
task set_tx_mem_addr; |
input [31:0] tx_mem_address; |
begin |
#1 tx_mem_addr_in = tx_mem_address; |
end |
endtask // set_tx_mem_addr |
|
// storage memory for RX data to be transmited to MAC |
reg [7:0] rx_mem [0:4194303]; // 4194304 locations (22 address lines) of 8-bit data width |
|
// MAC RX signals |
reg [3:0] mrxd_o; |
reg mrxdv_o; |
reg mrxerr_o; |
|
initial |
begin |
mrxd_o = 0; |
mrxdv_o = 0; |
mrxerr_o = 0; |
mcrs_rx = 0; |
end |
|
task send_rx_packet; |
input [(8*8)-1:0] preamble_data; // preamble data to be sent - correct is 64'h0055_5555_5555_5555 |
input [3:0] preamble_len; // length of preamble in bytes - max is 4'h8, correct is 4'h7 |
input [7:0] sfd_data; // SFD data to be sent - correct is 8'hD5 |
input [31:0] start_addr; // start address |
input [31:0] len; // length of frame in Bytes (without preamble and SFD) |
input plus_drible_nibble; // if length is longer for one nibble |
integer rx_cnt; |
reg [31:0] rx_mem_addr_in; // address for reading from RX memory |
reg [7:0] rx_mem_data_out; // data for reading from RX memory |
begin |
@(posedge mrx_clk_o); |
// generating CARRIER SENSE for TX with or without delay |
if (real_carrier_sense) |
#1 mcrs_rx = 1; |
else |
#1 mcrs_rx = 0; |
@(posedge mrx_clk_o); |
#1 mcrs_rx = 1; |
#1 mrxdv_o = 1; |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m) RX frame started with rx_dv set!", $time); |
`endif |
// set initial rx memory address |
rx_mem_addr_in = start_addr; |
|
// send preamble |
for (rx_cnt = 0; (rx_cnt < (preamble_len << 1)) && (rx_cnt < 16); rx_cnt = rx_cnt + 1) |
begin |
#1 mrxd_o = preamble_data[3:0]; |
#1 preamble_data = preamble_data >> 4; |
@(posedge mrx_clk_o); |
end |
|
// send SFD |
for (rx_cnt = 0; rx_cnt < 2; rx_cnt = rx_cnt + 1) |
begin |
#1 mrxd_o = sfd_data[3:0]; |
#1 sfd_data = sfd_data >> 4; |
@(posedge mrx_clk_o); |
end |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m) RX frame preamble and SFD sent!", $time); |
`endif |
// send packet's addresses, type/length, data and FCS |
for (rx_cnt = 0; rx_cnt < len; rx_cnt = rx_cnt + 1) |
begin |
#1; |
rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]]; |
mrxd_o = rx_mem_data_out[3:0]; |
@(posedge mrx_clk_o); |
#1; |
mrxd_o = rx_mem_data_out[7:4]; |
rx_mem_addr_in = rx_mem_addr_in + 1; |
@(posedge mrx_clk_o); |
#1; |
end |
if (plus_drible_nibble) |
begin |
rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]]; |
mrxd_o = rx_mem_data_out[3:0]; |
@(posedge mrx_clk_o); |
end |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m) RX frame addresses, type/length, data and FCS sent!", $time); |
`endif |
#1 mcrs_rx = 0; |
#1 mrxdv_o = 0; |
@(posedge mrx_clk_o); |
`ifdef ETH_PHY_VERBOSE |
$display( " (%0t)(%m) RX frame ended with rx_dv reset!", $time); |
`endif |
end |
endtask // send_rx_packet |
|
|
|
task GetDataOnMRxD; |
input [15:0] Len; |
input [31:0] TransferType; |
integer tt; |
|
begin |
@ (posedge mrx_clk_o); |
#1 mrxdv_o=1'b1; |
|
for(tt=0; tt<15; tt=tt+1) |
begin |
mrxd_o=4'h5; // preamble |
@ (posedge mrx_clk_o); |
#1; |
end |
|
mrxd_o=4'hd; // SFD |
|
for(tt=1; tt<(Len+1); tt=tt+1) |
begin |
@ (posedge mrx_clk_o); |
#1; |
if(TransferType == `UNICAST_XFR && tt == 1) |
mrxd_o = 4'h0; // Unicast transfer |
else if(TransferType == `BROADCAST_XFR && tt < 7) |
mrxd_o = 4'hf; |
else |
mrxd_o = tt[3:0]; // Multicast transfer |
|
@ (posedge mrx_clk_o); |
#1; |
|
if(TransferType == `BROADCAST_XFR && tt == 6) |
mrxd_o = 4'he; |
else |
|
if(TransferType == `BROADCAST_XFR && tt < 7) |
mrxd_o = 4'hf; |
else |
mrxd_o = tt[7:4]; |
end |
|
@ (posedge mrx_clk_o); |
#1; |
mrxdv_o = 1'b0; |
end |
endtask // GetDataOnMRxD |
|
|
////////////////////////////////////////////////////////////////////// |
// |
// Tastks for controling PHY statuses and rx error |
// |
////////////////////////////////////////////////////////////////////// |
|
// Link control tasks |
task link_up_down; |
input test_op; |
begin |
#1 status_bit6_0[2] = test_op; // 1 - link up; 0 - link down |
end |
endtask |
|
// RX error |
task rx_err; |
input test_op; |
begin |
#1 mrxerr_o = test_op; // 1 - RX error set; 0 - RX error reset |
end |
endtask |
|
////////////////////////////////////////////////////////////////////// |
// |
// Tastks for controling PHY carrier sense and collision |
// |
////////////////////////////////////////////////////////////////////// |
|
// Collision |
task collision; |
input test_op; |
begin |
#1 task_mcoll = test_op; |
end |
endtask |
|
// Carrier sense |
task carrier_sense; |
input test_op; |
begin |
#1 task_mcrs = test_op; |
end |
endtask |
|
// Carrier sense lost - higher priority than Carrier sense task |
task carrier_sense_lost; |
input test_op; |
begin |
#1 task_mcrs_lost = test_op; |
end |
endtask |
|
// No collision detection in half duplex |
task no_collision_hd_detect; |
input test_op; |
begin |
#1 no_collision_in_half_duplex = test_op; |
end |
endtask |
|
// Collision detection in full duplex also |
task collision_fd_detect; |
input test_op; |
begin |
#1 collision_in_full_duplex = test_op; |
end |
endtask |
|
// No carrier sense detection at TX in half duplex |
task no_carrier_sense_tx_hd_detect; |
input test_op; |
begin |
#1 no_carrier_sense_in_tx_half_duplex = test_op; |
end |
endtask |
|
// No carrier sense detection at RX in half duplex |
task no_carrier_sense_rx_hd_detect; |
input test_op; |
begin |
#1 no_carrier_sense_in_rx_half_duplex = test_op; |
end |
endtask |
|
// Carrier sense detection at TX in full duplex also |
task carrier_sense_tx_fd_detect; |
input test_op; |
begin |
#1 carrier_sense_in_tx_full_duplex = test_op; |
end |
endtask |
|
// No carrier sense detection at RX in full duplex |
task no_carrier_sense_rx_fd_detect; |
input test_op; |
begin |
#1 no_carrier_sense_in_rx_full_duplex = test_op; |
end |
endtask |
|
// Set real delay on carrier sense signal (and therefor collision signal) |
task carrier_sense_real_delay; |
input test_op; |
begin |
#1 real_carrier_sense = test_op; |
end |
endtask |
|
////////////////////////////////////////////////////////////////////// |
// |
// Tastks for controling PHY management test operation |
// |
////////////////////////////////////////////////////////////////////// |
|
// Set registers to test operation and respond to all phy addresses |
task test_regs; |
input test_op; |
begin |
#1 registers_addr_data_test_operation = test_op; |
respond_to_all_phy_addr = test_op; |
end |
endtask |
|
// Clears data memory for testing the MII |
task clear_test_regs; |
integer i; |
begin |
for (i = 0; i < 32; i = i + 1) |
begin |
#1 data_mem[i] = 16'h0; |
end |
end |
endtask |
|
// Accept frames with preamble suppresed |
task preamble_suppresed; |
input test_op; |
begin |
#1 no_preamble = test_op; |
md_transfer_cnt_reset = 1'b1; |
@(posedge mdc_i); |
#1 md_transfer_cnt_reset = 1'b0; |
end |
endtask |
|
|
|
// Sideband signals for external SMII converter --jb |
assign link_o = status_bit6_0[2]; |
|
assign speed_o = eth_speed; |
|
assign duplex_o = control_bit8_0[8]; |
|
|
|
|
endmodule |
|
/openrisc/trunk/orpsocv2/bench/verilog/orpsoc_testbench_defines.v
43,6 → 43,11
`define CLOCK_PERIOD 40 |
`define CLOCK_RATE 25000000 |
|
// Period for 125MHz clock is 8ns |
`define ETH_CLK_PERIOD 8 |
|
|
|
// The ORPSoC tests makefile should generate the test_define.v file in |
// the sim/run directory. |
`ifdef TEST_DEFINE_FILE |
/openrisc/trunk/orpsocv2/bench/verilog/smii_phy.v
0,0 → 1,468
////////////////////////////////////////////////////////////////////// |
//// //// |
//// SMII Receiver/Decoder (usually at PHY end) //// |
//// //// |
//// Description //// |
//// Low pin count serial MII ethernet interface //// |
//// //// |
//// To Do: //// |
//// - //// |
//// //// |
//// Author(s): //// |
//// - Michael Unneback, unneback@opencores.org //// |
//// ORSoC AB michael.unneback@orsoc.se //// |
//// - Julius Baxter, jb@orsoc.se //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
module smii_phy |
( |
// SMII |
input smii_tx, |
input smii_sync, |
output smii_rx, |
|
// MII |
// TX |
/* ALL I/Os swapped compared to SMII on MAC end MAC - jb */ |
output reg [3:0] ethphy_mii_tx_d, |
output reg ethphy_mii_tx_en, |
output reg ethphy_mii_tx_err, |
input ethphy_mii_tx_clk, |
// RX |
input [3:0] ethphy_mii_rx_d, |
input ethphy_mii_rx_dv, |
input ethphy_mii_rx_err, |
input ethphy_mii_rx_clk, |
input ethphy_mii_mcoll, |
input ethphy_mii_crs, |
|
input fast_ethernet, |
input duplex, |
input link, |
|
// internal |
//input [10:1] state, |
// clock and reset |
input clk, /* Global reference clock for both SMII modules */ |
input rst_n |
); |
|
reg [3:0] rx_tmp; |
|
reg jabber = 0; |
|
reg mtx_clk_tmp, mrx_clk_tmp; |
|
reg [3:0] tx_cnt; |
reg [3:0] rx_cnt; |
|
|
/**************************************************************************/ |
/* Counters */ |
/**************************************************************************/ |
|
/* Generate the state counter, based on incoming sync signal */ |
/* 10-bit shift register, indicating where we are */ |
reg [10:1] state_shiftreg; |
|
always @(posedge clk) |
begin |
if (!rst_n) |
begin |
state_shiftreg <= 10'b0000000001; |
end |
else |
begin |
if (smii_sync) /* sync signal from MAC */ |
state_shiftreg <= 10'b0000000010; |
else if (state_shiftreg[10]) |
state_shiftreg <= 10'b0000000001; |
else |
state_shiftreg[10:2] <= state_shiftreg[9:1]; |
end // else: !if(!rst_n) |
end // always @ (posedge clk) |
|
|
/* counter from 0 to 9, counting the 10-bit segments we'll transmit |
via SMII*/ |
reg [3:0] segment_ctr; |
|
always @(posedge clk) |
begin |
if(!rst_n) |
segment_ctr <= 4'h0; |
else |
begin |
if(fast_ethernet) /* If using 100Mbs, then each segment is |
different, we don't count the repeats */ |
segment_ctr <= 4'h0; |
else if (state_shiftreg[10]) |
if (segment_ctr == 4'h9) /* Wrap */ |
segment_ctr <= 4'h0; |
else /* Increment */ |
segment_ctr <= segment_ctr + 1'b1; |
end |
end |
|
/**************************************************************************/ |
/* RX path logic PHY->(MII->SMII)->MAC */ |
/**************************************************************************/ |
|
reg rx_nibble_sel, rx_byte_valid; |
reg [7:0] rx_data_byte_rx_clk; |
|
/* Receive the RX data from the PHY and serialise it */ |
/* If RX data valid goes high, then it's the beginning of a |
proper data segment*/ |
always @(posedge ethphy_mii_rx_clk or negedge rst_n) |
begin |
if(!rst_n) |
begin |
rx_nibble_sel <= 0; /* start with low nibble receiving */ |
rx_data_byte_rx_clk <= 0; |
rx_byte_valid <= 0; |
end |
else |
begin |
/* Half way through, and at the end of each 10-bit section |
and whenever we should load a new segment (each time for |
fast ethernet, else once every 10 times; whenever segment_ctr |
is 0)*/ |
//if ((state_shiftreg[6] | state_shiftreg[10]) & (segment_ctr==4'h0)) |
// begin |
/* Alternate the nibble we're selecting when RX_dv */ |
if(!ethphy_mii_rx_dv) /* data on rx line is not valid */ |
rx_nibble_sel <= 0; |
else |
rx_nibble_sel <= ~rx_nibble_sel; |
|
if (!ethphy_mii_rx_dv & !rx_nibble_sel) |
rx_byte_valid <= 0; |
else if (rx_nibble_sel) /* sampled high nibble, byte OK*/ |
rx_byte_valid <= 1; |
|
if (ethphy_mii_rx_dv & !rx_nibble_sel) |
/* Sampling low nibble */ |
rx_data_byte_rx_clk[3:0] <= ethphy_mii_rx_d; |
else if (ethphy_mii_rx_dv & rx_nibble_sel) |
/* Sample high nibble */ |
rx_data_byte_rx_clk[7:4] <= ethphy_mii_rx_d; |
|
//end // if ((state_shiftreg[4] | state_shiftreg[9]) & (segment_ctr==4'h0)) |
end // else: !if(!rst_n) |
end // always @ (posedge clk)' |
|
/* SMII domain RX signals */ |
reg [7:0] rx_data_byte; |
reg rx_line_rx_dv; /* Reg for second bit of SMII RX sequence, RX_DV */ |
|
/* A wire hooked up from bit 0 with the last byte of the state counter/shiftreg */ |
wire [7:0] state_shiftreg_top_byte; |
assign state_shiftreg_top_byte[7:0] = state_shiftreg[10:3]; |
|
/* Move RX's DV and data into SMII clk domain */ |
always @(posedge clk) |
begin |
if(!rst_n) |
begin |
rx_line_rx_dv <= 0; |
end |
else |
begin |
/* When we're at the beginning of a new 10-bit sequence and |
the beginning of the 10-segment loop load the valid bit */ |
if(state_shiftreg[1] & (segment_ctr==4'h0)) |
begin |
rx_line_rx_dv <= rx_byte_valid; |
rx_data_byte <= rx_data_byte_rx_clk; |
end |
end // else: !if(!rst_n) |
end // always @ (posedge clk) |
|
/* Assign the rx line out */ |
assign smii_rx = state_shiftreg[1] ? ethphy_mii_crs : /* 1st bit is MII CRS */ |
/* next is RX_DV bit */ |
state_shiftreg[2] ? ((rx_byte_valid & (segment_ctr==4'h0)) | |
rx_line_rx_dv) : |
/* Depending on RX_DV, output the status byte or data byte */ |
rx_line_rx_dv ? |(state_shiftreg_top_byte & rx_data_byte) : |
/* Output status byte */ |
|(state_shiftreg_top_byte & |
/* Status seq.: CRS, DV, ER, Speed, Duplex, Link, Jabber, UPV, FCD, 1 */ |
{1'b1,1'b0,1'b1,jabber,link,duplex,fast_ethernet,ethphy_mii_rx_err}); |
|
/**************************************************************************/ |
/* TX path logic MAC->(SMII->MII)->PHY */ |
/**************************************************************************/ |
|
/* We ignore the data when TX_EN bit is not high - |
it's only used in MAC to MAC comms*/ |
|
|
/* Register the sequence appropriately as it comes in */ |
reg tx_er_seqbit_scratch; |
reg tx_en_seqbit_scratch; |
reg [7:0] tx_data_byte_scratch; |
|
reg [1:0] tx_byte_to_phy; /* PHY sourced TX_CLK domain */ |
|
wire tx_fifo_empty; |
wire tx_fifo_full; |
wire [7:0] tx_fifo_q_dat; |
wire tx_fifo_q_err; |
reg tx_fifo_pop; |
|
|
/* Signal to tell us an appropriate time to copy the values out of the |
temp regs we put the incoming TX line into when we've received a |
sequence off the SMII TX line that has TX_EN high */ |
wire tx_seqbits_copy; |
assign tx_seqbits_copy = ((((!fast_ethernet) & (segment_ctr==4'h1)) | |
((fast_ethernet) & (state_shiftreg[1]))) |
& tx_en_seqbit_scratch); |
|
always @(posedge clk) |
begin |
if (!rst_n) |
begin |
tx_er_seqbit_scratch <= 0; |
tx_en_seqbit_scratch <= 0; |
tx_data_byte_scratch <= 0; |
end |
else |
begin |
if (segment_ctr==4'h0) |
begin |
if(state_shiftreg[1]) |
tx_er_seqbit_scratch <= smii_tx; |
|
if(state_shiftreg[2]) |
tx_en_seqbit_scratch <= smii_tx; |
|
/* Preserve all but current bit of interest, as indicated |
by state vector bit (reversed, becuase we get MSbit |
first) and OR in the current smii_tx line value at this |
position*/ |
if((|state_shiftreg[10:3]) & tx_en_seqbit_scratch) |
tx_data_byte_scratch <= (tx_data_byte_scratch & ~state_shiftreg_top_byte) | |
({8{smii_tx}} & state_shiftreg_top_byte); |
|
end // if (segment_ctr==4'h0) |
|
/* If we've just received a sequence with TX_EN then put |
these values in the proper regs at the appropriate time, |
depending on the speed , ready for transmission to the PHY */ |
if (tx_seqbits_copy) |
begin |
|
/* Now clear the tx_en scratch bit so we don't do |
this again */ |
tx_en_seqbit_scratch <= 0; |
|
end // if (tx_seqbits_copy) |
end |
end // always @ (posedge clk) |
|
|
/* In the event we have a valid byte frame then get it to the |
PHY as quickly as possible - this is TX_CLK domain */ |
always @(posedge ethphy_mii_tx_clk or negedge rst_n) |
begin |
if(!rst_n) |
begin |
tx_byte_to_phy <= 0; |
tx_fifo_pop <= 1'b0; |
/* Output MII registers to the PHY */ |
ethphy_mii_tx_d <= 0; |
ethphy_mii_tx_en <= 0; |
ethphy_mii_tx_err <= 0; |
|
end |
else |
begin |
|
if(!tx_fifo_empty) /* A byte ready to go to the MAC */ |
begin |
if(tx_byte_to_phy == 2'b00) |
begin |
/* Pop */ |
tx_fifo_pop <= 1; |
tx_byte_to_phy <= 2'b01; |
end |
end |
|
/* FIFO control loop */ |
if (tx_byte_to_phy == 2'b01) /* Output bits 3-0 (bottom nibble ) */ |
begin |
ethphy_mii_tx_d <= tx_fifo_q_dat[3:0]; |
ethphy_mii_tx_en <= 1; |
ethphy_mii_tx_err <= tx_fifo_q_err; |
tx_fifo_pop <= 0; |
tx_byte_to_phy <= 2'b10; |
end |
else if (tx_byte_to_phy == 2'b10) /* Output bits 7-4 (top nibble) */ |
begin |
ethphy_mii_tx_d <= tx_fifo_q_dat[7:4]; |
if(!tx_fifo_empty) /* Check if more in FIFO */ |
begin |
tx_fifo_pop <= 1; /* Pop again */ |
tx_byte_to_phy <= 2'b01; |
end |
else /* Finish up */ |
begin |
tx_byte_to_phy <= 2'b11; |
end |
end |
else if (tx_byte_to_phy == 2'b11) /* De-assert TX_EN */ |
begin |
ethphy_mii_tx_en <= 0; |
tx_byte_to_phy <= 2'b00; |
end |
end // else: !if(!rst_n) |
end // always @ (posedge ethphy_mii_tx_clk or negedge rst_n) |
|
/* A fifo, storing TX bytes coming from the SMII interface */ |
generic_fifo #(9, 64) tx_fifo |
( |
// Outputs |
.psh_full (tx_fifo_full), |
.pop_q ({tx_fifo_q_err,tx_fifo_q_dat}), |
.pop_empty (tx_fifo_empty), |
// Inputs |
.async_rst_n (rst_n), |
.psh_clk (clk), |
.psh_we (tx_seqbits_copy), |
.psh_d ({tx_er_seqbit_scratch,tx_data_byte_scratch}), |
.pop_clk (), |
.pop_re (tx_fifo_pop)); |
|
|
//assign mcoll = mcrs & mtxen; |
|
endmodule // smii_top |
|
|
|
/* Generic fifo - this is bad, should probably be done some other way */ |
module generic_fifo (async_rst_n, psh_clk, psh_we, psh_d, psh_full, pop_clk, pop_re, pop_q, pop_empty); |
|
parameter dw = 8; |
parameter size = 64; |
|
/* Asynch. reset, active low */ |
input async_rst_n; |
|
/* Push side signals */ |
input psh_clk; |
input psh_we; |
input [dw-1:0] psh_d; |
output psh_full; |
|
/* Pop side signals */ |
input pop_clk; |
input pop_re; |
output reg [dw-1:0] pop_q; |
output pop_empty; |
|
/* Actual FIFO memory */ |
reg [dw-1:0] fifo_mem [0:size-1]; |
|
/* Poorly defined pointer logic -- will need to be changed if the size paramter is too big - Verilog needs some log base 2 thing */ |
reg [7:0] ptr; /* Only 8 bits, so max size of 255 of fifo! */ |
|
|
/* FIFO full signal for push side */ |
assign psh_full = (ptr == size-1) ? 1 : 0; |
/* FIFO empty signal for pop side */ |
assign pop_empty = (ptr == 0) ? 1 : 0; |
|
|
/* This will work if pushing side is a lot faster than popping side */ |
reg pop_re_psh_clk; |
wire pop_re_risingedge_psh_clk; /* Signal to help push side see when |
there's been a pop_re rising edge, |
sampled on push clock */ |
|
/* Detect edge of signal in pop domain for psh domain */ |
assign pop_re_risingedge_psh_clk = (pop_re & !pop_re_psh_clk); |
|
|
integer i; |
always @(posedge psh_clk or negedge async_rst_n) |
begin |
if (!async_rst_n) |
begin |
ptr <= 0; |
|
|
for (i=0;i<size;i=i+1) fifo_mem[i] <= 0; |
|
pop_re_psh_clk <= 0; |
|
end |
else |
begin |
|
pop_re_psh_clk <= pop_re; /* Register pop command in psh domain */ |
|
if (psh_we) /* Push into FIFO */ |
begin |
if (!pop_re_psh_clk) /* If no pop at the same time, simple */ |
begin |
fifo_mem[ptr] <= psh_d; |
ptr <= ptr + 1'b1; |
end |
else /* Pop at same edge */ |
begin |
/* Shift fifo contents */ |
for(i=1;i<size;i=i+1) |
fifo_mem[i-1] <= fifo_mem[i]; |
fifo_mem[size-1] <= 0; |
pop_q <= fifo_mem[0]; |
fifo_mem[ptr] <= psh_d; |
/* ptr remains unchanged */ |
end // else: !if!(pop_re_psh_clk) |
end // if (psh_we) |
else /* No push, see if there's a pop */ |
begin |
if (pop_re_risingedge_psh_clk) /* Detected a pop */ |
begin |
for(i=1;i<size;i=i+1) |
fifo_mem[i-1] <= fifo_mem[i]; |
fifo_mem[size-1] <= 0; |
pop_q <= fifo_mem[0]; |
ptr <= ptr - 1'b1; |
end |
end // else: !if(psh_we) |
end // else: !if(!async_rst_n) |
end // always @ (posedge psh_clk or negedge async_rst_n) |
|
|
endmodule // generic_fifo |
|
|
/openrisc/trunk/orpsocv2/bench/verilog/orpsoc_testbench.v
149,9 → 149,9
`ifdef USE_ETHERNET |
// Ethernet ports |
.eth_md_pad_io (eth_md_io[1:1]), |
.eth_mdc_pad_o (eth_mdc_o[1:1]), |
.eth_sync_pad_o (eth_sync_o[1:1]), |
.eth_tx_pad_o (eth_tx_o[1:1]), |
.eth_mdc_pad_o (eth_mdc_o[1:1]), |
.eth_rx_pad_i (eth_rx_i[1:1]), |
.eth_clk_pad_i (eth_clk_i), |
`endif // `ifdef USE_ETHERNET |
225,7 → 225,90
|
`endif // !`ifdef USE_SDRAM |
|
`ifdef USE_ETHERNET |
|
reg eth_clk; |
initial |
eth_clk <= 0; |
|
always |
#(8/2) eth_clk <= ~eth_clk; // 125 Mhz clock |
|
assign eth_clk_i = eth_clk; |
|
|
|
wire [3:0] ethphy_mii_tx_d; |
wire ethphy_mii_tx_en; |
wire ethphy_mii_tx_err; |
wire mcoll_o; |
wire mcrs_o; |
wire md_io; |
wire mrx_clk_o; |
wire [3:0] mrxd_o; |
wire mrxdv_o; |
wire mrxerr_o; |
wire mtx_clk_o; |
wire smii_rx; |
wire fast_ethernet, duplex, link; |
|
/* Converts SMII back to MII */ |
smii_phy smii_phyend |
( |
// Outputs |
.smii_rx (eth_rx_i[1:1]), /* SMII RX */ |
.ethphy_mii_tx_d (ethphy_mii_tx_d[3:0]), /* MII TX */ |
.ethphy_mii_tx_en (ethphy_mii_tx_en), /* MII TX */ |
.ethphy_mii_tx_err (ethphy_mii_tx_err), /* MII TX */ |
// Inputs |
.smii_tx (eth_tx_o[1:1]), /* SMII TX */ |
.smii_sync (eth_sync_o[1:1]), /* SMII SYNC */ |
.ethphy_mii_tx_clk (mtx_clk_o), /* MII TX */ |
|
.ethphy_mii_rx_d (mrxd_o[3:0]), /* MII RX */ |
.ethphy_mii_rx_dv (mrxdv_o), /* MII RX */ |
.ethphy_mii_rx_err (mrxerr_o), /* MII RX */ |
.ethphy_mii_rx_clk (mrx_clk_o), /* MII RX */ |
|
.ethphy_mii_mcoll (), |
.ethphy_mii_crs (mcrs_o), |
.fast_ethernet (fast_ethernet), |
.duplex (duplex), |
.link (link), |
.clk (eth_clk_i), |
.rst_n (rst_i)); |
|
`ifdef ENABLE_ETH_STIM |
/* Generates an RX packet */ |
`include "eth_stim.v" |
`endif |
|
eth_phy eth_phy0 |
( |
// Outputs |
.mtx_clk_o (mtx_clk_o), |
.mrx_clk_o (mrx_clk_o), |
.mrxd_o (mrxd_o[3:0]), |
.mrxdv_o (mrxdv_o), |
.mrxerr_o (mrxerr_o), |
.mcoll_o (mcoll_o), |
.mcrs_o (mcrs_o), |
// Sideband outputs for smii converter --jb |
.link_o (link), |
.speed_o (fast_ethernet), |
.duplex_o (duplex), |
// Inouts |
.md_io (eth_md_io[1:1]), |
// Inputs |
.m_rst_n_i (rst_i), |
.mtxd_i (ethphy_mii_tx_d[3:0]), |
.mtxen_i (ethphy_mii_tx_en), |
.mtxerr_i (ethphy_mii_tx_err), |
.mdc_i (eth_mdc_o[1:1])); |
|
`endif // `ifdef USE_ETHERNET |
|
|
initial |
begin |
$display("\nStarting RTL simulation of %s test\n", `TEST_NAME_STRING); |
/openrisc/trunk/orpsocv2/bench/verilog/mt48lc16m16a2.v
37,7 → 37,7
* |
**************************************************************************/ |
|
`timescale 1ns / 1ps |
`include "timescale.v" |
|
module mt48lc16m16a2 (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm); |
|
/openrisc/trunk/orpsocv2/rtl/verilog/components/smii/smii_sync.v
43,7 → 43,7
// SMII sync |
output sync, |
// internal |
output reg [10:1] state, // Changed for verilator -- jb |
output reg [10:1] state, |
// clock amd reset |
input clk, |
input rst |
52,7 → 52,7
// sync shall go high every 10:th cycle |
always @ (posedge clk or posedge rst) |
if (rst) |
state <= 10'b1000000000; |
state <= 10'b0000000001; |
else |
state <= {state[9:1],state[10]}; |
|
/openrisc/trunk/orpsocv2/rtl/verilog/components/smii/smii_txrx.v
66,7 → 66,7
output reg link, |
`endif |
// internal |
input [10:1] state, // Change bit size declaration order, was [1:10], not verilator compatible: %Error: Unsupported: MSB < LSB of bit range: 1<10 |
input [10:1] state, |
// clock and reset |
input clk, |
input rst |
112,14 → 112,27
|
///////////////////////////////////////////////// |
// Transmit |
|
/* Timing scheme: |
On the first clock of segment 0 (so each segment when 100Mb/s, |
fast ethernet, or every 10 segments for 10Mb/s ethernet) we |
deteremine if that segment is data or not, depending on what is |
in the tx_data_reg_valid register. If the MAC wants to transmit |
something, we overwrite the previously sent values when they're |
no longer needed. Once the first nibble is sent, we can then |
overwrite it, and same for the second - so we generate the TX |
clock when state is 5, and sample the new nibble on the next |
clock, same with the second nibble, that is clocked when state |
is 9, and sampled when it is 10, so it gets overwritten when |
we've finished putting it on the serial line.*/ |
|
always @ (posedge clk or posedge rst) |
if (rst) |
mtx_clk_tmp <= 1'b0; |
else |
if ((state[10] | state[5]) & (tx_cnt == 4'd0)) |
if ((state[5] | state[9]) & (tx_cnt == 4'd0)) |
mtx_clk_tmp <= 1'b1; |
else if (state[2] | state[7]) |
else if (state[6] | state[10]) |
mtx_clk_tmp <= 1'b0; |
|
`ifdef ACTEL |
141,26 → 154,32
a0 <= 1'b0; |
end |
else |
if ((state[4] | state[9]) & (tx_cnt == 4'd0)) |
if ((state[6] | state[10]) & (tx_cnt == 4'd0)) |
begin |
/* Toggale a0 when MII TX_EN goes high */ |
if (!mtxen) |
a0 <= 1'b0; |
else |
a0 <= ~a0; |
|
/* byte will be valid when MII TX_EN |
is high from the MAC */ |
if (!mtxen & !a0) |
tx_data_reg_valid <= 1'b0; |
else if (a0) |
tx_data_reg_valid <= 1'b1; |
|
/* Sample the nibble */ |
if (mtxen & !a0) |
//tx_data_reg[0:3] <= {mtxd[0],mtxd[1],mtxd[2],mtxd[3]}; |
tx_data_reg[3:0] <= {mtxd[3],mtxd[2],mtxd[1],mtxd[0]}; // Changed for verilator -- jb |
tx_data_reg[3:0] <= mtxd; |
else if (mtxen & a0) |
//tx_data_reg[4:7] <= {mtxd[0],mtxd[1],mtxd[2],mtxd[3]}; |
tx_data_reg[7:4] <= {mtxd[3],mtxd[2],mtxd[1],mtxd[0]}; // Changed for verilator -- jb |
tx_data_reg[7:4] <= mtxd; |
|
end // if ((state[4] | state[9]) & (tx_cnt == 4'd0)) |
|
|
// state flag |
/* Determine if we output a data byte or the inter-frame sequence |
with status information */ |
always @ (posedge clk or posedge rst) |
if (rst) |
state_data <= 1'b0; |
167,11 → 186,18
else |
if (state[1] & (tx_cnt == 4'd0)) |
state_data <= tx_data_reg_valid; |
|
|
/* A wire hooked up from bit 0 with the last byte of the state counter/shiftreg */ |
wire [7:0] state_data_byte; |
assign state_data_byte[7:0] = state[10:3]; |
|
/* Assign the SMII TX wire */ |
/* First bit always TX_ERR, then depending on the next bit, TX_EN, output |
either the inter-frame status byte or a data byte */ |
assign tx = state[1] ? mtxerr : |
state[2] ? ((tx_data_reg_valid & (tx_cnt == 4'd0)) | state_data) : |
state_data ? |(state[10:2] & tx_data_reg) : // changed bit select order to 10:2 -- jb |
|(state[10:2] & {mtxerr,speed,duplex,link,jabber,3'b111}); // changed bit select order to 10:2 -- jb |
state_data ? |(state_data_byte & tx_data_reg) : |
|(state_data_byte & {3'b111,jabber,link,duplex,speed,mtxerr}); |
|
///////////////////////////////////////////////// |
// Receive |
199,20 → 225,33
end |
else |
begin |
/* Continually shift rx into rx_tmp bit 2, and shift rx_tmp along */ |
rx_tmp[2:0] <= {rx,rx_tmp[2:1]}; |
|
/* We appear to be beginning our sampling when state bit 3 is set */ |
if (state[3]) |
mcrs <= rx; |
|
/* rx_tmp[3] is used as the RX_DV bit*/ |
if (state[4]) |
rx_tmp[3] <= rx; |
if (rx_tmp[3]) //rxdv |
|
if (rx_tmp[3]) //If data byte valid, and when we've got the first nibble, output it */ |
begin |
/* At this stage we've got the first 3 bits of the bottom |
nibble - we can sample the rx line directly to get the |
4th, and we'll also indicate that this byte is valid by |
raising the MII RX data valid (dv) line. */ |
if (state[8]) |
{mrxdv,mrxd} <= #1 {rx_tmp[3],rx,rx_tmp[2:0]}; |
/* High nibble, we have 3 bits and the final one is on |
the line - put it out for the MAC to read.*/ |
else if (state[2]) |
mrxd <= #1 {rx,rx_tmp[2:0]}; |
end |
else |
begin |
/* Not a data byte, it's the inter-frame status byte */ |
if (state[5]) |
mrxerr <= #1 rx; |
if (state[6]) |
248,6 → 287,7
assign #1 mrx_clk = mrx_clk_tmp; |
`endif |
|
assign mcoll = mcrs & mtxen; |
assign mcoll = mcrs & mtxen & !duplex; |
|
|
endmodule // smii_top |
/openrisc/trunk/orpsocv2/rtl/verilog/components/or1200r2/or1200_sprs.v
155,9 → 155,9
input [width-1:0] dat_i; // SPR write data |
input [`OR1200_ALUOP_WIDTH-1:0] alu_op; // ALU operation |
input [`OR1200_BRANCHOP_WIDTH-1:0] branch_op; // Branch operation |
input [width-1:0] epcr; // EPCR0 |
input [width-1:0] eear; // EEAR0 |
input [`OR1200_SR_WIDTH-1:0] esr; // ESR0 |
input [width-1:0] epcr /* verilator public */; // EPCR0 |
input [width-1:0] eear /* verilator public */; // EEAR0 |
input [`OR1200_SR_WIDTH-1:0] esr /* verilator public */; // ESR0 |
input except_started; // Exception was started |
output [width-1:0] to_wbmux; // For l.mfspr |
output epcr_we; // EPCR0 write enable |
166,7 → 166,7
output pc_we; // PC write enable |
output sr_we; // Write enable SR |
output [`OR1200_SR_WIDTH-1:0] to_sr; // Data to SR |
output [`OR1200_SR_WIDTH-1:0] sr; // SR |
output [`OR1200_SR_WIDTH-1:0] sr /* verilator public */; // SR |
input [31:0] spr_dat_cfgr; // Data from CFGR |
input [31:0] spr_dat_rf; // Data from RF |
input [31:0] spr_dat_npc; // Data from NPC |
404,6 → 404,33
always @(sr_reg or sr_reg_bit_eph_muxed) |
sr = {sr_reg[`OR1200_SR_WIDTH-1], sr_reg_bit_eph_muxed, sr_reg[`OR1200_SR_WIDTH-3:0]}; |
|
`ifdef verilator |
// Function to access various sprs (for Verilator). Have to hide this from |
// simulator, since functions with no inputs are not allowed in IEEE |
// 1364-2001. |
|
function [31:0] get_sr; |
// verilator public |
get_sr = sr; |
endfunction // get_sr |
|
function [31:0] get_epcr; |
// verilator public |
get_epcr = epcr; |
endfunction // get_epcr |
|
function [31:0] get_eear; |
// verilator public |
get_eear = eear; |
endfunction // get_eear |
|
function [31:0] get_esr; |
// verilator public |
get_esr = esr; |
endfunction // get_esr |
|
`endif |
|
// |
// MTSPR/MFSPR interface |
// |
/openrisc/trunk/orpsocv2/rtl/verilog/components/or1200r2/or1200_except.v
228,7 → 228,7
reg [`OR1200_EXCEPT_WIDTH-1:0] except_type; |
reg [31:0] id_pc; |
reg [31:0] ex_pc; |
reg [31:0] wb_pc; |
reg [31:0] wb_pc /* verilator public */; |
reg [31:0] epcr; |
reg [31:0] eear; |
reg [`OR1200_SR_WIDTH-1:0] esr; |
237,12 → 237,12
reg [`OR1200_EXCEPTFSM_WIDTH-1:0] state; |
reg extend_flush; |
reg extend_flush_last; |
reg ex_dslot; |
reg ex_dslot /* verilator public */; |
reg delayed1_ex_dslot; |
reg delayed2_ex_dslot; |
wire except_started; |
wire [12:0] except_trig; |
wire except_flushpipe; |
wire except_flushpipe /* verilator public */; |
reg [2:0] delayed_iee; |
reg [2:0] delayed_tee; |
wire int_pending; |
294,6 → 294,18
sig_syscall & du_dsr[`OR1200_DU_DSR_SCE] & ~ex_freeze |
}; |
|
`ifdef verilator |
// Function to access wb_pc (for Verilator). Have to hide this from |
// simulator, since functions with no inputs are not allowed in IEEE |
// 1364-2001. |
function [31:0] get_wb_pc; |
// verilator public |
get_wb_pc = wb_pc; |
endfunction // get_wb_pc |
|
`endif |
|
|
// |
// PC and Exception flags pipelines |
// |
/openrisc/trunk/orpsocv2/rtl/verilog/components/or1200r2/or1200_dpram.v
86,7 → 86,7
// |
// Generic RAM's registers and wires |
// |
reg [dw-1:0] mem [(1<<aw)-1:0]; // RAM content |
reg [dw-1:0] mem [(1<<aw)-1:0] /* verilator public */; // RAM content |
reg [aw-1:0] addr_a_reg; // RAM address registered |
|
|
96,22 → 96,7
// verilator public |
input [aw-1:0] gpr_no; |
|
get_gpr = { mem[gpr_no*32 + 31], mem[gpr_no*32 + 30], |
mem[gpr_no*32 + 29], mem[gpr_no*32 + 28], |
mem[gpr_no*32 + 27], mem[gpr_no*32 + 26], |
mem[gpr_no*32 + 25], mem[gpr_no*32 + 24], |
mem[gpr_no*32 + 23], mem[gpr_no*32 + 22], |
mem[gpr_no*32 + 21], mem[gpr_no*32 + 20], |
mem[gpr_no*32 + 19], mem[gpr_no*32 + 18], |
mem[gpr_no*32 + 17], mem[gpr_no*32 + 16], |
mem[gpr_no*32 + 15], mem[gpr_no*32 + 14], |
mem[gpr_no*32 + 13], mem[gpr_no*32 + 12], |
mem[gpr_no*32 + 11], mem[gpr_no*32 + 10], |
mem[gpr_no*32 + 9], mem[gpr_no*32 + 8], |
mem[gpr_no*32 + 7], mem[gpr_no*32 + 6], |
mem[gpr_no*32 + 5], mem[gpr_no*32 + 4], |
mem[gpr_no*32 + 3], mem[gpr_no*32 + 2], |
mem[gpr_no*32 + 1], mem[gpr_no*32 + 0] }; |
get_gpr = mem[gpr_no]; |
|
endfunction // get_gpr |
|
/openrisc/trunk/orpsocv2/rtl/verilog/components/uart16550/uart_top.v
141,204 → 141,204
`include "uart_defines.v" |
|
module uart_top ( |
wb_clk_i, |
|
// Wishbone signals |
wb_rst_i, wb_adr_i, wb_dat_i, wb_dat_o, wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_sel_i, |
int_o, // interrupt request |
wb_clk_i, |
|
// Wishbone signals |
wb_rst_i, wb_adr_i, wb_dat_i, wb_dat_o, wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_sel_i, |
int_o, // interrupt request |
|
// UART signals |
// serial input/output |
stx_pad_o, srx_pad_i, |
// UART signals |
// serial input/output |
stx_pad_o, srx_pad_i, |
|
// modem signals |
rts_pad_o, cts_pad_i, dtr_pad_o, dsr_pad_i, ri_pad_i, dcd_pad_i |
// modem signals |
rts_pad_o, cts_pad_i, dtr_pad_o, dsr_pad_i, ri_pad_i, dcd_pad_i |
`ifdef UART_HAS_BAUDRATE_OUTPUT |
, baud_o |
, baud_o |
`endif |
); |
); |
|
parameter uart_data_width = `UART_DATA_WIDTH; |
parameter uart_addr_width = `UART_ADDR_WIDTH; |
parameter uart_data_width = `UART_DATA_WIDTH; |
parameter uart_addr_width = `UART_ADDR_WIDTH; |
|
input wb_clk_i; |
input wb_clk_i; |
|
// WISHBONE interface |
input wb_rst_i; |
input [uart_addr_width-1:0] wb_adr_i; |
input [uart_data_width-1:0] wb_dat_i; |
output [uart_data_width-1:0] wb_dat_o; |
input wb_we_i; |
input wb_stb_i; |
input wb_cyc_i; |
input [3:0] wb_sel_i; |
output wb_ack_o; |
output int_o; |
// WISHBONE interface |
input wb_rst_i; |
input [uart_addr_width-1:0] wb_adr_i; |
input [uart_data_width-1:0] wb_dat_i; |
output [uart_data_width-1:0] wb_dat_o; |
input wb_we_i; |
input wb_stb_i; |
input wb_cyc_i; |
input [3:0] wb_sel_i; |
output wb_ack_o; |
output int_o; |
|
// UART signals |
input srx_pad_i; |
output stx_pad_o; |
output rts_pad_o; |
input cts_pad_i; |
output dtr_pad_o; |
input dsr_pad_i; |
input ri_pad_i; |
input dcd_pad_i; |
// UART signals |
input srx_pad_i; |
output stx_pad_o; |
output rts_pad_o; |
input cts_pad_i; |
output dtr_pad_o; |
input dsr_pad_i; |
input ri_pad_i; |
input dcd_pad_i; |
|
// optional baudrate output |
// optional baudrate output |
`ifdef UART_HAS_BAUDRATE_OUTPUT |
output baud_o; |
output baud_o; |
`endif |
|
|
wire stx_pad_o; |
wire rts_pad_o; |
wire dtr_pad_o; |
wire stx_pad_o; |
wire rts_pad_o; |
wire dtr_pad_o; |
|
wire [uart_addr_width-1:0] wb_adr_i; |
wire [uart_data_width-1:0] wb_dat_i; |
wire [uart_data_width-1:0] wb_dat_o; |
wire [uart_addr_width-1:0] wb_adr_i; |
wire [uart_data_width-1:0] wb_dat_i; |
wire [uart_data_width-1:0] wb_dat_o; |
|
wire [7:0] wb_dat8_i; // 8-bit internal data input |
wire [7:0] wb_dat8_o; // 8-bit internal data output |
wire [31:0] wb_dat32_o; // debug interface 32-bit output |
wire [3:0] wb_sel_i; // WISHBONE select signal |
wire [uart_addr_width-1:0] wb_adr_int; |
wire we_o; // Write enable for registers |
wire re_o; // Read enable for registers |
// |
// MODULE INSTANCES |
// |
wire [7:0] wb_dat8_i; // 8-bit internal data input |
wire [7:0] wb_dat8_o; // 8-bit internal data output |
wire [31:0] wb_dat32_o; // debug interface 32-bit output |
wire [3:0] wb_sel_i; // WISHBONE select signal |
wire [uart_addr_width-1:0] wb_adr_int; |
wire we_o; // Write enable for registers |
wire re_o; // Read enable for registers |
// |
// MODULE INSTANCES |
// |
|
`ifdef DATA_BUS_WIDTH_8 |
`else |
// debug interface wires |
wire [3:0] ier; |
wire [3:0] iir; |
wire [1:0] fcr; |
wire [4:0] mcr; |
wire [7:0] lcr; |
wire [7:0] msr; |
wire [7:0] lsr; |
wire [`UART_FIFO_COUNTER_W-1:0] rf_count; |
wire [`UART_FIFO_COUNTER_W-1:0] tf_count; |
wire [2:0] tstate; |
wire [3:0] rstate; |
// debug interface wires |
wire [3:0] ier; |
wire [3:0] iir; |
wire [1:0] fcr; |
wire [4:0] mcr; |
wire [7:0] lcr; |
wire [7:0] msr; |
wire [7:0] lsr; |
wire [`UART_FIFO_COUNTER_W-1:0] rf_count; |
wire [`UART_FIFO_COUNTER_W-1:0] tf_count; |
wire [2:0] tstate; |
wire [3:0] rstate; |
`endif |
|
`ifdef DATA_BUS_WIDTH_8 |
//// WISHBONE interface module |
uart_wb wb_interface( |
.clk( wb_clk_i ), |
.wb_rst_i( wb_rst_i ), |
.wb_dat_i(wb_dat_i), |
.wb_dat_o(wb_dat_o), |
.wb_dat8_i(wb_dat8_i), |
.wb_dat8_o(wb_dat8_o), |
.wb_dat32_o(32'b0), |
.wb_sel_i(4'b0), |
.wb_we_i( wb_we_i ), |
.wb_stb_i( wb_stb_i ), |
.wb_cyc_i( wb_cyc_i ), |
.wb_ack_o( wb_ack_o ), |
.wb_adr_i(wb_adr_i), |
.wb_adr_int(wb_adr_int), |
.we_o( we_o ), |
.re_o(re_o) |
); |
//// WISHBONE interface module |
uart_wb wb_interface( |
.clk( wb_clk_i ), |
.wb_rst_i( wb_rst_i ), |
.wb_dat_i(wb_dat_i), |
.wb_dat_o(wb_dat_o), |
.wb_dat8_i(wb_dat8_i), |
.wb_dat8_o(wb_dat8_o), |
.wb_dat32_o(32'b0), |
.wb_sel_i(4'b0), |
.wb_we_i( wb_we_i ), |
.wb_stb_i( wb_stb_i ), |
.wb_cyc_i( wb_cyc_i ), |
.wb_ack_o( wb_ack_o ), |
.wb_adr_i(wb_adr_i), |
.wb_adr_int(wb_adr_int), |
.we_o( we_o ), |
.re_o(re_o) |
); |
`else |
uart_wb wb_interface( |
.clk( wb_clk_i ), |
.wb_rst_i( wb_rst_i ), |
.wb_dat_i(wb_dat_i), |
.wb_dat_o(wb_dat_o), |
.wb_dat8_i(wb_dat8_i), |
.wb_dat8_o(wb_dat8_o), |
.wb_sel_i(wb_sel_i), |
.wb_dat32_o(wb_dat32_o), |
.wb_we_i( wb_we_i ), |
.wb_stb_i( wb_stb_i ), |
.wb_cyc_i( wb_cyc_i ), |
.wb_ack_o( wb_ack_o ), |
.wb_adr_i(wb_adr_i), |
.wb_adr_int(wb_adr_int), |
.we_o( we_o ), |
.re_o(re_o) |
); |
uart_wb wb_interface( |
.clk( wb_clk_i ), |
.wb_rst_i( wb_rst_i ), |
.wb_dat_i(wb_dat_i), |
.wb_dat_o(wb_dat_o), |
.wb_dat8_i(wb_dat8_i), |
.wb_dat8_o(wb_dat8_o), |
.wb_sel_i(wb_sel_i), |
.wb_dat32_o(wb_dat32_o), |
.wb_we_i( wb_we_i ), |
.wb_stb_i( wb_stb_i ), |
.wb_cyc_i( wb_cyc_i ), |
.wb_ack_o( wb_ack_o ), |
.wb_adr_i(wb_adr_i), |
.wb_adr_int(wb_adr_int), |
.we_o( we_o ), |
.re_o(re_o) |
); |
`endif |
|
// Registers |
uart_regs regs( |
.clk( wb_clk_i ), |
.wb_rst_i( wb_rst_i ), |
.wb_addr_i( wb_adr_int ), |
.wb_dat_i( wb_dat8_i ), |
.wb_dat_o( wb_dat8_o ), |
.wb_we_i( we_o ), |
.wb_re_i(re_o), |
.modem_inputs( {cts_pad_i, dsr_pad_i, |
ri_pad_i, dcd_pad_i} ), |
.stx_pad_o( stx_pad_o ), |
.srx_pad_i( srx_pad_i ), |
// Registers |
uart_regs regs( |
.clk( wb_clk_i ), |
.wb_rst_i( wb_rst_i ), |
.wb_addr_i( wb_adr_int ), |
.wb_dat_i( wb_dat8_i ), |
.wb_dat_o( wb_dat8_o ), |
.wb_we_i( we_o ), |
.wb_re_i(re_o), |
.modem_inputs( {cts_pad_i, dsr_pad_i, |
ri_pad_i, dcd_pad_i} ), |
.stx_pad_o( stx_pad_o ), |
.srx_pad_i( srx_pad_i ), |
`ifdef DATA_BUS_WIDTH_8 |
`else |
// debug interface signals enabled |
.ier(ier), |
.iir(iir), |
.fcr(fcr), |
.mcr(mcr), |
.lcr(lcr), |
.msr(msr), |
.lsr(lsr), |
.rf_count(rf_count), |
.tf_count(tf_count), |
.tstate(tstate), |
.rstate(rstate), |
// debug interface signals enabled |
.ier(ier), |
.iir(iir), |
.fcr(fcr), |
.mcr(mcr), |
.lcr(lcr), |
.msr(msr), |
.lsr(lsr), |
.rf_count(rf_count), |
.tf_count(tf_count), |
.tstate(tstate), |
.rstate(rstate), |
`endif |
.rts_pad_o( rts_pad_o ), |
.dtr_pad_o( dtr_pad_o ), |
.int_o( int_o ) |
.rts_pad_o( rts_pad_o ), |
.dtr_pad_o( dtr_pad_o ), |
.int_o( int_o ) |
`ifdef UART_HAS_BAUDRATE_OUTPUT |
, .baud_o(baud_o) |
, .baud_o(baud_o) |
`endif |
|
); |
); |
|
`ifdef DATA_BUS_WIDTH_8 |
`else |
uart_debug_if dbg(/*AUTOINST*/ |
// Outputs |
.wb_dat32_o (wb_dat32_o[31:0]), |
// Inputs |
.wb_adr_i (wb_adr_int[`UART_ADDR_WIDTH-1:0]), |
.ier (ier[3:0]), |
.iir (iir[3:0]), |
.fcr (fcr[1:0]), |
.mcr (mcr[4:0]), |
.lcr (lcr[7:0]), |
.msr (msr[7:0]), |
.lsr (lsr[7:0]), |
.rf_count (rf_count[`UART_FIFO_COUNTER_W-1:0]), |
.tf_count (tf_count[`UART_FIFO_COUNTER_W-1:0]), |
.tstate (tstate[2:0]), |
.rstate (rstate[3:0])); |
uart_debug_if dbg(/*AUTOINST*/ |
// Outputs |
.wb_dat32_o (wb_dat32_o[31:0]), |
// Inputs |
.wb_adr_i (wb_adr_int[`UART_ADDR_WIDTH-1:0]), |
.ier (ier[3:0]), |
.iir (iir[3:0]), |
.fcr (fcr[1:0]), |
.mcr (mcr[4:0]), |
.lcr (lcr[7:0]), |
.msr (msr[7:0]), |
.lsr (lsr[7:0]), |
.rf_count (rf_count[`UART_FIFO_COUNTER_W-1:0]), |
.tf_count (tf_count[`UART_FIFO_COUNTER_W-1:0]), |
.tstate (tstate[2:0]), |
.rstate (rstate[3:0])); |
`endif |
|
initial |
begin |
initial |
begin |
`ifdef UART16550_SIM_OUTPUT |
`ifdef DATA_BUS_WIDTH_8 |
$display("(%m) UART INFO: Data bus width is 8. No Debug interface.\n"); |
$display("(%m) UART INFO: Data bus width is 8. No Debug interface.\n"); |
`else |
$display("(%m) UART INFO: Data bus width is 32. Debug Interface present.\n"); |
$display("(%m) UART INFO: Data bus width is 32. Debug Interface present.\n"); |
`endif |
`ifdef UART_HAS_BAUDRATE_OUTPUT |
$display("(%m) UART INFO: Has baudrate output\n"); |
$display("(%m) UART INFO: Has baudrate output\n"); |
`else |
$display("(%m) UART INFO: Doesn't have baudrate output\n"); |
$display("(%m) UART INFO: Doesn't have baudrate output\n"); |
`endif |
`endif |
end |
end |
|
endmodule // uart_top |
|
/openrisc/trunk/orpsocv2/rtl/verilog/orpsoc_top.v
1,4 → 1,46
//module ref_design_top |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// orpsoc_top.v //// |
//// //// |
//// This file is part of the ORPSoCv2 project //// |
//// http://opencores.org/openrisc/?orpsocv2 //// |
//// //// |
//// This is the top level RTL file for ORPSoCv2 //// |
//// //// |
//// Author(s): //// |
//// - Michael Unneback, unneback@opencores.org //// |
//// ORSoC AB michael.unneback@orsoc.se //// |
//// - Julius Baxter, julius.baxter@orsoc.se //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2008, 2009 Authors //// |
//// //// |
//// 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
|
module orpsoc_top |
( |
output spi_sd_sclk_pad_o , |
24,7 → 66,7
output spi_flash_w_n_pad_o , |
output spi_flash_hold_n_pad_o, |
`endif // `ifdef USE_SDRAM |
`ifdef USE_ETHERNET |
`ifdef USE_ETHERNET_IO |
output [1:1] eth_sync_pad_o, |
output [1:1] eth_tx_pad_o, |
input [1:1] eth_rx_pad_i, |
31,7 → 73,7
input eth_clk_pad_i, |
inout [1:1] eth_md_pad_io, |
output [1:1] eth_mdc_pad_o, |
`endif // `ifdef USE_ETHERNET |
`endif // `ifdef USE_ETHERNET_IO |
output spi1_mosi_pad_o, |
input spi1_miso_pad_i, |
output spi1_ss_pad_o , |
349,7 → 391,7
assign pic_ints[7] = 1'b0; |
assign pic_ints[6] = 1'b0; |
assign pic_ints[5] = 1'b0; |
assign pic_ints[4] = 1'b0; |
assign pic_ints[4] = eth_int[1]; /* IRQ4, just like in Linux. Added jb 090716 */ |
assign pic_ints[3] = 1'b0; |
assign pic_ints[2] = uart0_irq; |
assign pic_ints[1] = 1'b0; |
550,8 → 592,7
wire m1rxerr; |
wire m1coll; |
wire m1crs; |
//wire [1:10] state; |
wire [10:1] state; // Changed for verilator -- jb |
wire [10:1] state; |
wire sync; |
wire [1:1] rx, tx; |
wire [1:1] mdc_o, md_i, md_o, md_oe; |
602,6 → 643,8
.md_padoe_o(md_oe[1]), |
.int_o(eth_int[1]) |
); |
|
`ifdef USE_ETHERNET_IO |
iobuftri iobuftri1 |
( |
.i(md_o[1]), |
632,6 → 675,7
.clk(eth_clk), |
.rst(wb_rst) |
); |
|
obufdff obufdff_sync1 |
( |
.d(sync), |
653,6 → 697,8
.clk(eth_clk), |
.rst(wb_rst) |
); |
`endif // `ifdef USE_ETHERNET_IO |
|
`else // !`ifdef USE_ETHERNET |
// If ethernet core is disabled, still ack anyone who tries |
// to access its config port. This allows linux to boot in |
/openrisc/trunk/orpsocv2/sim/bin/Makefile
201,22 → 201,37
# SystemC cycle-accurate model compilation |
# |
# A new addition to ORPSoC v2 is the cycle-accurate model. The primary enabler |
# behind this is verilator, which processes the RTL sources and generates a c++ |
# description of the system. This c++ description is then compiled with a |
# behind this is verilator, which processes the RTL source and generates a c++ |
# description of the system. This c++ description is then compiled, with a |
# SystemC wrapper. Finally a top-level SystemC testbench instantiates the |
# model, as well as any other modules - in this case a reset generation, UART |
# model, and other useful modules - in this case a reset generation, UART |
# decoder, and monitor module are included at the top level. These additional |
# modules and models are written in SystemC and compiled all together with the |
# cycle-accurate ORPSoC model to create the simulation executable. Finally this |
# executable is run and should be a cycle-representation of the system. VCDs |
# can be generated if enabled. The compiled mentioned above is all done with |
# the GNU c++ compiler, g++. |
# The compilation process is a little more tricky than a typical even-driven |
# modules and models are written in SystemC. Finally, everything is linked with |
# the cycle-accurate ORPSoC model to create the simulation executable. This |
# executable is the cycle-representation of the system. |
# |
# VCDs can be generated if the model is made with VCD=1 specified on the |
# command line. Specify a dump file with the "-vcd" option at runtime, eg: |
# "./Vorpsoc_top -vcd dump.vcd" |
# Note that this slows down the simulation. |
# |
# Logging of the processor's execution can be done by specifying a log file |
# on the command line at runtime, eg: "./Vorpsoc_top -log or1200_exec.log" |
# Note that this slows down the simulation. |
# |
# There are performance metrics printed at the conclusion of simulations. To |
# disable these launch the executable with either the -q or --no-perf-summary |
# options. eg: "./Vorpsoc_top -q" |
# |
# The compilation is all done with the GNU c++ compiler, g++. |
# |
# The compilation process is a little more complicated than the event-driven |
# simulator. It proceeds basically by generating the makefiles for compiling |
# the design with verilator, running these makes which produces a library |
# containing the cycle-accurate ORPSoC design, compiling the additional |
# top-level, and testbench, systemC models into a library, and then linking it |
# all together into the simulation executable. |
# |
# The major advantage of the cycle-accurate model is that it is quicker, in |
# terms of simulated cycles/second, when compared with event-driven simulators. |
# It is, of course, less accurate in that it cannot model propegation delays. |
223,16 → 238,16
# However this is usually not an issue for simulating a design which is known |
# to synthesize and run OK. It is very useful for running complex software, |
# such as the linux kernel and real-time OS applications, which generally |
# require long simulation times. |
# result in long simulation times. |
# |
# Currently the cycle-accurate model being used doesn't contain much more than |
# the processor and a UART, however it's exepected in future this will be |
# expanded on and more complex software test suites will be implemented to put |
# the system through its paces. |
# |
# |
|
|
# Name of |
# the directory we're currently in |
# Name of the directory we're currently in |
CUR_DIR=$(shell pwd) |
|
# The root path of the whole project |
275,7 → 290,9
|
# Enable ethernet if defined on the command line |
ifdef USE_ETHERNET |
EVENT_SIM_FLAGS += "-D USE_ETHERNET=$(USE_ETHERNET)" |
EVENT_SIM_FLAGS += "-D USE_ETHERNET=$(USE_ETHERNET) -D USE_ETHERNET_IO=$(USE_ETHERNET)" |
# Extra tests we do if ethernet is enabled |
TESTS += eth-basic |
endif |
|
SIM_FLASH_MEM_FILE="flash.in" |
296,7 → 313,7
|
|
ifdef UART_PRINTF |
TEST_SW_MAKE_OPTS=UART_PRINTF=1 |
TEST_SW_MAKE_OPTS="UART_PRINTF=1" |
endif |
|
.PHONY: prepare_sw |
357,7 → 374,7
# Define USE_SDRAM to enable the external SDRAM, otherwise the simulation |
# defaults to an internal SRAM. Eg. $ make rtl-tests USE_SDRAM=1 VCD=1 |
# Verilator defaults to internal memories |
rtl-tests: prepare_sw_uart_printf prepare_rtl prepare_dirs |
rtl-tests: prepare_sw prepare_rtl prepare_dirs |
@echo |
@echo "Beginning loop that will complete the following tests: $(TESTS)" |
@echo |
386,6 → 403,10
fi; \ |
echo "\`define TEST_NAME_STRING \"$$TEST\"" > $(SIM_RUN_DIR)/test_define.v; \ |
echo "\`define TEST_RESULTS_DIR \"$(SIM_RESULTS_DIR)/\" " >> $(SIM_RUN_DIR)/test_define.v; \ |
if echo $$TEST | grep -q -i ^eth; then \ |
echo "\`define ENABLE_ETH_STIM" >> $(SIM_RUN_DIR)/test_define.v; \ |
echo "\`define ETH_PHY_VERBOSE" >> $(SIM_RUN_DIR)/test_define.v; \ |
fi; \ |
if [ -z $$NO_SIM_LOGGING ]; then \ |
echo "\`define OR1200_DISPLAY_ARCH_STATE" >> $(SIM_RUN_DIR)/test_define.v; \ |
fi; \ |
442,6 → 463,10
if [ ! -z $$USE_SDRAM ]; then \ |
echo "\`define USE_SDRAM" >> $(SIM_RUN_DIR)/test_define.v; \ |
fi; \ |
if echo $$TEST | grep -q -i ^eth; then \ |
echo "\`define ENABLE_ETH_STIM" >> $(SIM_RUN_DIR)/test_define.v; \ |
echo "\`define ETH_PHY_VERBOSE" >> $(SIM_RUN_DIR)/test_define.v; \ |
fi; \ |
echo "+nocopyright" >> $(SIM_RUN_DIR)/$(ICARUS_COMMAND_FILE).generated; \ |
echo "+nowarn+MACRDF" >> $(SIM_RUN_DIR)/$(ICARUS_COMMAND_FILE).generated; \ |
echo "\`define TEST_NAME_STRING \"$$TEST\"" > $(SIM_RUN_DIR)/test_define.v; \ |
700,14 → 725,10
clean: clean-sw clean-sim clean-sysc clean-rtl clean_vpi |
|
clean-sw: |
@for TEST in $(TESTS); do \ |
echo "Current test: $$TEST"; \ |
CURRENT_TEST_SW_DIR=$(SW_DIR)/`echo $$TEST | cut -d "-" -f 1`; \ |
echo "Current test sw directory: " $$CURRENT_TEST_SW_DIR; \ |
$(MAKE) -C $$CURRENT_TEST_SW_DIR clean; \ |
@for SWDIR in `ls $(SW_DIR)`; do \ |
echo $$SWDIR; \ |
$(MAKE) -C $(SW_DIR)/$$SWDIR clean; \ |
done |
$(MAKE) -C $(SW_DIR)/support clean |
$(MAKE) -C $(SW_DIR)/utils clean |
|
clean-sim: |
rm -rf $(SIM_RESULTS_DIR) $(SIM_RUN_DIR)/*.* $(SIM_VLT_DIR) |
719,4 → 740,5
clean-rtl: |
# Clean away temporary verilog source files |
rm -f $(RTL_VERILOG_DIR)/intercon.v |
rm -f $(RTL_VERILOG_DIR)/components/wb_sdram_ctrl/wb_sdram_ctrl_fsm.v |
rm -f $(RTL_VERILOG_DIR)/components/wb_sdram_ctrl/wb_sdram_ctrl_fsm.v |
|
/openrisc/trunk/orpsocv2/sim/bin/verilator.scr
34,3 → 34,4
-v $BACKEND_DIR/sim_lib.v |
|
+define+DISABLE_IOS_FOR_VERILATOR |
|
/openrisc/trunk/orpsocv2/sw/eth/eth-basic.c
0,0 → 1,735
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Simple Ethernet test code //// |
//// //// |
//// Description //// |
//// ORPSoC test software //// |
//// //// |
//// To Do: //// |
//// - It's a simple test for now, but could be adapted for //// |
//// standalone use. //// |
//// //// |
//// 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 "support.h" |
#include "board.h" |
#include "uart.h" |
#include "open_eth.h" |
|
#include "ethphy_micrel.h" |
|
/* Dummy exception functions */ |
void buserr_except(){} |
void dpf_except(){} |
void ipf_except(){} |
void lpint_except(){} |
void align_except(){} |
void illegal_except(){} |
void hpint_except(){} |
void dtlbmiss_except(){} |
void itlbmiss_except(){} |
void range_except(){} |
void syscall_except(){} |
void res1_except(){} |
void trap_except(){} |
void res2_except(){} |
|
/* Functions in this file */ |
void ethmac_setup(void); |
void oeth_printregs(void); |
void ethphy_init(void); |
void oeth_dump_bds(); |
|
/* 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 */ |
#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 8 |
#define OETH_TXBD_NUM 8 |
#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 2048 |
#define OETH_TX_BUFF_SIZE 2048 |
|
/* 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 |
*/ |
#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; |
}; |
|
|
void oeth_printregs(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
printk("Oeth regs: Mode Register : 0x%lx\n",(unsigned long) regs->moder); /* Mode Register */ |
printk("Oeth regs: Interrupt Source Register 0x%lx\n", (unsigned long) regs->int_src); /* Interrupt Source Register */ |
printk("Oeth regs: Interrupt Mask Register 0x%lx\n",(unsigned long) regs->int_mask); /* Interrupt Mask Register */ |
printk("Oeth regs: Back to Bak Inter Packet Gap Register 0x%lx\n",(unsigned long) regs->ipgt); /* Back to Bak Inter Packet Gap Register */ |
printk("Oeth regs: Non Back to Back Inter Packet Gap Register 1 0x%lx\n",(unsigned long) regs->ipgr1); /* Non Back to Back Inter Packet Gap Register 1 */ |
printk("Oeth regs: Non Back to Back Inter Packet Gap Register 2 0x%lx\n",(unsigned long) regs->ipgr2); /* Non Back to Back Inter Packet Gap Register 2 */ |
printk("Oeth regs: Packet Length Register (min. and max.) 0x%lx\n",(unsigned long) regs->packet_len); /* Packet Length Register (min. and max.) */ |
printk("Oeth regs: Collision and Retry Configuration Register 0x%lx\n",(unsigned long) regs->collconf); /* Collision and Retry Configuration Register */ |
printk("Oeth regs: Transmit Buffer Descriptor Number Register 0x%lx\n",(unsigned long) regs->tx_bd_num); /* Transmit Buffer Descriptor Number Register */ |
printk("Oeth regs: Control Module Mode Register 0x%lx\n",(unsigned long) regs->ctrlmoder); /* Control Module Mode Register */ |
printk("Oeth regs: MII Mode Register 0x%lx\n",(unsigned long) regs->miimoder); /* MII Mode Register */ |
printk("Oeth regs: MII Command Register 0x%lx\n",(unsigned long) regs->miicommand); /* MII Command Register */ |
printk("Oeth regs: MII Address Register 0x%lx\n",(unsigned long) regs->miiaddress); /* MII Address Register */ |
printk("Oeth regs: MII Transmit Data Register 0x%lx\n",(unsigned long) regs->miitx_data); /* MII Transmit Data Register */ |
printk("Oeth regs: MII Receive Data Register 0x%lx\n",(unsigned long) regs->miirx_data); /* MII Receive Data Register */ |
printk("Oeth regs: MII Status Register 0x%lx\n",(unsigned long) regs->miistatus); /* MII Status Register */ |
printk("Oeth regs: MAC Individual Address Register 0 0x%lx\n",(unsigned long) regs->mac_addr0); /* MAC Individual Address Register 0 */ |
printk("Oeth regs: MAC Individual Address Register 1 0x%lx\n",(unsigned long) regs->mac_addr1); /* MAC Individual Address Register 1 */ |
printk("Oeth regs: Hash Register 0 0x%lx\n",(unsigned long) regs->hash_addr0); /* Hash Register 0 */ |
printk("Oeth regs: Hash Register 1 0x%lx\n",(unsigned long) regs->hash_addr1); /* Hash Register 1 */ |
|
} |
|
static int last_char; |
|
void spin_cursor(void) |
{ |
#ifdef RTLSIM |
return; |
#endif |
volatile unsigned int i; // So the loop doesn't get optimised away |
printk(" \r"); |
if (last_char == 0) |
printk("/"); |
else if (last_char == 1) |
printk("-"); |
else if (last_char == 2) |
printk("\\"); |
else if (last_char == 3) |
printk("|"); |
else if (last_char == 4) |
printk("/"); |
else if (last_char == 5) |
printk("-"); |
else if (last_char == 6) |
printk("\\"); |
else if (last_char == 7) |
{ |
printk("|"); |
last_char=-1; |
} |
|
last_char++; |
|
for(i=0;i<20000;i++); |
|
} |
|
#define PHYNUM 0 |
|
/* 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; /* Basic Control Register */ |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
|
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
|
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 ethphy_init(void) |
{ |
volatile int i; |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Init the Micrel KSZ80001L PHY */ |
/* First reset it */ |
|
/* printk("Oeth: regs->miistatus %x regs->miirx_data %x\n",regs->miistatus, regs->miirx_data); */ |
/* regs->miiaddress = (MICREL_KSZ8001_BCR_ADR << 8); /\* PHY's Basic Control Register *\/ */ |
/* regs->miitx_data = MICREL_KSZ8001_BCR_RESET; */ |
/* regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; */ |
/* printk("Oeth: regs->miiaddress %x regs->miicommand %x\n",regs->miiaddress, regs->miicommand); */ |
/* regs->miicommand = 0; */ |
/* while(regs->miistatus & OETH_MIISTATUS_BUSY) */ |
/* spin_cursor(); */ |
/* printk("\r"); */ |
|
|
printk("Oeth: Reading PHY r0 (status reg)\n"); |
regs->miiaddress = MICREL_KSZ8001_BCR_ADR<<8 | PHYNUM; /* Basic Control Register */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
|
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
|
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
printk("\r"); |
|
/* while (regs->miirx_data & MICREL_KSZ8001_BCR_RESET) */ |
/* { */ |
/* regs->miiaddress = MICREL_KSZ8001_BCR_ADR<<8; /\* Basic Control Register *\/ */ |
/* regs->miitx_data = 0; */ |
/* regs->miicommand = OETH_MIICOMMAND_RSTAT; */ |
/* regs->miicommand = 0; */ |
/* while(regs->miistatus & OETH_MIISTATUS_BUSY) */ |
/* spin_cursor(); */ |
/* } */ |
/* printk("\r"); */ |
|
printk("\nOeth: PHY r0 value: %x\n",regs->miirx_data); |
|
/* PHY reset and confirmed as such */ |
|
/* Now read the link status */ |
regs->miiaddress = MICREL_KSZ8001_BSR_ADR<<8 | PHYNUM; /* Basic Status Register */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
|
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
|
printk("\r"); |
printk("Oeth: PHY BSR: 0x%x\n",regs->miirx_data & 0xffff); |
|
/* Read the operation mode */ |
regs->miiaddress = MICREL_KSZ8001_100BTPCR_ADR<<8 | PHYNUM; /* 100BASE-TX */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
printk("\r"); |
printk("Oeth: PHY 100BASE-TX PHY Control Register: 0x%x\n",regs->miirx_data); |
|
|
/* Read the PHY identification register 1 */ |
regs->miiaddress = MICREL_KSZ8001_PI1_ADR<<8 | PHYNUM; /* PI1 */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
printk("\r"); |
printk("Oeth: PHY PHY Identifier I: 0x%x\n",regs->miirx_data); |
|
/* Read the PHY identification register 2 */ |
regs->miiaddress = MICREL_KSZ8001_PI2_ADR<<8 | PHYNUM; /* PI2 */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
printk("\r"); |
printk("Oeth: PHY PHY Identifier II: 0x%x\n",regs->miirx_data); |
|
|
} |
|
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/*printk("\nbefore reset\n\n"); |
oeth_printregs();*/ |
|
/* 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 */ |
|
//printk("\nafter reset\n\n"); |
//oeth_printregs(); |
|
/* 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 = 0x00000012; |
|
/* 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; |
*/ |
|
/* Disable interrupt sources |
*/ |
regs->int_mask = 0; |
|
printk("\nafter config\n\n"); |
oeth_printregs(); |
|
// 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 for TX buffers*/ |
for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) { |
for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) { |
//tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[k].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
/* Setup for RX buffers */ |
for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) { |
for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) { |
//rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; |
rx_bd[k].len_status = OETH_RX_BD_EMPTY; |
rx_bd[k].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; |
|
/* Enable RX of packets */ |
/* Set RXEN in MAC MODER */ |
regs->moder = OETH_MODER_RXEN | regs->moder; |
|
|
} |
|
/* Find the next available transmit buffer */ |
struct oeth_bd* get_next_tx_bd() |
{ |
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* 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 NOT ready for transmit. ie we can manipulate it */ |
{ |
printk("Oeth: Using TX_bd at 0x%lx\n",(unsigned long)&tx_bd[i]); |
return (struct oeth_bd*) &tx_bd[i]; |
} |
} |
|
printk("No free tx buffers\n"); |
/* Set to null our returned buffer */ |
tx_bd = (volatile oeth_bd *) 0; |
return (struct oeth_bd*) tx_bd; |
|
} |
|
|
/* print packet contents */ |
static void |
oeth_print_packet(unsigned long add, int len) |
{ |
int i; |
printk("ipacket: add = %lx len = %d\n", add, len); |
for(i = 0; i < len; i++) { |
if(!(i % 16)) |
printk("\n"); |
printk(" %.2x", *(((unsigned char *)add) + i)); |
} |
printk("\n"); |
} |
|
/* 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; |
|
if((tx_bd = (volatile oeth_bd *) get_next_tx_bd()) == NULL) |
{ |
printk("No more TX buffers available\n"); |
return; |
} |
printk("Oeth: TX_bd buffer address: 0x%lx\n",(unsigned long) tx_bd->addr); |
|
/* 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; |
|
printk("Oeth: Copying %d bytes from 0x%lx to TX_bd buffer at 0x%lx\n",length,(unsigned long) data,(unsigned long) tx_bd->addr); |
|
/* Copy the data into the transmit buffer, word 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); |
} |
printk("Oeth: Data copied to buffer\n"); |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
//oeth_print_packet(tx_bd->addr, (tx_bd->len_status >> 16)); |
|
/* Send it on its way. Tell controller its ready, |
* and to put the CRC on the end. |
*/ |
tx_bd->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_CRC); |
|
oeth_dump_bds(); |
|
printk("Oeth: MODER addr: 0x%x\n", regs->moder); |
|
/* Set TXEN in MAC MODER */ |
regs->moder = OETH_MODER_TXEN | regs->moder; |
|
printk("Oeth: TXBD Status 0x%x\n", tx_bd->len_status); |
|
i=0; |
|
/* Wait for BD READY bit to be cleared, indicating it's been sent */ |
while (OETH_TX_BD_READY & tx_bd->len_status) |
{ |
#ifndef RTLSIM |
//for(i=0;i<40000;i++); |
//printk("Oeth: TXBD Status 0x%x\n", tx_bd->len_status); |
//oeth_printregs(); |
spin_cursor(); |
if (i++%64==63) {oeth_dump_bds();} |
#endif |
} |
|
#ifdef RTLSIM |
|
return; |
#else |
printk("sent\n"); |
#endif |
|
} |
|
/* enable RX, loop waiting for arrived packets and print them out */ |
void oeth_monitor_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Set RXEN in MAC MODER */ |
regs->moder = OETH_MODER_RXEN | regs->moder; |
|
|
volatile oeth_bd *rx_bd; |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
volatile int i; |
|
while (1) |
{ |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
if (!(rx_bd[i].len_status & OETH_RX_BD_EMPTY)) /* Not empty */ |
{ |
// Something in this buffer! |
printk("Oeth: RX in buf %d - len_status: 0x%lx\n",i, rx_bd[i].len_status); |
oeth_print_packet(rx_bd[i].addr, rx_bd[i].len_status >> 16); |
/* Clear recieved bit */ |
rx_bd[i].len_status |= OETH_RX_BD_EMPTY; |
printk("\t end of packet\n\n"); |
} |
} |
} |
} |
|
/* Print out all buffer descriptors */ |
void oeth_dump_bds() |
{ |
unsigned long* bd_base = (unsigned long*) OETH_BD_BASE; |
|
int i; |
for(i=0;i<OETH_TXBD_NUM;i++) |
{ |
printk("oeth: tx_bd%d: len_status: %lx ",i,*bd_base++); |
printk("addr: %lx\n", *bd_base++); |
} |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
printk("oeth: rx_bd%d: len_status: %lx ",i,*bd_base++); |
printk("addr: %lx\n", *bd_base++); |
} |
|
} |
|
|
|
void send_packet() |
{ |
/* This should be 98 bytes big */ |
char ping_packet[] = { |
0x00, 0x24, 0xe8, 0x91, 0x7c, 0x0d, /*DST MAC*/ |
0x00, 0xe0, 0x18, 0x73, 0x1d, 0x05, /*SRC MAC*/ |
0x08, 0x00, /*TYPE*/ |
/* IP */ |
0x45, /* Version, header length*/ |
0x00, /* Differentiated services field */ |
0x00, 0x54, /* Total length */ |
0x00, 0x00, /* Identification */ |
0x40, /* Flags */ |
0x00, /* Fragment offset */ |
0x40, /* Time to live */ |
0x01, /* Protocol (0x01 = ICMP */ |
0xef, 0xf3, /* Header checksum */ |
0xc0, 0xa8, 0x64, 0xfb, /* Source IP */ |
0xc0, 0xa8, 0x64, 0x69, /* Dest. IP */ |
/* ICMP Message body */ |
0x08, 0x00, 0x9a, 0xd4, 0xc8, 0x18, 0x00, 0x01, 0xd9, 0x8c, 0x54, |
0x4a, 0x7b, 0x37, 0x01, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, |
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, |
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, |
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, |
0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 |
}; |
|
/*Send packet */ |
tx_packet((void*) ping_packet, 98); |
|
} |
|
void printstring(char* string) |
{ |
while (*string) uart_putc(*string++); |
} |
|
int main () |
{ |
last_char=0; /* Init for spin_cursor()*/ |
#ifndef RTLSIM |
uart_init(); // init the UART before we can printf |
printf("\n\tethphytest\n\n"); |
#endif |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
//scan_ethphys(); /* Scan MIIM bus for PHYs */ |
//ethphy_init(); /* Attempt reset and configuration of PHY via MIIM */ |
//ethmac_scanstatus(); /* Enable scanning of status register via MIIM */ |
|
//oeth_monitor_rx(); |
|
send_packet(); |
|
#ifdef RTLSIM |
report(0xdeaddead); |
or32_exit(0); |
#else |
while(1) |
spin_cursor(); |
#endif |
|
} |
/openrisc/trunk/orpsocv2/sw/eth/ethphy_micrel.h
0,0 → 1,43
|
/* Micrel KSZ8001 PHY configuration */ |
/* Register addresses */ |
#define MICREL_KSZ8001_BCR_ADR 0x0 /* Basic Control Register */ |
#define MICREL_KSZ8001_BSR_ADR 0x1 /* Basic Status Register */ |
#define MICREL_KSZ8001_PI1_ADR 0x2 /* PHY Identifier I */ |
#define MICREL_KSZ8001_PI2_ADR 0x3 /* PHY Identifier II */ |
#define MICREL_KSZ8001_ANAR_ADR 0x4 /* Auto-Negotiation Advertisement Register */ |
#define MICREL_KSZ8001_ANLPAR_ADR 0x5 /* Auto-Negotiation Link Partner Ability Register */ |
#define MICREL_KSZ8001_ANER_ADR 0x6 /* Auto-Negotiation Expansion Register */ |
#define MICREL_KSZ8001_ANNPR_ADR 0x7 /* Auto-Negotiation Next Page Register */ |
#define MICREL_KSZ8001_LPNPA_ADR 0x8 /* Link Partner Next Page Ability */ |
#define MICREL_KSZ8001_RXERCR_ADR 0x15 /* RXER Counter Register */ |
#define MICREL_KSZ8001_ICSR_ADR 0x1b /* Interrupt Control/Status Register */ |
#define MICREL_KSZ8001_LMDCSR_ADR 0x1d /* LinkMD Control/Status Register */ |
#define MICREL_KSZ8001_PCR_ADR 0x1e /* PHY Control Register */ |
#define MICREL_KSZ8001_100BTPCR_ADR 0x1f /* 100BASE-TX PHY Control Register */ |
|
/* Basic Control Register bits */ |
#define MICREL_KSZ8001_BCR_DIS_TRANS (1<<0) /* Disable Transmitter */ |
#define MICREL_KSZ8001_BCR_COL_TEST (1<<7) /* Collision Test */ |
#define MICREL_KSZ8001_BCR_DUP (1<<8) /* Duplex Mode */ |
#define MICREL_KSZ8001_BCR_RST_AUTONEG (1<<9) /* Restart Auto-Negotiation */ |
#define MICREL_KSZ8001_BCR_ISOLATE (1<<10) /* Isolate */ |
#define MICREL_KSZ8001_BCR_PWR_DOWN (1<<11) /* Power Down */ |
#define MICREL_KSZ8001_BCR_AUTONEG_EN (1<<12) /* Auto-Negotiation Enable */ |
#define MICREL_KSZ8001_BCR_SPD_SEL (1<<13) /* Speed Select */ |
#define MICREL_KSZ8001_BCR_LOOP_BACK (1<<14) /* Loop Back */ |
#define MICREL_KSZ8001_BCR_RESET (1<<15)/* Reset */ |
|
/* Basic Status Register bits */ |
#define MICREL_KSZ8001_BSR_EC (1<<0) /* Extended Capability */ |
#define MICREL_KSZ8001_BSR_JD (1<<1) /* Jabber Detect */ |
#define MICREL_KSZ8001_BSR_LS (1<<2) /* Link Status */ |
#define MICREL_KSZ8001_BSR_AUTONEG_ABLE (1<<3) /* Auto-Negotiation Ability */ |
#define MICREL_KSZ8001_BSR_RF (1<<4) /* Remote Fault */ |
#define MICREL_KSZ8001_BSR_AUTONEG_CMPLT (1<<5) /* Auto-Negotiation Complete */ |
#define MICREL_KSZ8001_BSR_NP (1<<6) /* No Premble */ |
#define MICREL_KSZ8001_BSR_10BTHD (1<<11) /* 10BASE-T Half Duplex */ |
#define MICREL_KSZ8001_BSR_10BTFD (1<<12) /* 10BASE-T Full Duplex */ |
#define MICREL_KSZ8001_BSR_100BTXHD (1<<13) /* 100BASE-TX Half Duplex */ |
#define MICREL_KSZ8001_BSR_100BTXFD (1<<14) /* 100BASE-TX Full Duplex */ |
#define MICREL_KSZ8001_BSR_100BT4 (1<<15) /* 100BASE-T4 Capable */ |
/openrisc/trunk/orpsocv2/sw/eth/open_eth.h
0,0 → 1,149
|
typedef unsigned int uint; |
|
/* Ethernet configuration registers */ |
typedef struct _oeth_regs { |
uint moder; /* Mode Register */ |
uint int_src; /* Interrupt Source Register */ |
uint int_mask; /* Interrupt Mask Register */ |
uint ipgt; /* Back to Bak Inter Packet Gap Register */ |
uint ipgr1; /* Non Back to Back Inter Packet Gap Register 1 */ |
uint ipgr2; /* Non Back to Back Inter Packet Gap Register 2 */ |
uint packet_len; /* Packet Length Register (min. and max.) */ |
uint collconf; /* Collision and Retry Configuration Register */ |
uint tx_bd_num; /* Transmit Buffer Descriptor Number Register */ |
uint ctrlmoder; /* Control Module Mode Register */ |
uint miimoder; /* MII Mode Register */ |
uint miicommand; /* MII Command Register */ |
uint miiaddress; /* MII Address Register */ |
uint miitx_data; /* MII Transmit Data Register */ |
uint miirx_data; /* MII Receive Data Register */ |
uint miistatus; /* MII Status Register */ |
uint mac_addr0; /* MAC Individual Address Register 0 */ |
uint mac_addr1; /* MAC Individual Address Register 1 */ |
uint hash_addr0; /* Hash Register 0 */ |
uint hash_addr1; /* Hash Register 1 */ |
} oeth_regs; |
|
/* Ethernet buffer descriptor */ |
typedef struct _oeth_bd { |
#if 0 |
ushort len; /* Buffer length */ |
ushort status; /* Buffer status */ |
#else |
uint len_status; |
#endif |
uint addr; /* Buffer address */ |
} oeth_bd; |
|
// From include/asm/board.h |
#define ETH_BASE_ADD 0x92000000 |
|
#define OETH_REG_BASE ETH_BASE_ADD |
#define OETH_BD_BASE (ETH_BASE_ADD + 0x400) |
#define OETH_TOTAL_BD 128 |
#define OETH_MAXBUF_LEN 0x600 |
|
/* Tx BD */ |
#define OETH_TX_BD_READY 0x8000 /* Tx BD Ready */ |
#define OETH_TX_BD_IRQ 0x4000 /* Tx BD IRQ Enable */ |
#define OETH_TX_BD_WRAP 0x2000 /* Tx BD Wrap (last BD) */ |
#define OETH_TX_BD_PAD 0x1000 /* Tx BD Pad Enable */ |
#define OETH_TX_BD_CRC 0x0800 /* Tx BD CRC Enable */ |
|
#define OETH_TX_BD_UNDERRUN 0x0100 /* Tx BD Underrun Status */ |
#define OETH_TX_BD_RETRY 0x00F0 /* Tx BD Retry Status */ |
#define OETH_TX_BD_RETLIM 0x0008 /* Tx BD Retransmission Limit Status */ |
#define OETH_TX_BD_LATECOL 0x0004 /* Tx BD Late Collision Status */ |
#define OETH_TX_BD_DEFER 0x0002 /* Tx BD Defer Status */ |
#define OETH_TX_BD_CARRIER 0x0001 /* Tx BD Carrier Sense Lost Status */ |
#define OETH_TX_BD_STATS (OETH_TX_BD_UNDERRUN | \ |
OETH_TX_BD_RETRY | \ |
OETH_TX_BD_RETLIM | \ |
OETH_TX_BD_LATECOL | \ |
OETH_TX_BD_DEFER | \ |
OETH_TX_BD_CARRIER) |
|
/* Rx BD */ |
#define OETH_RX_BD_EMPTY 0x8000 /* Rx BD Empty */ |
#define OETH_RX_BD_IRQ 0x4000 /* Rx BD IRQ Enable */ |
#define OETH_RX_BD_WRAP 0x2000 /* Rx BD Wrap (last BD) */ |
|
#define OETH_RX_BD_MISS 0x0080 /* Rx BD Miss Status */ |
#define OETH_RX_BD_OVERRUN 0x0040 /* Rx BD Overrun Status */ |
#define OETH_RX_BD_INVSIMB 0x0020 /* Rx BD Invalid Symbol Status */ |
#define OETH_RX_BD_DRIBBLE 0x0010 /* Rx BD Dribble Nibble Status */ |
#define OETH_RX_BD_TOOLONG 0x0008 /* Rx BD Too Long Status */ |
#define OETH_RX_BD_SHORT 0x0004 /* Rx BD Too Short Frame Status */ |
#define OETH_RX_BD_CRCERR 0x0002 /* Rx BD CRC Error Status */ |
#define OETH_RX_BD_LATECOL 0x0001 /* Rx BD Late Collision Status */ |
#define OETH_RX_BD_STATS (OETH_RX_BD_MISS | \ |
OETH_RX_BD_OVERRUN | \ |
OETH_RX_BD_INVSIMB | \ |
OETH_RX_BD_DRIBBLE | \ |
OETH_RX_BD_TOOLONG | \ |
OETH_RX_BD_SHORT | \ |
OETH_RX_BD_CRCERR | \ |
OETH_RX_BD_LATECOL) |
|
/* MODER Register */ |
#define OETH_MODER_RXEN 0x00000001 /* Receive Enable */ |
#define OETH_MODER_TXEN 0x00000002 /* Transmit Enable */ |
#define OETH_MODER_NOPRE 0x00000004 /* No Preamble */ |
#define OETH_MODER_BRO 0x00000008 /* Reject Broadcast */ |
#define OETH_MODER_IAM 0x00000010 /* Use Individual Hash */ |
#define OETH_MODER_PRO 0x00000020 /* Promiscuous (receive all) */ |
#define OETH_MODER_IFG 0x00000040 /* Min. IFG not required */ |
#define OETH_MODER_LOOPBCK 0x00000080 /* Loop Back */ |
#define OETH_MODER_NOBCKOF 0x00000100 /* No Backoff */ |
#define OETH_MODER_EXDFREN 0x00000200 /* Excess Defer */ |
#define OETH_MODER_FULLD 0x00000400 /* Full Duplex */ |
#define OETH_MODER_RST 0x00000800 /* Reset MAC */ |
#define OETH_MODER_DLYCRCEN 0x00001000 /* Delayed CRC Enable */ |
#define OETH_MODER_CRCEN 0x00002000 /* CRC Enable */ |
#define OETH_MODER_HUGEN 0x00004000 /* Huge Enable */ |
#define OETH_MODER_PAD 0x00008000 /* Pad Enable */ |
#define OETH_MODER_RECSMALL 0x00010000 /* Receive Small */ |
|
/* Interrupt Source Register */ |
#define OETH_INT_TXB 0x00000001 /* Transmit Buffer IRQ */ |
#define OETH_INT_TXE 0x00000002 /* Transmit Error IRQ */ |
#define OETH_INT_RXF 0x00000004 /* Receive Frame IRQ */ |
#define OETH_INT_RXE 0x00000008 /* Receive Error IRQ */ |
#define OETH_INT_BUSY 0x00000010 /* Busy IRQ */ |
#define OETH_INT_TXC 0x00000020 /* Transmit Control Frame IRQ */ |
#define OETH_INT_RXC 0x00000040 /* Received Control Frame IRQ */ |
|
/* Interrupt Mask Register */ |
#define OETH_INT_MASK_TXB 0x00000001 /* Transmit Buffer IRQ Mask */ |
#define OETH_INT_MASK_TXE 0x00000002 /* Transmit Error IRQ Mask */ |
#define OETH_INT_MASK_RXF 0x00000004 /* Receive Frame IRQ Mask */ |
#define OETH_INT_MASK_RXE 0x00000008 /* Receive Error IRQ Mask */ |
#define OETH_INT_MASK_BUSY 0x00000010 /* Busy IRQ Mask */ |
#define OETH_INT_MASK_TXC 0x00000020 /* Transmit Control Frame IRQ Mask */ |
#define OETH_INT_MASK_RXC 0x00000040 /* Received Control Frame IRQ Mask */ |
|
/* Control Module Mode Register */ |
#define OETH_CTRLMODER_PASSALL 0x00000001 /* Pass Control Frames */ |
#define OETH_CTRLMODER_RXFLOW 0x00000002 /* Receive Control Flow Enable */ |
#define OETH_CTRLMODER_TXFLOW 0x00000004 /* Transmit Control Flow Enable */ |
|
/* MII Mode Register */ |
#define OETH_MIIMODER_CLKDIV 0x000000FF /* Clock Divider */ |
#define OETH_MIIMODER_NOPRE 0x00000100 /* No Preamble */ |
#define OETH_MIIMODER_RST 0x00000200 /* MIIM Reset */ |
|
/* MII Command Register */ |
#define OETH_MIICOMMAND_SCANSTAT 0x00000001 /* Scan Status */ |
#define OETH_MIICOMMAND_RSTAT 0x00000002 /* Read Status */ |
#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */ |
|
/* MII Address Register */ |
#define OETH_MIIADDRESS_FIAD 0x0000001F /* PHY Address */ |
#define OETH_MIIADDRESS_RGAD 0x00001F00 /* RGAD Address */ |
|
/* MII Status Register */ |
#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */ |
#define OETH_MIISTATUS_BUSY 0x00000002 /* MII Busy */ |
#define OETH_MIISTATUS_NVALID 0x00000004 /* Data in MII Status Register is invalid */ |
|
/openrisc/trunk/orpsocv2/sw/eth/eth-int.c
0,0 → 1,962
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet test code //// |
//// //// |
//// Description //// |
//// ORPSoC test software //// |
//// //// |
//// To Do: //// |
//// - It's a simple test for now, but could be adapted for //// |
//// standalone use. //// |
//// //// |
//// 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 "support.h" |
#include "board.h" |
#include "spr_defs.h" |
#include "int.h" |
#include "uart.h" |
#include "open_eth.h" |
|
#include "ethphy_micrel.h" |
|
/* Dummy exception functions */ |
void buserr_except(){} |
void dpf_except(){} |
void ipf_except(){} |
void lpint_except(){} |
void align_except(){} |
void illegal_except(){} |
void hpint_except(){} |
void dtlbmiss_except(){} |
void itlbmiss_except(){} |
void range_except(){} |
void syscall_except(){} |
void res1_except(){} |
void trap_except(){} |
void res2_except(){} |
|
/* Exception efective address */ |
volatile unsigned long except_ea; |
|
/* Eception PC */ |
volatile unsigned long except_pc; |
|
volatile unsigned tx_done; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
void oeth_printregs(void); |
void ethphy_init(void); |
void oeth_dump_bds(); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(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 */ |
#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 8 |
#define OETH_TXBD_NUM 8 |
#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 2048 |
#define OETH_TX_BUFF_SIZE 2048 |
|
/* 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 |
*/ |
#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; |
}; |
|
|
void oeth_printregs(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
printk("Oeth regs: Mode Register : 0x%lx\n",(unsigned long) regs->moder); /* Mode Register */ |
printk("Oeth regs: Interrupt Source Register 0x%lx\n", (unsigned long) regs->int_src); /* Interrupt Source Register */ |
printk("Oeth regs: Interrupt Mask Register 0x%lx\n",(unsigned long) regs->int_mask); /* Interrupt Mask Register */ |
printk("Oeth regs: Back to Bak Inter Packet Gap Register 0x%lx\n",(unsigned long) regs->ipgt); /* Back to Bak Inter Packet Gap Register */ |
printk("Oeth regs: Non Back to Back Inter Packet Gap Register 1 0x%lx\n",(unsigned long) regs->ipgr1); /* Non Back to Back Inter Packet Gap Register 1 */ |
printk("Oeth regs: Non Back to Back Inter Packet Gap Register 2 0x%lx\n",(unsigned long) regs->ipgr2); /* Non Back to Back Inter Packet Gap Register 2 */ |
printk("Oeth regs: Packet Length Register (min. and max.) 0x%lx\n",(unsigned long) regs->packet_len); /* Packet Length Register (min. and max.) */ |
printk("Oeth regs: Collision and Retry Configuration Register 0x%lx\n",(unsigned long) regs->collconf); /* Collision and Retry Configuration Register */ |
printk("Oeth regs: Transmit Buffer Descriptor Number Register 0x%lx\n",(unsigned long) regs->tx_bd_num); /* Transmit Buffer Descriptor Number Register */ |
printk("Oeth regs: Control Module Mode Register 0x%lx\n",(unsigned long) regs->ctrlmoder); /* Control Module Mode Register */ |
printk("Oeth regs: MII Mode Register 0x%lx\n",(unsigned long) regs->miimoder); /* MII Mode Register */ |
printk("Oeth regs: MII Command Register 0x%lx\n",(unsigned long) regs->miicommand); /* MII Command Register */ |
printk("Oeth regs: MII Address Register 0x%lx\n",(unsigned long) regs->miiaddress); /* MII Address Register */ |
printk("Oeth regs: MII Transmit Data Register 0x%lx\n",(unsigned long) regs->miitx_data); /* MII Transmit Data Register */ |
printk("Oeth regs: MII Receive Data Register 0x%lx\n",(unsigned long) regs->miirx_data); /* MII Receive Data Register */ |
printk("Oeth regs: MII Status Register 0x%lx\n",(unsigned long) regs->miistatus); /* MII Status Register */ |
printk("Oeth regs: MAC Individual Address Register 0 0x%lx\n",(unsigned long) regs->mac_addr0); /* MAC Individual Address Register 0 */ |
printk("Oeth regs: MAC Individual Address Register 1 0x%lx\n",(unsigned long) regs->mac_addr1); /* MAC Individual Address Register 1 */ |
printk("Oeth regs: Hash Register 0 0x%lx\n",(unsigned long) regs->hash_addr0); /* Hash Register 0 */ |
printk("Oeth regs: Hash Register 1 0x%lx\n",(unsigned long) regs->hash_addr1); /* Hash Register 1 */ |
|
} |
|
static int last_char; |
|
void spin_cursor(void) |
{ |
#ifdef RTLSIM |
return; |
#endif |
volatile unsigned int i; // So the loop doesn't get optimised away |
printk(" \r"); |
if (last_char == 0) |
printk("/"); |
else if (last_char == 1) |
printk("-"); |
else if (last_char == 2) |
printk("\\"); |
else if (last_char == 3) |
printk("|"); |
else if (last_char == 4) |
printk("/"); |
else if (last_char == 5) |
printk("-"); |
else if (last_char == 6) |
printk("\\"); |
else if (last_char == 7) |
{ |
printk("|"); |
last_char=-1; |
} |
|
last_char++; |
|
for(i=0;i<20000;i++); |
|
} |
|
#define PHYNUM 0 |
|
/* 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; /* Basic Control Register */ |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
|
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
|
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 ethphy_init(void) |
{ |
volatile int i; |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Init the Micrel KSZ80001L PHY */ |
/* First reset it */ |
|
/* printk("Oeth: regs->miistatus %x regs->miirx_data %x\n",regs->miistatus, regs->miirx_data); */ |
/* regs->miiaddress = (MICREL_KSZ8001_BCR_ADR << 8); /\* PHY's Basic Control Register *\/ */ |
/* regs->miitx_data = MICREL_KSZ8001_BCR_RESET; */ |
/* regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; */ |
/* printk("Oeth: regs->miiaddress %x regs->miicommand %x\n",regs->miiaddress, regs->miicommand); */ |
/* regs->miicommand = 0; */ |
/* while(regs->miistatus & OETH_MIISTATUS_BUSY) */ |
/* spin_cursor(); */ |
/* printk("\r"); */ |
|
|
printk("Oeth: Reading PHY r0 (status reg)\n"); |
regs->miiaddress = MICREL_KSZ8001_BCR_ADR<<8 | PHYNUM; /* Basic Control Register */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
|
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
|
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
printk("\r"); |
|
/* while (regs->miirx_data & MICREL_KSZ8001_BCR_RESET) */ |
/* { */ |
/* regs->miiaddress = MICREL_KSZ8001_BCR_ADR<<8; /\* Basic Control Register *\/ */ |
/* regs->miitx_data = 0; */ |
/* regs->miicommand = OETH_MIICOMMAND_RSTAT; */ |
/* regs->miicommand = 0; */ |
/* while(regs->miistatus & OETH_MIISTATUS_BUSY) */ |
/* spin_cursor(); */ |
/* } */ |
/* printk("\r"); */ |
|
printk("\nOeth: PHY r0 value: %x\n",regs->miirx_data); |
|
/* PHY reset and confirmed as such */ |
|
/* Now read the link status */ |
regs->miiaddress = MICREL_KSZ8001_BSR_ADR<<8 | PHYNUM; /* Basic Status Register */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
|
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
|
printk("\r"); |
printk("Oeth: PHY BSR: 0x%x\n",regs->miirx_data & 0xffff); |
|
/* Read the operation mode */ |
regs->miiaddress = MICREL_KSZ8001_100BTPCR_ADR<<8 | PHYNUM; /* 100BASE-TX */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
printk("\r"); |
printk("Oeth: PHY 100BASE-TX PHY Control Register: 0x%x\n",regs->miirx_data); |
|
|
/* Read the PHY identification register 1 */ |
regs->miiaddress = MICREL_KSZ8001_PI1_ADR<<8 | PHYNUM; /* PI1 */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
printk("\r"); |
printk("Oeth: PHY PHY Identifier I: 0x%x\n",regs->miirx_data); |
|
/* Read the PHY identification register 2 */ |
regs->miiaddress = MICREL_KSZ8001_PI2_ADR<<8 | PHYNUM; /* PI2 */ |
regs->miitx_data = 0; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/ |
regs->miicommand = 0; |
while(regs->miistatus & OETH_MIISTATUS_BUSY) |
spin_cursor(); |
printk("\r"); |
printk("Oeth: PHY PHY Identifier II: 0x%x\n",regs->miirx_data); |
|
|
} |
|
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/*printk("\nbefore reset\n\n"); |
oeth_printregs();*/ |
|
/* 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 */ |
|
//printk("\nafter reset\n\n"); |
//oeth_printregs(); |
|
/* 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; |
|
printk("\nafter config\n\n"); |
oeth_printregs(); |
|
// 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 for TX buffers*/ |
for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) { |
for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) { |
//tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[k].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
/* Setup for RX buffers */ |
for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) { |
for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) { |
rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; /* Enable interrupt */ |
rx_bd[k].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; /* Final buffer has wrap bit set */ |
|
/* Enable receiver and transmiter |
*/ |
regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN; |
|
return; |
} |
|
/* Find the next available transmit buffer */ |
struct oeth_bd* get_next_tx_bd() |
{ |
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* 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 NOT ready for transmit. ie we can manipulate it */ |
{ |
printk("Oeth: Using TX_bd at 0x%lx\n",(unsigned long)&tx_bd[i]); |
return (struct oeth_bd*) &tx_bd[i]; |
} |
} |
|
printk("No free tx buffers\n"); |
/* Set to null our returned buffer */ |
tx_bd = (volatile oeth_bd *) 0; |
return (struct oeth_bd*) tx_bd; |
|
} |
|
|
/* print packet contents */ |
static void |
oeth_print_packet(unsigned long add, int len) |
{ |
int i; |
printk("ipacket: add = %lx len = %d\n", add, len); |
for(i = 0; i < len; i++) { |
if(!(i % 16)) |
printk("\n"); |
printk(" %.2x", *(((unsigned char *)add) + i)); |
} |
printk("\n"); |
} |
|
/* 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; |
|
if((tx_bd = (volatile oeth_bd *) get_next_tx_bd()) == NULL) |
{ |
printk("No more TX buffers available\n"); |
return; |
} |
printk("Oeth: TX_bd buffer address: 0x%lx\n",(unsigned long) tx_bd->addr); |
|
/* 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; |
|
printk("Oeth: Copying %d bytes from 0x%lx to TX_bd buffer at 0x%lx\n",length,(unsigned long) data,(unsigned long) tx_bd->addr); |
|
/* 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); |
} |
printk("Oeth: Data copied to buffer\n"); |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
//oeth_print_packet(tx_bd->addr, (tx_bd->len_status >> 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); |
|
oeth_dump_bds(); |
|
printk("Oeth: MODER addr: 0x%x\n", regs->moder); |
|
printk("Oeth: TXBD Status 0x%x\n", tx_bd->len_status); |
|
i=0; |
|
/* Wait for BD READY bit to be cleared, indicating it's been sent */ |
/* Not if we've got interrupts enabled. */ |
/* |
while (OETH_TX_BD_READY & tx_bd->len_status) |
{ |
#ifndef RTLSIM |
//for(i=0;i<40000;i++); |
//printk("Oeth: TXBD Status 0x%x\n", tx_bd->len_status); |
//oeth_printregs(); |
spin_cursor(); |
if (i++%64==63) {oeth_dump_bds();} |
#endif |
} |
*/ |
|
return; |
|
|
} |
|
/* enable RX, loop waiting for arrived packets and print them out */ |
void oeth_monitor_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Set RXEN in MAC MODER */ |
regs->moder = OETH_MODER_RXEN | regs->moder; |
|
|
volatile oeth_bd *rx_bd; |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
volatile int i; |
|
while (1) |
{ |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
if (!(rx_bd[i].len_status & OETH_RX_BD_EMPTY)) /* Not empty */ |
{ |
// Something in this buffer! |
printk("Oeth: RX in buf %d - len_status: 0x%lx\n",i, rx_bd[i].len_status); |
oeth_print_packet(rx_bd[i].addr, rx_bd[i].len_status >> 16); |
/* Clear recieved bit */ |
rx_bd[i].len_status |= OETH_RX_BD_EMPTY; |
printk("\t end of packet\n\n"); |
} |
} |
} |
} |
|
/* Print out all buffer descriptors */ |
void oeth_dump_bds() |
{ |
unsigned long* bd_base = (unsigned long*) OETH_BD_BASE; |
|
int i; |
for(i=0;i<OETH_TXBD_NUM;i++) |
{ |
printk("oeth: tx_bd%d: len_status: %lx ",i,*bd_base++); |
printk("addr: %lx\n", *bd_base++); |
} |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
printk("oeth: rx_bd%d: len_status: %lx ",i,*bd_base++); |
printk("addr: %lx\n", *bd_base++); |
} |
|
} |
|
|
|
void send_packet() |
{ |
/* This should be 98 bytes big */ |
char ping_packet[] = { |
0x00, 0x24, 0xe8, 0x91, 0x7c, 0x0d, /*DST MAC*/ |
0x00, 0xe0, 0x18, 0x73, 0x1d, 0x05, /*SRC MAC*/ |
0x08, 0x00, /*TYPE*/ |
/* IP */ |
0x45, /* Version, header length*/ |
0x00, /* Differentiated services field */ |
0x00, 0x54, /* Total length */ |
0x00, 0x00, /* Identification */ |
0x40, /* Flags */ |
0x00, /* Fragment offset */ |
0x40, /* Time to live */ |
0x01, /* Protocol (0x01 = ICMP */ |
0xef, 0xf3, /* Header checksum */ |
0xc0, 0xa8, 0x64, 0xfb, /* Source IP */ |
0xc0, 0xa8, 0x64, 0x69, /* Dest. IP */ |
/* ICMP Message body */ |
0x08, 0x00, 0x9a, 0xd4, 0xc8, 0x18, 0x00, 0x01, 0xd9, 0x8c, 0x54, |
0x4a, 0x7b, 0x37, 0x01, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, |
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, |
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, |
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, |
0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 |
}; |
|
/*Send packet */ |
tx_packet((void*) ping_packet, 98); |
|
} |
|
void printstring(char* string) |
{ |
while (*string) uart_putc(*string++); |
} |
|
|
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
#ifndef RTLSIM |
printk("."); |
|
printk("\n=tx_ | %x | %x | %x | %x | %x | %x | %x | %x\n", |
((oeth_bd *)(OETH_BD_BASE))->len_status, |
((oeth_bd *)(OETH_BD_BASE+8))->len_status, |
((oeth_bd *)(OETH_BD_BASE+16))->len_status, |
((oeth_bd *)(OETH_BD_BASE+24))->len_status, |
((oeth_bd *)(OETH_BD_BASE+32))->len_status, |
((oeth_bd *)(OETH_BD_BASE+40))->len_status, |
((oeth_bd *)(OETH_BD_BASE+48))->len_status, |
((oeth_bd *)(OETH_BD_BASE+56))->len_status); |
|
printk("=rx_ | %x | %x | %x | %x | %x | %x | %x | %x\n", |
((oeth_bd *)(OETH_BD_BASE+64))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+8))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+16))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+24))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+32))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+40))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+48))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+56))->len_status); |
#endif |
|
|
/* 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(); |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
#ifndef RTLSIM |
printk("b"); |
#endif |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
|
#if 0 |
if (serviced == 0) { |
void die(const char * str, struct pt_regs * regs, long err); |
int show_stack(unsigned long *esp); |
printk("!"); |
// printk("unserviced irq\n"); |
// show_stack(NULL); |
// die("unserviced irq\n", regs, 801); |
} |
#endif |
|
if (serviced == 0) |
#ifdef RTLSIM |
report(0); |
#else |
printk("\neth interrupt called but nothing serviced\n"); |
#endif |
else /* Something happened ... either RX or TX */ |
#ifdef RTLSIM |
report(0xdeaddead); |
#else |
printk(" | serviced 0x%x\n", serviced); |
#endif |
|
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; |
|
printk("r"); |
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
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; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
|
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
} |
|
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
|
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. */ |
|
#ifdef RTLSIM |
report(pkt_len); |
#else |
oeth_print_packet(rx_bdp[i].addr, rx_bdp[i].len_status >> 16); |
printk("\t end of packet\n\n"); |
#endif |
|
/* 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 */ |
|
|
} |
} |
} |
} |
|
|
|
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; |
|
printk("T%d",i); |
|
} |
} |
return; |
} |
|
|
|
int main () |
{ |
/* Install interrupt handler */ |
excpt_int = (unsigned long)int_main; |
|
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(IRQ_ETH_0, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
mtspr (SPR_SR, mfspr (SPR_SR) | SPR_SR_IEE); |
|
last_char=0; /* Variable init for spin_cursor() */ |
|
#ifndef RTLSIM |
uart_init(); // init the UART before we can printf |
printf("\n\teth interrupts test\n\n"); |
#endif |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
//scan_ethphys(); /* Scan MIIM bus for PHYs */ |
//ethphy_init(); /* Attempt reset and configuration of PHY via MIIM */ |
//ethmac_scanstatus(); /* Enable scanning of status register via MIIM */ |
|
//oeth_monitor_rx(); |
|
/* clear tx_done, the tx interrupt handler will set it when it's been transmitted */ |
tx_done = 0; |
|
send_packet(); |
|
while(tx_done==0); |
|
#ifdef RTLSIM |
report(0xdeaddead); |
or32_exit(0); |
#else |
while(1) |
spin_cursor(); |
#endif |
|
} |
/openrisc/trunk/orpsocv2/sw/eth/except.S
0,0 → 1,193
#include "spr_defs.h" |
#include "board.h" |
|
// Linked from 0x200, so add 0x200 to the .org for the physical address |
.section .vectors, "ax" |
|
/* |
.org 0x100 |
|
_reset: |
l.nop |
l.j _reset_except |
l.nop |
*/ |
.org 0x000 |
|
_except_200: |
l.nop |
l.j _buserr_except |
l.nop |
|
.org 0x100 |
|
_except_300: |
l.nop |
l.j _dpf_except |
l.nop |
|
.org 0x200 |
|
_except_400: |
l.nop |
l.j _ipf_except |
l.nop |
|
.org 0x300 |
|
_except_500: |
l.nop |
l.j _lpint_except |
l.nop |
|
.org 0x400 |
|
_except_600: |
l.nop |
l.j _align_except |
l.nop |
|
.org 0x500 |
|
_except_700: |
l.nop |
l.j _illegal_except |
l.nop |
|
.org 0x600 |
|
_int_vector: |
l.nop |
l.addi r1,r1,-116 |
l.sw 0x18(r1),r9 |
l.jal store_regs |
l.nop |
|
l.mfspr r3,r0,SPR_EPCR_BASE |
l.movhi r4,hi(_except_pc) |
l.ori r4,r4,lo(_except_pc) |
l.sw 0(r4),r3 |
|
l.mfspr r3,r0,SPR_EEAR_BASE |
l.movhi r4,hi(_except_ea) |
l.ori r4,r4,lo(_except_ea) |
l.sw 0(r4),r3 |
|
l.movhi r9,hi(end_except) |
l.ori r9,r9,lo(end_except) |
l.movhi r10,hi(_excpt_int) |
l.ori r10,r10,lo(_excpt_int) |
l.lwz r10,0(r10) |
l.jr r10 |
l.nop |
|
.org 0x700 |
|
_except_900: |
l.nop |
l.j _dtlbmiss_except |
l.nop |
|
.org 0x800 |
|
_except_a00: |
l.nop |
l.j _itlbmiss_except |
l.nop |
|
.org 0x900 |
|
_except_b00: |
l.nop |
l.j _range_except |
l.nop |
|
.org 0xa00 |
|
_except_c00: |
l.nop |
l.j _syscall_except |
l.nop |
|
.org 0xb00 |
|
_except_d00: |
l.nop |
l.j _res1_except |
l.nop |
|
|
.org 0xc00 |
_except_e00: |
l.nop |
l.j _trap_except |
l.nop |
|
|
store_regs: |
l.sw 0x00(r1),r3 |
l.sw 0x04(r1),r4 |
l.sw 0x08(r1),r5 |
l.sw 0x0c(r1),r6 |
l.sw 0x10(r1),r7 |
l.sw 0x14(r1),r8 |
l.sw 0x1c(r1),r10 |
l.sw 0x20(r1),r11 |
l.sw 0x24(r1),r12 |
l.sw 0x28(r1),r13 |
l.sw 0x2c(r1),r14 |
l.sw 0x30(r1),r15 |
l.sw 0x34(r1),r16 |
l.sw 0x38(r1),r17 |
l.sw 0x3c(r1),r18 |
l.sw 0x40(r1),r19 |
l.sw 0x44(r1),r20 |
l.sw 0x48(r1),r21 |
l.sw 0x4c(r1),r22 |
l.sw 0x50(r1),r23 |
l.sw 0x54(r1),r24 |
l.sw 0x58(r1),r25 |
l.sw 0x5c(r1),r26 |
l.sw 0x60(r1),r27 |
l.sw 0x64(r1),r28 |
l.sw 0x68(r1),r29 |
l.sw 0x6c(r1),r30 |
l.sw 0x70(r1),r31 |
l.jr r9 |
l.nop |
|
end_except: |
l.lwz r3,0x00(r1) |
l.lwz r4,0x04(r1) |
l.lwz r5,0x08(r1) |
l.lwz r6,0x0c(r1) |
l.lwz r7,0x10(r1) |
l.lwz r8,0x14(r1) |
l.lwz r9,0x18(r1) |
l.lwz r10,0x1c(r1) |
l.lwz r11,0x20(r1) |
l.lwz r12,0x24(r1) |
l.lwz r13,0x28(r1) |
l.lwz r14,0x2c(r1) |
l.lwz r15,0x30(r1) |
l.lwz r16,0x34(r1) |
l.lwz r17,0x38(r1) |
l.lwz r18,0x3c(r1) |
l.lwz r19,0x40(r1) |
l.lwz r20,0x44(r1) |
l.lwz r21,0x48(r1) |
l.lwz r22,0x4c(r1) |
l.lwz r23,0x50(r1) |
l.lwz r24,0x54(r1) |
l.lwz r25,0x58(r1) |
l.lwz r26,0x5c(r1) |
l.lwz r27,0x60(r1) |
l.lwz r28,0x64(r1) |
l.lwz r29,0x68(r1) |
l.lwz r30,0x6c(r1) |
l.lwz r31,0x70(r1) |
l.addi r1,r1,116 |
l.mtspr r0,r9,SPR_EPCR_BASE |
l.rfe |
l.nop |
|
openrisc/trunk/orpsocv2/sw/eth/except.S
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: openrisc/trunk/orpsocv2/sw/eth/Makefile
===================================================================
--- openrisc/trunk/orpsocv2/sw/eth/Makefile (nonexistent)
+++ openrisc/trunk/orpsocv2/sw/eth/Makefile (revision 44)
@@ -0,0 +1,27 @@
+include ../support/Makefile.inc
+
+
+# We use our own except here, containing interrupt handler vector
+common = except.o ../support/libsupport.a
+
+
+all: eth-basic eth-int
+
+eth-basic: eth-basic.o ../support/reset-nocache.o $(common)
+ $(OR32_TOOL_PREFIX)-gcc $(GCC_OPT) -T ../support/orp.ld $? -o $@.or32 $(GCC_LIB_OPTS)
+ $(OR32_TOOL_PREFIX)-objcopy -O binary $@.or32 $@.bin
+ ../utils/bin2hex $@.bin 1 -size_word > $@$(FLASH_MEM_HEX_FILE_SUFFIX).hex
+ ../utils/bin2vmem $@.bin > $@.vmem
+
+eth-int: eth-int.o ../support/reset-nocache.o $(common)
+ $(OR32_TOOL_PREFIX)-gcc $(GCC_OPT) -T ../support/orp.ld $? -o $@.or32 $(GCC_LIB_OPTS)
+ $(OR32_TOOL_PREFIX)-objcopy -O binary $@.or32 $@.bin
+ ../utils/bin2hex $@.bin 1 -size_word > $@$(FLASH_MEM_HEX_FILE_SUFFIX).hex
+ ../utils/bin2vmem $@.bin > $@.vmem
+
+
+%.o: %.c
+ $(OR32_TOOL_PREFIX)-gcc -DRTLSIM -I ../support $(GCC_OPT) -O2 -g -c -Wall $< -o $@
+
+%.o: %.S
+ $(OR32_TOOL_PREFIX)-gcc -DRTLSIM -I ../support $(GCC_OPT) -O2 -g -c -Wall $< -o $@
Index: openrisc/trunk/orpsocv2/sw/dhry/dhry.c
===================================================================
--- openrisc/trunk/orpsocv2/sw/dhry/dhry.c (revision 43)
+++ openrisc/trunk/orpsocv2/sw/dhry/dhry.c (revision 44)
@@ -16,8 +16,9 @@
*/
#include "support.h"
#include "dhry.h"
-
+#ifndef NUM_RUNS
#define NUM_RUNS (1)
+#endif
#define DLX_FREQ 200 /* in MHz */
#define PROC_6 1
/openrisc/trunk/orpsocv2/sw/dhry/Makefile
4,6 → 4,12
#common = ../support/libsupport.a |
common = ../support/libsupport.a ../support/except.o |
|
ifdef NUM_RUNS |
NUM_RUNS=($(NUM_RUNS)) |
else |
NUM_RUNS="(10)" |
endif |
|
all: $(cases) |
|
dhry-nocache-O0: dhry-O0.o ../support/reset-nocache.o $(common) |
28,7 → 34,7
|
|
dhry-O0.o: dhry.c |
$(OR32_TOOL_PREFIX)-gcc -I../support -O0 $(GCC_OPT) $? -mhard-div -c -o $@ |
$(OR32_TOOL_PREFIX)-gcc -DNUM_RUNS=$(NUM_RUNS) -I../support -O0 $(GCC_OPT) $? -mhard-div -c -o $@ |
|
dhry-O2.o: dhry.c |
$(OR32_TOOL_PREFIX)-gcc -I../support -O2 $(GCC_OPT) $? -mhard-div -c -o $@ |
$(OR32_TOOL_PREFIX)-gcc -DNUM_RUNS=$(NUM_RUNS) -I../support -O2 $(GCC_OPT) $? -mhard-div -c -o $@ |
/openrisc/trunk/orpsocv2/sw/support/int.h
13,3 → 13,6
|
/* Initialize routine */ |
int int_init(); |
|
/* Actual interrup handler function */ |
void int_main(); |
/openrisc/trunk/orpsocv2/sw/support/Makefile.inc
4,7 → 4,7
|
#GCC_LIB_OPTS= -lgcc -liberty |
|
GCC_OPT=-mhard-mul |
GCC_OPT=-mhard-mul -g |
|
ifdef UART_PRINTF |
GCC_OPT += -DUART_PRINTF |
/openrisc/trunk/orpsocv2/sw/support/except.S
1,6 → 1,6
#include "spr_defs.h" |
|
// Linked from 0x200, so subtract 0x200 from each .org |
// Linked from 0x200, so add 0x200 to the .org for the physical address |
.section .vectors, "ax" |
|
/* |
/openrisc/trunk/orpsocv2/sw/support/board.h
20,7 → 20,8
#define UART_BASE 0x90000000 |
#define UART_IRQ 19 |
#define ETH_BASE 0xD0000000 |
#define ETH_IRQ 15 |
//#define ETH_IRQ 15 |
#define IRQ_ETH_0 (4) /* interrupt source for Ethernet dvice 0 */ |
#define MC_BASE_ADDR 0x60000000 |
#define SPI_BASE 0xa0000000 |
|