From e9be448bbd3fed1d480cee89560f897b9e5be125 Mon Sep 17 00:00:00 2001 From: Lucas Bollen Date: Thu, 11 Jan 2024 14:03:54 +0100 Subject: [PATCH 1/4] Change `Example.Project` to contain a better example Co-authored-by: Peter Lebbing --- deca.hsfiles | 1 + projects/simple-nix/nix/nixpkgs.nix | 2 + projects/simple-nix/stack.yaml | 9 +- projects/simple-nix/{{name}}.cabal | 1 + projects/simple/src/Example/Project.hs | 63 +++++++--- projects/simple/stack.yaml | 1 + .../simple/tests/Tests/Example/Project.hs | 44 +++++-- projects/simple/tests/unittests.hs | 2 +- projects/simple/{{name}}.cabal | 1 + simple-nix.hsfiles | 115 ++++++++++++++---- simple.hsfiles | 113 +++++++++++++---- 11 files changed, 267 insertions(+), 85 deletions(-) mode change 100644 => 120000 projects/simple-nix/stack.yaml diff --git a/deca.hsfiles b/deca.hsfiles index 3d4faeb..12e8499 100644 --- a/deca.hsfiles +++ b/deca.hsfiles @@ -605,6 +605,7 @@ extra-deps: - clash-ghc-1.8.1@sha256:3bab304fa5584f3541650bddd01160f2710b9ced52e52c06481a91ac73d71bb8,9753 - clash-lib-1.8.1@sha256:17d78e786dedf16a76394cd5813372870a3d70a1a4c7f964309f126b800e90f6,15693 - clash-prelude-1.8.1@sha256:c3fbb9f6b8e74140fb3d5c4d59ec84cfe4a53e9f8520e606c187cfc04b149065,17626 +- clash-prelude-hedgehog-1.8.1@sha256:9ec3aa3f8195481f5ce4942b34a49c97dd132dd1c8f1fa58aeecbd82c2602e86,1410 - concurrent-supply-0.1.8@sha256:80b658533141660818d0781b8c8fb9a8cf69b987fcfbab782dc788bfc7df4846,1627 - prettyprinter-interp-0.2.0.0@sha256:69c339a95b265dab9b3478ca19ec96952b6b472bd0ff6e2127112a9562362c1d,2086 diff --git a/projects/simple-nix/nix/nixpkgs.nix b/projects/simple-nix/nix/nixpkgs.nix index 86427c3..1d4cb91 100644 --- a/projects/simple-nix/nix/nixpkgs.nix +++ b/projects/simple-nix/nix/nixpkgs.nix @@ -19,6 +19,8 @@ let self.callCabal2nix "clash-lib" (sources.clash-compiler + "/clash-lib") {}; clash-ghc = self.callCabal2nix "clash-ghc" (sources.clash-compiler + "/clash-ghc") {}; + clash-prelude-hedgehog = + self.callCabal2nix "clash-prelude" (sources.clash-compiler + "/clash-prelude-hedgehog") {}; tasty-hedgehog = self.callCabal2nix "tasty-hedgehog" sources.tasty-hedgehog {}; hedgehog = diff --git a/projects/simple-nix/stack.yaml b/projects/simple-nix/stack.yaml deleted file mode 100644 index 1139fe6..0000000 --- a/projects/simple-nix/stack.yaml +++ /dev/null @@ -1,8 +0,0 @@ -resolver: lts-21.20 - -extra-deps: -- clash-ghc-1.8.1@sha256:3bab304fa5584f3541650bddd01160f2710b9ced52e52c06481a91ac73d71bb8,9753 -- clash-lib-1.8.1@sha256:17d78e786dedf16a76394cd5813372870a3d70a1a4c7f964309f126b800e90f6,15693 -- clash-prelude-1.8.1@sha256:c3fbb9f6b8e74140fb3d5c4d59ec84cfe4a53e9f8520e606c187cfc04b149065,17626 -- concurrent-supply-0.1.8@sha256:80b658533141660818d0781b8c8fb9a8cf69b987fcfbab782dc788bfc7df4846,1627 -- prettyprinter-interp-0.2.0.0@sha256:69c339a95b265dab9b3478ca19ec96952b6b472bd0ff6e2127112a9562362c1d,2086 diff --git a/projects/simple-nix/stack.yaml b/projects/simple-nix/stack.yaml new file mode 120000 index 0000000..e4e2fdf --- /dev/null +++ b/projects/simple-nix/stack.yaml @@ -0,0 +1 @@ +../simple/stack.yaml \ No newline at end of file diff --git a/projects/simple-nix/{{name}}.cabal b/projects/simple-nix/{{name}}.cabal index 1375f4e..9fd7a77 100644 --- a/projects/simple-nix/{{name}}.cabal +++ b/projects/simple-nix/{{name}}.cabal @@ -120,6 +120,7 @@ test-suite test-library build-depends: {{name}}, QuickCheck, + clash-prelude-hedgehog, hedgehog, tasty >= 1.2 && < 1.5, tasty-hedgehog, diff --git a/projects/simple/src/Example/Project.hs b/projects/simple/src/Example/Project.hs index 6b67e59..22e4be4 100644 --- a/projects/simple/src/Example/Project.hs +++ b/projects/simple/src/Example/Project.hs @@ -1,19 +1,54 @@ -module Example.Project (topEntity, plus) where +-- @createDomain@ below generates a warning about orphan instances, but we like +-- our code to be warning-free. +{-# OPTIONS_GHC -Wno-orphans #-} + +module Example.Project where import Clash.Prelude --- | Add two numbers. Example: +-- Create a domain with the frequency of your input clock. For this example we used +-- 50 MHz. +createDomain vSystem{vName="Dom50", vPeriod=hzToPeriod 50e6} + +-- | @topEntity@ is Clash@s equivalent of @main@ in other programming languages. +-- Clash will look for it when compiling "Example.Project" and translate it to +-- HDL. While polymorphism can be used freely in Clash projects, a @topEntity@ +-- must be monomorphic and must use non- recursive types. Or, to put it +-- hand-wavily, a @topEntity@ must be translatable to a static number of wires. -- --- >>> plus 3 5 --- 8 -plus :: Signed 8 -> Signed 8 -> Signed 8 -plus a b = a + b +-- Top entities must be monomorphic, meaning we have to specify all type variables. +-- In this case, we are using the @Dom50@ domain, which we created with @createDomain@ +-- and we are using 8-bit unsigned numbers. +topEntity :: + Clock Dom50 -> + Reset Dom50 -> + Enable Dom50 -> + Signal Dom50 (Unsigned 8) -> + Signal Dom50 (Unsigned 8) +topEntity = exposeClockResetEnable accum + +-- To specify the names of the ports of our top entity, we create a @Synthesize@ annotation. +{-# ANN topEntity + (Synthesize + { t_name = "accum" + , t_inputs = [ PortName "CLK" + , PortName "RST" + , PortName "EN" + , PortName "DIN" + ] + , t_output = PortName "DOUT" + }) #-} + +-- Make sure GHC does not apply any optimizations to the boundaries of the design. +-- For GHC versions 9.2 or older, use: {-# NOINLINE topEntity #-} +{-# OPAQUE topEntity #-} --- | 'topEntity' is Clash's equivalent of 'main' in other programming --- languages. Clash will look for it when compiling 'Example.Project' --- and translate it to HDL. While polymorphism can be used freely in --- Clash projects, a 'topEntity' must be monomorphic and must use non- --- recursive types. Or, to put it hand-wavily, a 'topEntity' must be --- translatable to a static number of wires. -topEntity :: Signed 8 -> Signed 8 -> Signed 8 -topEntity = plus +-- | A simple accumulator that works on unsigned numbers of any size. +-- It has hidden clock, reset, and enable signals. +accum :: + (HiddenClockResetEnable dom, KnownNat n) => + Signal dom (Unsigned n) -> + Signal dom (Unsigned n) +accum = mealy accumT 0 + where + accumT s i = (s + i, s) diff --git a/projects/simple/stack.yaml b/projects/simple/stack.yaml index 1139fe6..58702d5 100644 --- a/projects/simple/stack.yaml +++ b/projects/simple/stack.yaml @@ -4,5 +4,6 @@ extra-deps: - clash-ghc-1.8.1@sha256:3bab304fa5584f3541650bddd01160f2710b9ced52e52c06481a91ac73d71bb8,9753 - clash-lib-1.8.1@sha256:17d78e786dedf16a76394cd5813372870a3d70a1a4c7f964309f126b800e90f6,15693 - clash-prelude-1.8.1@sha256:c3fbb9f6b8e74140fb3d5c4d59ec84cfe4a53e9f8520e606c187cfc04b149065,17626 +- clash-prelude-hedgehog-1.8.1@sha256:9ec3aa3f8195481f5ce4942b34a49c97dd132dd1c8f1fa58aeecbd82c2602e86,1410 - concurrent-supply-0.1.8@sha256:80b658533141660818d0781b8c8fb9a8cf69b987fcfbab782dc788bfc7df4846,1627 - prettyprinter-interp-0.2.0.0@sha256:69c339a95b265dab9b3478ca19ec96952b6b472bd0ff6e2127112a9562362c1d,2086 diff --git a/projects/simple/tests/Tests/Example/Project.hs b/projects/simple/tests/Tests/Example/Project.hs index dcce6a3..cb05a8a 100644 --- a/projects/simple/tests/Tests/Example/Project.hs +++ b/projects/simple/tests/Tests/Example/Project.hs @@ -2,25 +2,49 @@ module Tests.Example.Project where import Prelude +import Clash.Hedgehog.Sized.Unsigned import Test.Tasty import Test.Tasty.TH import Test.Tasty.Hedgehog -import Hedgehog ((===)) +import qualified Clash.Prelude as C import qualified Hedgehog as H import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range -import Example.Project (plus) +-- Import the module containing the @accum@ function +import Example.Project (accum) -prop_plusIsCommutative :: H.Property -prop_plusIsCommutative = H.property $ do - a <- H.forAll (Gen.integral (Range.linear minBound maxBound)) - b <- H.forAll (Gen.integral (Range.linear minBound maxBound)) - plus a b === plus b a +-- Define a Hedgehog property to test the @accum@ function +prop_accum :: H.Property +prop_accum = H.property $ do -tests :: TestTree -tests = $(testGroupGenerator) + -- Simulate for a random duration between 1 and 100 cycles + simDuration <- H.forAll (Gen.integral (Range.linear 1 100)) + + -- Generate a list of random unsigned numbers. + inp <- H.forAll + (Gen.list (Range.singleton simDuration) + (genUnsigned Range.linearBounded)) + let + + -- Simulate the @accum@ function for the pre-existing @System@ domain + -- and 8 bit unsigned numbers. + -- + -- The (hidden) reset input of @accum@ will be asserted in the first cycle; + -- during this cycle it will emit its initial value and the input is + -- ignored. So we need to present a dummy input value. + simOut = C.sampleN (simDuration + 1) (accum @C.System @8 (C.fromList (0:inp))) + -- Calculate the expected output. The first cycle is the initial value, and + -- the result of the final input value does not appear because the + -- accumulator has 1 cycle latency. + expected = 0 : init (scanl (+) 0 inp) + + -- Check that the simulated output matches the expected output + simOut H.=== expected + +accumTests :: TestTree +accumTests = $(testGroupGenerator) main :: IO () -main = defaultMain tests +main = defaultMain accumTests diff --git a/projects/simple/tests/unittests.hs b/projects/simple/tests/unittests.hs index bb3fa79..45055bc 100644 --- a/projects/simple/tests/unittests.hs +++ b/projects/simple/tests/unittests.hs @@ -6,5 +6,5 @@ import qualified Tests.Example.Project main :: IO () main = defaultMain $ testGroup "." - [ Tests.Example.Project.tests + [ Tests.Example.Project.accumTests ] diff --git a/projects/simple/{{name}}.cabal b/projects/simple/{{name}}.cabal index 65b0407..c1af69f 100644 --- a/projects/simple/{{name}}.cabal +++ b/projects/simple/{{name}}.cabal @@ -124,6 +124,7 @@ test-suite test-library build-depends: {{name}}, QuickCheck, + clash-prelude-hedgehog, hedgehog, tasty >= 1.2 && < 1.5, tasty-hedgehog, diff --git a/simple-nix.hsfiles b/simple-nix.hsfiles index 9efce31..cd60d48 100644 --- a/simple-nix.hsfiles +++ b/simple-nix.hsfiles @@ -167,6 +167,8 @@ let self.callCabal2nix "clash-lib" (sources.clash-compiler + "/clash-lib") {}; clash-ghc = self.callCabal2nix "clash-ghc" (sources.clash-compiler + "/clash-ghc") {}; + clash-prelude-hedgehog = + self.callCabal2nix "clash-prelude" (sources.clash-compiler + "/clash-prelude-hedgehog") {}; tasty-hedgehog = self.callCabal2nix "tasty-hedgehog" sources.tasty-hedgehog {}; hedgehog = @@ -492,25 +494,60 @@ pkgs.stdenv.mkDerivation { } {-# START_FILE src/Example/Project.hs #-} -module Example.Project (topEntity, plus) where +-- @createDomain@ below generates a warning about orphan instances, but we like +-- our code to be warning-free. +{-# OPTIONS_GHC -Wno-orphans #-} + +module Example.Project where import Clash.Prelude --- | Add two numbers. Example: +-- Create a domain with the frequency of your input clock. For this example we used +-- 50 MHz. +createDomain vSystem{vName="Dom50", vPeriod=hzToPeriod 50e6} + +-- | @topEntity@ is Clash@s equivalent of @main@ in other programming languages. +-- Clash will look for it when compiling "Example.Project" and translate it to +-- HDL. While polymorphism can be used freely in Clash projects, a @topEntity@ +-- must be monomorphic and must use non- recursive types. Or, to put it +-- hand-wavily, a @topEntity@ must be translatable to a static number of wires. -- --- >>> plus 3 5 --- 8 -plus :: Signed 8 -> Signed 8 -> Signed 8 -plus a b = a + b - --- | 'topEntity' is Clash's equivalent of 'main' in other programming --- languages. Clash will look for it when compiling 'Example.Project' --- and translate it to HDL. While polymorphism can be used freely in --- Clash projects, a 'topEntity' must be monomorphic and must use non- --- recursive types. Or, to put it hand-wavily, a 'topEntity' must be --- translatable to a static number of wires. -topEntity :: Signed 8 -> Signed 8 -> Signed 8 -topEntity = plus +-- Top entities must be monomorphic, meaning we have to specify all type variables. +-- In this case, we are using the @Dom50@ domain, which we created with @createDomain@ +-- and we are using 8-bit unsigned numbers. +topEntity :: + Clock Dom50 -> + Reset Dom50 -> + Enable Dom50 -> + Signal Dom50 (Unsigned 8) -> + Signal Dom50 (Unsigned 8) +topEntity = exposeClockResetEnable accum + +-- To specify the names of the ports of our top entity, we create a @Synthesize@ annotation. +{-# ANN topEntity + (Synthesize + { t_name = "accum" + , t_inputs = [ PortName "CLK" + , PortName "RST" + , PortName "EN" + , PortName "DIN" + ] + , t_output = PortName "DOUT" + }) #-} + +-- Make sure GHC does not apply any optimizations to the boundaries of the design. +-- For GHC versions 9.2 or older, use: {-# NOINLINE topEntity #-} +{-# OPAQUE topEntity #-} + +-- | A simple accumulator that works on unsigned numbers of any size. +-- It has hidden clock, reset, and enable signals. +accum :: + (HiddenClockResetEnable dom, KnownNat n) => + Signal dom (Unsigned n) -> + Signal dom (Unsigned n) +accum = mealy accumT 0 + where + accumT s i = (s + i, s) {-# START_FILE stack.yaml #-} resolver: lts-21.20 @@ -519,6 +556,7 @@ extra-deps: - clash-ghc-1.8.1@sha256:3bab304fa5584f3541650bddd01160f2710b9ced52e52c06481a91ac73d71bb8,9753 - clash-lib-1.8.1@sha256:17d78e786dedf16a76394cd5813372870a3d70a1a4c7f964309f126b800e90f6,15693 - clash-prelude-1.8.1@sha256:c3fbb9f6b8e74140fb3d5c4d59ec84cfe4a53e9f8520e606c187cfc04b149065,17626 +- clash-prelude-hedgehog-1.8.1@sha256:9ec3aa3f8195481f5ce4942b34a49c97dd132dd1c8f1fa58aeecbd82c2602e86,1410 - concurrent-supply-0.1.8@sha256:80b658533141660818d0781b8c8fb9a8cf69b987fcfbab782dc788bfc7df4846,1627 - prettyprinter-interp-0.2.0.0@sha256:69c339a95b265dab9b3478ca19ec96952b6b472bd0ff6e2127112a9562362c1d,2086 @@ -527,28 +565,52 @@ module Tests.Example.Project where import Prelude +import Clash.Hedgehog.Sized.Unsigned import Test.Tasty import Test.Tasty.TH import Test.Tasty.Hedgehog -import Hedgehog ((===)) +import qualified Clash.Prelude as C import qualified Hedgehog as H import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range -import Example.Project (plus) +-- Import the module containing the @accum@ function +import Example.Project (accum) + +-- Define a Hedgehog property to test the @accum@ function +prop_accum :: H.Property +prop_accum = H.property $ do + + -- Simulate for a random duration between 1 and 100 cycles + simDuration <- H.forAll (Gen.integral (Range.linear 1 100)) + + -- Generate a list of random unsigned numbers. + inp <- H.forAll + (Gen.list (Range.singleton simDuration) + (genUnsigned Range.linearBounded)) + let + + -- Simulate the @accum@ function for the pre-existing @System@ domain + -- and 8 bit unsigned numbers. + -- + -- The (hidden) reset input of @accum@ will be asserted in the first cycle; + -- during this cycle it will emit its initial value and the input is + -- ignored. So we need to present a dummy input value. + simOut = C.sampleN (simDuration + 1) (accum @C.System @8 (C.fromList (0:inp))) + -- Calculate the expected output. The first cycle is the initial value, and + -- the result of the final input value does not appear because the + -- accumulator has 1 cycle latency. + expected = 0 : init (scanl (+) 0 inp) -prop_plusIsCommutative :: H.Property -prop_plusIsCommutative = H.property $ do - a <- H.forAll (Gen.integral (Range.linear minBound maxBound)) - b <- H.forAll (Gen.integral (Range.linear minBound maxBound)) - plus a b === plus b a + -- Check that the simulated output matches the expected output + simOut H.=== expected -tests :: TestTree -tests = $(testGroupGenerator) +accumTests :: TestTree +accumTests = $(testGroupGenerator) main :: IO () -main = defaultMain tests +main = defaultMain accumTests {-# START_FILE tests/doctests.hs #-} module Main where @@ -569,7 +631,7 @@ import qualified Tests.Example.Project main :: IO () main = defaultMain $ testGroup "." - [ Tests.Example.Project.tests + [ Tests.Example.Project.accumTests ] {-# START_FILE {{name}}.cabal #-} @@ -695,6 +757,7 @@ test-suite test-library build-depends: {{name}}, QuickCheck, + clash-prelude-hedgehog, hedgehog, tasty >= 1.2 && < 1.5, tasty-hedgehog, diff --git a/simple.hsfiles b/simple.hsfiles index 945823a..c3838fe 100644 --- a/simple.hsfiles +++ b/simple.hsfiles @@ -428,25 +428,60 @@ cradle: component: "{{ name }}:exe:clash" {-# START_FILE src/Example/Project.hs #-} -module Example.Project (topEntity, plus) where +-- @createDomain@ below generates a warning about orphan instances, but we like +-- our code to be warning-free. +{-# OPTIONS_GHC -Wno-orphans #-} + +module Example.Project where import Clash.Prelude --- | Add two numbers. Example: --- --- >>> plus 3 5 --- 8 -plus :: Signed 8 -> Signed 8 -> Signed 8 -plus a b = a + b +-- Create a domain with the frequency of your input clock. For this example we used +-- 50 MHz. +createDomain vSystem{vName="Dom50", vPeriod=hzToPeriod 50e6} --- | 'topEntity' is Clash's equivalent of 'main' in other programming --- languages. Clash will look for it when compiling 'Example.Project' --- and translate it to HDL. While polymorphism can be used freely in --- Clash projects, a 'topEntity' must be monomorphic and must use non- --- recursive types. Or, to put it hand-wavily, a 'topEntity' must be --- translatable to a static number of wires. -topEntity :: Signed 8 -> Signed 8 -> Signed 8 -topEntity = plus +-- | @topEntity@ is Clash@s equivalent of @main@ in other programming languages. +-- Clash will look for it when compiling "Example.Project" and translate it to +-- HDL. While polymorphism can be used freely in Clash projects, a @topEntity@ +-- must be monomorphic and must use non- recursive types. Or, to put it +-- hand-wavily, a @topEntity@ must be translatable to a static number of wires. +-- +-- Top entities must be monomorphic, meaning we have to specify all type variables. +-- In this case, we are using the @Dom50@ domain, which we created with @createDomain@ +-- and we are using 8-bit unsigned numbers. +topEntity :: + Clock Dom50 -> + Reset Dom50 -> + Enable Dom50 -> + Signal Dom50 (Unsigned 8) -> + Signal Dom50 (Unsigned 8) +topEntity = exposeClockResetEnable accum + +-- To specify the names of the ports of our top entity, we create a @Synthesize@ annotation. +{-# ANN topEntity + (Synthesize + { t_name = "accum" + , t_inputs = [ PortName "CLK" + , PortName "RST" + , PortName "EN" + , PortName "DIN" + ] + , t_output = PortName "DOUT" + }) #-} + +-- Make sure GHC does not apply any optimizations to the boundaries of the design. +-- For GHC versions 9.2 or older, use: {-# NOINLINE topEntity #-} +{-# OPAQUE topEntity #-} + +-- | A simple accumulator that works on unsigned numbers of any size. +-- It has hidden clock, reset, and enable signals. +accum :: + (HiddenClockResetEnable dom, KnownNat n) => + Signal dom (Unsigned n) -> + Signal dom (Unsigned n) +accum = mealy accumT 0 + where + accumT s i = (s + i, s) {-# START_FILE stack.yaml #-} resolver: lts-21.20 @@ -455,6 +490,7 @@ extra-deps: - clash-ghc-1.8.1@sha256:3bab304fa5584f3541650bddd01160f2710b9ced52e52c06481a91ac73d71bb8,9753 - clash-lib-1.8.1@sha256:17d78e786dedf16a76394cd5813372870a3d70a1a4c7f964309f126b800e90f6,15693 - clash-prelude-1.8.1@sha256:c3fbb9f6b8e74140fb3d5c4d59ec84cfe4a53e9f8520e606c187cfc04b149065,17626 +- clash-prelude-hedgehog-1.8.1@sha256:9ec3aa3f8195481f5ce4942b34a49c97dd132dd1c8f1fa58aeecbd82c2602e86,1410 - concurrent-supply-0.1.8@sha256:80b658533141660818d0781b8c8fb9a8cf69b987fcfbab782dc788bfc7df4846,1627 - prettyprinter-interp-0.2.0.0@sha256:69c339a95b265dab9b3478ca19ec96952b6b472bd0ff6e2127112a9562362c1d,2086 @@ -463,28 +499,52 @@ module Tests.Example.Project where import Prelude +import Clash.Hedgehog.Sized.Unsigned import Test.Tasty import Test.Tasty.TH import Test.Tasty.Hedgehog -import Hedgehog ((===)) +import qualified Clash.Prelude as C import qualified Hedgehog as H import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range -import Example.Project (plus) +-- Import the module containing the @accum@ function +import Example.Project (accum) -prop_plusIsCommutative :: H.Property -prop_plusIsCommutative = H.property $ do - a <- H.forAll (Gen.integral (Range.linear minBound maxBound)) - b <- H.forAll (Gen.integral (Range.linear minBound maxBound)) - plus a b === plus b a +-- Define a Hedgehog property to test the @accum@ function +prop_accum :: H.Property +prop_accum = H.property $ do -tests :: TestTree -tests = $(testGroupGenerator) + -- Simulate for a random duration between 1 and 100 cycles + simDuration <- H.forAll (Gen.integral (Range.linear 1 100)) + + -- Generate a list of random unsigned numbers. + inp <- H.forAll + (Gen.list (Range.singleton simDuration) + (genUnsigned Range.linearBounded)) + let + + -- Simulate the @accum@ function for the pre-existing @System@ domain + -- and 8 bit unsigned numbers. + -- + -- The (hidden) reset input of @accum@ will be asserted in the first cycle; + -- during this cycle it will emit its initial value and the input is + -- ignored. So we need to present a dummy input value. + simOut = C.sampleN (simDuration + 1) (accum @C.System @8 (C.fromList (0:inp))) + -- Calculate the expected output. The first cycle is the initial value, and + -- the result of the final input value does not appear because the + -- accumulator has 1 cycle latency. + expected = 0 : init (scanl (+) 0 inp) + + -- Check that the simulated output matches the expected output + simOut H.=== expected + +accumTests :: TestTree +accumTests = $(testGroupGenerator) main :: IO () -main = defaultMain tests +main = defaultMain accumTests {-# START_FILE tests/doctests.hs #-} module Main where @@ -505,7 +565,7 @@ import qualified Tests.Example.Project main :: IO () main = defaultMain $ testGroup "." - [ Tests.Example.Project.tests + [ Tests.Example.Project.accumTests ] {-# START_FILE {{name}}.cabal #-} @@ -635,6 +695,7 @@ test-suite test-library build-depends: {{name}}, QuickCheck, + clash-prelude-hedgehog, hedgehog, tasty >= 1.2 && < 1.5, tasty-hedgehog, From b3cd6aca97e4e982f0f750a5080ea15671928492 Mon Sep 17 00:00:00 2001 From: Lucas Bollen Date: Thu, 11 Jan 2024 14:04:21 +0100 Subject: [PATCH 2/4] Add FlexibleContexts, NamedFieldPuns, RecordWildCards --- projects/simple-nix/{{name}}.cabal | 3 +++ projects/simple/{{name}}.cabal | 3 +++ simple-nix.hsfiles | 3 +++ simple.hsfiles | 3 +++ 4 files changed, 12 insertions(+) diff --git a/projects/simple-nix/{{name}}.cabal b/projects/simple-nix/{{name}}.cabal index 9fd7a77..1233aa4 100644 --- a/projects/simple-nix/{{name}}.cabal +++ b/projects/simple-nix/{{name}}.cabal @@ -20,12 +20,15 @@ common common-options DeriveLift DeriveTraversable DerivingStrategies + FlexibleContexts InstanceSigs KindSignatures LambdaCase + NamedFieldPuns NoStarIsType PolyKinds RankNTypes + RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections diff --git a/projects/simple/{{name}}.cabal b/projects/simple/{{name}}.cabal index c1af69f..e4f7dbf 100644 --- a/projects/simple/{{name}}.cabal +++ b/projects/simple/{{name}}.cabal @@ -20,12 +20,15 @@ common common-options DeriveLift DeriveTraversable DerivingStrategies + FlexibleContexts InstanceSigs KindSignatures LambdaCase + NamedFieldPuns NoStarIsType PolyKinds RankNTypes + RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections diff --git a/simple-nix.hsfiles b/simple-nix.hsfiles index cd60d48..07f6c2e 100644 --- a/simple-nix.hsfiles +++ b/simple-nix.hsfiles @@ -657,12 +657,15 @@ common common-options DeriveLift DeriveTraversable DerivingStrategies + FlexibleContexts InstanceSigs KindSignatures LambdaCase + NamedFieldPuns NoStarIsType PolyKinds RankNTypes + RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections diff --git a/simple.hsfiles b/simple.hsfiles index c3838fe..63eecf2 100644 --- a/simple.hsfiles +++ b/simple.hsfiles @@ -591,12 +591,15 @@ common common-options DeriveLift DeriveTraversable DerivingStrategies + FlexibleContexts InstanceSigs KindSignatures LambdaCase + NamedFieldPuns NoStarIsType PolyKinds RankNTypes + RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections From 947c9d176d9d6218a35bf72ff89e0bafad11da41 Mon Sep 17 00:00:00 2001 From: Lucas Bollen Date: Thu, 8 Feb 2024 13:33:22 +0100 Subject: [PATCH 3/4] Bump `clash-prelude` bounds in `simple/README.md` --- projects/simple/README.md | 2 +- simple.hsfiles | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/simple/README.md b/projects/simple/README.md index 71d9c58..86fcb31 100644 --- a/projects/simple/README.md +++ b/projects/simple/README.md @@ -152,7 +152,7 @@ Note that this whole section is a `common` "stanza". We'll use it as a template Cabal, -- clash-prelude will set suitable version bounds for the plugins - clash-prelude >= 1.6.4 && < 1.8, + clash-prelude >= 1.8.1 && < 1.10, ghc-typelits-natnormalise, ghc-typelits-extra, ghc-typelits-knownnat diff --git a/simple.hsfiles b/simple.hsfiles index 63eecf2..5b4e6c0 100644 --- a/simple.hsfiles +++ b/simple.hsfiles @@ -222,7 +222,7 @@ Note that this whole section is a `common` "stanza". We'll use it as a template Cabal, -- clash-prelude will set suitable version bounds for the plugins - clash-prelude >= 1.6.4 && < 1.8, + clash-prelude >= 1.8.1 && < 1.10, ghc-typelits-natnormalise, ghc-typelits-extra, ghc-typelits-knownnat From 62e8416837a43ebd3f9e8d5f84423f21108473ab Mon Sep 17 00:00:00 2001 From: Lucas Bollen Date: Thu, 8 Feb 2024 13:33:40 +0100 Subject: [PATCH 4/4] Add `Contributing` section to `README.md` --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c27f4aa..223ba43 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # Stack Templates -Templates for `stack new` command. If you wish to alter a template, edit them in `projects/` and run `./render.hs`. To instantiate one the projects: - +Templates for `stack new` command. To use this template perform the following steps: 1. [Install Stack](https://docs.haskellstack.org/en/stable/README/#how-to-install) 2. Run `stack new my-clash-project clash-lang/simple`. Replace `simple` by the template you'd like to use. 3. Read `my-clash-project/README.md`. Enjoy! @@ -8,5 +7,21 @@ Templates for `stack new` command. If you wish to alter a template, edit them in ## Cabal users All starter projects are also available on [clash-lang/clash-starters](https://github.com/clash-lang/clash-starters). +## Contributing +If you wish to contribute to this template, edit them in `projects/` and perform the following steps to test the template: +1. Edit the template +2. Run `./render.hs` to instantiate them. +3. Go to the parent directory: `cd ..` and instantiate the template using the rendered `.hsfiles`. +``` +cd .. +stack new my-template stack-templates/simple.hsfiles +``` +4. Use the template: +``` +cd my-template +cabal build +cabal test +``` + ## License The default license for each of the starter project is BSD2. However, this whole repository -including every starter project- is licensed under CC0. That means the authors, to the extent possible under law, have waived all copyright and related or neighboring rights to this "Clash Example Project". Feel free to choose any license for the starter projects that you want.