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

Use Circuit for Bittide Nodes #627

Merged
merged 2 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 0 additions & 1 deletion bittide/src/Bittide/Ethernet/Mac.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ macStatusInterfaceWb ::
( CP.HiddenClockResetEnable dom
, KnownNat nBytes
, KnownNat aw
, 2 <= aw
, 1 <= nBytes
, counterWidth <= nBytes * 8
) =>
Expand Down
162 changes: 145 additions & 17 deletions bittide/src/Bittide/Node.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
{-# LANGUAGE GADTs #-}
{-# OPTIONS_GHC -fconstraint-solver-iterations=6 #-}

{-# OPTIONS -fplugin=Protocols.Plugin #-}

module Bittide.Node where

import Clash.Prelude
import Clash.Sized.Vector.ToTuple (vecToTuple)

import Protocols
import Protocols.Idle
import Protocols.Internal (vecCircuits)
import Protocols.Wishbone

import VexRiscv

import Bittide.Calendar
Expand All @@ -21,8 +24,6 @@ import Bittide.ScatterGather
import Bittide.SharedTypes
import Bittide.Switch

import Control.Arrow ((&&&))

{- | A simple node consisting of one external bidirectional link and two 'gppe's.
This node's 'switch' has a 'CalendarConfig' of for a 'calendar' with up to @1024@ entries,
however, the 'calendar' is initialized with a single entry of repeated zeroes.
Expand Down Expand Up @@ -74,20 +75,19 @@ node ::
forall dom extLinks gppes.
(HiddenClockResetEnable dom, KnownNat extLinks, KnownNat gppes) =>
NodeConfig extLinks gppes ->
Vec extLinks (Signal dom (DataLink 64)) ->
Vec extLinks (Signal dom (DataLink 64))
node (NodeConfig nmuConfig switchConfig gppeConfigs) linksIn = linksOut
where
(switchOut, swS2M) = switch switchConfig swM2S switchIn
switchIn = nmuToSwitch :> pesToSwitch ++ linksIn
(splitAtI -> ((head &&& tail) -> (switchToNmu, switchToPes), linksOut)) = switchOut
(nmuToSwitch, nmuM2Ss) = managementUnit nmuConfig switchToNmu nmuS2Ms
(swM2S, peM2Ss) = (head &&& tail) nmuM2Ss

nmuS2Ms = swS2M :> peS2Ms
Circuit
(Vec extLinks (CSignal dom (DataLink 64)))
(Vec extLinks (CSignal dom (DataLink 64)))
node (NodeConfig nmuConfig switchConfig gppeConfigs) = circuit $ \linksIn -> do
switchOut <- (switchC @_ @_ @_ @_ @64 switchConfig) -< (switchIn, swWb)
switchIn <- appendC3 -< ([nmuLinkOut], pesToSwitch, linksIn)
([nmuLinkIn], switchToPes, linksOut) <- splitC3 -< switchOut
(nmuLinkOut, nmuWbs0) <- managementUnitC nmuConfig -< nmuLinkIn
([swWb], nmuWbs1) <- splitAtC d1 -< nmuWbs0
peWbs <- unconcatC d2 -< nmuWbs1

(pesToSwitch, concat -> peS2Ms) =
unzip $ gppe <$> zip3 gppeConfigs switchToPes (unconcatI peM2Ss)
pesToSwitch <- vecCircuits (map gppeC gppeConfigs) <| zipC -< (switchToPes, peWbs)
idC -< linksOut

type NmuInternalBusses = 6
type NmuRemBusWidth nodeBusses = 30 - CLog 2 (nodeBusses + NmuInternalBusses)
Expand Down Expand Up @@ -158,11 +158,30 @@ gppe (GppeConfig scatterConfig gatherConfig peConfig, linkIn, vecToTuple -> (nmu

{-# NOINLINE managementUnit #-}

gppeC ::
(KnownNat nmuRemBusWidth, HiddenClockResetEnable dom) =>
-- | Configures all local parameters
GppeConfig nmuRemBusWidth ->
-- |
-- ( Incoming 'Bittide.Link'
-- , Incoming @Vector@ of master busses
-- )
Circuit
(CSignal dom (DataLink 64), Vec 2 (Wishbone dom 'Standard nmuRemBusWidth (Bytes 4)))
(CSignal dom (DataLink 64))
gppeC (GppeConfig scatterConfig gatherConfig peConfig) = circuit $ \(linkIn, nmuWbs) -> do
[wbScatCal, wbGathCal] <- idC -< nmuWbs
jtag <- idleSource -< ()
[wbScat, wbGu] <- processingElement peConfig -< jtag
linkOut <- gatherUnitWbC gatherConfig -< (wbGu, wbGathCal)
scatterUnitWbC scatterConfig -< (linkIn, wbScat, wbScatCal)
idC -< linkOut

{- | A special purpose 'processingElement' that manages a Bittide Node. It contains
a 'processingElement', 'linkToPe' and 'peToLink' which create the interface for the
Bittide Link. It takes a 'ManagementConfig', incoming link and a vector of incoming
'WishboneS2M' signals and produces the outgoing link alongside a vector of
'WishhboneM2S' signals.
'WishboneM2S' signals.
-}
managementUnit ::
forall dom nodeBusses.
Expand Down Expand Up @@ -191,3 +210,112 @@ managementUnit (ManagementConfig scatterConfig gatherConfig peConfig) linkIn nod
(vecToTuple -> (nmuM2S0, nmuM2S1), nodeM2Ss) = splitAtI rest
(_, nmuM2Ss) = toSignals (processingElement peConfig) (pure $ JtagIn low low low, nmuS2Ms)
nmuS2Ms = suS2M :> guS2M :> nmuS2M0 :> nmuS2M1 :> nodeS2Ms

managementUnitC ::
forall dom nodeBusses.
( HiddenClockResetEnable dom
, CLog 2 (nodeBusses + NmuInternalBusses) <= 30
) =>
-- |
-- ( Configures all local parameters
-- , Incoming 'Bittide.Link'
-- , Incoming @Vector@ of master busses
-- )
ManagementConfig nodeBusses ->
Circuit
(CSignal dom (DataLink 64))
( CSignal dom (DataLink 64)
, Vec nodeBusses (Wishbone dom 'Standard (NmuRemBusWidth nodeBusses) (Bytes 4))
)
managementUnitC (ManagementConfig scatterConfig gatherConfig peConfig) = circuit $ \linkIn -> do
jtag <- idleSource -< ()
peWbs <- processingElement peConfig -< jtag
([wbScatCal, wbScat, wbGathCal, wbGu], nmuWbs) <- splitAtC d4 -< peWbs
linkOut <- gatherUnitWbC gatherConfig -< (wbGu, wbGathCal)
scatterUnitWbC scatterConfig -< (linkIn, wbScat, wbScatCal)
idC -< (linkOut, nmuWbs)

-- These functions should be added to `clash-protocols`, there is a PR for this:
-- https://github.com/clash-lang/clash-protocols/pull/116
-- And a bittide-hardware issue:
-- https://github.com/bittide/bittide-hardware/issues/645
-- Append two separate vectors of the same circuits into one vector of circuits
lmbollen marked this conversation as resolved.
Show resolved Hide resolved
appendC ::
(KnownNat n0) =>
Circuit (Vec n0 circuit, Vec n1 circuit) (Vec (n0 + n1) circuit)
appendC = Circuit go
where
go ((fwd0, fwd1), splitAtI -> (bwd0, bwd1)) = ((bwd0, bwd1), (fwd0 ++ fwd1))

-- Append three separate vectors of the same circuits into one vector of circuits
appendC3 ::
(KnownNat n0, KnownNat n1) =>
Circuit (Vec n0 circuit, Vec n1 circuit, Vec n2 circuit) (Vec (n0 + n1 + n2) circuit)
appendC3 = Circuit go
where
go ((fwd0, fwd1, fwd2), splitAtI -> (bwd0, splitAtI -> (bwd1, bwd2))) = ((bwd0, bwd1, bwd2), (fwd0 ++ fwd1 ++ fwd2))

-- Transforms two vectors of circuits into a vector of tuples of circuits.
-- Only works if the two vectors have the same length.
zipC ::
(KnownNat n) =>
Circuit (Vec n a, Vec n b) (Vec n (a, b))
zipC = Circuit go
where
go ((fwd0, fwd1), bwd) = (unzip bwd, zip fwd0 fwd1)

-- Transforms three vectors of circuits into a vector of tuples of circuits.
-- Only works if the three vectors have the same length.
zipC3 ::
(KnownNat n) =>
Circuit (Vec n a, Vec n b, Vec n c) (Vec n (a, b, c))
zipC3 = Circuit go
where
go ((fwd0, fwd1, fwd2), bwd) = (unzip3 bwd, zip3 fwd0 fwd1 fwd2)

-- Split a vector of circuits into two vectors of circuits.
splitC ::
(KnownNat n0) =>
Circuit (Vec (n0 + n1) circuit) (Vec n0 circuit, Vec n1 circuit)
splitC = Circuit go
where
go (splitAtI -> (fwd0, fwd1), (bwd0, bwd1)) = (bwd0 ++ bwd1, (fwd0, fwd1))

-- Split a vector of circuits into three vectors of circuits.
splitC3 ::
(KnownNat n0, KnownNat n1) =>
Circuit (Vec (n0 + n1 + n2) circuit) (Vec n0 circuit, Vec n1 circuit, Vec n2 circuit)
splitC3 = Circuit go
where
go (splitAtI -> (fwd0, splitAtI -> (fwd1, fwd2)), (bwd0, bwd1, bwd2)) = (bwd0 ++ bwd1 ++ bwd2, (fwd0, fwd1, fwd2))

-- Unzip a vector of tuples of circuits into a tuple of vectors of circuits.
unzipC ::
(KnownNat n) =>
Circuit (Vec n (a, b)) (Vec n a, Vec n b)
unzipC = Circuit go
where
go (fwd, (bwd0, bwd1)) = (zip bwd0 bwd1, unzip fwd)

-- Unzip a vector of 3-tuples of circuits into a 3-tuple of vectors of circuits.
unzipC3 ::
(KnownNat n) =>
Circuit (Vec n (a, b, c)) (Vec n a, Vec n b, Vec n c)
unzipC3 = Circuit go
where
go (fwd, (bwd0, bwd1, bwd2)) = (zip3 bwd0 bwd1 bwd2, unzip3 fwd)

concatC ::
(KnownNat n0, KnownNat n1) =>
Circuit (Vec n0 (Vec n1 circuit)) (Vec (n0 * n1) circuit)
concatC = Circuit go
where
go (fwd, bwd) = (unconcat SNat bwd, concat fwd)

unconcatC ::
(KnownNat n, KnownNat m) =>
SNat m ->
Circuit (Vec (n * m) circuit) (Vec n (Vec m circuit))
unconcatC SNat = Circuit go
where
go (fwd, bwd) = (concat bwd, unconcat SNat fwd)
78 changes: 64 additions & 14 deletions bittide/src/Bittide/ScatterGather.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,25 @@

module Bittide.ScatterGather (
scatterUnitWb,
scatterUnitWbC,
ScatterConfig (..),
gatherUnitWb,
gatherUnitWbC,
GatherConfig (..),
) where

import Clash.Prelude

import Protocols.Wishbone

import Bittide.Calendar
import Bittide.DoubleBufferedRam
import Bittide.Extra.Maybe
import Bittide.SharedTypes

import Protocols
import Protocols.Wishbone

import Data.Constraint.Nat.Extra

{- | Existential type to explicitly differentiate between a configuration for
the 'scatterUnitWb' and 'gatherUnitWb' at type level and hide the memory depth from
higher level APIs.
Expand Down Expand Up @@ -185,26 +190,49 @@ addStalling endOfMetacycle (incomingBus@WishboneS2M{..}, wbAddr, writeOp0) =

{-# NOINLINE scatterUnitWb #-}

scatterUnitWbC ::
forall dom awSu nBytesCal awCal.
( HiddenClockResetEnable dom
, KnownNat awSu
, KnownNat nBytesCal
, 1 <= nBytesCal
, KnownNat awCal
) =>
-- | Configuration for the 'calendar'.
ScatterConfig nBytesCal awCal ->
Circuit
( CSignal dom (DataLink 64)
, Wishbone dom 'Standard awSu (Bytes 4)
, Wishbone dom 'Standard awCal (Bytes nBytesCal)
)
()
scatterUnitWbC conf = case cancelMulDiv @nBytesCal @8 of
Dict -> Circuit go
where
go ((linkIn, wbM2SSu, wbM2SCal), _) = ((pure (), wbS2MSu, wbS2MCal), ())
where
(wbS2MSu, wbS2MCal) = scatterUnitWb conf wbM2SCal linkIn wbM2SSu

{- | Wishbone addressable 'scatterUnit', the wishbone port can read the data from this
memory element as if it has a 32 bit port by selecting the upper 32 or lower 32 bits
of the read data.
-}
scatterUnitWb ::
forall dom addrWidthSu nBytesCal addrWidthCal.
forall dom awSu nBytesCal awCal.
( HiddenClockResetEnable dom
, KnownNat addrWidthSu
, KnownNat awSu
, KnownNat nBytesCal
, 1 <= nBytesCal
, KnownNat addrWidthCal
, KnownNat awCal
) =>
-- | Configuration for the 'calendar'.
ScatterConfig nBytesCal addrWidthCal ->
ScatterConfig nBytesCal awCal ->
-- | Wishbone (master -> slave) port 'calendar'.
Signal dom (WishboneM2S addrWidthCal nBytesCal (Bytes nBytesCal)) ->
Signal dom (WishboneM2S awCal nBytesCal (Bytes nBytesCal)) ->
-- | Incoming frame from Bittide link.
Signal dom (DataLink 64) ->
-- | Wishbone (master -> slave) port scatter memory.
Signal dom (WishboneM2S addrWidthSu 4 (Bytes 4)) ->
Signal dom (WishboneM2S awSu 4 (Bytes 4)) ->
-- |
-- 1. Wishbone (slave -> master) port scatter memory
-- 2. Wishbone (slave -> master) port 'calendar'
Expand All @@ -226,24 +254,46 @@ scatterUnitWb (ScatterConfig calConfig) wbInCal linkIn wbInSu =

{-# NOINLINE gatherUnitWb #-}

gatherUnitWbC ::
forall dom awGu nBytesCal awCal.
( HiddenClockResetEnable dom
, KnownNat awGu
, KnownNat nBytesCal
, 1 <= nBytesCal
, KnownNat awCal
) =>
-- | Configuration for the 'calendar'.
GatherConfig nBytesCal awCal ->
Circuit
( Wishbone dom 'Standard awGu (Bytes 4)
, Wishbone dom 'Standard awCal (Bytes nBytesCal)
)
(CSignal dom (DataLink 64))
gatherUnitWbC conf = case (cancelMulDiv @nBytesCal @8) of
Dict -> Circuit go
where
go ((wbInGu, wbInCal), _) = ((wbOutGu, wbOutCal), linkOut)
where
(linkOut, wbOutGu, wbOutCal) = gatherUnitWb conf wbInCal wbInGu

{- | Wishbone addressable 'gatherUnit', the wishbone port can write data to this
memory element as if it has a 32 bit port by controlling the byte enables of the
'gatherUnit' based on the third bit.
-}
gatherUnitWb ::
forall dom addrWidthGu nBytesCal addrWidthCal.
forall dom awGu nBytesCal awCal.
( HiddenClockResetEnable dom
, KnownNat addrWidthGu
, KnownNat awGu
, KnownNat nBytesCal
, 1 <= nBytesCal
, KnownNat addrWidthCal
, KnownNat awCal
) =>
-- | Configuration for the 'calendar'.
GatherConfig nBytesCal addrWidthCal ->
GatherConfig nBytesCal awCal ->
-- | Wishbone (master -> slave) data 'calendar'.
Signal dom (WishboneM2S addrWidthCal nBytesCal (Bytes nBytesCal)) ->
Signal dom (WishboneM2S awCal nBytesCal (Bytes nBytesCal)) ->
-- | Wishbone (master -> slave) port gather memory.
Signal dom (WishboneM2S addrWidthGu 4 (Bytes 4)) ->
Signal dom (WishboneM2S awGu 4 (Bytes 4)) ->
-- |
-- 1. Wishbone (slave -> master) port gather memory
-- 2. Wishbone (slave -> master) port 'calendar'
Expand Down
8 changes: 4 additions & 4 deletions bittide/src/Bittide/Switch.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ switchC ::
) =>
CalendarConfig nBytes addrW (CalendarEntry links) ->
Circuit
( CSignal dom (Vec links (DataLink frameWidth))
, Wishbone dom 'Standard addrW (Bytes nBytes)
( Vec links (CSignal dom (DataLink frameWidth))
, Wishbone dom 'Standard addrW (Bytes nBytes) -- calendar interface
)
(CSignal dom (Vec links (DataLink frameWidth)))
(Vec links (CSignal dom (DataLink frameWidth)))
switchC conf = case (cancelMulDiv @nBytes @8) of
Dict -> Circuit go
where
go ((unbundle -> streamsIn, calM2S), _) = ((pure (), calS2M), bundle streamsOut)
go ((streamsIn, calM2S), _) = ((repeat $ pure (), calS2M), streamsOut)
where
(streamsOut, calS2M) = switch conf calM2S streamsIn

Expand Down
Loading