Merge FPGA repository back into UHD repository

The FPGA codebase was removed from the UHD repository in 2014 to reduce
the size of the repository. However, over the last half-decade, the
split between the repositories has proven more burdensome than it has
been helpful. By merging the FPGA code back, it will be possible to
create atomic commits that touch both FPGA and UHD codebases. Continuous
integration testing is also simplified by merging the repositories,
because it was previously difficult to automatically derive the correct
UHD branch when testing a feature branch on the FPGA repository.

This commit also updates the license files and paths therein.

We are therefore merging the repositories again. Future development for
FPGA code will happen in the same repository as the UHD host code and
MPM code.

== Original Codebase and Rebasing ==

The original FPGA repository will be hosted for the foreseeable future
at its original local location: https://github.com/EttusResearch/fpga/

It can be used for bisecting, reference, and a more detailed history.

The final commit from said repository to be merged here is
05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as
v4.0.0.0-pre-uhd-merge.

If you have changes in the FPGA repository that you want to rebase onto
the UHD repository, simply run the following commands:

- Create a directory to store patches (this should be an empty
  directory):

    mkdir ~/patches

- Now make sure that your FPGA codebase is based on the same state as
  the code that was merged:

    cd src/fpga # Or wherever your FPGA code is stored
    git rebase v4.0.0.0-pre-uhd-merge

  Note: The rebase command may look slightly different depending on what
  exactly you're trying to rebase.

- Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge:

    git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches

  Note: Make sure that only patches are stored in your output directory.
  It should otherwise be empty. Make sure that you picked the correct
  range of commits, and only commits you wanted to rebase were exported
  as patch files.

