`include "timescale.v" module eth_transmitcontrol (MTxClk, TxReset, TxUsedDataIn, TxUsedDataOut, TxDoneIn, TxAbortIn, TxStartFrmIn, TPauseRq, TxUsedDataOutDetected, TxFlow, DlyCrcEn, TxPauseTV, MAC, TxCtrlStartFrm, TxCtrlEndFrm, SendingCtrlFrm, CtrlMux, ControlData, WillSendControlFrame, BlockTxDone ); input MTxClk; input TxReset; input TxUsedDataIn; input TxUsedDataOut; input TxDoneIn; input TxAbortIn; input TxStartFrmIn; input TPauseRq; input TxUsedDataOutDetected; input TxFlow; input DlyCrcEn; input [15:0] TxPauseTV; input [47:0] MAC; output TxCtrlStartFrm; output TxCtrlEndFrm; output SendingCtrlFrm; output CtrlMux; output [7:0] ControlData; output WillSendControlFrame; output BlockTxDone; reg SendingCtrlFrm; reg CtrlMux; reg WillSendControlFrame; reg [3:0] DlyCrcCnt; reg [5:0] ByteCnt; reg ControlEnd_q; reg [7:0] MuxedCtrlData; reg TxCtrlStartFrm; reg TxCtrlStartFrm_q; reg TxCtrlEndFrm; reg [7:0] ControlData; reg TxUsedDataIn_q; reg BlockTxDone; wire IncrementDlyCrcCnt; wire ResetByteCnt; wire IncrementByteCnt; wire ControlEnd; wire IncrementByteCntBy2; wire EnableCnt; // A command for Sending the control frame is active (latched) always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) WillSendControlFrame <= 1'b0; else if(TxCtrlEndFrm & CtrlMux) WillSendControlFrame <= 1'b0; else if(TPauseRq & TxFlow) WillSendControlFrame <= 1'b1; end // Generation of the transmit control packet start frame always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) TxCtrlStartFrm <= 1'b0; else if(TxUsedDataIn_q & CtrlMux) TxCtrlStartFrm <= 1'b0; else if(WillSendControlFrame & ~TxUsedDataOut & (TxDoneIn | TxAbortIn | TxStartFrmIn | (~TxUsedDataOutDetected))) TxCtrlStartFrm <= 1'b1; end // Generation of the transmit control packet end frame always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) TxCtrlEndFrm <= 1'b0; else if(ControlEnd | ControlEnd_q) TxCtrlEndFrm <= 1'b1; else TxCtrlEndFrm <= 1'b0; end // Generation of the multiplexer signal (controls muxes for switching between // normal and control packets) always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) CtrlMux <= 1'b0; else if(WillSendControlFrame & ~TxUsedDataOut) CtrlMux <= 1'b1; else if(TxDoneIn) CtrlMux <= 1'b0; end // Generation of the Sending Control Frame signal (enables padding and CRC) always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) SendingCtrlFrm <= 1'b0; else if(WillSendControlFrame & TxCtrlStartFrm) SendingCtrlFrm <= 1'b1; else if(TxDoneIn) SendingCtrlFrm <= 1'b0; end always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) TxUsedDataIn_q <= 1'b0; else TxUsedDataIn_q <= TxUsedDataIn; end // Generation of the signal that will block sending the Done signal to the eth_wishbone module // While sending the control frame always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) BlockTxDone <= 1'b0; else if(TxCtrlStartFrm) BlockTxDone <= 1'b1; else if(TxStartFrmIn) BlockTxDone <= 1'b0; end always @ (posedge MTxClk) begin ControlEnd_q <= ControlEnd; TxCtrlStartFrm_q <= TxCtrlStartFrm; end assign IncrementDlyCrcCnt = CtrlMux & TxUsedDataIn & ~DlyCrcCnt[2]; // Delayed CRC counter always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) DlyCrcCnt <= 4'h0; else if(ResetByteCnt) DlyCrcCnt <= 4'h0; else if(IncrementDlyCrcCnt) DlyCrcCnt <= DlyCrcCnt + 4'd1; end assign ResetByteCnt = TxReset | (~TxCtrlStartFrm & (TxDoneIn | TxAbortIn)); assign IncrementByteCnt = CtrlMux & (TxCtrlStartFrm & ~TxCtrlStartFrm_q & ~TxUsedDataIn | TxUsedDataIn & ~ControlEnd); assign IncrementByteCntBy2 = CtrlMux & TxCtrlStartFrm & (~TxCtrlStartFrm_q) & TxUsedDataIn; // When TxUsedDataIn and CtrlMux are set at the same time assign EnableCnt = (~DlyCrcEn | DlyCrcEn & (&DlyCrcCnt[1:0])); // Byte counter always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) ByteCnt <= 6'h0; else if(ResetByteCnt) ByteCnt <= 6'h0; else if(IncrementByteCntBy2 & EnableCnt) ByteCnt <= (ByteCnt[5:0] ) + 6'd2; else if(IncrementByteCnt & EnableCnt) ByteCnt <= (ByteCnt[5:0] ) + 6'd1; end assign ControlEnd = ByteCnt[5:0] == 6'h22; // Control data generation (goes to the TxEthMAC module) always @ (ByteCnt or DlyCrcEn or MAC or TxPauseTV or DlyCrcCnt) begin case(ByteCnt) 6'h0: if(~DlyCrcEn | DlyCrcEn & (&DlyCrcCnt[1:0])) MuxedCtrlData[7:0] = 8'h01; // Reserved Multicast Address else MuxedCtrlData[7:0] = 8'h0; 6'h2: MuxedCtrlData[7:0] = 8'h80; 6'h4: MuxedCtrlData[7:0] = 8'hC2; 6'h6: MuxedCtrlData[7:0] = 8'h00; 6'h8: MuxedCtrlData[7:0] = 8'h00; 6'hA: MuxedCtrlData[7:0] = 8'h01; 6'hC: MuxedCtrlData[7:0] = MAC[47:40]; 6'hE: MuxedCtrlData[7:0] = MAC[39:32]; 6'h10: MuxedCtrlData[7:0] = MAC[31:24]; 6'h12: MuxedCtrlData[7:0] = MAC[23:16]; 6'h14: MuxedCtrlData[7:0] = MAC[15:8]; 6'h16: MuxedCtrlData[7:0] = MAC[7:0]; 6'h18: MuxedCtrlData[7:0] = 8'h88; // Type/Length 6'h1A: MuxedCtrlData[7:0] = 8'h08; 6'h1C: MuxedCtrlData[7:0] = 8'h00; // Opcode 6'h1E: MuxedCtrlData[7:0] = 8'h01; 6'h20: MuxedCtrlData[7:0] = TxPauseTV[15:8]; // Pause timer value 6'h22: MuxedCtrlData[7:0] = TxPauseTV[7:0]; default: MuxedCtrlData[7:0] = 8'h0; endcase end // Latched Control data always @ (posedge MTxClk or posedge TxReset) begin if(TxReset) ControlData[7:0] <= 8'h0; else if(~ByteCnt[0]) ControlData[7:0] <= MuxedCtrlData[7:0]; end endmodule