I've written a simple VHDL wrapper around the MAC, which sends packets with lengths of 1052 bytes through the Gigabyte Ethernet. When I send packets continuously with pauses between them not longer than ca. 3.5µs, everything works correctly. When there is a pause longer than ca. 3.5 µs, during the transfer of the next packet, the tx_mac_wa signal doesn't go up, so the whole transfer is interrupted...
I have analyzed the problem with wireshark, and my fpgadbg debugger. I have stated, that the last packet before the longer pause is correctly transmitted. The TX fifo gets filled when new data are written, and the tx_fifo_wa goes down when the fifo is filled to the set TX_Hwmark level.
What's interesting, in that state the FIFO_rd signal in MAC_tx block remains high all the time, which causes Current_state_MAC in MAC_tx_FF to enter the MAC_FF_Err state.
So the direct cause of the problem is that MAC_tx continues to read FIFO, even though the previous packet is finished (the eop was set in the last word!)
I have analyzed states of the MAC_TX_CTRL state machine. It appears, that when the last word of the packet gets sent, the machine enters the StateIdle for one clock cycle. However the Fifo_ra signal is still high (it goes low after that cycle). As a result the state machine enters the StatePreamble, and tries to send the next packet (but the FIFO is empty). So the reason is, that the Fifo_ra signal is delayed. However the Fifo_ra is held high, as long as Packet_number_inFF_reg is high (see MAC_tx_FF.v, line 435). The Packet_number is updated only after sending of packet is finished.
Finally, I have found a workaround, based on introducing of an additional state StateIdle2. The only action in StateIdle is to enter the StateIdle2. In StateIdle2 we perform all tests, which previously were done in StateIdle. Probably there is a better way to solve that problem, but I had no time to investigate internals of all affected blocks more thoroughly... Below is the patch, I've applied to fix the problem:
*** /tmp/MAC_tx_Ctrl.v 2006-06-25 06:59:00.000000000 +0200 --- MAC_tx_Ctrl.v 2011-10-09 11:43:32.544538167 +0200
* 174,179 ** --- 174,180 ---- parameter StateSwitchNext =4'd12; parameter StateDefer =4'd13; parameter StateSendPauseFrame =4'd14;
* 277,282 **
--- 278,285 ----
else
Next_state=Current_state;
StateIdle:
Next_state=StateIdle2;
StateIdle2:
if (!FullDuplex&&CRS)
Next_state=StateDefer;
else if (pause_apply)
As the bugtracker does not display my patch correctly, I have sent it also to the discussion group. Please check: http://groups.google.com/group/opencores-tri-mode-eth-mac/t/a95de1361bbe2904
BTW, the fpgadbg, which I used to investigate the problem is available at http://www.ise.pw.edu.pl/~wzab/fpgadbg
Today I have stated, that in some conditions one "wait state" is too low. Therefore I had to add StateIdle3 state. As the number of states is now higher than 16, I had also to add additional bit to the CurrentState and NextState registers. So now the state machine works as follows: StateIdle -> StateIdle2 (unconditionally) StateIdle2 -> StateIdle3 (unconditionally) StateIdle3 -> Perform checks which were originally done in StateIdle.
The patch is sent to the discussion group. It seems, that after this change the controller works relaibly.
Hi, your solution doesn't work for me. But I have found another solution which solves the problem: In modul MAC_tx_FF.v Line 435 old version:
always @ (posedge Clk_SYS or posedge Reset)
if (Reset)
Fifo_ra_tmp <=0;
else if (Packet_number_inFF_reg>=1||Fifo_data_count>=Tx_Lwmark)
Fifo_ra_tmp <=1;
else
Fifo_ra_tmp <=0;
new version:
always @ (posedge Clk_SYS or posedge Reset)
if (Reset)
Fifo_ra_tmp <=0;
else if (Packet_number_inFF_reg>1||Fifo_data_count>=Tx_Lwmark)
Fifo_ra_tmp <=1;
else
Fifo_ra_tmp <=0;
Greetings from Germany
As mentionned in the google group by Mark Kaper. The fix for this problem is to get the Empty signal out of the tx_FF and into the tx_ctrl module.
THen change the StateIdle to the following.
Instead of making delay, it will wait just the right amount of clock cycle before quitting the StateIdle state.
StateIdle:
if (!FullDuplex&&CRS)
Next_state=StateDefer;
else if (pause_apply)
Next_state=StatePause;
else if (!Fifo_empty&&((FullDuplex&&Fifo_ra)||(!FullDuplex&&!CRS&&Fifo_ra)||(pause_frame_send_en_dl1&&(xoff_gen||xon_gen))))
Next_state=StatePreamble;
else
Next_state=Current_state;