{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}

module Clash.Signal.Internal.Ambiguous
  ( knownVDomain
  , clockPeriod
  , activeEdge
  , resetKind
  , initBehavior
  , resetPolarity
  ) where

import           Clash.Signal.Internal
import           Clash.Promoted.Nat         (SNat)

-- | Get the clock period from a KnownDomain context
clockPeriod
  :: forall dom period
   . (KnownDomain dom, DomainPeriod dom ~ period)
  => SNat period
clockPeriod :: SNat period
clockPeriod =
  case KnownDomain dom => SDomainConfiguration dom (KnownConf dom)
forall (dom :: Domain).
KnownDomain dom =>
SDomainConfiguration dom (KnownConf dom)
knownDomain @dom of
    SDomainConfiguration{SNat period
sPeriod :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
       (reset :: ResetKind) (init :: InitBehavior)
       (polarity :: ResetPolarity).
SDomainConfiguration
  dom ('DomainConfiguration dom period edge reset init polarity)
-> SNat period
sPeriod :: SNat period
sPeriod} ->
      SNat period
SNat period
sPeriod
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE clockPeriod #-}
-- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

-- | Get 'ActiveEdge' from a KnownDomain context. Example usage:
--
-- @
-- f :: forall dom . KnownDomain dom => ....
-- f a b c =
--   case activeEdge @dom of
--     SRising -> foo
--     SFalling -> bar
-- @
activeEdge
  :: forall dom edge
   . (KnownDomain dom, DomainActiveEdge dom ~ edge)
  => SActiveEdge edge
activeEdge :: SActiveEdge edge
activeEdge =
  case KnownDomain dom => SDomainConfiguration dom (KnownConf dom)
forall (dom :: Domain).
KnownDomain dom =>
SDomainConfiguration dom (KnownConf dom)
knownDomain @dom of
    SDomainConfiguration{SActiveEdge edge
sActiveEdge :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
       (reset :: ResetKind) (init :: InitBehavior)
       (polarity :: ResetPolarity).
SDomainConfiguration
  dom ('DomainConfiguration dom period edge reset init polarity)
-> SActiveEdge edge
sActiveEdge :: SActiveEdge edge
sActiveEdge} ->
      SActiveEdge edge
SActiveEdge edge
sActiveEdge
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE activeEdge #-}
-- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

-- | Get 'ResetKind' from a KnownDomain context. Example usage:
--
-- @
-- f :: forall dom . KnownDomain dom => ....
-- f a b c =
--   case resetKind @dom of
--     SAsynchronous -> foo
--     SSynchronous -> bar
-- @
resetKind
  :: forall dom sync
   . (KnownDomain dom, DomainResetKind dom ~ sync)
  => SResetKind sync
resetKind :: SResetKind sync
resetKind =
  case KnownDomain dom => SDomainConfiguration dom (KnownConf dom)
forall (dom :: Domain).
KnownDomain dom =>
SDomainConfiguration dom (KnownConf dom)
knownDomain @dom of
    SDomainConfiguration{SResetKind reset
sResetKind :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
       (reset :: ResetKind) (init :: InitBehavior)
       (polarity :: ResetPolarity).
SDomainConfiguration
  dom ('DomainConfiguration dom period edge reset init polarity)
-> SResetKind reset
sResetKind :: SResetKind reset
sResetKind} ->
      SResetKind sync
SResetKind reset
sResetKind
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE resetKind #-}
-- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

-- | Get 'InitBehavior' from a KnownDomain context. Example usage:
--
-- @
-- f :: forall dom . KnownDomain dom => ....
-- f a b c =
--   case initBehavior @dom of
--     SDefined -> foo
--     SUnknown -> bar
-- @
initBehavior
  :: forall dom init
   . (KnownDomain dom, DomainInitBehavior dom ~ init)
  => SInitBehavior init
initBehavior :: SInitBehavior init
initBehavior =
  case KnownDomain dom => SDomainConfiguration dom (KnownConf dom)
forall (dom :: Domain).
KnownDomain dom =>
SDomainConfiguration dom (KnownConf dom)
knownDomain @dom of
    SDomainConfiguration{SInitBehavior init
sInitBehavior :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
       (reset :: ResetKind) (init :: InitBehavior)
       (polarity :: ResetPolarity).
SDomainConfiguration
  dom ('DomainConfiguration dom period edge reset init polarity)
-> SInitBehavior init
sInitBehavior :: SInitBehavior init
sInitBehavior} ->
      SInitBehavior init
SInitBehavior init
sInitBehavior
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE initBehavior #-}
-- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

-- | Get 'ResetPolarity' from a KnownDomain context. Example usage:
--
-- @
-- f :: forall dom . KnownDomain dom => ....
-- f a b c =
--   case resetPolarity @dom of
--     SActiveHigh -> foo
--     SActiveLow -> bar
-- @
resetPolarity
  :: forall dom polarity
   . (KnownDomain dom, DomainResetPolarity dom ~ polarity)
  => SResetPolarity polarity
resetPolarity :: SResetPolarity polarity
resetPolarity =
  case KnownDomain dom => SDomainConfiguration dom (KnownConf dom)
forall (dom :: Domain).
KnownDomain dom =>
SDomainConfiguration dom (KnownConf dom)
knownDomain @dom of
    SDomainConfiguration{SResetPolarity polarity
sResetPolarity :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
       (reset :: ResetKind) (init :: InitBehavior)
       (polarity :: ResetPolarity).
SDomainConfiguration
  dom ('DomainConfiguration dom period edge reset init polarity)
-> SResetPolarity polarity
sResetPolarity :: SResetPolarity polarity
sResetPolarity} ->
      SResetPolarity polarity
SResetPolarity polarity
sResetPolarity
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE resetPolarity #-}
-- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

-- | Like 'knownDomain but yields a 'VDomainConfiguration'. Should only be used
-- in combination with 'createDomain'.
knownVDomain
  :: forall dom
   . KnownDomain dom
  => VDomainConfiguration
knownVDomain :: VDomainConfiguration
knownVDomain =
  SDomainConfiguration dom (KnownConf dom) -> VDomainConfiguration
forall (dom :: Domain) (conf :: DomainConfiguration).
SDomainConfiguration dom conf -> VDomainConfiguration
vDomain (KnownDomain dom => SDomainConfiguration dom (KnownConf dom)
forall (dom :: Domain).
KnownDomain dom =>
SDomainConfiguration dom (KnownConf dom)
knownDomain @dom)