Skip to content

Commit

Permalink
Merge Rudi and ConfReg
Browse files Browse the repository at this point in the history
  • Loading branch information
jvnknvlgl committed Jul 24, 2024
1 parent 545218d commit 73f1eaa
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 233 deletions.
8 changes: 4 additions & 4 deletions clash-cores/src/Clash/Cores/Sgmii.hs
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ sgmiiRx rxCg =
<$> bsOk
<*> syncStatus
<*> regMaybe 0 rxConfReg
<*> regMaybe Invalid rudi
<*> (toStatus <$> regMaybe Invalid rudi)
<*> regMaybe Conf xmit

(xmit, txConfReg) = autoNeg syncStatus rudi rxConfReg
(rxDv, rxEr, rxDw, rudi, rxConfReg) =
pcsReceive cg rd dw rxEven syncStatus xmit
rxConfReg = toConfReg <$> regMaybe (C 0) rudi
(xmit, txConfReg) = autoNeg syncStatus rudi
(rxDv, rxEr, rxDw, rudi) = pcsReceive cg rd dw rxEven syncStatus xmit
(cg, rd, dw, rxEven, syncStatus) = sync bsCg
(bsCg, bsOk) = bitSlip rxCg syncStatus

Expand Down
270 changes: 85 additions & 185 deletions clash-cores/src/Clash/Cores/Sgmii/AutoNeg.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -fconstraint-solver-iterations=10 #-}

