Skip to content

Commit cb003b3

Browse files
lmbollenjaschutte
authored andcommitted
Add truncateAbortedPackets (clash-lang#159)
1 parent 10de155 commit cb003b3

File tree

2 files changed

+57
-1
lines changed
  • clash-protocols
    • src/Protocols/PacketStream
    • tests/Tests/Protocols/PacketStream

2 files changed

+57
-1
lines changed

clash-protocols/src/Protocols/PacketStream/Base.hs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module Protocols.PacketStream.Base (
2929
zeroOutInvalidBytesC,
3030
stripTrailingEmptyC,
3131
unsafeAbortOnBackpressureC,
32+
truncateAbortedPackets,
3233

3334
-- * Components imported from DfConv
3435
void,
@@ -439,6 +440,41 @@ zeroOutInvalidBytesC = Circuit $ \(fwdIn, bwdIn) -> (bwdIn, fmap (go <$>) fwdIn)
439440
(\(j :: Index dataWidth) byte -> if resize j < i then byte else 0x00)
440441
(_data transferIn)
441442

443+
data TruncateState = Forwarding | Truncating
444+
deriving (Show, ShowX, Eq, Generic, NFDataX)
445+
446+
{- |
447+
When a packet is aborted, this circuit will truncate the current packet by setting the
448+
'_last' field of the transaction to @Just 0@ and the '_abort' field to @True@.
449+
All subsequent transactions will be consumed without being forwarded.
450+
-}
451+
truncateAbortedPackets ::
452+
forall (dom :: Domain) (dataWidth :: Nat) (meta :: Type).
453+
(HiddenClockResetEnable dom, KnownNat dataWidth, ShowX meta) =>
454+
(1 <= dataWidth) =>
455+
Circuit
456+
(PacketStream dom dataWidth meta)
457+
(PacketStream dom dataWidth meta)
458+
truncateAbortedPackets = forceResetSanity |> Circuit (unbundle . mealy go Forwarding . bundle)
459+
where
460+
go state (Nothing, _) = (state, (deepErrorX "truncateAbortedPackets: undefined ack", Nothing))
461+
go Truncating (Just m2s, _) = (nextState, (PacketStreamS2M True, Nothing))
462+
where
463+
nextState
464+
| Maybe.isJust m2s._last = Forwarding
465+
| otherwise = Truncating
466+
go Forwarding (Just m2sLeft, PacketStreamS2M ack) = (nextState, (PacketStreamS2M ack, Just m2sRight))
467+
where
468+
m2sRight
469+
| m2sLeft._abort = m2sLeft{_last = Just 0}
470+
| otherwise = m2sLeft
471+
472+
nextState
473+
-- Note that there is no need to move to 'Truncating' if the transfer we
474+
-- see here is the last transfer of a packet (i.e., '_last' is @Just _@).
475+
| Maybe.isNothing m2sLeft._last && m2sLeft._abort && ack = Truncating
476+
| otherwise = Forwarding
477+
442478
{- |
443479
Copy data of a single `PacketStream` to multiple. LHS will only receive
444480
an acknowledgement when all RHS receivers have acknowledged data.

clash-protocols/tests/Tests/Protocols/PacketStream/Base.hs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Clash.Prelude
99
import Data.List qualified as L
1010
import "extra" Data.List.Extra (unsnoc)
1111

12-
import Hedgehog (Property)
12+
import Hedgehog (Gen, Property)
1313
import Hedgehog.Gen qualified as Gen
1414
import Hedgehog.Range qualified as Range
1515

@@ -44,6 +44,26 @@ prop_strip_trailing_empty =
4444
then ys L.++ [l2{_last = Just maxBound, _abort = _abort l2 || _abort l}]
4545
else packet
4646

47+
prop_truncate_aborted_packets :: Property
48+
prop_truncate_aborted_packets =
49+
idWithModelSingleDomain
50+
@System
51+
defExpectOptions
52+
gen
53+
(exposeClockResetEnable model')
54+
(exposeClockResetEnable truncateAbortedPackets)
55+
where
56+
gen :: Gen [PacketStreamM2S 4 ()]
57+
gen = genPackets 0 10 (genValidPacket defPacketOptions Gen.enumBounded (Range.linear 0 10))
58+
59+
model' packets = L.concatMap model (chunkByPacket packets)
60+
61+
model :: [PacketStreamM2S 4 ()] -> [PacketStreamM2S 4 ()]
62+
model [] = []
63+
model (x : xs)
64+
| x._abort = [x{_last = Just 0}]
65+
| otherwise = x : model xs
66+
4767
tests :: TestTree
4868
tests =
4969
localOption (mkTimeout 20_000_000 {- 20 seconds -})

0 commit comments

Comments
 (0)