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

Fix Clash.Clocks lock signal (copy #2417) #2420

Merged
merged 1 commit into from
Feb 10, 2023
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
5 changes: 5 additions & 0 deletions changelog/2023-02-05T12_23_02+01_00_clocks-lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FIXED: The Haskell simulation of the PLL lock signal in `Clash.Clocks` (used by
`Clash.Intel.ClockGen`) is fixed: the signal is now unasserted for the time the
reset input is asserted and vice versa, and no longer crashes the simulation.
HDL generation is unchanged. The PLL functions now have an additional
constraint: `KnownDomain pllLock`.
3 changes: 2 additions & 1 deletion clash-prelude/clash-prelude.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Maintainer: QBayLogic B.V. <devops@qbaylogic.com>
Copyright: Copyright © 2013-2016, University of Twente,
2016-2017, Myrtle Software Ltd,
2017-2019, QBayLogic B.V., Google Inc.,
2021-2022, QBayLogic B.V.
2021-2023, QBayLogic B.V.
Category: Hardware
Build-type: Simple

Expand Down Expand Up @@ -410,6 +410,7 @@ test-suite unittests
Clash.Tests.BitVector
Clash.Tests.BlockRam
Clash.Tests.BlockRam.Blob
Clash.Tests.Clocks
Clash.Tests.Counter
Clash.Tests.DerivingDataRepr
Clash.Tests.DerivingDataReprTypes
Expand Down
21 changes: 16 additions & 5 deletions clash-prelude/src/Clash/Clocks/Deriving.hs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{-|
Copyright : (C) 2018, Google Inc
2019, Myrtle Software Ltd
2023, QBayLogic B.V.
License : BSD2 (see the file LICENSE)
Maintainer : Christiaan Baaij <christiaan.baaij@gmail.com>
Maintainer : QBayLogic B.V. <devops@qbaylogic.com>
-}

{-# LANGUAGE CPP #-}
Expand All @@ -12,6 +13,7 @@ Maintainer : Christiaan Baaij <christiaan.baaij@gmail.com>
module Clash.Clocks.Deriving (deriveClocksInstances) where

import Control.Monad (foldM)
import Clash.Explicit.Signal (unsafeSynchronizer)
import Clash.Signal.Internal
import Language.Haskell.TH.Compat
import Language.Haskell.TH.Syntax
Expand All @@ -26,22 +28,26 @@ derive' n = do
instType1 <- AppT instType0 <$> lockType
let instHead = AppT (ConT $ mkName "Clocks") instType1

cxtRHS <- foldM (\a n' -> AppT a <$> knownDomainCxt n') (TupleT n) [1..n]
cxtRHS0 <-
foldM (\a n' -> AppT a <$> knownDomainCxt n') (TupleT $ n + 1) [1..n]
cxtRHS1 <- AppT cxtRHS0 <$> lockKnownDomainCxt
#if MIN_VERSION_template_haskell(2,15,0)
let cxtLHS = AppT (ConT $ mkName "ClocksCxt") instType1
let cxtTy = TySynInstD (TySynEqn Nothing cxtLHS cxtRHS)
let cxtTy = TySynInstD (TySynEqn Nothing cxtLHS cxtRHS1)
#else
let cxtTy = TySynInstD (mkName "ClocksCxt") (TySynEqn [instType1] cxtRHS)
let cxtTy = TySynInstD (mkName "ClocksCxt") (TySynEqn [instType1] cxtRHS1)
#endif

-- Function definition of 'clocks'
let clk = mkName "clk"
let rst = mkName "rst"

-- Implementation of 'clocks'
lockImpl <- [| unsafeSynchronizer clockGen clockGen
(unsafeToLowPolarity $(varE rst)) |]
let noInline = PragmaD $ InlineP (mkName "clocks") NoInline FunLike AllPhases
let clkImpls = replicate n (clkImpl clk)
let instTuple = mkTupE $ clkImpls ++ [AppE (VarE 'unsafeCoerce) (VarE rst)]
let instTuple = mkTupE $ clkImpls ++ [lockImpl]
let funcBody = NormalB instTuple
let instFunc = FunD (mkName "clocks") [Clause [VarP clk, VarP rst] funcBody []]

Expand All @@ -62,6 +68,11 @@ derive' n = do
let c = varT $ mkName "pllLock" in
[t| Signal $c Bool |]

lockKnownDomainCxt =
let p = varT $ mkName "pllLock" in
[t| KnownDomain $p |]


clkImpl clk = AppE (VarE 'unsafeCoerce) (VarE clk)

-- Derive instances for up to and including to /n/ clocks
Expand Down
50 changes: 50 additions & 0 deletions clash-prelude/tests/Clash/Tests/Clocks.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}

module Clash.Tests.Clocks(tests) where

import qualified Prelude as P

import Test.Tasty
import Test.Tasty.HUnit

import Clash.Explicit.Prelude
import Clash.Intel.ClockGen (altpll)

-- Ratio of clock periods in 'createDomain' and 'resetLen' are chosen, rest is
-- derived from that

createDomain vSystem{vName="ClocksSlow", vPeriod=3 * vPeriod vSystem}

resetLen :: SNat 10
resetLen = SNat

lockResampled :: Assertion
lockResampled =
unlockedLenSeen @?= unlockedLen
where
pll ::
Clock ClocksSlow ->
Reset ClocksSlow ->
(Clock System, Signal System Bool)
pll = altpll (SSymbol @"pll")

unlockedLenSeen =
P.length . P.takeWhile not .
-- Arbitrary cut-off so simulation always ends
sampleN (unlockedLen + 100) .
snd $ pll clockGen (resetGenN resetLen)

clockRatio :: Int
clockRatio = fromIntegral $ snatToNatural (clockPeriod @ClocksSlow) `div`
snatToNatural (clockPeriod @System)

unlockedLen :: Int
unlockedLen = snatToNum resetLen * clockRatio - clockRatio + 1

tests :: TestTree
tests =
testGroup "Clocks class"
[ testCase "Lock is resampled from reset" lockResampled ]
2 changes: 2 additions & 0 deletions clash-prelude/tests/unittests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import qualified Clash.Tests.BitPack
import qualified Clash.Tests.BitVector
import qualified Clash.Tests.BlockRam
import qualified Clash.Tests.BlockRam.Blob
import qualified Clash.Tests.Clocks
import qualified Clash.Tests.Counter
import qualified Clash.Tests.DerivingDataRepr
import qualified Clash.Tests.Fixed
Expand All @@ -34,6 +35,7 @@ tests = testGroup "Unittests"
, Clash.Tests.BitVector.tests
, Clash.Tests.BlockRam.tests
, Clash.Tests.BlockRam.Blob.tests
, Clash.Tests.Clocks.tests
, Clash.Tests.Counter.tests
, Clash.Tests.DerivingDataRepr.tests
, Clash.Tests.Fixed.tests
Expand Down