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
@@ -399,20 +400,62 @@ resetGlitchFilter# SNat reg dffSync rstIn0 =
399400 SActiveHigh -> True
400401 SActiveLow -> False
401402
402- -- | Hold reset for a number of cycles relative to an incoming reset signal.
403+ -- | Register a synchronous reset signal.
404+ --
405+ -- `registerSyncReset` delays an incoming reset by one clock cycle using a
406+ -- register. This can be useful to break combinational paths involving reset
407+ -- logic.
408+ --
409+ -- __NB__: This is not a synchronizer. Use `resetSynchronizer` to synchronize
410+ -- a reset.
411+ --
412+ -- Example:
413+ --
414+ -- >>> let sampleReset = sampleN 7 . unsafeToActiveHigh
415+ -- >>> let rst = unsafeFromActiveHigh (fromList [False, True, False, False, True, False])
416+ -- >>> sampleReset (registerSyncReset @XilinxSystem clockGen rst enableGen True)
417+ -- [True,False,True,False,False,True,False]
418+ --
419+ registerSyncReset
420+ :: forall dom
421+ . KnownDomain dom
422+ => HasSynchronousReset dom
423+ => Clock dom
424+ -> Reset dom
425+ -> Enable dom
426+ -> Bool
427+ -- ^ Initial assert value of the register if supported by the domain.
428+ -- If True the initial reset value is asserted.
429+ -- If False the initial reset value is de-asserted.
430+ -> Reset dom
431+ registerSyncReset clk (unsafeFromReset -> rst) en initialValue = unsafeToReset outRst
432+ where
433+ intialRst :: Bool
434+ intialRst =
435+ case resetPolarity @ dom of
436+ SActiveHigh -> initialValue
437+ SActiveLow -> not initialValue
438+ outRst = delay clk en intialRst rst
439+
440+ -- | Hold reset for a number of cycles relative to an incoming reset
441+ -- signal.
442+ --
443+ -- __NB__: The output of this function is combinational for @n > 0@ on domains
444+ -- with a synchronous reset. Use `registerSyncReset` to add an output register if
445+ -- desired.
403446--
404447-- Example:
405448--
406- -- >>> let sampleWithReset = sampleN 8 . unsafeToActiveHigh
407- -- >>> sampleWithReset (holdReset @System clockGen enableGen (SNat @2) (resetGenN (SNat @3)))
449+ -- >>> let sampleReset = sampleN 8 . unsafeToActiveHigh
450+ -- >>> sampleReset (holdReset @System clockGen enableGen (SNat @2) (resetGenN (SNat @3)))
408451-- [True,True,True,True,True,False,False,False]
409452--
410453-- 'holdReset' holds the reset for an additional 2 clock cycles for a total
411454-- of 5 clock cycles where the reset is asserted. 'holdReset' also works on
412455-- intermediate assertions of the reset signal:
413456--
414457-- >>> let rst = fromList [True, False, False, False, True, False, False, False]
415- -- >>> sampleWithReset (holdReset @System clockGen enableGen (SNat @2) (unsafeFromActiveHigh rst))
458+ -- >>> sampleReset (holdReset @System clockGen enableGen (SNat @2) (unsafeFromActiveHigh rst))
416459-- [True,True,True,False,True,True,True,False]
417460--
418461holdReset
@@ -427,11 +470,66 @@ holdReset
427470 -> Reset dom
428471 -- ^ Reset to extend
429472 -> Reset dom
430- holdReset clk en SNat rst =
431- unsafeFromActiveHigh ((/= maxBound ) <$> counter)
473+ holdReset clk en n rst = case resetKind @ dom of
474+ SSynchronous -> holdResetSync clk en n rst
475+ SAsynchronous -> holdResetAsync clk en n rst
476+
477+ holdResetSync
478+ :: forall dom n
479+ . KnownDomain dom
480+ => DomainResetKind dom ~ 'Synchronous
481+ => Clock dom
482+ -> Enable dom
483+ -- ^ Global enable
484+ -> SNat n
485+ -- ^ Hold for /n/ cycles
486+ -> Reset dom
487+ -- ^ Reset to extend
488+ -> Reset dom
489+ holdResetSync clk en sn@ SNat rst = rstOut
490+ where
491+ rstOut = case snatToInteger sn of
492+ 0 -> rst
493+ 1 -> orReset rst (unsafeToReset regReset)
494+ where
495+ isActiveHigh = case resetPolarity @ dom of { SActiveHigh -> True ; _ -> False }
496+ regReset = register clk rst en isActiveHigh (pure (not isActiveHigh))
497+ _ -> orReset rst (unsafeToReset rawRst)
498+ where
499+ counter :: Signal dom (Index (n + 1 ))
500+ counter = register clk rst en 0 (satSucc SatBound <$> counter)
501+ rawRst :: Signal dom Bool
502+ rawRst = case resetPolarity @ dom of
503+ SActiveHigh -> (/= maxBound ) <$> counter
504+ SActiveLow -> (== maxBound ) <$> counter
505+
506+ holdResetAsync
507+ :: forall dom n
508+ . KnownDomain dom
509+ => DomainResetKind dom ~ 'Asynchronous
510+ => Clock dom
511+ -> Enable dom
512+ -- ^ Global enable
513+ -> SNat n
514+ -- ^ Hold for /n/ cycles
515+ -> Reset dom
516+ -- ^ Reset to extend
517+ -> Reset dom
518+ holdResetAsync clk en sn@ SNat rst = rstOut
432519 where
433- counter :: Signal dom (Index (n + 1 ))
434- counter = register clk rst en 0 (satSucc SatBound <$> counter)
520+ isActiveHigh = case resetPolarity @ dom of { SActiveHigh -> True ; _ -> False }
521+ rstOut = case toUNat sn of
522+ UZero -> rst
523+ USucc UZero -> unsafeToReset (register clk rst en isActiveHigh (pure (not isActiveHigh)))
524+ USucc (USucc _) -> unsafeToReset (register clk rst en isActiveHigh rawRst)
525+ where
526+ counter :: Signal dom (Index n )
527+ counter = register clk rst en 0 (satSucc SatBound <$> counter)
528+ rawRst :: Signal dom Bool
529+ rawRst = case resetPolarity @ dom of
530+ SActiveHigh -> (/= maxBound ) <$> counter
531+ SActiveLow -> (== maxBound ) <$> counter
532+
435533
436534-- | Convert between different types of reset, adding a synchronizer when
437535-- the domains are not the same. See 'resetSynchronizer' for further details
0 commit comments