11{-|
2- Copyright : (C) 2020-2023 , QBayLogic B.V.,
2+ Copyright : (C) 2020-2026 , QBayLogic B.V.,
33 2022-2023, Google LLC
44License : BSD2 (see the file LICENSE)
55Maintainer : QBayLogic B.V. <devops@qbaylogic.com>
@@ -23,6 +23,7 @@ module Clash.Explicit.Reset
2323 , resetGlitchFilter
2424 , resetGlitchFilterWithReset
2525 , unsafeResetGlitchFilter
26+ , registerSyncReset
2627 , holdReset
2728 , convertReset
2829 , noReset
@@ -55,8 +56,10 @@ import Clash.Class.Num (satSucc, SaturationMode(SatBound))
5556import Clash.Explicit.Signal
5657import Clash.Explicit.Synchronizer (dualFlipFlopSynchronizer )
5758import Clash.Promoted.Nat
59+ import Clash.Promoted.Nat.Literals
5860import Clash.Signal.Internal
5961import Clash.Sized.Index (Index )
62+ import Clash.Magic (clashCompileError )
6063
6164import GHC.Stack (HasCallStack )
6265import GHC.TypeLits (type (+ ), type (<= ))
@@ -399,20 +402,62 @@ resetGlitchFilter# SNat reg dffSync rstIn0 =
399402 SActiveHigh -> True
400403 SActiveLow -> False
401404
402- -- | Hold reset for a number of cycles relative to an incoming reset signal.
405+ -- | Register a synchronous reset signal.
406+ --
407+ -- `registerSyncReset` delays an incoming reset by one clock cycle using a
408+ -- register. This can be useful to break combinational paths involving reset
409+ -- logic.
410+ --
411+ -- __NB__: This is not a synchronizer. Use `resetSynchronizer` to synchronize
412+ -- a reset.
413+ --
414+ -- Example:
415+ --
416+ -- >>> let sampleReset = sampleN 7 . unsafeToActiveHigh
417+ -- >>> let rst = unsafeFromActiveHigh (fromList [False, True, False, False, True, False])
418+ -- >>> sampleReset (registerSyncReset @XilinxSystem clockGen rst enableGen True)
419+ -- [True,False,True,False,False,True,False]
420+ --
421+ registerSyncReset
422+ :: forall dom
423+ . KnownDomain dom
424+ => DomainResetKind dom ~ 'Synchronous
425+ => Clock dom
426+ -> Reset dom
427+ -> Enable dom
428+ -> Bool
429+ -- ^ Initial assert value of the register if supported by the domain.
430+ -- If True the initial reset value is asserted.
431+ -- If False the initial reset value is de-asserted.
432+ -> Reset dom
433+ registerSyncReset clk (unsafeFromReset -> rst) en initialValue = unsafeToReset outRst
434+ where
435+ intialRst :: Bool
436+ intialRst =
437+ case resetPolarity @ dom of
438+ SActiveHigh -> initialValue
439+ SActiveLow -> not initialValue
440+ outRst = delay clk en intialRst rst
441+
442+ -- | Hold/stretch reset for a number of cycles relative to an incoming reset
443+ -- signal.
444+ --
445+ -- __NB__: The output of this function is combinational for @n > 1@ on domains
446+ -- with a synchronous reset. Use `registerSyncReset` to add an output register if
447+ -- desired.
403448--
404449-- Example:
405450--
406- -- >>> let sampleWithReset = sampleN 8 . unsafeToActiveHigh
407- -- >>> sampleWithReset (holdReset @System clockGen enableGen (SNat @2) (resetGenN (SNat @3)))
451+ -- >>> let sampleReset = sampleN 8 . unsafeToActiveHigh
452+ -- >>> sampleReset (holdReset @System clockGen enableGen (SNat @2) (resetGenN (SNat @3)))
408453-- [True,True,True,True,True,False,False,False]
409454--
410455-- 'holdReset' holds the reset for an additional 2 clock cycles for a total
411456-- of 5 clock cycles where the reset is asserted. 'holdReset' also works on
412457-- intermediate assertions of the reset signal:
413458--
414459-- >>> let rst = fromList [True, False, False, False, True, False, False, False]
415- -- >>> sampleWithReset (holdReset @System clockGen enableGen (SNat @2) (unsafeFromActiveHigh rst))
460+ -- >>> sampleReset (holdReset @System clockGen enableGen (SNat @2) (unsafeFromActiveHigh rst))
416461-- [True,True,True,False,True,True,True,False]
417462--
418463holdReset
@@ -427,11 +472,66 @@ holdReset
427472 -> Reset dom
428473 -- ^ Reset to extend
429474 -> Reset dom
430- holdReset clk en SNat rst =
431- unsafeFromActiveHigh ((/= maxBound ) <$> counter)
475+ holdReset clk en n rst = case resetKind @ dom of
476+ SSynchronous -> holdResetSync clk en n rst
477+ SAsynchronous -> holdResetAsync clk en n rst
478+
479+ holdResetSync
480+ :: forall dom n
481+ . KnownDomain dom
482+ => DomainResetKind dom ~ 'Synchronous
483+ => Clock dom
484+ -> Enable dom
485+ -- ^ Global enable
486+ -> SNat n
487+ -- ^ Hold for /n/ cycles
488+ -> Reset dom
489+ -- ^ Reset to extend
490+ -> Reset dom
491+ holdResetSync clk en sn@ SNat rst = rstOut
432492 where
433- counter :: Signal dom (Index (n + 1 ))
434- counter = register clk rst en 0 (satSucc SatBound <$> counter)
493+ isActiveHigh = case resetPolarity @ dom of { SActiveHigh -> True ; _ -> False }
494+
495+ rstOut = case snatToInteger sn of
496+ 0 -> rst
497+ 1 -> unsafeToReset (register clk rst en isActiveHigh (unsafeFromReset rst))
498+ _ -> unsafeToReset rawRst
499+ where
500+ counter :: Signal dom (Index (n + 1 ))
501+ counter = register clk rst en 0 (satSucc SatBound <$> counter)
502+ rawRst :: Signal dom Bool
503+ rawRst = case resetPolarity @ dom of
504+ SActiveHigh -> (/= maxBound ) <$> counter
505+ SActiveLow -> (== maxBound ) <$> counter
506+
507+ holdResetAsync
508+ :: forall dom n
509+ . KnownDomain dom
510+ => DomainResetKind dom ~ 'Asynchronous
511+ => Clock dom
512+ -> Enable dom
513+ -- ^ Global enable
514+ -> SNat n
515+ -- ^ Hold for /n/ cycles
516+ -> Reset dom
517+ -- ^ Reset to extend
518+ -> Reset dom
519+ holdResetAsync clk en sn@ SNat rst = rstOut
520+ where
521+ isActiveHigh = case resetPolarity @ dom of { SActiveHigh -> True ; _ -> False }
522+ rstOut = case (snatToInteger sn, compareSNat d2 sn) of
523+ (0 , _) -> rst
524+ (1 , _) -> unsafeToReset (register clk rst en isActiveHigh (pure (not isActiveHigh)))
525+ (_, SNatLE ) -> unsafeToReset (register clk rst en isActiveHigh rawRst)
526+ where
527+ counter :: Signal dom (Index n )
528+ counter = register clk rst en 0 (satSucc SatBound <$> counter)
529+ rawRst :: Signal dom Bool
530+ rawRst = case resetPolarity @ dom of
531+ SActiveHigh -> (/= maxBound ) <$> counter
532+ SActiveLow -> (== maxBound ) <$> counter
533+ (_, SNatGT ) -> clashCompileError " holdResetAsync: Impossbile! n =! 0 && n != 1 && 2 > n, Please report this at https://github.com/clash-lang/clash-compiler/issues."
534+
435535
436536-- | Convert between different types of reset, adding a synchronizer when
437537-- the domains are not the same. See 'resetSynchronizer' for further details
0 commit comments