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

Subversion Repositories openrisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/orpsocv2/bench/verilog
    from Rev 40 to Rev 44
    Reverse comparison

Rev 40 → Rev 44

/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
/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
 
 
 
 
/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
 
/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
/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
 
/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);
/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);
 

powered by: WebSVN 2.1.0

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