OpenCores

* Ethernet MAC 10/100 Mbps

Issue List
Mac Latchup; 2 issues, solutions found. #13
Open Joshua5526 opened this issue over 4 years ago
Joshua5526 commented over 4 years ago

Hello. I have discovered 2 issues and have working solutions. Sorry if this is a double post opencores.org locked up last time I hit submit.

====================================== The first issue is in the wishbone module.

The variable RxStatus gets assigned the value from bd_ram which was supposed to be loaded into RxPointerMSB. This messes up WrapRxStatusBit causing the RxBDAddress to increment instead of reset.

The way RxStatus reads the RxPointerMSB's value is a badly timed RxAbort from a packet which is coming in before the core is ready for it. If it activates right when the pointer is getting or about to be read from the ram, RxBDRead activates again and because RxEn is already active for the pointer read, it doesn't take two cycles and it snags the wrong value.

The correction for this first problem is to block StartRxBdRead if RxPointerRead is active. So change assign StartRxBDRead = RxStatusWrite | RxAbortSync3 & ~RxAbortSync4 | r_RxEn & ~r_RxEn_q; to assign StartRxBDRead = RxStatusWrite | (RxAbortSync3 & ~RxAbortSync4 & ~RxPointerRead) | r_RxEn & ~r_RxEn_q;

The possible side effect of this change is that the core may pass on a packet which has the wrong mac address, but as seeing that mac's are sometimes configured to be promiscuous and the higher level ip layer should filter out these packets anyways, this does not seem to be a problem.

===================================== The second issue is in the txstatem and by implication probably the rxstatem.

The state machine is encoded as a one hot encoding with different 1 bit registers being active for different states by passing the bit around depending on what state is active and conditions. The problem is that sometimes the bit gets lost. There is currently no logic for dealing with this condition and when it happens the TX core halts.

This issue has been most frequently observed on system boot. The StateDefer comes up first and tries to pass the bit to StateIPG but I have seen one out of 250 boots for StateDefer to drop and StateIPG to not pick it up. Perhaps this has to do with the asynchronous nature between when the global reset releases and the external PHY clock.

To correct this problem I defined a new signal which detects when no state is active. wire NoActiveState; assign NoActiveState = ~StateIdle & ~StateIPG & ~StatePreamble & ~StateData0 & ~StateData1 & ~StatePAD & ~StateFCS & ~StateJam & ~StateBackOff & ~StateDefer; and then include that is a start condition for the reset state StateDefer

assign StartDefer = StateIPG & ~Rule1 & CarrierSense & NibCnt6:0 <= IPGR1 & NibCnt6:0 != IPGR2 | StateIdle & CarrierSense | StateJam & NibCntEq7 & (NoBckof | RandomEq0 | ~ColWindow | RetryMax) | StateBackOff & (TxUnderRun | RandomEqByteCnt) | StartTxDone | TooBig | NoActiveState;

I have scoped this running with automated reboots and have seen the NoActiveState kick in multiple times and this prevented the problem where our device would randomly come up deaf. The reboots would happen about every 5 seconds and the signal activated about 24 times overnight.

The corresponding addition to the rxstatem are: create the line: wire NoActiveState; assign NoActiveState = ~StateIdle & ~StateDrop & ~StatePreamble & ~StateSFD & ~StateData0 & ~StateData1;

and append the signal to StartDrop: assign StartDrop = (MRxDV & (StateIdle & Transmitting | StateSFD & ~IFGCounterEq24 & MRxDEqD | StateData0 & ByteCntMaxFrame)) | NoActiveState;

Joshua5526 commented over 4 years ago

The brackets got replaced with links, here it is again with the brackets escaped:

In wishbone:

assign StartRxBDRead = RxStatusWrite | (RxAbortSync3 & ~RxAbortSync4 & ~RxPointerRead) | r_RxEn & ~r_RxEn_q;

In txstatem:

wire NoActiveState;

assign NoActiveState = ~StateIdle & ~StateIPG & ~StatePreamble & ~StateData[0] & ~StateData[1] & ~StatePAD & ~StateFCS & ~StateJam & ~StateBackOff & ~StateDefer;

assign StartDefer = StateIPG & ~Rule1 & CarrierSense & NibCnt[6:0] <= IPGR1 & NibCnt[6:0] != IPGR2 | StateIdle & CarrierSense | StateJam & NibCntEq7 & (NoBckof | RandomEq0 | ~ColWindow | RetryMax) | StateBackOff & (TxUnderRun | RandomEqByteCnt) | StartTxDone | TooBig | NoActiveState;

In rxstatem:

wire NoActiveState;

assign NoActiveState = ~StateIdle & ~StateDrop & ~StatePreamble & ~StateSFD & ~StateData0 & ~StateData1;

assign StartDrop = (MRxDV & (StateIdle & Transmitting | StateSFD & ~IFGCounterEq24 & MRxDEqD | StateData0 & ByteCntMaxFrame)) | NoActiveState;


Assignee
No one
Labels
Bug