diff options
Diffstat (limited to 'fpga/usrp2/simple_gemac')
32 files changed, 3696 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..7bcc58c91 --- /dev/null +++ b/fpga/usrp2/simple_gemac/Makefile.srcs @@ -0,0 +1,29 @@ +# +# Copyright 2010 Ettus Research LLC +# + +################################################## +# Simple GEMAC Sources +################################################## +SIMPLE_GEMAC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../simple_gemac/, \ +simple_gemac_wrapper.v \ +simple_gemac_wrapper19.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..50a52b954 --- /dev/null +++ b/fpga/usrp2/simple_gemac/address_filter.v @@ -0,0 +1,35 @@ + + +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..6047e7c93 --- /dev/null +++ b/fpga/usrp2/simple_gemac/address_filter_promisc.v @@ -0,0 +1,32 @@ + + +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..ac019083a --- /dev/null +++ b/fpga/usrp2/simple_gemac/crc.v @@ -0,0 +1,66 @@ +
 +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..d371bb9c5 --- /dev/null +++ b/fpga/usrp2/simple_gemac/delay_line.v @@ -0,0 +1,21 @@ + + +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..d49f30e24 --- /dev/null +++ b/fpga/usrp2/simple_gemac/eth_tasks.v @@ -0,0 +1,156 @@ + + +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..ff3ae5407 --- /dev/null +++ b/fpga/usrp2/simple_gemac/eth_tasks_f19.v @@ -0,0 +1,92 @@ + + +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..dc64971d4 --- /dev/null +++ b/fpga/usrp2/simple_gemac/eth_tasks_f36.v @@ -0,0 +1,92 @@ + + +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..0a369c914 --- /dev/null +++ b/fpga/usrp2/simple_gemac/ethrx_realign.v @@ -0,0 +1,72 @@ + +// 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..be53abf4c --- /dev/null +++ b/fpga/usrp2/simple_gemac/ethtx_realign.v @@ -0,0 +1,77 @@ + +//////////////////////////////////////////////////////////////////////// +// 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..d09bf377f --- /dev/null +++ b/fpga/usrp2/simple_gemac/flow_ctrl_rx.v @@ -0,0 +1,61 @@ +
 +// 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..f80f5a76d --- /dev/null +++ b/fpga/usrp2/simple_gemac/flow_ctrl_tx.v @@ -0,0 +1,39 @@ +
 +// 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..3530a0c59 --- /dev/null +++ b/fpga/usrp2/simple_gemac/ll8_to_txmac.v @@ -0,0 +1,43 @@ + +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..9da732f7f --- /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..a15c94205 --- /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..3df6c560a --- /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..0b97bb7bc --- /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..5ec233d95 --- /dev/null +++ b/fpga/usrp2/simple_gemac/rxmac_to_ll8.v @@ -0,0 +1,54 @@ + +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..2dd8deb99 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac.v @@ -0,0 +1,64 @@ + +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..32f517bb3 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_rx.v @@ -0,0 +1,179 @@ + + +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..6091751a7 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_tb.v @@ -0,0 +1,200 @@ + + +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..dd870d04d --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_tx.v @@ -0,0 +1,254 @@ + +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..1ef38be11 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wb.v @@ -0,0 +1,162 @@ + +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..8390eb2c6 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper.v @@ -0,0 +1,154 @@ + +module simple_gemac_wrapper +  #(parameter RXFIFOSIZE=9, +    parameter TXFIFOSIZE=9) +   (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(pause_req), .pause_time_req(pause_time_req),  +      .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 +   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)); +    +   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_wrapper19.build b/fpga/usrp2/simple_gemac/simple_gemac_wrapper19.build new file mode 100755 index 000000000..b9475baa2 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper19.build @@ -0,0 +1 @@ +iverilog -Wimplict -Wportbind -y ../fifo/ -y ../models/ -y . -y miim -y ../coregen/ -y ../control_lib/ -o simple_gemac_wrapper19_tb simple_gemac_wrapper19_tb.v diff --git a/fpga/usrp2/simple_gemac/simple_gemac_wrapper19.v b/fpga/usrp2/simple_gemac/simple_gemac_wrapper19.v new file mode 100644 index 000000000..2ac8b9be1 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper19.v @@ -0,0 +1,157 @@ + +module simple_gemac_wrapper19 +  #(parameter RXFIFOSIZE=9, +    parameter TXFIFOSIZE=6) +   (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 [18:0] rx_f19_data, output rx_f19_src_rdy, input rx_f19_dst_rdy, +    input [18:0] tx_f19_data, input tx_f19_src_rdy, output tx_f19_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(pause_req), .pause_time_req(pause_time_req),  +      .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; +    +   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) ); + +   fifo_2clock_cascade #(.WIDTH(36), .SIZE(RXFIFOSIZE)) rx_2clk_fifo +     (.wclk(rx_clk), .datain(rx_f19_data_int2),  +      .src_rdy_i(rx_f19_src_rdy_int2), .dst_rdy_o(rx_f19_dst_rdy_int2), .space(rx_fifo_space), +      .rclk(sys_clk), .dataout(rx_f19_data),  +      .src_rdy_o(rx_f19_src_rdy), .dst_rdy_i(rx_f19_dst_rdy), .occupied(), .arst(reset)); +    +   // TX FIFO Chain +   wire 	  tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy; +   wire 	  tx_ll_sof2, tx_ll_eof2, tx_ll_src_rdy2, tx_ll_dst_rdy2; +   wire 	  tx_ll_sof2_n, tx_ll_eof2_n, tx_ll_src_rdy2_n, tx_ll_dst_rdy2_n; +   wire [7:0] 	  tx_ll_data, tx_ll_data2; +   wire [18:0] 	  tx_f19_data_int1; +   wire 	  tx_f19_src_rdy_int1, tx_f19_dst_rdy_int1; + +   fifo_2clock_cascade #(.WIDTH(19), .SIZE(4)) tx_2clk_fifo +     (.wclk(sys_clk), .datain(tx_f19_data),  +      .src_rdy_i(tx_f19_src_rdy), .dst_rdy_o(tx_f19_dst_rdy), .space(), +      .rclk(tx_clk), .dataout(tx_f19_data_int1),  +      .src_rdy_o(tx_f19_src_rdy_int1), .dst_rdy_i(tx_f19_dst_rdy_int1), .occupied(), .arst(rx_reset)); +    +   fifo19_to_ll8 fifo19_to_ll8 +     (.clk(tx_clk), .reset(tx_reset), .clear(clear), +      .f19_data(tx_f19_data_int1), .f19_src_rdy_i(tx_f19_src_rdy_int1), .f19_dst_rdy_o(tx_f19_dst_rdy_int1), +      .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_n)); + +   assign tx_ll_sof2 	    = ~tx_ll_sof2_n; +   assign tx_ll_eof2 	    = ~tx_ll_eof2_n; +   assign tx_ll_src_rdy2    = ~tx_ll_src_rdy2_n; +   assign tx_ll_dst_rdy2_n  = ~tx_ll_dst_rdy2; +    +   ll8_shortfifo tx_sfifo +     (.clk(tx_clk), .reset(tx_reset), .clear(clear), +      .datain(tx_ll_data2), .sof_i(tx_ll_sof2), .eof_i(tx_ll_eof2), +      .error_i(0), .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(), .src_rdy_o(tx_ll_src_rdy), .dst_rdy_i(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 +   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)); +    +   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,  +			  tx_ll_sof2, tx_ll_eof2, tx_ll_src_rdy2, tx_ll_dst_rdy2 }, +			{ tx_valid, tx_error, tx_ack, tx_f19_src_rdy_int1, tx_f19_dst_rdy_int1, tx_f19_data_int1[18:16]}, +			{ tx_data} }; +   assign debug_rx  = { { rx_f19_src_rdy, rx_f19_dst_rdy, debug_state[5:0] }, +			{ rx_ll_sof, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy, 4'b0 }, +			{ rx_valid, rx_error, rx_ack, rx_f19_src_rdy_int1, rx_f19_dst_rdy_int1, rx_f19_data_int1[18:16]}, +			{ rx_data} }; + +   assign debug  = debug_rx; +    +endmodule // simple_gemac_wrapper19 diff --git a/fpga/usrp2/simple_gemac/simple_gemac_wrapper19_tb.v b/fpga/usrp2/simple_gemac/simple_gemac_wrapper19_tb.v new file mode 100644 index 000000000..b61d60d30 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper19_tb.v @@ -0,0 +1,209 @@ + + +module simple_gemac_wrapper19_tb; +`include "eth_tasks_f19.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; +    +   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 [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 [19:0]  tx_f19_data=0; +   reg 	       tx_f19_src_rdy = 0; +   wire        tx_f19_dst_rdy; +   wire [35:0] rx_f19_data; +   wire        rx_f19_src_rdy; +   wire        rx_f19_dst_rdy = 1; +    +   simple_gemac_wrapper19 simple_gemac_wrapper19 +     (.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), +      //.pause_req(pause_req), .pause_time(pause_time), + +      .sys_clk(sys_clk), .rx_f19_data(rx_f19_data), .rx_f19_src_rdy(rx_f19_src_rdy), .rx_f19_dst_rdy(rx_f19_dst_rdy), +      .tx_f19_data(tx_f19_data), .tx_f19_src_rdy(tx_f19_src_rdy), .tx_f19_dst_rdy(tx_f19_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_wrapper19_tb.vcd"); +   initial $dumpvars(0,simple_gemac_wrapper19_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_fifo19(32'hA0B0C0D0,10);    // This packet gets dropped by the filters +	repeat (1000) +	  @(posedge sys_clk); + +	SendPacket_to_fifo19(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_wrapper19_tb 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..804fa8748 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper_f36_tb.v @@ -0,0 +1,243 @@ + + +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..0aadc7e93 --- /dev/null +++ b/fpga/usrp2/simple_gemac/simple_gemac_wrapper_tb.v @@ -0,0 +1,205 @@ + + +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 | 
