{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_HADDOCK hide #-}
module Protocols.PacketStream.PacketFifo (
packetFifoC,
FullMode (..),
) where
import Clash.Prelude
import Data.Maybe
import Data.Maybe.Extra (toMaybe)
import Protocols
import Protocols.PacketStream.Base
type PacketStreamContent (dataWidth :: Nat) (meta :: Type) =
(Vec dataWidth (BitVector 8), Maybe (Index (dataWidth + 1)))
data FullMode
=
Backpressure
|
Drop
toPacketStreamContent ::
PacketStreamM2S dataWidth meta -> PacketStreamContent dataWidth meta
toPacketStreamContent PacketStreamM2S{..} = (_data, _last)
toPacketStreamM2S ::
PacketStreamContent dataWidth meta -> meta -> PacketStreamM2S dataWidth meta
toPacketStreamM2S (d, l) m = PacketStreamM2S d l m False
data PacketFifoState contentDepth metaDepth = PacketFifoState
{ _canRead :: Bool
, _dropping :: Bool
, _basePtr :: Unsigned contentDepth
, _cReadPtr :: Unsigned contentDepth
, _cWritePtr :: Unsigned contentDepth
, _mReadPtr :: Unsigned metaDepth
, _mWritePtr :: Unsigned metaDepth
}
deriving (Generic, NFDataX, Show, ShowX)
packetFifoT ::
forall
(dataWidth :: Nat)
(meta :: Type)
(contentDepth :: Nat)
(metaDepth :: Nat).
(KnownNat dataWidth) =>
(KnownNat contentDepth) =>
(KnownNat metaDepth) =>
(1 <= contentDepth) =>
(1 <= metaDepth) =>
(NFDataX meta) =>
PacketFifoState contentDepth metaDepth ->
( Maybe (PacketStreamM2S dataWidth meta)
, PacketStreamS2M
, PacketStreamContent dataWidth meta
, meta
) ->
( PacketFifoState contentDepth metaDepth
, ( Unsigned contentDepth
, Unsigned metaDepth
, Maybe (Unsigned contentDepth, PacketStreamContent dataWidth meta)
, Maybe (Unsigned metaDepth, meta)
, PacketStreamS2M
, Maybe (PacketStreamM2S dataWidth meta)
)
)
packetFifoT st@PacketFifoState{..} (fwdIn, bwdIn, cRam, mRam) =
(nextSt, (cReadPtr', mReadPtr', cWriteCmd, mWriteCmd, bwdOut, fwdOut))
where
pktTooBig = _cWritePtr + 1 == _cReadPtr && fifoEmpty
(lastPkt, dropping) = case fwdIn of
Nothing -> (False, _dropping || pktTooBig)
Just PacketStreamM2S{..} -> (isJust _last, _dropping || pktTooBig || _abort)
fifoEmpty = _mReadPtr == _mWritePtr
fifoSinglePacket = _mReadPtr + 1 == _mWritePtr
fifoFull =
(_cWritePtr + 1 == _cReadPtr)
|| (_mWritePtr + 1 == _mReadPtr && lastPkt)
readEn = _canRead && not fifoEmpty
cReadEn = readEn && _ready bwdIn
mReadEn = readEn && _ready bwdIn && isJust (snd cRam)
bwdOut = PacketStreamS2M (not fifoFull || dropping)
fwdOut =
if readEn
then Just (toPacketStreamM2S cRam mRam)
else Nothing
canRead' = not (lastPkt && (fifoEmpty || (mReadEn && fifoSinglePacket)))
dropping' = dropping && not lastPkt
basePtr' = if lastPkt && _ready bwdOut then cWritePtr' else _basePtr
cReadPtr' = if cReadEn then _cReadPtr + 1 else _cReadPtr
mReadPtr' = if mReadEn then _mReadPtr + 1 else _mReadPtr
(cWriteCmd, cWritePtr') =
if not dropping && not fifoFull
then
( (\t -> (_cWritePtr, toPacketStreamContent t)) <$> fwdIn
, _cWritePtr + 1
)
else
( Nothing
, if dropping then _basePtr else _cWritePtr
)
(mWriteCmd, mWritePtr') =
if not dropping && not fifoFull && lastPkt
then ((\t -> (_mWritePtr, _meta t)) <$> fwdIn, _mWritePtr + 1)
else (Nothing, _mWritePtr)
nextSt = case fwdIn of
Nothing -> st{_canRead = True, _cReadPtr = cReadPtr', _mReadPtr = mReadPtr'}
Just _ ->
PacketFifoState
{ _canRead = canRead'
, _dropping = dropping'
, _basePtr = basePtr'
, _cReadPtr = cReadPtr'
, _cWritePtr = cWritePtr'
, _mReadPtr = mReadPtr'
, _mWritePtr = mWritePtr'
}
packetFifoImpl ::
forall
(dom :: Domain)
(dataWidth :: Nat)
(meta :: Type)
(contentSizeBits :: Nat)
(metaSizeBits :: Nat).
(HiddenClockResetEnable dom) =>
(KnownNat dataWidth) =>
(1 <= contentSizeBits) =>
(1 <= metaSizeBits) =>
(NFDataX meta) =>
SNat contentSizeBits ->
SNat metaSizeBits ->
( Signal dom (Maybe (PacketStreamM2S dataWidth meta))
, Signal dom PacketStreamS2M
) ->
( Signal dom PacketStreamS2M
, Signal dom (Maybe (PacketStreamM2S dataWidth meta))
)
packetFifoImpl SNat SNat (fwdIn, bwdIn) = (PacketStreamS2M . not <$> fullBuffer, fwdOut)
where
fwdOut = toMaybe <$> (not <$> emptyBuffer) <*> (toPacketStreamM2S <$> ramContent <*> ramMeta)
ramContent =
blockRam1
NoClearOnReset
(SNat @(2 ^ contentSizeBits))
(errorX "initial block ram content")
cReadAddr'
writeCommand
ramMeta =
blockRam1
NoClearOnReset
(SNat @(2 ^ metaSizeBits))
(errorX "initial block ram meta content")
mReadAddr'
mWriteCommand
writeCommand =
toMaybe
<$> writeEnable
<*> bundle (cWordAddr, toPacketStreamContent . fromJustX <$> fwdIn)
mWriteCommand = toMaybe <$> nextPacketIn <*> bundle (mWriteAddr, _meta . fromJustX <$> fwdIn)
cWordAddr, cPacketAddr, cReadAddr :: Signal dom (Unsigned contentSizeBits)
cWordAddr = register 0 $ mux dropping' cPacketAddr $ mux writeEnable (cWordAddr + 1) cWordAddr
cPacketAddr = register 0 $ mux nextPacketIn (cWordAddr + 1) cPacketAddr
cReadAddr' = mux readEnable (cReadAddr + 1) cReadAddr
cReadAddr = register 0 cReadAddr'
mWriteAddr, mReadAddr :: Signal dom (Unsigned metaSizeBits)
mWriteAddr = register 0 mWriteAddr'
mWriteAddr' = mux nextPacketIn (mWriteAddr + 1) mWriteAddr
mReadAddr' = mux mReadEnable (mReadAddr + 1) mReadAddr
mReadAddr = register 0 mReadAddr'
mReadEnable = lastWordOut .&&. readEnable
dropping', dropping, emptyBuffer :: Signal dom Bool
dropping' = abortIn .||. dropping
dropping = register False $ dropping' .&&. (not <$> lastWordIn)
emptyBuffer = register 0 mWriteAddr .==. mReadAddr
writeEnable = writeRequest .&&. (not <$> fullBuffer) .&&. (not <$> dropping')
readEnable = (not <$> emptyBuffer) .&&. (_ready <$> bwdIn)
fullBuffer = ((cWordAddr + 1) .==. cReadAddr) .||. ((mWriteAddr + 1) .==. mReadAddr)
writeRequest = isJust <$> fwdIn
lastWordIn = maybe False (isJust . _last) <$> fwdIn
lastWordOut = maybe False (isJust . _last) <$> fwdOut
abortIn = maybe False _abort <$> fwdIn
nextPacketIn = lastWordIn .&&. writeEnable
packetFifoC ::
forall
(dom :: Domain)
(dataWidth :: Nat)
(meta :: Type)
(contentDepth :: Nat)
(metaDepth :: Nat).
(HiddenClockResetEnable dom) =>
(KnownNat dataWidth) =>
(1 <= contentDepth) =>
(1 <= metaDepth) =>
(NFDataX meta) =>
SNat contentDepth ->
SNat metaDepth ->
FullMode ->
Circuit (PacketStream dom dataWidth meta) (PacketStream dom dataWidth meta)
packetFifoC cSize@SNat mSize@SNat fullMode =
let
ckt (fwdIn, bwdIn) = (bwdOut, fwdOut)
where
ramContent =
blockRam1
NoClearOnReset
(SNat @(2 ^ contentDepth))
(deepErrorX "initial block ram content")
cReadPtr
cWriteCommand
ramMeta =
blockRam1
NoClearOnReset
(SNat @(2 ^ metaDepth))
(deepErrorX "initial block ram meta content")
mReadPtr
mWriteCommand
(cReadPtr, mReadPtr, cWriteCommand, mWriteCommand, bwdOut, fwdOut) =
mealyB
(packetFifoT @dataWidth @meta @contentDepth @metaDepth)
(PacketFifoState False False 0 0 0 0 0)
(fwdIn, bwdIn, ramContent, ramMeta)
in
case fullMode of
Backpressure ->
forceResetSanity |> fromSignals ckt
Drop ->
toCSignal
|> unsafeAbortOnBackpressureC
|> forceResetSanity
|> fromSignals (packetFifoImpl cSize mSize)