diff options
| -rw-r--r-- | simple_gemac/crc.v | 63 | ||||
| -rw-r--r-- | simple_gemac/flow_ctrl_rx.v | 85 | ||||
| -rw-r--r-- | simple_gemac/flow_ctrl_tx.v | 36 | ||||
| -rw-r--r-- | simple_gemac/simple_gemac.v | 55 | ||||
| -rw-r--r-- | simple_gemac/simple_gemac_tb.v | 88 | ||||
| -rw-r--r-- | simple_gemac/simple_gemac_tx.v | 200 | 
6 files changed, 527 insertions, 0 deletions
| diff --git a/simple_gemac/crc.v b/simple_gemac/crc.v new file mode 100644 index 000000000..c54623859 --- /dev/null +++ b/simple_gemac/crc.v @@ -0,0 +1,63 @@ +
 +module crc
 +  (input clk, 
 +   input reset,
 +   input clear, 
 +   input [7:0] data,
 +   input calc,
 +   output [31:0] crc_out);
 +   
 +   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] };
 +   
 +endmodule // crc
 diff --git a/simple_gemac/flow_ctrl_rx.v b/simple_gemac/flow_ctrl_rx.v new file mode 100644 index 000000000..7ded9e08b --- /dev/null +++ b/simple_gemac/flow_ctrl_rx.v @@ -0,0 +1,85 @@ +
 +// RX side of flow control -- when we are running out of RX space, send a PAUSE
 +
 +module flow_ctrl_rx
 +  (input        rst,
 +   //host processor
 +   input        pause_frame_send_en,
 +   input [15:0] pause_quanta_set,
 +   input [15:0] fc_hwmark,
 +   input [15:0] fc_lwmark,
 +   // From MAC_rx_ctrl
 +   input        rx_clk,
 +   input [15:0] rx_fifo_space,
 +   // MAC_tx_ctrl
 +   input        tx_clk,
 +   output reg   xoff_gen,
 +   output reg   xon_gen,
 +   input        xoff_gen_complete,
 +   input        xon_gen_complete
 +   );
 +   
 +   // ******************************************************************************        
 +   // Force our TX to send a PAUSE frame because our RX is nearly full
 +   // ******************************************************************************
 +
 +   reg xon_int, xoff_int;
 +   reg [21:0] countdown;
 + 
 +   always @(posedge rx_clk or posedge rst)
 +     if(rst)
 +       begin
 +	  xon_int <= 0;
 +	  xoff_int <= 0;
 +       end
 +     else 
 +       begin
 +	  xon_int <= 0;
 +	  xoff_int <= 0;
 +	  if(pause_frame_send_en)
 +	    if(countdown == 0)
 +	      if(rx_fifo_space < fc_lwmark)
 +		xoff_int <= 1;
 +	      else
 +		;
 +	    else
 +	      if(rx_fifo_space > fc_hwmark)
 +		xon_int <= 1;
 +       end // else: !if(rst)
 +   
 +   reg xoff_int_d1, xon_int_d1;
 +
 +   always @(posedge rx_clk)
 +     xon_int_d1 <= xon_int;
 +   always @(posedge rx_clk)
 +     xoff_int_d1 <= xoff_int;
 +   
 +   always @ (posedge tx_clk or posedge rst)
 +     if (rst)
 +       xoff_gen        <=0;
 +     else if (xoff_gen_complete)
 +       xoff_gen        <=0;
 +     else if (xoff_int | xoff_int_d1)
 +       xoff_gen        <=1;
 +   
 +   always @ (posedge tx_clk or posedge rst)
 +     if (rst)
 +       xon_gen     <=0;
 +     else if (xon_gen_complete)
 +       xon_gen     <=0;
 +     else if (xon_int | xon_int_d1)
 +       xon_gen     <=1;                     
 +
 +   wire [15:0] pq_reduced = pause_quanta_set - 2;
 +   
 +   always @(posedge tx_clk or posedge rst)
 +     if(rst)
 +       countdown <= 0;
 +     else if(xoff_gen)
 +       countdown <= {pq_reduced,6'd0};
 +     else if(xon_gen)
 +       countdown <= 0;
 +     else if(countdown != 0)
 +       countdown <= countdown - 1;
 +   
 +endmodule // flow_ctrl
 diff --git a/simple_gemac/flow_ctrl_tx.v b/simple_gemac/flow_ctrl_tx.v new file mode 100644 index 000000000..9f7556de4 --- /dev/null +++ b/simple_gemac/flow_ctrl_tx.v @@ -0,0 +1,36 @@ +
 +// 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        pause_quanta_sub);
 +     
 +   // ******************************************************************************        
 +   // Inhibit our TX from transmitting because they sent us a PAUSE frame
 +   // ******************************************************************************
 +
 +   reg [15: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; 
 +     else if((pause_quanta_counter!=0) & pause_quanta_sub)
 +       pause_quanta_counter <= pause_quanta_counter - 1;
 +
 +   assign	pause_apply = tx_pause_en & (pause_quanta_counter != 0);
 +   
 +endmodule // flow_ctrl
 diff --git a/simple_gemac/simple_gemac.v b/simple_gemac/simple_gemac.v new file mode 100644 index 000000000..0769fe615 --- /dev/null +++ b/simple_gemac/simple_gemac.v @@ -0,0 +1,55 @@ + +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, + +   // 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 +   ); + +   localparam SGE_IFG 		     = 8'd12;  // 12 should be the absolute minimum +   localparam SGE_RESPECT_FLOW_CTRL  = 1'b1;  // stop sending if other side requests + +   wire rst_rxclk, rst_txclk;    +   oneshot_2clk tx_rst_1shot (.clk_in(tx_clk),.in(reset),.clk_out(tx_clk),.out(rst_txclk));  // FIXME clocks +   oneshot_2clk rx_rst_1shot (.clk_in(sys_clk),.in(reset),.clk_out(rx_clk),.out(rst_rxclk)); + +   wire [15:0] pause_quanta_rcvd; +    +   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(48'hF1_F2_F3_F4_F5_F6), +      .pause_req(pause_req), .pause_time(pause_time),  // We request flow control +      .pause_apply(pause_apply), .pause_applied(pause_applied)  // 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), +      .pause_quanta_rcvd(pause_qanta_rcvd), .pause_rcvd(pause_rcvd)  +      ); +  */  +   flow_ctrl_tx flow_ctrl_tx +     (.rst(reset_txclk), .tx_clk(tx_clk), +      .tx_pause_en(SGE_RESPECT_FLOW_CTRL), +      .pause_quanta(pause_quanta_rcvd), // 16 bit value +      .pause_quanta_val(pause_rcvd), +      .pause_apply(pause_apply), +      .pause_quanta_sub(pause_applied) +      ); + +    +endmodule // simple_gemac diff --git a/simple_gemac/simple_gemac_tb.v b/simple_gemac/simple_gemac_tb.v new file mode 100644 index 000000000..61dbbe4c9 --- /dev/null +++ b/simple_gemac/simple_gemac_tb.v @@ -0,0 +1,88 @@ + + +module simple_gemac_tb; + +      +   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; +   wire [7:0] GMII_RXD, GMII_TXD; + +   wire rx_valid, rx_error, rx_ack; +   wire tx_ack; +   reg tx_valid = 0, tx_error = 0; +    +   wire [7:0] rx_data; +   reg [7:0] tx_data; +    +   wire [15:0] pause_time = 16'hBEEF; +   reg pause_req = 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), +      .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) +      ); + +   task SendFlowCtrl; +     begin +	$display("Sending Flow Control"); +	@(posedge clk); +	pause_req <= 1; +	@(posedge clk); +	pause_req <= 0; +     end +   endtask // SendFlowCtrl + +   reg [31:0] count; +   task SendPacket; +      input [7:0] data_start; +      input [31:0] data_len; +      begin +	 $display("Sending Packet"); +	 count <= 0; +	 tx_data  <= data_start; +	 tx_error <= 0; +	 tx_valid <= 1; +	 while(~tx_ack) +	   @(posedge tx_clk); +	 while(count < data_len) +	   begin +	      tx_data <= tx_data + 1; +	      count   <= count + 1; +	      @(posedge clk); +	   end +	 tx_valid <= 0; +	 @(posedge tx_clk); +      end +   endtask // SendPacket +   	 +   initial $dumpfile("simple_gemac_tb.vcd"); +   initial $dumpvars(0,simple_gemac_tb); +	 +   initial +     begin +	@(negedge reset); +	repeat (20) +	  @(posedge clk); +	SendFlowCtrl; +	repeat (100) +	  @(posedge clk); +	SendPacket(8'hAA,10); +	repeat (1000) +	  @(posedge clk); +	$finish; +     end +    +endmodule // simple_gemac_tb diff --git a/simple_gemac/simple_gemac_tx.v b/simple_gemac/simple_gemac_tx.v new file mode 100644 index 000000000..cddb18a3a --- /dev/null +++ b/simple_gemac/simple_gemac_tx.v @@ -0,0 +1,200 @@ + +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 pause_applied +   ); +    +   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 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; +    +   localparam TX_IDLE 	     = 0; +   localparam TX_PREAMBLE    = 1; +   localparam TX_SOF_DEL     = TX_PREAMBLE + 7; +   localparam TX_IN_FRAME    = TX_SOF_DEL + 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 	     = 56; +   localparam TX_PAUSE_PRE   = TX_PAUSE + 1; +   localparam TX_PAUSE_SOF   = 64; +   localparam TX_PAUSE_END   = TX_PAUSE_SOF + 18; + +   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) +	       tx_state <= TX_PREAMBLE; +	 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) +	     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 : +	   tx_state <= TX_PAUSE_PRE; +	 TX_PAUSE_END : +	   tx_state <= TX_PAD; +	 default : +	   tx_state  <= tx_state + 1; +       endcase // case (tx_state) + +   always @(posedge tx_clk) +     if(reset) +       begin +	  GMII_TX_EN <= 0; +	  GMII_TX_ER <= 0; +	  GMII_TXD   <= 0; +       end +     else +       casex(tx_state) +	 TX_IDLE : +	   begin +	      GMII_TX_EN <= 0; +	      GMII_TX_ER <= 0; +	      GMII_TXD <= 0; +	   end +	 TX_PREAMBLE, TX_PAUSE_PRE : +	   begin +	      GMII_TXD 	 <= 8'h55; +	      GMII_TX_EN <= 1; +	   end +	 TX_SOF_DEL, TX_PAUSE_SOF : +	   GMII_TXD <= 8'hD5; +	 TX_IN_FRAME, TX_IN_FRAME_2 : +	   GMII_TXD <= tx_data; +	 TX_ERROR : +	   begin +	      GMII_TX_ER <= 1; +	      GMII_TXD 	 <= 0; +	   end +	 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]; +	 TX_PAD : +	   GMII_TXD <= 0; +	 8'b01xx_xxxx :  // In Pause Frame +	   GMII_TXD <= 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    = 1; +    +   crc crc(.clk(tx_clk), .reset(reset), .clear(clear_crc), +	    .data(GMII_TXD), .calc(calc_crc), .crc_out(crc_out)); + +   assign tx_ack = (tx_state == TX_IN_FRAME); +endmodule // simple_gemac_tx | 
