diff --git a/bittide/src/Bittide/Ethernet/Mac.hs b/bittide/src/Bittide/Ethernet/Mac.hs index b5b504816..2305259ee 100644 --- a/bittide/src/Bittide/Ethernet/Mac.hs +++ b/bittide/src/Bittide/Ethernet/Mac.hs @@ -46,7 +46,6 @@ macStatusInterfaceWb :: ( CP.HiddenClockResetEnable dom , KnownNat nBytes , KnownNat aw - , 2 <= aw , 1 <= nBytes , counterWidth <= nBytes * 8 ) => diff --git a/bittide/src/Bittide/Node.hs b/bittide/src/Bittide/Node.hs index c4b50aec8..57c05fb89 100644 --- a/bittide/src/Bittide/Node.hs +++ b/bittide/src/Bittide/Node.hs @@ -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 @@ -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. @@ -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) @@ -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. @@ -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 +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) diff --git a/bittide/src/Bittide/ScatterGather.hs b/bittide/src/Bittide/ScatterGather.hs index 9b785221d..d1f3834d6 100644 --- a/bittide/src/Bittide/ScatterGather.hs +++ b/bittide/src/Bittide/ScatterGather.hs @@ -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. @@ -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' @@ -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' diff --git a/bittide/src/Bittide/Switch.hs b/bittide/src/Bittide/Switch.hs index e6dda2dea..5dbc3cc57 100644 --- a/bittide/src/Bittide/Switch.hs +++ b/bittide/src/Bittide/Switch.hs @@ -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