Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SGMII support to clash-cores #2727

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e76b5bb
Add common types and functions
jvnknvlgl Jul 17, 2024
1ee7773
Add word alignment block
jvnknvlgl Jul 17, 2024
7f45f1a
Add synchronization block
jvnknvlgl Jul 17, 2024
f5dbb5b
Add PCS receive block
jvnknvlgl Jul 17, 2024
5183c60
Add auto-negotiation block
jvnknvlgl Jul 17, 2024
8051e30
Add PCS transmit block
jvnknvlgl Jul 17, 2024
3c19861
Add rate adaptation block
jvnknvlgl Jul 17, 2024
ee8f959
Add top-level SGMII block
jvnknvlgl Jul 17, 2024
622d999
Include modules in project
jvnknvlgl Jul 17, 2024
647320c
Ignore .tix files from HPC
jvnknvlgl Jul 17, 2024
803be75
Reorganize function definitions
jvnknvlgl Jul 23, 2024
35914b6
Improve auto-negotiation block
jvnknvlgl Jul 23, 2024
8663b08
Improve PCS receive block
jvnknvlgl Jul 25, 2024
b7ef75a
Improve synchronization block
jvnknvlgl Jul 25, 2024
bb67331
Explicitly export functions
jvnknvlgl Jul 24, 2024
fc8a770
Remove OverloadedRecordDot
jvnknvlgl Jul 29, 2024
93a8e9f
CI fixes for 8.10 and 9.8
jvnknvlgl Jul 30, 2024
933411b
Change layout of status
jvnknvlgl Aug 1, 2024
0448ca2
Rename self to s for brevity
jvnknvlgl Aug 1, 2024
7af0888
Refactor rate adaptation tests
jvnknvlgl Aug 1, 2024
e071b53
Expand Cg to CodeGroup
jvnknvlgl Aug 14, 2024
c3322d3
Prefix C, I and Invalid with Rudi
jvnknvlgl Aug 14, 2024
70cdaf8
Haddock changes and fixes
jvnknvlgl Aug 16, 2024
8c424fa
Multi-line module haddock
jvnknvlgl Aug 19, 2024
b03b99e
Handle Invalid in abilityMatch
jvnknvlgl Aug 19, 2024
75895bd
Remove fromJust pattern
jvnknvlgl Aug 19, 2024
1346c87
More descriptive names in BitSlipState
jvnknvlgl Aug 26, 2024
228b7a6
Only reset count when Just is received
jvnknvlgl Aug 26, 2024
107535e
Remove reverseBV from BitSlip
jvnknvlgl Aug 26, 2024
b93942c
Remove fromJust from BitSlip
jvnknvlgl Aug 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ cabal.config
*.bin
*.log
*.tar.gz
*.tix

