diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-01-23 16:10:22 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2020-01-28 09:35:36 -0800 |
commit | bafa9d95453387814ef25e6b6256ba8db2df612f (patch) | |
tree | 39ba24b5b67072d354775272e687796bb511848d /fpga/usrp2/simple_gemac | |
parent | 3075b981503002df3115d5f1d0b97d2619ba30f2 (diff) | |
download | uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.gz uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.bz2 uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.zip |
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>
Diffstat (limited to 'fpga/usrp2/simple_gemac')
29 files changed, 3689 insertions, 0 deletions
diff --git a/fpga/usrp2/simple_gemac/.gitignore b/fpga/usrp2/simple_gemac/.gitignore new file mode 100644 index 000000000..17f35e962 --- /dev/null +++ b/fpga/usrp2/simple_gemac/.gitignore @@ -0,0 +1,4 @@ +/a.out +/*.vcd +simple_gemac_wrapper_tb + diff --git a/fpga/usrp2/simple_gemac/Makefile.srcs b/fpga/usrp2/simple_gemac/Makefile.srcs new file mode 100644 index 000000000..4ba3852b0 --- /dev/null +++ b/fpga/usrp2/simple_gemac/Makefile.srcs @@ -0,0 +1,28 @@ +# +# Copyright 2010 Ettus Research LLC +# + +################################################## +# Simple GEMAC Sources +################################################## +SIMPLE_GEMAC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../simple_gemac/, \ +simple_gemac_wrapper.v \ +simple_gemac.v \ +simple_gemac_wb.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 \ +miim/eth_miim.v \ +miim/eth_clockgen.v \ +miim/eth_outputcontrol.v \ +miim/eth_shiftreg.v \ +ethtx_realign.v \ +ethrx_realign.v \ +)) diff --git a/fpga/usrp2/simple_gemac/address_filter.v b/fpga/usrp2/simple_gemac/address_filter.v new file mode 100644 index 000000000..bf6194600 --- /dev/null +++ b/fpga/usrp2/simple_gemac/address_filter.v @@ -0,0 +1,52 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +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 + + diff --git a/fpga/usrp2/simple_gemac/address_filter_promisc.v b/fpga/usrp2/simple_gemac/address_filter_promisc.v new file mode 100644 index 000000000..3ff05fbe1 --- /dev/null +++ b/fpga/usrp2/simple_gemac/address_filter_promisc.v @@ -0,0 +1,49 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +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 <= (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 diff --git a/fpga/usrp2/simple_gemac/crc.v b/fpga/usrp2/simple_gemac/crc.v new file mode 100644 index 000000000..23cb84c60 --- /dev/null +++ b/fpga/usrp2/simple_gemac/crc.v @@ -0,0 +1,83 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +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 diff --git a/fpga/usrp2/simple_gemac/delay_line.v b/fpga/usrp2/simple_gemac/delay_line.v new file mode 100644 index 000000000..5a559a504 --- /dev/null +++ b/fpga/usrp2/simple_gemac/delay_line.v @@ -0,0 +1,38 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +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 diff --git a/fpga/usrp2/simple_gemac/eth_tasks.v b/fpga/usrp2/simple_gemac/eth_tasks.v new file mode 100644 index 000000000..731fd6d52 --- /dev/null +++ b/fpga/usrp2/simple_gemac/eth_tasks.v @@ -0,0 +1,173 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +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 diff --git a/fpga/usrp2/simple_gemac/eth_tasks_f19.v b/fpga/usrp2/simple_gemac/eth_tasks_f19.v new file mode 100644 index 000000000..3ff23a413 --- /dev/null +++ b/fpga/usrp2/simple_gemac/eth_tasks_f19.v @@ -0,0 +1,109 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +task SendFlowCtrl; + input [15:0] fc_len; + begin + $display("Sending Flow Control, quanta = %d, time = %d", fc_len,$time); + pause_time <= fc_len; + @(posedge eth_clk); + pause_req <= 1; + @(posedge eth_clk); + pause_req <= 0; + $display("Sent Flow Control"); + end +endtask // SendFlowCtrl + +task SendPacket_to_fifo19; + input [31:0] data_start; + input [15:0] data_len; + reg [15:0] count; + begin + $display("Sending Packet Len=%d, %d", data_len, $time); + count <= 2; + tx_f19_data <= {2'b0, 1'b0, 1'b1, data_start}; + tx_f19_src_rdy <= 1; + #1; + while(count < data_len) + begin + while(~tx_f19_dst_rdy) + @(posedge sys_clk); + @(posedge sys_clk); + //tx_f19_data[31:0] = tx_f19_data[31:0] + 32'h0101_0101; + count = count + 4; + //tx_f19_data[32] <= 0; + end + //tx_f19_data[33] <= 1; + while(~tx_f19_dst_rdy) + @(posedge sys_clk); + @(posedge sys_clk); + tx_f19_src_rdy <= 0; + end +endtask // SendPacket_to_fifo19 + +/* +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_f19; + 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_f19_dst_rdy) + @(posedge clk); + tx_f19_data <= pkt_rom[0]; + tx_f19_src_rdy <= 1; + tx_f19_eof <= 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 +*/ diff --git a/fpga/usrp2/simple_gemac/eth_tasks_f36.v b/fpga/usrp2/simple_gemac/eth_tasks_f36.v new file mode 100644 index 000000000..dee651d80 --- /dev/null +++ b/fpga/usrp2/simple_gemac/eth_tasks_f36.v @@ -0,0 +1,109 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +task SendFlowCtrl; + input [15:0] fc_len; + begin + $display("Sending Flow Control, quanta = %d, time = %d", fc_len,$time); + //pause_time <= fc_len; + @(posedge eth_clk); + //pause_req <= 1; + @(posedge eth_clk); + //pause_req <= 0; + $display("Sent Flow Control"); + end +endtask // SendFlowCtrl + +task SendPacket_to_fifo36; + input [31:0] data_start; + input [15:0] data_len; + reg [15:0] count; + begin + $display("Sending Packet Len=%d, %d", data_len, $time); + count <= 2; + tx_f36_data <= {2'b0, 1'b0, 1'b1, data_start}; + tx_f36_src_rdy <= 1; + #1; + while(count < data_len) + begin + while(~tx_f36_dst_rdy) + @(posedge sys_clk); + @(posedge sys_clk); + tx_f36_data[31:0] = tx_f36_data[31:0] + 32'h0101_0101; + count = count + 4; + tx_f36_data[32] <= 0; + end + tx_f36_data[33] <= 1; + while(~tx_f36_dst_rdy) + @(posedge sys_clk); + @(posedge sys_clk); + tx_f36_src_rdy <= 0; + end +endtask // SendPacket_to_fifo36 + +/* +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_f36; + 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_f36_dst_rdy) + @(posedge clk); + tx_f36_data <= pkt_rom[0]; + tx_f36_src_rdy <= 1; + tx_f36_eof <= 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 +*/ diff --git a/fpga/usrp2/simple_gemac/ethrx_realign.v b/fpga/usrp2/simple_gemac/ethrx_realign.v new file mode 100644 index 000000000..a08feb91e --- /dev/null +++ b/fpga/usrp2/simple_gemac/ethrx_realign.v @@ -0,0 +1,89 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +// NOTE: Will not work with single-line frames + +module ethrx_realign + (input clk, input reset, input clear, + input [35:0] datain, input src_rdy_i, output dst_rdy_o, + output [35:0] dataout, output src_rdy_o, input dst_rdy_i); + + reg [1:0] state; + reg [15:0] held; + reg [1:0] held_occ; + + wire xfer_in = src_rdy_i & dst_rdy_o; + wire xfer_out = src_rdy_o & dst_rdy_i; + + wire sof_in = datain[32]; + wire eof_in = datain[33]; + wire [1:0] occ_in = datain[35:34]; + wire sof_out, eof_out; + wire [1:0] occ_out; + + always @(posedge clk) + if(reset | clear) + begin + held <= 0; + held_occ <= 0; + end + else if(xfer_in) + begin + held <= datain[15:0]; + held_occ <= datain[35:34]; + end + + localparam RE_IDLE = 0; + localparam RE_HELD = 1; + localparam RE_DONE = 2; + + always @(posedge clk) + if(reset | clear) + state <= RE_IDLE; + else + case(state) + RE_IDLE : + if(src_rdy_i & dst_rdy_i) + if(eof_in) + state <= RE_DONE; + else + state <= RE_HELD; + + RE_HELD : + if(src_rdy_i & dst_rdy_i & eof_in) + if((occ_in==0)|(occ_in==3)) + state <= RE_DONE; + else + state <= RE_IDLE; + + RE_DONE : + if(dst_rdy_i) + state <= RE_IDLE; + + endcase // case (state) + + + assign sof_out = (state == RE_IDLE); + assign eof_out = (state == RE_DONE) | (occ_in == 1) | (occ_in == 2); + assign occ_out = (state == RE_DONE) ? ((held_occ == 3) ? 1 : 2) : + (occ_in == 1) ? 3 : 0; + + assign dataout = {occ_out,eof_out,sof_out,held,datain[31:16]}; + assign src_rdy_o = (state == RE_DONE) | src_rdy_i; + assign dst_rdy_o = dst_rdy_i & ((state == RE_IDLE)|(state == RE_HELD)); +endmodule // ethrx_realign diff --git a/fpga/usrp2/simple_gemac/ethtx_realign.v b/fpga/usrp2/simple_gemac/ethtx_realign.v new file mode 100644 index 000000000..236b2d4e1 --- /dev/null +++ b/fpga/usrp2/simple_gemac/ethtx_realign.v @@ -0,0 +1,94 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +//////////////////////////////////////////////////////////////////////// +// Ethernet TX - Realign +// +// - removes a 2-byte pad from the front a fifo36 stream +// - occupancy is preserved +// + +module ethtx_realign + (input clk, input reset, input clear, + input [35:0] datain, input src_rdy_i, output dst_rdy_o, + output [35:0] dataout, output src_rdy_o, input dst_rdy_i); + + reg [1:0] state; + reg [15:0] held; + reg [1:0] held_occ; + reg held_sof; + + wire xfer_in = src_rdy_i & dst_rdy_o; + wire xfer_out = src_rdy_o & dst_rdy_i; + + wire sof_in = datain[32]; + wire eof_in = datain[33]; + wire [1:0] occ_in = datain[35:34]; + wire occ_low = occ_in[1] ^ occ_in[0]; //occ is 1 or 2 + + always @(posedge clk) + if(reset | clear) + begin + held <= 0; + held_occ <= 0; + held_sof <= 0; + end + else if(xfer_in) + begin + held <= datain[15:0]; + held_occ <= occ_in; + held_sof <= sof_in; + end + + localparam RE_IDLE = 0; + localparam RE_HELD = 1; + localparam RE_DONE = 2; + + always @(posedge clk) + if(reset | clear) + state <= RE_IDLE; + else + case(state) + RE_IDLE : + if(xfer_in & eof_in) + state <= RE_DONE; + else if(xfer_in & sof_in) + state <= RE_HELD; + + RE_HELD : + if(xfer_in & xfer_out & eof_in) + if(occ_low) + state <= RE_IDLE; + else + state <= RE_DONE; + + RE_DONE : + if(xfer_out) + state <= RE_IDLE; + + endcase // case (state) + + wire sof_out = held_sof; + wire eof_out = (state == RE_HELD)? (eof_in & occ_low) : (state == RE_DONE); + wire [1:0] occ_out = ((state == RE_DONE)? held_occ : occ_in) ^ 2'b10; //(occ + 2)%4 + + assign dataout = {occ_out,eof_out,sof_out,held,datain[31:16]}; + assign src_rdy_o = (state == RE_HELD)? src_rdy_i : (state == RE_DONE); + assign dst_rdy_o = (state == RE_HELD)? dst_rdy_i : (state == RE_IDLE); + +endmodule // ethtx_realign diff --git a/fpga/usrp2/simple_gemac/flow_ctrl_rx.v b/fpga/usrp2/simple_gemac/flow_ctrl_rx.v new file mode 100644 index 000000000..bf000d11c --- /dev/null +++ b/fpga/usrp2/simple_gemac/flow_ctrl_rx.v @@ -0,0 +1,78 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +// 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 diff --git a/fpga/usrp2/simple_gemac/flow_ctrl_tx.v b/fpga/usrp2/simple_gemac/flow_ctrl_tx.v new file mode 100644 index 000000000..620c1ee7b --- /dev/null +++ b/fpga/usrp2/simple_gemac/flow_ctrl_tx.v @@ -0,0 +1,56 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +// 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 diff --git a/fpga/usrp2/simple_gemac/ll8_to_txmac.v b/fpga/usrp2/simple_gemac/ll8_to_txmac.v new file mode 100644 index 000000000..ac81afa63 --- /dev/null +++ b/fpga/usrp2/simple_gemac/ll8_to_txmac.v @@ -0,0 +1,60 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module ll8_to_txmac + (input clk, input reset, input clear, + input [7:0] ll_data, input ll_sof, 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 + diff --git a/fpga/usrp2/simple_gemac/miim/eth_clockgen.v b/fpga/usrp2/simple_gemac/miim/eth_clockgen.v new file mode 100644 index 000000000..5fe9001b2 --- /dev/null +++ b/fpga/usrp2/simple_gemac/miim/eth_clockgen.v @@ -0,0 +1,141 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// eth_clockgen.v //// +//// //// +//// This file is part of the Ethernet IP core project //// +//// http://www.opencores.org/projects/ethmac/ //// +//// //// +//// Author(s): //// +//// - Igor Mohor (igorM@opencores.org) //// +//// //// +//// All additional information is avaliable in the Readme.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 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: eth_clockgen.v,v $ +// Revision 1.2 2005/12/13 12:54:49 maverickist +// first simulation passed +// +// Revision 1.1.1.1 2005/12/13 01:51:45 Administrator +// no message +// +// Revision 1.2 2005/04/27 15:58:45 Administrator +// no message +// +// Revision 1.1.1.1 2004/12/15 06:38:54 Administrator +// no message +// +// Revision 1.3 2002/01/23 10:28:16 mohor +// Link in the header changed. +// +// Revision 1.2 2001/10/19 08:43:51 mohor +// eth_timescale.v changed to timescale.v This is done because of the +// simulation of the few cores in a one joined project. +// +// Revision 1.1 2001/08/06 14:44:29 mohor +// A define FPGA added to select between Artisan RAM (for ASIC) and Block Ram (For Virtex). +// Include files fixed to contain no path. +// File names and module names changed ta have a eth_ prologue in the name. +// File eth_timescale.v is used to define timescale +// All pin names on the top module are changed to contain _I, _O or _OE at the end. +// Bidirectional signal MDIO is changed to three signals (Mdc_O, Mdi_I, Mdo_O +// and Mdo_OE. The bidirectional signal must be created on the top level. This +// is done due to the ASIC tools. +// +// Revision 1.1 2001/07/30 21:23:42 mohor +// Directory structure changed. Files checked and joind together. +// +// Revision 1.3 2001/06/01 22:28:55 mohor +// This files (MIIM) are fully working. They were thoroughly tested. The testbench is not updated. +// +// + +module eth_clockgen(Clk, Reset, Divider, MdcEn, MdcEn_n, Mdc); + +//parameter Tp=1; + +input Clk; // Input clock (Host clock) +input Reset; // Reset signal +input [7:0] Divider; // Divider (input clock will be divided by the Divider[7:0]) + +output Mdc; // Output clock +output MdcEn; // Enable signal is asserted for one Clk period before Mdc rises. +output MdcEn_n; // Enable signal is asserted for one Clk period before Mdc falls. + +reg Mdc; +reg [7:0] Counter; + +wire CountEq0; +wire [7:0] CounterPreset; +wire [7:0] TempDivider; + + +assign TempDivider[7:0] = (Divider[7:0]<2)? 8'h02 : Divider[7:0]; // If smaller than 2 +assign CounterPreset[7:0] = (TempDivider[7:0]>>1) -1; // We are counting half of period + + +// Counter counts half period +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + Counter[7:0] <= 8'h1; + else + begin + if(CountEq0) + begin + Counter[7:0] <= CounterPreset[7:0]; + end + else + Counter[7:0] <= Counter - 8'h1; + end +end + + +// Mdc is asserted every other half period +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + Mdc <= 1'b0; + else + begin + if(CountEq0) + Mdc <= ~Mdc; + end +end + + +assign CountEq0 = Counter == 8'h0; +assign MdcEn = CountEq0 & ~Mdc; +assign MdcEn_n = CountEq0 & Mdc; + +endmodule + + diff --git a/fpga/usrp2/simple_gemac/miim/eth_miim.v b/fpga/usrp2/simple_gemac/miim/eth_miim.v new file mode 100644 index 000000000..ed851e482 --- /dev/null +++ b/fpga/usrp2/simple_gemac/miim/eth_miim.v @@ -0,0 +1,470 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// eth_miim.v //// +//// //// +//// This file is part of the Ethernet IP core project //// +//// http://www.opencores.org/projects/ethmac/ //// +//// //// +//// Author(s): //// +//// - Igor Mohor (igorM@opencores.org) //// +//// //// +//// All additional information is avaliable in the Readme.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 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: eth_miim.v,v $ +// Revision 1.3 2006/01/19 14:07:53 maverickist +// verification is complete. +// +// Revision 1.1.1.1 2005/12/13 01:51:44 Administrator +// no message +// +// Revision 1.4 2005/08/16 12:07:57 Administrator +// no message +// +// Revision 1.3 2005/05/19 07:04:29 Administrator +// no message +// +// Revision 1.2 2005/04/27 15:58:46 Administrator +// no message +// +// Revision 1.1.1.1 2004/12/15 06:38:54 Administrator +// no message +// +// Revision 1.5 2003/05/16 10:08:27 mohor +// Busy was set 2 cycles too late. Reported by Dennis Scott. +// +// Revision 1.4 2002/08/14 18:32:10 mohor +// - Busy signal was not set on time when scan status operation was performed +// and clock was divided with more than 2. +// - Nvalid remains valid two more clocks (was previously cleared too soon). +// +// Revision 1.3 2002/01/23 10:28:16 mohor +// Link in the header changed. +// +// Revision 1.2 2001/10/19 08:43:51 mohor +// eth_timescale.v changed to timescale.v This is done because of the +// simulation of the few cores in a one joined project. +// +// Revision 1.1 2001/08/06 14:44:29 mohor +// A define FPGA added to select between Artisan RAM (for ASIC) and Block Ram (For Virtex). +// Include files fixed to contain no path. +// File names and module names changed ta have a eth_ prologue in the name. +// File eth_timescale.v is used to define timescale +// All pin names on the top module are changed to contain _I, _O or _OE at the end. +// Bidirectional signal MDIO is changed to three signals (Mdc_O, Mdi_I, Mdo_O +// and Mdo_OE. The bidirectional signal must be created on the top level. This +// is done due to the ASIC tools. +// +// Revision 1.2 2001/08/02 09:25:31 mohor +// Unconnected signals are now connected. +// +// Revision 1.1 2001/07/30 21:23:42 mohor +// Directory structure changed. Files checked and joind together. +// +// Revision 1.3 2001/06/01 22:28:56 mohor +// This files (MIIM) are fully working. They were thoroughly tested. The testbench is not updated. +// +// + +module eth_miim +( + Clk, + Reset, + Divider, + NoPre, + CtrlData, + Rgad, + Fiad, + WCtrlData, + RStat, + ScanStat, + Mdio, + Mdc, + Busy, + Prsd, + LinkFail, + Nvalid, + WCtrlDataStart, + RStatStart, + UpdateMIIRX_DATAReg +); + +input Clk; // Host Clock +input Reset; // General Reset +input [7:0] Divider; // Divider for the host clock +input [15:0] CtrlData; // Control Data (to be written to the PHY reg.) +input [4:0] Rgad; // Register Address (within the PHY) +input [4:0] Fiad; // PHY Address +input NoPre; // No Preamble (no 32-bit preamble) +input WCtrlData; // Write Control Data operation +input RStat; // Read Status operation +input ScanStat; // Scan Status operation +inout Mdio; // MII Management Data In + +output Mdc; // MII Management Data Clock + +output Busy; // Busy Signal +output LinkFail; // Link Integrity Signal +output Nvalid; // Invalid Status (qualifier for the valid scan result) + +output [15:0] Prsd; // Read Status Data (data read from the PHY) + +output WCtrlDataStart; // This signals resets the WCTRLDATA bit in the MIIM Command register +output RStatStart; // This signal resets the RSTAT BIT in the MIIM Command register +output UpdateMIIRX_DATAReg;// Updates MII RX_DATA register with read data + +//parameter Tp = 1; + + +reg Nvalid; +reg EndBusy_d; // Pre-end Busy signal +reg EndBusy; // End Busy signal (stops the operation in progress) + +reg WCtrlData_q1; // Write Control Data operation delayed 1 Clk cycle +reg WCtrlData_q2; // Write Control Data operation delayed 2 Clk cycles +reg WCtrlData_q3; // Write Control Data operation delayed 3 Clk cycles +reg WCtrlDataStart; // Start Write Control Data Command (positive edge detected) +reg WCtrlDataStart_q; +reg WCtrlDataStart_q1; // Start Write Control Data Command delayed 1 Mdc cycle +reg WCtrlDataStart_q2; // Start Write Control Data Command delayed 2 Mdc cycles + +reg RStat_q1; // Read Status operation delayed 1 Clk cycle +reg RStat_q2; // Read Status operation delayed 2 Clk cycles +reg RStat_q3; // Read Status operation delayed 3 Clk cycles +reg RStatStart; // Start Read Status Command (positive edge detected) +reg RStatStart_q1; // Start Read Status Command delayed 1 Mdc cycle +reg RStatStart_q2; // Start Read Status Command delayed 2 Mdc cycles + +reg ScanStat_q1; // Scan Status operation delayed 1 cycle +reg ScanStat_q2; // Scan Status operation delayed 2 cycles +reg SyncStatMdcEn; // Scan Status operation delayed at least cycles and synchronized to MdcEn + +wire WriteDataOp; // Write Data Operation (positive edge detected) +wire ReadStatusOp; // Read Status Operation (positive edge detected) +wire ScanStatusOp; // Scan Status Operation (positive edge detected) +wire StartOp; // Start Operation (start of any of the preceding operations) +wire EndOp; // End of Operation + +reg InProgress; // Operation in progress +reg InProgress_q1; // Operation in progress delayed 1 Mdc cycle +reg InProgress_q2; // Operation in progress delayed 2 Mdc cycles +reg InProgress_q3; // Operation in progress delayed 3 Mdc cycles + +reg WriteOp; // Write Operation Latch (When asserted, write operation is in progress) +reg [6:0] BitCounter; // Bit Counter + + +wire [3:0] ByteSelect; // Byte Select defines which byte (preamble, data, operation, etc.) is loaded and shifted through the shift register. +wire MdcEn; // MII Management Data Clock Enable signal is asserted for one Clk period before Mdc rises. +wire ShiftedBit; // This bit is output of the shift register and is connected to the Mdo signal + + +wire LatchByte1_d2; +wire LatchByte0_d2; +reg LatchByte1_d; +reg LatchByte0_d; +reg [1:0] LatchByte; // Latch Byte selects which part of Read Status Data is updated from the shift register + +reg UpdateMIIRX_DATAReg;// Updates MII RX_DATA register with read data + +wire Mdo; // MII Management Data Output +wire MdoEn; // MII Management Data Output Enable +wire Mdi; + +assign Mdi=Mdio; +assign Mdio=MdoEn?Mdo:1'bz; + + + +// Generation of the EndBusy signal. It is used for ending the MII Management operation. +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + begin + EndBusy_d <= 1'b0; + EndBusy <= 1'b0; + end + else + begin + EndBusy_d <= ~InProgress_q2 & InProgress_q3; + EndBusy <= EndBusy_d; + end +end + + +// Update MII RX_DATA register +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + UpdateMIIRX_DATAReg <= 0; + else + if(EndBusy & ~WCtrlDataStart_q) + UpdateMIIRX_DATAReg <= 1; + else + UpdateMIIRX_DATAReg <= 0; +end + + + +// Generation of the delayed signals used for positive edge triggering. +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + begin + WCtrlData_q1 <= 1'b0; + WCtrlData_q2 <= 1'b0; + WCtrlData_q3 <= 1'b0; + + RStat_q1 <= 1'b0; + RStat_q2 <= 1'b0; + RStat_q3 <= 1'b0; + + ScanStat_q1 <= 1'b0; + ScanStat_q2 <= 1'b0; + SyncStatMdcEn <= 1'b0; + end + else + begin + WCtrlData_q1 <= WCtrlData; + WCtrlData_q2 <= WCtrlData_q1; + WCtrlData_q3 <= WCtrlData_q2; + + RStat_q1 <= RStat; + RStat_q2 <= RStat_q1; + RStat_q3 <= RStat_q2; + + ScanStat_q1 <= ScanStat; + ScanStat_q2 <= ScanStat_q1; + if(MdcEn) + SyncStatMdcEn <= ScanStat_q2; + end +end + + +// Generation of the Start Commands (Write Control Data or Read Status) +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + begin + WCtrlDataStart <= 1'b0; + WCtrlDataStart_q <= 1'b0; + RStatStart <= 1'b0; + end + else + begin + if(EndBusy) + begin + WCtrlDataStart <= 1'b0; + RStatStart <= 1'b0; + end + else + begin + if(WCtrlData_q2 & ~WCtrlData_q3) + WCtrlDataStart <= 1'b1; + if(RStat_q2 & ~RStat_q3) + RStatStart <= 1'b1; + WCtrlDataStart_q <= WCtrlDataStart; + end + end +end + + +// Generation of the Nvalid signal (indicates when the status is invalid) +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + Nvalid <= 1'b0; + else + begin + if(~InProgress_q2 & InProgress_q3) + begin + Nvalid <= 1'b0; + end + else + begin + if(ScanStat_q2 & ~SyncStatMdcEn) + Nvalid <= 1'b1; + end + end +end + +// Signals used for the generation of the Operation signals (positive edge) +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + begin + WCtrlDataStart_q1 <= 1'b0; + WCtrlDataStart_q2 <= 1'b0; + + RStatStart_q1 <= 1'b0; + RStatStart_q2 <= 1'b0; + + InProgress_q1 <= 1'b0; + InProgress_q2 <= 1'b0; + InProgress_q3 <= 1'b0; + + LatchByte0_d <= 1'b0; + LatchByte1_d <= 1'b0; + + LatchByte <= 2'b00; + end + else + begin + if(MdcEn) + begin + WCtrlDataStart_q1 <= WCtrlDataStart; + WCtrlDataStart_q2 <= WCtrlDataStart_q1; + + RStatStart_q1 <= RStatStart; + RStatStart_q2 <= RStatStart_q1; + + LatchByte[0] <= LatchByte0_d; + LatchByte[1] <= LatchByte1_d; + + LatchByte0_d <= LatchByte0_d2; + LatchByte1_d <= LatchByte1_d2; + + InProgress_q1 <= InProgress; + InProgress_q2 <= InProgress_q1; + InProgress_q3 <= InProgress_q2; + end + end +end + + +// Generation of the Operation signals +assign WriteDataOp = WCtrlDataStart_q1 & ~WCtrlDataStart_q2; +assign ReadStatusOp = RStatStart_q1 & ~RStatStart_q2; +assign ScanStatusOp = SyncStatMdcEn & ~InProgress & ~InProgress_q1 & ~InProgress_q2; +assign StartOp = WriteDataOp | ReadStatusOp | ScanStatusOp; + +// Busy +reg Busy; +always @ (posedge Clk or posedge Reset) + if (Reset) + Busy <=0; + else if(WCtrlData | WCtrlDataStart | RStat | RStatStart | SyncStatMdcEn | EndBusy | InProgress | InProgress_q3 | Nvalid) + Busy <=1; + else + Busy <=0; + +//assign Busy = WCtrlData | WCtrlDataStart | RStat | RStatStart | SyncStatMdcEn | EndBusy | InProgress | InProgress_q3 | Nvalid; + + +// Generation of the InProgress signal (indicates when an operation is in progress) +// Generation of the WriteOp signal (indicates when a write is in progress) +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + begin + InProgress <= 1'b0; + WriteOp <= 1'b0; + end + else + begin + if(MdcEn) + begin + if(StartOp) + begin + if(~InProgress) + WriteOp <= WriteDataOp; + InProgress <= 1'b1; + end + else + begin + if(EndOp) + begin + InProgress <= 1'b0; + WriteOp <= 1'b0; + end + end + end + end +end + + + +// Bit Counter counts from 0 to 63 (from 32 to 63 when NoPre is asserted) +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + BitCounter[6:0] <= 7'h0; + else + begin + if(MdcEn) + begin + if(InProgress) + begin + if(NoPre & ( BitCounter == 7'h0 )) + BitCounter[6:0] <= 7'h21; + else + BitCounter[6:0] <= BitCounter[6:0] + 1'b1; + end + else + BitCounter[6:0] <= 7'h0; + end + end +end + + +// Operation ends when the Bit Counter reaches 63 +assign EndOp = BitCounter==63; + +assign ByteSelect[0] = InProgress & ((NoPre & (BitCounter == 7'h0)) | (~NoPre & (BitCounter == 7'h20))); +assign ByteSelect[1] = InProgress & (BitCounter == 7'h28); +assign ByteSelect[2] = InProgress & WriteOp & (BitCounter == 7'h30); +assign ByteSelect[3] = InProgress & WriteOp & (BitCounter == 7'h38); + + +// Latch Byte selects which part of Read Status Data is updated from the shift register +assign LatchByte1_d2 = InProgress & ~WriteOp & BitCounter == 7'h37; +assign LatchByte0_d2 = InProgress & ~WriteOp & BitCounter == 7'h3F; + +wire MdcEn_n; + +// Connecting the Clock Generator Module +eth_clockgen clkgen(.Clk(Clk), .Reset(Reset), .Divider(Divider[7:0]), .MdcEn(MdcEn), .MdcEn_n(MdcEn_n), .Mdc(Mdc) + ); + +// Connecting the Shift Register Module +eth_shiftreg shftrg(.Clk(Clk), .Reset(Reset), .MdcEn_n(MdcEn_n), .Mdi(Mdi), .Fiad(Fiad), .Rgad(Rgad), + .CtrlData(CtrlData), .WriteOp(WriteOp), .ByteSelect(ByteSelect), .LatchByte(LatchByte), + .ShiftedBit(ShiftedBit), .Prsd(Prsd), .LinkFail(LinkFail) + ); + +// Connecting the Output Control Module +eth_outputcontrol outctrl(.Clk(Clk), .Reset(Reset), .MdcEn_n(MdcEn_n), .InProgress(InProgress), + .ShiftedBit(ShiftedBit), .BitCounter(BitCounter), .WriteOp(WriteOp), .NoPre(NoPre), + .Mdo(Mdo), .MdoEn(MdoEn) + ); + +endmodule diff --git a/fpga/usrp2/simple_gemac/miim/eth_outputcontrol.v b/fpga/usrp2/simple_gemac/miim/eth_outputcontrol.v new file mode 100644 index 000000000..99c125823 --- /dev/null +++ b/fpga/usrp2/simple_gemac/miim/eth_outputcontrol.v @@ -0,0 +1,158 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// eth_outputcontrol.v //// +//// //// +//// This file is part of the Ethernet IP core project //// +//// http://www.opencores.org/projects/ethmac/ //// +//// //// +//// Author(s): //// +//// - Igor Mohor (igorM@opencores.org) //// +//// //// +//// All additional information is avaliable in the Readme.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 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: eth_outputcontrol.v,v $ +// Revision 1.2 2005/12/13 12:54:49 maverickist +// first simulation passed +// +// Revision 1.1.1.1 2005/12/13 01:51:45 Administrator +// no message +// +// Revision 1.2 2005/04/27 15:58:46 Administrator +// no message +// +// Revision 1.1.1.1 2004/12/15 06:38:54 Administrator +// no message +// +// Revision 1.4 2002/07/09 20:11:59 mohor +// Comment removed. +// +// Revision 1.3 2002/01/23 10:28:16 mohor +// Link in the header changed. +// +// Revision 1.2 2001/10/19 08:43:51 mohor +// eth_timescale.v changed to timescale.v This is done because of the +// simulation of the few cores in a one joined project. +// +// Revision 1.1 2001/08/06 14:44:29 mohor +// A define FPGA added to select between Artisan RAM (for ASIC) and Block Ram (For Virtex). +// Include files fixed to contain no path. +// File names and module names changed ta have a eth_ prologue in the name. +// File eth_timescale.v is used to define timescale +// All pin names on the top module are changed to contain _I, _O or _OE at the end. +// Bidirectional signal MDIO is changed to three signals (Mdc_O, Mdi_I, Mdo_O +// and Mdo_OE. The bidirectional signal must be created on the top level. This +// is done due to the ASIC tools. +// +// Revision 1.1 2001/07/30 21:23:42 mohor +// Directory structure changed. Files checked and joind together. +// +// Revision 1.3 2001/06/01 22:28:56 mohor +// This files (MIIM) are fully working. They were thoroughly tested. The testbench is not updated. +// +// + +module eth_outputcontrol(Clk, Reset, InProgress, ShiftedBit, BitCounter, WriteOp, NoPre, MdcEn_n, Mdo, MdoEn); + +input Clk; // Host Clock +input Reset; // General Reset +input WriteOp; // Write Operation Latch (When asserted, write operation is in progress) +input NoPre; // No Preamble (no 32-bit preamble) +input InProgress; // Operation in progress +input ShiftedBit; // This bit is output of the shift register and is connected to the Mdo signal +input [6:0] BitCounter; // Bit Counter +input MdcEn_n; // MII Management Data Clock Enable signal is asserted for one Clk period before Mdc falls. + +output Mdo; // MII Management Data Output +output MdoEn; // MII Management Data Output Enable + +wire SerialEn; + +reg MdoEn_2d; +reg MdoEn_d; +reg MdoEn; + +reg Mdo_2d; +reg Mdo_d; +reg Mdo; // MII Management Data Output + + + +// Generation of the Serial Enable signal (enables the serialization of the data) +assign SerialEn = WriteOp & InProgress & ( BitCounter>31 | ( ( BitCounter == 0 ) & NoPre ) ) + | ~WriteOp & InProgress & (( BitCounter>31 & BitCounter<46 ) | ( ( BitCounter == 0 ) & NoPre )); + + +// Generation of the MdoEn signal +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + begin + MdoEn_2d <= 1'b0; + MdoEn_d <= 1'b0; + MdoEn <= 1'b0; + end + else + begin + if(MdcEn_n) + begin + MdoEn_2d <= SerialEn | InProgress & BitCounter<32; + MdoEn_d <= MdoEn_2d; + MdoEn <= MdoEn_d; + end + end +end + + +// Generation of the Mdo signal. +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + begin + Mdo_2d <= 1'b0; + Mdo_d <= 1'b0; + Mdo <= 1'b0; + end + else + begin + if(MdcEn_n) + begin + Mdo_2d <= ~SerialEn & BitCounter<32; + Mdo_d <= ShiftedBit | Mdo_2d; + Mdo <= Mdo_d; + end + end +end + + + +endmodule diff --git a/fpga/usrp2/simple_gemac/miim/eth_shiftreg.v b/fpga/usrp2/simple_gemac/miim/eth_shiftreg.v new file mode 100644 index 000000000..9aa350b2b --- /dev/null +++ b/fpga/usrp2/simple_gemac/miim/eth_shiftreg.v @@ -0,0 +1,159 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// eth_shiftreg.v //// +//// //// +//// This file is part of the Ethernet IP core project //// +//// http://www.opencores.org/projects/ethmac/ //// +//// //// +//// Author(s): //// +//// - Igor Mohor (igorM@opencores.org) //// +//// //// +//// All additional information is avaliable in the Readme.txt //// +//// file. //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 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: eth_shiftreg.v,v $ +// Revision 1.2 2005/12/13 12:54:49 maverickist +// first simulation passed +// +// Revision 1.1.1.1 2005/12/13 01:51:45 Administrator +// no message +// +// Revision 1.2 2005/04/27 15:58:47 Administrator +// no message +// +// Revision 1.1.1.1 2004/12/15 06:38:54 Administrator +// no message +// +// Revision 1.5 2002/08/14 18:16:59 mohor +// LinkFail signal was not latching appropriate bit. +// +// Revision 1.4 2002/03/02 21:06:01 mohor +// LinkFail signal was not latching appropriate bit. +// +// Revision 1.3 2002/01/23 10:28:16 mohor +// Link in the header changed. +// +// Revision 1.2 2001/10/19 08:43:51 mohor +// eth_timescale.v changed to timescale.v This is done because of the +// simulation of the few cores in a one joined project. +// +// Revision 1.1 2001/08/06 14:44:29 mohor +// A define FPGA added to select between Artisan RAM (for ASIC) and Block Ram (For Virtex). +// Include files fixed to contain no path. +// File names and module names changed ta have a eth_ prologue in the name. +// File eth_timescale.v is used to define timescale +// All pin names on the top module are changed to contain _I, _O or _OE at the end. +// Bidirectional signal MDIO is changed to three signals (Mdc_O, Mdi_I, Mdo_O +// and Mdo_OE. The bidirectional signal must be created on the top level. This +// is done due to the ASIC tools. +// +// Revision 1.1 2001/07/30 21:23:42 mohor +// Directory structure changed. Files checked and joind together. +// +// Revision 1.3 2001/06/01 22:28:56 mohor +// This files (MIIM) are fully working. They were thoroughly tested. The testbench is not updated. +// +// + +module eth_shiftreg(Clk, Reset, MdcEn_n, Mdi, Fiad, Rgad, CtrlData, WriteOp, ByteSelect, + LatchByte, ShiftedBit, Prsd, LinkFail); + + +input Clk; // Input clock (Host clock) +input Reset; // Reset signal +input MdcEn_n; // Enable signal is asserted for one Clk period before Mdc falls. +input Mdi; // MII input data +input [4:0] Fiad; // PHY address +input [4:0] Rgad; // Register address (within the selected PHY) +input [15:0]CtrlData; // Control data (data to be written to the PHY) +input WriteOp; // The current operation is a PHY register write operation +input [3:0] ByteSelect; // Byte select +input [1:0] LatchByte; // Byte select for latching (read operation) + +output ShiftedBit; // Bit shifted out of the shift register +output[15:0]Prsd; // Read Status Data (data read from the PHY) +output LinkFail; // Link Integrity Signal + +reg [7:0] ShiftReg; // Shift register for shifting the data in and out +reg [15:0]Prsd; +reg LinkFail; + + + + +// ShiftReg[7:0] :: Shift Register Data +always @ (posedge Clk or posedge Reset) +begin + if(Reset) + begin + ShiftReg[7:0] <= 8'h0; + Prsd[15:0] <= 16'h0; + LinkFail <= 1'b0; + end + else + begin + if(MdcEn_n) + begin + if(|ByteSelect) + begin + case (ByteSelect[3:0]) + 4'h1 : ShiftReg[7:0] <= {2'b01, ~WriteOp, WriteOp, Fiad[4:1]}; + 4'h2 : ShiftReg[7:0] <= {Fiad[0], Rgad[4:0], 2'b10}; + 4'h4 : ShiftReg[7:0] <= CtrlData[15:8]; + 4'h8 : ShiftReg[7:0] <= CtrlData[7:0]; + default : ShiftReg[7:0] <= 8'h0; + endcase + end + else + begin + ShiftReg[7:0] <= {ShiftReg[6:0], Mdi}; + if(LatchByte[0]) + begin + Prsd[7:0] <= {ShiftReg[6:0], Mdi}; + if(Rgad == 5'h01) + LinkFail <= ~ShiftReg[1]; // this is bit [2], because it is not shifted yet + end + else + begin + if(LatchByte[1]) + Prsd[15:8] <= {ShiftReg[6:0], Mdi}; + end + end + end + end +end + + +assign ShiftedBit = ShiftReg[7]; + + +endmodule diff --git a/fpga/usrp2/simple_gemac/rxmac_to_ll8.v b/fpga/usrp2/simple_gemac/rxmac_to_ll8.v new file mode 100644 index 000000000..5acb08bb7 --- /dev/null +++ b/fpga/usrp2/simple_gemac/rxmac_to_ll8.v @@ -0,0 +1,71 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +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 diff --git a/fpga/usrp2/simple_gemac/simple_gemac.v b/fpga/usrp2/simple_gemac/simple_gemac.v new file mode 100644 index 000000000..ec13d3c96 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac.v @@ -0,0 +1,81 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +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 diff --git a/fpga/usrp2/simple_gemac/simple_gemac_rx.v b/fpga/usrp2/simple_gemac/simple_gemac_rx.v new file mode 100644 index 000000000..e6c0424bd --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_rx.v @@ -0,0 +1,196 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +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) // | (~pkt_long_enough & ~rx_dv_d1) & (rx_state != RX_IDLE)) + 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 rx_clk = GMII_RX_CLK; + + assign debug = rx_state; + +endmodule // simple_gemac_rx diff --git a/fpga/usrp2/simple_gemac/simple_gemac_tb.v b/fpga/usrp2/simple_gemac/simple_gemac_tb.v new file mode 100644 index 000000000..ed7d796dc --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_tb.v @@ -0,0 +1,217 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +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 diff --git a/fpga/usrp2/simple_gemac/simple_gemac_tx.v b/fpga/usrp2/simple_gemac/simple_gemac_tx.v new file mode 100644 index 000000000..ecabc3dad --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_tx.v @@ -0,0 +1,271 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +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; +*/ diff --git a/fpga/usrp2/simple_gemac/simple_gemac_wb.v b/fpga/usrp2/simple_gemac/simple_gemac_wb.v new file mode 100644 index 000000000..0ddb8398a --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wb.v @@ -0,0 +1,179 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module wb_reg + #(parameter ADDR=0, + parameter DEFAULT=0, + parameter WIDTH=32) + (input clk, input rst, + input [5:0] adr, input wr_acc, + input [31:0] dat_i, output reg [WIDTH-1:0] dat_o); + + always @(posedge clk) + if(rst) + dat_o <= DEFAULT; + else if(wr_acc & (adr == ADDR)) + dat_o <= dat_i[WIDTH-1:0]; + +endmodule // wb_reg + + + +module simple_gemac_wb + (input wb_clk, input wb_rst, + input wb_cyc, input wb_stb, output reg wb_ack, input wb_we, + input [7:0] wb_adr, input [31:0] wb_dat_i, output reg [31:0] wb_dat_o, + + inout mdio, output mdc, + output [47:0] ucast_addr, output [47:0] mcast_addr, + output pass_ucast, output pass_mcast, output pass_bcast, + output pass_pause, output pass_all, + output pause_respect_en, output pause_request_en, + output [15:0] pause_time, output [15:0] pause_thresh ); + + wire acc = wb_cyc & wb_stb; + wire wr_acc = wb_cyc & wb_stb & wb_we; + wire rd_acc = wb_cyc & wb_stb & ~wb_we; + + always @(posedge wb_clk) + if(wb_rst) + wb_ack <= 0; + else + wb_ack <= acc & ~wb_ack; + + wire [6:0] misc_settings; + assign {pause_request_en, pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all, pause_respect_en} = misc_settings; + + wb_reg #(.ADDR(0),.DEFAULT(7'b0111011),.WIDTH(7)) + wb_reg_settings (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(misc_settings) ); + wb_reg #(.ADDR(1),.DEFAULT(0),.WIDTH(16)) + wb_reg_ucast_h (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(ucast_addr[47:32]) ); + wb_reg #(.ADDR(2),.DEFAULT(0),.WIDTH(32)) + wb_reg_ucast_l (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(ucast_addr[31:0]) ); + wb_reg #(.ADDR(3),.DEFAULT(0),.WIDTH(16)) + wb_reg_mcast_h (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(mcast_addr[47:32]) ); + wb_reg #(.ADDR(4),.DEFAULT(0),.WIDTH(32)) + wb_reg_mcast_l (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(mcast_addr[31:0]) ); + + //MII to CPU + wire [7:0] Divider; // Divider for the host clock + wire [15:0] CtrlData; // Control Data (to be written to the PHY reg.) + wire [4:0] Rgad; // Register Address (within the PHY) + wire [4:0] Fiad; // PHY Address + wire NoPre; // No Preamble (no 32-bit preamble) + wire WCtrlData; // Write Control Data operation + wire RStat; // Read Status operation + wire ScanStat; // Scan Status operation + wire Busy; // Busy Signal + wire LinkFail; // Link Integrity Signal + wire Nvalid; // Invalid Status (qualifier for the valid scan result) + wire [15:0] Prsd; // Read Status Data (data read from the PHY) + wire WCtrlDataStart; // This signals resets the WCTRLDATA bit in the MIIM Command register + wire RStatStart; // This signal resets the RSTAT BIT in the MIIM Command register + wire UpdateMIIRX_DATAReg; // Updates MII RX_DATA register with read data + + // registers for controlling the MII interface + reg [2:0] MIICOMMAND; + wire [12:0] MIIADDRESS; + reg [15:0] MIIRX_DATA; + wire [2:0] MIISTATUS; + + wb_reg #(.ADDR(5),.DEFAULT(0),.WIDTH(9)) + wb_reg_miimoder (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o({NoPre,Divider}) ); + + wb_reg #(.ADDR(6),.DEFAULT(0),.WIDTH(13)) + wb_reg_miiaddr (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(MIIADDRESS) ); + + wb_reg #(.ADDR(7),.DEFAULT(0),.WIDTH(16)) + wb_reg_miidata (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(CtrlData) ); + + // MIICOMMAND register - needs special treatment because of auto-resetting bits + always @ (posedge wb_clk) + if (wb_rst) + MIICOMMAND <= 0; + else + if (wr_acc & (wb_adr[7:2] == 6'd8)) + MIICOMMAND <= wb_dat_i; + else + begin + if ( WCtrlDataStart ) + MIICOMMAND[2] <= 0; + if ( RStatStart ) + MIICOMMAND[1] <= 0; + end + + // MIIRX_DATA register + always @(posedge wb_clk) + if (wb_rst) + MIIRX_DATA <= 0; + else + if (UpdateMIIRX_DATAReg ) + MIIRX_DATA <= Prsd; + + // MIICOMMAND + assign WCtrlData = MIICOMMAND[2]; + assign RStat = MIICOMMAND[1]; + assign ScanStat = MIICOMMAND[0]; + // MIIADDRESS + assign Rgad = MIIADDRESS[12:8]; + assign Fiad = MIIADDRESS[4:0]; + // MIISTATUS + assign MIISTATUS[2:0] = { Nvalid, Busy, LinkFail }; + + eth_miim eth_miim + (.Clk(wb_clk), .Reset(wb_rst), + .Divider(Divider), .NoPre(NoPre), .CtrlData(CtrlData), .Rgad(Rgad), .Fiad(Fiad), + .WCtrlData(WCtrlData), .RStat(RStat), .ScanStat(ScanStat), .Mdio(mdio), .Mdc(mdc), + .Busy(Busy), .Prsd(Prsd), .LinkFail(LinkFail), .Nvalid(Nvalid), + .WCtrlDataStart(WCtrlDataStart), .RStatStart(RStatStart), + .UpdateMIIRX_DATAReg(UpdateMIIRX_DATAReg) ); + + wb_reg #(.ADDR(11),.DEFAULT(0),.WIDTH(16)) + wb_reg_pausetime (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(pause_time) ); + + wb_reg #(.ADDR(12),.DEFAULT(0),.WIDTH(16)) + wb_reg_pausethresh (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(pause_thresh) ); + + always @(posedge wb_clk) + case(wb_adr[7:2]) + //0 : wb_dat_o <= misc_settings; + //1 : wb_dat_o <= ucast_addr[47:32]; + //2 : wb_dat_o <= ucast_addr[31:0]; + //3 : wb_dat_o <= mcast_addr[47:32]; + //4 : wb_dat_o <= mcast_addr[31:0]; + //5 : wb_dat_o <= {NoPre,Divider}; + //6 : wb_dat_o <= MIIADDRESS; + //7 : wb_dat_o <= CtrlData; + 8 : wb_dat_o <= MIICOMMAND; + 9 : wb_dat_o <= MIISTATUS; + 10: wb_dat_o <= MIIRX_DATA; + //11: wb_dat_o <= pause_time; + //12: wb_dat_o <= pause_thresh; + endcase // case (wb_adr[7:2]) + +endmodule // simple_gemac_wb diff --git a/fpga/usrp2/simple_gemac/simple_gemac_wrapper.build b/fpga/usrp2/simple_gemac/simple_gemac_wrapper.build new file mode 100755 index 000000000..9293deca6 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper.build @@ -0,0 +1 @@ +iverilog -Wimplict -Wportbind -y ../fifo/ -y ../models/ -y . -y miim -y ../coregen/ -y ../control_lib/ -o simple_gemac_wrapper_tb simple_gemac_wrapper_tb.v diff --git a/fpga/usrp2/simple_gemac/simple_gemac_wrapper.v b/fpga/usrp2/simple_gemac/simple_gemac_wrapper.v new file mode 100644 index 000000000..ec09379ed --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper.v @@ -0,0 +1,175 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + +module simple_gemac_wrapper + #(parameter RXFIFOSIZE=9, + parameter TXFIFOSIZE=9, + parameter RX_FLOW_CTRL=0) + (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 [35:0] rx_f36_data, output rx_f36_src_rdy, input rx_f36_dst_rdy, + input [35:0] tx_f36_data, input tx_f36_src_rdy, output tx_f36_dst_rdy, + + // Wishbone Interface + input wb_clk, input wb_rst, input wb_stb, input wb_cyc, output wb_ack, input wb_we, + input [7:0] wb_adr, input [31:0] wb_dat_i, output [31:0] wb_dat_o, + + // MIIM + inout mdio, output mdc, + output [31:0] debug); + + 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 [47:0] ucast_addr, mcast_addr; + wire pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all; + 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(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), + .debug(debug_state) + ); + + simple_gemac_wb simple_gemac_wb + (.wb_clk(wb_clk), .wb_rst(wb_rst), + .wb_cyc(wb_cyc), .wb_stb(wb_stb), .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(mdio), .mdc(mdc), + .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_respect_en(pause_respect_en), .pause_request_en(pause_request_en), + .pause_time(pause_time), .pause_thresh(pause_thresh) ); + + // RX FIFO Chain + wire rx_ll_sof, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy; + wire [7:0] rx_ll_data; + + wire [18:0] rx_f19_data_int1, rx_f19_data_int2; + wire rx_f19_src_rdy_int1, rx_f19_dst_rdy_int1, rx_f19_src_rdy_int2, rx_f19_dst_rdy_int2; + wire [35:0] rx_f36_data_int; + wire rx_f36_src_rdy_int, rx_f36_dst_rdy_int; + + rxmac_to_ll8 rx_adapt + (.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(rx_ll_sof), .ll_eof(rx_ll_eof), .ll_error(), // error also encoded in sof/eof + .ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy)); + + ll8_to_fifo19 ll8_to_fifo19 + (.clk(rx_clk), .reset(rx_reset), .clear(0), + .ll_data(rx_ll_data), .ll_sof(rx_ll_sof), .ll_eof(rx_ll_eof), + .ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy), + .f19_data(rx_f19_data_int1), .f19_src_rdy_o(rx_f19_src_rdy_int1), .f19_dst_rdy_i(rx_f19_dst_rdy_int1)); + + fifo19_rxrealign fifo19_rxrealign + (.clk(rx_clk), .reset(rx_reset), .clear(0), + .datain(rx_f19_data_int1), .src_rdy_i(rx_f19_src_rdy_int1), .dst_rdy_o(rx_f19_dst_rdy_int1), + .dataout(rx_f19_data_int2), .src_rdy_o(rx_f19_src_rdy_int2), .dst_rdy_i(rx_f19_dst_rdy_int2) ); + + fifo19_to_fifo36 rx_fifo19_to_fifo36 + (.clk(rx_clk), .reset(rx_reset), .clear(0), + .f19_datain(rx_f19_data_int2), .f19_src_rdy_i(rx_f19_src_rdy_int2), .f19_dst_rdy_o(rx_f19_dst_rdy_int2), + .f36_dataout(rx_f36_data_int), .f36_src_rdy_o(rx_f36_src_rdy_int), .f36_dst_rdy_i(rx_f36_dst_rdy_int) ); + + fifo_2clock_cascade #(.WIDTH(36), .SIZE(RXFIFOSIZE)) rx_2clk_fifo + (.wclk(rx_clk), .datain(rx_f36_data_int), + .src_rdy_i(rx_f36_src_rdy_int), .dst_rdy_o(rx_f36_dst_rdy_int), .space(rx_fifo_space), + .rclk(sys_clk), .dataout(rx_f36_data), + .src_rdy_o(rx_f36_src_rdy), .dst_rdy_i(rx_f36_dst_rdy), .occupied(), .arst(reset)); + + // TX FIFO Chain + wire tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy; + wire [7:0] tx_ll_data; + wire [35:0] tx_f36_data_int1, tx_f36_data_int2; + wire tx_f36_src_rdy_int1, tx_f36_dst_rdy_int1, tx_f36_src_rdy_int2, tx_f36_dst_rdy_int2; + + fifo_2clock_cascade #(.WIDTH(36), .SIZE(TXFIFOSIZE)) tx_2clk_fifo + (.wclk(sys_clk), .datain(tx_f36_data), .src_rdy_i(tx_f36_src_rdy), .dst_rdy_o(tx_f36_dst_rdy), .space(), + .rclk(tx_clk), .dataout(tx_f36_data_int1), .src_rdy_o(tx_f36_src_rdy_int1), .dst_rdy_i(tx_f36_dst_rdy_int1), .occupied(), + .arst(reset)); + + ethtx_realign ethtx_realign + (.clk(tx_clk), .reset(tx_reset), .clear(clear), + .datain(tx_f36_data_int1), .src_rdy_i(tx_f36_src_rdy_int1), .dst_rdy_o(tx_f36_dst_rdy_int1), + .dataout(tx_f36_data_int2), .src_rdy_o(tx_f36_src_rdy_int2), .dst_rdy_i(tx_f36_dst_rdy_int2) ); + + fifo36_to_ll8 fifo36_to_ll8 + (.clk(tx_clk), .reset(tx_reset), .clear(clear), + .f36_data(tx_f36_data_int2), .f36_src_rdy_i(tx_f36_src_rdy_int2), .f36_dst_rdy_o(tx_f36_dst_rdy_int2), + .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)); + + ll8_to_txmac ll8_to_txmac + (.clk(tx_clk), .reset(tx_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)); + + // 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 + + wire [31:0] debug_tx, debug_rx; + + assign debug_tx = { { tx_ll_data }, + { tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy, 4'b0 }, + { tx_valid, tx_error, tx_ack, tx_f36_src_rdy_int1, tx_f36_dst_rdy_int1, tx_f36_data_int1[34:32]}, + { tx_data} }; + assign debug_rx = { { rx_ll_data }, + { rx_ll_sof, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy, 4'b0 }, + { rx_valid, rx_error, rx_ack, rx_f36_src_rdy_int, rx_f36_dst_rdy_int, rx_f36_data_int[34:32]}, + { rx_data} }; + + assign debug = debug_rx; + +endmodule // simple_gemac_wrapper + diff --git a/fpga/usrp2/simple_gemac/simple_gemac_wrapper_f36_tb.v b/fpga/usrp2/simple_gemac/simple_gemac_wrapper_f36_tb.v new file mode 100644 index 000000000..2904e38d4 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper_f36_tb.v @@ -0,0 +1,260 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +module simple_gemac_wrapper_f36_tb; +`include "eth_tasks_f36.v" + + reg clk = 0; + reg reset = 1; + + initial #1000 reset = 0; + always #50 clk = ~clk; + + reg wb_clk = 0; + wire wb_rst = reset; + always #173 wb_clk = ~wb_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 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; + wire rx_ll_dst_rdy2; + wire [7:0] rx_ll_data, rx_ll_data2; + wire rx_ll_error, rx_ll_error2; + + 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_dat; + reg tx_f36_src_rdy; + wire tx_f36_dst_rdy; + + wire [35:0] rx_f36_dat; + wire rx_f36_src_rdy; + reg rx_f36_dst_rdy = 1; + + simple_gemac_wrapper simple_gemac_wrapper + (.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), + .rx_clk(rx_clk), .rx_ll_data(rx_ll_data), .rx_ll_sof(rx_ll_sof), + .rx_ll_eof(rx_ll_eof), .rx_ll_src_rdy(rx_ll_src_rdy), .rx_ll_dst_rdy(rx_ll_dst_rdy), + .tx_clk(tx_clk), .tx_ll_data(tx_ll_data), .tx_ll_sof(tx_ll_sof), + .tx_ll_eof(tx_ll_eof), .tx_ll_src_rdy(tx_ll_src_rdy), .tx_ll_dst_rdy(tx_ll_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(mdio), .mdc(mdc) ); + + wire rx_ll_dst_rdy2_n; + assign rx_ll_dst_rdy2 = ~rx_ll_dst_rdy2_n; + + 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)); + + ll8_to_fifo36 ll8_to_fifo36 + (.clk(clk), .reset(reset), .clear(0), + .ll_data(rx_ll_data2), .ll_sof_n(~rx_ll_sof2), .ll_eof_n(~rx_ll_eof2), + .ll_src_rdy_n(~rx_ll_src_rdy2), .ll_dst_rdy_n(rx_ll_dst_rdy2_n), + .f36_data(rx_f36_dat), .f36_src_rdy_o(rx_f36_src_rdy), .f36_dst_rdy_i(rx_f36_dst_rdy)); + + wire tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy; + wire tx_ll_sof2_n, tx_ll_eof2_n; + wire tx_ll_src_rdy2_n, tx_ll_dst_rdy2; + wire [7:0] tx_ll_data, tx_ll_data2; + wire tx_ll_error; + wire tx_ll_error2 = 0; + + fifo36_to_ll8 fifo36_to_ll8 + (.clk(clk), .reset(reset), .clear(clear), + .f36_data(tx_f36_dat), .f36_src_rdy_i(tx_f36_src_rdy), .f36_dst_rdy_o(tx_f36_dst_rdy), + .ll_data(tx_ll_data2), .ll_sof_n(tx_ll_sof2_n), .ll_eof_n(tx_ll_eof2_n), + .ll_src_rdy_n(tx_ll_src_rdy2_n), .ll_dst_rdy_n(~tx_ll_dst_rdy2)); + + ll8_shortfifo tx_sfifo + (.clk(clk), .reset(reset), .clear(clear), + .datain(tx_ll_data2), .sof_i(~tx_ll_sof2_n), .eof_i(~tx_ll_eof2_n), + .error_i(tx_ll_error2), .src_rdy_i(~tx_ll_src_rdy2_n), .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)); + + initial $dumpfile("simple_gemac_wrapper_f36_tb.vcd"); + initial $dumpvars(0,simple_gemac_wrapper_f36_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); + WishboneWR(0,6'b111001); + WishboneWR(4,16'hF1F2); + WishboneWR(8,32'hF3F4_F5F6); + WishboneWR(12,16'h0000); + WishboneWR(16,32'h0000_0000); + + @(posedge clk); + SendFlowCtrl(16'h0007); // Send flow control + @(posedge clk); + #30000; + @(posedge clk); + SendFlowCtrl(16'h0009); // Increase flow control before it expires + #10000; + @(posedge clk); + SendFlowCtrl(16'h0000); // Cancel flow control before it expires + @(posedge clk); + + SendPacket_to_fifo36(8'hAA,10); // This packet gets dropped by the filters + repeat (10) + @(posedge clk); + + SendPacketFromFile_fifo36(60,0,0); // The rest are valid packets + repeat (10) + @(posedge clk); + + SendPacketFromFile_fifo36(61,0,0); + repeat (10) + @(posedge clk); + SendPacketFromFile_fifo36(62,0,0); + repeat (10) + @(posedge clk); + SendPacketFromFile_fifo36(63,0,0); + repeat (1) + @(posedge clk); + SendPacketFromFile_fifo36(64,0,0); + repeat (10) + @(posedge clk); + SendPacketFromFile_fifo36(59,0,0); + repeat (1) + @(posedge clk); + SendPacketFromFile_fifo36(58,0,0); + repeat (1) + @(posedge clk); + SendPacketFromFile_fifo36(100,0,0); + repeat (1) + @(posedge clk); + SendPacketFromFile_fifo36(200,150,30); // waiting 14 empties the fifo, 15 underruns + repeat (1) + @(posedge clk); + SendPacketFromFile_fifo36(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_f36_dst_rdy <= 0; + repeat (30) // Repeat of 14 fills the shortfifo, but works. 15 overflows + @(posedge clk); + rx_f36_dst_rdy <= 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_f36_src_rdy & rx_f36_dst_rdy) + begin + if(rx_f36_dat[32] & ~rx_f36_dat[33]) + $display("RX-PKT-START %d",$time); + $display("RX-PKT SOF %d EOF %d ERR %d OCC %d DAT %x",rx_f36_dat[32],rx_f36_dat[33], + &rx_f36_dat[33:32],rx_f36_dat[35:34],rx_f36_dat[31:0]); + if(rx_f36_dat[33] & ~rx_f36_dat[32]) + $display("RX-PKT-END %d",$time); + if(rx_f36_dat[33] & rx_f36_dat[32]) + $display("RX-PKT-ERROR %d",$time); + end + +endmodule // simple_gemac_wrapper_tb diff --git a/fpga/usrp2/simple_gemac/simple_gemac_wrapper_tb.v b/fpga/usrp2/simple_gemac/simple_gemac_wrapper_tb.v new file mode 100644 index 000000000..5a3f3f832 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper_tb.v @@ -0,0 +1,222 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + + + +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 diff --git a/fpga/usrp2/simple_gemac/test_packet.mem b/fpga/usrp2/simple_gemac/test_packet.mem new file mode 100644 index 000000000..7f41d3e42 --- /dev/null +++ b/fpga/usrp2/simple_gemac/test_packet.mem @@ -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 |