-- |
Expand All @@ -19,12 +18,9 @@ module Clash.Cores.Sgmii.AutoNeg (

import Clash.Cores.Sgmii.Common
import Clash.Prelude
import Data.Maybe (fromJust, fromMaybe, isJust)
import Data.Maybe (fromMaybe)
import Data.Proxy

-- | List of values for 'ConfReg'
type ConfRegs = Vec 3 ConfReg

-- | List of values for 'Rudi'
type Rudis = Vec 3 Rudi

Expand All @@ -41,51 +37,44 @@ type Timeout dom = Index (DivRU (Microseconds 1600) (Max 1 (DomainPeriod dom)))
-- SGMII always requires auto-negotiation to be available.
data AutoNegState dom
= AnEnable
{ _rudis :: Maybe Rudis
, _rxConfRegs :: Maybe ConfRegs
, _failT :: Timeout dom
}
{_rudis :: Maybe Rudis, _rxConfReg :: ConfReg, _failT :: Timeout dom}
| AnRestart
{ _rudis :: Maybe Rudis
, _rxConfRegs :: Maybe ConfRegs
, _rxConfReg :: ConfReg
, _failT :: Timeout dom
, _linkT :: Timeout dom
}
| AbilityDetect
{_rudis :: Maybe Rudis, _rxConfReg :: ConfReg, _failT :: Timeout dom}
| AckDetect
{ _rudis :: Maybe Rudis
, _rxConfRegs :: Maybe ConfRegs
, _rxConfReg :: ConfReg
, _failT :: Timeout dom
, _txConfReg :: ConfReg
, _hist :: ConfReg
}
| AcknowledgeDetect
| CompleteAck
{ _rudis :: Maybe Rudis
, _rxConfRegs :: Maybe ConfRegs
, _failT :: Timeout dom
, _txConfReg :: ConfReg
, _rxConfReg :: ConfReg
}
| CompleteAcknowledge
{ _rudis :: Maybe Rudis
, _rxConfRegs :: Maybe ConfRegs
, _failT :: Timeout dom
, _linkT :: Timeout dom
}
| IdleDetect
{ _rudis :: Maybe Rudis
, _rxConfRegs :: Maybe ConfRegs
, _rxConfReg :: ConfReg
, _failT :: Timeout dom
, _linkT :: Timeout dom
}
| LinkOk
{ _rudis :: Maybe Rudis
, _rxConfRegs :: Maybe ConfRegs
, _failT :: Timeout dom
}
{_rudis :: Maybe Rudis, _rxConfReg :: ConfReg, _failT :: Timeout dom}
deriving (Generic, NFDataX, Eq, Show)

-- | The default configuration of the MAC as defined in the SGMII standard
mrAdvAbility :: ConfReg
mrAdvAbility = 0b0100000000000001
confReg :: ConfReg
confReg = 0b0100000000000001

-- | Set the acknowledge bit of a 'ConfReg' to zero
noAckBit :: ConfReg -> ConfReg
noAckBit = replaceBit (14 :: Index 16) 0

-- | The duration of @linkT@ is 1.6 ms according to the SGMII reference,
-- which means that it has a frequency of 625 Hz. This is the same as 200000
Expand All @@ -96,93 +85,35 @@ mrAdvAbility = 0b0100000000000001
timeout :: (KnownDomain dom) => Proxy dom -> Timeout dom
timeout Proxy = if clashSimulation then 3 else maxBound

-- | Function that handles the reset to 'AnEnable', this is split out to reduce
-- the amount of state transitions in every state
anEnable ::
forall dom.
(KnownDomain dom) =>
-- | Fail timer value
Timeout dom ->
-- | New incoming RUDI value
Maybe Rudi ->
-- | History of RUDI values
Rudis ->
-- | History of configuration registers
ConfRegs ->
-- | Possible state transition
Maybe (AutoNegState dom)
anEnable failT rudi rudis rxConfRegs
| failT >= timeout (Proxy @dom) =
Just (AnEnable (Just rudis) (Just rxConfRegs) (timeout (Proxy @dom) - 1))
| rudi == Just Invalid = Just (AnEnable (Just rudis) (Just rxConfRegs) failT)
| otherwise = Nothing

-- | Check if the the last three received values of @rxConfReg@ are the same
-- (with the exception for bit 14, the acknowledge bit, which is discarded).
-- If there has been 'Rudi' value of 'I' in the same set of values, then
-- return 'False'.
abilityMatch ::
-- | Last three values for 'Rudi'
Rudis ->
-- | Last three values for 'ConfReg'
ConfRegs ->
-- | Whether they satisfy the 'abilityMatch' condition
Bool
abilityMatch rudis rxConfRegs =
repeat (head rxConfRegs') == rxConfRegs' && I `notElem` rudis
abilityMatch :: Rudis -> Bool
abilityMatch rudis =
repeat (head rxConfRegs) == rxConfRegs && I `notElem` rudis
where
rxConfRegs' = map (replaceBit (14 :: Index 16) 0) rxConfRegs
rxConfRegs = map (noAckBit . fromMaybe 0 . toConfReg) rudis

-- | Check if the last three values for 'ConfReg' are all the same, and also
-- check whether bit 14 (the acknowledge bit) has been asserted
acknowledgeMatch ::
-- | Last three values for 'ConfReg'
ConfRegs ->
-- | Whether they satisfy the 'acknowledgeMatch' condition
Bool
acknowledgeMatch rxConfRegs =
ackMatch :: Rudis -> Bool
ackMatch rudis =
repeat (head rxConfRegs) == rxConfRegs && testBit (head rxConfRegs) 14
where
rxConfRegs = map (fromMaybe 0 . toConfReg) rudis

-- | Check if both 'abilityMatch' and 'acknowledgeMatch' are true for the same
-- | Check if both 'abilityMatch' and 'ackMatch' are true for the same
-- set of 'Rudi' and 'ConfReg' values.
consistencyMatch ::
-- | 'ConfReg' that was used to set 'abilityMatch'
ConfReg ->
-- | Last three values for 'ConfReg'
ConfRegs ->
-- | Whether they satisfy the 'consistencyMatch' condition
Bool
consistencyMatch rxConfReg rxConfRegs = rxConfReg' == head rxConfRegs'
consistencyMatch :: ConfReg -> Rudis -> Bool
consistencyMatch rxConfReg rudis = noAckBit rxConfReg == head rxConfRegs'
where
rxConfReg' = replaceBit (14 :: Index 16) 0 rxConfReg
rxConfRegs' = map (replaceBit (14 :: Index 16) 0) rxConfRegs
rxConfRegs' = map (noAckBit . fromMaybe 0 . toConfReg) rudis

-- | Function that checks that the last three values of 'Rudi' have been 'I'
idleMatch :: Rudis -> Bool
idleMatch = (==) (repeat I)

-- | General part of the status update of the auto negotiation function, where
-- the new values of 'Rudi', 'ConfReg' and the 'Timeout's are handled.
anUpdate ::
(KnownDomain dom) =>
AutoNegState dom ->
SyncStatus ->
Maybe Rudi ->
Maybe ConfReg ->
(Rudis, ConfRegs, Timeout dom, Timeout dom)
anUpdate s syncStatus rudi rxConfReg = (rudis, rxConfRegs, failT, linkT)
where
rudis = maybe rudis' (rudis' <<+) rudi
where
rudis' = fromMaybe (repeat I) s._rudis

rxConfRegs = maybe rxConfRegs' (rxConfRegs' <<+) rxConfReg
where
rxConfRegs' = fromMaybe (repeat 0) s._rxConfRegs

