📄 eth_phy.v
字号:
reg [31:0] tx_len_err;
// TX control
always@(posedge mtx_clk_o)
begin
// storing data and basic checking of frame
if (!m_rst_n_i)
begin
tx_cnt <= 0;
tx_preamble_ok <= 0;
tx_sfd_ok <= 0;
tx_len <= 0;
tx_len_err <= 0;
end
else
begin
if (!mtxen_i)
begin
tx_cnt <= 0;
end
else
begin
// tx nibble counter
tx_cnt <= tx_cnt + 1;
// set initial values and check first preamble nibble
if (tx_cnt == 0)
begin
`ifdef 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_len_err <= 0;
// tx_mem_addr_in <= 0;
end
// check preamble
if ((tx_cnt > 0) && (tx_cnt <= 13))
begin
if ((tx_preamble_ok != 1) || (mtxd_i != 4'h5))
tx_preamble_ok <= 0;
end
// check SFD
if (tx_cnt == 14)
begin
`ifdef 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
if (mtxerr_i)
tx_len_err <= tx_len;
end
end
end
// generating CARRIER SENSE for TX with or without delay
if (!m_rst_n_i)
begin
mcrs_tx <= 0;
mtxen_d1 <= 0;
mtxen_d2 <= 0;
mtxen_d3 <= 0;
mtxen_d4 <= 0;
mtxen_d5 <= 0;
mtxen_d6 <= 0;
end
else
begin
mtxen_d1 <= mtxen_i;
mtxen_d2 <= mtxen_d1;
mtxen_d3 <= mtxen_d2;
mtxen_d4 <= mtxen_d3;
mtxen_d5 <= mtxen_d4;
mtxen_d6 <= mtxen_d5;
if (real_carrier_sense)
mcrs_tx <= mtxen_d6;
else
mcrs_tx <= mtxen_i;
end
end
`ifdef 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*8)-1:0] preamble_data; // preamble data to be sent - correct is 64'h0055_5555_5555_5555
input [3:0] preamble_len; // length of preamble in bytes - max is 4'h8, correct is 4'h7
input [7:0] sfd_data; // SFD data to be sent - correct is 8'hD5
input [31:0] start_addr; // start address
input [31:0] len; // length of frame in Bytes (without preamble and SFD)
input plus_drible_nibble; // if length is longer for one nibble
integer rx_cnt;
reg [31:0] rx_mem_addr_in; // address for reading from RX memory
reg [7:0] rx_mem_data_out; // data for reading from RX memory
begin
@(posedge mrx_clk_o);
// generating CARRIER SENSE for TX with or without delay
if (real_carrier_sense)
#1 mcrs_rx = 1;
else
#1 mcrs_rx = 0;
@(posedge mrx_clk_o);
#1 mcrs_rx = 1;
#1 mrxdv_o = 1;
`ifdef 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 << 1)) && (rx_cnt < 16); rx_cnt = rx_cnt + 1)
begin
#1 mrxd_o = preamble_data[3:0];
#1 preamble_data = preamble_data >> 4;
@(posedge mrx_clk_o);
end
// send SFD
for (rx_cnt = 0; rx_cnt < 2; rx_cnt = rx_cnt + 1)
begin
#1 mrxd_o = sfd_data[3:0];
#1 sfd_data = sfd_data >> 4;
@(posedge mrx_clk_o);
end
`ifdef 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
#1;
rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]];
mrxd_o = rx_mem_data_out[3:0];
@(posedge mrx_clk_o);
#1;
mrxd_o = rx_mem_data_out[7:4];
rx_mem_addr_in = rx_mem_addr_in + 1;
@(posedge mrx_clk_o);
#1;
end
if (plus_drible_nibble)
begin
rx_mem_data_out = rx_mem[rx_mem_addr_in[21:0]];
mrxd_o = rx_mem_data_out[3:0];
@(posedge mrx_clk_o);
end
`ifdef VERBOSE
$fdisplay(phy_log, " (%0t)(%m) RX frame addresses, type/length, data and FCS sent!", $time);
`endif
#1 mcrs_rx = 0;
#1 mrxdv_o = 0;
@(posedge mrx_clk_o);
`ifdef 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
// Carrier sense lost - higher priority than Carrier sense task
task carrier_sense_lost;
input test_op;
begin
#1 task_mcrs_lost = test_op;
end
endtask
// No collision detection in half duplex
task no_collision_hd_detect;
input test_op;
begin
#1 no_collision_in_half_duplex = test_op;
end
endtask
// Collision detection in full duplex also
task collision_fd_detect;
input test_op;
begin
#1 collision_in_full_duplex = test_op;
end
endtask
// No carrier sense detection at TX in half duplex
task no_carrier_sense_tx_hd_detect;
input test_op;
begin
#1 no_carrier_sense_in_tx_half_duplex = test_op;
end
endtask
// No carrier sense detection at RX in half duplex
task no_carrier_sense_rx_hd_detect;
input test_op;
begin
#1 no_carrier_sense_in_rx_half_duplex = test_op;
end
endtask
// Carrier sense detection at TX in full duplex also
task carrier_sense_tx_fd_detect;
input test_op;
begin
#1 carrier_sense_in_tx_full_duplex = test_op;
end
endtask
// No carrier sense detection at RX in full duplex
task no_carrier_sense_rx_fd_detect;
input test_op;
begin
#1 no_carrier_sense_in_rx_full_duplex = test_op;
end
endtask
// Set real delay on carrier sense signal (and therefor collision signal)
task carrier_sense_real_delay;
input test_op;
begin
#1 real_carrier_sense = test_op;
end
endtask
//////////////////////////////////////////////////////////////////////
//
// Tastks for controling PHY management test operation
//
//////////////////////////////////////////////////////////////////////
// Set registers to test operation and respond to all phy addresses
task test_regs;
input test_op;
begin
#1 registers_addr_data_test_operation = test_op;
respond_to_all_phy_addr = test_op;
end
endtask
// Clears data memory for testing the MII
task clear_test_regs;
integer i;
begin
for (i = 0; i < 32; i = i + 1)
begin
#1 data_mem[i] = 16'h0;
end
end
endtask
// Accept frames with preamble suppresed
task preamble_suppresed;
input test_op;
begin
#1 no_preamble = test_op;
md_transfer_cnt_reset = 1'b1;
@(posedge mdc_i);
#1 md_transfer_cnt_reset = 1'b0;
end
endtask
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -