content: {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE TemplateHaskell #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE DataKinds #-}
  
  {-# OPTIONS_GHC -Wno-orphans #-}
  
  module Clash.Tests.Reset where
  
  import Test.Tasty
  import Test.Tasty.HUnit
  import Test.Tasty.TH
  import Clash.Explicit.Prelude
  
  import qualified Prelude as P
  
  -- Testing with explicit declaration of the Low type alias
  type Low = ("Low" :: Domain)
  createDomain vSystem{vName="Low", vResetPolarity=ActiveLow}
  
  sampleResetN :: KnownDomain dom => Int -> Reset dom -> [Bool]
  sampleResetN n = sampleN n . unsafeToActiveHigh
  
  resetFromList :: KnownDomain dom => [Bool] -> Reset dom
  resetFromList = unsafeFromActiveHigh . fromList
  
  onePeriodGlitchReset :: KnownDomain dom => Reset dom
  onePeriodGlitchReset =
    resetFromList [True,True,False,False,True,False,False,True,True,False,False,False]
  
  -- | Introduce a glitch of one period, and see if it's filtered out
  --
  -- Note that since 'System' is a domain with asynchronous resets,
  -- 'resetGlitchFilter' first synchronizes the incoming reset. This leads to an
  -- additional delay of two cycles with respect to the output.
  case_onePeriodGlitch :: Assertion
  case_onePeriodGlitch =
        [True,True,True,True,True,True,False,False,False,False,False,True,True,False]
    @=? sampleResetN 14 (resetGlitchFilter d2 systemClockGen onePeriodGlitchReset)
  
  -- | Same as 'case_onePeriodGlitch' but on a domain with active low resets
  case_onePeriodGlitch_LowPolarity :: Assertion
  case_onePeriodGlitch_LowPolarity =
        [True,True,True,True,True,True,False,False,False,False,False,True,True,False]
    @=? sampleResetN 14 (resetGlitchFilter d2 (clockGen @Low) onePeriodGlitchReset)
  
  -- Check that the meaning of @Reset@ is maintained when converting from
  -- active-low to active-high.
  case_convertReset_polarity_change :: Assertion
  case_convertReset_polarity_change =
        -- In domains with synchronous resets and defined initial values,
        -- @resetSynchronizer@ will start with an asserted reset.
        True : True : P.replicate 8 False
    @=? sampleResetN 10 (convertReset (clockGen @Low) (clockGen @System)
                                      (resetFromList $ P.repeat False))
  
  tests :: TestTree
  tests = testGroup "Reset"
    [ $(testGroupGenerator)
    ]
  
  main :: IO ()
  main = defaultMain tests
  