Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace topEntity and enable extra extensions #33

Merged
merged 4 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
# 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!

## 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.
1 change: 1 addition & 0 deletions deca.hsfiles
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions projects/simple-nix/nix/nixpkgs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
8 changes: 0 additions & 8 deletions projects/simple-nix/stack.yaml

This file was deleted.

1 change: 1 addition & 0 deletions projects/simple-nix/stack.yaml
4 changes: 4 additions & 0 deletions projects/simple-nix/{{name}}.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ common common-options
DeriveLift
DeriveTraversable
DerivingStrategies
FlexibleContexts
InstanceSigs
KindSignatures
LambdaCase
NamedFieldPuns
NoStarIsType
PolyKinds
RankNTypes
RecordWildCards
ScopedTypeVariables
StandaloneDeriving
TupleSections
Expand Down Expand Up @@ -120,6 +123,7 @@ test-suite test-library
build-depends:
{{name}},
QuickCheck,
clash-prelude-hedgehog,
hedgehog,
tasty >= 1.2 && < 1.5,
tasty-hedgehog,
Expand Down
2 changes: 1 addition & 1 deletion projects/simple/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
63 changes: 49 additions & 14 deletions projects/simple/src/Example/Project.hs
Original file line number Diff line number Diff line change
@@ -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
lmbollen marked this conversation as resolved.
Show resolved Hide resolved
{ 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)
1 change: 1 addition & 0 deletions projects/simple/stack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
44 changes: 34 additions & 10 deletions projects/simple/tests/Tests/Example/Project.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion projects/simple/tests/unittests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import qualified Tests.Example.Project

main :: IO ()
main = defaultMain $ testGroup "."
[ Tests.Example.Project.tests
[ Tests.Example.Project.accumTests
]
4 changes: 4 additions & 0 deletions projects/simple/{{name}}.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ common common-options
DeriveLift
DeriveTraversable
DerivingStrategies
FlexibleContexts
InstanceSigs
KindSignatures
LambdaCase
NamedFieldPuns
NoStarIsType
PolyKinds
RankNTypes
RecordWildCards
ScopedTypeVariables
StandaloneDeriving
TupleSections
Expand Down Expand Up @@ -124,6 +127,7 @@ test-suite test-library
build-depends:
{{name}},
QuickCheck,
clash-prelude-hedgehog,
hedgehog,
tasty >= 1.2 && < 1.5,
tasty-hedgehog,
Expand Down
Loading
Loading