{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_HADDOCK hide #-}
module Protocols.PacketStream.Converters (
downConverterC,
upConverterC,
unsafeUpConverterC,
) where
import Clash.Prelude
import Data.Maybe (fromMaybe, isJust)
import Data.Maybe.Extra
import Data.Type.Equality ((:~:) (Refl))
import Protocols (CSignal, Circuit (..), fromSignals, idC, (|>))
import Protocols.PacketStream.Base
data UpConverterState (dwIn :: Nat) (n :: Nat) (meta :: Type) = UpConverterState
{ _ucBuf :: Vec (dwIn * n) (BitVector 8)
, _ucIdx :: Index n
, _ucIdx2 :: Index (dwIn * n + 1)
, _ucFlush :: Bool
, _ucAborted :: Bool
, _ucLastIdx :: Maybe (Index (dwIn * n + 1))
, _ucMeta :: meta
}
deriving (Generic, NFDataX, Show, ShowX)
nextState ::
forall (dwIn :: Nat) (meta :: Type) (n :: Nat).
(1 <= dwIn) =>
(1 <= n) =>
(KnownNat dwIn) =>
(KnownNat n) =>
(NFDataX meta) =>
UpConverterState dwIn n meta ->
Maybe (PacketStreamM2S dwIn meta) ->
PacketStreamS2M ->
UpConverterState dwIn n meta
nextState st@(UpConverterState{..}) Nothing (PacketStreamS2M inReady) =
nextSt
where
outReady = not _ucFlush || inReady
nextStRaw =
st
{ _ucFlush = False
, _ucAborted = not _ucFlush && _ucAborted
, _ucLastIdx = Nothing
}
nextSt = if outReady then nextStRaw else st
nextState st@(UpConverterState{..}) (Just PacketStreamM2S{..}) (PacketStreamS2M inReady) =
nextSt
where
nextAbort = (not _ucFlush && _ucAborted) || _abort
outReady = not _ucFlush || inReady
bufFull = _ucIdx == maxBound
nextBuf =
bitCoerce
$ replace
_ucIdx
(pack _data :: BitVector (8 * dwIn))
(bitCoerce _ucBuf :: Vec n (BitVector (8 * dwIn)))
nextFlush = isJust _last || bufFull
nextIdx = if nextFlush then 0 else _ucIdx + 1
(nextIdx2, nextLastIdx) = case sameNat (SNat @(FLog 2 dwIn)) (SNat @(CLog 2 dwIn)) of
Just Refl ->
( 0
, (\i -> shiftL (resize _ucIdx) (natToNum @(Log 2 dwIn)) + resize i) <$> _last
)
Nothing ->
( if nextFlush then 0 else _ucIdx2 + natToNum @dwIn
, (\i -> _ucIdx2 + resize i) <$> _last
)
nextStRaw =
UpConverterState
{ _ucBuf = nextBuf
, _ucIdx = nextIdx
, _ucIdx2 = nextIdx2
, _ucFlush = nextFlush
, _ucAborted = nextAbort
, _ucLastIdx = nextLastIdx
, _ucMeta = _meta
}
nextSt = if outReady then nextStRaw else st
upConverter ::
forall (dwIn :: Nat) (meta :: Type) (dom :: Domain) (n :: Nat).
(HiddenClockResetEnable dom) =>
(1 <= dwIn) =>
(1 <= n) =>
(KnownNat dwIn) =>
(KnownNat n) =>
(NFDataX meta) =>
( Signal dom (Maybe (PacketStreamM2S dwIn meta))
, Signal dom PacketStreamS2M
) ->
( Signal dom PacketStreamS2M
, Signal dom (Maybe (PacketStreamM2S (dwIn * n) meta))
)
upConverter = mealyB go s0
where
errPrefix = "upConverterT: undefined initial "
s0 =
UpConverterState
{ _ucBuf = repeat (nullByte "upConverter")
, _ucIdx = 0
, _ucIdx2 = 0
, _ucFlush = False
, _ucAborted = False
, _ucLastIdx = deepErrorX (errPrefix <> " _ucLastIdx")
, _ucMeta = deepErrorX (errPrefix <> " _ucMeta")
}
go st@(UpConverterState{..}) (fwdIn, bwdIn) =
(nextState st fwdIn bwdIn, (PacketStreamS2M outReady, fwdOut))
where
outReady = not _ucFlush || _ready bwdIn
fwdOut =
toMaybe _ucFlush
$ PacketStreamM2S
{ _data = _ucBuf
, _last = _ucLastIdx
, _meta = _ucMeta
, _abort = _ucAborted
}
upConverterC ::
forall (dwIn :: Nat) (n :: Nat) (meta :: Type) (dom :: Domain).
(HiddenClockResetEnable dom) =>
(1 <= dwIn) =>
(1 <= n) =>
(KnownNat dwIn) =>
(KnownNat n) =>
(NFDataX meta) =>
Circuit (PacketStream dom dwIn meta) (PacketStream dom (dwIn * n) meta)
upConverterC = case sameNat d1 (SNat @n) of
Just Refl -> idC
_ -> forceResetSanity |> fromSignals upConverter
unsafeUpConverterC ::
forall (dwIn :: Nat) (meta :: Type) (dom :: Domain) (n :: Nat).
(HiddenClockResetEnable dom) =>
(1 <= dwIn) =>
(1 <= n) =>
(KnownNat dwIn) =>
(KnownNat n) =>
(NFDataX meta) =>
Circuit
(CSignal dom (Maybe (PacketStreamM2S dwIn meta)))
(CSignal dom (Maybe (PacketStreamM2S (dwIn * n) meta)))
unsafeUpConverterC = case sameNat d1 (SNat @n) of
Just Refl -> idC
_ -> unsafeDropBackpressure (fromSignals upConverter)
data DownConverterState (dwOut :: Nat) (n :: Nat) (meta :: Type) = DownConverterState
{ _dcBuf :: Vec (dwOut * n) (BitVector 8)
, _dcLast :: Bool
, _dcMeta :: meta
, _dcAborted :: Bool
, _dcSize :: Index (dwOut * n + 1)
, _dcZeroByteTransfer :: Bool
}
deriving (Generic, NFDataX)
downConverterT ::
forall (dwOut :: Nat) (n :: Nat) (meta :: Type).
(KnownNat dwOut) =>
(KnownNat n) =>
(1 <= dwOut) =>
(1 <= n) =>
(NFDataX meta) =>
DownConverterState dwOut n meta ->
(Maybe (PacketStreamM2S (dwOut * n) meta), PacketStreamS2M) ->
( DownConverterState dwOut n meta
, (PacketStreamS2M, Maybe (PacketStreamM2S dwOut meta))
)
downConverterT st@(DownConverterState{..}) (fwdIn, bwdIn) =
(nextSt, (PacketStreamS2M readyOut, fwdOut))
where
(shiftedBuf, dataOut) =
leToPlus @dwOut @(dwOut * n)
$ shiftOutFrom0 (SNat @dwOut) _dcBuf
fwdOut =
toMaybe (_dcSize > 0 || _dcZeroByteTransfer)
$ PacketStreamM2S
{ _data = dataOut
, _last =
if _dcZeroByteTransfer
then Just 0
else toMaybe (_dcSize <= natToNum @dwOut && _dcLast) (resize _dcSize)
, _meta = _dcMeta
, _abort = _dcAborted
}
emptyState = _dcSize == 0 && not _dcZeroByteTransfer
readyOut =
emptyState || (_dcSize <= natToNum @dwOut && _ready bwdIn)
nextSt
| isJust fwdIn && readyOut = newState (fromJustX fwdIn)
| not emptyState && _ready bwdIn =
st
{ _dcBuf = shiftedBuf
, _dcSize = satSub SatBound _dcSize (natToNum @dwOut)
, _dcZeroByteTransfer = False
}
| otherwise = st
newState PacketStreamM2S{..} =
DownConverterState
{ _dcBuf = _data
, _dcMeta = _meta
, _dcSize = fromMaybe (natToNum @(dwOut * n)) _last
, _dcLast = isJust _last
, _dcAborted = _abort
, _dcZeroByteTransfer = _last == Just 0
}
downConverterC ::
forall (dwOut :: Nat) (n :: Nat) (meta :: Type) (dom :: Domain).
(HiddenClockResetEnable dom) =>
(KnownNat dwOut) =>
(KnownNat n) =>
(1 <= dwOut) =>
(1 <= n) =>
(NFDataX meta) =>
Circuit (PacketStream dom (dwOut * n) meta) (PacketStream dom dwOut meta)
downConverterC = case sameNat d1 (SNat @n) of
Just Refl -> idC
_ -> forceResetSanity |> fromSignals (mealyB downConverterT s0)
where
errPrefix = "downConverterT: undefined initial "
s0 =
DownConverterState
{ _dcBuf = deepErrorX (errPrefix <> "_dcBuf")
, _dcLast = deepErrorX (errPrefix <> "_dcLast")
, _dcMeta = deepErrorX (errPrefix <> "_dcMeta")
, _dcAborted = deepErrorX (errPrefix <> "_dcAborted")
, _dcSize = 0
, _dcZeroByteTransfer = False
}