{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_HADDOCK hide #-}
module Protocols.PacketStream.Padding (
stripPaddingC,
) where
import Clash.Prelude
import Data.Bifunctor qualified as B
import Data.Maybe
import Data.Type.Equality ((:~:) (Refl))
import Protocols
import Protocols.PacketStream.Base
data StripPaddingState p dataWidth meta
= Counting
{ _buffer :: PacketStreamM2S dataWidth meta
, _valid :: Bool
, _counter :: Unsigned p
}
| Strip
{ _buffer :: PacketStreamM2S dataWidth meta
}
deriving (Generic, NFDataX)
stripPaddingT ::
forall dataWidth meta p.
(KnownNat dataWidth) =>
(KnownNat p) =>
(meta -> Unsigned p) ->
StripPaddingState p dataWidth meta ->
( Maybe (PacketStreamM2S dataWidth meta)
, PacketStreamS2M
) ->
( StripPaddingState p dataWidth meta
, ( PacketStreamS2M
, Maybe (PacketStreamM2S dataWidth meta)
)
)
stripPaddingT _ st@Counting{} (Nothing, bwdIn) = (nextSt, (deepErrorX "undefined ack", fwdOut))
where
fwdOut =
if _valid st
then Just (_buffer st)
else Nothing
nextSt
| isJust fwdOut && _ready bwdIn = st{_valid = False}
| otherwise = st
stripPaddingT toLength st@Counting{} (Just inPkt, bwdIn) = (nextSt, (bwdOut, fwdOut))
where
expectedLen = toLength (_meta inPkt)
toAdd :: Unsigned p
toAdd = case _last inPkt of
Nothing -> natToNum @dataWidth
Just size -> bitCoerce (resize size :: Index (2 ^ p))
carry :: Bool
nextCount :: Unsigned p
(carry, nextCount) =
B.bimap unpack unpack
$ split
$ add (_counter st) toAdd
prematureEnd =
isJust (_last inPkt)
&& (nextCount < expectedLen)
&& not carry
tooBig = nextCount > expectedLen || carry
fwdOut =
if _valid st
then Just (_buffer st)
else Nothing
bwdOut = PacketStreamS2M (isNothing fwdOut || _ready bwdIn)
nextLast
| tooBig = case sameNat d1 (SNat @dataWidth) of
Just Refl -> Just 0
Nothing -> Just $ bitCoerce $ resize $ expectedLen - _counter st
| otherwise = _last inPkt
nextBuf = inPkt{_last = nextLast, _abort = _abort inPkt || prematureEnd}
nextValid = isJust (_last inPkt) || not tooBig
nextCounter =
if prematureEnd || isJust (_last inPkt)
then 0
else nextCount
nextSt
| isJust fwdOut && not (_ready bwdIn) = st
| isNothing (_last inPkt) && tooBig = Strip nextBuf
| otherwise = Counting nextBuf nextValid nextCounter
stripPaddingT _ st@Strip{} (Nothing, _) = (st, (deepErrorX "undefined ack", Nothing))
stripPaddingT _ Strip{_buffer = f} (Just inPkt, _) =
(nextSt, (PacketStreamS2M True, Nothing))
where
nextAborted = _abort f || _abort inPkt
nextSt =
if isJust (_last inPkt)
then Counting f{_abort = nextAborted} True 0
else Strip (f{_abort = nextAborted})
stripPaddingC ::
forall dataWidth meta p dom.
(HiddenClockResetEnable dom) =>
(KnownNat dataWidth) =>
(KnownNat p) =>
(NFDataX meta) =>
(meta -> Unsigned p) ->
Circuit (PacketStream dom dataWidth meta) (PacketStream dom dataWidth meta)
stripPaddingC toLength =
forceResetSanity
|> fromSignals (mealyB (stripPaddingT toLength) s0)
where
s0 =
Counting
{ _buffer = deepErrorX "stripPaddingT: undefined initial buffer."
, _valid = False
, _counter = 0
}