failT = if syncStatus == Fail then s._failT + 1 else 0
linkT = s._linkT + 1

-- | State transition function for 'autoNeg' as defined in IEEE 802.3 Clause 37.
-- It takes the current 'SyncStatus' from 'Sgmii.sync' as well as the 'Rudi'
-- and 'ConfReg' signals from 'Sgmii.pcsReceive'.
Expand All @@ -192,81 +123,55 @@ autoNegT ::
-- | Current state
AutoNegState dom ->
-- | New input values
(SyncStatus, Maybe Rudi, Maybe ConfReg) ->
(SyncStatus, Maybe Rudi) ->
-- | New state
AutoNegState dom
autoNegT self@AnEnable{} (syncStatus, rudi, rxConfReg)
| isJust s = fromJust s
| otherwise = AnRestart Nothing Nothing failT 0
where
s = anEnable failT rudi rudis rxConfRegs
(rudis, rxConfRegs, failT, _) = anUpdate self syncStatus rudi rxConfReg
autoNegT self@AnRestart{} (syncStatus, rudi, rxConfReg)
| isJust s = fromJust s
| linkT >= timeout (Proxy @dom) =
AbilityDetect Nothing Nothing failT mrAdvAbility
| otherwise = AnRestart (Just rudis) (Just rxConfRegs) failT linkT
where
s = anEnable failT rudi rudis rxConfRegs
(rudis, rxConfRegs, failT, linkT) = anUpdate self syncStatus rudi rxConfReg
autoNegT self@AbilityDetect{} (syncStatus, rudi, rxConfReg)
| isJust s = fromJust s
| abilityMatch rudis rxConfRegs && last rxConfRegs /= 0 =
AcknowledgeDetect Nothing Nothing failT txConfReg (last rxConfRegs)
| otherwise = AbilityDetect (Just rudis) (Just rxConfRegs) failT mrAdvAbility
where
s = anEnable failT rudi rudis rxConfRegs
(rudis, rxConfRegs, failT, _) = anUpdate self syncStatus rudi rxConfReg
txConfReg = replaceBit (14 :: Index 16) 0 mrAdvAbility
autoNegT self@AcknowledgeDetect{..} (syncStatus, rudi, rxConfReg)
| isJust s = fromJust s
| acknowledgeMatch rxConfRegs
&& not (consistencyMatch _rxConfReg rxConfRegs) =
AnEnable Nothing Nothing failT
| abilityMatch rudis rxConfRegs && last rxConfRegs == 0 =
AnEnable Nothing Nothing failT
| acknowledgeMatch rxConfRegs && consistencyMatch _rxConfReg rxConfRegs =
CompleteAcknowledge Nothing Nothing failT 0
| otherwise =
AcknowledgeDetect
(Just rudis)
(Just rxConfRegs)
failT
txConfReg
_rxConfReg
where
s = anEnable failT rudi rudis rxConfRegs
(rudis, rxConfRegs, failT, _) = anUpdate self syncStatus rudi rxConfReg
txConfReg = replaceBit (14 :: Index 16) 1 _txConfReg
autoNegT self@CompleteAcknowledge{} (syncStatus, rudi, rxConfReg)
| isJust s = fromJust s
| abilityMatch rudis rxConfRegs && last rxConfRegs == 0 =
AnEnable Nothing Nothing failT
| linkT >= timeout (Proxy @dom) && not (abilityMatch rudis rxConfRegs) =
IdleDetect Nothing Nothing failT 0
| linkT >= timeout (Proxy @dom) && last rxConfRegs /= 0 =
IdleDetect Nothing Nothing failT 0
| otherwise = CompleteAcknowledge (Just rudis) (Just rxConfRegs) failT linkT
where
s = anEnable failT rudi rudis rxConfRegs
(rudis, rxConfRegs, failT, linkT) = anUpdate self syncStatus rudi rxConfReg
autoNegT self@IdleDetect{} (syncStatus, rudi, rxConfReg)
| isJust s = fromJust s
| abilityMatch rudis rxConfRegs && last rxConfRegs == 0 =
AnEnable Nothing Nothing failT
| linkT >= timeout (Proxy @dom) && idleMatch rudis =
LinkOk Nothing Nothing failT
| otherwise = IdleDetect (Just rudis) (Just rxConfRegs) failT linkT
where
s = anEnable failT rudi rudis rxConfRegs
(rudis, rxConfRegs, failT, linkT) = anUpdate self syncStatus rudi rxConfReg
autoNegT self@LinkOk{} (syncStatus, rudi, rxConfReg)
| isJust s = fromJust s
| abilityMatch rudis rxConfRegs = AnEnable Nothing Nothing failT
| otherwise = LinkOk (Just rudis) (Just rxConfRegs) failT
autoNegT self (syncStatus, rudi)
| failT >= timeout (Proxy @dom) =
AnEnable (Just rudis) rxConfReg (timeout (Proxy @dom) - 1)
| rudi == Just Invalid = AnEnable (Just rudis) rxConfReg failT
| otherwise = case self of
AnEnable{}
| otherwise -> AnRestart Nothing rxConfReg failT 0
AnRestart{}
| linkT >= timeout (Proxy @dom) -> AbilityDetect Nothing rxConfReg failT
| otherwise -> AnRestart (Just rudis) rxConfReg failT linkT
AbilityDetect{}
| abilityMatch rudis && rxConfReg /= 0 ->
AckDetect Nothing rxConfReg failT rxConfReg
| otherwise -> AbilityDetect (Just rudis) rxConfReg failT
AckDetect{}
| ackMatch rudis && not (consistencyMatch self._rxConfReg rudis) ->
AnEnable Nothing rxConfReg failT
| abilityMatch rudis && rxConfReg == 0 ->
AnEnable Nothing rxConfReg failT
| ackMatch rudis && consistencyMatch self._rxConfReg rudis ->
CompleteAck Nothing rxConfReg failT 0
| otherwise -> AckDetect (Just rudis) rxConfReg failT self._hist
CompleteAck{}
| abilityMatch rudis && rxConfReg == 0 ->
AnEnable Nothing rxConfReg failT
| linkT >= timeout (Proxy @dom) && not (abilityMatch rudis) ->
IdleDetect Nothing rxConfReg failT 0
| linkT >= timeout (Proxy @dom) && rxConfReg /= 0 ->
IdleDetect Nothing rxConfReg failT 0
| otherwise -> CompleteAck (Just rudis) rxConfReg failT linkT
IdleDetect{}
| abilityMatch rudis && rxConfReg == 0 ->
AnEnable Nothing rxConfReg failT
| linkT >= timeout (Proxy @dom) && idleMatch rudis ->
LinkOk Nothing rxConfReg failT
| otherwise -> IdleDetect (Just rudis) rxConfReg failT linkT
LinkOk{}
| abilityMatch rudis -> AnEnable Nothing rxConfReg failT
| otherwise -> LinkOk (Just rudis) rxConfReg failT
where
s = anEnable failT rudi rudis rxConfRegs
(rudis, rxConfRegs, failT, _) = anUpdate self syncStatus rudi rxConfReg
rudis = maybe rudis' (rudis' <<+) rudi
where
rudis' = fromMaybe (repeat I) self._rudis
rxConfReg = fromMaybe self._rxConfReg (toConfReg =<< rudi)
failT = if syncStatus == Fail then self._failT + 1 else 0
linkT = self._linkT + 1