*~
*.DS_Store
Expand Down
15 changes: 15 additions & 0 deletions clash-cores/clash-cores.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ library
Clash.Cores.LineCoding8b10b
Clash.Cores.LineCoding8b10b.Decoder
Clash.Cores.LineCoding8b10b.Encoder
Clash.Cores.Sgmii
Clash.Cores.Sgmii.AutoNeg
Clash.Cores.Sgmii.BitSlip
Clash.Cores.Sgmii.Common
Clash.Cores.Sgmii.PcsReceive
Clash.Cores.Sgmii.PcsTransmit
Clash.Cores.Sgmii.PcsTransmit.CodeGroup
Clash.Cores.Sgmii.PcsTransmit.OrderedSet
Clash.Cores.Sgmii.RateAdapt
Clash.Cores.Sgmii.Sync
Clash.Cores.SPI
Clash.Cores.UART
Clash.Cores.Xilinx.BlockRam
Expand Down Expand Up @@ -202,6 +212,11 @@ test-suite unittests
Test.Cores.Internal.SampleSPI
Test.Cores.LineCoding8b10b
Test.Cores.Internal.Signals
Test.Cores.Sgmii.AutoNeg
Test.Cores.Sgmii.BitSlip
Test.Cores.Sgmii.RateAdapt
Test.Cores.Sgmii.Sgmii
Test.Cores.Sgmii.Sync
Test.Cores.SPI
Test.Cores.SPI.MultiSlave
Test.Cores.UART
Expand Down
325 changes: 325 additions & 0 deletions clash-cores/src/Clash/Cores/Sgmii.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
{-# LANGUAGE CPP #-}

{- |
Copyright : (C) 2024, QBayLogic B.V.
License : BSD2 (see the file LICENSE)
Maintainer : QBayLogic B.V. <devops@qbaylogic.com>

Top-level SGMII module that combines all the blocks that are defined in the
sub-modules to one function that can be used in different projects.

Example usage:

@
topEntity ::
Clock Dom0 ->
Clock Dom1 ->
Reset Dom0 ->
Reset Dom1 ->
Signal Dom1 Bool ->
Signal Dom1 Bool ->
Signal Dom1 (BitVector 8) ->
Signal Dom0 (BitVector 10) ->
( Signal rxDom SgmiiStatus
, Signal rxDom Bool
, Signal rxDom Bool
, Signal rxDom (BitVector 8)
, Signal txDom (BitVector 10)
)
topEntity = sgmii rxTxCdc
@
Here, the type of @rxTxCdc@, which is the function that handles the
clock domain crossing between the transmit and receive domain between the
auto-negotiation block and transmission block, needs to be the following:

@
rxTxCdc ::
forall dom0 dom1.
(KnownDomain dom0, KnownDomain dom1) =>
Clock rxDom ->
Clock txDom ->
Signal rxDom (Maybe Xmit) ->
Signal rxDom (Maybe ConfReg) ->
Signal rxDom (Maybe ConfReg) ->
( Signal txDom (Maybe Xmit)
, Signal txDom (Maybe ConfReg)
, Signal txDom (Maybe ConfReg)
)
@

For Xilinx boards, this could be implemented by using, for example, the
function 'Clash.Cores.Xilinx.Xpm.Cdc.Handshake.xpmCdcHandshake', but
vendor-neutral implementations could make use of other word-synchronizers.

As the decoding of incoming 10-bit code groups is done on a best-effort
basis and they are always transmitted to @TXD@, this port should only be
read when @RX_DV@ is asserted as invalid data might be provided when it is
not.
-}
module Clash.Cores.Sgmii
( sgmii
, sgmiiRA
, sgmiiRx
, sgmiiTx
)
where

import Clash.Cores.LineCoding8b10b
import Clash.Cores.Sgmii.AutoNeg
import Clash.Cores.Sgmii.BitSlip
import Clash.Cores.Sgmii.Common
import Clash.Cores.Sgmii.PcsReceive
import Clash.Cores.Sgmii.PcsTransmit
import Clash.Cores.Sgmii.RateAdapt
import Clash.Cores.Sgmii.Sync
import Clash.Prelude
import Data.Maybe (fromMaybe, isJust)

-- | Receive side of the SGMII block, that combines all the functions that are
-- in the receive domain
sgmiiRx ::
(HiddenClockResetEnable dom) =>
-- | Input code group
Signal dom CodeGroup ->
-- | Output tuple
( Signal dom SgmiiStatus
, Signal dom Bool
, Signal dom Bool
, Signal dom (BitVector 8)
, Signal dom (Maybe Xmit)
, Signal dom (Maybe ConfReg)
, Signal dom (Maybe ConfReg)
, Signal dom CodeGroup
)
sgmiiRx rxCg =
( rxStatus
, regMaybe False rxDv
, regMaybe False rxEr
, regMaybe 0 ((fmap . fmap) fromSymbol rxDw)
, xmit
, txConfReg
, rxConfReg
, bsCg
)
where
rxStatus =
SgmiiStatus
<$> bsStatus
<*> syncStatus
<*> (toLinkSpeed <$> regMaybe 0 rxConfReg)
<*> regMaybe Conf xmit
<*> regMaybe RudiInvalid rudi

rxConfReg = toConfReg <$> regMaybe (RudiC 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, bsStatus) = bitSlip rxCg syncStatus

-- | Transmit side of the SGMII block, that combines all the functions that are
-- in the transmit domain
sgmiiTx ::
(HiddenClockResetEnable dom) =>
-- | @TX_EN@ signal
Signal dom Bool ->
-- | @TX_ER@ signal
Signal dom Bool ->
-- | Input data word
Signal dom (BitVector 8) ->
-- | 'Xmit' signal
Signal dom (Maybe Xmit) ->
-- | Configuration register from MAC
Signal dom (Maybe ConfReg) ->
-- | Configuration register from PHY
Signal dom (Maybe ConfReg) ->
-- | Output code group
Signal dom CodeGroup
sgmiiTx txEn txEr txDw xmit txConfReg _ =
pcsTransmit txEn txEr txDw xmit txConfReg

-- | Top-level SGMII function that takes as its second argument a function that
-- implements a clock domain crossing between the auto-negotiation and
-- transmission blocks. This block does not implement the serialization and
-- deserialization of the 10-bit code groups, but leaves this to be
-- implemented externally. These 10-bit code groups do not have to be word
-- aligned as this is implemented internally in the 'bitSlip' block.
--
-- This function implements SGMII as described
-- [here](https://archive.org/download/sgmii/SGMII.pdf), without the optional
-- EEE (Energy-Efficient Ethernet) capability.
--
-- This function reports its internal status by using 'SgmiiStatus', this
-- reports the synchronization status of the line in the first bit, the
-- configuration register in the following 16 bits, and the values of 'Rudi'
-- and 'Xmit' in the following 2-bit groups.
sgmii ::
forall rxDom txDom.
(KnownDomain rxDom, KnownDomain txDom) =>
-- | Function used for the clock domain crossing between 'autoNeg' and
-- 'pcsTransmit', for the values of 'Xmit' and 'ConfReg'
( Clock rxDom ->
Clock txDom ->
Signal rxDom (Maybe Xmit) ->
Signal rxDom (Maybe ConfReg) ->
Signal rxDom (Maybe ConfReg) ->
( Signal txDom (Maybe Xmit)
, Signal txDom (Maybe ConfReg)
, Signal txDom (Maybe ConfReg)
)
) ->
-- | Clock of the receive domain, which is a 125 MHz clock that is derived
-- from the 625 MHz clock that is received from the PHY
Clock rxDom ->
-- | Clock of the transmit domain, which can be an internal clock of the FPGA
Clock txDom ->
-- | Reset of the receive domain
Reset rxDom ->
-- | Reset of the transmit domain
Reset txDom ->
-- | Input signal @TX_EN@, which enables data transmission when 'Xmit' from
-- 'autoNeg' is set to 'Data'
Signal txDom Bool ->
-- | Input signal @TX_ER@, which is used to propagate error values to the PHY
Signal txDom Bool ->
-- | Data octet @TXD@ to be transmitted to the PHY
Signal txDom (BitVector 8) ->
-- | Input code group from the PHY
Signal rxDom CodeGroup ->
-- | Tuple that contains the output signals from the SGMII block which are:
--
-- - The current status of the receive block,
-- - The @RX_DV@ signal that indicates an incoming data packet,
-- - The @RX_ER@ signal that indicates a receive error,
-- - The @RXD@ signal which is the incoming data octet from the PHY,
-- - The word-aligned version of the received code group from the PHY,
-- - A 10-bit code group that can be serialized and transmitted to the PHY.
( Signal rxDom SgmiiStatus
, Signal rxDom Bool
, Signal rxDom Bool
, Signal rxDom (BitVector 8)
, Signal rxDom CodeGroup
, Signal txDom CodeGroup
)
sgmii rxTxCdc rxClk txClk rxRst txRst txEn txEr txDw rxCg =
(rxStatus, rxDv, rxEr, rxDw, bsCg, txCg)
where
txCg = sgmiiTx' txEn txEr txDw xmit2 txConfReg2 rxConfReg2
where
sgmiiTx' = exposeClockResetEnable sgmiiTx txClk txRst enableGen

(xmit2, txConfReg2, rxConfReg2) =
rxTxCdc rxClk txClk xmit1 txConfReg1 rxConfReg1

(rxStatus, rxDv, rxEr, rxDw, xmit1, txConfReg1, rxConfReg1, bsCg) =
sgmiiRx' rxCg
where
sgmiiRx' = exposeClockResetEnable sgmiiRx rxClk rxRst enableGen

{-# CLASH_OPAQUE sgmii #-}

-- | Receive side of the SGMII block, that combines all the functions that are
-- in the receive domain, rate-adapted
sgmiiRxRA ::
(HiddenClockResetEnable dom) =>
-- | Input code group
Signal dom CodeGroup ->
-- | Output tuple
( Signal dom SgmiiStatus
, Signal dom Bool
, Signal dom (Maybe (BitVector 8))
, Signal dom (Maybe Xmit)
, Signal dom (Maybe ConfReg)
, Signal dom (Maybe ConfReg)
, Signal dom CodeGroup
)
sgmiiRxRA rxCg = (rxStatus, rxEr, out, xmit, txConfReg, rxConfReg, bsCg)
where
out = rateAdaptRx linkSpeed $ orNothing <$> rxDv <*> rxDw
linkSpeed = toLinkSpeed <$> regMaybe 0 rxConfReg
(rxStatus, rxDv, rxEr, rxDw, xmit, txConfReg, rxConfReg, bsCg) = sgmiiRx rxCg

-- | Transmit side of the SGMII block, that combines all the functions that are
-- in the transmit domain, rate-adapted
sgmiiTxRA ::
(HiddenClockResetEnable dom) =>
-- | @TX_ER@ signal
Signal dom Bool ->
-- | Input data word
Signal dom (Maybe (BitVector 8)) ->
-- | 'Xmit' signal
Signal dom (Maybe Xmit) ->
-- | Configuration register from MAC
Signal dom (Maybe ConfReg) ->
-- | Configuration register from PHY
Signal dom (Maybe ConfReg) ->
-- | Ready signal and output code group
(Signal dom Bool, Signal dom CodeGroup)
sgmiiTxRA txEr txDw xmit txConfReg rxConfReg = (txReady, txCg)
where
linkSpeed = toLinkSpeed <$> regMaybe 0 rxConfReg
txCg =
sgmiiTx (isJust <$> out) txEr (fromMaybe 0 <$> out) xmit txConfReg rxConfReg
(txReady, out) = rateAdaptTx linkSpeed txDw

-- | Rate-adapted version of 'sgmii'
sgmiiRA ::
forall rxDom txDom.
(KnownDomain rxDom, KnownDomain txDom) =>
-- | Function used for the clock domain crossing between 'autoNeg' and
-- 'pcsTransmit', for the values of 'Xmit' and 'ConfReg'
( Clock rxDom ->
Clock txDom ->
Signal rxDom (Maybe Xmit) ->
Signal rxDom (Maybe ConfReg) ->
Signal rxDom (Maybe ConfReg) ->
( Signal txDom (Maybe Xmit)
, Signal txDom (Maybe ConfReg)
, Signal txDom (Maybe ConfReg)
)
) ->
-- | Clock of the receive domain, which is a 125 MHz clock that is derived
-- from the 625 MHz clock that is received from the PHY
Clock rxDom ->
-- | Clock of the transmit domain, which can be an internal clock of the FPGA
Clock txDom ->
-- | Reset of the receive domain
Reset rxDom ->
-- | Reset of the transmit domain
Reset txDom ->
-- | @TX_ER@ signal
Signal txDom Bool ->
-- | Data octet @TXD@ to be transmitted to the PHY
Signal txDom (Maybe (BitVector 8)) ->
-- | Input code group from the PHY
Signal rxDom CodeGroup ->
-- | Tuple that contains the output signals from the SGMII block which are:
--
-- - The current status of the receive block,
-- - The @RX_ER@ signal that indicates a receive error,
-- - The incoming data octet from the PHY or 'Nothing' when no data word is
-- received,
-- - The word-aligned version of the received code group from the PHY,
-- - A 10-bit code group that can be serialized and transmitted to the PHY,
-- - A boolean that indicates if a new data word can be provided.
( Signal rxDom SgmiiStatus
, Signal rxDom Bool
, Signal rxDom (Maybe (BitVector 8))
, Signal rxDom CodeGroup
, Signal txDom CodeGroup
, Signal txDom Bool
)
sgmiiRA rxTxCdc rxClk txClk rxRst txRst txEr txDw rxCg =
(rxStatus, rxEr, rxDw, bsCg, txCg, txReady)
where
(txReady, txCg) = sgmiiTx' txEr txDw xmit2 txConfReg2 rxConfReg2
where
sgmiiTx' = exposeClockResetEnable sgmiiTxRA txClk txRst enableGen

(xmit2, txConfReg2, rxConfReg2) =
rxTxCdc rxClk txClk xmit1 txConfReg1 rxConfReg1

(rxStatus, rxEr, rxDw, xmit1, txConfReg1, rxConfReg1, bsCg) = sgmiiRx' rxCg
where
sgmiiRx' = exposeClockResetEnable sgmiiRxRA rxClk rxRst enableGen

{-# CLASH_OPAQUE sgmiiRA #-}
Loading