URL
https://opencores.org/ocsvn/ethmac/ethmac/trunk
Subversion Repositories ethmac
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 168 to Rev 169
- ↔ Reverse comparison
Rev 168 → Rev 169
/trunk/bench/verilog/eth_phy_defines.v
0,0 → 1,87
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name: eth_phy_defines.v //// |
//// //// |
//// This file is part of the "Ethernet MAC" 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 $ |
// |
// |
|
// Address of PHY device (LXT971A) |
`define ETH_PHY_ADDR 5'h01 |
|
// 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 |
|
|
|
|
/trunk/bench/verilog/wb_slave_behavioral.v
0,0 → 1,407
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name: wb_slave_behavioral.v //// |
//// //// |
//// This file is part of the "PCI bridge" project //// |
//// http://www.opencores.org/cores/pci/ //// |
//// //// |
//// Author(s): //// |
//// - Tadej Markovic, tadej@opencores.org //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Tadej Markovic, tadej@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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.2 2002/03/06 09:10:56 mihad |
// Added missing include statements |
// |
// Revision 1.1 2002/02/01 13:39:43 mihad |
// Initial testbench import. Still under development |
// |
// |
|
`include "timescale.v" |
`include "wb_model_defines.v" |
module WB_SLAVE_BEHAVIORAL |
( |
CLK_I, |
RST_I, |
ACK_O, |
ADR_I, |
CYC_I, |
DAT_O, |
DAT_I, |
ERR_O, |
RTY_O, |
SEL_I, |
STB_I, |
WE_I, |
CAB_I |
); |
|
/*------------------------------------------------------------------------------------------------------ |
WISHBONE signals |
------------------------------------------------------------------------------------------------------*/ |
input CLK_I; |
input RST_I; |
output ACK_O; |
input `WB_ADDR_TYPE ADR_I; |
input CYC_I; |
output `WB_DATA_TYPE DAT_O; |
input `WB_DATA_TYPE DAT_I; |
output ERR_O; |
output RTY_O; |
input `WB_SEL_TYPE SEL_I; |
input STB_I; |
input WE_I; |
input CAB_I; |
|
reg `WB_DATA_TYPE DAT_O; |
|
/*------------------------------------------------------------------------------------------------------ |
Asynchronous dual-port RAM signals for storing and fetching the data |
------------------------------------------------------------------------------------------------------*/ |
//reg `WB_DATA_TYPE wb_memory [0:16777215]; // WB memory - 24 addresses connected - 2 LSB not used |
reg `WB_DATA_TYPE wb_memory [0:1048575]; // WB memory - 20 addresses connected - 2 LSB not used |
reg `WB_DATA_TYPE mem_wr_data_out; |
reg `WB_DATA_TYPE mem_rd_data_in; |
|
/*------------------------------------------------------------------------------------------------------ |
Maximum values for WAIT and RETRY counters and which response !!! |
------------------------------------------------------------------------------------------------------*/ |
reg [2:0] a_e_r_resp; // tells with which cycle_termination_signal must wb_slave respond ! |
reg [3:0] wait_cyc; |
reg [7:0] max_retry; |
|
// assign registers to default state while in reset |
always@(RST_I) |
begin |
if (RST_I) |
begin |
a_e_r_resp <= 3'b000; // do not respond |
wait_cyc <= 4'b0; // no wait cycles |
max_retry <= 8'h0; // no retries |
end |
end //reset |
|
task cycle_response; |
input [2:0] ack_err_rty_resp; // acknowledge, error or retry response input flags |
input [3:0] wait_cycles; // if wait cycles before each data termination cycle (ack, err or rty) |
input [7:0] retry_cycles; // noumber of retry cycles before acknowledge cycle |
begin |
// assign values |
a_e_r_resp <= #1 ack_err_rty_resp; |
wait_cyc <= #1 wait_cycles; |
max_retry <= #1 retry_cycles; |
end |
endtask // cycle_response |
|
/*------------------------------------------------------------------------------------------------------ |
Tasks for writing and reading to and from memory !!! |
------------------------------------------------------------------------------------------------------*/ |
reg `WB_ADDR_TYPE task_wr_adr_i; |
reg `WB_ADDR_TYPE task_rd_adr_i; |
reg `WB_DATA_TYPE task_dat_i; |
reg `WB_DATA_TYPE task_dat_o; |
reg `WB_SEL_TYPE task_sel_i; |
reg task_wr_data; |
reg task_data_written; |
reg `WB_DATA_TYPE task_mem_wr_data; |
|
// write to memory |
task wr_mem; |
input `WB_ADDR_TYPE adr_i; |
input `WB_DATA_TYPE dat_i; |
input `WB_SEL_TYPE sel_i; |
begin |
task_data_written = 0; |
task_wr_adr_i = adr_i; |
task_dat_i = dat_i; |
task_sel_i = sel_i; |
task_wr_data = 1; |
wait(task_data_written); |
task_wr_data = 0; |
end |
endtask |
|
// read from memory |
task rd_mem; |
input `WB_ADDR_TYPE adr_i; |
output `WB_DATA_TYPE dat_o; |
input `WB_SEL_TYPE sel_i; |
begin |
task_rd_adr_i = adr_i; |
task_sel_i = sel_i; |
#1; |
dat_o = task_dat_o; |
end |
endtask |
|
/*------------------------------------------------------------------------------------------------------ |
Internal signals and logic |
------------------------------------------------------------------------------------------------------*/ |
reg calc_ack; |
reg calc_err; |
reg calc_rty; |
|
reg [7:0] retry_cnt; |
reg [7:0] retry_num; |
reg retry_expired; |
|
// Retry counter |
always@(posedge RST_I or posedge CLK_I) |
begin |
if (RST_I) |
retry_cnt <= #1 8'h00; |
else |
begin |
if (calc_ack || calc_err) |
retry_cnt <= #1 8'h00; |
else if (calc_rty) |
retry_cnt <= #1 retry_num; |
end |
end |
|
always@(retry_cnt or max_retry) |
begin |
if (retry_cnt < max_retry) |
begin |
retry_num = retry_cnt + 1'b1; |
retry_expired = 1'b0; |
end |
else |
begin |
retry_num = retry_cnt; |
retry_expired = 1'b1; |
end |
end |
|
reg [3:0] wait_cnt; |
reg [3:0] wait_num; |
reg wait_expired; |
|
// Wait counter |
always@(posedge RST_I or posedge CLK_I) |
begin |
if (RST_I) |
wait_cnt <= #1 4'h0; |
else |
begin |
if (wait_expired || ~STB_I) |
wait_cnt <= #1 4'h0; |
else |
wait_cnt <= #1 wait_num; |
end |
end |
|
always@(wait_cnt or wait_cyc or STB_I or a_e_r_resp or retry_expired) |
begin |
if ((wait_cyc > 0) && (STB_I)) |
begin |
if (wait_cnt < wait_cyc) // 4'h2) |
begin |
wait_num = wait_cnt + 1'b1; |
wait_expired = 1'b0; |
calc_ack = 1'b0; |
calc_err = 1'b0; |
calc_rty = 1'b0; |
end |
else |
begin |
wait_num = wait_cnt; |
wait_expired = 1'b1; |
if (a_e_r_resp == 3'b100) |
begin |
calc_ack = 1'b1; |
calc_err = 1'b0; |
calc_rty = 1'b0; |
end |
else |
if (a_e_r_resp == 3'b010) |
begin |
calc_ack = 1'b0; |
calc_err = 1'b1; |
calc_rty = 1'b0; |
end |
else |
if (a_e_r_resp == 3'b001) |
begin |
calc_err = 1'b0; |
if (retry_expired) |
begin |
calc_ack = 1'b1; |
calc_rty = 1'b0; |
end |
else |
begin |
calc_ack = 1'b0; |
calc_rty = 1'b1; |
end |
end |
else |
begin |
calc_ack = 1'b0; |
calc_err = 1'b0; |
calc_rty = 1'b0; |
end |
end |
end |
else |
if ((wait_cyc == 0) && (STB_I)) |
begin |
wait_num = 2'h0; |
wait_expired = 1'b1; |
if (a_e_r_resp == 3'b100) |
begin |
calc_ack = 1'b1; |
calc_err = 1'b0; |
calc_rty = 1'b0; |
end |
else if (a_e_r_resp == 3'b010) |
begin |
calc_ack = 1'b0; |
calc_err = 1'b1; |
calc_rty = 1'b0; |
end |
else if (a_e_r_resp == 3'b001) |
begin |
calc_err = 1'b0; |
if (retry_expired) |
begin |
calc_ack = 1'b1; |
calc_rty = 1'b0; |
end |
else |
begin |
calc_ack = 1'b0; |
calc_rty = 1'b1; |
end |
end |
else |
begin |
calc_ack = 1'b0; |
calc_err = 1'b0; |
calc_rty = 1'b0; |
end |
end |
else |
begin |
wait_num = 2'h0; |
wait_expired = 1'b0; |
calc_ack = 1'b0; |
calc_err = 1'b0; |
calc_rty = 1'b0; |
end |
end |
|
wire rd_sel = (CYC_I && STB_I && ~WE_I); |
wire wr_sel = (CYC_I && STB_I && WE_I); |
|
// Generate cycle termination signals |
assign ACK_O = calc_ack && STB_I; |
assign ERR_O = calc_err && STB_I; |
assign RTY_O = calc_rty && STB_I; |
|
// Assign address to asynchronous memory |
always@(RST_I or ADR_I) |
begin |
if (RST_I) // this is added because at start of test bench we need address change in order to get data! |
begin |
#1 mem_rd_data_in = `WB_DATA_WIDTH'hxxxx_xxxx; |
end |
else |
begin |
// #1 mem_rd_data_in = wb_memory[ADR_I[25:2]]; |
#1 mem_rd_data_in = wb_memory[ADR_I[21:2]]; |
end |
end |
|
// Data input/output interface |
always@(rd_sel or mem_rd_data_in or RST_I) |
begin |
if (RST_I) |
DAT_O <=#1 `WB_DATA_WIDTH'hxxxx_xxxx; // assign outputs to unknown state while in reset |
else if (rd_sel) |
DAT_O <=#1 mem_rd_data_in; |
else |
DAT_O <=#1 `WB_DATA_WIDTH'hxxxx_xxxx; |
end |
|
|
always@(RST_I or task_rd_adr_i) |
begin |
if (RST_I) |
task_dat_o = `WB_DATA_WIDTH'hxxxx_xxxx; |
else |
task_dat_o = wb_memory[task_rd_adr_i[21:2]]; |
end |
always@(CLK_I or wr_sel or task_wr_data or ADR_I or task_wr_adr_i or |
mem_wr_data_out or DAT_I or task_mem_wr_data or task_dat_i or |
SEL_I or task_sel_i) |
begin |
if (task_wr_data) |
begin |
task_mem_wr_data = wb_memory[task_wr_adr_i[21:2]]; |
|
if (task_sel_i[3]) |
task_mem_wr_data[31:24] = task_dat_i[31:24]; |
if (task_sel_i[2]) |
task_mem_wr_data[23:16] = task_dat_i[23:16]; |
if (task_sel_i[1]) |
task_mem_wr_data[15: 8] = task_dat_i[15: 8]; |
if (task_sel_i[0]) |
task_mem_wr_data[ 7: 0] = task_dat_i[ 7: 0]; |
|
wb_memory[task_wr_adr_i[21:2]] = task_mem_wr_data; // write data |
task_data_written = 1; |
end |
else if (wr_sel && CLK_I) |
begin |
// mem_wr_data_out = wb_memory[ADR_I[25:2]]; // if no SEL_I is active, old value will be written |
mem_wr_data_out = wb_memory[ADR_I[21:2]]; // if no SEL_I is active, old value will be written |
|
if (SEL_I[3]) |
mem_wr_data_out[31:24] = DAT_I[31:24]; |
if (SEL_I[2]) |
mem_wr_data_out[23:16] = DAT_I[23:16]; |
if (SEL_I[1]) |
mem_wr_data_out[15: 8] = DAT_I[15: 8]; |
if (SEL_I[0]) |
mem_wr_data_out[ 7: 0] = DAT_I[ 7: 0]; |
|
// wb_memory[ADR_I[25:2]] <= mem_wr_data_out; // write data |
wb_memory[ADR_I[21:2]] = mem_wr_data_out; // write data |
end |
end |
|
endmodule |
/trunk/bench/verilog/wb_master_behavioral.v
0,0 → 1,773
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name "wb_master_behavioral.v" //// |
//// //// |
//// This file is part of the "PCI bridge" project //// |
//// http://www.opencores.org/cores/pci/ //// |
//// //// |
//// Author(s): //// |
//// - Miha Dolenc (mihad@opencores.org) //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Miha Dolenc, mihad@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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.1 2002/07/29 11:25:20 mihad |
// Adding test bench for memory interface |
// |
// Revision 1.1 2002/02/01 13:39:43 mihad |
// Initial testbench import. Still under development |
// |
|
`include "wb_model_defines.v" |
`include "timescale.v" |
module WB_MASTER_BEHAVIORAL |
( |
CLK_I, |
RST_I, |
TAG_I, |
TAG_O, |
ACK_I, |
ADR_O, |
CYC_O, |
DAT_I, |
DAT_O, |
ERR_I, |
RTY_I, |
SEL_O, |
STB_O, |
WE_O, |
CAB_O |
); |
|
input CLK_I; |
input RST_I; |
input `WB_TAG_TYPE TAG_I; |
output `WB_TAG_TYPE TAG_O; |
input ACK_I; |
output `WB_ADDR_TYPE ADR_O; |
output CYC_O; |
input `WB_DATA_TYPE DAT_I; |
output `WB_DATA_TYPE DAT_O; |
input ERR_I; |
input RTY_I; |
output `WB_SEL_TYPE SEL_O; |
output STB_O; |
output WE_O; |
output CAB_O; |
|
// instantiate low level master module |
WB_MASTER32 wbm_low_level |
( |
.CLK_I(CLK_I), |
.RST_I(RST_I), |
.TAG_I(TAG_I), |
.TAG_O(TAG_O), |
.ACK_I(ACK_I), |
.ADR_O(ADR_O), |
.CYC_O(CYC_O), |
.DAT_I(DAT_I), |
.DAT_O(DAT_O), |
.ERR_I(ERR_I), |
.RTY_I(RTY_I), |
.SEL_O(SEL_O), |
.STB_O(STB_O), |
.WE_O(WE_O), |
.CAB_O(CAB_O) |
) ; |
|
// block read and write buffers definition |
// single write buffer |
reg `WRITE_STIM_TYPE blk_write_data [0:(`MAX_BLK_SIZE - 1)] ; |
// read stimulus buffer - addresses, tags, selects etc. |
reg `READ_STIM_TYPE blk_read_data_in [0:(`MAX_BLK_SIZE - 1)] ; |
// read return buffer - data and tags received while performing block reads |
reg `READ_RETURN_TYPE blk_read_data_out [0:(`MAX_BLK_SIZE - 1)] ; |
|
// single write task |
task wb_single_write ; |
input `WRITE_STIM_TYPE write_data ; |
input `WB_TRANSFER_FLAGS write_flags ; |
inout `WRITE_RETURN_TYPE return ; |
reg in_use ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg retry ; |
begin:main |
|
return`TB_ERROR_BIT = 1'b0 ; |
cab = 0 ; |
return`CYC_ACTUAL_TRANSFER = 0 ; |
rty_count = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_single_write routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
|
retry = 1 ; |
|
while (retry === 1) |
begin |
// synchronize operation to clock |
@(posedge CLK_I) ; |
|
wbm_low_level.start_cycle(cab, 1'b1, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_single_write, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// first insert initial wait states |
cyc_count = write_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.wbm_write(write_data, return) ; |
|
if ( return`CYC_ERR === 0 && return`CYC_ACK === 0 && return`CYC_RTY === 1 && write_flags`WB_TRANSFER_AUTO_RTY === 1 && return`TB_ERROR_BIT === 0) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_single_write, Time %t ", $time) ; |
retry = 0 ; |
end |
else |
begin |
retry = 1 ; |
rty_count = rty_count + 1 ; |
end |
end |
else |
retry = 0 ; |
|
// if test bench error bit is set, there is no meaning in introducing subsequent wait states |
if ( return`TB_ERROR_BIT !== 0 ) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
cyc_count = write_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.end_cycle ; |
end |
|
in_use = 0 ; |
|
end //main |
endtask // wb_single_write |
|
task wb_single_read ; |
input `READ_STIM_TYPE read_data ; |
input `WB_TRANSFER_FLAGS read_flags ; |
inout `READ_RETURN_TYPE return ; |
reg in_use ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg retry ; |
begin:main |
|
return`TB_ERROR_BIT = 1'b0 ; |
cab = 0 ; |
rty_count = 0 ; |
return`CYC_ACTUAL_TRANSFER = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_single_read routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
|
retry = 1 ; |
|
while (retry === 1) |
begin |
// synchronize operation to clock |
@(posedge CLK_I) ; |
|
wbm_low_level.start_cycle(cab, 1'b0, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_single_read, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// first insert initial wait states |
cyc_count = read_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.wbm_read(read_data, return) ; |
|
if ( return`CYC_ERR === 0 && return`CYC_ACK === 0 && return`CYC_RTY === 1 && read_flags`WB_TRANSFER_AUTO_RTY === 1 && return`TB_ERROR_BIT === 0) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_single_read, Time %t ", $time) ; |
retry = 0 ; |
end |
else |
begin |
retry = 1 ; |
rty_count = rty_count + 1 ; |
end |
end |
else |
begin |
retry = 0 ; |
end |
|
// if test bench error bit is set, there is no meaning in introducing subsequent wait states |
if ( return`TB_ERROR_BIT !== 0 ) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
cyc_count = read_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.end_cycle ; |
end |
|
in_use = 0 ; |
|
end //main |
endtask // wb_single_read |
|
task wb_RMW_read ; |
input `READ_STIM_TYPE read_data ; |
input `WB_TRANSFER_FLAGS read_flags ; |
inout `READ_RETURN_TYPE return ; |
reg in_use ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg retry ; |
begin:main |
|
return`TB_ERROR_BIT = 1'b0 ; |
cab = 0 ; |
rty_count = 0 ; |
return`CYC_ACTUAL_TRANSFER = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_RMW_read routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
|
retry = 1 ; |
|
while (retry === 1) |
begin |
// synchronize operation to clock |
@(posedge CLK_I) ; |
|
wbm_low_level.start_cycle(cab, 1'b0, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_RMW_read, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// first insert initial wait states |
cyc_count = read_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.wbm_read(read_data, return) ; |
|
if ( return`CYC_ERR === 0 && return`CYC_ACK === 0 && return`CYC_RTY === 1 && read_flags`WB_TRANSFER_AUTO_RTY === 1 && return`TB_ERROR_BIT === 0) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_RMW_read, Time %t ", $time) ; |
retry = 0 ; |
end |
else |
begin |
retry = 1 ; |
rty_count = rty_count + 1 ; |
end |
end |
else |
begin |
retry = 0 ; |
end |
|
// if test bench error bit is set, there is no meaning in introducing subsequent wait states |
if ( return`TB_ERROR_BIT !== 0 ) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
cyc_count = read_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
if (retry === 1) |
wbm_low_level.end_cycle ; |
else |
wbm_low_level.modify_cycle ; |
end |
|
in_use = 0 ; |
|
end //main |
endtask // wb_RMW_read |
|
task wb_RMW_write ; |
input `WRITE_STIM_TYPE write_data ; |
input `WB_TRANSFER_FLAGS write_flags ; |
inout `WRITE_RETURN_TYPE return ; |
reg in_use ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg retry ; |
begin:main |
|
return`TB_ERROR_BIT = 1'b0 ; |
cab = 0 ; |
return`CYC_ACTUAL_TRANSFER = 0 ; |
rty_count = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_RMW_write routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
|
retry = 1 ; |
|
while (retry === 1) |
begin |
// synchronize operation to clock |
//@(posedge CLK_I) ; |
ok = 1 ; |
if (rty_count !== 0) |
wbm_low_level.start_cycle(cab, 1'b1, ok) ; |
|
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_single_write, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// first insert initial wait states |
cyc_count = write_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.wbm_write(write_data, return) ; |
|
if ( return`CYC_ERR === 0 && return`CYC_ACK === 0 && return`CYC_RTY === 1 && write_flags`WB_TRANSFER_AUTO_RTY === 1 && return`TB_ERROR_BIT === 0) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_single_write, Time %t ", $time) ; |
retry = 0 ; |
end |
else |
begin |
retry = 1 ; |
rty_count = rty_count + 1 ; |
end |
end |
else |
retry = 0 ; |
|
// if test bench error bit is set, there is no meaning in introducing subsequent wait states |
if ( return`TB_ERROR_BIT !== 0 ) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
cyc_count = write_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.end_cycle ; |
end |
|
in_use = 0 ; |
|
end //main |
endtask // wb_RMW_write |
|
task wb_block_write ; |
input `WB_TRANSFER_FLAGS write_flags ; |
inout `WRITE_RETURN_TYPE return ; |
|
reg in_use ; |
reg `WRITE_STIM_TYPE current_write ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg end_blk ; |
begin:main |
|
return`CYC_ACTUAL_TRANSFER = 0 ; |
rty_count = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_block_write routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if (write_flags`WB_TRANSFER_SIZE > `MAX_BLK_SIZE) |
begin |
$display("*E, number of transfers passed to wb_block_write routine exceeds defined maximum transaction length! Time %t", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
@(posedge CLK_I) ; |
cab = write_flags`WB_TRANSFER_CAB ; |
wbm_low_level.start_cycle(cab, 1'b1, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_block_write, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// insert initial wait states |
cyc_count = write_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
end_blk = 0 ; |
while (end_blk === 0) |
begin |
// collect data for current data beat |
current_write = blk_write_data[return`CYC_ACTUAL_TRANSFER] ; |
wbm_low_level.wbm_write(current_write, return) ; |
|
// check result of write operation |
// check for severe test error |
if (return`TB_ERROR_BIT !== 0) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
// slave returned error or error signal had invalid value |
if (return`CYC_ERR !== 0) |
end_blk = 1 ; |
|
if ( |
(return`CYC_RTY !== 0) && (return`CYC_RTY !== 1) || |
(return`CYC_ACK !== 0) && (return`CYC_ACK !== 1) || |
(return`CYC_ERR !== 0) && (return`CYC_ERR !== 1) |
) |
begin |
end_blk = 1 ; |
$display("*E, at least one slave response signal was invalid when cycle finished! Routine wb_block_write, Time %t ", $time) ; |
$display("ACK = %b \t RTY_O = %b \t ERR_O = %b \t", return`CYC_ACK, return`CYC_RTY, return`CYC_ERR) ; |
end |
|
if ((return`CYC_RTY === 1) && (write_flags`WB_TRANSFER_AUTO_RTY !== 1)) |
end_blk = 1 ; |
|
if ((return`CYC_RTY === 1) && (write_flags`WB_TRANSFER_AUTO_RTY === 1)) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_block_write, Time %t ", $time) ; |
end_blk = 1 ; |
end |
else |
begin |
rty_count = rty_count + 1 ; |
end |
end |
else |
rty_count = 0 ; |
|
// check if slave responded at all |
if (return`CYC_RESPONSE === 0) |
end_blk = 1 ; |
|
// check if all intended data was transfered |
if (return`CYC_ACTUAL_TRANSFER === write_flags`WB_TRANSFER_SIZE) |
end_blk = 1 ; |
|
// insert subsequent wait cycles, if transfer is supposed to continue |
if ( end_blk === 0 ) |
begin |
cyc_count = write_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
end |
|
if ( (end_blk === 0) && (return`CYC_RTY === 1) ) |
begin |
wbm_low_level.end_cycle ; |
@(posedge CLK_I) ; |
wbm_low_level.start_cycle(cab, 1'b1, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_block_write, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
end_blk = 1 ; |
end |
end |
end //while |
|
wbm_low_level.end_cycle ; |
in_use = 0 ; |
end //main |
endtask //wb_block_write |
|
task wb_block_read ; |
input `WB_TRANSFER_FLAGS read_flags ; |
inout `READ_RETURN_TYPE return ; |
|
reg in_use ; |
reg `READ_STIM_TYPE current_read ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg end_blk ; |
integer transfered ; |
begin:main |
|
return`CYC_ACTUAL_TRANSFER = 0 ; |
transfered = 0 ; |
rty_count = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_block_read routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if (read_flags`WB_TRANSFER_SIZE > `MAX_BLK_SIZE) |
begin |
$display("*E, number of transfers passed to wb_block_read routine exceeds defined maximum transaction length! Time %t", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
@(posedge CLK_I) ; |
cab = read_flags`WB_TRANSFER_CAB ; |
|
wbm_low_level.start_cycle(cab, 1'b0, ok) ; |
|
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_block_read, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// insert initial wait states |
cyc_count = read_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
end_blk = 0 ; |
while (end_blk === 0) |
begin |
// collect data for current data beat |
current_read = blk_read_data_in[return`CYC_ACTUAL_TRANSFER] ; |
|
wbm_low_level.wbm_read(current_read, return) ; |
|
if ( transfered !== return`CYC_ACTUAL_TRANSFER ) |
begin |
blk_read_data_out[transfered] = return ; |
transfered = return`CYC_ACTUAL_TRANSFER ; |
end |
|
// check result of read operation |
// check for severe test error |
if (return`TB_ERROR_BIT !== 0) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
// slave returned error or error signal had invalid value |
if (return`CYC_ERR !== 0) |
end_blk = 1 ; |
|
if ( |
(return`CYC_RTY !== 0) && (return`CYC_RTY !== 1) || |
(return`CYC_ACK !== 0) && (return`CYC_ACK !== 1) || |
(return`CYC_ERR !== 0) && (return`CYC_ERR !== 1) |
) |
begin |
end_blk = 1 ; |
$display("*E, at least one slave response signal was invalid when cycle finished! Routine wb_block_read, Time %t ", $time) ; |
$display("ACK = %b \t RTY_O = %b \t ERR_O = %b \t", return`CYC_ACK, return`CYC_RTY, return`CYC_ERR) ; |
end |
|
if ((return`CYC_RTY === 1) && (read_flags`WB_TRANSFER_AUTO_RTY !== 1)) |
end_blk = 1 ; |
|
if ((return`CYC_RTY === 1) && (read_flags`WB_TRANSFER_AUTO_RTY === 1)) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_block_read, Time %t ", $time) ; |
end_blk = 1 ; |
end |
else |
begin |
rty_count = rty_count + 1 ; |
end |
end |
else |
rty_count = 0 ; |
|
// check if slave responded at all |
if (return`CYC_RESPONSE === 0) |
end_blk = 1 ; |
|
// check if all intended data was transfered |
if (return`CYC_ACTUAL_TRANSFER === read_flags`WB_TRANSFER_SIZE) |
end_blk = 1 ; |
|
// insert subsequent wait cycles, if transfer is supposed to continue |
if ( end_blk === 0 ) |
begin |
cyc_count = read_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
end |
|
if ( (end_blk === 0) && (return`CYC_RTY === 1) ) |
begin |
wbm_low_level.end_cycle ; |
@(posedge CLK_I) ; |
wbm_low_level.start_cycle(cab, 1'b0, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_block_read, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
end_blk = 1 ; |
end |
end |
end //while |
|
wbm_low_level.end_cycle ; |
in_use = 0 ; |
end //main |
endtask //wb_block_read |
|
endmodule |
|
/trunk/bench/verilog/eth_phy.v
0,0 → 1,1330
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name: eth_phy.v //// |
//// //// |
//// This file is part of the "Ethernet MAC" 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 $ |
// |
// |
|
`include "timescale.v" |
`include "eth_phy_defines.v" |
`include "tb_eth_defines.v" |
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, |
|
// SYSTEM |
phy_log |
); |
|
////////////////////////////////////////////////////////////////////// |
// |
// 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; |
// SYSTEM |
input [31:0] phy_log; |
|
|
////////////////////////////////////////////////////////////////////// |
// |
// 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 VERBOSE |
#1 $fdisplay(phy_log, " (%0t)(%m)MAC RX clock is %f MHz while ethernet link is down!", |
$time, (1000/(rx_link_down_halfperiod*2)) ); |
`endif |
end |
end |
|
`ifdef VERBOSE |
always@(status_bit6_0[2]) |
begin |
if (!status_bit6_0[2]) // Link is down |
#1 $fdisplay(phy_log, " (%0t)(%m)Ethernet link is down!", $time); |
else |
#1 $fdisplay(phy_log, " (%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 VERBOSE |
always@(eth_speed) |
begin |
if (eth_speed) |
#1 $fdisplay(phy_log, " (%0t)(%m)PHY configured to 100 Mbps!", $time); |
else |
#1 $fdisplay(phy_log, " (%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 |
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 |
mrx_clk_o = 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_o = ~mrx_clk_o; // 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_o = ~mrx_clk_o; // period is calculated from frequency in GHz |
end |
end |
else // Link is down |
begin |
#(rx_link_down_halfperiod) mrx_clk_o = ~mrx_clk_o; // random frequency between 2 MHz and 40 MHz |
end |
end |
end |
|
////////////////////////////////////////////////////////////////////// |
// |
// 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 VERBOSE |
$fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong first start bit (without preamble)", $time); |
`endif |
#10 $stop; |
end |
end |
end |
else // with preamble |
begin |
`ifdef VERBOSE |
#4 $fdisplay(phy_log, " (%0t)(%m)MIIM - 32-bit preamble received", $time); |
`endif |
if (md_io_reg !== 1'b0) |
begin |
// ERROR - start ! |
`ifdef VERBOSE |
$fdisplay(phy_log, "*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 VERBOSE |
if (no_preamble) |
$fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong second start bit (without preamble)", $time); |
else |
$fdisplay(phy_log, "*E (%0t)(%m)MIIM - wrong second start bit", $time); |
`endif |
#10 $stop; |
end |
else |
begin |
`ifdef VERBOSE |
if (no_preamble) |
#1 $fdisplay(phy_log, " (%0t)(%m)MIIM - 2 start bits received (without preamble)", $time); |
else |
#1 $fdisplay(phy_log, " (%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 VERBOSE |
$fdisplay(phy_log, " (%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 VERBOSE |
$fdisplay(phy_log, " (%0t)(%m)MIIM - op-code for WRITING to registers", $time); |
`endif |
end |
else |
begin |
// ERROR - wrong opcode ! |
`ifdef VERBOSE |
#1 $fdisplay(phy_log, "*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 VERBOSE |
#1 $fdisplay(phy_log, "*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 VERBOSE |
$fdisplay(phy_log, " (%0t)(%m)MIIM - received correct PHY ADDRESS: %x", $time, phy_address); |
`endif |
end |
else |
begin |
`ifdef VERBOSE |
#1 $fdisplay(phy_log, "*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 VERBOSE |
#1 $fdisplay(phy_log, "*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 VERBOSE |
#1 $fdisplay(phy_log, "*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 VERBOSE |
$fdisplay(phy_log, " (%0t)(%m)MIIM - received correct PHY ADDRESS: %x", $time, phy_address); |
$fdisplay(phy_log, " (%0t)(%m)MIIM - WRITING to register %x COMPLETED!", $time, reg_address); |
`endif |
end |
else |
begin |
`ifdef VERBOSE |
#1 $fdisplay(phy_log, "*W (%0t)(%m)MIIM - received different PHY ADDRESS: %x", $time, phy_address); |
$fdisplay(phy_log, "*W (%0t)(%m)MIIM - NO WRITING to register %x !", $time, reg_address); |
`endif |
end |
end |
else // read |
begin |
`ifdef VERBOSE |
if ((phy_address === `ETH_PHY_ADDR) || respond_to_all_phy_addr) // check the PHY address |
#1 $fdisplay(phy_log, " (%0t)(%m)MIIM - READING from register %x COMPLETED!", |
$time, reg_address); |
else |
#1 $fdisplay(phy_log, "*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 |
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_d; |
// 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; |
// generate collision in full-duplex mode also - not normal operation |
reg collision_in_full_duplex; |
// generate carrier sense during TX in full-duplex mode also - not normal operation |
reg carrier_sense_in_tx_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; |
collision_in_full_duplex = 0; |
carrier_sense_in_tx_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 |
) |
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 VERBOSE |
if (mcrs_rx && mcrs_tx) |
$fdisplay(phy_log, " (%0t)(%m) Collision set in FullDuplex!", $time); |
if (task_mcoll) |
$fdisplay(phy_log, " (%0t)(%m) Collision set in FullDuplex from TASK!", $time); |
`endif |
end |
else |
begin |
mcoll_o = task_mcoll; |
`ifdef VERBOSE |
if (task_mcoll) |
$fdisplay(phy_log, " (%0t)(%m) Collision set in FullDuplex from TASK!", $time); |
`endif |
end |
end |
else // half duplex |
begin |
mcoll_o = (mcrs_rx && mcrs_tx) || task_mcoll; |
`ifdef VERBOSE |
if (mcrs_rx && mcrs_tx) |
$fdisplay(phy_log, " (%0t)(%m) Collision set in HalfDuplex!", $time); |
if (task_mcoll) |
$fdisplay(phy_log, " (%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 |
mcrs_rx or mcrs_tx or task_mcrs |
) |
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 || mcrs_tx || task_mcrs; |
else |
mcrs_o = mcrs_rx || task_mcrs; |
end |
else // half duplex |
begin |
mcrs_o = mcrs_rx || mcrs_tx || task_mcrs; |
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; |
|
// 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; |
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 VERBOSE |
$fdisplay(phy_log, " (%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_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 VERBOSE |
if (tx_preamble_ok == 1) |
$fdisplay(phy_log, " (%0t)(%m) TX frame preamble OK!", $time); |
else |
$fdisplay(phy_log, "*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 VERBOSE |
if (tx_sfd_ok == 1) |
$fdisplay(phy_log, " (%0t)(%m) TX frame SFD OK!", $time); |
else |
$fdisplay(phy_log, "*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 |
end |
end |
end |
|
// generating CARRIER SENSE for TX with or without delay |
if (!m_rst_n_i) |
begin |
mcrs_tx <= 0; |
mtxen_d <= 0; |
end |
else |
begin |
if (!real_carrier_sense) |
begin |
mtxen_d <= mtxen_i; |
mcrs_tx <= mtxen_i; |
end |
else |
begin |
mtxen_d <= mtxen_i; |
mcrs_tx <= mtxen_d; |
end |
end |
end |
|
`ifdef 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 |
$fdisplay(phy_log, " (%0t)(%m) TX frame ended with tx_en reset!", $time); |
frame_started <= 0; |
end |
end |
|
always@(posedge mrxerr_o) |
begin |
$fdisplay(phy_log, " (%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*32)-1:0] preamble_data; // preamble data to be sent |
input [3:0] preamble_len; // length of preamble - max is 8 |
input [7:0] sfd_data; // SFD data to be sent |
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 VERBOSE |
$fdisplay(phy_log, " (%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) || (rx_cnt < 8); 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 VERBOSE |
$fdisplay(phy_log, " (%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 |
@(posedge mrx_clk_o); |
#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; |
#1; |
end |
if (plus_drible_nibble) |
begin |
@(posedge mrx_clk_o); |
#1; |
rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]]; |
mrxd_o = rx_mem_data_out[3:0]; |
end |
`ifdef VERBOSE |
$fdisplay(phy_log, " (%0t)(%m) RX frame addresses, type/length, data and FCS sent!", $time); |
`endif |
@(posedge mrx_clk_o); |
#1 mcrs_rx = 0; |
#1 mrxdv_o = 0; |
`ifdef VERBOSE |
$fdisplay(phy_log, " (%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 |
|
// Collision detection in full duplex also |
task collision_fd_detect; |
input test_op; |
begin |
#1 collision_in_full_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 |
|
// Set real delay on carrier sense 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 |
|
|
|
|
|
endmodule |
|
/trunk/bench/verilog/tb_eth_defines.v
41,9 → 41,6
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.4 2002/07/25 17:19:06 mohor |
// Define ETH_MIIMODER_RST corrected to 0x00000400. |
// |
// Revision 1.3 2002/07/19 13:57:53 mohor |
// Testing environment also includes traffic cop, memory interface and host |
// interface. |
60,6 → 57,9
// |
|
|
|
//`define VERBOSE // if log files of device modules are written |
|
//`define EXTERNAL_DMA // Using DMA |
|
`define MULTICAST_XFR 0 |
122,7 → 122,7
`define ETH_IPGR2 `ETH_BASE + 32'h14 /* Non Back to Back Inter Packet Gap Register 2 */ |
`define ETH_PACKETLEN `ETH_BASE + 32'h18 /* Packet Length Register (min. and max.) */ |
`define ETH_COLLCONF `ETH_BASE + 32'h1C /* Collision and Retry Configuration Register */ |
`define ETH_RX_BD_NUM `ETH_BASE + 32'h20 /* Receive Buffer Descriptor Number Register */ |
`define ETH_TX_BD_NUM `ETH_BASE + 32'h20 /* Transmit Buffer Descriptor Number Register */ |
`define ETH_CTRLMODER `ETH_BASE + 32'h24 /* Control Module Mode Register */ |
`define ETH_MIIMODER `ETH_BASE + 32'h28 /* MII Mode Register */ |
`define ETH_MIICOMMAND `ETH_BASE + 32'h2C /* MII Command Register */ |
134,8 → 134,6
`define ETH_MAC_ADDR1 `ETH_BASE + 32'h44 /* MAC Individual Address Register 1 */ |
`define ETH_HASH_ADDR0 `ETH_BASE + 32'h48 /* Hash Register 0 */ |
`define ETH_HASH_ADDR1 `ETH_BASE + 32'h4C /* Hash Register 1 */ |
`define ETH_TX_CTRL `ETH_BASE + 32'h50 /* Tx Control Register */ |
`define ETH_RX_CTRL `ETH_BASE + 32'h54 /* Rx Control Register */ |
|
/* MODER Register */ |
`define ETH_MODER_RXEN 32'h00000001 /* Receive Enable */ |
182,7 → 180,7
/* MII Mode Register */ |
`define ETH_MIIMODER_CLKDIV 32'h000000FF /* Clock Divider */ |
`define ETH_MIIMODER_NOPRE 32'h00000100 /* No Preamble */ |
`define ETH_MIIMODER_RST 32'h00000400 /* MIIM Reset */ |
`define ETH_MIIMODER_RST 32'h00000200 /* MIIM Reset */ |
|
/* MII Command Register */ |
`define ETH_MIICOMMAND_SCANSTAT 32'h00000001 /* Scan Status */ |
194,6 → 192,6
`define ETH_MIIADDRESS_RGAD 32'h00001F00 /* RGAD Address */ |
|
/* MII Status Register */ |
`define ETH_MIISTATUS_LINKFAIL 32'h00000001 /* Link Fail */ |
`define ETH_MIISTATUS_BUSY 32'h00000002 /* MII Busy */ |
`define ETH_MIISTATUS_NVALID 32'h00000004 /* Data in MII Status Register is invalid */ |
`define ETH_MIISTATUS_LINKFAIL 0 /* Link Fail bit */ |
`define ETH_MIISTATUS_BUSY 1 /* MII Busy bit */ |
`define ETH_MIISTATUS_NVALID 2 /* Data in MII Status Register is invalid bit */ |
/trunk/bench/verilog/tb_ethernet.v
6,9 → 6,9
//// http://www.opencores.org/projects/ethmac/ //// |
//// //// |
//// Author(s): //// |
//// - Igor Mohor (igorM@opencores.org) //// |
//// - Tadej Markovic, tadej@opencores.org //// |
//// //// |
//// All additional information is avaliable in the Readme.txt //// |
//// All additional information is available in the Readme.txt //// |
//// file. //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
41,12 → 41,6
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.4 2002/09/06 11:03:24 mohor |
// Valid testbench. |
// |
// Revision 1.3 2002/07/23 16:34:31 mohor |
// gsr added for use when ETH_XILINX_RAMB4 define is set. |
// |
// Revision 1.2 2002/07/19 14:02:47 mohor |
// Clock mrx_clk set to 2.5 MHz. |
// |
60,7 → 54,10
// |
|
|
`define TIME $display(" Time: %0t", $time) |
|
`include "eth_phy_defines.v" |
`include "wb_model_defines.v" |
`include "tb_eth_defines.v" |
`include "eth_defines.v" |
`include "timescale.v" |
68,104 → 65,57
module tb_ethernet(); |
|
|
parameter Tp = 1; |
reg wb_clk; |
reg wb_rst; |
wire wb_int; |
|
wire mtx_clk; // This goes to PHY |
wire mrx_clk; // This goes to PHY |
|
reg wb_clk_o; |
reg wb_rst_o; |
|
reg mtx_clk; |
reg mrx_clk; |
|
wire [3:0] MTxD; |
wire MTxEn; |
wire MTxErr; |
|
reg [3:0] MRxD; // This goes to PHY |
reg MRxDV; // This goes to PHY |
reg MRxErr; // This goes to PHY |
reg MColl; // This goes to PHY |
reg MCrs; // This goes to PHY |
wire [3:0] MRxD; // This goes to PHY |
wire MRxDV; // This goes to PHY |
wire MRxErr; // This goes to PHY |
wire MColl; // This goes to PHY |
wire MCrs; // This goes to PHY |
|
wire Mdi_I; |
wire Mdo_O; |
wire Mdo_OE; |
tri Mdio_IO; |
wire Mdc_O; |
|
integer tx_log; |
integer rx_log; |
|
reg StartTB; |
parameter Tp = 1; |
|
`ifdef ETH_XILINX_RAMB4 |
reg gsr; |
`endif |
|
|
integer packet_ready_cnt, send_packet_cnt; |
|
|
// Ethernet Slave Interface signals |
wire [31:0] eth_sl_wb_adr; |
wire [31:0] eth_sl_wb_adr_i, eth_sl_wb_dat_o, eth_sl_wb_dat_i; |
wire [3:0] eth_sl_wb_sel_i; |
wire eth_sl_wb_we_i, eth_sl_wb_cyc_i, eth_sl_wb_stb_i, eth_sl_wb_ack_o, eth_sl_wb_err_o; |
|
// Memory Slave Interface signals |
wire [31:0] mem_sl_wb_adr_i, mem_sl_wb_dat_o, mem_sl_wb_dat_i; |
wire [3:0] mem_sl_wb_sel_i; |
wire mem_sl_wb_we_i, mem_sl_wb_cyc_i, mem_sl_wb_stb_i, mem_sl_wb_ack_o, mem_sl_wb_err_o; |
|
// Ethernet Master Interface signals |
wire [31:0] eth_ma_wb_adr_o, eth_ma_wb_dat_i, eth_ma_wb_dat_o; |
wire [3:0] eth_ma_wb_sel_o; |
wire eth_ma_wb_we_o, eth_ma_wb_cyc_o, eth_ma_wb_stb_o, eth_ma_wb_ack_i, eth_ma_wb_err_i; |
|
// Host Master Interface signals |
wire [31:0] host_ma_wb_adr_o, host_ma_wb_dat_i, host_ma_wb_dat_o; |
wire [3:0] host_ma_wb_sel_o; |
wire host_ma_wb_we_o, host_ma_wb_cyc_o, host_ma_wb_stb_o, host_ma_wb_ack_i, host_ma_wb_err_i; |
|
|
|
eth_cop i_eth_cop |
( |
// WISHBONE common |
.wb_clk_i(wb_clk_o), .wb_rst_i(wb_rst_o), |
|
// WISHBONE MASTER 1 Ethernet Master Interface is connected here |
.m1_wb_adr_i(eth_ma_wb_adr_o), .m1_wb_sel_i(eth_ma_wb_sel_o), .m1_wb_we_i (eth_ma_wb_we_o), |
.m1_wb_dat_o(eth_ma_wb_dat_i), .m1_wb_dat_i(eth_ma_wb_dat_o), .m1_wb_cyc_i(eth_ma_wb_cyc_o), |
.m1_wb_stb_i(eth_ma_wb_stb_o), .m1_wb_ack_o(eth_ma_wb_ack_i), .m1_wb_err_o(eth_ma_wb_err_i), |
|
// WISHBONE MASTER 2 Host Interface is connected here |
.m2_wb_adr_i(host_ma_wb_adr_o), .m2_wb_sel_i(host_ma_wb_sel_o), .m2_wb_we_i (host_ma_wb_we_o), |
.m2_wb_dat_o(host_ma_wb_dat_i), .m2_wb_dat_i(host_ma_wb_dat_o), .m2_wb_cyc_i(host_ma_wb_cyc_o), |
.m2_wb_stb_i(host_ma_wb_stb_o), .m2_wb_ack_o(host_ma_wb_ack_i), .m2_wb_err_o(host_ma_wb_err_i), |
|
// WISHBONE slave 1 Ethernet Slave Interface is connected here |
.s1_wb_adr_o(eth_sl_wb_adr_i), .s1_wb_sel_o(eth_sl_wb_sel_i), .s1_wb_we_o (eth_sl_wb_we_i), |
.s1_wb_cyc_o(eth_sl_wb_cyc_i), .s1_wb_stb_o(eth_sl_wb_stb_i), .s1_wb_ack_i(eth_sl_wb_ack_o), |
.s1_wb_err_i(eth_sl_wb_err_o), .s1_wb_dat_i(eth_sl_wb_dat_o), .s1_wb_dat_o(eth_sl_wb_dat_i), |
|
// WISHBONE slave 2 Memory Interface is connected here |
.s2_wb_adr_o(mem_sl_wb_adr_i), .s2_wb_sel_o(mem_sl_wb_sel_i), .s2_wb_we_o (mem_sl_wb_we_i), |
.s2_wb_cyc_o(mem_sl_wb_cyc_i), .s2_wb_stb_o(mem_sl_wb_stb_i), .s2_wb_ack_i(mem_sl_wb_ack_o), |
.s2_wb_err_i(mem_sl_wb_err_o), .s2_wb_dat_i(mem_sl_wb_dat_o), .s2_wb_dat_o(mem_sl_wb_dat_i) |
); |
|
|
|
|
// Connecting Ethernet top module |
eth_top ethtop |
eth_top eth_top |
( |
// WISHBONE common |
.wb_clk_i(wb_clk_o), .wb_rst_i(wb_rst_o), |
.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), |
|
// WISHBONE slave |
.wb_adr_i(eth_sl_wb_adr_i[11:2]), .wb_sel_i(eth_sl_wb_sel_i), .wb_we_i(eth_sl_wb_we_i), |
.wb_cyc_i(eth_sl_wb_cyc_i), .wb_stb_i(eth_sl_wb_stb_i), .wb_ack_o(eth_sl_wb_ack_o), |
.wb_err_o(eth_sl_wb_err_o), .wb_dat_i(eth_sl_wb_dat_i), .wb_dat_o(eth_sl_wb_dat_o), |
.wb_adr_i(eth_sl_wb_adr_i[11:2]), .wb_sel_i(eth_sl_wb_sel_i), .wb_we_i(eth_sl_wb_we_i), |
.wb_cyc_i(eth_sl_wb_cyc_i), .wb_stb_i(eth_sl_wb_stb_i), .wb_ack_o(eth_sl_wb_ack_o), |
.wb_err_o(eth_sl_wb_err_o), .wb_dat_i(eth_sl_wb_dat_i), .wb_dat_o(eth_sl_wb_dat_o), |
|
// WISHBONE master |
.m_wb_adr_o(eth_ma_wb_adr_o), .m_wb_sel_o(eth_ma_wb_sel_o), .m_wb_we_o(eth_ma_wb_we_o), |
182,367 → 132,6038
// MIIM |
.mdc_pad_o(Mdc_O), .md_pad_i(Mdi_I), .md_pad_o(Mdo_O), .md_padoe_o(Mdo_OE), |
|
.int_o() |
.int_o(wb_int) |
); |
|
|
|
// Connecting Memory Interface Module |
eth_memory i_eth_memory |
// Connecting Ethernet PHY Module |
assign Mdio_IO = Mdo_OE ? Mdo_O : 1'bz ; |
assign Mdi_I = Mdio_IO; |
integer phy_log_file_desc; |
|
eth_phy eth_phy |
( |
// WISHBONE common |
.wb_clk_i(wb_clk_o), .wb_rst_i(wb_rst_o), |
// WISHBONE reset |
.m_rst_n_i(!wb_rst), |
|
// WISHBONE slave: Memory Interface is connected here |
.wb_adr_i(mem_sl_wb_adr_i), .wb_sel_i(mem_sl_wb_sel_i), .wb_we_i (mem_sl_wb_we_i), |
.wb_cyc_i(mem_sl_wb_cyc_i), .wb_stb_i(mem_sl_wb_stb_i), .wb_ack_o(mem_sl_wb_ack_o), |
.wb_err_o(mem_sl_wb_err_o), .wb_dat_o(mem_sl_wb_dat_o), .wb_dat_i(mem_sl_wb_dat_i) |
// MAC TX |
.mtx_clk_o(mtx_clk), .mtxd_i(MTxD), .mtxen_i(MTxEn), .mtxerr_i(MTxErr), |
|
// MAC RX |
.mrx_clk_o(mrx_clk), .mrxd_o(MRxD), .mrxdv_o(MRxDV), .mrxerr_o(MRxErr), |
.mcoll_o(MColl), .mcrs_o(MCrs), |
|
// MIIM |
.mdc_i(Mdc_O), .md_io(Mdio_IO), |
|
// SYSTEM |
.phy_log(phy_log_file_desc) |
); |
|
|
// Connecting Host Interface |
eth_host eth_host |
|
// Connecting WB Master as Host Interface |
integer host_log_file_desc; |
|
WB_MASTER_BEHAVIORAL wb_master |
( |
.CLK_I(wb_clk), |
.RST_I(wb_rst), |
.TAG_I({`WB_TAG_WIDTH{1'b0}}), |
.TAG_O(), |
.ACK_I(eth_sl_wb_ack_o), |
.ADR_O(eth_sl_wb_adr), // only eth_sl_wb_adr_i[11:2] used |
.CYC_O(eth_sl_wb_cyc_i), |
.DAT_I(eth_sl_wb_dat_o), |
.DAT_O(eth_sl_wb_dat_i), |
.ERR_I(eth_sl_wb_err_o), |
.RTY_I(1'b0), // inactive (1'b0) |
.SEL_O(eth_sl_wb_sel_i), |
.STB_O(eth_sl_wb_stb_i), |
.WE_O (eth_sl_wb_we_i), |
.CAB_O() // NOT USED for now! |
); |
|
assign eth_sl_wb_adr_i = {20'h0, eth_sl_wb_adr[11:2], 2'h0}; |
|
|
|
// Connecting WB Slave as Memory Interface Module |
integer memory_log_file_desc; |
|
WB_SLAVE_BEHAVIORAL wb_slave |
( |
.CLK_I(wb_clk), |
.RST_I(wb_rst), |
.ACK_O(eth_ma_wb_ack_i), |
.ADR_I(eth_ma_wb_adr_o), |
.CYC_I(eth_ma_wb_cyc_o), |
.DAT_O(eth_ma_wb_dat_i), |
.DAT_I(eth_ma_wb_dat_o), |
.ERR_O(eth_ma_wb_err_i), |
.RTY_O(), // NOT USED for now! |
.SEL_I(eth_ma_wb_sel_o), |
.STB_I(eth_ma_wb_stb_o), |
.WE_I (eth_ma_wb_we_o), |
.CAB_I(1'b0) // inactive (1'b0) |
); |
|
|
|
// Connecting WISHBONE Bus Monitors to ethernet master and slave interfaces |
integer wb_s_mon_log_file_desc ; |
integer wb_m_mon_log_file_desc ; |
|
WB_BUS_MON wb_eth_slave_bus_mon |
( |
// WISHBONE common |
.wb_clk_i(wb_clk_o), .wb_rst_i(wb_rst_o), |
.CLK_I(wb_clk), |
.RST_I(wb_rst), |
|
// WISHBONE slave |
.ACK_I(eth_sl_wb_ack_o), |
.ADDR_O({20'h0, eth_sl_wb_adr_i[11:2], 2'b0}), |
.CYC_O(eth_sl_wb_cyc_i), |
.DAT_I(eth_sl_wb_dat_o), |
.DAT_O(eth_sl_wb_dat_i), |
.ERR_I(eth_sl_wb_err_o), |
.RTY_I(1'b0), |
.SEL_O(eth_sl_wb_sel_i), |
.STB_O(eth_sl_wb_stb_i), |
.WE_O (eth_sl_wb_we_i), |
.TAG_I({`WB_TAG_WIDTH{1'b0}}), |
.TAG_O(), |
.CAB_O(1'b0), |
.log_file_desc (wb_s_mon_log_file_desc) |
); |
|
WB_BUS_MON wb_eth_master_bus_mon |
( |
// WISHBONE common |
.CLK_I(wb_clk), |
.RST_I(wb_rst), |
|
// WISHBONE master |
.wb_adr_o(host_ma_wb_adr_o), .wb_sel_o(host_ma_wb_sel_o), .wb_we_o (host_ma_wb_we_o), |
.wb_dat_i(host_ma_wb_dat_i), .wb_dat_o(host_ma_wb_dat_o), .wb_cyc_o(host_ma_wb_cyc_o), |
.wb_stb_o(host_ma_wb_stb_o), .wb_ack_i(host_ma_wb_ack_i), .wb_err_i(host_ma_wb_err_i) |
.ACK_I(eth_ma_wb_ack_i), |
.ADDR_O(eth_ma_wb_adr_o), |
.CYC_O(eth_ma_wb_cyc_o), |
.DAT_I(eth_ma_wb_dat_i), |
.DAT_O(eth_ma_wb_dat_o), |
.ERR_I(eth_ma_wb_err_i), |
.RTY_I(1'b0), |
.SEL_O(eth_ma_wb_sel_o), |
.STB_O(eth_ma_wb_stb_o), |
.WE_O (eth_ma_wb_we_o), |
.TAG_I({`WB_TAG_WIDTH{1'b0}}), |
.TAG_O(), |
.CAB_O(1'b0), |
.log_file_desc(wb_m_mon_log_file_desc) |
); |
|
|
|
reg StartTB; |
integer tb_log_file; |
|
initial |
begin |
tb_log_file = $fopen("../log/eth_tb.log"); |
if (tb_log_file < 2) |
begin |
$display("*E Could not open/create testbench log file in ../log/ directory!"); |
$finish; |
end |
$fdisplay(tb_log_file, "========================== ETHERNET IP Core Testbench results ==========================="); |
$fdisplay(tb_log_file, " "); |
|
// Reset pulse |
phy_log_file_desc = $fopen("../log/eth_tb_phy.log"); |
if (phy_log_file_desc < 2) |
begin |
$fdisplay(tb_log_file, "*E Could not open/create eth_tb_phy.log file in ../log/ directory!"); |
$finish; |
end |
$fdisplay(phy_log_file_desc, "================ PHY Module Testbench access log ================"); |
$fdisplay(phy_log_file_desc, " "); |
|
memory_log_file_desc = $fopen("../log/eth_tb_memory.log"); |
if (memory_log_file_desc < 2) |
begin |
$fdisplay(tb_log_file, "*E Could not open/create eth_tb_memory.log file in ../log/ directory!"); |
$finish; |
end |
$fdisplay(memory_log_file_desc, "=============== MEMORY Module Testbench access log ==============="); |
$fdisplay(memory_log_file_desc, " "); |
|
host_log_file_desc = $fopen("../log/eth_tb_host.log"); |
if (host_log_file_desc < 2) |
begin |
$fdisplay(tb_log_file, "*E Could not open/create eth_tb_host.log file in ../log/ directory!"); |
$finish; |
end |
$fdisplay(host_log_file_desc, "================ HOST Module Testbench access log ================"); |
$fdisplay(host_log_file_desc, " "); |
|
wb_s_mon_log_file_desc = $fopen("../log/eth_tb_wb_s_mon.log"); |
if (wb_s_mon_log_file_desc < 2) |
begin |
$fdisplay(tb_log_file, "*E Could not open/create eth_tb_wb_s_mon.log file in ../log/ directory!"); |
$finish; |
end |
$fdisplay(wb_s_mon_log_file_desc, "============== WISHBONE Slave Bus Monitor error log =============="); |
$fdisplay(wb_s_mon_log_file_desc, " "); |
$fdisplay(wb_s_mon_log_file_desc, " Only ERRONEOUS conditions are logged !"); |
$fdisplay(wb_s_mon_log_file_desc, " "); |
|
wb_m_mon_log_file_desc = $fopen("../log/eth_tb_wb_m_mon.log"); |
if (wb_m_mon_log_file_desc < 2) |
begin |
$fdisplay(tb_log_file, "*E Could not open/create eth_tb_wb_m_mon.log file in ../log/ directory!"); |
$finish; |
end |
$fdisplay(wb_m_mon_log_file_desc, "============= WISHBONE Master Bus Monitor error log ============="); |
$fdisplay(wb_m_mon_log_file_desc, " "); |
$fdisplay(wb_m_mon_log_file_desc, " Only ERRONEOUS conditions are logged !"); |
$fdisplay(wb_m_mon_log_file_desc, " "); |
|
// Clear memories |
clear_memories; |
|
// Reset pulse |
wb_rst = 1'b1; |
#423 wb_rst = 1'b0; |
#423 StartTB = 1'b1; |
end |
|
|
|
// Generating wb_clk clock |
initial |
begin |
MCrs=0; // This should come from PHY |
MColl=0; // This should come from PHY |
MRxD=0; // This should come from PHY |
MRxDV=0; // This should come from PHY |
MRxErr=0; // This should come from PHY |
packet_ready_cnt = 0; |
send_packet_cnt = 0; |
tx_log = $fopen("ethernet_tx.log"); |
rx_log = $fopen("ethernet_rx.log"); |
wb_rst_o = 1'b1; |
`ifdef ETH_XILINX_RAMB4 |
gsr = 1'b0; |
#100 gsr = 1'b1; |
#100 gsr = 1'b0; |
`endif |
#100 wb_rst_o = 1'b0; |
#100 StartTB = 1'b1; |
wb_clk=0; |
// forever #2.5 wb_clk = ~wb_clk; // 2*2.5 ns -> 200.0 MHz |
// forever #5 wb_clk = ~wb_clk; // 2*5 ns -> 100.0 MHz |
// forever #10 wb_clk = ~wb_clk; // 2*10 ns -> 50.0 MHz |
// forever #12.5 wb_clk = ~wb_clk; // 2*12.5 ns -> 40 MHz |
// forever #15 wb_clk = ~wb_clk; // 2*10 ns -> 33.3 MHz |
forever #20 wb_clk = ~wb_clk; // 2*20 ns -> 25 MHz |
// forever #25 wb_clk = ~wb_clk; // 2*25 ns -> 20.0 MHz |
// forever #31.25 wb_clk = ~wb_clk; // 2*31.25 ns -> 16.0 MHz |
// forever #50 wb_clk = ~wb_clk; // 2*50 ns -> 10.0 MHz |
// forever #55 wb_clk = ~wb_clk; // 2*55 ns -> 9.1 MHz |
end |
|
`ifdef ETH_XILINX_RAMB4 |
assign glbl.GSR = gsr; |
`endif |
|
|
integer tests_successfull; |
integer tests_failed; |
reg [799:0] test_name; // used for tb_log_file |
|
// Generating wb_clk_o clock |
reg [3:0] wbm_init_waits; // initial wait cycles between CYC_O and STB_O of WB Master |
reg [3:0] wbm_subseq_waits; // subsequent wait cycles between STB_Os of WB Master |
reg [2:0] wbs_waits; // wait cycles befor WB Slave responds |
reg [7:0] wbs_retries; // if RTY response, then this is the number of retries before ACK |
|
initial |
begin |
wb_clk_o=0; |
// forever #2.5 wb_clk_o = ~wb_clk_o; // 2*2.5 ns -> 200.0 MHz |
// forever #5 wb_clk_o = ~wb_clk_o; // 2*5 ns -> 100.0 MHz |
// forever #10 wb_clk_o = ~wb_clk_o; // 2*10 ns -> 50.0 MHz |
// forever #12.5 wb_clk_o = ~wb_clk_o; // 2*12.5 ns -> 40 MHz |
// forever #15 wb_clk_o = ~wb_clk_o; // 2*10 ns -> 33.3 MHz |
forever #20 wb_clk_o = ~wb_clk_o; // 2*20 ns -> 25 MHz |
// forever #25 wb_clk_o = ~wb_clk_o; // 2*25 ns -> 20.0 MHz |
// forever #31.25 wb_clk_o = ~wb_clk_o; // 2*31.25 ns -> 16.0 MHz |
// forever #50 wb_clk_o = ~wb_clk_o; // 2*50 ns -> 10.0 MHz |
// forever #55 wb_clk_o = ~wb_clk_o; // 2*55 ns -> 9.1 MHz |
wait(StartTB); // Start of testbench |
|
// Initial global values |
tests_successfull = 0; |
tests_failed = 0; |
|
wbm_init_waits = 4'h1; |
wbm_subseq_waits = 4'h3; |
wbs_waits = 4'h1; |
wbs_retries = 8'h2; |
wb_slave.cycle_response(`ACK_RESPONSE, wbs_waits, wbs_retries); |
|
|
// Call tests |
// ---------- |
test_access_to_mac_reg(0, 3); // 0 - 3 |
test_mii(0, 17); // 0 - 17 |
test_note("PHY generates ideal Carrier sense and Collision signals for following tests"); |
eth_phy.carrier_sense_real_delay(0); |
test_mac_full_duplex_transmit(0, 3); // 0 - (3) |
|
test_note("PHY generates 'real' Carrier sense and Collision signals for following tests"); |
eth_phy.carrier_sense_real_delay(1); |
|
|
// Finish test's logs |
test_summary; |
$display("\n\n END of SIMULATION"); |
$fclose(tb_log_file | phy_log_file_desc | memory_log_file_desc | host_log_file_desc); |
$fclose(wb_s_mon_log_file_desc | wb_m_mon_log_file_desc); |
|
$stop; |
end |
|
|
// Generating mtx_clk clock |
initial |
|
////////////////////////////////////////////////////////////// |
// Test tasks |
////////////////////////////////////////////////////////////// |
|
task test_access_to_mac_reg; |
input [31:0] start_task; |
input [31:0] end_task; |
integer bit_start_1; |
integer bit_end_1; |
integer bit_start_2; |
integer bit_end_2; |
integer num_of_reg; |
integer i_addr; |
integer i_data; |
integer i_length; |
integer tmp_data; |
reg [31:0] tx_bd_num; |
reg [((`MAX_BLK_SIZE * 32) - 1):0] burst_data; |
reg [((`MAX_BLK_SIZE * 32) - 1):0] burst_tmp_data; |
integer i; |
integer i1; |
integer i2; |
integer i3; |
integer fail; |
reg [31:0] addr; |
reg [31:0] data; |
reg [31:0] data_max; |
begin |
mtx_clk=0; |
#3 forever #20 mtx_clk = ~mtx_clk; // 2*20 ns -> 25 MHz |
// #3 forever #200 mtx_clk = ~mtx_clk; // 2*200 ns -> 2.5 MHz |
// ACCESS TO MAC REGISTERS TEST |
test_heading("ACCESS TO MAC REGISTERS TEST"); |
$display(" "); |
$display("ACCESS TO MAC REGISTERS TEST"); |
fail = 0; |
|
/* Register space |
-------------- |
`define ETH_MODER `ETH_BASE + 32'h00 Mode Register |
`define ETH_INT `ETH_BASE + 32'h04 Interrupt Source Register |
`define ETH_INT_MASK `ETH_BASE + 32'h08 Interrupt Mask Register |
`define ETH_IPGT `ETH_BASE + 32'h0C Back to Bak Inter Packet Gap Register |
`define ETH_IPGR1 `ETH_BASE + 32'h10 Non Back to Back Inter Packet Gap Register 1 |
`define ETH_IPGR2 `ETH_BASE + 32'h14 Non Back to Back Inter Packet Gap Register 2 |
`define ETH_PACKETLEN `ETH_BASE + 32'h18 Packet Length Register (min. and max.) |
`define ETH_COLLCONF `ETH_BASE + 32'h1C Collision and Retry Configuration Register |
`define ETH_TX_BD_NUM `ETH_BASE + 32'h20 Transmit Buffer Descriptor Number Register |
`define ETH_CTRLMODER `ETH_BASE + 32'h24 Control Module Mode Register |
`define ETH_MIIMODER `ETH_BASE + 32'h28 MII Mode Register |
`define ETH_MIICOMMAND `ETH_BASE + 32'h2C MII Command Register |
`define ETH_MIIADDRESS `ETH_BASE + 32'h30 MII Address Register |
`define ETH_MIITX_DATA `ETH_BASE + 32'h34 MII Transmit Data Register |
`define ETH_MIIRX_DATA `ETH_BASE + 32'h38 MII Receive Data Register |
`define ETH_MIISTATUS `ETH_BASE + 32'h3C MII Status Register |
`define ETH_MAC_ADDR0 `ETH_BASE + 32'h40 MAC Individual Address Register 0 |
`define ETH_MAC_ADDR1 `ETH_BASE + 32'h44 MAC Individual Address Register 1 |
`define ETH_HASH_ADDR0 `ETH_BASE + 32'h48 Hash Register 0 |
`define ETH_HASH_ADDR1 `ETH_BASE + 32'h4C Hash Register 1 |
*/ |
|
|
if ((start_task <= 0) && (end_task >= 0)) |
begin |
// TEST 'WALKING ONE' WITH SINGLE CYCLES ACROSS MAC REGISTERS ( VARIOUS BUS DELAYS ) |
test_name = "TEST 'WALKING ONE' WITH SINGLE CYCLES ACROSS MAC REGISTERS ( VARIOUS BUS DELAYS )"; |
`TIME; $display(" TEST 'WALKING ONE' WITH SINGLE CYCLES ACROSS MAC REGISTERS ( VARIOUS BUS DELAYS )"); |
|
data = 0; |
for (i = 0; i <= 4; i = i + 1) // for initial wait cycles on WB bus |
begin |
wbm_init_waits = i; |
wbm_subseq_waits = {$random} % 5; // it is not important for single accesses |
for (i_addr = 0; i_addr <= 32'h4C; i_addr = i_addr + 4) // register address |
begin |
addr = `ETH_BASE + i_addr; |
// set ranges of R/W bits |
case (addr) |
`ETH_MODER: |
begin |
bit_start_1 = 0; |
bit_end_1 = 16; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_INT: // READONLY - tested within INT test |
begin |
bit_start_1 = 32; // not used |
bit_end_1 = 32; // not used |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_INT_MASK: |
begin |
bit_start_1 = 0; |
bit_end_1 = 6; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_IPGT: |
begin |
bit_start_1 = 0; |
bit_end_1 = 6; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_IPGR1: |
begin |
bit_start_1 = 0; |
bit_end_1 = 6; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_IPGR2: |
begin |
bit_start_1 = 0; |
bit_end_1 = 6; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_PACKETLEN: |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_COLLCONF: |
begin |
bit_start_1 = 0; |
bit_end_1 = 5; |
bit_start_2 = 16; |
bit_end_2 = 19; |
end |
`ETH_TX_BD_NUM: |
begin |
bit_start_1 = 0; |
bit_end_1 = 7; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_CTRLMODER: |
begin |
bit_start_1 = 0; |
bit_end_1 = 2; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIIMODER: |
begin |
bit_start_1 = 0; |
bit_end_1 = 9; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIICOMMAND: // "WRITEONLY" - tested within MIIM test - 3 LSBits are not written here!!! |
begin |
bit_start_1 = 32; // not used |
bit_end_1 = 32; // not used |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIIADDRESS: |
begin |
bit_start_1 = 0; |
bit_end_1 = 4; |
bit_start_2 = 8; |
bit_end_2 = 12; |
end |
`ETH_MIITX_DATA: |
begin |
bit_start_1 = 0; |
bit_end_1 = 15; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIIRX_DATA: // READONLY - tested within MIIM test |
begin |
bit_start_1 = 32; // not used |
bit_end_1 = 32; // not used |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIISTATUS: // READONLY - tested within MIIM test |
begin |
bit_start_1 = 32; // not used |
bit_end_1 = 32; // not used |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MAC_ADDR0: |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MAC_ADDR1: |
begin |
bit_start_1 = 0; |
bit_end_1 = 15; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_HASH_ADDR0: |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
default: // `ETH_HASH_ADDR1: |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
endcase |
for (i_data = 0; i_data <= 31; i_data = i_data + 1) // the position of walking one |
begin |
data = 1'b1 << i_data; |
if ( (addr == `ETH_MIICOMMAND) && (i_data <= 2) ) // DO NOT WRITE to 3 LSBits of MIICOMMAND !!! |
begin |
end |
else |
begin |
wbm_write(addr, data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
wbm_read(addr, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if ( ((i_data >= bit_start_1) && (i_data <= bit_end_1)) || |
((i_data >= bit_start_2) && (i_data <= bit_end_2)) ) // data should be equal to tmp_data |
begin |
if (tmp_data !== data) |
begin |
fail = fail + 1; |
test_fail("RW bit of the MAC register was not written or not read"); |
`TIME; |
$display("wbm_init_waits %d, addr %h, data %h, tmp_data %h", |
wbm_init_waits, addr, data, tmp_data); |
end |
end |
else // data should not be equal to tmp_data |
begin |
if (tmp_data === data) |
begin |
fail = fail + 1; |
test_fail("NON RW bit of the MAC register was written, but it shouldn't be"); |
`TIME; |
$display("wbm_init_waits %d, addr %h, data %h, tmp_data %h", |
wbm_init_waits, addr, data, tmp_data); |
end |
end |
end |
end |
end |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; // Errors were reported previously |
end |
|
// Generating mrx_clk clock |
initial |
|
if ((start_task <= 4) && (end_task >= 4)) // not used, since burst access to reg. is not supported |
begin |
mrx_clk=0; |
#16 forever #20 mrx_clk = ~mrx_clk; // 2*20 ns -> 25 MHz |
// #16 forever #200 mrx_clk = ~mrx_clk; // 2*200 ns -> 2.5 MHz |
/* // TEST 'WALKING ONE' WITH BURST CYCLES ACROSS MAC REGISTERS ( VARIOUS BUS DELAYS ) |
test_name = "TEST 'WALKING ONE' WITH BURST CYCLES ACROSS MAC REGISTERS ( VARIOUS BUS DELAYS )"; |
`TIME; $display(" TEST 'WALKING ONE' WITH BURST CYCLES ACROSS MAC REGISTERS ( VARIOUS BUS DELAYS )"); |
|
data = 0; |
burst_data = 0; |
burst_tmp_data = 0; |
i_length = 10; // two bursts for length 20 |
for (i = 0; i <= 4; i = i + 1) // for initial wait cycles on WB bus |
begin |
for (i1 = 0; i1 <= 4; i1 = i1 + 1) // for initial wait cycles on WB bus |
begin |
wbm_init_waits = i; |
wbm_subseq_waits = i1; |
#1; |
for (i_data = 0; i_data <= 31; i_data = i_data + 1) // the position of walking one |
begin |
data = 1'b1 << i_data; |
#1; |
for (i2 = 32'h4C; i2 >= 0; i2 = i2 - 4) |
begin |
burst_data = burst_data << 32; |
// DO NOT WRITE to 3 LSBits of MIICOMMAND !!! |
if ( ((`ETH_BASE + i2) == `ETH_MIICOMMAND) && (i_data <= 2) ) |
begin |
#1 burst_data[31:0] = 0; |
end |
else |
begin |
#1 burst_data[31:0] = data; |
end |
end |
#1; |
// 2 burst writes |
addr = `ETH_BASE; // address of a first burst |
wbm_write(addr, burst_data[(32 * 10 - 1):0], 4'hF, i_length, wbm_init_waits, wbm_subseq_waits); |
burst_tmp_data = burst_data >> (32 * i_length); |
addr = addr + 32'h28; // address of a second burst |
wbm_write(addr, burst_tmp_data[(32 * 10 - 1):0], 4'hF, i_length, wbm_init_waits, wbm_subseq_waits); |
#1; |
// 2 burst reads |
addr = `ETH_BASE; // address of a first burst |
wbm_read(addr, burst_tmp_data[(32 * 10 - 1):0], 4'hF, i_length, |
wbm_init_waits, wbm_subseq_waits); // first burst |
burst_tmp_data = burst_tmp_data << (32 * i_length); |
addr = addr + 32'h28; // address of a second burst |
wbm_read(addr, burst_tmp_data[(32 * 10 - 1):0], 4'hF, i_length, |
wbm_init_waits, wbm_subseq_waits); // second burst |
#1; |
for (i2 = 0; i2 <= 32'h4C; i2 = i2 + 4) |
begin |
// set ranges of R/W bits |
case (`ETH_BASE + i2) |
`ETH_MODER: |
begin |
bit_start_1 = 0; |
bit_end_1 = 16; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_INT: // READONLY - tested within INT test |
begin |
bit_start_1 = 32; // not used |
bit_end_1 = 32; // not used |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_INT_MASK: |
begin |
bit_start_1 = 0; |
bit_end_1 = 6; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_IPGT: |
begin |
bit_start_1 = 0; |
bit_end_1 = 6; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_IPGR1: |
begin |
bit_start_1 = 0; |
bit_end_1 = 6; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_IPGR2: |
begin |
bit_start_1 = 0; |
bit_end_1 = 6; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_PACKETLEN: |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_COLLCONF: |
begin |
bit_start_1 = 0; |
bit_end_1 = 5; |
bit_start_2 = 16; |
bit_end_2 = 19; |
end |
`ETH_TX_BD_NUM: |
begin |
bit_start_1 = 0; |
bit_end_1 = 7; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_CTRLMODER: |
begin |
bit_start_1 = 0; |
bit_end_1 = 2; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIIMODER: |
begin |
bit_start_1 = 0; |
bit_end_1 = 9; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIICOMMAND: // "WRITEONLY" - tested within MIIM test - 3 LSBits are not written here!!! |
begin |
bit_start_1 = 32; // not used |
bit_end_1 = 32; // not used |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIIADDRESS: |
begin |
bit_start_1 = 0; |
bit_end_1 = 4; |
bit_start_2 = 8; |
bit_end_2 = 12; |
end |
`ETH_MIITX_DATA: |
begin |
bit_start_1 = 0; |
bit_end_1 = 15; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIIRX_DATA: // READONLY - tested within MIIM test |
begin |
bit_start_1 = 32; // not used |
bit_end_1 = 32; // not used |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MIISTATUS: // READONLY - tested within MIIM test |
begin |
bit_start_1 = 32; // not used |
bit_end_1 = 32; // not used |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MAC_ADDR0: |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_MAC_ADDR1: |
begin |
bit_start_1 = 0; |
bit_end_1 = 15; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
`ETH_HASH_ADDR0: |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
default: // `ETH_HASH_ADDR1: |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
endcase |
#1; |
// 3 LSBits of MIICOMMAND are NOT written !!! |
if ( ((`ETH_BASE + i2) == `ETH_MIICOMMAND) && (i_data <= 2) ) |
begin |
if (burst_tmp_data[31:0] !== burst_data[31:0]) |
begin |
fail = fail + 1; |
test_fail("NON WR bit of the MAC MIICOMMAND register was wrong written or read"); |
`TIME; |
$display("wbm_init_waits %d, wbm_subseq_waits %d, addr %h, data %h, tmp_data %h", |
wbm_init_waits, wbm_subseq_waits, i2, burst_data[31:0], burst_tmp_data[31:0]); |
end |
end |
else |
begin |
if ( ((i_data >= bit_start_1) && (i_data <= bit_end_1)) || |
((i_data >= bit_start_2) && (i_data <= bit_end_2)) ) // data should be equal to tmp_data |
begin |
if (burst_tmp_data[31:0] !== burst_data[31:0]) |
begin |
fail = fail + 1; |
test_fail("RW bit of the MAC register was not written or not read"); |
`TIME; |
$display("wbm_init_waits %d, wbm_subseq_waits %d, addr %h, data %h, tmp_data %h", |
wbm_init_waits, wbm_subseq_waits, i2, burst_data[31:0], burst_tmp_data[31:0]); |
end |
end |
else // data should not be equal to tmp_data |
begin |
if (burst_tmp_data[31:0] === burst_data[31:0]) |
begin |
fail = fail + 1; |
test_fail("NON RW bit of the MAC register was written, but it shouldn't be"); |
`TIME; |
$display("wbm_init_waits %d, wbm_subseq_waits %d, addr %h, data %h, tmp_data %h", |
wbm_init_waits, wbm_subseq_waits, i2, burst_data[31:0], burst_tmp_data[31:0]); |
end |
end |
end |
burst_tmp_data = burst_tmp_data >> 32; |
burst_data = burst_data >> 32; |
end |
end |
end |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0;*/ |
end |
|
reg [31:0] tmp; |
initial |
|
if ((start_task <= 1) && (end_task >= 1)) |
begin |
wait(StartTB); // Start of testbench |
|
// TEST 'WALKING ONE' WITH SINGLE CYCLES ACROSS MAC BUFFER DESC. ( VARIOUS BUS DELAYS ) |
test_name = "TEST 'WALKING ONE' WITH SINGLE CYCLES ACROSS MAC BUFFER DESC. ( VARIOUS BUS DELAYS )"; |
`TIME; $display(" TEST 'WALKING ONE' WITH SINGLE CYCLES ACROSS MAC BUFFER DESC. ( VARIOUS BUS DELAYS )"); |
|
eth_host.wb_write(`ETH_MODER, 4'hf, 32'h0); // Reset OFF |
eth_host.wb_read(`ETH_MODER, 4'hf, tmp); |
eth_host.wb_write(`ETH_MAC_ADDR1, 4'hf, 32'h0002); // Set ETH_MAC_ADDR1 register |
eth_host.wb_write(`ETH_MAC_ADDR0, 4'hf, 32'h03040506); // Set ETH_MAC_ADDR0 register |
data = 0; |
// set TX and RX buffer descriptors |
tx_bd_num = 32'h40; |
wbm_write(`ETH_TX_BD_NUM, tx_bd_num, 4'hF, 1, 0, 0); |
for (i = 0; i <= 4; i = i + 1) // for initial wait cycles on WB bus |
begin |
wbm_init_waits = i; |
wbm_subseq_waits = {$random} % 5; // it is not important for single accesses |
for (i_addr = 32'h400; i_addr <= 32'h7FC; i_addr = i_addr + 4) // buffer descriptor address |
begin |
addr = `ETH_BASE + i_addr; |
if (i_addr < (32'h400 + (tx_bd_num << 3))) // TX buffer descriptors |
begin |
// set ranges of R/W bits |
case (addr[3]) |
1'b0: // buffer control bits |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; // 8; |
bit_start_2 = 11; |
bit_end_2 = 31; |
end |
default: // 1'b1: // buffer pointer |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
endcase |
end |
else // RX buffer descriptors |
begin |
// set ranges of R/W bits |
case (addr[3]) |
1'b0: // buffer control bits |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; // 7; |
bit_start_2 = 13; |
bit_end_2 = 31; |
end |
default: // 1'b1: // buffer pointer |
begin |
bit_start_1 = 0; |
bit_end_1 = 31; |
bit_start_2 = 32; // not used |
bit_end_2 = 32; // not used |
end |
endcase |
end |
|
initialize_txbd(3); |
initialize_rxbd(2); |
for (i_data = 0; i_data <= 31; i_data = i_data + 1) // the position of walking one |
begin |
data = 1'b1 << i_data; |
if ( (addr[3] == 0) && (i_data == 15) ) // DO NOT WRITE to this bit !!! |
begin |
end |
else |
begin |
wbm_write(addr, data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
wbm_read(addr, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if ( ((i_data >= bit_start_1) && (i_data <= bit_end_1)) || |
((i_data >= bit_start_2) && (i_data <= bit_end_2)) ) // data should be equal to tmp_data |
begin |
if (tmp_data !== data) |
begin |
fail = fail + 1; |
test_fail("RW bit of the MAC buffer descriptors was not written or not read"); |
`TIME; |
$display("wbm_init_waits %d, addr %h, data %h, tmp_data %h", |
wbm_init_waits, addr, data, tmp_data); |
end |
end |
else // data should not be equal to tmp_data |
begin |
if (tmp_data === data) |
begin |
fail = fail + 1; |
test_fail("NON RW bit of the MAC buffer descriptors was written, but it shouldn't be"); |
`TIME; |
$display("wbm_init_waits %d, addr %h, data %h, tmp_data %h", |
wbm_init_waits, addr, data, tmp_data); |
end |
end |
end |
end |
end |
case (i) |
0: $display(" buffer descriptors tested with 0 bus delay"); |
1: $display(" buffer descriptors tested with 1 bus delay cycle"); |
2: $display(" buffer descriptors tested with 2 bus delay cycles"); |
3: $display(" buffer descriptors tested with 3 bus delay cycles"); |
default: $display(" buffer descriptors tested with 4 bus delay cycles"); |
endcase |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
// eth_host.wb_write(`ETH_MODER, 4'hf, `ETH_MODER_RXEN | `ETH_MODER_TXEN | `ETH_MODER_PRO | |
// `ETH_MODER_CRCEN | `ETH_MODER_PAD); // Set MODER register |
// eth_host.wb_write(`ETH_MODER, 4'hf, `ETH_MODER_RXEN | `ETH_MODER_TXEN | |
// `ETH_MODER_CRCEN | `ETH_MODER_PAD); // Set MODER register |
eth_host.wb_write(`ETH_MODER, 4'hf, `ETH_MODER_RXEN | `ETH_MODER_TXEN | `ETH_MODER_BRO | |
`ETH_MODER_CRCEN | `ETH_MODER_PAD); // Set MODER register |
// eth_host.wb_write(`ETH_MODER, 4'hf, `ETH_MODER_RXEN | `ETH_MODER_TXEN | `ETH_MODER_PRO | |
// `ETH_MODER_CRCEN | `ETH_MODER_PAD | `ETH_MODER_LOOPBCK); // Set MODER register |
// eth_host.wb_write(`ETH_MODER, 4'hf, `ETH_MODER_RXEN | `ETH_MODER_TXEN | `ETH_MODER_PRO | |
// `ETH_MODER_CRCEN | `ETH_MODER_PAD | `ETH_MODER_LOOPBCK | |
// `ETH_MODER_FULLD); // Set MODER register |
eth_host.wb_read(`ETH_MODER, 4'hf, tmp); |
/* Register RESET values MAX. values |
----------------------------------------- |
ETH_MODER 32'h0000_A800 32'h0000_A800 Mode Register |
ETH_INT 32'h0000_0000 32'h0000_0000 Interrupt Source Register |
ETH_INT_MASK 32'h0000_0000 32'h0000_0000 Interrupt Mask Register |
ETH_IPGT 32'h0000_0012 32'h0000_0012 Back to Bak Inter Packet Gap Register |
ETH_IPGR1 32'h0000_000C 32'h0000_000C Non Back to Back Inter Packet Gap Register 1 |
ETH_IPGR2 32'h0000_0012 32'h0000_0012 Non Back to Back Inter Packet Gap Register 2 |
ETH_PACKETLEN 32'h0040_0600 32'h0040_0600 Packet Length Register (min. and max.) |
ETH_COLLCONF 32'h000F_003F 32'h000F_003F Collision and Retry Configuration Register |
ETH_TX_BD_NUM 32'h0000_0040 32'h0000_0080 Transmit Buffer Descriptor Number Register |
ETH_CTRLMODER 32'h0000_0000 32'h0000_0000 Control Module Mode Register |
ETH_MIIMODER 32'h0000_0064 32'h0000_0064 MII Mode Register |
ETH_MIICOMMAND 32'h0000_0000 32'h0000_0000 MII Command Register |
ETH_MIIADDRESS 32'h0000_0000 32'h0000_0000 MII Address Register |
ETH_MIITX_DATA 32'h0000_0000 32'h0000_0000 MII Transmit Data Register |
ETH_MIIRX_DATA 32'h0000_0000 32'h0000_0000 MII Receive Data Register |
ETH_MIISTATUS 32'h0000_0000 32'h0000_0000 MII Status Register |
ETH_MAC_ADDR0 32'h0000_0000 32'h0000_0000 MAC Individual Address Register 0 |
ETH_MAC_ADDR1 32'h0000_0000 32'h0000_0000 MAC Individual Address Register 1 |
ETH_HASH_ADDR0 32'h0000_0000 32'h0000_0000 Hash Register 0 |
ETH_HASH_ADDR1 32'h0000_0000 32'h0000_0000 Hash Register 1 |
*/ |
|
set_packet(16'h64, 8'h1); |
set_packet(16'h34, 8'h11); |
send_packet; |
set_packet(16'h34, 8'h21); |
set_packet(16'h34, 8'h31); |
/* |
eth_host.wb_write(`ETH_CTRLMODER, 4'hf, 32'h4); // Enable Tx Flow control |
eth_host.wb_write(`ETH_CTRLMODER, 4'hf, 32'h5); // Enable Tx Flow control |
eth_host.wb_write(`ETH_TX_CTRL, 4'hf, 32'h10013); // Send Control frame with PAUSE_TV=0x0013 |
*/ |
send_packet; |
|
if ((start_task <= 2) && (end_task >= 2)) |
begin |
// TEST MAX REG. VALUES AND REG. VALUES AFTER WRITING INVERSE RESET VALUES AND HARD RESET OF THE MAC |
test_name = |
"TEST MAX REG. VALUES AND REG. VALUES AFTER WRITING INVERSE RESET VALUES AND HARD RESET OF THE MAC"; |
`TIME; $display( |
" TEST MAX REG. VALUES AND REG. VALUES AFTER WRITING INVERSE RESET VALUES AND HARD RESET OF THE MAC"); |
|
GetDataOnMRxD(100, `UNICAST_XFR); // LengthRx bytes is comming on MRxD[3:0] signals |
// reset MAC registers |
hard_reset; |
for (i = 0; i <= 4; i = i + 1) // 0, 2 - WRITE; 1, 3, 4 - READ |
begin |
for (i_addr = 0; i_addr <= 32'h4C; i_addr = i_addr + 4) // register address |
begin |
addr = `ETH_BASE + i_addr; |
// set ranges of R/W bits |
case (addr) |
`ETH_MODER: |
begin |
data = 32'h0000_A800; |
data_max = 32'h0001_FFFF; |
end |
`ETH_INT: // READONLY - tested within INT test |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_0000; |
end |
`ETH_INT_MASK: |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_007F; |
end |
`ETH_IPGT: |
begin |
data = 32'h0000_0012; |
data_max = 32'h0000_007F; |
end |
`ETH_IPGR1: |
begin |
data = 32'h0000_000C; |
data_max = 32'h0000_007F; |
end |
`ETH_IPGR2: |
begin |
data = 32'h0000_0012; |
data_max = 32'h0000_007F; |
end |
`ETH_PACKETLEN: |
begin |
data = 32'h0040_0600; |
data_max = 32'hFFFF_FFFF; |
end |
`ETH_COLLCONF: |
begin |
data = 32'h000F_003F; |
data_max = 32'h000F_003F; |
end |
`ETH_TX_BD_NUM: |
begin |
data = 32'h0000_0040; |
data_max = 32'h0000_0080; |
end |
`ETH_CTRLMODER: |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_0007; |
end |
`ETH_MIIMODER: |
begin |
data = 32'h0000_0064; |
data_max = 32'h0000_03FF; |
end |
`ETH_MIICOMMAND: // "WRITEONLY" - tested within MIIM test - 3 LSBits are not written here!!! |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_0007; |
end |
`ETH_MIIADDRESS: |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_1F1F; |
end |
`ETH_MIITX_DATA: |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_FFFF; |
end |
`ETH_MIIRX_DATA: // READONLY - tested within MIIM test |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_0000; |
end |
`ETH_MIISTATUS: // READONLY - tested within MIIM test |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_0000; |
end |
`ETH_MAC_ADDR0: |
begin |
data = 32'h0000_0000; |
data_max = 32'hFFFF_FFFF; |
end |
`ETH_MAC_ADDR1: |
begin |
data = 32'h0000_0000; |
data_max = 32'h0000_FFFF; |
end |
`ETH_HASH_ADDR0: |
begin |
data = 32'h0000_0000; |
data_max = 32'hFFFF_FFFF; |
end |
default: // `ETH_HASH_ADDR1: |
begin |
data = 32'h0000_0000; |
data_max = 32'hFFFF_FFFF; |
end |
endcase |
|
repeat (1000) @(posedge wb_clk_o); // Waiting for TxEthMac to finish transmit |
wbm_init_waits = {$random} % 3; |
wbm_subseq_waits = {$random} % 5; // it is not important for single accesses |
if (i == 0) |
wbm_write(addr, ~data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
else if (i == 2) |
wbm_write(addr, 32'hFFFFFFFF, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
else if ((i == 1) || (i == 4)) |
begin |
wbm_read(addr, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp_data !== data) |
begin |
fail = fail + 1; |
test_fail("RESET value of the MAC register is not correct"); |
`TIME; |
$display(" addr %h, data %h, tmp_data %h", addr, data, tmp_data); |
end |
end |
else // check maximum values |
begin |
wbm_read(addr, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (addr == `ETH_TX_BD_NUM) // previous data should remain in this register |
begin |
if (tmp_data !== data) |
begin |
fail = fail + 1; |
test_fail("Previous value of the TX_BD_NUM register did not remain"); |
`TIME; |
$display(" addr %h, data_max %h, tmp_data %h", addr, data_max, tmp_data); |
end |
// try maximum (80) |
wbm_write(addr, data_max, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
wbm_read(addr, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp_data !== data_max) |
begin |
fail = fail + 1; |
test_fail("MAX value of the TX_BD_NUM register is not correct"); |
`TIME; |
$display(" addr %h, data_max %h, tmp_data %h", addr, data_max, tmp_data); |
end |
// try one less than maximum (80) |
wbm_write(addr, (data_max - 1), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
wbm_read(addr, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp_data !== (data_max - 1)) |
begin |
fail = fail + 1; |
test_fail("ONE less than MAX value of the TX_BD_NUM register is not correct"); |
`TIME; |
$display(" addr %h, data_max %h, tmp_data %h", addr, data_max, tmp_data); |
end |
// try one more than maximum (80) |
wbm_write(addr, (data_max + 1), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
wbm_read(addr, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp_data !== (data_max - 1)) // previous data should remain in this register |
begin |
fail = fail + 1; |
test_fail("Previous value of the TX_BD_NUM register did not remain"); |
`TIME; |
$display(" addr %h, data_max %h, tmp_data %h", addr, data_max, tmp_data); |
end |
end |
else |
begin |
if (tmp_data !== data_max) |
begin |
fail = fail + 1; |
test_fail("MAX value of the MAC register is not correct"); |
`TIME; |
$display(" addr %h, data_max %h, tmp_data %h", addr, data_max, tmp_data); |
end |
end |
end |
end |
// reset MAC registers |
if ((i == 0) || (i == 3)) |
begin |
hard_reset; |
end |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
GetDataOnMRxD(500, `BROADCAST_XFR); // LengthRx bytes is comming on MRxD[3:0] signals |
|
repeat (1000) @(posedge mrx_clk); // Waiting for TxEthMac to finish transmit |
if ((start_task <= 3) && (end_task >= 3)) |
begin |
// TEST BUFFER DESC. RAM PRESERVING VALUES AFTER HARD RESET OF THE MAC AND RESETING THE LOGIC |
test_name = "TEST BUFFER DESC. RAM PRESERVING VALUES AFTER HARD RESET OF THE MAC AND RESETING THE LOGIC"; |
`TIME; |
$display(" TEST BUFFER DESC. RAM PRESERVING VALUES AFTER HARD RESET OF THE MAC AND RESETING THE LOGIC"); |
|
// reset MAC registers |
hard_reset; |
// reset LOGIC with soft reset |
reset_mac; |
reset_mii; |
for (i = 0; i <= 3; i = i + 1) // 0, 2 - WRITE; 1, 3 - READ |
begin |
for (i_addr = 32'h400; i_addr <= 32'h7FC; i_addr = i_addr + 4) // buffer descriptor address |
begin |
addr = `ETH_BASE + i_addr; |
|
GetDataOnMRxD(1200, `BROADCAST_XFR); // LengthRx bytes is comming on MRxD[3:0] signals |
wbm_init_waits = {$random} % 3; |
wbm_subseq_waits = {$random} % 5; // it is not important for single accesses |
if (i == 0) |
begin |
data = 32'hFFFFFFFF; |
wbm_write(addr, 32'hFFFFFFFF, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
else if (i == 2) |
begin |
data = 32'h00000000; |
wbm_write(addr, 32'h00000000, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
else |
begin |
wbm_read(addr, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp_data !== data) |
begin |
fail = fail + 1; |
test_fail("PRESERVED value of the MAC buffer descriptors is not correct"); |
`TIME; |
$display(" addr %h, data %h, tmp_data %h", addr, data, tmp_data); |
end |
end |
end |
if ((i == 0) || (i == 2)) |
begin |
// reset MAC registers |
hard_reset; |
// reset LOGIC with soft reset |
reset_mac; |
reset_mii; |
end |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
GetDataOnMRxD(1000, `UNICAST_XFR); // LengthRx bytes is comming on MRxD[3:0] signals |
end |
endtask // test_access_to_mac_reg |
|
repeat (10000) @(posedge wb_clk_o); // Waiting for TxEthMac to finish transmit |
|
// Reading and printing interrupts |
eth_host.wb_read(`ETH_INT, 4'hf, tmp); |
$display("Print irq = 0x%0x", tmp); |
|
//Clearing all interrupts |
eth_host.wb_write(`ETH_INT, 4'hf, 32'h60); |
|
// Reading and printing interrupts |
eth_host.wb_read(`ETH_INT, 4'hf, tmp); |
$display("Print irq = 0x%0x", tmp); |
task test_mii; |
input [31:0] start_task; |
input [31:0] end_task; |
integer i; |
integer i1; |
integer i2; |
integer i3; |
integer cnt; |
integer fail; |
reg [8:0] clk_div; // only 8 bits are valid! |
reg [4:0] phy_addr; |
reg [4:0] reg_addr; |
reg [15:0] phy_data; |
reg [15:0] tmp_data; |
begin |
// MIIM MODULE TEST |
test_heading("MIIM MODULE TEST"); |
$display(" "); |
$display("MIIM MODULE TEST"); |
fail = 0; |
|
$display("\n\n End of simulation"); |
$stop; |
// reset MIIM LOGIC with soft reset |
reset_mii; |
|
|
if ((start_task <= 0) && (end_task >= 0)) |
begin |
// TEST CLOCK DIVIDER OF MII MANAGEMENT MODULE WITH ALL POSSIBLE FREQUENCES |
test_name = "TEST CLOCK DIVIDER OF MII MANAGEMENT MODULE WITH ALL POSSIBLE FREQUENCES"; |
`TIME; $display(" TEST CLOCK DIVIDER OF MII MANAGEMENT MODULE WITH ALL POSSIBLE FREQUENCES"); |
|
wait(Mdc_O); // wait for MII clock to be 1 |
for(clk_div = 0; clk_div <= 255; clk_div = clk_div + 1) |
begin |
i1 = 0; |
i2 = 0; |
#Tp mii_set_clk_div(clk_div[7:0]); |
@(posedge Mdc_O); |
#Tp; |
fork |
begin |
@(posedge Mdc_O); |
#Tp; |
disable count_i1; |
disable count_i2; |
end |
begin: count_i1 |
forever |
begin |
@(posedge wb_clk); |
i1 = i1 + 1; |
#Tp; |
end |
end |
begin: count_i2 |
forever |
begin |
@(negedge wb_clk); |
i2 = i2 + 1; |
#Tp; |
end |
end |
join |
if((clk_div[7:0] == 0) || (clk_div[7:0] == 1) || (clk_div[7:0] == 2) || (clk_div[7:0] == 3)) |
begin |
if((i1 == i2) && (i1 == 2)) |
begin |
end |
else |
begin |
fail = fail + 1; |
test_fail("Clock divider of MII module did'nt divide frequency corectly (it should divid with 2)"); |
end |
end |
else |
begin |
if((i1 == i2) && (i1 == {clk_div[7:1], 1'b0})) |
begin |
end |
else |
begin |
fail = fail + 1; |
test_fail("Clock divider of MII module did'nt divide frequency corectly"); |
end |
end |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
|
task initialize_txbd; |
input [6:0] txbd_num; |
|
integer i; |
integer bd_status_addr, buf_addr, bd_ptr_addr; |
|
for(i=0; i<txbd_num; i=i+1) begin |
buf_addr = `TX_BUF_BASE + i * 32'h600; |
bd_status_addr = `TX_BD_BASE + i * 8; |
bd_ptr_addr = bd_status_addr + 4; |
|
// Initializing BD - status |
if(i==txbd_num-1) |
eth_host.wb_write(bd_status_addr, 4'hf, 32'h00007800); // last BD: + WRAP |
if ((start_task <= 1) && (end_task >= 1)) |
begin |
// TEST VARIOUS READINGS FROM 'REAL' PHY REGISTERS |
test_name = "TEST VARIOUS READINGS FROM 'REAL' PHY REGISTERS"; |
`TIME; $display(" TEST VARIOUS READINGS FROM 'REAL' PHY REGISTERS"); |
|
// set the fastest possible MII |
clk_div = 0; |
mii_set_clk_div(clk_div[7:0]); |
// set address |
reg_addr = 5'h1F; |
phy_addr = 5'h1; |
while(reg_addr >= 5'h4) |
begin |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== 16'hDEAD) |
begin |
test_fail("Wrong data was read from PHY from 'not used' address space"); |
fail = fail + 1; |
end |
if (reg_addr == 5'h4) // go out of for loop |
reg_addr = 5'h3; |
else |
eth_host.wb_write(bd_status_addr, 4'hf, 32'h00005800); // IRQ + PAD + CRC |
reg_addr = reg_addr - 5'h9; |
end |
|
eth_host.wb_write(bd_ptr_addr, 4'hf, buf_addr); // Initializing BD - pointer |
// set address |
reg_addr = 5'h3; |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== {`PHY_ID2, `MAN_MODEL_NUM, `MAN_REVISION_NUM}) |
begin |
test_fail("Wrong data was read from PHY from ID register 2"); |
fail = fail + 1; |
end |
endtask // initialize_txbd |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
task initialize_rxbd; |
input [6:0] rxbd_num; |
if ((start_task <= 2) && (end_task >= 2)) |
begin |
// TEST VARIOUS WRITINGS TO 'REAL' PHY REGISTERS ( CONTROL AND NON WRITABLE REGISTERS ) |
test_name = "TEST VARIOUS WRITINGS TO 'REAL' PHY REGISTERS ( CONTROL AND NON WRITABLE REGISTERS )"; |
`TIME; $display(" TEST VARIOUS WRITINGS TO 'REAL' PHY REGISTERS ( CONTROL AND NON WRITABLE REGISTERS )"); |
|
// negate data and try to write into unwritable register |
tmp_data = ~phy_data; |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, tmp_data); |
check_mii_busy; // wait for write to finish |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp_data !== phy_data) |
begin |
test_fail("Data was written into unwritable PHY register - ID register 2"); |
fail = fail + 1; |
end |
|
// set address |
reg_addr = 5'h0; // control register |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// write request |
phy_data = 16'h7DFF; // bit 15 (RESET bit) and bit 9 are self clearing bits |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
check_mii_busy; // wait for write to finish |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== 16'h7DFF) |
begin |
test_fail("Data was not correctly written into OR read from writable PHY register - control register"); |
fail = fail + 1; |
end |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, tmp_data); |
check_mii_busy; // wait for write to finish |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from writable PHY register - control register"); |
fail = fail + 1; |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 3) && (end_task >= 3)) |
begin |
// TEST RESET PHY THROUGH MII MANAGEMENT MODULE |
test_name = "TEST RESET PHY THROUGH MII MANAGEMENT MODULE"; |
`TIME; $display(" TEST RESET PHY THROUGH MII MANAGEMENT MODULE"); |
|
// set address |
reg_addr = 5'h0; // control register |
// write request |
phy_data = 16'h7DFF; // bit 15 (RESET bit) and bit 9 are self clearing bits |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
check_mii_busy; // wait for write to finish |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from writable PHY register - control register"); |
fail = fail + 1; |
end |
// set reset bit - selfclearing bit in PHY |
phy_data = phy_data | 16'h8000; |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
check_mii_busy; // wait for write to finish |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// check self clearing of reset bit |
if (tmp_data[15] !== 1'b0) |
begin |
test_fail("Reset bit should be self cleared - control register"); |
fail = fail + 1; |
end |
// check reset value of control register |
if (tmp_data !== {2'h0, (`LED_CFG1 || `LED_CFG2), `LED_CFG1, 3'h0, `LED_CFG3, 8'h0}) |
begin |
test_fail("PHY was not reset correctly AND/OR reset bit not self cleared"); |
fail = fail + 1; |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 4) && (end_task >= 4)) |
begin |
// TEST 'WALKING ONE' ACROSS PHY ADDRESS ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST 'WALKING ONE' ACROSS PHY ADDRESS ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST 'WALKING ONE' ACROSS PHY ADDRESS ( WITH AND WITHOUT PREAMBLE )"); |
|
// set PHY to test mode |
#Tp eth_phy.test_regs(1); // set test registers (wholy writable registers) and respond to all PHY addresses |
for (i = 0; i <= 1; i = i + 1) |
begin |
#Tp eth_phy.preamble_suppresed(i); |
#Tp eth_phy.clear_test_regs; |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i, 8'h0}), 4'hF, 1, wbm_init_waits, |
wbm_subseq_waits); |
// walk one across phy address |
for (phy_addr = 5'h1; phy_addr > 5'h0; phy_addr = phy_addr << 1) |
begin |
reg_addr = $random; |
tmp_data = $random; |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, tmp_data); |
check_mii_busy; // wait for write to finish |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
#Tp; |
if (phy_data !== tmp_data) |
begin |
if (i) |
test_fail("Data was not correctly written into OR read from test registers (without preamble)"); |
else |
test_fail("Data was not correctly written into OR read from test registers (with preamble)"); |
fail = fail + 1; |
end |
@(posedge wb_clk); |
#Tp; |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.test_regs(0); |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 5) && (end_task >= 5)) |
begin |
// TEST 'WALKING ONE' ACROSS PHY'S REGISTER ADDRESS ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST 'WALKING ONE' ACROSS PHY'S REGISTER ADDRESS ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST 'WALKING ONE' ACROSS PHY'S REGISTER ADDRESS ( WITH AND WITHOUT PREAMBLE )"); |
|
// set PHY to test mode |
#Tp eth_phy.test_regs(1); // set test registers (wholy writable registers) and respond to all PHY addresses |
for (i = 0; i <= 1; i = i + 1) |
begin |
#Tp eth_phy.preamble_suppresed(i); |
#Tp eth_phy.clear_test_regs; |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i, 8'h0}), 4'hF, 1, wbm_init_waits, |
wbm_subseq_waits); |
// walk one across reg address |
for (reg_addr = 5'h1; reg_addr > 5'h0; reg_addr = reg_addr << 1) |
begin |
phy_addr = $random; |
tmp_data = $random; |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, tmp_data); |
check_mii_busy; // wait for write to finish |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
#Tp; |
if (phy_data !== tmp_data) |
begin |
if (i) |
test_fail("Data was not correctly written into OR read from test registers (without preamble)"); |
else |
test_fail("Data was not correctly written into OR read from test registers (with preamble)"); |
fail = fail + 1; |
end |
@(posedge wb_clk); |
#Tp; |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.test_regs(0); |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 6) && (end_task >= 6)) |
begin |
// TEST 'WALKING ONE' ACROSS PHY'S DATA ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST 'WALKING ONE' ACROSS PHY'S DATA ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST 'WALKING ONE' ACROSS PHY'S DATA ( WITH AND WITHOUT PREAMBLE )"); |
|
// set PHY to test mode |
#Tp eth_phy.test_regs(1); // set test registers (wholy writable registers) and respond to all PHY addresses |
for (i = 0; i <= 1; i = i + 1) |
begin |
#Tp eth_phy.preamble_suppresed(i); |
#Tp eth_phy.clear_test_regs; |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i, 8'h0}), 4'hF, 1, wbm_init_waits, |
wbm_subseq_waits); |
// walk one across data |
for (tmp_data = 16'h1; tmp_data > 16'h0; tmp_data = tmp_data << 1) |
begin |
phy_addr = $random; |
reg_addr = $random; |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, tmp_data); |
check_mii_busy; // wait for write to finish |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
#Tp; |
if (phy_data !== tmp_data) |
begin |
if (i) |
test_fail("Data was not correctly written into OR read from test registers (without preamble)"); |
else |
test_fail("Data was not correctly written into OR read from test registers (with preamble)"); |
fail = fail + 1; |
end |
@(posedge wb_clk); |
#Tp; |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.test_regs(0); |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 7) && (end_task >= 7)) |
begin |
// TEST READING FROM PHY WITH WRONG PHY ADDRESS ( HOST READING HIGH 'Z' DATA ) |
test_name = "TEST READING FROM PHY WITH WRONG PHY ADDRESS ( HOST READING HIGH 'Z' DATA )"; |
`TIME; $display(" TEST READING FROM PHY WITH WRONG PHY ADDRESS ( HOST READING HIGH 'Z' DATA )"); |
|
phy_addr = 5'h2; // wrong PHY address |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
$display(" => Two errors will be displayed from WB Bus Monitor, because correct HIGH Z data was read"); |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp_data !== 16'hzzzz) |
begin |
test_fail("Data was read from PHY register with wrong PHY address - control register"); |
fail = fail + 1; |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 8) && (end_task >= 8)) |
begin |
// TEST WRITING TO PHY WITH WRONG PHY ADDRESS AND READING FROM CORRECT ONE |
test_name = "TEST WRITING TO PHY WITH WRONG PHY ADDRESS AND READING FROM CORRECT ONE"; |
`TIME; $display(" TEST WRITING TO PHY WITH WRONG PHY ADDRESS AND READING FROM CORRECT ONE"); |
|
// set address |
reg_addr = 5'h0; // control register |
phy_addr = 5'h2; // wrong PHY address |
// write request |
phy_data = 16'h7DFF; // bit 15 (RESET bit) and bit 9 are self clearing bits |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
check_mii_busy; // wait for write to finish |
|
phy_addr = 5'h1; // correct PHY address |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data === tmp_data) |
begin |
test_fail("Data was written into PHY register with wrong PHY address - control register"); |
fail = fail + 1; |
end |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 9) && (end_task >= 9)) |
begin |
// TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER READ REQUEST ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER READ REQUEST ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; |
$display(" TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER READ REQUEST ( WITH AND WITHOUT PREAMBLE )"); |
|
for (i2 = 0; i2 <= 1; i2 = i2 + 1) // choose preamble or not |
begin |
#Tp eth_phy.preamble_suppresed(i2); |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i2, 8'h0}), 4'hF, 1, wbm_init_waits, |
wbm_subseq_waits); |
i = 0; |
cnt = 0; |
while (i < 80) // delay for sliding of writing a STOP SCAN command |
begin |
for (i3 = 0; i3 <= 1; i3 = i3 + 1) // choose read or write after read will be finished |
begin |
// set address |
reg_addr = 5'h0; // control register |
phy_addr = 5'h1; // correct PHY address |
cnt = 0; |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
fork |
begin |
repeat(i) @(posedge Mdc_O); |
// write command 0x0 into MII command register |
// MII command written while read in progress |
wbm_write(`ETH_MIICOMMAND, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge wb_clk); |
#Tp check_mii_busy; // wait for read to finish |
end |
begin |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
end |
join |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Read request did not proceed correctly, while SCAN STOP command was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Read request did not proceed correctly, while SCAN STOP command was written"); |
fail = fail + 1; |
end |
end |
// check the BUSY signal to see if the bus is still IDLE |
for (i1 = 0; i1 < 8; i1 = i1 + 1) |
check_mii_busy; // wait for bus to become idle |
|
integer i; |
integer bd_status_addr, buf_addr, bd_ptr_addr; |
// try normal write or read after read was finished |
#Tp phy_data = {8'h7D, (i[7:0] + 1)}; |
#Tp cnt = 0; |
if (i3 == 0) // write after read |
begin |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while(Mdio_IO !== 1'bz) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
@(posedge Mdc_O); |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read and check data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from PHY register - control register"); |
fail = fail + 1; |
end |
end |
else // read after read |
begin |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
@(posedge Mdc_O); |
check_mii_busy; // wait for read to finish |
// read and check data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from PHY register - control register"); |
fail = fail + 1; |
end |
end |
// check if transfer was a proper length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("New request did not proceed correctly, after read request"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("New request did not proceed correctly, after read request"); |
fail = fail + 1; |
end |
end |
end |
#Tp; |
// set delay of writing the command |
if (i2) // without preamble |
begin |
case(i) |
0, 1: i = i + 1; |
18, 19, 20, 21, 22, |
23, 24, 25, 26, 27, |
28, 29, 30, 31, 32, |
33, 34, 35: i = i + 1; |
36: i = 80; |
default: i = 18; |
endcase |
end |
else // with preamble |
begin |
case(i) |
0, 1: i = i + 1; |
50, 51, 52, 53, 54, |
55, 56, 57, 58, 59, |
60, 61, 62, 63, 64, |
65, 66, 67: i = i + 1; |
68: i = 80; |
default: i = 50; |
endcase |
end |
@(posedge wb_clk); |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 10) && (end_task >= 10)) |
begin |
// TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER WRITE REQUEST ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER WRITE REQUEST ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; |
$display(" TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER WRITE REQUEST ( WITH AND WITHOUT PREAMBLE )"); |
|
for (i2 = 0; i2 <= 1; i2 = i2 + 1) // choose preamble or not |
begin |
#Tp eth_phy.preamble_suppresed(i2); |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i2, 8'h0}), 4'hF, 1, wbm_init_waits, |
wbm_subseq_waits); |
i = 0; |
cnt = 0; |
while (i < 80) // delay for sliding of writing a STOP SCAN command |
begin |
for (i3 = 0; i3 <= 1; i3 = i3 + 1) // choose read or write after write will be finished |
begin |
// set address |
reg_addr = 5'h0; // control register |
phy_addr = 5'h1; // correct PHY address |
cnt = 0; |
// write request |
phy_data = {8'h75, (i[7:0] + 1)}; |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
fork |
begin |
repeat(i) @(posedge Mdc_O); |
// write command 0x0 into MII command register |
// MII command written while read in progress |
wbm_write(`ETH_MIICOMMAND, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge wb_clk); |
#Tp check_mii_busy; // wait for write to finish |
end |
begin |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while(Mdio_IO !== 1'bz) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
end |
join |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Write request did not proceed correctly, while SCAN STOP command was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Write request did not proceed correctly, while SCAN STOP command was written"); |
fail = fail + 1; |
end |
end |
// check the BUSY signal to see if the bus is still IDLE |
for (i1 = 0; i1 < 8; i1 = i1 + 1) |
check_mii_busy; // wait for bus to become idle |
|
for(i=0; i<rxbd_num; i=i+1) begin |
buf_addr = `RX_BUF_BASE + i * 32'h600; |
bd_status_addr = `RX_BD_BASE + i * 8; |
bd_ptr_addr = bd_status_addr + 4; |
|
// Initializing BD - status |
if(i==rxbd_num-1) |
eth_host.wb_write(bd_status_addr, 4'hf, 32'h0000e000); // last BD: + WRAP |
// try normal write or read after write was finished |
#Tp cnt = 0; |
if (i3 == 0) // write after write |
begin |
phy_data = {8'h7A, (i[7:0] + 1)}; |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while(Mdio_IO !== 1'bz) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
@(posedge Mdc_O); |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read and check data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data , 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from PHY register - control register"); |
fail = fail + 1; |
end |
end |
else // read after write |
begin |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
@(posedge Mdc_O); |
check_mii_busy; // wait for read to finish |
// read and check data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data , 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from PHY register - control register"); |
fail = fail + 1; |
end |
end |
// check if transfer was a proper length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("New request did not proceed correctly, after write request"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("New request did not proceed correctly, after write request"); |
fail = fail + 1; |
end |
end |
end |
#Tp; |
// set delay of writing the command |
if (i2) // without preamble |
begin |
case(i) |
0, 1: i = i + 1; |
18, 19, 20, 21, 22, |
23, 24, 25, 26, 27, |
28, 29, 30, 31, 32, |
33, 34, 35: i = i + 1; |
36: i = 80; |
default: i = 18; |
endcase |
end |
else // with preamble |
begin |
case(i) |
0, 1: i = i + 1; |
50, 51, 52, 53, 54, |
55, 56, 57, 58, 59, |
60, 61, 62, 63, 64, |
65, 66, 67: i = i + 1; |
68: i = 80; |
default: i = 50; |
endcase |
end |
@(posedge wb_clk); |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 11) && (end_task >= 11)) |
begin |
// TEST BUSY AND NVALID STATUS DURATIONS DURING WRITE ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST BUSY AND NVALID STATUS DURATIONS DURING WRITE ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST BUSY AND NVALID STATUS DURATIONS DURING WRITE ( WITH AND WITHOUT PREAMBLE )"); |
|
reset_mii; // reset MII |
// set link up, if it wasn't due to previous tests, since there weren't PHY registers |
#Tp eth_phy.link_up_down(1); |
// set the MII |
clk_div = 64; |
mii_set_clk_div(clk_div[7:0]); |
// set address |
reg_addr = 5'h1; // status register |
phy_addr = 5'h1; // correct PHY address |
|
for (i = 0; i <= 1; i = i + 1) |
begin |
#Tp eth_phy.preamble_suppresed(i); |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i, 8'h0}) | (`ETH_MIIMODER_CLKDIV & clk_div), |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge Mdc_O); |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, 16'h5A5A); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to late, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z anymore - 1. read"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during write"); |
fail = fail + 1; |
end |
end |
else // Busy bit should already be set to '1', due to reads from MII status register |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set after write, due to reads from MII status register"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during write"); |
fail = fail + 1; |
end |
end |
|
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer bits |
if (i) |
begin |
repeat(32) @(posedge Mdc_O); |
end |
else |
eth_host.wb_write(bd_status_addr, 4'hf, 32'h0000c000); // IRQ + PAD + CRC |
begin |
repeat(64) @(posedge Mdc_O); |
end |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
eth_host.wb_write(bd_ptr_addr, 4'hf, buf_addr); // Initializing BD - pointer |
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO === 1'bz) // Mdio_IO should not be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to late, Mdio_IO is HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set while MII IO signal is not active anymore"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during write"); |
fail = fail + 1; |
end |
end |
else // Busy bit should still be set to '1' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set while MII IO signal not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during write"); |
fail = fail + 1; |
end |
end |
|
// wait for next negative clock edge |
@(negedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to early, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during write"); |
fail = fail + 1; |
end |
end |
else // Busy bit should still be set to '1' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set after MII IO signal become HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during write"); |
fail = fail + 1; |
end |
end |
|
// wait for Busy to become inactive |
i1 = 0; |
while (i1 <= 2) |
begin |
// wait for next positive clock edge |
@(posedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to early, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during write"); |
fail = fail + 1; |
end |
end |
else // wait for Busy bit to be set to '0' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
i1 = 3; // end of Busy checking |
end |
else |
begin |
if (i1 == 2) |
begin |
test_fail("Busy signal should be cleared after 2 periods after MII IO signal become HIGH Z"); |
fail = fail + 1; |
end |
#Tp i1 = i1 + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set after write"); |
fail = fail + 1; |
end |
end |
end |
end |
endtask // initialize_rxbd |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
task set_packet; |
input [15:0] len; |
input [7:0] start_data; |
if ((start_task <= 12) && (end_task >= 12)) |
begin |
// TEST BUSY AND NVALID STATUS DURATIONS DURING READ ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST BUSY AND NVALID STATUS DURATIONS DURING READ ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST BUSY AND NVALID STATUS DURATIONS DURING READ ( WITH AND WITHOUT PREAMBLE )"); |
|
integer i, sd; |
integer bd_status_addr, bd_ptr_addr, buffer, bd; |
reset_mii; // reset MII |
// set link up, if it wasn't due to previous tests, since there weren't PHY registers |
#Tp eth_phy.link_up_down(1); |
// set the MII |
clk_div = 64; |
mii_set_clk_div(clk_div[7:0]); |
// set address |
reg_addr = 5'h1; // status register |
phy_addr = 5'h1; // correct PHY address |
|
for (i = 0; i <= 1; i = i + 1) |
begin |
#Tp eth_phy.preamble_suppresed(i); |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i, 8'h0}) | (`ETH_MIIMODER_CLKDIV & clk_div), |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge Mdc_O); |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to late, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z anymore - 1. read"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during read"); |
fail = fail + 1; |
end |
end |
else // Busy bit should already be set to '1', due to reads from MII status register |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set after read, due to reads from MII status register"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during read"); |
fail = fail + 1; |
end |
end |
|
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer bits |
if (i) |
begin |
repeat(31) @(posedge Mdc_O); |
end |
else |
begin |
repeat(63) @(posedge Mdc_O); |
end |
// wait for next negative clock edge |
@(negedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO === 1'bz) // Mdio_IO should not be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to late, Mdio_IO is HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set while MII IO signal is not active anymore"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during read"); |
fail = fail + 1; |
end |
end |
else // Busy bit should still be set to '1' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set while MII IO signal not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during read"); |
fail = fail + 1; |
end |
end |
|
// wait for next positive clock edge |
@(posedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to early, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during read"); |
fail = fail + 1; |
end |
end |
else // Busy bit should still be set to '1' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set after MII IO signal become HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during read"); |
fail = fail + 1; |
end |
end |
|
// wait for Busy to become inactive |
i1 = 0; |
while (i1 <= 2) |
begin |
// wait for next positive clock edge |
@(posedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to early, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set during read"); |
fail = fail + 1; |
end |
end |
else // wait for Busy bit to be set to '0' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
i1 = 3; // end of Busy checking |
end |
else |
begin |
if (i1 == 2) |
begin |
test_fail("Busy signal should be cleared after 2 periods after MII IO signal become HIGH Z"); |
fail = fail + 1; |
end |
#Tp i1 = i1 + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] !== 1'b0) |
begin |
test_fail("Nvalid signal was set after read"); |
fail = fail + 1; |
end |
end |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 13) && (end_task >= 13)) |
begin |
// TEST BUSY AND NVALID STATUS DURATIONS DURING SCAN ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST BUSY AND NVALID STATUS DURATIONS DURING SCAN ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST BUSY AND NVALID STATUS DURATIONS DURING SCAN ( WITH AND WITHOUT PREAMBLE )"); |
|
reset_mii; // reset MII |
// set link up, if it wasn't due to previous tests, since there weren't PHY registers |
#Tp eth_phy.link_up_down(1); |
// set the MII |
clk_div = 64; |
mii_set_clk_div(clk_div[7:0]); |
// set address |
reg_addr = 5'h1; // status register |
phy_addr = 5'h1; // correct PHY address |
|
for (i = 0; i <= 1; i = i + 1) |
begin |
#Tp eth_phy.preamble_suppresed(i); |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i, 8'h0}) | (`ETH_MIIMODER_CLKDIV & clk_div), |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge Mdc_O); |
// scan request |
#Tp mii_scan_req(phy_addr, reg_addr); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to late, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z anymore - 1. read"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] === 1'b0) |
begin |
test_fail("Nvalid signal was not set while MII IO signal is not HIGH Z anymore - 1. read"); |
fail = fail + 1; |
end |
end |
else // Busy bit should already be set to '1', due to reads from MII status register |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set after scan, due to reads from MII status register"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] === 1'b0) |
begin |
test_fail("Nvalid signal should be set after scan, due to reads from MII status register"); |
fail = fail + 1; |
end |
end |
|
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer bits |
if (i) |
begin |
repeat(21) @(posedge Mdc_O); |
end |
else |
begin |
repeat(53) @(posedge Mdc_O); |
end |
// stop scan |
#Tp mii_scan_finish; // finish scan operation |
|
// wait for next positive clock edge |
repeat(10) @(posedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO === 1'bz) // Mdio_IO should not be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to late, Mdio_IO is HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set while MII IO signal is not active anymore"); |
fail = fail + 1; |
end |
// Nvalid signal can be cleared here - it is still Testbench error |
end |
else // Busy bit should still be set to '1', Nvalid bit should still be set to '1' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set while MII IO signal not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] === 1'b0) |
begin |
test_fail("Nvalid signal should be set while MII IO signal not HIGH Z"); |
fail = fail + 1; |
end |
end |
|
// wait for next negative clock edge |
@(negedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO === 1'bz) // Mdio_IO should not be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to late, Mdio_IO is HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set while MII IO signal is not active anymore"); |
fail = fail + 1; |
end |
// Nvalid signal can be cleared here - it is still Testbench error |
end |
else // Busy bit should still be set to '1', Nvalid bit should still be set to '1' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set while MII IO signal not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] === 1'b0) |
begin |
test_fail("Nvalid signal should be set while MII IO signal not HIGH Z"); |
fail = fail + 1; |
end |
end |
|
// wait for next negative clock edge |
@(posedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to early, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] === 1'b0) |
begin |
test_fail("Nvalid signal was not set while MII IO signal is not HIGH Z"); |
fail = fail + 1; |
end |
end |
else // Busy bit should still be set to '1', Nvalid bit can be set to '0' |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal should be set after MII IO signal become HIGH Z"); |
fail = fail + 1; |
end |
if (phy_data[`ETH_MIISTATUS_NVALID] === 1'b0) |
begin |
i2 = 1; // check finished |
end |
else |
begin |
i2 = 0; // check must continue |
end |
end |
|
// wait for Busy to become inactive |
i1 = 0; |
while ((i1 <= 2) || (i2 == 0)) |
begin |
// wait for next positive clock edge |
@(posedge Mdc_O); |
// read data from MII status register - Busy and Nvalid bits |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// check MII IO signal and Busy and Nvalid bits |
if (Mdio_IO !== 1'bz) // Mdio_IO should be HIGH Z here - testbench selfcheck |
begin |
test_fail("Testbench error - read was to early, Mdio_IO is not HIGH Z - set higher clock divider"); |
if (i1 <= 2) |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
test_fail("Busy signal was not set while MII IO signal is not HIGH Z"); |
fail = fail + 1; |
end |
end |
if (i2 == 0) |
begin |
if (phy_data[`ETH_MIISTATUS_NVALID] === 1'b0) |
begin |
test_fail("Nvalid signal was not set while MII IO signal is not HIGH Z"); |
fail = fail + 1; |
end |
end |
end |
else // wait for Busy bit to be set to '0' |
begin |
if (i1 <= 2) |
begin |
if (phy_data[`ETH_MIISTATUS_BUSY] === 1'b0) |
begin |
i1 = 3; // end of Busy checking |
end |
else |
begin |
if (i1 == 2) |
begin |
test_fail("Busy signal should be cleared after 2 periods after MII IO signal become HIGH Z"); |
fail = fail + 1; |
end |
#Tp i1 = i1 + 1; |
end |
end |
if (i2 == 0) |
begin |
if (phy_data[`ETH_MIISTATUS_NVALID] === 1'b0) |
begin |
i2 = 1; |
end |
else |
begin |
test_fail("Nvalid signal should be cleared after MII IO signal become HIGH Z"); |
fail = fail + 1; |
end |
end |
end |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 14) && (end_task >= 14)) |
begin |
// TEST SCAN STATUS FROM PHY WITH DETECTING LINK-FAIL BIT ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST SCAN STATUS FROM PHY WITH DETECTING LINK-FAIL BIT ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST SCAN STATUS FROM PHY WITH DETECTING LINK-FAIL BIT ( WITH AND WITHOUT PREAMBLE )"); |
|
reset_mii; // reset MII |
// set link up, if it wasn't due to previous tests, since there weren't PHY registers |
#Tp eth_phy.link_up_down(1); |
// set MII speed |
clk_div = 6; |
mii_set_clk_div(clk_div[7:0]); |
// set address |
reg_addr = 5'h1; // status register |
phy_addr = 5'h1; // correct PHY address |
|
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data from PHY status register - remember LINK-UP status |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
for (i = 0; i <= 1; i = i + 1) |
begin |
#Tp eth_phy.preamble_suppresed(i); |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i, 8'h0}) | (`ETH_MIIMODER_CLKDIV & clk_div), |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (i) |
begin |
// change saved data when preamble is suppressed |
#Tp tmp_data = tmp_data | 16'h0040; // put bit 6 to ONE |
end |
|
// scan request |
#Tp mii_scan_req(phy_addr, reg_addr); |
check_mii_scan_valid; // wait for scan to make first data valid |
|
fork |
begin |
repeat(2) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] !== 1'b0) |
begin |
test_fail("Link FAIL bit was set in the MII status register"); |
fail = fail + 1; |
end |
end |
begin |
// Completely check second scan |
#Tp cnt = 0; |
// wait for serial bus to become active - second scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i == 0)) || ((cnt == 15) && (i == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Second scan request did not proceed correctly"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Second scan request did not proceed correctly"); |
fail = fail + 1; |
end |
end |
end |
join |
// check third to fifth scans |
for (i3 = 0; i3 <= 2; i3 = i3 + 1) |
begin |
fork |
begin |
repeat(2) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] !== 1'b0) |
begin |
test_fail("Link FAIL bit was set in the MII status register"); |
fail = fail + 1; |
end |
if (i3 == 2) // after fourth scan read |
begin |
@(posedge Mdc_O); |
// change saved data |
#Tp tmp_data = tmp_data & 16'hFFFB; // put bit 3 to ZERO |
// set link down |
#Tp eth_phy.link_up_down(0); |
end |
end |
begin |
// Completely check scans |
#Tp cnt = 0; |
// wait for serial bus to become active - second scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i == 0)) || ((cnt == 15) && (i == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Fifth scan request did not proceed correctly"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Fifth scan request did not proceed correctly"); |
fail = fail + 1; |
end |
end |
end |
join |
end |
|
fork |
begin |
repeat(2) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] === 1'b0) |
begin |
test_fail("Link FAIL bit was not set in the MII status register"); |
fail = fail + 1; |
end |
// wait to see if data stayed latched |
repeat(4) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not latched correctly in status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] === 1'b0) |
begin |
test_fail("Link FAIL bit was not set in the MII status register"); |
fail = fail + 1; |
end |
// change saved data |
#Tp tmp_data = tmp_data | 16'h0004; // put bit 2 to ONE |
// set link up |
#Tp eth_phy.link_up_down(1); |
end |
begin |
// Wait for sixth scan |
// wait for serial bus to become active - sixth scan |
wait(Mdio_IO !== 1'bz); |
// wait for serial bus to become inactive - turn-around cycle in sixth scan |
wait(Mdio_IO === 1'bz); |
// wait for serial bus to become active - end of turn-around cycle in sixth scan |
wait(Mdio_IO !== 1'bz); |
// wait for serial bus to become inactive - end of sixth scan |
wait(Mdio_IO === 1'bz); |
end |
join |
|
@(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] !== 1'b0) |
begin |
test_fail("Link FAIL bit was set in the MII status register"); |
fail = fail + 1; |
end |
// wait to see if data stayed latched |
repeat(4) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] !== 1'b0) |
begin |
test_fail("Link FAIL bit was set in the MII status register"); |
fail = fail + 1; |
end |
|
// STOP SCAN |
#Tp mii_scan_finish; // finish scan operation |
#Tp check_mii_busy; // wait for scan to finish |
end |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 15) && (end_task >= 15)) |
begin |
// TEST SCAN STATUS FROM PHY WITH SLIDING LINK-FAIL BIT ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST SCAN STATUS FROM PHY WITH SLIDING LINK-FAIL BIT ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST SCAN STATUS FROM PHY WITH SLIDING LINK-FAIL BIT ( WITH AND WITHOUT PREAMBLE )"); |
|
// set address |
reg_addr = 5'h1; // status register |
phy_addr = 5'h1; // correct PHY address |
|
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read data from PHY status register - remember LINK-UP status |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
for (i2 = 0; i2 <= 1; i2 = i2 + 1) // choose preamble or not |
begin |
#Tp eth_phy.preamble_suppresed(i2); |
// MII mode register |
#Tp wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i2, 8'h0}), 4'hF, 1, wbm_init_waits, |
wbm_subseq_waits); |
if (i2) |
begin |
// change saved data when preamble is suppressed |
#Tp tmp_data = tmp_data | 16'h0040; // put bit 6 to ONE |
end |
|
i = 0; |
while (i < 80) // delay for sliding of LinkFail bit |
begin |
// first there are two scans |
#Tp cnt = 0; |
// scan request |
#Tp mii_scan_req(phy_addr, reg_addr); |
#Tp check_mii_scan_valid; // wait for scan to make first data valid |
|
// check second scan |
fork |
begin |
repeat(4) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Second data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] !== 1'b0) |
begin |
test_fail("Link FAIL bit was set in the MII status register"); |
fail = fail + 1; |
end |
end |
begin |
// Completely check scan |
#Tp cnt = 0; |
// wait for serial bus to become active - second scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Second scan request did not proceed correctly"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Second scan request did not proceed correctly"); |
fail = fail + 1; |
end |
end |
end |
join |
// reset counter |
#Tp cnt = 0; |
// SLIDING LINK DOWN and CHECK |
fork |
begin |
// set link down |
repeat(i) @(posedge Mdc_O); |
// set link down |
#Tp eth_phy.link_up_down(0); |
end |
begin |
// check data in MII registers after each scan in this fork statement |
if (i2) // without preamble |
wait (cnt == 32); |
else // with preamble |
wait (cnt == 64); |
repeat(3) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if ( ((i < 49) && !i2) || ((i < 17) && i2) ) |
begin |
if (phy_data !== (tmp_data & 16'hFFFB)) // bit 3 is ZERO |
begin |
test_fail("Third data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
end |
else |
begin |
if (phy_data !== tmp_data) |
begin |
test_fail("Third data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if ( ((i < 49) && !i2) || ((i < 17) && i2) ) |
begin |
if (phy_data[0] === 1'b0) |
begin |
test_fail("Link FAIL bit was not set in the MII status register"); |
fail = fail + 1; |
end |
end |
else |
begin |
if (phy_data[0] !== 1'b0) |
begin |
test_fail("Link FAIL bit was set in the MII status register"); |
fail = fail + 1; |
end |
end |
end |
begin |
// check length |
for (i3 = 0; i3 <= 1; i3 = i3 + 1) // two scans |
begin |
#Tp cnt = 0; |
// wait for serial bus to become active if there is more than one scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("3. or 4. scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("3. or 4. scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
end |
end |
join |
// reset counter |
#Tp cnt = 0; |
// check fifth scan and data from fourth scan |
fork |
begin |
repeat(2) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== (tmp_data & 16'hFFFB)) // bit 3 is ZERO |
begin |
test_fail("4. data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] === 1'b0) |
begin |
test_fail("Link FAIL bit was not set in the MII status register"); |
fail = fail + 1; |
end |
end |
begin |
// Completely check intermediate scan |
#Tp cnt = 0; |
// wait for serial bus to become active - second scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Fifth scan request did not proceed correctly"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Fifth scan request did not proceed correctly"); |
fail = fail + 1; |
end |
end |
end |
join |
// reset counter |
#Tp cnt = 0; |
// SLIDING LINK UP and CHECK |
fork |
begin |
// set link up |
repeat(i) @(posedge Mdc_O); |
// set link up |
#Tp eth_phy.link_up_down(1); |
end |
begin |
// check data in MII registers after each scan in this fork statement |
repeat(2) @(posedge Mdc_O); |
if (i2) // without preamble |
wait (cnt == 32); |
else // with preamble |
wait (cnt == 64); |
repeat(3) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if ( ((i < 49) && !i2) || ((i < 17) && i2) ) |
begin |
if (phy_data !== tmp_data) |
begin |
test_fail("6. data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
end |
else |
begin |
if (phy_data !== (tmp_data & 16'hFFFB)) // bit 3 is ZERO |
begin |
test_fail("6. data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if ( ((i < 49) && !i2) || ((i < 17) && i2) ) |
begin |
if (phy_data[0] !== 1'b0) |
begin |
test_fail("Link FAIL bit was set in the MII status register"); |
fail = fail + 1; |
end |
end |
else |
begin |
if (phy_data[0] === 1'b0) |
begin |
test_fail("Link FAIL bit was not set in the MII status register"); |
fail = fail + 1; |
end |
end |
end |
begin |
// check length |
for (i3 = 0; i3 <= 1; i3 = i3 + 1) // two scans |
begin |
#Tp cnt = 0; |
// wait for serial bus to become active if there is more than one scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("Scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
end |
end |
join |
// check last scan |
repeat(4) @(posedge Mdc_O); |
// read data from PHY status register |
#Tp wbm_read(`ETH_MIIRX_DATA, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("7. data was not correctly scaned from status register"); |
fail = fail + 1; |
end |
// read data from MII status register |
#Tp wbm_read(`ETH_MIISTATUS, phy_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data[0] !== 1'b0) |
begin |
test_fail("Link FAIL bit was set in the MII status register"); |
fail = fail + 1; |
end |
|
#Tp mii_scan_finish; // finish scan operation |
#Tp check_mii_busy; // wait for scan to finish |
#Tp; |
// set delay of writing the command |
if (i2) // without preamble |
begin |
case(i) |
0, 1, 2, 3, 4: i = i + 1; |
13, 14, 15, 16, 17, |
18, 19, 20, 21, 22, |
23, 24, 25, 26, 27, |
28, 29, 30, 31, 32, |
33, 34, 35: i = i + 1; |
36: i = 80; |
default: i = 13; |
endcase |
end |
else // with preamble |
begin |
case(i) |
0, 1, 2, 3, 4: i = i + 1; |
45, 46, 47, 48, 49, |
50, 51, 52, 53, 54, |
55, 56, 57, 58, 59, |
60, 61, 62, 63, 64, |
65, 66, 67: i = i + 1; |
68: i = 80; |
default: i = 45; |
endcase |
end |
@(posedge wb_clk); |
#Tp; |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 16) && (end_task >= 16)) |
begin |
// TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER SCAN REQUEST ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER SCAN REQUEST ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; |
$display(" TEST SLIDING STOP SCAN COMMAND IMMEDIATELY AFTER SCAN REQUEST ( WITH AND WITHOUT PREAMBLE )"); |
|
for (i2 = 0; i2 <= 1; i2 = i2 + 1) // choose preamble or not |
begin |
#Tp eth_phy.preamble_suppresed(i2); |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i2, 8'h0}), 4'hF, 1, wbm_init_waits, |
wbm_subseq_waits); |
i = 0; |
cnt = 0; |
while (i < 80) // delay for sliding of writing a STOP SCAN command |
begin |
for (i3 = 0; i3 <= 1; i3 = i3 + 1) // choose read or write after scan will be finished |
begin |
// set address |
reg_addr = 5'h0; // control register |
phy_addr = 5'h1; // correct PHY address |
cnt = 0; |
// scan request |
#Tp mii_scan_req(phy_addr, reg_addr); |
fork |
begin |
repeat(i) @(posedge Mdc_O); |
// write command 0x0 into MII command register |
// MII command written while scan in progress |
wbm_write(`ETH_MIICOMMAND, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge wb_clk); |
#Tp check_mii_busy; // wait for scan to finish |
@(posedge wb_clk); |
disable check; |
end |
begin: check |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
cnt = 0; |
// wait for serial bus to become active if there is more than one scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
end |
join |
// check the BUSY signal to see if the bus is still IDLE |
for (i1 = 0; i1 < 8; i1 = i1 + 1) |
check_mii_busy; // wait for bus to become idle |
|
// try normal write or read after scan was finished |
phy_data = {8'h7D, (i[7:0] + 1)}; |
cnt = 0; |
if (i3 == 0) // write after scan |
begin |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while(Mdio_IO !== 1'bz) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
@(posedge Mdc_O); |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read and check data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from PHY register - control register"); |
fail = fail + 1; |
end |
end |
else // read after scan |
begin |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
@(posedge Mdc_O); |
check_mii_busy; // wait for read to finish |
// read and check data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from PHY register - control register"); |
fail = fail + 1; |
end |
end |
// check if transfer was a proper length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("New request did not proceed correctly, after scan request"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("New request did not proceed correctly, after scan request"); |
fail = fail + 1; |
end |
end |
end |
#Tp; |
// set delay of writing the command |
if (i2) // without preamble |
begin |
case(i) |
0, 1: i = i + 1; |
18, 19, 20, 21, 22, |
23, 24, 25, 26, 27, |
28, 29, 30, 31, 32, |
33, 34, 35: i = i + 1; |
36: i = 80; |
default: i = 18; |
endcase |
end |
else // with preamble |
begin |
case(i) |
0, 1: i = i + 1; |
50, 51, 52, 53, 54, |
55, 56, 57, 58, 59, |
60, 61, 62, 63, 64, |
65, 66, 67: i = i + 1; |
68: i = 80; |
default: i = 50; |
endcase |
end |
@(posedge wb_clk); |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 17) && (end_task >= 17)) |
begin |
// TEST SLIDING STOP SCAN COMMAND AFTER 2. SCAN ( WITH AND WITHOUT PREAMBLE ) |
test_name = "TEST SLIDING STOP SCAN COMMAND AFTER 2. SCAN ( WITH AND WITHOUT PREAMBLE )"; |
`TIME; $display(" TEST SLIDING STOP SCAN COMMAND AFTER 2. SCAN ( WITH AND WITHOUT PREAMBLE )"); |
|
for (i2 = 0; i2 <= 1; i2 = i2 + 1) // choose preamble or not |
begin |
sd = start_data; |
bd_status_addr = `TX_BD_BASE + packet_ready_cnt * 8; |
bd_ptr_addr = bd_status_addr + 4; |
|
// Reading BD + buffer pointer |
eth_host.wb_read(bd_status_addr, 4'hf, bd); |
eth_host.wb_read(bd_ptr_addr, 4'hf, buffer); |
#Tp eth_phy.preamble_suppresed(i2); |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_NOPRE & {23'h0, i2, 8'h0}), 4'hF, 1, wbm_init_waits, |
wbm_subseq_waits); |
|
while(bd & `ETH_TX_BD_READY) begin // Buffer is ready. Don't touch !!! |
repeat(100) @(posedge wb_clk_o); |
i=i+1; |
eth_host.wb_read(bd_status_addr, 4'hf, bd); |
if(i>1000) begin |
$display("(%0t)(%m)Waiting for TxBD ready to clear timeout", $time); |
$stop; |
i = 0; |
cnt = 0; |
while (i < 80) // delay for sliding of writing a STOP SCAN command |
begin |
for (i3 = 0; i3 <= 1; i3 = i3 + 1) // choose read or write after scan will be finished |
begin |
// first there are two scans |
// set address |
reg_addr = 5'h0; // control register |
phy_addr = 5'h1; // correct PHY address |
cnt = 0; |
// scan request |
#Tp mii_scan_req(phy_addr, reg_addr); |
// wait and check first 2 scans |
begin |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
cnt = 0; |
// wait for serial bus to become active if there is more than one scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
end |
|
// reset counter |
cnt = 0; |
fork |
begin |
repeat(i) @(posedge Mdc_O); |
// write command 0x0 into MII command register |
// MII command written while scan in progress |
wbm_write(`ETH_MIICOMMAND, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge wb_clk); |
#Tp check_mii_busy; // wait for scan to finish |
@(posedge wb_clk); |
disable check_3; |
end |
begin: check_3 |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
cnt = 0; |
// wait for serial bus to become active if there is more than one scan |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
// check transfer length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("First scan request did not proceed correctly, while SCAN STOP was written"); |
fail = fail + 1; |
end |
end |
end |
join |
// check the BUSY signal to see if the bus is still IDLE |
for (i1 = 0; i1 < 8; i1 = i1 + 1) |
check_mii_busy; // wait for bus to become idle |
|
// try normal write or read after scan was finished |
phy_data = {8'h7D, (i[7:0] + 1)}; |
cnt = 0; |
if (i3 == 0) // write after scan |
begin |
// write request |
#Tp mii_write_req(phy_addr, reg_addr, phy_data); |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while(Mdio_IO !== 1'bz) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
@(posedge Mdc_O); |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
check_mii_busy; // wait for read to finish |
// read and check data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from PHY register - control register"); |
fail = fail + 1; |
end |
end |
else // read after scan |
begin |
// read request |
#Tp mii_read_req(phy_addr, reg_addr); |
// wait for serial bus to become active |
wait(Mdio_IO !== 1'bz); |
// count transfer length |
while( (Mdio_IO !== 1'bz) || ((cnt == 47) && (i2 == 0)) || ((cnt == 15) && (i2 == 1)) ) |
begin |
@(posedge Mdc_O); |
#Tp cnt = cnt + 1; |
end |
@(posedge Mdc_O); |
check_mii_busy; // wait for read to finish |
// read and check data |
#Tp wbm_read(`ETH_MIIRX_DATA, tmp_data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (phy_data !== tmp_data) |
begin |
test_fail("Data was not correctly written into OR read from PHY register - control register"); |
fail = fail + 1; |
end |
end |
// check if transfer was a proper length |
if (i2) // without preamble |
begin |
if (cnt != 33) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("New request did not proceed correctly, after scan request"); |
fail = fail + 1; |
end |
end |
else // with preamble |
begin |
if (cnt != 65) // at this value Mdio_IO is HIGH Z |
begin |
test_fail("New request did not proceed correctly, after scan request"); |
fail = fail + 1; |
end |
end |
end |
#Tp; |
// set delay of writing the command |
if (i2) // without preamble |
begin |
case(i) |
0, 1: i = i + 1; |
18, 19, 20, 21, 22, |
23, 24, 25, 26, 27, |
28, 29, 30, 31, 32, |
33, 34, 35: i = i + 1; |
36: i = 80; |
default: i = 18; |
endcase |
end |
else // with preamble |
begin |
case(i) |
0, 1: i = i + 1; |
50, 51, 52, 53, 54, |
55, 56, 57, 58, 59, |
60, 61, 62, 63, 64, |
65, 66, 67: i = i + 1; |
68: i = 80; |
default: i = 50; |
endcase |
end |
@(posedge wb_clk); |
end |
end |
// set PHY to normal mode |
#Tp eth_phy.preamble_suppresed(0); |
// MII mode register |
wbm_write(`ETH_MIIMODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
// First write might not be word allign. |
if(buffer[1:0]==1) begin |
eth_host.wb_write(buffer-1, 4'h7, {8'h0, sd[7:0], sd[7:0]+3'h1, sd[7:0]+3'h2}); |
sd=sd+3; |
i=3; |
end |
endtask // test_mii |
|
|
task test_mac_full_duplex_transmit; |
input [31:0] start_task; |
input [31:0] end_task; |
integer bit_start_1; |
integer bit_end_1; |
integer bit_start_2; |
integer bit_end_2; |
integer num_of_reg; |
integer i_addr; |
integer i_data; |
integer i_length; |
integer tmp_data; |
reg [31:0] tx_bd_num; |
reg [((`MAX_BLK_SIZE * 32) - 1):0] burst_data; |
reg [((`MAX_BLK_SIZE * 32) - 1):0] burst_tmp_data; |
integer i; |
integer i1; |
integer i2; |
integer i3; |
integer fail; |
integer speed; |
reg [31:0] addr; |
reg [31:0] data; |
reg [31:0] tmp; |
reg [ 7:0] st_data; |
reg [15:0] max_tmp; |
reg [15:0] min_tmp; |
begin |
// MAC FULL DUPLEX TRANSMIT TEST |
test_heading("MAC FULL DUPLEX TRANSMIT TEST"); |
$display(" "); |
$display("MAC FULL DUPLEX TRANSMIT TEST"); |
fail = 0; |
|
// reset MAC registers |
hard_reset; |
// reset MAC and MII LOGIC with soft reset |
reset_mac; |
reset_mii; |
// set wb slave response |
wb_slave.cycle_response(`ACK_RESPONSE, wbs_waits, wbs_retries); |
|
/* |
TASKS for set and control TX buffer descriptors (also send packet - set_tx_bd_ready): |
------------------------------------------------------------------------------------- |
set_tx_bd |
(tx_bd_num_start[6:0], tx_bd_num_end[6:0], len[15:0], irq, pad, crc, txpnt[31:0]); |
set_tx_bd_wrap |
(tx_bd_num_end[6:0]); |
set_tx_bd_ready |
(tx_bd_num_start[6:0], tx_bd_num_end[6:0]); |
check_tx_bd |
(tx_bd_num_start[6:0], tx_bd_status[31:0]); |
clear_tx_bd |
(tx_bd_num_start[6:0], tx_bd_num_end[6:0]); |
|
TASKS for set and control RX buffer descriptors: |
------------------------------------------------ |
set_rx_bd |
(rx_bd_num_strat[6:0], rx_bd_num_end[6:0], irq, rxpnt[31:0]); |
set_rx_bd_wrap |
(rx_bd_num_end[6:0]); |
set_rx_bd_empty |
(rx_bd_num_strat[6:0], rx_bd_num_end[6:0]); |
check_rx_bd |
(rx_bd_num_end[6:0], rx_bd_status); |
clear_rx_bd |
(rx_bd_num_strat[6:0], rx_bd_num_end[6:0]); |
|
TASKS for set and check TX packets: |
----------------------------------- |
set_tx_packet |
(txpnt[31:0], len[15:0], eth_start_data[7:0]); |
check_tx_packet |
(txpnt_wb[31:0], txpnt_phy[31:0], len[15:0], failure[31:0]); |
|
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]); |
|
TASKS for append and check CRC to/of TX packet: |
----------------------------------------------- |
append_tx_crc |
(txpnt_wb[31:0], len[15:0], negated_crc); |
check_tx_crc |
(txpnt_phy[31:0], len[15:0], negated_crc, failure[31:0]); |
|
TASK for append CRC to RX packet (CRC is checked together with check_rx_packet): |
-------------------------------------------------------------------------------- |
append_rx_crc |
(rxpnt_phy[31:0], len[15:0], plus_nibble, negated_crc); |
*/ |
|
|
if ((start_task <= 0) && (end_task >= 0)) |
begin |
// TEST NO TRANSMIT WHEN ALL BUFFERS ARE RX ( 10Mbps ) |
test_name = "TEST NO TRANSMIT WHEN ALL BUFFERS ARE RX ( 10Mbps )"; |
`TIME; $display(" TEST NO TRANSMIT WHEN ALL BUFFERS ARE RX ( 10Mbps )"); |
|
// unmask interrupts |
wbm_write(`ETH_INT_MASK, `ETH_INT_TXB | `ETH_INT_TXE | `ETH_INT_RXF | `ETH_INT_RXE | `ETH_INT_BUSY | |
`ETH_INT_TXC | `ETH_INT_RXC, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set all buffer descriptors to RX - must be set before TX enable |
wbm_write(`ETH_TX_BD_NUM, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// enable TX, set full-duplex mode, padding and CRC appending |
wbm_write(`ETH_MODER, `ETH_MODER_TXEN | `ETH_MODER_FULLD | `ETH_MODER_PAD | `ETH_MODER_CRCEN, |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// write to phy's control register for 10Mbps |
#Tp eth_phy.control_bit14_10 = 5'b00000; // bit 13 reset - speed 10 |
#Tp eth_phy.control_bit8_0 = 9'h1_00; // bit 6 reset - (10/100), bit 8 set - FD |
speed = 10; |
|
i = 0; |
while (i < 128) |
begin |
for (i1 = 0; i1 <= i; i1 = i1 + 1) |
begin |
set_tx_packet((`MEMORY_BASE + (i1 * 200)), 100, 0); |
set_tx_bd(i1, i1, 100, 1'b1, 1'b1, 1'b1, (`MEMORY_BASE + (i1 * 200))); |
end |
else if(buffer[1:0]==2) begin |
eth_host.wb_write(buffer-2, 4'h3, {16'h0, sd[7:0], sd[7:0]+3'h1}); |
sd=sd+2; |
i=2; |
end |
else if(buffer[1:0]==3) begin |
eth_host.wb_write(buffer-3, 4'h1, {24'h0, sd[7:0]}); |
sd=sd+1; |
i=1; |
set_tx_bd_wrap(i); |
fork |
begin |
set_tx_bd_ready(0, i); |
repeat(20) @(negedge mtx_clk); |
#1 disable check_tx_en10; |
end |
begin: check_tx_en10 |
wait (MTxEn === 1'b1); |
test_fail("Tramsmit should not start at all"); |
fail = fail + 1; |
`TIME; $display("*E Transmit of %d packets should not start at all - active MTxEn", i); |
end |
join |
for (i2 = 0; i2 < 20; i2 = i2 + 1) |
begin |
check_tx_bd(0, tmp); |
#1; |
if (tmp[15] === 1'b0) |
begin |
test_fail("Tramsmit should not start at all"); |
fail = fail + 1; |
`TIME; $display("*E Transmit of %d packets should not start at all - ready is 0", i); |
end |
if (tmp[8:0] !== 0) |
begin |
test_fail("Tramsmit should not be finished since it should not start at all"); |
fail = fail + 1; |
`TIME; $display("*E Transmit of should not be finished since it should not start at all"); |
end |
@(posedge wb_clk); |
end |
wbm_read(`ETH_INT, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp[6:0] !== 0) |
begin |
test_fail("Tramsmit should not get INT since it should not start at all"); |
fail = fail + 1; |
`TIME; $display("*E Transmit of should not get INT since it should not start at all"); |
end |
clear_tx_bd(0, i); |
if ((i < 5) || (i > 124)) |
i = i + 1; |
else |
i=0; |
i = i + 120; |
end |
// disable TX |
wbm_write(`ETH_MODER, `ETH_MODER_FULLD | `ETH_MODER_PAD | `ETH_MODER_CRCEN, |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
for(i=i; i<len-4; i=i+4) begin // Last 0-3 bytes are not written |
eth_host.wb_write(buffer+i, 4'hf, {sd[7:0], sd[7:0]+3'h1, sd[7:0]+3'h2, sd[7:0]+3'h3}); |
sd=sd+4; |
if ((start_task <= 1) && (end_task >= 1)) |
begin |
// TEST NO TRANSMIT WHEN ALL BUFFERS ARE RX ( 100Mbps ) |
test_name = "TEST NO TRANSMIT WHEN ALL BUFFERS ARE RX ( 100Mbps )"; |
`TIME; $display(" TEST NO TRANSMIT WHEN ALL BUFFERS ARE RX ( 100Mbps )"); |
|
// unmask interrupts |
wbm_write(`ETH_INT_MASK, `ETH_INT_TXB | `ETH_INT_TXE | `ETH_INT_RXF | `ETH_INT_RXE | `ETH_INT_BUSY | |
`ETH_INT_TXC | `ETH_INT_RXC, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set all buffer descriptors to RX - must be set before TX enable |
wbm_write(`ETH_TX_BD_NUM, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// enable TX, set full-duplex mode, padding and CRC appending |
wbm_write(`ETH_MODER, `ETH_MODER_TXEN | `ETH_MODER_FULLD | `ETH_MODER_PAD | `ETH_MODER_CRCEN, |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// write to phy's control register for 100Mbps |
#Tp eth_phy.control_bit14_10 = 5'b01000; // bit 13 set - speed 100 |
#Tp eth_phy.control_bit8_0 = 9'h1_00; // bit 6 reset - (10/100), bit 8 set - FD |
speed = 100; |
|
i = 0; |
while (i < 128) |
begin |
for (i1 = 0; i1 <= i; i1 = i1 + 1) |
begin |
set_tx_packet((`MEMORY_BASE + (i1 * 200)), 100, 0); |
set_tx_bd(i1, i1, 100, 1'b1, 1'b1, 1'b1, (`MEMORY_BASE + (i1 * 200))); |
end |
set_tx_bd_wrap(i); |
fork |
begin |
set_tx_bd_ready(0, i); |
repeat(20) @(negedge mtx_clk); |
#1 disable check_tx_en100; |
end |
begin: check_tx_en100 |
wait (MTxEn === 1'b1); |
test_fail("Tramsmit should not start at all"); |
fail = fail + 1; |
`TIME; $display("*E Transmit of %d packets should not start at all - active MTxEn", i); |
end |
join |
for (i2 = 0; i2 < 20; i2 = i2 + 1) |
begin |
check_tx_bd(0, tmp); |
#1; |
if (tmp[15] === 1'b0) |
begin |
test_fail("Tramsmit should not start at all"); |
fail = fail + 1; |
`TIME; $display("*E Transmit of %d packets should not start at all - ready is 0", i); |
end |
if (tmp[8:0] !== 0) |
begin |
test_fail("Tramsmit should not be finished since it should not start at all"); |
fail = fail + 1; |
`TIME; $display("*E Transmit of should not be finished since it should not start at all"); |
end |
@(posedge wb_clk); |
end |
wbm_read(`ETH_INT, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if (tmp[6:0] !== 0) |
begin |
test_fail("Tramsmit should not get INT since it should not start at all"); |
fail = fail + 1; |
`TIME; $display("*E Transmit of should not get INT since it should not start at all"); |
end |
clear_tx_bd(0, i); |
if ((i < 5) || (i > 124)) |
i = i + 1; |
else |
i = i + 120; |
end |
// disable TX |
wbm_write(`ETH_MODER, `ETH_MODER_FULLD | `ETH_MODER_PAD | `ETH_MODER_CRCEN, |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
if ((start_task <= 2) && (end_task >= 2)) |
begin |
// TEST TRANSMIT PACKETS FROM MINFL TO MAXFL SIZES AT ONE TX BD ( 10Mbps ) |
test_name = "TEST TRANSMIT PACKETS FROM MINFL TO MAXFL SIZES AT ONE TX BD ( 10Mbps )"; |
`TIME; $display(" TEST TRANSMIT PACKETS FROM MINFL TO MAXFL SIZES AT ONE TX BD ( 10Mbps )"); |
|
max_tmp = 0; |
min_tmp = 0; |
// unmask interrupts |
wbm_write(`ETH_INT_MASK, `ETH_INT_TXB | `ETH_INT_TXE | `ETH_INT_RXF | `ETH_INT_RXE | `ETH_INT_BUSY | |
`ETH_INT_TXC | `ETH_INT_RXC, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set one TX buffer descriptor - must be set before TX enable |
wbm_write(`ETH_TX_BD_NUM, 32'h1, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// enable TX, set full-duplex mode, padding and CRC appending |
wbm_write(`ETH_MODER, `ETH_MODER_TXEN | `ETH_MODER_FULLD | `ETH_MODER_PAD | `ETH_MODER_CRCEN, |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// prepare two packets of MAXFL length |
wbm_read(`ETH_PACKETLEN, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
max_tmp = tmp[15:0]; // 18 bytes consists of 6B dest addr, 6B source addr, 2B type/len, 4B CRC |
min_tmp = tmp[31:16]; |
st_data = 8'h5A; |
set_tx_packet(`MEMORY_BASE, (max_tmp - 4), st_data); // length without CRC |
st_data = 8'h10; |
set_tx_packet((`MEMORY_BASE + max_tmp), (max_tmp - 4), st_data); // length without CRC |
// check WB INT signal |
if (wb_int !== 1'b0) |
begin |
test_fail("WB INT signal should not be set"); |
fail = fail + 1; |
end |
|
// write to phy's control register for 10Mbps |
#Tp eth_phy.control_bit14_10 = 5'b00000; // bit 13 reset - speed 10 |
#Tp eth_phy.control_bit8_0 = 9'h1_00; // bit 6 reset - (10/100), bit 8 set - FD |
speed = 10; |
|
for (i_length = (min_tmp - 4); i_length <= (max_tmp - 4); i_length = i_length + 1) |
begin |
// choose generating carrier sense and collision |
case (i_length[1:0]) |
2'h0: |
begin |
|
end |
2'h1: |
begin |
|
end |
2'h2: |
begin |
|
end |
default: // 2'h3: |
begin |
|
end |
endcase |
// choose WB memory destination address regarding the speed |
if (i_length[0] == 0) |
set_tx_bd(0, 0, i_length, 1'b1, 1'b1, 1'b1, `MEMORY_BASE); |
else |
set_tx_bd(0, 0, i_length, 1'b1, 1'b1, 1'b1, (`MEMORY_BASE + max_tmp)); |
eth_phy.set_tx_mem_addr(max_tmp); |
// set wrap bit |
set_tx_bd_wrap(0); |
set_tx_bd_ready(0, 0); |
#1 check_tx_bd(0, data); |
if (i_length < min_tmp) // just first four |
begin |
while (data[15] === 1) |
begin |
#1 check_tx_bd(0, data); |
@(posedge wb_clk); |
end |
end |
else if (i_length > (max_tmp - 8)) // just last four |
begin |
tmp = 0; |
wait (MTxEn === 1'b1); // start transmit |
while (tmp < (i_length - 20)) |
begin |
#1 tmp = tmp + 1; |
@(posedge wb_clk); |
end |
#1 check_tx_bd(0, data); |
while (data[15] === 1) |
begin |
#1 check_tx_bd(0, data); |
@(posedge wb_clk); |
end |
end |
else |
begin |
wait (MTxEn === 1'b1); // start transmit |
wait (MTxEn === 1'b0); // end transmit |
repeat (2) @(posedge mtx_clk); |
repeat (3) @(posedge wb_clk); |
end |
// check length of a PACKET |
if (eth_phy.tx_len != (i_length + 4)) |
begin |
test_fail("Wrong length of the packet out from MAC"); |
fail = fail + 1; |
end |
// check transmitted TX packet data |
if (i_length[0] == 0) |
begin |
check_tx_packet(`MEMORY_BASE, max_tmp, i_length, tmp); |
end |
else |
begin |
check_tx_packet((`MEMORY_BASE + max_tmp), max_tmp, i_length, tmp); |
end |
if (tmp > 0) |
begin |
test_fail("Wrong data of the transmitted packet"); |
fail = fail + 1; |
end |
// check WB INT signal |
if (wb_int !== 1'b1) |
begin |
test_fail("WB INT signal should not be set"); |
fail = fail + 1; |
end |
// check transmited TX packet CRC |
check_tx_crc(max_tmp, i_length, 1'b0, tmp); // length without CRC |
if (tmp > 0) |
begin |
test_fail("Wrong CRC of the transmitted packet"); |
fail = fail + 1; |
end |
// check TX buffer descriptor of a packet |
check_tx_bd(0, data); |
|
|
// clear TX buffer descriptor |
clear_tx_bd(0, 0); |
// check interrupts |
wbm_read(`ETH_INT, data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if ((data & `ETH_INT_TXB) !== 1'b1) |
begin |
`TIME; |
test_fail("Interrupt Transmit Buffer was not set"); |
fail = fail + 1; |
end |
if ((data & (~`ETH_INT_TXB)) !== 0) |
begin |
`TIME; |
test_fail("Other interrupts (except Transmit Buffer) were set"); |
fail = fail + 1; |
end |
// clear interrupts |
wbm_write(`ETH_INT, data, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// check WB INT signal |
if (wb_int !== 1'b0) |
begin |
test_fail("WB INT signal should not be set"); |
fail = fail + 1; |
end |
|
end |
// disable TX |
wbm_write(`ETH_MODER, `ETH_MODER_FULLD | `ETH_MODER_PAD | `ETH_MODER_CRCEN, |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
if(fail == 0) |
test_ok; |
else |
fail = 0; |
end |
|
|
/* |
wbm_write(`ETH_MODER, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
wbm_read(`ETH_MODER, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
// Last word |
if(len-i==3) |
eth_host.wb_write(buffer+i, 4'he, {sd[7:0], sd[7:0]+3'h1, sd[7:0]+3'h2, 8'h0}); |
else if(len-i==2) |
eth_host.wb_write(buffer+i, 4'hc, {sd[7:0], sd[7:0]+3'h1, 16'h0}); |
else if(len-i==1) |
eth_host.wb_write(buffer+i, 4'h8, {sd[7:0], 24'h0}); |
else if(len-i==4) |
eth_host.wb_write(buffer+i, 4'hf, {sd[7:0], sd[7:0]+3'h1, sd[7:0]+3'h2, sd[7:0]+3'h3}); |
else |
$display("(%0t)(%m) ERROR", $time); |
wbm_write(32'hd0000000, `ETH_MODER_RXEN | `ETH_MODER_TXEN | `ETH_MODER_PRO | `ETH_MODER_CRCEN | |
`ETH_MODER_PAD, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
wbm_read(32'hd0000000, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
|
|
|
|
set_tx_bd(3); |
set_rx_bd(6); |
|
set_tx_packet(16'h34, 8'h1); |
set_tx_packet(16'h34, 8'h11); |
send_tx_packet; |
set_tx_packet(16'h34, 8'h21); |
set_tx_packet(16'h34, 8'h31); |
send_tx_packet; |
|
// Checking WRAP bit |
if(bd & `ETH_TX_BD_WRAP) |
packet_ready_cnt = 0; |
else |
packet_ready_cnt = packet_ready_cnt+1; |
|
// Writing len to bd |
bd = bd | (len<<16); |
eth_host.wb_write(bd_status_addr, 4'hf, bd); |
|
eth_phy.GetDataOnMRxD(100, `BROADCAST_XFR); // LengthRx bytes is comming on MRxD[3:0] signals |
repeat (100) @(posedge mrx_clk); // Waiting for TxEthMac to finish transmit |
|
eth_phy.GetDataOnMRxD(70, `BROADCAST_XFR); // LengthRx bytes is comming on MRxD[3:0] signals |
repeat (10000) @(posedge wb_clk); // Waiting for TxEthMac to finish transmit |
|
eth_phy.GetDataOnMRxD(70, `MULTICAST_XFR); // LengthRx bytes is comming on MRxD[3:0] signals |
repeat (10000) @(posedge wb_clk); // Waiting for TxEthMac to finish transmit |
*/ |
|
|
end |
endtask // test_mac_full_duplex_transmit |
|
|
////////////////////////////////////////////////////////////// |
// WB Behavioral Models Basic tasks |
////////////////////////////////////////////////////////////// |
|
task wbm_write; |
input [31:0] address_i; |
input [((`MAX_BLK_SIZE * 32) - 1):0] data_i; |
input [3:0] sel_i; |
input [31:0] size_i; |
input [3:0] init_waits_i; |
input [3:0] subseq_waits_i; |
|
reg `WRITE_STIM_TYPE write_data; |
reg `WB_TRANSFER_FLAGS flags; |
reg `WRITE_RETURN_TYPE write_status; |
integer i; |
begin |
write_status = 0; |
|
flags = 0; |
flags`WB_TRANSFER_SIZE = size_i; |
flags`INIT_WAITS = init_waits_i; |
flags`SUBSEQ_WAITS = subseq_waits_i; |
|
write_data = 0; |
write_data`WRITE_DATA = data_i[31:0]; |
write_data`WRITE_ADDRESS = address_i; |
write_data`WRITE_SEL = sel_i; |
|
for (i = 0; i < size_i; i = i + 1) |
begin |
wb_master.blk_write_data[i] = write_data; |
data_i = data_i >> 32; |
write_data`WRITE_DATA = data_i[31:0]; |
write_data`WRITE_ADDRESS = write_data`WRITE_ADDRESS + 4; |
end |
endtask // set_packet |
|
wb_master.wb_block_write(flags, write_status); |
|
task send_packet; |
if (write_status`CYC_ACTUAL_TRANSFER !== size_i) |
begin |
`TIME; |
$display("*E WISHBONE Master was unable to complete the requested write operation to MAC!"); |
end |
end |
endtask // wbm_write |
|
integer bd_status_addr, bd_ptr_addr, buffer, bd; |
|
task wbm_read; |
input [31:0] address_i; |
output [((`MAX_BLK_SIZE * 32) - 1):0] data_o; |
input [3:0] sel_i; |
input [31:0] size_i; |
input [3:0] init_waits_i; |
input [3:0] subseq_waits_i; |
|
reg `READ_RETURN_TYPE read_data; |
reg `WB_TRANSFER_FLAGS flags; |
reg `READ_RETURN_TYPE read_status; |
integer i; |
begin |
read_status = 0; |
data_o = 0; |
|
flags = 0; |
flags`WB_TRANSFER_SIZE = size_i; |
flags`INIT_WAITS = init_waits_i; |
flags`SUBSEQ_WAITS = subseq_waits_i; |
|
read_data = 0; |
read_data`READ_ADDRESS = address_i; |
read_data`READ_SEL = sel_i; |
|
for (i = 0; i < size_i; i = i + 1) |
begin |
bd_status_addr = `TX_BD_BASE + send_packet_cnt * 8; |
wb_master.blk_read_data_in[i] = read_data; |
read_data`READ_ADDRESS = read_data`READ_ADDRESS + 4; |
end |
|
wb_master.wb_block_read(flags, read_status); |
|
if (read_status`CYC_ACTUAL_TRANSFER !== size_i) |
begin |
`TIME; |
$display("*E WISHBONE Master was unable to complete the requested read operation from MAC!"); |
end |
|
for (i = 0; i < size_i; i = i + 1) |
begin |
data_o = data_o << 32; |
read_data = wb_master.blk_read_data_out[(size_i - 1) - i]; // [31 - i]; |
data_o[31:0] = read_data`READ_DATA; |
end |
end |
endtask // wbm_read |
|
|
////////////////////////////////////////////////////////////// |
// Ethernet Basic tasks |
////////////////////////////////////////////////////////////// |
|
task hard_reset; // MAC registers |
begin |
// reset MAC registers |
@(posedge wb_clk); |
#2 wb_rst = 1'b1; |
repeat(2) @(posedge wb_clk); |
#2 wb_rst = 1'b0; |
end |
endtask // hard_reset |
|
task reset_mac; // MAC module |
reg [31:0] tmp; |
reg [31:0] tmp_no_rst; |
begin |
// read MODER register first |
wbm_read(`ETH_MODER, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set reset bit - write back to MODER register with RESET bit |
wbm_write(`ETH_MODER, (`ETH_MODER_RST | tmp), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// clear reset bit - write back to MODER register without RESET bit |
tmp_no_rst = `ETH_MODER_RST; |
tmp_no_rst = ~tmp_no_rst; |
wbm_write(`ETH_MODER, (tmp_no_rst & tmp), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
endtask // reset_mac |
|
task set_tx_bd; |
input [6:0] tx_bd_num_start; |
input [6:0] tx_bd_num_end; |
input [15:0] len; |
input irq; |
input pad; |
input crc; |
input [31:0] txpnt; |
|
integer i; |
integer bd_status_addr, bd_ptr_addr; |
// integer buf_addr; |
begin |
for(i = tx_bd_num_start; i <= tx_bd_num_end; i = i + 1) |
begin |
// buf_addr = `TX_BUF_BASE + i * 32'h600; |
bd_status_addr = `TX_BD_BASE + i * 8; |
bd_ptr_addr = bd_status_addr + 4; |
// initialize BD - status |
// wbm_write(bd_status_addr, 32'h00005800, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); // IRQ + PAD + CRC |
wbm_write(bd_status_addr, {len, 1'b0, irq, 1'b0, pad, crc, 11'h0}, |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); // IRQ + PAD + CRC |
// initialize BD - pointer |
// wbm_write(bd_ptr_addr, buf_addr, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); // Initializing BD-pointer |
wbm_write(bd_ptr_addr, txpnt, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); // Initializing BD-pointer |
end |
end |
endtask // set_tx_bd |
|
task set_tx_bd_wrap; |
input [6:0] tx_bd_num_end; |
integer bd_status_addr, tmp; |
begin |
bd_status_addr = `TX_BD_BASE + tx_bd_num_end * 8; |
wbm_read(bd_status_addr, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set wrap bit to this BD - this BD should be last-one |
wbm_write(bd_status_addr, (`ETH_TX_BD_WRAP | tmp), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
endtask // set_tx_bd_wrap |
|
task set_tx_bd_ready; |
input [6:0] tx_nd_num_strat; |
input [6:0] tx_bd_num_end; |
integer i; |
integer bd_status_addr, tmp; |
begin |
for(i = tx_nd_num_strat; i <= tx_bd_num_end; i = i + 1) |
begin |
bd_status_addr = `TX_BD_BASE + i * 8; |
wbm_read(bd_status_addr, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set empty bit to this BD - this BD should be ready |
wbm_write(bd_status_addr, (`ETH_TX_BD_READY | tmp), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
end |
endtask // set_tx_bd_ready |
|
task check_tx_bd; |
input [6:0] tx_bd_num_end; |
output [31:0] tx_bd_status; |
integer bd_status_addr, tmp; |
begin |
bd_status_addr = `TX_BD_BASE + tx_bd_num_end * 8; |
wbm_read(bd_status_addr, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
#1 tx_bd_status = tmp; |
#1; |
end |
endtask // check_tx_bd |
|
task clear_tx_bd; |
input [6:0] tx_nd_num_strat; |
input [6:0] tx_bd_num_end; |
integer i; |
integer bd_status_addr, bd_ptr_addr; |
begin |
for(i = tx_nd_num_strat; i <= tx_bd_num_end; i = i + 1) |
begin |
bd_status_addr = `TX_BD_BASE + i * 8; |
bd_ptr_addr = bd_status_addr + 4; |
// clear BD - status |
wbm_write(bd_status_addr, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// clear BD - pointer |
wbm_write(bd_ptr_addr, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
end |
endtask // clear_tx_bd |
|
task set_rx_bd; |
input [6:0] rx_bd_num_strat; |
input [6:0] rx_bd_num_end; |
input irq; |
input [31:0] rxpnt; |
// input [6:0] rxbd_num; |
integer i; |
integer bd_status_addr, bd_ptr_addr; |
// integer buf_addr; |
begin |
for(i = rx_bd_num_strat; i <= rx_bd_num_end; i = i + 1) |
begin |
// buf_addr = `RX_BUF_BASE + i * 32'h600; |
bd_status_addr = `RX_BD_BASE + i * 8; |
bd_ptr_addr = bd_status_addr + 4; |
|
// Reading BD + buffer pointer |
eth_host.wb_read(bd_status_addr, 4'hf, bd); |
eth_host.wb_read(bd_ptr_addr, 4'hf, buffer); |
// initialize BD - status |
// wbm_write(bd_status_addr, 32'h0000c000, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); // IRQ + PAD + CRC |
wbm_write(bd_status_addr, {17'h0, irq, 14'h0}, |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// initialize BD - pointer |
// wbm_write(bd_ptr_addr, buf_addr, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); // Initializing BD-pointer |
wbm_write(bd_ptr_addr, rxpnt, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); // Initializing BD-pointer |
end |
end |
endtask // set_rx_bd |
|
if(bd & `ETH_TX_BD_WRAP) |
send_packet_cnt=0; |
else |
send_packet_cnt=send_packet_cnt+1; |
task set_rx_bd_wrap; |
input [6:0] rx_bd_num_end; |
integer bd_status_addr, tmp; |
begin |
bd_status_addr = `RX_BD_BASE + rx_bd_num_end * 8; |
wbm_read(bd_status_addr, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set wrap bit to this BD - this BD should be last-one |
wbm_write(bd_status_addr, (`ETH_RX_BD_WRAP | tmp), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
endtask // set_rx_bd_wrap |
|
// Setting ETH_TX_BD_READY bit |
bd = bd | `ETH_TX_BD_READY; |
eth_host.wb_write(bd_status_addr, 4'hf, bd); |
task set_rx_bd_empty; |
input [6:0] rx_bd_num_strat; |
input [6:0] rx_bd_num_end; |
integer i; |
integer bd_status_addr, tmp; |
begin |
for(i = rx_bd_num_strat; i <= rx_bd_num_end; i = i + 1) |
begin |
bd_status_addr = `RX_BD_BASE + i * 8; |
wbm_read(bd_status_addr, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set empty bit to this BD - this BD should be ready |
wbm_write(bd_status_addr, (`ETH_RX_BD_EMPTY | tmp), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
end |
endtask // set_rx_bd_empty |
|
task check_rx_bd; |
input [6:0] rx_bd_num_end; |
output [31:0] rx_bd_status; |
integer bd_status_addr, tmp; |
begin |
bd_status_addr = `RX_BD_BASE + rx_bd_num_end * 8; |
wbm_read(bd_status_addr, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
#1 rx_bd_status = tmp; |
#1; |
end |
endtask // check_rx_bd |
|
endtask // send_packet |
task clear_rx_bd; |
input [6:0] rx_bd_num_strat; |
input [6:0] rx_bd_num_end; |
integer i; |
integer bd_status_addr, bd_ptr_addr; |
begin |
for(i = rx_bd_num_strat; i <= rx_bd_num_end; i = i + 1) |
begin |
bd_status_addr = `RX_BD_BASE + i * 8; |
bd_ptr_addr = bd_status_addr + 4; |
// clear BD - status |
wbm_write(bd_status_addr, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// clear BD - pointer |
wbm_write(bd_ptr_addr, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
end |
endtask // clear_rx_bd |
|
task set_tx_packet; |
input [31:0] txpnt; |
input [15:0] len; |
input [7:0] eth_start_data; |
integer i, sd; |
integer buffer; |
reg delta_t; |
begin |
buffer = txpnt; |
sd = eth_start_data; |
delta_t = 0; |
|
task GetDataOnMRxD; |
input [15:0] Len; |
input [31:0] TransferType; |
integer tt; |
// First write might not be word allign. |
if(buffer[1:0] == 1) |
begin |
wb_slave.wr_mem(buffer - 1, {8'h0, sd[7:0], sd[7:0] + 3'h1, sd[7:0] + 3'h2}, 4'h7); |
sd = sd + 3; |
i = 3; |
end |
else if(buffer[1:0] == 2) |
begin |
wb_slave.wr_mem(buffer - 2, {16'h0, sd[7:0], sd[7:0] + 3'h1}, 4'h3); |
sd = sd + 2; |
i = 2; |
end |
else if(buffer[1:0] == 3) |
begin |
wb_slave.wr_mem(buffer - 3, {24'h0, sd[7:0]}, 4'h1); |
sd = sd + 1; |
i = 1; |
end |
else |
i = 0; |
delta_t = !delta_t; |
|
for(i = i; i < (len - 4); i = i + 4) // Last 0-3 bytes are not written |
begin |
wb_slave.wr_mem(buffer + i, {sd[7:0], sd[7:0] + 3'h1, sd[7:0] + 3'h2, sd[7:0] + 3'h3}, 4'hF); |
sd = sd + 4; |
end |
delta_t = !delta_t; |
|
// Last word |
if((len - i) == 3) |
begin |
@ (posedge mrx_clk); |
#1MRxDV=1'b1; |
|
for(tt=0; tt<15; tt=tt+1) |
wb_slave.wr_mem(buffer + i, {sd[7:0], sd[7:0] + 3'h1, sd[7:0] + 3'h2, 8'h0}, 4'hE); |
end |
else if((len - i) == 2) |
begin |
wb_slave.wr_mem(buffer + i, {sd[7:0], sd[7:0] + 3'h1, 16'h0}, 4'hC); |
end |
else if((len - i) == 1) |
begin |
wb_slave.wr_mem(buffer + i, {sd[7:0], 24'h0}, 4'h8); |
end |
else if((len - i) == 4) |
begin |
wb_slave.wr_mem(buffer + i, {sd[7:0], sd[7:0] + 3'h1, sd[7:0] + 3'h2, sd[7:0] + 3'h3}, 4'hF); |
end |
else |
$display("(%0t)(%m) ERROR", $time); |
delta_t = !delta_t; |
end |
endtask // set_tx_packet |
|
task check_tx_packet; |
input [31:0] txpnt_wb; // source |
input [31:0] txpnt_phy; // destination |
input [15:0] len; |
output [31:0] failure; |
integer i, data_wb, data_phy; |
reg [31:0] addr_wb, addr_phy; |
reg [31:0] failure; |
reg delta_t; |
begin |
addr_wb = txpnt_wb; |
addr_phy = txpnt_phy; |
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 - 1, data_wb, 4'h7); |
data_phy[31:24] = 0; |
data_phy[23:16] = eth_phy.tx_mem[addr_phy[21:0]]; |
data_phy[15: 8] = eth_phy.tx_mem[addr_phy[21:0] + 1]; |
data_phy[ 7: 0] = eth_phy.tx_mem[addr_phy[21:0] + 2]; |
i = 3; |
if (data_phy[23:0] !== data_wb[23:0]) |
begin |
`TIME; |
$display("*E Wrong 1. word (3 bytes) of TX packet!"); |
failure = 1; |
end |
end |
else if (addr_wb[1:0] == 2) |
begin |
wb_slave.rd_mem(addr_wb - 2, data_wb, 4'h3); |
data_phy[31:16] = 0; |
data_phy[15: 8] = eth_phy.tx_mem[addr_phy[21:0]]; |
data_phy[ 7: 0] = eth_phy.tx_mem[addr_phy[21:0] + 1]; |
i = 2; |
if (data_phy[15:0] !== data_wb[15:0]) |
begin |
`TIME; |
$display("*E Wrong 1. word (2 bytes) of TX packet!"); |
failure = 1; |
end |
end |
else if (addr_wb[1:0] == 3) |
begin |
wb_slave.rd_mem(addr_wb - 3, data_wb, 4'h1); |
data_phy[31: 8] = 0; |
data_phy[ 7: 0] = eth_phy.tx_mem[addr_phy[21:0]]; |
i = 1; |
if (data_phy[7:0] !== data_wb[7:0]) |
begin |
`TIME; |
$display("*E Wrong 1. word (1 byte) of TX packet!"); |
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 + i, data_wb, 4'hF); |
data_phy[31:24] = eth_phy.tx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy.tx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy.tx_mem[addr_phy[21:0] + i + 2]; |
data_phy[ 7: 0] = eth_phy.tx_mem[addr_phy[21:0] + i + 3]; |
if (data_phy[31:0] !== data_wb[31:0]) |
begin |
`TIME; |
$display("*E Wrong %d. word (4 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
delta_t = !delta_t; |
|
// Last word |
if((len - i) == 3) |
begin |
wb_slave.rd_mem(addr_wb + i, data_wb, 4'hE); |
data_phy[31:24] = eth_phy.tx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy.tx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy.tx_mem[addr_phy[21:0] + i + 2]; |
data_phy[ 7: 0] = 0; |
if (data_phy[31:8] !== data_wb[31:8]) |
begin |
`TIME; |
$display("*E Wrong %d. word (3 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
else if((len - i) == 2) |
begin |
wb_slave.rd_mem(addr_wb + i, data_wb, 4'hC); |
data_phy[31:24] = eth_phy.tx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy.tx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = 0; |
data_phy[ 7: 0] = 0; |
if (data_phy[31:16] !== data_wb[31:16]) |
begin |
`TIME; |
$display("*E Wrong %d. word (2 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
else if((len - i) == 1) |
begin |
wb_slave.rd_mem(addr_wb + i, data_wb, 4'h8); |
data_phy[31:24] = eth_phy.tx_mem[addr_phy[21:0] + i]; |
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 %d. word (1 byte) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
else if((len - i) == 4) |
begin |
wb_slave.rd_mem(addr_wb + i, data_wb, 4'hF); |
data_phy[31:24] = eth_phy.tx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy.tx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy.tx_mem[addr_phy[21:0] + i + 2]; |
data_phy[ 7: 0] = eth_phy.tx_mem[addr_phy[21:0] + i + 3]; |
if (data_phy[31:0] !== data_wb[31:0]) |
begin |
`TIME; |
$display("*E Wrong %d. word (4 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
else |
$display("(%0t)(%m) ERROR", $time); |
delta_t = !delta_t; |
end |
endtask // check_tx_packet |
|
task set_rx_packet; |
input [31:0] rxpnt; |
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_phy.rx_mem[buffer] = dest_addr[47:40]; |
dest_addr = dest_addr << 8; |
end |
else if (i < 12) |
begin |
eth_phy.rx_mem[buffer] = source_addr[47:40]; |
source_addr = source_addr << 8; |
end |
else if (i < 14) |
begin |
eth_phy.rx_mem[buffer] = type_len[15:8]; |
type_len = type_len << 8; |
end |
else |
begin |
eth_phy.rx_mem[buffer] = sd[7:0]; |
sd = sd + 1; |
end |
buffer = buffer + 1; |
end |
delta_t = !delta_t; |
if (plus_dribble_nibble) |
eth_phy.rx_mem[buffer] = {4'h0, 4'hD /*sd[3:0]*/}; |
delta_t = !delta_t; |
end |
endtask // set_rx_packet |
|
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 - 1, data_wb, 4'h7); |
data_phy[31:24] = 0; |
data_phy[23:16] = eth_phy.rx_mem[addr_phy[21:0]]; |
data_phy[15: 8] = eth_phy.rx_mem[addr_phy[21:0] + 1]; |
data_phy[ 7: 0] = eth_phy.rx_mem[addr_phy[21:0] + 2]; |
i = 3; |
if (data_phy[23:0] !== data_wb[23:0]) |
begin |
`TIME; |
$display("*E Wrong 1. word (3 bytes) of TX packet!"); |
failure = 1; |
end |
end |
else if (addr_wb[1:0] == 2) |
begin |
wb_slave.rd_mem(addr_wb - 2, data_wb, 4'h3); |
data_phy[31:16] = 0; |
data_phy[15: 8] = eth_phy.rx_mem[addr_phy[21:0]]; |
data_phy[ 7: 0] = eth_phy.rx_mem[addr_phy[21:0] + 1]; |
i = 2; |
if (data_phy[15:0] !== data_wb[15:0]) |
begin |
`TIME; |
$display("*E Wrong 1. word (2 bytes) of TX packet!"); |
failure = 1; |
end |
end |
else if (addr_wb[1:0] == 3) |
begin |
wb_slave.rd_mem(addr_wb - 3, data_wb, 4'h1); |
data_phy[31: 8] = 0; |
data_phy[ 7: 0] = eth_phy.rx_mem[addr_phy[21:0]]; |
i = 1; |
if (data_phy[7:0] !== data_wb[7:0]) |
begin |
`TIME; |
$display("*E Wrong 1. word (1 byte) of TX packet!"); |
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 + i, data_wb, 4'hF); |
data_phy[31:24] = eth_phy.rx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy.rx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy.rx_mem[addr_phy[21:0] + i + 2]; |
data_phy[ 7: 0] = eth_phy.rx_mem[addr_phy[21:0] + i + 3]; |
if (data_phy[31:0] !== data_wb[31:0]) |
begin |
`TIME; |
$display("*E Wrong %d. word (4 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
delta_t = !delta_t; |
|
// Last word |
if((len - i) == 3) |
begin |
wb_slave.rd_mem(addr_wb + i, data_wb, 4'hF); |
data_phy[31:24] = eth_phy.rx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy.rx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy.rx_mem[addr_phy[21:0] + i + 2]; |
if (plus_dribble_nibble) |
data_phy[ 7: 0] = eth_phy.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 %d. word (3 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
if (plus_dribble_nibble && successful_dribble_nibble) |
begin |
if (data_phy[3:0] !== data_wb[3:0]) |
begin |
MRxD=4'h5; // preamble |
@ (posedge mrx_clk); |
#1; |
`TIME; |
$display("*E Wrong dribble nibble in %d. word (3 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
|
MRxD=4'hd; // SFD |
|
for(tt=1; tt<(Len+1); tt=tt+1) |
end |
else if (plus_dribble_nibble && !successful_dribble_nibble) |
begin |
if (data_phy[3:0] === data_wb[3:0]) |
begin |
@ (posedge mrx_clk); |
#1; |
if(TransferType == `UNICAST_XFR && tt == 1) |
MRxD= 4'h0; // Unicast transfer |
else if(TransferType == `BROADCAST_XFR && tt < 7) |
MRxD = 4'hf; |
else |
MRxD=tt[3:0]; // Multicast transfer |
|
@ (posedge mrx_clk); |
#1; |
if(TransferType == `BROADCAST_XFR && tt < 7) |
MRxD = 4'hf; |
else |
MRxD=tt[7:4]; |
`TIME; |
$display("*E Wrong dribble nibble in %d. word (3 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
end |
else if((len - i) == 2) |
begin |
wb_slave.rd_mem(addr_wb + i, data_wb, 4'hE); |
data_phy[31:24] = eth_phy.rx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy.rx_mem[addr_phy[21:0] + i + 1]; |
if (plus_dribble_nibble) |
data_phy[15: 8] = eth_phy.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 %d. word (2 bytes) of TX packet!", ((i/4)+1)); |
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 %d. word (2 bytes) of TX 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 %d. word (2 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
end |
else if((len - i) == 1) |
begin |
wb_slave.rd_mem(addr_wb + i, data_wb, 4'hC); |
data_phy[31:24] = eth_phy.rx_mem[addr_phy[21:0] + i]; |
if (plus_dribble_nibble) |
data_phy[23:16] = eth_phy.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 %d. word (1 byte) of TX packet!", ((i/4)+1)); |
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 %d. word (1 byte) of TX 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 %d. word (1 byte) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
end |
end |
else if((len - i) == 4) |
begin |
wb_slave.rd_mem(addr_wb + i, data_wb, 4'hF); |
data_phy[31:24] = eth_phy.rx_mem[addr_phy[21:0] + i]; |
data_phy[23:16] = eth_phy.rx_mem[addr_phy[21:0] + i + 1]; |
data_phy[15: 8] = eth_phy.rx_mem[addr_phy[21:0] + i + 2]; |
data_phy[ 7: 0] = eth_phy.rx_mem[addr_phy[21:0] + i + 3]; |
if (data_phy[31:0] !== data_wb[31:0]) |
begin |
`TIME; |
$display("*E Wrong %d. word (4 bytes) of TX packet!", ((i/4)+1)); |
failure = failure + 1; |
end |
if (plus_dribble_nibble) |
begin |
wb_slave.rd_mem(addr_wb + i + 4, data_wb, 4'h8); |
data_phy[31:24] = eth_phy.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 %d. word (0 bytes) of TX 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 %d. word (0 bytes) of TX 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 |
|
@ (posedge mrx_clk); |
#1; |
MRxDV=1'b0; |
////////////////////////////////////////////////////////////// |
// Ethernet CRC Basic tasks |
////////////////////////////////////////////////////////////// |
|
task append_tx_crc; |
input [31:0] txpnt_wb; // source |
input [15:0] len; // length in bytes without CRC |
input negated_crc; // if appended CRC is correct or not |
reg [31:0] crc; |
reg [31:0] addr_wb; |
reg delta_t; |
begin |
addr_wb = txpnt_wb + len; |
delta_t = 0; |
// calculate CRC from prepared packet |
paralel_crc_mac(txpnt_wb, {16'h0, len}, 1'b0, crc); |
if (negated_crc) |
crc = ~crc; |
delta_t = !delta_t; |
|
// Write might not be word allign. |
if (addr_wb[1:0] == 1) |
begin |
wb_slave.wr_mem(addr_wb - 1, {8'h0, crc[7:0], crc[15:8], crc[23:16]}, 4'h7); |
wb_slave.wr_mem(addr_wb + 3, {crc[31:24], 24'h0}, 4'h8); |
end |
endtask // GetDataOnMRxD |
else if (addr_wb[1:0] == 2) |
begin |
wb_slave.wr_mem(addr_wb - 2, {16'h0, crc[7:0], crc[15:8]}, 4'h3); |
wb_slave.wr_mem(addr_wb + 2, {crc[23:16], crc[31:24], 16'h0}, 4'hC); |
end |
else if (addr_wb[1:0] == 3) |
begin |
wb_slave.wr_mem(addr_wb - 3, {24'h0, crc[7:0]}, 4'h1); |
wb_slave.wr_mem(addr_wb + 1, {crc[15:8], crc[23:16], crc[31:24], 8'h0}, 4'hE); |
end |
else |
begin |
wb_slave.wr_mem(addr_wb, {crc[7:0], crc[15:8], crc[23:16], crc[31:24]}, 4'hF); |
end |
delta_t = !delta_t; |
end |
endtask // append_tx_crc |
|
task check_tx_crc; // used to check crc added to TX packets by MAC |
input [31:0] txpnt_phy; // destination |
input [15:0] len; // length in bytes without CRC |
input negated_crc; // if appended CRC is correct or not |
output [31:0] failure; |
reg [31:0] failure; |
reg [31:0] crc_calc; |
reg [31:0] crc; |
reg [31:0] addr_phy; |
reg delta_t; |
begin |
addr_phy = txpnt_phy; |
failure = 0; |
// calculate CRC from sent packet |
// serial_crc_phy_tx(addr_phy, {16'h0, len}, 1'b0, crc_calc); |
//#10; |
paralel_crc_phy_tx(addr_phy, {16'h0, len}, 1'b0, crc_calc); |
|
addr_phy = addr_phy + len; |
// Read CRC - BIG endian |
crc[31:24] = eth_phy.tx_mem[addr_phy[21:0]]; |
crc[23:16] = eth_phy.tx_mem[addr_phy[21:0] + 1]; |
crc[15: 8] = eth_phy.tx_mem[addr_phy[21:0] + 2]; |
crc[ 7: 0] = eth_phy.tx_mem[addr_phy[21:0] + 3]; |
|
delta_t = !delta_t; |
if (negated_crc) |
begin |
if ((~crc_calc) !== crc) |
begin |
`TIME; |
$display("*E Negated CRC was not successfuly transmitted!"); |
failure = failure + 1; |
end |
end |
else |
begin |
if (crc_calc !== crc) |
begin |
`TIME; |
$display("*E Transmitted CRC was not correct!"); |
failure = failure + 1; |
end |
end |
delta_t = !delta_t; |
end |
endtask // check_tx_crc |
|
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_phy.rx_mem[addr_phy]; |
eth_phy.rx_mem[addr_phy] = {crc[3:0], tmp[3:0]}; |
eth_phy.rx_mem[addr_phy + 1] = {crc[11:8], crc[7:4]}; |
eth_phy.rx_mem[addr_phy + 2] = {crc[19:16], crc[15:12]}; |
eth_phy.rx_mem[addr_phy + 3] = {crc[27:24], crc[23:20]}; |
eth_phy.rx_mem[addr_phy + 4] = {4'h0, crc[31:28]}; |
end |
else |
begin |
eth_phy.rx_mem[addr_phy] = crc[7:0]; |
eth_phy.rx_mem[addr_phy + 1] = crc[15:8]; |
eth_phy.rx_mem[addr_phy + 2] = crc[23:16]; |
eth_phy.rx_mem[addr_phy + 3] = crc[31:24]; |
end |
end |
endtask // append_rx_crc |
|
// paralel CRC checking for PHY TX |
task paralel_crc_phy_tx; |
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_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15: 8] = eth_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[ 7: 0] = eth_phy.tx_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_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15: 8] = eth_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[ 7: 0] = eth_phy.tx_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_tx |
|
// 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; |
reg [21:0] addr_cnt; // only 22 address lines |
integer word_cnt; |
integer bit_cnt; |
reg [31:0] load_reg; |
reg [31:0] crc_shift_reg; |
reg [31:0] crc_store_reg; |
reg delta_t; |
begin |
#1 addr_cnt = start_addr[21:0]; |
word_cnt = 24; // start of the frame |
crc_shift_reg = 0; |
delta_t = 0; |
// length must include 4 bytes of ZEROs, to generate CRC |
// get number of bits from Byte length (2^3 = 8) |
if (plus_dribble_nibble) |
bit_cnt = ((len + 4) << 3) + 3'h4; // one nibble longer |
else |
bit_cnt = ((len + 4) << 3); |
load_reg[31:24] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15:8] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[7:0] = eth_phy.rx_mem[addr_cnt]; |
|
while (bit_cnt > 0) |
begin |
// wait for delta time |
delta_t = !delta_t; |
// store previous data |
crc_store_reg = crc_shift_reg; |
// shift data in |
if(bit_cnt <= 32) // for additional 32 bits shift ZEROs in! |
crc_shift_reg[0] = 1'b0 ^ crc_store_reg[31]; |
else |
crc_shift_reg[0] = load_reg[word_cnt] ^ crc_store_reg[31]; |
crc_shift_reg[1] = crc_store_reg[0] ^ crc_store_reg[31]; |
crc_shift_reg[2] = crc_store_reg[1] ^ crc_store_reg[31]; |
crc_shift_reg[3] = crc_store_reg[2]; |
crc_shift_reg[4] = crc_store_reg[3] ^ crc_store_reg[31]; |
crc_shift_reg[5] = crc_store_reg[4] ^ crc_store_reg[31]; |
crc_shift_reg[6] = crc_store_reg[5]; |
crc_shift_reg[7] = crc_store_reg[6] ^ crc_store_reg[31]; |
crc_shift_reg[8] = crc_store_reg[7] ^ crc_store_reg[31]; |
crc_shift_reg[9] = crc_store_reg[8]; |
crc_shift_reg[10] = crc_store_reg[9] ^ crc_store_reg[31]; |
crc_shift_reg[11] = crc_store_reg[10] ^ crc_store_reg[31]; |
crc_shift_reg[12] = crc_store_reg[11] ^ crc_store_reg[31]; |
crc_shift_reg[13] = crc_store_reg[12]; |
crc_shift_reg[14] = crc_store_reg[13]; |
crc_shift_reg[15] = crc_store_reg[14]; |
crc_shift_reg[16] = crc_store_reg[15] ^ crc_store_reg[31]; |
crc_shift_reg[17] = crc_store_reg[16]; |
crc_shift_reg[18] = crc_store_reg[17]; |
crc_shift_reg[19] = crc_store_reg[18]; |
crc_shift_reg[20] = crc_store_reg[19]; |
crc_shift_reg[21] = crc_store_reg[20]; |
crc_shift_reg[22] = crc_store_reg[21] ^ crc_store_reg[31]; |
crc_shift_reg[23] = crc_store_reg[22] ^ crc_store_reg[31]; |
crc_shift_reg[24] = crc_store_reg[23]; |
crc_shift_reg[25] = crc_store_reg[24]; |
crc_shift_reg[26] = crc_store_reg[25] ^ crc_store_reg[31]; |
crc_shift_reg[27] = crc_store_reg[26]; |
crc_shift_reg[28] = crc_store_reg[27]; |
crc_shift_reg[29] = crc_store_reg[28]; |
crc_shift_reg[30] = crc_store_reg[29]; |
crc_shift_reg[31] = crc_store_reg[30]; |
// wait for delta time |
delta_t = !delta_t; |
// increment address and load new data |
if (word_cnt == 7) |
begin |
addr_cnt = addr_cnt + 1; |
load_reg[31:24] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15:8] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[7:0] = eth_phy.rx_mem[addr_cnt]; |
end |
// set new load bit position |
if(word_cnt == 31) |
word_cnt = 16; |
else if (word_cnt == 23) |
word_cnt = 8; |
else if (word_cnt == 15) |
word_cnt = 0; |
else if (word_cnt == 7) |
word_cnt = 24; |
else |
word_cnt = word_cnt + 1; |
// decrement bit counter |
bit_cnt = bit_cnt - 1; |
// wait for delta time |
delta_t = !delta_t; |
end // while |
|
// put CRC out |
crc = crc_shift_reg; |
#1; |
end |
endtask // paralel_crc_phy_rx |
|
// paralel CRC checking for MAC |
task paralel_crc_mac; |
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; |
reg [19:0] addr_cnt; // only 20 address lines |
integer word_cnt; |
integer bit_cnt; |
reg [31:0] load_reg; |
reg [31:0] crc_shift_reg; |
reg [31:0] crc_store_reg; |
reg delta_t; |
begin |
#1 addr_cnt = start_addr[19:0]; |
// set starting point depending with which byte frame starts (e.g. if addr_cnt[1:0] == 0, then |
// MSB of the packet must be written to the LSB of Big ENDIAN Word [31:24]) |
if (addr_cnt[1:0] == 2'h1) |
word_cnt = 16; // start of the frame for Big ENDIAN Bytes (Litle ENDIAN bits) |
else if (addr_cnt[1:0] == 2'h2) |
word_cnt = 8; // start of the frame for Big ENDIAN Bytes (Litle ENDIAN bits) |
else if (addr_cnt[1:0] == 2'h3) |
word_cnt = 0; // start of the frame for Big ENDIAN Bytes (Litle ENDIAN bits) |
else |
word_cnt = 24; // start of the frame for Big ENDIAN Bytes (Litle ENDIAN bits) |
|
crc_shift_reg = 0; |
delta_t = 0; |
// length must include 4 bytes of ZEROs, to generate CRC |
// get number of bits from Byte length (2^3 = 8) |
if (plus_dribble_nibble) |
bit_cnt = ((len + 4) << 3) + 3'h4; // one nibble longer |
else |
bit_cnt = ((len + 4) << 3); |
load_reg = wb_slave.wb_memory[{12'h0, addr_cnt}]; |
|
while (bit_cnt > 0) |
begin |
// wait for delta time |
delta_t = !delta_t; |
// store previous data |
crc_store_reg = crc_shift_reg; |
// shift data in |
if(bit_cnt <= 32) // for additional 32 bits shift ZEROs in! |
crc_shift_reg[0] = 1'b0 ^ crc_store_reg[31]; |
else |
crc_shift_reg[0] = load_reg[word_cnt] ^ crc_store_reg[31]; |
crc_shift_reg[1] = crc_store_reg[0] ^ crc_store_reg[31]; |
crc_shift_reg[2] = crc_store_reg[1] ^ crc_store_reg[31]; |
crc_shift_reg[3] = crc_store_reg[2]; |
crc_shift_reg[4] = crc_store_reg[3] ^ crc_store_reg[31]; |
crc_shift_reg[5] = crc_store_reg[4] ^ crc_store_reg[31]; |
crc_shift_reg[6] = crc_store_reg[5]; |
crc_shift_reg[7] = crc_store_reg[6] ^ crc_store_reg[31]; |
crc_shift_reg[8] = crc_store_reg[7] ^ crc_store_reg[31]; |
crc_shift_reg[9] = crc_store_reg[8]; |
crc_shift_reg[10] = crc_store_reg[9] ^ crc_store_reg[31]; |
crc_shift_reg[11] = crc_store_reg[10] ^ crc_store_reg[31]; |
crc_shift_reg[12] = crc_store_reg[11] ^ crc_store_reg[31]; |
crc_shift_reg[13] = crc_store_reg[12]; |
crc_shift_reg[14] = crc_store_reg[13]; |
crc_shift_reg[15] = crc_store_reg[14]; |
crc_shift_reg[16] = crc_store_reg[15] ^ crc_store_reg[31]; |
crc_shift_reg[17] = crc_store_reg[16]; |
crc_shift_reg[18] = crc_store_reg[17]; |
crc_shift_reg[19] = crc_store_reg[18]; |
crc_shift_reg[20] = crc_store_reg[19]; |
crc_shift_reg[21] = crc_store_reg[20]; |
crc_shift_reg[22] = crc_store_reg[21] ^ crc_store_reg[31]; |
crc_shift_reg[23] = crc_store_reg[22] ^ crc_store_reg[31]; |
crc_shift_reg[24] = crc_store_reg[23]; |
crc_shift_reg[25] = crc_store_reg[24]; |
crc_shift_reg[26] = crc_store_reg[25] ^ crc_store_reg[31]; |
crc_shift_reg[27] = crc_store_reg[26]; |
crc_shift_reg[28] = crc_store_reg[27]; |
crc_shift_reg[29] = crc_store_reg[28]; |
crc_shift_reg[30] = crc_store_reg[29]; |
crc_shift_reg[31] = crc_store_reg[30]; |
// wait for delta time |
delta_t = !delta_t; |
// increment address and load new data for Big ENDIAN Bytes (Litle ENDIAN bits) |
if (word_cnt == 7) |
begin |
addr_cnt = addr_cnt + 4; |
load_reg = wb_slave.wb_memory[{12'h0, addr_cnt}]; |
end |
// set new load bit position for Big ENDIAN Bytes (Litle ENDIAN bits) |
if(word_cnt == 31) |
word_cnt = 16; |
else if (word_cnt == 23) |
word_cnt = 8; |
else if (word_cnt == 15) |
word_cnt = 0; |
else if (word_cnt == 7) |
word_cnt = 24; |
else |
word_cnt = word_cnt + 1; |
// decrement bit counter |
bit_cnt = bit_cnt - 1; |
// wait for delta time |
delta_t = !delta_t; |
end // while |
|
// put CRC out |
crc = crc_shift_reg; |
#1; |
end |
endtask // paralel_crc_mac |
|
// serial CRC checking for PHY TX |
task serial_crc_phy_tx; |
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; |
reg [21:0] addr_cnt; // only 22 address lines |
integer word_cnt; |
integer bit_cnt; |
reg [31:0] load_reg; |
reg [31:0] crc_shift_reg; |
reg [31:0] crc_store_reg; |
reg delta_t; |
begin |
#1 addr_cnt = start_addr[21:0]; |
word_cnt = 24; // 27; // start of the frame - nibble granularity (MSbit first) |
crc_store_reg = 32'hFFFF_FFFF; // INITIAL value |
delta_t = 0; |
// length must include 4 bytes of ZEROs, to generate CRC |
// get number of bits from Byte length (2^3 = 8) |
if (plus_dribble_nibble) |
bit_cnt = ((len + 4) << 3) + 3'h4; // one nibble longer |
else |
bit_cnt = ((len + 4) << 3); |
// because of MAGIC NUMBER nibbles are swapped [3:0] -> [0:3] |
load_reg[31:24] = eth_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15: 8] = eth_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[ 7: 0] = eth_phy.tx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
#1; |
while (bit_cnt > 0) |
begin |
// wait for delta time |
delta_t = !delta_t; |
#1; |
// shift data in |
|
if(bit_cnt <= 32) // for additional 32 bits shift ZEROs in! |
crc_shift_reg[0] = 1'b0 ^ crc_store_reg[31]; |
else |
|
crc_shift_reg[0] = load_reg[word_cnt] ^ crc_store_reg[31]; |
crc_shift_reg[1] = crc_store_reg[0] ^ crc_store_reg[31]; |
crc_shift_reg[2] = crc_store_reg[1] ^ crc_store_reg[31]; |
crc_shift_reg[3] = crc_store_reg[2]; |
crc_shift_reg[4] = crc_store_reg[3] ^ crc_store_reg[31]; |
crc_shift_reg[5] = crc_store_reg[4] ^ crc_store_reg[31]; |
crc_shift_reg[6] = crc_store_reg[5]; |
crc_shift_reg[7] = crc_store_reg[6] ^ crc_store_reg[31]; |
crc_shift_reg[8] = crc_store_reg[7] ^ crc_store_reg[31]; |
crc_shift_reg[9] = crc_store_reg[8]; |
crc_shift_reg[10] = crc_store_reg[9] ^ crc_store_reg[31]; |
crc_shift_reg[11] = crc_store_reg[10] ^ crc_store_reg[31]; |
crc_shift_reg[12] = crc_store_reg[11] ^ crc_store_reg[31]; |
crc_shift_reg[13] = crc_store_reg[12]; |
crc_shift_reg[14] = crc_store_reg[13]; |
crc_shift_reg[15] = crc_store_reg[14]; |
crc_shift_reg[16] = crc_store_reg[15] ^ crc_store_reg[31]; |
crc_shift_reg[17] = crc_store_reg[16]; |
crc_shift_reg[18] = crc_store_reg[17]; |
crc_shift_reg[19] = crc_store_reg[18]; |
crc_shift_reg[20] = crc_store_reg[19]; |
crc_shift_reg[21] = crc_store_reg[20]; |
crc_shift_reg[22] = crc_store_reg[21] ^ crc_store_reg[31]; |
crc_shift_reg[23] = crc_store_reg[22] ^ crc_store_reg[31]; |
crc_shift_reg[24] = crc_store_reg[23]; |
crc_shift_reg[25] = crc_store_reg[24]; |
crc_shift_reg[26] = crc_store_reg[25] ^ crc_store_reg[31]; |
crc_shift_reg[27] = crc_store_reg[26]; |
crc_shift_reg[28] = crc_store_reg[27]; |
crc_shift_reg[29] = crc_store_reg[28]; |
crc_shift_reg[30] = crc_store_reg[29]; |
crc_shift_reg[31] = crc_store_reg[30]; |
// wait for delta time |
delta_t = !delta_t; |
|
// store previous data |
crc_store_reg = crc_shift_reg; |
|
// put CRC out |
case (bit_cnt) |
33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 1: |
begin |
crc = crc_store_reg; |
crc = {!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]}; |
end |
default: crc = crc; |
endcase |
|
// increment address and load new data |
#1; |
if (word_cnt == 7)//4) |
begin |
// because of MAGIC NUMBER nibbles are swapped [3:0] -> [0:3] |
load_reg[31:24] = eth_phy.tx_mem[addr_cnt]; |
// load_reg[31:24] = {load_reg[28], load_reg[29], load_reg[30], load_reg[31], |
// load_reg[24], load_reg[25], load_reg[26], load_reg[27]}; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy.tx_mem[addr_cnt]; |
// load_reg[23:16] = {load_reg[20], load_reg[21], load_reg[22], load_reg[23], |
// load_reg[16], load_reg[17], load_reg[18], load_reg[19]}; |
addr_cnt = addr_cnt + 1; |
load_reg[15: 8] = eth_phy.tx_mem[addr_cnt]; |
// load_reg[15: 8] = {load_reg[12], load_reg[13], load_reg[14], load_reg[15], |
// load_reg[ 8], load_reg[ 9], load_reg[10], load_reg[11]}; |
addr_cnt = addr_cnt + 1; |
load_reg[ 7: 0] = eth_phy.tx_mem[addr_cnt]; |
// load_reg[ 7: 0] = {load_reg[ 4], load_reg[ 5], load_reg[ 6], load_reg[ 7], |
// load_reg[ 0], load_reg[ 1], load_reg[ 2], load_reg[ 3]}; |
addr_cnt = addr_cnt + 1; |
end |
#1; |
// set new load bit position |
if(word_cnt == 31) |
word_cnt = 16; |
else if (word_cnt == 23) |
word_cnt = 8; |
else if (word_cnt == 15) |
word_cnt = 0; |
else if (word_cnt == 7) |
word_cnt = 24; |
|
// if(word_cnt == 24) |
// word_cnt = 31; |
// else if (word_cnt == 28) |
// word_cnt = 19; |
// else if (word_cnt == 16) |
// word_cnt = 23; |
// else if (word_cnt == 20) |
// word_cnt = 11; |
// else if(word_cnt == 8) |
// word_cnt = 15; |
// else if (word_cnt == 12) |
// word_cnt = 3; |
// else if (word_cnt == 0) |
// word_cnt = 7; |
// else if (word_cnt == 4) |
// word_cnt = 27; |
else |
word_cnt = word_cnt + 1;// - 1; |
#1; |
// decrement bit counter |
bit_cnt = bit_cnt - 1; |
#1; |
// wait for delta time |
delta_t = !delta_t; |
end // while |
|
#1; |
end |
endtask // serial_crc_phy_tx |
|
// serial CRC calculating for PHY RX |
task serial_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; |
reg [21:0] addr_cnt; // only 22 address lines |
integer word_cnt; |
integer bit_cnt; |
reg [31:0] load_reg; |
reg [31:0] crc_shift_reg; |
reg [31:0] crc_store_reg; |
reg delta_t; |
begin |
#1 addr_cnt = start_addr[21:0]; |
word_cnt = 24; // start of the frame |
crc_shift_reg = 0; |
delta_t = 0; |
// length must include 4 bytes of ZEROs, to generate CRC |
// get number of bits from Byte length (2^3 = 8) |
if (plus_dribble_nibble) |
bit_cnt = ((len + 4) << 3) + 3'h4; // one nibble longer |
else |
bit_cnt = ((len + 4) << 3); |
load_reg[31:24] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15:8] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[7:0] = eth_phy.rx_mem[addr_cnt]; |
|
while (bit_cnt > 0) |
begin |
// wait for delta time |
delta_t = !delta_t; |
// store previous data |
crc_store_reg = crc_shift_reg; |
// shift data in |
if(bit_cnt <= 32) // for additional 32 bits shift ZEROs in! |
crc_shift_reg[0] = 1'b0 ^ crc_store_reg[31]; |
else |
crc_shift_reg[0] = load_reg[word_cnt] ^ crc_store_reg[31]; |
crc_shift_reg[1] = crc_store_reg[0] ^ crc_store_reg[31]; |
crc_shift_reg[2] = crc_store_reg[1] ^ crc_store_reg[31]; |
crc_shift_reg[3] = crc_store_reg[2]; |
crc_shift_reg[4] = crc_store_reg[3] ^ crc_store_reg[31]; |
crc_shift_reg[5] = crc_store_reg[4] ^ crc_store_reg[31]; |
crc_shift_reg[6] = crc_store_reg[5]; |
crc_shift_reg[7] = crc_store_reg[6] ^ crc_store_reg[31]; |
crc_shift_reg[8] = crc_store_reg[7] ^ crc_store_reg[31]; |
crc_shift_reg[9] = crc_store_reg[8]; |
crc_shift_reg[10] = crc_store_reg[9] ^ crc_store_reg[31]; |
crc_shift_reg[11] = crc_store_reg[10] ^ crc_store_reg[31]; |
crc_shift_reg[12] = crc_store_reg[11] ^ crc_store_reg[31]; |
crc_shift_reg[13] = crc_store_reg[12]; |
crc_shift_reg[14] = crc_store_reg[13]; |
crc_shift_reg[15] = crc_store_reg[14]; |
crc_shift_reg[16] = crc_store_reg[15] ^ crc_store_reg[31]; |
crc_shift_reg[17] = crc_store_reg[16]; |
crc_shift_reg[18] = crc_store_reg[17]; |
crc_shift_reg[19] = crc_store_reg[18]; |
crc_shift_reg[20] = crc_store_reg[19]; |
crc_shift_reg[21] = crc_store_reg[20]; |
crc_shift_reg[22] = crc_store_reg[21] ^ crc_store_reg[31]; |
crc_shift_reg[23] = crc_store_reg[22] ^ crc_store_reg[31]; |
crc_shift_reg[24] = crc_store_reg[23]; |
crc_shift_reg[25] = crc_store_reg[24]; |
crc_shift_reg[26] = crc_store_reg[25] ^ crc_store_reg[31]; |
crc_shift_reg[27] = crc_store_reg[26]; |
crc_shift_reg[28] = crc_store_reg[27]; |
crc_shift_reg[29] = crc_store_reg[28]; |
crc_shift_reg[30] = crc_store_reg[29]; |
crc_shift_reg[31] = crc_store_reg[30]; |
// wait for delta time |
delta_t = !delta_t; |
// increment address and load new data |
if (word_cnt == 7) |
begin |
addr_cnt = addr_cnt + 1; |
load_reg[31:24] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[23:16] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[15:8] = eth_phy.rx_mem[addr_cnt]; |
addr_cnt = addr_cnt + 1; |
load_reg[7:0] = eth_phy.rx_mem[addr_cnt]; |
end |
// set new load bit position |
if(word_cnt == 31) |
word_cnt = 16; |
else if (word_cnt == 23) |
word_cnt = 8; |
else if (word_cnt == 15) |
word_cnt = 0; |
else if (word_cnt == 7) |
word_cnt = 24; |
else |
word_cnt = word_cnt + 1; |
// decrement bit counter |
bit_cnt = bit_cnt - 1; |
// wait for delta time |
delta_t = !delta_t; |
end // while |
|
// put CRC out |
crc = crc_shift_reg; |
#1; |
end |
endtask // serial_crc_phy_rx |
|
// serial CRC checking for MAC |
task serial_crc_mac; |
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; |
reg [19:0] addr_cnt; // only 20 address lines |
integer word_cnt; |
integer bit_cnt; |
reg [31:0] load_reg; |
reg [31:0] crc_shift_reg; |
reg [31:0] crc_store_reg; |
reg delta_t; |
begin |
#1 addr_cnt = start_addr[19:0]; |
// set starting point depending with which byte frame starts (e.g. if addr_cnt[1:0] == 0, then |
// MSB of the packet must be written to the LSB of Big ENDIAN Word [31:24]) |
if (addr_cnt[1:0] == 2'h1) |
word_cnt = 16; // start of the frame for Big ENDIAN Bytes (Litle ENDIAN bits) |
else if (addr_cnt[1:0] == 2'h2) |
word_cnt = 8; // start of the frame for Big ENDIAN Bytes (Litle ENDIAN bits) |
else if (addr_cnt[1:0] == 2'h3) |
word_cnt = 0; // start of the frame for Big ENDIAN Bytes (Litle ENDIAN bits) |
else |
word_cnt = 24; // start of the frame for Big ENDIAN Bytes (Litle ENDIAN bits) |
|
crc_shift_reg = 0; |
delta_t = 0; |
// length must include 4 bytes of ZEROs, to generate CRC |
// get number of bits from Byte length (2^3 = 8) |
if (plus_dribble_nibble) |
bit_cnt = ((len + 4) << 3) + 3'h4; // one nibble longer |
else |
bit_cnt = ((len + 4) << 3); |
load_reg = wb_slave.wb_memory[{12'h0, addr_cnt}]; |
|
while (bit_cnt > 0) |
begin |
// wait for delta time |
delta_t = !delta_t; |
// store previous data |
crc_store_reg = crc_shift_reg; |
// shift data in |
if(bit_cnt <= 32) // for additional 32 bits shift ZEROs in! |
crc_shift_reg[0] = 1'b0 ^ crc_store_reg[31]; |
else |
crc_shift_reg[0] = load_reg[word_cnt] ^ crc_store_reg[31]; |
crc_shift_reg[1] = crc_store_reg[0] ^ crc_store_reg[31]; |
crc_shift_reg[2] = crc_store_reg[1] ^ crc_store_reg[31]; |
crc_shift_reg[3] = crc_store_reg[2]; |
crc_shift_reg[4] = crc_store_reg[3] ^ crc_store_reg[31]; |
crc_shift_reg[5] = crc_store_reg[4] ^ crc_store_reg[31]; |
crc_shift_reg[6] = crc_store_reg[5]; |
crc_shift_reg[7] = crc_store_reg[6] ^ crc_store_reg[31]; |
crc_shift_reg[8] = crc_store_reg[7] ^ crc_store_reg[31]; |
crc_shift_reg[9] = crc_store_reg[8]; |
crc_shift_reg[10] = crc_store_reg[9] ^ crc_store_reg[31]; |
crc_shift_reg[11] = crc_store_reg[10] ^ crc_store_reg[31]; |
crc_shift_reg[12] = crc_store_reg[11] ^ crc_store_reg[31]; |
crc_shift_reg[13] = crc_store_reg[12]; |
crc_shift_reg[14] = crc_store_reg[13]; |
crc_shift_reg[15] = crc_store_reg[14]; |
crc_shift_reg[16] = crc_store_reg[15] ^ crc_store_reg[31]; |
crc_shift_reg[17] = crc_store_reg[16]; |
crc_shift_reg[18] = crc_store_reg[17]; |
crc_shift_reg[19] = crc_store_reg[18]; |
crc_shift_reg[20] = crc_store_reg[19]; |
crc_shift_reg[21] = crc_store_reg[20]; |
crc_shift_reg[22] = crc_store_reg[21] ^ crc_store_reg[31]; |
crc_shift_reg[23] = crc_store_reg[22] ^ crc_store_reg[31]; |
crc_shift_reg[24] = crc_store_reg[23]; |
crc_shift_reg[25] = crc_store_reg[24]; |
crc_shift_reg[26] = crc_store_reg[25] ^ crc_store_reg[31]; |
crc_shift_reg[27] = crc_store_reg[26]; |
crc_shift_reg[28] = crc_store_reg[27]; |
crc_shift_reg[29] = crc_store_reg[28]; |
crc_shift_reg[30] = crc_store_reg[29]; |
crc_shift_reg[31] = crc_store_reg[30]; |
// wait for delta time |
delta_t = !delta_t; |
// increment address and load new data for Big ENDIAN Bytes (Litle ENDIAN bits) |
if (word_cnt == 7) |
begin |
addr_cnt = addr_cnt + 4; |
load_reg = wb_slave.wb_memory[{12'h0, addr_cnt}]; |
end |
// set new load bit position for Big ENDIAN Bytes (Litle ENDIAN bits) |
if(word_cnt == 31) |
word_cnt = 16; |
else if (word_cnt == 23) |
word_cnt = 8; |
else if (word_cnt == 15) |
word_cnt = 0; |
else if (word_cnt == 7) |
word_cnt = 24; |
else |
word_cnt = word_cnt + 1; |
// decrement bit counter |
bit_cnt = bit_cnt - 1; |
// wait for delta time |
delta_t = !delta_t; |
end // while |
|
// put CRC out |
crc = crc_shift_reg; |
#1; |
end |
endtask // serial_crc_mac |
|
////////////////////////////////////////////////////////////// |
// MIIM Basic tasks |
////////////////////////////////////////////////////////////// |
|
task reset_mii; // MII module |
reg [31:0] tmp; |
reg [31:0] tmp_no_rst; |
begin |
// read MII mode register first |
wbm_read(`ETH_MIIMODER, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// set reset bit - write back to MII mode register with RESET bit |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_RST | tmp), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// clear reset bit - write back to MII mode register without RESET bit |
tmp_no_rst = `ETH_MIIMODER_RST; |
tmp_no_rst = ~tmp_no_rst; |
wbm_write(`ETH_MIIMODER, (tmp_no_rst & tmp), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
endtask // reset_mii |
|
task mii_set_clk_div; // set clock divider for MII clock |
input [7:0] clk_div; |
begin |
// MII mode register |
wbm_write(`ETH_MIIMODER, (`ETH_MIIMODER_CLKDIV & clk_div), 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
endtask // mii_set_clk_div |
|
|
task check_mii_busy; // MII - check if BUSY |
reg [31:0] tmp; |
begin |
@(posedge wb_clk); |
// MII read status register |
wbm_read(`ETH_MIISTATUS, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
while(tmp[`ETH_MIISTATUS_BUSY] !== 1'b0) //`ETH_MIISTATUS_BUSY |
begin |
@(posedge wb_clk); |
wbm_read(`ETH_MIISTATUS, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
end |
endtask // check_mii_busy |
|
|
task check_mii_scan_valid; // MII - check if SCAN data are valid |
reg [31:0] tmp; |
begin |
@(posedge wb_clk); |
// MII read status register |
wbm_read(`ETH_MIISTATUS, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
while(tmp[`ETH_MIISTATUS_NVALID] !== 1'b0) //`ETH_MIISTATUS_NVALID |
begin |
@(posedge wb_clk); |
wbm_read(`ETH_MIISTATUS, tmp, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
end |
end |
endtask // check_mii_scan_valid |
|
|
task mii_write_req; // requests write to MII |
input [4:0] phy_addr; |
input [4:0] reg_addr; |
input [15:0] data_in; |
begin |
// MII address, PHY address = 1, command register address = 0 |
wbm_write(`ETH_MIIADDRESS, (`ETH_MIIADDRESS_FIAD & phy_addr) | (`ETH_MIIADDRESS_RGAD & (reg_addr << 8)), |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// MII TX data |
wbm_write(`ETH_MIITX_DATA, {16'h0000, data_in}, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// MII command |
wbm_write(`ETH_MIICOMMAND, `ETH_MIICOMMAND_WCTRLDATA, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge wb_clk); |
end |
endtask // mii_write_req |
|
|
task mii_read_req; // requests read from MII |
input [4:0] phy_addr; |
input [4:0] reg_addr; |
begin |
// MII address, PHY address = 1, command register address = 0 |
wbm_write(`ETH_MIIADDRESS, (`ETH_MIIADDRESS_FIAD & phy_addr) | (`ETH_MIIADDRESS_RGAD & (reg_addr << 8)), |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// MII command |
wbm_write(`ETH_MIICOMMAND, `ETH_MIICOMMAND_RSTAT, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge wb_clk); |
end |
endtask // mii_read_req |
|
|
task mii_scan_req; // requests scan from MII |
input [4:0] phy_addr; |
input [4:0] reg_addr; |
begin |
// MII address, PHY address = 1, command register address = 0 |
wbm_write(`ETH_MIIADDRESS, (`ETH_MIIADDRESS_FIAD & phy_addr) | (`ETH_MIIADDRESS_RGAD & (reg_addr << 8)), |
4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
// MII command |
wbm_write(`ETH_MIICOMMAND, `ETH_MIICOMMAND_SCANSTAT, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge wb_clk); |
end |
endtask // mii_scan_req |
|
|
task mii_scan_finish; // finish scan from MII |
begin |
// MII command |
wbm_write(`ETH_MIICOMMAND, 32'h0, 4'hF, 1, wbm_init_waits, wbm_subseq_waits); |
@(posedge wb_clk); |
end |
endtask // mii_scan_finish |
|
////////////////////////////////////////////////////////////// |
// Log files and memory tasks |
////////////////////////////////////////////////////////////// |
|
task clear_memories; |
reg [22:0] adr_i; |
reg delta_t; |
begin |
delta_t = 0; |
for (adr_i = 0; adr_i < 4194304; adr_i = adr_i + 1) |
begin |
eth_phy.rx_mem[adr_i[21:0]] = 0; |
eth_phy.tx_mem[adr_i[21:0]] = 0; |
wb_slave.wb_memory[adr_i[21:2]] = 0; |
delta_t = !delta_t; |
end |
end |
endtask // clear_memories |
|
task test_note; |
input [799:0] test_note ; |
reg [799:0] display_note ; |
begin |
display_note = test_note; |
while ( display_note[799:792] == 0 ) |
display_note = display_note << 8 ; |
$fdisplay( tb_log_file, " " ) ; |
$fdisplay( tb_log_file, "NOTE: %s", display_note ) ; |
$fdisplay( tb_log_file, " " ) ; |
end |
endtask // test_note |
|
task test_heading; |
input [799:0] test_heading ; |
reg [799:0] display_test ; |
begin |
display_test = test_heading; |
while ( display_test[799:792] == 0 ) |
display_test = display_test << 8 ; |
$fdisplay( tb_log_file, " ***************************************************************************************" ) ; |
$fdisplay( tb_log_file, " ***************************************************************************************" ) ; |
$fdisplay( tb_log_file, " Heading: %s", display_test ) ; |
$fdisplay( tb_log_file, " ***************************************************************************************" ) ; |
$fdisplay( tb_log_file, " ***************************************************************************************" ) ; |
$fdisplay( tb_log_file, " " ) ; |
end |
endtask // test_heading |
|
|
task test_fail ; |
input [7999:0] failure_reason ; |
// reg [8007:0] display_failure ; |
reg [7999:0] display_failure ; |
reg [799:0] display_test ; |
begin |
tests_failed = tests_failed + 1 ; |
|
display_failure = failure_reason; // {failure_reason, "!"} ; |
while ( display_failure[7999:7992] == 0 ) |
display_failure = display_failure << 8 ; |
|
display_test = test_name ; |
while ( display_test[799:792] == 0 ) |
display_test = display_test << 8 ; |
|
$fdisplay( tb_log_file, " *************************************************************************************" ) ; |
$fdisplay( tb_log_file, " At time: %t ", $time ) ; |
$fdisplay( tb_log_file, " Test: %s", display_test ) ; |
$fdisplay( tb_log_file, " *FAILED* because") ; |
$fdisplay( tb_log_file, " %s", display_failure ) ; |
$fdisplay( tb_log_file, " *************************************************************************************" ) ; |
$fdisplay( tb_log_file, " " ) ; |
|
`ifdef STOP_ON_FAILURE |
#20 $stop ; |
`endif |
end |
endtask // test_fail |
|
|
task test_ok ; |
reg [799:0] display_test ; |
begin |
tests_successfull = tests_successfull + 1 ; |
|
display_test = test_name ; |
while ( display_test[799:792] == 0 ) |
display_test = display_test << 8 ; |
|
$fdisplay( tb_log_file, " *************************************************************************************" ) ; |
$fdisplay( tb_log_file, " At time: %t ", $time ) ; |
$fdisplay( tb_log_file, " Test: %s", display_test ) ; |
$fdisplay( tb_log_file, " reported *SUCCESSFULL*! ") ; |
$fdisplay( tb_log_file, " *************************************************************************************" ) ; |
$fdisplay( tb_log_file, " " ) ; |
end |
endtask // test_ok |
|
|
task test_summary; |
begin |
$fdisplay(tb_log_file, "**************************** Ethernet MAC test summary **********************************") ; |
$fdisplay(tb_log_file, "Tests performed: %d", tests_successfull + tests_failed) ; |
$fdisplay(tb_log_file, "Failed tests : %d", tests_failed) ; |
$fdisplay(tb_log_file, "Successfull tests: %d", tests_successfull) ; |
$fdisplay(tb_log_file, "**************************** Ethernet MAC test summary **********************************") ; |
$fclose(tb_log_file) ; |
end |
endtask // test_summary |
|
|
endmodule |
/trunk/bench/verilog/wb_model_defines.v
0,0 → 1,100
// WISHBONE frequency in GHz |
`define WB_FREQ 0.100 |
|
// memory frequency in GHz |
`define MEM_FREQ 0.100 |
|
// setup and hold time definitions for WISHBONE - used in BFMs for signal generation |
`define Tsetup 4 |
`define Thold 1 |
|
// how many clock cycles should model wait for design's response - integer 32 bit value |
`define WAIT_FOR_RESPONSE 1023 |
|
// maximum number of transactions allowed in single call to block or cab transfer routines |
`define MAX_BLK_SIZE 1024 |
|
// maximum retry terminations allowed for WISHBONE master to repeat an access |
`define WB_TB_MAX_RTY 0 |
|
|
// some common types and defines |
`define WB_ADDR_WIDTH 32 |
`define WB_DATA_WIDTH 32 |
`define WB_SEL_WIDTH `WB_DATA_WIDTH/8 |
`define WB_TAG_WIDTH 1 |
`define WB_ADDR_TYPE [(`WB_ADDR_WIDTH - 1):0] |
`define WB_DATA_TYPE [(`WB_DATA_WIDTH - 1):0] |
`define WB_SEL_TYPE [(`WB_SEL_WIDTH - 1):0] |
`define WB_TAG_TYPE [(`WB_TAG_WIDTH - 1):0] |
|
// read cycle stimulus - consists of: |
// - address field - which address read will be performed from |
// - sel field - what byte select value should be |
// - tag field - what tag values should be put on the bus |
`define READ_STIM_TYPE [(`WB_ADDR_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH - 1):0] |
`define READ_STIM_LENGTH (`WB_ADDR_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH) |
`define READ_ADDRESS [(`WB_ADDR_WIDTH - 1):0] |
`define READ_SEL [(`WB_ADDR_WIDTH + `WB_SEL_WIDTH - 1):`WB_ADDR_WIDTH] |
`define READ_TAG_STIM [(`WB_ADDR_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH - 1):(`WB_ADDR_WIDTH + `WB_SEL_WIDTH)] |
|
// read cycle return type consists of: |
// - read data field |
// - tag field received from WISHBONE |
// - wishbone slave response fields - ACK, ERR and RTY |
// - test bench error indicator (when testcase has not used wb master model properly) |
// - how much data was actually transfered |
`define READ_RETURN_TYPE [(32 + 4 + `WB_DATA_WIDTH + `WB_TAG_WIDTH - 1):0] |
`define READ_DATA [(32 + `WB_DATA_WIDTH + 4 - 1):32 + 4] |
`define READ_TAG_RET [(32 + 4 + `WB_DATA_WIDTH + `WB_TAG_WIDTH - 1):(`WB_DATA_WIDTH + 32 + 4)] |
`define READ_RETURN_LENGTH (32 + 4 + `WB_DATA_WIDTH + `WB_TAG_WIDTH - 1) |
|
// write cycle stimulus type consists of |
// - address field |
// - data field |
// - sel field |
// - tag field |
`define WRITE_STIM_TYPE [(`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH - 1):0] |
`define WRITE_ADDRESS [(`WB_ADDR_WIDTH - 1):0] |
`define WRITE_DATA [(`WB_ADDR_WIDTH + `WB_DATA_WIDTH - 1):`WB_ADDR_WIDTH] |
`define WRITE_SEL [(`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH - 1):(`WB_ADDR_WIDTH + `WB_DATA_WIDTH)] |
`define WRITE_TAG_STIM [(`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH - 1):(`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH)] |
|
// length of WRITE_STIMULUS |
`define WRITE_STIM_LENGTH (`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH) |
|
// write cycle return type consists of: |
// - test bench error indicator (when testcase has not used wb master model properly) |
// - wishbone slave response fields - ACK, ERR and RTY |
// - tag field received from WISHBONE |
// - how much data was actually transfered |
`define WRITE_RETURN_TYPE [(32 + 4 + `WB_TAG_WIDTH - 1):0] |
`define WRITE_TAG_RET [(32 + 4 + `WB_TAG_WIDTH - 1):32 + 4] |
|
// this four fields are common to both read and write routines return values |
`define TB_ERROR_BIT [0] |
`define CYC_ACK [1] |
`define CYC_RTY [2] |
`define CYC_ERR [3] |
`define CYC_RESPONSE [3:1] |
`define CYC_ACTUAL_TRANSFER [35:4] |
|
// block transfer flags |
`define WB_TRANSFER_FLAGS [41:0] |
// consists of: |
// - number of transfer cycles to perform |
// - flag that enables retry termination handling - if disabled, block transfer routines will return on any termination other than acknowledge |
// - flag indicating CAB transfer is to be performed - ignored by all single transfer routines |
// - number of initial wait states to insert |
// - number of subsequent wait states to insert |
`define WB_TRANSFER_SIZE [41:10] |
`define WB_TRANSFER_AUTO_RTY [8] |
`define WB_TRANSFER_CAB [9] |
`define INIT_WAITS [3:0] |
`define SUBSEQ_WAITS [7:4] |
|
// wb slave response |
`define ACK_RESPONSE 3'b100 |
`define ERR_RESPONSE 3'b010 |
`define RTY_RESPONSE 3'b001 |
`define NO_RESPONSE 3'b000 |
/trunk/bench/verilog/wb_master32.v
0,0 → 1,371
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name "wb_master32.v" //// |
//// //// |
//// This file is part of the "PCI bridge" project //// |
//// http://www.opencores.org/cores/pci/ //// |
//// //// |
//// Author(s): //// |
//// - Miha Dolenc (mihad@opencores.org) //// |
//// //// |
//// All additional information is avaliable in the README.pdf //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001 Miha Dolenc, mihad@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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.1 2002/07/29 11:25:20 mihad |
// Adding test bench for memory interface |
// |
// Revision 1.1 2002/02/01 13:39:43 mihad |
// Initial testbench import. Still under development |
// |
// |
|
`include "wb_model_defines.v" |
`include "timescale.v" |
module WB_MASTER32 |
( |
CLK_I, |
RST_I, |
TAG_I, |
TAG_O, |
ACK_I, |
ADR_O, |
CYC_O, |
DAT_I, |
DAT_O, |
ERR_I, |
RTY_I, |
SEL_O, |
STB_O, |
WE_O, |
CAB_O |
); |
|
input CLK_I; |
input RST_I; |
input `WB_TAG_TYPE TAG_I; |
output `WB_TAG_TYPE TAG_O; |
input ACK_I; |
output `WB_ADDR_TYPE ADR_O; |
output CYC_O; |
input `WB_DATA_TYPE DAT_I; |
output `WB_DATA_TYPE DAT_O; |
input ERR_I; |
input RTY_I; |
output `WB_SEL_TYPE SEL_O; |
output STB_O; |
output WE_O; |
output CAB_O ; |
|
// period length |
real Tp ; |
|
reg `WB_ADDR_TYPE ADR_O; |
reg `WB_SEL_TYPE SEL_O; |
reg `WB_TAG_TYPE TAG_O; |
reg CYC_O; |
reg WE_O; |
reg `WB_DATA_TYPE DAT_O; |
reg CAB_O ; |
reg STB_O ; |
|
// variable used for indication on whether cycle was already started |
reg in_use ; |
|
// because of non-blocking assignments CYC_O is not sufficient indicator for cycle starting - this var is used in its place |
reg cycle_in_progress ; |
|
// same goes for CAB_O signal |
reg cab ; |
|
reg we ; |
|
task start_cycle ; |
input is_cab ; |
input write ; |
output ok ; // ok indicates to the caller that cycle was started succesfully - if not, caller must take appropriate action |
begin:main |
|
ok = 1 ; |
|
// just check if valid value is provided for CAB_O signal (no x's or z's allowed) |
if ( (is_cab !== 1'b0) && (is_cab !== 1'b1) ) |
begin |
$display("*E, invalid CAB value for cycle! Requested CAB_O value = %b, Time %t ", is_cab, $time) ; |
ok = 0 ; |
disable main ; |
end |
|
if ( (cycle_in_progress === 1) || (CYC_O === 1)) |
begin |
// cycle was previously started - allow cycle to continue if CAB and WE values match |
$display("*W, cycle already in progress when start_cycle routine was called! Time %t ", $time) ; |
if ((CAB_O !== is_cab) || (WE_O !== write) ) |
begin |
ok = 0 ; |
if ( is_cab === 1 ) |
$display("*E, cab cycle start attempted when non-cab cycle was in progress! Time %t", $time) ; |
else |
$display("*E, non-cab cycle start attempted when cab cycle was in progress! Time %t", $time) ; |
|
if ( we === 1 ) |
$display("*E, write cycle start attempted when read cycle was in progress! Time %t", $time) ; |
else |
$display("*E, read cycle start attempted when write cycle was in progress! Time %t", $time) ; |
|
disable main ; |
end |
end |
|
CYC_O <= #(Tp - `Tsetup) 1'b1 ; |
CAB_O <= #(Tp - `Tsetup) is_cab ; |
WE_O <= #(Tp - `Tsetup) write ; |
|
// this non-blocking assignments are made to internal variables, so read and write tasks can be called immediately after cycle start task |
cycle_in_progress = 1'b1 ; |
cab = is_cab ; |
we = write ; |
end |
endtask //start_cycle |
|
task end_cycle ; |
begin |
if ( CYC_O !== 1'b1 ) |
$display("*W, end_cycle routine called when CYC_O value was %b! Time %t ", CYC_O, $time) ; |
|
CYC_O <= #`Thold 1'b0 ; |
CAB_O <= #`Thold 1'b0 ; |
cycle_in_progress = 1'b0 ; |
end |
endtask //end_cycle |
|
task modify_cycle ; |
begin |
if ( CYC_O !== 1'b1 ) |
$display("*W, modify_cycle routine called when CYC_O value was %b! Time %t ", CYC_O, $time) ; |
|
we = ~we ; |
WE_O <= #(Tp - `Tsetup) we ; |
end |
endtask //modify_cycle |
|
task wbm_read ; |
input `READ_STIM_TYPE input_data ; |
inout `READ_RETURN_TYPE output_data ; |
reg `WB_ADDR_TYPE address ; |
reg `WB_DATA_TYPE data ; |
reg `WB_SEL_TYPE sel ; |
reg `WB_TAG_TYPE tag ; |
integer num_of_cyc ; |
begin:main |
output_data`TB_ERROR_BIT = 1'b0 ; |
|
// check if task was called before previous call to read or write finished |
if ( in_use === 1 ) |
begin |
$display("*E, wbm_read routine re-entered or called concurently with write routine! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if ( cycle_in_progress !== 1 ) |
begin |
$display("*E, wbm_read routine called without start_cycle routine being called first! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if ( we !== 0 ) |
begin |
$display("*E, wbm_read routine called after write cycle was started! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// this branch contains timing controls - claim the use of WISHBONE |
in_use = 1 ; |
|
num_of_cyc = `WAIT_FOR_RESPONSE ; |
|
// assign data outputs |
ADR_O <= #(Tp - `Tsetup) input_data`READ_ADDRESS ; |
SEL_O <= #(Tp - `Tsetup) input_data`READ_SEL ; |
TAG_O <= #(Tp - `Tsetup) input_data`READ_TAG_STIM ; |
|
// assign control output |
STB_O <= #(Tp - `Tsetup) 1'b1 ; |
|
output_data`CYC_ACK = 0 ; |
output_data`CYC_RTY = 0 ; |
output_data`CYC_ERR = 0 ; |
|
@(posedge CLK_I) ; |
output_data`CYC_ACK = ACK_I ; |
output_data`CYC_RTY = RTY_I ; |
output_data`CYC_ERR = ERR_I ; |
|
while ( (num_of_cyc > 0) && (output_data`CYC_RESPONSE === 0) ) |
begin |
@(posedge CLK_I) ; |
output_data`CYC_ACK = ACK_I ; |
output_data`CYC_RTY = RTY_I ; |
output_data`CYC_ERR = ERR_I ; |
num_of_cyc = num_of_cyc - 1 ; |
end |
|
output_data`READ_DATA = DAT_I ; |
output_data`READ_TAG_RET = TAG_I ; |
|
if ( output_data`CYC_RESPONSE === 0 ) |
begin |
|
$display("*W, Terminating read cycle because no response was received in %d cycles! Time %t ", `WAIT_FOR_RESPONSE, $time) ; |
end |
|
if ( output_data`CYC_ACK === 1 && output_data`CYC_RTY === 0 && output_data`CYC_ERR === 0 ) |
output_data`CYC_ACTUAL_TRANSFER = output_data`CYC_ACTUAL_TRANSFER + 1 ; |
|
STB_O <= #`Thold 1'b0 ; |
ADR_O <= #`Thold {`WB_ADDR_WIDTH{1'bx}} ; |
SEL_O <= #`Thold {`WB_SEL_WIDTH{1'bx}} ; |
TAG_O <= #`Thold {`WB_TAG_WIDTH{1'bx}} ; |
|
in_use = 0 ; |
end |
endtask // wbm_read |
|
task wbm_write ; |
input `WRITE_STIM_TYPE input_data ; |
inout `WRITE_RETURN_TYPE output_data ; |
reg `WB_ADDR_TYPE address ; |
reg `WB_DATA_TYPE data ; |
reg `WB_SEL_TYPE sel ; |
reg `WB_TAG_TYPE tag ; |
integer num_of_cyc ; |
begin:main |
output_data`TB_ERROR_BIT = 1'b0 ; |
|
// check if task was called before previous call to read or write finished |
if ( in_use === 1 ) |
begin |
$display("*E, wbm_write routine re-entered or called concurently with read routine! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if ( cycle_in_progress !== 1 ) |
begin |
$display("*E, wbm_write routine called without start_cycle routine being called first! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if ( we !== 1 ) |
begin |
$display("*E, wbm_write routine after read cycle was started! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// this branch contains timing controls - claim the use of WISHBONE |
in_use = 1 ; |
|
num_of_cyc = `WAIT_FOR_RESPONSE ; |
|
ADR_O <= #(Tp - `Tsetup) input_data`WRITE_ADDRESS ; |
DAT_O <= #(Tp - `Tsetup) input_data`WRITE_DATA ; |
SEL_O <= #(Tp - `Tsetup) input_data`WRITE_SEL ; |
TAG_O <= #(Tp - `Tsetup) input_data`WRITE_TAG_STIM ; |
|
STB_O <= #(Tp - `Tsetup) 1'b1 ; |
|
output_data`CYC_ACK = 0 ; |
output_data`CYC_RTY = 0 ; |
output_data`CYC_ERR = 0 ; |
|
@(posedge CLK_I) ; |
output_data`CYC_ACK = ACK_I ; |
output_data`CYC_RTY = RTY_I ; |
output_data`CYC_ERR = ERR_I ; |
|
while ( (num_of_cyc > 0) && (output_data`CYC_RESPONSE === 0) ) |
begin |
@(posedge CLK_I) ; |
output_data`CYC_ACK = ACK_I ; |
output_data`CYC_RTY = RTY_I ; |
output_data`CYC_ERR = ERR_I ; |
num_of_cyc = num_of_cyc - 1 ; |
end |
|
output_data`WRITE_TAG_RET = TAG_I ; |
if ( output_data`CYC_RESPONSE === 0 ) |
begin |
$display("*W, Terminating write cycle because no response was received in %d cycles! Time %t ", `WAIT_FOR_RESPONSE, $time) ; |
end |
|
if ( output_data`CYC_ACK === 1 && output_data`CYC_RTY === 0 && output_data`CYC_ERR === 0 ) |
output_data`CYC_ACTUAL_TRANSFER = output_data`CYC_ACTUAL_TRANSFER + 1 ; |
|
ADR_O <= #`Thold {`WB_ADDR_WIDTH{1'bx}} ; |
DAT_O <= #`Thold {`WB_DATA_WIDTH{1'bx}} ; |
SEL_O <= #`Thold {`WB_SEL_WIDTH{1'bx}} ; |
TAG_O <= #`Thold {`WB_TAG_WIDTH{1'bx}} ; |
|
STB_O <= #`Thold 1'b0 ; |
|
in_use = 0 ; |
end |
endtask //wbm_write |
|
initial |
begin |
Tp = 1 / `WB_FREQ ; |
in_use = 0 ; |
cycle_in_progress = 0 ; |
cab = 0 ; |
ADR_O <= {`WB_ADDR_WIDTH{1'bx}} ; |
DAT_O <= {`WB_DATA_WIDTH{1'bx}} ; |
SEL_O <= {`WB_SEL_WIDTH{1'bx}} ; |
TAG_O <= {`WB_TAG_WIDTH{1'bx}} ; |
CYC_O <= 1'b0 ; |
STB_O <= 1'b0 ; |
CAB_O <= 1'b0 ; |
WE_O <= 1'b0 ; |
if ( `Tsetup > Tp || `Thold >= Tp ) |
begin |
$display("Either Tsetup or Thold values for WISHBONE BFMs are too large!") ; |
$stop ; |
end |
end |
|
endmodule |
/trunk/bench/verilog/wb_bus_mon.v
0,0 → 1,395
////////////////////////////////////////////////////////////////////// |
//// //// |
//// File name "wb_bus_mon.v" //// |
//// //// |
//// This file is part of the "PCI bridge" project //// |
//// http://www.opencores.org/cores/pci/ //// |
//// //// |
//// Author(s): //// |
//// - mihad@opencores.org //// |
//// - Miha Dolenc //// |
//// //// |
//// All additional information is avaliable in the README.pdf //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001 Miha Dolenc, mihad@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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.1 2002/02/01 13:39:43 mihad |
// Initial testbench import. Still under development |
// |
// Revision 1.1 2001/08/06 18:12:58 mihad |
// Pocasi delamo kompletno zadevo |
// |
// |
|
`include "wb_model_defines.v" |
// WISHBONE bus monitor module - it connects to WISHBONE master signals and |
// monitors for any illegal combinations appearing on the bus. |
module WB_BUS_MON( |
CLK_I, |
RST_I, |
ACK_I, |
ADDR_O, |
CYC_O, |
DAT_I, |
DAT_O, |
ERR_I, |
RTY_I, |
SEL_O, |
STB_O, |
WE_O, |
TAG_I, |
TAG_O, |
CAB_O, |
log_file_desc |
) ; |
|
input CLK_I ; |
input RST_I ; |
input ACK_I ; |
input [(`WB_ADDR_WIDTH-1):0] ADDR_O ; |
input CYC_O ; |
input [(`WB_DATA_WIDTH-1):0] DAT_I ; |
input [(`WB_DATA_WIDTH-1):0] DAT_O ; |
input ERR_I ; |
input RTY_I ; |
input [(`WB_SEL_WIDTH-1):0] SEL_O ; |
input STB_O ; |
input WE_O ; |
input [(`WB_TAG_WIDTH-1):0] TAG_I ; |
input [(`WB_TAG_WIDTH-1):0] TAG_O ; |
input CAB_O ; |
input [31:0] log_file_desc ; |
|
always@(posedge CLK_I or posedge RST_I) |
begin |
if (RST_I) |
begin |
// when reset is applied, all control signals must be low |
if (CYC_O) |
begin |
$display("*E (%0t) CYC_O active under reset", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)CYC_O active under reset", $time) ; |
end |
if (STB_O) |
begin |
$display("*E (%0t) STB_O active under reset", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)STB_O active under reset", $time) ; |
end |
/*if (ACK_I) |
$display("ACK_I active under reset") ;*/ |
if (ERR_I) |
begin |
$display("*E (%0t) ERR_I active under reset", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)ERR_I active under reset", $time) ; |
end |
if (RTY_I) |
begin |
$display("*E (%0t) RTY_I active under reset", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)RTY_I active under reset", $time) ; |
end |
if (CAB_O) |
begin |
$display("*E (%0t) CAB_O active under reset", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)CAB_O active under reset", $time) ; |
end |
end // reset |
else |
if (~CYC_O) |
begin |
// when cycle indicator is low, all control signals must be low |
if (STB_O) |
begin |
$display("*E (%0t) STB_O active without CYC_O being active", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)STB_O active without CYC_O being active", $time) ; |
end |
if (ACK_I) |
begin |
$display("*E (%0t) ACK_I active without CYC_O being active", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)ACK_I active without CYC_O being active", $time) ; |
end |
if (ERR_I) |
begin |
$display("*E (%0t) ERR_I active without CYC_O being active", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)ERR_I active without CYC_O being active", $time) ; |
end |
if (RTY_I) |
begin |
$display("*E (%0t) RTY_I active without CYC_O being active", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)RTY_I active without CYC_O being active", $time) ; |
end |
if (CAB_O) |
begin |
$display("*E (%0t) CAB_O active without CYC_O being active", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)CAB_O active without CYC_O being active", $time) ; |
end |
end // ~CYC_O |
end |
|
reg [`WB_DATA_WIDTH-1:0] previous_data ; |
reg [`WB_ADDR_WIDTH-1:0] previous_address ; |
reg [`WB_SEL_WIDTH-1:0] previous_sel ; |
reg previous_stb ; |
reg previous_ack ; |
reg previous_err ; |
reg previous_rty ; |
reg previous_cyc ; |
reg can_change ; |
|
always@(posedge CLK_I or posedge RST_I) |
begin |
if (RST_I) |
begin |
previous_stb <= 1'b0 ; |
previous_ack <= 1'b0 ; |
previous_err <= 1'b0 ; |
previous_rty <= 1'b0 ; |
previous_cyc <= 1'b0 ; |
end |
else |
begin |
previous_stb <= STB_O ; |
previous_ack <= ACK_I ; |
previous_err <= ERR_I ; |
previous_rty <= RTY_I ; |
previous_cyc <= CYC_O ; |
end |
end |
|
// cycle monitor |
always@(posedge CLK_I) |
begin |
if (CYC_O && ~RST_I) // cycle in progress |
begin |
if (STB_O) |
begin |
// check for two control signals active at same edge |
if ( ACK_I && RTY_I ) |
begin |
$display("*E (%0t) ACK_I and RTY_I asserted at the same time during cycle", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)ACK_I and RTY_I asserted at the same time during cycle", $time) ; |
end |
if ( ACK_I && ERR_I ) |
begin |
$display("*E (%0t) ACK_I and ERR_I asserted at the same time during cycle", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)ACK_I and ERR_I asserted at the same time during cycle", $time) ; |
end |
if ( RTY_I && ERR_I ) |
begin |
$display("*E (%0t) RTY_I and ERR_I asserted at the same time during cycle", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)RTY_I and ERR_I asserted at the same time during cycle", $time) ; |
end |
|
if ( can_change !== 1 ) |
begin |
if ( ADDR_O !== previous_address ) |
begin |
$display("*E (%0t) WB bus monitor detected address change in the middle of the cycle!", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)WB bus monitor detected address change in the middle of the cycle!", $time) ; |
end |
|
if ( SEL_O !== previous_sel ) |
begin |
$display("*E (%0t) WB bus monitor detected select lines changed in the middle of the cycle!", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)WB bus monitor detected select lines changed in the middle of the cycle!", $time) ; |
end |
|
if ( (WE_O !== 0) && ( DAT_O !== previous_data ) ) |
begin |
$display("*E (%0t) WB bus monitor detected data lines changed in the middle of the cycle!", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)WB bus monitor detected data lines changed in the middle of the cycle!", $time) ; |
end |
end |
|
if ( ACK_I || RTY_I || ERR_I ) |
can_change = 1 ; |
else |
begin |
previous_data = DAT_O ; |
previous_address = ADDR_O ; |
previous_sel = SEL_O ; |
can_change = 0 ; |
end |
|
end // STB_O |
else |
begin //~STB_O |
// while STB_O is inactive, only ACK_I is allowed to be active |
if ( ERR_I ) |
begin |
$display("*E (%0t) ERR_I asserted during cycle without STB_O", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)ERR_I asserted during cycle without STB_O", $time) ; |
end |
if ( RTY_I ) |
begin |
$display("*E (%0t) RTY_I asserted during cycle without STB_O", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)RTY_I asserted during cycle without STB_O", $time) ; |
end |
|
if ((previous_ack !== 1) && (previous_err !== 1) && (previous_rty !== 1) && (previous_stb !== 0)) |
begin |
$display("STB_O de-asserted without reception of slave response") ; |
$fdisplay(log_file_desc, "STB_O de-asserted without reception of slave response") ; |
end |
|
can_change = 1 ; |
end // ~STB_O |
end // cycle in progress |
else if (!RST_I) |
begin |
// cycle not in progress anymore |
can_change = 1 ; |
if ((previous_ack !== 1) && (previous_err !== 1) && (previous_rty !== 1) && (previous_stb !== 0)) |
begin |
$display("STB_O de-asserted without reception of slave response") ; |
$fdisplay(log_file_desc, "STB_O de-asserted without reception of slave response") ; |
end |
end |
end // cycle monitor |
|
// CAB_O monitor - CAB_O musn't change during one cycle |
reg [1:0] first_cab_val ; |
always@(posedge CLK_I or RST_I) |
begin |
if ((CYC_O === 0) || RST_I) |
first_cab_val <= 2'b00 ; |
else |
begin |
// cycle in progress - is this first clock edge in a cycle ? |
if (first_cab_val[1] === 1'b0) |
first_cab_val <= {1'b1, CAB_O} ; |
else if ( first_cab_val[0] !== CAB_O ) |
begin |
$display("*E (%0t) CAB_O value changed during cycle", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)CAB_O value changed during cycle", $time) ; |
end |
end |
end // CAB_O monitor |
|
// WE_O monitor for consecutive address bursts |
reg [1:0] first_we_val ; |
always@(posedge CLK_I or posedge RST_I) |
begin |
if (~CYC_O || ~CAB_O || RST_I) |
first_we_val <= 2'b00 ; |
else |
if (STB_O) |
begin |
// cycle in progress - is this first clock edge in a cycle ? |
if (first_we_val[1] == 1'b0) |
first_we_val <= {1'b1, WE_O} ; |
else if ( first_we_val[0] != WE_O ) |
begin |
$display("*E (%0t) WE_O value changed during CAB cycle", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)WE_O value changed during CAB cycle", $time) ; |
end |
end |
end // CAB_O monitor |
|
// address monitor for consecutive address bursts |
reg [`WB_ADDR_WIDTH:0] address ; |
always@(posedge CLK_I or posedge RST_I) |
begin |
if (~CYC_O || ~CAB_O || RST_I) |
address <= {(`WB_ADDR_WIDTH + 1){1'b0}} ; |
else |
begin |
if (STB_O && ACK_I) |
begin |
if (address[`WB_ADDR_WIDTH] == 1'b0) |
address <= {1'b1, (ADDR_O + `WB_SEL_WIDTH)} ; |
else |
begin |
if ( address[(`WB_ADDR_WIDTH-1):0] != ADDR_O) |
begin |
$display("*E (%0t) Consecutive address burst address incrementing incorrect", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)Consecutive address burst address incrementing incorrect", $time) ; |
end |
else |
address <= {1'b1, (ADDR_O + `WB_SEL_WIDTH)} ; |
end |
end |
end |
end // address monitor |
|
// data monitor |
always@(posedge CLK_I or posedge RST_I) |
begin |
if (CYC_O && STB_O && ~RST_I) |
begin |
if ( ((^ADDR_O) !== 1'b1) && ((^ADDR_O) !== 1'b0) ) |
begin |
$display("*E (%0t) Master provided invalid address and qualified it with STB_O", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)Master provided invalid address and qualified it with STB_O", $time) ; |
end |
if ( WE_O ) |
begin |
if ( |
(SEL_O[0] && (((^DAT_O[7:0]) !== 1'b0) && ((^DAT_O[7:0]) !== 1'b1))) || |
(SEL_O[1] && (((^DAT_O[15:8]) !== 1'b0) && ((^DAT_O[15:8]) !== 1'b1))) || |
(SEL_O[2] && (((^DAT_O[23:16]) !== 1'b0) && ((^DAT_O[23:16]) !== 1'b1))) || |
(SEL_O[3] && (((^DAT_O[31:24]) !== 1'b0) && ((^DAT_O[31:24]) !== 1'b1))) |
) |
begin |
$display("*E (%0t) Master provided invalid data during write and qualified it with STB_O", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)Master provided invalid data during write and qualified it with STB_O", $time) ; |
$display("*E (%0t) Byte select value: SEL_O = %b, Data bus value: DAT_O = %h ", $time, SEL_O, DAT_O) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)Byte select value: SEL_O = %b, Data bus value: DAT_O = %h ", $time, SEL_O, DAT_O) ; |
end |
|
end |
else |
if (~WE_O && ACK_I) |
begin |
if ( |
(SEL_O[0] && (((^DAT_I[7:0]) !== 1'b0) && ((^DAT_I[7:0]) !== 1'b1))) || |
(SEL_O[1] && (((^DAT_I[15:8]) !== 1'b0) && ((^DAT_I[15:8]) !== 1'b1))) || |
(SEL_O[2] && (((^DAT_I[23:16]) !== 1'b0) && ((^DAT_I[23:16]) !== 1'b1))) || |
(SEL_O[3] && (((^DAT_I[31:24]) !== 1'b0) && ((^DAT_I[31:24]) !== 1'b1))) |
) |
begin |
$display("*E (%0t) Slave provided invalid data during read and qualified it with ACK_I", $time) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)Slave provided invalid data during read and qualified it with ACK_I", $time) ; |
$display("*E (%0t) Byte select value: SEL_O = %b, Data bus value: DAT_I = %h ", $time, SEL_O, DAT_I) ; |
$fdisplay(log_file_desc, "*E (%0t)(%m)Byte select value: SEL_O = %b, Data bus value: DAT_I = %h ", $time, SEL_O, DAT_I) ; |
end |
end |
end |
end |
|
initial |
begin |
previous_data = 0 ; |
previous_address = 0 ; |
can_change = 1 ; |
end |
endmodule // BUS_MON |