-- | Output function for 'autoNeg' as defined in IEEE 802.3 Clause 37. Returns
-- the new value for 'Xmit' and 'ConfReg' for 'Sgmii.pcsTransmit'.
Expand All @@ -277,17 +182,14 @@ autoNegO ::
AutoNegState dom ->
-- | New outputs
(AutoNegState dom, Maybe Xmit, Maybe ConfReg)
autoNegO self@AnEnable{} = (self, Just Conf, Just 0)
autoNegO self@AnRestart{} = (self, Nothing, Just 0)
autoNegO self@AbilityDetect{..} = (self, Nothing, Just txConfReg)
where
txConfReg = replaceBit (14 :: Index 16) 0 _txConfReg
autoNegO self@AcknowledgeDetect{..} = (self, Nothing, Just txConfReg)
where
txConfReg = replaceBit (14 :: Index 16) 1 _txConfReg
autoNegO self@CompleteAcknowledge{} = (self, Nothing, Nothing)
autoNegO self@IdleDetect{} = (self, Just Idle, Nothing)
autoNegO self@LinkOk{} = (self, Just Data, Nothing)
autoNegO self = case self of
AnEnable{} -> (self, Just Conf, Just 0)
AnRestart{} -> (self, Nothing, Just 0)
AbilityDetect{} -> (self, Nothing, Just (noAckBit confReg))
AckDetect{} -> (self, Nothing, Just confReg)
CompleteAck{} -> (self, Nothing, Nothing)
IdleDetect{} -> (self, Just Idle, Nothing)
LinkOk{} -> (self, Just Data, Nothing)

-- | Function that implements the auto-negotiation block as defined in IEEE
-- 802.3 Clause 37, but modified to comply to the SGMII standard. This
Expand All @@ -303,17 +205,15 @@ autoNeg ::
Signal dom SyncStatus ->
-- | A new value of 'Rudi' from 'Sgmii.pcsReceive'
Signal dom (Maybe Rudi) ->
-- | A new value of 'ConfReg' from 'Sgmii.pcsReceive'
Signal dom (Maybe ConfReg) ->
-- | Tuple containing the new value for 'Xmit' and a new 'ConfReg'
(Signal dom (Maybe Xmit), Signal dom (Maybe ConfReg))
autoNeg syncStatus rudi rxConfReg = (xmit, txConfReg)
autoNeg syncStatus rudi = (xmit, txConfReg)
where
(_, xmit, txConfReg) =
mooreB
(autoNegT @dom)
(autoNegO @dom)
(AnEnable Nothing Nothing 0)
(syncStatus, rudi, rxConfReg)
(AnEnable Nothing 0 0)
(syncStatus, rudi)

{-# CLASH_OPAQUE autoNeg #-}
Loading

0 comments on commit 73f1eaa

Please sign in to comment.