diff --git a/clash-protocols/clash-protocols.cabal b/clash-protocols/clash-protocols.cabal index 822584c7..6e259f61 100644 --- a/clash-protocols/clash-protocols.cabal +++ b/clash-protocols/clash-protocols.cabal @@ -152,6 +152,7 @@ library Protocols.PacketStream.Converters Protocols.PacketStream.Delay Protocols.PacketStream.Depacketizers + Protocols.PacketStream.Hedgehog Protocols.PacketStream.PacketFifo Protocols.PacketStream.Packetizers Protocols.PacketStream.Routing @@ -198,7 +199,6 @@ test-suite unittests Tests.Protocols.Wishbone Tests.Protocols.PacketStream Tests.Protocols.PacketStream.AsyncFifo - Tests.Protocols.PacketStream.Base Tests.Protocols.PacketStream.Converters Tests.Protocols.PacketStream.Delay Tests.Protocols.PacketStream.Depacketizers diff --git a/clash-protocols/src/Protocols/PacketStream/Hedgehog.hs b/clash-protocols/src/Protocols/PacketStream/Hedgehog.hs new file mode 100644 index 00000000..3a5e2e68 --- /dev/null +++ b/clash-protocols/src/Protocols/PacketStream/Hedgehog.hs @@ -0,0 +1,418 @@ +{-# LANGUAGE RecordWildCards #-} + +{- | +Copyright : (C) 2024, QBayLogic B.V. +License : BSD2 (see the file LICENSE) +Maintainer : QBayLogic B.V. + +Provides Hedgehog generators, models and utility functions for testing +`PacketStream` circuits. +-} +module Protocols.PacketStream.Hedgehog ( + -- * Utility functions + chopPacket, + chunkByPacket, + chunkToPacket, + fullPackets, + smearAbort, + + -- * Models + dropAbortedPackets, + downConvert, + upConvert, + depacketizerModel, + depacketizeToDfModel, + packetize, + packetizeFromDf, + + -- * Hedgehog generators + AbortMode (..), + genValidPacket, + genValidPackets, +) where + +import Prelude + +import Clash.Hedgehog.Sized.Vector (genVec) +import qualified Clash.Prelude as C +import qualified Clash.Sized.Vector as Vec + +import Hedgehog (Gen, Range) +import qualified Hedgehog.Gen as Gen + +import Protocols.PacketStream.Base + +import qualified Data.List as L +import Data.Maybe (fromJust, isJust) + +-- | Partition a list based on given function. +chunkBy :: (a -> Bool) -> [a] -> [[a]] +chunkBy _ [] = [] +chunkBy predicate list = L.filter (not . null) (chunkByHelper predicate list []) + +-- Helper function to accumulate chunks. +chunkByHelper :: (a -> Bool) -> [a] -> [a] -> [[a]] +chunkByHelper _ [] acc = [L.reverse acc] +chunkByHelper predicate (x : xs) acc + | predicate x = L.reverse (x : acc) : chunkByHelper predicate xs [] + | otherwise = chunkByHelper predicate xs (x : acc) + +-- | Partition a list of `PacketStream` transfers into complete packets. +chunkByPacket :: + [PacketStreamM2S dataWidth meta] -> + [[PacketStreamM2S dataWidth meta]] +chunkByPacket = chunkBy (isJust . _last) + +{- | +If a packet contains a transfer with `_abort` set, set the `_abort` of +all following transfers in the same packet. +-} +smearAbort :: + [PacketStreamM2S dataWidth meta] -> + [PacketStreamM2S dataWidth meta] +smearAbort [] = [] +smearAbort (x : xs) = L.reverse $ L.foldl' go [x] xs + where + go [] _ = [] + go l@(a : _) (PacketStreamM2S dat last' meta abort) = + PacketStreamM2S dat last' meta (_abort a || abort) : l + +-- | Partition a list into groups of given size +chopBy :: Int -> [a] -> [[a]] +chopBy _ [] = [] +chopBy n xs = as : chopBy n bs where (as, bs) = splitAt n xs + +{- | +Merge a list of `PacketStream` transfers with data width @1@ to +a single `PacketStream` transfer with data width @dataWidth@. +-} +chunkToPacket :: + (C.KnownNat dataWidth) => + [PacketStreamM2S 1 meta] -> + PacketStreamM2S dataWidth meta +chunkToPacket l = + PacketStreamM2S + { _last = + if isJust (_last lastTransfer) + then Just (fromIntegral $ L.length l - 1) + else Nothing + , _abort = any _abort l + , _meta = _meta lastTransfer + , _data = foldr ((C.+>>) . C.head . _data) (C.repeat 0) l + } + where + lastTransfer = L.last l + +{- | +Split a single `PacketStream` transfer with data width @dataWidth@ to +a list of `PacketStream` transfers with data width @1@. +-} +chopPacket :: + forall dataWidth meta. + (1 C.<= dataWidth) => + (C.KnownNat dataWidth) => + PacketStreamM2S dataWidth meta -> + [PacketStreamM2S 1 meta] +chopPacket PacketStreamM2S{..} = packets + where + lasts = case _last of + Nothing -> repeat Nothing + Just in' -> replicate (fromIntegral in') Nothing ++ [Just (0 :: C.Index 1)] + + datas = case _last of + Nothing -> C.toList _data + Just in' -> take (fromIntegral in' + 1) $ C.toList _data + + packets = + ( \(idx, dat) -> + PacketStreamM2S (pure dat) idx _meta _abort + ) + <$> zip lasts datas + +-- | Set `_last` of the last transfer in the list to @Just 0@ +fullPackets :: + (C.KnownNat dataWidth) => + [PacketStreamM2S dataWidth meta] -> + [PacketStreamM2S dataWidth meta] +fullPackets [] = [] +fullPackets fragments = + let lastFragment = (last fragments){_last = Just 0} + in init fragments ++ [lastFragment] + +-- | Drops packets if one of the transfers in the packet has `_abort` set. +dropAbortedPackets :: + [PacketStreamM2S dataWidth meta] -> + [PacketStreamM2S dataWidth meta] +dropAbortedPackets packets = concat $ filter (not . any _abort) (chunkByPacket packets) + +{- | +Splits a list of `PacketStream` transfers with data width @1@ into +a list of `PacketStream` transfers with data width @dataWidth@ +-} +downConvert :: + forall dataWidth meta. + (1 C.<= dataWidth) => + (C.KnownNat dataWidth) => + [PacketStreamM2S dataWidth meta] -> + [PacketStreamM2S 1 meta] +downConvert = concatMap chopPacket + +{- | +Merges a list of `PacketStream` transfers with data width @dataWidth into +a list of `PacketStream` transfers with data width @1@ +-} +upConvert :: + forall dataWidth meta. + (1 C.<= dataWidth) => + (C.KnownNat dataWidth) => + [PacketStreamM2S 1 meta] -> + [PacketStreamM2S dataWidth meta] +upConvert packets = + map + chunkToPacket + (chunkByPacket packets >>= chopBy (C.natToNum @dataWidth)) + +-- | Model of the generic `Protocols.PacketStream.depacketizerC`. +depacketizerModel :: + forall + (dataWidth :: C.Nat) + (headerBytes :: C.Nat) + (metaIn :: C.Type) + (header :: C.Type) + (metaOut :: C.Type). + (C.KnownNat dataWidth) => + (C.KnownNat headerBytes) => + (1 C.<= dataWidth) => + (1 C.<= headerBytes) => + (C.BitPack header) => + (C.BitSize header ~ headerBytes C.* 8) => + (header -> metaIn -> metaOut) -> + [PacketStreamM2S dataWidth metaIn] -> + [PacketStreamM2S dataWidth metaOut] +depacketizerModel toMetaOut ps = L.concat dataWidthPackets + where + hdrbytes = C.natToNum @headerBytes + + parseHdr :: + ([PacketStreamM2S 1 metaIn], [PacketStreamM2S 1 metaIn]) -> + [PacketStreamM2S 1 metaOut] + parseHdr (hdrF, fwdF) = fmap (\f -> f{_meta = metaOut}) fwdF + where + hdr = C.bitCoerce $ Vec.unsafeFromList @headerBytes $ _data <$> hdrF + metaOut = toMetaOut hdr (_meta $ L.head fwdF) + + bytePackets :: [[PacketStreamM2S 1 metaIn]] + bytePackets = + L.filter (\fs -> L.length fs > hdrbytes) $ + L.concatMap chopPacket . smearAbort <$> chunkByPacket ps + + parsedPackets :: [[PacketStreamM2S 1 metaOut]] + parsedPackets = parseHdr . L.splitAt hdrbytes <$> bytePackets + + dataWidthPackets :: [[PacketStreamM2S dataWidth metaOut]] + dataWidthPackets = L.map upConvert parsedPackets + +-- | Model of the generic `Protocols.PacketStream.depacketizeToDfC`. +depacketizeToDfModel :: + forall + (dataWidth :: C.Nat) + (headerBytes :: C.Nat) + (a :: C.Type) + (header :: C.Type) + (metaIn :: C.Type). + (C.KnownNat dataWidth) => + (C.KnownNat headerBytes) => + (1 C.<= dataWidth) => + (1 C.<= headerBytes) => + (C.BitPack header) => + (C.BitSize header ~ headerBytes C.* 8) => + (header -> metaIn -> a) -> + [PacketStreamM2S dataWidth metaIn] -> + [a] +depacketizeToDfModel toOut ps = L.map parseHdr bytePackets + where + parseHdr :: [PacketStreamM2S 1 metaIn] -> a + parseHdr hdrF = + toOut + (C.bitCoerce $ Vec.unsafeFromList $ _data <$> hdrF) + (_meta $ L.head hdrF) + + bytePackets :: [[PacketStreamM2S 1 metaIn]] + bytePackets = + L.filter + (\pkt -> L.length pkt >= C.natToNum @headerBytes) + (chunkByPacket $ downConvert (dropAbortedPackets ps)) + +-- | Model of the generic `Protocols.PacketStream.packetizerC`. +packetize :: + forall + (dataWidth :: C.Nat) + (headerBytes :: C.Nat) + (metaIn :: C.Type) + (header :: C.Type) + (metaOut :: C.Type). + (C.KnownNat dataWidth) => + (C.KnownNat headerBytes) => + (1 C.<= dataWidth) => + (1 C.<= headerBytes) => + (C.BitPack header) => + (C.BitSize header ~ headerBytes C.* 8) => + (metaIn -> metaOut) -> + (metaIn -> header) -> + [PacketStreamM2S dataWidth metaIn] -> + [PacketStreamM2S dataWidth metaOut] +packetize toMetaOut toHeader ps = L.concatMap (upConvert . prependHdr) bytePackets + where + prependHdr :: [PacketStreamM2S 1 metaIn] -> [PacketStreamM2S 1 metaOut] + prependHdr fragments = hdr L.++ L.map (\f -> f{_meta = metaOut}) fragments + where + h = L.head fragments + metaOut = toMetaOut (_meta h) + hdr = L.map go (C.toList $ C.bitCoerce (toHeader (_meta h))) + go byte = PacketStreamM2S (C.singleton byte) Nothing metaOut (_abort h) + + bytePackets :: [[PacketStreamM2S 1 metaIn]] + bytePackets = downConvert . smearAbort <$> chunkByPacket ps + +-- | Model of the generic `Protocols.PacketStream.packetizeFromDfC`. +packetizeFromDf :: + forall + (dataWidth :: C.Nat) + (headerBytes :: C.Nat) + (a :: C.Type) + (header :: C.Type) + (metaOut :: C.Type). + (C.KnownNat dataWidth) => + (C.KnownNat headerBytes) => + (1 C.<= dataWidth) => + (1 C.<= headerBytes) => + (C.BitPack header) => + (C.BitSize header ~ headerBytes C.* 8) => + (a -> metaOut) -> + (a -> header) -> + [a] -> + [PacketStreamM2S dataWidth metaOut] +packetizeFromDf toMetaOut toHeader = L.concatMap (upConvert . dfToPacket) + where + dfToPacket :: a -> [PacketStreamM2S 1 metaOut] + dfToPacket d = + fullPackets $ + L.map + (\byte -> PacketStreamM2S (C.singleton byte) Nothing (toMetaOut d) False) + (C.toList $ C.bitCoerce (toHeader d)) + +{- | +If set to @NoAbort@, packets will never contain a transfer with _abort set. +Otherwise, transfers of roughly 50% of the packets will randomly have _abort set. +-} +data AbortMode = Abort | NoAbort + +{- | +Generate valid packets, i.e. packets of which all transfers carry the same +`_meta` and with all unenabled bytes in `_data` set to 0x00. +-} +genValidPackets :: + forall (dataWidth :: C.Nat) (metaType :: C.Type). + (1 C.<= dataWidth) => + (C.KnownNat dataWidth) => + (C.BitPack metaType) => + -- | The amount of packets to generate. + Range Int -> + -- | The amount of transfers with @_last = Nothing@ to generate per packet. + -- This function will always generate an extra transfer per packet + -- with @_last = Just i@. + Range Int -> + -- | If set to @NoAbort@, no generated packets will have `_abort` set in + -- any of their transfers. Else, roughly 50% of packets will contain + -- fragments with their `_abort` randomly set. + AbortMode -> + Gen [PacketStreamM2S dataWidth metaType] +genValidPackets pkts size Abort = concat <$> Gen.list pkts gen + where + gen = do + abortPacket <- Gen.bool + genValidPacket size (if abortPacket then Abort else NoAbort) +genValidPackets pkts size NoAbort = + concat <$> Gen.list pkts (genValidPacket size NoAbort) + +{- | +Generate a valid packet, i.e. a packet of which all transfers carry the same +`_meta` and with all unenabled bytes in `_data` set to 0x00. +-} +genValidPacket :: + forall (dataWidth :: C.Nat) (metaType :: C.Type). + (1 C.<= dataWidth) => + (C.KnownNat dataWidth) => + (C.BitPack metaType) => + -- | The amount of transfers with @_last = Nothing@ to generate. + -- This function will always generate an extra transfer with @_last = Just i@. + Range Int -> + -- | If set to @NoAbort@, no transfers in the packet will have @_abort@ set. + -- Else, they will randomly have @_abort@ set. + AbortMode -> + Gen [PacketStreamM2S dataWidth metaType] +genValidPacket size abortMode = do + meta <- C.unpack <$> Gen.enumBounded + transfers <- Gen.list size (genTransfer @dataWidth meta abortMode) + lastTransfer <- genLastTransfer @dataWidth meta abortMode + pure (transfers ++ [lastTransfer]) + +-- | Generate a single transfer which is not yet the end of a packet. +genTransfer :: + forall (dataWidth :: C.Nat) (metaType :: C.Type). + (1 C.<= dataWidth) => + (C.KnownNat dataWidth) => + -- | We need to use the same metadata + -- for every transfer in a packet to satisfy the protocol + -- invariant that metadata is constant for an entire packet. + metaType -> + -- | If set to @NoAbort@, hardcode @_abort@ to @False@. Else, + -- randomly generate it. + AbortMode -> + Gen (PacketStreamM2S dataWidth metaType) +genTransfer meta abortMode = + PacketStreamM2S + <$> genVec Gen.enumBounded + <*> Gen.constant Nothing + <*> Gen.constant meta + <*> case abortMode of + Abort -> Gen.enumBounded + NoAbort -> Gen.constant False + +{- | +Generate the last transfer of a packet, i.e. a transfer with @_last@ set as @Just@. +All bytes which are not enabled are set to 0x00. +-} +genLastTransfer :: + forall (dataWidth :: C.Nat) (metaType :: C.Type). + (1 C.<= dataWidth) => + (C.KnownNat dataWidth) => + -- | We need to use the same metadata + -- for every transfer in a packet to satisfy the protocol + -- invariant that metadata is constant for an entire packet. + metaType -> + -- | If set to @NoAbort@, hardcode @_abort@ to @False@. Else, + -- randomly generate it. + AbortMode -> + Gen (PacketStreamM2S dataWidth metaType) +genLastTransfer meta abortMode = + setNull + <$> ( PacketStreamM2S + <$> genVec Gen.enumBounded + <*> (Just <$> Gen.enumBounded) + <*> Gen.constant meta + <*> case abortMode of + Abort -> Gen.enumBounded + NoAbort -> Gen.constant False + ) + where + setNull transfer = + let i = fromJust (_last transfer) + in transfer + { _data = + fromJust + ( Vec.fromList $ + take (1 + fromIntegral i) (C.toList (_data transfer)) + ++ replicate ((C.natToNum @dataWidth) - 1 - fromIntegral i) 0x00 + ) + } diff --git a/clash-protocols/tests/Tests/Protocols/PacketStream/AsyncFifo.hs b/clash-protocols/tests/Tests/Protocols/PacketStream/AsyncFifo.hs index b3573868..8ece86c5 100644 --- a/clash-protocols/tests/Tests/Protocols/PacketStream/AsyncFifo.hs +++ b/clash-protocols/tests/Tests/Protocols/PacketStream/AsyncFifo.hs @@ -1,32 +1,21 @@ -{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NumericUnderscores #-} -{-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -Wno-orphans #-} module Tests.Protocols.PacketStream.AsyncFifo where --- base -import Prelude +import Clash.Prelude --- clash-prelude -import Clash.Prelude as C - --- hedgehog -import Hedgehog +import Hedgehog (Property) import qualified Hedgehog.Range as Range --- tasty -import Test.Tasty +import Test.Tasty (TestTree, localOption, mkTimeout) import Test.Tasty.Hedgehog (HedgehogTestLimit (HedgehogTestLimit)) import Test.Tasty.Hedgehog.Extra (testProperty) import Test.Tasty.TH (testGroupGenerator) --- clash-protocols import Protocols.Hedgehog -import Protocols.PacketStream.AsyncFifo - --- tests -import Tests.Protocols.PacketStream.Base +import Protocols.PacketStream.AsyncFifo (asyncFifoC) +import Protocols.PacketStream.Hedgehog createDomain vSystem @@ -57,10 +46,10 @@ clk125 = clockGen -- Assert the reset for a different amount of cycles in each domain -- to properly test the async fifo. rst50 :: Reset TestDom50 -rst50 = resetGenN d50 +rst50 = resetGenN d30 rst125 :: Reset TestDom125 -rst125 = resetGenN d60 +rst125 = resetGenN d40 en50 :: Enable TestDom50 en50 = enableGen diff --git a/clash-protocols/tests/Tests/Protocols/PacketStream/Base.hs b/clash-protocols/tests/Tests/Protocols/PacketStream/Base.hs deleted file mode 100644 index ff7f8af6..00000000 --- a/clash-protocols/tests/Tests/Protocols/PacketStream/Base.hs +++ /dev/null @@ -1,242 +0,0 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE RecordWildCards #-} - -module Tests.Protocols.PacketStream.Base ( - chunkBy, - chunkByPacket, - smearAbort, - chopBy, - chunkToPacket, - chopPacket, - fullPackets, - dropAbortedPackets, - downConvert, - upConvert, - AbortMode (..), - genValidPacket, - genValidPackets, - genVec, -) where - --- base -import qualified Data.List as L -import qualified Data.Maybe as M -import Prelude - --- clash -import qualified Clash.Prelude as C -import qualified Clash.Sized.Vector as Vec - --- hedgehog -import Hedgehog -import qualified Hedgehog.Gen as Gen - --- clash-protocols -import Protocols.PacketStream.Base - --- | Partition a list based on given function -chunkBy :: (a -> Bool) -> [a] -> [[a]] -chunkBy _ [] = [] -chunkBy predicate list = L.filter (not . null) $ chunkByHelper predicate list [] - --- Helper function to accumulate chunks -chunkByHelper :: (a -> Bool) -> [a] -> [a] -> [[a]] -chunkByHelper _ [] acc = [L.reverse acc] -chunkByHelper predicate (x : xs) acc - | predicate x = L.reverse (x : acc) : chunkByHelper predicate xs [] - | otherwise = chunkByHelper predicate xs (x : acc) - --- | Partition a list of PacketStreams into complete packets -chunkByPacket :: [PacketStreamM2S n meta] -> [[PacketStreamM2S n meta]] -chunkByPacket = chunkBy (M.isJust . _last) - --- | Smear abort over the rest of a list of packets -smearAbort :: [PacketStreamM2S n meta] -> [PacketStreamM2S n meta] -smearAbort [] = [] -smearAbort (x : xs) = L.reverse $ L.foldl' go [x] xs - where - go [] _ = [] - go l@(a : _) (PacketStreamM2S dat last' meta abort) = - PacketStreamM2S dat last' meta (_abort a || abort) : l - --- | Partition a list into groups of given size -chopBy :: Int -> [a] -> [[a]] -chopBy _ [] = [] -chopBy n xs = as : chopBy n bs where (as, bs) = splitAt n xs - --- | Merge a list of PacketStream 1 into a PacketStream n -chunkToPacket :: (C.KnownNat n) => [PacketStreamM2S 1 meta] -> PacketStreamM2S n meta -chunkToPacket l = - PacketStreamM2S - { _last = - if M.isJust (_last lastTransfer) then M.Just (fromIntegral $ L.length l - 1) else Nothing - , _abort = any _abort l - , _meta = _meta lastTransfer - , _data = foldr ((C.+>>) . C.head . _data) (C.repeat 0) l - } - where - lastTransfer = L.last l - --- | Split a PacketStream n into a list of PacketStream 1 -chopPacket :: - forall n meta. - (1 C.<= n) => - (C.KnownNat n) => - PacketStreamM2S n meta -> - [PacketStreamM2S 1 meta] -chopPacket PacketStreamM2S{..} = packets - where - lasts = case _last of - Nothing -> repeat Nothing - Just in' -> replicate (fromIntegral in') Nothing ++ [Just (0 :: C.Index 1)] - - datas = case _last of - Nothing -> C.toList _data - Just in' -> take (fromIntegral in' + 1) $ C.toList _data - - packets = (\(idx, dat) -> PacketStreamM2S (pure dat) idx _meta _abort) <$> zip lasts datas - --- | Set the _last of the last element of a list of PacketStreams to 0 -fullPackets :: (C.KnownNat n) => [PacketStreamM2S n meta] -> [PacketStreamM2S n meta] -fullPackets [] = [] -fullPackets fragments = - let lastFragment = (last fragments){_last = Just 0} - in init fragments ++ [lastFragment] - --- | Drops packets if one of the transfers in the packet has the abort flag set -dropAbortedPackets :: [PacketStreamM2S n meta] -> [PacketStreamM2S n meta] -dropAbortedPackets packets = concat $ filter (not . any _abort) (chunkByPacket packets) - --- | Split a list of PacketStream n into a list of PacketStream 1 -downConvert :: - forall n meta. - (1 C.<= n) => - (C.KnownNat n) => - [PacketStreamM2S n meta] -> - [PacketStreamM2S 1 meta] -downConvert = concatMap chopPacket - --- | Merge a list of PacketStream 1 into a list of PacketStream n -upConvert :: - forall n meta. - (1 C.<= n) => - (C.KnownNat n) => - [PacketStreamM2S 1 meta] -> - [PacketStreamM2S n meta] -upConvert packets = map chunkToPacket (chunkByPacket packets >>= chopBy (C.natToNum @n)) - -{- | If set to @NoAbort@, packets will never contain a transfer with _abort set. - Otherwise, transfers of roughly 50% of the packets will randomly have _abort set. --} -data AbortMode = Abort | NoAbort - -{- | Generate valid packets, i.e. packets of which all transfers carry the same - @_meta@ and with all unenabled bytes in @_data@ set to 0x00. --} -genValidPackets :: - forall (dataWidth :: C.Nat) (metaType :: C.Type). - (1 C.<= dataWidth) => - (C.KnownNat dataWidth) => - (C.BitPack metaType) => - -- | The amount of packets to generate. - Range Int -> - -- | The amount of transfers to generate. - Range Int -> - -- | If set to @NoAbort@, no generated packets will have @_abort@ set in - -- any of their transfers. Else, roughly 50% of packets will contain - -- fragments with their @_abort@ randomly set. - AbortMode -> - Gen [PacketStreamM2S dataWidth metaType] -genValidPackets r1 r2 Abort = concat <$> Gen.list r1 x - where - x = do - abortPacket <- Gen.bool - genValidPacket r2 (if abortPacket then Abort else NoAbort) -genValidPackets r1 r2 NoAbort = concat <$> Gen.list r1 (genValidPacket r2 NoAbort) - -{- | Generate a valid packet, i.e. a packet of which all transfers carry the same - @_meta@ and with all unenabled bytes in @_data@ set to 0x00. --} -genValidPacket :: - forall (dataWidth :: C.Nat) (metaType :: C.Type). - (1 C.<= dataWidth) => - (C.KnownNat dataWidth) => - (C.BitPack metaType) => - -- | The amount of transfers to generate. - Range Int -> - -- | If set to @NoAbort@, no transfers in the packet will have @_abort@ set. - -- Else, they will randomly have @_abort@ set. - AbortMode -> - Gen [PacketStreamM2S dataWidth metaType] -genValidPacket r abortMode = do - meta <- C.unpack <$> Gen.enumBounded - transfers <- Gen.list r (genTransfer @dataWidth meta abortMode) - lastTransfer <- genLastTransfer @dataWidth meta abortMode - pure (transfers ++ [lastTransfer]) - --- | Generate a single transfer which is not yet the end of a packet. -genTransfer :: - forall (dataWidth :: C.Nat) (metaType :: C.Type). - (1 C.<= dataWidth) => - (C.KnownNat dataWidth) => - -- | We need to use the same metadata - -- for every transfer in a packet to satisfy the protocol - -- invariant that metadata is constant for an entire packet. - metaType -> - -- | If set to @NoAbort@, hardcode @_abort@ to @False@. Else, - -- randomly generate it. - AbortMode -> - Gen (PacketStreamM2S dataWidth metaType) -genTransfer meta abortMode = - PacketStreamM2S - <$> genVec Gen.enumBounded - <*> Gen.constant Nothing - <*> Gen.constant meta - <*> case abortMode of - Abort -> Gen.enumBounded - NoAbort -> Gen.constant False - -{- | Generate the last transfer of a packet, i.e. a transfer with @_last@ set as @Just@. - All bytes which are not enabled are set to 0x00. --} -genLastTransfer :: - forall (dataWidth :: C.Nat) (metaType :: C.Type). - (1 C.<= dataWidth) => - (C.KnownNat dataWidth) => - -- | We need to use the same metadata - -- for every transfer in a packet to satisfy the protocol - -- invariant that metadata is constant for an entire packet. - metaType -> - -- | If set to @NoAbort@, hardcode @_abort@ to @False@. Else, - -- randomly generate it. - AbortMode -> - Gen (PacketStreamM2S dataWidth metaType) -genLastTransfer meta abortMode = - setNull - <$> ( PacketStreamM2S - <$> genVec Gen.enumBounded - <*> (Just <$> Gen.enumBounded) - <*> Gen.constant meta - <*> case abortMode of - Abort -> Gen.enumBounded - NoAbort -> Gen.constant False - ) - where - setNull transfer = - let i = M.fromJust (_last transfer) - in transfer - { _data = - M.fromJust - ( Vec.fromList $ - take (1 + fromIntegral i) (C.toList (_data transfer)) - ++ replicate ((C.natToNum @dataWidth) - 1 - fromIntegral i) 0x00 - ) - } - --- | Randomly generate a vector of length @n@. -genVec :: - forall (n :: C.Nat) (a :: C.Type). - (C.KnownNat n, 1 C.<= n) => - Gen a -> - Gen (C.Vec n a) -genVec gen = sequence (C.repeat gen) diff --git a/clash-protocols/tests/Tests/Protocols/PacketStream/Converters.hs b/clash-protocols/tests/Tests/Protocols/PacketStream/Converters.hs index c87563a8..3cebebde 100644 --- a/clash-protocols/tests/Tests/Protocols/PacketStream/Converters.hs +++ b/clash-protocols/tests/Tests/Protocols/PacketStream/Converters.hs @@ -1,102 +1,90 @@ -{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NumericUnderscores #-} -{-# LANGUAGE RecordWildCards #-} module Tests.Protocols.PacketStream.Converters where --- base -import Prelude +import Clash.Prelude --- clash-prelude -import Clash.Prelude (type (<=)) -import qualified Clash.Prelude as C - --- hedgehog -import Hedgehog +import Hedgehog (Property) import qualified Hedgehog.Range as Range --- tasty import Test.Tasty import Test.Tasty.Hedgehog (HedgehogTestLimit (HedgehogTestLimit)) import Test.Tasty.Hedgehog.Extra (testProperty) import Test.Tasty.TH (testGroupGenerator) --- clash-protocols import Protocols.Hedgehog import Protocols.PacketStream.Converters - --- tests -import Tests.Protocols.PacketStream.Base +import Protocols.PacketStream.Hedgehog generateUpConverterProperty :: - forall (dwIn :: C.Nat) (dwOut :: C.Nat) (n :: C.Nat). + forall (dwIn :: Nat) (dwOut :: Nat) (n :: Nat). (1 <= dwIn) => (1 <= dwOut) => (1 <= n) => - (C.KnownNat n) => - (dwOut ~ n C.* dwIn) => - C.SNat dwIn -> - C.SNat dwOut -> + (KnownNat n) => + (dwOut ~ n * dwIn) => + SNat dwIn -> + SNat dwOut -> Property -generateUpConverterProperty C.SNat C.SNat = +generateUpConverterProperty SNat SNat = idWithModelSingleDomain defExpectOptions (genValidPackets (Range.linear 1 10) (Range.linear 1 20) Abort) - (C.exposeClockResetEnable (upConvert . downConvert)) - (C.exposeClockResetEnable @C.System (upConverterC @dwIn @dwOut @Int)) + (exposeClockResetEnable (upConvert . downConvert)) + (exposeClockResetEnable @System (upConverterC @dwIn @dwOut @Int)) prop_upConverter4to8 :: Property -prop_upConverter4to8 = generateUpConverterProperty C.d4 C.d8 +prop_upConverter4to8 = generateUpConverterProperty d4 d8 prop_upConverter3to6 :: Property -prop_upConverter3to6 = generateUpConverterProperty C.d3 C.d6 +prop_upConverter3to6 = generateUpConverterProperty d3 d6 prop_upConverter2to4 :: Property -prop_upConverter2to4 = generateUpConverterProperty C.d2 C.d4 +prop_upConverter2to4 = generateUpConverterProperty d2 d4 prop_upConverter1to4 :: Property -prop_upConverter1to4 = generateUpConverterProperty C.d1 C.d4 +prop_upConverter1to4 = generateUpConverterProperty d1 d4 prop_upConverter1to2 :: Property -prop_upConverter1to2 = generateUpConverterProperty C.d1 C.d2 +prop_upConverter1to2 = generateUpConverterProperty d1 d2 prop_upConverter1to1 :: Property -prop_upConverter1to1 = generateUpConverterProperty C.d1 C.d1 +prop_upConverter1to1 = generateUpConverterProperty d1 d1 generateDownConverterProperty :: - forall (dwIn :: C.Nat) (dwOut :: C.Nat) (n :: C.Nat). + forall (dwIn :: Nat) (dwOut :: Nat) (n :: Nat). (1 <= dwIn) => (1 <= dwOut) => (1 <= n) => - (C.KnownNat n) => - (dwIn ~ n C.* dwOut) => - C.SNat dwIn -> - C.SNat dwOut -> + (KnownNat n) => + (dwIn ~ n * dwOut) => + SNat dwIn -> + SNat dwOut -> Property -generateDownConverterProperty C.SNat C.SNat = +generateDownConverterProperty SNat SNat = idWithModelSingleDomain defExpectOptions{eoSampleMax = 1000} (genValidPackets (Range.linear 1 8) (Range.linear 1 10) Abort) - (C.exposeClockResetEnable (upConvert . downConvert)) - (C.exposeClockResetEnable @C.System (downConverterC @dwIn @dwOut @Int)) + (exposeClockResetEnable (upConvert . downConvert)) + (exposeClockResetEnable @System (downConverterC @dwIn @dwOut @Int)) prop_downConverter8to4 :: Property -prop_downConverter8to4 = generateDownConverterProperty C.d8 C.d4 +prop_downConverter8to4 = generateDownConverterProperty d8 d4 prop_downConverter6to3 :: Property -prop_downConverter6to3 = generateDownConverterProperty C.d6 C.d3 +prop_downConverter6to3 = generateDownConverterProperty d6 d3 prop_downConverter4to2 :: Property -prop_downConverter4to2 = generateDownConverterProperty C.d4 C.d2 +prop_downConverter4to2 = generateDownConverterProperty d4 d2 prop_downConverter4to1 :: Property -prop_downConverter4to1 = generateDownConverterProperty C.d4 C.d1 +prop_downConverter4to1 = generateDownConverterProperty d4 d1 prop_downConverter2to1 :: Property -prop_downConverter2to1 = generateDownConverterProperty C.d2 C.d1 +prop_downConverter2to1 = generateDownConverterProperty d2 d1 prop_downConverter1to1 :: Property -prop_downConverter1to1 = generateDownConverterProperty C.d1 C.d1 +prop_downConverter1to1 = generateDownConverterProperty d1 d1 tests :: TestTree tests = diff --git a/clash-protocols/tests/Tests/Protocols/PacketStream/Delay.hs b/clash-protocols/tests/Tests/Protocols/PacketStream/Delay.hs index 8b1b3f35..65d19a5e 100644 --- a/clash-protocols/tests/Tests/Protocols/PacketStream/Delay.hs +++ b/clash-protocols/tests/Tests/Protocols/PacketStream/Delay.hs @@ -1,45 +1,38 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NumericUnderscores #-} -module Tests.Protocols.PacketStream.Delay where +module Tests.Protocols.PacketStream.Delay ( + tests, +) where --- base -import Prelude +import Clash.Prelude --- clash-prelude -import qualified Clash.Prelude as C - --- hedgehog import Hedgehog import qualified Hedgehog.Range as Range --- tasty import Test.Tasty import Test.Tasty.Hedgehog (HedgehogTestLimit (HedgehogTestLimit)) import Test.Tasty.Hedgehog.Extra (testProperty) import Test.Tasty.TH (testGroupGenerator) --- clash-protocols import Protocols import Protocols.Hedgehog import Protocols.PacketStream - --- tests -import Tests.Protocols.PacketStream.Base +import Protocols.PacketStream.Hedgehog prop_delaystream_id :: Property prop_delaystream_id = idWithModelSingleDomain - @C.System + @System defExpectOptions (genValidPackets (Range.linear 1 10) (Range.linear 1 6) Abort) - (C.exposeClockResetEnable id) - (C.exposeClockResetEnable ckt) + (exposeClockResetEnable id) + (exposeClockResetEnable ckt) where ckt :: - (C.HiddenClockResetEnable C.System) => - Circuit (PacketStream C.System 2 ()) (PacketStream C.System 2 ()) - ckt = delayStream @C.System @2 @() @4 C.d4 + (HiddenClockResetEnable System) => + Circuit (PacketStream System 2 ()) (PacketStream System 2 ()) + ckt = delayStream @System @2 @() @4 d4 tests :: TestTree tests = diff --git a/clash-protocols/tests/Tests/Protocols/PacketStream/Depacketizers.hs b/clash-protocols/tests/Tests/Protocols/PacketStream/Depacketizers.hs index be9572de..7988cc0e 100644 --- a/clash-protocols/tests/Tests/Protocols/PacketStream/Depacketizers.hs +++ b/clash-protocols/tests/Tests/Protocols/PacketStream/Depacketizers.hs @@ -2,108 +2,25 @@ {-# LANGUAGE NumericUnderscores #-} module Tests.Protocols.PacketStream.Depacketizers ( - depacketizerModel, - depacketizeToDfModel, tests, ) where --- base -import qualified Data.List as L -import Prelude - --- clash import Clash.Prelude -import Clash.Sized.Vector (unsafeFromList) --- hedgehog import Hedgehog import qualified Hedgehog.Range as Range --- tasty import Test.Tasty import Test.Tasty.Hedgehog (HedgehogTestLimit (HedgehogTestLimit)) import Test.Tasty.Hedgehog.Extra (testProperty) import Test.Tasty.TH (testGroupGenerator) --- clash-protocols -import Protocols.Hedgehog -import Protocols.PacketStream.Base - --- tests import Protocols +import Protocols.Hedgehog import Protocols.PacketStream (depacketizeToDfC, depacketizerC) -import Tests.Protocols.PacketStream.Base - --- | Model of the generic `depacketizerC`. -depacketizerModel :: - forall - (dataWidth :: Nat) - (headerBytes :: Nat) - (metaIn :: Type) - (metaOut :: Type) - (header :: Type). - ( KnownNat dataWidth - , KnownNat headerBytes - , 1 <= dataWidth - , 1 <= headerBytes - , BitPack header - , BitSize header ~ headerBytes * 8 - ) => - (header -> metaIn -> metaOut) -> - [PacketStreamM2S dataWidth metaIn] -> - [PacketStreamM2S dataWidth metaOut] -depacketizerModel toMetaOut ps = L.concat dataWidthPackets - where - hdrbytes = natToNum @headerBytes - - parseHdr :: - ([PacketStreamM2S 1 metaIn], [PacketStreamM2S 1 metaIn]) -> [PacketStreamM2S 1 metaOut] - parseHdr (hdrF, fwdF) = fmap (\f -> f{_meta = metaOut}) fwdF - where - hdr = bitCoerce $ unsafeFromList @headerBytes $ _data <$> hdrF - metaOut = toMetaOut hdr (_meta $ L.head fwdF) - - bytePackets :: [[PacketStreamM2S 1 metaIn]] - bytePackets = - L.filter (\fs -> L.length fs > hdrbytes) $ - L.concatMap chopPacket . smearAbort <$> chunkByPacket ps - - parsedPackets :: [[PacketStreamM2S 1 metaOut]] - parsedPackets = parseHdr . L.splitAt hdrbytes <$> bytePackets - - dataWidthPackets :: [[PacketStreamM2S dataWidth metaOut]] - dataWidthPackets = fmap chunkToPacket . chopBy (natToNum @dataWidth) <$> parsedPackets - --- | Model of the generic `depacketizeToDfC`. -depacketizeToDfModel :: - forall - (dataWidth :: Nat) - (headerBytes :: Nat) - (meta :: Type) - (a :: Type) - (header :: Type). - ( KnownNat dataWidth - , KnownNat headerBytes - , 1 <= dataWidth - , 1 <= headerBytes - , BitPack header - , BitSize header ~ headerBytes * 8 - ) => - (header -> meta -> a) -> - [PacketStreamM2S dataWidth meta] -> - [a] -depacketizeToDfModel toOut ps = parseHdr <$> bytePackets - where - hdrbytes = natToNum @headerBytes - - parseHdr :: [PacketStreamM2S 1 meta] -> a - parseHdr hdrF = toOut (bitCoerce $ unsafeFromList @headerBytes $ _data <$> hdrF) (_meta $ L.head hdrF) - - bytePackets :: [[PacketStreamM2S 1 meta]] - bytePackets = - L.filter (\fs -> L.length fs >= hdrbytes) $ - L.concatMap chopPacket <$> chunkByPacket (dropAbortedPackets ps) +import Protocols.PacketStream.Base +import Protocols.PacketStream.Hedgehog {- | Test the depacketizer with varying datawidth and number of bytes in the header, with metaIn = () and toMetaOut = const. diff --git a/clash-protocols/tests/Tests/Protocols/PacketStream/PacketFifo.hs b/clash-protocols/tests/Tests/Protocols/PacketStream/PacketFifo.hs index 53e8022b..175693e7 100644 --- a/clash-protocols/tests/Tests/Protocols/PacketStream/PacketFifo.hs +++ b/clash-protocols/tests/Tests/Protocols/PacketStream/PacketFifo.hs @@ -1,52 +1,38 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NumericUnderscores #-} -{-# LANGUAGE RecordWildCards #-} -module Tests.Protocols.PacketStream.PacketFifo where +module Tests.Protocols.PacketStream.PacketFifo ( + tests, +) where --- base -import Data.Int (Int16) -import Prelude +import Clash.Prelude --- clash-prelude -import Clash.Prelude hiding (drop, take, undefined, (++)) -import qualified Clash.Prelude as C +import Data.Int (Int16) +import qualified Data.List as L --- hedgehog import Hedgehog as H import qualified Hedgehog.Range as Range --- tasty import Test.Tasty import Test.Tasty.Hedgehog (HedgehogTestLimit (HedgehogTestLimit)) import Test.Tasty.Hedgehog.Extra (testProperty) import Test.Tasty.TH (testGroupGenerator) --- clash-protocols import Protocols import Protocols.Hedgehog import Protocols.PacketStream.Base +import Protocols.PacketStream.Hedgehog import Protocols.PacketStream.PacketFifo --- tests -import Tests.Protocols.PacketStream.Base as U - -isSubsequenceOf :: (Eq a) => [a] -> [a] -> Bool -isSubsequenceOf [] _ = True -isSubsequenceOf _ [] = False -isSubsequenceOf (x : xs) (y : ys) - | x == y = isSubsequenceOf xs ys - | otherwise = isSubsequenceOf xs (y : ys) - -- | test for id and proper dropping of aborted packets prop_packetFifo_id :: Property prop_packetFifo_id = idWithModelSingleDomain - @C.System + @System defExpectOptions{eoSampleMax = 1000, eoStopAfterEmpty = 1000} (genValidPackets (Range.linear 1 30) (Range.linear 1 10) Abort) - (C.exposeClockResetEnable dropAbortedPackets) - (C.exposeClockResetEnable ckt) + (exposeClockResetEnable dropAbortedPackets) + (exposeClockResetEnable ckt) where ckt :: (HiddenClockResetEnable System) => @@ -57,11 +43,11 @@ prop_packetFifo_id = prop_packetFifo_small_buffer_id :: Property prop_packetFifo_small_buffer_id = idWithModelSingleDomain - @C.System + @System defExpectOptions{eoSampleMax = 1000, eoStopAfterEmpty = 1000} (genValidPackets (Range.linear 1 10) (Range.linear 1 30) NoAbort) - (C.exposeClockResetEnable dropAbortedPackets) - (C.exposeClockResetEnable ckt) + (exposeClockResetEnable dropAbortedPackets) + (exposeClockResetEnable ckt) where ckt :: (HiddenClockResetEnable System) => @@ -87,7 +73,7 @@ prop_packetFifo_no_gaps = property $ do cfg = SimulationConfig 1 (2 * packetSize) False cktResult = simulateC ckt cfg (Just <$> packets) - assert $ noGaps $ take (5 * maxInputSize) cktResult + assert $ noGaps $ L.take (5 * maxInputSize) cktResult where noGaps :: [Maybe (PacketStreamM2S 4 Int16)] -> Bool noGaps (Just (PacketStreamM2S{_last = Nothing}) : Nothing : _) = False @@ -98,11 +84,11 @@ prop_packetFifo_no_gaps = property $ do prop_overFlowDrop_packetFifo_id :: Property prop_overFlowDrop_packetFifo_id = idWithModelSingleDomain - @C.System + @System defExpectOptions{eoSampleMax = 2000, eoStopAfterEmpty = 1000} (genValidPackets (Range.linear 1 30) (Range.linear 1 10) Abort) - (C.exposeClockResetEnable dropAbortedPackets) - (C.exposeClockResetEnable ckt) + (exposeClockResetEnable dropAbortedPackets) + (exposeClockResetEnable ckt) where ckt :: (HiddenClockResetEnable System) => @@ -113,12 +99,12 @@ prop_overFlowDrop_packetFifo_id = prop_overFlowDrop_packetFifo_drop :: Property prop_overFlowDrop_packetFifo_drop = idWithModelSingleDomain - @C.System + @System defExpectOptions{eoSampleMax = 1000, eoStopAfterEmpty = 1000} -- make sure the timeout is long as the packetFifo can be quiet for a while while dropping - (liftA3 (\a b c -> a ++ b ++ c) genSmall genBig genSmall) - (C.exposeClockResetEnable model) - (C.exposeClockResetEnable ckt) + (liftA3 (\a b c -> a L.++ b L.++ c) genSmall genBig genSmall) + (exposeClockResetEnable model) + (exposeClockResetEnable ckt) where ckt :: (HiddenClockResetEnable System) => @@ -126,7 +112,7 @@ prop_overFlowDrop_packetFifo_drop = ckt = packetFifoC d5 d5 Drop model :: [PacketStreamM2S 4 Int16] -> [PacketStreamM2S 4 Int16] - model packets = Prelude.concat $ take 1 packetChunk ++ drop 2 packetChunk + model packets = Prelude.concat $ L.take 1 packetChunk L.++ L.drop 2 packetChunk where packetChunk = chunkByPacket packets @@ -137,11 +123,11 @@ prop_overFlowDrop_packetFifo_drop = prop_packetFifo_small_metaBuffer :: Property prop_packetFifo_small_metaBuffer = idWithModelSingleDomain - @C.System + @System defExpectOptions (genValidPackets (Range.linear 1 30) (Range.linear 1 4) Abort) - (C.exposeClockResetEnable dropAbortedPackets) - (C.exposeClockResetEnable ckt) + (exposeClockResetEnable dropAbortedPackets) + (exposeClockResetEnable ckt) where ckt :: (HiddenClockResetEnable System) => diff --git a/clash-protocols/tests/Tests/Protocols/PacketStream/Packetizers.hs b/clash-protocols/tests/Tests/Protocols/PacketStream/Packetizers.hs index e85e0dec..9104ac1c 100644 --- a/clash-protocols/tests/Tests/Protocols/PacketStream/Packetizers.hs +++ b/clash-protocols/tests/Tests/Protocols/PacketStream/Packetizers.hs @@ -2,97 +2,27 @@ {-# LANGUAGE NumericUnderscores #-} module Tests.Protocols.PacketStream.Packetizers ( - packetizerModel, - packetizeFromDfModel, tests, ) where --- base -import qualified Data.List as L -import Prelude - --- clash +import Clash.Hedgehog.Sized.Vector (genVec) import Clash.Prelude --- hedgehog import Hedgehog import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range --- tasty import Test.Tasty import Test.Tasty.Hedgehog (HedgehogTestLimit (HedgehogTestLimit)) - import Test.Tasty.Hedgehog.Extra (testProperty) import Test.Tasty.TH (testGroupGenerator) --- clash-protocols import Protocols import qualified Protocols.Df as Df import Protocols.Hedgehog -import Protocols.PacketStream.Base - --- tests import Protocols.PacketStream (packetizeFromDfC, packetizerC) -import Tests.Protocols.PacketStream.Base - --- | Model of the generic `packetizerC`. -packetizerModel :: - forall - (dataWidth :: Nat) - (headerBytes :: Nat) - (metaIn :: Type) - (header :: Type) - (metaOut :: Type). - (KnownNat dataWidth) => - (KnownNat headerBytes) => - (1 <= dataWidth) => - (1 <= headerBytes) => - (BitPack header) => - (BitSize header ~ headerBytes * 8) => - (metaIn -> metaOut) -> - (metaIn -> header) -> - [PacketStreamM2S dataWidth metaIn] -> - [PacketStreamM2S dataWidth metaOut] -packetizerModel toMetaOut toHeader ps = L.concatMap (upConvert . prependHdr) bytePackets - where - prependHdr :: [PacketStreamM2S 1 metaIn] -> [PacketStreamM2S 1 metaOut] - prependHdr fragments = hdr L.++ L.map (\f -> f{_meta = metaOut}) fragments - where - h = L.head fragments - metaOut = toMetaOut (_meta h) - hdr = L.map go (toList $ bitCoerce (toHeader (_meta h))) - go byte = PacketStreamM2S (singleton byte) Nothing metaOut (_abort h) - - bytePackets :: [[PacketStreamM2S 1 metaIn]] - bytePackets = downConvert . smearAbort <$> chunkByPacket ps - --- | Model of the generic `packetizeFromDfC`. -packetizeFromDfModel :: - forall - (dataWidth :: Nat) - (headerBytes :: Nat) - (a :: Type) - (header :: Type) - (metaOut :: Type). - (KnownNat dataWidth) => - (KnownNat headerBytes) => - (1 <= dataWidth) => - (1 <= headerBytes) => - (BitPack header) => - (BitSize header ~ headerBytes * 8) => - (a -> metaOut) -> - (a -> header) -> - [a] -> - [PacketStreamM2S dataWidth metaOut] -packetizeFromDfModel toMetaOut toHeader = L.concatMap (upConvert . packetize) - where - packetize :: a -> [PacketStreamM2S 1 metaOut] - packetize d = - fullPackets $ - L.map - (\byte -> PacketStreamM2S (byte :> Nil) Nothing (toMetaOut d) False) - (toList $ bitCoerce (toHeader d)) +import Protocols.PacketStream.Base +import Protocols.PacketStream.Hedgehog {- | Test the packetizer with varying datawidth and number of bytes in the header, with metaOut = (). @@ -114,7 +44,7 @@ packetizerPropertyGenerator SNat SNat = (exposeClockResetEnable model) (exposeClockResetEnable ckt) where - model = packetizerModel (const ()) id + model = packetize (const ()) id ckt :: (HiddenClockResetEnable System) => Circuit @@ -158,7 +88,7 @@ packetizeFromDfPropertyGenerator SNat SNat = (exposeClockResetEnable model) (exposeClockResetEnable ckt) where - model = packetizeFromDfModel (const ()) id + model = packetizeFromDf (const ()) id ckt :: (HiddenClockResetEnable System) => Circuit (Df.Df System (Vec headerBytes (BitVector 8))) (PacketStream System dataWidth ()) diff --git a/clash-protocols/tests/Tests/Protocols/PacketStream/Routing.hs b/clash-protocols/tests/Tests/Protocols/PacketStream/Routing.hs index 26bb410e..96e9f110 100644 --- a/clash-protocols/tests/Tests/Protocols/PacketStream/Routing.hs +++ b/clash-protocols/tests/Tests/Protocols/PacketStream/Routing.hs @@ -1,53 +1,42 @@ -{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NumericUnderscores #-} -{-# LANGUAGE RecordWildCards #-} -module Tests.Protocols.PacketStream.Routing where +module Tests.Protocols.PacketStream.Routing ( + tests, +) where --- base -import Data.List (groupBy, sortOn) -import Prelude - --- clash-prelude -import Clash.Prelude (type (<=)) +import Clash.Prelude import qualified Clash.Prelude as C --- hedgehog import Hedgehog hiding (Parallel) import qualified Hedgehog.Range as Range --- tasty import Test.Tasty import Test.Tasty.Hedgehog (HedgehogTestLimit (HedgehogTestLimit)) import Test.Tasty.Hedgehog.Extra (testProperty) import Test.Tasty.TH (testGroupGenerator) --- clash-protocols - import Protocols.Hedgehog import Protocols.PacketStream.Base +import Protocols.PacketStream.Hedgehog import Protocols.PacketStream.Routing --- tests -import Tests.Protocols.PacketStream.Base - import qualified Data.List as L -- | Tests the round-robin packet arbiter with one source; essentially an id test prop_packetarbiter_roundrobin_id :: Property -prop_packetarbiter_roundrobin_id = makePropPacketArbiter C.d1 C.d2 RoundRobin +prop_packetarbiter_roundrobin_id = makePropPacketArbiter d1 d2 RoundRobin -- | Tests the parallel packet arbiter with one source; essentially an id test prop_packetarbiter_parallel_id :: Property -prop_packetarbiter_parallel_id = makePropPacketArbiter C.d1 C.d2 Parallel +prop_packetarbiter_parallel_id = makePropPacketArbiter d1 d2 Parallel -- Tests the round-robin arbiter with five sources prop_packetarbiter_roundrobin :: Property -prop_packetarbiter_roundrobin = makePropPacketArbiter C.d5 C.d2 RoundRobin +prop_packetarbiter_roundrobin = makePropPacketArbiter d5 d2 RoundRobin -- Tests the parallel arbiter with five sources prop_packetarbiter_parallel :: Property -prop_packetarbiter_parallel = makePropPacketArbiter C.d5 C.d2 Parallel +prop_packetarbiter_parallel = makePropPacketArbiter d5 d2 Parallel {- | Tests a packet arbiter for any data width and number of sources. In particular, tests that packets from all sources are sent out unmodified in the same order @@ -55,32 +44,32 @@ they were in in the source streams. -} makePropPacketArbiter :: forall p n. - ( C.KnownNat p + ( KnownNat p , 1 <= p - , C.KnownNat n + , KnownNat n , 1 <= n ) => - C.SNat p -> - C.SNat n -> + SNat p -> + SNat n -> ArbiterMode -> Property makePropPacketArbiter _ _ mode = propWithModelSingleDomain - @C.System + @System defExpectOptions{eoSampleMax = 1000} genSources - (C.exposeClockResetEnable concat) - (C.exposeClockResetEnable (packetArbiterC mode)) + (exposeClockResetEnable L.concat) + (exposeClockResetEnable (packetArbiterC mode)) (\xs ys -> partitionPackets xs === partitionPackets ys) where - genSources = mapM setMeta (C.indicesI @p) + genSources = mapM setMeta (indicesI @p) setMeta j = do pkts <- genValidPackets @n @() (Range.linear 1 10) (Range.linear 1 10) Abort pure $ L.map (\pkt -> pkt{_meta = j}) pkts partitionPackets packets = - sortOn (_meta . head . head) $ - groupBy (\a b -> _meta a == _meta b) <$> chunkByPacket packets + L.sortOn (_meta . L.head . L.head) $ + L.groupBy (\a b -> _meta a == _meta b) <$> chunkByPacket packets {- | Tests that the packet dispatcher works correctly with one sink that accepts all packets; essentially an id test. @@ -88,8 +77,8 @@ all packets; essentially an id test. prop_packetdispatcher_id :: Property prop_packetdispatcher_id = makePropPacketDispatcher - C.d4 - ((const True :: Int -> Bool) C.:> C.Nil) + d4 + ((const True :: Int -> Bool) :> Nil) {- | Tests the packet dispatcher for a data width of four bytes and three overlapping but incomplete dispatch functions, effectively testing whether @@ -97,43 +86,43 @@ the circuit sends input to the first allowed output channel and drops input if there are none. -} prop_packetdispatcher :: Property -prop_packetdispatcher = makePropPacketDispatcher C.d4 fs +prop_packetdispatcher = makePropPacketDispatcher d4 fs where - fs :: C.Vec 3 (C.Index 4 -> Bool) + fs :: Vec 3 (Index 4 -> Bool) fs = (>= 3) - C.:> (>= 2) - C.:> (>= 1) - C.:> C.Nil + :> (>= 2) + :> (>= 1) + :> Nil {- | Generic test function for the packet dispatcher, testing for all data widths, dispatch functions, and some meta types -} makePropPacketDispatcher :: - forall (p :: C.Nat) (dataWidth :: C.Nat) (a :: C.Type). - ( C.KnownNat p + forall (p :: Nat) (dataWidth :: Nat) (a :: Type). + ( KnownNat p , 1 <= p - , C.KnownNat dataWidth + , KnownNat dataWidth , 1 <= dataWidth , TestType a , Bounded a - , C.BitPack a + , BitPack a ) => - C.SNat dataWidth -> - C.Vec p (a -> Bool) -> + SNat dataWidth -> + Vec p (a -> Bool) -> Property makePropPacketDispatcher _ fs = - idWithModelSingleDomain @C.System + idWithModelSingleDomain @System defExpectOptions{eoSampleMax = 2000, eoStopAfterEmpty = 1000} (genValidPackets (Range.linear 1 10) (Range.linear 1 6) Abort) - (C.exposeClockResetEnable (model 0)) - (C.exposeClockResetEnable (packetDispatcherC fs)) + (exposeClockResetEnable (model 0)) + (exposeClockResetEnable (packetDispatcherC fs)) where model :: - C.Index p -> [PacketStreamM2S dataWidth a] -> C.Vec p [PacketStreamM2S dataWidth a] + Index p -> [PacketStreamM2S dataWidth a] -> Vec p [PacketStreamM2S dataWidth a] model _ [] = pure [] model i (y : ys) - | (fs C.!! i) (_meta y) = let next = model 0 ys in C.replace i (y : (next C.!! i)) next + | (fs C.!! i) (_meta y) = let next = model 0 ys in replace i (y : (next C.!! i)) next | i < maxBound = model (i + 1) (y : ys) | otherwise = model 0 ys