- Go to the UHD repository and apply the patches:

    cd src/uhd # Or wherever your UHD repository is stored
    git am --directory fpga ~/patches/*
    rm -rf ~/patches # This is for cleanup

== Contributors ==

The following people have contributed mainly to these files (this list
is not complete):

Co-authored-by: Alex Williams <alex.williams@ni.com>
Co-authored-by: Andrej Rode <andrej.rode@ettus.com>
Co-authored-by: Ashish Chaudhari <ashish@ettus.com>
Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Derek Kozel <derek.kozel@ettus.com>
Co-authored-by: EJ Kreinar <ej@he360.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Ian Buckley <ian.buckley@gmail.com>
Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Jon Kiser <jon.kiser@ni.com>
Co-authored-by: Josh Blum <josh@joshknows.com>
Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Matt Ettus <matt@ettus.com>
Co-authored-by: Michael West <michael.west@ettus.com>
Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com>
Co-authored-by: Nick Foster <nick@ettus.com>
Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Paul David <paul.david@ettus.com>
Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com>
Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com>
Co-authored-by: Sylvain Munaut <tnt@246tNt.com>
Co-authored-by: Trung Tran <trung.tran@ettus.com>
Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>


Original-commit: bafa9d95453387814ef25e6b6256ba8db2df612f
This commit is contained in:
Martin Braun
2020-01-28 09:35:36 -08:00
co-authored by Alex Williams Andrej Rode Ashish Chaudhari Ben Hilburn Ciro Nishiguchi Daniel Jepson Derek Kozel EJ Kreinar Humberto Jimenez Ian Buckley Jörg Hofrichter Jon Kiser Josh Blum Jonathon Pendlum Matt Ettus Michael West Moritz Fischer Nick Foster Nicolas Cuervo Paul Butler Paul David Ryan Marlow Sugandha Gupta Sylvain Munaut Trung Tran Vidush Vishwanath Wade Fife
parent 74893643ca
commit 6b67702ad7
2157 changed files with 1282567 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
/a.out
/*.vcd
simple_gemac_wrapper_tb
+25
View File
@@ -0,0 +1,25 @@
#
# Copyright 2010 Ettus Research LLC
#
##################################################
# Simple GEMAC Sources
##################################################
SIMPLE_GEMAC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/simple_gemac/, \
simple_gemac_wrapper.v \
simple_gemac.v \
simple_gemac_tx.v \
simple_gemac_rx.v \
crc.v \
delay_line.v \
flow_ctrl_tx.v \
flow_ctrl_rx.v \
address_filter.v \
address_filter_promisc.v \
ll8_to_txmac.v \
rxmac_to_ll8.v \
ll8_to_axi64.v \
axi64_to_ll8.v \
gmii_to_axis.v \
mdio.v \
))
+43
View File
@@ -0,0 +1,43 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module address_filter
(input clk,
input reset,
input go,
input [7:0] data,
input [47:0] address,
output match,
output done);
reg [2:0] af_state;
always @(posedge clk)
if(reset)
af_state <= 0;
else
if(go)
af_state <= (data == address[47:40]) ? 1 : 7;
else
case(af_state)
1 : af_state <= (data == address[39:32]) ? 2 : 7;
2 : af_state <= (data == address[31:24]) ? 3 : 7;
3 : af_state <= (data == address[23:16]) ? 4 : 7;
4 : af_state <= (data == address[15:8]) ? 5 : 7;
5 : af_state <= (data == address[7:0]) ? 6 : 7;
6, 7 : af_state <= 0;
endcase // case (af_state)
assign match = (af_state==6);
assign done = (af_state==6)|(af_state==7);
endmodule // address_filter
+40
View File
@@ -0,0 +1,40 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module address_filter_promisc
(input clk,
input reset,
input go,
input [7:0] data,
output match,
output done);
reg [2:0] af_state;
always @(posedge clk)
if(reset)
af_state <= 0;
else
if(go)
af_state <= 1;//(data[0] == 1'b0) ? 1 : 7;
else
case(af_state)
1 : af_state <= 2;
2 : af_state <= 3;
3 : af_state <= 4;
4 : af_state <= 5;
5 : af_state <= 6;
6, 7 : af_state <= 0;
endcase // case (af_state)
assign match = (af_state==6);
assign done = (af_state==6)|(af_state==7);
endmodule // address_filter_promisc
+61
View File
@@ -0,0 +1,61 @@
//
// Copyright 2014 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module axi64_to_ll8
#(parameter START_BYTE=6)
(input clk, input reset, input clear,
input [63:0] axi64_tdata, input axi64_tlast, input [3:0] axi64_tuser, input axi64_tvalid, output axi64_tready,
output [7:0] ll_data, output ll_eof, output ll_src_rdy, input ll_dst_rdy);
reg [7:0] data_int;
wire eof_int, valid_int, ready_int;
reg [2:0] state = START_BYTE;
reg eof, done;
reg [3:0] occ;
wire [63:0] axi64_tdata_gated;
wire axi64_tlast_gated;
wire [3:0] axi64_tuser_gated;
wire axi64_tvalid_gated;
wire axi64_tready_gated;
axi_packet_gate #(
.WIDTH(68),
.SIZE(10)
) axi64_packet_gater (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({axi64_tuser, axi64_tdata}), .i_tlast(axi64_tlast),
.i_tvalid(axi64_tvalid), .i_tready(axi64_tready),
.o_tdata({axi64_tuser_gated, axi64_tdata_gated}), .o_tlast(axi64_tlast_gated),
.o_tvalid(axi64_tvalid_gated), .o_tready(axi64_tready_gated)
);
always @(posedge clk)
if(reset | clear)
state <= START_BYTE;
else
if(valid_int & ready_int)
if(eof_int)
state <= START_BYTE;
else
state <= state + 3'd1;
assign valid_int = axi64_tvalid_gated;
assign axi64_tready_gated = ready_int & (eof_int | state == 7);
assign eof_int = axi64_tlast_gated & (axi64_tuser_gated[2:0] == (state + 3'd1));
always @*
data_int <= axi64_tdata_gated[state*8 +: 8];
axi_fifo_short #(.WIDTH(9)) ll8_fifo
(.clk(clk), .reset(reset), .clear(0),
.i_tdata({eof_int, data_int}), .i_tvalid(valid_int), .i_tready(ready_int),
.o_tdata({ll_eof, ll_data}), .o_tvalid(ll_src_rdy), .o_tready(ll_dst_rdy),
.space(), .occupied());
endmodule // axi64_to_ll8
+74
View File
@@ -0,0 +1,74 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module crc
(input clk,
input reset,
input clear,
input [7:0] data,
input calc,
output [31:0] crc_out,
output match);
function[31:0] NextCRC;
input[7:0] D;
input[31:0] C;
reg[31:0] NewCRC;
begin
NewCRC[0] = C[24]^C[30]^D[1]^D[7];
NewCRC[1] = C[25]^C[31]^D[0]^D[6]^C[24]^C[30]^D[1]^D[7];
NewCRC[2] = C[26]^D[5]^C[25]^C[31]^D[0]^D[6]^C[24]^C[30]^D[1]^D[7];
NewCRC[3] = C[27]^D[4]^C[26]^D[5]^C[25]^C[31]^D[0]^D[6];
NewCRC[4] = C[28]^D[3]^C[27]^D[4]^C[26]^D[5]^C[24]^C[30]^D[1]^D[7];
NewCRC[5] = C[29]^D[2]^C[28]^D[3]^C[27]^D[4]^C[25]^C[31]^D[0]^D[6]^C[24]^C[30]^D[1]^D[7];
NewCRC[6] = C[30]^D[1]^C[29]^D[2]^C[28]^D[3]^C[26]^D[5]^C[25]^C[31]^D[0]^D[6];
NewCRC[7] = C[31]^D[0]^C[29]^D[2]^C[27]^D[4]^C[26]^D[5]^C[24]^D[7];
NewCRC[8] = C[0]^C[28]^D[3]^C[27]^D[4]^C[25]^D[6]^C[24]^D[7];
NewCRC[9] = C[1]^C[29]^D[2]^C[28]^D[3]^C[26]^D[5]^C[25]^D[6];
NewCRC[10] = C[2]^C[29]^D[2]^C[27]^D[4]^C[26]^D[5]^C[24]^D[7];
NewCRC[11] = C[3]^C[28]^D[3]^C[27]^D[4]^C[25]^D[6]^C[24]^D[7];
NewCRC[12] = C[4]^C[29]^D[2]^C[28]^D[3]^C[26]^D[5]^C[25]^D[6]^C[24]^C[30]^D[1]^D[7];
NewCRC[13] = C[5]^C[30]^D[1]^C[29]^D[2]^C[27]^D[4]^C[26]^D[5]^C[25]^C[31]^D[0]^D[6];
NewCRC[14] = C[6]^C[31]^D[0]^C[30]^D[1]^C[28]^D[3]^C[27]^D[4]^C[26]^D[5];
NewCRC[15] = C[7]^C[31]^D[0]^C[29]^D[2]^C[28]^D[3]^C[27]^D[4];
NewCRC[16] = C[8]^C[29]^D[2]^C[28]^D[3]^C[24]^D[7];
NewCRC[17] = C[9]^C[30]^D[1]^C[29]^D[2]^C[25]^D[6];
NewCRC[18] = C[10]^C[31]^D[0]^C[30]^D[1]^C[26]^D[5];
NewCRC[19] = C[11]^C[31]^D[0]^C[27]^D[4];
NewCRC[20] = C[12]^C[28]^D[3];
NewCRC[21] = C[13]^C[29]^D[2];
NewCRC[22] = C[14]^C[24]^D[7];
NewCRC[23] = C[15]^C[25]^D[6]^C[24]^C[30]^D[1]^D[7];
NewCRC[24] = C[16]^C[26]^D[5]^C[25]^C[31]^D[0]^D[6];
NewCRC[25] = C[17]^C[27]^D[4]^C[26]^D[5];
NewCRC[26] = C[18]^C[28]^D[3]^C[27]^D[4]^C[24]^C[30]^D[1]^D[7];
NewCRC[27] = C[19]^C[29]^D[2]^C[28]^D[3]^C[25]^C[31]^D[0]^D[6];
NewCRC[28] = C[20]^C[30]^D[1]^C[29]^D[2]^C[26]^D[5];
NewCRC[29] = C[21]^C[31]^D[0]^C[30]^D[1]^C[27]^D[4];
NewCRC[30] = C[22]^C[31]^D[0]^C[28]^D[3];
NewCRC[31] = C[23]^C[29]^D[2];
NextCRC = NewCRC;
end
endfunction
reg [31:0] crc_reg;
always @ (posedge clk)
if (reset | clear)
crc_reg <= 32'hffffffff;
else if (calc)
crc_reg <= NextCRC(data,crc_reg);
assign crc_out = ~{crc_reg[24],crc_reg[25],crc_reg[26],crc_reg[27],crc_reg[28],crc_reg[29],crc_reg[30],crc_reg[31],
crc_reg[16],crc_reg[17],crc_reg[18],crc_reg[19],crc_reg[20],crc_reg[21],crc_reg[22],crc_reg[23],
crc_reg[8],crc_reg[9],crc_reg[10],crc_reg[11],crc_reg[12],crc_reg[13],crc_reg[14],crc_reg[15],
crc_reg[0],crc_reg[1],crc_reg[2],crc_reg[3],crc_reg[4],crc_reg[5],crc_reg[6],crc_reg[7] };
assign match = (crc_reg == 32'hc704_dd7b);
endmodule // crc
+29
View File
@@ -0,0 +1,29 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module delay_line
#(parameter WIDTH=32)
(input clk,
input [3:0] delay,
input [WIDTH-1:0] din,
output [WIDTH-1:0] dout);
genvar i;
generate
for (i=0;i<WIDTH;i=i+1)
begin : gen_delay
SRL16E
srl16e(.Q(dout[i]),
.A0(delay[0]),.A1(delay[1]),.A2(delay[2]),.A3(delay[3]),
.CE(1),.CLK(clk),.D(din[i]));
end
endgenerate
endmodule // delay_line
+164
View File
@@ -0,0 +1,164 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
task SendFlowCtrl;
input [15:0] fc_len;
begin
$display("Sending Flow Control, quanta = %d, time = %d", fc_len,$time);
pause_time <= fc_len;
@(posedge clk);
pause_req <= 1;
@(posedge clk);
pause_req <= 0;
$display("Sent Flow Control");
end
endtask // SendFlowCtrl
task SendPacket2MAC;
input tx_clk;
input [7:0] data_start;
input [31:0] data_len;
output [7:0] tx_data;
output tx_valid;
output tx_error;
input tx_ack;
reg [15:0] count;
begin
$display("Sending Packet Len=%d, %d", data_len, $time);
count <= 1;
tx_data <= data_start;
tx_error <= 0;
tx_valid <= 1;
while(~tx_ack)
@(posedge tx_clk);
$display("Packet Accepted, %d", $time);
while(count < data_len)
begin
tx_data <= tx_data + 1;
count <= count + 1;
@(posedge clk);
end
tx_valid <= 0;
@(posedge tx_clk);
end
endtask // SendPacket2MAC
task SendPacket_to_ll8;
input [7:0] data_start;
input [15:0] data_len;
// output [7:0] tx_data;
// output tx_sof;
// output tx_eof;
// output tx_src_rdy;
// input tx_dst_rdy;
reg [15:0] count;
begin
$display("Sending Packet Len=%d, %d", data_len, $time);
count <= 2;
tx_ll_data2 <= data_start;
tx_ll_src_rdy2 <= 1;
tx_ll_sof2 <= 1;
tx_ll_eof2 <= 0;
#1;
while(count < data_len)
begin
while(~tx_ll_dst_rdy2)
@(posedge clk);
@(posedge clk);
tx_ll_data2 = tx_ll_data2 + 1;
count = count + 1;
tx_ll_sof2 <= 0;
end
tx_ll_eof2 <= 1;
while(~tx_ll_dst_rdy2)
@(posedge clk);
@(posedge clk);
tx_ll_src_rdy2 <= 0;
end
endtask // SendPacket_to_ll8
task SendPacketFromFile;
input clk;
input [31:0] data_len;
output [7:0] tx_data;
output tx_valid;
output tx_error;
input tx_ack;
reg [15:0] count;
begin
$display("Sending Packet From File Len=%d, %d",data_len,$time);
$readmemh("test_packet.mem",pkt_rom );
count = 0;
tx_data = pkt_rom[count];
tx_error = 0;
tx_valid = 1;
while(~tx_ack)
@(posedge clk);
$display("Packet Accepted, %d",$time);
count = 1;
while(count < data_len)
begin
tx_data = pkt_rom[count];
count = count + 1;
@(posedge clk);
end
tx_valid <= 0;
@(posedge clk);
end
endtask // SendPacketFromFile
task Waiter;
input [31:0] wait_length;
begin
tx_ll_src_rdy2 <= 0;
repeat(wait_length)
@(posedge clk);
tx_ll_src_rdy2 <= 1;
end
endtask // Waiter
task SendPacketFromFile_ll8;
input [31:0] data_len;
input [31:0] wait_length;
input [31:0] wait_time;
integer count;
begin
$display("Sending Packet From File to LL8 Len=%d, %d",data_len,$time);
$readmemh("test_packet.mem",pkt_rom );
while(~tx_ll_dst_rdy2)
@(posedge clk);
tx_ll_data2 <= pkt_rom[0];
tx_ll_src_rdy2 <= 1;
tx_ll_sof2 <= 1;
tx_ll_eof2 <= 0;
@(posedge clk);
for(i=1;i<data_len-1;i=i+1)
begin
while(~tx_ll_dst_rdy2)
@(posedge clk);
tx_ll_data2 <= pkt_rom[i];
tx_ll_sof2 <= 0;
@(posedge clk);
if(i==wait_time)
Waiter(wait_length);
end
while(~tx_ll_dst_rdy2)
@(posedge clk);
tx_ll_eof2 <= 1;
tx_ll_data2 <= pkt_rom[data_len-1];
@(posedge clk);
tx_ll_src_rdy2 <= 0;
end
endtask // SendPacketFromFile_ll8
+69
View File
@@ -0,0 +1,69 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// RX side of flow control -- when we are running out of RX space, send a PAUSE
module flow_ctrl_rx
(input pause_request_en, input [15:0] pause_time, input [15:0] pause_thresh,
input rx_clk, input rx_reset, input [15:0] rx_fifo_space,
input tx_clk, input tx_reset, output reg pause_req, output reg [15:0] pause_time_req
);
// ******************************************************************************
// Force our TX to send a PAUSE frame because our RX is nearly full
// ******************************************************************************
// RX Clock Domain
reg xon, xoff;
reg [21:0] countdown;
wire [15:0] pause_low_thresh = pause_thresh;
wire [15:0] pause_hi_thresh = 16'hFFFF;
wire [21:0] pq_reduced = {pause_time,6'd0} - 1700;
always @(posedge rx_clk)
if(rx_reset)
xoff <= 0;
else
xoff <= (pause_request_en & (countdown==0) & (rx_fifo_space < pause_low_thresh));
always @(posedge rx_clk)
if(rx_reset)
xon <= 0;
else
xon <= ((countdown!=0) & (rx_fifo_space > pause_hi_thresh));
always @(posedge rx_clk)
if(rx_reset)
countdown <= 0;
else if(xoff)
countdown <= pq_reduced;
else if(xon)
countdown <= 0;
else if(countdown != 0)
countdown <= countdown - 1;
// Cross clock domains
wire xon_tx, xoff_tx;
oneshot_2clk send_xon (.clk_in(rx_clk), .in(xon), .clk_out(tx_clk), .out(xon_tx));
oneshot_2clk send_xoff (.clk_in(rx_clk), .in(xoff), .clk_out(tx_clk), .out(xoff_tx));
always @(posedge tx_clk)
if(xoff_tx)
pause_time_req <= pause_time;
else if(xon_tx)
pause_time_req <= 0;
always @(posedge tx_clk)
if(tx_reset)
pause_req <= 0;
else
pause_req <= xon_tx | xoff_tx;
endmodule // flow_ctrl_rx
+47
View File
@@ -0,0 +1,47 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// TX side of flow control -- when other side sends PAUSE, we wait
module flow_ctrl_tx
(input rst,
input tx_clk,
//host processor
input tx_pause_en,
// From MAC_rx_ctrl
input [15:0] pause_quanta,
input pause_quanta_val,
// MAC_tx_ctrl
output pause_apply,
input paused);
// ******************************************************************************
// Inhibit our TX from transmitting because they sent us a PAUSE frame
// ******************************************************************************
// Pauses are in units of 512 bit times, or 64 bytes/clock cycles, and can be
// as big as 16 bits, so 22 bits are needed for the counter
reg [15+6:0] pause_quanta_counter;
reg pqval_d1, pqval_d2;
always @(posedge tx_clk) pqval_d1 <= pause_quanta_val;
always @(posedge tx_clk) pqval_d2 <= pqval_d1;
always @ (posedge tx_clk or posedge rst)
if (rst)
pause_quanta_counter <= 0;
else if (pqval_d1 & ~pqval_d2)
pause_quanta_counter <= {pause_quanta, 6'b0};
else if((pause_quanta_counter!=0) & paused)
pause_quanta_counter <= pause_quanta_counter - 1;
assign pause_apply = tx_pause_en & (pause_quanta_counter != 0);
endmodule // flow_ctrl
+239
View File
@@ -0,0 +1,239 @@
//
// Copyright 2017 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module gmii_to_axis
#(
parameter RX_FLOW_CTRL=0,
parameter PORTNUM=8'd0
)
(
input clk125,
input reset,
// GMII
output gmii_gtx_clk,
output gmii_tx_en,
output gmii_tx_er,
output [7:0] gmii_txd,
input gmii_rx_clk,
input gmii_rx_dv,
input gmii_rx_er,
input [7:0] gmii_rxd,
// Client FIFO Interfaces
input sys_clk,
output [63:0] rx_tdata,
output [3:0] rx_tuser,
output rx_tlast,
output rx_tvalid,
input rx_tready,
input [63:0] tx_tdata,
input [3:0] tx_tuser,
input tx_tlast,
input tx_tvalid,
output tx_tready,
output [31:0] debug_rx,
output [31:0] debug_tx
);
wire clear = 1'b0;
wire [7:0] rx_data, tx_data;
wire tx_clk, tx_valid, tx_error, tx_ack;
wire rx_clk, rx_valid, rx_error, rx_ack;
wire pause_req;
wire pause_request_en, pause_respect_en;
wire [15:0] pause_time, pause_thresh, pause_time_req, rx_fifo_space;
wire [31:0] debug_state;
wire tx_reset, rx_reset;
reset_sync reset_sync_tx
(
.clk(tx_clk),
.reset_in(reset),
.reset_out(tx_reset)
);
reset_sync reset_sync_rx (
.clk(rx_clk),
.reset_in(reset),
.reset_out(rx_reset)
);
simple_gemac simple_gemac
(
.clk125(clk125), .reset(reset),
.GMII_GTX_CLK(gmii_gtx_clk),
.GMII_TX_EN(gmii_tx_en),
.GMII_TX_ER(gmii_tx_er),
.GMII_TXD(gmii_txd),
.GMII_RX_CLK(gmii_rx_clk),
.GMII_RX_DV(gmii_rx_dv),
.GMII_RX_ER(gmii_rx_er),
.GMII_RXD(gmii_rxd),
.pause_req(RX_FLOW_CTRL ? pause_req : 1'b0),
.pause_time_req(RX_FLOW_CTRL ? pause_time_req : 16'd0),
.pause_respect_en(pause_respect_en),
.ucast_addr(48'h0),
.mcast_addr(48'h0),
.pass_ucast(1'b0),
.pass_mcast(1'b0),
.pass_bcast(1'b0),
.pass_pause(1'b0),
.pass_all(1'b1),
.rx_clk(rx_clk),
.rx_data(rx_data),
.rx_valid(rx_valid),
.rx_error(rx_error),
.rx_ack(rx_ack),
.tx_clk(tx_clk),
.tx_data(tx_data),
.tx_valid(tx_valid),
.tx_error(tx_error),
.tx_ack(tx_ack),
.debug(debug_state)
);
assign pause_respect_en = 1'b0;
assign pause_request_en = 1'b0;
///////////////////////////////////////////////////////////////////////////////////////
// RX FIFO Chain
wire rx_ll_eof;
wire rx_ll_error;
wire rx_ll_src_rdy;
wire rx_ll_dst_rdy;
wire [7:0] rx_ll_data;
wire [63:0] rx_tdata_int;
wire [3:0] rx_tuser_int;
wire rx_tlast_int;
wire rx_tvalid_int;
wire rx_tready_int;
rxmac_to_ll8 rxmac_to_ll8
(
.clk(rx_clk),
.reset(rx_reset),
.clear(clear),
.rx_data(rx_data),
.rx_valid(rx_valid),
.rx_error(rx_error),
.rx_ack(rx_ack),
.ll_data(rx_ll_data),
.ll_sof(),
.ll_eof(rx_ll_eof),
.ll_error(rx_ll_error), // ignore sof
.ll_src_rdy(rx_ll_src_rdy),
.ll_dst_rdy(rx_ll_dst_rdy)
);
ll8_to_axi64 #(.START_BYTE(6), .LABEL(PORTNUM)) ll8_to_axi64
(
.clk(rx_clk),
.reset(rx_reset),
.clear(clear),
.ll_data(rx_ll_data),
.ll_eof(rx_ll_eof),
.ll_error(rx_ll_error),
.ll_src_rdy(rx_ll_src_rdy),
.ll_dst_rdy(rx_ll_dst_rdy),
.axi64_tdata(rx_tdata_int),
.axi64_tlast(rx_tlast_int),
.axi64_tuser(rx_tuser_int),
.axi64_tvalid(rx_tvalid_int),
.axi64_tready(rx_tready_int)
);
axi64_8k_2clk_fifo rxfifo_2clk
(
.s_aresetn(~rx_reset),
.s_aclk(rx_clk),
.s_axis_tvalid(rx_tvalid_int),
.s_axis_tready(rx_tready_int),
.s_axis_tdata(rx_tdata_int),
.s_axis_tlast(rx_tlast_int),
.s_axis_tuser(rx_tuser_int),
.axis_wr_data_count(),
.m_aclk(sys_clk),
.m_axis_tvalid(rx_tvalid),
.m_axis_tready(rx_tready),
.m_axis_tdata(rx_tdata),
.m_axis_tlast(rx_tlast),
.m_axis_tuser(rx_tuser),
.axis_rd_data_count()
);
///////////////////////////////////////////////////////////////////////////////////////
// TX FIFO Chain
wire tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy;
wire [7:0] tx_ll_data;
wire [63:0] tx_tdata_int;
wire [3:0] tx_tuser_int;
wire tx_tlast_int;
wire tx_tvalid_int;
wire tx_tready_int;
axi64_8k_2clk_fifo txfifo_2clk
(
.s_aresetn(~tx_reset),
.s_aclk(sys_clk),
.s_axis_tvalid(tx_tvalid),
.s_axis_tready(tx_tready),
.s_axis_tdata(tx_tdata),
.s_axis_tlast(tx_tlast),
.s_axis_tuser(tx_tuser),
.axis_wr_data_count(),
.m_aclk(tx_clk),
.m_axis_tvalid(tx_tvalid_int),
.m_axis_tready(tx_tready_int),
.m_axis_tdata(tx_tdata_int),
.m_axis_tlast(tx_tlast_int),
.m_axis_tuser(tx_tuser_int),
.axis_rd_data_count()
);
axi64_to_ll8 #(.START_BYTE(6)) axi64_to_ll8
(
.clk(tx_clk),
.reset(tx_reset),
.clear(clear),
.axi64_tdata(tx_tdata_int),
.axi64_tlast(tx_tlast_int),
.axi64_tuser(tx_tuser_int),
.axi64_tvalid(tx_tvalid_int),
.axi64_tready(tx_tready_int),
.ll_data(tx_ll_data),
.ll_eof(tx_ll_eof),
.ll_src_rdy(tx_ll_src_rdy),
.ll_dst_rdy(tx_ll_dst_rdy)
);
ll8_to_txmac ll8_to_txmac
(
.clk(tx_clk),
.reset(tx_reset),
.clear(clear),
.ll_data(tx_ll_data),
.ll_eof(tx_ll_eof),
.ll_src_rdy(tx_ll_src_rdy),
.ll_dst_rdy(tx_ll_dst_rdy),
.tx_data(tx_data),
.tx_valid(tx_valid),
.tx_error(tx_error),
.tx_ack(tx_ack)
);
endmodule
+94
View File
@@ -0,0 +1,94 @@
//
// Copyright 2014 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Takes 8-bit wide data on a Local-link fifo interface and converts to 64-bit wide axi
// Parameter START_BYTE controls which byte of the 8 the first incoming byte goes into
// Use START_BYTE=6 with ethernet to nicely align the words for processing of IP packets
// Parameter LABEL specifies a value to put in the high word of the very first packet.
// This is useful for labeling packets with the port it came from so downstream knows
// how to process it. LABEL gets overwritten if START_BYTE = 0
module ll8_to_axi64
#(parameter START_BYTE=6,
parameter LABEL=8'h00)
(input clk, input reset, input clear,
input [7:0] ll_data, input ll_eof, input ll_error, input ll_src_rdy, output ll_dst_rdy,
output [63:0] axi64_tdata, output axi64_tlast, output [3:0] axi64_tuser, output axi64_tvalid, input axi64_tready);
wire error_int, eof_int;
wire [7:0] data_int;
wire valid_int, ready_int;
axi_fifo_short #(.WIDTH(10)) ll8_fifo
(.clk(clk), .reset(reset), .clear(0),
.i_tdata({ll_error, ll_eof, ll_data}), .i_tvalid(ll_src_rdy), .i_tready(ll_dst_rdy),
.o_tdata({error_int, eof_int, data_int}), .o_tvalid(valid_int), .o_tready(ready_int),
.space(), .occupied());
wire [7:0] label_wire = LABEL; // Enforces parameter width
reg [3:0] state = START_BYTE;
reg [63:0] holding; // = {label_wire, 56'h0};
reg err, eof, done;
reg [3:0] occ;
localparam WAIT = 4'd8;
always @(posedge clk)
if(reset | clear)
begin
state <= START_BYTE;
holding <= {56'h0, label_wire};
err <= 1'b0;
eof <= 1'b0;
occ <= 3'd0;
done <= 1'b0;
end
else
if(state == WAIT)
begin
state <= START_BYTE;
done <= 1'b0;
holding <= {56'h0, label_wire};
end
else if(valid_int & ready_int)
begin
holding[state*8 +: 8] <= data_int;
err <= error_int;
eof <= eof_int;
if(error_int | eof_int)
begin
occ <= state+1;
done <= 1'b1;
state <= WAIT;
end
else if (state == 4'd7)
begin
occ <= 3'd0;
done <= 1'b1;
state <= 4'd0;
end
else
begin
occ <= 3'd0;
done <= 1'b0;
state <= state + 4'd1;
end // else: !if(state == 4'd7)
end // if (valid_int & ready_int)
else
done <= 1'b0;
assign axi64_tdata = holding;
assign axi64_tlast = eof;
assign axi64_tuser[3] = err;
assign axi64_tuser[2:0] = occ;
assign ready_int = axi64_tready & (state != WAIT);
assign axi64_tvalid = done;
endmodule // ll8_to_axi64
+100
View File
@@ -0,0 +1,100 @@
//
// Copyright 2014 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
`timescale 1ns/1ps
module ll8_to_axi64_tb();
reg clk = 0;
reg reset = 1;
always #10 clk = ~clk;
initial $dumpfile("ll8_to_axi64_tb.vcd");
initial $dumpvars(0,ll8_to_axi64_tb);
initial
begin
#1000 reset = 0;
#2000000;
$finish;
end
wire [63:0] tdata, tdata_int;
wire [3:0] tuser, tuser_int;
wire tlast, tlast_int;
wire tvalid, tvalid_int, tready, tready_int;
reg [7:0] ll_data;
reg ll_eof, ll_error, ll_src_rdy;
wire ll_dst_rdy;
wire [7:0] ll_data2;
wire ll_eof2, ll_src_rdy2, ll_dst_rdy2;
localparam RPT_COUNT = 12;
initial
begin
ll_src_rdy <= 0;
while(reset)
@(posedge clk);
@(posedge clk);
{ll_error, ll_eof, ll_data} <= { 1'b0, 1'b0, 8'hA0 };
repeat(RPT_COUNT-1)
begin
ll_src_rdy <= 1;
@(posedge clk);
ll_data <= ll_data + 1;
end
ll_eof <= 1;
ll_data <= ll_data + 1;
@(posedge clk);
{ll_error, ll_eof, ll_data} <= { 1'b0, 1'b0, 8'hC0 };
repeat(RPT_COUNT-1)
begin
ll_src_rdy <= 1;
@(posedge clk);
ll_data <= ll_data + 1;
end
ll_eof <= 1; ll_error <= 1;
ll_data <= ll_data + 1;
@(posedge clk);
ll_src_rdy <= 1'b0;
end
ll8_to_axi64 #(.START_BYTE(6), .LABEL(8'h89)) ll8_to_axi64
(.clk(clk), .reset(reset), .clear(1'b0),
.ll_data(ll_data), .ll_eof(ll_eof), .ll_error(ll_error), .ll_src_rdy(ll_src_rdy), .ll_dst_rdy(ll_dst_rdy),
.axi64_tdata(tdata), .axi64_tlast(tlast), .axi64_tuser(tuser), .axi64_tvalid(tvalid), .axi64_tready(tready) );
axi_fifo_short #(.WIDTH(69)) axi_fifo_short
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({tlast,tuser,tdata}), .i_tvalid(tvalid), .i_tready(tready),
.o_tdata({tlast_int,tuser_int,tdata_int}), .o_tvalid(tvalid_int), .o_tready(tready_int));
axi64_to_ll8 #(.START_BYTE(6)) axi64_to_ll8
(.clk(clk), .reset(reset), .clear(1'b0),
.axi64_tdata(tdata_int), .axi64_tlast(tlast_int), .axi64_tuser(tuser_int), .axi64_tvalid(tvalid_int), .axi64_tready(tready_int),
.ll_data(ll_data2), .ll_eof(ll_eof2), .ll_src_rdy(ll_src_rdy2), .ll_dst_rdy(ll_dst_rdy2) );
/*
always @(posedge clk)
if(ll_src_rdy2 & ll_dst_rdy2)
$display("EOF %x\tDATA %x",ll_eof2, ll_data2);
*/
assign ll_dst_rdy2 = 1;
always @(posedge clk)
if(tvalid_int & tready_int)
$display("TERR %x\tTUSER %x\tTLAST %x\tTDATA %x",tuser_int[3],tuser_int[2:0], tlast_int, tdata_int);
endmodule // ll8_to_axi64_tb
+51
View File
@@ -0,0 +1,51 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module ll8_to_txmac
(input clk, input reset, input clear,
input [7:0] ll_data, input ll_eof, input ll_src_rdy, output ll_dst_rdy,
output [7:0] tx_data, output tx_valid, output tx_error, input tx_ack );
reg [2:0] xfer_state;
localparam XFER_IDLE = 0;
localparam XFER_ACTIVE = 1;
localparam XFER_WAIT1 = 2;
localparam XFER_UNDERRUN = 3;
localparam XFER_DROP = 4;
always @(posedge clk)
if(reset | clear)
xfer_state <= XFER_IDLE;
else
case(xfer_state)
XFER_IDLE :
if(tx_ack)
xfer_state <= XFER_ACTIVE;
XFER_ACTIVE :
if(~ll_src_rdy)
xfer_state <= XFER_UNDERRUN;
else if(ll_eof)
xfer_state <= XFER_WAIT1;
XFER_WAIT1 :
xfer_state <= XFER_IDLE;
XFER_UNDERRUN :
xfer_state <= XFER_DROP;
XFER_DROP :
if(ll_eof)
xfer_state <= XFER_IDLE;
endcase // case (xfer_state)
assign ll_dst_rdy = (xfer_state == XFER_ACTIVE) | tx_ack | (xfer_state == XFER_DROP);
assign tx_valid = (ll_src_rdy & (xfer_state == XFER_IDLE))|(xfer_state == XFER_ACTIVE);
assign tx_data = ll_data;
assign tx_error = (xfer_state == XFER_UNDERRUN);
endmodule // ll8_to_txmac
+852
View File
@@ -0,0 +1,852 @@
//
// Copyright 2014 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Define MDIO to add support for clause 22 and clause 45 MDIO interface
`define MDIO
// If WB clock is 62.5MHz and max MDC spec is 2.5MHz, then divide by 25
//`define MDC_HALF_PERIOD 13 // Closest int to 12.5
`define MDC_HALF_PERIOD 100
// Registers
`define CPUREG_MDIO_DATA 8'h10
`define CPUREG_MDIO_ADDR 8'h14
`define CPUREG_MDIO_OP 8'h18
`define CPUREG_MDIO_CONTROL 8'h1c
`define CPUREG_MDIO_STATUS 8'h1c
`define CPUREG_GPIO 8'h20
module mdio
(
// Wishbone Bus
input wb_clk_i,
input wb_rst_i,
input [7:0] wb_adr_i,
input [31:0] wb_dat_i,
input wb_we_i,
input wb_stb_i,
input wb_cyc_i,
output reg [31:0] wb_dat_o,
output wb_ack_o,
output reg wb_int_o,
// MDIO
output reg mdc,
output reg mdio_out,
output reg mdio_tri,
input mdio_in
);
//
// State Declarations
//
parameter
IDLE = 0,
PREAMBLE1 = 1,
PREAMBLE2 = 2,
PREAMBLE3 = 3,
PREAMBLE4 = 4,
PREAMBLE5 = 5,
PREAMBLE6 = 6,
PREAMBLE7 = 7,
PREAMBLE8 = 8,
PREAMBLE9 = 9,
PREAMBLE10 = 10,
PREAMBLE11 = 11,
PREAMBLE12 = 12,
PREAMBLE13 = 13,
PREAMBLE14 = 14,
PREAMBLE15 = 15,
PREAMBLE16 = 16,
PREAMBLE17 = 17,
PREAMBLE18 = 18,
PREAMBLE19 = 19,
PREAMBLE20 = 20,
PREAMBLE21 = 21,
PREAMBLE22 = 22,
PREAMBLE23 = 23,
PREAMBLE24 = 24,
PREAMBLE25 = 25,
PREAMBLE26 = 26,
PREAMBLE27 = 27,
PREAMBLE28 = 28,
PREAMBLE29 = 29,
PREAMBLE30 = 30,
PREAMBLE31 = 31,
PREAMBLE32 = 32,
START1 = 33,
C22_START2 = 34,
C45_START2 = 35,
OP1 = 36,
OP2 = 37,
PRTAD1 = 38,
PRTAD2 = 39,
PRTAD3 = 40,
PRTAD4 = 41,
PRTAD5 = 42,
DEVAD1 = 43,
DEVAD2 = 44,
DEVAD3 = 45,
DEVAD4 = 46,
DEVAD5 = 47,
TA1 = 48,
TA2 = 49,
TA3 = 50,
READ1 = 51,
READ2 = 52,
READ3 = 53,
READ4 = 54,
READ5 = 55,
READ6 = 56,
READ7 = 57,
READ8 = 58,
READ9 = 59,
READ10 = 60,
READ11 = 61,
READ12 = 62,
READ13 = 63,
READ14 = 64,
READ15 = 65,
READ16 = 66,
WRITE1 = 67,
WRITE2 = 68,
WRITE3 = 69,
WRITE4 = 70,
WRITE5 = 71,
WRITE6 = 72,
WRITE7 = 73,
WRITE8 = 74,
WRITE9 = 75,
WRITE10 = 76,
WRITE11 = 77,
WRITE12 = 78,
WRITE13 = 79,
WRITE14 = 80,
WRITE15 = 81,
WRITE16 = 82,
C45_ADDR1 = 83,
C45_ADDR2 = 84,
C45_ADDR3 = 85,
C45_ADDR4 = 86,
C45_ADDR5 = 87,
C45_ADDR6 = 88,
C45_ADDR7 = 89,
C45_ADDR8 = 90,
C45_ADDR9 = 91,
C45_ADDR10 = 92,
C45_ADDR11 = 93,
C45_ADDR12 = 94,
C45_ADDR13 = 95,
C45_ADDR14 = 96,
C45_ADDR15 = 97,
C45_ADDR16 = 98,
PREIDLE = 99;
reg cpuack;
reg [15:0] mdio_read_data;
reg [15:0] mdio_write_data;
reg [15:0] mdio_address;
reg [12:0] mdio_operation;
reg mdio_control;
reg [7:0] mdc_clk_count;
reg mdc_falling_edge;
reg mdio_running;
reg mdio_done;
reg [7:0] state;
assign wb_ack_o = cpuack && wb_stb_i;
always @(posedge wb_clk_i or posedge wb_rst_i) begin
if (wb_rst_i == 1'b1) begin
wb_dat_o <= 32'b0;
wb_int_o <= 1'b0;
cpuack <= 1'b0;
mdio_address <= 0;
mdio_operation <= 0;
mdio_write_data <= 0;
mdio_running <= 0;
end
else begin
wb_int_o <= 1'b0;
cpuack <= wb_cyc_i && wb_stb_i;
// Handshake to MDIO state machine to reset running flag in status.
// Wait for falling MDC edge to prevent S/W race condition occuring
// where done flag still asserted but running flag now cleared (repeatedly).
if (mdio_done && mdc_falling_edge)
mdio_running <= 0;
//
// Read access
//
if (wb_cyc_i && wb_stb_i && !wb_we_i) begin
case ({wb_adr_i[7:2], 2'b0})
`CPUREG_MDIO_DATA: begin
wb_dat_o <= {16'b0, mdio_read_data};
end
`CPUREG_MDIO_STATUS: begin
wb_dat_o <= {31'b0, mdio_running};
end
default: begin
end
endcase
end
//
// Write access
//
if (wb_cyc_i && wb_stb_i && wb_we_i) begin
$display("reg write @ addr %x",({wb_adr_i[7:2], 2'b0}));
case ({wb_adr_i[7:2], 2'b0})
`CPUREG_MDIO_DATA: begin
mdio_write_data <= wb_dat_i[15:0];
end
`CPUREG_MDIO_ADDR: begin
mdio_address <= wb_dat_i[15:0];
end
`CPUREG_MDIO_OP: begin
mdio_operation <= wb_dat_i[12:0];
end
`CPUREG_MDIO_CONTROL: begin
// Trigger mdio operation here. Cleared by state machine at end of bus transaction.
if (wb_dat_i[0])
mdio_running <= 1;
end
default: begin
end
endcase
end
end
end // always @ (posedge wb_clk_i or posedge wb_rst_i)
//
// Produce mdc clock as a signal synchronously from Wishbone clock.
//
always @(posedge wb_clk_i or posedge wb_rst_i)
if (wb_rst_i)
begin
mdc_clk_count <= 1;
mdc <= 0;
mdc_falling_edge <= 0;
end
else if (mdc_clk_count == `MDC_HALF_PERIOD)
begin
mdc_clk_count <= 1;
mdc <= ~mdc;
mdc_falling_edge <= mdc;
end
else
begin
mdc_clk_count <= mdc_clk_count + 1;
mdc_falling_edge <= 0;
end
//
// MDIO state machine
//
always @(posedge wb_clk_i or posedge wb_rst_i)
if (wb_rst_i)
begin
mdio_tri <= 1;
mdio_out <= 0;
mdio_done <= 0;
mdio_read_data <= 0;
state <= IDLE;
end
else if (mdc_falling_edge)
//
// This is the MDIO bus controller. Use falling edge of MDC.
//
begin
// Defaults
mdio_tri <= 1;
mdio_out <= 0;
mdio_done <= 0;
case(state)
// IDLE.
// In Clause 22 & 45 the master of the MDIO bus is tristate during idle.
//
IDLE: begin
mdio_tri <= 1;
mdio_out <= 0;
if (mdio_running)
state <= PREAMBLE1;
end
// Preamble. All MDIO transactions begin witrh 32bits of 1 bits as a preamble.
PREAMBLE1: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE2;
end
PREAMBLE2: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE3;
end
PREAMBLE3: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE4;
end
PREAMBLE4: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE5;
end
PREAMBLE5: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE6;
end
PREAMBLE6: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE7;
end
PREAMBLE7: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE8;
end
PREAMBLE8: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE9;
end
PREAMBLE9: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE10;
end
PREAMBLE10: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE11;
end
PREAMBLE11: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE12;
end
PREAMBLE12: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE13;
end
PREAMBLE13: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE14;
end
PREAMBLE14: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE15;
end
PREAMBLE15: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE16;
end
PREAMBLE16: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE17;
end
PREAMBLE17: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE18;
end
PREAMBLE18: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE19;
end
PREAMBLE19: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE20;
end
PREAMBLE20: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE21;
end
PREAMBLE21: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE22;
end
PREAMBLE22: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE23;
end
PREAMBLE23: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE24;
end
PREAMBLE24: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE25;
end
PREAMBLE25: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE26;
end
PREAMBLE26: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE27;
end
PREAMBLE27: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE28;
end
PREAMBLE28: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE29;
end
PREAMBLE29: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE30;
end
PREAMBLE30: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE31;
end
PREAMBLE31: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= PREAMBLE32;
end
PREAMBLE32: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= START1;
end
//
// Start code for Clause 22 is 01 and Clause 45 is 00
//
START1: begin
mdio_tri <= 0;
mdio_out <= 0;
if (mdio_operation[12])
// Clause 45 bit set.
state <= C45_START2;
else
state <= C22_START2;
end
//
// 2nd Clause 22 start bit is a 1
//
C22_START2: begin
mdio_tri <= 0;
mdio_out <= 1;
state <= OP1;
end
//
// 2nd Clause 45 start bit is a 0
//
C45_START2: begin
mdio_tri <= 0;
mdio_out <= 0;
state <= OP1;
end
//
// Both Clause 22 & 45 use 2 bits for operation and are compatable.
// Note we don't screen here for illegal Clause 22 ops.
//
OP1: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[11];
state <= OP2;
end
OP2: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[10];
state <= PRTAD1;
end
//
// Both Clause 22 & 45 use 2 sucsessive 5 bit fields to form a hierarchical address
// though it's used slightly different between the 2 standards.
//
PRTAD1: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[9];
state <= PRTAD2;
end
PRTAD2: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[8];
state <= PRTAD3;
end
PRTAD3: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[7];
state <= PRTAD4;
end
PRTAD4: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[6];
state <= PRTAD5;
end
PRTAD5: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[5];
state <= DEVAD1;
end
DEVAD1: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[4];
state <= DEVAD2;
end
DEVAD2: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[3];
state <= DEVAD3;
end
DEVAD3: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[2];
state <= DEVAD4;
end
DEVAD4: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[1];
state <= DEVAD5;
end
DEVAD5: begin
mdio_tri <= 0;
mdio_out <= mdio_operation[0];
state <= TA1;
end
//
// Both Clause 22 & Clause 45 use the same turn around on the bus.
// Reads have Z as the first bit and 0 driven by the slave for the 2nd bit.
// Note that slaves drive the bus on the rising edge of MDC.
// Writes and Address cycles have 10 driven by the master.
//
TA1: begin
// Clause22 write or clause45 write or address go to state TA2
if ((mdio_operation[12:11] == 2'b10) || (mdio_operation[12:11] == 2'b01))
begin
mdio_tri <= 0;
mdio_out <= 1;
state <= TA2;
end
else // Read
begin
mdio_tri <= 1;
state <= TA3;
end
end
TA2: begin
mdio_tri <= 0;
mdio_out <= 0;
if (!mdio_operation[12]) // Clause 22 Write
state <= WRITE1;
else if (mdio_operation[10]) // Clause 45 Write
state <= WRITE1;
else // Clause 45 ADDRESS
state <= C45_ADDR1;
end
TA3: begin
mdio_tri <= 1;
state <= READ1;
end
//
// Clause 22 Reads and both forms of clause 45 Reads have the same bus transaction from here out.
//
READ1: begin
mdio_tri <= 1;
mdio_read_data[15] <= mdio_in;
state <= READ2;
end
READ2: begin
mdio_tri <= 1;
mdio_read_data[14] <= mdio_in;
state <= READ3;
end
READ3: begin
mdio_tri <= 1;
mdio_read_data[13] <= mdio_in;
state <= READ4;
end
READ4: begin
mdio_tri <= 1;
mdio_read_data[12] <= mdio_in;
state <= READ5;
end
READ5: begin
mdio_tri <= 1;
mdio_read_data[11] <= mdio_in;
state <= READ6;
end
READ6: begin
mdio_tri <= 1;
mdio_read_data[10] <= mdio_in;
state <= READ7;
end
READ7: begin
mdio_tri <= 1;
mdio_read_data[9] <= mdio_in;
state <= READ8;
end
READ8: begin
mdio_tri <= 1;
mdio_read_data[8] <= mdio_in;
state <= READ9;
end
READ9: begin
mdio_tri <= 1;
mdio_read_data[7] <= mdio_in;
state <= READ10;
end
READ10: begin
mdio_tri <= 1;
mdio_read_data[6] <= mdio_in;
state <= READ11;
end
READ11: begin
mdio_tri <= 1;
mdio_read_data[5] <= mdio_in;
state <= READ12;
end
READ12: begin
mdio_tri <= 1;
mdio_read_data[4] <= mdio_in;
state <= READ13;
end
READ13: begin
mdio_tri <= 1;
mdio_read_data[3] <= mdio_in;
state <= READ14;
end
READ14: begin
mdio_tri <= 1;
mdio_read_data[2] <= mdio_in;
state <= READ15;
end
READ15: begin
mdio_tri <= 1;
mdio_read_data[1] <= mdio_in;
state <= READ16;
end
READ16: begin
mdio_tri <= 1;
mdio_read_data[0] <= mdio_in;
state <= PREIDLE;
mdio_done <= 1;
end
//
// Write 16bits of data for all types of Write.
//
WRITE1:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[15];
state <= WRITE2;
end
WRITE2:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[14];
state <= WRITE3;
end
WRITE3:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[13];
state <= WRITE4;
end
WRITE4:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[12];
state <= WRITE5;
end
WRITE5:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[11];
state <= WRITE6;
end
WRITE6:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[10];
state <= WRITE7;
end
WRITE7:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[9];
state <= WRITE8;
end
WRITE8:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[8];
state <= WRITE9;
end
WRITE9:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[7];
state <= WRITE10;
end
WRITE10:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[6];
state <= WRITE11;
end
WRITE11:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[5];
state <= WRITE12;
end
WRITE12:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[4];
state <= WRITE13;
end
WRITE13:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[3];
state <= WRITE14;
end
WRITE14:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[2];
state <= WRITE15;
end
WRITE15:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[1];
state <= WRITE16;
end
WRITE16:begin
mdio_tri <= 0;
mdio_out <= mdio_write_data[0];
state <= PREIDLE;
mdio_done <= 1;
end
//
// Write 16bits of address for a Clause 45 Address transaction
//
C45_ADDR1:begin
mdio_tri <= 0;
mdio_out <= mdio_address[15];
state <= C45_ADDR2;
end
C45_ADDR2:begin
mdio_tri <= 0;
mdio_out <= mdio_address[14];
state <= C45_ADDR3;
end
C45_ADDR3:begin
mdio_tri <= 0;
mdio_out <= mdio_address[13];
state <= C45_ADDR4;
end
C45_ADDR4:begin
mdio_tri <= 0;
mdio_out <= mdio_address[12];
state <= C45_ADDR5;
end
C45_ADDR5:begin
mdio_tri <= 0;
mdio_out <= mdio_address[11];
state <= C45_ADDR6;
end
C45_ADDR6:begin
mdio_tri <= 0;
mdio_out <= mdio_address[10];
state <= C45_ADDR7;
end
C45_ADDR7:begin
mdio_tri <= 0;
mdio_out <= mdio_address[9];
state <= C45_ADDR8;
end
C45_ADDR8:begin
mdio_tri <= 0;
mdio_out <= mdio_address[8];
state <= C45_ADDR9;
end
C45_ADDR9:begin
mdio_tri <= 0;
mdio_out <= mdio_address[7];
state <= C45_ADDR10;
end
C45_ADDR10:begin
mdio_tri <= 0;
mdio_out <= mdio_address[6];
state <= C45_ADDR11;
end
C45_ADDR11:begin
mdio_tri <= 0;
mdio_out <= mdio_address[5];
state <= C45_ADDR12;
end
C45_ADDR12:begin
mdio_tri <= 0;
mdio_out <= mdio_address[4];
state <= C45_ADDR13;
end
C45_ADDR13:begin
mdio_tri <= 0;
mdio_out <= mdio_address[3];
state <= C45_ADDR14;
end
C45_ADDR14:begin
mdio_tri <= 0;
mdio_out <= mdio_address[2];
state <= C45_ADDR15;
end
C45_ADDR15:begin
mdio_tri <= 0;
mdio_out <= mdio_address[1];
state <= C45_ADDR16;
end
C45_ADDR16:begin
mdio_tri <= 0;
mdio_out <= mdio_address[0];
state <= PREIDLE;
mdio_done <= 1;
end
//
// PREIDLE allows the mdio_running bit to reset.
//
PREIDLE: begin
state <= IDLE;
end
endcase // case(state)
end // if (mdc_falling_edge)
endmodule
+62
View File
@@ -0,0 +1,62 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module rxmac_to_ll8
(input clk, input reset, input clear,
input [7:0] rx_data, input rx_valid, input rx_error, input rx_ack,
output [7:0] ll_data, output ll_sof, output ll_eof, output ll_error, output ll_src_rdy, input ll_dst_rdy );
reg [2:0] xfer_state;
localparam XFER_IDLE = 0;
localparam XFER_ACTIVE = 1;
localparam XFER_ERROR = 2;
localparam XFER_ERROR2 = 3;
localparam XFER_OVERRUN = 4;
localparam XFER_OVERRUN2 = 5;
assign ll_data = rx_data;
assign ll_src_rdy = ((rx_valid & (xfer_state != XFER_OVERRUN2) )
| (xfer_state == XFER_ERROR)
| (xfer_state == XFER_OVERRUN));
assign ll_sof = ((xfer_state==XFER_IDLE)|(xfer_state==XFER_ERROR)|(xfer_state==XFER_OVERRUN));
assign ll_eof = (rx_ack | (xfer_state==XFER_ERROR) | (xfer_state==XFER_OVERRUN));
assign ll_error = (xfer_state == XFER_ERROR)|(xfer_state==XFER_OVERRUN);
always @(posedge clk)
if(reset | clear)
xfer_state <= XFER_IDLE;
else
case(xfer_state)
XFER_IDLE :
if(rx_valid)
xfer_state <= XFER_ACTIVE;
XFER_ACTIVE :
if(rx_error)
xfer_state <= XFER_ERROR;
else if(~rx_valid)
xfer_state <= XFER_IDLE;
else if(~ll_dst_rdy)
xfer_state <= XFER_OVERRUN;
XFER_ERROR :
if(ll_dst_rdy)
xfer_state <= XFER_ERROR2;
XFER_ERROR2 :
if(~rx_error)
xfer_state <= XFER_IDLE;
XFER_OVERRUN :
if(ll_dst_rdy)
xfer_state <= XFER_OVERRUN2;
XFER_OVERRUN2 :
if(~rx_valid)
xfer_state <= XFER_IDLE;
endcase // case (xfer_state)
endmodule // rxmac_to_ll8
+72
View File
@@ -0,0 +1,72 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module simple_gemac
(input clk125, input reset,
// GMII
output GMII_GTX_CLK, output GMII_TX_EN, output GMII_TX_ER, output [7:0] GMII_TXD,
input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
// Flow Control Interface
input pause_req, input [15:0] pause_time_req, input pause_respect_en,
// Settings
input [47:0] ucast_addr, input [47:0] mcast_addr,
input pass_ucast, input pass_mcast, input pass_bcast, input pass_pause, input pass_all,
// RX Client Interface
output rx_clk, output [7:0] rx_data, output rx_valid, output rx_error, output rx_ack,
// TX Client Interface
output tx_clk, input [7:0] tx_data, input tx_valid, input tx_error, output tx_ack,
output [31:0] debug
);
localparam SGE_IFG = 8'd12; // 12 should be the absolute minimum
wire rst_rxclk, rst_txclk;
reset_sync reset_sync_tx (.clk(tx_clk),.reset_in(reset),.reset_out(rst_txclk));
reset_sync reset_sync_rx (.clk(rx_clk),.reset_in(reset),.reset_out(rst_rxclk));
wire [15:0] pause_quanta_rcvd;
wire pause_rcvd, pause_apply, paused;
simple_gemac_tx simple_gemac_tx
(.clk125(clk125),.reset(rst_txclk),
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
.tx_clk(tx_clk), .tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack),
.ifg(SGE_IFG), .mac_addr(ucast_addr),
.pause_req(pause_req), .pause_time(pause_time_req), // We request flow control
.pause_apply(pause_apply), .paused(paused) // We respect flow control
);
simple_gemac_rx simple_gemac_rx
(.reset(rst_rxclk),
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
.GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD),
.rx_clk(rx_clk), .rx_data(rx_data), .rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
.ucast_addr(ucast_addr), .mcast_addr(mcast_addr),
.pass_ucast(pass_ucast), .pass_mcast(pass_mcast), .pass_bcast(pass_bcast),
.pass_pause(pass_pause), .pass_all(pass_all),
.pause_quanta_rcvd(pause_quanta_rcvd), .pause_rcvd(pause_rcvd),
.debug(debug)
);
flow_ctrl_tx flow_ctrl_tx
(.rst(rst_txclk), .tx_clk(tx_clk),
.tx_pause_en(pause_respect_en),
.pause_quanta(pause_quanta_rcvd), // 16 bit value
.pause_quanta_val(pause_rcvd),
.pause_apply(pause_apply),
.paused(paused)
);
endmodule // simple_gemac
+185
View File
@@ -0,0 +1,185 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module simple_gemac_rx
(input reset,
input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
output rx_clk, output [7:0] rx_data, output reg rx_valid, output rx_error, output reg rx_ack,
input [47:0] ucast_addr, input [47:0] mcast_addr,
input pass_ucast, input pass_mcast, input pass_bcast, input pass_pause, input pass_all,
output reg [15:0] pause_quanta_rcvd, output pause_rcvd,
output [31:0] debug );
localparam RX_IDLE = 0;
localparam RX_PREAMBLE = 1;
localparam RX_FRAME = 2;
localparam RX_GOODFRAME = 3;
localparam RX_DO_PAUSE = 4;
localparam RX_ERROR = 5;
localparam RX_DROP = 6;
localparam RX_PAUSE = 16;
localparam RX_PAUSE_CHK88 = RX_PAUSE + 5;
localparam RX_PAUSE_CHK08 = RX_PAUSE_CHK88 + 1;
localparam RX_PAUSE_CHK00 = RX_PAUSE_CHK08 + 1;
localparam RX_PAUSE_CHK01 = RX_PAUSE_CHK00 + 1;
localparam RX_PAUSE_STORE_MSB = RX_PAUSE_CHK01 + 1;
localparam RX_PAUSE_STORE_LSB = RX_PAUSE_STORE_MSB + 1;
localparam RX_PAUSE_WAIT_CRC = RX_PAUSE_STORE_LSB + 1;
reg [7:0] rxd_d1;
reg rx_dv_d1, rx_er_d1;
assign rx_clk = GMII_RX_CLK;
always @(posedge rx_clk)
begin
rx_dv_d1 <= GMII_RX_DV;
rx_er_d1 <= GMII_RX_ER;
rxd_d1 <= GMII_RXD;
end
reg [7:0] rx_state;
wire [7:0] rxd_del;
wire rx_dv_del, rx_er_del;
reg go_filt;
wire match_crc;
wire clear_crc = rx_state == RX_IDLE;
wire calc_crc = (rx_state == RX_FRAME) | rx_state[7:4]==4'h1;
localparam DELAY = 6;
delay_line #(.WIDTH(10)) rx_delay
(.clk(rx_clk), .delay(DELAY), .din({rx_dv_d1,rx_er_d1,rxd_d1}),.dout({rx_dv_del,rx_er_del,rxd_del}));
always @(posedge rx_clk)
if(reset)
rx_ack <= 0;
else
rx_ack <= (rx_state == RX_GOODFRAME);
wire is_ucast, is_bcast, is_mcast, is_pause, is_any_ucast;
wire keep_packet = (pass_all & is_any_ucast) | (pass_ucast & is_ucast) | (pass_mcast & is_mcast) |
(pass_bcast & is_bcast) | (pass_pause & is_pause);
assign rx_data = rxd_del;
assign rx_error = (rx_state == RX_ERROR);
always @(posedge rx_clk)
if(reset)
rx_valid <= 0;
else if(keep_packet)
rx_valid <= 1;
else if((rx_state == RX_IDLE)|(rx_state == RX_ERROR))
rx_valid <= 0;
address_filter af_ucast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
.address(ucast_addr), .match(is_ucast), .done());
address_filter af_mcast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
.address(mcast_addr), .match(is_mcast), .done());
address_filter af_bcast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
.address(48'hFFFF_FFFF_FFFF), .match(is_bcast), .done());
address_filter af_pause (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
.address(48'h0180_c200_0001), .match(is_pause), .done());
address_filter_promisc af_promisc (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
.match(is_any_ucast), .done());
always @(posedge rx_clk)
go_filt <= (rx_state==RX_PREAMBLE) & (rxd_d1 == 8'hD5);
reg [15:0] pkt_len_ctr;
always @(posedge rx_clk)
if(reset |(rx_state == RX_IDLE))
pkt_len_ctr <= 0;
else
pkt_len_ctr <= pkt_len_ctr + 1;
localparam MIN_PAUSE_LEN = 71; // 6
wire pkt_long_enough = (pkt_len_ctr >= MIN_PAUSE_LEN);
always @(posedge rx_clk)
if(reset)
rx_state <= RX_IDLE;
else
if(rx_er_d1 & ~((rxd_d1==8'h0F)&(~rx_dv_d1))) //Handle odd-length pkts from Xilinx IP.
rx_state <= RX_ERROR;
else
case(rx_state)
RX_IDLE :
if(rx_dv_d1)
if(rxd_d1 == 8'h55)
rx_state <= RX_PREAMBLE;
else
rx_state <= RX_ERROR;
RX_PREAMBLE :
if(~rx_dv_d1)
rx_state <= RX_ERROR;
else if(rxd_d1 == 8'hD5)
rx_state <= RX_FRAME;
else if(rxd_d1 != 8'h55)
rx_state <= RX_ERROR;
RX_FRAME :
if(is_pause)
rx_state <= RX_PAUSE;
else if(~rx_dv_d1)
if(match_crc)
rx_state <= RX_GOODFRAME;
else
rx_state <= RX_ERROR;
RX_PAUSE_CHK88 :
if(rxd_d1 != 8'h88)
rx_state <= RX_DROP;
else
rx_state <= RX_PAUSE_CHK08;
RX_PAUSE_CHK08 :
if(rxd_d1 != 8'h08)
rx_state <= RX_DROP;
else
rx_state <= RX_PAUSE_CHK00;
RX_PAUSE_CHK00 :
if(rxd_d1 != 8'h00)
rx_state <= RX_DROP;
else
rx_state <= RX_PAUSE_CHK01;
RX_PAUSE_CHK01 :
if(rxd_d1 != 8'h01)
rx_state <= RX_DROP;
else
rx_state <= RX_PAUSE_STORE_MSB;
RX_PAUSE_WAIT_CRC :
if(pkt_long_enough)
if(match_crc)
rx_state <= RX_DO_PAUSE;
else
rx_state <= RX_DROP;
RX_DO_PAUSE :
rx_state <= RX_IDLE;
RX_GOODFRAME :
rx_state <= RX_IDLE;
RX_DROP, RX_ERROR :
if(~rx_dv_d1)
rx_state <= RX_IDLE;
default
rx_state <= rx_state + 1;
endcase // case (rx_state)
assign pause_rcvd = (rx_state == RX_DO_PAUSE);
crc crc_check(.clk(rx_clk),.reset(reset),.clear(clear_crc),
.data(rxd_d1),.calc(calc_crc),.crc_out(),.match(match_crc));
always @(posedge rx_clk)
if(reset)
pause_quanta_rcvd <= 0;
else if(rx_state == RX_PAUSE_STORE_MSB)
pause_quanta_rcvd[15:8] <= rxd_d1;
else if(rx_state == RX_PAUSE_STORE_LSB)
pause_quanta_rcvd[7:0] <= rxd_d1;
assign debug = rx_state;
endmodule // simple_gemac_rx
+208
View File
@@ -0,0 +1,208 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module simple_gemac_tb;
`include "eth_tasks.v"
reg clk = 0;
reg reset = 1;
initial #1000 reset = 0;
always #50 clk = ~clk;
wire GMII_RX_DV, GMII_RX_ER, GMII_TX_EN, GMII_TX_ER, GMII_GTX_CLK;
wire [7:0] GMII_RXD, GMII_TXD;
wire rx_valid, rx_error, rx_ack;
wire tx_ack, tx_valid, tx_error;
wire [7:0] rx_data, tx_data;
reg [15:0] pause_time;
reg pause_req = 0;
wire GMII_RX_CLK = GMII_GTX_CLK;
reg [7:0] FORCE_DAT_ERR = 0;
reg FORCE_ERR = 0;
// Loopback
assign GMII_RX_DV = GMII_TX_EN;
assign GMII_RX_ER = GMII_TX_ER | FORCE_ERR;
assign GMII_RXD = GMII_TXD ^ FORCE_DAT_ERR;
wire [47:0] ucast_addr = 48'hF1F2_F3F4_F5F6;
wire [47:0] mcast_addr = 0;
wire pass_ucast =1, pass_mcast=0, pass_bcast=1, pass_pause=0, pass_all=0;
simple_gemac simple_gemac
(.clk125(clk), .reset(reset),
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
.GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD),
.pause_req(pause_req), .pause_time(pause_time), .pause_en(1),
.ucast_addr(ucast_addr), .mcast_addr(mcast_addr),
.pass_ucast(pass_ucast), .pass_mcast(pass_mcast), .pass_bcast(pass_bcast),
.pass_pause(pass_pause), .pass_all(pass_all),
.rx_clk(rx_clk), .rx_data(rx_data),
.rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
.tx_clk(tx_clk), .tx_data(tx_data),
.tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack)
);
wire rx_ll_sof, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy;
wire rx_ll_sof2, rx_ll_eof2, rx_ll_src_rdy2;
reg rx_ll_dst_rdy2 = 1;
wire [7:0] rx_ll_data, rx_ll_data2;
wire rx_ll_error, rx_ll_error2;
rxmac_to_ll8 rx_adapt
(.clk(clk), .reset(reset), .clear(0),
.rx_data(rx_data), .rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
.ll_data(rx_ll_data), .ll_sof(rx_ll_sof), .ll_eof(rx_ll_eof), .ll_error(rx_ll_error),
.ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy));
ll8_shortfifo rx_sfifo
(.clk(clk), .reset(reset), .clear(0),
.datain(rx_ll_data), .sof_i(rx_ll_sof), .eof_i(rx_ll_eof),
.error_i(rx_ll_error), .src_rdy_i(rx_ll_src_rdy), .dst_rdy_o(rx_ll_dst_rdy),
.dataout(rx_ll_data2), .sof_o(rx_ll_sof2), .eof_o(rx_ll_eof2),
.error_o(rx_ll_error2), .src_rdy_o(rx_ll_src_rdy2), .dst_rdy_i(rx_ll_dst_rdy2));
wire tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy;
reg tx_ll_sof2=0, tx_ll_eof2=0;
reg tx_ll_src_rdy2 = 0;
wire tx_ll_dst_rdy2;
wire [7:0] tx_ll_data;
reg [7:0] tx_ll_data2 = 0;
wire tx_ll_error;
wire tx_ll_error2 = 0;
ll8_shortfifo tx_sfifo
(.clk(clk), .reset(reset), .clear(clear),
.datain(tx_ll_data2), .sof_i(tx_ll_sof2), .eof_i(tx_ll_eof2),
.error_i(tx_ll_error2), .src_rdy_i(tx_ll_src_rdy2), .dst_rdy_o(tx_ll_dst_rdy2),
.dataout(tx_ll_data), .sof_o(tx_ll_sof), .eof_o(tx_ll_eof),
.error_o(tx_ll_error), .src_rdy_o(tx_ll_src_rdy), .dst_rdy_i(tx_ll_dst_rdy));
ll8_to_txmac ll8_to_txmac
(.clk(clk), .reset(reset), .clear(clear),
.ll_data(tx_ll_data), .ll_sof(tx_ll_sof), .ll_eof(tx_ll_eof),
.ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy),
.tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack));
initial $dumpfile("simple_gemac_tb.vcd");
initial $dumpvars(0,simple_gemac_tb);
integer i;
reg [7:0] pkt_rom[0:65535];
reg [1023:0] ROMFile;
initial
for (i=0;i<65536;i=i+1)
pkt_rom[i] <= 8'h0;
initial
begin
@(negedge reset);
repeat (10)
@(posedge clk);
SendFlowCtrl(16'h0007); // Send flow control
@(posedge clk);
#30000;
@(posedge clk);
SendFlowCtrl(16'h0009); // Increas flow control before it expires
#10000;
@(posedge clk);
SendFlowCtrl(16'h0000); // Cancel flow control before it expires
@(posedge clk);
SendPacket_to_ll8(8'hAA,10); // This packet gets dropped by the filters
repeat (10)
@(posedge clk);
SendPacketFromFile_ll8(60,0,0); // The rest are valid packets
repeat (10)
@(posedge clk);
SendPacketFromFile_ll8(61,0,0);
repeat (10)
@(posedge clk);
SendPacketFromFile_ll8(62,0,0);
repeat (10)
@(posedge clk);
SendPacketFromFile_ll8(63,0,0);
repeat (1)
@(posedge clk);
SendPacketFromFile_ll8(64,0,0);
repeat (10)
@(posedge clk);
SendPacketFromFile_ll8(59,0,0);
repeat (1)
@(posedge clk);
SendPacketFromFile_ll8(58,0,0);
repeat (1)
@(posedge clk);
SendPacketFromFile_ll8(100,0,0);
repeat (1)
@(posedge clk);
SendPacketFromFile_ll8(200,150,30); // waiting 14 empties the fifo, 15 underruns
repeat (1)
@(posedge clk);
SendPacketFromFile_ll8(100,0,30);
#10000 $finish;
end
// Force a CRC error
initial
begin
#90000;
@(posedge clk);
FORCE_DAT_ERR <= 8'h10;
@(posedge clk);
FORCE_DAT_ERR <= 8'h00;
end
// Force an RX_ER error (i.e. link loss)
initial
begin
#116000;
@(posedge clk);
FORCE_ERR <= 1;
@(posedge clk);
FORCE_ERR <= 0;
end
// Cause receive fifo to fill, causing an RX overrun
initial
begin
#126000;
@(posedge clk);
rx_ll_dst_rdy2 <= 0;
repeat (30) // Repeat of 14 fills the shortfifo, but works. 15 overflows
@(posedge clk);
rx_ll_dst_rdy2 <= 1;
end
// Tests: Send and recv flow control, send and receive good packets, RX CRC err, RX_ER, RX overrun, TX underrun
// Still need to test: CRC errors on Pause Frames
always @(posedge clk)
if(rx_ll_src_rdy2 & rx_ll_dst_rdy2)
begin
if(rx_ll_sof2 & ~rx_ll_eof2)
$display("RX-PKT-START %d",$time);
$display("RX-PKT SOF %d EOF %d ERR%d DAT %x",rx_ll_sof2,rx_ll_eof2,rx_ll_error2,rx_ll_data2);
if(rx_ll_eof2 & ~rx_ll_sof2)
$display("RX-PKT-END %d",$time);
end
endmodule // simple_gemac_tb
+262
View File
@@ -0,0 +1,262 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module simple_gemac_tx
(input clk125, input reset,
output GMII_GTX_CLK, output reg GMII_TX_EN, output reg GMII_TX_ER, output reg [7:0] GMII_TXD,
output tx_clk, input [7:0] tx_data, input tx_valid, input tx_error, output tx_ack,
input [7:0] ifg, input [47:0] mac_addr,
input pause_req, input [15:0] pause_time,
input pause_apply, output reg paused
);
reg tx_en_pre, tx_er_pre;
reg [7:0] txd_pre;
assign GMII_GTX_CLK = clk125;
assign tx_clk = clk125;
reg [7:0] tx_state;
reg [7:0] ifg_ctr;
reg [15:0] frame_len_ctr;
reg [7:0] pause_ctr, pause_dat;
wire in_ifg = (ifg_ctr != 0);
wire [31:0] crc_out;
localparam TX_IDLE = 0;
localparam TX_PREAMBLE = 1;
localparam TX_SOF_DEL = TX_PREAMBLE + 7;
localparam TX_FIRSTBYTE = TX_SOF_DEL + 1;
localparam TX_IN_FRAME = TX_FIRSTBYTE + 1;
localparam TX_IN_FRAME_2 = TX_IN_FRAME + 1;
localparam TX_PAD = TX_IN_FRAME_2 + 1;
localparam TX_CRC_0 = 16;
localparam TX_CRC_1 = TX_CRC_0 + 1;
localparam TX_CRC_2 = TX_CRC_0 + 2;
localparam TX_CRC_3 = TX_CRC_0 + 3;
localparam TX_ERROR = 32;
localparam TX_PAUSE = 55;
localparam TX_PAUSE_SOF = TX_PAUSE + 7;
localparam TX_PAUSE_FIRST = TX_PAUSE_SOF + 1;
localparam TX_PAUSE_END = TX_PAUSE_SOF + 18;
localparam MIN_FRAME_LEN = 64 + 8 - 4; // Min frame length includes preamble but not CRC
localparam MAX_FRAME_LEN = 8192; // How big are the jumbo frames we want to handle?
always @(posedge tx_clk)
if(reset |(tx_state == TX_IDLE))
frame_len_ctr <= 0;
else
frame_len_ctr <= frame_len_ctr + 1;
reg send_pause;
reg [15:0] pause_time_held;
always @(posedge tx_clk)
if(reset)
send_pause <= 0;
else if(pause_req)
send_pause <= 1;
else if(tx_state == TX_PAUSE)
send_pause <= 0;
always @(posedge tx_clk)
if(pause_req)
pause_time_held <= pause_time;
always @(posedge tx_clk)
if(reset)
tx_state <= TX_IDLE;
else
case(tx_state)
TX_IDLE :
if(~in_ifg)
if(send_pause)
tx_state <= TX_PAUSE;
else if(tx_valid & ~pause_apply)
tx_state <= TX_PREAMBLE;
TX_FIRSTBYTE :
if(tx_error)
tx_state <= TX_ERROR; // underrun
else if(~tx_valid)
tx_state <= TX_PAD;
else
tx_state <= TX_IN_FRAME;
TX_IN_FRAME :
if(tx_error)
tx_state <= TX_ERROR; // underrun
else if(~tx_valid)
tx_state <= TX_PAD;
else if(frame_len_ctr == MIN_FRAME_LEN - 1)
tx_state <= TX_IN_FRAME_2;
TX_IN_FRAME_2 :
if(tx_error)
tx_state <= TX_ERROR; // underrun
else if(~tx_valid)
tx_state <= TX_CRC_0;
TX_PAD :
if(frame_len_ctr == MIN_FRAME_LEN)
tx_state <= TX_CRC_0;
TX_CRC_3 :
tx_state <= TX_IDLE;
TX_ERROR :
tx_state <= TX_IDLE;
TX_PAUSE_END :
tx_state <= TX_PAD;
default :
tx_state <= tx_state + 1;
endcase // case (tx_state)
always @(posedge tx_clk)
if(reset)
begin
tx_en_pre <= 0;
tx_er_pre <= 0;
txd_pre <= 0;
end
else
casex(tx_state)
TX_IDLE :
begin
tx_en_pre <= 0;
tx_er_pre <= 0;
txd_pre <= 0;
end
TX_PREAMBLE, TX_PAUSE :
begin
txd_pre <= 8'h55;
tx_en_pre <= 1;
end
TX_SOF_DEL, TX_PAUSE_SOF :
txd_pre <= 8'hD5;
TX_FIRSTBYTE, TX_IN_FRAME, TX_IN_FRAME_2 :
txd_pre <= tx_valid ? tx_data : 0;
TX_ERROR :
begin
tx_er_pre <= 1;
txd_pre <= 0;
end
TX_CRC_3 :
tx_en_pre <= 0;
TX_PAD :
txd_pre <= 0;
TX_PAUSE_FIRST, 8'b01xx_xxxx : // In Pause Frame
txd_pre <= pause_dat;
endcase // case (tx_state)
localparam SGE_FLOW_CTRL_ADDR = 48'h01_80_C2_00_00_01;
always @(posedge tx_clk)
case(tx_state)
TX_PAUSE_SOF :
pause_dat <= SGE_FLOW_CTRL_ADDR[47:40]; // Note everything must be 1 cycle early
TX_PAUSE_SOF + 1:
pause_dat <= SGE_FLOW_CTRL_ADDR[39:32];
TX_PAUSE_SOF + 2:
pause_dat <= SGE_FLOW_CTRL_ADDR[31:24];
TX_PAUSE_SOF + 3:
pause_dat <= SGE_FLOW_CTRL_ADDR[23:16];
TX_PAUSE_SOF + 4:
pause_dat <= SGE_FLOW_CTRL_ADDR[15:8];
TX_PAUSE_SOF + 5:
pause_dat <= SGE_FLOW_CTRL_ADDR[7:0];
TX_PAUSE_SOF + 6:
pause_dat <= mac_addr[47:40];
TX_PAUSE_SOF + 7:
pause_dat <= mac_addr[39:32];
TX_PAUSE_SOF + 8:
pause_dat <= mac_addr[31:24];
TX_PAUSE_SOF + 9:
pause_dat <= mac_addr[23:16];
TX_PAUSE_SOF + 10:
pause_dat <= mac_addr[15:8];
TX_PAUSE_SOF + 11:
pause_dat <= mac_addr[7:0];
TX_PAUSE_SOF + 12:
pause_dat <= 8'h88; // Type = 8808 = MAC ctrl frame
TX_PAUSE_SOF + 13:
pause_dat <= 8'h08;
TX_PAUSE_SOF + 14:
pause_dat <= 8'h00; // Opcode = 0001 = PAUSE
TX_PAUSE_SOF + 15:
pause_dat <= 8'h01;
TX_PAUSE_SOF + 16:
pause_dat <= pause_time_held[15:8];
TX_PAUSE_SOF + 17:
pause_dat <= pause_time_held[7:0];
endcase // case (tx_state)
wire start_ifg = (tx_state == TX_CRC_3);
always @(posedge tx_clk)
if(reset)
ifg_ctr <= 100;
else if(start_ifg)
ifg_ctr <= ifg;
else if(ifg_ctr != 0)
ifg_ctr <= ifg_ctr - 1;
wire clear_crc = (tx_state == TX_IDLE);
wire calc_crc =
(tx_state==TX_IN_FRAME) |
(tx_state==TX_IN_FRAME_2) |
(tx_state==TX_PAD) |
(tx_state[6]);
crc crc(.clk(tx_clk), .reset(reset), .clear(clear_crc),
.data(txd_pre), .calc(calc_crc), .crc_out(crc_out));
assign tx_ack = (tx_state == TX_FIRSTBYTE);
always @(posedge tx_clk)
begin
GMII_TX_EN <= tx_en_pre;
GMII_TX_ER <= tx_er_pre;
case(tx_state)
TX_CRC_0 :
GMII_TXD <= crc_out[31:24];
TX_CRC_1 :
GMII_TXD <= crc_out[23:16];
TX_CRC_2 :
GMII_TXD <= crc_out[15:8];
TX_CRC_3 :
GMII_TXD <= crc_out[7:0];
default :
GMII_TXD <= txd_pre;
endcase // case (tx_state)
end
// report that we are paused only when we get back to IDLE
always @(posedge tx_clk)
if(reset)
paused <= 0;
else if(~pause_apply)
paused <= 0;
else if(tx_state == TX_IDLE)
paused <= 1;
endmodule // simple_gemac_tx
// Testing code
/*
reg [7:0] crc_ctr;
reg calc_crc_d1;
always @(posedge tx_clk)
calc_crc_d1 <= calc_crc;
always @(posedge tx_clk)
if(reset)
crc_ctr <= 0;
else if(calc_crc)
crc_ctr <= crc_ctr+1;
else if(calc_crc_d1)
$display("CRC COUNT = %d",crc_ctr);
else
crc_ctr <= 0;
*/
+1
View File
@@ -0,0 +1 @@
iverilog -Wimplict -Wportbind -y ../fifo/ -y ../models/ -y . -y miim -y ../control -y ../coregen/ -y ../control_lib/ -o simple_gemac_wrapper_tb simple_gemac_wrapper_tb.v
+185
View File
@@ -0,0 +1,185 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module simple_gemac_wrapper
#(parameter RX_FLOW_CTRL=0,
parameter PORTNUM=8'd0)
(input clk125, input reset,
// GMII
output GMII_GTX_CLK, output GMII_TX_EN, output GMII_TX_ER, output [7:0] GMII_TXD,
input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
// Client FIFO Interfaces
input sys_clk,
output [63:0] rx_tdata, output [3:0] rx_tuser, output rx_tlast, output rx_tvalid, input rx_tready,
input [63:0] tx_tdata, input [3:0] tx_tuser, input tx_tlast, input tx_tvalid, output tx_tready,
// Wishbone Bus
input wb_clk_i,
input wb_rst_i,
input [7:0] wb_adr_i,
input [31:0] wb_dat_i,
input wb_we_i,
input wb_stb_i,
input wb_cyc_i,
output [31:0] wb_dat_o,
output wb_ack_o,
output wb_int_o,
// MDIO
output mdc,
input mdio_out,
output mdio_tri,
output mdio_in,
// Debug
output [31:0] debug_rx,
output [31:0] debug_tx
);
wire clear = 0;
wire [7:0] rx_data, tx_data;
wire tx_clk, tx_valid, tx_error, tx_ack;
wire rx_clk, rx_valid, rx_error, rx_ack;
wire pause_req;
wire pause_request_en, pause_respect_en;
wire [15:0] pause_time, pause_thresh, pause_time_req, rx_fifo_space;
wire [31:0] debug_state;
wire tx_reset, rx_reset;
reset_sync reset_sync_tx (.clk(tx_clk),.reset_in(reset),.reset_out(tx_reset));
reset_sync reset_sync_rx (.clk(rx_clk),.reset_in(reset),.reset_out(rx_reset));
simple_gemac simple_gemac
(.clk125(clk125), .reset(reset),
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
.GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD),
.pause_req(RX_FLOW_CTRL ? pause_req : 1'b0), .pause_time_req(RX_FLOW_CTRL ? pause_time_req : 16'd0),
.pause_respect_en(pause_respect_en),
.ucast_addr(48'h0), .mcast_addr(48'h0),
.pass_ucast(1'b0), .pass_mcast(1'b0), .pass_bcast(1'b0),
.pass_pause(1'b0), .pass_all(1'b1),
.rx_clk(rx_clk), .rx_data(rx_data),
.rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
.tx_clk(tx_clk), .tx_data(tx_data),
.tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack),
.debug(debug_state)
);
assign pause_respect_en = 1'b0;
assign pause_request_en = 1'b0;
// /////////////////////////////////////////////////////////////////////////////////////
// RX FIFO Chain
wire rx_ll_eof, rx_ll_error, rx_ll_src_rdy, rx_ll_dst_rdy;
wire [7:0] rx_ll_data;
wire [63:0] rx_tdata_int;
wire [3:0] rx_tuser_int;
wire rx_tlast_int, rx_tvalid_int, rx_tready_int;
rxmac_to_ll8 rxmac_to_ll8
(.clk(rx_clk), .reset(rx_reset), .clear(0),
.rx_data(rx_data), .rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
.ll_data(rx_ll_data), .ll_sof(), .ll_eof(rx_ll_eof), .ll_error(rx_ll_error), // ignore sof
.ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy));
ll8_to_axi64 #(.START_BYTE(6), .LABEL(PORTNUM)) ll8_to_axi64
(.clk(rx_clk), .reset(rx_reset), .clear(0),
.ll_data(rx_ll_data), .ll_eof(rx_ll_eof), .ll_error(rx_ll_error), .ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy),
.axi64_tdata(rx_tdata_int), .axi64_tlast(rx_tlast_int), .axi64_tuser(rx_tuser_int),
.axi64_tvalid(rx_tvalid_int), .axi64_tready(rx_tready_int));
axi64_8k_2clk_fifo rxfifo_2clk
(.s_aresetn(~rx_reset),
.s_aclk(rx_clk), .s_axis_tvalid(rx_tvalid_int), .s_axis_tready(rx_tready_int),
.s_axis_tdata(rx_tdata_int), .s_axis_tlast(rx_tlast_int), .s_axis_tuser(rx_tuser_int),
.axis_wr_data_count(),
.m_aclk(sys_clk), .m_axis_tvalid(rx_tvalid), .m_axis_tready(rx_tready),
.m_axis_tdata(rx_tdata), .m_axis_tlast(rx_tlast), .m_axis_tuser(rx_tuser),
.axis_rd_data_count() );
// /////////////////////////////////////////////////////////////////////////////////////
// TX FIFO Chain
wire tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy;
wire [7:0] tx_ll_data;
wire [63:0] tx_tdata_int;
wire [3:0] tx_tuser_int;
wire tx_tlast_int, tx_tvalid_int, tx_tready_int;
axi64_8k_2clk_fifo txfifo_2clk
(.s_aresetn(~tx_reset),
.s_aclk(sys_clk), .s_axis_tvalid(tx_tvalid), .s_axis_tready(tx_tready),
.s_axis_tdata(tx_tdata), .s_axis_tlast(tx_tlast), .s_axis_tuser(tx_tuser),
.axis_wr_data_count(),
.m_aclk(tx_clk), .m_axis_tvalid(tx_tvalid_int), .m_axis_tready(tx_tready_int),
.m_axis_tdata(tx_tdata_int), .m_axis_tlast(tx_tlast_int), .m_axis_tuser(tx_tuser_int),
.axis_rd_data_count() );
axi64_to_ll8 #(.START_BYTE(6)) axi64_to_ll8
(.clk(tx_clk), .reset(tx_reset), .clear(0),
.axi64_tdata(tx_tdata_int), .axi64_tlast(tx_tlast_int), .axi64_tuser(tx_tuser_int),
.axi64_tvalid(tx_tvalid_int), .axi64_tready(tx_tready_int),
.ll_data(tx_ll_data), .ll_eof(tx_ll_eof), .ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy));
ll8_to_txmac ll8_to_txmac
(.clk(tx_clk), .reset(tx_reset), .clear(clear),
.ll_data(tx_ll_data), .ll_eof(tx_ll_eof), .ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy),
.tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack));
// /////////////////////////////////////////////////////////////////////////////////////
// Flow Control
generate
if(RX_FLOW_CTRL==1)
flow_ctrl_rx flow_ctrl_rx
(.pause_request_en(pause_request_en), .pause_time(pause_time), .pause_thresh(pause_thresh),
.rx_clk(rx_clk), .rx_reset(rx_reset), .rx_fifo_space(rx_fifo_space),
.tx_clk(tx_clk), .tx_reset(tx_reset), .pause_req(pause_req), .pause_time_req(pause_time_req));
endgenerate
assign debug_tx = { { tx_ll_data },
{ 1'b0, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy, 4'b0 },
{ tx_valid, tx_error, tx_ack, 5'b0},
{ tx_data} };
assign debug_rx = { { rx_ll_data },
{ rx_ll_error, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy, 4'b0 },
{ rx_valid, rx_error, rx_ack, 5'b0},
{ rx_data} };
//
// Wishbone MDIO controller
//
mdio mdio_gige_inst
(
.wb_clk_i(wb_clk_i),
.wb_rst_i(wb_rst_i),
.wb_adr_i(wb_adr_i),
.wb_dat_i(wb_dat_i),
.wb_we_i(wb_we_i),
.wb_stb_i(wb_stb_i),
.wb_cyc_i(wb_cyc_i),
.wb_dat_o(wb_dat_o),
.wb_ack_o(wb_ack_o),
.wb_int_o(wb_int_o),
.mdc(mdc),
.mdio_out(mdio_in), // Switch sense of in and out here for master and slave.
.mdio_tri(mdio_tri),
.mdio_in(mdio_out) // Switch sense of in and out here for master and slave.
);
endmodule // simple_gemac_wrapper
+213
View File
@@ -0,0 +1,213 @@
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module simple_gemac_wrapper_tb;
`include "eth_tasks_f36.v"
reg reset = 1;
initial #1000 reset = 0;
wire wb_rst = reset;
reg eth_clk = 0;
always #50 eth_clk = ~eth_clk;
reg wb_clk = 0;
always #173 wb_clk = ~wb_clk;
reg sys_clk = 0;
always #77 sys_clk = ~ sys_clk;
wire GMII_RX_DV, GMII_RX_ER, GMII_TX_EN, GMII_TX_ER, GMII_GTX_CLK;
wire [7:0] GMII_RXD, GMII_TXD;
wire rx_valid, rx_error, rx_ack;
wire tx_ack, tx_valid, tx_error;
wire [7:0] rx_data, tx_data;
wire GMII_RX_CLK = GMII_GTX_CLK;
reg [7:0] FORCE_DAT_ERR = 0;
reg FORCE_ERR = 0;
// Loopback
assign GMII_RX_DV = GMII_TX_EN;
assign GMII_RX_ER = GMII_TX_ER | FORCE_ERR;
assign GMII_RXD = GMII_TXD ^ FORCE_DAT_ERR;
wire [31:0] wb_dat_o;
reg [31:0] wb_dat_i;
reg [7:0] wb_adr;
reg wb_stb=0, wb_cyc=0, wb_we=0;
wire wb_ack;
reg [35:0] tx_f36_data=0;
reg tx_f36_src_rdy = 0;
wire tx_f36_dst_rdy;
wire [35:0] rx_f36_data;
wire rx_f36_src_rdy;
wire rx_f36_dst_rdy = 1;
simple_gemac_wrapper simple_gemac_wrapper
(.clk125(eth_clk), .reset(reset),
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
.GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD),
.sys_clk(sys_clk), .rx_f36_data(rx_f36_data), .rx_f36_src_rdy(rx_f36_src_rdy), .rx_f36_dst_rdy(rx_f36_dst_rdy),
.tx_f36_data(tx_f36_data), .tx_f36_src_rdy(tx_f36_src_rdy), .tx_f36_dst_rdy(tx_f36_dst_rdy),
.wb_clk(wb_clk), .wb_rst(wb_rst), .wb_stb(wb_stb), .wb_cyc(wb_cyc), .wb_ack(wb_ack), .wb_we(wb_we),
.wb_adr(wb_adr), .wb_dat_i(wb_dat_i), .wb_dat_o(wb_dat_o),
.mdio(), .mdc(),
.debug() );
initial $dumpfile("simple_gemac_wrapper_tb.vcd");
initial $dumpvars(0,simple_gemac_wrapper_tb);
integer i;
reg [7:0] pkt_rom[0:65535];
reg [1023:0] ROMFile;
initial
for (i=0;i<65536;i=i+1)
pkt_rom[i] <= 8'h0;
initial
begin
@(negedge reset);
repeat (10)
@(posedge wb_clk);
WishboneWR(0,6'b111101);
WishboneWR(4,16'hA0B0);
WishboneWR(8,32'hC0D0_A1B1);
WishboneWR(12,16'h0000);
WishboneWR(16,32'h0000_0000);
@(posedge eth_clk);
SendFlowCtrl(16'h0007); // Send flow control
@(posedge eth_clk);
#30000;
@(posedge eth_clk);
SendFlowCtrl(16'h0009); // Increase flow control before it expires
#10000;
@(posedge eth_clk);
SendFlowCtrl(16'h0000); // Cancel flow control before it expires
@(posedge eth_clk);
repeat (1000)
@(posedge sys_clk);
SendPacket_to_fifo36(32'hA0B0C0D0,10); // This packet gets dropped by the filters
repeat (1000)
@(posedge sys_clk);
SendPacket_to_fifo36(32'hAABBCCDD,100); // This packet gets dropped by the filters
repeat (10)
@(posedge sys_clk);
/*
SendPacketFromFile_f36(60,0,0); // The rest are valid packets
repeat (10)
@(posedge clk);
SendPacketFromFile_f36(61,0,0);
repeat (10)
@(posedge clk);
SendPacketFromFile_f36(62,0,0);
repeat (10)
@(posedge clk);
SendPacketFromFile_f36(63,0,0);
repeat (1)
@(posedge clk);
SendPacketFromFile_f36(64,0,0);
repeat (10)
@(posedge clk);
SendPacketFromFile_f36(59,0,0);
repeat (1)
@(posedge clk);
SendPacketFromFile_f36(58,0,0);
repeat (1)
@(posedge clk);
SendPacketFromFile_f36(100,0,0);
repeat (1)
@(posedge clk);
SendPacketFromFile_f36(200,150,30); // waiting 14 empties the fifo, 15 underruns
repeat (1)
@(posedge clk);
SendPacketFromFile_f36(100,0,30);
*/
#100000 $finish;
end
// Force a CRC error
initial
begin
#90000;
@(posedge eth_clk);
FORCE_DAT_ERR <= 8'h10;
@(posedge eth_clk);
FORCE_DAT_ERR <= 8'h00;
end
// Force an RX_ER error (i.e. link loss)
initial
begin
#116000;
@(posedge eth_clk);
FORCE_ERR <= 1;
@(posedge eth_clk);
FORCE_ERR <= 0;
end
/*
// Cause receive fifo to fill, causing an RX overrun
initial
begin
#126000;
@(posedge clk);
rx_ll_dst_rdy2 <= 0;
repeat (30) // Repeat of 14 fills the shortfifo, but works. 15 overflows
@(posedge clk);
rx_ll_dst_rdy2 <= 1;
end
*/
// Tests: Send and recv flow control, send and receive good packets, RX CRC err, RX_ER, RX overrun, TX underrun
// Still need to test: CRC errors on Pause Frames, MDIO, wishbone
task WishboneWR;
input [7:0] adr;
input [31:0] value;
begin
wb_adr <= adr;
wb_dat_i <= value;
wb_stb <= 1;
wb_cyc <= 1;
wb_we <= 1;
while (~wb_ack)
@(posedge wb_clk);
@(posedge wb_clk);
wb_stb <= 0;
wb_cyc <= 0;
wb_we <= 0;
end
endtask // WishboneWR
/*
always @(posedge clk)
if(rx_ll_src_rdy2 & rx_ll_dst_rdy2)
begin
if(rx_ll_sof2 & ~rx_ll_eof2)
$display("RX-PKT-START %d",$time);
$display("RX-PKT SOF %d EOF %d ERR%d DAT %x",rx_ll_sof2,rx_ll_eof2,rx_ll_error2,rx_ll_data2);
if(rx_ll_eof2 & ~rx_ll_sof2)
$display("RX-PKT-END %d",$time);
end
*/
endmodule // simple_gemac_wrapper_tb
+66
View File
@@ -0,0 +1,66 @@
ff
ff
ff
ff
ff
ff
08
00
07
5c
2e
e4
08
06
00
01
08
04
06
02
00
01
08
00
07
5c
2e
e4
03
64
00
00
00
00
00
00
02
64
00
3a
f3
5c
4f
12
01
10
00
01
00
00
00
00
00
00
20
41
42
41
08
00
AA
BB
CC
DD
EE
FF